From eccee5ef0deefa57ee0c5c166816354241807c56 Mon Sep 17 00:00:00 2001 From: Joe Bailey-Roberts Date: Thu, 1 Jun 2023 07:19:07 +0100 Subject: [PATCH 01/19] Import PostPicker and TermSelector --- src/components/PostPicker/README.md | 13 +++ src/components/PostPicker/index.jsx | 150 ++++++++++++++++++++++++++ src/components/TermSelector/index.jsx | 78 ++++++++++++++ src/index.js | 2 + 4 files changed, 243 insertions(+) create mode 100644 src/components/PostPicker/README.md create mode 100644 src/components/PostPicker/index.jsx create mode 100644 src/components/TermSelector/index.jsx diff --git a/src/components/PostPicker/README.md b/src/components/PostPicker/README.md new file mode 100644 index 0000000..0fa6452 --- /dev/null +++ b/src/components/PostPicker/README.md @@ -0,0 +1,13 @@ +# PostPicker + +The `PostPicker` control allows a user to select one or more posts from a given post type, which can be filtered by a taxonomy. + +TODO: Implement multiple taxonomy filters. + +## Props + +- title +- postType +- taxonomies +- values +- onChange diff --git a/src/components/PostPicker/index.jsx b/src/components/PostPicker/index.jsx new file mode 100644 index 0000000..1c229e5 --- /dev/null +++ b/src/components/PostPicker/index.jsx @@ -0,0 +1,150 @@ +import React, { ReactNode } from 'react'; + +import { + Button, + CheckboxControl, + Flex, + FlexItem, + Modal, + Notice, + SearchControl, + Spinner, +} from '@wordpress/components'; +import { useSelect } from '@wordpress/data'; +import { + useState, + useMemo, +} from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; + +import TermSelector from '../TermSelector'; + +/** + * List of selectable posts + * + * @param {object} props Component props + * @returns {ReactNode} Component + */ +function PostList( props ) { + + const { isResolving, onChange, queriedPosts, values } = props; + + return useMemo( () => + ( +
+ { + ( isResolving && ) + || ( queriedPosts.length < 1 && + + { __( 'No results found' ) } + + ) + || ( + queriedPosts.map( post => ( + { + if ( checked ) { + onChange( [ ...values, post.id ] ); + } else { + onChange( values.filter( value => ( value !== post.id ) ) ); + } + } } + /> + ) ) + ) + } +
+ ), + [ isResolving, onChange, queriedPosts, values ] + ); +} + +/** + * Component allowing the selection of one or more posts + * + * @param {object} props Component props + * @returns {ReactNode} Component + */ +function PostPicker( props ) { + + const { title, postType, taxonomies, values, onChange } = props; + + const taxonomy = taxonomies[0]; + + const [ modalOpen, setModalOpen ] = useState( false ); + + const [ search, setSearch ] = useState(); + + const [ taxQuery, setTaxQuery ] = useState( [] ); + + const queryArgs = { + search, + per_page: -1, + [taxonomy]: taxQuery, + }; + + const queriedPosts = useSelect( ( select ) => { + return select( 'core' ).getEntityRecords( 'postType', postType, queryArgs ) ?? []; + }, [ postType, queryArgs ] ); + + const isResolving = useSelect( ( select ) => { + return select( 'core/data' ).isResolving( 'core', 'getEntityRecords', [ 'postType', postType, queryArgs ] ); + } ); + + return ( + <> + + { + modalOpen && + setModalOpen( false ) } + > + + + setSearch( text ) } + /> + setTaxQuery( terms ) } + /> + + + + + + + } + + ); +} + +export default PostPicker; diff --git a/src/components/TermSelector/index.jsx b/src/components/TermSelector/index.jsx new file mode 100644 index 0000000..4755fc4 --- /dev/null +++ b/src/components/TermSelector/index.jsx @@ -0,0 +1,78 @@ +import React, { ReactNode } from 'react'; + +import { FormTokenField } from '@wordpress/components'; +import { useSelect } from '@wordpress/data'; + +/** + * Generate a list of term IDs, keyed by title. + * + * @param {object[]} termObjects array of terms, returned from getEntityRecords. + * @returns {Array} array of term IDs, keyed by title. + */ +function generateTitleToIdMap( termObjects ) { + + if ( ! termObjects ) { + return []; + } + + return termObjects.reduce( ( accumulator, currentTerm ) => { + accumulator[currentTerm.name] = currentTerm.id; + return accumulator; + }, {} ); + +} + +/** + * Generate a list of term titles, keyed by id. + * + * @param {object[]} termObjects array of terms, returned from getEntityRecords. + * @returns {Array} array of term titles, keyed by id. + */ +function generateIdToTitleMap( termObjects ) { + + if ( ! termObjects ) { + return []; + } + + return termObjects.reduce( ( accumulator, currentTerm ) => { + accumulator[currentTerm.id] = currentTerm.name; + return accumulator; + }, {} ); +} + +/** + * Form token field to select one or more terms. + * + * @param {object} props Component props + * @returns {ReactNode} Component + */ +function TermSelector( props ) { + const { taxonomy, value, onChange } = props; + + const { taxonomyTermsById, taxonomyTermsByTitle } = useSelect( ( select ) => { + + const termObjects = select( 'core' ).getEntityRecords( 'taxonomy', taxonomy, { per_page: 100 } ) ?? []; + + const taxonomyTermsById = generateIdToTitleMap( termObjects ); + const taxonomyTermsByTitle = generateTitleToIdMap( termObjects ); + + return { + taxonomyTermsById, + taxonomyTermsByTitle, + }; + + }, [ taxonomy ] ); + + const selectedTerms = value.map( id => taxonomyTermsById[id] ); + + return ( { + onChange( terms.map( term => taxonomyTermsByTitle[term] ) ); + } } + /> ); +} + +export default TermSelector; diff --git a/src/index.js b/src/index.js index a8bb58f..3c9e3d8 100644 --- a/src/index.js +++ b/src/index.js @@ -6,9 +6,11 @@ export { default as ImageControl } from './components/ImageControl'; export { default as InnerBlockSlider } from './components/InnerBlockSlider'; export { default as LinkToolbar } from './components/LinkToolbar'; export { default as PlainTextWithLimit } from './components/PlainTextWithLimit'; +export { default as PostPickler } from './components/PostPicker'; export { default as PostTitleControl } from './components/PostTitleControl'; export { default as PostTypeCheck } from './components/PostTypeCheck'; export { default as RichTextWithLimit } from './components/RichTextWithLimit'; +export { default as TermSelector } from './components/TermSelector'; export { default as useActiveBlockStyle } from './hooks/useActiveBlockStyle'; export { default as useBlockStyles } from './hooks/useBlockStyles'; From b0b170813a9312cced4bc3221015c6cc9fc39cc8 Mon Sep 17 00:00:00 2001 From: Matthew Haines-Young Date: Thu, 1 Jun 2023 17:22:56 +0100 Subject: [PATCH 02/19] Matts post picker modifications --- .../PostPicker/{index.jsx => index.js} | 102 +++++++++++++----- .../TermSelector/{index.jsx => index.js} | 11 +- src/index.js | 2 +- 3 files changed, 83 insertions(+), 32 deletions(-) rename src/components/PostPicker/{index.jsx => index.js} (56%) rename src/components/TermSelector/{index.jsx => index.js} (88%) diff --git a/src/components/PostPicker/index.jsx b/src/components/PostPicker/index.js similarity index 56% rename from src/components/PostPicker/index.jsx rename to src/components/PostPicker/index.js index 1c229e5..5c11463 100644 --- a/src/components/PostPicker/index.jsx +++ b/src/components/PostPicker/index.js @@ -1,4 +1,4 @@ -import React, { ReactNode } from 'react'; +import React, { ReactNode, useCallback, useEffect } from 'react'; import { Button, @@ -26,8 +26,20 @@ import TermSelector from '../TermSelector'; * @returns {ReactNode} Component */ function PostList( props ) { + const { + postType, + queryArgs, + onChange, + values = [], + } = props; - const { isResolving, onChange, queriedPosts, values } = props; + const queriedPosts = useSelect( ( select ) => { + return select( 'core' ).getEntityRecords( 'postType', postType, queryArgs ) ?? []; + }, [ postType, queryArgs ] ); + + const isResolving = useSelect( ( select ) => { + return select( 'core/data' ).isResolving( 'core', 'getEntityRecords', [ 'postType', postType, queryArgs ] ); + } ); return useMemo( () => ( @@ -35,6 +47,8 @@ function PostList( props ) { height: 400, maxHeight: '100%', overflow: 'scroll', + paddingLeft: 4, + marginLeft: -4, } }> { ( isResolving && ) @@ -49,8 +63,8 @@ function PostList( props ) { queriedPosts.map( post => ( { if ( checked ) { onChange( [ ...values, post.id ] ); @@ -75,31 +89,60 @@ function PostList( props ) { * @returns {ReactNode} Component */ function PostPicker( props ) { - - const { title, postType, taxonomies, values, onChange } = props; - - const taxonomy = taxonomies[0]; + const { + title = __( 'Select posts', 'block_editor_components' ), + postType = 'post', + taxonomies = [], + values, + onChange, + } = props; const [ modalOpen, setModalOpen ] = useState( false ); const [ search, setSearch ] = useState(); - const [ taxQuery, setTaxQuery ] = useState( [] ); + const taxObjects = useSelect( select => { + return taxonomies.map( taxonomy => select( 'core' ).getTaxonomy( taxonomy ) ); + }, [ taxonomies ] ); + + const [ taxQueries, setTaxQueries ] = useState( [] ); + + /** + * Helper function to update tax query for a taxonomy. + * + * Sets correct property value of rest_base. + * Merges the new data with existing data. + * + * @param {*} taxonomy Taxonomy. + * @param {*} newTerms New terms. + */ + const updateTaxQueryState = useCallback( ( taxonomy, newTerms ) => { + const taxObject = taxObjects.find( t => t && t.slug === taxonomy ); + + if ( taxObject ) { + setTaxQueries( { + ...taxQueries, + [`${taxObject.rest_base}`]: newTerms, + } ); + } + }, [ taxQueries, taxObjects ] ); + + // Ensure initial tax query state is set. + // Use effect to account for delay loading tax objects. + useEffect( () => { + taxObjects.forEach( taxObject => { + if ( taxObject && ! taxQueries[ taxObject.rest_base ] ) { + updateTaxQueryState( taxObject.rest_base, [] ); + } + } ); + }, [ taxObjects, updateTaxQueryState, taxQueries ] ); const queryArgs = { search, - per_page: -1, - [taxonomy]: taxQuery, + per_page: 30, + ...taxQueries, }; - const queriedPosts = useSelect( ( select ) => { - return select( 'core' ).getEntityRecords( 'postType', postType, queryArgs ) ?? []; - }, [ postType, queryArgs ] ); - - const isResolving = useSelect( ( select ) => { - return select( 'core/data' ).isResolving( 'core', 'getEntityRecords', [ 'postType', postType, queryArgs ] ); - } ); - return ( <> - { - modalOpen && - setModalOpen( false ) } + { modalOpen && ( + setModalOpen( false ) } > - - - setSearch( text ) } - /> - { taxonomies.map( taxonomy => { - const taxObject = taxObjects.find( t => t && t.slug === taxonomy ); - - return taxObject ? ( - updateTaxQueryState( taxonomy, terms ) } - /> - ) : null; - } ) } - - - - - +
+ + { tabPanel => ( +
+ { tabPanel.name === 'browse' && ( + + ) } + + { tabPanel.name === 'selection' && ( + + ) } +
+ ) } +
+
- } + ) } ); } From f46590c66053de2b84545d0dd9c7d43cd55b6f8c Mon Sep 17 00:00:00 2001 From: Matthew Haines-Young Date: Fri, 2 Jun 2023 10:22:04 +0100 Subject: [PATCH 04/19] Export components --- src/components/PostPicker/index.js | 172 +++++++++++++++++++---------- 1 file changed, 113 insertions(+), 59 deletions(-) diff --git a/src/components/PostPicker/index.js b/src/components/PostPicker/index.js index e66ad8a..178d0a5 100644 --- a/src/components/PostPicker/index.js +++ b/src/components/PostPicker/index.js @@ -243,18 +243,91 @@ function BrowsePanel( props ) { } /** - * Component allowing the selection of one or more posts + * Post Picker Modal Component. * - * @param {object} props Component props + * @param {object} props Props. * @returns {ReactNode} Component */ -function PostPicker( props ) { +export function PostPickerModal( props ) { const { - title = __( 'Select posts', 'block_editor_components' ), + title, postType = 'post', taxonomies = [], - values, + values = [], onChange, + setModalOpen, + } = props; + + return ( + setModalOpen( false ) } + > +
+ ( + <>Foo + ), + }, + { + name: 'selection', + title: __( 'Current Selection', 'skyscanner' ), + }, + ] } + > + { tabPanel => ( +
+ { tabPanel.name === 'browse' && ( + + ) } + + { tabPanel.name === 'selection' && ( + + ) } +
+ ) } +
+
+
+ ); +} +/** + * Component allowing the selection of one or more posts + * + * @param {object} props Component props + * @returns {ReactNode} Component + */ +function PostPickerButton( props ) { + const { + title = __( 'Select posts', 'block_editor_components' ), } = props; const [ modalOpen, setModalOpen ] = useState( false ); @@ -268,64 +341,45 @@ function PostPicker( props ) { { title } { modalOpen && ( - setModalOpen( false ) } - > -
- - { tabPanel => ( -
- { tabPanel.name === 'browse' && ( - - ) } + /> + ) } + + ); +} - { tabPanel.name === 'selection' && ( - - ) } -
- ) } -
-
-
+/** + * Post picker toolbar button. + * + * @param props + */ +function PostPickerToolbarButton( props ) { + const { + title = __( 'Select posts', 'block_editor_components' ), + } = props; + + const [ modalOpen, setModalOpen ] = useState( false ); + + return ( + <> + + { modalOpen && ( + ) } ); } -export default PostPicker; +export default PostPickerButton; From c70edafc96e80f79f366a4ce240bbe650a65c36a Mon Sep 17 00:00:00 2001 From: Matthew Haines-Young Date: Fri, 2 Jun 2023 10:22:44 +0100 Subject: [PATCH 05/19] Re-order, and support toolbar button props --- src/components/PostPicker/index.js | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/components/PostPicker/index.js b/src/components/PostPicker/index.js index 178d0a5..84859af 100644 --- a/src/components/PostPicker/index.js +++ b/src/components/PostPicker/index.js @@ -3,6 +3,7 @@ import React, { ReactNode, useCallback, useEffect } from 'react'; import { Button, ButtonGroup, + ToolbarButton, TabPanel, CheckboxControl, Flex, @@ -319,27 +320,29 @@ export function PostPickerModal( props ) {
); } + /** - * Component allowing the selection of one or more posts + * Post picker toolbar button. * - * @param {object} props Component props - * @returns {ReactNode} Component + * @param props */ -function PostPickerButton( props ) { +export function PostPickerToolbarButton( props ) { const { title = __( 'Select posts', 'block_editor_components' ), + icon = 'edit', } = props; const [ modalOpen, setModalOpen ] = useState( false ); return ( <> - + { modalOpen && ( Date: Fri, 2 Jun 2023 10:48:23 +0100 Subject: [PATCH 06/19] Update src/components/PostPicker/index.js Co-authored-by: Tom J Nowell --- src/components/PostPicker/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/PostPicker/index.js b/src/components/PostPicker/index.js index 5c11463..dc3168f 100644 --- a/src/components/PostPicker/index.js +++ b/src/components/PostPicker/index.js @@ -64,7 +64,7 @@ function PostList( props ) { { if ( checked ) { onChange( [ ...values, post.id ] ); From 2d8207f0e9b4ded2009d0a0bf2acf0407f1d257f Mon Sep 17 00:00:00 2001 From: Matthew Haines-Young Date: Fri, 2 Jun 2023 10:51:18 +0100 Subject: [PATCH 07/19] Make term field label translatable --- src/components/TermSelector/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/TermSelector/index.js b/src/components/TermSelector/index.js index 02bfba1..6e0945b 100644 --- a/src/components/TermSelector/index.js +++ b/src/components/TermSelector/index.js @@ -2,6 +2,7 @@ import React, { ReactNode } from 'react'; import { FormTokenField } from '@wordpress/components'; import { useSelect } from '@wordpress/data'; +import { __, sprintf } from '@wordpress/i18n'; /** * Generate a list of term IDs, keyed by title. @@ -67,7 +68,7 @@ function TermSelector( props ) { const selectedTerms = value.map( id => taxonomyTermsById[id] ); return ( { From 7965ca62826f50ad0dba3358da77d810fc2e5e14 Mon Sep 17 00:00:00 2001 From: Matthew Haines-Young Date: Fri, 2 Jun 2023 11:00:27 +0100 Subject: [PATCH 08/19] Revert "Update src/components/PostPicker/index.js" This reverts commit 1d8780b2705ab72a6f7c05fbd7786661c175f5bf. --- src/components/PostPicker/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/PostPicker/index.js b/src/components/PostPicker/index.js index dc3168f..5c11463 100644 --- a/src/components/PostPicker/index.js +++ b/src/components/PostPicker/index.js @@ -64,7 +64,7 @@ function PostList( props ) { { if ( checked ) { onChange( [ ...values, post.id ] ); From e811bb0bb81ba34eefea536f8308595ca7a3a0de Mon Sep 17 00:00:00 2001 From: Matthew Haines-Young Date: Fri, 2 Jun 2023 11:02:52 +0100 Subject: [PATCH 09/19] Update src/components/PostPicker/index.js Co-authored-by: Tom J Nowell --- src/components/PostPicker/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/PostPicker/index.js b/src/components/PostPicker/index.js index 84859af..91eb6c5 100644 --- a/src/components/PostPicker/index.js +++ b/src/components/PostPicker/index.js @@ -205,7 +205,7 @@ function BrowsePanel( props ) { return ( Date: Fri, 2 Jun 2023 11:04:57 +0100 Subject: [PATCH 10/19] More translations --- src/components/PostPicker/index.js | 7 ++++--- src/components/TermSelector/index.js | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/components/PostPicker/index.js b/src/components/PostPicker/index.js index 84859af..fdeac7e 100644 --- a/src/components/PostPicker/index.js +++ b/src/components/PostPicker/index.js @@ -214,7 +214,7 @@ function BrowsePanel( props ) { } } > setSearch( text ) } @@ -273,14 +273,14 @@ export function PostPickerModal( props ) { tabs={ [ { name: 'browse', - title: __( 'Browse Posts', 'skyscanner' ), + title: __( 'Browse Posts', 'block-editor-components' ), content: () => ( <>Foo ), }, { name: 'selection', - title: __( 'Current Selection', 'skyscanner' ), + title: __( 'Current Selection', 'block-editor-components' ), }, ] } > @@ -325,6 +325,7 @@ export function PostPickerModal( props ) { * Post picker toolbar button. * * @param props + * @returns {ReactNode} Component */ export function PostPickerToolbarButton( props ) { const { diff --git a/src/components/TermSelector/index.js b/src/components/TermSelector/index.js index 6e0945b..7d6b499 100644 --- a/src/components/TermSelector/index.js +++ b/src/components/TermSelector/index.js @@ -68,7 +68,7 @@ function TermSelector( props ) { const selectedTerms = value.map( id => taxonomyTermsById[id] ); return ( { From ab9e64b3acb0270fac5b4ed2cba5508f0331b5cd Mon Sep 17 00:00:00 2001 From: Matthew Haines-Young Date: Fri, 2 Jun 2023 11:25:08 +0100 Subject: [PATCH 11/19] Translation Textdomain --- src/components/PostPicker/index.js | 4 ++-- src/components/TermSelector/index.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/PostPicker/index.js b/src/components/PostPicker/index.js index 5c11463..d87ce1f 100644 --- a/src/components/PostPicker/index.js +++ b/src/components/PostPicker/index.js @@ -56,7 +56,7 @@ function PostList( props ) { - { __( 'No results found' ) } + { __( 'No results found', 'block-editor-components' ) } ) || ( @@ -90,7 +90,7 @@ function PostList( props ) { */ function PostPicker( props ) { const { - title = __( 'Select posts', 'block_editor_components' ), + title = __( 'Select posts', 'block-editor-components' ), postType = 'post', taxonomies = [], values, diff --git a/src/components/TermSelector/index.js b/src/components/TermSelector/index.js index 6e0945b..7d6b499 100644 --- a/src/components/TermSelector/index.js +++ b/src/components/TermSelector/index.js @@ -68,7 +68,7 @@ function TermSelector( props ) { const selectedTerms = value.map( id => taxonomyTermsById[id] ); return ( { From 33510fbbf527dfe79588f253da0a8688988a565c Mon Sep 17 00:00:00 2001 From: Matthew Haines-Young Date: Fri, 2 Jun 2023 12:03:02 +0100 Subject: [PATCH 12/19] Set default search state --- src/components/PostPicker/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/PostPicker/index.js b/src/components/PostPicker/index.js index de4cded..f0ae468 100644 --- a/src/components/PostPicker/index.js +++ b/src/components/PostPicker/index.js @@ -159,7 +159,7 @@ function BrowsePanel( props ) { taxonomies, } = props; - const [ search, setSearch ] = useState(); + const [ search, setSearch ] = useState( '' ); const taxObjects = useSelect( select => { return taxonomies.map( taxonomy => select( 'core' ).getTaxonomy( taxonomy ) ); @@ -198,7 +198,7 @@ function BrowsePanel( props ) { }, [ taxObjects, updateTaxQueryState, taxQueries ] ); const queryArgs = { - search, + search: search || undefined, // When empty, set as undefined to omit query var from API request. per_page: 30, ...taxQueries, }; From 7492d3f45bc722cb06a6005c9d9619946697da34 Mon Sep 17 00:00:00 2001 From: Matthew Haines-Young Date: Fri, 2 Jun 2023 13:27:13 +0100 Subject: [PATCH 13/19] Documentation --- src/components/PostPicker/README.md | 72 ++++++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 6 deletions(-) diff --git a/src/components/PostPicker/README.md b/src/components/PostPicker/README.md index 0fa6452..9681316 100644 --- a/src/components/PostPicker/README.md +++ b/src/components/PostPicker/README.md @@ -2,12 +2,72 @@ The `PostPicker` control allows a user to select one or more posts from a given post type, which can be filtered by a taxonomy. -TODO: Implement multiple taxonomy filters. +``` +import PostPicker from '@humanmade/block-editor-components'; + +... + + setAttributes( { postIds: newValue } ) } + values={ attributes.postIds || [] } +/> +``` ## Props -- title -- postType -- taxonomies -- values -- onChange +The `LinkToolbar` component does not have any custom props other than `opensInNewTab`, `value` and `onChange`, which are all passed on as is to the nested [`LinkControl`](https://github.com/WordPress/gutenberg/blob/trunk/packages/block-editor/src/components/link-control/index.js) component. + +### `values` + +The saved values. Array of post IDs. + +| Type | Required | Default | +|--------------------------------------|--------------------------------------|--------------------------------------| +| `Array` | yes | `undefined` | + + +### `onChange` + +The callback to use for handling changing the selected posts. `onChange` will receive an array of post IDs. + +| Type | Required | Default | +|--------------------------------------|--------------------------------------|--------------------------------------| +| `Function` | yes | `undefined` | + +### `title` + +The title, used by button and modal title. + +| Type | Required | Default | +|--------------------------------------|--------------------------------------|--------------------------------------| +| `String` | no | `Select Posts` + +### `postType` + +Post type to select from. + +| Type | Required | Default | +|--------------------------------------|--------------------------------------|--------------------------------------| +| `String` | no | `post` + +### `taxonomies` + +Taxonomies that results can be filtered by. Array of taxonomy slugs. e.g. `[ 'category', 'post_tag' ]`. + +| Type | Required | Default | +|--------------------------------------|--------------------------------------|--------------------------------------| +| `Array` | no | `[]` + + +# Post Picker Toolbar Button + +There is also a `PostPickerToolbarButton` component available if you import it directly from the source file, which is intended for use within the BlockControls. It supports all the same props as the PostPicker component, with the addition of an `icon`. + +### `icon` + +Button icon. Passed through to `ToolbarButton`, refer to the documentation of that component for more info. + +| Type | Required | Default | +|--------------------------------------|--------------------------------------|--------------------------------------| +| `string` | no | `edit` From 846015b7f53f4d2a2672d0e47155268a39b3f190 Mon Sep 17 00:00:00 2001 From: Matthew Haines-Young Date: Fri, 2 Jun 2023 16:13:35 +0100 Subject: [PATCH 14/19] Expose all components --- src/components/PostPicker/README.md | 28 +++++++++++++++++++--------- src/components/PostPicker/index.js | 6 ++---- src/index.js | 2 +- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/components/PostPicker/README.md b/src/components/PostPicker/README.md index 9681316..6ff471e 100644 --- a/src/components/PostPicker/README.md +++ b/src/components/PostPicker/README.md @@ -1,6 +1,14 @@ # PostPicker -The `PostPicker` control allows a user to select one or more posts from a given post type, which can be filtered by a taxonomy. +The `PostPicker` controls allows a user to select one or more posts from a given post type, which can be filtered by a taxonomy. + +Note there are several components exposed under PostPicker. + +* `PostPickerButton` A simple button. +* `PostPickerToolbarButton` A button for use within `BlockControls` toolbar. +* `PostPickerModal` The actual modal interface, that can be integrated into your own UI. + +## `PostPickerButton` ``` import PostPicker from '@humanmade/block-editor-components'; @@ -14,11 +22,11 @@ import PostPicker from '@humanmade/block-editor-components'; /> ``` -## Props +### Props The `LinkToolbar` component does not have any custom props other than `opensInNewTab`, `value` and `onChange`, which are all passed on as is to the nested [`LinkControl`](https://github.com/WordPress/gutenberg/blob/trunk/packages/block-editor/src/components/link-control/index.js) component. -### `values` +#### `values` The saved values. Array of post IDs. @@ -27,7 +35,7 @@ The saved values. Array of post IDs. | `Array` | yes | `undefined` | -### `onChange` +#### `onChange` The callback to use for handling changing the selected posts. `onChange` will receive an array of post IDs. @@ -35,7 +43,7 @@ The callback to use for handling changing the selected posts. `onChange` will re |--------------------------------------|--------------------------------------|--------------------------------------| | `Function` | yes | `undefined` | -### `title` +#### `title` The title, used by button and modal title. @@ -43,7 +51,7 @@ The title, used by button and modal title. |--------------------------------------|--------------------------------------|--------------------------------------| | `String` | no | `Select Posts` -### `postType` +#### `postType` Post type to select from. @@ -51,7 +59,7 @@ Post type to select from. |--------------------------------------|--------------------------------------|--------------------------------------| | `String` | no | `post` -### `taxonomies` +#### `taxonomies` Taxonomies that results can be filtered by. Array of taxonomy slugs. e.g. `[ 'category', 'post_tag' ]`. @@ -60,11 +68,13 @@ Taxonomies that results can be filtered by. Array of taxonomy slugs. e.g. `[ 'ca | `Array` | no | `[]` -# Post Picker Toolbar Button +## Post Picker Toolbar Button There is also a `PostPickerToolbarButton` component available if you import it directly from the source file, which is intended for use within the BlockControls. It supports all the same props as the PostPicker component, with the addition of an `icon`. -### `icon` +## props + +#### `icon` Button icon. Passed through to `ToolbarButton`, refer to the documentation of that component for more info. diff --git a/src/components/PostPicker/index.js b/src/components/PostPicker/index.js index f0ae468..0ba5440 100644 --- a/src/components/PostPicker/index.js +++ b/src/components/PostPicker/index.js @@ -324,7 +324,7 @@ export function PostPickerModal( props ) { /** * Post picker toolbar button. * - * @param props + * @param props Component props. * @returns {ReactNode} Component */ export function PostPickerToolbarButton( props ) { @@ -361,7 +361,7 @@ export function PostPickerToolbarButton( props ) { * @param {object} props Component props * @returns {ReactNode} Component */ -function PostPickerButton( props ) { +export function PostPickerButton( props ) { const { title = __( 'Select posts', 'block-editor-components' ), } = props; @@ -386,5 +386,3 @@ function PostPickerButton( props ) { ); } - -export default PostPickerButton; diff --git a/src/index.js b/src/index.js index fc2d0a4..5eb016b 100644 --- a/src/index.js +++ b/src/index.js @@ -6,7 +6,7 @@ export { default as ImageControl } from './components/ImageControl'; export { default as InnerBlockSlider } from './components/InnerBlockSlider'; export { default as LinkToolbar } from './components/LinkToolbar'; export { default as PlainTextWithLimit } from './components/PlainTextWithLimit'; -export { default as PostPicker } from './components/PostPicker'; +export * as PostPicker from './components/PostPicker'; export { default as PostTitleControl } from './components/PostTitleControl'; export { default as PostTypeCheck } from './components/PostTypeCheck'; export { default as RichTextWithLimit } from './components/RichTextWithLimit'; From 9d7b796428d69f4eb01cd866383b8d3a6295a22e Mon Sep 17 00:00:00 2001 From: Matthew Haines-Young Date: Fri, 2 Jun 2023 16:15:17 +0100 Subject: [PATCH 15/19] Expose as separate components --- dist/index.js | 2 +- src/components/PostPicker/README.md | 8 +++----- src/index.js | 6 +++++- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/dist/index.js b/dist/index.js index 4a18e67..c51866a 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1,2 +1,2 @@ /*! For license information please see index.js.LICENSE.txt */ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports["@humanmade/block-editor-components"]=t():e["@humanmade/block-editor-components"]=t()}(self,(()=>(()=>{var e={184:(e,t)=>{var n;!function(){"use strict";var o={}.hasOwnProperty;function r(){for(var e=[],t=0;t{"use strict";var o=n(414);function r(){}function l(){}l.resetWarningCache=r,e.exports=function(){function e(e,t,n,r,l,a){if(a!==o){var i=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw i.name="Invariant Violation",i}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:l,resetWarningCache:r};return n.PropTypes=n,n}},697:(e,t,n)=>{e.exports=n(703)()},414:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"}},t={};function n(o){var r=t[o];if(void 0!==r)return r.exports;var l=t[o]={exports:{}};return e[o](l,l.exports,n),l.exports}n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var o in t)n.o(t,o)&&!n.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var o={};return(()=>{"use strict";n.r(o),n.d(o,{ConditionalComponent:()=>r,FetchAllTermSelectControl:()=>f,FileControls:()=>v,GenericServerSideEdit:()=>h,ImageControl:()=>C,InnerBlockSlider:()=>L,LinkToolbar:()=>j,PlainTextWithLimit:()=>q,PostPicker:()=>z,PostTitleControl:()=>V,PostTypeCheck:()=>G,RichTextWithLimit:()=>Y,TermSelector:()=>D,createOptionFromPost:()=>ue,createOptionFromTerm:()=>de,createOptionsFromPosts:()=>me,createOptionsFromPostsWithHierarchy:()=>pe,createOptionsFromTerms:()=>fe,createOptionsFromTermsWithHierarchy:()=>ge,findBlockByName:()=>re,findInvalidBlock:()=>le,findInvalidBlocks:()=>ae,findValidBlock:()=>ie,findValidBlocks:()=>ce,getImageDataForSize:()=>k,useActiveBlockStyle:()=>K,useBlockStyles:()=>X,useDisallowedBlocks:()=>Z,useMeta:()=>ee,useRenderAppenderWithBlockLimit:()=>te,useSelectBlock:()=>ne,useSetAttribute:()=>oe,withActiveVariation:()=>be});const e=window.wp.element,t=window.React;function r(t){const{children:n=null,ComponentFalse:o=(()=>null),ComponentTrue:r=(()=>n),predicate:l,...a}=t,i=l(a)?r:o;return(0,e.createElement)(i,a)}function l(){return l=Object.assign?Object.assign.bind():function(e){for(var t=1;t{var t;return null===(t=e("core").getTaxonomy(a))||void 0===t?void 0:t.rest_base}),[a]);return(0,t.useEffect)((()=>{h&&(async()=>{try{const e=await i()({path:(0,d.addQueryArgs)(`/wp/v2/${h}`,{_fields:"id,name",context:"view",per_page:-1})});if(null==e||!e.length)return void y(r?[r]:[]);y([...o?[o]:[],...fe(e)])}catch(t){var e;v(null!==(e=t.message)&&void 0!==e?e:(0,u.__)("Unknown error.","block-editor-components"))}})()}),[h,o,r]),g?(0,e.createElement)(c.Notice,{isDismissible:!1,status:"error"},(0,e.createElement)("p",null,g)):b?(0,e.createElement)(c.SelectControl,l({},f,{options:b})):(0,e.createElement)(c.Spinner,null)},g=window.wp.blockEditor;function v(t){const{value:n,onChange:o,...r}=t;return(0,e.createElement)(g.MediaUploadCheck,null,(0,e.createElement)(g.MediaUpload,l({title:(0,u.__)("Select or Upload File","block-editor-components")},r,{multiple:!1,render:t=>{let{open:r}=t;return(0,e.createElement)(c.ToolbarGroup,null,(0,e.createElement)(c.ToolbarButton,{icon:"admin-links",label:n?(0,u.__)("Edit file","block-editor-components"):(0,u.__)("Select file","block-editor-components"),onClick:r}),n&&(0,e.createElement)(c.ToolbarButton,{icon:"editor-unlink",label:(0,u.__)("Deselect file","block-editor-components"),onClick:()=>o(null)}))},value:n,onSelect:o})))}const b=window.wp.serverSideRender;var y=n.n(b);const h=function(t){let{attributes:n,context:o,name:r}=t;return(0,e.createElement)("div",(0,g.useBlockProps)(),(0,e.createElement)(c.Disabled,null,(0,e.createElement)(y(),{attributes:n,block:r,EmptyResponsePlaceholder:()=>(0,e.createElement)("div",{className:`wp-block-${r.replace("/","-")}`},r," ",(0,u.__)("Block rendered as empty.")),urlQueryArgs:"object"==typeof o&&Object.hasOwn(o,"postId")?{post_id:o.postId}:{}})))};function k(e,t){var n,o;const r=null!==(n=null==e?void 0:e.sizes)&&void 0!==n?n:null==e||null===(o=e.media_details)||void 0===o?void 0:o.sizes,l=null==r?void 0:r[t];return l?{src:l.url||l.source_url,width:l.width,height:l.height}:null}const E=["image"],S=(0,u.__)("Select Image","block-editor-components"),w=(0,u.__)("Select Image","block-editor-components"),_=(0,u.__)("Remove image","block-editor-components"),T=(0,u.__)("Replace Image","block-editor-components");function C(t){const{buttonText:n=S,className:o,help:r,id:l,label:a,modalTitle:i=w,removeButtonText:u=_,replaceButtonText:d=T,size:m,value:p,onChange:f}=t,v=(0,s.useSelect)((e=>{const t=e("core").getMedia(p,{context:"view"});return t?t.alt_text:""}),[p]),b=(0,s.useSelect)((e=>{const t=e("core").getMedia(p,{context:"view"});if(t){if(m){const e=k(t,m);if(e)return e.src}return t.source_url}}),[m,p]);return(0,e.createElement)(c.BaseControl,{className:o,help:r,id:l,label:a},(0,e.createElement)(g.MediaUploadCheck,null,(0,e.createElement)(g.MediaUpload,{allowedTypes:E,render:t=>{let{open:o}=t;return(0,e.createElement)("div",null,p?b?(0,e.createElement)(c.Button,{isLink:!0,onClick:o},(0,e.createElement)("img",{alt:v,src:b})):(0,e.createElement)(c.Spinner,null):null,(0,e.createElement)(c.Button,{isSecondary:!0,onClick:o},p?d:n))},title:i,onSelect:f})),(0,e.createElement)("br",null),p?(0,e.createElement)(c.Button,{isDestructive:!0,isLink:!0,onClick:()=>f(null)},u):null)}var x=n(697),B=n.n(x);const P=window.wp.blocks;function I(n){let{className:o,allowedBlocks:r,template:l,currentItemIndex:a,parentBlockId:i,renderAppender:c,captureToolbars:s}=n;const u=(0,t.useRef)(),d=(0,g.useInnerBlocksProps)({id:`inner-block-display-single-${i}`,className:o},{__experimentalCaptureToolbars:s,allowedBlocks:r,orientation:"horizontal",renderAppender:c,template:l,templateLock:!1});return(0,t.useEffect)((()=>{u.current&&(u.current.innerHTML=`#inner-block-display-single-${i} > *:not(:nth-child(${a+1}) ) { display: none; }`)}),[a,u,i]),(0,e.createElement)(e.Fragment,null,(0,e.createElement)("style",{ref:u}),(0,e.createElement)("div",d))}I.defaultProps={currentItemIndex:0,renderAppender:!1,captureToolbars:!0},I.propTypes={parentBlockId:B().string.isRequired,allowedBlocks:B().arrayOf(B().string).isRequired,template:B().array,className:B().string,currentItemIndex:B().number,renderAppender:B().oneOfType([B().bool,B().element])};const O=I;var R=n(184),N=n.n(R);function F(t){let{totalPages:n,currentPage:o,setCurrentPage:r,prevEnabled:l,nextEnabled:a,addSlide:i=(()=>{}),addSlideEnabled:s=!1}=t;return(0,e.createElement)("div",{className:"inner-block-slider__navigation"},(0,e.createElement)(c.IconButton,{disabled:!l,icon:"arrow-left-alt2",isSecondary:!0,isSmall:!0,onClick:()=>{l&&r(o-1)}}),[...Array(n).keys()].map((t=>(0,e.createElement)(c.Button,{key:t+1,"aria-label":`Slide ${t+1}`,className:N()("components-button","is-not-small",{"is-primary":o===t+1,"is-secondary":o!==t+1}),type:"button",onClick:()=>{r(t+1)}},t+1))),(0,e.createElement)(c.IconButton,{disabled:!a,icon:"arrow-right-alt2",isSecondary:!0,isSmall:!0,onClick:()=>{a&&r(o+1)}}),(0,e.createElement)(c.IconButton,{disabled:!s,icon:"plus-alt2",isSecondary:!0,isSmall:!0,onClick:()=>i()}))}F.propTypes={totalPages:B().number.isRequired,currentPage:B().number.isRequired,setCurrentPage:B().func.isRequired,prevEnabled:B().bool.isRequired,nextEnabled:B().bool.isRequired,addSlide:B().func,addSlideEnabled:B().bool};const M=F,A=n=>{let{parentBlockId:o,allowedBlock:r,template:l,slideLimit:a}=n;const i=l||[[r]],c=(0,s.useSelect)((e=>e("core/block-editor").getBlock(o).innerBlocks)),[u,d]=(0,t.useState)(0),m=(0,t.useRef)(c.length),{insertBlock:p}=(0,s.useDispatch)("core/block-editor");return(0,t.useEffect)((()=>{(c.length>m.current||c.lengthc.length)&&d(c.length-1),m.current=c.length}),[c.length,u,m]),(0,e.createElement)("div",{className:"inner-block-slider"},(0,e.createElement)(O,{allowedBlocks:[r],className:"slides",currentItemIndex:u,parentBlockId:o,template:i}),(0,e.createElement)(M,{addSlide:()=>{const e=(0,P.createBlock)(r);p(e,void 0,o)},addSlideEnabled:c.length1,setCurrentPage:e=>d(e-1),totalPages:c.length}))};A.defaultProps={slideLimit:10,template:null},A.propTypes={parentBlockId:B().string.isRequired,allowedBlock:B().string.isRequired,template:B().array};const L=A;function j(n){const{onChange:o,opensInNewTab:r,url:l}=n,[a,i]=(0,t.useState)(!1),s=(0,t.useMemo)((()=>[{icon:"admin-links",title:(0,u.__)("Link","block-editor-components"),isActive:(null==l?void 0:l.length)>0,onClick:()=>i(!a)}]),[i,a,l]),d=(0,t.useMemo)((()=>({url:l,opensInNewTab:r})),[r,l]);return(0,e.createElement)(e.Fragment,null,(0,e.createElement)(c.ToolbarGroup,{controls:s}),a&&(0,e.createElement)(c.Popover,null,(0,e.createElement)(g.__experimentalLinkControl,{forceIsEditingLink:a,opensInNewTab:r,value:d,onChange:o})))}function q(n){var o;const{className:r,limit:a=0,onChange:i,...c}=n,[s,u]=(0,t.useState)(a&&(null===(o=n.value)||void 0===o?void 0:o.length)>a);return(0,e.createElement)(g.PlainText,l({className:`${r} limit-text ${s?"invalid":""}`.trim(),onChange:e=>{a&&e.length>a?s||u(!0):(s&&u(!1),i(e))}},c))}const D=function(t){const{taxonomy:n,value:o=[],onChange:r}=t,l=(0,s.useSelect)((e=>e("core").getTaxonomy(n)),[n]),{taxonomyTermsById:a,taxonomyTermsByTitle:i}=(0,s.useSelect)((e=>{var t;const o=null!==(t=e("core").getEntityRecords("taxonomy",n,{per_page:100}))&&void 0!==t?t:[],r=function(e){return e?e.reduce(((e,t)=>(e[t.id]=t.name,e)),{}):[]}(o),l=function(e){return e?e.reduce(((e,t)=>(e[t.name]=t.id,e)),{}):[]}(o);return{taxonomyTermsById:r,taxonomyTermsByTitle:l}}),[n]),u=o.map((e=>a[e]));return(0,e.createElement)(c.FormTokenField,{label:`Filter by ${l?l.labels.singular_name:""}`,suggestions:Object.values(a),value:u,onChange:e=>{r(e.map((e=>i[e])))}})};function $(t){const{postType:n,queryArgs:o,onChange:r,values:l=[],isSortable:a=!1}=t,i=(0,s.useSelect)((e=>{var t;return null!==(t=e("core").getEntityRecords("postType",n,o))&&void 0!==t?t:[]}),[n,o]),d=(0,s.useSelect)((e=>e("core/data").isResolving("core","getEntityRecords",["postType",n,o])));return(0,e.createElement)("div",{style:{marginTop:-24,paddingTop:24,paddingLeft:4,marginLeft:-4}},d&&(0,e.createElement)(c.Spinner,null)||i.length<1&&(0,e.createElement)(c.Notice,{isDismissible:!1},(0,u.__)("No results found"))||i.map((t=>{var n;return(0,e.createElement)("div",{style:{display:"grid",gridTemplateColumns:"1fr auto",marginRight:-2,paddingRight:2}},(0,e.createElement)(c.CheckboxControl,{key:t.id,checked:l.includes(t.id),label:(null===(n=t.title)||void 0===n?void 0:n.rendered)||(0,u.__)("(No title)","block-editor-components"),onChange:e=>{r(e?[...l,t.id]:l.filter((e=>e!==t.id)))}}),a&&(0,e.createElement)(c.ButtonGroup,null,(0,e.createElement)(c.Button,{icon:"arrow-up-alt2",iconSize:12,isSmall:!0,label:(0,u.__)("Move up","block-editor-components"),variant:"secondary",onClick:()=>(e=>{const t=l.indexOf(e);-1!==t&&0!==t&&r([...l.slice(0,t-1),l[t],l[t-1],...l.slice(t+1)])})(t.id)}),(0,e.createElement)(c.Button,{icon:"arrow-down-alt2",iconSize:12,isSmall:!0,label:(0,u.__)("Move down","block-editor-components"),variant:"secondary",onClick:()=>(e=>{const t=l.indexOf(e);-1!==t&&t!==l.length-1&&r([...l.slice(0,t),l[t+1],l[t],...l.slice(t+2)])})(t.id)})))})))}function W(n){const{postType:o,onChange:r,values:l,taxonomies:a}=n,[i,u]=(0,e.useState)(),d=(0,s.useSelect)((e=>a.map((t=>e("core").getTaxonomy(t)))),[a]),[m,p]=(0,e.useState)([]),f=(0,t.useCallback)(((e,t)=>{const n=d.find((t=>t&&t.slug===e));n&&p({...m,[`${n.rest_base}`]:t})}),[m,d]);(0,t.useEffect)((()=>{d.forEach((e=>{e&&!m[e.rest_base]&&f(e.rest_base,[])}))}),[d,f,m]);const g={search:i,per_page:30,...m};return(0,e.createElement)(c.Flex,{align:"flex-start",s:!0,style:{gap:24}},(0,e.createElement)(c.FlexItem,{style:{width:"35%"}},(0,e.createElement)(c.SearchControl,{label:"Search Posts",style:{marginBottom:24},value:i,onChange:e=>u(e)}),a.map((t=>{const n=d.find((e=>e&&e.slug===t));return n?(0,e.createElement)(D,{taxonomy:t,value:m[n.rest_base],onChange:e=>f(t,e)}):null}))),(0,e.createElement)(c.FlexItem,{style:{width:"65%"}},(0,e.createElement)($,{postType:o,queryArgs:g,values:l,onChange:r})))}function U(t){const{title:n,postType:o="post",taxonomies:r=[],values:l=[],onChange:a,setModalOpen:i}=t;return(0,e.createElement)(c.Modal,{style:{width:"800px",maxWidth:"100%"},title:n,onRequestClose:()=>i(!1)},(0,e.createElement)("div",{style:{marginTop:-16}},(0,e.createElement)(c.TabPanel,{tabs:[{name:"browse",title:(0,u.__)("Browse Posts","skyscanner"),content:()=>(0,e.createElement)(e.Fragment,null,"Foo")},{name:"selection",title:(0,u.__)("Current Selection","skyscanner")}]},(t=>(0,e.createElement)("div",{style:{marginTop:"calc( var(--wp-admin-border-width-focus) * -1 )",borderStyle:"none",borderTop:"var( --wp-admin-border-width-focus ) solid #ddd",paddingTop:24}},"browse"===t.name&&(0,e.createElement)(W,{postType:o,taxonomies:r,values:l,onChange:a}),"selection"===t.name&&(0,e.createElement)($,{isSortable:!0,postType:o,queryArgs:{include:l,orderby:"include",per_page:l.length},values:l,onChange:a}))))))}const z=function(t){const{title:n=(0,u.__)("Select posts","block_editor_components")}=t,[o,r]=(0,e.useState)(!1);return(0,e.createElement)(e.Fragment,null,(0,e.createElement)(c.Button,{variant:"primary",onClick:()=>r(!0)},n),o&&(0,e.createElement)(U,l({},t,{setModalOpen:r,title:n})))},H=/[\r\n]+/g;function V(n){const{editPost:o}=(0,s.useDispatch)("core/editor"),r=(0,s.useSelect)((e=>e("core/editor").getEditedPostAttribute("title")),[]),a=(0,t.useCallback)((e=>o({title:e.replace(H," ")})),[o]);return(0,e.createElement)(g.RichText,l({},n,{allowedFormats:[],value:r,onChange:a}))}function G(e){var t;const{postType:n}=e;return(0,s.useSelect)((e=>e("core/editor").getCurrentPostType()),[])===n?e.children:null!==(t=e.fallback)&&void 0!==t?t:null}const Q=window.wp.dom;function Y(n){var o;const{className:r,limit:a=0,onChange:i,...c}=n,s=(0,t.useRef)(),[u,d]=(0,t.useState)(a&&(null===(o=n.value)||void 0===o?void 0:o.length)>a),[m,p]=(0,t.useState)(!1);return(0,e.createElement)(g.RichText,l({ref:s,className:`${r} limit-text ${u?"invalid":""}`.trim(),onChange:e=>{if(a&&(0,Q.__unstableStripHTML)(e).length>a)return p(!1),s.current.innerHTML=n.value,(e=>{const t=document.createRange();t.selectNodeContents(e),t.collapse(!1);const n=window.getSelection();n.removeAllRanges(),n.addRange(t)})(s.current),void(u||d(!0));m&&u&&d(!1),p(!0),i(e)}},c))}const J=/^is-style-/;function K(e){const{blockName:n,className:o}=(0,s.useSelect)((t=>{var n,o,r;const l=t("core/block-editor").getBlock(e);return{blockName:null!==(n=null==l?void 0:l.name)&&void 0!==n?n:"",className:null!==(o=null==l||null===(r=l.attributes)||void 0===r?void 0:r.className)&&void 0!==o?o:""}}),[e]),{blockStyles:r,defaultStyle:l}=X(n),a=(0,t.useMemo)((()=>r.map((e=>{let{name:t}=e;return t}))),[r]),i=(0,t.useMemo)((()=>function(){return(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"").trim().replace(/\s+/," ").split(" ").map((e=>J.test(e)?e.replace(J,""):"")).filter(Boolean)}(o)),[o]);return(0,t.useMemo)((()=>{var e;return null!==(e=i.find((e=>a.includes(e))))&&void 0!==e?e:l}),[a,i,l])}function X(e){const n=(0,s.useSelect)((t=>t("core/blocks").getBlockStyles(e)),[e]);return(0,t.useMemo)((()=>{var e,t;return{blockStyles:n,defaultStyle:null!==(e=null===(t=n.find((e=>{let{isDefault:t}=e;return t})))||void 0===t?void 0:t.name)&&void 0!==e?e:""}}),[n])}function Z(e){return(0,t.useMemo)((()=>{const t=(0,P.getBlockTypes)();return null!=t&&t.length?t.filter((t=>{let{name:n,parent:o}=t;return!o&&!e.includes(n)})).map((e=>{let{name:t}=e;return t})):[]}),[e])}function ee(e,n){var o;const{editPost:r}=(0,s.useDispatch)("core/editor"),l=(0,s.useSelect)((e=>e("core/editor").getEditedPostAttribute("meta"))),a=(0,t.useCallback)((t=>r({meta:{[e]:t}})),[r,e]);return[null!==(o=null==l?void 0:l[e])&&void 0!==o?o:n,a]}function te(e,t,n){return(0,s.useSelect)((o=>{const{innerBlocks:r}=o("core/block-editor").getBlock(e);return(null==r?void 0:r.length){const n=document.getElementById(`block-${t}`);n&&(e(t),setTimeout((()=>n.scrollIntoView({behavior:"smooth"})),200))}),[e])}function oe(e,n,o){return(0,t.useCallback)((function(){let t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:o;return n({[e]:t})}),[e,o,n])}function re(e){const{getBlocks:t}=(0,s.select)("core/block-editor");return t().find((t=>{let{name:n}=t;return n===e}))}function le(e,t){return e.find((e=>!t(e)))}function ae(e,t){return e.filter((e=>!t(e)))}function ie(e,t){return e.find((e=>t(e)))}function ce(e,t){return e.filter((e=>t(e)))}const se=window.wp.htmlEntities;function ue(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";const{id:n,title:o}=e;return{label:t+(0,se.decodeEntities)(o.rendered||(0,u.sprintf)((0,u.__)("#%d (no title)","block-editor-components"),n)),value:n}}function de(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";const{id:n,name:o}=e;return{label:t+(0,se.decodeEntities)(o||(0,u.sprintf)((0,u.__)("#%d (no name)","block-editor-components"),n)),value:n}}function me(e){return e.map((e=>ue(e)))}function pe(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"\u2014 ",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;return e.map((e=>{let{children:o=[],...r}=e;return[ue(r,t.repeat(n)),...pe(o,t,n+1)]})).flat()}function fe(e){return e.map((e=>de(e)))}function ge(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"\u2014 ",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;return e.map((e=>{let{children:o=[],...r}=e;return[de(r,t.repeat(n)),...ge(o,t,n+1)]})).flat()}function ve(e){return(t,n)=>e.every((e=>t[e]===n[e]))}function be(e){var t;if(null!==(t=e.variations)&&void 0!==t&&t.length){for(var n=arguments.length,o=new Array(n>1?n-1:0),r=1;r(e.isActive=t,e)))}return e}})(),o})())); \ No newline at end of file +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports["@humanmade/block-editor-components"]=t():e["@humanmade/block-editor-components"]=t()}(self,(()=>(()=>{var e={184:(e,t)=>{var n;!function(){"use strict";var o={}.hasOwnProperty;function l(){for(var e=[],t=0;t{"use strict";var o=n(414);function l(){}function r(){}r.resetWarningCache=l,e.exports=function(){function e(e,t,n,l,r,i){if(i!==o){var a=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw a.name="Invariant Violation",a}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:r,resetWarningCache:l};return n.PropTypes=n,n}},697:(e,t,n)=>{e.exports=n(703)()},414:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"}},t={};function n(o){var l=t[o];if(void 0!==l)return l.exports;var r=t[o]={exports:{}};return e[o](r,r.exports,n),r.exports}n.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return n.d(t,{a:t}),t},n.d=(e,t)=>{for(var o in t)n.o(t,o)&&!n.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},n.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),n.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var o={};return(()=>{"use strict";n.r(o),n.d(o,{ConditionalComponent:()=>l,FetchAllTermSelectControl:()=>f,FileControls:()=>g,GenericServerSideEdit:()=>y,ImageControl:()=>C,InnerBlockSlider:()=>L,LinkToolbar:()=>j,PlainTextWithLimit:()=>q,PostPickerButton:()=>K,PostPickerModal:()=>Y,PostPickerToolbarButton:()=>J,PostTitleControl:()=>$,PostTypeCheck:()=>W,RichTextWithLimit:()=>H,TermSelector:()=>V,createOptionFromPost:()=>me,createOptionFromTerm:()=>pe,createOptionsFromPosts:()=>fe,createOptionsFromPostsWithHierarchy:()=>be,createOptionsFromTerms:()=>ge,createOptionsFromTermsWithHierarchy:()=>ve,findBlockByName:()=>ie,findInvalidBlock:()=>ae,findInvalidBlocks:()=>ce,findValidBlock:()=>se,findValidBlocks:()=>ue,getImageDataForSize:()=>k,useActiveBlockStyle:()=>Z,useBlockStyles:()=>ee,useDisallowedBlocks:()=>te,useMeta:()=>ne,useRenderAppenderWithBlockLimit:()=>oe,useSelectBlock:()=>le,useSetAttribute:()=>re,withActiveVariation:()=>he});const e=window.wp.element,t=window.React;function l(t){const{children:n=null,ComponentFalse:o=(()=>null),ComponentTrue:l=(()=>n),predicate:r,...i}=t,a=r(i)?l:o;return(0,e.createElement)(a,i)}function r(){return r=Object.assign?Object.assign.bind():function(e){for(var t=1;t{var t;return null===(t=e("core").getTaxonomy(i))||void 0===t?void 0:t.rest_base}),[i]);return(0,t.useEffect)((()=>{y&&(async()=>{try{const e=await a()({path:(0,d.addQueryArgs)(`/wp/v2/${y}`,{_fields:"id,name",context:"view",per_page:-1})});if(null==e||!e.length)return void h(l?[l]:[]);h([...o?[o]:[],...ge(e)])}catch(t){var e;g(null!==(e=t.message)&&void 0!==e?e:(0,u.__)("Unknown error.","block-editor-components"))}})()}),[y,o,l]),b?(0,e.createElement)(c.Notice,{isDismissible:!1,status:"error"},(0,e.createElement)("p",null,b)):v?(0,e.createElement)(c.SelectControl,r({},f,{options:v})):(0,e.createElement)(c.Spinner,null)},b=window.wp.blockEditor;function g(t){const{value:n,onChange:o,...l}=t;return(0,e.createElement)(b.MediaUploadCheck,null,(0,e.createElement)(b.MediaUpload,r({title:(0,u.__)("Select or Upload File","block-editor-components")},l,{multiple:!1,render:t=>{let{open:l}=t;return(0,e.createElement)(c.ToolbarGroup,null,(0,e.createElement)(c.ToolbarButton,{icon:"admin-links",label:n?(0,u.__)("Edit file","block-editor-components"):(0,u.__)("Select file","block-editor-components"),onClick:l}),n&&(0,e.createElement)(c.ToolbarButton,{icon:"editor-unlink",label:(0,u.__)("Deselect file","block-editor-components"),onClick:()=>o(null)}))},value:n,onSelect:o})))}const v=window.wp.serverSideRender;var h=n.n(v);const y=function(t){let{attributes:n,context:o,name:l}=t;return(0,e.createElement)("div",(0,b.useBlockProps)(),(0,e.createElement)(c.Disabled,null,(0,e.createElement)(h(),{attributes:n,block:l,EmptyResponsePlaceholder:()=>(0,e.createElement)("div",{className:`wp-block-${l.replace("/","-")}`},l," ",(0,u.__)("Block rendered as empty.")),urlQueryArgs:"object"==typeof o&&Object.hasOwn(o,"postId")?{post_id:o.postId}:{}})))};function k(e,t){var n,o;const l=null!==(n=null==e?void 0:e.sizes)&&void 0!==n?n:null==e||null===(o=e.media_details)||void 0===o?void 0:o.sizes,r=null==l?void 0:l[t];return r?{src:r.url||r.source_url,width:r.width,height:r.height}:null}const E=["image"],S=(0,u.__)("Select Image","block-editor-components"),_=(0,u.__)("Select Image","block-editor-components"),w=(0,u.__)("Remove image","block-editor-components"),T=(0,u.__)("Replace Image","block-editor-components");function C(t){const{buttonText:n=S,className:o,help:l,id:r,label:i,modalTitle:a=_,removeButtonText:u=w,replaceButtonText:d=T,size:m,value:p,onChange:f}=t,g=(0,s.useSelect)((e=>{const t=e("core").getMedia(p,{context:"view"});return t?t.alt_text:""}),[p]),v=(0,s.useSelect)((e=>{const t=e("core").getMedia(p,{context:"view"});if(t){if(m){const e=k(t,m);if(e)return e.src}return t.source_url}}),[m,p]);return(0,e.createElement)(c.BaseControl,{className:o,help:l,id:r,label:i},(0,e.createElement)(b.MediaUploadCheck,null,(0,e.createElement)(b.MediaUpload,{allowedTypes:E,render:t=>{let{open:o}=t;return(0,e.createElement)("div",null,p?v?(0,e.createElement)(c.Button,{isLink:!0,onClick:o},(0,e.createElement)("img",{alt:g,src:v})):(0,e.createElement)(c.Spinner,null):null,(0,e.createElement)(c.Button,{isSecondary:!0,onClick:o},p?d:n))},title:a,onSelect:f})),(0,e.createElement)("br",null),p?(0,e.createElement)(c.Button,{isDestructive:!0,isLink:!0,onClick:()=>f(null)},u):null)}var B=n(697),x=n.n(B);const P=window.wp.blocks;function I(n){let{className:o,allowedBlocks:l,template:r,currentItemIndex:i,parentBlockId:a,renderAppender:c,captureToolbars:s}=n;const u=(0,t.useRef)(),d=(0,b.useInnerBlocksProps)({id:`inner-block-display-single-${a}`,className:o},{__experimentalCaptureToolbars:s,allowedBlocks:l,orientation:"horizontal",renderAppender:c,template:r,templateLock:!1});return(0,t.useEffect)((()=>{u.current&&(u.current.innerHTML=`#inner-block-display-single-${a} > *:not(:nth-child(${i+1}) ) { display: none; }`)}),[i,u,a]),(0,e.createElement)(e.Fragment,null,(0,e.createElement)("style",{ref:u}),(0,e.createElement)("div",d))}I.defaultProps={currentItemIndex:0,renderAppender:!1,captureToolbars:!0},I.propTypes={parentBlockId:x().string.isRequired,allowedBlocks:x().arrayOf(x().string).isRequired,template:x().array,className:x().string,currentItemIndex:x().number,renderAppender:x().oneOfType([x().bool,x().element])};const O=I;var R=n(184),N=n.n(R);function M(t){let{totalPages:n,currentPage:o,setCurrentPage:l,prevEnabled:r,nextEnabled:i,addSlide:a=(()=>{}),addSlideEnabled:s=!1}=t;return(0,e.createElement)("div",{className:"inner-block-slider__navigation"},(0,e.createElement)(c.IconButton,{disabled:!r,icon:"arrow-left-alt2",isSecondary:!0,isSmall:!0,onClick:()=>{r&&l(o-1)}}),[...Array(n).keys()].map((t=>(0,e.createElement)(c.Button,{key:t+1,"aria-label":`Slide ${t+1}`,className:N()("components-button","is-not-small",{"is-primary":o===t+1,"is-secondary":o!==t+1}),type:"button",onClick:()=>{l(t+1)}},t+1))),(0,e.createElement)(c.IconButton,{disabled:!i,icon:"arrow-right-alt2",isSecondary:!0,isSmall:!0,onClick:()=>{i&&l(o+1)}}),(0,e.createElement)(c.IconButton,{disabled:!s,icon:"plus-alt2",isSecondary:!0,isSmall:!0,onClick:()=>a()}))}M.propTypes={totalPages:x().number.isRequired,currentPage:x().number.isRequired,setCurrentPage:x().func.isRequired,prevEnabled:x().bool.isRequired,nextEnabled:x().bool.isRequired,addSlide:x().func,addSlideEnabled:x().bool};const F=M,A=n=>{let{parentBlockId:o,allowedBlock:l,template:r,slideLimit:i}=n;const a=r||[[l]],c=(0,s.useSelect)((e=>e("core/block-editor").getBlock(o).innerBlocks)),[u,d]=(0,t.useState)(0),m=(0,t.useRef)(c.length),{insertBlock:p}=(0,s.useDispatch)("core/block-editor");return(0,t.useEffect)((()=>{(c.length>m.current||c.lengthc.length)&&d(c.length-1),m.current=c.length}),[c.length,u,m]),(0,e.createElement)("div",{className:"inner-block-slider"},(0,e.createElement)(O,{allowedBlocks:[l],className:"slides",currentItemIndex:u,parentBlockId:o,template:a}),(0,e.createElement)(F,{addSlide:()=>{const e=(0,P.createBlock)(l);p(e,void 0,o)},addSlideEnabled:c.length1,setCurrentPage:e=>d(e-1),totalPages:c.length}))};A.defaultProps={slideLimit:10,template:null},A.propTypes={parentBlockId:x().string.isRequired,allowedBlock:x().string.isRequired,template:x().array};const L=A;function j(n){const{onChange:o,opensInNewTab:l,url:r}=n,[i,a]=(0,t.useState)(!1),s=(0,t.useMemo)((()=>[{icon:"admin-links",title:(0,u.__)("Link","block-editor-components"),isActive:(null==r?void 0:r.length)>0,onClick:()=>a(!i)}]),[a,i,r]),d=(0,t.useMemo)((()=>({url:r,opensInNewTab:l})),[l,r]);return(0,e.createElement)(e.Fragment,null,(0,e.createElement)(c.ToolbarGroup,{controls:s}),i&&(0,e.createElement)(c.Popover,null,(0,e.createElement)(b.__experimentalLinkControl,{forceIsEditingLink:i,opensInNewTab:l,value:d,onChange:o})))}function q(n){var o;const{className:l,limit:i=0,onChange:a,...c}=n,[s,u]=(0,t.useState)(i&&(null===(o=n.value)||void 0===o?void 0:o.length)>i);return(0,e.createElement)(b.PlainText,r({className:`${l} limit-text ${s?"invalid":""}`.trim(),onChange:e=>{i&&e.length>i?s||u(!0):(s&&u(!1),a(e))}},c))}const D=/[\r\n]+/g;function $(n){const{editPost:o}=(0,s.useDispatch)("core/editor"),l=(0,s.useSelect)((e=>e("core/editor").getEditedPostAttribute("title")),[]),i=(0,t.useCallback)((e=>o({title:e.replace(D," ")})),[o]);return(0,e.createElement)(b.RichText,r({},n,{allowedFormats:[],value:l,onChange:i}))}function W(e){var t;const{postType:n}=e;return(0,s.useSelect)((e=>e("core/editor").getCurrentPostType()),[])===n?e.children:null!==(t=e.fallback)&&void 0!==t?t:null}const U=window.wp.dom,z=e=>{const t=document.createRange();t.selectNodeContents(e),t.collapse(!1);const n=window.getSelection();n.removeAllRanges(),n.addRange(t)};function H(n){var o;const{className:l,limit:i=0,onChange:a,...c}=n,s=(0,t.useRef)(),[u,d]=(0,t.useState)(i&&(null===(o=n.value)||void 0===o?void 0:o.length)>i),[m,p]=(0,t.useState)(!1);return(0,e.createElement)(b.RichText,r({ref:s,className:`${l} limit-text ${u?"invalid":""}`.trim(),onChange:e=>{if(i&&(0,U.__unstableStripHTML)(e).length>i)return p(!1),s.current.innerHTML=n.value,z(s.current),void(u||d(!0));m&&u&&d(!1),p(!0),a(e)}},c))}const V=function(t){const{taxonomy:n,value:o=[],onChange:l}=t,r=(0,s.useSelect)((e=>e("core").getTaxonomy(n)),[n]),{taxonomyTermsById:i,taxonomyTermsByTitle:a}=(0,s.useSelect)((e=>{var t;const o=null!==(t=e("core").getEntityRecords("taxonomy",n,{per_page:100}))&&void 0!==t?t:[],l=function(e){return e?e.reduce(((e,t)=>(e[t.id]=t.name,e)),{}):[]}(o),r=function(e){return e?e.reduce(((e,t)=>(e[t.name]=t.id,e)),{}):[]}(o);return{taxonomyTermsById:l,taxonomyTermsByTitle:r}}),[n]),d=o.map((e=>i[e]));return(0,e.createElement)(c.FormTokenField,{label:(0,u.sprintf)((0,u.__)("Filter by %s","block-editor-components"),r?r.labels.singular_name:""),suggestions:Object.values(i),value:d,onChange:e=>{l(e.map((e=>a[e])))}})};function G(t){const{postType:n,queryArgs:o,onChange:l,values:r=[],isSortable:i=!1}=t,a=(0,s.useSelect)((e=>{var t;return null!==(t=e("core").getEntityRecords("postType",n,o))&&void 0!==t?t:[]}),[n,o]),d=(0,s.useSelect)((e=>e("core/data").isResolving("core","getEntityRecords",["postType",n,o])));return(0,e.createElement)("div",{style:{marginTop:-24,paddingTop:24,paddingLeft:4,marginLeft:-4}},d&&(0,e.createElement)(c.Spinner,null)||a.length<1&&(0,e.createElement)(c.Notice,{isDismissible:!1},(0,u.__)("No results found","block-editor-components"))||a.map((t=>{var n;return(0,e.createElement)("div",{style:{display:"grid",gridTemplateColumns:"1fr auto",marginRight:-2,paddingRight:2}},(0,e.createElement)(c.CheckboxControl,{key:t.id,checked:r.includes(t.id),label:(null===(n=t.title)||void 0===n?void 0:n.rendered)||(0,u.__)("(No title)","block-editor-components"),onChange:e=>{l(e?[...r,t.id]:r.filter((e=>e!==t.id)))}}),i&&(0,e.createElement)(c.ButtonGroup,null,(0,e.createElement)(c.Button,{icon:"arrow-up-alt2",iconSize:12,isSmall:!0,label:(0,u.__)("Move up","block-editor-components"),variant:"secondary",onClick:()=>(e=>{const t=r.indexOf(e);-1!==t&&0!==t&&l([...r.slice(0,t-1),r[t],r[t-1],...r.slice(t+1)])})(t.id)}),(0,e.createElement)(c.Button,{icon:"arrow-down-alt2",iconSize:12,isSmall:!0,label:(0,u.__)("Move down","block-editor-components"),variant:"secondary",onClick:()=>(e=>{const t=r.indexOf(e);-1!==t&&t!==r.length-1&&l([...r.slice(0,t),r[t+1],r[t],...r.slice(t+2)])})(t.id)})))})))}function Q(n){const{postType:o,onChange:l,values:r,taxonomies:i}=n,[a,d]=(0,e.useState)(""),m=(0,s.useSelect)((e=>i.map((t=>e("core").getTaxonomy(t)))),[i]),[p,f]=(0,e.useState)([]),b=(0,t.useCallback)(((e,t)=>{const n=m.find((t=>t&&t.slug===e));n&&f({...p,[`${n.rest_base}`]:t})}),[p,m]);(0,t.useEffect)((()=>{m.forEach((e=>{e&&!p[e.rest_base]&&b(e.rest_base,[])}))}),[m,b,p]);const g={search:a||void 0,per_page:30,...p};return(0,e.createElement)(c.Flex,{align:"flex-start",style:{gap:24}},(0,e.createElement)(c.FlexItem,{style:{width:"35%"}},(0,e.createElement)(c.SearchControl,{label:(0,u.__)("Search Posts","block-editor-components"),style:{marginBottom:24},value:a,onChange:e=>d(e)}),i.map((t=>{const n=m.find((e=>e&&e.slug===t));return n?(0,e.createElement)(V,{taxonomy:t,value:p[n.rest_base],onChange:e=>b(t,e)}):null}))),(0,e.createElement)(c.FlexItem,{style:{width:"65%"}},(0,e.createElement)(G,{postType:o,queryArgs:g,values:r,onChange:l})))}function Y(t){const{title:n,postType:o="post",taxonomies:l=[],values:r=[],onChange:i,setModalOpen:a}=t;return(0,e.createElement)(c.Modal,{style:{width:"800px",maxWidth:"100%"},title:n,onRequestClose:()=>a(!1)},(0,e.createElement)("div",{style:{marginTop:-16}},(0,e.createElement)(c.TabPanel,{tabs:[{name:"browse",title:(0,u.__)("Browse Posts","block-editor-components"),content:()=>(0,e.createElement)(e.Fragment,null,"Foo")},{name:"selection",title:(0,u.__)("Current Selection","block-editor-components")}]},(t=>(0,e.createElement)("div",{style:{marginTop:"calc( var(--wp-admin-border-width-focus) * -1 )",borderStyle:"none",borderTop:"var( --wp-admin-border-width-focus ) solid #ddd",paddingTop:24}},"browse"===t.name&&(0,e.createElement)(Q,{postType:o,taxonomies:l,values:r,onChange:i}),"selection"===t.name&&(0,e.createElement)(G,{isSortable:!0,postType:o,queryArgs:{include:r,orderby:"include",per_page:r.length},values:r,onChange:i}))))))}function J(t){const{title:n=(0,u.__)("Select posts","block-editor-components"),icon:o="edit"}=t,[l,i]=(0,e.useState)(!1);return(0,e.createElement)(e.Fragment,null,(0,e.createElement)(c.ToolbarButton,{icon:o,onClick:()=>i(!0),label:n},n),l&&(0,e.createElement)(Y,r({},t,{setModalOpen:i,title:n})))}function K(t){const{title:n=(0,u.__)("Select posts","block-editor-components")}=t,[o,l]=(0,e.useState)(!1);return(0,e.createElement)(e.Fragment,null,(0,e.createElement)(c.Button,{variant:"primary",onClick:()=>l(!0)},n),o&&(0,e.createElement)(Y,r({},t,{setModalOpen:l,title:n})))}const X=/^is-style-/;function Z(e){const{blockName:n,className:o}=(0,s.useSelect)((t=>{var n,o,l;const r=t("core/block-editor").getBlock(e);return{blockName:null!==(n=null==r?void 0:r.name)&&void 0!==n?n:"",className:null!==(o=null==r||null===(l=r.attributes)||void 0===l?void 0:l.className)&&void 0!==o?o:""}}),[e]),{blockStyles:l,defaultStyle:r}=ee(n),i=(0,t.useMemo)((()=>l.map((e=>{let{name:t}=e;return t}))),[l]),a=(0,t.useMemo)((()=>function(){return(arguments.length>0&&void 0!==arguments[0]?arguments[0]:"").trim().replace(/\s+/," ").split(" ").map((e=>X.test(e)?e.replace(X,""):"")).filter(Boolean)}(o)),[o]);return(0,t.useMemo)((()=>{var e;return null!==(e=a.find((e=>i.includes(e))))&&void 0!==e?e:r}),[i,a,r])}function ee(e){const n=(0,s.useSelect)((t=>t("core/blocks").getBlockStyles(e)),[e]);return(0,t.useMemo)((()=>{var e,t;return{blockStyles:n,defaultStyle:null!==(e=null===(t=n.find((e=>{let{isDefault:t}=e;return t})))||void 0===t?void 0:t.name)&&void 0!==e?e:""}}),[n])}function te(e){return(0,t.useMemo)((()=>{const t=(0,P.getBlockTypes)();return null!=t&&t.length?t.filter((t=>{let{name:n,parent:o}=t;return!o&&!e.includes(n)})).map((e=>{let{name:t}=e;return t})):[]}),[e])}function ne(e,n){var o;const{editPost:l}=(0,s.useDispatch)("core/editor"),r=(0,s.useSelect)((e=>e("core/editor").getEditedPostAttribute("meta"))),i=(0,t.useCallback)((t=>l({meta:{[e]:t}})),[l,e]);return[null!==(o=null==r?void 0:r[e])&&void 0!==o?o:n,i]}function oe(e,t,n){return(0,s.useSelect)((o=>{const{innerBlocks:l}=o("core/block-editor").getBlock(e);return(null==l?void 0:l.length){const n=document.getElementById(`block-${t}`);n&&(e(t),setTimeout((()=>n.scrollIntoView({behavior:"smooth"})),200))}),[e])}function re(e,n,o){return(0,t.useCallback)((function(){return n({[e]:arguments.length>0&&void 0!==arguments[0]?arguments[0]:o})}),[e,o,n])}function ie(e){const{getBlocks:t}=(0,s.select)("core/block-editor");return t().find((t=>{let{name:n}=t;return n===e}))}function ae(e,t){return e.find((e=>!t(e)))}function ce(e,t){return e.filter((e=>!t(e)))}function se(e,t){return e.find((e=>t(e)))}function ue(e,t){return e.filter((e=>t(e)))}const de=window.wp.htmlEntities;function me(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";const{id:n,title:o}=e;return{label:t+(0,de.decodeEntities)(o.rendered||(0,u.sprintf)((0,u.__)("#%d (no title)","block-editor-components"),n)),value:n}}function pe(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";const{id:n,name:o}=e;return{label:t+(0,de.decodeEntities)(o||(0,u.sprintf)((0,u.__)("#%d (no name)","block-editor-components"),n)),value:n}}function fe(e){return e.map((e=>me(e)))}function be(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"\u2014 ",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;return e.map((e=>{let{children:o=[],...l}=e;return[me(l,t.repeat(n)),...be(o,t,n+1)]})).flat()}function ge(e){return e.map((e=>pe(e)))}function ve(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"\u2014 ",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:0;return e.map((e=>{let{children:o=[],...l}=e;return[pe(l,t.repeat(n)),...ve(o,t,n+1)]})).flat()}function he(e){var t;if(null!==(t=e.variations)&&void 0!==t&&t.length){for(var n=arguments.length,o=new Array(n>1?n-1:0),l=1;le.every((e=>t[e]===n[e]))}(o);e.variations=e.variations.map((e=>(e.isActive=t,e)))}return e}})(),o})())); \ No newline at end of file diff --git a/src/components/PostPicker/README.md b/src/components/PostPicker/README.md index 6ff471e..5106b64 100644 --- a/src/components/PostPicker/README.md +++ b/src/components/PostPicker/README.md @@ -1,8 +1,6 @@ # PostPicker -The `PostPicker` controls allows a user to select one or more posts from a given post type, which can be filtered by a taxonomy. - -Note there are several components exposed under PostPicker. +There are several `PostPicker` controls. * `PostPickerButton` A simple button. * `PostPickerToolbarButton` A button for use within `BlockControls` toolbar. @@ -11,11 +9,11 @@ Note there are several components exposed under PostPicker. ## `PostPickerButton` ``` -import PostPicker from '@humanmade/block-editor-components'; +import { PostPickerButton } from '@humanmade/block-editor-components'; ... - setAttributes( { postIds: newValue } ) } values={ attributes.postIds || [] } diff --git a/src/index.js b/src/index.js index 5eb016b..6350054 100644 --- a/src/index.js +++ b/src/index.js @@ -6,11 +6,15 @@ export { default as ImageControl } from './components/ImageControl'; export { default as InnerBlockSlider } from './components/InnerBlockSlider'; export { default as LinkToolbar } from './components/LinkToolbar'; export { default as PlainTextWithLimit } from './components/PlainTextWithLimit'; -export * as PostPicker from './components/PostPicker'; export { default as PostTitleControl } from './components/PostTitleControl'; export { default as PostTypeCheck } from './components/PostTypeCheck'; export { default as RichTextWithLimit } from './components/RichTextWithLimit'; export { default as TermSelector } from './components/TermSelector'; +export { + PostPickerButton, + PostPickerToolbarButton, + PostPickerModal, +} from './components/PostPicker'; export { default as useActiveBlockStyle } from './hooks/useActiveBlockStyle'; export { default as useBlockStyles } from './hooks/useBlockStyles'; From d45e7c4bbbd619f7ffc80528c326debfb4678eb6 Mon Sep 17 00:00:00 2001 From: Matthew Haines-Young Date: Mon, 5 Jun 2023 09:11:27 +0100 Subject: [PATCH 16/19] Update .eslintignore Remove typo --- .eslintignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.eslintignore b/.eslintignore index 751d899..c37c647 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,4 +1,3 @@ **/node_modules/ /.github/ /dist/ -e From 61fd611398a70c54070dde65c0767315c2f418ee Mon Sep 17 00:00:00 2001 From: Matthew Haines-Young Date: Mon, 5 Jun 2023 09:22:40 +0100 Subject: [PATCH 17/19] Code review feedback --- src/components/PostPicker/index.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/components/PostPicker/index.js b/src/components/PostPicker/index.js index 0ba5440..2d1eca0 100644 --- a/src/components/PostPicker/index.js +++ b/src/components/PostPicker/index.js @@ -14,10 +14,7 @@ import { Spinner, } from '@wordpress/components'; import { useSelect } from '@wordpress/data'; -import { - useState, - useMemo, -} from '@wordpress/element'; +import { useState } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import TermSelector from '../TermSelector'; @@ -148,8 +145,8 @@ function PostList( props ) { /** * Post Picker Browse Post Panel. * - * @param props - * @returns {ReactNode} Component + * @param {object} props Component props. + * @returns {ReactNode} Component. */ function BrowsePanel( props ) { const { @@ -339,8 +336,8 @@ export function PostPickerToolbarButton( props ) { <> setModalOpen( true ) } label={ title } + onClick={ () => setModalOpen( true ) } > { title } From a3ef1d9ec7500bca81a179e83df8808e1cf6b371 Mon Sep 17 00:00:00 2001 From: Matthew Haines-Young Date: Thu, 8 Jun 2023 16:46:00 +0100 Subject: [PATCH 18/19] Fitler empty values --- src/components/TermSelector/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/TermSelector/index.js b/src/components/TermSelector/index.js index 7d6b499..6993ecd 100644 --- a/src/components/TermSelector/index.js +++ b/src/components/TermSelector/index.js @@ -65,7 +65,7 @@ function TermSelector( props ) { }; }, [ taxonomy ] ); - const selectedTerms = value.map( id => taxonomyTermsById[id] ); + const selectedTerms = value.map( id => taxonomyTermsById[id] ).filter( Boolean ); return ( Date: Wed, 26 Jul 2023 13:25:49 +0100 Subject: [PATCH 19/19] Apply suggestions from code review --- src/components/PostPicker/README.md | 2 +- src/components/PostPicker/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/PostPicker/README.md b/src/components/PostPicker/README.md index 5106b64..ab7ae3f 100644 --- a/src/components/PostPicker/README.md +++ b/src/components/PostPicker/README.md @@ -8,7 +8,7 @@ There are several `PostPicker` controls. ## `PostPickerButton` -``` +```jsx import { PostPickerButton } from '@humanmade/block-editor-components'; ... diff --git a/src/components/PostPicker/index.js b/src/components/PostPicker/index.js index 2d1eca0..14e0b8a 100644 --- a/src/components/PostPicker/index.js +++ b/src/components/PostPicker/index.js @@ -321,7 +321,7 @@ export function PostPickerModal( props ) { /** * Post picker toolbar button. * - * @param props Component props. + * @param {object} props Props. * @returns {ReactNode} Component */ export function PostPickerToolbarButton( props ) {