diff --git a/packages/components/src/OverflowTypography/OverflowTypography.stories.tsx b/packages/components/src/OverflowTypography/OverflowTypography.stories.tsx index f61a9dcf2..dde74b28d 100644 --- a/packages/components/src/OverflowTypography/OverflowTypography.stories.tsx +++ b/packages/components/src/OverflowTypography/OverflowTypography.stories.tsx @@ -1,5 +1,7 @@ import { type Meta, type StoryObj } from '@storybook/react'; +import { styled } from '../styles'; + import { OverflowTypography } from './OverflowTypography'; /** @@ -31,9 +33,13 @@ export const Interaction: Story = { }, }; +const Wrapper = styled.div` + max-width: 500px; +`; + export const Example = () => { return ( -
+ Not enough long text for special behavior. @@ -42,7 +48,7 @@ export const Example = () => { Lorem ipsum dolor sit amet, consectetur adipisicing elit. Atque aut delectus dolorem ea, explicabo illo minus nostrum quae quod veniam. -
+ ); }; @@ -53,7 +59,7 @@ export const Example = () => { */ export const RowsCount = () => { return ( -
+ default props, Lorem ipsum dolor sit amet, consectetur adipisicing elit. Atque aut delectus dolorem ea, explicabo illo minus nostrum quae quod @@ -65,7 +71,7 @@ export const RowsCount = () => { sit amet. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Qui, tempore. -
+ ); }; @@ -74,7 +80,7 @@ export const RowsCount = () => { */ export const TooltipProps = () => { return ( -
+ { adipisicing elit. Assumenda autem debitis eligendi inventore magni nobis perspiciatis quisquam ratione, unde vel? -
+ + ); +}; + +/** + * Prop `visibleLastSymbolsCount` позволяет задавать число отображаемых символов после сокращения. + * При использовании `visibleLastSymbolsCount` не работает props `rowsCount` + */ +export const VisibleLastSymbols = () => { + return ( + + + Lorem ipsum dolor sit amet, consectetur adipisicing elit. Adipisci animi + consectetur corporis dolores eos, esse eum expedita hic minima + molestias, nobis odio qui quisquam rem saepe ut, velit voluptate + voluptates! + + ); }; diff --git a/packages/components/src/OverflowTypography/OverflowTypography.tsx b/packages/components/src/OverflowTypography/OverflowTypography.tsx index c85b0e7b6..8992e31a9 100644 --- a/packages/components/src/OverflowTypography/OverflowTypography.tsx +++ b/packages/components/src/OverflowTypography/OverflowTypography.tsx @@ -3,10 +3,10 @@ import { type PropsWithChildren } from 'react'; import { Tooltip } from '../Tooltip'; import { type TooltipProps as BasicTooltipProps } from '../Tooltip'; -import { type TypographyProps } from '../Typography'; +import { Typography, type TypographyProps } from '../Typography'; -import { StyledTypography } from './styles'; -import { useOverflowed } from './hooks'; +import { StyledTypography, Wrapper } from './styles'; +import { useLogic } from './useLogic'; type TooltipProps = Omit; @@ -31,6 +31,10 @@ type TooltipCustomizable = { */ title?: ReactNode; }; + /** + * Количество отображаемых после сокращения в конце символов + */ + visibleLastSymbolsCount?: number; }; export type OverflowedElementProps = OverflowedProps & @@ -45,29 +49,65 @@ export const DEFAULT_ROWS_COUNT = 1; export const OverflowTypography = forwardRef< HTMLElement, OverflowedTypographyProps ->( - ( - { tooltipProps, children, rowsCount = DEFAULT_ROWS_COUNT, ...props }, +>((props, forwardedRef) => { + const { + ref, + isOverflowed, + secondPartLabel, + firstPartLabel, + isTruncatedStringVisible, + } = useLogic({ + ...props, forwardedRef, - ) => { - const { ref, isOverflowed } = useOverflowed(forwardedRef); + }); + + const { + tooltipProps, + children, + rowsCount = DEFAULT_ROWS_COUNT, + visibleLastSymbolsCount, + align = 'left', + ...restProps + } = props; + + const typographyProps = { + ...restProps, + ref, + align, + children, + rowsCount, + hasMultipleRows: rowsCount > DEFAULT_ROWS_COUNT, + }; - const typographyProps = { - ...props, - ref, - children, - rowsCount, - hasMultipleRows: rowsCount > DEFAULT_ROWS_COUNT, - }; + if (isTruncatedStringVisible) { + return ( + + + + + + + ); + } - if (children && isOverflowed) { - return ( - - - - ); - } + if (children && isOverflowed) { + return ( + + + + ); + } - return ; - }, -); + return ; +}); diff --git a/packages/components/src/OverflowTypography/styles.ts b/packages/components/src/OverflowTypography/styles.ts index 55e3b75b9..313a5bae1 100644 --- a/packages/components/src/OverflowTypography/styles.ts +++ b/packages/components/src/OverflowTypography/styles.ts @@ -26,3 +26,12 @@ export const StyledTypography = styled(Typography, { hasMultipleRows ? 'vertical' : ''}; -webkit-line-clamp: ${({ rowsCount }) => rowsCount}; `; + +export const Wrapper = styled(Typography, { + shouldForwardProp: (prop) => !['$align'].includes(prop), +})<{ $align: string }>` + display: flex; + justify-content: ${({ $align }) => $align}; + + white-space: nowrap; +`; diff --git a/packages/components/src/OverflowTypography/useLogic/index.ts b/packages/components/src/OverflowTypography/useLogic/index.ts new file mode 100644 index 000000000..51786a09c --- /dev/null +++ b/packages/components/src/OverflowTypography/useLogic/index.ts @@ -0,0 +1 @@ +export * from './useLogic'; diff --git a/packages/components/src/OverflowTypography/useLogic/useLogic.ts b/packages/components/src/OverflowTypography/useLogic/useLogic.ts new file mode 100644 index 000000000..3dce28f2e --- /dev/null +++ b/packages/components/src/OverflowTypography/useLogic/useLogic.ts @@ -0,0 +1,35 @@ +import { type ForwardedRef } from 'react'; + +import { useOverflowed } from '../hooks'; +import { type OverflowedTypographyProps } from '../OverflowTypography'; +import { truncateString } from '../utils'; + +type UseLogicParams = OverflowedTypographyProps & { + forwardedRef: ForwardedRef; +}; + +export const useLogic = ({ + forwardedRef, + children, + visibleLastSymbolsCount, +}: UseLogicParams) => { + const { ref, isOverflowed } = useOverflowed(forwardedRef); + + const canSlice = children && typeof children === 'string'; + + const { firstPartLabel, secondPartLabel } = + canSlice && isOverflowed && visibleLastSymbolsCount + ? truncateString(visibleLastSymbolsCount, children) + : { firstPartLabel: '', secondPartLabel: '' }; + + const isTruncatedStringVisible = + canSlice && isOverflowed && Boolean(visibleLastSymbolsCount); + + return { + isTruncatedStringVisible, + isOverflowed, + ref, + firstPartLabel, + secondPartLabel, + }; +}; diff --git a/packages/components/src/OverflowTypography/utils/index.ts b/packages/components/src/OverflowTypography/utils/index.ts new file mode 100644 index 000000000..e6b48f170 --- /dev/null +++ b/packages/components/src/OverflowTypography/utils/index.ts @@ -0,0 +1 @@ +export { truncateString } from './truncateString'; diff --git a/packages/components/src/OverflowTypography/utils/truncateString/index.ts b/packages/components/src/OverflowTypography/utils/truncateString/index.ts new file mode 100644 index 000000000..02892935e --- /dev/null +++ b/packages/components/src/OverflowTypography/utils/truncateString/index.ts @@ -0,0 +1 @@ +export * from './truncateString'; diff --git a/packages/components/src/OverflowTypography/utils/truncateString/truncateString.ts b/packages/components/src/OverflowTypography/utils/truncateString/truncateString.ts new file mode 100644 index 000000000..2c27f396f --- /dev/null +++ b/packages/components/src/OverflowTypography/utils/truncateString/truncateString.ts @@ -0,0 +1,9 @@ +export const truncateString = ( + visibleLastSymbolsCount: number, + label: string, +) => { + const firstPartLabel = label.slice(0, -visibleLastSymbolsCount); + const secondPartLabel = label.slice(-visibleLastSymbolsCount); + + return { firstPartLabel, secondPartLabel }; +};