Skip to content

Commit

Permalink
feat(ui): CopyToClipboard
Browse files Browse the repository at this point in the history
  • Loading branch information
vio committed Sep 25, 2024
1 parent 5fe6e2b commit ece5364
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 0 deletions.
58 changes: 58 additions & 0 deletions packages/ui/src/ui/copy-to-clipboard/copy-to-clipboard.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
.root {
padding: var(--space-xxxsmall);
}

.wrapper {
display: flex;
gap: var(--space-xxsmall);
align-items: center;
}

.content {
flex: 1 1 auto;
white-space: nowrap;
line-height: 1.1;
}

.icon {
flex: 0 0 auto;
position: relative;
width: var(--space-small);
height: var(--space-small);
}

.iconCopy,
.iconDone {
position: absolute;
top: 0;
left: 0;
}

.iconCopy {
color: var(--color-text-ultra-light);
}

.iconDone {
color: var(--color-success);
}

/** done state */
.iconCopy {
opacity: 1;
transition: var(--ui-transition-out);
}

.iconDone {
opacity: 0;
transition: var(--ui-transition-out);
}

.done .iconCopy {
opacity: 0;
transition: var(--ui-transition-in);
}

.done .iconDone {
opacity: 1;
transition: var(--ui-transition-in);
}
33 changes: 33 additions & 0 deletions packages/ui/src/ui/copy-to-clipboard/copy-to-clipboard.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Meta, StoryObj } from '@storybook/react';
import { CopyToClipboard } from '.';

const meta: Meta<typeof CopyToClipboard> = {
title: 'UI/CopyToClipboard',
component: CopyToClipboard,
};

export default meta;

type Story = StoryObj<Meta>;

export const Default: Story = {
args: {
text: 'Lorem ipsum dolor sit amd',
},
};

export const Inline: Story = {
args: {
...Default.args,
children: Default.args?.text,
outline: true,
size: 'small',
},
};

export const Outline: Story = {
args: {
...Default.args,
outline: true,
},
};
57 changes: 57 additions & 0 deletions packages/ui/src/ui/copy-to-clipboard/copy-to-clipboard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import type { ComponentProps } from 'react';
import React, { useCallback, useState } from 'react';
import cx from 'classnames';
import { useCopyToClipboard } from 'react-use';

import { Button } from '../button';
import { Icon } from '../icon';
import { Tooltip } from '../tooltip';
import css from './copy-to-clipboard.module.css';

export type CopyToClipboardProps = {
/**
* Text to copy to clipboard
*/
text: string;
} & ComponentProps<typeof Button>;

export const CopyToClipboard = (props: CopyToClipboardProps) => {
const { className = '', children, text, ...restProps } = props;

const [, copyToClipboard] = useCopyToClipboard();
const [doneTimeout, setDoneTimeout] = useState<ReturnType<typeof setTimeout> | null>();

const handleOnClick = useCallback(() => {
if (doneTimeout) {
clearTimeout(doneTimeout);
setDoneTimeout(null);
}

setDoneTimeout(null);
copyToClipboard(text);

const done = setTimeout(() => setDoneTimeout(null), 2000);
setDoneTimeout(done);
}, [text, doneTimeout, setDoneTimeout]);

const rootClassName = cx(css.root, className, doneTimeout && css.done);

return (
<Tooltip
title={doneTimeout ? 'Copied' : 'Copy to clipboard'}
as={Button}
type="button"
onClick={handleOnClick}
className={rootClassName}
{...restProps}
>
<span className={css.wrapper}>
{children && <span className={css.content}>{children}</span>}
<span className={css.icon}>
<Icon className={css.iconCopy} glyph={Icon.ICONS.CLIPBOARD} />
<Icon className={css.iconDone} glyph={Icon.ICONS.CLIPBOARD_CHECK} />
</span>
</span>
</Tooltip>
);
};
1 change: 1 addition & 0 deletions packages/ui/src/ui/copy-to-clipboard/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './copy-to-clipboard';
1 change: 1 addition & 0 deletions packages/ui/src/ui/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export { Alert } from './alert';
export { Button } from './button';
export { CopyToClipboard } from './copy-to-clipboard';
export { Container } from './container';
export { ControlGroup } from './control-group';
export { Dropdown } from './dropdown';
Expand Down

0 comments on commit ece5364

Please sign in to comment.