From d047e66acee1aeaf9d5206750c608d6354055525 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Mon, 28 Sep 2020 12:49:55 +0300 Subject: [PATCH 1/6] update/move Query filters --- packages/block-library/src/query-loop/edit.js | 6 +- packages/block-library/src/query/constants.js | 2 +- .../query/edit/query-inspector-controls.js | 80 +++++++++++- .../src/query/edit/query-toolbar.js | 121 +++--------------- packages/block-library/src/query/editor.scss | 10 ++ 5 files changed, 115 insertions(+), 104 deletions(-) diff --git a/packages/block-library/src/query-loop/edit.js b/packages/block-library/src/query-loop/edit.js index 6e2113b496bbf0..fbf92894f03cc0 100644 --- a/packages/block-library/src/query-loop/edit.js +++ b/packages/block-library/src/query-loop/edit.js @@ -15,7 +15,11 @@ import { */ import { useQueryContext } from '../query'; -const TEMPLATE = [ [ 'core/post-title' ], [ 'core/post-content' ] ]; +const TEMPLATE = [ + [ 'core/post-title' ], + [ 'core/post-date' ], + [ 'core/post-excerpt' ], +]; export default function QueryLoopEdit( { clientId, context: { diff --git a/packages/block-library/src/query/constants.js b/packages/block-library/src/query/constants.js index 311232afe3adcc..db1a244abf38dc 100644 --- a/packages/block-library/src/query/constants.js +++ b/packages/block-library/src/query/constants.js @@ -1,4 +1,4 @@ -export const MAX_FETCHED_TERMS = 100; +export const MAX_FETCHED_TERMS = -1; export default { MAX_FETCHED_TERMS, diff --git a/packages/block-library/src/query/edit/query-inspector-controls.js b/packages/block-library/src/query/edit/query-inspector-controls.js index ec6a28d6721897..c210f87a92f84f 100644 --- a/packages/block-library/src/query/edit/query-inspector-controls.js +++ b/packages/block-library/src/query/edit/query-inspector-controls.js @@ -1,19 +1,68 @@ +/** + * External dependencies + */ +import { debounce } from 'lodash'; + /** * WordPress dependencies */ -import { PanelBody, QueryControls } from '@wordpress/components'; + +import { + PanelBody, + QueryControls, + TextControl, + FormTokenField, +} from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { InspectorControls } from '@wordpress/block-editor'; import { useSelect } from '@wordpress/data'; +import { useEffect, useState, useCallback } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { getTermsInfo } from '../utils'; +import { MAX_FETCHED_TERMS } from '../constants'; export default function QueryInspectorControls( { query, setQuery } ) { const { order, orderBy, author: selectedAuthorId } = query; - const { authorList } = useSelect( ( select ) => { + const { authorList, categories, tags } = useSelect( ( select ) => { const { getEntityRecords } = select( 'core' ); + const termsQuery = { per_page: MAX_FETCHED_TERMS }; + const _categories = getEntityRecords( + 'taxonomy', + 'category', + termsQuery + ); + const _tags = getEntityRecords( 'taxonomy', 'post_tag', termsQuery ); return { + categories: getTermsInfo( _categories ), + tags: getTermsInfo( _tags ), authorList: getEntityRecords( 'root', 'user', { per_page: -1 } ), }; }, [] ); + + // Handles categories and tags changes. + const onTermsChange = ( terms, queryProperty ) => ( newTermValues ) => { + const termIds = newTermValues.reduce( ( accumulator, termValue ) => { + const termId = termValue?.id || terms.mapByName[ termValue ]?.id; + if ( termId ) accumulator.push( termId ); + return accumulator; + }, [] ); + setQuery( { [ queryProperty ]: termIds } ); + }; + const onCategoriesChange = onTermsChange( categories, 'categoryIds' ); + const onTagsChange = onTermsChange( tags, 'tagIds' ); + + const [ querySearch, setQuerySearch ] = useState( query.search ); + const onChangeDebounced = useCallback( + debounce( () => setQuery( { search: querySearch } ), 250 ), + [ querySearch ] + ); + useEffect( () => { + onChangeDebounced(); + return onChangeDebounced.cancel; + }, [ querySearch, onChangeDebounced ] ); return ( @@ -29,6 +78,33 @@ export default function QueryInspectorControls( { query, setQuery } ) { } ) } /> + { categories?.terms?.length > 0 && ( + ( { + id: categoryId, + value: categories.mapById[ categoryId ].name, + } ) ) } + suggestions={ categories.names } + onChange={ onCategoriesChange } + /> + ) } + { tags?.terms?.length > 0 && ( + ( { + id: tagId, + value: tags.mapById[ tagId ].name, + } ) ) } + suggestions={ tags.names } + onChange={ onTagsChange } + /> + ) } + ); diff --git a/packages/block-library/src/query/edit/query-toolbar.js b/packages/block-library/src/query/edit/query-toolbar.js index 3436348975e240..5eb6c47d73a894 100644 --- a/packages/block-library/src/query/edit/query-toolbar.js +++ b/packages/block-library/src/query/edit/query-toolbar.js @@ -1,70 +1,21 @@ -/** - * External dependencies - */ -import { debounce } from 'lodash'; - /** * WordPress dependencies */ -import { useSelect } from '@wordpress/data'; -import { useEffect, useState, useCallback } from '@wordpress/element'; import { - Toolbar, + ToolbarGroup, Dropdown, ToolbarButton, RangeControl, - TextControl, - FormTokenField, + __experimentalNumberControl as NumberControl, } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { postList } from '@wordpress/icons'; -/** - * Internal dependencies - */ -import { getTermsInfo } from '../utils'; -import { MAX_FETCHED_TERMS } from '../constants'; - export default function QueryToolbar( { query, setQuery } ) { - const { categories, tags } = useSelect( ( select ) => { - const { getEntityRecords } = select( 'core' ); - const termsQuery = { per_page: MAX_FETCHED_TERMS }; - const _categories = getEntityRecords( - 'taxonomy', - 'category', - termsQuery - ); - const _tags = getEntityRecords( 'taxonomy', 'post_tag', termsQuery ); - return { - categories: getTermsInfo( _categories ), - tags: getTermsInfo( _tags ), - }; - }, [] ); - const [ querySearch, setQuerySearch ] = useState( query.search ); - const onChangeDebounced = useCallback( - debounce( () => setQuery( { search: querySearch } ), 250 ), - [ querySearch ] - ); - useEffect( () => { - onChangeDebounced(); - return onChangeDebounced.cancel; - }, [ querySearch, onChangeDebounced ] ); - - // Handles categories and tags changes. - const onTermsChange = ( terms, queryProperty ) => ( newTermValues ) => { - const termIds = newTermValues.reduce( ( accumulator, termValue ) => { - const termId = termValue?.id || terms.mapByName[ termValue ]?.id; - if ( termId ) accumulator.push( termId ); - return accumulator; - }, [] ); - setQuery( { [ queryProperty ]: termIds } ); - }; - const onCategoriesChange = onTermsChange( categories, 'categoryIds' ); - const onTagsChange = onTermsChange( tags, 'tagIds' ); - return ( - + ( ( <> - setQuery( { perPage: value ?? -1 } ) } + step="1" + value={ query.perPage } + /> + + setQuery( { offset: value } ) + } + step="1" + value={ query.offset } /> - - setQuery( { offset: value ?? 0 } ) - } - /> - { categories?.terms && ( - ( { - id: categoryId, - value: - categories.mapById[ categoryId ] - .name, - } ) - ) } - suggestions={ categories.names } - onChange={ onCategoriesChange } - /> - ) } - { tags?.terms && ( - ( { - id: tagId, - value: tags.mapById[ tagId ].name, - } ) - ) } - suggestions={ tags.names } - onChange={ onTagsChange } - /> - ) } - setQuerySearch( value ) } - /> ) } /> - + ); } diff --git a/packages/block-library/src/query/editor.scss b/packages/block-library/src/query/editor.scss index 90f58ba63a2f15..fe7eb85d9d9c0b 100644 --- a/packages/block-library/src/query/editor.scss +++ b/packages/block-library/src/query/editor.scss @@ -1,3 +1,13 @@ .editor-styles-wrapper .wp-block.wp-block-query { max-width: 100%; } + +.block-library-query-toolbar__popover { + .components-number-control { + justify-content: space-between; + margin-bottom: $grid-unit-10; + .components-input-control__container { + flex: 0 0 60px; + } + } +} From 984a810da88a2640d3c3dc932a5e6a97f2d02b29 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Mon, 28 Sep 2020 13:11:46 +0300 Subject: [PATCH 2/6] Change max fetched terms limit --- packages/block-library/src/query/constants.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/query/constants.js b/packages/block-library/src/query/constants.js index db1a244abf38dc..311232afe3adcc 100644 --- a/packages/block-library/src/query/constants.js +++ b/packages/block-library/src/query/constants.js @@ -1,4 +1,4 @@ -export const MAX_FETCHED_TERMS = -1; +export const MAX_FETCHED_TERMS = 100; export default { MAX_FETCHED_TERMS, From 392ba1d87a16eb9b8f9873650b8b1832e4033b7f Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Mon, 28 Sep 2020 17:29:29 +0300 Subject: [PATCH 3/6] get default posts_per_page from options --- lib/edit-site-page.php | 1 + packages/block-library/src/query/block.json | 2 +- packages/block-library/src/query/constants.js | 2 ++ packages/block-library/src/query/edit/index.js | 14 ++++++++++++++ .../block-library/src/query/edit/query-toolbar.js | 7 +++++-- .../e2e-tests/fixtures/blocks/core__query.json | 2 +- 6 files changed, 24 insertions(+), 4 deletions(-) diff --git a/lib/edit-site-page.php b/lib/edit-site-page.php index 689e628c6eeae7..204651e9002804 100644 --- a/lib/edit-site-page.php +++ b/lib/edit-site-page.php @@ -131,6 +131,7 @@ function gutenberg_edit_site_init( $hook ) { 'isRTL' => is_rtl(), 'maxUploadFileSize' => $max_upload_size, 'siteUrl' => site_url(), + 'postsPerPage' => get_option( 'posts_per_page'), ); $settings['styles'] = gutenberg_get_editor_styles(); diff --git a/packages/block-library/src/query/block.json b/packages/block-library/src/query/block.json index 63d489ad0d5525..3e6244bc67be91 100644 --- a/packages/block-library/src/query/block.json +++ b/packages/block-library/src/query/block.json @@ -8,7 +8,7 @@ "query": { "type": "object", "default": { - "perPage": 3, + "perPage": null, "pages": 1, "offset": 0, "categoryIds": [], diff --git a/packages/block-library/src/query/constants.js b/packages/block-library/src/query/constants.js index 311232afe3adcc..9f606c1c6920c3 100644 --- a/packages/block-library/src/query/constants.js +++ b/packages/block-library/src/query/constants.js @@ -1,5 +1,7 @@ export const MAX_FETCHED_TERMS = 100; +export const DEFAULTS_POSTS_PER_PAGE = 3; export default { MAX_FETCHED_TERMS, + DEFAULTS_POSTS_PER_PAGE, }; diff --git a/packages/block-library/src/query/edit/index.js b/packages/block-library/src/query/edit/index.js index e43c16074346d2..b0580889d5601c 100644 --- a/packages/block-library/src/query/edit/index.js +++ b/packages/block-library/src/query/edit/index.js @@ -1,6 +1,7 @@ /** * WordPress dependencies */ +import { useSelect } from '@wordpress/data'; import { useInstanceId } from '@wordpress/compose'; import { useEffect } from '@wordpress/element'; import { @@ -15,6 +16,7 @@ import { import QueryToolbar from './query-toolbar'; import QueryProvider from './query-provider'; import QueryInspectorControls from './query-inspector-controls'; +import { DEFAULTS_POSTS_PER_PAGE } from '../constants'; const TEMPLATE = [ [ 'core/query-loop' ], [ 'core/query-pagination' ] ]; export default function QueryEdit( { @@ -23,6 +25,18 @@ export default function QueryEdit( { } ) { const instanceId = useInstanceId( QueryEdit ); const blockWrapperProps = useBlockWrapperProps(); + const { postsPerPage } = useSelect( ( select ) => { + const { getSettings } = select( 'core/block-editor' ); + return { + postsPerPage: + +getSettings().postsPerPage || DEFAULTS_POSTS_PER_PAGE, + }; + }, [] ); + useEffect( () => { + if ( ! query.perPage && postsPerPage ) { + updateQuery( { perPage: postsPerPage } ); + } + }, [ query.perPage ] ); // We need this for multi-query block pagination. // Query parameters for each block are scoped to their ID. useEffect( () => { diff --git a/packages/block-library/src/query/edit/query-toolbar.js b/packages/block-library/src/query/edit/query-toolbar.js index 5eb6c47d73a894..63a25e2c199104 100644 --- a/packages/block-library/src/query/edit/query-toolbar.js +++ b/packages/block-library/src/query/edit/query-toolbar.js @@ -31,20 +31,23 @@ export default function QueryToolbar( { query, setQuery } ) { min={ 1 } max={ 100 } onChange={ ( value ) => - setQuery( { perPage: value ?? -1 } ) + setQuery( { perPage: +value ?? -1 } ) } step="1" value={ query.perPage } + isDragEnabled={ false } /> - setQuery( { offset: value } ) + setQuery( { offset: +value } ) } step="1" value={ query.offset } + isDragEnabled={ false } /> Date: Mon, 28 Sep 2020 18:36:17 +0300 Subject: [PATCH 4/6] fix php linting --- lib/edit-site-page.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/edit-site-page.php b/lib/edit-site-page.php index 204651e9002804..83089981f59756 100644 --- a/lib/edit-site-page.php +++ b/lib/edit-site-page.php @@ -131,7 +131,7 @@ function gutenberg_edit_site_init( $hook ) { 'isRTL' => is_rtl(), 'maxUploadFileSize' => $max_upload_size, 'siteUrl' => site_url(), - 'postsPerPage' => get_option( 'posts_per_page'), + 'postsPerPage' => get_option( 'posts_per_page' ), ); $settings['styles'] = gutenberg_get_editor_styles(); From 3860267f4d3d6848e3a605ee418f6592a780d171 Mon Sep 17 00:00:00 2001 From: Jon Q Date: Mon, 28 Sep 2020 11:42:57 -0400 Subject: [PATCH 5/6] Update InputControl to align label/control to the edges and have custom widths. --- .../test/__snapshots__/index.js.snap | 2 +- .../src/components/unit-control/README.md | 2 +- .../src/query/edit/query-toolbar.js | 75 +++++++++++-------- packages/block-library/src/query/editor.scss | 10 --- .../components/src/input-control/README.md | 2 +- .../components/src/input-control/index.js | 2 + .../src/input-control/input-base.js | 5 ++ .../styles/input-control-styles.js | 46 +++++++----- .../components/src/number-control/README.md | 2 +- .../components/src/unit-control/README.md | 2 +- 10 files changed, 82 insertions(+), 66 deletions(-) diff --git a/packages/block-editor/src/components/responsive-block-control/test/__snapshots__/index.js.snap b/packages/block-editor/src/components/responsive-block-control/test/__snapshots__/index.js.snap index e0233344f6352d..08c0a5a88f75b6 100644 --- a/packages/block-editor/src/components/responsive-block-control/test/__snapshots__/index.js.snap +++ b/packages/block-editor/src/components/responsive-block-control/test/__snapshots__/index.js.snap @@ -1,3 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Basic rendering should render with required props 1`] = `"
Padding

Toggle between using the same value for all screen sizes or using a unique value per screen size.

All is used here for testing purposes to ensure we have access to details about the device.

"`; +exports[`Basic rendering should render with required props 1`] = `"
Padding

Toggle between using the same value for all screen sizes or using a unique value per screen size.

All is used here for testing purposes to ensure we have access to details about the device.

"`; diff --git a/packages/block-editor/src/components/unit-control/README.md b/packages/block-editor/src/components/unit-control/README.md index 89e66b7f3a444d..4d99d85254decb 100644 --- a/packages/block-editor/src/components/unit-control/README.md +++ b/packages/block-editor/src/components/unit-control/README.md @@ -71,7 +71,7 @@ If this property is added, a label will be generated using label property as the #### labelPosition -The position of the label (`top`, `side`, or `bottom`). +The position of the label (`top`, `side`, `bottom`, or `edge`). - Type: `String` - Required: No diff --git a/packages/block-library/src/query/edit/query-toolbar.js b/packages/block-library/src/query/edit/query-toolbar.js index 63a25e2c199104..8d519befd697c1 100644 --- a/packages/block-library/src/query/edit/query-toolbar.js +++ b/packages/block-library/src/query/edit/query-toolbar.js @@ -6,6 +6,7 @@ import { Dropdown, ToolbarButton, RangeControl, + BaseControl, __experimentalNumberControl as NumberControl, } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; @@ -25,39 +26,47 @@ export default function QueryToolbar( { query, setQuery } ) { ) } renderContent={ () => ( <> - - setQuery( { perPage: +value ?? -1 } ) - } - step="1" - value={ query.perPage } - isDragEnabled={ false } - /> - - setQuery( { offset: +value } ) - } - step="1" - value={ query.offset } - isDragEnabled={ false } - /> - - setQuery( { pages: value ?? -1 } ) - } - /> + + + setQuery( { perPage: +value ?? -1 } ) + } + step="1" + value={ query.perPage } + isDragEnabled={ false } + /> + + + + setQuery( { offset: +value } ) + } + step="1" + value={ query.offset } + isDragEnabled={ false } + /> + + + + setQuery( { pages: value ?? -1 } ) + } + /> + ) } /> diff --git a/packages/block-library/src/query/editor.scss b/packages/block-library/src/query/editor.scss index fe7eb85d9d9c0b..90f58ba63a2f15 100644 --- a/packages/block-library/src/query/editor.scss +++ b/packages/block-library/src/query/editor.scss @@ -1,13 +1,3 @@ .editor-styles-wrapper .wp-block.wp-block-query { max-width: 100%; } - -.block-library-query-toolbar__popover { - .components-number-control { - justify-content: space-between; - margin-bottom: $grid-unit-10; - .components-input-control__container { - flex: 0 0 60px; - } - } -} diff --git a/packages/components/src/input-control/README.md b/packages/components/src/input-control/README.md index 6af3626a09f1dd..fef516a7a3f187 100644 --- a/packages/components/src/input-control/README.md +++ b/packages/components/src/input-control/README.md @@ -54,7 +54,7 @@ If this property is added, a label will be generated using label property as the ### labelPosition -The position of the label (`top`, `side`, or `bottom`). +The position of the label (`top`, `side`, `bottom`, or `edge`). - Type: `String` - Required: No diff --git a/packages/components/src/input-control/index.js b/packages/components/src/input-control/index.js index bd6cb82d8be982..86d58484d9abfd 100644 --- a/packages/components/src/input-control/index.js +++ b/packages/components/src/input-control/index.js @@ -26,6 +26,7 @@ function useUniqueId( idProp ) { export function InputControl( { __unstableStateReducer: stateReducer = ( state ) => state, + __unstableInputWidth, className, disabled = false, hideLabelFromVision = false, @@ -63,6 +64,7 @@ export function InputControl( return ( @@ -60,9 +63,11 @@ export function InputBase( { prefix && ( diff --git a/packages/components/src/input-control/styles/input-control-styles.js b/packages/components/src/input-control/styles/input-control-styles.js index cd57f1ef4ca308..ca48b2d32d7ace 100644 --- a/packages/components/src/input-control/styles/input-control-styles.js +++ b/packages/components/src/input-control/styles/input-control-styles.js @@ -33,6 +33,10 @@ const rootLabelPositionStyles = ( { labelPosition } ) => { align-items: flex-start; flex-direction: column-reverse; `; + case 'edge': + return css` + justify-content: space-between; + `; default: return ''; } @@ -42,9 +46,9 @@ export const Root = styled( Flex )` position: relative; border-radius: 2px; - ${ rootFloatLabelStyles }; - ${ rootFocusedStyles }; - ${ rootLabelPositionStyles }; + ${ rootFloatLabelStyles } + ${ rootFocusedStyles } + ${ rootLabelPositionStyles } `; const containerDisabledStyles = ( { disabled } ) => { @@ -55,12 +59,18 @@ const containerDisabledStyles = ( { disabled } ) => { return css( { backgroundColor } ); }; -const containerWidthStyles = ( { labelPosition } ) => { +const containerWidthStyles = ( { __unstableInputWidth, labelPosition } ) => { + if ( ! __unstableInputWidth ) return css( { width: '100%' } ); + if ( labelPosition === 'side' ) return ''; - return css` - width: 100%; - `; + if ( labelPosition === 'edge' ) { + return css( { + flex: `0 0 ${ __unstableInputWidth }`, + } ); + } + + return css( { width: __unstableInputWidth } ); }; export const Container = styled.div` @@ -71,8 +81,8 @@ export const Container = styled.div` flex: 1; position: relative; - ${ containerDisabledStyles }; - ${ containerWidthStyles }; + ${ containerDisabledStyles } + ${ containerWidthStyles } `; const disabledStyles = ( { disabled } ) => { @@ -156,8 +166,8 @@ const dragStyles = ( { isDragging, dragCursor } ) => { } return css` - ${ defaultArrowStyles }; - ${ activeDragCursorStyles }; + ${ defaultArrowStyles } + ${ activeDragCursorStyles } `; }; @@ -178,12 +188,12 @@ export const Input = styled.input` padding-right: 8px; width: 100%; - ${ dragStyles }; - ${ disabledStyles }; - ${ fontSizeStyles }; - ${ sizeStyles }; + ${ dragStyles } + ${ disabledStyles } + ${ fontSizeStyles } + ${ sizeStyles } - ${ placeholderStyles }; + ${ placeholderStyles } } `; @@ -206,7 +216,7 @@ const BaseLabel = styled( Text )` padding-top: 0; z-index: 1; - ${ labelTruncation }; + ${ labelTruncation } } `; @@ -252,7 +262,7 @@ export const BackdropUI = styled.div` right: 0; top: 0; - ${ backdropFocusedStyles }; + ${ backdropFocusedStyles } ${ rtl( { paddingLeft: 2 } ) } } `; diff --git a/packages/components/src/number-control/README.md b/packages/components/src/number-control/README.md index 36b21f63a40a83..efb77dd18a40a8 100644 --- a/packages/components/src/number-control/README.md +++ b/packages/components/src/number-control/README.md @@ -72,7 +72,7 @@ If this property is added, a label will be generated using label property as the ### labelPosition -The position of the label (`top`, `side`, or `bottom`). +The position of the label (`top`, `side`, `bottom`, or `edge`). - Type: `String` - Required: No diff --git a/packages/components/src/unit-control/README.md b/packages/components/src/unit-control/README.md index ad60d0abd445ca..b024e6aaf5e5ee 100644 --- a/packages/components/src/unit-control/README.md +++ b/packages/components/src/unit-control/README.md @@ -50,7 +50,7 @@ If this property is added, a label will be generated using label property as the ### labelPosition -The position of the label (`top`, `side`, or `bottom`). +The position of the label (`top`, `side`, `bottom`, or `edge`). - Type: `String` - Required: No From ee5b1ab23fbd846477eb2547c3242d4828b283d6 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Tue, 29 Sep 2020 12:26:09 +0300 Subject: [PATCH 6/6] fallback for undefined categoryIds --- .../src/query/edit/query-inspector-controls.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/block-library/src/query/edit/query-inspector-controls.js b/packages/block-library/src/query/edit/query-inspector-controls.js index c210f87a92f84f..632a80ce4a4c26 100644 --- a/packages/block-library/src/query/edit/query-inspector-controls.js +++ b/packages/block-library/src/query/edit/query-inspector-controls.js @@ -81,10 +81,12 @@ export default function QueryInspectorControls( { query, setQuery } ) { { categories?.terms?.length > 0 && ( ( { - id: categoryId, - value: categories.mapById[ categoryId ].name, - } ) ) } + value={ ( query.categoryIds || [] ).map( + ( categoryId ) => ( { + id: categoryId, + value: categories.mapById[ categoryId ].name, + } ) + ) } suggestions={ categories.names } onChange={ onCategoriesChange } />