diff --git a/app/javascript/flavours/glitch/features/compose/components/content_type_button.jsx b/app/javascript/flavours/glitch/features/compose/components/content_type_button.jsx index 9ac382091e..c1d6860bde 100644 --- a/app/javascript/flavours/glitch/features/compose/components/content_type_button.jsx +++ b/app/javascript/flavours/glitch/features/compose/components/content_type_button.jsx @@ -1,17 +1,14 @@ -import { useCallback, useState, useRef } from 'react'; +import { useCallback } from 'react'; import { useIntl, defineMessages } from 'react-intl'; -import Overlay from 'react-overlays/Overlay'; - import CodeIcon from '@/material-icons/400-24px/code.svg?react'; import DescriptionIcon from '@/material-icons/400-24px/description.svg?react'; import MarkdownIcon from '@/material-icons/400-24px/markdown.svg?react'; import { changeComposeContentType } from 'flavours/glitch/actions/compose'; -import { IconButton } from 'flavours/glitch/components/icon_button'; import { useAppSelector, useAppDispatch } from 'flavours/glitch/store'; -import DropdownMenu from './dropdown_menu'; +import { DropdownIconButton } from './dropdown_icon_button'; const messages = defineMessages({ change_content_type: { id: 'compose.content-type.change', defaultMessage: 'Change advanced formatting options' }, @@ -30,38 +27,10 @@ export const ContentTypeButton = () => { const contentType = useAppSelector((state) => state.getIn(['compose', 'content_type'])); const dispatch = useAppDispatch(); - 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 handleChange = useCallback((value) => { dispatch(changeComposeContentType(value)); }, [dispatch]); - const handleOverlayEnter = useCallback((state) => { - setPlacement(state.placement); - }, [setPlacement]); - if (!showButton) { return null; } @@ -85,31 +54,13 @@ export const ContentTypeButton = () => { }[contentType]; return ( -
- - - - {({ props, placement }) => ( -
-
- -
-
- )} -
-
+ ); }; diff --git a/app/javascript/flavours/glitch/features/compose/components/dropdown_icon_button.jsx b/app/javascript/flavours/glitch/features/compose/components/dropdown_icon_button.jsx new file mode 100644 index 0000000000..58a9e633fb --- /dev/null +++ b/app/javascript/flavours/glitch/features/compose/components/dropdown_icon_button.jsx @@ -0,0 +1,76 @@ +import PropTypes from 'prop-types'; +import { useCallback, useState, useRef } from 'react'; + +import Overlay from 'react-overlays/Overlay'; + +import { IconButton } from 'flavours/glitch/components/icon_button'; + +import DropdownMenu from './dropdown_menu'; + +export const DropdownIconButton = ({ value, 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 ( +
+ + + + {({ props, placement }) => ( +
+
+ +
+
+ )} +
+
+ ); +}; + +DropdownIconButton.propTypes = { + value: PropTypes.string.isRequired, + icon: PropTypes.string, + onChange: PropTypes.func.isRequired, + iconComponent: PropTypes.func.isRequired, + options: PropTypes.array.isRequired, + title: PropTypes.string.isRequired, +}; diff --git a/app/javascript/flavours/glitch/features/compose/components/federation_button.jsx b/app/javascript/flavours/glitch/features/compose/components/federation_button.jsx index a7ef0aa028..a1bb53f692 100644 --- a/app/javascript/flavours/glitch/features/compose/components/federation_button.jsx +++ b/app/javascript/flavours/glitch/features/compose/components/federation_button.jsx @@ -1,16 +1,13 @@ -import { useCallback, useState, useRef } from 'react'; +import { useCallback } from 'react'; import { useIntl, defineMessages } from 'react-intl'; -import Overlay from 'react-overlays/Overlay'; - import ShareIcon from '@/material-icons/400-24px/share.svg?react'; import ShareOffIcon from '@/material-icons/400-24px/share_off.svg?react'; import { changeComposeAdvancedOption } from 'flavours/glitch/actions/compose'; -import { IconButton } from 'flavours/glitch/components/icon_button'; import { useAppSelector, useAppDispatch } from 'flavours/glitch/store'; -import DropdownMenu from './dropdown_menu'; +import { DropdownIconButton } from './dropdown_icon_button'; const messages = defineMessages({ change_federation_settings: { id: 'compose.change_federation', defaultMessage: 'Change federation settings' }, @@ -26,69 +23,23 @@ export const FederationButton = () => { const do_not_federate = useAppSelector((state) => state.getIn(['compose', 'advanced_options', 'do_not_federate'])); const dispatch = useAppDispatch(); - 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 handleChange = useCallback((value) => { dispatch(changeComposeAdvancedOption('do_not_federate', value === 'local-only')); }, [dispatch]); - const handleOverlayEnter = useCallback((state) => { - setPlacement(state.placement); - }, [setPlacement]); - const options = [ { icon: 'link', iconComponent: ShareIcon, value: 'federated', text: intl.formatMessage(messages.federated_label), meta: intl.formatMessage(messages.federated_meta) }, { icon: 'link-slash', iconComponent: ShareOffIcon, value: 'local-only', text: intl.formatMessage(messages.local_only_label), meta: intl.formatMessage(messages.local_only_meta) }, ]; return ( -
- - - - {({ props, placement }) => ( -
-
- -
-
- )} -
-
+ ); };