CardTool.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. // Card Tools
  2. // -----------------------------------
  3. import React, { Component } from 'react';
  4. import PropTypes from 'prop-types';
  5. const checkRequiredProps = (props, propName, componentName) => {
  6. if (!props.dismiss && !props.refresh) {
  7. return new Error(`One of 'dismiss' or 'refresh' is required by '${componentName}' component.`)
  8. }
  9. }
  10. /**
  11. * Add action icons to card components to allow
  12. * refresh data or remove a card element
  13. */
  14. class CardTool extends Component {
  15. static propTypes = {
  16. /** show the refreshe icon */
  17. refresh: checkRequiredProps,
  18. /** show the remove icon */
  19. dismiss: checkRequiredProps,
  20. /** triggers before card is removed */
  21. onRemove: PropTypes.func,
  22. /** triggers after card was removed */
  23. onRemoved: PropTypes.func,
  24. /** triggers when user click on refresh button */
  25. onRefresh: PropTypes.func,
  26. /** name if the icon class to use as spinner */
  27. spinner: PropTypes.string
  28. }
  29. static defaultProps = {
  30. refresh: false,
  31. dismiss: false,
  32. onRemove: () => {},
  33. onRemoved: () => {},
  34. onRefresh: () => {},
  35. spinner: 'standard'
  36. }
  37. /**
  38. * Helper function to find the closest
  39. * ascending .card element
  40. */
  41. getCardParent(item) {
  42. var el = item.parentElement;
  43. while (el && !el.classList.contains('card'))
  44. el = el.parentElement
  45. return el
  46. }
  47. handleDismiss = e => {
  48. // find the first parent card
  49. const card = this.getCardParent(this.element);
  50. const destroyCard = () => {
  51. // remove card
  52. card.parentNode.removeChild(card);
  53. // An event to catch when the card has been removed from DOM
  54. this.props.onRemoved();
  55. }
  56. const animate = function(item, cb) {
  57. if ('onanimationend' in window) { // animation supported
  58. item.addEventListener('animationend', cb.bind(this))
  59. item.className += ' animated bounceOut'; // requires animate.css
  60. } else cb.call(this) // no animation, just remove
  61. }
  62. const confirmRemove = function() {
  63. animate(card, function() {
  64. destroyCard();
  65. })
  66. }
  67. // Trigger the event and finally remove the element
  68. this.props.onRemove(card, confirmRemove);
  69. }
  70. handleRefresh = e => {
  71. const WHIRL_CLASS = 'whirl';
  72. const card = this.getCardParent(this.element);
  73. const showSpinner = function(card, spinner) {
  74. card.classList.add(WHIRL_CLASS);
  75. spinner.forEach(function(s) { card.classList.add(s) })
  76. }
  77. // method to clear the spinner when done
  78. const done = () => { card.classList.remove(WHIRL_CLASS); }
  79. // start showing the spinner
  80. showSpinner(card, this.props.spinner.split(' '));
  81. // event to remove spinner when refres is done
  82. this.props.onRefresh(card, done);
  83. }
  84. setRef = node => this.element = node;
  85. render() {
  86. return (
  87. <div ref={this.setRef} className="card-tool float-right">
  88. { this.props.refresh && <em onClick={this.handleRefresh} className="fas fa-sync"></em> }
  89. { this.props.dismiss && <em onClick={this.handleDismiss} className="fa fa-times"></em> }
  90. </div>
  91. )
  92. }
  93. }
  94. export default CardTool;