From b167bc8452d90e2161c1fb94b72fb8c13f8b1166 Mon Sep 17 00:00:00 2001 From: Jason Date: Wed, 31 Jul 2024 18:18:43 -0500 Subject: [PATCH 01/12] feat(react): add CopyButton component --- docs/pages/components/CopyButton.mdx | 28 +++++ .../react/src/components/CopyButton/index.tsx | 109 ++++++++++++++++++ packages/react/src/index.ts | 1 + 3 files changed, 138 insertions(+) create mode 100644 docs/pages/components/CopyButton.mdx create mode 100644 packages/react/src/components/CopyButton/index.tsx diff --git a/docs/pages/components/CopyButton.mdx b/docs/pages/components/CopyButton.mdx new file mode 100644 index 000000000..e9a312e6a --- /dev/null +++ b/docs/pages/components/CopyButton.mdx @@ -0,0 +1,28 @@ +--- +title: Button +description: An interactive component that copies the provided value to the user's clipboard when clicked. +source: https://github.com/dequelabs/cauldron/tree/develop/packages/react/src/components/CopyButton/index.tsx +--- + +import { CopyButton } from '@deque/cauldron-react' + +```js +import { CopyButton } from '@deque/cauldron-react' +``` + +## Examples + +### Default + +```jsx example + +``` + +## Props + + + +## Related Components + +- [Button](./Button) \ No newline at end of file diff --git a/packages/react/src/components/CopyButton/index.tsx b/packages/react/src/components/CopyButton/index.tsx new file mode 100644 index 000000000..c0738e75e --- /dev/null +++ b/packages/react/src/components/CopyButton/index.tsx @@ -0,0 +1,109 @@ +import React, { forwardRef, useState, useCallback, useEffect } from 'react'; +import { ContentNode } from '../../types'; +import Button from '../Button'; +import Offscreen from '../Offscreen'; +import Tooltip from '../Tooltip'; +import Icon from '../Icon'; +import useSharedRef from '../../utils/useSharedRef'; + +type ButtonProps = React.ComponentProps; + +export interface CopyButtonProps + extends Omit { + value: string; + variant?: Extract< + ButtonProps['variant'], + 'primary' | 'secondary' | 'tertiary' + >; + children?: ContentNode; + notificationLabel?: ContentNode; + hideVisibleLabel?: boolean; + tooltipPlacement?: React.ComponentProps['placement']; + onCopy?: (text: string) => void; +} + +function copyTextToClipboard(text: string) { + const element = document.createElement('textarea'); + element.value = text; + element.setAttribute('aria-hidden', 'true'); + document.body.appendChild(element); + + element.select(); + + let copied; + try { + copied = document.execCommand('copy'); + } catch (ex) { + copied = false; + } + + element.remove(); + + return copied; +} + +const NOTIFICATION_TIMEOUT_MS = 2000; + +const CopyButton = forwardRef( + ( + { + value, + variant = 'tertiary', + children = 'Copy', + notificationLabel = 'Copied', + hideVisibleLabel = false, + tooltipPlacement = 'auto', + onCopy, + ...props + }: CopyButtonProps, + ref + ) => { + const [copied, setCopied] = useState(false); + const copyButtonRef = useSharedRef(ref); + const handleClick = useCallback(() => { + copyTextToClipboard(value); + setCopied(true); + if (typeof onCopy === 'function') { + onCopy(value); + } + }, [value, onCopy]); + + useEffect(() => { + const timeoutId = setTimeout(() => { + setCopied(false); + }, NOTIFICATION_TIMEOUT_MS); + + return () => { + clearTimeout(timeoutId); + }; + }, [copied]); + + return ( + <> + + + {notificationLabel} + + + {copied ? notificationLabel : null} + + + ); + } +); + +CopyButton.displayName = 'CopyButton'; + +export default CopyButton; diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index a4892d9cf..98c5011d3 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -127,6 +127,7 @@ export { export { default as Popover } from './components/Popover'; export { default as Timeline, TimelineItem } from './components/Timeline'; export { default as TextEllipsis } from './components/TextEllipsis'; +export { default as CopyButton } from './components/CopyButton'; /** * Helpers / Utils From e3fe652b50d4630d1db99b2a35da5b1a9c48d891 Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 1 Aug 2024 10:10:29 -0500 Subject: [PATCH 02/12] more copy things --- docs/pages/components/CopyButton.mdx | 2 +- .../react/src/components/CopyButton/index.tsx | 25 ++--------- .../react/src/utils/copyTextToClipboard.ts | 43 +++++++++++++++++++ 3 files changed, 47 insertions(+), 23 deletions(-) create mode 100644 packages/react/src/utils/copyTextToClipboard.ts diff --git a/docs/pages/components/CopyButton.mdx b/docs/pages/components/CopyButton.mdx index e9a312e6a..2ae8e6e56 100644 --- a/docs/pages/components/CopyButton.mdx +++ b/docs/pages/components/CopyButton.mdx @@ -15,7 +15,7 @@ import { CopyButton } from '@deque/cauldron-react' ### Default ```jsx example - + ``` ## Props diff --git a/packages/react/src/components/CopyButton/index.tsx b/packages/react/src/components/CopyButton/index.tsx index c0738e75e..aed083c5c 100644 --- a/packages/react/src/components/CopyButton/index.tsx +++ b/packages/react/src/components/CopyButton/index.tsx @@ -5,6 +5,7 @@ import Offscreen from '../Offscreen'; import Tooltip from '../Tooltip'; import Icon from '../Icon'; import useSharedRef from '../../utils/useSharedRef'; +import copyTextToClipboard from '../../utils/copyTextToClipboard'; type ButtonProps = React.ComponentProps; @@ -22,26 +23,6 @@ export interface CopyButtonProps onCopy?: (text: string) => void; } -function copyTextToClipboard(text: string) { - const element = document.createElement('textarea'); - element.value = text; - element.setAttribute('aria-hidden', 'true'); - document.body.appendChild(element); - - element.select(); - - let copied; - try { - copied = document.execCommand('copy'); - } catch (ex) { - copied = false; - } - - element.remove(); - - return copied; -} - const NOTIFICATION_TIMEOUT_MS = 2000; const CopyButton = forwardRef( @@ -96,8 +77,8 @@ const CopyButton = forwardRef( > {notificationLabel} - - {copied ? notificationLabel : null} + + {copied ? notificationLabel : ' '} ); diff --git a/packages/react/src/utils/copyTextToClipboard.ts b/packages/react/src/utils/copyTextToClipboard.ts new file mode 100644 index 000000000..26726ad05 --- /dev/null +++ b/packages/react/src/utils/copyTextToClipboard.ts @@ -0,0 +1,43 @@ +export default async function copyTextToClipboard( + text: string +): Promise { + let copied = false; + + if ('clipboard' in navigator) { + try { + await navigator.clipboard.writeText(text); + copied = true; + } catch (ex) { + // fallback to execCommand + } + } else { + const element = document.createElement('span'); + element.textContent = text; + element.setAttribute('aria-hidden', 'true'); + element.style.position = 'absolute'; + element.style.height = '1px'; + element.style.width = '1px'; + element.style.overflow = 'hidden'; + element.style.clip = 'rect(1px, 1px, 1px, 1px)'; + element.style.marginTop = '-1px'; + element.style.webkitUserSelect = 'text'; + element.style.userSelect = 'text'; + document.body.appendChild(element); + + const range = document.createRange(); + const selection = document.getSelection(); + range.selectNodeContents(element); + selection?.addRange(range); + + try { + document.execCommand('copy'); + copied = true; + } catch (ex) { + // no fallback + } + + element.remove(); + } + + return copied; +} From a1abf2d826d9702c15e0cf2ed8e156608741f8bb Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 1 Aug 2024 13:32:14 -0500 Subject: [PATCH 03/12] forward progress --- docs/components/CopyToClipboardButton.tsx | 114 ------------------ docs/components/Example.tsx | 33 ++++- .../react/src/components/CopyButton/index.tsx | 2 +- .../react/src/components/Icon/icons/copy.svg | 2 +- 4 files changed, 29 insertions(+), 122 deletions(-) delete mode 100644 docs/components/CopyToClipboardButton.tsx diff --git a/docs/components/CopyToClipboardButton.tsx b/docs/components/CopyToClipboardButton.tsx deleted file mode 100644 index 2dc43c338..000000000 --- a/docs/components/CopyToClipboardButton.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import React, { useRef, useEffect, useState, useMemo } from 'react'; -import { IconButton, Toast } from '@deque/cauldron-react'; - -interface CopyToClipboardButtonProps - extends React.HTMLAttributes { - label?: string; - value: string; -} - -function copyTextToClipboard(text: string) { - const element = document.createElement('textarea'); - element.value = text; - element.setAttribute('aria-hidden', 'true'); - document.body.appendChild(element); - - element.select(); - - let copied; - try { - copied = document.execCommand('copy'); - } catch (ex) { - copied = false; - } - - element.remove(); - - return copied; -} - -// Note: eventually we want to natively handle multiple toasts, but for now we will limit the copy toast notification -// to only display a single notification to prevent weird focus issues -const notificationsMap = new Map>(); -function CopyNotificationToast( - props: React.ComponentProps -): JSX.Element { - const { show, onDismiss } = props; - const id = useMemo(() => Symbol('toast'), []); - const [deferredShow, setDeferredShow] = useState(false); - - useEffect(() => { - if (show) { - Array.from(notificationsMap.values()).forEach(({ onDismiss }) => { - // force any open toasts to dismiss themselves - onDismiss(); - }); - notificationsMap.set(id, props); - // toast sets show via set timeout, so this matches the behavior to avoid a race condition - setTimeout(() => setDeferredShow(show)); - } else { - notificationsMap.delete(id); - setDeferredShow(false); - } - - return () => { - notificationsMap.delete(id); - }; - }, [show]); - - return ; -} - -export default function CopyToClipboardButton({ - value, - label = 'copy to clipboard', - ...props -}: CopyToClipboardButtonProps) { - const ref = useRef(); - const toastRef = useRef(); - const [accessibleName, setAccessibleName] = useState(label); - const [showToast, setShowToast] = useState(false); - const handleClick = () => { - copyTextToClipboard(value); - setShowToast(true); - toastRef.current?.focus(); - }; - - const handleDismiss = () => { - setShowToast(false); - ref.current?.focus(); - }; - - useEffect(() => { - // We don't know what context this button will be included in, so providing - // a minimal accessible name of "example, x of y" - const elements = Array.from( - document.querySelectorAll('[data-copy-example]') - ); - const index = elements.findIndex((element) => element === ref.current); - if (index !== -1 && elements.length) { - setAccessibleName(`${label}, ${index + 1} of ${elements.length}`); - } - }, [value]); - - return ( - <> - - - Example copied to clipboard! - - - ); -} diff --git a/docs/components/Example.tsx b/docs/components/Example.tsx index ebc8fbd29..f7d2aaddd 100644 --- a/docs/components/Example.tsx +++ b/docs/components/Example.tsx @@ -1,6 +1,5 @@ -import React from 'react'; -import { Code } from '@deque/cauldron-react'; -import CopyToClipboardButton from './CopyToClipboardButton'; +import React, { useEffect, useState, useRef } from 'react'; +import { Code, CopyButton } from '@deque/cauldron-react'; import './example.css'; interface ExampleProps extends React.HTMLAttributes { @@ -8,15 +7,37 @@ interface ExampleProps extends React.HTMLAttributes { } export default function Example({ children, raw, ...props }: ExampleProps) { + const label = 'copy code example to clipboard'; + const [accessibleName, setAccessibleName] = useState(label); + const ref = useRef(); + + useEffect(() => { + // We don't know what context this button will be included in, so providing + // a minimal accessible name of "example, x of y" + const elements = Array.from( + document.querySelectorAll('[data-copy-example]') + ); + const index = elements.findIndex((element) => element === ref.current); + if (index !== -1 && elements.length) { + setAccessibleName(`${label}, ${index + 1} of ${elements.length}`); + } + console.log(index, ref.current); + }, [raw]); + return (
{children}
- + hideVisibleLabel + thin + > + {accessibleName} +
); diff --git a/packages/react/src/components/CopyButton/index.tsx b/packages/react/src/components/CopyButton/index.tsx index aed083c5c..c1d2e1c04 100644 --- a/packages/react/src/components/CopyButton/index.tsx +++ b/packages/react/src/components/CopyButton/index.tsx @@ -75,7 +75,7 @@ const CopyButton = forwardRef( placement={tooltipPlacement} association="none" > - {notificationLabel} + {hideVisibleLabel && !copied ? children : notificationLabel} {copied ? notificationLabel : ' '} diff --git a/packages/react/src/components/Icon/icons/copy.svg b/packages/react/src/components/Icon/icons/copy.svg index 28892bf53..dc8a95057 100644 --- a/packages/react/src/components/Icon/icons/copy.svg +++ b/packages/react/src/components/Icon/icons/copy.svg @@ -1 +1 @@ - + \ No newline at end of file From 9a305ce6dc37bfc38396aae1c96d82e9b0495693 Mon Sep 17 00:00:00 2001 From: Jason Date: Thu, 1 Aug 2024 16:13:24 -0500 Subject: [PATCH 04/12] screenshots and stuff --- docs/components/Example.tsx | 1 + docs/components/example.css | 1 + docs/pages/components/CopyButton.mdx | 71 +++++++++ e2e/screenshots/copybutton-condensed-.png | Bin 0 -> 2442 bytes .../copybutton-condensed-thin-.png | Bin 0 -> 1781 bytes e2e/screenshots/copybutton-thin-.png | Bin 0 -> 5839 bytes e2e/screenshots/copybutton.png | Bin 0 -> 7164 bytes .../dark--copybutton-condensed-.png | Bin 0 -> 2704 bytes .../dark--copybutton-condensed-thin-.png | Bin 0 -> 2019 bytes e2e/screenshots/dark--copybutton-thin-.png | Bin 0 -> 6118 bytes e2e/screenshots/dark--copybutton.png | Bin 0 -> 7517 bytes .../react/src/components/CopyButton/index.tsx | 22 ++- .../components/CopyButton/screenshots.e2e.tsx | 150 ++++++++++++++++++ packages/styles/button.css | 9 ++ 14 files changed, 251 insertions(+), 3 deletions(-) create mode 100644 e2e/screenshots/copybutton-condensed-.png create mode 100644 e2e/screenshots/copybutton-condensed-thin-.png create mode 100644 e2e/screenshots/copybutton-thin-.png create mode 100644 e2e/screenshots/copybutton.png create mode 100644 e2e/screenshots/dark--copybutton-condensed-.png create mode 100644 e2e/screenshots/dark--copybutton-condensed-thin-.png create mode 100644 e2e/screenshots/dark--copybutton-thin-.png create mode 100644 e2e/screenshots/dark--copybutton.png create mode 100644 packages/react/src/components/CopyButton/screenshots.e2e.tsx diff --git a/docs/components/Example.tsx b/docs/components/Example.tsx index f7d2aaddd..09dec099b 100644 --- a/docs/components/Example.tsx +++ b/docs/components/Example.tsx @@ -33,6 +33,7 @@ export default function Example({ children, raw, ...props }: ExampleProps) { ref={ref} data-copy-example value={raw} + notificationLabel="copied" hideVisibleLabel thin > diff --git a/docs/components/example.css b/docs/components/example.css index df6f7cb1c..db15b7310 100644 --- a/docs/components/example.css +++ b/docs/components/example.css @@ -41,6 +41,7 @@ body.cauldron--theme-dark { display: flex; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; + align-items: flex-start; } .Component__example__code pre.Code { diff --git a/docs/pages/components/CopyButton.mdx b/docs/pages/components/CopyButton.mdx index 2ae8e6e56..cb6e2b45d 100644 --- a/docs/pages/components/CopyButton.mdx +++ b/docs/pages/components/CopyButton.mdx @@ -18,9 +18,80 @@ import { CopyButton } from '@deque/cauldron-react' ``` +### Label + +Both the accessible name and the notification label can be customized. + +```jsx example + + Copy CSS Selector + +``` + +### Hide Visible Label + +When space is limited, the visible label of the button can be optionally hidden, with the label show on hover or focus with a tooltip. + +```jsx example + +``` + +### Variants + +`CopyButton` is an extension of `Button` and limited variants are available to be used: + +```jsx example + + +``` + ## Props +Unless otherwise noted, prop types are inherited from [Button](./Button). + ## Related Components diff --git a/e2e/screenshots/copybutton-condensed-.png b/e2e/screenshots/copybutton-condensed-.png new file mode 100644 index 0000000000000000000000000000000000000000..35cd39f4925eac7020c0853282ef03f18e614636 GIT binary patch literal 2442 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 K3f1yv!T$#z^H@Xx literal 0 HcmV?d00001 diff --git a/e2e/screenshots/copybutton.png b/e2e/screenshots/copybutton.png new file mode 100644 index 0000000000000000000000000000000000000000..bdefbce41a7538e276438a74a70a4c29e5eb9405 GIT binary patch literal 7164 zcmZ8`byQT}AMFLnp%G~TNu`nQ?nXKUkp`)uJEWvUBm{<`M!KY18bm<4>pMtyH}Cp; zf4sHcnYCulx^vf!bN1)6_x^lhv@{g)Ae0aQ0PvKR~L2-jCczX$^HEw!Ni#jF0wvKd_xEoJRjIA3D(el8yVwjK?7G~`z|#i*jN z={di@x*pgws=45G%r@#Ua+Dmc;i;Pj2(i#mL$?rGtsel?P$@b>8nkWde-l4mrOki; zjb%!UM1jYnmvP61!BeHqY+PNaLZs*daEWJ!3)*^}8&IYE7RXmHpO8@IaK9qKz~FYF z3b!LDfMTI_VH3~teZ0x4zIHSl`at!L?(<|5>Jwf36pFZ8$*;@UMj}4w&s6SIsve0|#eOZ!;<4KAxJ+H**4htvZ zXejSvjeS&iTs1{ek1iP5loHvr9(e{|YW}+&_wiG?Z?rG2J1(A)&ZfzYO)E*__55_KY&Mbg6LW}Ii{v*D=Ptf;NLYHG+6 zY?w=E*6dKgw+^n&YqBqI`bzbF-OR7Blg2i1oS1ESh?vv)Id#cV_jmkWnbF@=YFVF~X@#?*-fgbNi$bXWhrXw1zaW!!2K69eNlIj)PzdQ1ASO_M1;K+Z4X zyqoI1Aizy=t{*!`^?fP$GoyW7x;jwR6wog%DxFcn?uGM8Wt|Sb2f>GvFhTZ7$91i% zpKb}Jj)tB@EmY(IxFNmn;5GFya@G zLe0{YmY91+EfI72Dg;eG9&dK+J7P4{V}zy3kljvZ8-k1RFwbo1ALD@_*mJW zC7$Rl%Kwk1V<+lg`wI=r{@&2P=Z*rI!}7dIN@qQ16j0t8F$XoSjf?$-!}i;Q^W7QI z=bPITg|;>}7diIPm?Z1T&Ycc*e1iP->2VdZ(Z#wYQZGqW3&ic_?>}OCR#aCXUuX6D z!73(F!I!u!6#XFJc)^P!W~=FfsIKN=VNsl^b9*?O(EK2jW}(sTy}UenK#_jw>B&j!2NE!Bi6zV~*+d-=%1t^R9c*gmLIZEVBh80XCFdIvT~4O%rLx^KUhm6e$^I0rslZ+3QeCWH$M3rjxUo%YiPQxg%b z>Fu^A_FB%>+9%7d(^2CW=3h9@RI~-%-~87bOY6T^?Jue>WsLis$z*zxCpGs6*Y(@9hcJ6k>_2H1QQP@xnMw z>zX;{36sV$2?{p+_%VKMp`UtZLg+q@Q0{P(kD53Kh4zj5JoEe0;YyF#MK> zTy4wV*??rFM_k0f%&g7wnhjskyK=iyEOa(eMx zbm^VNs5W?Zz_t6Pn}W!uwg_?4;-V>M+QNbANS3hd7sjaW>+M3g)$4C?^9I{e?`7Xj zm-NL6pGlUQni|+8xgU>B&GpE>NY|_8@pusyQdN5o5kRVNijRNUzS+Of+%OoBQtEK^ zhIRG3C62VU*|*i?`$va_gbWNsRlF^447?SXY zo1{IQ4azN>bP^yS=XQPQvdzzr((o6>;rc>S++B_x7gXl{S@Va$+>Xz-C!TB0 z?O$|tbtSWCmQ3xm2i|JHCB%7nc-Yu*md(8v>OY{Pql4cjRTiPf<(w~H&bInOm6Zoe z^hzTMXz_uogO)>yo2`77Y#&q`J-CSH&e2+Te0+RRP>`m?wUxX34->_rQlDOyg>wa= zuIuY-#Y7rC))X)C>*;NjpbwD}7LTz|xVN{*|btxbfBw^aRJ(a7lA zoD&VV#m}w?oc#QJ|Eqlf$e^N%J}4kuq!MeFD%H+ZQ^=Pd-Ef6@lVNu;r}0za`F&xe z!2NEx({EY5_E4bnV#1yuP5RHaN0Q;MzsIm!UDkDx@(emG{3w=lf*hTNCYB`qQf;

MGTZMpQt-l?ji9G>2Ij?;l_p>dwxi~*;)MDRma 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 hzbj(NxokY5B<`AK4;pPxe$x3vaUV) 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 B#=8Ij literal 0 HcmV?d00001 diff --git a/e2e/screenshots/dark--copybutton-thin-.png b/e2e/screenshots/dark--copybutton-thin-.png new file mode 100644 index 0000000000000000000000000000000000000000..ca90836d898b1618d3e3a3a83d8de26d19ee5e0e GIT binary patch literal 6118 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 literal 0 HcmV?d00001 diff --git a/e2e/screenshots/dark--copybutton.png b/e2e/screenshots/dark--copybutton.png new file mode 100644 index 0000000000000000000000000000000000000000..642b08094c13b94fc3bfedc88d7146ee104ae477 GIT binary patch literal 7517 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 z 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 ODWIaDDPJvX75+b453{WR literal 0 HcmV?d00001 diff --git a/packages/react/src/components/CopyButton/index.tsx b/packages/react/src/components/CopyButton/index.tsx index c1d2e1c04..f944944bc 100644 --- a/packages/react/src/components/CopyButton/index.tsx +++ b/packages/react/src/components/CopyButton/index.tsx @@ -1,4 +1,6 @@ import React, { forwardRef, useState, useCallback, useEffect } from 'react'; +import { createPortal } from 'react-dom'; +import classnames from 'classnames'; import { ContentNode } from '../../types'; import Button from '../Button'; import Offscreen from '../Offscreen'; @@ -59,9 +61,17 @@ const CopyButton = forwardRef( }; }, [copied]); + // The visibility of the tooltip only needs to be controlled + // when we are visually displaying the notification label + const showTooltip = + hideVisibleLabel && !copied ? undefined : copied ? true : false; + return ( <>