diff --git a/packages/base-styles/_z-index.scss b/packages/base-styles/_z-index.scss
index b028f3d3023b58..8baf03c3fa61bb 100644
--- a/packages/base-styles/_z-index.scss
+++ b/packages/base-styles/_z-index.scss
@@ -76,6 +76,11 @@ $z-layers: (
// should overlap most block content.
".block-editor-block-list__block.is-{selected,hovered} .block-editor-block-mover": 61,
+ // Query block setup state.
+ ".block-editor-block-pattern-setup .pattern-slide": 100,
+ ".block-editor-block-pattern-setup .{next,previous}-slide": 101,
+ ".block-editor-block-pattern-setup .active-slide": 102,
+
// Show sidebar above wp-admin navigation bar for mobile viewports:
// #wpadminbar { z-index: 99999 }
".interface-interface-skeleton__sidebar": 100000,
diff --git a/packages/block-editor/src/components/block-pattern-setup/constants.js b/packages/block-editor/src/components/block-pattern-setup/constants.js
new file mode 100644
index 00000000000000..07e03528f1d257
--- /dev/null
+++ b/packages/block-editor/src/components/block-pattern-setup/constants.js
@@ -0,0 +1,4 @@
+export const VIEWMODES = {
+ carousel: 'carousel',
+ grid: 'grid',
+};
diff --git a/packages/block-editor/src/components/block-pattern-setup/index.js b/packages/block-editor/src/components/block-pattern-setup/index.js
new file mode 100644
index 00000000000000..26c5533be8c840
--- /dev/null
+++ b/packages/block-editor/src/components/block-pattern-setup/index.js
@@ -0,0 +1,184 @@
+/**
+ * WordPress dependencies
+ */
+import { useDispatch } from '@wordpress/data';
+import { cloneBlock } from '@wordpress/blocks';
+import {
+ VisuallyHidden,
+ __unstableComposite as Composite,
+ __unstableUseCompositeState as useCompositeState,
+ __unstableCompositeItem as CompositeItem,
+} from '@wordpress/components';
+
+import { useState } from '@wordpress/element';
+import { useInstanceId } from '@wordpress/compose';
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies
+ */
+import { store as blockEditorStore } from '../../store';
+import BlockPreview from '../block-preview';
+import SetupToolbar from './setup-toolbar';
+import usePatternsSetup from './use-patterns-setup';
+import { VIEWMODES } from './constants';
+
+const SetupContent = ( {
+ viewMode,
+ activeSlide,
+ patterns,
+ onBlockPatternSelect,
+} ) => {
+ const composite = useCompositeState();
+ const containerClass = 'block-editor-block-pattern-setup__container';
+ if ( viewMode === VIEWMODES.carousel ) {
+ const slideClass = new Map( [
+ [ activeSlide, 'active-slide' ],
+ [ activeSlide - 1, 'previous-slide' ],
+ [ activeSlide + 1, 'next-slide' ],
+ ] );
+ return (
+
+
+ { patterns.map( ( pattern, index ) => (
+
+ ) ) }
+
+
+ );
+ }
+ return (
+
+ { patterns.map( ( pattern ) => (
+
+ ) ) }
+
+ );
+};
+
+function BlockPattern( { pattern, onSelect, composite } ) {
+ const baseClassName = 'block-editor-block-pattern-setup-list';
+ const { blocks, title, description, viewportWidth = 700 } = pattern;
+ const descriptionId = useInstanceId(
+ BlockPattern,
+ `${ baseClassName }__item-description`
+ );
+ return (
+
+
onSelect( blocks ) }
+ >
+
+
+ { title }
+
+
+ { !! description && (
+
+ { description }
+
+ ) }
+
+ );
+}
+
+function BlockPatternSlide( { className, pattern } ) {
+ const { blocks, title, description } = pattern;
+ const descriptionId = useInstanceId(
+ BlockPatternSlide,
+ 'block-editor-block-pattern-setup-list__item-description'
+ );
+ return (
+
+
+ { !! description && (
+
+ { description }
+
+ ) }
+
+ );
+}
+
+const BlockPatternSetup = ( {
+ clientId,
+ blockName,
+ filterPatternsFn,
+ startBlankComponent,
+} ) => {
+ const [ viewMode, setViewMode ] = useState( VIEWMODES.carousel );
+ const [ activeSlide, setActiveSlide ] = useState( 0 );
+ const [ showBlank, setShowBlank ] = useState( false );
+ const { replaceBlock } = useDispatch( blockEditorStore );
+ const patterns = usePatternsSetup( clientId, blockName, filterPatternsFn );
+
+ if ( ! patterns?.length || showBlank ) {
+ return startBlankComponent;
+ }
+
+ const onBlockPatternSelect = ( blocks ) => {
+ const clonedBlocks = blocks.map( ( block ) => cloneBlock( block ) );
+ replaceBlock( clientId, clonedBlocks );
+ };
+ return (
+
+ {
+ setActiveSlide( ( active ) => active + 1 );
+ } }
+ handlePrevious={ () => {
+ setActiveSlide( ( active ) => active - 1 );
+ } }
+ onBlockPatternSelect={ () => {
+ onBlockPatternSelect( patterns[ activeSlide ].blocks );
+ } }
+ onStartBlank={ () => {
+ setShowBlank( true );
+ } }
+ />
+
+
+ );
+};
+
+export default BlockPatternSetup;
diff --git a/packages/block-editor/src/components/block-pattern-setup/setup-toolbar.js b/packages/block-editor/src/components/block-pattern-setup/setup-toolbar.js
new file mode 100644
index 00000000000000..7eba89edb25793
--- /dev/null
+++ b/packages/block-editor/src/components/block-pattern-setup/setup-toolbar.js
@@ -0,0 +1,97 @@
+/**
+ * WordPress dependencies
+ */
+import { __ } from '@wordpress/i18n';
+import { Button } from '@wordpress/components';
+import {
+ chevronRight,
+ chevronLeft,
+ grid,
+ stretchFullWidth,
+} from '@wordpress/icons';
+
+/**
+ * Internal dependencies
+ */
+import { VIEWMODES } from './constants';
+
+const Actions = ( { onStartBlank, onBlockPatternSelect } ) => (
+
+
+
+
+);
+
+const CarouselNavigation = ( {
+ handlePrevious,
+ handleNext,
+ activeSlide,
+ totalSlides,
+} ) => (
+
+
+
+
+);
+
+const SetupToolbar = ( {
+ viewMode,
+ setViewMode,
+ handlePrevious,
+ handleNext,
+ activeSlide,
+ totalSlides,
+ onBlockPatternSelect,
+ onStartBlank,
+} ) => {
+ const isCarouselView = viewMode === VIEWMODES.carousel;
+ const displayControls = (
+
+
+ );
+ return (
+
+ { isCarouselView && (
+
+ ) }
+ { displayControls }
+ { isCarouselView && (
+
+ ) }
+
+ );
+};
+
+export default SetupToolbar;
diff --git a/packages/block-editor/src/components/block-pattern-setup/style.scss b/packages/block-editor/src/components/block-pattern-setup/style.scss
new file mode 100644
index 00000000000000..a1876fd5c6022e
--- /dev/null
+++ b/packages/block-editor/src/components/block-pattern-setup/style.scss
@@ -0,0 +1,128 @@
+.block-editor-block-pattern-setup {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: flex-start;
+ width: 100%;
+ border-radius: $radius-block-ui;
+ box-shadow: inset 0 0 0 $border-width $gray-900;
+ outline: 1px solid transparent; // Shown for Windows 10 High Contrast mode.
+
+ // TODO change to check parent.
+ &.view-mode-grid {
+ .block-editor-block-pattern-setup__toolbar {
+ justify-content: center;
+ }
+
+ .block-editor-block-pattern-setup__container {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ grid-gap: $grid-unit-20;
+ padding: $grid-unit-20;
+ max-height: 550px;
+ overflow: auto;
+ margin: 0 $border-width $border-width $border-width;
+ width: calc(100% - #{ $border-width * 2 });
+ background: $white;
+
+ .block-editor-block-preview__container,
+ div[role="button"] {
+ cursor: pointer;
+ }
+
+ .block-editor-block-pattern-setup-list__item-title {
+ padding: $grid-unit-05;
+ font-size: $helptext-font-size;
+ text-align: center;
+ }
+
+ .block-editor-block-preview__container {
+ border-radius: $radius-block-ui;
+ border: $border-width solid $gray-300;
+ }
+ }
+ }
+
+ .block-editor-block-pattern-setup__toolbar {
+ box-sizing: border-box;
+ position: relative;
+ padding: $grid-unit-20;
+ width: 100%;
+ text-align: left;
+ margin: 0;
+ color: $gray-900;
+ // Block UI appearance.
+ border-radius: $radius-block-ui $radius-block-ui 0 0;
+ background-color: $white;
+ box-shadow: inset 0 0 0 $border-width $gray-900;
+ outline: 1px solid transparent; // Shown for Windows 10 High Contrast mode.
+
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: space-between;
+
+ .block-editor-block-pattern-setup__display-controls {
+ display: flex;
+ }
+
+ .block-editor-block-pattern-setup__navigation,
+ .block-editor-block-pattern-setup__actions {
+ width: calc(50% - 36px); // This ensures the grid / list toggle is centrally aligned.
+ display: flex;
+ }
+
+ .block-editor-block-pattern-setup__actions {
+ justify-content: flex-end;
+ }
+ }
+ .block-editor-block-pattern-setup__container {
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ box-sizing: border-box;
+
+ .carousel-container {
+ overflow: hidden;
+ text-align: center;
+ position: relative;
+ padding: 0;
+ margin: 0;
+ list-style: none;
+ transform-style: preserve-3d;
+ * {
+ box-sizing: border-box;
+ }
+ .pattern-slide {
+ opacity: 0;
+ position: absolute;
+ top: 0;
+ width: 100%;
+ margin: auto;
+ padding: $grid-unit-20;
+ transition: transform 0.5s, opacity 0.5s, z-index 0.5s;
+ z-index: z-index(".block-editor-block-pattern-setup .pattern-slide");
+
+ &.active-slide {
+ opacity: 1;
+ position: relative;
+ z-index: z-index(".block-editor-block-pattern-setup .active-slide");
+ }
+
+ &.previous-slide {
+ transform: translateX(-100%);
+ z-index: z-index(".block-editor-block-pattern-setup .{next,previous}-slide");
+ }
+
+ &.next-slide {
+ transform: translateX(100%);
+ z-index: z-index(".block-editor-block-pattern-setup .{next,previous}-slide");
+ }
+ }
+ }
+
+ .block-list-appender {
+ display: none;
+ }
+ }
+}
diff --git a/packages/block-editor/src/components/block-pattern-setup/use-patterns-setup.js b/packages/block-editor/src/components/block-pattern-setup/use-patterns-setup.js
new file mode 100644
index 00000000000000..1b6a90b87457a0
--- /dev/null
+++ b/packages/block-editor/src/components/block-pattern-setup/use-patterns-setup.js
@@ -0,0 +1,34 @@
+/**
+ * WordPress dependencies
+ */
+import { useSelect } from '@wordpress/data';
+
+/**
+ * Internal dependencies
+ */
+import { store as blockEditorStore } from '../../store';
+
+function usePatternsSetup( clientId, blockName, filterPatternsFn ) {
+ return useSelect(
+ ( select ) => {
+ const {
+ getBlockRootClientId,
+ __experimentalGetPatternsByBlockTypes,
+ __experimentalGetAllowedPatterns,
+ } = select( blockEditorStore );
+ const rootClientId = getBlockRootClientId( clientId );
+ if ( filterPatternsFn ) {
+ return __experimentalGetAllowedPatterns( rootClientId ).filter(
+ filterPatternsFn
+ );
+ }
+ return __experimentalGetPatternsByBlockTypes(
+ blockName,
+ rootClientId
+ );
+ },
+ [ clientId, blockName, filterPatternsFn ]
+ );
+}
+
+export default usePatternsSetup;
diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js
index dc88ae5a36deb3..64c5b34a8b4d16 100644
--- a/packages/block-editor/src/components/index.js
+++ b/packages/block-editor/src/components/index.js
@@ -27,6 +27,7 @@ export { BlockNavigationBlockFill as __experimentalBlockNavigationBlockFill } fr
export { default as __experimentalBlockNavigationEditor } from './block-navigation/editor';
export { default as __experimentalBlockNavigationTree } from './block-navigation/tree';
export { default as __experimentalBlockVariationPicker } from './block-variation-picker';
+export { default as __experimentalBlockPatternSetup } from './block-pattern-setup';
export { default as __experimentalBlockVariationTransforms } from './block-variation-transforms';
export {
BlockVerticalAlignmentToolbar,
diff --git a/packages/block-editor/src/style.scss b/packages/block-editor/src/style.scss
index 745e64a980d2a9..515f4195850007 100644
--- a/packages/block-editor/src/style.scss
+++ b/packages/block-editor/src/style.scss
@@ -26,6 +26,7 @@
@import "./components/block-switcher/style.scss";
@import "./components/block-types-list/style.scss";
@import "./components/block-variation-picker/style.scss";
+@import "./components/block-pattern-setup/style.scss";
@import "./components/block-variation-transforms/style.scss";
@import "./components/border-style-control/style.scss";
@import "./components/button-block-appender/style.scss";
diff --git a/packages/block-library/src/query/edit/block-setup/index.js b/packages/block-library/src/query/edit/block-setup/index.js
deleted file mode 100644
index 37008b6010ff7e..00000000000000
--- a/packages/block-library/src/query/edit/block-setup/index.js
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * WordPress dependencies
- */
-import { useSelect } from '@wordpress/data';
-import { useBlockProps } from '@wordpress/block-editor';
-import { store as blocksStore } from '@wordpress/blocks';
-import { Placeholder } from '@wordpress/components';
-
-/**
- * Internal dependencies
- */
-import LayoutSetupStep from './layout-step';
-
-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 }
-
-
- );
-};
-
-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
deleted file mode 100644
index 9df6893856722f..00000000000000
--- a/packages/block-library/src/query/edit/block-setup/layout-step.js
+++ /dev/null
@@ -1,200 +0,0 @@
-/**
- * WordPress dependencies
- */
-import { useSelect } from '@wordpress/data';
-import { useState } from '@wordpress/element';
-import { store as blocksStore } from '@wordpress/blocks';
-import { useInstanceId } from '@wordpress/compose';
-import {
- BlockPreview,
- store as blockEditorStore,
-} from '@wordpress/block-editor';
-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 [ showBack, setShowBack ] = useState( false );
- const {
- defaultVariation,
- blockVariations,
- patterns,
- hasBlockVariations,
- } = useSelect(
- ( select ) => {
- const { getBlockVariations, getDefaultBlockVariation } = select(
- blocksStore
- );
- const { __experimentalGetPatternsByBlockTypes } = select(
- blockEditorStore
- );
- const { name } = blockType;
- const _patterns = __experimentalGetPatternsByBlockTypes( name );
- const _blockVariations = getBlockVariations( name, 'block' );
- return {
- defaultVariation: getDefaultBlockVariation( name, 'block' ),
- blockVariations: _blockVariations,
- patterns: _patterns,
- hasBlockVariations: !! _blockVariations?.length,
- };
- },
- [ blockType ]
- );
- const [ showBlockVariations, setShowBlockVariations ] = useState(
- ! patterns?.length && hasBlockVariations
- );
- const composite = useCompositeState();
- // Show nothing if block variations and block pattterns do not exist.
- if ( ! hasBlockVariations && ! patterns?.length ) return null;
-
- const showPatternsList = ! showBlockVariations && !! patterns.length;
- return (
- <>
- { showBack && (
- {
- setShowBack( false );
- setShowBlockVariations( false );
- } }
- >
- { __( 'Back' ) }
-
- ) }
-
- { showBlockVariations && (
- <>
- { blockVariations.map( ( variation ) => (
- onVariationSelect( nextVariation ) }
- composite={ composite }
- />
- ) ) }
- >
- ) }
- { showPatternsList && (
- <>
- { patterns.map( ( pattern ) => (
-
- ) ) }
- >
- ) }
- { ! showBlockVariations && hasBlockVariations && (
- {
- setShowBack( true );
- setShowBlockVariations( true );
- } }
- composite={ composite }
- />
- ) }
-
- >
- );
-};
-
-function BlockPattern( { pattern, onSelect, composite } ) {
- const { viewportWidth, blocks } = pattern;
- const descriptionId = useInstanceId(
- BlockPattern,
- 'block-setup-block-layout-list__item-description'
- );
- return (
-
-
onSelect( blocks ) }
- >
-
-
-
- { pattern.title }
-
- { !! pattern.description && (
-
- { pattern.description }
-
- ) }
-
- );
-}
-
-function BlockVariation( { variation, onSelect, composite } ) {
- const descriptionId = useInstanceId(
- BlockVariation,
- 'block-setup-block-layout-list__item-description'
- );
- return (
-
-
onSelect( variation ) }
- label={ variation.description || variation.title }
- >
- { variation.icon && (
-
-
-
- ) }
-
-
- { variation.title }
-
- { !! variation.description && (
-
- { variation.description }
-
- ) }
-
- );
-}
-
-export default LayoutSetupStep;
diff --git a/packages/block-library/src/query/edit/index.js b/packages/block-library/src/query/edit/index.js
index ce83e54e6c97ad..c64acc48b2f41c 100644
--- a/packages/block-library/src/query/edit/index.js
+++ b/packages/block-library/src/query/edit/index.js
@@ -9,6 +9,7 @@ import {
useBlockProps,
store as blockEditorStore,
__experimentalUseInnerBlocksProps as useInnerBlocksProps,
+ __experimentalBlockPatternSetup as BlockPatternSetup,
} from '@wordpress/block-editor';
/**
@@ -16,7 +17,7 @@ import {
*/
import QueryToolbar from './query-toolbar';
import QueryInspectorControls from './query-inspector-controls';
-import QueryBlockSetup from './query-block-setup';
+import QueryPlaceholder from './query-placeholder';
import { DEFAULTS_POSTS_PER_PAGE } from '../constants';
const TEMPLATE = [ [ 'core/query-loop' ] ];
@@ -87,6 +88,22 @@ export function QueryContent( { attributes, setAttributes } ) {
);
}
+function QueryPatternSetup( props ) {
+ const { clientId, name: blockName } = props;
+ const blockProps = useBlockProps();
+ // `startBlankComponent` is what to render when clicking `Start blank`
+ // or if no matched patterns are found.
+ return (
+
+ }
+ />
+
+ );
+}
+
const QueryEdit = ( props ) => {
const { clientId } = props;
const hasInnerBlocks = useSelect(
@@ -94,7 +111,7 @@ const QueryEdit = ( props ) => {
!! select( blockEditorStore ).getBlocks( clientId ).length,
[ clientId ]
);
- const Component = hasInnerBlocks ? QueryContent : QueryBlockSetup;
+ const Component = hasInnerBlocks ? QueryContent : QueryPatternSetup;
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
deleted file mode 100644
index f7837da313fc37..00000000000000
--- a/packages/block-library/src/query/edit/query-block-setup.js
+++ /dev/null
@@ -1,120 +0,0 @@
-/**
- * External dependencies
- */
-import { cloneDeep } from 'lodash';
-/**
- * WordPress dependencies
- */
-import { useDispatch } from '@wordpress/data';
-import { __, _x } from '@wordpress/i18n';
-import { SelectControl, ToggleControl } from '@wordpress/components';
-import {
- cloneBlock,
- createBlocksFromInnerBlocksTemplate,
-} from '@wordpress/blocks';
-import { store as blockEditorStore } from '@wordpress/block-editor';
-
-/**
- * Internal dependencies
- */
-import BlockSetup from './block-setup';
-import { usePostTypes } from '../utils';
-
-const QueryBlockSetup = ( {
- clientId,
- attributes: { query },
- setAttributes,
- name: blockName,
-} ) => {
- const { postType, inherit } = query;
- const { replaceBlocks, replaceInnerBlocks } = useDispatch(
- blockEditorStore
- );
- const { postTypesSelectOptions } = usePostTypes();
- const updateQuery = ( newQuery ) =>
- setAttributes( { query: { ...query, ...newQuery } } );
- const onVariationSelect = ( nextVariation ) => {
- if ( nextVariation.attributes ) {
- setAttributes( nextVariation.attributes );
- }
- if ( nextVariation.innerBlocks ) {
- replaceInnerBlocks(
- clientId,
- createBlocksFromInnerBlocksTemplate(
- nextVariation.innerBlocks
- ),
- false
- );
- }
- };
- const onBlockPatternSelect = ( blocks ) => {
- const clonedBlocks = blocks.map( ( block ) => {
- const clone = cloneBlock( block );
- /**
- * TODO: this check will be revised with the ongoing work on block patterns.
- * For now we keep the value of posts per page (`query.perPage`) from Query patterns
- * so as to preview the pattern as intended, without possible big previews.
- * During insertion, we need to override the Query's attributes that can be set in
- * the Placeholder and we unset the `perPage` value to be set appropriately by Query block.
- */
- if ( block.name === 'core/query' ) {
- /**
- * We need to `cloneDeep` the Query's attributes, as `cloneBlock` does a swallow
- * copy of the block.
- */
- const queryAttributes = cloneDeep( clone.attributes );
- Object.assign( queryAttributes.query, {
- inherit: query.inherit,
- postType: query.postType,
- perPage: null,
- } );
- return {
- ...clone,
- attributes: queryAttributes,
- };
- }
- return clone;
- } );
- replaceBlocks( clientId, clonedBlocks );
- };
- 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 } )
- }
- />
- ) }
-
-
- );
-};
-
-export default QueryBlockSetup;
diff --git a/packages/block-library/src/query/editor.scss b/packages/block-library/src/query/editor.scss
index 164d1f6f00bbc1..27d4ce00c4939a 100644
--- a/packages/block-library/src/query/editor.scss
+++ b/packages/block-library/src/query/editor.scss
@@ -5,123 +5,3 @@
.wp-block-query__create-new-link {
padding: 0 $grid-unit-20 $grid-unit-20 56px;
}
-
-.wp-block-query {
- .components-placeholder {
- .block-setup-navigation {
- padding: $grid-unit-15 0 0;
- }
-
- .block-attributes-setup-container {
- padding-top: $grid-unit-30;
-
- .components-base-control__help {
- margin: $grid-unit-15 auto;
- }
- }
- }
-}
-
-.block-setup-block-layout-list__container {
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
-
- .block-setup-block-layout-list__list-item {
- cursor: pointer;
- margin: 0 $grid-unit-15 $grid-unit-15 0;
- width: 200px;
- text-align: center;
- display: flex;
- flex-direction: column;
-
- &.is-block-variation {
- width: 90px;
-
- button {
- display: inline-flex;
- margin-right: 0;
- height: auto;
- }
- }
-
- .block-setup-block-layout-list__item-title {
- padding: $grid-unit-05 0;
- font-size: $helptext-font-size;
- }
-
- .block-setup-block-layout-list__item {
- height: 100%;
- max-height: 140px;
- display: flex;
- flex-direction: column;
- padding: 2px;
- transition: all 0.05s ease-in-out;
- @include reduce-motion("transition");
- border-radius: $radius-block-ui;
- border: $border-width solid $gray-300;
-
- &: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-editor-block-preview__container {
- margin: auto 0;
- cursor: pointer; // This is for the BlockPreview.
- }
-
- .block-setup-block-layout-list__item-variation-icon {
- color: var(--wp-admin-theme-color);
- padding: $grid-unit-05 * 1.5;
- border-radius: $radius-block-ui;
- box-shadow: inset 0 0 0 1px var(--wp-admin-theme-color);
- display: inline-flex;
- margin: $grid-unit-15 auto auto auto;
-
- svg {
- fill: currentColor;
- outline: none;
- }
- }
- }
- }
-
- // Size consecutive block variation icons the same.
- .block-setup-block-layout-list__list-item.is-block-variation .block-setup-block-layout-list__item {
- height: 90px;
- min-height: 90px;
- }
-
- // Size the block variation icon same as the thumbnail on step 1.
- .block-setup-block-layout-list__list-item:not(.is-block-variation) + .block-setup-block-layout-list__list-item.is-block-variation .block-setup-block-layout-list__item {
- height: 100%;
- }
-}
-
-.components-button.block-setup-block-layout-back-button.is-tertiary.has-icon {
- color: inherit;
- padding-left: 0;
- display: inline-flex;
- margin-right: auto;
- margin-top: -$grid-unit-15;
-
- &:hover:not(:disabled) {
- box-shadow: none;
- color: var(--wp-admin-theme-color);
- }
-
- &:active:not(:disabled) {
- background: transparent;
- color: $gray-300;
- }
-
- svg {
- margin-right: 0;
- }
-}
diff --git a/packages/e2e-tests/plugins/query-block.php b/packages/e2e-tests/plugins/query-block.php
new file mode 100644
index 00000000000000..f985c0d772224f
--- /dev/null
+++ b/packages/e2e-tests/plugins/query-block.php
@@ -0,0 +1,38 @@
+ __( 'Query Test 1', 'gutenberg' ),
+ 'blockTypes' => array( 'core/query' ),
+ 'content' => '
+
+
+
+ ',
+ )
+);
+register_block_pattern(
+ 'query/test-2',
+ array(
+ 'title' => __( 'Query Test 2', 'gutenberg' ),
+ 'blockTypes' => array( 'core/query' ),
+ 'content' => '
+
+
+
+
+ ',
+ )
+);
diff --git a/packages/e2e-tests/specs/experiments/blocks/query.test.js b/packages/e2e-tests/specs/experiments/blocks/query.test.js
new file mode 100644
index 00000000000000..254acdd009b2dd
--- /dev/null
+++ b/packages/e2e-tests/specs/experiments/blocks/query.test.js
@@ -0,0 +1,103 @@
+/**
+ * WordPress dependencies
+ */
+import {
+ activatePlugin,
+ deactivatePlugin,
+ activateTheme,
+ createNewPost,
+ insertBlock,
+ publishPost,
+ trashAllPosts,
+} from '@wordpress/e2e-test-utils';
+
+const createDemoPosts = async () => {
+ await createNewPost( { postType: 'post', title: `Post 1` } );
+ await publishPost();
+};
+
+describe( 'Query block', () => {
+ beforeAll( async () => {
+ await activatePlugin( 'gutenberg-test-query-block' );
+ await activateTheme( 'tt1-blocks' );
+ await createDemoPosts();
+ } );
+ afterAll( async () => {
+ await activateTheme( 'twentytwentyone' );
+ await trashAllPosts();
+ await deactivatePlugin( 'gutenberg-test-query-block' );
+ } );
+ beforeEach( async () => {
+ await createNewPost( { postType: 'page', title: `Query Page` } );
+ } );
+ afterEach( async () => {
+ await trashAllPosts( 'page' );
+ } );
+ describe( 'Query block insertion', () => {
+ it( 'Carousel', async () => {
+ await insertBlock( 'Query' );
+ // Wait for pattern blocks to be loaded.
+ await page.waitForSelector(
+ '.block-editor-block-pattern-setup__container .wp-block-post-title'
+ );
+ /**
+ * Ensure that carousel is working by checking slider css classes
+ * and navigating to the next pattern.
+ */
+ await page.waitForSelector(
+ 'li.pattern-slide.active-slide[aria-label="Query Test 1"]'
+ );
+ const nextPatternButton = await page.waitForSelector(
+ '.block-editor-block-pattern-setup__navigation button[aria-label="Next pattern"]'
+ );
+ await nextPatternButton.click();
+ await page.waitForSelector(
+ 'li.pattern-slide.active-slide[aria-label="Query Test 2"]'
+ );
+ // Choose the selected pattern.
+ const chooseButton = await page.waitForXPath(
+ '//div[contains(@class, "block-editor-block-pattern-setup__actions")]//button[text()="Choose"]'
+ );
+ chooseButton.click();
+ // Wait for pattern setup to go away.
+ await page.waitForSelector( '.block-editor-block-pattern-setup', {
+ hidden: true,
+ } );
+ /**
+ * We can't use `getEditedPostContent` easily for now because
+ * `query` makes used of `instanceId` so it's not very reliable.
+ * This should be revisited.
+ */
+ await page.waitForSelector( '.wp-block-post-date' );
+ await page.waitForSelector( '.wp-block-post-title' );
+ } );
+ it( 'Grid view', async () => {
+ await insertBlock( 'Query' );
+ // Wait for patterns setup to be loaded.
+ await page.waitForSelector(
+ '.block-editor-block-pattern-setup__display-controls'
+ );
+ // Click the Grid view button.
+ const gridViewButton = await page.waitForSelector(
+ '.block-editor-block-pattern-setup__display-controls button[aria-label="Grid view"]'
+ );
+ await gridViewButton.click();
+ // Wait for patterns to be loaded and click the wanted pattern.
+ const gridPattern = await page.waitForXPath(
+ '//div[@class="block-editor-block-pattern-setup-list__item-title" and contains(text(), "Query Test 2")]'
+ );
+ await gridPattern.click();
+ // Wait for pattern setup to go away.
+ await page.waitForSelector( '.block-editor-block-pattern-setup', {
+ hidden: true,
+ } );
+ /**
+ * We can't use `getEditedPostContent` easily for now because
+ * `query` makes used of `instanceId` so it's not very reliable.
+ * This should be revisited.
+ */
+ await page.waitForSelector( '.wp-block-post-date' );
+ await page.waitForSelector( '.wp-block-post-title' );
+ } );
+ } );
+} );