howler/app/soapbox/features/emoji/containers/emoji-picker-dropdown-container.tsx

80 lines
2.1 KiB
TypeScript

import { useFloating, shift } from '@floating-ui/react';
import clsx from 'clsx';
import React, { KeyboardEvent, useState } from 'react';
import { createPortal } from 'react-dom';
import { defineMessages, useIntl } from 'react-intl';
import { IconButton } from 'soapbox/components/ui';
import { useClickOutside } from 'soapbox/hooks';
import EmojiPickerDropdown, { IEmojiPickerDropdown } from '../components/emoji-picker-dropdown';
export const messages = defineMessages({
emoji: { id: 'emoji_button.label', defaultMessage: 'Insert emoji' },
});
const EmojiPickerDropdownContainer = (
props: Pick<IEmojiPickerDropdown, 'onPickEmoji' | 'condensed' | 'withCustom'>,
) => {
const intl = useIntl();
const title = intl.formatMessage(messages.emoji);
const [visible, setVisible] = useState(false);
const { x, y, strategy, refs, update } = useFloating<HTMLButtonElement>({
middleware: [shift()],
});
useClickOutside(refs, () => {
setVisible(false);
});
const handleToggle = (e: MouseEvent | KeyboardEvent) => {
e.stopPropagation();
setVisible(!visible);
};
return (
<div className='relative'>
<IconButton
className={clsx({
'text-gray-600 hover:text-gray-700 dark:hover:text-gray-500': true,
})}
ref={refs.setReference}
src={require('@tabler/icons/mood-happy.svg')}
title={title}
aria-label={title}
aria-expanded={visible}
role='button'
onClick={handleToggle as any}
onKeyDown={handleToggle as React.KeyboardEventHandler<HTMLButtonElement>}
tabIndex={0}
/>
{createPortal(
<div
className='z-[101]'
ref={refs.setFloating}
style={{
position: strategy,
top: y ?? 0,
left: x ?? 0,
width: 'max-content',
}}
>
<EmojiPickerDropdown
visible={visible}
setVisible={setVisible}
update={update}
{...props}
/>
</div>,
document.body,
)}
</div>
);
};
export default EmojiPickerDropdownContainer;