From 96dff4acb9b532fbd28deae5441b53e67d6371ce Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Tue, 9 Feb 2021 18:45:49 +0200 Subject: [PATCH 01/14] first stab --- lib/load.php | 117 +++++++++++++ .../src/query/edit/block-setup/index.js | 101 +++++++++++ .../src/query/edit/block-setup/layout-step.js | 161 ++++++++++++++++++ .../block-library/src/query/edit/index.js | 6 +- .../src/query/edit/query-block-setup.js | 109 ++++++++++++ .../src/query/edit/query-placeholder.js | 1 + packages/block-library/src/query/editor.scss | 38 +++++ packages/block-library/src/query/index.js | 3 + 8 files changed, 533 insertions(+), 3 deletions(-) create mode 100644 packages/block-library/src/query/edit/block-setup/index.js create mode 100644 packages/block-library/src/query/edit/block-setup/layout-step.js create mode 100644 packages/block-library/src/query/edit/query-block-setup.js diff --git a/lib/load.php b/lib/load.php index 8027efa785f1e7..b691da96f6f9ba 100644 --- a/lib/load.php +++ b/lib/load.php @@ -128,3 +128,120 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/block-supports/typography.php'; require __DIR__ . '/block-supports/custom-classname.php'; require __DIR__ . '/block-supports/border.php'; + + +// Demo query patterns. +register_block_pattern_category( + 'core/query', + array( 'label' => __( 'Core Query block', 'gutenberg' ) ) +); +register_block_pattern( + 'test/query', + array( + 'title' => __( 'Query Pattern one', 'gutenberg' ), + 'categories' => array( 'core/query' ), + 'content' => ' + +
+
+ + +
+ + +
+
+ ', + ) +); + +register_block_pattern( + 'test/query-2', + array( + 'title' => __( 'Query Pattern two', 'gutenberg' ), + 'categories' => array( 'core/query' ), + 'content' => ' +
+
+ +
+ + +
+ + +
+ +
+
+ ', + ) +); + +register_block_pattern( + 'test/query-3', + array( + 'title' => __( 'Query Pattern three', 'gutenberg' ), + 'categories' => array( 'core/query' ), + 'content' => ' + +
+ + +
+
+
+ + +
+
+
+ ', + ) +); + +register_block_pattern( + 'test/query-4', + array( + 'title' => __( 'Query Pattern four', 'gutenberg' ), + 'categories' => array( 'core/query' ), + 'content' => ' +
+
+ +
+ + +
+ + +
+ +
+
+ ', + ) +); + +register_block_pattern( + 'test/query-5', + array( + 'title' => __( 'Query Pattern two', 'gutenberg' ), + 'categories' => array( 'core/query' ), + 'content' => ' +
+
+ +
+ + +
+ + +
+ +
+
+ ', + ) +); diff --git a/packages/block-library/src/query/edit/block-setup/index.js b/packages/block-library/src/query/edit/block-setup/index.js new file mode 100644 index 00000000000000..71d2422cd7fd41 --- /dev/null +++ b/packages/block-library/src/query/edit/block-setup/index.js @@ -0,0 +1,101 @@ +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { useBlockProps } from '@wordpress/block-editor'; +import { store as blocksStore } from '@wordpress/blocks'; +import { useState, useMemo } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; +import { Placeholder, Button } from '@wordpress/components'; + +/** + * Internal dependencies + */ +import LayoutSetupStep from './layout-step'; + +const BlockSetup = ( { blockName, label, steps } ) => { + const [ activeStep, setActiveStep ] = useState( 0 ); + const { blockType } = useSelect( + ( select ) => { + const { getBlockType } = select( blocksStore ); + return { blockType: getBlockType( blockName ) }; + }, + [ blockName ] + ); + const blockProps = useBlockProps(); + const setUpSteps = useMemo( () => { + return steps.map( ( step ) => { + if ( step.useLayoutSetupStep ) { + return { + ...step, + content: ( + + ), + }; + } + return step; + } ); + }, [ steps ] ); + + const icon = blockType?.icon?.src; // TODO add a default icon here + const placeholderLabel = label || blockType?.title; + + const handleNext = () => + setActiveStep( ( previousActiveStep ) => previousActiveStep + 1 ); + const handlePrevious = () => + setActiveStep( ( previousActiveStep ) => previousActiveStep - 1 ); + + const { activeStepContent, instructions } = useMemo( () => { + return { + instructions: setUpSteps[ activeStep ]?.instructions, + activeStepContent: setUpSteps[ activeStep ]?.content, + }; + }, [ activeStep, setUpSteps ] ); + const stepInfoText = `Step ${ activeStep + 1 } of ${ steps.length }:`; + return ( +
+ +
+ { activeStepContent } +
+ +
+
+ ); +}; + +const BlockSetupNavigation = ( { + handleNext, + handlePrevious, + totalSteps, + currentStep, +} ) => { + const showPrevious = currentStep !== 0; + const showNext = currentStep < totalSteps - 1; + return ( +
+ { showPrevious && ( + + ) } + { showNext && ( + + ) } +
+ ); +}; + +export default BlockSetup; diff --git a/packages/block-library/src/query/edit/block-setup/layout-step.js b/packages/block-library/src/query/edit/block-setup/layout-step.js new file mode 100644 index 00000000000000..7e6f90de9e1a0c --- /dev/null +++ b/packages/block-library/src/query/edit/block-setup/layout-step.js @@ -0,0 +1,161 @@ +/** + * WordPress dependencies + */ +import { ENTER, SPACE } from '@wordpress/keycodes'; +import { useSelect } from '@wordpress/data'; +import { useMemo } from '@wordpress/element'; +import { parse, store as blocksStore } from '@wordpress/blocks'; +import { useInstanceId } from '@wordpress/compose'; +import { + BlockPreview, + store as blockEditorStore, +} from '@wordpress/block-editor'; +import { __ } from '@wordpress/i18n'; +import { Button, VisuallyHidden } from '@wordpress/components'; + +const LayoutSetupStep = ( { + blockType, + onVariationSelect, + onBlockPatternSelect, +} ) => { + const { defaultVariation, scopeVariations, patterns } = useSelect( + ( select ) => { + const { getBlockVariations, getDefaultBlockVariation } = select( + blocksStore + ); + const { getSettings } = select( blockEditorStore ); + const { __experimentalBlockPatterns: allPatterns } = getSettings(); + const { name, isMatchingBlockPattern } = blockType; + let _patterns; + if ( isMatchingBlockPattern ) { + _patterns = allPatterns?.filter( isMatchingBlockPattern ); + } + return { + defaultVariation: getDefaultBlockVariation( name, 'block' ), + scopeVariations: getBlockVariations( name, 'block' ), + patterns: _patterns, + }; + }, + [ blockType ] + ); + // TODO check about `useAsyncList` + return ( +
+ + onVariationSelect( nextVariation ) + } + /> + { !! patterns.length && ( + + ) } +
+ ); +}; + +function PatternsPicker( { patterns, onSelect } ) { + return ( +
+
{ __( 'Available block patterns' ) }
+
+ { patterns.map( ( pattern ) => ( + + ) ) } +
+
+ ); +} + +function BlockPattern( { pattern, onSelect } ) { + const { content, viewportWidth } = pattern; + const blocks = useMemo( () => parse( content ), [ content ] ); + const instanceId = useInstanceId( BlockPattern ); + const descriptionId = `block-editor-block-patterns-list__item-description-${ instanceId }`; + + return ( +
onSelect( blocks ) } + onKeyDown={ ( event ) => { + if ( ENTER === event.keyCode || SPACE === event.keyCode ) { + onSelect( blocks ); + } + } } + tabIndex={ 0 } + aria-label={ pattern.title } + aria-describedby={ pattern.description ? descriptionId : undefined } + > + +
+ { pattern.title } +
+ { !! pattern.description && ( + + { pattern.description } + + ) } +
+ ); +} + +function BlockVariationPicker( { variations, onSelect, allowSkip } ) { + return ( +
+
{ __( 'Block variations' ) }
+ { /* + * Disable reason: The `list` ARIA role is redundant but + * Safari+VoiceOver won't announce the list otherwise. + */ + /* eslint-disable jsx-a11y/no-redundant-roles */ } +
    + { variations.map( ( variation ) => ( +
  • +
  • + ) ) } +
+ { /* eslint-enable jsx-a11y/no-redundant-roles */ } + { allowSkip && ( +
+ +
+ ) } +
+ ); +} + +export default LayoutSetupStep; diff --git a/packages/block-library/src/query/edit/index.js b/packages/block-library/src/query/edit/index.js index 9b9c2a388604c6..bffc76490c4fc0 100644 --- a/packages/block-library/src/query/edit/index.js +++ b/packages/block-library/src/query/edit/index.js @@ -7,6 +7,7 @@ import { useEffect } from '@wordpress/element'; import { BlockControls, useBlockProps, + store as blockEditorStore, __experimentalUseInnerBlocksProps as useInnerBlocksProps, store as blockEditorStore, } from '@wordpress/block-editor'; @@ -17,7 +18,7 @@ import { import QueryToolbar from './query-toolbar'; import QueryProvider from './query-provider'; import QueryInspectorControls from './query-inspector-controls'; -import QueryPlaceholder from './query-placeholder'; +import QueryBlockSetup from './query-block-setup'; import { DEFAULTS_POSTS_PER_PAGE } from '../constants'; const TEMPLATE = [ [ 'core/query-loop' ] ]; @@ -93,8 +94,7 @@ const QueryEdit = ( props ) => { !! select( blockEditorStore ).getBlocks( clientId ).length, [ clientId ] ); - const Component = hasInnerBlocks ? QueryContent : QueryPlaceholder; - + const Component = hasInnerBlocks ? QueryContent : QueryBlockSetup; return ; }; diff --git a/packages/block-library/src/query/edit/query-block-setup.js b/packages/block-library/src/query/edit/query-block-setup.js new file mode 100644 index 00000000000000..7e57b6891a1278 --- /dev/null +++ b/packages/block-library/src/query/edit/query-block-setup.js @@ -0,0 +1,109 @@ +/** + * WordPress dependencies + */ +import { useSelect, useDispatch } from '@wordpress/data'; +import { __ } from '@wordpress/i18n'; +import { SelectControl, ToggleControl } from '@wordpress/components'; +import { createBlocksFromInnerBlocksTemplate } from '@wordpress/blocks'; +import { store as blockEditorStore } from '@wordpress/block-editor'; +import { useMemo } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import BlockSetup from './block-setup'; + +const QueryBlockSetup = ( { + clientId, + attributes: { query }, + setAttributes, + name, +} ) => { + const { postType, inherit } = query; + const { replaceInnerBlocks } = useDispatch( blockEditorStore ); + const { postTypes } = useSelect( ( select ) => { + const { getPostTypes } = select( 'core' ); + const excludedPostTypes = [ 'attachment' ]; + const filteredPostTypes = getPostTypes( { per_page: -1 } )?.filter( + ( { viewable, slug } ) => + viewable && ! excludedPostTypes.includes( slug ) + ); + return { + postTypes: filteredPostTypes, + }; + }, [] ); + const updateQuery = ( newQuery ) => + setAttributes( { query: { ...query, ...newQuery } } ); + const postTypesSelectOptions = useMemo( + () => + ( postTypes || [] ).map( ( { labels, slug } ) => ( { + label: labels.singular_name, + value: slug, + } ) ), + [ postTypes ] + ); + const onFinish = ( innerBlocks ) => { + if ( innerBlocks ) { + replaceInnerBlocks( + clientId, + createBlocksFromInnerBlocksTemplate( innerBlocks ), + false + ); + } + }; + const blockSetupProps = { + // label: __( 'Set me up :)' ), + canSkip: true, + onSkip: () => {}, + steps: [ + { + instructions: __( 'Basic setup' ), + content: ( +
+ + updateQuery( { inherit: !! value } ) + } + help={ __( + 'Disable the option to customize the query arguments. Leave enabled to inherit the global query depending on the URL.' + ) } + /> + { ! inherit && ( + + updateQuery( { postType: newValue } ) + } + /> + ) } +
+ ), + }, + { + instructions: __( + 'Select a block variation or a block pattern to start with' + ), + useLayoutSetupStep: true, + onVariationSelect: ( nextVariation ) => { + if ( nextVariation.attributes ) { + setAttributes( nextVariation.attributes ); + } + if ( nextVariation.innerBlocks ) { + onFinish( nextVariation.innerBlocks ); + } + }, + showBlockPatterns: true, + onBlockPatternSelect: ( blocks ) => { + onFinish( [ [ 'core/query-loop', {}, blocks ] ] ); + }, + }, + ], + }; + return ; +}; + +export default QueryBlockSetup; diff --git a/packages/block-library/src/query/edit/query-placeholder.js b/packages/block-library/src/query/edit/query-placeholder.js index 51b31d59e11c6d..2d16b96a46a64f 100644 --- a/packages/block-library/src/query/edit/query-placeholder.js +++ b/packages/block-library/src/query/edit/query-placeholder.js @@ -5,6 +5,7 @@ import { useSelect, useDispatch } from '@wordpress/data'; import { useBlockProps, __experimentalBlockVariationPicker, + store as blockEditorStore, __experimentalGetMatchingVariation as getMatchingVariation, store as blockEditorStore, } from '@wordpress/block-editor'; diff --git a/packages/block-library/src/query/editor.scss b/packages/block-library/src/query/editor.scss index e28e6de5643246..fbc191bf2678db 100644 --- a/packages/block-library/src/query/editor.scss +++ b/packages/block-library/src/query/editor.scss @@ -9,3 +9,41 @@ .wp-block-query__create-new-link { padding: 0 $grid-unit-20 $grid-unit-20 56px; } + +.wp-block-query { + .components-placeholder { + h6 { + margin: 0 auto 10px; + } + .components-placeholder__instructions { + font-size: 14px; + } + .block-setup-navigation { + padding: 10px 0 0; + } + .block-attributes-setup-container { + padding: 20px; + .components-base-control__help { + margin: 10px auto; + } + } + .layout-step-container { + .block-patterns-picker-container { + padding-top: 10px; + border-top: 1px solid $gray-200; + .block-patterns-picker-container__grid { + box-sizing: border-box; + display: grid; + grid-template-columns: repeat(3, 1fr); + outline: none; + grid-gap: $grid-unit-10; + max-height: 200px; + overflow: auto; + .block-editor-block-preview__container { + cursor: pointer; + } + } + } + } + } +} diff --git a/packages/block-library/src/query/index.js b/packages/block-library/src/query/index.js index 62b8404c8b4f14..29bb912c693163 100644 --- a/packages/block-library/src/query/index.js +++ b/packages/block-library/src/query/index.js @@ -22,6 +22,9 @@ export const settings = { edit, save, variations, + isMatchingBlockPattern: ( pattern ) => { + return pattern.categories?.includes( 'core/query' ); + }, }; export { useQueryContext } from './edit'; From 426351f24d2a99bdabf8a9082a7cb1fbc55e2e18 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Mon, 15 Feb 2021 18:45:22 +0200 Subject: [PATCH 02/14] first iterations from design Keyboard navigation, style changes, refactor LayoutStep, create `usePostTypes` util hook --- lib/load.php | 2 +- .../src/query/edit/block-setup/index.js | 120 ++++------ .../src/query/edit/block-setup/layout-step.js | 225 ++++++++++-------- .../src/query/edit/query-block-setup.js | 140 +++++------ .../query/edit/query-inspector-controls.js | 66 ++--- packages/block-library/src/query/editor.scss | 66 +++-- packages/block-library/src/query/utils.js | 37 +++ 7 files changed, 334 insertions(+), 322 deletions(-) diff --git a/lib/load.php b/lib/load.php index b691da96f6f9ba..6403c63325689d 100644 --- a/lib/load.php +++ b/lib/load.php @@ -226,7 +226,7 @@ function gutenberg_is_experiment_enabled( $name ) { register_block_pattern( 'test/query-5', array( - 'title' => __( 'Query Pattern two', 'gutenberg' ), + 'title' => __( 'Query Pattern five', 'gutenberg' ), 'categories' => array( 'core/query' ), 'content' => '
diff --git a/packages/block-library/src/query/edit/block-setup/index.js b/packages/block-library/src/query/edit/block-setup/index.js index 71d2422cd7fd41..6606674407d69b 100644 --- a/packages/block-library/src/query/edit/block-setup/index.js +++ b/packages/block-library/src/query/edit/block-setup/index.js @@ -1,101 +1,69 @@ /** * WordPress dependencies */ -import { useSelect } from '@wordpress/data'; +// import { useSelect } from '@wordpress/data'; import { useBlockProps } from '@wordpress/block-editor'; -import { store as blocksStore } from '@wordpress/blocks'; -import { useState, useMemo } from '@wordpress/element'; -import { __ } from '@wordpress/i18n'; -import { Placeholder, Button } from '@wordpress/components'; +// import { store as blocksStore } from '@wordpress/blocks'; +// import { useState } from '@wordpress/element'; +// import { __ } from '@wordpress/i18n'; +import { Placeholder } from '@wordpress/components'; -/** - * Internal dependencies - */ -import LayoutSetupStep from './layout-step'; - -const BlockSetup = ( { blockName, label, steps } ) => { - const [ activeStep, setActiveStep ] = useState( 0 ); - const { blockType } = useSelect( - ( select ) => { - const { getBlockType } = select( blocksStore ); - return { blockType: getBlockType( blockName ) }; - }, - [ blockName ] - ); +const BlockSetup = ( { icon, label, children } ) => { + // const [ activeStep, setActiveStep ] = useState( 0 ); const blockProps = useBlockProps(); - const setUpSteps = useMemo( () => { - return steps.map( ( step ) => { - if ( step.useLayoutSetupStep ) { - return { - ...step, - content: ( - - ), - }; - } - return step; - } ); - }, [ steps ] ); - - const icon = blockType?.icon?.src; // TODO add a default icon here - const placeholderLabel = label || blockType?.title; + // const handleNext = () => + // setActiveStep( ( previousActiveStep ) => previousActiveStep + 1 ); + // const handlePrevious = () => + // setActiveStep( ( previousActiveStep ) => previousActiveStep - 1 ); - const handleNext = () => - setActiveStep( ( previousActiveStep ) => previousActiveStep + 1 ); - const handlePrevious = () => - setActiveStep( ( previousActiveStep ) => previousActiveStep - 1 ); - - const { activeStepContent, instructions } = useMemo( () => { - return { - instructions: setUpSteps[ activeStep ]?.instructions, - activeStepContent: setUpSteps[ activeStep ]?.content, - }; - }, [ activeStep, setUpSteps ] ); - const stepInfoText = `Step ${ activeStep + 1 } of ${ steps.length }:`; + // const { activeStepContent, instructions } = useMemo( () => { + // return { + // instructions: setUpSteps[ activeStep ]?.instructions, + // activeStepContent: setUpSteps[ activeStep ]?.content, + // }; + // }, [ activeStep, setUpSteps ] ); + // const stepInfoText = `Step ${ activeStep + 1 } of ${ steps.length }:`; return (
-
+ { children } + { /*
{ activeStepContent } -
- */ } + { /* + /> */ }
); }; -const BlockSetupNavigation = ( { - handleNext, - handlePrevious, - totalSteps, - currentStep, -} ) => { - const showPrevious = currentStep !== 0; - const showNext = currentStep < totalSteps - 1; - return ( -
- { showPrevious && ( - - ) } - { showNext && ( - - ) } -
- ); -}; +// const BlockSetupNavigation = ( { +// handleNext, +// handlePrevious, +// totalSteps, +// currentStep, +// } ) => { +// const showPrevious = currentStep !== 0; +// const showNext = currentStep < totalSteps - 1; +// return ( +//
+// { showPrevious && ( +// +// ) } +// { showNext && ( +// +// ) } +//
+// ); +// }; export default BlockSetup; diff --git a/packages/block-library/src/query/edit/block-setup/layout-step.js b/packages/block-library/src/query/edit/block-setup/layout-step.js index 7e6f90de9e1a0c..a6cc052956c562 100644 --- a/packages/block-library/src/query/edit/block-setup/layout-step.js +++ b/packages/block-library/src/query/edit/block-setup/layout-step.js @@ -1,9 +1,8 @@ /** * WordPress dependencies */ -import { ENTER, SPACE } from '@wordpress/keycodes'; import { useSelect } from '@wordpress/data'; -import { useMemo } from '@wordpress/element'; +import { useState, useMemo } from '@wordpress/element'; import { parse, store as blocksStore } from '@wordpress/blocks'; import { useInstanceId } from '@wordpress/compose'; import { @@ -11,14 +10,20 @@ import { store as blockEditorStore, } from '@wordpress/block-editor'; import { __ } from '@wordpress/i18n'; -import { Button, VisuallyHidden } from '@wordpress/components'; +import { + Button, + VisuallyHidden, + __unstableComposite as Composite, + __unstableUseCompositeState as useCompositeState, + __unstableCompositeItem as CompositeItem, +} from '@wordpress/components'; const LayoutSetupStep = ( { blockType, onVariationSelect, onBlockPatternSelect, } ) => { - const { defaultVariation, scopeVariations, patterns } = useSelect( + const { defaultVariation, blockVariations, patterns } = useSelect( ( select ) => { const { getBlockVariations, getDefaultBlockVariation } = select( blocksStore @@ -32,128 +37,146 @@ const LayoutSetupStep = ( { } return { defaultVariation: getDefaultBlockVariation( name, 'block' ), - scopeVariations: getBlockVariations( name, 'block' ), + blockVariations: getBlockVariations( name, 'block' ), patterns: _patterns, }; }, [ blockType ] ); + const [ showBlockVariations, setShowBlockVariations ] = useState( + ! patterns?.length + ); + // TODO check about `useAsyncList` + const composite = useCompositeState(); + // TODO check this line :) + if ( ! showBlockVariations && ! patterns?.length ) return null; + const showPatternsList = ! showBlockVariations && !! patterns.length; return ( -
- - onVariationSelect( nextVariation ) - } - /> - { !! patterns.length && ( - + { showBlockVariations && ( + <> + { blockVariations.map( ( variation ) => ( + + onVariationSelect( nextVariation ) + } + composite={ composite } + /> + ) ) } + + ) } + { ! showBlockVariations && !! blockVariations?.length && ( + { + setShowBlockVariations( true ); + } } + composite={ composite } /> ) } -
+ { showPatternsList && ( + <> + { patterns.map( ( pattern ) => ( + + ) ) } + + ) } + ); }; -function PatternsPicker( { patterns, onSelect } ) { - return ( -
-
{ __( 'Available block patterns' ) }
-
- { patterns.map( ( pattern ) => ( - - ) ) } -
-
- ); -} - -function BlockPattern( { pattern, onSelect } ) { +function BlockPattern( { pattern, onSelect, composite } ) { const { content, viewportWidth } = pattern; const blocks = useMemo( () => parse( content ), [ content ] ); - const instanceId = useInstanceId( BlockPattern ); - const descriptionId = `block-editor-block-patterns-list__item-description-${ instanceId }`; - + const descriptionId = useInstanceId( + BlockPattern, + 'block-setup-block-layout-list__item-description' + ); return (
onSelect( blocks ) } - onKeyDown={ ( event ) => { - if ( ENTER === event.keyCode || SPACE === event.keyCode ) { - onSelect( blocks ); - } - } } - tabIndex={ 0 } + className="block-setup-block-layout-list__list-item" aria-label={ pattern.title } - aria-describedby={ pattern.description ? descriptionId : undefined } + // aria-describedby={ variation.description ? descriptionId : undefined } > - -
- { pattern.title } -
- { !! pattern.description && ( - - { pattern.description } - - ) } + onSelect( blocks ) } + > + +
+ { pattern.title } +
+ { !! pattern.description && ( + + { pattern.description } + + ) } +
); } -function BlockVariationPicker( { variations, onSelect, allowSkip } ) { +function BlockVariation( { variation, title, onSelect, composite } ) { + const descriptionId = useInstanceId( + BlockVariation, + 'block-setup-block-layout-list__item-description' + ); return ( -
-
{ __( 'Block variations' ) }
- { /* - * Disable reason: The `list` ARIA role is redundant but - * Safari+VoiceOver won't announce the list otherwise. - */ - /* eslint-disable jsx-a11y/no-redundant-roles */ } -
    + onSelect( variation ) } + label={ title || variation.description || variation.title } > - { variations.map( ( variation ) => ( -
  • -
  • - ) ) } -
- { /* eslint-enable jsx-a11y/no-redundant-roles */ } - { allowSkip && ( -
- +
+
- ) } + { !! variation.description && ( + + { variation.description } + + ) } +
); } diff --git a/packages/block-library/src/query/edit/query-block-setup.js b/packages/block-library/src/query/edit/query-block-setup.js index 7e57b6891a1278..45d406a1221954 100644 --- a/packages/block-library/src/query/edit/query-block-setup.js +++ b/packages/block-library/src/query/edit/query-block-setup.js @@ -2,46 +2,40 @@ * WordPress dependencies */ import { useSelect, useDispatch } from '@wordpress/data'; -import { __ } from '@wordpress/i18n'; +import { __, _x } from '@wordpress/i18n'; import { SelectControl, ToggleControl } from '@wordpress/components'; -import { createBlocksFromInnerBlocksTemplate } from '@wordpress/blocks'; +import { + createBlocksFromInnerBlocksTemplate, + store as blocksStore, +} from '@wordpress/blocks'; import { store as blockEditorStore } from '@wordpress/block-editor'; -import { useMemo } from '@wordpress/element'; /** * Internal dependencies */ import BlockSetup from './block-setup'; +import LayoutSetupStep from './block-setup/layout-step'; +import { usePostTypes } from '../utils'; const QueryBlockSetup = ( { clientId, attributes: { query }, setAttributes, - name, + name: blockName, } ) => { const { postType, inherit } = query; const { replaceInnerBlocks } = useDispatch( blockEditorStore ); - const { postTypes } = useSelect( ( select ) => { - const { getPostTypes } = select( 'core' ); - const excludedPostTypes = [ 'attachment' ]; - const filteredPostTypes = getPostTypes( { per_page: -1 } )?.filter( - ( { viewable, slug } ) => - viewable && ! excludedPostTypes.includes( slug ) - ); - return { - postTypes: filteredPostTypes, - }; - }, [] ); + const { blockType } = useSelect( + ( select ) => { + const { getBlockType } = select( blocksStore ); + return { blockType: getBlockType( blockName ) }; + }, + [ blockName ] + ); + const { postTypesSelectOptions } = usePostTypes(); const updateQuery = ( newQuery ) => setAttributes( { query: { ...query, ...newQuery } } ); - const postTypesSelectOptions = useMemo( - () => - ( postTypes || [] ).map( ( { labels, slug } ) => ( { - label: labels.singular_name, - value: slug, - } ) ), - [ postTypes ] - ); + const onFinish = ( innerBlocks ) => { if ( innerBlocks ) { replaceInnerBlocks( @@ -51,59 +45,57 @@ const QueryBlockSetup = ( { ); } }; - const blockSetupProps = { - // label: __( 'Set me up :)' ), - canSkip: true, - onSkip: () => {}, - steps: [ - { - instructions: __( 'Basic setup' ), - content: ( -
- - updateQuery( { inherit: !! value } ) + const onVariationSelect = ( nextVariation ) => { + if ( nextVariation.attributes ) { + setAttributes( nextVariation.attributes ); + } + if ( nextVariation.innerBlocks ) { + onFinish( nextVariation.innerBlocks ); + } + }; + const onBlockPatternSelect = ( blocks ) => { + onFinish( [ [ 'core/query-loop', {}, blocks ] ] ); + }; + const inheritToggleHelp = !! inherit + ? _x( + 'Inherit the global query depending on the URL.', + 'Query block `inherit` option helping text' + ) + : _x( + 'Customize the query arguments.', + 'Query block `inherit` option helping text' + ); + return ( + + <> + +
+ + updateQuery( { inherit: !! value } ) + } + help={ inheritToggleHelp } + /> + { ! inherit && ( + + updateQuery( { postType: newValue } ) } - help={ __( - 'Disable the option to customize the query arguments. Leave enabled to inherit the global query depending on the URL.' - ) } /> - { ! inherit && ( - - updateQuery( { postType: newValue } ) - } - /> - ) } -
- ), - }, - { - instructions: __( - 'Select a block variation or a block pattern to start with' - ), - useLayoutSetupStep: true, - onVariationSelect: ( nextVariation ) => { - if ( nextVariation.attributes ) { - setAttributes( nextVariation.attributes ); - } - if ( nextVariation.innerBlocks ) { - onFinish( nextVariation.innerBlocks ); - } - }, - showBlockPatterns: true, - onBlockPatternSelect: ( blocks ) => { - onFinish( [ [ 'core/query-loop', {}, blocks ] ] ); - }, - }, - ], - }; - return ; + ) } +
+ + + ); }; export default QueryBlockSetup; diff --git a/packages/block-library/src/query/edit/query-inspector-controls.js b/packages/block-library/src/query/edit/query-inspector-controls.js index 188f5fdc9161f1..1b982e6d971f62 100644 --- a/packages/block-library/src/query/edit/query-inspector-controls.js +++ b/packages/block-library/src/query/edit/query-inspector-controls.js @@ -25,7 +25,6 @@ import { useEffect, useState, useCallback, - useMemo, createInterpolateElement, } from '@wordpress/element'; import { store as coreStore } from '@wordpress/core-data'; @@ -33,7 +32,7 @@ import { store as coreStore } from '@wordpress/core-data'; /** * Internal dependencies */ -import { getTermsInfo } from '../utils'; +import { getTermsInfo, usePostTypes } from '../utils'; import { MAX_FETCHED_TERMS } from '../constants'; const stickyOptions = [ @@ -73,43 +72,24 @@ export default function QueryInspectorControls( { const [ showCategories, setShowCategories ] = useState( true ); const [ showTags, setShowTags ] = useState( true ); const [ showSticky, setShowSticky ] = useState( postType === 'post' ); - const { authorList, categories, tags, postTypes } = useSelect( - ( select ) => { - const { getEntityRecords, getPostTypes } = select( coreStore ); - const termsQuery = { per_page: MAX_FETCHED_TERMS }; - const _categories = getEntityRecords( - 'taxonomy', - 'category', - termsQuery - ); - const _tags = getEntityRecords( - 'taxonomy', - 'post_tag', - termsQuery - ); - const excludedPostTypes = [ 'attachment' ]; - const filteredPostTypes = getPostTypes( { per_page: -1 } )?.filter( - ( { viewable, slug } ) => - viewable && ! excludedPostTypes.includes( slug ) - ); - return { - categories: getTermsInfo( _categories ), - tags: getTermsInfo( _tags ), - authorList: getEntityRecords( 'root', 'user', { - per_page: -1, - } ), - postTypes: filteredPostTypes, - }; - }, - [] - ); - const postTypesTaxonomiesMap = useMemo( () => { - if ( ! postTypes?.length ) return; - return postTypes.reduce( ( accumulator, type ) => { - accumulator[ type.slug ] = type.taxonomies; - return accumulator; - }, {} ); - }, [ postTypes ] ); + const { postTypesTaxonomiesMap, postTypesSelectOptions } = usePostTypes(); + const { authorList, categories, tags } = useSelect( ( select ) => { + const { getEntityRecords } = select( coreStore ); + const termsQuery = { per_page: MAX_FETCHED_TERMS }; + const _categories = getEntityRecords( + 'taxonomy', + 'category', + termsQuery + ); + const _tags = getEntityRecords( 'taxonomy', 'post_tag', termsQuery ); + return { + categories: getTermsInfo( _categories ), + tags: getTermsInfo( _tags ), + authorList: getEntityRecords( 'root', 'user', { + per_page: -1, + } ), + }; + }, [] ); useEffect( () => { if ( ! postTypesTaxonomiesMap ) return; const postTypeTaxonomies = postTypesTaxonomiesMap[ postType ]; @@ -119,14 +99,6 @@ export default function QueryInspectorControls( { useEffect( () => { setShowSticky( postType === 'post' ); }, [ postType ] ); - const postTypesSelectOptions = useMemo( - () => - ( postTypes || [] ).map( ( { labels, slug } ) => ( { - label: labels.singular_name, - value: slug, - } ) ), - [ postTypes ] - ); const onPostTypeChange = ( newValue ) => { const updateQuery = { postType: newValue }; if ( ! postTypesTaxonomiesMap[ newValue ].includes( 'category' ) ) { diff --git a/packages/block-library/src/query/editor.scss b/packages/block-library/src/query/editor.scss index fbc191bf2678db..459a7f2f6781bc 100644 --- a/packages/block-library/src/query/editor.scss +++ b/packages/block-library/src/query/editor.scss @@ -12,37 +12,57 @@ .wp-block-query { .components-placeholder { - h6 { - margin: 0 auto 10px; - } - .components-placeholder__instructions { - font-size: 14px; - } .block-setup-navigation { padding: 10px 0 0; } .block-attributes-setup-container { - padding: 20px; + padding: 20px 0; .components-base-control__help { margin: 10px auto; } } - .layout-step-container { - .block-patterns-picker-container { - padding-top: 10px; - border-top: 1px solid $gray-200; - .block-patterns-picker-container__grid { - box-sizing: border-box; - display: grid; - grid-template-columns: repeat(3, 1fr); - outline: none; - grid-gap: $grid-unit-10; - max-height: 200px; - overflow: auto; - .block-editor-block-preview__container { - cursor: pointer; - } - } + } +} + +.block-setup-block-layout-list__container { + display: flex; + flex-direction: row; + flex-wrap: wrap; + // align-items: flex-end; // Should we add some alignment here? + .block-setup-block-layout-list__list-item { + cursor: pointer; + margin: $grid-unit-10 $grid-unit-10 0 0; + width: 200px; + text-align: center; + &.is-block-variation { + width: 85px; + button { + display: inline-flex; + margin-right: 0; + height: auto; + } + } + .block-setup-block-layout-list__item { + height: 100%; + padding: 2px; + border-radius: $radius-block-ui; + transition: all 0.05s ease-in-out; + border: $border-width solid transparent; + &:hover { + border: $border-width solid var(--wp-admin-theme-color); + } + &:focus { + box-shadow: inset 0 0 0 1px $white, 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color); + // Windows High Contrast mode will show this outline, but not the box-shadow. + outline: 2px solid transparent; + } + .block-setup-block-layout-list__item-title { + padding: $grid-unit-05; + font-size: 12px; + text-align: center; + } + .block-editor-block-preview__container { + cursor: pointer; // This is for the BlockPreview. } } } diff --git a/packages/block-library/src/query/utils.js b/packages/block-library/src/query/utils.js index 2e55a6b9365ced..87b94b3bb80a4d 100644 --- a/packages/block-library/src/query/utils.js +++ b/packages/block-library/src/query/utils.js @@ -1,3 +1,9 @@ +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { useMemo } from '@wordpress/element'; + /** * WordPress term object from REST API. * Categories ref: https://developer.wordpress.org/rest-api/reference/categories/ @@ -45,3 +51,34 @@ export const getTermsInfo = ( terms ) => ( { { mapById: {}, mapByName: {}, names: [] } ), } ); + +// TODO jsdoc +export const usePostTypes = () => { + const { postTypes } = useSelect( ( select ) => { + const { getPostTypes } = select( 'core' ); + const excludedPostTypes = [ 'attachment' ]; + const filteredPostTypes = getPostTypes( { per_page: -1 } )?.filter( + ( { viewable, slug } ) => + viewable && ! excludedPostTypes.includes( slug ) + ); + return { + postTypes: filteredPostTypes, + }; + }, [] ); + const postTypesTaxonomiesMap = useMemo( () => { + if ( ! postTypes?.length ) return; + return postTypes.reduce( ( accumulator, type ) => { + accumulator[ type.slug ] = type.taxonomies; + return accumulator; + }, {} ); + }, [ postTypes ] ); + const postTypesSelectOptions = useMemo( + () => + ( postTypes || [] ).map( ( { labels, slug } ) => ( { + label: labels.singular_name, + value: slug, + } ) ), + [ postTypes ] + ); + return { postTypesTaxonomiesMap, postTypesSelectOptions }; +}; From 6494ed884095d6c700b4642d7a45d62ce3529675 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Thu, 18 Feb 2021 10:35:11 +0200 Subject: [PATCH 03/14] remove duplicate imports from rebase --- packages/block-library/src/query/edit/index.js | 1 - packages/block-library/src/query/edit/query-placeholder.js | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/block-library/src/query/edit/index.js b/packages/block-library/src/query/edit/index.js index bffc76490c4fc0..5d6b59c033e2a7 100644 --- a/packages/block-library/src/query/edit/index.js +++ b/packages/block-library/src/query/edit/index.js @@ -9,7 +9,6 @@ import { useBlockProps, store as blockEditorStore, __experimentalUseInnerBlocksProps as useInnerBlocksProps, - store as blockEditorStore, } from '@wordpress/block-editor'; /** diff --git a/packages/block-library/src/query/edit/query-placeholder.js b/packages/block-library/src/query/edit/query-placeholder.js index 2d16b96a46a64f..63bf146be5800b 100644 --- a/packages/block-library/src/query/edit/query-placeholder.js +++ b/packages/block-library/src/query/edit/query-placeholder.js @@ -7,7 +7,6 @@ import { __experimentalBlockVariationPicker, store as blockEditorStore, __experimentalGetMatchingVariation as getMatchingVariation, - store as blockEditorStore, } from '@wordpress/block-editor'; import { createBlocksFromInnerBlocksTemplate, From 773d9fa2437217cbf913414d69f419aadaaa02a9 Mon Sep 17 00:00:00 2001 From: ntsekouras Date: Thu, 18 Feb 2021 16:41:23 +0200 Subject: [PATCH 04/14] design iteration part 2 + keyboard navigation --- .../src/query/edit/block-setup/index.js | 80 ++++------ .../src/query/edit/block-setup/layout-step.js | 143 ++++++++++-------- .../src/query/edit/query-block-setup.js | 64 +++----- packages/block-library/src/query/editor.scss | 28 +++- 4 files changed, 163 insertions(+), 152 deletions(-) diff --git a/packages/block-library/src/query/edit/block-setup/index.js b/packages/block-library/src/query/edit/block-setup/index.js index 6606674407d69b..37008b6010ff7e 100644 --- a/packages/block-library/src/query/edit/block-setup/index.js +++ b/packages/block-library/src/query/edit/block-setup/index.js @@ -1,69 +1,49 @@ /** * WordPress dependencies */ -// import { useSelect } from '@wordpress/data'; +import { useSelect } from '@wordpress/data'; import { useBlockProps } from '@wordpress/block-editor'; -// import { store as blocksStore } from '@wordpress/blocks'; -// import { useState } from '@wordpress/element'; -// import { __ } from '@wordpress/i18n'; +import { store as blocksStore } from '@wordpress/blocks'; import { Placeholder } from '@wordpress/components'; -const BlockSetup = ( { icon, label, children } ) => { - // const [ activeStep, setActiveStep ] = useState( 0 ); - const blockProps = useBlockProps(); - // const handleNext = () => - // setActiveStep( ( previousActiveStep ) => previousActiveStep + 1 ); - // const handlePrevious = () => - // setActiveStep( ( previousActiveStep ) => previousActiveStep - 1 ); +/** + * Internal dependencies + */ +import LayoutSetupStep from './layout-step'; - // const { activeStepContent, instructions } = useMemo( () => { - // return { - // instructions: setUpSteps[ activeStep ]?.instructions, - // activeStepContent: setUpSteps[ activeStep ]?.content, - // }; - // }, [ activeStep, setUpSteps ] ); - // const stepInfoText = `Step ${ activeStep + 1 } of ${ steps.length }:`; +const BlockSetup = ( { + blockName, + useLayoutSetup, + onVariationSelect = () => {}, + onBlockPatternSelect = () => {}, + children, +} ) => { + const { blockType } = useSelect( + ( select ) => { + const { getBlockType } = select( blocksStore ); + return { blockType: getBlockType( blockName ) }; + }, + [ blockName ] + ); + const blockProps = useBlockProps(); return (
+ { useLayoutSetup && ( + + ) } { children } - { /*
- { activeStepContent } -
*/ } - { /* */ }
); }; -// const BlockSetupNavigation = ( { -// handleNext, -// handlePrevious, -// totalSteps, -// currentStep, -// } ) => { -// const showPrevious = currentStep !== 0; -// const showNext = currentStep < totalSteps - 1; -// return ( -//
-// { showPrevious && ( -// -// ) } -// { showNext && ( -// -// ) } -//
-// ); -// }; - export default BlockSetup; diff --git a/packages/block-library/src/query/edit/block-setup/layout-step.js b/packages/block-library/src/query/edit/block-setup/layout-step.js index a6cc052956c562..5dc538a0308d21 100644 --- a/packages/block-library/src/query/edit/block-setup/layout-step.js +++ b/packages/block-library/src/query/edit/block-setup/layout-step.js @@ -9,21 +9,29 @@ import { BlockPreview, store as blockEditorStore, } from '@wordpress/block-editor'; -import { __ } from '@wordpress/i18n'; +import { __, isRTL } from '@wordpress/i18n'; import { Button, + Icon, VisuallyHidden, __unstableComposite as Composite, __unstableUseCompositeState as useCompositeState, __unstableCompositeItem as CompositeItem, } from '@wordpress/components'; +import { chevronRight, chevronLeft } from '@wordpress/icons'; const LayoutSetupStep = ( { blockType, onVariationSelect, onBlockPatternSelect, } ) => { - const { defaultVariation, blockVariations, patterns } = useSelect( + const [ showBack, setShowBack ] = useState( false ); + const { + defaultVariation, + blockVariations, + patterns, + hasBlockVariations, + } = useSelect( ( select ) => { const { getBlockVariations, getDefaultBlockVariation } = select( blocksStore @@ -32,71 +40,89 @@ const LayoutSetupStep = ( { const { __experimentalBlockPatterns: allPatterns } = getSettings(); const { name, isMatchingBlockPattern } = blockType; let _patterns; + // TODO create selector if ( isMatchingBlockPattern ) { _patterns = allPatterns?.filter( isMatchingBlockPattern ); } + const _blockVariations = getBlockVariations( name, 'block' ); return { defaultVariation: getDefaultBlockVariation( name, 'block' ), - blockVariations: getBlockVariations( name, 'block' ), + blockVariations: _blockVariations, patterns: _patterns, + hasBlockVariations: !! _blockVariations?.length, }; }, [ blockType ] ); const [ showBlockVariations, setShowBlockVariations ] = useState( - ! patterns?.length + ! patterns?.length && hasBlockVariations ); - - // TODO check about `useAsyncList` const composite = useCompositeState(); - // TODO check this line :) - if ( ! showBlockVariations && ! patterns?.length ) return null; + // Show nothing if block variations and block pattterns do not exist. + if ( ! hasBlockVariations && ! patterns?.length ) return null; + const showPatternsList = ! showBlockVariations && !! patterns.length; return ( - - { showBlockVariations && ( - <> - { blockVariations.map( ( variation ) => ( - - onVariationSelect( nextVariation ) - } - composite={ composite } - /> - ) ) } - - ) } - { ! showBlockVariations && !! blockVariations?.length && ( - { - setShowBlockVariations( true ); + <> + { showBack && ( + ) } - + + { showBlockVariations && ( + <> + { blockVariations.map( ( variation ) => ( + onVariationSelect( nextVariation ) } + composite={ composite } + /> + ) ) } + + ) } + { ! showBlockVariations && hasBlockVariations && ( + { + setShowBack( true ); + setShowBlockVariations( true ); + } } + composite={ composite } + /> + ) } + { showPatternsList && ( + <> + { patterns.map( ( pattern ) => ( + + ) ) } + + ) } + + ); }; @@ -158,18 +184,11 @@ function BlockVariation( { variation, title, onSelect, composite } ) { onClick={ () => onSelect( variation ) } label={ title || variation.description || variation.title } > -
-