diff --git a/packages/block-editor/src/components/inserter/search-results.js b/packages/block-editor/src/components/inserter/search-results.js
index edd99609ea916c..d213bdd1af227a 100644
--- a/packages/block-editor/src/components/inserter/search-results.js
+++ b/packages/block-editor/src/components/inserter/search-results.js
@@ -50,6 +50,7 @@ function InserterSearchResults( {
shouldFocusBlock = true,
prioritizePatterns,
selectBlockOnInsert,
+ showBlocks = true,
} ) {
const debouncedSpeak = useDebounce( speak, 500 );
@@ -167,7 +168,7 @@ function InserterSearchResults( {
const hasItems =
filteredBlockTypes.length > 0 || filteredBlockPatterns.length > 0;
- const blocksUI = !! filteredBlockTypes.length && (
+ const blocksUI = showBlocks && !! filteredBlockTypes.length && (
{ __( 'Blocks' ) } }
>
diff --git a/packages/block-editor/src/components/inserter/style.scss b/packages/block-editor/src/components/inserter/style.scss
index 35c18e1d9acce5..685355a81a2971 100644
--- a/packages/block-editor/src/components/inserter/style.scss
+++ b/packages/block-editor/src/components/inserter/style.scss
@@ -767,3 +767,13 @@ $block-inserter-tabs-height: 44px;
}
}
}
+
+.is-zoom-out {
+ .block-editor-inserter__menu {
+ display: flex;
+ }
+
+ .block-editor-inserter__patterns-category-dialog {
+ position: static;
+ }
+}
diff --git a/packages/block-editor/src/components/inserter/tabs.js b/packages/block-editor/src/components/inserter/tabs.js
index 4795c3ce4fdc24..ee920df4ca214c 100644
--- a/packages/block-editor/src/components/inserter/tabs.js
+++ b/packages/block-editor/src/components/inserter/tabs.js
@@ -29,13 +29,14 @@ const mediaTab = {
};
function InserterTabs( {
+ showBlocks = true,
showPatterns = false,
showMedia = false,
onSelect,
tabsContents,
} ) {
const tabs = [
- blocksTab,
+ showBlocks && blocksTab,
showPatterns && patternsTab,
showMedia && mediaTab,
].filter( Boolean );
diff --git a/packages/block-editor/src/components/resizable-box-popover/index.js b/packages/block-editor/src/components/resizable-box-popover/index.js
index 8a49c1631287a1..61f599663a4f5d 100644
--- a/packages/block-editor/src/components/resizable-box-popover/index.js
+++ b/packages/block-editor/src/components/resizable-box-popover/index.js
@@ -16,7 +16,7 @@ export default function ResizableBoxPopover( {
return (
diff --git a/packages/block-editor/src/components/rich-text/index.js b/packages/block-editor/src/components/rich-text/index.js
index 5f94206c78752f..458f5a96609b65 100644
--- a/packages/block-editor/src/components/rich-text/index.js
+++ b/packages/block-editor/src/components/rich-text/index.js
@@ -26,6 +26,7 @@ import { getBlockType, store as blocksStore } from '@wordpress/blocks';
*/
import { useBlockEditorAutocompleteProps } from '../autocomplete';
import { useBlockEditContext } from '../block-edit';
+import { blockBindingsKey } from '../block-edit/context';
import FormatToolbarContainer from './format-toolbar-container';
import { store as blockEditorStore } from '../../store';
import { useUndoAutomaticChange } from './use-undo-automatic-change';
@@ -117,11 +118,9 @@ export function RichTextWrapper(
props = removeNativeProps( props );
const anchorRef = useRef();
- const {
- clientId,
- isSelected: isBlockSelected,
- name: blockName,
- } = useBlockEditContext();
+ const context = useBlockEditContext();
+ const { clientId, isSelected: isBlockSelected, name: blockName } = context;
+ const blockBindings = context[ blockBindingsKey ];
const selector = ( select ) => {
// Avoid subscribing to the block editor store if the block is not
// selected.
@@ -129,12 +128,10 @@ export function RichTextWrapper(
return { isSelected: false };
}
- const { getSelectionStart, getSelectionEnd, getBlockAttributes } =
+ const { getSelectionStart, getSelectionEnd } =
select( blockEditorStore );
const selectionStart = getSelectionStart();
const selectionEnd = getSelectionEnd();
- const blockBindings =
- getBlockAttributes( clientId )?.metadata?.bindings;
let isSelected;
@@ -147,48 +144,57 @@ export function RichTextWrapper(
isSelected = selectionStart.clientId === clientId;
}
- // Disable Rich Text editing if block bindings specify that.
- let disableBoundBlocks = false;
- if ( blockBindings && blockName in BLOCK_BINDINGS_ALLOWED_BLOCKS ) {
- const blockTypeAttributes = getBlockType( blockName ).attributes;
- const { getBlockBindingsSource } = unlock( select( blocksStore ) );
- for ( const [ attribute, args ] of Object.entries(
- blockBindings
- ) ) {
- if (
- blockTypeAttributes?.[ attribute ]?.source !== 'rich-text'
- ) {
- break;
- }
-
- // If the source is not defined, or if its value of `lockAttributesEditing` is `true`, disable it.
- const blockBindingsSource = getBlockBindingsSource(
- args.source
- );
- if (
- ! blockBindingsSource ||
- blockBindingsSource.lockAttributesEditing
- ) {
- disableBoundBlocks = true;
- break;
- }
- }
- }
-
return {
selectionStart: isSelected ? selectionStart.offset : undefined,
selectionEnd: isSelected ? selectionEnd.offset : undefined,
isSelected,
- disableBoundBlocks,
};
};
- const { selectionStart, selectionEnd, isSelected, disableBoundBlocks } =
- useSelect( selector, [
- clientId,
- identifier,
- originalIsSelected,
- isBlockSelected,
- ] );
+ const { selectionStart, selectionEnd, isSelected } = useSelect( selector, [
+ clientId,
+ identifier,
+ originalIsSelected,
+ isBlockSelected,
+ ] );
+
+ const disableBoundBlocks = useSelect(
+ ( select ) => {
+ // Disable Rich Text editing if block bindings specify that.
+ let _disableBoundBlocks = false;
+ if ( blockBindings && blockName in BLOCK_BINDINGS_ALLOWED_BLOCKS ) {
+ const blockTypeAttributes =
+ getBlockType( blockName ).attributes;
+ const { getBlockBindingsSource } = unlock(
+ select( blocksStore )
+ );
+ for ( const [ attribute, args ] of Object.entries(
+ blockBindings
+ ) ) {
+ if (
+ blockTypeAttributes?.[ attribute ]?.source !==
+ 'rich-text'
+ ) {
+ break;
+ }
+
+ // If the source is not defined, or if its value of `lockAttributesEditing` is `true`, disable it.
+ const blockBindingsSource = getBlockBindingsSource(
+ args.source
+ );
+ if (
+ ! blockBindingsSource ||
+ blockBindingsSource.lockAttributesEditing
+ ) {
+ _disableBoundBlocks = true;
+ break;
+ }
+ }
+ }
+
+ return _disableBoundBlocks;
+ },
+ [ blockBindings, blockName ]
+ );
const shouldDisableEditing = disableEditing || disableBoundBlocks;
diff --git a/packages/block-editor/src/components/rich-text/use-enter.js b/packages/block-editor/src/components/rich-text/use-enter.js
index 4daf70e7fa3c74..6b40a82d72d4b2 100644
--- a/packages/block-editor/src/components/rich-text/use-enter.js
+++ b/packages/block-editor/src/components/rich-text/use-enter.js
@@ -21,6 +21,10 @@ export function useEnter( props ) {
propsRef.current = props;
return useRefEffect( ( element ) => {
function onKeyDown( event ) {
+ if ( event.target.contentEditable !== 'true' ) {
+ return;
+ }
+
if ( event.defaultPrevented ) {
return;
}
diff --git a/packages/block-editor/src/store/actions.js b/packages/block-editor/src/store/actions.js
index 018c9ff9115185..e9281727804f1c 100644
--- a/packages/block-editor/src/store/actions.js
+++ b/packages/block-editor/src/store/actions.js
@@ -924,10 +924,8 @@ export const __unstableExpandSelection =
export const mergeBlocks =
( firstBlockClientId, secondBlockClientId ) =>
( { registry, select, dispatch } ) => {
- const blocks = [ firstBlockClientId, secondBlockClientId ];
- dispatch( { type: 'MERGE_BLOCKS', blocks } );
-
- const [ clientIdA, clientIdB ] = blocks;
+ const clientIdA = firstBlockClientId;
+ const clientIdB = secondBlockClientId;
const blockA = select.getBlock( clientIdA );
const blockAType = getBlockType( blockA.name );
diff --git a/packages/block-editor/src/store/test/actions.js b/packages/block-editor/src/store/test/actions.js
index 932e97d95e2f2e..f960363cdb0ddb 100644
--- a/packages/block-editor/src/store/test/actions.js
+++ b/packages/block-editor/src/store/test/actions.js
@@ -832,10 +832,6 @@ describe( 'actions', () => {
blockB.clientId
)( { select, dispatch } );
- expect( dispatch ).toHaveBeenCalledWith( {
- type: 'MERGE_BLOCKS',
- blocks: [ blockA.clientId, blockB.clientId ],
- } );
expect( dispatch.selectBlock ).toHaveBeenCalledWith( 'chicken' );
} );
diff --git a/packages/block-editor/src/utils/calculate-scale.js b/packages/block-editor/src/utils/calculate-scale.js
new file mode 100644
index 00000000000000..f07ba24ea341a1
--- /dev/null
+++ b/packages/block-editor/src/utils/calculate-scale.js
@@ -0,0 +1,20 @@
+const clamp = ( lowerlimit, width, upperlimit ) => {
+ if ( width < lowerlimit ) return lowerlimit;
+ if ( width > upperlimit ) return upperlimit;
+ return width;
+};
+
+export default function calculateScale( scaleConfig, width ) {
+ const scaleSlope =
+ ( scaleConfig.maxScale - scaleConfig.minScale ) /
+ ( scaleConfig.maxWidth - scaleConfig.minWidth );
+
+ const scaleIntercept =
+ scaleConfig.minScale - scaleSlope * scaleConfig.minWidth;
+
+ return clamp(
+ scaleConfig.maxScale,
+ scaleSlope * width + scaleIntercept,
+ scaleConfig.minScale
+ );
+}
diff --git a/packages/block-library/src/cover/edit/block-controls.js b/packages/block-library/src/cover/edit/block-controls.js
index 59aaaaffe77d75..c4137ad2a8409a 100644
--- a/packages/block-library/src/cover/edit/block-controls.js
+++ b/packages/block-library/src/cover/edit/block-controls.js
@@ -8,6 +8,7 @@ import {
MediaReplaceFlow,
__experimentalBlockAlignmentMatrixControl as BlockAlignmentMatrixControl,
__experimentalBlockFullHeightAligmentControl as FullHeightAlignmentControl,
+ privateApis as blockEditorPrivateApis,
} from '@wordpress/block-editor';
import { __ } from '@wordpress/i18n';
@@ -15,6 +16,9 @@ import { __ } from '@wordpress/i18n';
* Internal dependencies
*/
import { ALLOWED_MEDIA_TYPES } from '../shared';
+import { unlock } from '../../lock-unlock';
+
+const { cleanEmptyObject } = unlock( blockEditorPrivateApis );
export default function CoverBlockControls( {
attributes,
@@ -30,7 +34,10 @@ export default function CoverBlockControls( {
const [ prevMinHeightValue, setPrevMinHeightValue ] = useState( minHeight );
const [ prevMinHeightUnit, setPrevMinHeightUnit ] =
useState( minHeightUnit );
- const isMinFullHeight = minHeightUnit === 'vh' && minHeight === 100;
+ const isMinFullHeight =
+ minHeightUnit === 'vh' &&
+ minHeight === 100 &&
+ ! attributes?.style?.dimensions?.aspectRatio;
const toggleMinFullHeight = () => {
if ( isMinFullHeight ) {
// If there aren't previous values, take the default ones.
@@ -51,10 +58,17 @@ export default function CoverBlockControls( {
setPrevMinHeightValue( minHeight );
setPrevMinHeightUnit( minHeightUnit );
- // Set full height.
+ // Set full height, and clear any aspect ratio value.
return setAttributes( {
minHeight: 100,
minHeightUnit: 'vh',
+ style: cleanEmptyObject( {
+ ...attributes?.style,
+ dimensions: {
+ ...attributes?.style?.dimensions,
+ aspectRatio: undefined, // Reset aspect ratio when minHeight is set.
+ },
+ } ),
} );
};
diff --git a/packages/data/src/redux-store/index.js b/packages/data/src/redux-store/index.js
index 7fdc9331a2474b..979c3127b9ed52 100644
--- a/packages/data/src/redux-store/index.js
+++ b/packages/data/src/redux-store/index.js
@@ -64,12 +64,16 @@ const mapValues = ( obj, callback ) =>
] )
);
-// Convert Map objects to plain objects
-const mapToObject = ( key, state ) => {
+// Convert non serializable types to plain objects
+const devToolsReplacer = ( key, state ) => {
if ( state instanceof Map ) {
return Object.fromEntries( state );
}
+ if ( state instanceof window.HTMLElement ) {
+ return null;
+ }
+
return state;
};
@@ -421,7 +425,7 @@ function instantiateReduxStore( key, options, registry, thunkArgs ) {
name: key,
instanceId: key,
serialize: {
- replacer: mapToObject,
+ replacer: devToolsReplacer,
},
} )
);
diff --git a/packages/e2e-test-utils-playwright/src/request-utils/index.ts b/packages/e2e-test-utils-playwright/src/request-utils/index.ts
index 5036f3d0e8a97c..f6818945e16936 100644
--- a/packages/e2e-test-utils-playwright/src/request-utils/index.ts
+++ b/packages/e2e-test-utils-playwright/src/request-utils/index.ts
@@ -93,7 +93,7 @@ class RequestUtils {
},
} );
- const requestUtils = new RequestUtils( requestContext, {
+ const requestUtils = new this( requestContext, {
user,
storageState,
storageStatePath,
diff --git a/packages/edit-site/src/components/block-editor/editor-canvas.js b/packages/edit-site/src/components/block-editor/editor-canvas.js
index 01bc4cdfa2ddfc..c3ee980515e6c7 100644
--- a/packages/edit-site/src/components/block-editor/editor-canvas.js
+++ b/packages/edit-site/src/components/block-editor/editor-canvas.js
@@ -26,10 +26,9 @@ import {
const { EditorCanvas: EditorCanvasRoot } = unlock( editorPrivateApis );
function EditorCanvas( { enableResizing, settings, children, ...props } ) {
- const { hasBlocks, isFocusMode, templateType, canvasMode, isZoomOutMode } =
- useSelect( ( select ) => {
- const { getBlockCount, __unstableGetEditorMode } =
- select( blockEditorStore );
+ const { hasBlocks, isFocusMode, templateType, canvasMode } = useSelect(
+ ( select ) => {
+ const { getBlockCount } = select( blockEditorStore );
const { getEditedPostType, getCanvasMode } = unlock(
select( editSiteStore )
);
@@ -38,11 +37,12 @@ function EditorCanvas( { enableResizing, settings, children, ...props } ) {
return {
templateType: _templateType,
isFocusMode: FOCUSABLE_ENTITIES.includes( _templateType ),
- isZoomOutMode: __unstableGetEditorMode() === 'zoom-out',
canvasMode: getCanvasMode(),
hasBlocks: !! getBlockCount(),
};
- }, [] );
+ },
+ []
+ );
const { setCanvasMode } = unlock( useDispatch( editSiteStore ) );
const [ isFocused, setIsFocused ] = useState( false );
@@ -107,9 +107,7 @@ function EditorCanvas( { enableResizing, settings, children, ...props } ) {
renderAppender={ showBlockAppender }
styles={ styles }
iframeProps={ {
- expand: isZoomOutMode,
- scale: isZoomOutMode ? 0.45 : undefined,
- frameSize: isZoomOutMode ? 100 : undefined,
+ shouldZoom: true,
className: classnames(
'edit-site-visual-editor__editor-canvas',
{
diff --git a/packages/edit-site/src/components/block-editor/style.scss b/packages/edit-site/src/components/block-editor/style.scss
index 3d042f612f29ed..fa7fd7e13df3e4 100644
--- a/packages/edit-site/src/components/block-editor/style.scss
+++ b/packages/edit-site/src/components/block-editor/style.scss
@@ -22,7 +22,6 @@
position: relative;
height: 100%;
display: block;
- overflow: hidden;
background-color: $gray-300;
// Centralize the editor horizontally (flex-direction is column).
align-items: center;
@@ -62,8 +61,6 @@
.components-resizable-box__container {
margin: 0 auto;
- // Removing this will cancel the bottom margins in the iframe.
- overflow: auto;
}
&.is-view-mode {
diff --git a/packages/edit-site/src/components/global-styles/screen-typography.js b/packages/edit-site/src/components/global-styles/screen-typography.js
index f76dc6fb381004..40e2ab08320b75 100644
--- a/packages/edit-site/src/components/global-styles/screen-typography.js
+++ b/packages/edit-site/src/components/global-styles/screen-typography.js
@@ -9,7 +9,7 @@ import { useSelect } from '@wordpress/data';
/**
* Internal dependencies
*/
-import TypographyElements from './typogrphy-elements';
+import TypographyElements from './typography-elements';
import FontFamilies from './font-families';
import ScreenHeader from './header';
diff --git a/packages/edit-site/src/components/global-styles/typogrphy-elements.js b/packages/edit-site/src/components/global-styles/typography-elements.js
similarity index 100%
rename from packages/edit-site/src/components/global-styles/typogrphy-elements.js
rename to packages/edit-site/src/components/global-styles/typography-elements.js
diff --git a/packages/edit-site/src/components/layout/index.js b/packages/edit-site/src/components/layout/index.js
index fcb0a74b0b3b88..d15be016173b03 100644
--- a/packages/edit-site/src/components/layout/index.js
+++ b/packages/edit-site/src/components/layout/index.js
@@ -70,6 +70,7 @@ export default function Layout() {
const {
isDistractionFree,
+ isZoomOutMode,
hasFixedToolbar,
hasBlockSelected,
canvasMode,
@@ -96,6 +97,9 @@ export default function Layout() {
'core',
'distractionFree'
),
+ isZoomOutMode:
+ select( blockEditorStore ).__unstableGetEditorMode() ===
+ 'zoom-out',
hasBlockSelected:
select( blockEditorStore ).getBlockSelectionStart(),
};
@@ -172,6 +176,7 @@ export default function Layout() {
'is-full-canvas': canvasMode === 'edit',
'has-fixed-toolbar': hasFixedToolbar,
'is-block-toolbar-visible': hasBlockSelected,
+ 'is-zoom-out': isZoomOutMode,
}
) }
>
diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-navigation-menu/edit-button.js b/packages/edit-site/src/components/sidebar-navigation-screen-navigation-menu/edit-button.js
deleted file mode 100644
index 962062a96da743..00000000000000
--- a/packages/edit-site/src/components/sidebar-navigation-screen-navigation-menu/edit-button.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/**
- * WordPress dependencies
- */
-import { __ } from '@wordpress/i18n';
-import { pencil } from '@wordpress/icons';
-/**
- * Internal dependencies
- */
-import SidebarButton from '../sidebar-button';
-import { useLink } from '../routes/link';
-import { NAVIGATION_POST_TYPE } from '../../utils/constants';
-
-export default function EditButton( { postId } ) {
- const linkInfo = useLink( {
- postId,
- postType: NAVIGATION_POST_TYPE,
- canvas: 'edit',
- } );
- return (
-
- );
-}
diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-navigation-menu/single-navigation-menu.js b/packages/edit-site/src/components/sidebar-navigation-screen-navigation-menu/single-navigation-menu.js
index 960e0363f2e588..e6348531516f66 100644
--- a/packages/edit-site/src/components/sidebar-navigation-screen-navigation-menu/single-navigation-menu.js
+++ b/packages/edit-site/src/components/sidebar-navigation-screen-navigation-menu/single-navigation-menu.js
@@ -10,7 +10,6 @@ import { SidebarNavigationScreenWrapper } from '../sidebar-navigation-screen-nav
import ScreenNavigationMoreMenu from './more-menu';
import NavigationMenuEditor from './navigation-menu-editor';
import buildNavigationLabel from '../sidebar-navigation-screen-navigation-menus/build-navigation-label';
-import EditButton from './edit-button';
export default function SingleNavigationMenu( {
navigationMenu,
@@ -30,7 +29,6 @@ export default function SingleNavigationMenu( {
onSave={ handleSave }
onDuplicate={ handleDuplicate }
/>
-
>
}
title={ buildNavigationLabel(
diff --git a/packages/edit-site/src/style.scss b/packages/edit-site/src/style.scss
index c86efc10eafb3c..8b6ba0093b4dc3 100644
--- a/packages/edit-site/src/style.scss
+++ b/packages/edit-site/src/style.scss
@@ -98,7 +98,7 @@ body.js.site-editor-php {
}
.interface-interface-skeleton__content {
- background-color: $gray-900;
+ background-color: $gray-300;
}
}
diff --git a/packages/element/README.md b/packages/element/README.md
index 5636fdda56a525..9ebf2a632d5019 100755
--- a/packages/element/README.md
+++ b/packages/element/README.md
@@ -247,7 +247,7 @@ This is the same concept as the React Native implementation.
_Related_
-- Here is an example of how to use the select method:
+- Here is an example of how to use the select method:
_Usage_
diff --git a/packages/element/src/platform.js b/packages/element/src/platform.js
index c646b6c86d51a2..841cd06e4cabb5 100644
--- a/packages/element/src/platform.js
+++ b/packages/element/src/platform.js
@@ -17,7 +17,7 @@ const Platform = {
*
* This is the same concept as the React Native implementation.
*
- * @see https://facebook.github.io/react-native/docs/platform-specific-code#platform-module
+ * @see https://reactnative.dev/docs/platform-specific-code#platform-module
*
* Here is an example of how to use the select method:
* @example
diff --git a/packages/interactivity/docs/api-reference.md b/packages/interactivity/docs/api-reference.md
index b755b124646679..d10d56390b9177 100644
--- a/packages/interactivity/docs/api-reference.md
+++ b/packages/interactivity/docs/api-reference.md
@@ -39,6 +39,7 @@ DOM elements are connected to data stored in the state and context through direc
- [Setting the store](#setting-the-store)
- [On the client side](#on-the-client-side)
- [On the server side](#on-the-server-side)
+ - [Store client methods](#store-client-methods)
## The directives
@@ -974,3 +975,76 @@ const { state } = store(
// The following call works as expected.
store( "myPlugin/private", { /* store part */ }, { lock: PRIVATE_LOCK } );
```
+
+### Store client methods
+
+Apart from the store function, there are also some methods that allows the developer to access data on their store functions.
+
+ - getContext()
+ - getElement()
+
+#### getContext()
+
+Retrieves the context inherited by the element evaluating a function from the store. The returned value depends on the element and the namespace where the function calling `getContext()` exists.
+
+```php
+// render.php
+
+
+
+```
+
+```js
+// store
+import { store, getContext } from '@wordpress/interactivity';
+
+store( "myPlugin", {
+ actions: {
+ log: () => {
+ const context = getContext();
+ // Logs "false"
+ console.log('context => ', context.isOpen)
+ },
+ },
+});
+```
+
+#### getElement()
+
+Retrieves a representation of the element that the action is bound to or called from. Such representation is read-only, and contains a reference to the DOM element, its props and a local reactive state.
+It returns an object with two keys:
+
+##### ref
+
+`ref` is the reference to the DOM element as an (HTMLElement)[https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement]
+
+#### attributes
+
+`attributes` contains a (Proxy)[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy], which adds a getter that allows to reference other store namespaces. Feel free to check the getter in the code. [Link](https://github.com/WordPress/gutenberg/blob/8cb23964d58f3ce5cf6ae1b6f967a4b8d4939a8e/packages/interactivity/src/store.ts#L70)
+
+Those attributes will contain the directives of that element. In the button example:
+
+```js
+// store
+import { store, getContext } from '@wordpress/interactivity';
+
+store( "myPlugin", {
+ actions: {
+ log: () => {
+ const element = getElement();
+ // Logs "false"
+ console.log('element attributes => ', element.attributes)
+ },
+ },
+});
+```
+
+The code will log:
+
+```json
+{
+ "data-wp-on--click": 'actions.increaseCounter',
+ "children": ['Log'],
+ "onclick": event => { evaluate(entry, event); }
+}
+```
diff --git a/packages/react-native-editor/__device-tests__/helpers/test-data.js b/packages/react-native-editor/__device-tests__/helpers/test-data.js
index 9816e7dc5354d1..a492b7997f26a3 100644
--- a/packages/react-native-editor/__device-tests__/helpers/test-data.js
+++ b/packages/react-native-editor/__device-tests__/helpers/test-data.js
@@ -203,6 +203,16 @@ exports.galleryBlock = ``;
+exports.galleryBlockTwoImages = `
+
+Paragraph
+
+
+Heading
+
+
+`;
+
exports.groupNestedStructure = `
Level 1
diff --git a/packages/react-native-editor/__device-tests__/pages/editor-page.js b/packages/react-native-editor/__device-tests__/pages/editor-page.js
index ec4483eb704153..4e8f5d9bfd4a5f 100644
--- a/packages/react-native-editor/__device-tests__/pages/editor-page.js
+++ b/packages/react-native-editor/__device-tests__/pages/editor-page.js
@@ -205,6 +205,36 @@ class EditorPage {
return lastElementFound;
}
+ /**
+ * Selects a block.
+ *
+ * @param {import('webdriverio').ChainablePromiseElement} block The block to select.
+ * @param {Object} options Configuration options.
+ * @param {Object} [options.offset={ x: 0, y: 0 }] The offset for the click position.
+ * @param {number|Function} [options.offset.x=0] The x-coordinate offset or a function that calculates the offset based on the block's width.
+ * @param {number|Function} [options.offset.y=0] The y-coordinate offset or a function that calculates the offset based on the block's height.
+ *
+ * @return {import('webdriverio').ChainablePromiseElement} The selected block.
+ */
+ async selectBlock( block, options = {} ) {
+ const { offset = { x: 0, y: 0 } } = options;
+ const size = await block.getSize();
+
+ let offsetX = offset.x;
+ if ( typeof offset.x === 'function' ) {
+ offsetX = offset.x( size.width );
+ }
+
+ let offsetY = offset.y;
+ if ( typeof offset.y === 'function' ) {
+ offsetY = offset.y( size.height );
+ }
+
+ await block.click( { x: offsetX, y: offsetY } );
+
+ return block;
+ }
+
async getFirstBlockVisible() {
const firstBlockLocator = `//*[contains(@${ this.accessibilityIdXPathAttrib }, " Block. Row ")]`;
return await waitForVisible( this.driver, firstBlockLocator );
@@ -1076,6 +1106,8 @@ const blockNames = {
button: 'Button',
preformatted: 'Preformatted',
unsupported: 'Unsupported',
+ mediaText: 'Media & Text',
+ quote: 'Quote',
};
module.exports = { setupEditor, blockNames };
diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php
index f474177dc17b5a..376eaaff4a2051 100644
--- a/phpunit/class-wp-theme-json-test.php
+++ b/phpunit/class-wp-theme-json-test.php
@@ -282,6 +282,9 @@ public function test_get_settings_appearance_true_opts_in() {
'typography' => array(
'lineHeight' => true,
),
+ 'shadow' => array(
+ 'defaultPresets' => true,
+ ),
'blocks' => array(
'core/paragraph' => array(
'typography' => array(
@@ -321,6 +324,9 @@ public function test_get_settings_appearance_true_opts_in() {
'typography' => array(
'lineHeight' => false,
),
+ 'shadow' => array(
+ 'defaultPresets' => true,
+ ),
),
),
);
diff --git a/schemas/json/theme.json b/schemas/json/theme.json
index a5b54de97ed70f..a9823f6cc6534b 100644
--- a/schemas/json/theme.json
+++ b/schemas/json/theme.json
@@ -77,7 +77,7 @@
"defaultPresets": {
"description": "Allow users to choose shadows from the default shadow presets.",
"type": "boolean",
- "default": true
+ "default": false
},
"presets": {
"description": "Shadow presets for the shadow picker.\nGenerates a single custom property (`--wp--preset--shadow--{slug}`) per preset value.",
diff --git a/test/e2e/specs/editor/various/dropdown-menu.spec.js b/test/e2e/specs/editor/various/dropdown-menu.spec.js
index 916ef3447d80a4..4c656fd3d6994a 100644
--- a/test/e2e/specs/editor/various/dropdown-menu.spec.js
+++ b/test/e2e/specs/editor/various/dropdown-menu.spec.js
@@ -13,9 +13,11 @@ test.describe( 'Dropdown Menu', () => {
.getByRole( 'region', { name: 'Editor top bar' } )
.getByRole( 'button', { name: 'Options' } )
.click();
- const menuItems = page.locator(
- '[role="menuitem"], [role="menuitemcheckbox"], [role="menuitemradio"]'
- );
+ const menuItems = page
+ .getByRole( 'menu', { name: 'Options' } )
+ .locator(
+ '[role="menuitem"], [role="menuitemcheckbox"], [role="menuitemradio"]'
+ );
const totalItems = await menuItems.count();
// Catch any issues with the selector, which could cause a false positive test result.
diff --git a/test/e2e/specs/site-editor/navigation-editor.spec.js b/test/e2e/specs/site-editor/navigation-editor.spec.js
index 344f776c71e027..0761f35535ba8e 100644
--- a/test/e2e/specs/site-editor/navigation-editor.spec.js
+++ b/test/e2e/specs/site-editor/navigation-editor.spec.js
@@ -19,7 +19,7 @@ test.describe( 'Editing Navigation Menus', () => {
requestUtils,
editor,
} ) => {
- await test.step( 'Manually browse to focus mode for a Navigation Menu', async () => {
+ await test.step( 'Check Navigation block is present and locked', async () => {
// create a Navigation Menu called "Test Menu" using the REST API helpers
const createdMenu = await requestUtils.createNavigationMenu( {
title: 'Primary Menu',
@@ -34,69 +34,12 @@ test.describe( 'Editing Navigation Menus', () => {
'',
} );
- // We could Navigate directly to editing the Navigation Menu but we intentionally do not do this.
- //
- // Why? To provide coverage for a bug that caused the Navigation Editor behaviours to fail
- // only when navigating through the editor screens (rather than going directly to the editor by URL).
- // See: https://github.com/WordPress/gutenberg/pull/56856.
- //
- // Example (what we could do):
- // await admin.visitSiteEditor( {
- // postId: createdMenu?.id,
- // postType: 'wp_navigation',
- // } );
- //
- await admin.visitSiteEditor();
-
- const editorSidebar = page.getByRole( 'region', {
- name: 'Navigation',
+ await admin.visitSiteEditor( {
+ postId: createdMenu?.id,
+ postType: 'wp_navigation',
+ canvas: 'edit',
} );
- await editorSidebar
- .getByRole( 'button', {
- name: 'Navigation',
- } )
- .click();
-
- // Wait for list of Navigations to appear.
- await expect(
- editorSidebar.getByRole( 'heading', {
- name: 'Navigation',
- level: 1,
- } )
- ).toBeVisible();
-
- await expect( page ).toHaveURL(
- `wp-admin/site-editor.php?path=%2Fnavigation`
- );
-
- await editorSidebar
- .getByRole( 'button', {
- name: 'Primary Menu',
- } )
- .click();
-
- await expect( page ).toHaveURL(
- `wp-admin/site-editor.php?postId=${ createdMenu?.id }&postType=wp_navigation`
- );
-
- // Wait for list of Navigations to appear.
- await expect(
- editorSidebar.getByRole( 'heading', {
- name: 'Primary Menu',
- level: 1,
- } )
- ).toBeVisible();
-
- // Switch to editing the Navigation Menu
- await editorSidebar
- .getByRole( 'link', {
- name: 'Edit',
- } )
- .click();
- } );
-
- await test.step( 'Check Navigation block is present and locked', async () => {
// Open List View.
await pageUtils.pressKeys( 'access+o' );
diff --git a/test/native/jest.config.js b/test/native/jest.config.js
index 4859ea597e0f63..8bd77280dc5509 100644
--- a/test/native/jest.config.js
+++ b/test/native/jest.config.js
@@ -58,7 +58,7 @@ module.exports = {
'node_modules',
],
moduleNameMapper: {
- // Mock the CSS modules. See https://facebook.github.io/jest/docs/en/webpack.html#handling-static-assets
+ // Mock the CSS modules. See https://jestjs.io/docs/webpack#handling-static-assets
'\\.(scss)$': '/test/native/__mocks__/styleMock.js',
'\\.(eot|otf|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
'/test/native/__mocks__/fileMock.js',