glitch-soc/mastodon

View on GitHub
app/javascript/flavours/glitch/features/compose/components/dropdown_icon_button.jsx

Summary

Maintainability
A
25 mins
Test Coverage
import PropTypes from 'prop-types';
import { useCallback, useState, useRef } from 'react';

import Overlay from 'react-overlays/Overlay';

import { DropdownSelector } from 'flavours/glitch/components/dropdown_selector';
import { IconButton } from 'flavours/glitch/components/icon_button';

export const DropdownIconButton = ({ value, disabled, icon, onChange, iconComponent, title, options }) => {
  const containerRef = useRef(null);

  const [activeElement, setActiveElement] = useState(null);
  const [open, setOpen] = useState(false);
  const [placement, setPlacement] = useState('bottom');

  const handleToggle = useCallback(() => {
    if (open && activeElement) {
      activeElement.focus({ preventScroll: true });
      setActiveElement(null);
    }

    setOpen(!open);
  }, [open, setOpen, activeElement, setActiveElement]);

  const handleClose = useCallback(() => {
    if (open && activeElement) {
      activeElement.focus({ preventScroll: true });
      setActiveElement(null);
    }

    setOpen(false);
  }, [open, setOpen, activeElement, setActiveElement]);

  const handleOverlayEnter = useCallback((state) => {
    setPlacement(state.placement);
  }, [setPlacement]);

  return (
    <div ref={containerRef}>
      <IconButton
        disabled={disabled}
        icon={icon}
        onClick={handleToggle}
        iconComponent={iconComponent}
        title={title}
        active={open}
        size={18}
        inverted
      />

      <Overlay show={open} offset={[5, 5]} placement={placement} flip target={containerRef} popperConfig={{ strategy: 'fixed', onFirstUpdate: handleOverlayEnter }}>
        {({ props, placement }) => (
          <div {...props}>
            <div className={`dropdown-animation privacy-dropdown__dropdown ${placement}`}>
              <DropdownSelector
                items={options}
                value={value}
                onClose={handleClose}
                onChange={onChange}
              />
            </div>
          </div>
        )}
      </Overlay>
    </div>
  );
};

DropdownIconButton.propTypes = {
  value: PropTypes.string.isRequired,
  disabled: PropTypes.bool,
  icon: PropTypes.string,
  onChange: PropTypes.func.isRequired,
  iconComponent: PropTypes.func.isRequired,
  options: PropTypes.array.isRequired,
  title: PropTypes.string.isRequired,
};