diff --git a/polaris-react/src/components/Tooltip/Tooltip.stories.tsx b/polaris-react/src/components/Tooltip/Tooltip.stories.tsx index 173bf0a2fc3..99fd3bee3f1 100644 --- a/polaris-react/src/components/Tooltip/Tooltip.stories.tsx +++ b/polaris-react/src/components/Tooltip/Tooltip.stories.tsx @@ -1,5 +1,9 @@ import React, {useState} from 'react'; -import {QuestionCircleIcon} from '@shopify/polaris-icons'; +import { + CheckIcon, + ClipboardIcon, + QuestionCircleIcon, +} from '@shopify/polaris-icons'; import type {ComponentMeta} from '@storybook/react'; import { Button, @@ -13,6 +17,7 @@ import { BlockStack, Popover, Card, + Link, } from '@shopify/polaris'; import type {TooltipProps} from '@shopify/polaris'; @@ -566,3 +571,74 @@ export function OneCharacter() { ); } + +export function CopyToClipboard() { + const [copy, status] = useCopyToClipboard({ + defaultValue: 'hello@example.com', + }); + + return ( +
+ + + hello@example.com + +
+ ); +} + +type Status = 'inactive' | 'copied' | 'failed'; + +interface UseCopyToClipboardOptions { + defaultValue?: string; + timeout?: number; +} + +/** + * Copy text to the native clipboard using the `navigator.clipboard` API + * Adapted from https://www.benmvp.com/blog/copy-to-clipboard-react-custom-hook + */ +function useCopyToClipboard(options: UseCopyToClipboardOptions = {}) { + const {defaultValue = '', timeout = 1500} = options; + + const [status, setStatus] = React.useState('inactive'); + + const copy = React.useCallback( + (value?: string) => { + navigator.clipboard + .writeText(typeof value === 'string' ? value : defaultValue) + .then( + () => setStatus('copied'), + () => setStatus('failed'), + ) + .catch((error) => { + throw error; + }); + }, + [defaultValue], + ); + + React.useEffect(() => { + if (status === 'inactive') return; + + const timeoutId = setTimeout(() => setStatus('inactive'), timeout); + + return () => clearTimeout(timeoutId); + }, [status, timeout]); + + return [copy, status] as const; +} diff --git a/polaris-react/src/components/Tooltip/Tooltip.tsx b/polaris-react/src/components/Tooltip/Tooltip.tsx index 635e3977fed..937ba1bbedc 100644 --- a/polaris-react/src/components/Tooltip/Tooltip.tsx +++ b/polaris-react/src/components/Tooltip/Tooltip.tsx @@ -158,7 +158,13 @@ export function Tooltip({ const handleKeyUp = useCallback( (event: React.KeyboardEvent) => { - if (event.key !== 'Escape') return; + if ( + event.key !== 'Escape' && + event.key !== 'Enter' && + event.key !== ' ' + ) { + return; + } handleClose?.(); handleBlur(); persistOnClick && togglePersisting(); @@ -206,6 +212,11 @@ export function Tooltip({ handleFocus(); }} onBlur={() => { + if (hoverDelayTimeout.current) { + clearTimeout(hoverDelayTimeout.current); + hoverDelayTimeout.current = null; + } + handleClose(); handleBlur();