From 3cd8056dd9778936714d44bc4d5464bb26e53ae7 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 4 Oct 2023 11:58:50 +1300 Subject: [PATCH 01/17] Add category selector to pattern creation modal --- .../src/components/category-selector.js | 70 +++++++++++++++++-- .../src/components/create-pattern-modal.js | 9 ++- 2 files changed, 69 insertions(+), 10 deletions(-) diff --git a/packages/patterns/src/components/category-selector.js b/packages/patterns/src/components/category-selector.js index 397d851d3886b9..745892e2441622 100644 --- a/packages/patterns/src/components/category-selector.js +++ b/packages/patterns/src/components/category-selector.js @@ -3,9 +3,10 @@ */ import { __ } from '@wordpress/i18n'; import { useMemo, useState } from '@wordpress/element'; -import { FormTokenField } from '@wordpress/components'; +import { FormTokenField, SelectControl } from '@wordpress/components'; import { useSelect } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; +import { store as blockEditorStore } from '@wordpress/block-editor'; import { useDebounce } from '@wordpress/compose'; import { decodeEntities } from '@wordpress/html-entities'; @@ -22,7 +23,12 @@ const DEFAULT_QUERY = { }; export const CATEGORY_SLUG = 'wp_pattern_category'; -export default function CategorySelector( { values, onChange } ) { +export default function CategorySelector( { + selectedCategoryValue, + newCategoryValues, + onChangeNewCategories, + onChangeSelectedCategory, +} ) { const [ search, setSearch ] = useState( '' ); const debouncedSearch = useDebounce( setSearch, 500 ); @@ -42,13 +48,51 @@ export default function CategorySelector( { values, onChange } ) { [ search ] ); + const { corePatternCategories, userPatternCategories } = useSelect( + ( select ) => { + const { getSettings } = select( blockEditorStore ); + const { getUserPatternCategories } = select( coreStore ); + + return { + corePatternCategories: + getSettings().__experimentalBlockPatternCategories, + userPatternCategories: getUserPatternCategories(), + }; + } + ); + + const categoryOptions = userPatternCategories.map( ( category ) => ( { + label: category.label, + value: category.label, + } ) ); + + corePatternCategories.forEach( ( category ) => { + if ( + ! categoryOptions.find( ( cat ) => cat.label === category.label ) && + category.name !== 'query' + ) { + categoryOptions.push( { + label: category.label, + value: category.label, + } ); + } + } ); + + categoryOptions.unshift( { + value: '', + label: __( 'Select a category' ), + disabled: true, + } ); + + categoryOptions.sort( ( a, b ) => a.label.localeCompare( b.label ) ); + const suggestions = useMemo( () => { return ( searchResults ?? [] ).map( ( term ) => unescapeString( term.name ) ); }, [ searchResults ] ); - function handleChange( termNames ) { + function handleChangeAdd( termNames ) { const uniqueTerms = termNames.reduce( ( terms, newTerm ) => { if ( ! terms.some( @@ -60,19 +104,31 @@ export default function CategorySelector( { values, onChange } ) { return terms; }, [] ); - onChange( uniqueTerms ); + onChangeNewCategories( uniqueTerms ); + } + + function handleOnChangeSelect( selectedCategory ) { + onChangeSelectedCategory( selectedCategory ); } return ( <> + + diff --git a/packages/patterns/src/components/create-pattern-modal.js b/packages/patterns/src/components/create-pattern-modal.js index 531936da5e5c28..2ff3beaf6ec1d8 100644 --- a/packages/patterns/src/components/create-pattern-modal.js +++ b/packages/patterns/src/components/create-pattern-modal.js @@ -36,6 +36,7 @@ export default function CreatePatternModal( { } ) { const [ syncType, setSyncType ] = useState( PATTERN_SYNC_TYPES.full ); const [ categoryTerms, setCategoryTerms ] = useState( [] ); + const [ selectedCategory, setSelectedCategory ] = useState( '' ); const [ title, setTitle ] = useState( '' ); const [ isSaving, setIsSaving ] = useState( false ); const { createPattern } = unlock( useDispatch( patternsStore ) ); @@ -50,7 +51,7 @@ export default function CreatePatternModal( { try { setIsSaving( true ); const categories = await Promise.all( - categoryTerms.map( ( termName ) => + [ ...categoryTerms, selectedCategory ].map( ( termName ) => findOrCreateTerm( termName ) ) ); @@ -126,8 +127,10 @@ export default function CreatePatternModal( { className="patterns-create-modal__name-input" /> Date: Wed, 4 Oct 2023 13:30:55 +1300 Subject: [PATCH 02/17] Switch to adding categories to the form token suggestion list --- .../src/components/category-selector.js | 91 +++++-------------- .../src/components/create-pattern-modal.js | 9 +- packages/patterns/src/components/style.scss | 8 ++ 3 files changed, 36 insertions(+), 72 deletions(-) diff --git a/packages/patterns/src/components/category-selector.js b/packages/patterns/src/components/category-selector.js index 745892e2441622..2c1d3035687a73 100644 --- a/packages/patterns/src/components/category-selector.js +++ b/packages/patterns/src/components/category-selector.js @@ -3,7 +3,7 @@ */ import { __ } from '@wordpress/i18n'; import { useMemo, useState } from '@wordpress/element'; -import { FormTokenField, SelectControl } from '@wordpress/components'; +import { FormTokenField } from '@wordpress/components'; import { useSelect } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; import { store as blockEditorStore } from '@wordpress/block-editor'; @@ -14,40 +14,12 @@ const unescapeString = ( arg ) => { return decodeEntities( arg ); }; -const EMPTY_ARRAY = []; -const MAX_TERMS_SUGGESTIONS = 20; -const DEFAULT_QUERY = { - per_page: MAX_TERMS_SUGGESTIONS, - _fields: 'id,name', - context: 'view', -}; export const CATEGORY_SLUG = 'wp_pattern_category'; -export default function CategorySelector( { - selectedCategoryValue, - newCategoryValues, - onChangeNewCategories, - onChangeSelectedCategory, -} ) { +export default function CategorySelector( { categoryValues, onChange } ) { const [ search, setSearch ] = useState( '' ); const debouncedSearch = useDebounce( setSearch, 500 ); - const { searchResults } = useSelect( - ( select ) => { - const { getEntityRecords } = select( coreStore ); - - return { - searchResults: !! search - ? getEntityRecords( 'taxonomy', CATEGORY_SLUG, { - ...DEFAULT_QUERY, - search, - } ) - : EMPTY_ARRAY, - }; - }, - [ search ] - ); - const { corePatternCategories, userPatternCategories } = useSelect( ( select ) => { const { getSettings } = select( blockEditorStore ); @@ -78,21 +50,22 @@ export default function CategorySelector( { } } ); - categoryOptions.unshift( { - value: '', - label: __( 'Select a category' ), - disabled: true, - } ); - categoryOptions.sort( ( a, b ) => a.label.localeCompare( b.label ) ); const suggestions = useMemo( () => { - return ( searchResults ?? [] ).map( ( term ) => - unescapeString( term.name ) - ); - }, [ searchResults ] ); + return ( categoryOptions ?? [] ) + .map( ( category ) => unescapeString( category.label ) ) + .filter( ( category ) => { + if ( search !== '' ) { + return category + .toLowerCase() + .includes( search.toLowerCase() ); + } + return true; + } ); + }, [ search, categoryOptions ] ); - function handleChangeAdd( termNames ) { + function handleChange( termNames ) { const uniqueTerms = termNames.reduce( ( terms, newTerm ) => { if ( ! terms.some( @@ -104,33 +77,19 @@ export default function CategorySelector( { return terms; }, [] ); - onChangeNewCategories( uniqueTerms ); - } - - function handleOnChangeSelect( selectedCategory ) { - onChangeSelectedCategory( selectedCategory ); + onChange( uniqueTerms ); } return ( - <> - - - - + ); } diff --git a/packages/patterns/src/components/create-pattern-modal.js b/packages/patterns/src/components/create-pattern-modal.js index 2ff3beaf6ec1d8..f676b49cedde4d 100644 --- a/packages/patterns/src/components/create-pattern-modal.js +++ b/packages/patterns/src/components/create-pattern-modal.js @@ -36,7 +36,6 @@ export default function CreatePatternModal( { } ) { const [ syncType, setSyncType ] = useState( PATTERN_SYNC_TYPES.full ); const [ categoryTerms, setCategoryTerms ] = useState( [] ); - const [ selectedCategory, setSelectedCategory ] = useState( '' ); const [ title, setTitle ] = useState( '' ); const [ isSaving, setIsSaving ] = useState( false ); const { createPattern } = unlock( useDispatch( patternsStore ) ); @@ -51,7 +50,7 @@ export default function CreatePatternModal( { try { setIsSaving( true ); const categories = await Promise.all( - [ ...categoryTerms, selectedCategory ].map( ( termName ) => + categoryTerms.map( ( termName ) => findOrCreateTerm( termName ) ) ); @@ -127,10 +126,8 @@ export default function CreatePatternModal( { className="patterns-create-modal__name-input" /> Date: Wed, 4 Oct 2023 13:36:12 +1300 Subject: [PATCH 03/17] tidy up variable naming --- packages/patterns/src/components/category-selector.js | 4 ++-- packages/patterns/src/components/create-pattern-modal.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/patterns/src/components/category-selector.js b/packages/patterns/src/components/category-selector.js index 2c1d3035687a73..4548368a24e23e 100644 --- a/packages/patterns/src/components/category-selector.js +++ b/packages/patterns/src/components/category-selector.js @@ -16,7 +16,7 @@ const unescapeString = ( arg ) => { export const CATEGORY_SLUG = 'wp_pattern_category'; -export default function CategorySelector( { categoryValues, onChange } ) { +export default function CategorySelector( { categoryTerms, onChange } ) { const [ search, setSearch ] = useState( '' ); const debouncedSearch = useDebounce( setSearch, 500 ); @@ -83,7 +83,7 @@ export default function CategorySelector( { categoryValues, onChange } ) { return ( Date: Wed, 4 Oct 2023 14:53:56 +1300 Subject: [PATCH 04/17] Make sure the slugs used in taxonomy match those used in core pattern categories --- .../src/components/category-selector.js | 41 ++------------ .../src/components/create-pattern-modal.js | 54 +++++++++++++++++-- 2 files changed, 56 insertions(+), 39 deletions(-) diff --git a/packages/patterns/src/components/category-selector.js b/packages/patterns/src/components/category-selector.js index 4548368a24e23e..e2bc68449662f9 100644 --- a/packages/patterns/src/components/category-selector.js +++ b/packages/patterns/src/components/category-selector.js @@ -4,9 +4,6 @@ import { __ } from '@wordpress/i18n'; import { useMemo, useState } from '@wordpress/element'; import { FormTokenField } from '@wordpress/components'; -import { useSelect } from '@wordpress/data'; -import { store as coreStore } from '@wordpress/core-data'; -import { store as blockEditorStore } from '@wordpress/block-editor'; import { useDebounce } from '@wordpress/compose'; import { decodeEntities } from '@wordpress/html-entities'; @@ -16,42 +13,14 @@ const unescapeString = ( arg ) => { export const CATEGORY_SLUG = 'wp_pattern_category'; -export default function CategorySelector( { categoryTerms, onChange } ) { +export default function CategorySelector( { + categoryTerms, + onChange, + categoryOptions, +} ) { const [ search, setSearch ] = useState( '' ); const debouncedSearch = useDebounce( setSearch, 500 ); - const { corePatternCategories, userPatternCategories } = useSelect( - ( select ) => { - const { getSettings } = select( blockEditorStore ); - const { getUserPatternCategories } = select( coreStore ); - - return { - corePatternCategories: - getSettings().__experimentalBlockPatternCategories, - userPatternCategories: getUserPatternCategories(), - }; - } - ); - - const categoryOptions = userPatternCategories.map( ( category ) => ( { - label: category.label, - value: category.label, - } ) ); - - corePatternCategories.forEach( ( category ) => { - if ( - ! categoryOptions.find( ( cat ) => cat.label === category.label ) && - category.name !== 'query' - ) { - categoryOptions.push( { - label: category.label, - value: category.label, - } ); - } - } ); - - categoryOptions.sort( ( a, b ) => a.label.localeCompare( b.label ) ); - const suggestions = useMemo( () => { return ( categoryOptions ?? [] ) .map( ( category ) => unescapeString( category.label ) ) diff --git a/packages/patterns/src/components/create-pattern-modal.js b/packages/patterns/src/components/create-pattern-modal.js index 810ddfbd7e2a63..d001911bba6890 100644 --- a/packages/patterns/src/components/create-pattern-modal.js +++ b/packages/patterns/src/components/create-pattern-modal.js @@ -10,10 +10,11 @@ import { ToggleControl, } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { useState } from '@wordpress/element'; -import { useDispatch } from '@wordpress/data'; +import { useState, useMemo } from '@wordpress/element'; +import { useDispatch, useSelect } from '@wordpress/data'; import { store as noticesStore } from '@wordpress/notices'; import { store as coreStore } from '@wordpress/core-data'; +import { store as blockEditorStore } from '@wordpress/block-editor'; /** * Internal dependencies @@ -42,6 +43,44 @@ export default function CreatePatternModal( { const { saveEntityRecord, invalidateResolution } = useDispatch( coreStore ); const { createErrorNotice } = useDispatch( noticesStore ); + const { corePatternCategories, userPatternCategories } = useSelect( + ( select ) => { + const { getSettings } = select( blockEditorStore ); + const { getUserPatternCategories } = select( coreStore ); + + return { + corePatternCategories: + getSettings().__experimentalBlockPatternCategories, + userPatternCategories: getUserPatternCategories(), + }; + } + ); + + const categoryOptions = useMemo( () => { + // We need to store the name separately as this is used as the slug in the + // taxonomy and may vary from the label. + const categories = userPatternCategories.map( ( category ) => ( { + label: category.label, + value: category.label, + name: category.name, + } ) ); + + corePatternCategories.forEach( ( category ) => { + if ( + ! categories.find( ( cat ) => cat.label === category.label ) && + category.name !== 'query' + ) { + categories.push( { + label: category.label, + value: category.label, + name: category.name, + } ); + } + } ); + + return categories.sort( ( a, b ) => a.label.localeCompare( b.label ) ); + }, [ userPatternCategories, corePatternCategories ] ); + async function onCreate( patternTitle, sync ) { if ( ! title || isSaving ) { return; @@ -84,10 +123,18 @@ export default function CreatePatternModal( { */ async function findOrCreateTerm( term ) { try { + // We need to match any existing term to the correct slug to prevent duplicates, eg. + // the core `Headers` category uses a the singular `header` as the slug. + const existingTerm = categoryOptions.find( + ( cat ) => cat.label === term + ); + const termData = existingTerm + ? { name: existingTerm.label, slug: existingTerm.name } + : { name: term }; const newTerm = await saveEntityRecord( 'taxonomy', CATEGORY_SLUG, - { name: term }, + termData, { throwOnError: true } ); invalidateResolution( 'getUserPatternCategories' ); @@ -128,6 +175,7 @@ export default function CreatePatternModal( { Date: Wed, 4 Oct 2023 15:36:13 +1300 Subject: [PATCH 05/17] Get categories from core store --- packages/patterns/src/components/create-pattern-modal.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/patterns/src/components/create-pattern-modal.js b/packages/patterns/src/components/create-pattern-modal.js index d001911bba6890..024badbbbc7f49 100644 --- a/packages/patterns/src/components/create-pattern-modal.js +++ b/packages/patterns/src/components/create-pattern-modal.js @@ -14,7 +14,6 @@ import { useState, useMemo } from '@wordpress/element'; import { useDispatch, useSelect } from '@wordpress/data'; import { store as noticesStore } from '@wordpress/notices'; import { store as coreStore } from '@wordpress/core-data'; -import { store as blockEditorStore } from '@wordpress/block-editor'; /** * Internal dependencies @@ -45,12 +44,11 @@ export default function CreatePatternModal( { const { corePatternCategories, userPatternCategories } = useSelect( ( select ) => { - const { getSettings } = select( blockEditorStore ); - const { getUserPatternCategories } = select( coreStore ); + const { getUserPatternCategories, getBlockPatternCategories } = + select( coreStore ); return { - corePatternCategories: - getSettings().__experimentalBlockPatternCategories, + corePatternCategories: getBlockPatternCategories(), userPatternCategories: getUserPatternCategories(), }; } From ee676d6e0bca360c3b0cb4799f7cc09de3e829fc Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 4 Oct 2023 16:20:54 +1300 Subject: [PATCH 06/17] Fix label --- packages/patterns/src/components/category-selector.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/patterns/src/components/category-selector.js b/packages/patterns/src/components/category-selector.js index e2bc68449662f9..c8ccf8f96bc5cb 100644 --- a/packages/patterns/src/components/category-selector.js +++ b/packages/patterns/src/components/category-selector.js @@ -56,7 +56,7 @@ export default function CategorySelector( { suggestions={ suggestions } onChange={ handleChange } onInputChange={ debouncedSearch } - label={ __( 'Category' ) } + label={ __( 'Categories' ) } tokenizeOnBlur={ true } __experimentalExpandOnFocus={ true } /> From 232772acc4aa8d65451969eb7378b3983e875689 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 4 Oct 2023 16:34:56 +1300 Subject: [PATCH 07/17] Simplify the merging of the categories. --- .../src/components/create-pattern-modal.js | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/packages/patterns/src/components/create-pattern-modal.js b/packages/patterns/src/components/create-pattern-modal.js index 024badbbbc7f49..5d9e72b4a56384 100644 --- a/packages/patterns/src/components/create-pattern-modal.js +++ b/packages/patterns/src/components/create-pattern-modal.js @@ -55,26 +55,28 @@ export default function CreatePatternModal( { ); const categoryOptions = useMemo( () => { - // We need to store the name separately as this is used as the slug in the - // taxonomy and may vary from the label. - const categories = userPatternCategories.map( ( category ) => ( { - label: category.label, - value: category.label, - name: category.name, - } ) ); - - corePatternCategories.forEach( ( category ) => { + // Merge the user and core pattern categories and remove any duplicates. + const categories = [ + ...userPatternCategories, + ...corePatternCategories, + ].reduce( ( uniqueCategories, category ) => { if ( - ! categories.find( ( cat ) => cat.label === category.label ) && + ! uniqueCategories.find( + ( existingCategory ) => + existingCategory.label === category.label + ) && category.name !== 'query' ) { - categories.push( { + // We need to store the name separately as this is used as the slug in the + // taxonomy and may vary from the label. + uniqueCategories.push( { label: category.label, value: category.label, name: category.name, } ); } - } ); + return uniqueCategories; + }, [] ); return categories.sort( ( a, b ) => a.label.localeCompare( b.label ) ); }, [ userPatternCategories, corePatternCategories ] ); From 3945d70dccdea04395f3a981be0a1e79c8545bbb Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 4 Oct 2023 16:58:45 +1300 Subject: [PATCH 08/17] Explain removal of the query slug category --- packages/patterns/src/components/create-pattern-modal.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/patterns/src/components/create-pattern-modal.js b/packages/patterns/src/components/create-pattern-modal.js index 5d9e72b4a56384..7d98ed64b12180 100644 --- a/packages/patterns/src/components/create-pattern-modal.js +++ b/packages/patterns/src/components/create-pattern-modal.js @@ -65,6 +65,8 @@ export default function CreatePatternModal( { ( existingCategory ) => existingCategory.label === category.label ) && + // There are two core categories with `Post` label so explictily remove the one with + // the `query` slug to avoid any confusion. category.name !== 'query' ) { // We need to store the name separately as this is used as the slug in the From 3817dbe20823a82cf8d7413b5fb2c03eb028e601 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Wed, 4 Oct 2023 17:03:50 +1300 Subject: [PATCH 09/17] fix comment typo --- packages/patterns/src/components/create-pattern-modal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/patterns/src/components/create-pattern-modal.js b/packages/patterns/src/components/create-pattern-modal.js index 7d98ed64b12180..4bbe96920e7e5f 100644 --- a/packages/patterns/src/components/create-pattern-modal.js +++ b/packages/patterns/src/components/create-pattern-modal.js @@ -126,7 +126,7 @@ export default function CreatePatternModal( { async function findOrCreateTerm( term ) { try { // We need to match any existing term to the correct slug to prevent duplicates, eg. - // the core `Headers` category uses a the singular `header` as the slug. + // the core `Headers` category uses the singular `header` as the slug. const existingTerm = categoryOptions.find( ( cat ) => cat.label === term ); From 18c49a4719acaa9fbfb0703fc211fd84cbbe9018 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Thu, 5 Oct 2023 17:31:12 +1300 Subject: [PATCH 10/17] Switch to using a map instead of an array for storing categories --- .../src/components/category-selector.js | 9 +++++---- .../src/components/create-pattern-modal.js | 19 +++++++------------ 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/packages/patterns/src/components/category-selector.js b/packages/patterns/src/components/category-selector.js index c8ccf8f96bc5cb..14b84d30a88091 100644 --- a/packages/patterns/src/components/category-selector.js +++ b/packages/patterns/src/components/category-selector.js @@ -16,13 +16,13 @@ export const CATEGORY_SLUG = 'wp_pattern_category'; export default function CategorySelector( { categoryTerms, onChange, - categoryOptions, + categoryMap, } ) { const [ search, setSearch ] = useState( '' ); const debouncedSearch = useDebounce( setSearch, 500 ); const suggestions = useMemo( () => { - return ( categoryOptions ?? [] ) + return ( Array.from( categoryMap.values() ) ?? [] ) .map( ( category ) => unescapeString( category.label ) ) .filter( ( category ) => { if ( search !== '' ) { @@ -31,8 +31,9 @@ export default function CategorySelector( { .includes( search.toLowerCase() ); } return true; - } ); - }, [ search, categoryOptions ] ); + } ) + .sort( ( a, b ) => a.localeCompare( b ) ); + }, [ search, categoryMap ] ); function handleChange( termNames ) { const uniqueTerms = termNames.reduce( ( terms, newTerm ) => { diff --git a/packages/patterns/src/components/create-pattern-modal.js b/packages/patterns/src/components/create-pattern-modal.js index 4bbe96920e7e5f..37df7cd876d2d0 100644 --- a/packages/patterns/src/components/create-pattern-modal.js +++ b/packages/patterns/src/components/create-pattern-modal.js @@ -54,33 +54,30 @@ export default function CreatePatternModal( { } ); - const categoryOptions = useMemo( () => { + const categoryMap = useMemo( () => { // Merge the user and core pattern categories and remove any duplicates. const categories = [ ...userPatternCategories, ...corePatternCategories, ].reduce( ( uniqueCategories, category ) => { if ( - ! uniqueCategories.find( - ( existingCategory ) => - existingCategory.label === category.label - ) && + ! uniqueCategories.get( category.label ) && // There are two core categories with `Post` label so explictily remove the one with // the `query` slug to avoid any confusion. category.name !== 'query' ) { // We need to store the name separately as this is used as the slug in the // taxonomy and may vary from the label. - uniqueCategories.push( { + uniqueCategories.set( category.label, { label: category.label, value: category.label, name: category.name, } ); } return uniqueCategories; - }, [] ); + }, new Map() ); - return categories.sort( ( a, b ) => a.label.localeCompare( b.label ) ); + return categories; }, [ userPatternCategories, corePatternCategories ] ); async function onCreate( patternTitle, sync ) { @@ -127,9 +124,7 @@ export default function CreatePatternModal( { try { // We need to match any existing term to the correct slug to prevent duplicates, eg. // the core `Headers` category uses the singular `header` as the slug. - const existingTerm = categoryOptions.find( - ( cat ) => cat.label === term - ); + const existingTerm = categoryMap.get( term ); const termData = existingTerm ? { name: existingTerm.label, slug: existingTerm.name } : { name: term }; @@ -177,7 +172,7 @@ export default function CreatePatternModal( { Date: Thu, 5 Oct 2023 17:38:47 +1300 Subject: [PATCH 11/17] switch to map has instead of get --- packages/patterns/src/components/create-pattern-modal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/patterns/src/components/create-pattern-modal.js b/packages/patterns/src/components/create-pattern-modal.js index 37df7cd876d2d0..3d47e3b17c0730 100644 --- a/packages/patterns/src/components/create-pattern-modal.js +++ b/packages/patterns/src/components/create-pattern-modal.js @@ -61,7 +61,7 @@ export default function CreatePatternModal( { ...corePatternCategories, ].reduce( ( uniqueCategories, category ) => { if ( - ! uniqueCategories.get( category.label ) && + ! uniqueCategories.has( category.label ) && // There are two core categories with `Post` label so explictily remove the one with // the `query` slug to avoid any confusion. category.name !== 'query' From a200196a7d4a4682a14d94fb5a37e054fc8e2fdb Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Thu, 5 Oct 2023 19:04:16 +1300 Subject: [PATCH 12/17] Use a forEach instead of a reduce --- .../src/components/create-pattern-modal.js | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/packages/patterns/src/components/create-pattern-modal.js b/packages/patterns/src/components/create-pattern-modal.js index 3d47e3b17c0730..abf742d08ac918 100644 --- a/packages/patterns/src/components/create-pattern-modal.js +++ b/packages/patterns/src/components/create-pattern-modal.js @@ -56,28 +56,26 @@ export default function CreatePatternModal( { const categoryMap = useMemo( () => { // Merge the user and core pattern categories and remove any duplicates. - const categories = [ - ...userPatternCategories, - ...corePatternCategories, - ].reduce( ( uniqueCategories, category ) => { - if ( - ! uniqueCategories.has( category.label ) && - // There are two core categories with `Post` label so explictily remove the one with - // the `query` slug to avoid any confusion. - category.name !== 'query' - ) { - // We need to store the name separately as this is used as the slug in the - // taxonomy and may vary from the label. - uniqueCategories.set( category.label, { - label: category.label, - value: category.label, - name: category.name, - } ); + const uniqueCategories = new Map(); + [ ...userPatternCategories, ...corePatternCategories ].forEach( + ( category ) => { + if ( + ! uniqueCategories.has( category.label ) && + // There are two core categories with `Post` label so explictily remove the one with + // the `query` slug to avoid any confusion. + category.name !== 'query' + ) { + // We need to store the name separately as this is used as the slug in the + // taxonomy and may vary from the label. + uniqueCategories.set( category.label, { + label: category.label, + value: category.label, + name: category.name, + } ); + } } - return uniqueCategories; - }, new Map() ); - - return categories; + ); + return uniqueCategories; }, [ userPatternCategories, corePatternCategories ] ); async function onCreate( patternTitle, sync ) { From 7815d52b01c0ccc761191613ad0fa8edb0b4b1b5 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Thu, 5 Oct 2023 19:10:48 +1300 Subject: [PATCH 13/17] Fix typo --- packages/patterns/src/components/create-pattern-modal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/patterns/src/components/create-pattern-modal.js b/packages/patterns/src/components/create-pattern-modal.js index abf742d08ac918..37dd725ef9226a 100644 --- a/packages/patterns/src/components/create-pattern-modal.js +++ b/packages/patterns/src/components/create-pattern-modal.js @@ -61,7 +61,7 @@ export default function CreatePatternModal( { ( category ) => { if ( ! uniqueCategories.has( category.label ) && - // There are two core categories with `Post` label so explictily remove the one with + // There are two core categories with `Post` label so explicitly remove the one with // the `query` slug to avoid any confusion. category.name !== 'query' ) { From 29865fbd6be0c73aacab53a4d1b62fca9b479ba5 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Thu, 5 Oct 2023 19:12:20 +1300 Subject: [PATCH 14/17] Remove unneeded fallback array --- packages/patterns/src/components/category-selector.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/patterns/src/components/category-selector.js b/packages/patterns/src/components/category-selector.js index 14b84d30a88091..aa8f44cd1c9741 100644 --- a/packages/patterns/src/components/category-selector.js +++ b/packages/patterns/src/components/category-selector.js @@ -22,7 +22,7 @@ export default function CategorySelector( { const debouncedSearch = useDebounce( setSearch, 500 ); const suggestions = useMemo( () => { - return ( Array.from( categoryMap.values() ) ?? [] ) + return Array.from( categoryMap.values() ) .map( ( category ) => unescapeString( category.label ) ) .filter( ( category ) => { if ( search !== '' ) { From ba3c8e1e1fd06eb394ed61be2e7a456bf82101e3 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Thu, 5 Oct 2023 14:25:38 -0700 Subject: [PATCH 15/17] Remove redundant `true` prop values --- packages/patterns/src/components/category-selector.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/patterns/src/components/category-selector.js b/packages/patterns/src/components/category-selector.js index aa8f44cd1c9741..aff20149475135 100644 --- a/packages/patterns/src/components/category-selector.js +++ b/packages/patterns/src/components/category-selector.js @@ -58,8 +58,8 @@ export default function CategorySelector( { onChange={ handleChange } onInputChange={ debouncedSearch } label={ __( 'Categories' ) } - tokenizeOnBlur={ true } - __experimentalExpandOnFocus={ true } + tokenizeOnBlur + __experimentalExpandOnFocus /> ); } From 906df26c736ba5a7ec9d8f4bc7b3dd55b31629c0 Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Fri, 6 Oct 2023 13:12:15 +0800 Subject: [PATCH 16/17] Fix dynamic height and width when adding new categories --- packages/patterns/src/components/category-selector.js | 1 + packages/patterns/src/components/style.scss | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/patterns/src/components/category-selector.js b/packages/patterns/src/components/category-selector.js index aff20149475135..7f00350e278ecf 100644 --- a/packages/patterns/src/components/category-selector.js +++ b/packages/patterns/src/components/category-selector.js @@ -60,6 +60,7 @@ export default function CategorySelector( { label={ __( 'Categories' ) } tokenizeOnBlur __experimentalExpandOnFocus + __next40pxDefaultSize /> ); } diff --git a/packages/patterns/src/components/style.scss b/packages/patterns/src/components/style.scss index b5e4262afc31aa..95ecae05767b15 100644 --- a/packages/patterns/src/components/style.scss +++ b/packages/patterns/src/components/style.scss @@ -1,5 +1,11 @@ .patterns-menu-items__convert-modal { z-index: z-index(".patterns-menu-items__convert-modal"); + + // Fix the modal width to prevent added categories from stretching the modal. + [role="dialog"] > [role="document"] { + width: 350px; + } + .patterns-menu-items__convert-modal-categories { max-width: 300px; } @@ -14,5 +20,8 @@ } .patterns-create-modal__name-input input[type="text"] { - min-height: 34px; + // Match the minimal height of the category selector. + min-height: 40px; + // Override the default 1px margin-x. + margin: 0; } From 862078fdcdcb5ad38497d22ebc1dfe15d89da2b4 Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Fri, 6 Oct 2023 17:14:32 +0800 Subject: [PATCH 17/17] Fix suggestions list width --- packages/patterns/src/components/style.scss | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/patterns/src/components/style.scss b/packages/patterns/src/components/style.scss index 95ecae05767b15..e7869520044950 100644 --- a/packages/patterns/src/components/style.scss +++ b/packages/patterns/src/components/style.scss @@ -7,15 +7,24 @@ } .patterns-menu-items__convert-modal-categories { - max-width: 300px; + width: 100%; + position: relative; + min-height: 40px; } .components-form-token-field__suggestions-list { position: absolute; + box-sizing: border-box; z-index: 1; background-color: $white; - width: 295px; + // Account for the border width of the token field. + width: calc(100% + 2px); + left: -1px; min-width: initial; - border: 1px solid $gray-600; + border: 1px solid var(--wp-admin-theme-color); + border-top: none; + box-shadow: 0 0 0 0.5px var(--wp-admin-theme-color); + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; } }