This repository has been archived by the owner on Sep 26, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(UIKIT-1772,CopyTypography): Реализован новый компонент CopyTypog…
…raphy (#1142)
- Loading branch information
1 parent
658f37b
commit d2a070e
Showing
9 changed files
with
264 additions
and
0 deletions.
There are no files selected for viewing
94 changes: 94 additions & 0 deletions
94
packages/components/src/CopyTypography/CopyTypography.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import { type Meta, type StoryObj } from '@storybook/react'; | ||
|
||
import { Typography } from '../Typography'; | ||
import { styled } from '../styles'; | ||
import { OverflowTypography } from '../OverflowTypography'; | ||
|
||
import { CopyTypography } from './CopyTypography'; | ||
|
||
/** | ||
* ### [Figma]() | ||
* ### [Guide]() | ||
* Компонент позволяет скопировать содержимое в буфер обмена | ||
*/ | ||
|
||
const meta: Meta<typeof CopyTypography> = { | ||
title: 'Components/Data Display/CopyTypography', | ||
component: CopyTypography, | ||
}; | ||
|
||
export default meta; | ||
|
||
type Story = StoryObj<typeof CopyTypography>; | ||
|
||
export const Interaction: Story = { | ||
args: { | ||
children: <Typography>Швецова М. Д.</Typography>, | ||
copyText: 'Швецова М. Д.', | ||
}, | ||
parameters: { | ||
docs: { | ||
disable: true, | ||
}, | ||
}, | ||
}; | ||
|
||
const Wrapper = styled.div` | ||
display: flex; | ||
flex-direction: column; | ||
gap: ${({ theme }) => theme.spacing(4)}; | ||
`; | ||
|
||
const OverflowWrapper = styled.div` | ||
width: 150px; | ||
`; | ||
|
||
export const Example = () => { | ||
return <CopyTypography>Швецова М. Д.</CopyTypography>; | ||
}; | ||
|
||
/** | ||
* prop `copyPosition` определяет расположение иконки(справа/слева от текста). По умолчанию справа | ||
*/ | ||
export const CopyPosition = () => { | ||
return ( | ||
<Wrapper> | ||
<CopyTypography>Швецова М. Д.</CopyTypography> | ||
<CopyTypography copyPosition="left">Швецова М. Д.</CopyTypography> | ||
</Wrapper> | ||
); | ||
}; | ||
|
||
/** | ||
* prop `copyText` указывает какой текст необходимо скопировать в буфер обмена. | ||
* Необходим для копирования текста вложенных компонентов или когда копируемое содержимое | ||
* должно отличаться от представления. | ||
*/ | ||
export const CopyText = () => { | ||
return ( | ||
<Wrapper> | ||
<CopyTypography copyText="Швецова Мария Дмитриевна"> | ||
Швецова М. Д. | ||
</CopyTypography> | ||
<CopyTypography copyText="Швецова М. Д."> | ||
<Typography>Швецова М. Д.</Typography> | ||
</CopyTypography> | ||
</Wrapper> | ||
); | ||
}; | ||
|
||
/** | ||
* prop `isShowCopyText` показывает в тултипе текст, который будет скопирован. | ||
* Необходимо отключать тултип у вложенных компонентов, при их наличии, для избежания их наложения | ||
*/ | ||
export const IsShowCopyText = () => { | ||
return ( | ||
<OverflowWrapper> | ||
<CopyTypography copyText="Швецова Мария Дмитриевна" isShowCopyText> | ||
<OverflowTypography tooltipProps={{ title: undefined }}> | ||
Швецова Мария Дмитриевна | ||
</OverflowTypography> | ||
</CopyTypography> | ||
</OverflowWrapper> | ||
); | ||
}; |
39 changes: 39 additions & 0 deletions
39
packages/components/src/CopyTypography/CopyTypography.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { describe, expect, it, vi } from 'vitest'; | ||
import { renderWithTheme, screen, userEvents } from '@astral/tests'; | ||
|
||
import { CopyTypography } from './CopyTypography'; | ||
|
||
describe('CopyTypography', () => { | ||
it('Значение копируется в буфер обмена, при клике на компонент', async () => { | ||
const copyText = 'it was copied'; | ||
|
||
const writeTextSpy = vi.fn(() => Promise.resolve()); | ||
|
||
Object.assign(navigator, { clipboard: { writeText: writeTextSpy } }); | ||
renderWithTheme(<CopyTypography>{copyText}</CopyTypography>); | ||
|
||
const element = screen.getByText(copyText); | ||
|
||
await userEvents.click(element); | ||
expect(writeTextSpy).toBeCalled(); | ||
}); | ||
|
||
it('Значение копируется в буфер обмена, если children содержит ReactNode и заданном copyText', async () => { | ||
const copyText = 'it was copied'; | ||
|
||
const writeTextSpy = vi.fn(() => Promise.resolve()); | ||
|
||
Object.assign(navigator, { clipboard: { writeText: writeTextSpy } }); | ||
|
||
renderWithTheme( | ||
<CopyTypography copyText={copyText}> | ||
<div>{copyText}</div> | ||
</CopyTypography>, | ||
); | ||
|
||
const element = screen.getByText(copyText); | ||
|
||
await userEvents.click(element); | ||
expect(writeTextSpy).toBeCalled(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { type TypographyProps } from '../Typography'; | ||
import { Tooltip } from '../Tooltip'; | ||
|
||
import { StyledCopyIcon, Wrapper } from './styles'; | ||
import { useLogic } from './useLogic'; | ||
|
||
export type CopyTypographyProps = TypographyProps & { | ||
/** | ||
* Текст, который будет скопирован. Перекрывает обычное копирование если children является строкой | ||
*/ | ||
copyText?: string; | ||
/** | ||
* Отображает иконку слева или справа от текста | ||
* @default right | ||
*/ | ||
copyPosition?: 'right' | 'left'; | ||
/** | ||
* Если `true`, в тултипе будет отображаться текст, который будет скопирован при нажатии | ||
*/ | ||
isShowCopyText?: boolean; | ||
}; | ||
|
||
export const CopyTypography = (props: CopyTypographyProps) => { | ||
const { | ||
children, | ||
copyPosition = 'right', | ||
copyText, | ||
isShowCopyText, | ||
color, | ||
...restProps | ||
} = props; | ||
|
||
const renderIcon = () => ( | ||
<StyledCopyIcon $copyPosition={copyPosition} color={color as 'secondary'} /> | ||
); | ||
|
||
const { handleMouseLeave, handleClick, tooltipTitle, isIconOnLeft } = | ||
useLogic(props); | ||
|
||
return ( | ||
<Tooltip title={tooltipTitle} disableInteractive placement="bottom"> | ||
<Wrapper | ||
onMouseLeave={handleMouseLeave} | ||
onClick={handleClick} | ||
component="div" | ||
color={color} | ||
{...restProps} | ||
> | ||
{isIconOnLeft && renderIcon()} | ||
{children} | ||
{!isIconOnLeft && renderIcon()} | ||
</Wrapper> | ||
</Tooltip> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export enum CopyStatus { | ||
Copied = 'Скопировано', | ||
Error = 'Ошибка копирования', | ||
CanCopy = 'Скопировать', | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './CopyTypography'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import { CopyOutlineSm } from '@astral/icons'; | ||
|
||
import { styled } from '../styles'; | ||
import { Typography } from '../Typography'; | ||
|
||
export const Wrapper = styled(Typography)` | ||
cursor: pointer; | ||
display: flex; | ||
align-items: center; | ||
&:hover { | ||
text-decoration: underline; | ||
} | ||
`; | ||
|
||
export const StyledCopyIcon = styled(CopyOutlineSm, { | ||
shouldForwardProp: (prop) => !['$copyPosition'].includes(prop), | ||
})<{ $copyPosition: 'left' | 'right' }>` | ||
margin-right: ${({ $copyPosition, theme }) => | ||
$copyPosition === 'left' ? theme.spacing(1) : ''}; | ||
margin-left: ${({ $copyPosition, theme }) => | ||
$copyPosition === 'right' ? theme.spacing(1) : ''}; | ||
/* Задаем размер иконки */ | ||
font-size: 16px; | ||
fill: ${({ color }) => color}; | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './useLogic'; |
38 changes: 38 additions & 0 deletions
38
packages/components/src/CopyTypography/useLogic/useLogic.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { type SyntheticEvent, useState } from 'react'; | ||
|
||
import { type CopyTypographyProps } from '../CopyTypography'; | ||
import { CopyStatus } from '../enums'; | ||
|
||
type UseLogicParams = CopyTypographyProps; | ||
|
||
export const useLogic = ({ | ||
children, | ||
copyText, | ||
isShowCopyText, | ||
copyPosition, | ||
}: UseLogicParams) => { | ||
const [status, setStatus] = useState<CopyStatus>(CopyStatus.CanCopy); | ||
|
||
const handleMouseLeave = () => { | ||
if (status !== CopyStatus.CanCopy) { | ||
setTimeout(() => { | ||
setStatus(CopyStatus.CanCopy); | ||
}, 100); | ||
} | ||
}; | ||
|
||
const handleClick = (event: SyntheticEvent<HTMLElement>) => { | ||
event.stopPropagation(); | ||
|
||
navigator.clipboard | ||
.writeText(copyText || (typeof children === 'string' ? children : '')) | ||
.then(() => setStatus(CopyStatus.Copied)) | ||
.catch(() => setStatus(CopyStatus.Error)); | ||
}; | ||
|
||
const tooltipTitle = isShowCopyText ? `${status}: ${copyText}` : status; | ||
|
||
const isIconOnLeft = copyPosition === 'left'; | ||
|
||
return { handleMouseLeave, handleClick, tooltipTitle, isIconOnLeft }; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters