diff --git a/@types/index.d.ts b/@types/index.d.ts index d5fabff..83d7c50 100644 --- a/@types/index.d.ts +++ b/@types/index.d.ts @@ -159,6 +159,7 @@ declare namespace EntitiesSearch { interface SearchControl extends Readonly<{ id?: string; + label?: string; onChange(phrase: string | React.ChangeEvent); }> {} diff --git a/sources/client/src/components/radio-control.tsx b/sources/client/src/components/radio-control.tsx index f8df171..fa44646 100644 --- a/sources/client/src/components/radio-control.tsx +++ b/sources/client/src/components/radio-control.tsx @@ -2,9 +2,17 @@ import EntitiesSearch from '@types'; import classnames from 'classnames'; import React, { JSX } from 'react'; +import { useId } from '../hooks/use-id'; + +interface Option extends EntitiesSearch.ControlOption { + readonly selectedValue: EntitiesSearch.SingularControl['value']; + readonly onChange: (event: React.ChangeEvent) => void; +} + export function RadioControl( props: EntitiesSearch.SingularControl & { className?: string; + id?: string; } ): JSX.Element { const className = classnames(props.className, 'wes-radio-control'); @@ -25,24 +33,36 @@ export function RadioControl( return (
{props.options.map((option) => ( -
- -
+ label={option.label} + value={option.value} + selectedValue={props.value} + onChange={onChange} + /> ))}
); } + +function Option(props: Option): JSX.Element { + const id = useId(); + const value = String(props.value); + + return ( +
+ +
+ ); +} diff --git a/sources/client/src/components/search-control.tsx b/sources/client/src/components/search-control.tsx index efbee8e..ee28471 100644 --- a/sources/client/src/components/search-control.tsx +++ b/sources/client/src/components/search-control.tsx @@ -1,19 +1,16 @@ import EntitiesSearch from '@types'; -import React, { JSX, PropsWithChildren, useCallback } from 'react'; +import React, { JSX } from 'react'; import { __ } from '@wordpress/i18n'; +import { useId } from '../hooks/use-id'; + export function SearchControl( props: EntitiesSearch.SearchControl ): JSX.Element { - const [searchValue, setSearchValue] = React.useState(''); - - const Container = useCallback( - (containerProps: PropsWithChildren) => ( -
{containerProps.children}
- ), - [] - ); + const id = useId(props.id); + const label = props.label || __('Search', 'wp-entities-search'); + const [searchValue, setSearchValue] = React.useState(''); const onChange = (event: React.ChangeEvent) => { setSearchValue(event.target.value); @@ -27,20 +24,12 @@ export function SearchControl( onChange, }; - if (props.id) { - return ( - - - - ); - } - return ( - - - +
+ +
); } diff --git a/sources/client/src/components/toggle-control.tsx b/sources/client/src/components/toggle-control.tsx index fabd0cf..a41f42a 100644 --- a/sources/client/src/components/toggle-control.tsx +++ b/sources/client/src/components/toggle-control.tsx @@ -2,9 +2,14 @@ import EntitiesSearch from '@types'; import classnames from 'classnames'; import React, { JSX } from 'react'; -import { slugifyOptionLabel } from '../utils/slugify-option-label'; +import { useId } from '../hooks/use-id'; import { NoOptionsMessage } from './no-options-message'; +interface Option extends EntitiesSearch.ControlOption { + readonly selectedValues: EntitiesSearch.BaseControl['value']; + readonly onChange: (event: React.ChangeEvent) => void; +} + export function ToggleControl( props: EntitiesSearch.BaseControl & { className?: string; @@ -36,36 +41,38 @@ export function ToggleControl( return (
- {props.options.map((option) => { - const value = String(option.value); - const id = idByControlOption(option); - return ( -
- -
- ); - })} + {props.options.map((option) => ( + + key={option.value} + label={option.label} + value={option.value} + selectedValues={props.value} + onChange={onChange} + /> + ))}
); } -function idByControlOption( - controlOption: EntitiesSearch.ControlOption -): string { - const { value } = controlOption; - const label = slugifyOptionLabel(controlOption); - return `wes-toggle-control-item__input-${label}-${value}`; +function Option(props: Option): JSX.Element { + const id = useId(); + const value = String(props.value); + + return ( +
+ +
+ ); } diff --git a/sources/client/src/hooks/use-id.ts b/sources/client/src/hooks/use-id.ts new file mode 100644 index 0000000..4d9e583 --- /dev/null +++ b/sources/client/src/hooks/use-id.ts @@ -0,0 +1,6 @@ +import React from 'react'; + +export function useId(maybeId?: string): string { + const fallbackId = React.useId(); + return maybeId ?? fallbackId; +} diff --git a/sources/client/src/hooks/use-search.ts b/sources/client/src/hooks/use-search.ts index 6ee1462..f5b7ed9 100644 --- a/sources/client/src/hooks/use-search.ts +++ b/sources/client/src/hooks/use-search.ts @@ -13,11 +13,10 @@ type SearchFunc = (phrase: SearchPhrase) => void; * Build a function to search the entities by a phrase * * @public - * @param setSearchPhrase A function to set the search phrase - * @param searchEntities The function that will search the entities - * @param kind The kind of entities to search - * @param entities The entities to exclude from the search - * @param dispatch The dispatch function to update the state + * @param searchEntities The function that will search the entities + * @param kind The kind of entities to search + * @param entities The entities to exclude from the search + * @param dispatch The dispatch function to update the state */ export function useSearch( searchEntities: EntitiesSearch.SearchEntitiesFunction, diff --git a/sources/client/src/index.ts b/sources/client/src/index.ts index 237370e..346be17 100644 --- a/sources/client/src/index.ts +++ b/sources/client/src/index.ts @@ -15,7 +15,6 @@ export * from './hooks/use-query-viewable-taxonomies'; export * from './utils/convert-entities-to-control-options'; export * from './utils/is-control-option'; export * from './utils/order-selected-options-at-the-top'; -export * from './utils/slugify-option-label'; export * from './utils/unique-control-options'; export * from './vo/control-option'; diff --git a/sources/client/src/utils/slugify-option-label.ts b/sources/client/src/utils/slugify-option-label.ts deleted file mode 100644 index 6411cc3..0000000 --- a/sources/client/src/utils/slugify-option-label.ts +++ /dev/null @@ -1,10 +0,0 @@ -import EntitiesSearch from '@types'; - -export function slugifyOptionLabel( - controlOption: EntitiesSearch.ControlOption -): string { - return controlOption.label - .toLowerCase() - .replace(/ /g, '-') - .replace(/[^\w-]+/g, ''); -} diff --git a/tests/client/unit/components/__snapshots__/radio-control.test.tsx.snap b/tests/client/unit/components/__snapshots__/radio-control.test.tsx.snap index cb3d09f..cd661c5 100644 --- a/tests/client/unit/components/__snapshots__/radio-control.test.tsx.snap +++ b/tests/client/unit/components/__snapshots__/radio-control.test.tsx.snap @@ -9,7 +9,7 @@ exports[`KindRadioControl renders the NoOptionsMessage when there are no options exports[`KindRadioControl renders the component 1`] = ` diff --git a/tests/client/unit/components/__snapshots__/search-control.test.tsx.snap b/tests/client/unit/components/__snapshots__/search-control.test.tsx.snap index c218d63..f416676 100644 --- a/tests/client/unit/components/__snapshots__/search-control.test.tsx.snap +++ b/tests/client/unit/components/__snapshots__/search-control.test.tsx.snap @@ -3,6 +3,7 @@ exports[`SearchControl renders the input outside the label if the id prop is not passed 1`] = ` diff --git a/tests/client/unit/components/__snapshots__/toggle-control.test.tsx.snap b/tests/client/unit/components/__snapshots__/toggle-control.test.tsx.snap index cf11520..63177aa 100644 --- a/tests/client/unit/components/__snapshots__/toggle-control.test.tsx.snap +++ b/tests/client/unit/components/__snapshots__/toggle-control.test.tsx.snap @@ -8,12 +8,12 @@ exports[`EntitiesToggleControl renders correctly 1`] = ` class="wes-toggle-control-item wes-toggle-control-item--1" >