Skip to content

Commit

Permalink
TreeSelect Convert to Typescript. (#41536)
Browse files Browse the repository at this point in the history
* [WIP] Refactaring to Typescript.

* Fix types

* use SelectControl type.

* refactoring type.

* Update packages/components/src/tree-select/stories/index.tsx

Co-authored-by: Lena Morita <lena@jaguchi.com>

* add changelog

Co-authored-by: Tetsuaki Hamano / 浜野 哲明 <tetsuaki.hamano@gmail.com>
Co-authored-by: Lena Morita <lena@jaguchi.com>
  • Loading branch information
3 people authored Jun 8, 2022
1 parent 9767234 commit cb13b43
Show file tree
Hide file tree
Showing 9 changed files with 220 additions and 131 deletions.
1 change: 1 addition & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- `FormTokenField`: Convert to TypeScript and refactor to functional component ([#41216](https://github.com/WordPress/gutenberg/pull/41216)).
- `RadioControl`: Convert to TypeScript ([#41568](https://github.com/WordPress/gutenberg/pull/41568)).
- `Flex` updated to satisfy `react/exhuastive-deps` eslint rule ([#41507](https://github.com/WordPress/gutenberg/pull/41507)).
- `TreeSelect`: Convert to TypeScript ([#41536](https://github.com/WordPress/gutenberg/pull/41536)).

## 19.12.0 (2022-06-01)

Expand Down
2 changes: 1 addition & 1 deletion packages/components/src/select-control/stories/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { useState } from '@wordpress/element';
/**
* Internal dependencies
*/
import SelectControl from '..';
import SelectControl from '../';

const meta: ComponentMeta< typeof SelectControl > = {
title: 'Components/SelectControl',
Expand Down
4 changes: 2 additions & 2 deletions packages/components/src/tree-select/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,12 @@ A function that receives the id of the new node element that is being selected.

The id of the currently selected node.

- Type: `Object`
- Type: `string` | `string[]`
- Required: No

### tree

An array containing the tree objects with the possible nodes the user can select.

- Type: `String`
- Type: `Object[]`
- Required: No
48 changes: 0 additions & 48 deletions packages/components/src/tree-select/index.js

This file was deleted.

99 changes: 99 additions & 0 deletions packages/components/src/tree-select/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/**
* External dependencies
*/
import { unescape as unescapeString, repeat, flatMap, compact } from 'lodash';

/**
* WordPress dependencies
*/
import { useMemo } from '@wordpress/element';
/**
* Internal dependencies
*/
import { SelectControl } from '../select-control';
import type { TreeSelectProps, Tree, SelectOptions } from './types';

function getSelectOptions( tree: Tree[], level = 0 ): SelectOptions {
return flatMap( tree, ( treeNode ) => [
{
value: treeNode.id,
label:
repeat( '\u00A0', level * 3 ) + unescapeString( treeNode.name ),
},
...getSelectOptions( treeNode.children || [], level + 1 ),
] );
}

/**
* TreeSelect component is used to generate select input fields.
*
* @example
* ```jsx
* import { TreeSelect } from '@wordpress/components';
* import { useState } from '@wordpress/element';
*
* const MyTreeSelect = () => {
* const [ page, setPage ] = useState( 'p21' );
*
* return (
* <TreeSelect
* label="Parent page"
* noOptionLabel="No parent page"
* onChange={ ( newPage ) => setPage( newPage ) }
* selectedId={ page }
* tree={ [
* {
* name: 'Page 1',
* id: 'p1',
* children: [
* { name: 'Descend 1 of page 1', id: 'p11' },
* { name: 'Descend 2 of page 1', id: 'p12' },
* ],
* },
* {
* name: 'Page 2',
* id: 'p2',
* children: [
* {
* name: 'Descend 1 of page 2',
* id: 'p21',
* children: [
* {
* name: 'Descend 1 of Descend 1 of page 2',
* id: 'p211',
* },
* ],
* },
* ],
* },
* ] }
* />
* );
* }
* ```
*/
export function TreeSelect( {
label,
noOptionLabel,
onChange,
selectedId,
tree = [],
...props
}: TreeSelectProps ) {
const options = useMemo( () => {
return compact( [
noOptionLabel && { value: '', label: noOptionLabel },
...getSelectOptions( tree ),
] );
}, [ noOptionLabel, tree ] );

return (
<SelectControl
{ ...{ label, options, onChange } }
value={ selectedId }
{ ...props }
/>
);
}

export default TreeSelect;
80 changes: 0 additions & 80 deletions packages/components/src/tree-select/stories/index.js

This file was deleted.

81 changes: 81 additions & 0 deletions packages/components/src/tree-select/stories/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/**
* External dependencies
*/
import type { ComponentMeta, ComponentStory } from '@storybook/react';
import type { ComponentProps } from 'react';
/**
* WordPress dependencies
*/
import { useState } from '@wordpress/element';

/**
* Internal dependencies
*/
import TreeSelect from '../';

const meta: ComponentMeta< typeof TreeSelect > = {
title: 'Components/TreeSelect',
component: TreeSelect,
argTypes: {
help: { control: { type: 'text' } },
label: { control: { type: 'text' } },
prefix: { control: { type: 'text' } },
suffix: { control: { type: 'text' } },
selectedId: { control: { type: null } },
},
parameters: {
controls: {
expanded: true,
},
docs: { source: { state: 'open' } },
},
};

export default meta;

const TreeSelectWithState: ComponentStory< typeof TreeSelect > = ( props ) => {
const [ selection, setSelection ] = useState<
ComponentProps< typeof TreeSelect >[ 'selectedId' ]
>();

return (
<TreeSelect
{ ...props }
onChange={ setSelection }
selectedId={ selection }
/>
);
};

export const Default = TreeSelectWithState.bind( {} );
Default.args = {
label: 'Label Text',
noOptionLabel: 'No parent page',
help: 'Help text to explain the select control.',
tree: [
{
name: 'Page 1',
id: 'p1',
children: [
{ name: 'Descend 1 of page 1', id: 'p11' },
{ name: 'Descend 2 of page 1', id: 'p12' },
],
},
{
name: 'Page 2',
id: 'p2',
children: [
{
name: 'Descend 1 of page 2',
id: 'p21',
children: [
{
name: 'Descend 1 of Descend 1 of page 2',
id: 'p211',
},
],
},
],
},
],
};
35 changes: 35 additions & 0 deletions packages/components/src/tree-select/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* External dependencies
*/
import type { ComponentProps } from 'react';

/**
* Internal dependencies
*/
import type SelectControl from '../select-control';
import type { SelectControlProps } from '../select-control/types';

export type SelectOptions = Required<
ComponentProps< typeof SelectControl >
>[ 'options' ];

export interface Tree {
id: string;
name: string;
children?: Tree[];
}

export interface TreeSelectProps extends Omit< SelectControlProps, 'value' > {
/**
* If this property is added, an option will be added with this label to represent empty selection.
*/
noOptionLabel?: string;
/**
* An array containing the tree objects with the possible nodes the user can select.
*/
tree?: Tree[];
/**
* The id of the currently selected node.
*/
selectedId?: ComponentProps< typeof SelectControl >[ 'value' ];
}
1 change: 1 addition & 0 deletions packages/components/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
"src/toggle-group-control/**/*",
"src/tools-panel/**/*",
"src/tooltip/**/*",
"src/tree-select/**/*",
"src/truncate/**/*",
"src/ui/**/*",
"src/unit-control/**/*",
Expand Down

0 comments on commit cb13b43

Please sign in to comment.