Skip to content

Commit

Permalink
Truncate: Convert component to TypeScript (#41697)
Browse files Browse the repository at this point in the history
  • Loading branch information
Petter Walbø Johnsgård authored Jun 23, 2022
1 parent 5cc4c08 commit 20cf7e8
Show file tree
Hide file tree
Showing 12 changed files with 134 additions and 100 deletions.
1 change: 1 addition & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
- `InputControl`: Add tests and update to use `@testing-library/user-event` ([#41421](https://github.com/WordPress/gutenberg/pull/41421)).
- `FormToggle`: Convert to TypeScript ([#41729](https://github.com/WordPress/gutenberg/pull/41729)).
- `ColorIndicator`: Convert to TypeScript ([#41587](https://github.com/WordPress/gutenberg/pull/41587)).
- `Truncate`: Convert to TypeScript ([#41697](https://github.com/WordPress/gutenberg/pull/41697)).
- `VStack`: Convert to TypeScript ([#41850](https://github.com/WordPress/gutenberg/pull/41587)).
- `AlignmentMatrixControl`: Refactor away from `_.flattenDeep()` in utils ([#41814](https://github.com/WordPress/gutenberg/pull/41814/)).
- `AutoComplete`: Revert recent `exhaustive-deps` refactor ([#41820](https://github.com/WordPress/gutenberg/pull/41820)).
Expand Down
2 changes: 1 addition & 1 deletion packages/components/src/text/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* Internal dependencies
*/
import type { Props as TruncateProps } from '../truncate/types';
import type { TruncateProps } from '../truncate/types';

/**
* External dependencies
Expand Down
28 changes: 16 additions & 12 deletions packages/components/src/truncate/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,14 @@ function Example() {

## Props

##### ellipsis
##### `ellipsis`: `string`

**Type**: `string`
The ellipsis string when truncating the text by the `limit` prop's value.

The ellipsis string when `truncate` is set.
- Required: No
- Default: ``

##### ellipsizeMode

**Type**: `"auto"`,`"head"`,`"tail"`,`"middle"`
##### `ellipsizeMode`: `'auto' | 'head' | 'tail' | 'middle' | 'none'`

Determines where to truncate. For example, we can truncate text right in the middle. To do this, we need to set `ellipsizeMode` to `middle` and a text `limit`.

Expand All @@ -41,17 +40,22 @@ Determines where to truncate. For example, we can truncate text right in the mid
- `middle`: Trims content in the middle. Requires a `limit`.
- `tail`: Trims content at the end. Requires a `limit`.

##### limit
- Required: No
- Default: `auto`

##### `limit`: `number`

**Type**: `number`
Determines the max number of characters to be displayed before the rest of the text gets truncated. Requires `ellipsizeMode` to assume values different from `auto` and `none`.

Determines the max characters when `truncate` is set.
- Required: No
- Default: `0`

##### numberOfLines
##### `numberOfLines`: `number`

**Type**: `number`
Clamps the text content to the specified `numberOfLines`, adding an ellipsis at the end. Note: this feature ignores the value of the `ellipsis` prop and always displays the default `` ellipsis.

Clamps the text content to the specifiec `numberOfLines`, adding the `ellipsis` at the end.
- Required: No
- Default: `0`

```jsx
import { __experimentalTruncate as Truncate } from '@wordpress/components';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
/**
* External dependencies
*/
import type { ForwardedRef } from 'react';

/**
* Internal dependencies
*/
import { contextConnect } from '../ui/context';
import { contextConnect, WordPressComponentProps } from '../ui/context';
import { View } from '../view';
import useTruncate from './hook';
import type { TruncateProps } from './types';

/**
* @param {import('../ui/context').WordPressComponentProps<import('./types').Props, 'span'>} props
* @param {import('react').ForwardedRef<any>} forwardedRef
*/
function Truncate( props, forwardedRef ) {
function UnconnectedTruncate(
props: WordPressComponentProps< TruncateProps, 'span' >,
forwardedRef: ForwardedRef< any >
) {
const truncateProps = useTruncate( props );

return <View as="span" { ...truncateProps } ref={ forwardedRef } />;
Expand All @@ -21,7 +26,6 @@ function Truncate( props, forwardedRef ) {
* `Subheading` is used to render text content. However,`Truncate` is
* available for custom implementations.
*
* @example
* ```jsx
* import { __experimentalTruncate as Truncate } from `@wordpress/components`;
*
Expand All @@ -36,6 +40,6 @@ function Truncate( props, forwardedRef ) {
* }
* ```
*/
const ConnectedTruncate = contextConnect( Truncate, 'Truncate' );
export const Truncate = contextConnect( UnconnectedTruncate, 'Truncate' );

export default ConnectedTruncate;
export default Truncate;
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ import { useMemo } from '@wordpress/element';
/**
* Internal dependencies
*/
import { useContextSystem } from '../ui/context';
import { useContextSystem, WordPressComponentProps } from '../ui/context';
import * as styles from './styles';
import { TRUNCATE_ELLIPSIS, TRUNCATE_TYPE, truncateContent } from './utils';
import { useCx } from '../utils/hooks/use-cx';
import type { TruncateProps } from './types';

/**
* @param {import('../ui/context').WordPressComponentProps<import('./types').Props, 'span'>} props
*/
export default function useTruncate( props ) {
export default function useTruncate(
props: WordPressComponentProps< TruncateProps, 'span' >
) {
const {
className,
children,
Expand All @@ -33,7 +33,7 @@ export default function useTruncate( props ) {
const cx = useCx();

const truncatedContent = truncateContent(
typeof children === 'string' ? /** @type {string} */ ( children ) : '',
typeof children === 'string' ? children : '',
{
ellipsis,
ellipsizeMode,
Expand All @@ -45,9 +45,7 @@ export default function useTruncate( props ) {
const shouldTruncate = ellipsizeMode === TRUNCATE_TYPE.auto;

const classes = useMemo( () => {
const sx = {};

sx.numberOfLines = css`
const truncateLines = css`
-webkit-box-orient: vertical;
-webkit-line-clamp: ${ numberOfLines };
display: -webkit-box;
Expand All @@ -56,7 +54,7 @@ export default function useTruncate( props ) {

return cx(
shouldTruncate && ! numberOfLines && styles.Truncate,
shouldTruncate && !! numberOfLines && sx.numberOfLines,
shouldTruncate && !! numberOfLines && truncateLines,
className
);
}, [ className, cx, numberOfLines, shouldTruncate ] );
Expand Down
File renamed without changes.
38 changes: 0 additions & 38 deletions packages/components/src/truncate/stories/index.js

This file was deleted.

49 changes: 49 additions & 0 deletions packages/components/src/truncate/stories/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* External dependencies
*/
import type { ComponentMeta, ComponentStory } from '@storybook/react';

/**
* Internal dependencies
*/
import { Truncate } from '..';

const meta: ComponentMeta< typeof Truncate > = {
component: Truncate,
title: 'Components (Experimental)/Truncate',
argTypes: {
children: { control: { type: 'text' } },
as: { control: { type: 'text' } },
},
parameters: {
controls: {
expanded: true,
},
docs: { source: { state: 'open' } },
},
};
export default meta;

const defaultText =
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut facilisis dictum tortor, eu tincidunt justo scelerisque tincidunt. Duis semper dui id augue malesuada, ut feugiat nisi aliquam. Vestibulum venenatis diam sem, finibus dictum massa semper in. Nulla facilisi. Nunc vulputate faucibus diam, in lobortis arcu ornare vel. In dignissim nunc sed facilisis finibus. Etiam imperdiet mattis arcu, sed rutrum sapien blandit gravida. Aenean sollicitudin neque eget enim blandit, sit amet rutrum leo vehicula. Nunc malesuada ultricies eros ut faucibus. Aliquam erat volutpat. Nulla nec feugiat risus. Vivamus iaculis dui aliquet ante ultricies feugiat. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Vivamus nec pretium velit, sit amet consectetur ante. Praesent porttitor ex eget fermentum mattis.';

const Template: ComponentStory< typeof Truncate > = ( args ) => {
return <Truncate { ...args } />;
};

export const Default: ComponentStory< typeof Truncate > = Template.bind( {} );
Default.args = {
numberOfLines: 2,
children: defaultText,
};

export const CharacterCount: ComponentStory< typeof Truncate > = Template.bind(
{}
);
CharacterCount.args = {
limit: 23,
children: defaultText,
ellipsizeMode: 'tail',
ellipsis: '[---]',
};
CharacterCount.storyName = 'Truncate by character count';
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { Truncate } from '..';
describe( 'props', () => {
test( 'should render correctly', () => {
const { container } = render( <Truncate>Lorem ipsum.</Truncate> );
expect( container.firstChild.textContent ).toEqual( 'Lorem ipsum.' );
expect( container.firstChild?.textContent ).toEqual( 'Lorem ipsum.' );
} );

test( 'should render limit', () => {
Expand All @@ -20,7 +20,7 @@ describe( 'props', () => {
Lorem ipsum.
</Truncate>
);
expect( container.firstChild.textContent ).toEqual( 'L…' );
expect( container.firstChild?.textContent ).toEqual( 'L…' );
} );

test( 'should render custom ellipsis', () => {
Expand All @@ -29,7 +29,7 @@ describe( 'props', () => {
Lorem ipsum.
</Truncate>
);
expect( container.firstChild.textContent ).toEqual( 'Lorem!!!' );
expect( container.firstChild?.textContent ).toEqual( 'Lorem!!!' );
} );

test( 'should render custom ellipsizeMode', () => {
Expand All @@ -38,6 +38,6 @@ describe( 'props', () => {
Lorem ipsum.
</Truncate>
);
expect( container.firstChild.textContent ).toEqual( 'Lo!!!m.' );
expect( container.firstChild?.textContent ).toEqual( 'Lo!!!m.' );
} );
} );
38 changes: 28 additions & 10 deletions packages/components/src/truncate/types.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
export type TruncateEllisizeMode = 'auto' | 'head' | 'tail' | 'middle' | 'none';
/**
* External dependencies
*/
import type { ReactNode } from 'react';

export interface Props {
export type TruncateEllipsizeMode =
| 'auto'
| 'head'
| 'tail'
| 'middle'
| 'none';

export type TruncateProps = {
/**
* The ellipsis string when `truncate` is set.
* The ellipsis string when truncating the text by the `limit` prop's value.
*
* @default '...'
* @default ''
*/
ellipsis?: string;
/**
* Determines where to truncate. For example, we can truncate text right in the middle. To do this, we need to set `ellipsizeMode` to `middle` and a text `limit`.
* Determines where to truncate. For example, we can truncate text right in
* the middle. To do this, we need to set `ellipsizeMode` to `middle` and a
* text `limit`.
*
* * `auto`: Trims content at the end automatically without a `limit`.
* * `head`: Trims content at the beginning. Requires a `limit`.
Expand All @@ -17,19 +29,25 @@ export interface Props {
*
* @default 'auto'
*/
ellipsizeMode?: TruncateEllisizeMode;
ellipsizeMode?: TruncateEllipsizeMode;
/**
* Determines the max characters when `truncate` is set.
* Determines the max number of characters to be displayed before the rest
* of the text gets truncated. Requires `ellipsizeMode` to assume values
* different from `auto` and `none`.
*
* @default 0
*/
limit?: number;
/**
* Clamps the text content to the specified `numberOfLines`, adding the `ellipsis` at the end.
* Clamps the text content to the specified `numberOfLines`, adding an
* ellipsis at the end. Note: this feature ignores the value of the
* `ellipsis` prop and always displays the default `…` ellipsis.
*
* @default 0
*/
numberOfLines?: number;
/**
* The children elements.
*/
children: React.ReactNode;
}
children: ReactNode;
};
Loading

0 comments on commit 20cf7e8

Please sign in to comment.