Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Common actions] Add Copy To Clipboard recipe #11645

Merged
merged 22 commits into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f50e41b
Initial Copy To Clipboard recipe
aaronccasanova Feb 22, 2024
d588b73
Remove pressed and isMouseHovered behavior
aaronccasanova Feb 29, 2024
068d0d8
Add controlled prop to open the Tooltip
aaronccasanova Mar 1, 2024
4681842
Merge branch 'main' of https://github.com/Shopify/polaris into copy-t…
aaronccasanova Mar 14, 2024
76905f8
Remove test inputs for establishing default values
aaronccasanova Mar 14, 2024
2e84379
Revert button style updates
aaronccasanova Mar 14, 2024
44609ab
Remove useHover and useMouseHover hooks
aaronccasanova Mar 14, 2024
7ac665f
Revert Tooltip instant prop update
aaronccasanova Mar 14, 2024
497a96f
Add changeset entry
aaronccasanova Mar 14, 2024
3b2f712
Remove extraneous imports
aaronccasanova Mar 15, 2024
c1e1060
Add a11y label
aaronccasanova Mar 15, 2024
df337f7
Merge branch 'main' of https://github.com/Shopify/polaris into copy-t…
aaronccasanova Mar 26, 2024
aef1555
Simplify copy to clipboard recipe
aaronccasanova Mar 26, 2024
d93bc1a
Update Tooltip to dismiss on enter/space key interactions
aaronccasanova Mar 26, 2024
09d0bd9
Clear hoverDelayTimeout onBlur to prevent flickering
aaronccasanova Mar 26, 2024
037ad1a
Update React imports in useCopyToClipboard hook
aaronccasanova Mar 26, 2024
2185140
Update changeset entry
aaronccasanova Mar 26, 2024
d1618f8
Add test cases for enter/space key interactions
aaronccasanova Mar 27, 2024
518832c
Scope enter/space key dismissal to non-activator wrapper keyup events
aaronccasanova Mar 27, 2024
fe089ee
Improve readability of onKeyUp conditionals
aaronccasanova Mar 27, 2024
0298d00
Separate test cases to cover events trigger by activator or child nodes
aaronccasanova Mar 27, 2024
450eca7
Update .changeset/flat-eagles-press.md
aaronccasanova Mar 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/flat-eagles-press.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/polaris': minor
---

Added `useCopyToClipboard` hook for building copy actions matching common actions guidelines
37 changes: 36 additions & 1 deletion polaris-react/src/components/Button/Button.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import React, {useCallback, useState} from 'react';
import React, {useCallback, useRef, useState} from 'react';
import type {ComponentMeta} from '@storybook/react';
import type {TextProps} from '@shopify/polaris';
import {
useCopyToClipboard,
useMouseHover,
Link,
Tooltip,
Button,
ButtonGroup,
Card,
Expand All @@ -18,6 +22,8 @@ import {
ChevronDownIcon,
EditIcon,
MagicIcon,
CheckIcon,
ClipboardIcon,
DeleteIcon,
} from '@shopify/polaris-icons';

Expand Down Expand Up @@ -832,3 +838,32 @@ export function LoadingState() {
</InlineStack>
);
}

export function CopyToClipboard() {
const [copy, status] = useCopyToClipboard({
defaultValue: '[email protected]',
});

return (
<div style={{maxWidth: 300, paddingTop: 100}}>
<Card>
<InlineStack align="space-between" gap="200">
<Link removeUnderline>[email protected]</Link>
<Tooltip
dismissOnMouseOut
hoverDelay={500}
preferredPosition="above"
open={status === 'copied' ? true : undefined}
content={status === 'copied' ? 'Copied' : 'Copy'}
>
<Button
variant="tertiary"
onClick={copy}
icon={status === 'copied' ? CheckIcon : ClipboardIcon}
/>
</Tooltip>
</InlineStack>
</Card>
</div>
);
}
1 change: 1 addition & 0 deletions polaris-react/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,7 @@ export {
export {useFrame, FrameContext} from './utilities/frame';
export {ScrollLockManagerContext as _SECRET_INTERNAL_SCROLL_LOCK_MANAGER_CONTEXT} from './utilities/scroll-lock-manager';
export {WithinContentContext as _SECRET_INTERNAL_WITHIN_CONTENT_CONTEXT} from './utilities/within-content-context';
export {useCopyToClipboard} from './utilities/use-copy-to-clipboard';
export {useEventListener} from './utilities/use-event-listener';
export {useTheme} from './utilities/use-theme';
export {useIndexResourceState} from './utilities/use-index-resource-state';
Expand Down
43 changes: 43 additions & 0 deletions polaris-react/src/utilities/use-copy-to-clipboard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react';

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
*/
export function useCopyToClipboard(options: UseCopyToClipboardOptions = {}) {
const {defaultValue = '', timeout = 1500} = options;

const [status, setStatus] = React.useState<Status>('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;
}
Loading