Skip to content

Commit

Permalink
[WiP] Refactor composer dropdowns
Browse files Browse the repository at this point in the history
  • Loading branch information
ClearlyClaire committed Feb 23, 2024
1 parent b2bcd3d commit 78379f8
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 118 deletions.
Original file line number Diff line number Diff line change
@@ -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' },
Expand All @@ -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;
}
Expand All @@ -85,31 +54,13 @@ export const ContentTypeButton = () => {
}[contentType];

return (
<div ref={containerRef}>
<IconButton
icon={icon}
onClick={handleToggle}
iconComponent={iconComponent}
title={intl.formatMessage(messages.change_content_type)}
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}`}>
<DropdownMenu
items={options}
value={contentType}
onClose={handleClose}
onChange={handleChange}
/>
</div>
</div>
)}
</Overlay>
</div>
<DropdownIconButton
icon={icon}
iconComponent={iconComponent}
onChange={handleChange}
options={options}
title={intl.formatMessage(messages.change_content_type)}
value={contentType}
/>
);
};
Original file line number Diff line number Diff line change
@@ -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 (
<div ref={containerRef}>
<IconButton
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}`}>
<DropdownMenu
items={options}
value={value}
onClose={handleClose}
onChange={onChange}
/>
</div>
</div>
)}
</Overlay>
</div>
);
};

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,
};
Original file line number Diff line number Diff line change
@@ -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' },
Expand All @@ -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: 'local-only', text: intl.formatMessage(messages.local_only_label), meta: intl.formatMessage(messages.local_only_meta) },
{ icon: 'link-slash', iconComponent: ShareOffIcon, value: 'federated', text: intl.formatMessage(messages.federated_label), meta: intl.formatMessage(messages.federated_meta) },
];

return (
<div ref={containerRef}>
<IconButton
icon={do_not_federate ? 'link-slash' : 'link'}
onClick={handleToggle}
iconComponent={do_not_federate ? ShareOffIcon : ShareIcon}
title={intl.formatMessage(messages.change_federation_settings)}
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}`}>
<DropdownMenu
items={options}
value={do_not_federate ? 'local-only' : 'federated'}
onClose={handleClose}
onChange={handleChange}
/>
</div>
</div>
)}
</Overlay>
</div>
<DropdownIconButton
icon={do_not_federate ? 'link-slash' : 'link'}
iconComponent={do_not_federate ? ShareOffIcon : ShareIcon}
onChange={handleChange}
options={options}
title={intl.formatMessage(messages.change_federation_settings)}
value={do_not_federate ? 'local-only' : 'federated'}
/>
);
};

0 comments on commit 78379f8

Please sign in to comment.