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

refactor: components ClipboardButton and ClipboardIcon #1123

Merged
merged 6 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
/src/components/Button @amje
/src/components/Card @Lunory
/src/components/Checkbox @zamkovskaya
/src/components/ClipboardButton @SeqviriouM
/src/components/ClipboardIcon @SeqviriouM
/src/components/ClipboardButton @Raubzeug
/src/components/ClipboardIcon @Raubzeug
/src/components/ControlLabel @korvin89
/src/components/CopyToClipboard @SeqviriouM
#/src/components/Dialog
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
"dependencies": {
"@bem-react/classname": "^1.6.0",
"@gravity-ui/i18n": "^1.1.0",
"@gravity-ui/icons": "^2.5.0",
"@gravity-ui/icons": "^2.8.1",
"@popperjs/core": "^2.11.8",
"blueimp-md5": "^2.19.0",
"focus-trap": "^7.5.2",
Expand Down
8 changes: 0 additions & 8 deletions src/components/ClipboardButton/ClipboardButton.scss

This file was deleted.

57 changes: 19 additions & 38 deletions src/components/ClipboardButton/ClipboardButton.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,24 @@
import React from 'react';

import {Button} from '../Button';
import type {ButtonProps} from '../Button';
import type {ButtonProps, ButtonSize} from '../Button';
import {ClipboardIcon} from '../ClipboardIcon';
import {CopyToClipboard} from '../CopyToClipboard';
import {CopyToClipboardStatus} from '../CopyToClipboard/types';
import type {CopyToClipboardBaseProps} from '../CopyToClipboard/types';
import type {CopyToClipboardBaseProps, CopyToClipboardStatus} from '../CopyToClipboard/types';
import {Tooltip} from '../Tooltip';
import type {QAProps} from '../types';
import {block} from '../utils/cn';

import i18n from './i18n';

import './ClipboardButton.scss';

export interface ClipboardButtonProps
extends CopyToClipboardBaseProps,
Omit<ClipboardButtonComponentProps, 'status' | 'onClick'>,
QAProps {
Omit<ClipboardButtonComponentProps, 'status' | 'onClick'> {
/** Time to restore initial state, ms */
timeout?: number;
}

interface ClipboardButtonComponentProps extends QAProps {
/** Icon size in pixels */
size?: number;
/** Element CSS class */
className?: string;
interface ClipboardButtonComponentProps
extends Omit<ButtonProps, 'href' | 'component' | 'target' | 'rel' | 'loading' | 'children'> {
status: CopyToClipboardStatus;
onClick?: ButtonProps['onClick'];
/** Disable tooltip. Tooltip won't be shown */
hasTooltip?: boolean;
/** Text shown before copy */
Expand All @@ -37,44 +27,35 @@ interface ClipboardButtonComponentProps extends QAProps {
tooltipSuccessText?: string;
}

const b = block('clipboard-button');

const DEFAULT_ICON_SIZE = 24;
const DEFAULT_TIMEOUT = 1000;

const ButtonSizeToIconSize: Record<ButtonSize, number> = {
xs: 12,
s: 16,
m: 16,
l: 16,
xl: 20,
};

const ClipboardButtonComponent = (props: ClipboardButtonComponentProps) => {
const {
size = DEFAULT_ICON_SIZE,
className,
qa,
size = 'm',
hasTooltip = true,
tooltipInitialText = i18n('startCopy'),
tooltipSuccessText = i18n('endCopy'),
status,
onClick,
view = 'flat',
...rest
} = props;
const buttonRef = React.useRef<HTMLButtonElement | null>(null);

React.useEffect(() => {
buttonRef?.current?.style.setProperty('--g-button-height', `${size}px`);
}, [size]);

return (
<Tooltip
disabled={!hasTooltip}
content={
status === CopyToClipboardStatus.Success ? tooltipSuccessText : tooltipInitialText
}
content={status === 'success' ? tooltipSuccessText : tooltipInitialText}
>
<Button
ref={buttonRef}
view="flat"
className={b(null, className)}
qa={qa}
onClick={onClick}
>
<Button view={view} size={size} {...rest}>
<Button.Icon>
<ClipboardIcon status={status} size={size} className={b('icon')} />
<ClipboardIcon size={ButtonSizeToIconSize[size]} status={status} />
</Button.Icon>
</Button>
</Tooltip>
Expand Down
11 changes: 5 additions & 6 deletions src/components/ClipboardButton/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,17 @@ LANDING_BLOCK-->

## Properties

`ClipboardButton` properties are inherited from `Button` [properties](../Button/README.md#properties) except `href`, `component`, `target`, `rel`, `loading`, `children`.

| Name | Description | Type | Default |
| :----------------- | :----------------------------------------------------------------------- | :-----------------------------------------------: | :---------: |
| text | Text to copy | `string` | |
| hasTooltip | Disable tooltip. Tooltip won't be shown | `boolean` | `true` |
| onCopy | Callback after copy `(text: string, result: boolean) => void` | `Function` | |
| options | Copy to clipboard options | [CopyToClipboardOptions](#copytoclipboardoptions) | |
| size | Icon size | `number` | `24` |
| className | CSS class name | `string` | |
| hasTooltip | Disable tooltip. Tooltip won't be shown | `boolean` | `true` |
| text | Text to copy | `string` | |
| timeout | Time before state bounces back to its normal after the button is clicked | `number` | `1000` |
| tooltipInitialText | Text shown before copy | `string` | `"Copy"` |
| tooltipSuccessText | Text shown after copy | `string` | `"Copied!"` |
| qa | HTML `data-qa` attribute, used in tests | `string` | |
| timeout | Time before state bounces back to its normal after the button is clicked | `number` | `1000` |

### CopyToClipboardOptions

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,38 @@
import React from 'react';

import type {Meta, StoryFn} from '@storybook/react';
import type {Meta, StoryObj} from '@storybook/react';

import {Showcase} from '../../../demo/Showcase';
import {ShowcaseItem} from '../../../demo/ShowcaseItem';
import {ClipboardButton} from '../ClipboardButton';
import type {ClipboardButtonProps} from '../ClipboardButton';

export default {
title: 'Components/Utils/ClipboardButton',
component: ClipboardButton,
} as Meta;

const DefaultTemplate: StoryFn<ClipboardButtonProps> = (args) => <ClipboardButton {...args} />;
export const Default = DefaultTemplate.bind({});
type Story = StoryObj<typeof ClipboardButton>;

export const Default: Story = {};

export const Size: Story = {
render: (args) => (
<Showcase>
<ShowcaseItem title="Size xs">
<ClipboardButton {...args} size="xs" />
</ShowcaseItem>
<ShowcaseItem title="Size s">
<ClipboardButton {...args} size="s" />
</ShowcaseItem>
<ShowcaseItem title="Size m">
<ClipboardButton {...args} size="m" />
</ShowcaseItem>
<ShowcaseItem title="Size l">
<ClipboardButton {...args} size="l" />
</ShowcaseItem>
<ShowcaseItem title="Size xl">
<ClipboardButton {...args} size="xl" />
</ShowcaseItem>
</Showcase>
),
};
23 changes: 0 additions & 23 deletions src/components/ClipboardIcon/ClipboardIcon.scss

This file was deleted.

51 changes: 12 additions & 39 deletions src/components/ClipboardIcon/ClipboardIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,48 +1,21 @@
import React from 'react';

import {CopyToClipboardStatus} from '../CopyToClipboard/types';
import {block} from '../utils/cn';
import {a11yHiddenSvgProps} from '../utils/svg';

import './ClipboardIcon.scss';
import {Copy, CopyCheck, CopyXmark} from '@gravity-ui/icons';

import type {CopyToClipboardStatus} from '../CopyToClipboard/types';
import {Icon} from '../Icon';
export interface ClipboardIconProps {
size: number;
size?: number;
status: CopyToClipboardStatus;
className?: string;
}

const b = block('clipboard-icon');

const renderStatusPath = (path: string) => (
<path
stroke="currentColor"
fill="transparent"
className={b('state')}
strokeWidth="1.5"
d={path}
/>
);

const STATUS_PATH = {
[CopyToClipboardStatus.Success]: renderStatusPath('M9.5 13l3 3l5 -5'),
[CopyToClipboardStatus.Error]: renderStatusPath('M9.5 10l8 8m-8 0l8 -8'),
};

export function ClipboardIcon({size, status, className}: ClipboardIconProps) {
return (
<svg
width={size}
height={size}
viewBox="0 0 24 24"
className={b(null, className)}
{...a11yHiddenSvgProps}
>
<path
fill="currentColor"
d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"
/>
{status === CopyToClipboardStatus.Pending ? null : STATUS_PATH[status]}
</svg>
);
export function ClipboardIcon({status, ...rest}: ClipboardIconProps) {
if (status === 'error') {
return <Icon data={CopyXmark} {...rest} />;
}
if (status === 'success') {
return <Icon data={CopyCheck} {...rest} />;
}
return <Icon data={Copy} {...rest} />;
}
6 changes: 3 additions & 3 deletions src/components/ClipboardIcon/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
import {ClipboardIcon} from '@gravity-ui/uikit';
```

ClipboardIcon is a svg copy-paste icon. This component is mainly used together with `CopyToClipboard` as wrap component.
This component is mainly used together with `CopyToClipboard` as wrap component.

### Status

Depends on `status` property additionally draws animated successful (✓ sign) or failed (X️ sign) operation indicators.
Depends on `status` property icon is changed.

<!--LANDING_BLOCK

Expand Down Expand Up @@ -43,6 +43,6 @@ LANDING_BLOCK-->

| Name | Description | Type | Default |
| :-------- | :---------------------------------------------- | :------- | :------ |
| classname | HTML `class` attribute | `string` | |
| className | HTML `class` attribute | `string` | |
| size | Sets icon size | `number` | |
| status | Available values: `pending`, `success`, `error` | `string` | |
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.clipboard-icon-stories {
display: grid;
gap: 10px;
grid-template-columns: auto;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type {Meta, StoryObj} from '@storybook/react';

import {ClipboardIcon} from '../ClipboardIcon';

export default {
title: 'Components/Utils/ClipboardIcon',
component: ClipboardIcon,
args: {size: 20},
} as Meta;

type Story = StoryObj<typeof ClipboardIcon>;

export const Default: Story = {args: {status: 'pending'}};

export const Success: Story = {args: {status: 'success'}};

export const Error: Story = {args: {status: 'error'}};
11 changes: 7 additions & 4 deletions src/components/CopyToClipboard/CopyToClipboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ import React from 'react';

import ReactCopyToClipboard from 'react-copy-to-clipboard';

import {CopyToClipboardStatus} from './types';
import type {CopyToClipboardBaseProps, CopyToClipboardContent} from './types';
import type {
CopyToClipboardBaseProps,
CopyToClipboardContent,
CopyToClipboardStatus,
} from './types';

interface CopyToClipboardGeneralProps extends CopyToClipboardBaseProps {
children: CopyToClipboardContent;
Expand All @@ -29,7 +32,7 @@ export class CopyToClipboard extends React.Component<
CopyToClipboardInnerProps,
CopyToClipboardState
> {
static INITIAL_STATUS = CopyToClipboardStatus.Pending;
static INITIAL_STATUS: CopyToClipboardStatus = 'pending';

state: CopyToClipboardState = {
status: CopyToClipboard.INITIAL_STATUS,
Expand Down Expand Up @@ -61,7 +64,7 @@ export class CopyToClipboard extends React.Component<
const {timeout, onCopy} = this.props;

this.setState({
status: result ? CopyToClipboardStatus.Success : CopyToClipboardStatus.Error,
status: result ? 'success' : 'error',
});

clearTimeout(this.timerId);
Expand Down
6 changes: 1 addition & 5 deletions src/components/CopyToClipboard/types.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import type ReactCopyToClipboard from 'react-copy-to-clipboard';

export enum CopyToClipboardStatus {
Pending = 'pending',
Success = 'success',
Error = 'error',
}
export type CopyToClipboardStatus = 'pending' | 'success' | 'error';

export type OnCopyHandler = (text: string, result: boolean) => void;

Expand Down
Loading