Skip to content

Commit

Permalink
CustomSelectControlV2: Rename for consistency (#60178)
Browse files Browse the repository at this point in the history
* CustomSelectControlV2: Rename for consistency

* Add changelog

* Improve naming consistency in tests

* Simply subcomponent composition and exports

* Apply suggestions to readme

Co-authored-by: mirka <0mirka00@git.wordpress.org>
Co-authored-by: tyxla <tyxla@git.wordpress.org>
  • Loading branch information
3 people committed Mar 27, 2024
1 parent c7036a5 commit ab708fd
Show file tree
Hide file tree
Showing 10 changed files with 96 additions and 77 deletions.
4 changes: 4 additions & 0 deletions packages/components/CHANGELOG.md
Expand Up @@ -6,6 +6,10 @@

- `InputControl`: Ignore IME events when `isPressEnterToChange` is enabled ([#60090](https://github.com/WordPress/gutenberg/pull/60090)).

### Experimental

- `CustomSelectControlV2`: Rename for consistency ([#60178](https://github.com/WordPress/gutenberg/pull/60178)).

### Internal

- `Popover`, `ColorPicker`: Obviate pointer event trap #59449 ([#59449](https://github.com/WordPress/gutenberg/pull/59449)).
Expand Down
54 changes: 27 additions & 27 deletions packages/components/src/custom-select-control-v2/README.md
@@ -1,4 +1,4 @@
# CustomSelect
# CustomSelectControlV2

<div class="callout callout-alert">
This feature is still experimental. “Experimental” means this is an early implementation subject to drastic and breaking changes.
Expand All @@ -12,31 +12,31 @@ Used to render a customizable select control component.

#### Uncontrolled Mode

CustomSelect can be used in an uncontrolled mode, where the component manages its own state. In this mode, the `defaultValue` prop can be used to set the initial selected value. If this prop is not set, the first value from the children will be selected by default.
`CustomSelectControlV2` can be used in an uncontrolled mode, where the component manages its own state. In this mode, the `defaultValue` prop can be used to set the initial selected value. If this prop is not set, the first value from the children will be selected by default.

```jsx
const UncontrolledCustomSelect = () => (
<CustomSelect label="Colors">
<CustomSelectItem value="Blue">
const UncontrolledCustomSelectControlV2 = () => (
<CustomSelectControlV2 label="Colors">
<CustomSelectControlV2.Item value="Blue">
{ /* The `defaultValue` since it wasn't defined */ }
<span style={ { color: 'blue' } }>Blue</span>
</CustomSelectItem>
<CustomSelectItem value="Purple">
</CustomSelectControlV2.Item>
<CustomSelectControlV2.Item value="Purple">
<span style={ { color: 'purple' } }>Purple</span>
</CustomSelectItem>
<CustomSelectItem value="Pink">
</CustomSelectControlV2.Item>
<CustomSelectControlV2.Item value="Pink">
<span style={ { color: 'deeppink' } }>Pink</span>
</CustomSelectItem>
</CustomSelect>
</CustomSelectControlV2.Item>
</CustomSelectControlV2>
);
```

#### Controlled Mode

CustomSelect can also be used in a controlled mode, where the parent component specifies the `value` and the `onChange` props to control selection.
`CustomSelectControlV2` can also be used in a controlled mode, where the parent component specifies the `value` and the `onChange` props to control selection.

```jsx
const ControlledCustomSelect = () => {
const ControlledCustomSelectControlV2 = () => {
const [ value, setValue ] = useState< string | string[] >();

const renderControlledValue = ( renderValue: string | string[] ) => (
Expand All @@ -46,7 +46,7 @@ const ControlledCustomSelect = () => {
);

return (
<CustomSelect
<CustomSelectControlV2
{ ...props }
onChange={ ( nextValue ) => {
setValue( nextValue );
Expand All @@ -55,11 +55,11 @@ const ControlledCustomSelect = () => {
value={ value }
>
{ [ 'blue', 'purple', 'pink' ].map( ( option ) => (
<CustomSelectItem key={ option } value={ option }>
<CustomSelectControlV2.Item key={ option } value={ option }>
{ renderControlledValue( option ) }
</CustomSelectItem>
</CustomSelectControlV2.Item>
) ) }
</CustomSelect>
</CustomSelectControlV2>
);
};
```
Expand All @@ -70,31 +70,31 @@ Multiple selection can be enabled by using an array for the `value` and
`defaultValue` props. The argument of the `onChange` function will also change accordingly.
```jsx
const MultiSelectCustomSelect = () => (
<CustomSelect defaultValue={ [ 'blue', 'pink' ] } label="Colors">
const MultiSelectCustomSelectControlV2 = () => (
<CustomSelectControlV2 defaultValue={ [ 'blue', 'pink' ] } label="Colors">
{ [ 'blue', 'purple', 'pink' ].map( ( item ) => (
<CustomSelectItem key={ item } value={ item }>
<CustomSelectControlV2.Item key={ item } value={ item }>
{ item }
</CustomSelectItem>
</CustomSelectControlV2.Item>
) ) }
</CustomSelect>
</CustomSelectControlV2>
);
```
### Components and Sub-components
CustomSelect is comprised of two individual components:
`CustomSelectControlV2` is comprised of two individual components:
- `CustomSelect`: a wrapper component and context provider. It is responsible for managing the state of the `CustomSelectItem` children.
- `CustomSelectItem`: renders a single select item. The first `CustomSelectItem` child will be used as the `defaultValue` when `defaultValue` is undefined.
- `CustomSelectControlV2`: a wrapper component and context provider. It is responsible for managing the state of the `CustomSelectControlV2.Item` children.
- `CustomSelectControlV2.Item`: renders a single select item. The first `CustomSelectControlV2.Item` child will be used as the `defaultValue` when `defaultValue` is undefined.
#### Props
The component accepts the following props:
##### `children`: `React.ReactNode`
The child elements. This should be composed of CustomSelect.Item components.
The child elements. This should be composed of `CustomSelectControlV2.Item` components.
- Required: yes
Expand Down Expand Up @@ -142,7 +142,7 @@ Can be used to externally control the value of the control.
- Required: no
### `CustomSelectItem`
### `CustomSelectControlV2.Item`
Used to render a select item.
Expand Down
Expand Up @@ -9,8 +9,9 @@ import * as Ariakit from '@ariakit/react';
import _CustomSelect from '../custom-select';
import type { CustomSelectProps } from '../types';
import type { WordPressComponentProps } from '../../context';
import Item from '../item';

function CustomSelect(
function CustomSelectControlV2(
props: WordPressComponentProps< CustomSelectProps, 'button', false >
) {
const { defaultValue, onChange, value, ...restProps } = props;
Expand All @@ -24,4 +25,6 @@ function CustomSelect(
return <_CustomSelect { ...restProps } store={ store } />;
}

export default CustomSelect;
CustomSelectControlV2.Item = Item;

export default CustomSelectControlV2;
3 changes: 1 addition & 2 deletions packages/components/src/custom-select-control-v2/index.tsx
@@ -1,5 +1,4 @@
/**
* Internal dependencies
*/
export { default as CustomSelect } from './default-component';
export { default as CustomSelectItem } from './custom-select-item';
export { default } from './default-component';
Expand Up @@ -26,4 +26,6 @@ export function CustomSelectItem( {
);
}

CustomSelectItem.displayName = 'CustomSelectControlV2.Item';

export default CustomSelectItem;
Expand Up @@ -11,12 +11,12 @@ import { useMemo } from '@wordpress/element';
* Internal dependencies
*/
import _CustomSelect from '../custom-select';
import CustomSelectItem from '../item';
import type { LegacyCustomSelectProps } from '../types';
import { CustomSelectItem } from '..';
import * as Styled from '../styles';
import { ContextSystemProvider } from '../../context';

function CustomSelect( props: LegacyCustomSelectProps ) {
function CustomSelectControl( props: LegacyCustomSelectProps ) {
const {
__experimentalShowSelectedHint,
__next40pxDefaultSize = false,
Expand Down Expand Up @@ -128,4 +128,4 @@ function CustomSelect( props: LegacyCustomSelectProps ) {
);
}

export default CustomSelect;
export default CustomSelectControl;
Expand Up @@ -12,7 +12,7 @@ import { useState } from '@wordpress/element';
/**
* Internal dependencies
*/
import UncontrolledCustomSelect from '..';
import UncontrolledCustomSelectControl from '..';

const customClass = 'amber-skies';

Expand Down Expand Up @@ -48,14 +48,14 @@ const legacyProps = {
],
};

const LegacyControlledCustomSelect = ( {
const ControlledCustomSelectControl = ( {
options,
onChange,
...restProps
}: React.ComponentProps< typeof UncontrolledCustomSelect > ) => {
}: React.ComponentProps< typeof UncontrolledCustomSelectControl > ) => {
const [ value, setValue ] = useState( options[ 0 ] );
return (
<UncontrolledCustomSelect
<UncontrolledCustomSelectControl
{ ...restProps }
options={ options }
onChange={ ( args: any ) => {
Expand All @@ -70,8 +70,8 @@ const LegacyControlledCustomSelect = ( {
};

describe.each( [
[ 'Uncontrolled', UncontrolledCustomSelect ],
[ 'Controlled', LegacyControlledCustomSelect ],
[ 'Uncontrolled', UncontrolledCustomSelectControl ],
[ 'Controlled', ControlledCustomSelectControl ],
] )( 'CustomSelectControl (%s)', ( ...modeAndComponent ) => {
const [ , Component ] = modeAndComponent;

Expand Down
Expand Up @@ -11,15 +11,14 @@ import { useState } from '@wordpress/element';
/**
* Internal dependencies
*/
import CustomSelect from '../default-component';
import { CustomSelectItem } from '..';
import CustomSelectControlV2 from '..';

const meta: Meta< typeof CustomSelect > = {
const meta: Meta< typeof CustomSelectControlV2 > = {
title: 'Components (Experimental)/CustomSelectControl v2/Default',
component: CustomSelect,
component: CustomSelectControlV2,
subcomponents: {
// @ts-expect-error - See https://github.com/storybookjs/storybook/issues/23170
CustomSelectItem,
'CustomSelectControlV2.Item': CustomSelectControlV2.Item,
},
argTypes: {
children: { control: { type: null } },
Expand Down Expand Up @@ -48,10 +47,10 @@ const meta: Meta< typeof CustomSelect > = {
};
export default meta;

const Template: StoryFn< typeof CustomSelect > = ( props ) => {
const Template: StoryFn< typeof CustomSelectControlV2 > = ( props ) => {
const [ value, setValue ] = useState< string | string[] >();
return (
<CustomSelect
<CustomSelectControlV2
{ ...props }
onChange={ ( nextValue: string | string[] ) => {
setValue( nextValue );
Expand All @@ -68,15 +67,15 @@ Default.args = {
defaultValue: 'Select a color...',
children: (
<>
<CustomSelectItem value="Blue">
<CustomSelectControlV2.Item value="Blue">
<span style={ { color: 'blue' } }>Blue</span>
</CustomSelectItem>
<CustomSelectItem value="Purple">
</CustomSelectControlV2.Item>
<CustomSelectControlV2.Item value="Purple">
<span style={ { color: 'purple' } }>Purple</span>
</CustomSelectItem>
<CustomSelectItem value="Pink">
</CustomSelectControlV2.Item>
<CustomSelectControlV2.Item value="Pink">
<span style={ { color: 'deeppink' } }>Pink</span>
</CustomSelectItem>
</CustomSelectControlV2.Item>
</>
),
};
Expand All @@ -100,9 +99,9 @@ MultipleSelection.args = {
'maroon',
'tangerine',
].map( ( item ) => (
<CustomSelectItem key={ item } value={ item }>
<CustomSelectControlV2.Item key={ item } value={ item }>
{ item }
</CustomSelectItem>
</CustomSelectControlV2.Item>
) ) }
</>
),
Expand Down Expand Up @@ -134,9 +133,9 @@ CustomSelectedValue.args = {
<>
{ [ 'mystery-person', 'identicon', 'wavatar', 'retro' ].map(
( option ) => (
<CustomSelectItem key={ option } value={ option }>
<CustomSelectControlV2.Item key={ option } value={ option }>
{ renderItem( option ) }
</CustomSelectItem>
</CustomSelectControlV2.Item>
)
) }
</>
Expand Down
Expand Up @@ -11,12 +11,12 @@ import { useState } from '@wordpress/element';
/**
* Internal dependencies
*/
import CustomSelect from '../legacy-component';
import CustomSelectControl from '../legacy-component';
import * as V1Story from '../../custom-select-control/stories/index.story';

const meta: Meta< typeof CustomSelect > = {
const meta: Meta< typeof CustomSelectControl > = {
title: 'Components (Experimental)/CustomSelectControl v2/Legacy',
component: CustomSelect,
component: CustomSelectControl,
argTypes: {
onChange: { control: { type: null } },
value: { control: { type: null } },
Expand All @@ -43,17 +43,23 @@ const meta: Meta< typeof CustomSelect > = {
};
export default meta;

const Template: StoryFn< typeof CustomSelect > = ( props ) => {
const Template: StoryFn< typeof CustomSelectControl > = ( props ) => {
const [ value, setValue ] = useState( props.options[ 0 ] );

const onChange: React.ComponentProps<
typeof CustomSelect
typeof CustomSelectControl
>[ 'onChange' ] = ( changeObject ) => {
setValue( changeObject.selectedItem );
props.onChange?.( changeObject );
};

return <CustomSelect { ...props } onChange={ onChange } value={ value } />;
return (
<CustomSelectControl
{ ...props }
onChange={ onChange }
value={ value }
/>
);
};

export const Default = Template.bind( {} );
Expand Down

0 comments on commit ab708fd

Please sign in to comment.