Fab.jsx 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  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 NavigationContainer from '../services/NavigationContainer';
  6. import { withUnstatedContainers } from './UnstatedUtils';
  7. import CreatePageIcon from './Icons/CreatePageIcon';
  8. import ReturnTopIcon from './Icons/ReturnTopIcon';
  9. const logger = loggerFactory('growi:cli:Fab');
  10. const Fab = (props) => {
  11. const { navigationContainer } = props;
  12. const [animateClasses, setAnimateClasses] = useState('invisible');
  13. const stickyChangeHandler = useCallback((event) => {
  14. logger.debug('StickyEvents.CHANGE detected');
  15. const classes = event.detail.isSticky ? 'animated fadeInUp faster' : 'animated fadeOut faster';
  16. setAnimateClasses(classes);
  17. }, []);
  18. // setup effect by sticky event
  19. useEffect(() => {
  20. // sticky
  21. // See: https://github.com/ryanwalters/sticky-events
  22. const stickyEvents = new StickyEvents({ stickySelector: '#grw-fav-sticky-trigger' });
  23. const { stickySelector } = stickyEvents;
  24. const elem = document.querySelector(stickySelector);
  25. elem.addEventListener(StickyEvents.CHANGE, stickyChangeHandler);
  26. // return clean up handler
  27. return () => {
  28. elem.removeEventListener(StickyEvents.CHANGE, stickyChangeHandler);
  29. };
  30. }, [stickyChangeHandler]);
  31. return (
  32. <div className="grw-fab d-none d-md-block">
  33. <div className={`rounded-circle position-absolute ${animateClasses}`} style={{ bottom: '2.3rem', right: '4rem' }}>
  34. <button
  35. type="button"
  36. className="btn btn-lg btn-create-page btn-primary rounded-circle p-0 waves-effect waves-light"
  37. onClick={navigationContainer.openPageCreateModal}
  38. >
  39. <CreatePageIcon />
  40. </button>
  41. </div>
  42. <div className={`rounded-circle position-absolute ${animateClasses}`} style={{ bottom: 0, right: 0 }}>
  43. <button type="button" className="btn btn-light btn-scroll-to-top rounded-circle p-0" onClick={() => navigationContainer.smoothScrollIntoView()}>
  44. <ReturnTopIcon />
  45. </button>
  46. </div>
  47. </div>
  48. );
  49. };
  50. Fab.propTypes = {
  51. navigationContainer: PropTypes.instanceOf(NavigationContainer).isRequired,
  52. };
  53. export default withUnstatedContainers(Fab, [NavigationContainer]);