diff --git a/app/javascript/flavours/glitch/components/account_header/buttons.tsx b/app/javascript/flavours/glitch/components/account_header/buttons.tsx index c90048fa66..77003e71e3 100644 --- a/app/javascript/flavours/glitch/components/account_header/buttons.tsx +++ b/app/javascript/flavours/glitch/components/account_header/buttons.tsx @@ -11,7 +11,7 @@ import NotificationsIcon from '@/material-icons/400-24px/notifications.svg?react import NotificationsActiveIcon from '@/material-icons/400-24px/notifications_active-fill.svg?react'; import ShareIcon from '@/material-icons/400-24px/share.svg?react'; -import { CopyIconButton } from '../copy_icon_button'; +import { CopyIconButton } from '../copy_button'; import { FollowButton } from '../follow_button'; import { IconButton } from '../icon_button'; diff --git a/app/javascript/flavours/glitch/components/account_header/name.tsx b/app/javascript/flavours/glitch/components/account_header/name.tsx index 53dbc905ec..01453c2b92 100644 --- a/app/javascript/flavours/glitch/components/account_header/name.tsx +++ b/app/javascript/flavours/glitch/components/account_header/name.tsx @@ -7,17 +7,16 @@ import classNames from 'classnames'; import Overlay from 'react-overlays/esm/Overlay'; -import { showAlert } from '@/flavours/glitch/actions/alerts'; import { useAccount } from '@/flavours/glitch/hooks/useAccount'; import { useRelationship } from '@/flavours/glitch/hooks/useRelationship'; -import { useAppDispatch, useAppSelector } from '@/flavours/glitch/store'; +import { useAppSelector } from '@/flavours/glitch/store'; import AtIcon from '@/material-icons/400-24px/alternate_email.svg?react'; import ContentCopyIcon from '@/material-icons/400-24px/content_copy.svg?react'; import HelpIcon from '@/material-icons/400-24px/help.svg?react'; import DomainIcon from '@/material-icons/400-24px/language.svg?react'; import { FollowsYouBadge } from '../badge'; -import { Button } from '../button'; +import { CopyButton } from '../copy_button'; import { DisplayName } from '../display_name'; import { Icon } from '../icon'; @@ -90,17 +89,6 @@ const AccountNameHelp: FC<{ const handle = `@${username}@${domain}`; - const dispatch = useAppDispatch(); - const [copied, setCopied] = useState(false); - const handleCopy = useCallback(() => { - void navigator.clipboard.writeText(handle); - setCopied(true); - dispatch(showAlert({ message: messages.copied })); - setTimeout(() => { - setCopied(false); - }, 700); - }, [handle, dispatch]); - return ( <> + )} diff --git a/app/javascript/flavours/glitch/components/copy_button.tsx b/app/javascript/flavours/glitch/components/copy_button.tsx new file mode 100644 index 0000000000..cb1ad29b80 --- /dev/null +++ b/app/javascript/flavours/glitch/components/copy_button.tsx @@ -0,0 +1,75 @@ +import { useState, useCallback } from 'react'; + +import { defineMessages } from 'react-intl'; + +import classNames from 'classnames'; + +import ContentCopyIcon from '@/material-icons/400-24px/content_copy.svg?react'; +import { showAlert } from 'flavours/glitch/actions/alerts'; +import { IconButton } from 'flavours/glitch/components/icon_button'; +import { useAppDispatch } from 'flavours/glitch/store'; + +import { Button } from './button'; + +const messages = defineMessages({ + copied: { + id: 'copy_icon_button.copied', + defaultMessage: 'Copied to clipboard', + }, +}); + +export function useCopyToClipboard({ text }: { text: string }) { + const [wasCopied, setWasCopied] = useState(false); + const dispatch = useAppDispatch(); + + const copyText = useCallback(() => { + void navigator.clipboard.writeText(text); + setWasCopied(true); + dispatch(showAlert({ message: messages.copied })); + setTimeout(() => { + setWasCopied(false); + }, 700); + }, [setWasCopied, text, dispatch]); + + return { copyText, wasCopied }; +} + +export const CopyButton: React.FC< + Omit< + React.ComponentPropsWithoutRef, + 'onClick' | 'text' | 'children' + > & { + value: string; + children: React.ReactNode | ((wasCopied: boolean) => React.ReactNode); + } +> = ({ value, children, ...otherProps }) => { + const { copyText, wasCopied } = useCopyToClipboard({ text: value }); + + const label = typeof children === 'function' ? children(wasCopied) : children; + + return ( + + ); +}; + +export const CopyIconButton: React.FC<{ + title: string; + value: string; + className?: string; + 'aria-describedby'?: string; +}> = ({ title, value, className, 'aria-describedby': ariaDescribedBy }) => { + const { copyText, wasCopied } = useCopyToClipboard({ text: value }); + + return ( + + ); +}; diff --git a/app/javascript/flavours/glitch/components/copy_icon_button.tsx b/app/javascript/flavours/glitch/components/copy_icon_button.tsx deleted file mode 100644 index 6f1dffbdf6..0000000000 --- a/app/javascript/flavours/glitch/components/copy_icon_button.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { useState, useCallback } from 'react'; - -import { defineMessages } from 'react-intl'; - -import classNames from 'classnames'; - -import ContentCopyIcon from '@/material-icons/400-24px/content_copy.svg?react'; -import { showAlert } from 'flavours/glitch/actions/alerts'; -import { IconButton } from 'flavours/glitch/components/icon_button'; -import { useAppDispatch } from 'flavours/glitch/store'; - -const messages = defineMessages({ - copied: { - id: 'copy_icon_button.copied', - defaultMessage: 'Copied to clipboard', - }, -}); - -export const CopyIconButton: React.FC<{ - title: string; - value: string; - className?: string; - 'aria-describedby'?: string; -}> = ({ title, value, className, 'aria-describedby': ariaDescribedBy }) => { - const [copied, setCopied] = useState(false); - const dispatch = useAppDispatch(); - - const handleClick = useCallback(() => { - void navigator.clipboard.writeText(value); - setCopied(true); - dispatch(showAlert({ message: messages.copied })); - setTimeout(() => { - setCopied(false); - }, 700); - }, [setCopied, value, dispatch]); - - return ( - - ); -}; diff --git a/app/javascript/flavours/glitch/components/form_fields/copy_link_field.tsx b/app/javascript/flavours/glitch/components/form_fields/copy_link_field.tsx index 6404e5ed56..aa2b63392d 100644 --- a/app/javascript/flavours/glitch/components/form_fields/copy_link_field.tsx +++ b/app/javascript/flavours/glitch/components/form_fields/copy_link_field.tsx @@ -4,7 +4,7 @@ import { useIntl } from 'react-intl'; import classNames from 'classnames'; -import { CopyIconButton } from 'flavours/glitch/components/copy_icon_button'; +import { CopyIconButton } from '@/flavours/glitch/components/copy_button'; import classes from './copy_link_field.module.scss'; import { FormFieldWrapper } from './form_field_wrapper';