Fab.jsx 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import React, { useState, useCallback, useEffect } from 'react';
  2. import PropTypes from 'prop-types';
  3. import loggerFactory from '@alias/logger';
  4. import StickyEvents from 'sticky-events';
  5. import AppContainer from '../services/AppContainer';
  6. import NavigationContainer from '../services/NavigationContainer';
  7. import { withUnstatedContainers } from './UnstatedUtils';
  8. import CreatePageIcon from './Icons/CreatePageIcon';
  9. import ReturnTopIcon from './Icons/ReturnTopIcon';
  10. const logger = loggerFactory('growi:cli:Fab');
  11. const Fab = (props) => {
  12. const { navigationContainer, appContainer } = props;
  13. const { currentUser } = appContainer;
  14. const [animateClasses, setAnimateClasses] = useState('invisible');
  15. const [buttonClasses, setButtonClasses] = useState('invisible');
  16. const stickyChangeHandler = useCallback((event) => {
  17. logger.debug('StickyEvents.CHANGE detected');
  18. const classes = event.detail.isSticky ? 'animated fadeInUp faster' : 'animated fadeOut faster';
  19. const buttonHidden = event.detail.isSticky ? null : 'disabled';
  20. setAnimateClasses(classes);
  21. setButtonClasses(buttonHidden);
  22. }, []);
  23. // setup effect by sticky event
  24. useEffect(() => {
  25. // sticky
  26. // See: https://github.com/ryanwalters/sticky-events
  27. const stickyEvents = new StickyEvents({ stickySelector: '#grw-fav-sticky-trigger' });
  28. const { stickySelector } = stickyEvents;
  29. const elem = document.querySelector(stickySelector);
  30. elem.addEventListener(StickyEvents.CHANGE, stickyChangeHandler);
  31. // return clean up handler
  32. return () => {
  33. elem.removeEventListener(StickyEvents.CHANGE, stickyChangeHandler);
  34. };
  35. }, [stickyChangeHandler]);
  36. function renderPageCreateButton() {
  37. return (
  38. <>
  39. <div className={`rounded-circle position-absolute ${animateClasses} grw-btn-disabled-default`} style={{ bottom: '2.3rem', right: '4rem' }}>
  40. <button
  41. type="button"
  42. className={`btn btn-lg btn-create-page btn-primary rounded-circle p-0 waves-effect waves-light ${buttonClasses}`}
  43. onClick={navigationContainer.openPageCreateModal}
  44. >
  45. <CreatePageIcon />
  46. </button>
  47. </div>
  48. </>
  49. );
  50. }
  51. return (
  52. <div className="grw-fab d-none d-md-block">
  53. {currentUser != null && renderPageCreateButton()}
  54. <div className={`rounded-circle position-absolute ${animateClasses} grw-btn-disabled-default`} style={{ bottom: 0, right: 0 }}>
  55. <button
  56. type="button"
  57. className={`btn btn-light btn-scroll-to-top rounded-circle p-0 ${buttonClasses}`}
  58. onClick={() => navigationContainer.smoothScrollIntoView()}
  59. >
  60. <ReturnTopIcon />
  61. </button>
  62. </div>
  63. </div>
  64. );
  65. };
  66. Fab.propTypes = {
  67. appContainer: PropTypes.instanceOf(AppContainer).isRequired,
  68. navigationContainer: PropTypes.instanceOf(NavigationContainer).isRequired,
  69. };
  70. export default withUnstatedContainers(Fab, [AppContainer, NavigationContainer]);