-
-
- { __( 'Navigation' ) }
-
-
- { isMenuSelected && actionHeaderText }
-
-
+
+ { __( 'Navigation' ) }
+
+
+ { isMenuSelected && actionHeaderText }
+
{ isMenuSelected && (
}
sidebar={
- ( hasPermanentSidebar ||
- hasSidebarEnabled ) && (
+ hasSidebarEnabled && (
)
}
@@ -190,7 +179,6 @@ export default function Layout( { blockEditorSettings } ) {
onSelectMenu={ selectMenu }
onDeleteMenu={ deleteMenu }
isMenuBeingDeleted={ isMenuBeingDeleted }
- hasPermanentSidebar={ hasPermanentSidebar }
/>
) }
diff --git a/packages/edit-navigation/src/components/layout/style.scss b/packages/edit-navigation/src/components/layout/style.scss
index 9689f2ecc13850..0d84561fc19a8c 100644
--- a/packages/edit-navigation/src/components/layout/style.scss
+++ b/packages/edit-navigation/src/components/layout/style.scss
@@ -34,45 +34,14 @@
// Reference element for the block popover position.
position: relative;
- // The 10px match that of similar settings pages.
- padding: $grid-unit-15 10px 10px 10px;
-
- @include break-medium() {
- // Provide space for the floating block toolbar.
- padding-top: $navigation-editor-spacing-top;
- }
-
// Ensure the entire layout is full-height, the background
// of the editing canvas needs to be full-height for block
// deselection to work.
flex-grow: 1;
}
- .interface-interface-skeleton__header {
- border-bottom-color: transparent;
- }
-
- // Force the sidebar to the right side of the screen on larger
- // breakpoints.
- &.has-permanent-sidebar .interface-interface-skeleton__sidebar {
- position: fixed !important;
- top: $grid-unit-40;
- right: 0;
- bottom: 0;
- left: auto;
-
- // Hide the toggle as the sidebar should be permanently open.
- .edit-navigation-sidebar__panel-tabs > button {
- display: none;
- }
- }
-
.edit-navigation-header {
background: $white;
-
- @include break-medium() {
- background: transparent;
- }
}
}
diff --git a/packages/edit-navigation/src/components/sidebar/index.js b/packages/edit-navigation/src/components/sidebar/index.js
index 4123ef911e146a..c6301230b1e587 100644
--- a/packages/edit-navigation/src/components/sidebar/index.js
+++ b/packages/edit-navigation/src/components/sidebar/index.js
@@ -13,6 +13,7 @@ import {
ComplementaryArea,
store as interfaceStore,
} from '@wordpress/interface';
+import { useViewportMatch } from '@wordpress/compose';
/**
* Internal dependencies
@@ -29,8 +30,8 @@ export default function Sidebar( {
isMenuBeingDeleted,
onDeleteMenu,
onSelectMenu,
- hasPermanentSidebar,
} ) {
+ const isLargeViewport = useViewportMatch( 'medium' );
const { sidebar, hasBlockSelection, hasSidebarEnabled } = useSelect(
( select ) => {
const _sidebar = select(
@@ -79,10 +80,10 @@ export default function Sidebar( {
scope={ SIDEBAR_SCOPE }
identifier={ sidebarName }
icon={ cog }
- isActiveByDefault={ hasPermanentSidebar }
+ isActiveByDefault={ isLargeViewport }
header={ }
headerClassName="edit-navigation-sidebar__panel-tabs"
- isPinnable={ ! hasPermanentSidebar }
+ isPinnable
>
{ sidebarName === SIDEBAR_MENU && (
<>
From 9385d9c0c4a7a373e2c757d06bd71f8d989d6167 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Greg=20Zi=C3=B3=C5=82kowski?=
Date: Mon, 23 Aug 2021 09:39:02 +0200
Subject: [PATCH 007/214] Block Editor: Try groups for InspectorControls
(#34069)
* Block Editor: Try groups for InspectorControls
* Update packages/block-editor/src/components/inspector-controls/fill.js
* Remove the `block` group in InspectorControls
* Make the group in InspectorControls experimental
* Update React Native implementation to match web
---
packages/block-editor/README.md | 4 +-
.../src/components/block-inspector/index.js | 18 +-
packages/block-editor/src/components/index.js | 6 +-
.../src/components/index.native.js | 6 +-
.../inspector-advanced-controls/README.md | 72 ------
.../inspector-advanced-controls/index.js | 32 ---
.../components/inspector-controls/README.md | 241 ++++--------------
.../src/components/inspector-controls/fill.js | 32 +++
.../{index.native.js => fill.native.js} | 28 +-
.../components/inspector-controls/groups.js | 14 +
.../components/inspector-controls/index.js | 34 ++-
.../src/components/inspector-controls/slot.js | 30 +++
.../inspector-controls/slot.native.js | 22 ++
packages/block-editor/src/hooks/anchor.js | 6 +-
.../src/hooks/custom-class-name.js | 6 +-
packages/block-library/src/button/edit.js | 5 +-
packages/block-library/src/group/edit.js | 6 +-
packages/block-library/src/image/image.js | 5 +-
packages/block-library/src/post-terms/edit.js | 6 +-
.../block-library/src/query/edit/index.js | 6 +-
.../template-part/edit/advanced-controls.js | 6 +-
21 files changed, 211 insertions(+), 374 deletions(-)
delete mode 100644 packages/block-editor/src/components/inspector-advanced-controls/README.md
delete mode 100644 packages/block-editor/src/components/inspector-advanced-controls/index.js
create mode 100644 packages/block-editor/src/components/inspector-controls/fill.js
rename packages/block-editor/src/components/inspector-controls/{index.native.js => fill.native.js} (57%)
create mode 100644 packages/block-editor/src/components/inspector-controls/groups.js
create mode 100644 packages/block-editor/src/components/inspector-controls/slot.js
create mode 100644 packages/block-editor/src/components/inspector-controls/slot.native.js
diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md
index 03ef4ee43b0381..b742a81e3dc8a0 100644
--- a/packages/block-editor/README.md
+++ b/packages/block-editor/README.md
@@ -438,9 +438,7 @@ Undocumented declaration.
### InspectorAdvancedControls
-_Related_
-
--
+Undocumented declaration.
### InspectorControls
diff --git a/packages/block-editor/src/components/block-inspector/index.js b/packages/block-editor/src/components/block-inspector/index.js
index 2a8f7ffeb40dbc..0ef6a790d16884 100644
--- a/packages/block-editor/src/components/block-inspector/index.js
+++ b/packages/block-editor/src/components/block-inspector/index.js
@@ -19,8 +19,10 @@ import { useSelect } from '@wordpress/data';
*/
import SkipToSelectedBlock from '../skip-to-selected-block';
import BlockCard from '../block-card';
-import InspectorControls from '../inspector-controls';
-import InspectorAdvancedControls from '../inspector-advanced-controls';
+import {
+ default as InspectorControls,
+ InspectorAdvancedControls,
+} from '../inspector-controls';
import BlockStyles from '../block-styles';
import MultiSelectionInspector from '../multi-selection-inspector';
import DefaultStylePicker from '../default-style-picker';
@@ -128,18 +130,15 @@ const BlockInspectorSingleBlock = ( {
) }
);
};
-const AdvancedControls = ( { slotName, bubblesVirtually } ) => {
- const slot = useSlot( slotName );
+const AdvancedControls = ( { bubblesVirtually } ) => {
+ const slot = useSlot( InspectorAdvancedControls.slotName );
const hasFills = Boolean( slot.fills && slot.fills.length );
if ( ! hasFills ) {
@@ -152,7 +151,8 @@ const AdvancedControls = ( { slotName, bubblesVirtually } ) => {
title={ __( 'Advanced' ) }
initialOpen={ false }
>
-
diff --git a/packages/block-editor/src/components/index.js b/packages/block-editor/src/components/index.js
index 8cf025bdcc10a5..99c1042b991730 100644
--- a/packages/block-editor/src/components/index.js
+++ b/packages/block-editor/src/components/index.js
@@ -52,8 +52,10 @@ export {
default as InnerBlocks,
useInnerBlocksProps as __experimentalUseInnerBlocksProps,
} from './inner-blocks';
-export { default as InspectorAdvancedControls } from './inspector-advanced-controls';
-export { default as InspectorControls } from './inspector-controls';
+export {
+ default as InspectorControls,
+ InspectorAdvancedControls,
+} from './inspector-controls';
export {
JustifyToolbar,
JustifyContentControl,
diff --git a/packages/block-editor/src/components/index.native.js b/packages/block-editor/src/components/index.native.js
index 89fa80d8b44c83..995042b7d65cdf 100644
--- a/packages/block-editor/src/components/index.native.js
+++ b/packages/block-editor/src/components/index.native.js
@@ -22,8 +22,10 @@ export {
default as InnerBlocks,
useInnerBlocksProps as __experimentalUseInnerBlocksProps,
} from './inner-blocks';
-export { default as InspectorAdvancedControls } from './inspector-advanced-controls';
-export { default as InspectorControls } from './inspector-controls';
+export {
+ default as InspectorControls,
+ InspectorAdvancedControls,
+} from './inspector-controls';
export {
JustifyToolbar,
JustifyContentControl,
diff --git a/packages/block-editor/src/components/inspector-advanced-controls/README.md b/packages/block-editor/src/components/inspector-advanced-controls/README.md
deleted file mode 100644
index b14b0cb6a73e24..00000000000000
--- a/packages/block-editor/src/components/inspector-advanced-controls/README.md
+++ /dev/null
@@ -1,72 +0,0 @@
-# InspectorAdvancedControls
-
-
-
-Inspector Advanced Controls appear under the _Advanced_ panel of a block's [InspectorControls](https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/inspector-controls/README.md) -- that is, they appear as a specific set of controls within a block's settings panels. As the name suggests, `InspectorAdvancedControls` is meant for controls that most users aren't meant to interact with most of the time, such as adding an HTML anchor or custom CSS classes to a block.
-
-## Usage
-
-{% codetabs %}
-{% ESNext %}
-
-```js
-const {
- TextControl,
-} = wp.components;
-const {
- InspectorControls,
- InspectorAdvancedControls,
-} = wp.editor;
-
-function MyBlockEdit( { attributes, setAttributes } ) {
- return (
- <>
-
- { /* Block markup goes here */ }
-
- { /* Regular control goes here */
-
-
- {
- setAttributes( {
- anchor: nextValue,
- } );
- } }
- />
-
- >
- );
-}
-```
-
-{% ES5 %}
-
-```js
-var el = wp.element.createElement,
- Fragment = wp.element.Fragment,
- InspectorControls = wp.editor.InspectorControls,
- InspectorAdvancedControlsControls = wp.editor.InspectorAdvancedControls,
- TextControl = wp.components.TextControl,
-
-function MyBlockEdit( props ) {
- return el( Fragment, null,
- el( 'div', null, /* Block markup goes here */ null ),
- el( InspectorControls, null, /* Regular control goes here */ null ),
- el( InspectorAdvancedControls, null,
- el( TextControl, {
- label: 'HTML anchor',
- value: props.attributes.anchor,
- onChange: function( nextValue ) {
- props.setAttributes( { anchor: nextValue } );
- }
- } )
- )
- );
-}
-```
-
-{% end %}
diff --git a/packages/block-editor/src/components/inspector-advanced-controls/index.js b/packages/block-editor/src/components/inspector-advanced-controls/index.js
deleted file mode 100644
index 4ed9b6341142d8..00000000000000
--- a/packages/block-editor/src/components/inspector-advanced-controls/index.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * WordPress dependencies
- */
-import {
- createSlotFill,
- __experimentalStyleProvider as StyleProvider,
-} from '@wordpress/components';
-
-/**
- * Internal dependencies
- */
-import { useBlockEditContext } from '../block-edit/context';
-
-const name = 'InspectorAdvancedControls';
-const { Fill, Slot } = createSlotFill( name );
-
-function InspectorAdvancedControls( { children } ) {
- const { isSelected } = useBlockEditContext();
- return isSelected ? (
-
- { children }
-
- ) : null;
-}
-
-InspectorAdvancedControls.slotName = name;
-InspectorAdvancedControls.Slot = Slot;
-
-/**
- * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/inspector-advanced-controls/README.md
- */
-export default InspectorAdvancedControls;
diff --git a/packages/block-editor/src/components/inspector-controls/README.md b/packages/block-editor/src/components/inspector-controls/README.md
index 8310ae3a8db7e2..2799431917b75e 100644
--- a/packages/block-editor/src/components/inspector-controls/README.md
+++ b/packages/block-editor/src/components/inspector-controls/README.md
@@ -6,201 +6,6 @@ Inspector Controls appear in the post settings sidebar when a block is being edi
## Usage
-{% codetabs %}
-{% ES5 %}
-
-```js
-var el = wp.element.createElement,
- Fragment = wp.element.Fragment,
- registerBlockType = wp.blocks.registerBlockType,
- RichText = wp.editor.RichText,
- InspectorControls = wp.blockEditor.InspectorControls,
- useBlockProps = wp.blockEditor.useBlockProps,
- CheckboxControl = wp.components.CheckboxControl,
- RadioControl = wp.components.RadioControl,
- TextControl = wp.components.TextControl,
- ToggleControl = wp.components.ToggleControl,
- SelectControl = wp.components.SelectControl,
- PanelBody = wp.components.PanelBody;
-
-registerBlockType( 'my-plugin/inspector-controls-example', {
- apiVersion: 2,
-
- title: 'Inspector controls example',
-
- icon: 'universal-access-alt',
-
- category: 'design',
-
- attributes: {
- content: {
- type: 'string',
- source: 'html',
- selector: 'p',
- },
- checkboxField: {
- type: 'boolean',
- default: true,
- },
- radioField: {
- type: 'string',
- default: 'yes',
- },
- textField: {
- type: 'string',
- },
- toggleField: {
- type: 'boolean',
- },
- selectField: {
- type: 'string',
- },
- },
-
- edit: function ( props ) {
- var blockProps = useBlockProps();
-
- var content = props.attributes.content,
- checkboxField = props.attributes.checkboxField,
- radioField = props.attributes.radioField,
- textField = props.attributes.textField,
- toggleField = props.attributes.toggleField,
- selectField = props.attributes.selectField;
-
- function onChangeContent( newContent ) {
- props.setAttributes( { content: newContent } );
- }
-
- function onChangeCheckboxField( newValue ) {
- props.setAttributes( { checkboxField: newValue } );
- }
-
- function onChangeRadioField( newValue ) {
- props.setAttributes( { radioField: newValue } );
- }
-
- function onChangeTextField( newValue ) {
- props.setAttributes( { textField: newValue } );
- }
-
- function onChangeToggleField( newValue ) {
- props.setAttributes( { toggleField: newValue } );
- }
-
- function onChangeSelectField( newValue ) {
- props.setAttributes( { selectField: newValue } );
- }
-
- return el(
- Fragment,
- null,
- el(
- InspectorControls,
- null,
- el(
- PanelBody,
- {
- title: 'Settings',
- },
- el( CheckboxControl, {
- heading: 'Checkbox Field',
- label: 'Tick Me',
- help: 'Additional help text',
- checked: checkboxField,
- onChange: onChangeCheckboxField,
- } ),
- el( RadioControl, {
- label: 'Radio Field',
- selected: radioField,
- options: [
- {
- label: 'Yes',
- value: 'yes',
- },
- {
- label: 'No',
- value: 'no',
- },
- ],
- onChange: onChangeRadioField,
- } ),
- el( TextControl, {
- label: 'Text Field',
- help: 'Additional help text',
- value: textField,
- onChange: onChangeTextField,
- } ),
- el( ToggleControl, {
- label: 'Toggle Field',
- checked: toggleField,
- onChange: onChangeToggleField,
- } ),
- el( SelectControl, {
- label: 'Select Field',
- value: selectField,
- options: [
- {
- value: 'a',
- label: 'Option A',
- },
- {
- value: 'b',
- label: 'Option B',
- },
- {
- value: 'c',
- label: 'Option C',
- },
- ],
- onChange: onChangeSelectField,
- } )
- )
- ),
- el(
- RichText,
- Object.assing( blockProps, {
- key: 'editable',
- tagName: 'p',
- onChange: onChangeContent,
- value: content,
- } )
- )
- );
- },
-
- save: function ( props ) {
- var blockProps = useBlockProps.save();
- var content = props.attributes.content,
- checkboxField = props.attributes.checkboxField,
- radioField = props.attributes.radioField,
- textField = props.attributes.textField,
- toggleField = props.attributes.toggleField,
- selectField = props.attributes.selectField;
-
- return el(
- 'div',
- blockProps,
- el( RichText.Content, {
- value: content,
- tagName: 'p',
- } ),
- el( 'h2', null, 'Inspector Control Fields' ),
- el(
- 'ul',
- null,
- el( 'li', null, 'Checkbox Field: ', checkboxField ),
- el( 'li', null, 'Radio Field: ', radioField ),
- el( 'li', null, 'Text Field: ', textField ),
- el( 'li', null, 'Toggle Field: ', toggleField ),
- el( 'li', null, 'Select Field: ', selectField )
- )
- );
- },
-} );
-```
-
-{% ESNext %}
-
```js
import { registerBlockType } from '@wordpress/blocks';
import {
@@ -209,7 +14,7 @@ import {
TextControl,
ToggleControl,
SelectControl,
- PanelBody
+ PanelBody,
} from '@wordpress/components';
import {
RichText,
@@ -289,7 +94,7 @@ registerBlockType( 'my-plugin/inspector-controls-example', {
return (
<>
-
+
+
+Inspector Advanced Controls appear under the _Advanced_ panel of a block's [InspectorControls](https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/inspector-controls/README.md) -- that is, they appear as a specific set of controls within a block's settings panels. As the name suggests, `InspectorAdvancedControls` is meant for controls that most users aren't meant to interact with most of the time, such as adding an HTML anchor or custom CSS classes to a block.
+
+### Usage
+
+```js
+import {
+ TextControl,
+} from '@wordpress/components';
+import {
+ InspectorControls,
+ InspectorAdvancedControls,
+} from '@wordpress/block-editor';
+
+function MyBlockEdit( { attributes, setAttributes } ) {
+ return (
+ <>
+
+ { /* Block markup goes here */ }
+
+ { /* Regular control goes here */
+
+
+ {
+ setAttributes( {
+ anchor: nextValue,
+ } );
+ } }
+ />
+
+ >
+ );
+}
+```
diff --git a/packages/block-editor/src/components/inspector-controls/fill.js b/packages/block-editor/src/components/inspector-controls/fill.js
new file mode 100644
index 00000000000000..bb1c8fd7accdf3
--- /dev/null
+++ b/packages/block-editor/src/components/inspector-controls/fill.js
@@ -0,0 +1,32 @@
+/**
+ * WordPress dependencies
+ */
+import { __experimentalStyleProvider as StyleProvider } from '@wordpress/components';
+import warning from '@wordpress/warning';
+
+/**
+ * Internal dependencies
+ */
+import useDisplayBlockControls from '../use-display-block-controls';
+import groups from './groups';
+
+export default function InspectorControlsFill( {
+ __experimentalGroup: group = 'default',
+ children,
+} ) {
+ const isDisplayed = useDisplayBlockControls();
+ const Fill = groups[ group ]?.Fill;
+ if ( ! Fill ) {
+ warning( `Unknown InspectorControl group "${ group }" provided.` );
+ return null;
+ }
+ if ( ! isDisplayed ) {
+ return null;
+ }
+
+ return (
+
+ { children }
+
+ );
+}
diff --git a/packages/block-editor/src/components/inspector-controls/index.native.js b/packages/block-editor/src/components/inspector-controls/fill.native.js
similarity index 57%
rename from packages/block-editor/src/components/inspector-controls/index.native.js
rename to packages/block-editor/src/components/inspector-controls/fill.native.js
index ed131ddb4ce6a7..01ac32b2565007 100644
--- a/packages/block-editor/src/components/inspector-controls/index.native.js
+++ b/packages/block-editor/src/components/inspector-controls/fill.native.js
@@ -7,18 +7,27 @@ import { View } from 'react-native';
* WordPress dependencies
*/
import { Children } from '@wordpress/element';
-import { createSlotFill, BottomSheetConsumer } from '@wordpress/components';
+import { BottomSheetConsumer } from '@wordpress/components';
+import warning from '@wordpress/warning';
/**
* Internal dependencies
*/
+import groups from './groups';
import { useBlockEditContext } from '../block-edit/context';
import { BlockSettingsButton } from '../block-settings';
-const { Fill, Slot } = createSlotFill( 'InspectorControls' );
-
-const FillWithSettingsButton = ( { children, ...props } ) => {
+export default function InspectorControlsFill( {
+ children,
+ __experimentalGroup: group = 'default',
+ ...props
+} ) {
const { isSelected } = useBlockEditContext();
+ const Fill = groups[ group ]?.Fill;
+ if ( ! Fill ) {
+ warning( `Unknown InspectorControl group "${ group }" provided.` );
+ return null;
+ }
if ( ! isSelected ) {
return null;
}
@@ -35,13 +44,4 @@ const FillWithSettingsButton = ( { children, ...props } ) => {
{ Children.count( children ) > 0 &&
}
>
);
-};
-
-const InspectorControls = FillWithSettingsButton;
-
-InspectorControls.Slot = Slot;
-
-/**
- * @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/inspector-controls/README.md
- */
-export default InspectorControls;
+}
diff --git a/packages/block-editor/src/components/inspector-controls/groups.js b/packages/block-editor/src/components/inspector-controls/groups.js
new file mode 100644
index 00000000000000..a989132afd4c72
--- /dev/null
+++ b/packages/block-editor/src/components/inspector-controls/groups.js
@@ -0,0 +1,14 @@
+/**
+ * WordPress dependencies
+ */
+import { createSlotFill } from '@wordpress/components';
+
+const InspectorControlsDefault = createSlotFill( 'InspectorControls' );
+const InspectorControlsAdvanced = createSlotFill( 'InspectorAdvancedControls' );
+
+const groups = {
+ default: InspectorControlsDefault,
+ advanced: InspectorControlsAdvanced,
+};
+
+export default groups;
diff --git a/packages/block-editor/src/components/inspector-controls/index.js b/packages/block-editor/src/components/inspector-controls/index.js
index 9a6cb7bab61a7d..4cb36cdc843994 100644
--- a/packages/block-editor/src/components/inspector-controls/index.js
+++ b/packages/block-editor/src/components/inspector-controls/index.js
@@ -1,27 +1,25 @@
-/**
- * WordPress dependencies
- */
-import {
- __experimentalStyleProvider as StyleProvider,
- createSlotFill,
-} from '@wordpress/components';
-
/**
* Internal dependencies
*/
-import useDisplayBlockControls from '../use-display-block-controls';
+import InspectorControlsFill from './fill';
+import InspectorControlsSlot from './slot';
-const { Fill, Slot } = createSlotFill( 'InspectorControls' );
+const InspectorControls = InspectorControlsFill;
-function InspectorControls( { children } ) {
- return useDisplayBlockControls() ? (
-
- { children }
-
- ) : null;
-}
+InspectorControls.Slot = InspectorControlsSlot;
-InspectorControls.Slot = Slot;
+// This is just here for backward compatibility.
+export const InspectorAdvancedControls = ( props ) => {
+ return (
+
+ );
+};
+InspectorAdvancedControls.Slot = ( props ) => {
+ return (
+
+ );
+};
+InspectorAdvancedControls.slotName = 'InspectorAdvancedControls';
/**
* @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/block-editor/src/components/inspector-controls/README.md
diff --git a/packages/block-editor/src/components/inspector-controls/slot.js b/packages/block-editor/src/components/inspector-controls/slot.js
new file mode 100644
index 00000000000000..f17714cfe41b61
--- /dev/null
+++ b/packages/block-editor/src/components/inspector-controls/slot.js
@@ -0,0 +1,30 @@
+/**
+ * WordPress dependencies
+ */
+import { __experimentalUseSlot as useSlot } from '@wordpress/components';
+import warning from '@wordpress/warning';
+
+/**
+ * Internal dependencies
+ */
+import groups from './groups';
+
+export default function InspectorControlsSlot( {
+ __experimentalGroup: group = 'default',
+ bubblesVirtually = true,
+ ...props
+} ) {
+ const Slot = groups[ group ]?.Slot;
+ const slot = useSlot( Slot?.__unstableName );
+ if ( ! Slot || ! slot ) {
+ warning( `Unknown InspectorControl group "${ group }" provided.` );
+ return null;
+ }
+
+ const hasFills = Boolean( slot.fills && slot.fills.length );
+ if ( ! hasFills ) {
+ return null;
+ }
+
+ return
;
+}
diff --git a/packages/block-editor/src/components/inspector-controls/slot.native.js b/packages/block-editor/src/components/inspector-controls/slot.native.js
new file mode 100644
index 00000000000000..adf4da06965e42
--- /dev/null
+++ b/packages/block-editor/src/components/inspector-controls/slot.native.js
@@ -0,0 +1,22 @@
+/**
+ * WordPress dependencies
+ */
+import warning from '@wordpress/warning';
+
+/**
+ * Internal dependencies
+ */
+import groups from './groups';
+
+export default function InspectorControlsSlot( {
+ __experimentalGroup: group = 'default',
+ ...props
+} ) {
+ const Slot = groups[ group ]?.Slot;
+ if ( ! Slot ) {
+ warning( `Unknown InspectorControl group "${ group }" provided.` );
+ return null;
+ }
+
+ return
;
+}
diff --git a/packages/block-editor/src/hooks/anchor.js b/packages/block-editor/src/hooks/anchor.js
index 3e1e2b813072ef..07024b78c51f66 100644
--- a/packages/block-editor/src/hooks/anchor.js
+++ b/packages/block-editor/src/hooks/anchor.js
@@ -16,7 +16,7 @@ import { Platform } from '@wordpress/element';
/**
* Internal dependencies
*/
-import { InspectorControls, InspectorAdvancedControls } from '../components';
+import { InspectorControls } from '../components';
/**
* Regular expression matching invalid anchor characters for replacement.
@@ -107,9 +107,9 @@ export const withInspectorControl = createHigherOrderComponent(
<>
{ isWeb && (
-
+
{ textControl }
-
+
) }
{ /*
* We plan to remove scoping anchors to 'core/heading' to support
diff --git a/packages/block-editor/src/hooks/custom-class-name.js b/packages/block-editor/src/hooks/custom-class-name.js
index ae5b623887cca0..0ed09f8975c5cb 100644
--- a/packages/block-editor/src/hooks/custom-class-name.js
+++ b/packages/block-editor/src/hooks/custom-class-name.js
@@ -15,7 +15,7 @@ import { createHigherOrderComponent } from '@wordpress/compose';
/**
* Internal dependencies
*/
-import { InspectorAdvancedControls } from '../components';
+import { InspectorControls } from '../components';
/**
* Filters registered block settings, extending attributes with anchor using ID
@@ -59,7 +59,7 @@ export const withInspectorControl = createHigherOrderComponent(
return (
<>
-
+
-
+
>
);
}
diff --git a/packages/block-library/src/button/edit.js b/packages/block-library/src/button/edit.js
index c0f80bc40ae0d2..fd7bb6edde87c3 100644
--- a/packages/block-library/src/button/edit.js
+++ b/packages/block-library/src/button/edit.js
@@ -20,7 +20,6 @@ import {
import {
BlockControls,
InspectorControls,
- InspectorAdvancedControls,
RichText,
useBlockProps,
__experimentalUseBorderProps as useBorderProps,
@@ -260,13 +259,13 @@ function ButtonEdit( props ) {
setAttributes={ setAttributes }
/>
-
+
-
+
>
);
}
diff --git a/packages/block-library/src/group/edit.js b/packages/block-library/src/group/edit.js
index 5628ea0105ce8d..c82ab09a1709af 100644
--- a/packages/block-library/src/group/edit.js
+++ b/packages/block-library/src/group/edit.js
@@ -5,7 +5,7 @@ import { useSelect } from '@wordpress/data';
import {
InnerBlocks,
useBlockProps,
- InspectorAdvancedControls,
+ InspectorControls,
__experimentalUseInnerBlocksProps as useInnerBlocksProps,
useSetting,
store as blockEditorStore,
@@ -45,7 +45,7 @@ function GroupEdit( { attributes, setAttributes, clientId } ) {
return (
<>
-
+
-
+
{ themeSupportsLayout &&
}
{ /* Ideally this is not needed but it's there for backward compatibility reason
to keep this div for themes that might rely on its presence */ }
diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js
index 54b552186e7ffe..b4cc2c29f6252a 100644
--- a/packages/block-library/src/image/image.js
+++ b/packages/block-library/src/image/image.js
@@ -21,7 +21,6 @@ import { useSelect, useDispatch } from '@wordpress/data';
import {
BlockControls,
InspectorControls,
- InspectorAdvancedControls,
RichText,
__experimentalImageSizeControl as ImageSizeControl,
__experimentalImageURLInputUI as ImageURLInputUI,
@@ -371,7 +370,7 @@ export default function Image( {
/>
-
+
}
/>
-
+
>
);
diff --git a/packages/block-library/src/post-terms/edit.js b/packages/block-library/src/post-terms/edit.js
index 4a939e2af579cd..4ce94235615a4f 100644
--- a/packages/block-library/src/post-terms/edit.js
+++ b/packages/block-library/src/post-terms/edit.js
@@ -8,7 +8,7 @@ import classnames from 'classnames';
*/
import {
AlignmentToolbar,
- InspectorAdvancedControls,
+ InspectorControls,
BlockControls,
Warning,
useBlockProps,
@@ -79,7 +79,7 @@ export default function PostTermsEdit( {
} }
/>
-
+
-
+
{ isLoading &&
}
{ ! isLoading &&
diff --git a/packages/block-library/src/query/edit/index.js b/packages/block-library/src/query/edit/index.js
index e297534ed8f797..b08bd12eba31bb 100644
--- a/packages/block-library/src/query/edit/index.js
+++ b/packages/block-library/src/query/edit/index.js
@@ -7,7 +7,7 @@ import { useInstanceId } from '@wordpress/compose';
import { useEffect } from '@wordpress/element';
import {
BlockControls,
- InspectorAdvancedControls,
+ InspectorControls,
useBlockProps,
useSetting,
store as blockEditorStore,
@@ -104,7 +104,7 @@ export function QueryContent( { attributes, setAttributes } ) {
setDisplayLayout={ updateDisplayLayout }
/>
-
+
-
+
>
);
diff --git a/packages/block-library/src/template-part/edit/advanced-controls.js b/packages/block-library/src/template-part/edit/advanced-controls.js
index 9086b307b1a839..26393db2d75858 100644
--- a/packages/block-library/src/template-part/edit/advanced-controls.js
+++ b/packages/block-library/src/template-part/edit/advanced-controls.js
@@ -4,7 +4,7 @@
import { useEntityProp } from '@wordpress/core-data';
import { SelectControl, TextControl } from '@wordpress/components';
import { sprintf, __ } from '@wordpress/i18n';
-import { InspectorAdvancedControls } from '@wordpress/block-editor';
+import { InspectorControls } from '@wordpress/block-editor';
import { useSelect } from '@wordpress/data';
export function TemplatePartAdvancedControls( {
@@ -44,7 +44,7 @@ export function TemplatePartAdvancedControls( {
}, [] );
return (
-
+
{ isEntityAvailable && (
<>
setAttributes( { tagName: value } ) }
/>
-
+
);
}
From 1f92131317ac5889b61cb1e5d885fc54c4a6eceb Mon Sep 17 00:00:00 2001
From: Grzegorz Ziolkowski
Date: Mon, 23 Aug 2021 09:52:33 +0200
Subject: [PATCH 008/214] Update changelog files
---
packages/components/CHANGELOG.md | 11 ++++++++---
packages/components/package.json | 2 +-
packages/eslint-plugin/CHANGELOG.md | 7 ++++++-
packages/eslint-plugin/package.json | 2 +-
.../CHANGELOG.md | 4 +++-
.../package.json | 2 +-
packages/scripts/CHANGELOG.md | 2 ++
packages/scripts/package.json | 2 +-
8 files changed, 23 insertions(+), 9 deletions(-)
diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md
index 2ed797b1a56a7d..752245898aa451 100644
--- a/packages/components/CHANGELOG.md
+++ b/packages/components/CHANGELOG.md
@@ -4,16 +4,21 @@
### Bug Fix
-- Listen to `resize` events correctly in `useBreakpointIndex`. This hook is used in `useResponsiveValue` and consequently in the `Flex` and `Grid` components ([#33902](https://github.com/WordPress/gutenberg/pull/33902))
- Fixed RTL styles in `Flex` component ([#33729](https://github.com/WordPress/gutenberg/pull/33729)).
+## 16.0.0 (2021-08-23)
+
### Breaking Change
-- Updated the visual styles of the RangeControl component ([#33824](https://github.com/WordPress/gutenberg/pull/33824))
+- Updated the visual styles of the RangeControl component ([#33824](https://github.com/WordPress/gutenberg/pull/33824)).
### New Feature
-- Add `hideLabelFromVision` prop to `RangeControl` ([#33714](https://github.com/WordPress/gutenberg/pull/33714))
+- Add `hideLabelFromVision` prop to `RangeControl` ([#33714](https://github.com/WordPress/gutenberg/pull/33714)).
+
+### Bug Fix
+
+- Listen to `resize` events correctly in `useBreakpointIndex`. This hook is used in `useResponsiveValue` and consequently in the `Flex` and `Grid` components ([#33902](https://github.com/WordPress/gutenberg/pull/33902))
## 15.0.0 (2021-07-29)
diff --git a/packages/components/package.json b/packages/components/package.json
index 8af8b32f533b10..71a9e6603ae50b 100644
--- a/packages/components/package.json
+++ b/packages/components/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/components",
- "version": "15.0.0",
+ "version": "16.0.0-prerelease",
"description": "UI components for WordPress.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md
index 587e5a10fd1648..5b8830ff10c976 100644
--- a/packages/eslint-plugin/CHANGELOG.md
+++ b/packages/eslint-plugin/CHANGELOG.md
@@ -4,9 +4,14 @@
### Bug Fix
-- Include `.jsx` extension when linting import statements in case TypeScript not present ([#33746](https://github.com/WordPress/gutenberg/pull/33746)).
- The recommended configuration will now respect `type` imports in TypeScript files ([#34055](https://github.com/WordPress/gutenberg/pull/34055)).
+## 9.1.1 (2021-08-23)
+
+### Bug Fix
+
+- Include `.jsx` extension when linting import statements in case TypeScript not present ([#33746](https://github.com/WordPress/gutenberg/pull/33746)).
+
## 9.1.0 (2021-07-21)
### Enhancement
diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json
index a80b690be4276c..306177e4aef3a6 100644
--- a/packages/eslint-plugin/package.json
+++ b/packages/eslint-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/eslint-plugin",
- "version": "9.1.0",
+ "version": "9.1.1-prerelease",
"description": "ESLint plugin for WordPress development.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/library-export-default-webpack-plugin/CHANGELOG.md b/packages/library-export-default-webpack-plugin/CHANGELOG.md
index f95007336313a7..dce16c429d1d84 100644
--- a/packages/library-export-default-webpack-plugin/CHANGELOG.md
+++ b/packages/library-export-default-webpack-plugin/CHANGELOG.md
@@ -2,9 +2,11 @@
## Unreleased
+## 2.2.0 (2021-08-23)
+
### Deprecations
-- This plugin is deprecated for webpack 5. Please use [`output.library.export`](https://webpack.js.org/configuration/output/#outputlibraryexport) instead ([#33818](ttps://github.com/WordPress/gutenberg/pull/33818)).
+- This plugin is deprecated for webpack 5. Please use [`output.library.export`](https://webpack.js.org/configuration/output/#outputlibraryexport) instead ([#33818](https://github.com/WordPress/gutenberg/pull/33818)).
## 2.0.0 (2021-01-21)
diff --git a/packages/library-export-default-webpack-plugin/package.json b/packages/library-export-default-webpack-plugin/package.json
index f7585909f5dfec..f9a36565fb2ae1 100644
--- a/packages/library-export-default-webpack-plugin/package.json
+++ b/packages/library-export-default-webpack-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/library-export-default-webpack-plugin",
- "version": "2.1.0",
+ "version": "2.2.0-prerelease",
"description": "Webpack plugin for exporting default property for selected libraries.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/scripts/CHANGELOG.md b/packages/scripts/CHANGELOG.md
index 72acb296712ac7..adaf85dc90af5a 100644
--- a/packages/scripts/CHANGELOG.md
+++ b/packages/scripts/CHANGELOG.md
@@ -2,6 +2,8 @@
## Unreleased
+## 18.0.0 (2021-08-23)
+
### Breaking Changes
- Increase the minimum Node.js version to v12.13 matching requirements from bundled dependencies ([#33818](https://github.com/WordPress/gutenberg/pull/33818)).
diff --git a/packages/scripts/package.json b/packages/scripts/package.json
index 561816a693aa9c..367f3424e5daa0 100644
--- a/packages/scripts/package.json
+++ b/packages/scripts/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/scripts",
- "version": "17.1.0",
+ "version": "18.0.0-prerelease",
"description": "Collection of reusable scripts for WordPress development.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
From d78f324141cd26b4290671583163c2c9717746df Mon Sep 17 00:00:00 2001
From: Grzegorz Ziolkowski
Date: Mon, 23 Aug 2021 09:54:08 +0200
Subject: [PATCH 009/214] chore(release): publish
- @wordpress/annotations@2.2.2
- @wordpress/block-directory@3.0.1
- @wordpress/block-editor@7.0.1
- @wordpress/block-library@5.0.1
- @wordpress/blocks@11.0.1
- @wordpress/components@16.0.0
- @wordpress/compose@5.0.1
- @wordpress/core-data@4.0.1
- @wordpress/customize-widgets@2.0.1
- @wordpress/data-controls@2.2.2
- @wordpress/data@6.0.1
- @wordpress/dom@3.2.2
- @wordpress/e2e-test-utils@5.4.2
- @wordpress/e2e-tests@2.4.1
- @wordpress/edit-post@5.0.1
- @wordpress/edit-site@3.0.1
- @wordpress/edit-widgets@3.0.1
- @wordpress/editor@11.0.1
- @wordpress/eslint-plugin@9.1.1
- @wordpress/format-library@3.0.1
- @wordpress/icons@5.0.1
- @wordpress/interface@4.0.1
- @wordpress/keyboard-shortcuts@3.0.1
- @wordpress/library-export-default-webpack-plugin@2.2.0
- @wordpress/list-reusable-blocks@3.0.1
- @wordpress/notices@3.2.2
- @wordpress/nux@5.0.1
- @wordpress/plugins@4.0.1
- @wordpress/readable-js-assets-webpack-plugin@1.0.2
- @wordpress/reusable-blocks@3.0.1
- @wordpress/rich-text@5.0.1
- @wordpress/scripts@18.0.0
- @wordpress/server-side-render@3.0.1
- @wordpress/viewport@4.0.1
- @wordpress/widgets@2.0.1
---
packages/annotations/package.json | 2 +-
packages/block-directory/package.json | 2 +-
packages/block-editor/package.json | 2 +-
packages/block-library/package.json | 2 +-
packages/blocks/package.json | 2 +-
packages/components/package.json | 2 +-
packages/compose/package.json | 2 +-
packages/core-data/package.json | 2 +-
packages/customize-widgets/package.json | 2 +-
packages/data-controls/package.json | 2 +-
packages/data/package.json | 2 +-
packages/dom/package.json | 2 +-
packages/e2e-test-utils/package.json | 2 +-
packages/e2e-tests/package.json | 2 +-
packages/edit-post/package.json | 2 +-
packages/edit-site/package.json | 2 +-
packages/edit-widgets/package.json | 2 +-
packages/editor/package.json | 2 +-
packages/eslint-plugin/package.json | 2 +-
packages/format-library/package.json | 2 +-
packages/icons/package.json | 2 +-
packages/interface/package.json | 2 +-
packages/keyboard-shortcuts/package.json | 2 +-
packages/library-export-default-webpack-plugin/package.json | 2 +-
packages/list-reusable-blocks/package.json | 2 +-
packages/notices/package.json | 2 +-
packages/nux/package.json | 2 +-
packages/plugins/package.json | 2 +-
packages/readable-js-assets-webpack-plugin/package.json | 2 +-
packages/reusable-blocks/package.json | 2 +-
packages/rich-text/package.json | 2 +-
packages/scripts/package.json | 2 +-
packages/server-side-render/package.json | 2 +-
packages/viewport/package.json | 2 +-
packages/widgets/package.json | 2 +-
35 files changed, 35 insertions(+), 35 deletions(-)
diff --git a/packages/annotations/package.json b/packages/annotations/package.json
index 95244ac008b6a0..b53046ace2124b 100644
--- a/packages/annotations/package.json
+++ b/packages/annotations/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/annotations",
- "version": "2.2.1",
+ "version": "2.2.2",
"description": "Annotate content in the Gutenberg editor.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/block-directory/package.json b/packages/block-directory/package.json
index f33aa6099bfa94..ce59cc46bb0619 100644
--- a/packages/block-directory/package.json
+++ b/packages/block-directory/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/block-directory",
- "version": "3.0.0",
+ "version": "3.0.1",
"description": "Extend editor with block directory features to search, download and install blocks.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/block-editor/package.json b/packages/block-editor/package.json
index 0550430cde029d..63a1cd006a4597 100644
--- a/packages/block-editor/package.json
+++ b/packages/block-editor/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/block-editor",
- "version": "7.0.0",
+ "version": "7.0.1",
"description": "Generic block editor.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/block-library/package.json b/packages/block-library/package.json
index d02fee6ab2f616..4ad410cac248dc 100644
--- a/packages/block-library/package.json
+++ b/packages/block-library/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/block-library",
- "version": "5.0.0",
+ "version": "5.0.1",
"description": "Block library for the WordPress editor.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/blocks/package.json b/packages/blocks/package.json
index 74c285fa650abe..8741fb317c907e 100644
--- a/packages/blocks/package.json
+++ b/packages/blocks/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/blocks",
- "version": "11.0.0",
+ "version": "11.0.1",
"description": "Block API for WordPress.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/components/package.json b/packages/components/package.json
index 71a9e6603ae50b..c4679b1a6485fe 100644
--- a/packages/components/package.json
+++ b/packages/components/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/components",
- "version": "16.0.0-prerelease",
+ "version": "16.0.0",
"description": "UI components for WordPress.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/compose/package.json b/packages/compose/package.json
index 7f9e47021c454a..f97c1131b59c47 100644
--- a/packages/compose/package.json
+++ b/packages/compose/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/compose",
- "version": "5.0.0",
+ "version": "5.0.1",
"description": "WordPress higher-order components (HOCs).",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/core-data/package.json b/packages/core-data/package.json
index 70cabd048f0518..557aa1c182e9fd 100644
--- a/packages/core-data/package.json
+++ b/packages/core-data/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/core-data",
- "version": "4.0.0",
+ "version": "4.0.1",
"description": "Access to and manipulation of core WordPress entities.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/customize-widgets/package.json b/packages/customize-widgets/package.json
index 1be81999fee62d..ae7260f507fe35 100644
--- a/packages/customize-widgets/package.json
+++ b/packages/customize-widgets/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/customize-widgets",
- "version": "2.0.0",
+ "version": "2.0.1",
"description": "Widgets blocks in Customizer Module for WordPress.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/data-controls/package.json b/packages/data-controls/package.json
index 7407d97bfb2c04..4b132809bea526 100644
--- a/packages/data-controls/package.json
+++ b/packages/data-controls/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/data-controls",
- "version": "2.2.1",
+ "version": "2.2.2",
"description": "A set of common controls for the @wordpress/data api.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/data/package.json b/packages/data/package.json
index ddd920360f30e3..7d3fa835579db7 100644
--- a/packages/data/package.json
+++ b/packages/data/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/data",
- "version": "6.0.0",
+ "version": "6.0.1",
"description": "Data module for WordPress.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/dom/package.json b/packages/dom/package.json
index 3adff09388c9e9..918415ad3d5fe7 100644
--- a/packages/dom/package.json
+++ b/packages/dom/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/dom",
- "version": "3.2.1",
+ "version": "3.2.2",
"description": "DOM utilities module for WordPress.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/e2e-test-utils/package.json b/packages/e2e-test-utils/package.json
index 204f11b26901b9..e6ac75c7bbb069 100644
--- a/packages/e2e-test-utils/package.json
+++ b/packages/e2e-test-utils/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/e2e-test-utils",
- "version": "5.4.1",
+ "version": "5.4.2",
"description": "End-To-End (E2E) test utils for WordPress.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/e2e-tests/package.json b/packages/e2e-tests/package.json
index d7e4331cd695b6..479f2331230e76 100644
--- a/packages/e2e-tests/package.json
+++ b/packages/e2e-tests/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/e2e-tests",
- "version": "2.4.0",
+ "version": "2.4.1",
"description": "End-To-End (E2E) tests for WordPress.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/edit-post/package.json b/packages/edit-post/package.json
index b5fe7f1c5e301c..6919bb5683d1a0 100644
--- a/packages/edit-post/package.json
+++ b/packages/edit-post/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/edit-post",
- "version": "5.0.0",
+ "version": "5.0.1",
"description": "Edit Post module for WordPress.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/edit-site/package.json b/packages/edit-site/package.json
index 955d1a94dd569d..988c8fce821c88 100644
--- a/packages/edit-site/package.json
+++ b/packages/edit-site/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/edit-site",
- "version": "3.0.0",
+ "version": "3.0.1",
"description": "Edit Site Page module for WordPress.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/edit-widgets/package.json b/packages/edit-widgets/package.json
index d898501b6b21c5..4d753c74255c9c 100644
--- a/packages/edit-widgets/package.json
+++ b/packages/edit-widgets/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/edit-widgets",
- "version": "3.0.0",
+ "version": "3.0.1",
"description": "Widgets Page module for WordPress..",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/editor/package.json b/packages/editor/package.json
index 4bed95f0740bfe..069d27437c8c33 100644
--- a/packages/editor/package.json
+++ b/packages/editor/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/editor",
- "version": "11.0.0",
+ "version": "11.0.1",
"description": "Enhanced block editor for WordPress posts.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json
index 306177e4aef3a6..ed0b6d76cea633 100644
--- a/packages/eslint-plugin/package.json
+++ b/packages/eslint-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/eslint-plugin",
- "version": "9.1.1-prerelease",
+ "version": "9.1.1",
"description": "ESLint plugin for WordPress development.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/format-library/package.json b/packages/format-library/package.json
index 52fdb9028d451b..68a8b2060f5973 100644
--- a/packages/format-library/package.json
+++ b/packages/format-library/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/format-library",
- "version": "3.0.0",
+ "version": "3.0.1",
"description": "Format library for the WordPress editor.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/icons/package.json b/packages/icons/package.json
index 200d3a701139f9..463ad625b130ed 100644
--- a/packages/icons/package.json
+++ b/packages/icons/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/icons",
- "version": "5.0.0",
+ "version": "5.0.1",
"description": "WordPress Icons package, based on dashicon.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/interface/package.json b/packages/interface/package.json
index ee0e53bae44b69..7880c08042ea64 100644
--- a/packages/interface/package.json
+++ b/packages/interface/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/interface",
- "version": "4.0.0",
+ "version": "4.0.1",
"description": "Interface module for WordPress. The package contains shared functionality across the modern JavaScript-based WordPress screens.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/keyboard-shortcuts/package.json b/packages/keyboard-shortcuts/package.json
index d44c89ddf24f50..007167b069f227 100644
--- a/packages/keyboard-shortcuts/package.json
+++ b/packages/keyboard-shortcuts/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/keyboard-shortcuts",
- "version": "3.0.0",
+ "version": "3.0.1",
"description": "Handling keyboard shortcuts.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/library-export-default-webpack-plugin/package.json b/packages/library-export-default-webpack-plugin/package.json
index f9a36565fb2ae1..5f3cedd95c103d 100644
--- a/packages/library-export-default-webpack-plugin/package.json
+++ b/packages/library-export-default-webpack-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/library-export-default-webpack-plugin",
- "version": "2.2.0-prerelease",
+ "version": "2.2.0",
"description": "Webpack plugin for exporting default property for selected libraries.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/list-reusable-blocks/package.json b/packages/list-reusable-blocks/package.json
index 9d7699f1b1957d..06cb297ceda026 100644
--- a/packages/list-reusable-blocks/package.json
+++ b/packages/list-reusable-blocks/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/list-reusable-blocks",
- "version": "3.0.0",
+ "version": "3.0.1",
"description": "Adding Export/Import support to the reusable blocks listing.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/notices/package.json b/packages/notices/package.json
index 3abcea38ad2ab8..d781ee3dcf84eb 100644
--- a/packages/notices/package.json
+++ b/packages/notices/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/notices",
- "version": "3.2.1",
+ "version": "3.2.2",
"description": "State management for notices.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/nux/package.json b/packages/nux/package.json
index 28a704db1cff2d..f8297a55a3727c 100644
--- a/packages/nux/package.json
+++ b/packages/nux/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/nux",
- "version": "5.0.0",
+ "version": "5.0.1",
"description": "NUX (New User eXperience) module for WordPress.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/plugins/package.json b/packages/plugins/package.json
index cf95ff899d3ae5..3145b2539a19db 100644
--- a/packages/plugins/package.json
+++ b/packages/plugins/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/plugins",
- "version": "4.0.0",
+ "version": "4.0.1",
"description": "Plugins module for WordPress.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/readable-js-assets-webpack-plugin/package.json b/packages/readable-js-assets-webpack-plugin/package.json
index 5689f99182ed60..54cf4f78a2940b 100644
--- a/packages/readable-js-assets-webpack-plugin/package.json
+++ b/packages/readable-js-assets-webpack-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/readable-js-assets-webpack-plugin",
- "version": "1.0.1",
+ "version": "1.0.2",
"description": "Generate a readable JS file for each JS asset.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/reusable-blocks/package.json b/packages/reusable-blocks/package.json
index d259a1b808ba66..f900c6fea1d978 100644
--- a/packages/reusable-blocks/package.json
+++ b/packages/reusable-blocks/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/reusable-blocks",
- "version": "3.0.0",
+ "version": "3.0.1",
"description": "Reusable blocks utilities.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/rich-text/package.json b/packages/rich-text/package.json
index 20a2613b082283..a82b4ed4200186 100644
--- a/packages/rich-text/package.json
+++ b/packages/rich-text/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/rich-text",
- "version": "5.0.0",
+ "version": "5.0.1",
"description": "Rich text value and manipulation API.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/scripts/package.json b/packages/scripts/package.json
index 367f3424e5daa0..78c2bc8102e6bd 100644
--- a/packages/scripts/package.json
+++ b/packages/scripts/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/scripts",
- "version": "18.0.0-prerelease",
+ "version": "18.0.0",
"description": "Collection of reusable scripts for WordPress development.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/server-side-render/package.json b/packages/server-side-render/package.json
index 31f439d5eedb5c..04e667999c63b7 100644
--- a/packages/server-side-render/package.json
+++ b/packages/server-side-render/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/server-side-render",
- "version": "3.0.0",
+ "version": "3.0.1",
"description": "The component used with WordPress to server-side render a preview of dynamic blocks to display in the editor.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/viewport/package.json b/packages/viewport/package.json
index 8f051774e39c4a..7a0271bea68eb5 100644
--- a/packages/viewport/package.json
+++ b/packages/viewport/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/viewport",
- "version": "4.0.0",
+ "version": "4.0.1",
"description": "Viewport module for WordPress.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
diff --git a/packages/widgets/package.json b/packages/widgets/package.json
index ae95b3f872ad77..2934f8442b10f9 100644
--- a/packages/widgets/package.json
+++ b/packages/widgets/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/widgets",
- "version": "2.0.0",
+ "version": "2.0.1",
"description": "Functionality used by the widgets block editor in the Widgets screen and the Customizer.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
From 292d9f2f8752c0aec610113f7f893739e32021e4 Mon Sep 17 00:00:00 2001
From: Daniel Richards
Date: Mon, 23 Aug 2021 16:59:30 +0800
Subject: [PATCH 010/214] Migrate post editor feature preferences to the
interface package (#34154)
* Migrate post editor feature preferences to the interface package
* Remove snapshot for MoreMenu
* Remove tests for actions/selectors that now call through to the interface store
* Remove reducer test
---
.../data/data-core-edit-post.md | 6 +-
.../data/src/plugins/persistence/index.js | 1 +
.../components/header/feature-toggle/index.js | 61 ---------
.../src/components/header/more-menu/index.js | 21 ++-
.../test/__snapshots__/index.js.snap | 129 ------------------
.../components/header/more-menu/test/index.js | 17 ---
.../components/header/writing-menu/index.js | 15 +-
packages/edit-post/src/index.js | 13 ++
.../plugins/welcome-guide-menu-item/index.js | 19 +--
packages/edit-post/src/store/actions.js | 16 +--
packages/edit-post/src/store/defaults.js | 9 --
packages/edit-post/src/store/reducer.js | 10 --
packages/edit-post/src/store/selectors.js | 11 +-
packages/edit-post/src/store/test/actions.js | 11 --
packages/edit-post/src/store/test/reducer.js | 12 --
.../edit-post/src/store/test/selectors.js | 46 -------
16 files changed, 53 insertions(+), 344 deletions(-)
delete mode 100644 packages/edit-post/src/components/header/feature-toggle/index.js
delete mode 100644 packages/edit-post/src/components/header/more-menu/test/__snapshots__/index.js.snap
delete mode 100644 packages/edit-post/src/components/header/more-menu/test/index.js
diff --git a/docs/reference-guides/data/data-core-edit-post.md b/docs/reference-guides/data/data-core-edit-post.md
index 2348d6544020da..e8dd31780a3ad6 100644
--- a/docs/reference-guides/data/data-core-edit-post.md
+++ b/docs/reference-guides/data/data-core-edit-post.md
@@ -502,16 +502,12 @@ _Returns_
### toggleFeature
-Returns an action object used to toggle a feature flag.
+Triggers an action used to toggle a feature flag.
_Parameters_
- _feature_ `string`: Feature name.
-_Returns_
-
-- `Object`: Action object.
-
### togglePinnedPluginItem
Triggers an action object used to toggle a plugin name flag.
diff --git a/packages/data/src/plugins/persistence/index.js b/packages/data/src/plugins/persistence/index.js
index f22e135100f166..24baf115aa1dcc 100644
--- a/packages/data/src/plugins/persistence/index.js
+++ b/packages/data/src/plugins/persistence/index.js
@@ -285,6 +285,7 @@ persistencePlugin.__unstableMigrate = ( pluginOptions ) => {
persistence,
'core/customize-widgets'
);
+ migrateFeaturePreferencesToInterfaceStore( persistence, 'core/edit-post' );
};
export default persistencePlugin;
diff --git a/packages/edit-post/src/components/header/feature-toggle/index.js b/packages/edit-post/src/components/header/feature-toggle/index.js
deleted file mode 100644
index 13f72ae8d75a4e..00000000000000
--- a/packages/edit-post/src/components/header/feature-toggle/index.js
+++ /dev/null
@@ -1,61 +0,0 @@
-/**
- * External dependencies
- */
-import { flow } from 'lodash';
-
-/**
- * WordPress dependencies
- */
-import { withSelect, withDispatch } from '@wordpress/data';
-import { compose } from '@wordpress/compose';
-import { MenuItem } from '@wordpress/components';
-import { __ } from '@wordpress/i18n';
-import { check } from '@wordpress/icons';
-import { speak } from '@wordpress/a11y';
-
-/**
- * Internal dependencies
- */
-import { store as editPostStore } from '../../../store';
-
-function FeatureToggle( {
- onToggle,
- isActive,
- label,
- info,
- messageActivated,
- messageDeactivated,
- shortcut,
-} ) {
- const speakMessage = () => {
- if ( isActive ) {
- speak( messageDeactivated || __( 'Feature deactivated' ) );
- } else {
- speak( messageActivated || __( 'Feature activated' ) );
- }
- };
-
- return (
-
- { label }
-
- );
-}
-
-export default compose( [
- withSelect( ( select, { feature } ) => ( {
- isActive: select( editPostStore ).isFeatureActive( feature ),
- } ) ),
- withDispatch( ( dispatch, ownProps ) => ( {
- onToggle() {
- dispatch( editPostStore ).toggleFeature( ownProps.feature );
- },
- } ) ),
-] )( FeatureToggle );
diff --git a/packages/edit-post/src/components/header/more-menu/index.js b/packages/edit-post/src/components/header/more-menu/index.js
index 17b763b26f3749..ed06ba47259996 100644
--- a/packages/edit-post/src/components/header/more-menu/index.js
+++ b/packages/edit-post/src/components/header/more-menu/index.js
@@ -2,9 +2,12 @@
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
-import { DropdownMenu, MenuGroup } from '@wordpress/components';
-import { moreVertical } from '@wordpress/icons';
-import { ActionItem, PinnedItems } from '@wordpress/interface';
+import { MenuGroup } from '@wordpress/components';
+import {
+ ActionItem,
+ MoreMenuDropdown,
+ PinnedItems,
+} from '@wordpress/interface';
import { useViewportMatch } from '@wordpress/compose';
/**
@@ -17,26 +20,18 @@ import WritingMenu from '../writing-menu';
const POPOVER_PROPS = {
className: 'edit-post-more-menu__content',
- position: 'bottom left',
-};
-const TOGGLE_PROPS = {
- tooltipPosition: 'bottom',
};
const MoreMenu = ( { showIconLabels } ) => {
const isLargeViewport = useViewportMatch( 'large' );
return (
-
{ ( { onClose } ) => (
@@ -61,7 +56,7 @@ const MoreMenu = ( { showIconLabels } ) => {
>
) }
-
+
);
};
diff --git a/packages/edit-post/src/components/header/more-menu/test/__snapshots__/index.js.snap b/packages/edit-post/src/components/header/more-menu/test/__snapshots__/index.js.snap
deleted file mode 100644
index 9ffdb5a699ff04..00000000000000
--- a/packages/edit-post/src/components/header/more-menu/test/__snapshots__/index.js.snap
+++ /dev/null
@@ -1,129 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`MoreMenu should match snapshot 1`] = `
-
-
-
-
- }
- label="Options"
- popoverProps={
- Object {
- "className": "edit-post-more-menu__content",
- "position": "bottom left",
- }
- }
- toggleProps={
- Object {
- "showTooltip": true,
- "tooltipPosition": "bottom",
- }
- }
- >
-
-
-
-
-
- }
- label="Options"
- onClick={[Function]}
- onKeyDown={[Function]}
- showTooltip={true}
- tooltipPosition="bottom"
- >
-
-
-
-
-
- }
- key="0,0"
- >
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-`;
diff --git a/packages/edit-post/src/components/header/more-menu/test/index.js b/packages/edit-post/src/components/header/more-menu/test/index.js
deleted file mode 100644
index 2da96abe04ea4e..00000000000000
--- a/packages/edit-post/src/components/header/more-menu/test/index.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * External dependencies
- */
-import { mount } from 'enzyme';
-
-/**
- * Internal dependencies
- */
-import MoreMenu from '../index';
-
-describe( 'MoreMenu', () => {
- it( 'should match snapshot', () => {
- const wrapper = mount( );
-
- expect( wrapper ).toMatchSnapshot();
- } );
-} );
diff --git a/packages/edit-post/src/components/header/writing-menu/index.js b/packages/edit-post/src/components/header/writing-menu/index.js
index 71d3ddb339d20b..bcd4edad123ce2 100644
--- a/packages/edit-post/src/components/header/writing-menu/index.js
+++ b/packages/edit-post/src/components/header/writing-menu/index.js
@@ -5,11 +5,7 @@ import { MenuGroup } from '@wordpress/components';
import { __, _x } from '@wordpress/i18n';
import { useViewportMatch } from '@wordpress/compose';
import { displayShortcut } from '@wordpress/keycodes';
-
-/**
- * Internal dependencies
- */
-import FeatureToggle from '../feature-toggle';
+import { MoreMenuFeatureToggle } from '@wordpress/interface';
function WritingMenu() {
const isLargeViewport = useViewportMatch( 'medium' );
@@ -19,7 +15,8 @@ function WritingMenu() {
return (
-
-
- select( editPostStore ).isEditingTemplate(),
[]
);
- const { toggleFeature } = useDispatch( editPostStore );
return (
-
- toggleFeature(
- isTemplateMode ? 'welcomeGuideTemplate' : 'welcomeGuide'
- )
- }
- >
- { __( 'Welcome Guide' ) }
-
+
);
}
diff --git a/packages/edit-post/src/store/actions.js b/packages/edit-post/src/store/actions.js
index 6cd238b06bdfde..d253d55e74efd7 100644
--- a/packages/edit-post/src/store/actions.js
+++ b/packages/edit-post/src/store/actions.js
@@ -153,17 +153,17 @@ export function removeEditorPanel( panelName ) {
}
/**
- * Returns an action object used to toggle a feature flag.
+ * Triggers an action used to toggle a feature flag.
*
* @param {string} feature Feature name.
- *
- * @return {Object} Action object.
*/
-export function toggleFeature( feature ) {
- return {
- type: 'TOGGLE_FEATURE',
- feature,
- };
+export function* toggleFeature( feature ) {
+ yield controls.dispatch(
+ interfaceStore.name,
+ 'toggleFeature',
+ 'core/edit-post',
+ feature
+ );
}
export function* switchEditorMode( mode ) {
diff --git a/packages/edit-post/src/store/defaults.js b/packages/edit-post/src/store/defaults.js
index 05cb4c8e1957a3..9bd5f366a02f9a 100644
--- a/packages/edit-post/src/store/defaults.js
+++ b/packages/edit-post/src/store/defaults.js
@@ -5,15 +5,6 @@ export const PREFERENCES_DEFAULTS = {
opened: true,
},
},
- features: {
- fixedToolbar: false,
- welcomeGuide: true,
- fullscreenMode: true,
- showIconLabels: false,
- themeStyles: true,
- showBlockBreadcrumbs: true,
- welcomeGuideTemplate: true,
- },
hiddenBlockTypes: [],
preferredStyleVariations: {},
localAutosaveInterval: 15,
diff --git a/packages/edit-post/src/store/reducer.js b/packages/edit-post/src/store/reducer.js
index 2f9f0ec544bf0e..3441c613f5f619 100644
--- a/packages/edit-post/src/store/reducer.js
+++ b/packages/edit-post/src/store/reducer.js
@@ -78,16 +78,6 @@ export const preferences = flow( [
return state;
},
- features( state, action ) {
- if ( action.type === 'TOGGLE_FEATURE' ) {
- return {
- ...state,
- [ action.feature ]: ! state[ action.feature ],
- };
- }
-
- return state;
- },
editorMode( state, action ) {
if ( action.type === 'SWITCH_MODE' ) {
return action.mode;
diff --git a/packages/edit-post/src/store/selectors.js b/packages/edit-post/src/store/selectors.js
index e8a8bddccbc168..2d40810a3cf569 100644
--- a/packages/edit-post/src/store/selectors.js
+++ b/packages/edit-post/src/store/selectors.js
@@ -189,9 +189,14 @@ export function isModalActive( state, modalName ) {
*
* @return {boolean} Is active.
*/
-export function isFeatureActive( state, feature ) {
- return get( state.preferences.features, [ feature ], false );
-}
+export const isFeatureActive = createRegistrySelector(
+ ( select ) => ( state, feature ) => {
+ return select( interfaceStore ).isFeatureActive(
+ 'core/edit-post',
+ feature
+ );
+ }
+);
/**
* Returns true if the plugin item is pinned to the header.
diff --git a/packages/edit-post/src/store/test/actions.js b/packages/edit-post/src/store/test/actions.js
index 9525fbd1ce8800..06739597fd9349 100644
--- a/packages/edit-post/src/store/test/actions.js
+++ b/packages/edit-post/src/store/test/actions.js
@@ -15,7 +15,6 @@ import {
togglePublishSidebar,
openModal,
closeModal,
- toggleFeature,
requestMetaBoxUpdates,
setIsListViewOpened,
} from '../actions';
@@ -90,16 +89,6 @@ describe( 'actions', () => {
} );
} );
- describe( 'toggleFeature', () => {
- it( 'should return TOGGLE_FEATURE action', () => {
- const feature = 'name';
- expect( toggleFeature( feature ) ).toEqual( {
- type: 'TOGGLE_FEATURE',
- feature,
- } );
- } );
- } );
-
describe( 'requestMetaBoxUpdates', () => {
it( 'should yield the REQUEST_META_BOX_UPDATES action', () => {
const fulfillment = requestMetaBoxUpdates();
diff --git a/packages/edit-post/src/store/test/reducer.js b/packages/edit-post/src/store/test/reducer.js
index 9ad1574f8de35a..67b097e27a8dd0 100644
--- a/packages/edit-post/src/store/test/reducer.js
+++ b/packages/edit-post/src/store/test/reducer.js
@@ -152,18 +152,6 @@ describe( 'state', () => {
expect( state.editorMode ).toBe( 'text' );
} );
- it( 'should toggle a feature flag', () => {
- const state = preferences(
- deepFreeze( { features: { chicken: true } } ),
- {
- type: 'TOGGLE_FEATURE',
- feature: 'chicken',
- }
- );
-
- expect( state.features ).toEqual( { chicken: false } );
- } );
-
describe( 'hiddenBlockTypes', () => {
it( 'concatenates unique names on disable', () => {
const original = deepFreeze( {
diff --git a/packages/edit-post/src/store/test/selectors.js b/packages/edit-post/src/store/test/selectors.js
index 7ec6bf55546ba9..d9828eaa87e5a9 100644
--- a/packages/edit-post/src/store/test/selectors.js
+++ b/packages/edit-post/src/store/test/selectors.js
@@ -11,7 +11,6 @@ import {
getPreference,
isEditorPanelOpened,
isModalActive,
- isFeatureActive,
hasMetaBoxes,
isSavingMetaBoxes,
getActiveMetaBoxLocations,
@@ -239,51 +238,6 @@ describe( 'selectors', () => {
} );
} );
- describe( 'isFeatureActive', () => {
- it( 'is tolerant to an undefined features preference', () => {
- // See: https://github.com/WordPress/gutenberg/issues/14580
- const state = {
- preferences: {},
- };
-
- expect( isFeatureActive( state, 'chicken' ) ).toBe( false );
- } );
-
- it( 'should return true if feature is active', () => {
- const state = {
- preferences: {
- features: {
- chicken: true,
- },
- },
- };
-
- expect( isFeatureActive( state, 'chicken' ) ).toBe( true );
- } );
-
- it( 'should return false if feature is not active', () => {
- const state = {
- preferences: {
- features: {
- chicken: false,
- },
- },
- };
-
- expect( isFeatureActive( state, 'chicken' ) ).toBe( false );
- } );
-
- it( 'should return false if feature is not referred', () => {
- const state = {
- preferences: {
- features: {},
- },
- };
-
- expect( isFeatureActive( state, 'chicken' ) ).toBe( false );
- } );
- } );
-
describe( 'hasMetaBoxes', () => {
it( 'should return true if there are active meta boxes', () => {
const state = {
From 13efc3aadc8c7a694f81bb4576147d7978058b2c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andr=C3=A9?=
Date: Mon, 23 Aug 2021 13:43:33 +0200
Subject: [PATCH 011/214] Documentation: fix typo in block gap docs (#34231)
---
docs/how-to-guides/themes/theme-json.md | 1 -
1 file changed, 1 deletion(-)
diff --git a/docs/how-to-guides/themes/theme-json.md b/docs/how-to-guides/themes/theme-json.md
index 460a43ba9161e2..b4151d83071f18 100644
--- a/docs/how-to-guides/themes/theme-json.md
+++ b/docs/how-to-guides/themes/theme-json.md
@@ -615,7 +615,6 @@ Each block declares which style properties it exposes via the [block supports me
"text": "value"
},
"spacing": {
- "blockGap": "value",
"margin": {
"top": "value",
"right": "value",
From 9e3be448664646245c875baa01539a7bd96ee99a Mon Sep 17 00:00:00 2001
From: Daniel Walmsley
Date: Mon, 23 Aug 2021 04:53:39 -0700
Subject: [PATCH 012/214] Remove deprecated import style for
storybook/addon-docs (#34095)
---
storybook/stories/docs/introduction.story.mdx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/storybook/stories/docs/introduction.story.mdx b/storybook/stories/docs/introduction.story.mdx
index bf4756bac9a12e..55fb09f0a9f850 100644
--- a/storybook/stories/docs/introduction.story.mdx
+++ b/storybook/stories/docs/introduction.story.mdx
@@ -1,4 +1,4 @@
-import { Meta } from '@storybook/addon-docs/blocks';
+import { Meta } from '@storybook/addon-docs';
From 19e5da6c5d169699b445a65e29dd3e1d71c948bd Mon Sep 17 00:00:00 2001
From: Addison Stavlo
Date: Mon, 23 Aug 2021 10:09:24 -0400
Subject: [PATCH 013/214] simple fix (#34203)
---
.../navigation-panel/content-navigation-item.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/edit-site/src/components/navigation-sidebar/navigation-panel/content-navigation-item.js b/packages/edit-site/src/components/navigation-sidebar/navigation-panel/content-navigation-item.js
index e33a4fba22ed50..43f460f26e367e 100644
--- a/packages/edit-site/src/components/navigation-sidebar/navigation-panel/content-navigation-item.js
+++ b/packages/edit-site/src/components/navigation-sidebar/navigation-panel/content-navigation-item.js
@@ -36,7 +36,7 @@ export default function ContentNavigationItem( { item } ) {
const template = select(
coreStore
).__experimentalGetTemplateForLink( item.link );
- return template?.content?.raw;
+ return template?.content;
},
[ isPreviewVisible ]
);
From 208eda8d71837a5792086519467e30e7907aa878 Mon Sep 17 00:00:00 2001
From: Joen A <1204802+jasmussen@users.noreply.github.com>
Date: Mon, 23 Aug 2021 18:17:13 +0200
Subject: [PATCH 014/214] Fix vertical page list. (#34226)
---
packages/block-library/src/navigation/style.scss | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/packages/block-library/src/navigation/style.scss b/packages/block-library/src/navigation/style.scss
index 2d3671c847a6c8..cf5a543e3e586b 100644
--- a/packages/block-library/src/navigation/style.scss
+++ b/packages/block-library/src/navigation/style.scss
@@ -338,13 +338,14 @@
// Horizontal layout
display: flex;
flex-wrap: wrap;
+}
- // Vertical layout
- .is-vertical & {
- display: block;
- flex-direction: column;
- align-items: flex-start;
- }
+// Vertical layout
+.is-vertical .wp-block-page-list, // Page list.
+.is-vertical .wp-block-navigation__container {
+ display: block;
+ flex-direction: column;
+ align-items: flex-start;
}
// Justification.
From 518e3c80966be2e8ba8cf085d6ec824b39934fb4 Mon Sep 17 00:00:00 2001
From: Joen A <1204802+jasmussen@users.noreply.github.com>
Date: Mon, 23 Aug 2021 18:25:36 +0200
Subject: [PATCH 015/214] Try: Fix navigation responsive menu overlay z index.
(#34228)
---
packages/block-library/src/navigation/style.scss | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/block-library/src/navigation/style.scss b/packages/block-library/src/navigation/style.scss
index cf5a543e3e586b..bdc8183a235ea3 100644
--- a/packages/block-library/src/navigation/style.scss
+++ b/packages/block-library/src/navigation/style.scss
@@ -442,6 +442,7 @@
display: flex;
flex-direction: row;
position: relative;
+ z-index: 2;
background-color: inherit;
.wp-block-navigation__responsive-container-close {
From c238f4324354a4a87293fe83ff1268ce7889e1c2 Mon Sep 17 00:00:00 2001
From: Jason Johnston
Date: Mon, 23 Aug 2021 13:02:59 -0400
Subject: [PATCH 016/214] [RNMobile] Use Flexbox for Inserter Menu tabs on
mobile (#34126)
* Use flexbox for tab positioning
* Make sure height is calculated correctly
Co-authored-by: jhnstn
---
.../block-editor/src/components/inserter/menu.native.js | 5 ++++-
.../src/components/inserter/style.native.scss | 7 +++----
.../block-editor/src/components/inserter/tabs.native.js | 8 +-------
3 files changed, 8 insertions(+), 12 deletions(-)
diff --git a/packages/block-editor/src/components/inserter/menu.native.js b/packages/block-editor/src/components/inserter/menu.native.js
index 198bb761329e38..5f556714456129 100644
--- a/packages/block-editor/src/components/inserter/menu.native.js
+++ b/packages/block-editor/src/components/inserter/menu.native.js
@@ -204,7 +204,10 @@ function InserterMenu( {
>
{ ( { listProps } ) => (
-
+
{ ! showTabs || filterValue ? (
{ tabs.map( ( { component: TabComponent }, index ) => (
-
+
Date: Mon, 23 Aug 2021 10:21:03 -0700
Subject: [PATCH 017/214] Rnmobile/add/typography controls (#33605)
* Allow for a non units to show without the unit picker.
* Add Line Height Controls
* Make variable more clear
* Revert Typography web
* Add support for font sizes
* Add bottom Cell sheet subLabel
* Update the colour of the subheading
* Update colours again for subheading
* Make the Typography UI only available in dev build
* Do not show items that we can't parse as numbers
* Add comment
* Move the FontSizePicker export
* Remove the not needed platform check
* Update comment to be more font size specific.
* Fix unit test for customLineHeight
* Revert the units logic to hide the Unit picker
* Remove the added borderRightWidth for picker that doesn't have childern
---
packages/base-styles/_colors.native.scss | 3 +
.../src/components/font-sizes/index.native.js | 8 +-
.../line-height-control/index.native.js | 25 +++
packages/block-editor/src/hooks/typography.js | 8 +-
.../src/hooks/typography.native.js | 64 +++++++
.../src/font-size-picker/index.native.js | 173 ++++++++++++++++++
.../src/font-size-picker/style.native.scss | 6 +
packages/components/src/index.native.js | 1 +
.../src/mobile/bottom-sheet/cell.native.js | 23 ++-
.../bottom-sheet/range-text-input.native.js | 1 +
.../mobile/bottom-sheet/styles.native.scss | 9 +
.../test/utils.native.js | 4 +-
.../global-styles-context/utils.native.js | 4 +-
.../src/unit-control/index.native.js | 4 +
14 files changed, 319 insertions(+), 14 deletions(-)
create mode 100644 packages/block-editor/src/components/line-height-control/index.native.js
create mode 100644 packages/block-editor/src/hooks/typography.native.js
create mode 100644 packages/components/src/font-size-picker/index.native.js
create mode 100644 packages/components/src/font-size-picker/style.native.scss
diff --git a/packages/base-styles/_colors.native.scss b/packages/base-styles/_colors.native.scss
index a34e5012eecf9c..ba76d005b622a3 100644
--- a/packages/base-styles/_colors.native.scss
+++ b/packages/base-styles/_colors.native.scss
@@ -53,6 +53,7 @@ $gray-text-min: darken($gray, 18%); //#537994
$gray-lighten-10: lighten($gray, 10%); // #a8bece
$gray-lighten-20: lighten($gray, 20%); // #c8d7e1
$gray-lighten-30: lighten($gray, 30%); // #e9eff3
+$gray-darken-10: darken($gray, 10%);
$gray-darken-20: darken($gray, 20%); // #4f748e
$gray-darken-30: darken($gray, 30%); // #3d596d
@@ -102,6 +103,8 @@ $app-background-dark-alt: $background-dark-elevated;
$modal-background: $white;
$modal-background-dark: $background-dark-elevated;
+$sub-heading: $gray-text-min;
+$sub-heading-dark: $white;
/**
* Deprecated colors.
* Please avoid using these.
diff --git a/packages/block-editor/src/components/font-sizes/index.native.js b/packages/block-editor/src/components/font-sizes/index.native.js
index 2ebb67cf494ba1..55ef51a02aa4d5 100644
--- a/packages/block-editor/src/components/font-sizes/index.native.js
+++ b/packages/block-editor/src/components/font-sizes/index.native.js
@@ -1 +1,7 @@
-export { getFontSize, getFontSizeClass } from './utils';
+export {
+ getFontSize,
+ getFontSizeClass,
+ getFontSizeObjectByValue,
+} from './utils';
+export { default as FontSizePicker } from './font-size-picker';
+export { default as withFontSizes } from './with-font-sizes';
diff --git a/packages/block-editor/src/components/line-height-control/index.native.js b/packages/block-editor/src/components/line-height-control/index.native.js
new file mode 100644
index 00000000000000..95645805592cf1
--- /dev/null
+++ b/packages/block-editor/src/components/line-height-control/index.native.js
@@ -0,0 +1,25 @@
+/**
+ * WordPress dependencies
+ */
+import { __ } from '@wordpress/i18n';
+import { UnitControl } from '@wordpress/components';
+/**
+ * Internal dependencies
+ */
+import { BASE_DEFAULT_VALUE, STEP, isLineHeightDefined } from './utils';
+
+export default function LineHeightControl( { value: lineHeight, onChange } ) {
+ const isDefined = isLineHeightDefined( lineHeight );
+ const value = isDefined ? lineHeight : BASE_DEFAULT_VALUE;
+ return (
+
+ );
+}
diff --git a/packages/block-editor/src/hooks/typography.js b/packages/block-editor/src/hooks/typography.js
index 1b961990acaaae..5bd009bb78dc3c 100644
--- a/packages/block-editor/src/hooks/typography.js
+++ b/packages/block-editor/src/hooks/typography.js
@@ -6,7 +6,6 @@ import { hasBlockSupport } from '@wordpress/blocks';
* External dependencies
*/
import { PanelBody } from '@wordpress/components';
-import { Platform } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
/**
@@ -83,11 +82,8 @@ export function TypographyPanel( props ) {
}
const hasTypographySupport = ( blockName ) => {
- return (
- Platform.OS === 'web' &&
- TYPOGRAPHY_SUPPORT_KEYS.some( ( key ) =>
- hasBlockSupport( blockName, key )
- )
+ return TYPOGRAPHY_SUPPORT_KEYS.some( ( key ) =>
+ hasBlockSupport( blockName, key )
);
};
diff --git a/packages/block-editor/src/hooks/typography.native.js b/packages/block-editor/src/hooks/typography.native.js
new file mode 100644
index 00000000000000..396d48439f3a36
--- /dev/null
+++ b/packages/block-editor/src/hooks/typography.native.js
@@ -0,0 +1,64 @@
+/**
+ * WordPress dependencies
+ */
+import { hasBlockSupport } from '@wordpress/blocks';
+/**
+ * External dependencies
+ */
+import { PanelBody } from '@wordpress/components';
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies
+ */
+import InspectorControls from '../components/inspector-controls';
+
+import {
+ LINE_HEIGHT_SUPPORT_KEY,
+ LineHeightEdit,
+ useIsLineHeightDisabled,
+} from './line-height';
+import {
+ FONT_SIZE_SUPPORT_KEY,
+ FontSizeEdit,
+ useIsFontSizeDisabled,
+} from './font-size';
+
+export const TYPOGRAPHY_SUPPORT_KEY = 'typography';
+export const TYPOGRAPHY_SUPPORT_KEYS = [
+ LINE_HEIGHT_SUPPORT_KEY,
+ FONT_SIZE_SUPPORT_KEY,
+];
+
+export function TypographyPanel( props ) {
+ const isDisabled = useIsTypographyDisabled( props );
+ const isSupported = hasTypographySupport( props.name );
+
+ // only enable TypographyPanel for development
+ // eslint-disable-next-line no-undef
+ if ( isDisabled || ! isSupported || ! __DEV__ ) return null;
+
+ return (
+
+
+
+
+
+
+ );
+}
+
+const hasTypographySupport = ( blockName ) => {
+ return TYPOGRAPHY_SUPPORT_KEYS.some( ( key ) =>
+ hasBlockSupport( blockName, key )
+ );
+};
+
+function useIsTypographyDisabled( props = {} ) {
+ const configs = [
+ useIsFontSizeDisabled( props ),
+ useIsLineHeightDisabled( props ),
+ ];
+
+ return configs.filter( Boolean ).length === configs.length;
+}
diff --git a/packages/components/src/font-size-picker/index.native.js b/packages/components/src/font-size-picker/index.native.js
new file mode 100644
index 00000000000000..2be833c450a82a
--- /dev/null
+++ b/packages/components/src/font-size-picker/index.native.js
@@ -0,0 +1,173 @@
+/**
+ * External dependencies
+ */
+import { View } from 'react-native';
+
+/**
+ * WordPress dependencies
+ */
+import { useNavigation } from '@react-navigation/native';
+import { useState } from '@wordpress/element';
+import { Icon, chevronRight, check } from '@wordpress/icons';
+import { __, sprintf } from '@wordpress/i18n';
+import { BottomSheet } from '@wordpress/components';
+
+/**
+ * Internal dependencies
+ */
+import { default as UnitControl, useCustomUnits } from '../unit-control';
+import styles from './style.scss';
+
+function FontSizePicker( {
+ fontSizes = [],
+ disableCustomFontSizes = false,
+ onChange,
+ value: selectedValue,
+} ) {
+ const [ showSubSheet, setShowSubSheet ] = useState( false );
+ const navigation = useNavigation();
+
+ const onChangeValue = ( value ) => {
+ return () => {
+ goBack();
+ onChange( value );
+ };
+ };
+
+ const selectedOption = fontSizes.find(
+ ( option ) => option.size === selectedValue
+ ) ?? { name: 'Custom' };
+
+ const goBack = () => {
+ setShowSubSheet( false );
+ navigation.goBack();
+ };
+
+ const openSubSheet = () => {
+ navigation.navigate( BottomSheet.SubSheet.screenName );
+ setShowSubSheet( true );
+ };
+ const label = __( 'Font Size' );
+
+ const units = useCustomUnits( {
+ availableUnits: [ 'px', 'em', 'rem' ],
+ } );
+
+ return (
+
+
+
+ }
+ showSheet={ showSubSheet }
+ >
+ <>
+
+
+
+
+ { selectedValue === undefined && (
+
+ ) }
+
+
+ { fontSizes.map( ( item, index ) => {
+ // Only display a choice that we can currenly select.
+ if ( ! parseFloat( item.size ) ) {
+ return null;
+ }
+ return (
+
+
+ { item.size === selectedValue && (
+
+ ) }
+
+
+ );
+ } ) }
+ { ! disableCustomFontSizes && (
+ {
+ if (
+ 0 === parseFloat( nextSize ) ||
+ ! nextSize
+ ) {
+ onChange( undefined );
+ } else {
+ onChange( nextSize );
+ }
+ } }
+ units={ units }
+ />
+ ) }
+
+ >
+
+ );
+}
+
+export default FontSizePicker;
diff --git a/packages/components/src/font-size-picker/style.native.scss b/packages/components/src/font-size-picker/style.native.scss
new file mode 100644
index 00000000000000..746e62b5bb3614
--- /dev/null
+++ b/packages/components/src/font-size-picker/style.native.scss
@@ -0,0 +1,6 @@
+.components-font-size-picker {
+ padding: 0 $block-edge-to-content;
+}
+.components-font-size-picker__font-size {
+ font-size: 11px;
+}
diff --git a/packages/components/src/index.native.js b/packages/components/src/index.native.js
index e8aef964cc1a6b..626c3f03da0bae 100644
--- a/packages/components/src/index.native.js
+++ b/packages/components/src/index.native.js
@@ -30,6 +30,7 @@ export {
Fill,
Provider as SlotFillProvider,
} from './slot-fill';
+export { default as FontSizePicker } from './font-size-picker'; // Intentionally called after slot-fill.
export { default as __experimentalStyleProvider } from './style-provider';
export { default as BaseControl } from './base-control';
export { default as TextareaControl } from './textarea-control';
diff --git a/packages/components/src/mobile/bottom-sheet/cell.native.js b/packages/components/src/mobile/bottom-sheet/cell.native.js
index ee5b7d0ace4c45..136e4daef1b220 100644
--- a/packages/components/src/mobile/bottom-sheet/cell.native.js
+++ b/packages/components/src/mobile/bottom-sheet/cell.native.js
@@ -101,6 +101,7 @@ class BottomSheetCell extends Component {
onPress,
onLongPress,
label,
+ subLabel,
value,
valuePlaceholder = '',
icon,
@@ -147,6 +148,11 @@ class BottomSheetCell extends Component {
? cellLabelStyle
: defaultMissingIconAndValue;
+ const defaultSubLabelStyleText = getStylesFromColorScheme(
+ styles.cellSubLabelText,
+ styles.cellSubLabelTextDark
+ );
+
const drawSeparator =
( separatorType && separatorType !== 'none' ) ||
separatorStyle === undefined;
@@ -366,7 +372,22 @@ class BottomSheetCell extends Component {
/>
) }
- { label && (
+ { subLabel && label && (
+
+
+ { label }
+
+
+ { subLabel }
+
+
+ ) }
+ { ! subLabel && label && (
diff --git a/packages/components/src/mobile/bottom-sheet/range-text-input.native.js b/packages/components/src/mobile/bottom-sheet/range-text-input.native.js
index 47885260653de8..91556f3cb834e4 100644
--- a/packages/components/src/mobile/bottom-sheet/range-text-input.native.js
+++ b/packages/components/src/mobile/bottom-sheet/range-text-input.native.js
@@ -194,6 +194,7 @@ class RangeTextInput extends Component {
} ),
{
width: 50 * fontScale,
+ borderRightWidth: children ? 1 : 0,
},
];
diff --git a/packages/components/src/mobile/bottom-sheet/styles.native.scss b/packages/components/src/mobile/bottom-sheet/styles.native.scss
index 7d60489fa4eac9..39ae11c027100f 100644
--- a/packages/components/src/mobile/bottom-sheet/styles.native.scss
+++ b/packages/components/src/mobile/bottom-sheet/styles.native.scss
@@ -304,3 +304,12 @@
.cellHelpLabelIOS {
padding-bottom: $grid-unit-10;
}
+
+.cellSubLabelText {
+ font-size: 12px;
+ color: $sub-heading;
+}
+
+.cellSubLabelTextDark {
+ color: $sub-heading-dark;
+}
diff --git a/packages/components/src/mobile/global-styles-context/test/utils.native.js b/packages/components/src/mobile/global-styles-context/test/utils.native.js
index 7b95e8a41a0c56..6a7f219118777a 100644
--- a/packages/components/src/mobile/global-styles-context/test/utils.native.js
+++ b/packages/components/src/mobile/global-styles-context/test/utils.native.js
@@ -134,9 +134,7 @@ describe( 'getGlobalStyles', () => {
},
typography: {
fontSizes: RAW_FEATURES.typography.fontSizes,
- custom: {
- 'line-height': RAW_FEATURES.custom[ 'line-height' ],
- },
+ customLineHeight: RAW_FEATURES.custom[ 'line-height' ],
},
},
__experimentalGlobalStylesBaseStyles: PARSED_GLOBAL_STYLES,
diff --git a/packages/components/src/mobile/global-styles-context/utils.native.js b/packages/components/src/mobile/global-styles-context/utils.native.js
index 5838d3aa7d555a..97aee36a6f36b1 100644
--- a/packages/components/src/mobile/global-styles-context/utils.native.js
+++ b/packages/components/src/mobile/global-styles-context/utils.native.js
@@ -206,9 +206,7 @@ export function getGlobalStyles( rawStyles, rawFeatures ) {
},
typography: {
fontSizes: features?.typography?.fontSizes,
- custom: {
- 'line-height': features?.custom?.[ 'line-height' ],
- },
+ customLineHeight: features?.custom?.[ 'line-height' ],
},
},
__experimentalGlobalStylesBaseStyles: globalStyles,
diff --git a/packages/components/src/unit-control/index.native.js b/packages/components/src/unit-control/index.native.js
index 9be10e31845b5e..b45f1c84e06792 100644
--- a/packages/components/src/unit-control/index.native.js
+++ b/packages/components/src/unit-control/index.native.js
@@ -94,6 +94,7 @@ function UnitControl( {
accessibilityHint,
unitButtonTextStyle,
unit,
+ units,
] );
const getAnchor = useCallback(
@@ -115,6 +116,9 @@ function UnitControl( {
};
const renderUnitPicker = useCallback( () => {
+ if ( units === false ) {
+ return null;
+ }
return (
{ renderUnitButton }
From fd0a2aad79785cabeac3b6542859ae356556d164 Mon Sep 17 00:00:00 2001
From: Matthew Kevins
Date: Tue, 24 Aug 2021 11:45:18 +1000
Subject: [PATCH 018/214] Bump mobile version in experiments page for gallery
(#34220)
This bumps the mobile app version in the note about backward
compatibility in the experiments page for the gallery with image blocks
flag.
---
lib/experiments-page.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/experiments-page.php b/lib/experiments-page.php
index 224f058edaddfe..ef9f17dea1057c 100644
--- a/lib/experiments-page.php
+++ b/lib/experiments-page.php
@@ -58,7 +58,7 @@ function gutenberg_initialize_experiments_settings() {
'gutenberg-experiments',
'gutenberg_experiments_section',
array(
- 'label' => __( 'Test a new gallery block that uses nested image blocks (Warning: The new gallery is not compatible with WordPress mobile apps prior to version 18.1. If you use the mobile app, please update to the latest version to avoid content loss.)', 'gutenberg' ),
+ 'label' => __( 'Test a new gallery block that uses nested image blocks (Warning: The new gallery is not compatible with WordPress mobile apps prior to version 18.2. If you use the mobile app, please update to the latest version to avoid content loss.)', 'gutenberg' ),
'id' => 'gutenberg-gallery-refactor',
)
);
From 2b437fef3dd67863fdaf7af0e59b08e9fc678c15 Mon Sep 17 00:00:00 2001
From: Aaron Robertshaw <60436221+aaronrobertshaw@users.noreply.github.com>
Date: Tue, 24 Aug 2021 12:44:50 +1000
Subject: [PATCH 019/214] Allow zero values for theme.json styles (#34251)
---
lib/class-wp-theme-json-gutenberg.php | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php
index 1b96923323b46b..cf713529b4f70d 100644
--- a/lib/class-wp-theme-json-gutenberg.php
+++ b/lib/class-wp-theme-json-gutenberg.php
@@ -548,8 +548,9 @@ private static function compute_style_properties( $styles ) {
foreach ( self::PROPERTIES_METADATA as $css_property => $value_path ) {
$value = self::get_property_value( $styles, $value_path );
- // Skip if empty or value represents array of longhand values.
- if ( empty( $value ) || is_array( $value ) ) {
+ // Skip if empty and not "0" or value represents array of longhand values.
+ $has_missing_value = empty( $value ) && ! is_numeric( $value );
+ if ( $has_missing_value || is_array( $value ) ) {
continue;
}
From 1971a3c205b56879683c2a9e426c4c3cdba805ac Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Greg=20Zi=C3=B3=C5=82kowski?=
Date: Tue, 24 Aug 2021 10:10:08 +0200
Subject: [PATCH 020/214] Block Editor: Absorb parent block toolbar controls
(#33955)
* Block Editor: Try to absorb parent block toolbar controls
* Try a new block controls group - parent
* Expose conditionally general duotone and align block controls
* Use __experimentalExposeControlsToChildren in block supports
---
.../src/components/block-controls/fill.js | 8 ++--
.../src/components/block-controls/groups.js | 2 +
.../src/components/block-controls/hook.js | 44 +++++++++++++++++++
.../src/components/block-toolbar/index.js | 4 ++
.../src/components/inner-blocks/index.js | 40 ++++++++++++-----
.../use-display-block-controls/index.js | 17 +++----
packages/block-editor/src/hooks/align.js | 26 ++++++-----
packages/block-editor/src/hooks/duotone.js | 2 +-
packages/block-library/src/buttons/block.json | 3 +-
packages/block-library/src/buttons/edit.js | 2 +-
.../block-library/src/social-links/block.json | 3 +-
.../block-library/src/social-links/edit.js | 2 +-
12 files changed, 110 insertions(+), 43 deletions(-)
create mode 100644 packages/block-editor/src/components/block-controls/hook.js
diff --git a/packages/block-editor/src/components/block-controls/fill.js b/packages/block-editor/src/components/block-controls/fill.js
index 2392c3d07ee3ae..10b94728306863 100644
--- a/packages/block-editor/src/components/block-controls/fill.js
+++ b/packages/block-editor/src/components/block-controls/fill.js
@@ -15,18 +15,18 @@ import {
/**
* Internal dependencies
*/
-import useDisplayBlockControls from '../use-display-block-controls';
-import groups from './groups';
+import useBlockControlsFill from './hook';
export default function BlockControlsFill( {
group = 'default',
controls,
children,
+ __experimentalExposeToChildren = false,
} ) {
- if ( ! useDisplayBlockControls() ) {
+ const Fill = useBlockControlsFill( group, __experimentalExposeToChildren );
+ if ( ! Fill ) {
return null;
}
- const Fill = groups[ group ].Fill;
return (
diff --git a/packages/block-editor/src/components/block-controls/groups.js b/packages/block-editor/src/components/block-controls/groups.js
index 42a94a4ab7a81b..9b9dfec8d8d450 100644
--- a/packages/block-editor/src/components/block-controls/groups.js
+++ b/packages/block-editor/src/components/block-controls/groups.js
@@ -7,12 +7,14 @@ const BlockControlsDefault = createSlotFill( 'BlockControls' );
const BlockControlsBlock = createSlotFill( 'BlockControlsBlock' );
const BlockControlsInline = createSlotFill( 'BlockFormatControls' );
const BlockControlsOther = createSlotFill( 'BlockControlsOther' );
+const BlockControlsParent = createSlotFill( 'BlockControlsParent' );
const groups = {
default: BlockControlsDefault,
block: BlockControlsBlock,
inline: BlockControlsInline,
other: BlockControlsOther,
+ parent: BlockControlsParent,
};
export default groups;
diff --git a/packages/block-editor/src/components/block-controls/hook.js b/packages/block-editor/src/components/block-controls/hook.js
new file mode 100644
index 00000000000000..d907a9aad5c364
--- /dev/null
+++ b/packages/block-editor/src/components/block-controls/hook.js
@@ -0,0 +1,44 @@
+/**
+ * WordPress dependencies
+ */
+import { store as blocksStore } from '@wordpress/blocks';
+import { useSelect } from '@wordpress/data';
+
+/**
+ * Internal dependencies
+ */
+import groups from './groups';
+import { store as blockEditorStore } from '../../store';
+import { useBlockEditContext } from '../block-edit/context';
+import useDisplayBlockControls from '../use-display-block-controls';
+
+export default function useBlockControlsFill( group, exposeToChildren ) {
+ const isDisplayed = useDisplayBlockControls();
+ const { clientId } = useBlockEditContext();
+ const isParentDisplayed = useSelect(
+ ( select ) => {
+ const { getBlockName, hasSelectedInnerBlock } = select(
+ blockEditorStore
+ );
+ const { hasBlockSupport } = select( blocksStore );
+ return (
+ exposeToChildren &&
+ hasBlockSupport(
+ getBlockName( clientId ),
+ '__experimentalExposeControlsToChildren',
+ false
+ ) &&
+ hasSelectedInnerBlock( clientId )
+ );
+ },
+ [ exposeToChildren, clientId ]
+ );
+
+ if ( isDisplayed ) {
+ return groups[ group ]?.Fill;
+ }
+ if ( isParentDisplayed ) {
+ return groups.parent.Fill;
+ }
+ return null;
+}
diff --git a/packages/block-editor/src/components/block-toolbar/index.js b/packages/block-editor/src/components/block-toolbar/index.js
index 599c936eeeb73a..def5b425760d10 100644
--- a/packages/block-editor/src/components/block-toolbar/index.js
+++ b/packages/block-editor/src/components/block-toolbar/index.js
@@ -123,6 +123,10 @@ export default function BlockToolbar( { hideDragHandle } ) {
{ shouldShowVisualToolbar && (
<>
+
{
export function useInnerBlocksProps( props = {}, options = {} ) {
const { clientId } = useBlockEditContext();
const isSmallScreen = useViewportMatch( 'medium', '<' );
- const hasOverlay = useSelect(
+ const { __experimentalCaptureToolbars, hasOverlay } = useSelect(
( select ) => {
if ( ! clientId ) {
- return;
+ return {};
}
const {
@@ -149,13 +153,22 @@ export function useInnerBlocksProps( props = {}, options = {} ) {
hasSelectedInnerBlock,
isNavigationMode,
} = select( blockEditorStore );
+ const blockName = getBlockName( clientId );
const enableClickThrough = isNavigationMode() || isSmallScreen;
- return (
- getBlockName( clientId ) !== 'core/template' &&
- ! isBlockSelected( clientId ) &&
- ! hasSelectedInnerBlock( clientId, true ) &&
- enableClickThrough
- );
+ return {
+ __experimentalCaptureToolbars: select(
+ blocksStore
+ ).hasBlockSupport(
+ blockName,
+ '__experimentalExposeControlsToChildren',
+ false
+ ),
+ hasOverlay:
+ blockName !== 'core/template' &&
+ ! isBlockSelected( clientId ) &&
+ ! hasSelectedInnerBlock( clientId, true ) &&
+ enableClickThrough,
+ };
},
[ clientId, isSmallScreen ]
);
@@ -167,11 +180,14 @@ export function useInnerBlocksProps( props = {}, options = {} ) {
} ),
] );
+ const innerBlocksProps = {
+ __experimentalCaptureToolbars,
+ ...options,
+ };
const InnerBlocks =
- options.value && options.onChange
+ innerBlocksProps.value && innerBlocksProps.onChange
? ControlledInnerBlocks
: UncontrolledInnerBlocks;
-
return {
...props,
ref,
@@ -183,7 +199,7 @@ export function useInnerBlocksProps( props = {}, options = {} ) {
}
),
children: clientId ? (
-
+
) : (
),
diff --git a/packages/block-editor/src/components/use-display-block-controls/index.js b/packages/block-editor/src/components/use-display-block-controls/index.js
index a3f4e7c4362f6c..605556f295b968 100644
--- a/packages/block-editor/src/components/use-display-block-controls/index.js
+++ b/packages/block-editor/src/components/use-display-block-controls/index.js
@@ -11,11 +11,10 @@ import { store as blockEditorStore } from '../../store';
export default function useDisplayBlockControls() {
const { isSelected, clientId, name } = useBlockEditContext();
- const isFirstAndSameTypeMultiSelected = useSelect(
+ return useSelect(
( select ) => {
- // Don't bother checking, see OR statement below.
if ( isSelected ) {
- return;
+ return true;
}
const {
@@ -24,16 +23,14 @@ export default function useDisplayBlockControls() {
getMultiSelectedBlockClientIds,
} = select( blockEditorStore );
- if ( ! isFirstMultiSelectedBlock( clientId ) ) {
- return false;
+ if ( isFirstMultiSelectedBlock( clientId ) ) {
+ return getMultiSelectedBlockClientIds().every(
+ ( id ) => getBlockName( id ) === name
+ );
}
- return getMultiSelectedBlockClientIds().every(
- ( id ) => getBlockName( id ) === name
- );
+ return false;
},
[ clientId, isSelected, name ]
);
-
- return isSelected || isFirstAndSameTypeMultiSelected;
}
diff --git a/packages/block-editor/src/hooks/align.js b/packages/block-editor/src/hooks/align.js
index 7cfd5f8b13fdef..b1e68b68bfe260 100644
--- a/packages/block-editor/src/hooks/align.js
+++ b/packages/block-editor/src/hooks/align.js
@@ -140,18 +140,20 @@ export const withToolbarControls = createHigherOrderComponent(
props.setAttributes( { align: nextAlign } );
};
- return [
- validAlignments.length > 0 && props.isSelected && (
-
-
-
- ),
- ,
- ];
+ return (
+ <>
+ { validAlignments.length > 0 && (
+
+
+
+ ) }
+
+ >
+ );
},
'withToolbarControls'
);
diff --git a/packages/block-editor/src/hooks/duotone.js b/packages/block-editor/src/hooks/duotone.js
index bf62161e1d1825..0bde4cdbe2c60e 100644
--- a/packages/block-editor/src/hooks/duotone.js
+++ b/packages/block-editor/src/hooks/duotone.js
@@ -140,7 +140,7 @@ function DuotonePanel( { attributes, setAttributes } ) {
}
return (
-
+
-
+
-
+
Date: Tue, 24 Aug 2021 15:53:18 +0200
Subject: [PATCH 021/214] Fix submenu positioning. (#34168)
---
packages/block-library/src/navigation/style.scss | 3 +++
1 file changed, 3 insertions(+)
diff --git a/packages/block-library/src/navigation/style.scss b/packages/block-library/src/navigation/style.scss
index bdc8183a235ea3..f63dab54701005 100644
--- a/packages/block-library/src/navigation/style.scss
+++ b/packages/block-library/src/navigation/style.scss
@@ -80,10 +80,13 @@
// Submenu indicator.
.wp-block-page-list__submenu-icon,
.wp-block-navigation-link__submenu-icon {
+ align-self: center;
height: inherit;
+ line-height: 0;
margin-left: 6px;
svg {
+ display: inline-block;
stroke: currentColor;
}
}
From 641060d92e2723d82144ae1206828db7e19d3cf4 Mon Sep 17 00:00:00 2001
From: Joen A <1204802+jasmussen@users.noreply.github.com>
Date: Tue, 24 Aug 2021 15:53:49 +0200
Subject: [PATCH 022/214] Enable flex on nav container to fix space between.
(#34258)
---
packages/block-library/src/navigation/style.scss | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/block-library/src/navigation/style.scss b/packages/block-library/src/navigation/style.scss
index f63dab54701005..b37e4dbd0244f4 100644
--- a/packages/block-library/src/navigation/style.scss
+++ b/packages/block-library/src/navigation/style.scss
@@ -341,6 +341,7 @@
// Horizontal layout
display: flex;
flex-wrap: wrap;
+ flex: 1;
}
// Vertical layout
From 790dd85a5d6e217817271452539f0c07db90c54f Mon Sep 17 00:00:00 2001
From: Jason Johnston
Date: Tue, 24 Aug 2021 12:10:54 -0400
Subject: [PATCH 023/214] Revert "[RNMobile] Use Flexbox for Inserter Menu tabs
on mobile (#34126)" (#34267)
This reverts commit c238f4324354a4a87293fe83ff1268ce7889e1c2.
Co-authored-by: jhnstn
---
.../block-editor/src/components/inserter/menu.native.js | 5 +----
.../src/components/inserter/style.native.scss | 7 ++++---
.../block-editor/src/components/inserter/tabs.native.js | 8 +++++++-
3 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/packages/block-editor/src/components/inserter/menu.native.js b/packages/block-editor/src/components/inserter/menu.native.js
index 5f556714456129..198bb761329e38 100644
--- a/packages/block-editor/src/components/inserter/menu.native.js
+++ b/packages/block-editor/src/components/inserter/menu.native.js
@@ -204,10 +204,7 @@ function InserterMenu( {
>
{ ( { listProps } ) => (
-
+
{ ! showTabs || filterValue ? (
{ tabs.map( ( { component: TabComponent }, index ) => (
-
+
Date: Tue, 24 Aug 2021 12:18:35 -0400
Subject: [PATCH 024/214] Query Loop: Update Post Template sub-block icon
(#34204)
Use the "layout" icon instead of "loop."
---
packages/block-library/src/post-template/index.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/block-library/src/post-template/index.js b/packages/block-library/src/post-template/index.js
index 5e3bba213228bf..ace8add51d3289 100644
--- a/packages/block-library/src/post-template/index.js
+++ b/packages/block-library/src/post-template/index.js
@@ -1,7 +1,7 @@
/**
* WordPress dependencies
*/
-import { loop } from '@wordpress/icons';
+import { layout } from '@wordpress/icons';
/**
* Internal dependencies
@@ -14,7 +14,7 @@ const { name } = metadata;
export { metadata, name };
export const settings = {
- icon: loop,
+ icon: layout,
edit,
save,
};
From 73f2b974b6b725fb5a1c20d32da04c8d6722d5b3 Mon Sep 17 00:00:00 2001
From: David Calhoun <438664+dcalhoun@users.noreply.github.com>
Date: Tue, 24 Aug 2021 11:28:50 -0500
Subject: [PATCH 025/214] Re-enable Android e2e tests (#34243)
* Re-enable Android e2e tests
* Pin Android emulator build ID
A breakage within Android Studio emulators caused the Android e2e tests
to fail with the following errors. To circumvent the issue, we leverage
the ability to pin the emulator to a specific build ID.
- https://git.io/JE3jX
- https://issuetracker.google.com/issues/191805460
- https://issuetracker.google.com/issues/191799887
```
dyld: lazy symbol binding failed: Symbol not found: _preadv
```
```
adb: no devices/emulators found
```
---
.github/workflows/rnmobile-android-runner.yml | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/rnmobile-android-runner.yml b/.github/workflows/rnmobile-android-runner.yml
index 18eda2ad1ef5a6..8bb83dfd7b6ec0 100644
--- a/.github/workflows/rnmobile-android-runner.yml
+++ b/.github/workflows/rnmobile-android-runner.yml
@@ -15,9 +15,7 @@ concurrency:
jobs:
test:
runs-on: macos-latest
- # The false value below disables the test while we investigate a
- # foundational error causing failures
- if: ${{ false && (github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request') }}
+ if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }}
strategy:
matrix:
native-test-name: [gutenberg-editor-initial-html]
@@ -41,9 +39,10 @@ jobs:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
- - uses: reactivecircus/android-emulator-runner@d2799957d660add41c61a5103e2fbb9e2889eb73 # v2.15.0
+ - uses: reactivecircus/android-emulator-runner@5de26e4bd23bf523e8a4b7f077df8bfb8e52b50e # v2.19.1
with:
api-level: 28
+ emulator-build: 7425822 # https://git.io/JE3jX
profile: pixel_xl
script: npm run native test:e2e:android:local ${{ matrix.native-test-name }}
From 45675ddfb6403e3979386894340d762756c5f2fd Mon Sep 17 00:00:00 2001
From: Paul Von Schrottky
Date: Tue, 24 Aug 2021 12:31:28 -0400
Subject: [PATCH 026/214] RNMobile: Fix broken documentation link (#34187)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* RNMobile: Fix broken link in https://developer.wordpress.org/block-editor/ which was fixed by running npm run docs:build
* Fix badly formatted docs table-of-content JSON
* Fix typos in docs
* Fix broken paths in docs
Co-authored-by: Greg Ziółkowski
---
docs/contributors/code/testing-overview.md | 4 ++--
docs/manifest.json | 6 ++++++
docs/toc.json | 15 ++++++++++-----
3 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/docs/contributors/code/testing-overview.md b/docs/contributors/code/testing-overview.md
index b4b9e062701813..98827115b62580 100644
--- a/docs/contributors/code/testing-overview.md
+++ b/docs/contributors/code/testing-overview.md
@@ -380,11 +380,11 @@ To locally run the tests in debug mode, follow these steps:
### Native mobile end-to-end tests
-Contributors to Gutenberg will note that PRs include continuous integration E2E tests running the native mobile E2E tests on Android and iOS. For troubleshooting failed tests, check our guide on [native mobile tests in continious integration](docs/contributors/native-mobile.md#native-mobile-e2e-tests-in-continuous-integration). More information on running these tests locally can be found in the [relevant directory README.md](https://github.com/WordPress/gutenberg/tree/HEAD/packages/react-native-editor/__device-tests__).
+Contributors to Gutenberg will note that PRs include continuous integration E2E tests running the native mobile E2E tests on Android and iOS. For troubleshooting failed tests, check our guide on [native mobile tests in continuous integration](/docs/contributors/code/native-mobile.md#native-mobile-e2e-tests-in-continuous-integration). More information on running these tests locally can be found in [here](/packages/react-native-editor/__device-tests__/README.md).
### Native mobile integration tests
-There is an ongoing effort to add integration tests to the native mobile project using the [`react-native-testing-library`](https://testing-library.com/docs/react-native-testing-library/intro/) library. A guide to writing integration tests can be found [here](native-mobile-integration-test-guide.md).
+There is an ongoing effort to add integration tests to the native mobile project using the [`react-native-testing-library`](https://testing-library.com/docs/react-native-testing-library/intro/) library. A guide to writing integration tests can be found [here](/docs/contributors/code/native-mobile-integration-test-guide.md).
## End-to-end Testing
diff --git a/docs/manifest.json b/docs/manifest.json
index 3fa9280108d4fb..5fdf1d29c05a82 100644
--- a/docs/manifest.json
+++ b/docs/manifest.json
@@ -2015,6 +2015,12 @@
"markdown_source": "../docs/contributors/code/native-mobile.md",
"parent": "code"
},
+ {
+ "title": "React Native Integration Test Guide",
+ "slug": "native-mobile-integration-test-guide",
+ "markdown_source": "../docs/contributors/code/native-mobile-integration-test-guide.md",
+ "parent": "code"
+ },
{
"title": "Getting Started for the React Native based Mobile Gutenberg",
"slug": "getting-started-native-mobile",
diff --git a/docs/toc.json b/docs/toc.json
index c8ce6140ef94f9..9d86afa1eb7f0e 100644
--- a/docs/toc.json
+++ b/docs/toc.json
@@ -178,11 +178,13 @@
},
{ "docs/how-to-guides/accessibility.md": [] },
{ "docs/how-to-guides/internationalization.md": [] },
- { "docs/how-to-guides/widgets/README.md": [
- { "docs/how-to-guides/widgets/overview.md": [] },
- { "docs/how-to-guides/widgets/opting-out.md": [] },
- { "docs/how-to-guides/widgets/legacy-widget-block.md": [] }
- ] }
+ {
+ "docs/how-to-guides/widgets/README.md": [
+ { "docs/how-to-guides/widgets/overview.md": [] },
+ { "docs/how-to-guides/widgets/opting-out.md": [] },
+ { "docs/how-to-guides/widgets/legacy-widget-block.md": [] }
+ ]
+ }
]
},
{
@@ -318,6 +320,9 @@
{ "docs/contributors/code/managing-packages.md": [] },
{ "docs/contributors/code/release.md": [] },
{ "docs/contributors/code/native-mobile.md": [] },
+ {
+ "docs/contributors/code/native-mobile-integration-test-guide.md": []
+ },
{
"docs/contributors/code/getting-started-native-mobile.md": []
}
From 3437ce32c775205c0e73b786751d92ec9549e7cd Mon Sep 17 00:00:00 2001
From: David Calhoun <438664+dcalhoun@users.noreply.github.com>
Date: Tue, 24 Aug 2021 14:28:33 -0500
Subject: [PATCH 027/214] Fix FlatList warning log from Columns block (#34200)
Replace unsupported use of `flex-wrap` with dynamic setting of
`horizontal` prop. The `horizontal` prop must be `false` to have the
`numOfColumns` property take effect.
```
WARN `flexWrap: 'wrap'` is not supported with the `VirtualizedList` components.Consider using `numColumns` with `FlatList` instead.
```
Related links:
- https://bit.ly/2UxBz3c
- https://git.io/J0prs
- https://git.io/J0prl
- https://git.io/J0pr8
- https://git.io/J0prV
---
packages/block-editor/src/components/block-list/index.native.js | 2 --
.../block-editor/src/components/block-list/style.native.scss | 1 -
packages/block-library/src/columns/edit.native.js | 2 +-
3 files changed, 1 insertion(+), 4 deletions(-)
diff --git a/packages/block-editor/src/components/block-list/index.native.js b/packages/block-editor/src/components/block-list/index.native.js
index 4ce520ed818751..697a9ffc19daa6 100644
--- a/packages/block-editor/src/components/block-list/index.native.js
+++ b/packages/block-editor/src/components/block-list/index.native.js
@@ -262,8 +262,6 @@ export class BlockList extends Component {
{ flex: isRootList ? 1 : 0 },
! isRootList && styles.overflowVisible,
] }
- horizontal={ horizontal }
- numColumns={ 1 }
extraData={ this.getExtraData() }
scrollEnabled={ isRootList }
contentContainerStyle={ [
diff --git a/packages/block-editor/src/components/block-list/style.native.scss b/packages/block-editor/src/components/block-list/style.native.scss
index fe63d30b4d0b21..6ff09277e9ea54 100644
--- a/packages/block-editor/src/components/block-list/style.native.scss
+++ b/packages/block-editor/src/components/block-list/style.native.scss
@@ -6,7 +6,6 @@
.horizontalContentContainer {
flex-direction: row;
- flex-wrap: wrap;
justify-content: flex-start;
align-items: stretch;
overflow: visible;
diff --git a/packages/block-library/src/columns/edit.native.js b/packages/block-library/src/columns/edit.native.js
index 9bf1ceae7ac99b..a7e765b8344a4e 100644
--- a/packages/block-library/src/columns/edit.native.js
+++ b/packages/block-library/src/columns/edit.native.js
@@ -274,7 +274,7 @@ function ColumnsEditContainer( {
orientation={
columnsInRow > 1 ? 'horizontal' : undefined
}
- horizontal={ true }
+ horizontal={ columnsInRow > 1 }
allowedBlocks={ ALLOWED_BLOCKS }
contentResizeMode="stretch"
onAddBlock={ onAddBlock }
From 58e6686267b018eb6a1daa5810097b22bda27942 Mon Sep 17 00:00:00 2001
From: Enej Bajgoric
Date: Tue, 24 Aug 2021 15:06:53 -0700
Subject: [PATCH 028/214] RNmobile: Fix the cancel button on Columns Block
(#34249)
---
.../src/components/block-variation-picker/style.native.scss | 2 ++
1 file changed, 2 insertions(+)
diff --git a/packages/block-editor/src/components/block-variation-picker/style.native.scss b/packages/block-editor/src/components/block-variation-picker/style.native.scss
index cfee074a24a982..c8bb66b7a714a0 100644
--- a/packages/block-editor/src/components/block-variation-picker/style.native.scss
+++ b/packages/block-editor/src/components/block-variation-picker/style.native.scss
@@ -17,6 +17,8 @@
.cancelButton {
color: $blue-wordpress;
font-size: 16px;
+ padding-left: $grid-unit-20;
+ padding-right: $grid-unit-20;
}
.cancelButtonDark {
From cb37d52289db37896ef9ab214c4305208c5649f1 Mon Sep 17 00:00:00 2001
From: Andrew Serong <14988353+andrewserong@users.noreply.github.com>
Date: Wed, 25 Aug 2021 09:53:24 +1000
Subject: [PATCH 029/214] File block: Update transform from image to use image
filename if caption is empty (#34256)
---
packages/block-library/src/file/transforms.js | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/packages/block-library/src/file/transforms.js b/packages/block-library/src/file/transforms.js
index 30e9808cb25251..242b60adfd7354 100644
--- a/packages/block-library/src/file/transforms.js
+++ b/packages/block-library/src/file/transforms.js
@@ -10,6 +10,7 @@ import { createBlobURL } from '@wordpress/blob';
import { createBlock } from '@wordpress/blocks';
import { select } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
+import { getPath } from '@wordpress/url';
const transforms = {
from: [
@@ -70,9 +71,11 @@ const transforms = {
type: 'block',
blocks: [ 'core/image' ],
transform: ( attributes ) => {
+ const filename = getPath( attributes.url )?.split( '/' ).pop();
+
return createBlock( 'core/file', {
href: attributes.url,
- fileName: attributes.caption,
+ fileName: attributes.caption || filename,
textLinkHref: attributes.url,
id: attributes.id,
anchor: attributes.anchor,
From e20259892d1063d3165ea920ce154226a01994cc Mon Sep 17 00:00:00 2001
From: Gutenberg Repository Automation
Date: Wed, 25 Aug 2021 04:23:23 +0000
Subject: [PATCH 030/214] Bump plugin version to 11.4.0-rc.1
---
gutenberg.php | 2 +-
package-lock.json | 2 +-
package.json | 2 +-
readme.txt | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/gutenberg.php b/gutenberg.php
index 63d4d1c4eb0955..474610ed70ee80 100644
--- a/gutenberg.php
+++ b/gutenberg.php
@@ -5,7 +5,7 @@
* Description: Printing since 1440. This is the development plugin for the new block editor in core.
* Requires at least: 5.6
* Requires PHP: 5.6
- * Version: 11.3.0
+ * Version: 11.4.0-rc.1
* Author: Gutenberg Team
* Text Domain: gutenberg
*
diff --git a/package-lock.json b/package-lock.json
index 629b31cb939cbf..77a1fa1c1c7115 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "gutenberg",
- "version": "11.3.0",
+ "version": "11.4.0-rc.1",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 6d3ff4a2f29773..5aa265595e143b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "gutenberg",
- "version": "11.3.0",
+ "version": "11.4.0-rc.1",
"private": true,
"description": "A new WordPress editor experience.",
"author": "The WordPress Contributors",
diff --git a/readme.txt b/readme.txt
index f0d9aa71b2bbb2..744abf34c84e4b 100644
--- a/readme.txt
+++ b/readme.txt
@@ -55,4 +55,4 @@ View release page .
+To read the changelog for Gutenberg 11.4.0-rc.1, please navigate to the release page .
From e7765c21767d834fec14f4581e8f4246e4442c0c Mon Sep 17 00:00:00 2001
From: Gutenberg Repository Automation
Date: Wed, 25 Aug 2021 06:00:08 +0000
Subject: [PATCH 031/214] Update Changelog for 11.4.0-rc.1
---
changelog.txt | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 147 insertions(+)
diff --git a/changelog.txt b/changelog.txt
index a25a0c2a499fd6..745a6fe44db929 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,5 +1,152 @@
== Changelog ==
+= 11.4.0-rc.1 =
+
+### Enhancements
+- Accessibility
+ - Cover Block: Allow alt text in Cover blocks. ([33226](https://github.com/WordPress/gutenberg/pull/33226))
+ - Add `aria-describedby` to custom select control component to describe currently-selected font size. ([33941](https://github.com/WordPress/gutenberg/pull/33941))
+- Block Editor
+ - Block Lists: improve iframe block, pattern and template previews. ([28165](https://github.com/WordPress/gutenberg/pull/28165))
+- Block Library
+ - Query Loop: Update Post Template sub-block icon. ([34204](https://github.com/WordPress/gutenberg/pull/34204))
+ - Convert Gallery block to use Image blocks. ([25940](https://github.com/WordPress/gutenberg/pull/25940))
+ - Post Featured Image: add duotone block supports. ([34113](https://github.com/WordPress/gutenberg/pull/34113))
+ - Post Featured Image: add contextual help text to the `scale`property. ([34158](https://github.com/WordPress/gutenberg/pull/34158))
+ - File block: update transform from image to use image filename if caption is empty. ([34256](https://github.com/WordPress/gutenberg/pull/34256))
+ - Post date Block: add font weight support to the block. ([34070](https://github.com/WordPress/gutenberg/pull/34070))
+ - Post terms: add font weight support to the block. ([34142](https://github.com/WordPress/gutenberg/pull/34142))
+ - Site Tagline: Add font weight support. ([33983](https://github.com/WordPress/gutenberg/pull/33983))
+ - Button: update spacing support to use axial padding. ([33859](https://github.com/WordPress/gutenberg/pull/33859))
+- Components
+ - Add deprecated props adapter for ColorPicker. ([34014](https://github.com/WordPress/gutenberg/pull/34014))
+ - Wrap SegmentedControl in a BaseControl with an added `help` property. ([34017](https://github.com/WordPress/gutenberg/pull/34017))
+ - Combobox: update the current selection if the list of suggestions is filtered. ([33928](https://github.com/WordPress/gutenberg/pull/33928))
+ - Post Title: Use rich text hook and updating tag to `h1` ([31569](https://github.com/WordPress/gutenberg/pull/31569))
+- Design Tools
+ - Add layout default value support for blocks. ([34194](https://github.com/WordPress/gutenberg/pull/34194))
+ - Dimensions Panel: Add padding tool as default for blocks where this is common setting. ([34026](https://github.com/WordPress/gutenberg/pull/34026))
+- Navigation Screen
+ - Update navigation screen topbar. ([34166](https://github.com/WordPress/gutenberg/pull/34166))
+- Packages
+ - Updates the "settings" icon, which toggles the display of additional controls in an interface. ([34165](https://github.com/WordPress/gutenberg/pull/34165))
+- Post Editor
+ - Migrate post editor feature preferences to the interface package. ([34154](https://github.com/WordPress/gutenberg/pull/34154))
+- Widgets Editor
+ - Migrate customize widgets feature preferences to interface package. ([34135](https://github.com/WordPress/gutenberg/pull/34135))
+ - Refactor editor 'feature' preferences to interface package. ([33774](https://github.com/WordPress/gutenberg/pull/33774))
+
+### Bug Fixes
+- Build Tooling
+ - Webpack: Fix watch on `.json` and `.php` files. ([34024](https://github.com/WordPress/gutenberg/pull/34024))
+- Components
+ - Fix RTL on `Flex` component. ([33729](https://github.com/WordPress/gutenberg/pull/33729))
+ - NavigationSidebar: fix template content for content-navigation-item preview. ([34203](https://github.com/WordPress/gutenberg/pull/34203))
+ - Remove deprecated import style for storybook/addon-docs. ([34095](https://github.com/WordPress/gutenberg/pull/34095))
+ - ToolsPanel: Add tools panel item deregistration. ([34085](https://github.com/WordPress/gutenberg/pull/34085))
+ - Post Title: Remove wrapper div & fix border style. ([34167](https://github.com/WordPress/gutenberg/pull/34167))
+- Core Data
+ - GetEntityRecords return items even if some included IDs don't exist. ([34034](https://github.com/WordPress/gutenberg/pull/34034))
+- Block API
+ - Spacing/Dimensions Supports: Separate spacing from dimensions for compatibility purposes. ([34059](https://github.com/WordPress/gutenberg/pull/34059))
+- Block Editor
+ - Font-size adjustment for tablet and mobile device previews. ([33342](https://github.com/WordPress/gutenberg/pull/33342))
+ - Fix single block selection by holding `shift` key. ([34137](https://github.com/WordPress/gutenberg/pull/34137))
+ - Fix unwanted additional spaces added around pasted text on Windows. ([33607](https://github.com/WordPress/gutenberg/pull/33607))
+ - Inserter: prevent non-deterministic order of inserter items. ([34078](https://github.com/WordPress/gutenberg/pull/34078))
+ - Try: Fix multiselect toolbar indent and reformat `BlockContextualToolbar()`. ([34038](https://github.com/WordPress/gutenberg/pull/34038)) ([34173](https://github.com/WordPress/gutenberg/pull/34173))
+- Block Library
+ - Latest Comments: use site locale in the editor. ([33944](https://github.com/WordPress/gutenberg/pull/33944))
+ - Navigation: fix vertical layout on the frontend. ([34226](https://github.com/WordPress/gutenberg/pull/34226))
+ - Navigation: add z-index value to responsive menu overlay. ([34228](https://github.com/WordPress/gutenberg/pull/34228))
+ - Navigation: enable flex on nav container to fix space between. ([34258](https://github.com/WordPress/gutenberg/pull/34258))
+ - Navigation: fix submenu icon positioning. ([34168](https://github.com/WordPress/gutenberg/pull/34168))
+ - Navigation block: add missing `` closing tag. ([34077](https://github.com/WordPress/gutenberg/pull/34077))
+ - Post Excerpt: remove interactive formatting. ([34083](https://github.com/WordPress/gutenberg/pull/34083))
+ - RichText: fix Space key for button and summary elements. ([30244](https://github.com/WordPress/gutenberg/pull/30244))
+ - Search Block: add space between generated border class names. ([34025](https://github.com/WordPress/gutenberg/pull/34025))
+- Design Tools
+ - Allow zero values for Theme JSON styles. ([34251](https://github.com/WordPress/gutenberg/pull/34251))
+- Global Styles
+ - Site editor: Fix for how CSS Custom Properties are generated. ([33932](https://github.com/WordPress/gutenberg/pull/33932))
+- Packages
+ - Rich Text: add check to `toTree()` in replacements before accessing its type. ([34020](https://github.com/WordPress/gutenberg/pull/34020))
+- Post Editor
+ - Fix selector params in `isPluginItemPinned()` selector. ([34155](https://github.com/WordPress/gutenberg/pull/34155))
+
+
+### Performance
+- Data Layer
+ - Data: Add a batch function to the data module to batch actions. ([34046](https://github.com/WordPress/gutenberg/pull/34046))
+
+### Experiments
+- Block API
+ - Block Editor: Absorb parent block toolbar controls. ([33955](https://github.com/WordPress/gutenberg/pull/33955))
+ - Block Editor: Use groups for InspectorControls. ([34069](https://github.com/WordPress/gutenberg/pull/34069))
+- Block Library
+ - Add generic classnames to children of Navigation. ([33918](https://github.com/WordPress/gutenberg/pull/33918))
+- Global Styles
+ - Add slashes back to the Theme JSON. ([33919](https://github.com/WordPress/gutenberg/pull/33919))
+ - Add block spacing gap configuration to theme.json and add support for this CSS variable to the "flow/default" layout. ([33812](https://github.com/WordPress/gutenberg/pull/33812))
+
+
+### Documentation
+- Packages
+ - Add documentation for mobile components directory. ([33872](https://github.com/WordPress/gutenberg/pull/33872))
+- Handbook
+ - Alphabetize glossary entries. ([34058](https://github.com/WordPress/gutenberg/pull/34058))
+ - Correct minor typos in wp-plugin.md ([34185](https://github.com/WordPress/gutenberg/pull/34185))
+ - Remove extraneous params from `block_type_metadata` hook. ([34151](https://github.com/WordPress/gutenberg/pull/34151))
+ - Update incorrect Settings examples in "Global Settings & Styles". ([34084](https://github.com/WordPress/gutenberg/pull/34084))
+ - Use block.json to add attributes in create block tutorial. ([33978](https://github.com/WordPress/gutenberg/pull/33978))
+ - Fix typo in block gap documentation in theme-json.md. ([34231](https://github.com/WordPress/gutenberg/pull/34231))
+ - Fix broken mobile testing documentation link in testing-overview.md . ([34187](https://github.com/WordPress/gutenberg/pull/34187))
+ - Fix typo in legacy-widget-block.md. ([34103](https://github.com/WordPress/gutenberg/pull/34103))
+ - Update spelling and `fontSize` examples in create-block-theme.md. ([34152](https://github.com/WordPress/gutenberg/pull/34152))
+- Library
+ - Bump mobile version in experiments page for gallery. ([34220](https://github.com/WordPress/gutenberg/pull/34220))
+
+### Code Quality
+- Block Editor
+ - Render head and body with single portal for block previews. ([34208](https://github.com/WordPress/gutenberg/pull/34208))
+ - BlockList: refactor element context for style/svg appending. ([34183](https://github.com/WordPress/gutenberg/pull/34183))
+ - BlockList: Use InnerBlocks internally. ([29895](https://github.com/WordPress/gutenberg/pull/29895))
+- Site Editor
+ - Remove extra dom element used for template part overlay. ([34012](https://github.com/WordPress/gutenberg/pull/34012))
+- Components
+ - Unit Control: add unit tests for `getValidParsedUnit` utility method. ([34029](https://github.com/WordPress/gutenberg/pull/34029))
+ - Rename `SegmentedControl` to `ToggleGroupControl`. ([34111](https://github.com/WordPress/gutenberg/pull/34111))
+ - Dropdown Menu: remove min-width from the dropdown component and add whitespace rule to avoid wrapping ([33995](https://github.com/WordPress/gutenberg/pull/33995))
+- Core Data
+ - Allow passing store definitions to controls. ([34170](https://github.com/WordPress/gutenberg/pull/34170))
+
+### Tools
+- ESLint
+ - Eslint plugin: Use @typescript-eslint/no-duplicate-imports in TS projects. ([34055](https://github.com/WordPress/gutenberg/pull/34055))
+- GitHub Contributor Templates
+ - Issue Forms: Simplify the bug report form template. ([34007](https://github.com/WordPress/gutenberg/pull/34007))
+- Logs
+ - Hide deprecation logs under a console group. ([34163](https://github.com/WordPress/gutenberg/pull/34163))
+- Testing
+ - Emulate reduced-motion in end-to-end tests. ([34132](https://github.com/WordPress/gutenberg/pull/34132))
+ - Re-enable Android end-to-end tests. ([34243](https://github.com/WordPress/gutenberg/pull/34243))
+ - Remove extra props from Cover deprecations. ([34066](https://github.com/WordPress/gutenberg/pull/34066))
+ - Remove the `ENVIRONMENT_DIRECTORY` env variable that was added to the performance jobs. ([34086](https://github.com/WordPress/gutenberg/pull/34086))
+ - Add snapshot test for changelog formatting. ([34049](https://github.com/WordPress/gutenberg/pull/34049))
+ - Experiment with using REST API in end-to-end tests to build up states. ([33414](https://github.com/WordPress/gutenberg/pull/33414))
+- Build Tooling
+ - Automated Changelog: force group all documentation tasks under `Documentation`. ([34042](https://github.com/WordPress/gutenberg/pull/34042))
+ - Automated Changelog: rename "Editor" grouping to "Post Editor" to avoid ambiguity with other editors. ([34093](https://github.com/WordPress/gutenberg/pull/34093))
+ - Automated Changelog: sort feature groups by issue name. ([34071](https://github.com/WordPress/gutenberg/pull/34071))
+ - Automated Changelog: use nested headings for feature groups instead of indenting lists. ([34040](https://github.com/WordPress/gutenberg/pull/34040))
+ - Automated Changelog: remove `Uncategorized` header in output and place items at top. ([34037](https://github.com/WordPress/gutenberg/pull/34037))
+ - Add Typescript extensions to watched files. ([34094](https://github.com/WordPress/gutenberg/pull/34094))
+ - Remove obsolete step that pushes tags in npm publishing flow. ([34114](https://github.com/WordPress/gutenberg/pull/34114))
+
+
+
+
+
= 11.3.0 =
### Enhancements
From 4037448e9214063128960fc086ae4cc4744158e0 Mon Sep 17 00:00:00 2001
From: Matthew Reishus
Date: Wed, 25 Aug 2021 01:05:27 -0500
Subject: [PATCH 032/214] Change default value of enableCustomFields to
undefined (#33931)
* Change default value of enableCustomFields to undefined
* Add comment explaining true/false/undefined for enableCustomFields
* Preferences: Hide 'Additional' section when custom fields are disabled and there are no meta boxes
* Tweak comments
Co-authored-by: Robert Anderson
---
.../edit-post/src/components/preferences-modal/index.js | 6 ++----
.../preferences-modal/test/__snapshots__/index.js.snap | 6 ++----
packages/editor/src/store/defaults.js | 9 +++++++--
3 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/packages/edit-post/src/components/preferences-modal/index.js b/packages/edit-post/src/components/preferences-modal/index.js
index 3a536a74140bde..ad67783a7f10a2 100644
--- a/packages/edit-post/src/components/preferences-modal/index.js
+++ b/packages/edit-post/src/components/preferences-modal/index.js
@@ -243,14 +243,12 @@ export default function PreferencesModal() {
/>
-
+ />
>
),
},
diff --git a/packages/edit-post/src/components/preferences-modal/test/__snapshots__/index.js.snap b/packages/edit-post/src/components/preferences-modal/test/__snapshots__/index.js.snap
index 5e96f24c36fef3..d8351581e23684 100644
--- a/packages/edit-post/src/components/preferences-modal/test/__snapshots__/index.js.snap
+++ b/packages/edit-post/src/components/preferences-modal/test/__snapshots__/index.js.snap
@@ -179,12 +179,10 @@ exports[`PreferencesModal should match snapshot when the modal is active small v
/>
-
+ />
diff --git a/packages/editor/src/store/defaults.js b/packages/editor/src/store/defaults.js
index 94125a58f1392f..03824561549f71 100644
--- a/packages/editor/src/store/defaults.js
+++ b/packages/editor/src/store/defaults.js
@@ -14,7 +14,12 @@ export const PREFERENCES_DEFAULTS = {
* allowedBlockTypes boolean|Array Allowed block types
* richEditingEnabled boolean Whether rich editing is enabled or not
* codeEditingEnabled boolean Whether code editing is enabled or not
- * enableCustomFields boolean Whether the WordPress custom fields are enabled or not
+ * enableCustomFields boolean Whether the WordPress custom fields are enabled or not.
+ * true = the user has opted to show the Custom Fields panel at the bottom of the editor.
+ * false = the user has opted to hide the Custom Fields panel at the bottom of the editor.
+ * undefined = the current environment does not support Custom Fields,
+ * so the option toggle in Preferences -> Panels to
+ * enable the Custom Fields panel is not displayed.
* autosaveInterval number Autosave Interval
* availableTemplates array? The available post templates
* disablePostFormats boolean Whether or not the post formats are disabled
@@ -27,6 +32,6 @@ export const EDITOR_SETTINGS_DEFAULTS = {
richEditingEnabled: true,
codeEditingEnabled: true,
- enableCustomFields: false,
+ enableCustomFields: undefined,
supportsLayout: true,
};
From 9a83b74ccd8c596eb840c506c73bbd0cebbbe5cc Mon Sep 17 00:00:00 2001
From: chad1008 <13856531+chad1008@users.noreply.github.com>
Date: Wed, 25 Aug 2021 04:11:33 -0400
Subject: [PATCH 033/214] Align labels on focal point picker position controls
above the text inputs to allow space for longer text when translated (#34209)
---
packages/components/src/focal-point-picker/controls.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/components/src/focal-point-picker/controls.js b/packages/components/src/focal-point-picker/controls.js
index ae375a1bc32ceb..36991e05604139 100644
--- a/packages/components/src/focal-point-picker/controls.js
+++ b/packages/components/src/focal-point-picker/controls.js
@@ -60,7 +60,7 @@ function UnitControl( props ) {
return (
Date: Wed, 25 Aug 2021 19:13:55 +0900
Subject: [PATCH 034/214] General Interface: Make permalinks documentation URL
translatable (#34282)
* Make the URL translatable.
* Update packages/edit-post/src/components/sidebar/post-link/index.js
Co-authored-by: Hiroshi Urabe
Co-authored-by: Hiroshi Urabe
---
.../edit-post/src/components/sidebar/post-link/index.js | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/packages/edit-post/src/components/sidebar/post-link/index.js b/packages/edit-post/src/components/sidebar/post-link/index.js
index 5b6ac7f7e92206..a3905a2275e5ec 100644
--- a/packages/edit-post/src/components/sidebar/post-link/index.js
+++ b/packages/edit-post/src/components/sidebar/post-link/index.js
@@ -95,7 +95,11 @@ function PostLink( {
/>
{ __( 'The last part of the URL.' ) }{ ' ' }
-
+
{ __( 'Read about permalinks' ) }
From 636b8710eefc530e0f17770d32fc7b27eedbbc55 Mon Sep 17 00:00:00 2001
From: Riad Benguella
Date: Wed, 25 Aug 2021 11:14:17 +0100
Subject: [PATCH 035/214] More work on the stability of the performance metrics
(#34229)
---
.../specs/performance/post-editor.test.js | 188 ++++++++++--------
1 file changed, 108 insertions(+), 80 deletions(-)
diff --git a/packages/e2e-tests/specs/performance/post-editor.test.js b/packages/e2e-tests/specs/performance/post-editor.test.js
index 8045291cb331a4..0bbfcd18660369 100644
--- a/packages/e2e-tests/specs/performance/post-editor.test.js
+++ b/packages/e2e-tests/specs/performance/post-editor.test.js
@@ -31,18 +31,18 @@ import {
jest.setTimeout( 1000000 );
describe( 'Post Editor Performance', () => {
- it( 'Loading, typing and selecting blocks', async () => {
- const traceFile = __dirname + '/trace.json';
- let traceResults;
- const results = {
- load: [],
- type: [],
- focus: [],
- inserterOpen: [],
- inserterHover: [],
- inserterSearch: [],
- };
+ const results = {
+ load: [],
+ type: [],
+ focus: [],
+ inserterOpen: [],
+ inserterHover: [],
+ inserterSearch: [],
+ };
+ const traceFile = __dirname + '/trace.json';
+ let traceResults;
+ beforeAll( async () => {
const html = readFile(
join( __dirname, '../../assets/large-post.html' )
);
@@ -63,7 +63,30 @@ describe( 'Post Editor Performance', () => {
dispatch( 'core/block-editor' ).resetBlocks( blocks );
}, html );
await saveDraft();
+ } );
+
+ afterAll( async () => {
+ const resultsFilename = basename( __filename, '.js' ) + '.results.json';
+ writeFileSync(
+ join( __dirname, resultsFilename ),
+ JSON.stringify( results, null, 2 )
+ );
+ deleteFile( traceFile );
+ } );
+ beforeEach( async () => {
+ // Disable auto-save to avoid impacting the metrics.
+ await page.evaluate( () => {
+ window.wp.data
+ .dispatch( 'core/edit-post' )
+ .__experimentalUpdateLocalAutosaveInterval( 100000000000 );
+ window.wp.data
+ .dispatch( 'core/editor' )
+ .updateEditorSettings( { autosaveInterval: 100000000000 } );
+ } );
+ } );
+
+ it( 'Loading', async () => {
// Measuring loading time
let i = 5;
while ( i-- ) {
@@ -72,7 +95,77 @@ describe( 'Post Editor Performance', () => {
await page.waitForSelector( '.wp-block' );
results.load.push( new Date() - startTime );
}
+ } );
+
+ it( 'Typing', async () => {
+ // Measuring typing performance
+ await insertBlock( 'Paragraph' );
+ let i = 20;
+ await page.tracing.start( {
+ path: traceFile,
+ screenshots: false,
+ categories: [ 'devtools.timeline' ],
+ } );
+ while ( i-- ) {
+ // Wait for the browser to be idle before starting the monitoring.
+ // The timeout should be big enough to allow all async tasks tor run.
+ // And also to allow Rich Text to mark the change as persistent.
+ // eslint-disable-next-line no-restricted-syntax
+ await page.waitForTimeout( 2000 );
+ await page.keyboard.type( 'x' );
+ }
+ await page.tracing.stop();
+ traceResults = JSON.parse( readFile( traceFile ) );
+ const [
+ keyDownEvents,
+ keyPressEvents,
+ keyUpEvents,
+ ] = getTypingEventDurations( traceResults );
+ if (
+ keyDownEvents.length === keyPressEvents.length &&
+ keyPressEvents.length === keyUpEvents.length
+ ) {
+ // The first character typed triggers a longer time (isTyping change)
+ // It can impact the stability of the metric, so we exclude it.
+ for ( let j = 1; j < keyDownEvents.length; j++ ) {
+ results.type.push(
+ keyDownEvents[ j ] + keyPressEvents[ j ] + keyUpEvents[ j ]
+ );
+ }
+ }
+ } );
+
+ it( 'Selecting blocks', async () => {
+ // Measuring block selection performance
+ await createNewPost();
+ await page.evaluate( () => {
+ const { createBlock } = window.wp.blocks;
+ const { dispatch } = window.wp.data;
+ const blocks = window.lodash
+ .times( 1000 )
+ .map( () => createBlock( 'core/paragraph' ) );
+ dispatch( 'core/block-editor' ).resetBlocks( blocks );
+ } );
+ const paragraphs = await page.$$( '.wp-block' );
+ await page.tracing.start( {
+ path: traceFile,
+ screenshots: false,
+ categories: [ 'devtools.timeline' ],
+ } );
+ await paragraphs[ 0 ].click();
+ for ( let j = 1; j <= 10; j++ ) {
+ // Wait for the browser to be idle before starting the monitoring.
+ // eslint-disable-next-line no-restricted-syntax
+ await page.waitForTimeout( 1000 );
+ await paragraphs[ j ].click();
+ }
+ await page.tracing.stop();
+ traceResults = JSON.parse( readFile( traceFile ) );
+ const [ focusEvents ] = getSelectionEventDurations( traceResults );
+ results.focus = focusEvents;
+ } );
+ it( 'Opening the inserter', async () => {
// Measure time to open inserter
await page.waitForSelector( '.edit-post-layout' );
for ( let j = 0; j < 10; j++ ) {
@@ -90,7 +183,9 @@ describe( 'Post Editor Performance', () => {
}
await closeGlobalBlockInserter();
}
+ } );
+ it( 'Searching the inserter', async () => {
// Measure time to search the inserter and get results
await openGlobalBlockInserter();
for ( let j = 0; j < 10; j++ ) {
@@ -123,7 +218,9 @@ describe( 'Post Editor Performance', () => {
await page.keyboard.press( 'Backspace' );
}
await closeGlobalBlockInserter();
+ } );
+ it( 'Hovering Inserter Items', async () => {
// Measure inserter hover performance
const paragraphBlockItem =
'.block-editor-inserter__menu .editor-block-list-item-paragraph';
@@ -157,74 +254,5 @@ describe( 'Post Editor Performance', () => {
}
}
await closeGlobalBlockInserter();
-
- // Measuring typing performance
- await insertBlock( 'Paragraph' );
- i = 20;
- await page.tracing.start( {
- path: traceFile,
- screenshots: false,
- categories: [ 'devtools.timeline' ],
- } );
- while ( i-- ) {
- // Wait for the browser to be idle before starting the monitoring.
- // eslint-disable-next-line no-restricted-syntax
- await page.waitForTimeout( 200 );
- await page.keyboard.type( 'x' );
- }
- await page.tracing.stop();
- traceResults = JSON.parse( readFile( traceFile ) );
- const [
- keyDownEvents,
- keyPressEvents,
- keyUpEvents,
- ] = getTypingEventDurations( traceResults );
- if (
- keyDownEvents.length === keyPressEvents.length &&
- keyPressEvents.length === keyUpEvents.length
- ) {
- for ( let j = 0; j < keyDownEvents.length; j++ ) {
- results.type.push(
- keyDownEvents[ j ] + keyPressEvents[ j ] + keyUpEvents[ j ]
- );
- }
- }
-
- // Measuring block selection performance
- await createNewPost();
- await page.evaluate( () => {
- const { createBlock } = window.wp.blocks;
- const { dispatch } = window.wp.data;
- const blocks = window.lodash
- .times( 1000 )
- .map( () => createBlock( 'core/paragraph' ) );
- dispatch( 'core/block-editor' ).resetBlocks( blocks );
- } );
- const paragraphs = await page.$$( '.wp-block' );
- await page.tracing.start( {
- path: traceFile,
- screenshots: false,
- categories: [ 'devtools.timeline' ],
- } );
- await paragraphs[ 0 ].click();
- for ( let j = 1; j <= 10; j++ ) {
- // Wait for the browser to be idle before starting the monitoring.
- // eslint-disable-next-line no-restricted-syntax
- await page.waitForTimeout( 200 );
- await paragraphs[ j ].click();
- }
- await page.tracing.stop();
- traceResults = JSON.parse( readFile( traceFile ) );
- const [ focusEvents ] = getSelectionEventDurations( traceResults );
- results.focus = focusEvents;
-
- const resultsFilename = basename( __filename, '.js' ) + '.results.json';
- writeFileSync(
- join( __dirname, resultsFilename ),
- JSON.stringify( results, null, 2 )
- );
- deleteFile( traceFile );
-
- expect( true ).toBe( true );
} );
} );
From 8a88997867b09a57e536a34ce6ffe8a07e1f3f62 Mon Sep 17 00:00:00 2001
From: Vicente Canales <1157901+vcanales@users.noreply.github.com>
Date: Wed, 25 Aug 2021 06:14:47 -0400
Subject: [PATCH 036/214] release workflow: only commit modified changelogs
(#34211)
---
.github/workflows/upload-release-to-plugin-repo.yml | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/upload-release-to-plugin-repo.yml b/.github/workflows/upload-release-to-plugin-repo.yml
index d7561fe3b296f4..59cfed85c1b8f5 100644
--- a/.github/workflows/upload-release-to-plugin-repo.yml
+++ b/.github/workflows/upload-release-to-plugin-repo.yml
@@ -79,8 +79,14 @@ jobs:
- name: Commit the Changelog update
run: |
git add changelog.txt
- git commit -m "Update Changelog for ${TAG#v}"
- git push --set-upstream origin "${{ matrix.branch }}"
+ # Remove files that are not meant to be commited
+ # ie. release_notes.txt created on the previous step.
+ git clean -fd
+ # Only attempt to commit changelog if it has been modified.
+ if ! git diff-index --quiet HEAD --; then
+ git commit -m "Update Changelog for ${TAG#v}"
+ git push --set-upstream origin "${{ matrix.branch }}"
+ fi
- name: Upload Changelog artifact
uses: actions/upload-artifact@e448a9b857ee2131e752b06002bf0e093c65e571 # v2.2.2
From ac41a59a2ce33cce69c4a6374a6dc759888d0ce1 Mon Sep 17 00:00:00 2001
From: Miguel Fonseca
Date: Wed, 25 Aug 2021 11:52:48 +0100
Subject: [PATCH 037/214] useDropZone: Ensure drag event targets HTMLElement
(#34272)
Attempts to fix a TypeError that has been logged in the wild but is yet
to be reproduced. In production builds, it manifests as `e.dataset is
undefined`, pointing to the useDropZone hook.
* Don't cast FocusTarget instance to HTMLElement prior to calling
isElementInZone.
* Perform type validations inside isElementInZone, then cast to
HTMLElement.
---
.../compose/src/hooks/use-drop-zone/index.js | 20 ++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/packages/compose/src/hooks/use-drop-zone/index.js b/packages/compose/src/hooks/use-drop-zone/index.js
index c2a6a4224f55fb..ea58eab14b9cb5 100644
--- a/packages/compose/src/hooks/use-drop-zone/index.js
+++ b/packages/compose/src/hooks/use-drop-zone/index.js
@@ -73,18 +73,24 @@ export default function useDropZone( {
/**
* Checks if an element is in the drop zone.
*
- * @param {HTMLElement|null} elementToCheck
+ * @param {EventTarget|null} targetToCheck
*
* @return {boolean} True if in drop zone, false if not.
*/
- function isElementInZone( elementToCheck ) {
+ function isElementInZone( targetToCheck ) {
+ const { defaultView } = ownerDocument;
if (
- ! elementToCheck ||
- ! element.contains( elementToCheck )
+ ! targetToCheck ||
+ ! defaultView ||
+ ! ( targetToCheck instanceof defaultView.HTMLElement ) ||
+ ! element.contains( targetToCheck )
) {
return false;
}
+ /** @type {HTMLElement|null} */
+ let elementToCheck = targetToCheck;
+
do {
if ( elementToCheck.dataset.isDropZone ) {
return elementToCheck === element;
@@ -155,11 +161,7 @@ export default function useDropZone( {
// leaving the drop zone, which means the `relatedTarget`
// (element that has been entered) should be outside the drop
// zone.
- if (
- isElementInZone(
- /** @type {HTMLElement|null} */ ( event.relatedTarget )
- )
- ) {
+ if ( isElementInZone( event.relatedTarget ) ) {
return;
}
From 599b60d2cc8b26b9bc2141305cfe5e07b23dab88 Mon Sep 17 00:00:00 2001
From: Robert Anderson
Date: Wed, 25 Aug 2021 21:00:24 +1000
Subject: [PATCH 038/214] Default batch processor: Respect the batch endpoint's
maxItems (#34280)
This updates the default batch processor to make multiple batch requests
if the number of requests to process exceeds the number of requests that
the batch endpoint can handle.
We determine the number of requests that the batch endpoint can handle
by making a preflight OPTIONS request to /batch/v1. By default it is 25
requests.
See https://make.wordpress.org/core/2020/11/20/rest-api-batch-framework-in-wordpress-5-6/.
---
.../core-data/src/batch/default-processor.js | 83 +++++++++++++------
.../src/batch/test/default-processor.js | 79 ++++++++++++------
2 files changed, 110 insertions(+), 52 deletions(-)
diff --git a/packages/core-data/src/batch/default-processor.js b/packages/core-data/src/batch/default-processor.js
index d459923218e129..34f38ff5c3d0da 100644
--- a/packages/core-data/src/batch/default-processor.js
+++ b/packages/core-data/src/batch/default-processor.js
@@ -1,10 +1,23 @@
+/**
+ * External dependencies
+ */
+import { chunk } from 'lodash';
+
/**
* WordPress dependencies
*/
import apiFetch from '@wordpress/api-fetch';
/**
- * Default batch processor. Sends its input requests to /v1/batch.
+ * Maximum number of requests to place in a single batch request. Obtained by
+ * sending a preflight OPTIONS request to /batch/v1/.
+ *
+ * @type {number?}
+ */
+let maxItems = null;
+
+/**
+ * Default batch processor. Sends its input requests to /batch/v1.
*
* @param {Array} requests List of API requests to perform at once.
*
@@ -13,33 +26,51 @@ import apiFetch from '@wordpress/api-fetch';
* (if not ).
*/
export default async function defaultProcessor( requests ) {
- const batchResponse = await apiFetch( {
- path: '/batch/v1',
- method: 'POST',
- data: {
- validation: 'require-all-validate',
- requests: requests.map( ( request ) => ( {
- path: request.path,
- body: request.data, // Rename 'data' to 'body'.
- method: request.method,
- headers: request.headers,
- } ) ),
- },
- } );
-
- if ( batchResponse.failed ) {
- return batchResponse.responses.map( ( response ) => ( {
- error: response?.body,
- } ) );
+ if ( maxItems === null ) {
+ const preflightResponse = await apiFetch( {
+ path: '/batch/v1',
+ method: 'OPTIONS',
+ } );
+ maxItems = preflightResponse.endpoints[ 0 ].args.requests.maxItems;
}
- return batchResponse.responses.map( ( response ) => {
- const result = {};
- if ( response.status >= 200 && response.status < 300 ) {
- result.output = response.body;
+ const results = [];
+
+ for ( const batchRequests of chunk( requests, maxItems ) ) {
+ const batchResponse = await apiFetch( {
+ path: '/batch/v1',
+ method: 'POST',
+ data: {
+ validation: 'require-all-validate',
+ requests: batchRequests.map( ( request ) => ( {
+ path: request.path,
+ body: request.data, // Rename 'data' to 'body'.
+ method: request.method,
+ headers: request.headers,
+ } ) ),
+ },
+ } );
+
+ let batchResults;
+
+ if ( batchResponse.failed ) {
+ batchResults = batchResponse.responses.map( ( response ) => ( {
+ error: response?.body,
+ } ) );
} else {
- result.error = response.body;
+ batchResults = batchResponse.responses.map( ( response ) => {
+ const result = {};
+ if ( response.status >= 200 && response.status < 300 ) {
+ result.output = response.body;
+ } else {
+ result.error = response.body;
+ }
+ return result;
+ } );
}
- return result;
- } );
+
+ results.push( ...batchResults );
+ }
+
+ return results;
}
diff --git a/packages/core-data/src/batch/test/default-processor.js b/packages/core-data/src/batch/test/default-processor.js
index c6d2515410b826..c712ecdff21aa5 100644
--- a/packages/core-data/src/batch/test/default-processor.js
+++ b/packages/core-data/src/batch/test/default-processor.js
@@ -11,6 +11,18 @@ import defaultProcessor from '../default-processor';
jest.mock( '@wordpress/api-fetch' );
describe( 'defaultProcessor', () => {
+ const preflightResponse = {
+ endpoints: [
+ {
+ args: {
+ requests: {
+ maxItems: 25,
+ },
+ },
+ },
+ ],
+ };
+
const requests = [
{
path: '/v1/cricketers',
@@ -26,7 +38,12 @@ describe( 'defaultProcessor', () => {
},
];
- const expectedFetchOptions = {
+ const expectedPreflightOptions = {
+ path: '/batch/v1',
+ method: 'OPTIONS',
+ };
+
+ const expectedBatchOptions = {
path: '/batch/v1',
method: 'POST',
data: {
@@ -49,21 +66,26 @@ describe( 'defaultProcessor', () => {
};
it( 'handles a successful request', async () => {
- apiFetch.mockImplementation( async () => ( {
- failed: false,
- responses: [
- {
- status: 200,
- body: 'Lyon',
- },
- {
- status: 400,
- body: 'Error!',
- },
- ],
- } ) );
+ apiFetch.mockImplementation( async ( { method } ) =>
+ method === 'OPTIONS'
+ ? preflightResponse
+ : {
+ failed: false,
+ responses: [
+ {
+ status: 200,
+ body: 'Lyon',
+ },
+ {
+ status: 400,
+ body: 'Error!',
+ },
+ ],
+ }
+ );
const results = await defaultProcessor( requests );
- expect( apiFetch ).toHaveBeenCalledWith( expectedFetchOptions );
+ expect( apiFetch ).toHaveBeenCalledWith( expectedPreflightOptions );
+ expect( apiFetch ).toHaveBeenCalledWith( expectedBatchOptions );
expect( results ).toEqual( [
{ output: 'Lyon' },
{ error: 'Error!' },
@@ -71,18 +93,23 @@ describe( 'defaultProcessor', () => {
} );
it( 'handles a failed request', async () => {
- apiFetch.mockImplementation( async () => ( {
- failed: true,
- responses: [
- null,
- {
- status: 400,
- body: 'Error!',
- },
- ],
- } ) );
+ apiFetch.mockImplementation( async ( { method } ) =>
+ method === 'OPTIONS'
+ ? preflightResponse
+ : {
+ failed: true,
+ responses: [
+ null,
+ {
+ status: 400,
+ body: 'Error!',
+ },
+ ],
+ }
+ );
const results = await defaultProcessor( requests );
- expect( apiFetch ).toHaveBeenCalledWith( expectedFetchOptions );
+ expect( apiFetch ).toHaveBeenCalledWith( expectedPreflightOptions );
+ expect( apiFetch ).toHaveBeenCalledWith( expectedBatchOptions );
expect( results ).toEqual( [
{ error: undefined },
{ error: 'Error!' },
From 60d907bc33fcbd47235b8e141909b368966c7995 Mon Sep 17 00:00:00 2001
From: Addison Stavlo
Date: Wed, 25 Aug 2021 08:55:47 -0400
Subject: [PATCH 039/214] Block Toolbar & Popover component - Prevent sticky
position from causing permanently obscured areas of the selected block.
(#33981)
* try using next block as anchor
* place popover below block if available when sticky
* if starts at bottom of block, keep there
* fix edge cases
* add bottom sticky position
* fix jumpy bug on using toolbar
* revert to default behavior as soon as there is room. no bottom sticky necessary
* refactor logic and comment
* remove unnecessary else
* gross selectors
* pass content wrapper through to popover as prop
* minor refactor
* use bottom sticky if necessary
* update names, comments, JSDocs
* add basic store tests
* remove store goo
* use the contentRef
* Update packages/block-editor/src/components/block-tools/block-popover.js
---
.../components/block-tools/block-popover.js | 3 +
packages/components/src/popover/index.js | 4 +-
packages/components/src/popover/utils.js | 99 ++++++++++++-------
3 files changed, 71 insertions(+), 35 deletions(-)
diff --git a/packages/block-editor/src/components/block-tools/block-popover.js b/packages/block-editor/src/components/block-tools/block-popover.js
index 8371cfff9bbba8..59d9ae24a71d3a 100644
--- a/packages/block-editor/src/components/block-tools/block-popover.js
+++ b/packages/block-editor/src/components/block-tools/block-popover.js
@@ -213,6 +213,9 @@ function BlockPopover( {
// Observe movement for block animations (especially horizontal).
__unstableObserveElement={ node }
shouldAnchorIncludePadding
+ // Used to safeguard sticky position behavior against cases where it would permanently
+ // obscure specific sections of a block.
+ __unstableEditorCanvasWrapper={ __unstableContentRef?.current }
>
{ ( shouldShowContextualToolbar || isToolbarForced ) && (
Date: Wed, 25 Aug 2021 13:49:20 +0000
Subject: [PATCH 040/214] Editor package: Replace hardcoded store key (#34296)
---
packages/editor/src/components/local-autosave-monitor/index.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/editor/src/components/local-autosave-monitor/index.js b/packages/editor/src/components/local-autosave-monitor/index.js
index 4587ec7611acef..b406a2545cf395 100644
--- a/packages/editor/src/components/local-autosave-monitor/index.js
+++ b/packages/editor/src/components/local-autosave-monitor/index.js
@@ -56,7 +56,7 @@ function useAutosaveNotice() {
} ),
[]
);
- const { getEditedPostAttribute } = useSelect( 'core/editor' );
+ const { getEditedPostAttribute } = useSelect( editorStore );
const { createWarningNotice, removeNotice } = useDispatch( noticesStore );
const { editPost, resetEditorBlocks } = useDispatch( editorStore );
From 3cc2b1730d16e06ac79b02526d77e6a74816999f Mon Sep 17 00:00:00 2001
From: Jason Johnston
Date: Wed, 25 Aug 2021 12:45:53 -0400
Subject: [PATCH 041/214] [RNMobile] Full screen block inserter menu for
Android (#34129)
* Use flexbox for tab positioning
* Allow bottomsheet to scroll while fullscreen
Changes cherry picked from https://github.com/WordPress/gutenberg/pull/34018/commits/c5aa56cd31b6abbd96cf1bc76d13b54189b078d3
* Fix input height
* Fix active search cut off
* Use fullscreen on Android only
* Add prop to allow drag indicator on Android
* Pass in initial number of items to render
* Update logic to show the drag indicator
* Fix block inserter scroll view height (#34139)
* Fix block inserter scroll view height
Leverages flex layout properties rather than explicit height to ensure
the scroll view coordinates its height with its sibling elements.
* Rename Sass selectors for improved clarity
Avoid referencing "tabs" as that is not relevant as this level of the
UI.
* Enable inserter block search
* Fix revert issue
* Blur inserter search when keyboard closes (#34278)
Co-authored-by: jhnstn
* Filter embed blocks from Inserter search block list
Co-authored-by: jhnstn
Co-authored-by: David Calhoun <438664+dcalhoun@users.noreply.github.com>
---
.../block-types-list/index.native.js | 10 ++++++++--
.../src/components/inserter/menu.native.js | 14 +++++++++++---
.../inserter/search-results.native.js | 19 ++++++++++++++++++-
.../src/components/inserter/style.native.scss | 13 ++++++++-----
.../src/components/inserter/tabs.native.js | 8 +-------
.../src/mobile/bottom-sheet/index.native.js | 12 +++++++++++-
.../src/search-control/index.native.js | 17 ++++++++++++-----
.../platform-style.android.scss | 5 +----
.../search-control/platform-style.ios.scss | 3 ---
.../src/search-control/style.native.scss | 4 +---
10 files changed, 71 insertions(+), 34 deletions(-)
diff --git a/packages/block-editor/src/components/block-types-list/index.native.js b/packages/block-editor/src/components/block-types-list/index.native.js
index 485cde15fbf1fa..81795d37e87789 100644
--- a/packages/block-editor/src/components/block-types-list/index.native.js
+++ b/packages/block-editor/src/components/block-types-list/index.native.js
@@ -22,7 +22,13 @@ import styles from './style.scss';
const MIN_COL_NUM = 3;
-export default function BlockTypesList( { name, items, onSelect, listProps } ) {
+export default function BlockTypesList( {
+ name,
+ items,
+ onSelect,
+ listProps,
+ initialNumToRender = 3,
+} ) {
const [ numberOfColumns, setNumberOfColumns ] = useState( MIN_COL_NUM );
const [ itemWidth, setItemWidth ] = useState();
const [ maxWidth, setMaxWidth ] = useState();
@@ -81,7 +87,7 @@ export default function BlockTypesList( { name, items, onSelect, listProps } ) {
keyboardShouldPersistTaps="always"
numColumns={ numberOfColumns }
data={ items }
- initialNumToRender={ 3 }
+ initialNumToRender={ initialNumToRender }
ItemSeparatorComponent={ () => (
{ ( { listProps } ) => (
-
+
{ ! showTabs || filterValue ? (
) : (
{
const allItems = select( blockEditorStore ).getInserterItems(
rootClientId
);
- const filteredItems = searchItems( allItems, filterValue );
+
+ const blockItems = allItems.filter(
+ ( { id, category } ) =>
+ ! NON_BLOCK_CATEGORIES.includes( category ) &&
+ // We don't want to show all possible embed variations
+ // as different blocks in the inserter. We'll only show a
+ // few popular ones.
+ ( category !== 'embed' ||
+ ( category === 'embed' &&
+ ALLOWED_EMBED_VARIATIONS.includes( id ) ) )
+ );
+
+ const filteredItems = searchItems( blockItems, filterValue );
return { blockTypes: filteredItems };
},
@@ -46,6 +62,7 @@ function InserterSearchResults( {
return (
);
diff --git a/packages/block-editor/src/components/inserter/style.native.scss b/packages/block-editor/src/components/inserter/style.native.scss
index 8fcb9c1cd04529..105af1f72b7d91 100644
--- a/packages/block-editor/src/components/inserter/style.native.scss
+++ b/packages/block-editor/src/components/inserter/style.native.scss
@@ -8,7 +8,11 @@
color: $blue-30;
}
-.list {
+.inserter-menu__list-wrapper {
+ flex: 1;
+}
+
+.inserter-menu__list {
padding-bottom: 20;
padding-top: 8;
}
@@ -51,13 +55,12 @@
.inserter-tabs__wrapper {
overflow: hidden;
+ flex: 1;
}
.inserter-tabs__container {
height: 100%;
width: 100%;
-}
-
-.inserter-tabs__item {
- position: absolute;
+ flex: 1;
+ flex-direction: row;
}
diff --git a/packages/block-editor/src/components/inserter/tabs.native.js b/packages/block-editor/src/components/inserter/tabs.native.js
index 06ab3bc859036e..73396ec63a6e9a 100644
--- a/packages/block-editor/src/components/inserter/tabs.native.js
+++ b/packages/block-editor/src/components/inserter/tabs.native.js
@@ -100,13 +100,7 @@ function InserterTabs( {
>
{ tabs.map( ( { component: TabComponent }, index ) => (
-
+
);
+ const showDragIndicator = () => {
+ // if iOS or not fullscreen show the drag indicator
+ if ( Platform.OS === 'ios' || ! this.state.isFullScreen ) {
+ return true;
+ }
+
+ // Otherwise check the allowDragIndicator
+ return this.props.allowDragIndicator;
+ };
+
return (
- { ! ( Platform.OS === 'android' && isFullScreen ) && (
+ { showDragIndicator() && (
) }
{ ! hideHeader && getHeader() }
diff --git a/packages/components/src/search-control/index.native.js b/packages/components/src/search-control/index.native.js
index 61241f77fb810b..6797c0c6a0bd95 100644
--- a/packages/components/src/search-control/index.native.js
+++ b/packages/components/src/search-control/index.native.js
@@ -8,6 +8,7 @@ import {
TouchableOpacity,
Platform,
useColorScheme,
+ Keyboard,
} from 'react-native';
/**
@@ -116,12 +117,18 @@ function SearchControl( {
setCurrentStyles( futureStyles );
}, [ isActive, isDark ] );
- useEffect(
- () => () => {
+ useEffect( () => {
+ const keyboardHideSubscription = Keyboard.addListener(
+ 'keyboardDidHide',
+ () => {
+ onCancel();
+ }
+ );
+ return () => {
clearTimeout( onCancelTimer.current );
- },
- []
- );
+ keyboardHideSubscription.remove();
+ };
+ }, [] );
const {
'search-control__container': containerStyle,
diff --git a/packages/components/src/search-control/platform-style.android.scss b/packages/components/src/search-control/platform-style.android.scss
index 1d774af4009000..f357c7a4e52fc9 100644
--- a/packages/components/src/search-control/platform-style.android.scss
+++ b/packages/components/src/search-control/platform-style.android.scss
@@ -1,10 +1,7 @@
-.search-control__container {
- height: 40px;
-}
-
.search-control__container--active {
border-bottom-color: $light-gray-500;
border-bottom-width: 1px;
+ margin-bottom: 0;
margin-left: 0;
margin-right: 0;
border-radius: 0;
diff --git a/packages/components/src/search-control/platform-style.ios.scss b/packages/components/src/search-control/platform-style.ios.scss
index f083df3e248ff4..34884b11b51bcd 100644
--- a/packages/components/src/search-control/platform-style.ios.scss
+++ b/packages/components/src/search-control/platform-style.ios.scss
@@ -1,6 +1,3 @@
-.search-control__container {
- height: 40px;
-}
.search-control__container--active {
margin-right: 0;
}
diff --git a/packages/components/src/search-control/style.native.scss b/packages/components/src/search-control/style.native.scss
index 18f2b7490719ae..5cac32eddd4a72 100644
--- a/packages/components/src/search-control/style.native.scss
+++ b/packages/components/src/search-control/style.native.scss
@@ -1,8 +1,6 @@
.search-control__container {
- height: 46px;
+ height: 48px;
margin: 0 16px $grid-unit-10;
- flex-direction: row;
- justify-content: space-between;
}
.search-control__inner-container {
From 3f2593fbfd61aff7bdbc2d177994c3b562f92bcc Mon Sep 17 00:00:00 2001
From: Vicente Canales <1157901+vcanales@users.noreply.github.com>
Date: Wed, 25 Aug 2021 16:53:36 -0400
Subject: [PATCH 042/214] add example for debugging e2e tests on vscode
(#29788)
---
.vscode/launch-example.json | 19 ++++++++++-
packages/e2e-tests/README.md | 62 ++++++++++++++++++++++++++++++++++++
2 files changed, 80 insertions(+), 1 deletion(-)
diff --git a/.vscode/launch-example.json b/.vscode/launch-example.json
index 3e333f450a0013..67b7a8859eb208 100644
--- a/.vscode/launch-example.json
+++ b/.vscode/launch-example.json
@@ -9,6 +9,23 @@
"pathMappings": {
"/var/www/html/wp-content/plugins/gutenberg": "${workspaceRoot}/"
}
+ },
+ {
+ "type": "node",
+ "request": "launch",
+ "name": "Debug current e2e test",
+ "program": "${workspaceRoot}/node_modules/@wordpress/scripts/bin/wp-scripts.js",
+ "args": [
+ "test-e2e",
+ "--config=${workspaceRoot}/packages/e2e-tests/jest.config.js",
+ "--verbose=true",
+ "--runInBand",
+ "--watch",
+ "${file}"
+ ],
+ "console": "integratedTerminal",
+ "internalConsoleOptions": "neverOpen",
+ "trace": "all"
}
]
-}
\ No newline at end of file
+}
diff --git a/packages/e2e-tests/README.md b/packages/e2e-tests/README.md
index a322b2e40cc489..5c24e95f8a62d6 100644
--- a/packages/e2e-tests/README.md
+++ b/packages/e2e-tests/README.md
@@ -10,6 +10,68 @@ Install the module
npm install @wordpress/e2e-tests --save-dev
```
+## Running tests
+
+The following commands are available on the Gutenberg repo:
+
+```json
+{
+ "test-e2e": "wp-scripts test-e2e --config packages/e2e-tests/jest.config.js",
+ "test-e2e:debug": "wp-scripts --inspect-brk test-e2e --config packages/e2e-tests/jest.config.js --puppeteer-devtools",
+ "test-e2e:watch": "npm run test-e2e -- --watch",
+}
+```
+
+### Run all available tests
+```bash
+npm run test-e2e
+```
+### Run all available tests and listen for changes.
+```bash
+npm run test-e2e:watch
+```
+
+### Run a specific test file
+```bash
+npm run test-e2e -- packages/e2e-test/
+# Or, in order to watch for changes:
+npm run test-e2e:watch -- packages/e2e-test/
+```
+### Debugging
+
+Makes e2e tests available to debug in a Chrome Browser.
+```bash
+npm run test-e2e:debug
+```
+After running the command, tests will be available for debugging in Chrome by going to chrome://inspect/#devices and clicking `inspect` under the path to `/test-e2e.js`.
+
+#### Debugging in `vscode`
+
+Debugging in a Chrome browser can be replaced with `vscode`'s debugger by adding the following configuration to `.vscode/launch.json`:
+
+```json
+{
+ "type": "node",
+ "request": "launch",
+ "name": "Debug current e2e test",
+ "program": "${workspaceRoot}/node_modules/@wordpress/scripts/bin/wp-scripts.js",
+ "args": [
+ "test-e2e",
+ "--config=${workspaceRoot}/packages/e2e-tests/jest.config.js",
+ "--verbose=true",
+ "--runInBand",
+ "--watch",
+ "${file}"
+ ],
+ "console": "integratedTerminal",
+ "internalConsoleOptions": "neverOpen",
+ "trace": "all"
+ }
+```
+
+This will run jest, targetting the spec file currently open in the editor. `vscode`'s debugger can now be used to add breakpoints and inspect tests as you would in Chrome DevTools.
+
+
**Note**: This package requires Node.js 12.0.0 or later. It is not compatible with older versions.
From fe7c73d7a081db2bd27dc6f2e22af87e4b7a8cf2 Mon Sep 17 00:00:00 2001
From: Joen A <1204802+jasmussen@users.noreply.github.com>
Date: Thu, 26 Aug 2021 10:21:20 +0200
Subject: [PATCH 043/214] Refactor navigation block to use generic classnames.
(#34171)
* Refactor navigation block to use generic classnames.
* Address feedback.
---
packages/base-styles/_z-index.scss | 4 +-
.../src/navigation-link/editor.scss | 20 ++--
.../block-library/src/navigation/editor.scss | 6 +-
.../block-library/src/navigation/style.scss | 106 ++++++------------
.../block-library/src/page-list/style.scss | 2 +-
.../src/components/editor/style.scss | 20 ++--
6 files changed, 61 insertions(+), 97 deletions(-)
diff --git a/packages/base-styles/_z-index.scss b/packages/base-styles/_z-index.scss
index de9ec9d6917e56..5b7ddc1a0f0e14 100644
--- a/packages/base-styles/_z-index.scss
+++ b/packages/base-styles/_z-index.scss
@@ -43,8 +43,8 @@ $z-layers: (
".wp-block-template-part__placeholder-preview-filter-input": 1,
// Navigation menu dropdown.
- ".has-child .wp-block-navigation-link__container": 28,
- ".has-child:hover .wp-block-navigation-link__container": 29,
+ ".has-child .wp-block-navigation__submenu-container": 28,
+ ".has-child:hover .wp-block-navigation__submenu-container": 29,
// Active pill button
".components-button {:focus or .is-primary}": 1,
diff --git a/packages/block-library/src/navigation-link/editor.scss b/packages/block-library/src/navigation-link/editor.scss
index a720088d055dd8..e11e9c949381c3 100644
--- a/packages/block-library/src/navigation-link/editor.scss
+++ b/packages/block-library/src/navigation-link/editor.scss
@@ -1,5 +1,5 @@
// Normalize Link and edit containers, to look mostly the same.
-.wp-block-navigation-link__container {
+.wp-block-navigation__submenu-container {
border-radius: 0;
// Make it the same height as the appender to prevent a jump.
@@ -15,22 +15,20 @@
.wp-block-navigation .has-child {
cursor: pointer;
- .submenu-container,
- .wp-block-navigation-link__container {
- z-index: z-index(".has-child .wp-block-navigation-link__container");
+ .wp-block-navigation__submenu-container {
+ z-index: z-index(".has-child .wp-block-navigation__submenu-container");
}
&:hover {
- .submenu-container,
- .wp-block-navigation-link__container {
- z-index: z-index(".has-child:hover .wp-block-navigation-link__container");
+ .wp-block-navigation__submenu-container {
+ z-index: z-index(".has-child:hover .wp-block-navigation__submenu-container");
}
}
// Show on editor selected, even if on frontend it only stays open on focus-within.
&.is-selected,
&.has-child-selected {
- > .wp-block-navigation-link__container {
+ > .wp-block-navigation__submenu-container {
// We use important here because if the parent block is selected and submenus are present, they should always be visible.
visibility: visible !important;
opacity: 1 !important;
@@ -44,11 +42,11 @@
*/
.wp-block-navigation-link {
- .wp-block-navigation-link__container {
+ .wp-block-navigation__submenu-container {
display: block;
}
- .wp-block-navigation-link__content {
+ .wp-block-navigation-item__content {
cursor: text;
}
@@ -96,7 +94,7 @@
}
// This needs extra specificity.
- &.wp-block-navigation-link__content {
+ &.wp-block-navigation-item__content {
cursor: pointer;
}
}
diff --git a/packages/block-library/src/navigation/editor.scss b/packages/block-library/src/navigation/editor.scss
index fff28e42151ab9..47fa26ce4920cc 100644
--- a/packages/block-library/src/navigation/editor.scss
+++ b/packages/block-library/src/navigation/editor.scss
@@ -37,7 +37,7 @@
// Only show the flyout on hover if the parent menu item is selected.
.wp-block-navigation:not(.is-selected):not(.has-child-selected) .has-child:hover {
- > .wp-block-navigation-link__container {
+ > .wp-block-navigation__submenu-container {
opacity: 0;
visibility: hidden;
}
@@ -47,7 +47,7 @@
.has-child {
&.is-selected,
&.has-child-selected {
- > .wp-block-navigation-link__container {
+ > .wp-block-navigation__submenu-container {
display: flex;
opacity: 1;
visibility: visible;
@@ -58,7 +58,7 @@
// Show a submenu when generally dragging (is-dragging-components-draggable) if that
// submenu has children (has-child) and is being dragged within (is-dragging-within).
.is-dragging-components-draggable .has-child.is-dragging-within {
- > .wp-block-navigation-link__container {
+ > .wp-block-navigation__submenu-container {
opacity: 1;
visibility: visible;
}
diff --git a/packages/block-library/src/navigation/style.scss b/packages/block-library/src/navigation/style.scss
index b37e4dbd0244f4..59edade44dcfa3 100644
--- a/packages/block-library/src/navigation/style.scss
+++ b/packages/block-library/src/navigation/style.scss
@@ -1,8 +1,11 @@
// Navigation block and menu item styles.
-// This also styles navigation links inside the Page List block,
-// as that block is meant to behave as menu items when leveraged.
-// The CSS lives here so that it is output even if you only use a
-// Page List block inside your navigation block.
+// These styles also affect the Page List block when used inside your navigation block.
+//
+// Classes:
+// - .wp-block-navigation__submenu-container targets submenu containers.
+// - .wp-block-navigation-item targets the menu item itself.
+// - .wp-block-navigation-item__content targets the link inside a menu item.
+// - .wp-block-navigation__submenu-icon targets the chevron icon indicating submenus.
.wp-block-navigation {
position: relative;
@@ -27,13 +30,12 @@
}
// Menu item container.
- .wp-block-pages-list__item,
- .wp-block-navigation-link {
+ .wp-block-navigation-item {
display: flex;
align-items: center;
position: relative;
- .wp-block-navigation-link__container:empty {
+ .wp-block-navigation__submenu-container:empty {
display: none;
}
}
@@ -50,9 +52,8 @@
// Force links to inherit text decoration applied to navigation block.
// The extra selector adds specificity to ensure it works when user-set.
&[style*="text-decoration"] {
- .wp-block-pages-list__item,
- .wp-block-navigation-link__container,
- .wp-block-navigation-link {
+ .wp-block-navigation-item,
+ .wp-block-navigation__submenu-container {
text-decoration: inherit;
}
@@ -78,8 +79,7 @@
}
// Submenu indicator.
- .wp-block-page-list__submenu-icon,
- .wp-block-navigation-link__submenu-icon {
+ .wp-block-navigation__submenu-icon {
align-self: center;
height: inherit;
line-height: 0;
@@ -99,7 +99,7 @@
// We use :where to keep specificity minimal, yet still scope it to only the navigation block.
// That way if padding is set in theme.json, it still wins.
// https://css-tricks.com/almanac/selectors/w/where/
- :where(.submenu-container, .wp-block-navigation-link__container) {
+ :where(.wp-block-navigation__submenu-container) {
background-color: inherit;
color: inherit;
position: absolute;
@@ -115,15 +115,13 @@
visibility: hidden;
// Submenu items.
- > .wp-block-pages-list__item,
- > .wp-block-navigation-link {
+ > .wp-block-navigation-item {
> a {
display: flex;
flex-grow: 1;
// Right-align the chevron in submenus.
- .wp-block-page-list__submenu-icon,
- .wp-block-navigation-link__submenu-icon {
+ .wp-block-navigation__submenu-icon {
margin-right: 0;
margin-left: auto;
}
@@ -143,8 +141,7 @@
// Nested submenus sit to the left on large breakpoints.
// On smaller breakpoints, they open vertically, accordion-style.
@include break-medium {
- .submenu-container,
- .wp-block-navigation-link__container {
+ .wp-block-navigation__submenu-container {
left: 100%;
top: -1px; // Border width.
@@ -161,8 +158,7 @@
}
// Reset the submenu indicator for horizontal flyouts.
- .wp-block-page-list__submenu-icon svg,
- .wp-block-navigation-link__submenu-icon svg {
+ .wp-block-navigation__submenu-icon svg {
transform: rotate(-90deg);
}
}
@@ -174,47 +170,26 @@
// Custom menu items.
// Show submenus on hover.
- &:hover > .wp-block-navigation-link__container {
+ &:hover > .wp-block-navigation__submenu-container {
visibility: visible;
opacity: 1;
}
// Keep submenus open when focus is within.
- &:focus-within > .wp-block-navigation-link__container {
+ &:focus-within > .wp-block-navigation__submenu-container {
visibility: visible;
opacity: 1;
}
-
- // Page list menu items.
- &:hover {
- cursor: pointer;
-
- > .submenu-container {
- visibility: visible;
- opacity: 1;
- }
- }
-
- &:focus-within {
- cursor: pointer;
-
- > .submenu-container {
- visibility: visible;
- opacity: 1;
- }
- }
}
// Submenu indentation when there's a background.
-.wp-block-navigation.has-background .has-child .submenu-container,
-.wp-block-navigation.has-background .has-child .wp-block-navigation-link__container {
+.wp-block-navigation.has-background .has-child .wp-block-navigation__submenu-container {
left: 0;
top: 100%;
// There's no border on submenus when there are backgrounds.
@include break-medium {
- .submenu-container,
- .wp-block-navigation-link__container {
+ .wp-block-navigation__submenu-container {
left: 100%;
top: 0;
}
@@ -229,8 +204,8 @@
// Menu items with no background.
.wp-block-page-list,
-.wp-block-page-list > .wp-block-pages-list__item,
-.wp-block-navigation__container > .wp-block-navigation-link {
+.wp-block-page-list > .wp-block-navigation-item,
+.wp-block-navigation__container > .wp-block-navigation-item {
margin: 0 2em 0 0;
// Margin of right-most margin should be zero, for right aligned or justified items.
@@ -245,8 +220,8 @@
// https://css-tricks.com/almanac/selectors/w/where/
.wp-block-navigation:where(.has-background) {
.wp-block-page-list,
- .wp-block-page-list > .wp-block-pages-list__item,
- .wp-block-navigation__container > .wp-block-navigation-link {
+ .wp-block-page-list > .wp-block-navigation-item,
+ .wp-block-navigation__container > .wp-block-navigation-item {
margin: 0 0.5em 0 0;
// Don't show right margin on the last child.
@@ -277,7 +252,7 @@
}
// Provide a default padding for submenus who should always have some, regardless of the top level menu items.
-.wp-block-navigation :where(.submenu-container, .wp-block-navigation-link__container) a {
+.wp-block-navigation :where(.wp-block-navigation__submenu-container) a {
padding: 0.5em 1em;
}
@@ -295,14 +270,12 @@
.wp-block-navigation.items-justified-right > .wp-block-navigation__container .has-child {
// First submenu.
- .submenu-container,
- .wp-block-navigation-link__container {
+ .wp-block-navigation__submenu-container {
left: auto;
right: 0;
// Nested submenus.
- .submenu-container,
- .wp-block-navigation-link__container {
+ .wp-block-navigation__submenu-container {
left: auto;
right: 100%;
}
@@ -311,8 +284,7 @@
// Default background and font color.
.wp-block-navigation:not(.has-background) {
- .submenu-container, // This target items created by the Page List block.
- .wp-block-navigation__container .wp-block-navigation-link__container {
+ .wp-block-navigation__submenu-container {
// Set a background color for submenus so that they're not transparent.
// NOTE TO DEVS - if refactoring this code, please double-check that
// submenus have a default background color, this feature has regressed
@@ -374,8 +346,7 @@
.is-vertical.items-justified-right > ul {
align-items: flex-end;
- .wp-block-navigation-link,
- .wp-block-pages-list__item {
+ .wp-block-navigation-item {
margin-right: 0;
justify-content: flex-end;
}
@@ -432,10 +403,8 @@
// Remove background colors for items inside the overlay menu.
// Has to be !important to override global styles.
// @todo: We should revisit this so that the overlay colors can be applied, instead of the background.
- .wp-block-pages-list__item .submenu-container,
- .wp-block-navigation-link .wp-block-navigation-link__container,
- .wp-block-pages-list__item,
- .wp-block-navigation-link {
+ .wp-block-navigation-item .wp-block-navigation__submenu-container,
+ .wp-block-navigation-item {
color: inherit !important;
background: transparent !important;
}
@@ -456,8 +425,7 @@
&.is-menu-open {
// Override breakpoint-inherited submenu rules.
- .submenu-container.submenu-container.submenu-container.submenu-container,
- .wp-block-navigation-link__container.wp-block-navigation-link__container.wp-block-navigation-link__container.wp-block-navigation-link__container {
+ .wp-block-navigation__submenu-container.wp-block-navigation__submenu-container.wp-block-navigation__submenu-container.wp-block-navigation__submenu-container {
left: 0;
}
}
@@ -537,13 +505,12 @@
// Always show submenus fully expanded inside the modal menu.
.wp-block-navigation .wp-block-navigation__responsive-container.is-menu-open {
- .wp-block-page-list__submenu-icon,
- .wp-block-navigation-link__submenu-icon {
+ .wp-block-navigation__submenu-icon {
display: none;
}
.has-child .submenu-container,
- .has-child .wp-block-navigation-link__container {
+ .has-child .wp-block-navigation__submenu-container {
position: relative;
opacity: 1;
visibility: visible;
@@ -552,8 +519,7 @@
border: none;
}
- .wp-block-navigation-link,
- .wp-block-pages-list__item {
+ .wp-block-navigation-item {
flex-direction: column;
align-items: flex-start;
}
diff --git a/packages/block-library/src/page-list/style.scss b/packages/block-library/src/page-list/style.scss
index 8b2355c8f97403..806c075319eaac 100644
--- a/packages/block-library/src/page-list/style.scss
+++ b/packages/block-library/src/page-list/style.scss
@@ -8,7 +8,7 @@
// Menu items generated by the page list do not get `has-[x]-background-color`,
// and must therefore inherit from the parent.
- .wp-block-pages-list__item {
+ .wp-block-navigation-item {
background-color: inherit;
}
diff --git a/packages/edit-navigation/src/components/editor/style.scss b/packages/edit-navigation/src/components/editor/style.scss
index eaa1ae7e3221e4..74077954e1dc35 100644
--- a/packages/edit-navigation/src/components/editor/style.scss
+++ b/packages/edit-navigation/src/components/editor/style.scss
@@ -34,7 +34,7 @@
display: block;
// Show submenus on click.
- > .wp-block-navigation-link__container {
+ > .wp-block-navigation__submenu-container {
// This unsets some styles inherited from the block, meant to only show submenus on click, not hover, when inside the editor.
opacity: 1;
visibility: visible;
@@ -44,8 +44,8 @@
}
// Fix focus outlines.
- &.is-selected > .wp-block-navigation-link__content,
- &.is-selected:hover > .wp-block-navigation-link__content {
+ &.is-selected > .wp-block-navigation-item__content,
+ &.is-selected:hover > .wp-block-navigation-item__content {
box-shadow: 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
}
@@ -59,7 +59,7 @@
margin-right: 0;
}
- .wp-block-navigation-link__content.wp-block-navigation-link__content.wp-block-navigation-link__content {
+ .wp-block-navigation-item__content.wp-block-navigation-item__content.wp-block-navigation-item__content {
padding: 0.5em 1em;
margin-bottom: 6px;
margin-right: 0;
@@ -91,7 +91,7 @@
pointer-events: none;
margin-right: 0;
- .wp-block-pages-list__item {
+ .wp-block-navigation-item {
color: $gray-700;
margin-bottom: 6px;
border-radius: $radius-block-ui;
@@ -101,7 +101,7 @@
}
// Submenu icon indicator.
- .wp-block-navigation-link__submenu-icon {
+ .wp-block-navigation__submenu-icon {
position: absolute;
top: 6px;
left: 0;
@@ -118,8 +118,8 @@
}
// Point downwards when open.
- .is-selected.has-child > .wp-block-navigation-link__submenu-icon svg,
- .has-child-selected.has-child > .wp-block-navigation-link__submenu-icon svg {
+ .is-selected.has-child > .wp-block-navigation__submenu-icon svg,
+ .has-child-selected.has-child > .wp-block-navigation__submenu-icon svg {
transform: rotate(0deg);
}
@@ -131,7 +131,7 @@
// Override for deeply nested submenus.
.has-child .wp-block-navigation__container .wp-block-navigation__container,
- .has-child .wp-block-navigation__container .wp-block-navigation-link__container {
+ .has-child .wp-block-navigation__container .wp-block-navigation__submenu-container {
left: auto;
}
@@ -139,7 +139,7 @@
// and adjust the spacing and submenu icon.
.wp-block-navigation-link.has-child.is-editing {
> .wp-block-navigation__container,
- > .wp-block-navigation-link__container {
+ > .wp-block-navigation__submenu-container {
opacity: 1;
visibility: visible;
position: relative;
From d8808e866ff760766c9eacbeb347c769fd7659ae Mon Sep 17 00:00:00 2001
From: George Mamadashvili
Date: Thu, 26 Aug 2021 08:55:14 +0000
Subject: [PATCH 044/214] ESLint: Add useSelect to direct function calls list
(#34301)
* ESLint: Add useSelect to direct function calls list
* Fix remaining error
* Fix store variable names
---
.../header/document-actions/index.js | 2 +-
.../data-no-store-string-literals.js | 30 ++++++++++---------
.../rules/data-no-store-string-literals.js | 10 +++++--
3 files changed, 24 insertions(+), 18 deletions(-)
diff --git a/packages/edit-site/src/components/header/document-actions/index.js b/packages/edit-site/src/components/header/document-actions/index.js
index fc9f592215df43..1844f198000b68 100644
--- a/packages/edit-site/src/components/header/document-actions/index.js
+++ b/packages/edit-site/src/components/header/document-actions/index.js
@@ -29,7 +29,7 @@ function getBlockDisplayText( block ) {
}
function useSecondaryText() {
- const { getBlock } = useSelect( 'core/block-editor' );
+ const { getBlock } = useSelect( blockEditorStore );
const activeEntityBlockId = useSelect(
( select ) =>
select(
diff --git a/packages/eslint-plugin/rules/__tests__/data-no-store-string-literals.js b/packages/eslint-plugin/rules/__tests__/data-no-store-string-literals.js
index ac74c7800a50a4..f7581ac0b14105 100644
--- a/packages/eslint-plugin/rules/__tests__/data-no-store-string-literals.js
+++ b/packages/eslint-plugin/rules/__tests__/data-no-store-string-literals.js
@@ -17,24 +17,25 @@ const ruleTester = new RuleTester( {
const valid = [
// Callback functions
- `import { createRegistrySelector } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; createRegistrySelector(( select ) => { select(store); });`,
- `import { useSelect } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; useSelect(( select ) => { select(store); });`,
- `import { withSelect } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; withSelect(( select ) => { select(store); });`,
- `import { withDispatch } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; withDispatch(( select ) => { select(store); });`,
- `import { withDispatch as withDispatchAlias } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; withDispatchAlias(( select ) => { select(store); });`,
+ `import { createRegistrySelector } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; createRegistrySelector(( select ) => { select(coreStore); });`,
+ `import { useSelect } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; useSelect(( select ) => { select(coreStore); });`,
+ `import { withSelect } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; withSelect(( select ) => { select(coreStore); });`,
+ `import { withDispatch } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; withDispatch(( select ) => { select(coreStore); });`,
+ `import { withDispatch as withDispatchAlias } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; withDispatchAlias(( select ) => { select(coreStore); });`,
// Direct function calls
- `import { useDispatch } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; useDispatch( store );`,
- `import { dispatch } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; dispatch( store );`,
- `import { select } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; select( store );`,
- `import { resolveSelect } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; resolveSelect( store );`,
- `import { resolveSelect as resolveSelectAlias } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; resolveSelectAlias( store );`,
+ `import { useDispatch } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; useDispatch( coreStore );`,
+ `import { dispatch } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; dispatch( coreStore );`,
+ `import { useSelect } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; useSelect( coreStore );`,
+ `import { select } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; select( coreStore );`,
+ `import { resolveSelect } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; resolveSelect( coreStore );`,
+ `import { resolveSelect as resolveSelectAlias } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; resolveSelectAlias( coreStore );`,
// Object property function calls
- `import { controls } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; controls.select( store );`,
- `import { controls } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; controls.dispatch( store );`,
- `import { controls } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; controls.resolveSelect( store );`,
- `import { controls as controlsAlias } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; controlsAlias.resolveSelect( store );`,
+ `import { controls } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; controls.select( coreStore );`,
+ `import { controls } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; controls.dispatch( coreStore );`,
+ `import { controls } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; controls.resolveSelect( coreStore );`,
+ `import { controls as controlsAlias } from '@wordpress/data'; import { store as coreStore } from '@wordpress/core-data'; controlsAlias.resolveSelect( coreStore );`,
];
const createSuggestionTestCase = ( code, output ) => ( {
@@ -63,6 +64,7 @@ const invalid = [
// Direct function calls
`import { useDispatch } from '@wordpress/data'; useDispatch( 'core' );`,
`import { dispatch } from '@wordpress/data'; dispatch( 'core' );`,
+ `import { useSelect } from '@wordpress/data'; useSelect( 'core' );`,
`import { select } from '@wordpress/data'; select( 'core' );`,
`import { resolveSelect } from '@wordpress/data'; resolveSelect( 'core' );`,
`import { resolveSelect as resolveSelectAlias } from '@wordpress/data'; resolveSelectAlias( 'core' );`,
diff --git a/packages/eslint-plugin/rules/data-no-store-string-literals.js b/packages/eslint-plugin/rules/data-no-store-string-literals.js
index 72dfc97654f2a2..805a9cc6bd610b 100644
--- a/packages/eslint-plugin/rules/data-no-store-string-literals.js
+++ b/packages/eslint-plugin/rules/data-no-store-string-literals.js
@@ -78,9 +78,13 @@ function collectAllNodesFromDirectFunctionCalls( context, node ) {
const specifiers = node.specifiers.filter(
( specifier ) =>
specifier.imported &&
- [ 'useDispatch', 'dispatch', 'select', 'resolveSelect' ].includes(
- specifier.imported.name
- )
+ [
+ 'useDispatch',
+ 'dispatch',
+ 'useSelect',
+ 'select',
+ 'resolveSelect',
+ ].includes( specifier.imported.name )
);
const references = getReferences( context, specifiers );
const possibleCallExpressionNodes = references
From 39806aa26f55b8b1ea246fcf56ba8afe7541bf64 Mon Sep 17 00:00:00 2001
From: Riad Benguella
Date: Thu, 26 Aug 2021 10:06:32 +0100
Subject: [PATCH 045/214] Improve the getBlock and getBlocks performance
(#34241)
---
.../data/data-core-block-editor.md | 8 +-
.../block-list/block-list-item.native.js | 9 +-
.../src/components/block-list/block.native.js | 4 +-
.../components/block-tools/block-popover.js | 5 +-
.../block-tools/block-selection-button.js | 6 +-
.../src/components/rich-text/index.native.js | 5 +-
packages/block-editor/src/store/actions.js | 2 +
packages/block-editor/src/store/reducer.js | 353 +++++++++++-------
packages/block-editor/src/store/selectors.js | 117 +-----
.../block-editor/src/store/test/reducer.js | 230 +++++++-----
.../block-editor/src/store/test/selectors.js | 249 +++++-------
.../convert-to-regular.js | 10 +-
packages/editor/src/store/selectors.js | 7 -
13 files changed, 478 insertions(+), 527 deletions(-)
diff --git a/docs/reference-guides/data/data-core-block-editor.md b/docs/reference-guides/data/data-core-block-editor.md
index 3cc75b50481683..2f5b5193452558 100644
--- a/docs/reference-guides/data/data-core-block-editor.md
+++ b/docs/reference-guides/data/data-core-block-editor.md
@@ -281,12 +281,6 @@ Returns all block objects for the current post being edited as an array in
the order they appear in the post. Note that this will exclude child blocks
of nested inner block controllers.
-Note: It's important to memoize this selector to avoid return a new instance
-on each call. We use the block cache state for each top-level block of the
-given clientID. This way, the selector only refreshes on changes to blocks
-associated with the given entity, and does not refresh when changes are made
-to blocks which are part of different inner block controllers.
-
_Parameters_
- _state_ `Object`: Editor state.
@@ -1225,6 +1219,8 @@ Returns an action object used in signalling that blocks have been received.
Unlike resetBlocks, these should be appended to the existing known set, not
replacing.
+Todo: This should be deprecated
+
_Parameters_
- _blocks_ `Object[]`: Array of block objects.
diff --git a/packages/block-editor/src/components/block-list/block-list-item.native.js b/packages/block-editor/src/components/block-list/block-list-item.native.js
index fae95956fa735a..0abe3c213d4a90 100644
--- a/packages/block-editor/src/components/block-list/block-list-item.native.js
+++ b/packages/block-editor/src/components/block-list/block-list-item.native.js
@@ -199,7 +199,7 @@ export default compose( [
isBlockInsertionPointVisible,
getSettings,
getBlockParents,
- __unstableGetBlockWithoutInnerBlocks,
+ getBlock,
} = select( blockEditorStore );
const blockClientIds = getBlockOrder( rootClientId );
@@ -225,14 +225,11 @@ export default compose( [
const isReadOnly = getSettings().readOnly;
- const block = __unstableGetBlockWithoutInnerBlocks( clientId );
- const { attributes, name } = block || {};
+ const { attributes, name } = getBlock( clientId );
const { align } = attributes || {};
const parents = getBlockParents( clientId, true );
const hasParents = !! parents.length;
- const parentBlock = hasParents
- ? __unstableGetBlockWithoutInnerBlocks( parents[ 0 ] )
- : {};
+ const parentBlock = hasParents ? getBlock( parents[ 0 ] ) : {};
const { align: parentBlockAlignment } =
parentBlock?.attributes || {};
const { name: parentBlockName } = parentBlock || {};
diff --git a/packages/block-editor/src/components/block-list/block.native.js b/packages/block-editor/src/components/block-list/block.native.js
index 3f700ec22a2920..b7543dc7977671 100644
--- a/packages/block-editor/src/components/block-list/block.native.js
+++ b/packages/block-editor/src/components/block-list/block.native.js
@@ -305,7 +305,7 @@ export default compose( [
getBlockIndex,
getSettings,
isBlockSelected,
- __unstableGetBlockWithoutInnerBlocks,
+ getBlock,
getSelectedBlockClientId,
getLowestCommonAncestorWithSelectedBlock,
getBlockParents,
@@ -315,7 +315,7 @@ export default compose( [
const order = getBlockIndex( clientId, rootClientId );
const isSelected = isBlockSelected( clientId );
const isInnerBlockSelected = hasSelectedInnerBlock( clientId );
- const block = __unstableGetBlockWithoutInnerBlocks( clientId );
+ const block = getBlock( clientId );
const { name, attributes, isValid } = block || {};
const blockType = getBlockType( name || 'core/missing' );
diff --git a/packages/block-editor/src/components/block-tools/block-popover.js b/packages/block-editor/src/components/block-tools/block-popover.js
index 59d9ae24a71d3a..3797f68edadffc 100644
--- a/packages/block-editor/src/components/block-tools/block-popover.js
+++ b/packages/block-editor/src/components/block-tools/block-popover.js
@@ -284,7 +284,7 @@ function wrapperSelector( select ) {
getSelectedBlockClientId,
getFirstMultiSelectedBlockClientId,
getBlockRootClientId,
- __unstableGetBlockWithoutInnerBlocks,
+ getBlock,
getBlockParents,
__experimentalGetBlockListSettingsForBlocks,
} = select( blockEditorStore );
@@ -296,8 +296,7 @@ function wrapperSelector( select ) {
return;
}
- const { name, attributes = {}, isValid } =
- __unstableGetBlockWithoutInnerBlocks( clientId ) || {};
+ const { name, attributes = {}, isValid } = getBlock( clientId ) || {};
const blockParentsClientIds = getBlockParents( clientId );
// Get Block List Settings for all ancestors of the current Block clientId
diff --git a/packages/block-editor/src/components/block-tools/block-selection-button.js b/packages/block-editor/src/components/block-tools/block-selection-button.js
index 12b4bb2d0407ad..8eb9a5b6950680 100644
--- a/packages/block-editor/src/components/block-tools/block-selection-button.js
+++ b/packages/block-editor/src/components/block-tools/block-selection-button.js
@@ -54,15 +54,13 @@ function BlockSelectionButton( { clientId, rootClientId, blockElement } ) {
const selected = useSelect(
( select ) => {
const {
- __unstableGetBlockWithoutInnerBlocks,
+ getBlock,
getBlockIndex,
hasBlockMovingClientId,
getBlockListSettings,
} = select( blockEditorStore );
const index = getBlockIndex( clientId, rootClientId );
- const { name, attributes } = __unstableGetBlockWithoutInnerBlocks(
- clientId
- );
+ const { name, attributes } = getBlock( clientId );
const blockMovingMode = hasBlockMovingClientId();
return {
index,
diff --git a/packages/block-editor/src/components/rich-text/index.native.js b/packages/block-editor/src/components/rich-text/index.native.js
index 5c9af75b2796fb..85c1e647853007 100644
--- a/packages/block-editor/src/components/rich-text/index.native.js
+++ b/packages/block-editor/src/components/rich-text/index.native.js
@@ -125,7 +125,7 @@ function RichTextWrapper(
getSelectionEnd,
getSettings,
didAutomaticChange,
- __unstableGetBlockWithoutInnerBlocks,
+ getBlock,
isMultiSelecting,
hasMultiSelection,
} = select( blockEditorStore );
@@ -149,8 +149,7 @@ function RichTextWrapper(
// If the block of this RichText is unmodified then it's a candidate for replacing when adding a new block.
// In order to fix https://github.com/wordpress-mobile/gutenberg-mobile/issues/1126, let's blur on unmount in that case.
// This apparently assumes functionality the BlockHlder actually
- const block =
- clientId && __unstableGetBlockWithoutInnerBlocks( clientId );
+ const block = clientId && getBlock( clientId );
const shouldBlurOnUnmount =
block && isSelected && isUnmodifiedDefaultBlock( block );
extraProps = {
diff --git a/packages/block-editor/src/store/actions.js b/packages/block-editor/src/store/actions.js
index 23ef155e31aff3..817953f3aef242 100644
--- a/packages/block-editor/src/store/actions.js
+++ b/packages/block-editor/src/store/actions.js
@@ -151,6 +151,8 @@ export function resetSelection(
* Unlike resetBlocks, these should be appended to the existing known set, not
* replacing.
*
+ * Todo: This should be deprecated
+ *
* @param {Object[]} blocks Array of block objects.
*
* @return {Object} Action object.
diff --git a/packages/block-editor/src/store/reducer.js b/packages/block-editor/src/store/reducer.js
index db5477661d50c2..4c18f041c7948f 100644
--- a/packages/block-editor/src/store/reducer.js
+++ b/packages/block-editor/src/store/reducer.js
@@ -13,7 +13,6 @@ import {
isEqual,
isEmpty,
identity,
- difference,
omitBy,
pickBy,
} from 'lodash';
@@ -215,150 +214,211 @@ export function isUpdatingSameBlockAttribute( action, lastAction ) {
);
}
-/**
- * Utility returning an object with an empty object value for each key.
- *
- * @param {Array} objectKeys Keys to fill.
- * @return {Object} Object filled with empty object as values for each clientId.
- */
-const fillKeysWithEmptyObject = ( objectKeys ) => {
- return objectKeys.reduce( ( result, key ) => {
- result[ key ] = {};
- return result;
- }, {} );
-};
+function buildBlockTree( state, blocks ) {
+ const result = {};
+ const stack = [ ...blocks ];
+ const flattenedBlocks = [ ...blocks ];
+ while ( stack.length ) {
+ const block = stack.shift();
+ stack.push( ...block.innerBlocks );
+ flattenedBlocks.push( ...block.innerBlocks );
+ }
+ // Create objects before mutating them, that way it's always defined.
+ for ( const block of flattenedBlocks ) {
+ result[ block.clientId ] = {};
+ }
+ for ( const block of flattenedBlocks ) {
+ result[ block.clientId ] = Object.assign( result[ block.clientId ], {
+ ...state.byClientId[ block.clientId ],
+ attributes: state.attributes[ block.clientId ],
+ innerBlocks: block.innerBlocks.map(
+ ( subBlock ) => result[ subBlock.clientId ]
+ ),
+ } );
+ }
+
+ return result;
+}
+
+function updateParentInnerBlocksInTree( state, tree, updatedClientIds ) {
+ const clientIds = new Set( [] );
+ const controlledParents = new Set();
+ for ( const clientId of updatedClientIds ) {
+ let current = clientId;
+ do {
+ if ( state.controlledInnerBlocks[ current ] ) {
+ controlledParents.add( current );
+ // If we reach a controlled parent, break out of the loop.
+ break;
+ } else {
+ clientIds.add( current );
+ }
+ // Should stop on controlled blocks.
+ current = state.parents[ current ];
+ } while ( current !== undefined );
+ }
+
+ // To make sure the order of assignments doesn't matter,
+ // we first create empty objects and mutates the inner blocks later.
+ for ( const clientId of clientIds ) {
+ tree[ clientId ] = {
+ ...tree[ clientId ],
+ };
+ }
+ for ( const clientId of clientIds ) {
+ tree[ clientId ].innerBlocks = ( state.order[ clientId ] || [] ).map(
+ ( subClientId ) => tree[ subClientId ]
+ );
+ }
+ // Controlled parent blocks, need a dedicated key for their inner blocks
+ // to be used when doing getBlocks( controlledBlockClientId ).
+ for ( const clientId of controlledParents ) {
+ tree[ 'controlled||' + clientId ] = {
+ innerBlocks: ( state.order[ clientId ] || [] ).map(
+ ( subClientId ) => tree[ subClientId ]
+ ),
+ };
+ }
+
+ return tree;
+}
/**
- * Higher-order reducer intended to compute a cache key for each block in the post.
- * A new instance of the cache key (empty object) is created each time the block object
- * needs to be refreshed (for any change in the block or its children).
+ * Higher-order reducer intended to compute full block objects key for each block in the post.
+ * This is a denormalization to optimize the performance of the getBlock selectors and avoid
+ * recomputing the block objects and avoid heavy memoization.
*
* @param {Function} reducer Original reducer function.
*
* @return {Function} Enhanced reducer function.
*/
-const withBlockCache = ( reducer ) => ( state = {}, action ) => {
+const withBlockTree = ( reducer ) => ( state = {}, action ) => {
const newState = reducer( state, action );
if ( newState === state ) {
return state;
}
- newState.cache = state.cache ? state.cache : {};
-
- /**
- * For each clientId provided, traverses up parents, adding the provided clientIds
- * and each parent's clientId to the returned array.
- *
- * When calling this function consider that it uses the old state, so any state
- * modifications made by the `reducer` will not be present.
- *
- * @param {Array} clientIds an Array of block clientIds.
- *
- * @return {Array} The provided clientIds and all of their parent clientIds.
- */
- const getBlocksWithParentsClientIds = ( clientIds ) => {
- return clientIds.reduce( ( result, clientId ) => {
- let current = clientId;
- do {
- result.push( current );
- current = state.parents[ current ];
- } while ( current && ! state.controlledInnerBlocks[ current ] );
- return result;
- }, [] );
- };
+ newState.tree = state.tree ? state.tree : {};
switch ( action.type ) {
- case 'RESET_BLOCKS':
- newState.cache = mapValues(
- flattenBlocks( action.blocks ),
- () => ( {} )
- );
- break;
case 'RECEIVE_BLOCKS':
case 'INSERT_BLOCKS': {
- const updatedBlockUids = keys( flattenBlocks( action.blocks ) );
- if (
- action.rootClientId &&
- ! state.controlledInnerBlocks[ action.rootClientId ]
- ) {
- updatedBlockUids.push( action.rootClientId );
- }
- newState.cache = {
- ...newState.cache,
- ...fillKeysWithEmptyObject(
- getBlocksWithParentsClientIds( updatedBlockUids )
- ),
- };
+ const subTree = buildBlockTree( newState, action.blocks );
+ newState.tree = updateParentInnerBlocksInTree(
+ newState,
+ {
+ ...newState.tree,
+ ...subTree,
+ },
+ action.rootClientId ? [ action.rootClientId ] : [ '' ]
+ );
break;
}
case 'UPDATE_BLOCK':
- newState.cache = {
- ...newState.cache,
- ...fillKeysWithEmptyObject(
- getBlocksWithParentsClientIds( [ action.clientId ] )
- ),
- };
+ newState.tree = updateParentInnerBlocksInTree(
+ newState,
+ {
+ ...newState.tree,
+ [ action.clientId ]: {
+ ...newState.byClientId[ action.clientId ],
+ attributes: newState.attributes[ action.clientId ],
+ },
+ },
+ [ action.clientId ]
+ );
break;
- case 'UPDATE_BLOCK_ATTRIBUTES':
- newState.cache = {
- ...newState.cache,
- ...fillKeysWithEmptyObject(
- getBlocksWithParentsClientIds( action.clientIds )
- ),
- };
+ case 'UPDATE_BLOCK_ATTRIBUTES': {
+ const newSubTree = action.clientIds.reduce(
+ ( result, clientId ) => {
+ result[ clientId ] = {
+ ...newState.tree[ clientId ],
+ attributes: newState.attributes[ clientId ],
+ };
+ return result;
+ },
+ {}
+ );
+ newState.tree = updateParentInnerBlocksInTree(
+ newState,
+ {
+ ...newState.tree,
+ ...newSubTree,
+ },
+ action.clientIds
+ );
break;
- case 'REPLACE_BLOCKS_AUGMENTED_WITH_CHILDREN':
- const parentClientIds = fillKeysWithEmptyObject(
- getBlocksWithParentsClientIds( action.replacedClientIds )
+ }
+ case 'REPLACE_BLOCKS_AUGMENTED_WITH_CHILDREN': {
+ const subTree = buildBlockTree( newState, action.blocks );
+ newState.tree = updateParentInnerBlocksInTree(
+ newState,
+ {
+ ...omit(
+ newState.tree,
+ action.replacedClientIds.concat(
+ action.replacedClientIds.map(
+ ( clientId ) => 'controlled||' + clientId
+ )
+ )
+ ),
+ ...subTree,
+ },
+ action.blocks.map( ( b ) => b.clientId )
);
-
- newState.cache = {
- ...omit( newState.cache, action.replacedClientIds ),
- ...omit( parentClientIds, action.replacedClientIds ),
- ...fillKeysWithEmptyObject(
- keys( flattenBlocks( action.blocks ) )
- ),
- };
break;
+ }
case 'REMOVE_BLOCKS_AUGMENTED_WITH_CHILDREN':
- newState.cache = {
- ...omit( newState.cache, action.removedClientIds ),
- ...fillKeysWithEmptyObject(
- difference(
- getBlocksWithParentsClientIds( action.clientIds ),
- action.clientIds
+ const parentsOfRemovedBlocks = [];
+ for ( const clientId of action.clientIds ) {
+ if (
+ state.parents[ clientId ] !== undefined &&
+ ( state.parents[ clientId ] === '' ||
+ newState.byClientId[ state.parents[ clientId ] ] )
+ ) {
+ parentsOfRemovedBlocks.push( state.parents[ clientId ] );
+ }
+ }
+ newState.tree = updateParentInnerBlocksInTree(
+ newState,
+ omit(
+ newState.tree,
+ action.removedClientIds.concat(
+ action.removedClientIds.map(
+ ( clientId ) => 'controlled||' + clientId
+ )
)
),
- };
+ parentsOfRemovedBlocks
+ );
break;
case 'MOVE_BLOCKS_TO_POSITION': {
- const updatedBlockUids = [ ...action.clientIds ];
+ const updatedBlockUids = [];
if ( action.fromRootClientId ) {
updatedBlockUids.push( action.fromRootClientId );
}
if ( action.toRootClientId ) {
updatedBlockUids.push( action.toRootClientId );
}
- newState.cache = {
- ...newState.cache,
- ...fillKeysWithEmptyObject(
- getBlocksWithParentsClientIds( updatedBlockUids )
- ),
- };
+ if ( ! action.fromRootClientId || ! action.fromRootClientId ) {
+ updatedBlockUids.push( '' );
+ }
+ newState.tree = updateParentInnerBlocksInTree(
+ newState,
+ newState.tree,
+ updatedBlockUids
+ );
break;
}
case 'MOVE_BLOCKS_UP':
case 'MOVE_BLOCKS_DOWN': {
- const updatedBlockUids = [];
- if ( action.rootClientId ) {
- updatedBlockUids.push( action.rootClientId );
- }
- newState.cache = {
- ...newState.cache,
- ...fillKeysWithEmptyObject(
- getBlocksWithParentsClientIds( updatedBlockUids )
- ),
- };
+ const updatedBlockUids = [
+ action.rootClientId ? action.rootClientId : '',
+ ];
+ newState.tree = updateParentInnerBlocksInTree(
+ newState,
+ newState.tree,
+ updatedBlockUids
+ );
break;
}
case 'SAVE_REUSABLE_BLOCK_SUCCESS': {
@@ -371,12 +431,21 @@ const withBlockCache = ( reducer ) => ( state = {}, action ) => {
} )
);
- newState.cache = {
- ...newState.cache,
- ...fillKeysWithEmptyObject(
- getBlocksWithParentsClientIds( updatedBlockUids )
- ),
- };
+ newState.tree = updateParentInnerBlocksInTree(
+ newState,
+ {
+ ...newState.tree,
+ ...updatedBlockUids.reduce( ( result, clientId ) => {
+ result[ clientId ] = {
+ ...newState.byClientId[ clientId ],
+ attributes: newState.attributes[ clientId ],
+ innerBlocks: newState.tree[ clientId ].innerBlocks,
+ };
+ return result;
+ }, {} ),
+ },
+ updatedBlockUids
+ );
}
}
@@ -531,21 +600,21 @@ const withInnerBlocksRemoveCascade = ( reducer ) => ( state, action ) => {
* @return {Function} Enhanced reducer function.
*/
const withBlockReset = ( reducer ) => ( state, action ) => {
- if ( state && action.type === 'RESET_BLOCKS' ) {
+ if ( action.type === 'RESET_BLOCKS' ) {
/**
* A list of client IDs associated with the top level entity (like a
* post or template). It excludes the client IDs of blocks associated
* with other entities, like inner block controllers or reusable blocks.
*/
const visibleClientIds = getNestedBlockClientIds(
- state.order,
+ state?.order ?? {},
'',
- state.controlledInnerBlocks
+ state?.controlledInnerBlocks ?? {}
);
// pickBy returns only the truthy values from controlledInnerBlocks
const controlledInnerBlocks = Object.keys(
- pickBy( state.controlledInnerBlocks )
+ pickBy( state?.controlledInnerBlocks ?? {} )
);
/**
@@ -569,35 +638,43 @@ const withBlockReset = ( reducer ) => ( state, action ) => {
* new value was used, template parts would disappear from the editor
* whenever you try to undo a change in the top level entity.
*/
- return {
+ const newState = {
...state,
byClientId: {
- ...omit( state.byClientId, visibleClientIds ),
+ ...omit( state?.byClientId, visibleClientIds ),
...getFlattenedBlocksWithoutAttributes( action.blocks ),
},
attributes: {
- ...omit( state.attributes, visibleClientIds ),
+ ...omit( state?.attributes, visibleClientIds ),
...getFlattenedBlockAttributes( action.blocks ),
},
order: {
- ...omit( state.order, visibleClientIds ),
+ ...omit( state?.order, visibleClientIds ),
...omit(
mapBlockOrder( action.blocks ),
controlledInnerBlocks
),
},
parents: {
- ...omit( state.parents, visibleClientIds ),
+ ...omit( state?.parents, visibleClientIds ),
...mapBlockParents( action.blocks ),
},
- cache: {
- ...omit( state.cache, visibleClientIds ),
- ...omit(
- mapValues( flattenBlocks( action.blocks ), () => ( {} ) ),
- controlledInnerBlocks
+ controlledInnerBlocks: state?.controlledInnerBlocks || {},
+ };
+
+ const subTree = buildBlockTree( newState, action.blocks );
+ newState.tree = {
+ ...omit( state?.tree, visibleClientIds ),
+ ...subTree,
+ // Root
+ '': {
+ innerBlocks: action.blocks.map(
+ ( subBlock ) => subTree[ subBlock.clientId ]
),
},
};
+
+ return newState;
}
return reducer( state, action );
@@ -727,7 +804,7 @@ const withSaveReusableBlock = ( reducer ) => ( state, action ) => {
export const blocks = flow(
combineReducers,
withSaveReusableBlock, // needs to be before withBlockCache
- withBlockCache, // needs to be before withInnerBlocksRemoveCascade
+ withBlockTree, // needs to be before withInnerBlocksRemoveCascade
withInnerBlocksRemoveCascade,
withReplaceInnerBlocks, // needs to be after withInnerBlocksRemoveCascade
withBlockReset,
@@ -736,9 +813,6 @@ export const blocks = flow(
)( {
byClientId( state = {}, action ) {
switch ( action.type ) {
- case 'RESET_BLOCKS':
- return getFlattenedBlocksWithoutAttributes( action.blocks );
-
case 'RECEIVE_BLOCKS':
case 'INSERT_BLOCKS':
return {
@@ -785,9 +859,6 @@ export const blocks = flow(
attributes( state = {}, action ) {
switch ( action.type ) {
- case 'RESET_BLOCKS':
- return getFlattenedBlockAttributes( action.blocks );
-
case 'RECEIVE_BLOCKS':
case 'INSERT_BLOCKS':
return {
@@ -873,15 +944,14 @@ export const blocks = flow(
order( state = {}, action ) {
switch ( action.type ) {
- case 'RESET_BLOCKS':
- return mapBlockOrder( action.blocks );
-
- case 'RECEIVE_BLOCKS':
+ case 'RECEIVE_BLOCKS': {
+ const blockOrder = mapBlockOrder( action.blocks );
return {
...state,
- ...omit( mapBlockOrder( action.blocks ), '' ),
+ ...omit( blockOrder, '' ),
+ '': ( state?.[ '' ] || [] ).concat( blockOrder ),
};
-
+ }
case 'INSERT_BLOCKS': {
const { rootClientId = '' } = action;
const subState = state[ rootClientId ] || [];
@@ -1049,9 +1119,6 @@ export const blocks = flow(
// an optimization for the selectors which derive the ancestry of a block.
parents( state = {}, action ) {
switch ( action.type ) {
- case 'RESET_BLOCKS':
- return mapBlockParents( action.blocks );
-
case 'RECEIVE_BLOCKS':
return {
...state,
diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js
index 61501dae210e85..d10a80d83e2451 100644
--- a/packages/block-editor/src/store/selectors.js
+++ b/packages/block-editor/src/store/selectors.js
@@ -132,30 +132,14 @@ export function getBlockAttributes( state, clientId ) {
*
* @return {Object} Parsed block object.
*/
-export const getBlock = createSelector(
- ( state, clientId ) => {
- const block = state.blocks.byClientId[ clientId ];
- if ( ! block ) {
- return null;
- }
+export function getBlock( state, clientId ) {
+ const block = state.blocks.byClientId[ clientId ];
+ if ( ! block ) {
+ return null;
+ }
- return {
- ...block,
- attributes: getBlockAttributes( state, clientId ),
- innerBlocks: areInnerBlocksControlled( state, clientId )
- ? EMPTY_ARRAY
- : getBlocks( state, clientId ),
- };
- },
- ( state, clientId ) => [
- // Normally, we'd have both `getBlockAttributes` dependencies and
- // `getBlocks` (children) dependencies here but for performance reasons
- // we use a denormalized cache key computed in the reducer that takes both
- // the attributes and inner blocks into account. The value of the cache key
- // is being changed whenever one of these dependencies is out of date.
- state.blocks.cache[ clientId ],
- ]
-);
+ return state.blocks.tree[ clientId ];
+}
export const __unstableGetBlockWithoutInnerBlocks = createSelector(
( state, clientId ) => {
@@ -180,81 +164,18 @@ export const __unstableGetBlockWithoutInnerBlocks = createSelector(
* the order they appear in the post. Note that this will exclude child blocks
* of nested inner block controllers.
*
- * Note: It's important to memoize this selector to avoid return a new instance
- * on each call. We use the block cache state for each top-level block of the
- * given clientID. This way, the selector only refreshes on changes to blocks
- * associated with the given entity, and does not refresh when changes are made
- * to blocks which are part of different inner block controllers.
- *
* @param {Object} state Editor state.
* @param {?string} rootClientId Optional root client ID of block list.
*
* @return {Object[]} Post blocks.
*/
-export const getBlocks = createSelector(
- ( state, rootClientId ) => {
- return map( getBlockOrder( state, rootClientId ), ( clientId ) =>
- getBlock( state, clientId )
- );
- },
- ( state, rootClientId ) =>
- map(
- state.blocks.order[ rootClientId || '' ],
- ( id ) => state.blocks.cache[ id ]
- )
-);
-
-/**
- * Similar to getBlock, except it will include the entire nested block tree as
- * inner blocks. The normal getBlock selector will exclude sections of the block
- * tree which belong to different entities.
- *
- * @param {Object} state Editor state.
- * @param {string} clientId Client ID of the block to get.
- *
- * @return {Object} The block with all
- */
-export const __unstableGetBlockWithBlockTree = createSelector(
- ( state, clientId ) => {
- const block = state.blocks.byClientId[ clientId ];
- if ( ! block ) {
- return null;
- }
-
- return {
- ...block,
- attributes: getBlockAttributes( state, clientId ),
- innerBlocks: __unstableGetBlockTree( state, clientId ),
- };
- },
- ( state ) => [
- state.blocks.byClientId,
- state.blocks.order,
- state.blocks.attributes,
- ]
-);
-
-/**
- * Similar to getBlocks, except this selector returns the entire block tree
- * represented in the block-editor store from the given root regardless of any
- * inner block controllers.
- *
- * @param {Object} state Editor state.
- * @param {?string} rootClientId Optional root client ID of block list.
- *
- * @return {Object[]} Post blocks.
- */
-export const __unstableGetBlockTree = createSelector(
- ( state, rootClientId = '' ) =>
- map( getBlockOrder( state, rootClientId ), ( clientId ) =>
- __unstableGetBlockWithBlockTree( state, clientId )
- ),
- ( state ) => [
- state.blocks.byClientId,
- state.blocks.order,
- state.blocks.attributes,
- ]
-);
+export function getBlocks( state, rootClientId ) {
+ const treeKey =
+ ! rootClientId || ! areInnerBlocksControlled( state, rootClientId )
+ ? rootClientId || ''
+ : 'controlled||' + rootClientId;
+ return state.blocks.tree[ treeKey ]?.innerBlocks || EMPTY_ARRAY;
+}
/**
* Returns a stripped down block object containing only its client ID,
@@ -369,11 +290,11 @@ export const getBlocksByClientId = createSelector(
map( castArray( clientIds ), ( clientId ) =>
getBlock( state, clientId )
),
- ( state ) => [
- state.blocks.byClientId,
- state.blocks.order,
- state.blocks.attributes,
- ]
+ ( state, clientIds ) =>
+ map(
+ castArray( clientIds ),
+ ( clientId ) => state.blocks.tree[ clientId ]
+ )
);
/**
diff --git a/packages/block-editor/src/store/test/reducer.js b/packages/block-editor/src/store/test/reducer.js
index b4ad1c12ec1980..2015ca50d00e13 100644
--- a/packages/block-editor/src/store/test/reducer.js
+++ b/packages/block-editor/src/store/test/reducer.js
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import { values, noop } from 'lodash';
+import { values, noop, omit } from 'lodash';
import deepFreeze from 'deep-freeze';
/**
@@ -236,7 +236,8 @@ describe( 'state', () => {
chicken: '',
'chicken-child': 'chicken',
},
- cache: {
+ tree: {
+ '': {},
chicken: {},
'chicken-child': {},
},
@@ -258,7 +259,7 @@ describe( 'state', () => {
const state = blocks( existingState, action );
- expect( state ).toEqual( {
+ expect( omit( state, [ 'tree' ] ) ).toEqual( {
isPersistentChange: true,
isIgnoredChange: false,
byClientId: {
@@ -289,14 +290,10 @@ describe( 'state', () => {
[ newChildBlockId ]: 'chicken',
chicken: '',
},
- cache: {
- chicken: {},
- [ newChildBlockId ]: {},
- },
controlledInnerBlocks: {},
} );
- expect( state.cache.chicken ).not.toBe(
- existingState.cache.chicken
+ expect( state.tree.chicken ).not.toBe(
+ existingState.tree.chicken
);
} );
@@ -319,7 +316,10 @@ describe( 'state', () => {
parents: {
chicken: '',
},
- cache: {
+ tree: {
+ '': {
+ innerBlocks: [],
+ },
chicken: {},
},
controlledInnerBlocks: {},
@@ -340,7 +340,7 @@ describe( 'state', () => {
const state = blocks( existingState, action );
- expect( state ).toEqual( {
+ expect( omit( state, [ 'tree' ] ) ).toEqual( {
isPersistentChange: true,
isIgnoredChange: false,
byClientId: {
@@ -371,15 +371,27 @@ describe( 'state', () => {
[ newChildBlockId ]: 'chicken',
chicken: '',
},
- cache: {
- chicken: {},
- [ newChildBlockId ]: {},
- },
controlledInnerBlocks: {},
} );
- expect( state.cache.chicken ).not.toBe(
- existingState.cache.chicken
+ expect( state.tree.chicken ).not.toBe(
+ existingState.tree.chicken
+ );
+ expect( state.tree[ '' ].innerBlocks[ 0 ] ).toBe(
+ state.tree.chicken
+ );
+ expect( state.tree.chicken.innerBlocks[ 0 ] ).toBe(
+ state.tree[ newChildBlockId ]
);
+ expect( state.tree[ newChildBlockId ] ).toEqual( {
+ clientId: newChildBlockId,
+ innerBlocks: [],
+ isValid: true,
+ name: 'core/test-child-block',
+ attributes: {
+ attr: false,
+ attr2: 'perfect',
+ },
+ } );
} );
it( 'can replace multiple child blocks', () => {
@@ -421,11 +433,7 @@ describe( 'state', () => {
'chicken-child': 'chicken',
'chicken-child-2': 'chicken',
},
- cache: {
- chicken: {},
- 'chicken-child': {},
- 'chicken-child-2': {},
- },
+ tree: {},
controlledInnerBlocks: {},
} );
@@ -455,7 +463,7 @@ describe( 'state', () => {
const state = blocks( existingState, action );
- expect( state ).toEqual( {
+ expect( omit( state, [ 'tree' ] ) ).toEqual( {
isPersistentChange: true,
isIgnoredChange: false,
byClientId: {
@@ -511,14 +519,31 @@ describe( 'state', () => {
[ newChildBlockId2 ]: 'chicken',
[ newChildBlockId3 ]: 'chicken',
},
- cache: {
- chicken: {},
- [ newChildBlockId1 ]: {},
- [ newChildBlockId2 ]: {},
- [ newChildBlockId3 ]: {},
- },
controlledInnerBlocks: {},
} );
+
+ expect( state.tree[ '' ].innerBlocks[ 0 ] ).toBe(
+ state.tree.chicken
+ );
+ expect( state.tree.chicken.innerBlocks[ 0 ] ).toBe(
+ state.tree[ newChildBlockId1 ]
+ );
+ expect( state.tree.chicken.innerBlocks[ 1 ] ).toBe(
+ state.tree[ newChildBlockId2 ]
+ );
+ expect( state.tree.chicken.innerBlocks[ 2 ] ).toBe(
+ state.tree[ newChildBlockId3 ]
+ );
+ expect( state.tree[ newChildBlockId1 ] ).toEqual( {
+ innerBlocks: [],
+ clientId: newChildBlockId1,
+ name: 'core/test-child-block',
+ isValid: true,
+ attributes: {
+ attr: false,
+ attr2: 'perfect',
+ },
+ } );
} );
it( 'can replace a child block that has other children', () => {
@@ -556,10 +581,8 @@ describe( 'state', () => {
'chicken-child': 'chicken',
'chicken-grand-child': 'chicken-child',
},
- cache: {
+ tree: {
chicken: {},
- 'chicken-child': {},
- 'chicken-grand-child': {},
},
controlledInnerBlocks: {},
} );
@@ -576,7 +599,7 @@ describe( 'state', () => {
const state = blocks( existingState, action );
- expect( state ).toEqual( {
+ expect( omit( state, [ 'tree' ] ) ).toEqual( {
isPersistentChange: true,
isIgnoredChange: false,
byClientId: {
@@ -604,16 +627,12 @@ describe( 'state', () => {
chicken: '',
[ newChildBlockId ]: 'chicken',
},
- cache: {
- chicken: {},
- [ newChildBlockId ]: {},
- },
controlledInnerBlocks: {},
} );
- // the cache key of the parent should be updated
- expect( existingState.cache.chicken ).not.toBe(
- state.cache.chicken
+ // the block object of the parent should be updated
+ expect( state.tree.chicken ).not.toBe(
+ existingState.tree.chicken
);
} );
} );
@@ -628,7 +647,7 @@ describe( 'state', () => {
parents: {},
isPersistentChange: true,
isIgnoredChange: false,
- cache: {},
+ tree: {},
controlledInnerBlocks: {},
} );
} );
@@ -648,9 +667,13 @@ describe( 'state', () => {
'': [ 'bananas' ],
bananas: [],
} );
- expect( state.cache ).toEqual( {
- bananas: {},
+ expect( state.tree.bananas ).toEqual( {
+ clientId: 'bananas',
+ innerBlocks: [],
} );
+ expect( state.tree[ '' ].innerBlocks[ 0 ] ).toBe(
+ state.tree.bananas
+ );
} );
} );
@@ -674,10 +697,6 @@ describe( 'state', () => {
apples: [],
bananas: [ 'apples' ],
} );
- expect( state.cache ).toEqual( {
- bananas: {},
- apples: {},
- } );
} );
it( 'should insert block', () => {
@@ -710,12 +729,17 @@ describe( 'state', () => {
chicken: [],
ribs: [],
} );
- expect( state.cache ).toEqual( {
- chicken: {},
- ribs: {},
+
+ expect( state.tree[ '' ].innerBlocks[ 0 ] ).toBe(
+ state.tree.chicken
+ );
+ expect( state.tree[ '' ].innerBlocks[ 1 ] ).toBe( state.tree.ribs );
+ expect( state.tree.chicken ).toEqual( {
+ clientId: 'chicken',
+ name: 'core/test-block',
+ attributes: {},
+ innerBlocks: [],
} );
- // The cache key is the same because the block has not been modified.
- expect( original.cache.chicken ).toBe( state.cache.chicken );
} );
it( 'should replace the block', () => {
@@ -754,10 +778,16 @@ describe( 'state', () => {
expect( state.parents ).toEqual( {
wings: '',
} );
- expect( state.cache ).toEqual( {
- wings: {},
+ expect( state.tree[ '' ].innerBlocks[ 0 ] ).toBe(
+ state.tree.wings
+ );
+ expect( state.tree.wings ).toEqual( {
+ clientId: 'wings',
+ name: 'core/freeform',
+ innerBlocks: [],
} );
} );
+
it( 'should replace the block and remove references to its inner blocks', () => {
const original = blocks( undefined, {
type: 'RESET_BLOCKS',
@@ -797,8 +827,13 @@ describe( 'state', () => {
expect( state.parents ).toEqual( {
wings: '',
} );
- expect( state.cache ).toEqual( {
- wings: {},
+ expect( state.tree[ '' ].innerBlocks[ 0 ] ).toBe(
+ state.tree.wings
+ );
+ expect( state.tree.wings ).toEqual( {
+ clientId: 'wings',
+ name: 'core/freeform',
+ innerBlocks: [],
} );
} );
@@ -813,22 +848,12 @@ describe( 'state', () => {
blocks: [ wrapperBlock ],
} );
- const originalWrapperBlockCacheKey =
- original.cache[ wrapperBlock.clientId ];
-
const state = blocks( original, {
type: 'REPLACE_BLOCKS',
clientIds: [ nestedBlock.clientId ],
blocks: [ replacementBlock ],
} );
- const newWrapperBlockCacheKey =
- state.cache[ wrapperBlock.clientId ];
-
- expect( newWrapperBlockCacheKey ).not.toBe(
- originalWrapperBlockCacheKey
- );
-
expect( state.order ).toEqual( {
'': [ wrapperBlock.clientId ],
[ wrapperBlock.clientId ]: [ replacementBlock.clientId ],
@@ -840,9 +865,15 @@ describe( 'state', () => {
[ replacementBlock.clientId ]: wrapperBlock.clientId,
} );
- expect( state.cache ).toEqual( {
- [ wrapperBlock.clientId ]: {},
- [ replacementBlock.clientId ]: {},
+ expect( state.tree[ wrapperBlock.clientId ].innerBlocks[ 0 ] ).toBe(
+ state.tree[ replacementBlock.clientId ]
+ );
+ expect( state.tree[ replacementBlock.clientId ] ).toEqual( {
+ clientId: replacementBlock.clientId,
+ name: 'core/test-block',
+ innerBlocks: [],
+ attributes: {},
+ isValid: true,
} );
} );
@@ -884,11 +915,8 @@ describe( 'state', () => {
'': [ 'chicken' ],
chicken: [],
} );
- expect( replacedState.cache ).toEqual( {
- chicken: {},
- } );
- expect( originalState.cache.chicken ).not.toBe(
- replacedState.cache.chicken
+ expect( originalState.tree.chicken ).not.toBe(
+ replacedState.tree.chicken
);
const nestedBlock = {
@@ -963,11 +991,18 @@ describe( 'state', () => {
expect( state.attributes.chicken ).toEqual( {
content: 'ribs',
} );
-
- expect( state.cache ).toEqual( {
- chicken: {},
+ expect( state.tree[ '' ].innerBlocks[ 0 ] ).toBe(
+ state.tree.chicken
+ );
+ expect( state.tree.chicken ).toEqual( {
+ clientId: 'chicken',
+ name: 'core/test-block',
+ innerBlocks: [],
+ attributes: {
+ content: 'ribs',
+ },
+ isValid: true,
} );
- expect( state.cache.chicken ).not.toBe( original.cache.chicken );
} );
it( 'should update the reusable block reference if the temporary id is swapped', () => {
@@ -1001,10 +1036,19 @@ describe( 'state', () => {
expect( state.attributes.chicken ).toEqual( {
ref: 3,
} );
- expect( state.cache ).toEqual( {
- chicken: {},
+
+ expect( state.tree[ '' ].innerBlocks[ 0 ] ).toBe(
+ state.tree.chicken
+ );
+ expect( state.tree.chicken ).toEqual( {
+ clientId: 'chicken',
+ name: 'core/block',
+ isValid: false,
+ innerBlocks: [],
+ attributes: {
+ ref: 3,
+ },
} );
- expect( state.cache.chicken ).not.toBe( original.cache.chicken );
} );
it( 'should move the block up', () => {
@@ -1031,8 +1075,11 @@ describe( 'state', () => {
} );
expect( state.order[ '' ] ).toEqual( [ 'ribs', 'chicken' ] );
- expect( state.cache.ribs ).toBe( original.cache.ribs );
- expect( state.cache.chicken ).toBe( original.cache.chicken );
+ expect( state.tree[ '' ].innerBlocks[ 0 ] ).toBe( state.tree.ribs );
+ expect( state.tree[ '' ].innerBlocks[ 1 ] ).toBe(
+ state.tree.chicken
+ );
+ expect( state.tree.chicken ).toBe( original.tree.chicken );
} );
it( 'should move the nested block up', () => {
@@ -1061,14 +1108,15 @@ describe( 'state', () => {
[ movedBlock.clientId ]: [],
[ siblingBlock.clientId ]: [],
} );
- expect( state.cache[ wrapperBlock.clientId ] ).not.toBe(
- original.cache[ wrapperBlock.clientId ]
+
+ expect( state.tree[ wrapperBlock.clientId ].innerBlocks[ 0 ] ).toBe(
+ state.tree[ movedBlock.clientId ]
);
- expect( state.cache[ movedBlock.clientId ] ).toBe(
- original.cache[ movedBlock.clientId ]
+ expect( state.tree[ wrapperBlock.clientId ].innerBlocks[ 1 ] ).toBe(
+ state.tree[ siblingBlock.clientId ]
);
- expect( state.cache[ siblingBlock.clientId ] ).toBe(
- original.cache[ siblingBlock.clientId ]
+ expect( state.tree[ movedBlock.clientId ] ).toBe(
+ original.tree[ movedBlock.clientId ]
);
} );
@@ -1351,9 +1399,7 @@ describe( 'state', () => {
expect( state.attributes ).toEqual( {
ribs: {},
} );
- expect( state.cache ).toEqual( {
- ribs: {},
- } );
+ expect( state.tree[ '' ].innerBlocks ).toHaveLength( 1 );
} );
it( 'should remove multiple blocks', () => {
diff --git a/packages/block-editor/src/store/test/selectors.js b/packages/block-editor/src/store/test/selectors.js
index 1d96c678b2b48e..e6f514f8faab9d 100644
--- a/packages/block-editor/src/store/test/selectors.js
+++ b/packages/block-editor/src/store/test/selectors.js
@@ -228,19 +228,19 @@ describe( 'selectors', () => {
parents: {
123: '',
},
- cache: {
- 123: {},
+ tree: {
+ 123: {
+ clientId: 123,
+ name: 'core/paragraph',
+ attributes: {},
+ innerBlocks: [],
+ },
},
controlledInnerBlocks: {},
},
};
- expect( getBlock( state, 123 ) ).toEqual( {
- clientId: 123,
- name: 'core/paragraph',
- attributes: {},
- innerBlocks: [],
- } );
+ expect( getBlock( state, 123 ) ).toBe( state.blocks.tree[ 123 ] );
} );
it( 'should return null if the block is not present in state', () => {
@@ -250,55 +250,19 @@ describe( 'selectors', () => {
attributes: {},
order: {},
parents: {},
- cache: {},
- controlledInnerBlocks: {},
- },
- };
-
- expect( getBlock( state, 123 ) ).toBe( null );
- } );
-
- it( 'should include inner blocks', () => {
- const state = {
- blocks: {
- byClientId: {
- 123: { clientId: 123, name: 'core/paragraph' },
- 456: { clientId: 456, name: 'core/paragraph' },
- },
- attributes: {
- 123: {},
- 456: {},
- },
- order: {
- '': [ 123 ],
- 123: [ 456 ],
- 456: [],
- },
- parents: {
- 123: '',
- 456: 123,
- },
- cache: {
- 123: {},
- 456: {},
+ tree: {
+ 123: {
+ clientId: 123,
+ name: 'core/paragraph',
+ attributes: {},
+ innerBlocks: [],
+ },
},
controlledInnerBlocks: {},
},
};
- expect( getBlock( state, 123 ) ).toEqual( {
- clientId: 123,
- name: 'core/paragraph',
- attributes: {},
- innerBlocks: [
- {
- clientId: 456,
- name: 'core/paragraph',
- attributes: {},
- innerBlocks: [],
- },
- ],
- } );
+ expect( getBlock( state, 123 ) ).toBe( null );
} );
} );
@@ -321,7 +285,23 @@ describe( 'selectors', () => {
123: '',
23: '',
},
- cache: {
+ tree: {
+ '': {
+ innerBlocks: [
+ {
+ clientId: 123,
+ name: 'core/paragraph',
+ attributes: {},
+ innerBlocks: [],
+ },
+ {
+ clientId: 23,
+ name: 'core/heading',
+ attributes: {},
+ innerBlocks: [],
+ },
+ ],
+ },
123: {},
23: {},
},
@@ -329,92 +309,9 @@ describe( 'selectors', () => {
},
};
- expect( getBlocks( state ) ).toEqual( [
- {
- clientId: 123,
- name: 'core/paragraph',
- attributes: {},
- innerBlocks: [],
- },
- {
- clientId: 23,
- name: 'core/heading',
- attributes: {},
- innerBlocks: [],
- },
- ] );
- } );
- it( 'only returns a new value if the cache key of a direct child changes', () => {
- const cacheRef = {};
- const state = {
- blocks: {
- byClientId: {
- 23: { clientId: 23, name: 'core/heading' },
- },
- attributes: {
- 23: {},
- },
- order: {
- '': [ 23 ],
- },
- parents: {
- 23: '',
- },
- cache: {
- 23: cacheRef,
- },
- controlledInnerBlocks: {},
- },
- };
- const oldBlocks = getBlocks( state );
-
- const newStateSameCache = {
- blocks: {
- byClientId: {
- 23: { clientId: 23, name: 'core/heading' },
- },
- attributes: {
- 23: {},
- },
- order: {
- '': [ 23 ],
- },
- parents: {
- 23: '',
- },
- cache: {
- 23: cacheRef,
- },
- controlledInnerBlocks: {},
- },
- };
- // Makes sure blocks are referentially equal if the cache key stays the same.
- const newBlocks = getBlocks( newStateSameCache );
- expect( oldBlocks ).toBe( newBlocks );
-
- const newStateNewCache = {
- blocks: {
- byClientId: {
- 23: { clientId: 23, name: 'core/heading' },
- },
- attributes: {
- 23: {},
- },
- order: {
- '': [ 23 ],
- },
- parents: {
- 23: '',
- },
- cache: {
- 23: {},
- },
- controlledInnerBlocks: {},
- },
- };
- // Blocks are referentially different if the cache key changes.
- const newBlocksNewCache = getBlocks( newStateNewCache );
- expect( oldBlocks ).not.toBe( newBlocksNewCache );
+ expect( getBlocks( state ) ).toBe(
+ state.blocks.tree[ '' ].innerBlocks
+ );
} );
} );
@@ -963,6 +860,14 @@ describe( 'selectors', () => {
23: '',
123: '',
},
+ tree: {
+ 23: {
+ clientId: 23,
+ name: 'core/heading',
+ attributes: {},
+ innerBlocks: [],
+ },
+ },
},
selection: {
selectionStart: {},
@@ -993,6 +898,14 @@ describe( 'selectors', () => {
123: '',
23: '',
},
+ tree: {
+ 23: {
+ clientId: 23,
+ name: 'core/heading',
+ attributes: {},
+ innerBlocks: [],
+ },
+ },
},
selection: {
selectionStart: { clientId: 23 },
@@ -1023,8 +936,13 @@ describe( 'selectors', () => {
123: '',
23: '',
},
- cache: {
- 23: {},
+ tree: {
+ 23: {
+ clientId: 23,
+ name: 'core/heading',
+ attributes: {},
+ innerBlocks: [],
+ },
},
controlledInnerBlocks: {},
},
@@ -1034,12 +952,9 @@ describe( 'selectors', () => {
},
};
- expect( getSelectedBlock( state ) ).toEqual( {
- clientId: 23,
- name: 'core/heading',
- attributes: {},
- innerBlocks: [],
- } );
+ expect( getSelectedBlock( state ) ).toEqual(
+ getBlock( state, 23 )
+ );
} );
} );
@@ -2560,7 +2475,11 @@ describe( 'selectors', () => {
attributes: {},
order: {},
parents: {},
- cache: {},
+ tree: {
+ '': {
+ innerBlocks: [],
+ },
+ },
},
settings: {
__experimentalReusableBlocks: [
@@ -2636,9 +2555,19 @@ describe( 'selectors', () => {
block3: '',
block4: '',
},
- cache: {
- block3: {},
- block4: {},
+ tree: {
+ block3: {
+ clientId: 'block3',
+ name: 'core/test-block-a',
+ attributes: {},
+ innerBlocks: [],
+ },
+ block4: {
+ clientId: 'block4',
+ name: 'core/test-block-a',
+ attributes: {},
+ innerBlocks: [],
+ },
},
controlledInnerBlocks: {},
},
@@ -2726,8 +2655,13 @@ describe( 'selectors', () => {
order: {
'': [ 'block1' ],
},
- cache: {
- block1: {},
+ tree: {
+ block1: {
+ clientId: 'block1',
+ name: 'core/test-block-b',
+ attributes: {},
+ innerBlocks: [],
+ },
},
controlledInnerBlocks: {},
},
@@ -2929,8 +2863,13 @@ describe( 'selectors', () => {
order: {
'': [ 'block1' ],
},
- cache: {
- block1: {},
+ tree: {
+ block1: {
+ clientId: 'block1',
+ name: 'core/with-tranforms-c',
+ attributes: {},
+ innerBlocks: [],
+ },
},
controlledInnerBlocks: {},
},
diff --git a/packages/edit-site/src/components/template-part-converter/convert-to-regular.js b/packages/edit-site/src/components/template-part-converter/convert-to-regular.js
index cfc43db26a657a..6407f8a22b0717 100644
--- a/packages/edit-site/src/components/template-part-converter/convert-to-regular.js
+++ b/packages/edit-site/src/components/template-part-converter/convert-to-regular.js
@@ -10,13 +10,7 @@ import { MenuItem } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
export default function ConvertToRegularBlocks( { clientId } ) {
- const { innerBlocks } = useSelect(
- ( select ) =>
- select( blockEditorStore ).__unstableGetBlockWithBlockTree(
- clientId
- ),
- [ clientId ]
- );
+ const { getBlocks } = useSelect( blockEditorStore );
const { replaceBlocks } = useDispatch( blockEditorStore );
return (
@@ -24,7 +18,7 @@ export default function ConvertToRegularBlocks( { clientId } ) {
{ ( { onClose } ) => (
{
- replaceBlocks( clientId, innerBlocks );
+ replaceBlocks( clientId, getBlocks( clientId ) );
onClose();
} }
>
diff --git a/packages/editor/src/store/selectors.js b/packages/editor/src/store/selectors.js
index 00d3e6527a71c4..d3e185e051e114 100644
--- a/packages/editor/src/store/selectors.js
+++ b/packages/editor/src/store/selectors.js
@@ -1394,13 +1394,6 @@ export const getBlock = getBlockEditorSelector( 'getBlock' );
*/
export const getBlocks = getBlockEditorSelector( 'getBlocks' );
-/**
- * @see __unstableGetBlockWithoutInnerBlocks in core/block-editor store.
- */
-export const __unstableGetBlockWithoutInnerBlocks = getBlockEditorSelector(
- '__unstableGetBlockWithoutInnerBlocks'
-);
-
/**
* @see getClientIdsOfDescendants in core/block-editor store.
*/
From 8d1ea0a3ad5440c64e8fae273e3d8125a3f61500 Mon Sep 17 00:00:00 2001
From: Alex Stine
Date: Thu, 26 Aug 2021 05:11:28 -0400
Subject: [PATCH 046/214] Accessibility improvement for font weight screen
reader description (#34312)
* Accessibility improvement for font weight/style description text.
* Fix linter error.
* Fix linter error.
---
.../font-appearance-control/index.js | 26 +++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/packages/block-editor/src/components/font-appearance-control/index.js b/packages/block-editor/src/components/font-appearance-control/index.js
index 224f9361d32f25..80b3b24357d660 100644
--- a/packages/block-editor/src/components/font-appearance-control/index.js
+++ b/packages/block-editor/src/components/font-appearance-control/index.js
@@ -163,12 +163,38 @@ export default function FontAppearanceControl( props ) {
return __( 'Appearance' );
};
+ // Adjusts screen reader description based on styles or weights.
+ const getDescribedBy = () => {
+ if ( ! hasFontStyles ) {
+ return sprintf(
+ // translators: %s: Currently selected font weight.
+ __( 'Currently selected font weight: %s' ),
+ currentSelection.name
+ );
+ }
+
+ if ( ! hasFontWeights ) {
+ return sprintf(
+ // translators: %s: Currently selected font style.
+ __( 'Currently selected font style: %s' ),
+ currentSelection.name
+ );
+ }
+
+ return sprintf(
+ // translators: %s: Currently selected font appearance.
+ __( 'Currently selected font appearance: %s' ),
+ currentSelection.name
+ );
+ };
+
return (
{ hasStylesOrWeights && (
From 96e4fcbaac987aca47985d86fa4707bc09d10083 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Greg=20Zi=C3=B3=C5=82kowski?=
Date: Thu, 26 Aug 2021 12:56:09 +0200
Subject: [PATCH 047/214] Jest Preset: Restore the default setting for the
`verbose` option (#34327)
---
packages/jest-preset-default/CHANGELOG.md | 4 ++++
packages/jest-preset-default/jest-preset.js | 1 -
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/packages/jest-preset-default/CHANGELOG.md b/packages/jest-preset-default/CHANGELOG.md
index 7342d85b69610d..6e18c4dd854ae0 100644
--- a/packages/jest-preset-default/CHANGELOG.md
+++ b/packages/jest-preset-default/CHANGELOG.md
@@ -2,6 +2,10 @@
## Unreleased
+### Bug Fix
+
+- Restore the default setting for the `verbose` option. In effect, each test won't get reported during the run ([#34327](https://github.com/WordPress/gutenberg/pull/34327)).
+
## 7.0.0 (2021-01-21)
### Breaking Changes
diff --git a/packages/jest-preset-default/jest-preset.js b/packages/jest-preset-default/jest-preset.js
index 252ac61a9c5df0..5dc0277f2d88e2 100644
--- a/packages/jest-preset-default/jest-preset.js
+++ b/packages/jest-preset-default/jest-preset.js
@@ -26,5 +26,4 @@ module.exports = {
transform: {
'^.+\\.[jt]sx?$': require.resolve( 'babel-jest' ),
},
- verbose: true,
};
From 640331cd0ac85eabc5ece96acc9a0494ed17b83d Mon Sep 17 00:00:00 2001
From: Riad Benguella
Date: Thu, 26 Aug 2021 12:35:44 +0100
Subject: [PATCH 048/214] Code cleanup to the getBlock refactoring (#34326)
---
docs/reference-guides/data/data-core-block-editor.md | 4 ++--
.../src/components/block-list/block-list-item.native.js | 2 +-
packages/block-editor/src/store/actions.js | 7 ++++++-
3 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/docs/reference-guides/data/data-core-block-editor.md b/docs/reference-guides/data/data-core-block-editor.md
index 2f5b5193452558..9f07302f001a83 100644
--- a/docs/reference-guides/data/data-core-block-editor.md
+++ b/docs/reference-guides/data/data-core-block-editor.md
@@ -1215,12 +1215,12 @@ _Parameters_
### receiveBlocks
+> **Deprecated**
+
Returns an action object used in signalling that blocks have been received.
Unlike resetBlocks, these should be appended to the existing known set, not
replacing.
-Todo: This should be deprecated
-
_Parameters_
- _blocks_ `Object[]`: Array of block objects.
diff --git a/packages/block-editor/src/components/block-list/block-list-item.native.js b/packages/block-editor/src/components/block-list/block-list-item.native.js
index 0abe3c213d4a90..857f0ed66ff51a 100644
--- a/packages/block-editor/src/components/block-list/block-list-item.native.js
+++ b/packages/block-editor/src/components/block-list/block-list-item.native.js
@@ -225,7 +225,7 @@ export default compose( [
const isReadOnly = getSettings().readOnly;
- const { attributes, name } = getBlock( clientId );
+ const { attributes, name } = getBlock( clientId ) || {};
const { align } = attributes || {};
const parents = getBlockParents( clientId, true );
const hasParents = !! parents.length;
diff --git a/packages/block-editor/src/store/actions.js b/packages/block-editor/src/store/actions.js
index 817953f3aef242..cd09e91dfbef9c 100644
--- a/packages/block-editor/src/store/actions.js
+++ b/packages/block-editor/src/store/actions.js
@@ -151,13 +151,18 @@ export function resetSelection(
* Unlike resetBlocks, these should be appended to the existing known set, not
* replacing.
*
- * Todo: This should be deprecated
+ * @deprecated
*
* @param {Object[]} blocks Array of block objects.
*
* @return {Object} Action object.
*/
export function receiveBlocks( blocks ) {
+ deprecated( 'wp.data.dispatch( "core/block-editor" ).receiveBlocks', {
+ since: '5.9',
+ alternative: 'resetBlocks or insertBlocks',
+ } );
+
return {
type: 'RECEIVE_BLOCKS',
blocks,
From bc42199951c32769deb4b356eb768914b666aa77 Mon Sep 17 00:00:00 2001
From: Joen A <1204802+jasmussen@users.noreply.github.com>
Date: Thu, 26 Aug 2021 15:09:49 +0200
Subject: [PATCH 049/214] Fix gray W menu color. (#34318)
---
.../src/components/header/fullscreen-mode-close/style.scss | 4 ++--
.../navigation-sidebar/navigation-toggle/style.scss | 5 +++--
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/packages/edit-post/src/components/header/fullscreen-mode-close/style.scss b/packages/edit-post/src/components/header/fullscreen-mode-close/style.scss
index 1cee0b961908f2..72f14c823e168c 100644
--- a/packages/edit-post/src/components/header/fullscreen-mode-close/style.scss
+++ b/packages/edit-post/src/components/header/fullscreen-mode-close/style.scss
@@ -11,7 +11,7 @@
align-items: center;
align-self: stretch;
border: none;
- background: #23282e; // WP-admin gray.
+ background: $gray-900;
color: $white;
border-radius: 0;
height: $header-height + $border-width;
@@ -38,7 +38,7 @@
bottom: 9px;
left: 9px;
border-radius: $radius-block-ui + $border-width + $border-width;
- box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) #23282e;
+ box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) $gray-900;
}
// Hover color.
diff --git a/packages/edit-site/src/components/navigation-sidebar/navigation-toggle/style.scss b/packages/edit-site/src/components/navigation-sidebar/navigation-toggle/style.scss
index d3ab0f7ac3d5b1..d78d3d4e6f6681 100644
--- a/packages/edit-site/src/components/navigation-sidebar/navigation-toggle/style.scss
+++ b/packages/edit-site/src/components/navigation-sidebar/navigation-toggle/style.scss
@@ -17,9 +17,10 @@
background: $gray-900;
border-radius: 0;
color: $white;
- height: $header-height;
+ height: $header-height + $border-width;
width: $header-height;
z-index: 1;
+ margin-bottom: - $border-width;
&.has-icon {
min-width: $header-height;
@@ -44,7 +45,7 @@
bottom: 9px;
left: 9px;
border-radius: $radius-block-ui + $border-width + $border-width;
- box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) #23282e;
+ box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) $gray-900;
}
// Hover color.
From 2f963dd8d0039d70861d2e05760c1f25fa228f95 Mon Sep 17 00:00:00 2001
From: Joen A <1204802+jasmussen@users.noreply.github.com>
Date: Thu, 26 Aug 2021 15:47:02 +0200
Subject: [PATCH 050/214] Fix subheadings from wrapping. (#34319)
---
packages/components/src/menu-group/style.scss | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/components/src/menu-group/style.scss b/packages/components/src/menu-group/style.scss
index 202bd74a469c1e..d9412c504940b3 100644
--- a/packages/components/src/menu-group/style.scss
+++ b/packages/components/src/menu-group/style.scss
@@ -18,4 +18,5 @@
text-transform: uppercase;
font-size: 11px;
font-weight: 500;
+ white-space: nowrap;
}
From c3d2b8ba48691ecf4d0a43eab887c5df581a3c9f Mon Sep 17 00:00:00 2001
From: Janw Oostendorp
Date: Thu, 26 Aug 2021 16:37:17 +0200
Subject: [PATCH 051/214] Added janw-me to the Codeowners for the PHP FSE
folder. (#32990)
* Added janw-me to the Codeowners for the PHP FSE folder.
---
.github/CODEOWNERS | 1 +
1 file changed, 1 insertion(+)
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 85d23fb60f268c..b22eec7c45d400 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -127,6 +127,7 @@
/lib/theme.json @timothybjabocs @spacedmonkey @nosolosw
/lib/class-wp-theme-json-gutenberg.php @timothybjabocs @spacedmonkey @nosolosw
/lib/class-wp-theme-json-resolver-gutenberg.php @timothybjabocs @spacedmonkey @nosolosw
+/lib/full-site-editing @janw-me
/phpunit/class-wp-theme-json-test.php @nosolosw
# Web App
From be7954e0fa98664613e9d8fda7478ad21023b804 Mon Sep 17 00:00:00 2001
From: David Calhoun <438664+dcalhoun@users.noreply.github.com>
Date: Thu, 26 Aug 2021 10:14:21 -0500
Subject: [PATCH 052/214] Fix Column bottom sheet Android close button (#34332)
* Fix Column bottom sheet Android close button
Apply required margin and padding to properly align Android close
button in the Column block bottom sheet.
* Update changelog
---
.../src/components/block-variation-picker/style.native.scss | 2 ++
packages/react-native-editor/CHANGELOG.md | 1 +
2 files changed, 3 insertions(+)
diff --git a/packages/block-editor/src/components/block-variation-picker/style.native.scss b/packages/block-editor/src/components/block-variation-picker/style.native.scss
index c8bb66b7a714a0..20b1297a593b15 100644
--- a/packages/block-editor/src/components/block-variation-picker/style.native.scss
+++ b/packages/block-editor/src/components/block-variation-picker/style.native.scss
@@ -27,4 +27,6 @@
.closeIcon {
color: $gray;
+ margin-left: $grid-unit-20;
+ padding: $grid-unit-20;
}
diff --git a/packages/react-native-editor/CHANGELOG.md b/packages/react-native-editor/CHANGELOG.md
index e8fd2e35beeae0..b7bb379c9b9a45 100644
--- a/packages/react-native-editor/CHANGELOG.md
+++ b/packages/react-native-editor/CHANGELOG.md
@@ -10,6 +10,7 @@ For each user feature we should also add a importance categorization label to i
-->
## Unreleased
+- [*] Column block: Fix Android close button alignment. [#34332]
## 1.60.0
- [**] Embed block: Add "Resize for smaller devices" setting. [#33654]
From 0b9114fa9c9372c162ee65762e97bb85a4241073 Mon Sep 17 00:00:00 2001
From: Paul Von Schrottky
Date: Thu, 26 Aug 2021 11:30:09 -0400
Subject: [PATCH 053/214] RNMobile: Fix links, images, and formatting in
documentation (#34300)
* RNMobile: Fix doc links, images and formatting
* Doc links were broken because they used relative paths to files outside of the docs folder
* An image was broken because it didn't use a direct link but instead used a relative link
* Code snippets needed to be indented properly
* Add language specifier to native doc code snippets
---
.../code/getting-started-native-mobile.md | 34 ++++++----
.../native-mobile-integration-test-guide.md | 68 +++++++++----------
docs/contributors/code/native-mobile.md | 2 +-
3 files changed, 52 insertions(+), 52 deletions(-)
diff --git a/docs/contributors/code/getting-started-native-mobile.md b/docs/contributors/code/getting-started-native-mobile.md
index a3dbeedcd98a31..dbdeba751aa503 100644
--- a/docs/contributors/code/getting-started-native-mobile.md
+++ b/docs/contributors/code/getting-started-native-mobile.md
@@ -9,15 +9,15 @@ For a developer experience closer to the one the project maintainers current hav
- git
- [nvm](https://github.com/creationix/nvm)
- Node.js and npm (use nvm to install them)
-- [AndroidStudio](https://developer.android.com/studio/) to be able to compile the Android version of the app
+- [Android Studio](https://developer.android.com/studio/) to be able to compile the Android version of the app
- [Xcode](https://developer.apple.com/xcode/) to be able to compile the iOS app
-- CocoaPods(`sudo gem install cocoapods`) needed to fetch React and third-party dependencies.
+- CocoaPods (`sudo gem install cocoapods`) needed to fetch React and third-party dependencies.
Note that the OS platform used by the maintainers is macOS but the tools and setup should be usable in other platforms too.
## Clone the project
-```
+```sh
git clone https://github.com/WordPress/gutenberg.git
```
@@ -25,14 +25,14 @@ git clone https://github.com/WordPress/gutenberg.git
Note that the commands described here should be run in the top-level directory of the cloned project. Before running the demo app, you need to download and install the project dependencies. This is done via the following command:
-```
+```sh
nvm install
npm ci
```
## Run
-```
+```sh
npm run native start:reset
```
@@ -40,7 +40,7 @@ Runs the packager (Metro) in development mode. The packager stays running to ser
With the packager running, open another terminal window and use the following command to compile and run the Android app:
-```
+```sh
npm run native android
```
@@ -48,7 +48,7 @@ The app should now open in a connected device or a running emulator and fetch th
To compile and run the iOS variant of the app using the _default_ simulator device, use:
-```
+```sh
npm run native ios
```
@@ -58,13 +58,13 @@ which will attempt to open your app in the iOS Simulator if you're on a Mac and
To compile and run the app using a different device simulator, use the following, noting the double sets of `--` to pass the simulator option down to the `react-native` CLI.
-```
+```sh
npm run native ios -- -- --simulator="DEVICE_NAME"
```
For example, if you'd like to run in an iPhone Xs Max, try:
-```
+```sh
npm run native ios -- -- --simulator="iPhone Xs Max"
```
@@ -86,7 +86,7 @@ One of the extensions we are using is the [React Native Tools](https://marketpla
Use the following command to run the test suite:
-```
+```sh
npm run native test
```
@@ -94,7 +94,7 @@ It will run the [jest](https://github.com/facebook/jest) test runner on your tes
To run the tests with debugger support, start it with the following CLI command:
-```
+```sh
npm run native test:debug
```
@@ -114,15 +114,21 @@ This repository uses Appium to run UI tests. The tests live in `__device-tests__
Then, to run the UI tests on iOS:
-`npm run native test:e2e:ios:local`
+```sh
+npm run native test:e2e:ios:local
+```
and for Android:
-`npm run native test:e2e:android:local`
+```sh
+npm run native test:e2e:android:local
+```
To run a single test instead of the entire suite, use `npm run native device-tests:local`. Here's an example that runs only `gutenberg-editor-gallery.test.js`:
-`npm run native test:e2e:android:local gutenberg-editor-gallery.test.js`
+```sh
+npm run native test:e2e:android:local gutenberg-editor-gallery.test.js
+```
Note: You might experience problems that seem to be related to the tests starting the Appium server, e.g. errors that say `Connection Refused`, `Connection Reset` or `The requested environment is not available`. For now, you can manually start the Appium server via [appium desktop](https://github.com/appium/appium-desktop) or the CLI, then change the port number in the tests while (optionally) commenting out related code in the `beforeAll` and `afterAll` block.
diff --git a/docs/contributors/code/native-mobile-integration-test-guide.md b/docs/contributors/code/native-mobile-integration-test-guide.md
index 46bcd271094b2d..14cb479dae1948 100644
--- a/docs/contributors/code/native-mobile-integration-test-guide.md
+++ b/docs/contributors/code/native-mobile-integration-test-guide.md
@@ -27,7 +27,7 @@ This part usually is covered by using the Jest callbacks `beforeAll` and `before
Here is an example of a common pattern if we expect all core blocks to be available:
-```
+```js
beforeAll( () => {
// Register all core blocks
registerCoreBlocks();
@@ -42,7 +42,7 @@ Before introducing the testing logic, we have to render the components that we w
Here is an example of rendering the Cover block (extracted from [this code](https://github.com/WordPress/gutenberg/blob/86cd187873984f80ddeeec3e82454b486dd1860f/packages/block-library/src/cover/test/edit.native.js#L82-L91)):
-```
+```js
// This import points to the index file of the block
import { metadata, settings, name } from '../index';
@@ -83,7 +83,7 @@ const { getByText, findByText } = render(
Here is an example of rendering the Buttons block (extracted from [this code](https://github.com/WordPress/gutenberg/blob/9201906891a68ca305daf7f8b6cd006e2b26291e/packages/block-library/src/buttons/test/edit.native.js#L32-L39)):
-```
+```js
const initialHtml = `
@@ -106,15 +106,15 @@ When querying we should follow this priority order:
Here are some examples:
-```
+```js
const mediaLibraryButton = getByText( 'WordPress Media Library' );
```
-```
+```js
const missingBlock = getByA11yLabel( /Unsupported Block\. Row 1/ );
```
-```
+```js
const radiusSlider = getByTestId( 'Slider Border Radius' );
```
@@ -126,19 +126,19 @@ After rendering the components or firing an event, side effects might happen due
Here are some examples:
-```
+```js
const mediaLibraryButton = await waitFor( () =>
getByText( 'WordPress Media Library' )
);
```
-```
+```js
const missingBlock = await waitFor( () =>
getByA11yLabel( /Unsupported Block\. Row 1/ )
);
```
-```
+```js
const radiusSlider = await waitFor( () =>
getByTestId( 'Slider Border Radius' )
);
@@ -152,13 +152,11 @@ NOTE: The `react-native-testing-library` package provides the `query*` and `find
It’s also possible to query elements contained in other elements via the `within` function, here is an example:
-```
+```js
const missingBlock = await waitFor( () =>
getByA11yLabel( /Unsupported Block\. Row 1/ )
);
-const translatedTableTitle = within( missingBlock ).getByText(
- 'Tabla'
-);
+const translatedTableTitle = within( missingBlock ).getByText( 'Tabla' );
```
## Fire events
@@ -169,7 +167,7 @@ Here is an example of a press event:
**Press event:**
-```
+```js
fireEvent.press( settingsButton );
```
@@ -177,7 +175,7 @@ We can also trigger any type of event, including custom events, in the following
**Custom event – onValueChange:**
-```
+```js
fireEvent( heightSlider, 'valueChange', '50' );
```
@@ -187,18 +185,16 @@ After querying elements and firing events, we have to verify that the logic work
Here is an example:
-```
-const translatedTableTitle = within( missingBlock ).getByText(
- 'Tabla'
-);
+```js
+const translatedTableTitle = within( missingBlock ).getByText( 'Tabla' );
expect( translatedTableTitle ).toBeDefined();
```
Additionally when rendering the entire editor, we can also verify if the HTML output is what we expect:
-```
+```js
expect( getEditorHtml() ).toBe(
-'\n
\n'
+ '\n
\n'
);
```
@@ -206,7 +202,7 @@ expect( getEditorHtml() ).toBe(
And finally, we have to clean up any potential modifications we’ve made that could affect the following tests. Here is an example of a typical cleanup after registering blocks that implies unregistering all blocks:
-```
+```js
afterAll( () => {
// Clean up registered blocks
getBlockTypes().forEach( ( block ) => {
@@ -221,9 +217,9 @@ afterAll( () => {
A common way to query a block is by its accessibility label, here is an example:
-```
+```js
const spacerBlock = await waitFor( () =>
-getByA11yLabel( /Spacer Block\. Row 1/ )
+ getByA11yLabel( /Spacer Block\. Row 1/ )
);
```
@@ -233,7 +229,7 @@ For further information about the accessibility label of a block, you can check
Here is an example of how to insert a Paragraph block:
-```
+```js
// Open the inserter menu
fireEvent.press( await waitFor( () => getByA11yLabel( 'Add block' ) ) );
@@ -255,12 +251,10 @@ fireEvent.press( await waitFor( () => getByText( `Paragraph` ) ) );
The block settings can be accessed by tapping the "Open Settings" button after selecting the block, here is an example:
-```
+```js
fireEvent.press( block );
-const settingsButton = await waitFor( () =>
- getByA11yLabel( 'Open Settings' )
-);
+const settingsButton = await waitFor( () => getByA11yLabel( 'Open Settings' ) );
fireEvent.press( settingsButton );
```
@@ -268,10 +262,10 @@ fireEvent.press( settingsButton );
When using the scoped component approach, we need first to render the `SlotFillProvider` and the `BottomSheetSettings` (note that we’re passing the `isVisible` prop to force the bottom sheet to be displayed) along with the block:
-```
+```js
-
-
+
+
```
@@ -285,7 +279,7 @@ The `FlatList` component renders its items depending on the scroll position, the
Here is an example of the FlatList used for rendering the block list in the inserter menu:
-```
+```js
const blockList = getByTestId( 'InserterUI-Blocks' );
// onScroll event used to force the FlatList to render all items
fireEvent.scroll( blockList, {
@@ -301,7 +295,7 @@ fireEvent.scroll( blockList, {
Sliders found in bottom sheets should be queried using their `testID`:
-```
+```js
const radiusSlider = await waitFor( () =>
getByTestId( 'Slider Border Radius' )
);
@@ -314,7 +308,7 @@ Note that a slider’s `testID` is "Slider " + label. So for a slider with a lab
One caveat when adding blocks is that if they contain inner blocks, these inner blocks are not rendered. The following example shows how we can make a Buttons block render its inner Button blocks (assumes we’ve already obtained a reference to the Buttons block as `buttonsBlock`):
-```
+```js
const innerBlockListWrapper = await waitFor( () =>
within( buttonsBlock ).getByTestId( 'block-list-wrapper' )
);
@@ -338,7 +332,7 @@ fireEvent.press( buttonInnerBlock );
If you have trouble locating an element’s identifier, you may wish to use Xcode’s Accessibility Inspector. Most identifiers are cross-platform, so even though the tests are run on Android by default, the Accessibility Inspector can be used to find the right identifier.
-
+
## Common pitfalls and caveats
@@ -362,7 +356,7 @@ By default, all tests run in Jest use the Android platform, so in case we need t
In case we only need to test logic controlled by the Platform object, we can mock the module with the following code (in this case it’s changing the platform to iOS):
-```
+```js
jest.mock( 'Platform', () => {
const Platform = jest.requireActual( 'Platform' );
Platform.OS = 'ios';
diff --git a/docs/contributors/code/native-mobile.md b/docs/contributors/code/native-mobile.md
index d216720eda4c35..2db44df33fef38 100644
--- a/docs/contributors/code/native-mobile.md
+++ b/docs/contributors/code/native-mobile.md
@@ -21,7 +21,7 @@ Also, the mobile client is packaged and released via the [official WordPress app
If you encounter a failed Android/iOS test on your pull request, we recommend the following steps:
1. Re-running the failed GitHub Action job ([guide for how to re-run](https://docs.github.com/en/actions/configuring-and-managing-workflows/managing-a-workflow-run#viewing-your-workflow-history)) - This should fix failed tests the majority of the time. Cases where you need to re-run tests for a pass should go down in the near future as flakiness in tests is actively being worked on. See the following GitHub issue for updated info on known failures: https://github.com/WordPress/gutenberg/issues/23949
-2. You can check if the test is failing locally by following the steps to run the E2E test on your machine from the [mobile getting started guide](/docs/contributors/code/getting-started-with-code-contribution-native-mobile.md#ui-tests), with even more relevant info in the [relevant directory README.md](https://github.com/WordPress/gutenberg/tree/HEAD/packages/react-native-editor/__device-tests__#running-the-tests-locally)
+2. You can check if the test is failing locally by following the steps to run the E2E test on your machine from the [mobile getting started guide](/docs/contributors/code/getting-started-native-mobile.md#ui-tests), with even more relevant info in the [relevant directory README.md](https://github.com/WordPress/gutenberg/tree/HEAD/packages/react-native-editor/__device-tests__#running-the-tests-locally)
3. In addition to reading the logs from the E2E test, you can download a video recording from the Artifacts section of the GitHub job that may have additional useful information.
4. Check if any changes in your PR would require corresponding changes to `.native.js` versions of files.
5. Lastly, if you're stuck on a failing mobile test, feel free to reach out to contributors on Slack in the #mobile or #core-editor chats in the WordPress Core Slack, [free to join](https://make.wordpress.org/chat/).
From a31cb9551c58b62d651c72999df2776641d81200 Mon Sep 17 00:00:00 2001
From: Joen A <1204802+jasmussen@users.noreply.github.com>
Date: Thu, 26 Aug 2021 17:40:01 +0200
Subject: [PATCH 054/214] Try: Vertical heading levels menu (#32926)
---
.../block-library/src/heading/editor.scss | 14 +---
.../src/heading/heading-level-dropdown.js | 84 ++++++-------------
.../components/src/dropdown-menu/index.js | 2 +
.../components/src/dropdown-menu/style.scss | 5 ++
4 files changed, 34 insertions(+), 71 deletions(-)
diff --git a/packages/block-library/src/heading/editor.scss b/packages/block-library/src/heading/editor.scss
index a1af2ba3702442..f70daaf4d3e652 100644
--- a/packages/block-library/src/heading/editor.scss
+++ b/packages/block-library/src/heading/editor.scss
@@ -1,20 +1,8 @@
// Remove padding in heading level control popover since the toolbar buttons already have padding.
.block-library-heading-level-dropdown .components-popover__content {
- // TODO: Find a less hardcoded way of doing this. `max-content` works on
- // Chromium, but it results in a scrollbar on Safari, and isn't supported
- // at all in IE11.
- min-width: 230px;
+ min-width: auto;
> div {
padding: 0;
}
}
-
-// The dropdown already has a border, so we can remove the one on the heading
-// level toolbar.
-.block-library-heading-level-toolbar {
- border: none;
- .components-toolbar-group {
- flex-wrap: nowrap;
- }
-}
diff --git a/packages/block-library/src/heading/heading-level-dropdown.js b/packages/block-library/src/heading/heading-level-dropdown.js
index 84d00181b71297..592787b5fa9ddc 100644
--- a/packages/block-library/src/heading/heading-level-dropdown.js
+++ b/packages/block-library/src/heading/heading-level-dropdown.js
@@ -1,14 +1,8 @@
/**
* WordPress dependencies
*/
-import {
- Dropdown,
- Toolbar,
- ToolbarButton,
- ToolbarGroup,
-} from '@wordpress/components';
+import { ToolbarDropdownMenu } from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
-import { DOWN } from '@wordpress/keycodes';
/**
* Internal dependencies
@@ -19,7 +13,6 @@ const HEADING_LEVELS = [ 1, 2, 3, 4, 5, 6 ];
const POPOVER_PROPS = {
className: 'block-library-heading-level-dropdown',
- isAlternate: true,
};
/** @typedef {import('@wordpress/element').WPComponent} WPComponent */
@@ -43,58 +36,33 @@ const POPOVER_PROPS = {
*/
export default function HeadingLevelDropdown( { selectedLevel, onChange } ) {
return (
-
{
- const openOnArrowDown = ( event ) => {
- if ( ! isOpen && event.keyCode === DOWN ) {
- event.preventDefault();
- onToggle();
- }
- };
+ icon={ }
+ label={ __( 'Change heading level' ) }
+ controls={ HEADING_LEVELS.map( ( targetLevel ) => {
+ {
+ const isActive = targetLevel === selectedLevel;
- return (
- }
- label={ __( 'Change heading level' ) }
- onClick={ onToggle }
- onKeyDown={ openOnArrowDown }
- showTooltip
- />
- );
- } }
- renderContent={ () => (
-
- {
- const isActive = targetLevel === selectedLevel;
- return {
- icon: (
-
- ),
- title: sprintf(
- // translators: %s: heading level e.g: "1", "2", "3"
- __( 'Heading %d' ),
- targetLevel
- ),
- isActive,
- onClick() {
- onChange( targetLevel );
- },
- };
- } ) }
- />
-
- ) }
+ return {
+ icon: (
+
+ ),
+ label: sprintf(
+ // translators: %s: heading level e.g: "1", "2", "3"
+ __( 'Heading %d' ),
+ targetLevel
+ ),
+ isActive,
+ onClick() {
+ onChange( targetLevel );
+ },
+ };
+ }
+ } ) }
/>
);
}
diff --git a/packages/components/src/dropdown-menu/index.js b/packages/components/src/dropdown-menu/index.js
index 9f734f31a317c0..f2ae27cd91e7d7 100644
--- a/packages/components/src/dropdown-menu/index.js
+++ b/packages/components/src/dropdown-menu/index.js
@@ -173,9 +173,11 @@ function DropdownMenu( {
indexOfSet > 0 &&
indexOfControl === 0,
'is-active': control.isActive,
+ 'is-icon-only': ! control.title,
}
) }
icon={ control.icon }
+ label={ control.label }
aria-checked={
control.role === 'menuitemcheckbox' ||
control.role === 'menuitemradio'
diff --git a/packages/components/src/dropdown-menu/style.scss b/packages/components/src/dropdown-menu/style.scss
index 958ac9b5a3caeb..60e1a91270294f 100644
--- a/packages/components/src/dropdown-menu/style.scss
+++ b/packages/components/src/dropdown-menu/style.scss
@@ -44,6 +44,11 @@
width: $button-size-small;
height: $button-size-small;
}
+
+ // If menu items are icon-only, make them stretch only to the icon size.
+ &.is-icon-only {
+ width: auto;
+ }
}
.components-menu-item__button,
From 5fd2c0919ed8644bb61e3dc7cbf19f859d1ae7f6 Mon Sep 17 00:00:00 2001
From: Paul Von Schrottky
Date: Thu, 26 Aug 2021 17:05:56 -0400
Subject: [PATCH 055/214] Update userAgent to be string instead of array
(#34308)
This change fixes issues that could arise with third-party code in Gutenberg Mobile which expects the userAgent to be a string.
---
packages/react-native-editor/src/globals.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/react-native-editor/src/globals.js b/packages/react-native-editor/src/globals.js
index 4e66ecb2c63939..cea706b35c1377 100644
--- a/packages/react-native-editor/src/globals.js
+++ b/packages/react-native-editor/src/globals.js
@@ -59,7 +59,7 @@ if ( ! global.window.matchMedia ) {
} );
}
-global.window.navigator.userAgent = [];
+global.window.navigator.userAgent = global.window.navigator.userAgent ?? '';
// Leverages existing console polyfill from react-native
global.nativeLoggingHook = nativeLoggingHook;
From d72c07625ad9721e3fd6df0d2409ea3b61e42b2a Mon Sep 17 00:00:00 2001
From: Gerardo Pacheco
Date: Thu, 26 Aug 2021 23:59:59 +0200
Subject: [PATCH 056/214] Mobile Release v1.60.1 (#34294)
* Release script: Update react-native-editor version to 1.60.0
* Release script: Update with changes from 'npm run core preios'
* Update changelog
* Release script: Update react-native-editor version to 1.60.1
* Release script: Update with changes from 'npm run core preios'
* RNmobile: Fix the cancel button on Columns Block (#34249)
* Mobile - Update changelog
* Fix Column bottom sheet Android close button (#34332)
* Fix Column bottom sheet Android close button
Apply required margin and padding to properly align Android close
button in the Column block bottom sheet.
* Update changelog
* Mobile - Update changelog
Co-authored-by: Enej Bajgoric
Co-authored-by: David Calhoun <438664+dcalhoun@users.noreply.github.com>
---
packages/react-native-aztec/package.json | 2 +-
packages/react-native-bridge/package.json | 2 +-
packages/react-native-editor/CHANGELOG.md | 3 +++
packages/react-native-editor/ios/Podfile.lock | 8 ++++----
packages/react-native-editor/package.json | 2 +-
5 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/packages/react-native-aztec/package.json b/packages/react-native-aztec/package.json
index dbfee6b32a2da1..f188e0722eac0d 100644
--- a/packages/react-native-aztec/package.json
+++ b/packages/react-native-aztec/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/react-native-aztec",
- "version": "1.60.0",
+ "version": "1.60.1",
"description": "Aztec view for react-native.",
"private": true,
"author": "The WordPress Contributors",
diff --git a/packages/react-native-bridge/package.json b/packages/react-native-bridge/package.json
index 04a797846903c4..e0ffa44432a45f 100644
--- a/packages/react-native-bridge/package.json
+++ b/packages/react-native-bridge/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/react-native-bridge",
- "version": "1.60.0",
+ "version": "1.60.1",
"description": "Native bridge library used to integrate the block editor into a native App.",
"private": true,
"author": "The WordPress Contributors",
diff --git a/packages/react-native-editor/CHANGELOG.md b/packages/react-native-editor/CHANGELOG.md
index b7bb379c9b9a45..663f41c835aede 100644
--- a/packages/react-native-editor/CHANGELOG.md
+++ b/packages/react-native-editor/CHANGELOG.md
@@ -10,6 +10,9 @@ For each user feature we should also add a importance categorization label to i
-->
## Unreleased
+
+## 1.60.1
+- [*] RNmobile: Fix the cancel button on Block Variation Picker / Columns Block. [#34249]
- [*] Column block: Fix Android close button alignment. [#34332]
## 1.60.0
diff --git a/packages/react-native-editor/ios/Podfile.lock b/packages/react-native-editor/ios/Podfile.lock
index a33a78ec390365..6a01df08345d4a 100644
--- a/packages/react-native-editor/ios/Podfile.lock
+++ b/packages/react-native-editor/ios/Podfile.lock
@@ -12,7 +12,7 @@ PODS:
- React-jsi (= 0.64.0)
- ReactCommon/turbomodule/core (= 0.64.0)
- glog (0.3.5)
- - Gutenberg (1.60.0):
+ - Gutenberg (1.60.1):
- React-Core (= 0.64.0)
- React-CoreModules (= 0.64.0)
- React-RCTImage (= 0.64.0)
@@ -303,7 +303,7 @@ PODS:
- React-Core
- RNSVG (9.13.7-wp):
- React-Core
- - RNTAztecView (1.60.0):
+ - RNTAztecView (1.60.1):
- React-Core
- WordPress-Aztec-iOS (~> 1.19.4)
- WordPress-Aztec-iOS (1.19.4)
@@ -459,7 +459,7 @@ SPEC CHECKSUMS:
FBLazyVector: 49cbe4b43e445b06bf29199b6ad2057649e4c8f5
FBReactNativeSpec: 80e9cf1155002ee4720084d8813326d913815e2f
glog: 73c2498ac6884b13ede40eda8228cb1eee9d9d62
- Gutenberg: d18ce5f2f99f78cd9c758d89d37c82a91be5cadd
+ Gutenberg: bc75d848519ff99520b0109a3d7f9c6f82caeae7
RCT-Folly: ec7a233ccc97cc556cf7237f0db1ff65b986f27c
RCTRequired: 2f8cb5b7533219bf4218a045f92768129cf7050a
RCTTypeSafety: 512728b73549e72ad7330b92f3d42936f2a4de5b
@@ -496,7 +496,7 @@ SPEC CHECKSUMS:
RNReanimated: ca6105fdc2739ea1b3a7a5350b6490d8160143bc
RNScreens: eb4e23256e7f2a5a1af87ea24dfeb49aea0ef310
RNSVG: 1b6dcbec5884b6dbe256bf8c38eeeab0acf05926
- RNTAztecView: 9ad0125ab87d59989d5279cdfdc2863e068059cb
+ RNTAztecView: 9611e25a2e52d206e7979081294b7c40c20d1bd5
WordPress-Aztec-iOS: 870c93297849072aadfc2223e284094e73023e82
Yoga: 8c8436d4171c87504c648ae23b1d81242bdf3bbf
diff --git a/packages/react-native-editor/package.json b/packages/react-native-editor/package.json
index 80aadd8c241ca8..91e4b9246ad81e 100644
--- a/packages/react-native-editor/package.json
+++ b/packages/react-native-editor/package.json
@@ -1,6 +1,6 @@
{
"name": "@wordpress/react-native-editor",
- "version": "1.60.0",
+ "version": "1.60.1",
"description": "Mobile WordPress gutenberg editor.",
"author": "The WordPress Contributors",
"license": "GPL-2.0-or-later",
From b18b086b6823de5255b5bc2058974e0171ac3a34 Mon Sep 17 00:00:00 2001
From: Jason Johnston
Date: Thu, 26 Aug 2021 18:09:29 -0400
Subject: [PATCH 057/214] Only handle keyboard hiding on Android (#34336)
Co-authored-by: jhnstn
---
packages/components/src/search-control/index.native.js | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/packages/components/src/search-control/index.native.js b/packages/components/src/search-control/index.native.js
index 6797c0c6a0bd95..2bf19b8a42b54b 100644
--- a/packages/components/src/search-control/index.native.js
+++ b/packages/components/src/search-control/index.native.js
@@ -121,7 +121,9 @@ function SearchControl( {
const keyboardHideSubscription = Keyboard.addListener(
'keyboardDidHide',
() => {
- onCancel();
+ if ( ! isIOS ) {
+ onCancel();
+ }
}
);
return () => {
From d75d953285df3d68bed216b0d58413f5591601f4 Mon Sep 17 00:00:00 2001
From: Andrew Serong <14988353+andrewserong@users.noreply.github.com>
Date: Fri, 27 Aug 2021 10:29:46 +1000
Subject: [PATCH 058/214] Add getFilename method to the url package (#34313)
* Add getFilename method to url package
* Update File block transform to use getFilename
* Update Image and Video blocks to use getFilename method
---
packages/block-library/src/file/transforms.js | 7 ++--
packages/block-library/src/image/image.js | 11 +-----
.../block-library/src/video/tracks-editor.js | 5 +--
packages/url/README.md | 19 ++++++++++
packages/url/src/get-filename.js | 25 ++++++++++++
packages/url/src/index.js | 1 +
packages/url/src/test/index.js | 38 +++++++++++++++++++
7 files changed, 90 insertions(+), 16 deletions(-)
create mode 100644 packages/url/src/get-filename.js
diff --git a/packages/block-library/src/file/transforms.js b/packages/block-library/src/file/transforms.js
index 242b60adfd7354..3f96667b14745e 100644
--- a/packages/block-library/src/file/transforms.js
+++ b/packages/block-library/src/file/transforms.js
@@ -10,7 +10,7 @@ import { createBlobURL } from '@wordpress/blob';
import { createBlock } from '@wordpress/blocks';
import { select } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
-import { getPath } from '@wordpress/url';
+import { getFilename } from '@wordpress/url';
const transforms = {
from: [
@@ -71,11 +71,10 @@ const transforms = {
type: 'block',
blocks: [ 'core/image' ],
transform: ( attributes ) => {
- const filename = getPath( attributes.url )?.split( '/' ).pop();
-
return createBlock( 'core/file', {
href: attributes.url,
- fileName: attributes.caption || filename,
+ fileName:
+ attributes.caption || getFilename( attributes.url ),
textLinkHref: attributes.url,
id: attributes.id,
anchor: attributes.anchor,
diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js
index b4cc2c29f6252a..dedd8786534be5 100644
--- a/packages/block-library/src/image/image.js
+++ b/packages/block-library/src/image/image.js
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import { get, filter, map, last, pick, includes } from 'lodash';
+import { get, filter, map, pick, includes } from 'lodash';
/**
* WordPress dependencies
@@ -30,7 +30,7 @@ import {
} from '@wordpress/block-editor';
import { useEffect, useState, useRef } from '@wordpress/element';
import { __, sprintf, isRTL } from '@wordpress/i18n';
-import { getPath } from '@wordpress/url';
+import { getFilename } from '@wordpress/url';
import { createBlock, switchToBlockType } from '@wordpress/blocks';
import { crop, overlayText, upload } from '@wordpress/icons';
import { store as noticesStore } from '@wordpress/notices';
@@ -49,13 +49,6 @@ import { isExternalImage } from './edit';
*/
import { MIN_SIZE, ALLOWED_MEDIA_TYPES } from './constants';
-function getFilename( url ) {
- const path = getPath( url );
- if ( path ) {
- return last( path.split( '/' ) );
- }
-}
-
export default function Image( {
temporaryURL,
attributes: {
diff --git a/packages/block-library/src/video/tracks-editor.js b/packages/block-library/src/video/tracks-editor.js
index 04f3f04f73cd05..9fcbbd5d4581c7 100644
--- a/packages/block-library/src/video/tracks-editor.js
+++ b/packages/block-library/src/video/tracks-editor.js
@@ -24,6 +24,7 @@ import {
import { upload, media } from '@wordpress/icons';
import { useSelect } from '@wordpress/data';
import { useState } from '@wordpress/element';
+import { getFilename } from '@wordpress/url';
const ALLOWED_TYPES = [ 'text/vtt' ];
@@ -99,9 +100,7 @@ function TrackList( { tracks, onEditPress } ) {
function SingleTrackEditor( { track, onChange, onClose, onRemove } ) {
const { src = '', label = '', srcLang = '', kind = DEFAULT_KIND } = track;
- const fileName = src.startsWith( 'blob:' )
- ? ''
- : src.substring( src.lastIndexOf( '/' ) + 1 );
+ const fileName = src.startsWith( 'blob:' ) ? '' : getFilename( src ) || '';
return (
diff --git a/packages/url/README.md b/packages/url/README.md
index d6b338071b1b96..367ba4c0675677 100644
--- a/packages/url/README.md
+++ b/packages/url/README.md
@@ -132,6 +132,25 @@ _Returns_
- `string|void`: The authority part of the URL.
+### getFilename
+
+Returns the filename part of the URL.
+
+_Usage_
+
+```js
+const filename1 = getFilename( 'http://localhost:8080/this/is/a/test.jpg' ); // 'test.jpg'
+const filename2 = getFilename( '/this/is/a/test.png' ); // 'test.png'
+```
+
+_Parameters_
+
+- _url_ `string`: The full URL.
+
+_Returns_
+
+- `string|void`: The filename part of the URL.
+
### getFragment
Returns the fragment part of the URL.
diff --git a/packages/url/src/get-filename.js b/packages/url/src/get-filename.js
new file mode 100644
index 00000000000000..2941f18fe07b4d
--- /dev/null
+++ b/packages/url/src/get-filename.js
@@ -0,0 +1,25 @@
+/**
+ * Returns the filename part of the URL.
+ *
+ * @param {string} url The full URL.
+ *
+ * @example
+ * ```js
+ * const filename1 = getFilename( 'http://localhost:8080/this/is/a/test.jpg' ); // 'test.jpg'
+ * const filename2 = getFilename( '/this/is/a/test.png' ); // 'test.png'
+ * ```
+ *
+ * @return {string|void} The filename part of the URL.
+ */
+export function getFilename( url ) {
+ let filename;
+ try {
+ filename = new URL( url, 'http://example.com' ).pathname
+ .split( '/' )
+ .pop();
+ } catch ( error ) {}
+
+ if ( filename ) {
+ return filename;
+ }
+}
diff --git a/packages/url/src/index.js b/packages/url/src/index.js
index f060ae8152897d..eb4ee3237fab8e 100644
--- a/packages/url/src/index.js
+++ b/packages/url/src/index.js
@@ -22,3 +22,4 @@ export { safeDecodeURI } from './safe-decode-uri';
export { safeDecodeURIComponent } from './safe-decode-uri-component';
export { filterURLForDisplay } from './filter-url-for-display';
export { cleanForSlug } from './clean-for-slug';
+export { getFilename } from './get-filename';
diff --git a/packages/url/src/test/index.js b/packages/url/src/test/index.js
index f4814b0b0bc83b..51bb69419bfa60 100644
--- a/packages/url/src/test/index.js
+++ b/packages/url/src/test/index.js
@@ -29,6 +29,7 @@ import {
filterURLForDisplay,
cleanForSlug,
getQueryArgs,
+ getFilename,
} from '../';
import wptData from './fixtures/wpt-data';
@@ -240,6 +241,7 @@ describe( 'isValidPath', () => {
expect( isValidPath( 'relative/path' ) ).toBe( true );
expect( isValidPath( 'slightly/longer/path/' ) ).toBe( true );
expect( isValidPath( 'path/with/percent%20encoding' ) ).toBe( true );
+ expect( isValidPath( '/' ) ).toBe( true );
} );
it( 'returns false if the path is invalid', () => {
@@ -252,6 +254,42 @@ describe( 'isValidPath', () => {
} );
} );
+describe( 'getFilename', () => {
+ it( 'returns the filename part of the URL', () => {
+ expect( getFilename( 'https://wordpress.org/image.jpg' ) ).toBe(
+ 'image.jpg'
+ );
+ expect(
+ getFilename( 'https://wordpress.org/image.jpg?query=test' )
+ ).toBe( 'image.jpg' );
+ expect( getFilename( 'https://wordpress.org/image.jpg#anchor' ) ).toBe(
+ 'image.jpg'
+ );
+ expect(
+ getFilename( 'http://localhost:8080/a/path/to/an/image.jpg' )
+ ).toBe( 'image.jpg' );
+ expect( getFilename( '/path/to/an/image.jpg' ) ).toBe( 'image.jpg' );
+ expect( getFilename( 'path/to/an/image.jpg' ) ).toBe( 'image.jpg' );
+ expect( getFilename( '/image.jpg' ) ).toBe( 'image.jpg' );
+ expect( getFilename( 'image.jpg' ) ).toBe( 'image.jpg' );
+ } );
+
+ it( 'returns undefined when the provided value does not contain a filename', () => {
+ expect( getFilename( 'http://localhost:8080/' ) ).toBe( undefined );
+ expect( getFilename( 'http://localhost:8080/a/path/' ) ).toBe(
+ undefined
+ );
+ expect( getFilename( 'http://localhost:8080/?query=test' ) ).toBe(
+ undefined
+ );
+ expect( getFilename( 'http://localhost:8080/#anchor' ) ).toBe(
+ undefined
+ );
+ expect( getFilename( 'a/path/' ) ).toBe( undefined );
+ expect( getFilename( '/' ) ).toBe( undefined );
+ } );
+} );
+
describe( 'getQueryString', () => {
it( 'returns the query string of a URL', () => {
expect(
From 807cac1dc98e4fc526d18a92f8b5978c8dc97619 Mon Sep 17 00:00:00 2001
From: Daniel Richards
Date: Fri, 27 Aug 2021 10:23:11 +0800
Subject: [PATCH 059/214] Fix button block focus trap after a URL has been
added (#34314)
* Rework button block link UI to match RichText format implementation
* Refine some more, determine visibility by selection and url state
* Add e2e test
* Also focus rich text when unlinking using a keyboard shortcut
---
packages/block-library/src/button/edit.js | 61 +++++++++++++------
.../specs/editor/blocks/buttons.test.js | 30 +++++++++
2 files changed, 74 insertions(+), 17 deletions(-)
diff --git a/packages/block-library/src/button/edit.js b/packages/block-library/src/button/edit.js
index fd7bb6edde87c3..0520144fb3b9ca 100644
--- a/packages/block-library/src/button/edit.js
+++ b/packages/block-library/src/button/edit.js
@@ -7,7 +7,7 @@ import classnames from 'classnames';
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
-import { useCallback, useState, useRef } from '@wordpress/element';
+import { useCallback, useEffect, useState, useRef } from '@wordpress/element';
import {
Button,
ButtonGroup,
@@ -73,27 +73,42 @@ function URLPicker( {
opensInNewTab,
onToggleOpenInNewTab,
anchorRef,
+ richTextRef,
} ) {
- const [ isURLPickerOpen, setIsURLPickerOpen ] = useState( false );
- const urlIsSet = !! url;
- const urlIsSetandSelected = urlIsSet && isSelected;
- const openLinkControl = () => {
- setIsURLPickerOpen( true );
- return false; // prevents default behaviour for event
+ const [ isEditingURL, setIsEditingURL ] = useState( false );
+ const isURLSet = !! url;
+
+ const startEditing = ( event ) => {
+ event.preventDefault();
+ setIsEditingURL( true );
};
- const unlinkButton = () => {
+
+ const unlink = () => {
setAttributes( {
url: undefined,
linkTarget: undefined,
rel: undefined,
} );
- setIsURLPickerOpen( false );
+ setIsEditingURL( false );
};
- const linkControl = ( isURLPickerOpen || urlIsSetandSelected ) && (
+
+ useEffect( () => {
+ if ( ! isSelected ) {
+ setIsEditingURL( false );
+ }
+ }, [ isSelected ] );
+
+ const isLinkControlVisible = isSelected && ( isEditingURL || isURLSet );
+
+ const linkControl = isLinkControlVisible && (
setIsURLPickerOpen( false ) }
+ onClose={ () => {
+ setIsEditingURL( false );
+ richTextRef.current?.focus();
+ } }
anchorRef={ anchorRef?.current }
+ focusOnMount={ isEditingURL ? 'firstElement' : false }
>
{
+ unlink();
+ richTextRef.current?.focus();
+ } }
+ forceIsEditingLink={ isEditingURL }
/>
);
+
return (
<>
- { ! urlIsSet && (
+ { ! isURLSet && (
) }
- { urlIsSetandSelected && (
+ { isURLSet && (
) }
@@ -138,8 +159,11 @@ function URLPicker( {
{
+ unlink();
+ richTextRef.current?.focus();
+ },
} }
/>
) }
@@ -201,6 +225,7 @@ function ButtonEdit( props ) {
const colorProps = useColorProps( attributes );
const spacingProps = useSpacingProps( attributes );
const ref = useRef();
+ const richTextRef = useRef();
const blockProps = useBlockProps( { ref } );
return (
@@ -213,6 +238,7 @@ function ButtonEdit( props ) {
} ) }
>
{
expect( await getEditedPostContent() ).toMatchSnapshot();
} );
+ it( 'moves focus from the link editor back to the button when escape is pressed after the URL has been submitted', async () => {
+ // Regression: https://github.com/WordPress/gutenberg/issues/34307
+ await insertBlock( 'Buttons' );
+ await pressKeyWithModifier( 'primary', 'k' );
+ await page.waitForFunction(
+ () => !! document.activeElement.closest( '.block-editor-url-input' )
+ );
+ await page.keyboard.type( 'https://example.com' );
+ await page.keyboard.press( 'Enter' );
+ await page.waitForFunction(
+ () =>
+ document.activeElement ===
+ document.querySelector(
+ '.block-editor-link-control a[href="https://example.com"]'
+ )
+ );
+ await page.keyboard.press( 'Escape' );
+
+ // Focus should move from the link control to the button block's text.
+ await page.waitForFunction(
+ () =>
+ document.activeElement ===
+ document.querySelector( '[aria-label="Button text"]' )
+ );
+
+ // The link control should still be visible when a URL is set.
+ const linkControl = await page.$( '.block-editor-link-control' );
+ expect( linkControl ).toBeTruthy();
+ } );
+
it( 'can jump to the link editor using the keyboard shortcut', async () => {
await insertBlock( 'Buttons' );
await page.keyboard.type( 'WordPress' );
From 46553eaea9b308b80786eadb1970d6c1ec609d0e Mon Sep 17 00:00:00 2001
From: Ramon
Date: Fri, 27 Aug 2021 19:23:08 +1000
Subject: [PATCH 060/214] i18n: Add context to 'none' strings for better
translations (#34341)
* Adding context to 'none' strings, and also implementing suggestions from #22095
This is because "None" can be translated differently in languages other than English depending on the context.
* As always, my linter was asleep
---
packages/block-library/src/audio/edit.js | 9 ++++++---
packages/block-library/src/audio/edit.native.js | 12 +++++++++---
packages/block-library/src/button/edit.native.js | 7 +++++--
packages/block-library/src/gallery/edit.js | 7 +++++--
packages/block-library/src/image/edit.native.js | 7 +++++--
.../block-library/src/video/edit-common-settings.js | 4 ++--
packages/components/src/dimension-control/sizes.js | 12 ++++++------
7 files changed, 38 insertions(+), 20 deletions(-)
diff --git a/packages/block-library/src/audio/edit.js b/packages/block-library/src/audio/edit.js
index c2fe191252a931..22b0ad592eb484 100644
--- a/packages/block-library/src/audio/edit.js
+++ b/packages/block-library/src/audio/edit.js
@@ -20,7 +20,7 @@ import {
store as blockEditorStore,
} from '@wordpress/block-editor';
import { useEffect } from '@wordpress/element';
-import { __ } from '@wordpress/i18n';
+import { __, _x } from '@wordpress/i18n';
import { useSelect } from '@wordpress/data';
import { audio as icon } from '@wordpress/icons';
import { createBlock } from '@wordpress/blocks';
@@ -157,7 +157,7 @@ function AudioEdit( {
checked={ loop }
/>
@@ -169,7 +169,10 @@ function AudioEdit( {
{ value: '', label: __( 'Browser default' ) },
{ value: 'auto', label: __( 'Auto' ) },
{ value: 'metadata', label: __( 'Metadata' ) },
- { value: 'none', label: __( 'None' ) },
+ {
+ value: 'none',
+ label: _x( 'None', '"Preload" value' ),
+ },
] }
/>
diff --git a/packages/block-library/src/audio/edit.native.js b/packages/block-library/src/audio/edit.native.js
index a46a3b57e46e35..a86abf369bd03c 100644
--- a/packages/block-library/src/audio/edit.native.js
+++ b/packages/block-library/src/audio/edit.native.js
@@ -26,7 +26,7 @@ import {
MediaUploadProgress,
store as blockEditorStore,
} from '@wordpress/block-editor';
-import { __, sprintf } from '@wordpress/i18n';
+import { __, _x, sprintf } from '@wordpress/i18n';
import { audio as icon, replace } from '@wordpress/icons';
import { useState } from '@wordpress/element';
import { useDispatch, useSelect } from '@wordpress/data';
@@ -197,7 +197,10 @@ function AudioEdit( {
checked={ loop }
/>
@@ -209,7 +212,10 @@ function AudioEdit( {
{ value: '', label: __( 'Browser default' ) },
{ value: 'auto', label: __( 'Auto' ) },
{ value: 'metadata', label: __( 'Metadata' ) },
- { value: 'none', label: __( 'None' ) },
+ {
+ value: 'none',
+ label: _x( 'None', '"Preload" value' ),
+ },
] }
hideCancelButton={ true }
/>
diff --git a/packages/block-library/src/button/edit.native.js b/packages/block-library/src/button/edit.native.js
index a06f5d06adccbe..ec9741fe5add4d 100644
--- a/packages/block-library/src/button/edit.native.js
+++ b/packages/block-library/src/button/edit.native.js
@@ -6,7 +6,7 @@ import { View, AccessibilityInfo, Platform, Text } from 'react-native';
* WordPress dependencies
*/
import { withInstanceId, compose } from '@wordpress/compose';
-import { __ } from '@wordpress/i18n';
+import { __, _x } from '@wordpress/i18n';
import {
RichText,
InspectorControls,
@@ -136,7 +136,10 @@ class ButtonEdit extends Component {
},
linkRel: {
label: __( 'Link Rel' ),
- placeholder: __( 'None' ),
+ placeholder: _x(
+ 'None',
+ 'Link rel attribute value placeholder'
+ ),
},
};
diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js
index 3a1fa9c990b952..ec4f274751580c 100644
--- a/packages/block-library/src/gallery/edit.js
+++ b/packages/block-library/src/gallery/edit.js
@@ -24,7 +24,7 @@ import {
useBlockProps,
} from '@wordpress/block-editor';
import { Platform, useEffect, useMemo } from '@wordpress/element';
-import { __, sprintf } from '@wordpress/i18n';
+import { __, _x, sprintf } from '@wordpress/i18n';
import { useSelect, useDispatch } from '@wordpress/data';
import { withViewportMatch } from '@wordpress/viewport';
import { View } from '@wordpress/primitives';
@@ -57,7 +57,10 @@ const MAX_COLUMNS = 8;
const linkOptions = [
{ value: LINK_DESTINATION_ATTACHMENT, label: __( 'Attachment Page' ) },
{ value: LINK_DESTINATION_MEDIA, label: __( 'Media File' ) },
- { value: LINK_DESTINATION_NONE, label: __( 'None' ) },
+ {
+ value: LINK_DESTINATION_NONE,
+ label: _x( 'None', 'Media item link option' ),
+ },
];
const ALLOWED_MEDIA_TYPES = [ 'image' ];
diff --git a/packages/block-library/src/image/edit.native.js b/packages/block-library/src/image/edit.native.js
index 54174c3607a74b..1233abbcdca605 100644
--- a/packages/block-library/src/image/edit.native.js
+++ b/packages/block-library/src/image/edit.native.js
@@ -42,7 +42,7 @@ import {
BlockStyles,
store as blockEditorStore,
} from '@wordpress/block-editor';
-import { __, sprintf } from '@wordpress/i18n';
+import { __, _x, sprintf } from '@wordpress/i18n';
import { getProtocol, hasQueryArg } from '@wordpress/url';
import { doAction, hasAction } from '@wordpress/hooks';
import { compose, withPreferredColorScheme } from '@wordpress/compose';
@@ -121,7 +121,10 @@ export class ImageEdit extends Component {
},
linkRel: {
label: __( 'Link Rel' ),
- placeholder: __( 'None' ),
+ placeholder: _x(
+ 'None',
+ 'Link rel attribute value placeholder'
+ ),
},
};
}
diff --git a/packages/block-library/src/video/edit-common-settings.js b/packages/block-library/src/video/edit-common-settings.js
index 74067cbd7dd8d4..5cd74c41bec92a 100644
--- a/packages/block-library/src/video/edit-common-settings.js
+++ b/packages/block-library/src/video/edit-common-settings.js
@@ -1,14 +1,14 @@
/**
* WordPress dependencies
*/
-import { __ } from '@wordpress/i18n';
+import { __, _x } from '@wordpress/i18n';
import { ToggleControl, SelectControl } from '@wordpress/components';
import { useMemo, useCallback, Platform } from '@wordpress/element';
const options = [
{ value: 'auto', label: __( 'Auto' ) },
{ value: 'metadata', label: __( 'Metadata' ) },
- { value: 'none', label: __( 'None' ) },
+ { value: 'none', label: _x( 'None', 'Preload value' ) },
];
const VideoSettings = ( { setAttributes, attributes } ) => {
diff --git a/packages/components/src/dimension-control/sizes.js b/packages/components/src/dimension-control/sizes.js
index 4a77ef25ff7734..55dcff9698d4e4 100644
--- a/packages/components/src/dimension-control/sizes.js
+++ b/packages/components/src/dimension-control/sizes.js
@@ -10,7 +10,7 @@
/**
* WordPress dependencies
*/
-import { __ } from '@wordpress/i18n';
+import { _x } from '@wordpress/i18n';
/**
* Finds the correct size object from the provided sizes
@@ -26,23 +26,23 @@ export const findSizeBySlug = ( sizes, slug ) =>
export default [
{
- name: __( 'None' ),
+ name: _x( 'None', 'Size of a UI element' ),
slug: 'none',
},
{
- name: __( 'Small' ),
+ name: _x( 'Small', 'Size of a UI element' ),
slug: 'small',
},
{
- name: __( 'Medium' ),
+ name: _x( 'Medium', 'Size of a UI element' ),
slug: 'medium',
},
{
- name: __( 'Large' ),
+ name: _x( 'Large', 'Size of a UI element' ),
slug: 'large',
},
{
- name: __( 'Extra Large' ),
+ name: _x( 'Extra Large', 'Size of a UI element' ),
slug: 'xlarge',
},
];
From f42fa3aaaaf8a0a6feca9cced6f9d0e6beb49cdd Mon Sep 17 00:00:00 2001
From: Jeremy Yip
Date: Fri, 27 Aug 2021 02:25:40 -0700
Subject: [PATCH 061/214] Global Styles: Fix block-level global styles color
panels (#34293)
Check if block color support have been explicitly opted out
BackgroundColor and color are opt-out block supports: they're enabled if there's support for any color unless the block opts-out from them explicitly. Global styles UI panels were't respecting this opt out process, which is why we add logic to validate whether or not a block has turned off background color and color supports.
---
packages/blocks/src/api/constants.js | 6 +-
.../editor/global-styles-provider.js | 20 ++-
.../editor/test/global-styles-provider.js | 131 ++++++++++++++++++
3 files changed, 153 insertions(+), 4 deletions(-)
create mode 100644 packages/edit-site/src/components/editor/test/global-styles-provider.js
diff --git a/packages/blocks/src/api/constants.js b/packages/blocks/src/api/constants.js
index 18342aa9162565..d7ce7cafd25261 100644
--- a/packages/blocks/src/api/constants.js
+++ b/packages/blocks/src/api/constants.js
@@ -24,7 +24,8 @@ export const __EXPERIMENTAL_STYLE_PROPERTY = {
},
backgroundColor: {
value: [ 'color', 'background' ],
- support: [ 'color' ],
+ support: [ 'color', 'background' ],
+ requiresOptOut: true,
},
borderColor: {
value: [ 'border', 'color' ],
@@ -50,7 +51,8 @@ export const __EXPERIMENTAL_STYLE_PROPERTY = {
},
color: {
value: [ 'color', 'text' ],
- support: [ 'color' ],
+ support: [ 'color', 'text' ],
+ requiresOptOut: true,
},
linkColor: {
value: [ 'elements', 'link', 'color', 'text' ],
diff --git a/packages/edit-site/src/components/editor/global-styles-provider.js b/packages/edit-site/src/components/editor/global-styles-provider.js
index 05e672dfa05f17..d85aecdf251bcc 100644
--- a/packages/edit-site/src/components/editor/global-styles-provider.js
+++ b/packages/edit-site/src/components/editor/global-styles-provider.js
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import { set, get, mergeWith, mapValues, setWith, clone } from 'lodash';
+import { set, get, has, mergeWith, mapValues, setWith, clone } from 'lodash';
/**
* WordPress dependencies
@@ -75,8 +75,24 @@ export const useGlobalStylesReset = () => {
const extractSupportKeys = ( supports ) => {
const supportKeys = [];
Object.keys( STYLE_PROPERTY ).forEach( ( name ) => {
+ if ( ! STYLE_PROPERTY[ name ].support ) {
+ return;
+ }
+
+ // Opting out means that, for certain support keys like background color,
+ // blocks have to explicitly set the support value false. If the key is
+ // unset, we still enable it.
+ if ( STYLE_PROPERTY[ name ].requiresOptOut ) {
+ if (
+ has( supports, STYLE_PROPERTY[ name ].support[ 0 ] ) &&
+ get( supports, STYLE_PROPERTY[ name ].support ) !== false
+ ) {
+ return supportKeys.push( name );
+ }
+ }
+
if ( get( supports, STYLE_PROPERTY[ name ].support, false ) ) {
- supportKeys.push( name );
+ return supportKeys.push( name );
}
} );
return supportKeys;
diff --git a/packages/edit-site/src/components/editor/test/global-styles-provider.js b/packages/edit-site/src/components/editor/test/global-styles-provider.js
new file mode 100644
index 00000000000000..0a31516576e572
--- /dev/null
+++ b/packages/edit-site/src/components/editor/test/global-styles-provider.js
@@ -0,0 +1,131 @@
+/**
+ * WordPress dependencies
+ */
+import { dispatch } from '@wordpress/data';
+
+/**
+ * External dependencies
+ */
+import { mount } from 'enzyme';
+import { act } from 'react-dom/test-utils';
+
+/**
+ * Internal dependencies
+ */
+import GlobalStylesProvider, {
+ useGlobalStylesContext,
+} from '../global-styles-provider';
+
+const settings = {
+ styles: [
+ {
+ css: 'body {\n\tmargin: 0;\n\tpadding: 0;\n}',
+ baseURL: 'http://localhost:4759/ponyfill.css',
+ },
+ ],
+ __experimentalGlobalStylesBaseStyles: {},
+};
+
+const generateCoverBlockType = ( colorSupports ) => {
+ return {
+ name: 'core/cover',
+ supports: {
+ color: colorSupports,
+ },
+ };
+};
+
+const FakeCmp = () => {
+ const globalStylesContext = useGlobalStylesContext();
+ const coverBlockSupports =
+ globalStylesContext.blocks[ 'core/cover' ].supports;
+
+ return
;
+};
+
+const generateWrapper = () => {
+ return mount(
+
+
+
+ );
+};
+
+describe( 'global styles provider', () => {
+ beforeAll( () => {
+ dispatch( 'core/edit-site' ).updateSettings( settings );
+ } );
+
+ describe( 'when a block enables color support', () => {
+ describe( 'and disables background color support', () => {
+ it( 'still enables text color support', () => {
+ act( () => {
+ dispatch( 'core/blocks' ).addBlockTypes(
+ generateCoverBlockType( {
+ link: true,
+ background: false,
+ } )
+ );
+ } );
+
+ const wrapper = generateWrapper();
+ const actual = wrapper
+ .findWhere( ( ele ) => Boolean( ele.prop( 'supports' ) ) )
+ .prop( 'supports' );
+ expect( actual ).not.toContain( 'backgroundColor' );
+ expect( actual ).toContain( 'color' );
+
+ act( () => {
+ dispatch( 'core/blocks' ).removeBlockTypes( 'core/cover' );
+ } );
+ } );
+ } );
+
+ describe( 'and both text color and background color support are disabled', () => {
+ it( 'disables text color and background color support', () => {
+ act( () => {
+ dispatch( 'core/blocks' ).addBlockTypes(
+ generateCoverBlockType( {
+ text: false,
+ background: false,
+ } )
+ );
+ } );
+
+ const wrapper = generateWrapper();
+ const actual = wrapper
+ .findWhere( ( ele ) => Boolean( ele.prop( 'supports' ) ) )
+ .prop( 'supports' );
+ expect( actual ).not.toContain( 'backgroundColor' );
+ expect( actual ).not.toContain( 'color' );
+
+ act( () => {
+ dispatch( 'core/blocks' ).removeBlockTypes( 'core/cover' );
+ } );
+ } );
+ } );
+
+ describe( 'and text color and background color supports are omitted', () => {
+ it( 'still enables both text color and background color supports', () => {
+ act( () => {
+ dispatch( 'core/blocks' ).addBlockTypes(
+ generateCoverBlockType( { link: true } )
+ );
+ } );
+
+ const wrapper = generateWrapper();
+ const actual = wrapper
+ .findWhere( ( ele ) => Boolean( ele.prop( 'supports' ) ) )
+ .prop( 'supports' );
+ expect( actual ).toContain( 'backgroundColor' );
+ expect( actual ).toContain( 'color' );
+
+ act( () => {
+ dispatch( 'core/blocks' ).removeBlockTypes( 'core/cover' );
+ } );
+ } );
+ } );
+ } );
+} );
From 662dabcaa7035276a3428f7271407f5b8443d9a9 Mon Sep 17 00:00:00 2001
From: Joen A <1204802+jasmussen@users.noreply.github.com>
Date: Fri, 27 Aug 2021 12:31:01 +0200
Subject: [PATCH 062/214] Fix navigation block classname issues (#34344)
* Fix missing class renames.
* Add readme notes.
* Fix flex issue.
---
packages/block-library/src/navigation-link/editor.scss | 2 +-
packages/block-library/src/navigation/editor.scss | 7 ++++---
.../block-library/src/navigation/placeholder-preview.js | 6 +++---
packages/components/src/navigation/README.md | 9 +++++++++
.../edit-navigation/src/components/editor/style.scss | 8 ++++----
5 files changed, 21 insertions(+), 11 deletions(-)
diff --git a/packages/block-library/src/navigation-link/editor.scss b/packages/block-library/src/navigation-link/editor.scss
index e11e9c949381c3..8f3c08717e5dd4 100644
--- a/packages/block-library/src/navigation-link/editor.scss
+++ b/packages/block-library/src/navigation-link/editor.scss
@@ -41,7 +41,7 @@
* Navigation Items.
*/
-.wp-block-navigation-link {
+.wp-block-navigation-item {
.wp-block-navigation__submenu-container {
display: block;
}
diff --git a/packages/block-library/src/navigation/editor.scss b/packages/block-library/src/navigation/editor.scss
index 47fa26ce4920cc..e85c873c700e1b 100644
--- a/packages/block-library/src/navigation/editor.scss
+++ b/packages/block-library/src/navigation/editor.scss
@@ -31,7 +31,7 @@
// Low specificity default to ensure background color applies to submenus.
.wp-block-navigation__container,
-.wp-block-navigation-link {
+.wp-block-navigation-item {
background-color: inherit;
}
@@ -215,7 +215,7 @@ $color-control-label-height: 20px;
// Style skeleton elements to mostly match the metrics of actual menu items.
// Needs specificity.
- .wp-block-navigation-link.wp-block-navigation-link {
+ .wp-block-navigation-item.wp-block-navigation-item {
position: relative;
min-width: 72px;
@@ -237,7 +237,7 @@ $color-control-label-height: 20px;
}
- .wp-block-navigation-link.wp-block-navigation-link,
+ .wp-block-navigation-item.wp-block-navigation-item,
.wp-block-navigation-placeholder__preview-search-icon {
opacity: 0.3;
}
@@ -250,6 +250,7 @@ $color-control-label-height: 20px;
width: 0;
overflow: hidden;
flex-wrap: nowrap;
+ flex: 0;
}
// Hide entirely when vertical.
diff --git a/packages/block-library/src/navigation/placeholder-preview.js b/packages/block-library/src/navigation/placeholder-preview.js
index fff5f80b39f069..a8c1ae6bdd451f 100644
--- a/packages/block-library/src/navigation/placeholder-preview.js
+++ b/packages/block-library/src/navigation/placeholder-preview.js
@@ -6,9 +6,9 @@ import { Icon, search } from '@wordpress/icons';
const PlaceholderPreview = () => {
return (
-
-
-
+
+
+
diff --git a/packages/components/src/navigation/README.md b/packages/components/src/navigation/README.md
index 1128874463d574..610b74d77ff1c9 100644
--- a/packages/components/src/navigation/README.md
+++ b/packages/components/src/navigation/README.md
@@ -44,6 +44,15 @@ const MyNavigation = () => (
);
```
+## CSS Classes leveraged
+
+The structural CSS for the navigation block targets generic classnames across menu items of multiple types including those automatically generated by the Page List block. Here are some of the notable classnames and what they are used for:
+
+- `.wp-block-navigation__submenu-container` is applied to submenus to main menu items.
+- `.wp-block-navigation-item` is applied to every menu item.
+- `.wp-block-navigation-item__content` is applied to the link inside a menu item.
+- `.wp-block-navigation-link__label` is applied to the innermost container around the menu item text label.
+- `.wp-block-navigation__submenu-icon` is applied to the submenu indicator (chevron).
## Navigation Props
diff --git a/packages/edit-navigation/src/components/editor/style.scss b/packages/edit-navigation/src/components/editor/style.scss
index 74077954e1dc35..5c5d813b02d38b 100644
--- a/packages/edit-navigation/src/components/editor/style.scss
+++ b/packages/edit-navigation/src/components/editor/style.scss
@@ -30,7 +30,7 @@
font-family: $default-font;
// Increase specificity.
- .wp-block-navigation-link {
+ .wp-block-navigation-item {
display: block;
// Show submenus on click.
@@ -55,7 +55,7 @@
// Menu items.
// This needs high specificity to override inherited values.
- &.wp-block-navigation-link.wp-block-navigation-link {
+ &.wp-block-navigation-item.wp-block-navigation-item {
margin-right: 0;
}
@@ -124,7 +124,7 @@
}
// Override inherited values to optimize menu items for the screen context.
- .wp-block-navigation-link.has-child {
+ .wp-block-navigation-item.has-child {
cursor: default;
border-radius: $radius-block-ui;
}
@@ -137,7 +137,7 @@
// When editing a link with children, highlight the parent
// and adjust the spacing and submenu icon.
- .wp-block-navigation-link.has-child.is-editing {
+ .wp-block-navigation-item.has-child.is-editing {
> .wp-block-navigation__container,
> .wp-block-navigation__submenu-container {
opacity: 1;
From 437b9733faf5b847ba1a579aea0e8bcaf0e4fbfd Mon Sep 17 00:00:00 2001
From: Jarda Snajdr
Date: Fri, 27 Aug 2021 13:59:52 +0200
Subject: [PATCH 063/214] core-data: remove the PROCESS_PENDING_LOCK_REQUESTS
action (#34343)
---
packages/core-data/src/locks/actions.js | 3 ---
packages/core-data/src/locks/test/actions.js | 27 --------------------
2 files changed, 30 deletions(-)
diff --git a/packages/core-data/src/locks/actions.js b/packages/core-data/src/locks/actions.js
index aab16dd703bbad..4dc6b324a29e68 100644
--- a/packages/core-data/src/locks/actions.js
+++ b/packages/core-data/src/locks/actions.js
@@ -38,9 +38,6 @@ export function* __unstableReleaseStoreLock( lock ) {
}
export function* __unstableProcessPendingLockRequests() {
- yield {
- type: 'PROCESS_PENDING_LOCK_REQUESTS',
- };
const lockRequests = yield controls.select(
STORE_NAME,
'__unstableGetPendingLockRequests'
diff --git a/packages/core-data/src/locks/test/actions.js b/packages/core-data/src/locks/test/actions.js
index f3d2cbdb1b44a1..70f77c1dc05e9c 100644
--- a/packages/core-data/src/locks/test/actions.js
+++ b/packages/core-data/src/locks/test/actions.js
@@ -76,11 +76,6 @@ describe( '__unstableProcessPendingLockRequests', () => {
it( 'Grants a lock request that may be granted', async () => {
const fulfillment = __unstableProcessPendingLockRequests();
- // Start
- expect( fulfillment.next().value.type ).toBe(
- 'PROCESS_PENDING_LOCK_REQUESTS'
- );
-
// Get pending lock requests
expect( fulfillment.next().value.type ).toBe( '@@data/SELECT' );
@@ -117,11 +112,6 @@ describe( '__unstableProcessPendingLockRequests', () => {
it( 'Does not grants a lock request that may not be granted', async () => {
const fulfillment = __unstableProcessPendingLockRequests();
- // Start
- expect( fulfillment.next().value.type ).toBe(
- 'PROCESS_PENDING_LOCK_REQUESTS'
- );
-
// Get pending lock requests
expect( fulfillment.next().value.type ).toBe( '@@data/SELECT' );
@@ -140,11 +130,6 @@ describe( '__unstableProcessPendingLockRequests', () => {
it( 'Handles multiple lock requests', async () => {
const fulfillment = __unstableProcessPendingLockRequests();
- // Start
- expect( fulfillment.next().value.type ).toBe(
- 'PROCESS_PENDING_LOCK_REQUESTS'
- );
-
// Get pending lock requests
expect( fulfillment.next().value.type ).toBe( '@@data/SELECT' );
@@ -201,10 +186,6 @@ describe( '__unstableAcquireStoreLock', () => {
// Start
expect( fulfillment.next().value.type ).toBe( 'ENQUEUE_LOCK_REQUEST' );
- // Get pending lock requests
- expect( fulfillment.next().value.type ).toBe(
- 'PROCESS_PENDING_LOCK_REQUESTS'
- );
expect( fulfillment.next().value.type ).toBe( '@@data/SELECT' );
// Check if lock may be granted
@@ -243,10 +224,6 @@ describe( '__unstableAcquireStoreLock', () => {
// Start
expect( fulfillment.next().value.type ).toBe( 'ENQUEUE_LOCK_REQUEST' );
- // Get pending lock requests
- expect( fulfillment.next().value.type ).toBe(
- 'PROCESS_PENDING_LOCK_REQUESTS'
- );
expect( fulfillment.next().value.type ).toBe( '@@data/SELECT' );
// Check if lock may be granted
@@ -286,10 +263,6 @@ describe( '__unstableReleaseStoreLock', () => {
lock,
} );
- // Attempt to grant any pending lock requests, find none, return
- expect( fulfillment.next().value.type ).toBe(
- 'PROCESS_PENDING_LOCK_REQUESTS'
- );
expect( fulfillment.next().value.type ).toBe( '@@data/SELECT' );
// Short-circuit with no results and return
From be41e01f8b59ec8583d19bf1e9caf1fec085a353 Mon Sep 17 00:00:00 2001
From: David Calhoun <438664+dcalhoun@users.noreply.github.com>
Date: Fri, 27 Aug 2021 09:38:40 -0500
Subject: [PATCH 064/214] Fix Animated warning log (#34197)
Animated now requires setting an explicit `useNativeDriver` option.
Without setting it, the following warning is produced.
```
WARN Animated: `useNativeDriver` was not specified. This is a required option and must be explicitly set to `true` or `false`
```
It cannot be set to `true` for this particular animation as it is not
supported and produces the following error.
```
ERROR Error: Style property 'left' is not supported by native animated module
```
---
packages/components/src/mobile/segmented-control/index.native.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/components/src/mobile/segmented-control/index.native.js b/packages/components/src/mobile/segmented-control/index.native.js
index b80db26fccd09a..2a3071d0963b74 100644
--- a/packages/components/src/mobile/segmented-control/index.native.js
+++ b/packages/components/src/mobile/segmented-control/index.native.js
@@ -94,6 +94,7 @@ const SegmentedControls = ( {
toValue: calculateEndValue( index ),
duration: ANIMATION_DURATION,
easing: Easing.ease,
+ useNativeDriver: false,
} ).start();
}
From 23bd5923edc83c8e7dab50682bae0b31de53f469 Mon Sep 17 00:00:00 2001
From: George Mamadashvili
Date: Fri, 27 Aug 2021 15:32:15 +0000
Subject: [PATCH 065/214] Navigation Screen: Decode entities in the menu names
(#34263)
* Navigation Screen: Decode entities in the menu names
* Fix menu switcher
---
packages/edit-navigation/src/components/header/index.js | 3 ++-
.../edit-navigation/src/components/menu-switcher/index.js | 3 ++-
.../edit-navigation/src/components/name-display/index.js | 3 ++-
.../edit-navigation/src/components/name-editor/index.js | 3 ++-
.../src/components/sidebar/manage-locations.js | 7 ++++---
5 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/packages/edit-navigation/src/components/header/index.js b/packages/edit-navigation/src/components/header/index.js
index 49cf4cb972f536..10a08fddd6ac00 100644
--- a/packages/edit-navigation/src/components/header/index.js
+++ b/packages/edit-navigation/src/components/header/index.js
@@ -4,6 +4,7 @@
import { DropdownMenu } from '@wordpress/components';
import { PinnedItems } from '@wordpress/interface';
import { __, sprintf } from '@wordpress/i18n';
+import { decodeEntities } from '@wordpress/html-entities';
/**
* Internal dependencies
@@ -42,7 +43,7 @@ export default function Header( {
{ __( 'Navigation' ) }
- { isMenuSelected && actionHeaderText }
+ { isMenuSelected && decodeEntities( actionHeaderText ) }
{ isMenuSelected && (
diff --git a/packages/edit-navigation/src/components/menu-switcher/index.js b/packages/edit-navigation/src/components/menu-switcher/index.js
index 68162e433a7d63..b6a18436437234 100644
--- a/packages/edit-navigation/src/components/menu-switcher/index.js
+++ b/packages/edit-navigation/src/components/menu-switcher/index.js
@@ -14,6 +14,7 @@ import {
} from '@wordpress/components';
import { useState } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
+import { decodeEntities } from '@wordpress/html-entities';
/**
* Internal dependencies
@@ -37,7 +38,7 @@ export default function MenuSwitcher( {
onSelect={ onSelectMenu }
choices={ menus.map( ( { id, name } ) => ( {
value: id,
- label: name,
+ label: decodeEntities( name ),
'aria-label': sprintf(
/* translators: %s: The name of a menu. */
__( "Switch to '%s'" ),
diff --git a/packages/edit-navigation/src/components/name-display/index.js b/packages/edit-navigation/src/components/name-display/index.js
index 794e686df4b040..6aa124dc0e6baa 100644
--- a/packages/edit-navigation/src/components/name-display/index.js
+++ b/packages/edit-navigation/src/components/name-display/index.js
@@ -7,6 +7,7 @@ import { BlockControls } from '@wordpress/block-editor';
import { useDispatch } from '@wordpress/data';
import { store as interfaceStore } from '@wordpress/interface';
import { sprintf, __ } from '@wordpress/i18n';
+import { decodeEntities } from '@wordpress/html-entities';
/**
* Internal dependencies
@@ -27,7 +28,7 @@ export default function NameDisplay() {
IsMenuNameControlFocusedContext
);
- const menuName = name ?? untitledMenu;
+ const menuName = decodeEntities( name ?? untitledMenu );
return (
diff --git a/packages/edit-navigation/src/components/name-editor/index.js b/packages/edit-navigation/src/components/name-editor/index.js
index 728dcb04b77c4d..a1c46345f23758 100644
--- a/packages/edit-navigation/src/components/name-editor/index.js
+++ b/packages/edit-navigation/src/components/name-editor/index.js
@@ -4,6 +4,7 @@
import { __ } from '@wordpress/i18n';
import { TextControl } from '@wordpress/components';
import { useEffect, useRef, useContext } from '@wordpress/element';
+import { decodeEntities } from '@wordpress/html-entities';
/**
* Internal dependencies
@@ -36,7 +37,7 @@ export function NameEditor() {
label={ __( 'Name' ) }
onBlur={ () => setIsMenuNameEditFocused( false ) }
className="edit-navigation-name-editor__text-control"
- value={ name || '' }
+ value={ decodeEntities( name || '' ) }
onChange={ setName }
/>
);
diff --git a/packages/edit-navigation/src/components/sidebar/manage-locations.js b/packages/edit-navigation/src/components/sidebar/manage-locations.js
index b77b0a39ff62b4..97b3b3da322cfe 100644
--- a/packages/edit-navigation/src/components/sidebar/manage-locations.js
+++ b/packages/edit-navigation/src/components/sidebar/manage-locations.js
@@ -11,6 +11,7 @@ import {
Spinner,
SelectControl,
} from '@wordpress/components';
+import { decodeEntities } from '@wordpress/html-entities';
/**
* Internal dependencies
@@ -82,7 +83,7 @@ export default function ManageLocations( {
sprintf(
// translators: menu name.
__( 'Currently using %s' ),
- menuOnLocation.name
+ decodeEntities( menuOnLocation.name )
)
}
/>
@@ -101,13 +102,13 @@ export default function ManageLocations( {
className="edit-navigation-manage-locations__select-menu"
label={ menuLocation.description }
labelPosition="top"
- value={ menuLocation.menu }
+ value={ decodeEntities( menuLocation.menu ) }
options={ [
{ value: 0, label: __( 'Select a Menu' ), key: 0 },
...menus.map( ( { id, name } ) => ( {
key: id,
value: id,
- label: name,
+ label: decodeEntities( name ),
} ) ),
] }
onChange={ ( menuId ) => {
From b4e74b74da8c3a33952f8a08b2e44db4a91e9561 Mon Sep 17 00:00:00 2001
From: Kerry Liu
Date: Fri, 27 Aug 2021 08:41:55 -0700
Subject: [PATCH 066/214] Block Navigation List: do not show appender and avoid
closing the modal on block select (#34337)
* Block Navigation List: do not show appender and avoid closing the modal on block select
* Block Navigation List: do not change modal size when dragging items
---
.../src/components/list-view/index.js | 24 ++++++++++++-------
.../src/navigation/block-navigation-list.js | 23 ++++++++++++------
.../src/navigation/use-block-navigator.js | 1 +
3 files changed, 32 insertions(+), 16 deletions(-)
diff --git a/packages/block-editor/src/components/list-view/index.js b/packages/block-editor/src/components/list-view/index.js
index 1fa3f75b64ced5..82909cd957368c 100644
--- a/packages/block-editor/src/components/list-view/index.js
+++ b/packages/block-editor/src/components/list-view/index.js
@@ -11,6 +11,7 @@ import {
useMemo,
useRef,
useReducer,
+ forwardRef,
} from '@wordpress/element';
import { __ } from '@wordpress/i18n';
@@ -48,15 +49,19 @@ const expanded = ( state, action ) => {
* @param {boolean} props.showOnlyCurrentHierarchy Flag to limit the list to the current hierarchy of blocks.
* @param {boolean} props.__experimentalFeatures Flag to enable experimental features.
* @param {boolean} props.__experimentalPersistentListViewFeatures Flag to enable features for the Persistent List View experiment.
+ * @param {Object} ref Forwarded ref
*/
-export default function ListView( {
- blocks,
- showOnlyCurrentHierarchy,
- onSelect = noop,
- __experimentalFeatures,
- __experimentalPersistentListViewFeatures,
- ...props
-} ) {
+function ListView(
+ {
+ blocks,
+ showOnlyCurrentHierarchy,
+ onSelect = noop,
+ __experimentalFeatures,
+ __experimentalPersistentListViewFeatures,
+ ...props
+ },
+ ref
+) {
const { clientIdsTree, selectedClientIds } = useListViewClientIds(
blocks,
showOnlyCurrentHierarchy,
@@ -74,7 +79,7 @@ export default function ListView( {
const { ref: dropZoneRef, target: blockDropTarget } = useListViewDropZone();
const elementRef = useRef();
- const treeGridRef = useMergeRefs( [ elementRef, dropZoneRef ] );
+ const treeGridRef = useMergeRefs( [ elementRef, dropZoneRef, ref ] );
const isMounted = useRef( false );
useEffect( () => {
@@ -144,3 +149,4 @@ export default function ListView( {
>
);
}
+export default forwardRef( ListView );
diff --git a/packages/block-library/src/navigation/block-navigation-list.js b/packages/block-library/src/navigation/block-navigation-list.js
index 2aee258574605c..814a56b20f4fd1 100644
--- a/packages/block-library/src/navigation/block-navigation-list.js
+++ b/packages/block-library/src/navigation/block-navigation-list.js
@@ -6,6 +6,7 @@ import {
store as blockEditorStore,
} from '@wordpress/block-editor';
import { useSelect } from '@wordpress/data';
+import { useRef, useEffect, useState } from '@wordpress/element';
export default function BlockNavigationList( {
clientId,
@@ -17,13 +18,21 @@ export default function BlockNavigationList( {
[ clientId ]
);
+ const listViewRef = useRef();
+ const [ minHeight, setMinHeight ] = useState( 300 );
+ useEffect( () => {
+ setMinHeight( listViewRef?.current?.clientHeight ?? 300 );
+ }, [] );
+
return (
-
+
+
+
);
}
diff --git a/packages/block-library/src/navigation/use-block-navigator.js b/packages/block-library/src/navigation/use-block-navigator.js
index 479a54c24e216e..0f4f89ffd1998a 100644
--- a/packages/block-library/src/navigation/use-block-navigator.js
+++ b/packages/block-library/src/navigation/use-block-navigator.js
@@ -30,6 +30,7 @@ export default function useBlockNavigator( clientId, __experimentalFeatures ) {
onRequestClose={ () => {
setIsNavigationListOpen( false );
} }
+ shouldCloseOnClickOutside={ false }
>
Date: Mon, 30 Aug 2021 11:48:50 +1000
Subject: [PATCH 067/214] Fix submenu layout in navigation page list. (#34342)
* Fix submenu layout in navigation page list.
* Update parent status before component renders.
---
packages/block-library/src/page-list/edit.js | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/packages/block-library/src/page-list/edit.js b/packages/block-library/src/page-list/edit.js
index 9818a320c326e4..58c0e1b6a28533 100644
--- a/packages/block-library/src/page-list/edit.js
+++ b/packages/block-library/src/page-list/edit.js
@@ -2,7 +2,6 @@
* External dependencies
*/
import classnames from 'classnames';
-import { isEmpty } from 'lodash';
/**
* WordPress dependencies
@@ -70,11 +69,6 @@ export default function PageListEdit( {
context.customOverlayBackgroundColor,
] );
- useEffect( () => {
- const isNavigationChild = isEmpty( context ) ? false : true;
- setAttributes( { isNavigationChild } );
- }, [] );
-
const { textColor, backgroundColor, showSubmenuIcon, style } =
context || {};
@@ -105,6 +99,10 @@ export default function PageListEdit( {
[ clientId ]
);
+ useEffect( () => {
+ setAttributes( { isNavigationChild: isParentNavigation } );
+ }, [] );
+
useEffect( () => {
if ( isParentNavigation ) {
apiFetch( {
@@ -127,6 +125,12 @@ export default function PageListEdit( {
const openModal = () => setOpen( true );
const closeModal = () => setOpen( false );
+ // Update parent status before component first renders.
+ const attributesWithParentStatus = {
+ ...attributes,
+ isNavigationChild: isParentNavigation,
+ };
+
return (
<>
{ allowConvertToLinks && (
@@ -145,7 +149,7 @@ export default function PageListEdit( {
>
From 098bd96ddaf4583e42c2eebb649aa4158d9e02cc Mon Sep 17 00:00:00 2001
From: Ramon
Date: Mon, 30 Aug 2021 11:59:22 +1000
Subject: [PATCH 068/214] change icon from horizontal to vertical ellipsis
(#34369)
---
.../src/tools-panel/tools-panel-header/component.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/components/src/tools-panel/tools-panel-header/component.js b/packages/components/src/tools-panel/tools-panel-header/component.js
index 6fa9391e20e0e2..b7e2e41634086b 100644
--- a/packages/components/src/tools-panel/tools-panel-header/component.js
+++ b/packages/components/src/tools-panel/tools-panel-header/component.js
@@ -1,7 +1,7 @@
/**
* WordPress dependencies
*/
-import { check, moreHorizontal } from '@wordpress/icons';
+import { check, moreVertical } from '@wordpress/icons';
import { __ } from '@wordpress/i18n';
/**
@@ -32,7 +32,7 @@ const ToolsPanelHeader = ( props, forwardedRef ) => {
{ header }
{ hasMenuItems && (
-
+
{ ( { onClose } ) => (
<>
From b2c4a00b5b92718e5fd5eca0103b4782e5601665 Mon Sep 17 00:00:00 2001
From: Adam Zielinski
Date: Mon, 30 Aug 2021 12:24:33 +0200
Subject: [PATCH 069/214] Make Test_Widget compatible with WP_Widget (#34355)
* Make Test_Widget compatible with WP_Widget
* Move the isset($instance['title']) from update() to form() where it's needed
* Explain why codingStandardsIgnoreStart
---
packages/e2e-tests/plugins/class-test-widget.php | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/packages/e2e-tests/plugins/class-test-widget.php b/packages/e2e-tests/plugins/class-test-widget.php
index a3ae60658c0d14..11ce978257fe46 100644
--- a/packages/e2e-tests/plugins/class-test-widget.php
+++ b/packages/e2e-tests/plugins/class-test-widget.php
@@ -48,7 +48,7 @@ public function form( $instance ) {
?>
Title:
-
+
Date: Mon, 30 Aug 2021 12:58:55 +0200
Subject: [PATCH 070/214] Fix metabox reordering (#30617)
---
.../data/data-core-edit-post.md | 16 +++
packages/edit-post/README.md | 5 +-
.../src/components/meta-boxes/index.js | 54 ++++++--
packages/edit-post/src/index.js | 7 +-
packages/edit-post/src/store/actions.js | 116 ++++++++++--------
packages/edit-post/src/store/reducer.js | 17 +++
packages/edit-post/src/store/selectors.js | 11 ++
7 files changed, 155 insertions(+), 71 deletions(-)
diff --git a/docs/reference-guides/data/data-core-edit-post.md b/docs/reference-guides/data/data-core-edit-post.md
index e8dd31780a3ad6..72a76d56fad15f 100644
--- a/docs/reference-guides/data/data-core-edit-post.md
+++ b/docs/reference-guides/data/data-core-edit-post.md
@@ -6,6 +6,18 @@ Namespace: `core/edit-post`.
+### areMetaBoxesInitialized
+
+Returns true if meta boxes are initialized.
+
+_Parameters_
+
+- _state_ `Object`: Global application state.
+
+_Returns_
+
+- `boolean`: Whether meta boxes are initialized.
+
### getActiveGeneralSidebarName
Returns the current active general sidebar name, or null if there is no
@@ -351,6 +363,10 @@ _Returns_
- `Object`: Action object.
+### initializeMetaBoxes
+
+Initializes WordPress `postboxes` script and the logic for saving meta boxes.
+
### metaBoxUpdatesFailure
Returns an action object used to signal a failed meta box update.
diff --git a/packages/edit-post/README.md b/packages/edit-post/README.md
index 9768fe6b6fd211..677e0c8257aa05 100644
--- a/packages/edit-post/README.md
+++ b/packages/edit-post/README.md
@@ -31,13 +31,10 @@ They can be found in the global variable `wp.editPost` when defining `wp-edit-po
Initializes and returns an instance of Editor.
-The return value of this function is not necessary if we change where we
-call initializeEditor(). This is due to metaBox timing.
-
_Parameters_
- _id_ `string`: Unique identifier for editor instance.
-- _postType_ `Object`: Post type of the post to edit.
+- _postType_ `string`: Post type of the post to edit.
- _postId_ `Object`: ID of the post to edit.
- _settings_ `?Object`: Editor settings object.
- _initialEdits_ `Object`: Programmatic edits to apply initially, to be considered as non-user-initiated (bypass for unsaved changes prompt).
diff --git a/packages/edit-post/src/components/meta-boxes/index.js b/packages/edit-post/src/components/meta-boxes/index.js
index e5e3e2ac2066df..15851ae5247873 100644
--- a/packages/edit-post/src/components/meta-boxes/index.js
+++ b/packages/edit-post/src/components/meta-boxes/index.js
@@ -6,7 +6,9 @@ import { map } from 'lodash';
/**
* WordPress dependencies
*/
-import { withSelect } from '@wordpress/data';
+import { useSelect, useRegistry } from '@wordpress/data';
+import { useEffect } from '@wordpress/element';
+import { store as editorStore } from '@wordpress/editor';
/**
* Internal dependencies
@@ -15,7 +17,44 @@ import MetaBoxesArea from './meta-boxes-area';
import MetaBoxVisibility from './meta-box-visibility';
import { store as editPostStore } from '../../store';
-function MetaBoxes( { location, isVisible, metaBoxes } ) {
+export default function MetaBoxes( { location } ) {
+ const registry = useRegistry();
+ const {
+ metaBoxes,
+ isVisible,
+ areMetaBoxesInitialized,
+ isEditorReady,
+ } = useSelect(
+ ( select ) => {
+ const { __unstableIsEditorReady } = select( editorStore );
+ const {
+ isMetaBoxLocationVisible,
+ getMetaBoxesPerLocation,
+ areMetaBoxesInitialized: _areMetaBoxesInitialized,
+ } = select( editPostStore );
+ return {
+ metaBoxes: getMetaBoxesPerLocation( location ),
+ isVisible: isMetaBoxLocationVisible( location ),
+ areMetaBoxesInitialized: _areMetaBoxesInitialized(),
+ isEditorReady: __unstableIsEditorReady(),
+ };
+ },
+ [ location ]
+ );
+
+ // When editor is ready, initialize postboxes (wp core script) and metabox
+ // saving. This initializes all meta box locations, not just this specific
+ // one.
+ useEffect( () => {
+ if ( isEditorReady && ! areMetaBoxesInitialized ) {
+ registry.dispatch( editPostStore ).initializeMetaBoxes();
+ }
+ }, [ isEditorReady, areMetaBoxesInitialized ] );
+
+ if ( ! areMetaBoxesInitialized ) {
+ return null;
+ }
+
return (
<>
{ map( metaBoxes, ( { id } ) => (
@@ -25,14 +64,3 @@ function MetaBoxes( { location, isVisible, metaBoxes } ) {
>
);
}
-
-export default withSelect( ( select, { location } ) => {
- const { isMetaBoxLocationVisible, getMetaBoxesPerLocation } = select(
- editPostStore
- );
-
- return {
- metaBoxes: getMetaBoxesPerLocation( location ),
- isVisible: isMetaBoxLocationVisible( location ),
- };
-} )( MetaBoxes );
diff --git a/packages/edit-post/src/index.js b/packages/edit-post/src/index.js
index 81b5f6a706c2c9..c20cff1441222b 100644
--- a/packages/edit-post/src/index.js
+++ b/packages/edit-post/src/index.js
@@ -14,7 +14,6 @@ import { store as interfaceStore } from '@wordpress/interface';
*/
import './hooks';
import './plugins';
-export { store } from './store';
import Editor from './editor';
/**
@@ -63,11 +62,8 @@ export function reinitializeEditor(
/**
* Initializes and returns an instance of Editor.
*
- * The return value of this function is not necessary if we change where we
- * call initializeEditor(). This is due to metaBox timing.
- *
* @param {string} id Unique identifier for editor instance.
- * @param {Object} postType Post type of the post to edit.
+ * @param {string} postType Post type of the post to edit.
* @param {Object} postId ID of the post to edit.
* @param {?Object} settings Editor settings object.
* @param {Object} initialEdits Programmatic edits to apply initially, to be
@@ -170,3 +166,4 @@ export { default as PluginSidebar } from './components/sidebar/plugin-sidebar';
export { default as PluginSidebarMoreMenuItem } from './components/header/plugin-sidebar-more-menu-item';
export { default as __experimentalFullscreenModeClose } from './components/header/fullscreen-mode-close';
export { default as __experimentalMainDashboardButton } from './components/header/main-dashboard-button';
+export { store } from './store';
diff --git a/packages/edit-post/src/store/actions.js b/packages/edit-post/src/store/actions.js
index d253d55e74efd7..23d7c4613de593 100644
--- a/packages/edit-post/src/store/actions.js
+++ b/packages/edit-post/src/store/actions.js
@@ -9,7 +9,7 @@ import { castArray, reduce } from 'lodash';
import { __ } from '@wordpress/i18n';
import { apiFetch } from '@wordpress/data-controls';
import { store as interfaceStore } from '@wordpress/interface';
-import { controls, dispatch, select, subscribe } from '@wordpress/data';
+import { controls, select, subscribe, dispatch } from '@wordpress/data';
import { speak } from '@wordpress/a11y';
import { store as noticesStore } from '@wordpress/notices';
import { store as coreStore } from '@wordpress/core-data';
@@ -265,8 +265,6 @@ export function showBlockTypes( blockNames ) {
};
}
-let saveMetaboxUnsubscribe;
-
/**
* Returns an action object used in signaling
* what Meta boxes are available in which location.
@@ -280,52 +278,6 @@ export function* setAvailableMetaBoxesPerLocation( metaBoxesPerLocation ) {
type: 'SET_META_BOXES_PER_LOCATIONS',
metaBoxesPerLocation,
};
-
- const postType = yield controls.select( editorStore, 'getCurrentPostType' );
- if ( window.postboxes.page !== postType ) {
- window.postboxes.add_postbox_toggles( postType );
- }
-
- let wasSavingPost = yield controls.select( editorStore, 'isSavingPost' );
- let wasAutosavingPost = yield controls.select(
- editorStore,
- 'isAutosavingPost'
- );
-
- // Meta boxes are initialized once at page load. It is not necessary to
- // account for updates on each state change.
- //
- // See: https://github.com/WordPress/WordPress/blob/5.1.1/wp-admin/includes/post.php#L2307-L2309
- const hasActiveMetaBoxes = yield controls.select(
- editPostStore,
- 'hasMetaBoxes'
- );
-
- // First remove any existing subscription in order to prevent multiple saves
- if ( !! saveMetaboxUnsubscribe ) {
- saveMetaboxUnsubscribe();
- }
-
- // Save metaboxes when performing a full save on the post.
- saveMetaboxUnsubscribe = subscribe( () => {
- const isSavingPost = select( editorStore ).isSavingPost();
- const isAutosavingPost = select( editorStore ).isAutosavingPost();
-
- // Save metaboxes on save completion, except for autosaves that are not a post preview.
- const shouldTriggerMetaboxesSave =
- hasActiveMetaBoxes &&
- wasSavingPost &&
- ! isSavingPost &&
- ! wasAutosavingPost;
-
- // Save current state for next inspection.
- wasSavingPost = isSavingPost;
- wasAutosavingPost = isAutosavingPost;
-
- if ( shouldTriggerMetaboxesSave ) {
- dispatch( editPostStore ).requestMetaBoxUpdates();
- }
- } );
}
/**
@@ -531,3 +483,69 @@ export function* __unstableCreateTemplate( template ) {
}
);
}
+
+let metaBoxesInitialized = false;
+
+/**
+ * Initializes WordPress `postboxes` script and the logic for saving meta boxes.
+ */
+export function* initializeMetaBoxes() {
+ const isEditorReady = yield controls.select(
+ editorStore,
+ '__unstableIsEditorReady'
+ );
+
+ if ( ! isEditorReady ) {
+ return;
+ }
+
+ const postType = yield controls.select( editorStore, 'getCurrentPostType' );
+
+ // Only initialize once.
+ if ( metaBoxesInitialized ) {
+ return;
+ }
+
+ if ( window.postboxes.page !== postType ) {
+ window.postboxes.add_postbox_toggles( postType );
+ }
+
+ metaBoxesInitialized = true;
+
+ let wasSavingPost = yield controls.select( editorStore, 'isSavingPost' );
+ let wasAutosavingPost = yield controls.select(
+ editorStore,
+ 'isAutosavingPost'
+ );
+ const hasMetaBoxes = yield controls.select( editPostStore, 'hasMetaBoxes' );
+
+ // Save metaboxes when performing a full save on the post.
+ subscribe( () => {
+ const isSavingPost = select( editorStore ).isSavingPost();
+ const isAutosavingPost = select( editorStore ).isAutosavingPost();
+
+ // Save metaboxes on save completion, except for autosaves that are not a post preview.
+ //
+ // Meta boxes are initialized once at page load. It is not necessary to
+ // account for updates on each state change.
+ //
+ // See: https://github.com/WordPress/WordPress/blob/5.1.1/wp-admin/includes/post.php#L2307-L2309
+ const shouldTriggerMetaboxesSave =
+ hasMetaBoxes &&
+ wasSavingPost &&
+ ! isSavingPost &&
+ ! wasAutosavingPost;
+
+ // Save current state for next inspection.
+ wasSavingPost = isSavingPost;
+ wasAutosavingPost = isAutosavingPost;
+
+ if ( shouldTriggerMetaboxesSave ) {
+ dispatch( editPostStore ).requestMetaBoxUpdates();
+ }
+ } );
+
+ return {
+ type: 'META_BOXES_INITIALIZED',
+ };
+}
diff --git a/packages/edit-post/src/store/reducer.js b/packages/edit-post/src/store/reducer.js
index 3441c613f5f619..d3eaa38fac7c06 100644
--- a/packages/edit-post/src/store/reducer.js
+++ b/packages/edit-post/src/store/reducer.js
@@ -281,9 +281,26 @@ function isEditingTemplate( state = false, action ) {
return state;
}
+/**
+ * Reducer tracking whether meta boxes are initialized.
+ *
+ * @param {boolean} state
+ * @param {Object} action
+ *
+ * @return {boolean} Updated state.
+ */
+function metaBoxesInitialized( state = false, action ) {
+ switch ( action.type ) {
+ case 'META_BOXES_INITIALIZED':
+ return true;
+ }
+ return state;
+}
+
const metaBoxes = combineReducers( {
isSaving: isSavingMetaBoxes,
locations: metaBoxLocations,
+ initialized: metaBoxesInitialized,
} );
export default combineReducers( {
diff --git a/packages/edit-post/src/store/selectors.js b/packages/edit-post/src/store/selectors.js
index 2d40810a3cf569..e127f6294210a8 100644
--- a/packages/edit-post/src/store/selectors.js
+++ b/packages/edit-post/src/store/selectors.js
@@ -367,6 +367,17 @@ export function isEditingTemplate( state ) {
return state.isEditingTemplate;
}
+/**
+ * Returns true if meta boxes are initialized.
+ *
+ * @param {Object} state Global application state.
+ *
+ * @return {boolean} Whether meta boxes are initialized.
+ */
+export function areMetaBoxesInitialized( state ) {
+ return state.metaBoxes.initialized;
+}
+
/**
* Retrieves the template of the currently edited post.
*
From 4d6e17409816002a218eda8f031c54259315a2b6 Mon Sep 17 00:00:00 2001
From: Adam Zielinski
Date: Mon, 30 Aug 2021 13:17:34 +0200
Subject: [PATCH 071/214] Legacy widget rendering endpoint (#34230)
* Add a polyfill for the widget render endpoint
* Remove unnecessary whitespace
* Fill some blanks in docstrings
* Adjust the registered callback name
* Lint
* Lint
* Polyfill the entire /encode endpoint
* Adjust directory and class names
* Revert to /render polyfill for WordPress 5.8.1
* Rename id_base parameter to id
* Lint
---
lib/compat/wordpress-5.8.1/index.php | 9 ++
...b-rest-widget-render-endpoint-polyfill.php | 121 ++++++++++++++++++
.../widget-render-api-endpoint/index.php | 22 ++++
lib/load.php | 1 +
4 files changed, 153 insertions(+)
create mode 100644 lib/compat/wordpress-5.8.1/index.php
create mode 100644 lib/compat/wordpress-5.8.1/widget-render-api-endpoint/class-gb-rest-widget-render-endpoint-polyfill.php
create mode 100644 lib/compat/wordpress-5.8.1/widget-render-api-endpoint/index.php
diff --git a/lib/compat/wordpress-5.8.1/index.php b/lib/compat/wordpress-5.8.1/index.php
new file mode 100644
index 00000000000000..d825f2d93c9167
--- /dev/null
+++ b/lib/compat/wordpress-5.8.1/index.php
@@ -0,0 +1,9 @@
+rest_base . '/(?P[a-zA-Z0-9_-]+)/render';
+
+ // Don't override if already registered.
+ $registered_routes = rest_get_server()->get_routes( 'wp/v2' );
+ if ( array_key_exists( $route, $registered_routes ) ) {
+ return;
+ }
+
+ register_rest_route(
+ $this->namespace,
+ $route,
+ array(
+ array(
+ 'methods' => WP_REST_Server::CREATABLE,
+ 'permission_callback' => array( $this, 'get_item_permissions_check' ),
+ 'callback' => array( $this, 'render' ),
+ 'args' => array(
+ 'id' => array(
+ 'description' => __( 'The widget type id.', 'default' ),
+ 'type' => 'string',
+ 'required' => true,
+ ),
+ 'instance' => array(
+ 'description' => __( 'Current instance settings of the widget.', 'default' ),
+ 'type' => 'object',
+ ),
+ ),
+ ),
+ )
+ );
+ }
+
+ /**
+ * Renders a single Legacy Widget and wraps it in a JSON-encodable array.
+ *
+ * @param WP_REST_Request $request Full details about the request.
+ *
+ * @return array An array with rendered Legacy Widget HTML.
+ */
+ public function render( $request ) {
+ return array(
+ 'preview' => $this->render_legacy_widget_preview_iframe(
+ $request['id'],
+ isset( $request['instance'] ) ? $request['instance'] : null
+ ),
+ );
+ }
+
+ /**
+ * Renders a page containing a preview of the requested Legacy Widget block.
+ *
+ * @param string $id_base The id base of the requested widget.
+ * @param array $instance The widget instance attributes.
+ *
+ * @return string Rendered Legacy Widget block preview.
+ */
+ private function render_legacy_widget_preview_iframe( $id_base, $instance ) {
+ if ( ! defined( 'IFRAME_REQUEST' ) ) {
+ define( 'IFRAME_REQUEST', true );
+ }
+
+ ob_start();
+ ?>
+
+ >
+
+
+
+
+
+
+
+ >
+
+
+ get_registered( 'core/legacy-widget' );
+ echo $block->render(
+ array(
+ 'idBase' => $id_base,
+ 'instance' => $instance,
+ )
+ );
+ ?>
+
+
+
+
+
+ /render endpoint in WP versions where it's missing
+ *
+ * @package gutenberg
+ */
+
+// Load the polyfill class.
+require_once __DIR__ . '/class-gb-rest-widget-render-endpoint-polyfill.php';
+
+/**
+ * Registers routes from the GB_REST_Widget_Render_Endpoint_Polyfill class.
+ */
+function setup_widget_render_api_endpoint_polyfill() {
+ $polyfill = new GB_REST_Widget_Render_Endpoint_Polyfill();
+ $polyfill->register_routes();
+}
+
+// Priority should be larger than 99 which is the one used for registering the core routes.
+add_action( 'rest_api_init', 'setup_widget_render_api_endpoint_polyfill', 100 );
+
+
diff --git a/lib/load.php b/lib/load.php
index 43456b27da16b5..57692dc37319ca 100644
--- a/lib/load.php
+++ b/lib/load.php
@@ -82,6 +82,7 @@ function gutenberg_is_experiment_enabled( $name ) {
require __DIR__ . '/compat.php';
require __DIR__ . '/compat/wordpress-5.8/index.php';
+require __DIR__ . '/compat/wordpress-5.8.1/index.php';
require __DIR__ . '/utils.php';
require __DIR__ . '/editor-settings.php';
From 0dc7ad2054ae8300f928c6ffd5270425f1f71545 Mon Sep 17 00:00:00 2001
From: Adam Zielinski
Date: Mon, 30 Aug 2021 13:28:11 +0200
Subject: [PATCH 072/214] Refactor saveEntityRecord from redux-rungen to async
thunks (#33201)
* Migrate saveEntityRecord to thunks
* Adjust ifNotResolved tests
* Adjust the integration tests
* Adjust args to select()
* Refactor functions depending on saveEditedEntityRecord to thunks
* Lint
* Adjust saveEntityRecord to deal with async calls instead of generators
* Call dispatch.saveEntityRecord instead of dispatch( saveEntityRecord )
* Remove async/await from saveEditedEntityRecord and __experimentalSaveSpecifiedEntityEdits
* Make ifNotResolved return an enhanced resolver returning a promise and add a test case for that
* Quality-of-life refactor of __unstableFetch from if to a default argument
* Adjust the second instance of __unstableFetch
* Adjust the documentation of __unstableFetch to clarify it must be a promise, not a control descriptor
* Remove a commented line
---
docs/reference-guides/data/data-core.md | 2 +-
packages/core-data/README.md | 2 +-
packages/core-data/src/actions.js | 130 +++-----
packages/core-data/src/index.js | 1 +
packages/core-data/src/test/actions.js | 278 ++++++++++++------
packages/core-data/src/test/integration.js | 5 +
.../core-data/src/utils/if-not-resolved.js | 34 +--
.../src/utils/test/if-not-resolved.js | 55 ++--
8 files changed, 275 insertions(+), 232 deletions(-)
diff --git a/docs/reference-guides/data/data-core.md b/docs/reference-guides/data/data-core.md
index 7ad08fa7f9ff22..cfecc33470ab6c 100644
--- a/docs/reference-guides/data/data-core.md
+++ b/docs/reference-guides/data/data-core.md
@@ -702,7 +702,7 @@ _Parameters_
- _record_ `Object`: Record to be saved.
- _options_ `Object`: Saving options.
- _options.isAutosave_ `[boolean]`: Whether this is an autosave.
-- _options.\_\_unstableFetch_ `[Function]`: Internal use only. Function to call instead of `apiFetch()`. Must return a control descriptor.
+- _options.\_\_unstableFetch_ `[Function]`: Internal use only. Function to call instead of `apiFetch()`. Must return a promise.
### undo
diff --git a/packages/core-data/README.md b/packages/core-data/README.md
index 96f6c1e300404e..4e906e79bb1be3 100644
--- a/packages/core-data/README.md
+++ b/packages/core-data/README.md
@@ -236,7 +236,7 @@ _Parameters_
- _record_ `Object`: Record to be saved.
- _options_ `Object`: Saving options.
- _options.isAutosave_ `[boolean]`: Whether this is an autosave.
-- _options.\_\_unstableFetch_ `[Function]`: Internal use only. Function to call instead of `apiFetch()`. Must return a control descriptor.
+- _options.\_\_unstableFetch_ `[Function]`: Internal use only. Function to call instead of `apiFetch()`. Must return a promise.
### undo
diff --git a/packages/core-data/src/actions.js b/packages/core-data/src/actions.js
index 6c3d392c31210b..fcc41bf5dd6cbf 100644
--- a/packages/core-data/src/actions.js
+++ b/packages/core-data/src/actions.js
@@ -9,6 +9,7 @@ import { v4 as uuid } from 'uuid';
*/
import { controls } from '@wordpress/data';
import { apiFetch, __unstableAwaitPromise } from '@wordpress/data-controls';
+import triggerFetch from '@wordpress/api-fetch';
import { addQueryArgs } from '@wordpress/url';
/**
@@ -357,16 +358,15 @@ export function __unstableCreateUndoLevel() {
* @param {boolean} [options.isAutosave=false] Whether this is an autosave.
* @param {Function} [options.__unstableFetch] Internal use only. Function to
* call instead of `apiFetch()`.
- * Must return a control
- * descriptor.
+ * Must return a promise.
*/
-export function* saveEntityRecord(
+export const saveEntityRecord = (
kind,
name,
record,
- { isAutosave = false, __unstableFetch = null } = {}
-) {
- const entities = yield getKindEntities( kind );
+ { isAutosave = false, __unstableFetch = triggerFetch } = {}
+) => async ( { select, dispatch } ) => {
+ const entities = await dispatch( getKindEntities( kind ) );
const entity = find( entities, { kind, name } );
if ( ! entity ) {
return;
@@ -374,10 +374,12 @@ export function* saveEntityRecord(
const entityIdKey = entity.key || DEFAULT_ENTITY_KEY;
const recordId = record[ entityIdKey ];
- const lock = yield* __unstableAcquireStoreLock(
- STORE_NAME,
- [ 'entities', 'data', kind, name, recordId || uuid() ],
- { exclusive: true }
+ const lock = await dispatch(
+ __unstableAcquireStoreLock(
+ STORE_NAME,
+ [ 'entities', 'data', kind, name, recordId || uuid() ],
+ { exclusive: true }
+ )
);
try {
// Evaluate optimized edits.
@@ -385,15 +387,9 @@ export function* saveEntityRecord(
for ( const [ key, value ] of Object.entries( record ) ) {
if ( typeof value === 'function' ) {
const evaluatedValue = value(
- yield controls.select(
- STORE_NAME,
- 'getEditedEntityRecord',
- kind,
- name,
- recordId
- )
+ select.getEditedEntityRecord( kind, name, recordId )
);
- yield editEntityRecord(
+ await dispatch.editEntityRecord(
kind,
name,
recordId,
@@ -406,22 +402,20 @@ export function* saveEntityRecord(
}
}
- yield {
+ await dispatch( {
type: 'SAVE_ENTITY_RECORD_START',
kind,
name,
recordId,
isAutosave,
- };
+ } );
let updatedRecord;
let error;
try {
const path = `${ entity.baseURL }${
recordId ? '/' + recordId : ''
}`;
- const persistedRecord = yield controls.select(
- STORE_NAME,
- 'getRawEntityRecord',
+ const persistedRecord = select.getRawEntityRecord(
kind,
name,
recordId
@@ -432,14 +426,9 @@ export function* saveEntityRecord(
// This is fine for now as it is the only supported autosave,
// but ideally this should all be handled in the back end,
// so the client just sends and receives objects.
- const currentUser = yield controls.select(
- STORE_NAME,
- 'getCurrentUser'
- );
+ const currentUser = select.getCurrentUser();
const currentUserId = currentUser ? currentUser.id : undefined;
- const autosavePost = yield controls.select(
- STORE_NAME,
- 'getAutosave',
+ const autosavePost = select.getAutosave(
persistedRecord.type,
persistedRecord.id,
currentUserId
@@ -471,13 +460,8 @@ export function* saveEntityRecord(
method: 'POST',
data,
};
- if ( __unstableFetch ) {
- updatedRecord = yield __unstableAwaitPromise(
- __unstableFetch( options )
- );
- } else {
- updatedRecord = yield apiFetch( options );
- }
+ updatedRecord = await __unstableFetch( options );
+
// An autosave may be processed by the server as a regular save
// when its update is requested by the author and the post had
// draft or auto-draft status.
@@ -521,7 +505,7 @@ export function* saveEntityRecord(
},
{}
);
- yield receiveEntityRecords(
+ await dispatch.receiveEntityRecords(
kind,
name,
newRecord,
@@ -529,7 +513,10 @@ export function* saveEntityRecord(
true
);
} else {
- yield receiveAutosaves( persistedRecord.id, updatedRecord );
+ await dispatch.receiveAutosaves(
+ persistedRecord.id,
+ updatedRecord
+ );
}
} else {
let edits = record;
@@ -547,14 +534,8 @@ export function* saveEntityRecord(
method: recordId ? 'PUT' : 'POST',
data: edits,
};
- if ( __unstableFetch ) {
- updatedRecord = yield __unstableAwaitPromise(
- __unstableFetch( options )
- );
- } else {
- updatedRecord = yield apiFetch( options );
- }
- yield receiveEntityRecords(
+ updatedRecord = await __unstableFetch( options );
+ await dispatch.receiveEntityRecords(
kind,
name,
updatedRecord,
@@ -566,20 +547,20 @@ export function* saveEntityRecord(
} catch ( _error ) {
error = _error;
}
- yield {
+ dispatch( {
type: 'SAVE_ENTITY_RECORD_FINISH',
kind,
name,
recordId,
error,
isAutosave,
- };
+ } );
return updatedRecord;
} finally {
- yield* __unstableReleaseStoreLock( lock );
+ await dispatch( __unstableReleaseStoreLock( lock ) );
}
-}
+};
/**
* Runs multiple core-data actions at the same time using one API request.
@@ -658,28 +639,23 @@ export function* __experimentalBatch( requests ) {
* @param {Object} recordId ID of the record.
* @param {Object} options Saving options.
*/
-export function* saveEditedEntityRecord( kind, name, recordId, options ) {
- if (
- ! ( yield controls.select(
- STORE_NAME,
- 'hasEditsForEntityRecord',
- kind,
- name,
- recordId
- ) )
- ) {
+export const saveEditedEntityRecord = (
+ kind,
+ name,
+ recordId,
+ options
+) => async ( { select, dispatch } ) => {
+ if ( ! select.hasEditsForEntityRecord( kind, name, recordId ) ) {
return;
}
- const edits = yield controls.select(
- STORE_NAME,
- 'getEntityRecordNonTransientEdits',
+ const edits = select.getEntityRecordNonTransientEdits(
kind,
name,
recordId
);
const record = { id: recordId, ...edits };
- return yield* saveEntityRecord( kind, name, record, options );
-}
+ return await dispatch.saveEntityRecord( kind, name, record, options );
+};
/**
* Action triggered to save only specified properties for the entity.
@@ -690,27 +666,17 @@ export function* saveEditedEntityRecord( kind, name, recordId, options ) {
* @param {Array} itemsToSave List of entity properties to save.
* @param {Object} options Saving options.
*/
-export function* __experimentalSaveSpecifiedEntityEdits(
+export const __experimentalSaveSpecifiedEntityEdits = (
kind,
name,
recordId,
itemsToSave,
options
-) {
- if (
- ! ( yield controls.select(
- STORE_NAME,
- 'hasEditsForEntityRecord',
- kind,
- name,
- recordId
- ) )
- ) {
+) => async ( { select, dispatch } ) => {
+ if ( ! select.hasEditsForEntityRecord( kind, name, recordId ) ) {
return;
}
- const edits = yield controls.select(
- STORE_NAME,
- 'getEntityRecordNonTransientEdits',
+ const edits = select.getEntityRecordNonTransientEdits(
kind,
name,
recordId
@@ -721,8 +687,8 @@ export function* __experimentalSaveSpecifiedEntityEdits(
editsToSave[ edit ] = edits[ edit ];
}
}
- return yield* saveEntityRecord( kind, name, editsToSave, options );
-}
+ return await dispatch.saveEntityRecord( kind, name, editsToSave, options );
+};
/**
* Returns an action object used in signalling that Upload permissions have been received.
diff --git a/packages/core-data/src/index.js b/packages/core-data/src/index.js
index 4830da46ccc98f..43b9cadb1bc775 100644
--- a/packages/core-data/src/index.js
+++ b/packages/core-data/src/index.js
@@ -63,6 +63,7 @@ const storeConfig = {
actions: { ...actions, ...entityActions, ...locksActions },
selectors: { ...selectors, ...entitySelectors, ...locksSelectors },
resolvers: { ...resolvers, ...entityResolvers },
+ __experimentalUseThunks: true,
};
/**
diff --git a/packages/core-data/src/test/actions.js b/packages/core-data/src/test/actions.js
index 6dfec991e2a03d..8ee805c489853c 100644
--- a/packages/core-data/src/test/actions.js
+++ b/packages/core-data/src/test/actions.js
@@ -2,6 +2,9 @@
* WordPress dependencies
*/
import { controls } from '@wordpress/data';
+import apiFetch from '@wordpress/api-fetch';
+
+jest.mock( '@wordpress/api-fetch' );
/**
* Internal dependencies
@@ -10,7 +13,6 @@ import {
editEntityRecord,
saveEntityRecord,
deleteEntityRecord,
- receiveEntityRecords,
receiveUserPermission,
receiveAutosaves,
receiveCurrentUser,
@@ -106,54 +108,83 @@ describe( 'deleteEntityRecord', () => {
} );
describe( 'saveEntityRecord', () => {
+ beforeEach( async () => {
+ apiFetch.mockReset();
+ jest.useFakeTimers();
+ } );
+
it( 'triggers a POST request for a new record', async () => {
const post = { title: 'new post' };
const entities = [
{ name: 'post', kind: 'postType', baseURL: '/wp/v2/posts' },
];
- const fulfillment = saveEntityRecord( 'postType', 'post', post );
- // Trigger generator
- fulfillment.next();
+ const select = {
+ getRawEntityRecord: () => post,
+ };
- // Provide entities and acquire lock
- expect( fulfillment.next( entities ).value.type ).toBe(
- 'MOCKED_ACQUIRE_LOCK'
- );
+ const dispatch = Object.assign( jest.fn(), {
+ receiveEntityRecords: jest.fn(),
+ } );
+ // Provide entities
+ dispatch.mockReturnValueOnce( entities );
- // Trigger apiFetch
- expect( fulfillment.next().value.type ).toEqual(
- 'SAVE_ENTITY_RECORD_START'
- );
+ // Provide response
+ const updatedRecord = { ...post, id: 10 };
+ apiFetch.mockImplementation( () => {
+ return updatedRecord;
+ } );
- expect( fulfillment.next().value.type ).toBe( '@@data/SELECT' );
- const { value: apiFetchAction } = fulfillment.next( {} );
- expect( apiFetchAction.request ).toEqual( {
+ const result = await saveEntityRecord(
+ 'postType',
+ 'post',
+ post
+ )( { select, dispatch } );
+
+ expect( apiFetch ).toHaveBeenCalledTimes( 1 );
+ expect( apiFetch ).toHaveBeenCalledWith( {
path: '/wp/v2/posts',
method: 'POST',
data: post,
} );
- // Provide response and trigger action
- const updatedRecord = { ...post, id: 10 };
- const { value: received } = fulfillment.next( updatedRecord );
- expect( received ).toEqual(
- receiveEntityRecords(
- 'postType',
- 'post',
- updatedRecord,
- undefined,
- true,
- { title: 'new post' }
- )
- );
- expect( fulfillment.next().value.type ).toBe(
- 'SAVE_ENTITY_RECORD_FINISH'
- );
- // Release lock
- expect( fulfillment.next().value.type ).toEqual(
- 'MOCKED_RELEASE_LOCK'
+
+ expect( dispatch ).toHaveBeenCalledTimes( 5 );
+ expect( dispatch ).toHaveBeenCalledWith( {
+ type: 'SAVE_ENTITY_RECORD_START',
+ kind: 'postType',
+ name: 'post',
+ recordId: undefined,
+ isAutosave: false,
+ } );
+ expect( dispatch ).toHaveBeenCalledWith( [
+ {
+ type: 'MOCKED_ACQUIRE_LOCK',
+ },
+ ] );
+ expect( dispatch ).toHaveBeenCalledWith( {
+ type: 'SAVE_ENTITY_RECORD_FINISH',
+ kind: 'postType',
+ name: 'post',
+ recordId: undefined,
+ error: undefined,
+ isAutosave: false,
+ } );
+ expect( dispatch ).toHaveBeenCalledWith( [
+ {
+ type: 'MOCKED_RELEASE_LOCK',
+ },
+ ] );
+
+ expect( dispatch.receiveEntityRecords ).toHaveBeenCalledTimes( 1 );
+ expect( dispatch.receiveEntityRecords ).toHaveBeenCalledWith(
+ 'postType',
+ 'post',
+ updatedRecord,
+ undefined,
+ true,
+ post
);
- expect( fulfillment.next().value ).toBe( updatedRecord );
+ expect( result ).toBe( updatedRecord );
} );
it( 'triggers a PUT request for an existing record', async () => {
@@ -161,41 +192,73 @@ describe( 'saveEntityRecord', () => {
const entities = [
{ name: 'post', kind: 'postType', baseURL: '/wp/v2/posts' },
];
- const fulfillment = saveEntityRecord( 'postType', 'post', post );
- // Trigger generator
- fulfillment.next();
+ const select = {
+ getRawEntityRecord: () => post,
+ };
- // Provide entities and acquire lock
- expect( fulfillment.next( entities ).value.type ).toBe(
- 'MOCKED_ACQUIRE_LOCK'
- );
+ const dispatch = Object.assign( jest.fn(), {
+ receiveEntityRecords: jest.fn(),
+ } );
+ // Provide entities
+ dispatch.mockReturnValueOnce( entities );
- // Trigger apiFetch
- expect( fulfillment.next().value.type ).toEqual(
- 'SAVE_ENTITY_RECORD_START'
- );
- expect( fulfillment.next().value.type ).toBe( '@@data/SELECT' );
- const { value: apiFetchAction } = fulfillment.next( {} );
- expect( apiFetchAction.request ).toEqual( {
+ // Provide response
+ const updatedRecord = { ...post, id: 10 };
+ apiFetch.mockImplementation( () => {
+ return updatedRecord;
+ } );
+
+ const result = await saveEntityRecord(
+ 'postType',
+ 'post',
+ post
+ )( { select, dispatch } );
+
+ expect( apiFetch ).toHaveBeenCalledTimes( 1 );
+ expect( apiFetch ).toHaveBeenCalledWith( {
path: '/wp/v2/posts/10',
method: 'PUT',
data: post,
} );
- // Provide response and trigger action
- const { value: received } = fulfillment.next( post );
- expect( received ).toEqual(
- receiveEntityRecords( 'postType', 'post', post, undefined, true, {
- title: 'new post',
- id: 10,
- } )
- );
- expect( fulfillment.next().value.type ).toBe(
- 'SAVE_ENTITY_RECORD_FINISH'
- );
- // Release lock
- expect( fulfillment.next().value.type ).toEqual(
- 'MOCKED_RELEASE_LOCK'
+
+ expect( dispatch ).toHaveBeenCalledTimes( 5 );
+ expect( dispatch ).toHaveBeenCalledWith( {
+ type: 'SAVE_ENTITY_RECORD_START',
+ kind: 'postType',
+ name: 'post',
+ recordId: 10,
+ isAutosave: false,
+ } );
+ expect( dispatch ).toHaveBeenCalledWith( [
+ {
+ type: 'MOCKED_ACQUIRE_LOCK',
+ },
+ ] );
+ expect( dispatch ).toHaveBeenCalledWith( {
+ type: 'SAVE_ENTITY_RECORD_FINISH',
+ kind: 'postType',
+ name: 'post',
+ recordId: 10,
+ error: undefined,
+ isAutosave: false,
+ } );
+ expect( dispatch ).toHaveBeenCalledWith( [
+ {
+ type: 'MOCKED_RELEASE_LOCK',
+ },
+ ] );
+
+ expect( dispatch.receiveEntityRecords ).toHaveBeenCalledTimes( 1 );
+ expect( dispatch.receiveEntityRecords ).toHaveBeenCalledWith(
+ 'postType',
+ 'post',
+ updatedRecord,
+ undefined,
+ true,
+ post
);
+
+ expect( result ).toBe( updatedRecord );
} );
it( 'triggers a PUT request for an existing record with a custom key', async () => {
@@ -208,45 +271,70 @@ describe( 'saveEntityRecord', () => {
key: 'slug',
},
];
- const fulfillment = saveEntityRecord( 'root', 'postType', postType );
- // Trigger generator
- fulfillment.next();
+ const select = {
+ getRawEntityRecord: () => ( {} ),
+ };
- // Provide entities and acquire lock
- expect( fulfillment.next( entities ).value.type ).toBe(
- 'MOCKED_ACQUIRE_LOCK'
- );
+ const dispatch = Object.assign( jest.fn(), {
+ receiveEntityRecords: jest.fn(),
+ } );
+ // Provide entities
+ dispatch.mockReturnValueOnce( entities );
- // Trigger apiFetch
- expect( fulfillment.next().value.type ).toEqual(
- 'SAVE_ENTITY_RECORD_START'
- );
- expect( fulfillment.next().value.type ).toBe( '@@data/SELECT' );
- const { value: apiFetchAction } = fulfillment.next( {} );
- expect( apiFetchAction.request ).toEqual( {
+ // Provide response
+ apiFetch.mockImplementation( () => postType );
+
+ const result = await saveEntityRecord(
+ 'root',
+ 'postType',
+ postType
+ )( { select, dispatch } );
+
+ expect( apiFetch ).toHaveBeenCalledTimes( 1 );
+ expect( apiFetch ).toHaveBeenCalledWith( {
path: '/wp/v2/types/page',
method: 'PUT',
data: postType,
} );
- // Provide response and trigger action
- const { value: received } = fulfillment.next( postType );
- expect( received ).toEqual(
- receiveEntityRecords(
- 'root',
- 'postType',
- postType,
- undefined,
- true,
- { slug: 'page', title: 'Pages' }
- )
- );
- expect( fulfillment.next().value.type ).toBe(
- 'SAVE_ENTITY_RECORD_FINISH'
- );
- // Release lock
- expect( fulfillment.next().value.type ).toEqual(
- 'MOCKED_RELEASE_LOCK'
+
+ expect( dispatch ).toHaveBeenCalledTimes( 5 );
+ expect( dispatch ).toHaveBeenCalledWith( {
+ type: 'SAVE_ENTITY_RECORD_START',
+ kind: 'root',
+ name: 'postType',
+ recordId: 'page',
+ isAutosave: false,
+ } );
+ expect( dispatch ).toHaveBeenCalledWith( [
+ {
+ type: 'MOCKED_ACQUIRE_LOCK',
+ },
+ ] );
+ expect( dispatch ).toHaveBeenCalledWith( {
+ type: 'SAVE_ENTITY_RECORD_FINISH',
+ kind: 'root',
+ name: 'postType',
+ recordId: 'page',
+ error: undefined,
+ isAutosave: false,
+ } );
+ expect( dispatch ).toHaveBeenCalledWith( [
+ {
+ type: 'MOCKED_RELEASE_LOCK',
+ },
+ ] );
+
+ expect( dispatch.receiveEntityRecords ).toHaveBeenCalledTimes( 1 );
+ expect( dispatch.receiveEntityRecords ).toHaveBeenCalledWith(
+ 'root',
+ 'postType',
+ postType,
+ undefined,
+ true,
+ { slug: 'page', title: 'Pages' }
);
+
+ expect( result ).toBe( postType );
} );
} );
diff --git a/packages/core-data/src/test/integration.js b/packages/core-data/src/test/integration.js
index 43fbdaeb27bd97..6eb1645c506fc7 100644
--- a/packages/core-data/src/test/integration.js
+++ b/packages/core-data/src/test/integration.js
@@ -213,6 +213,11 @@ describe( 'saveEntityRecord', () => {
slug: 'post-1',
newField: 'a',
} );
+
+ // Wait a few ticks – without rungen we have less control over the flow of things.
+ // @TODO: A better solution
+ await runPendingPromises();
+ await runPendingPromises();
await runPendingPromises();
// There should ONLY be a single hanging API call (PUT) by this point.
diff --git a/packages/core-data/src/utils/if-not-resolved.js b/packages/core-data/src/utils/if-not-resolved.js
index 0baf36f0e5d8d9..653827cdfe6c02 100644
--- a/packages/core-data/src/utils/if-not-resolved.js
+++ b/packages/core-data/src/utils/if-not-resolved.js
@@ -1,13 +1,3 @@
-/**
- * WordPress dependencies
- */
-import { controls } from '@wordpress/data';
-
-/**
- * Internal dependencies
- */
-import { STORE_NAME } from '../name';
-
/**
* Higher-order function which invokes the given resolver only if it has not
* already been resolved with the arguments passed to the enhanced function.
@@ -20,21 +10,13 @@ import { STORE_NAME } from '../name';
*
* @return {Function} Enhanced resolver.
*/
-const ifNotResolved = ( resolver, selectorName ) =>
- /**
- * @param {...any} args Original resolver arguments.
- */
- function* resolveIfNotResolved( ...args ) {
- const hasStartedResolution = yield controls.select(
- STORE_NAME,
- 'hasStartedResolution',
- selectorName,
- args
- );
-
- if ( ! hasStartedResolution ) {
- yield* resolver( ...args );
- }
- };
+const ifNotResolved = ( resolver, selectorName ) => ( ...args ) => async ( {
+ select,
+ dispatch,
+} ) => {
+ if ( ! select.hasStartedResolution( selectorName, args ) ) {
+ await dispatch( resolver( ...args ) );
+ }
+};
export default ifNotResolved;
diff --git a/packages/core-data/src/utils/test/if-not-resolved.js b/packages/core-data/src/utils/test/if-not-resolved.js
index a773097d70514f..291e224b3833cd 100644
--- a/packages/core-data/src/utils/test/if-not-resolved.js
+++ b/packages/core-data/src/utils/test/if-not-resolved.js
@@ -27,49 +27,50 @@ describe( 'ifNotResolved', () => {
expect( resolver ).toBeInstanceOf( Function );
} );
- it( 'triggers original resolver if not already resolved', () => {
- controls.select.mockImplementation( ( _storeKey, selectorName ) => ( {
- _nextValue:
- selectorName === 'hasStartedResolution' ? false : undefined,
- } ) );
+ it( 'triggers original resolver if not already resolved', async () => {
+ const select = { hasStartedResolution: () => false };
+ const dispatch = () => {};
const originalResolver = jest
.fn()
- .mockImplementation( function* () {} );
+ .mockImplementation( async function () {} );
const resolver = ifNotResolved( originalResolver, 'originalResolver' );
-
- const runResolver = resolver();
-
- let next, nextValue;
- do {
- next = runResolver.next( nextValue );
- nextValue = next.value?._nextValue;
- } while ( ! next.done );
+ await resolver()( { select, dispatch } );
expect( originalResolver ).toHaveBeenCalledTimes( 1 );
} );
- it( 'does not trigger original resolver if already resolved', () => {
- controls.select.mockImplementation( ( _storeKey, selectorName ) => ( {
- _nextValue:
- selectorName === 'hasStartedResolution' ? true : undefined,
- } ) );
+ it( 'does not trigger original resolver if already resolved', async () => {
+ const select = { hasStartedResolution: () => true };
+ const dispatch = () => {};
const originalResolver = jest
.fn()
- .mockImplementation( function* () {} );
+ .mockImplementation( async function () {} );
const resolver = ifNotResolved( originalResolver, 'originalResolver' );
+ await resolver()( { select, dispatch } );
+
+ expect( originalResolver ).toHaveBeenCalledTimes( 0 );
+ } );
- const runResolver = resolver();
+ it( 'returns a promise when the resolver was not already resolved', async () => {
+ const select = { hasStartedResolution: () => false };
+ let thunkRetval;
+ const dispatch = jest.fn( ( thunk ) => {
+ thunkRetval = thunk();
+ return thunkRetval;
+ } );
- let next, nextValue;
- do {
- next = runResolver.next( nextValue );
- nextValue = next.value?._nextValue;
- } while ( ! next.done );
+ const originalResolver = jest.fn( () => () =>
+ Promise.resolve( 'success!' )
+ );
- expect( originalResolver ).toHaveBeenCalledTimes( 0 );
+ const resolver = ifNotResolved( originalResolver, 'originalResolver' );
+ const result = resolver()( { select, dispatch } );
+
+ await expect( result ).resolves.toBe( undefined );
+ await expect( thunkRetval ).resolves.toBe( 'success!' );
} );
} );
From fa4f49d7a12cb5faffe3d8cdd0972e0c9dc3e350 Mon Sep 17 00:00:00 2001
From: Jonny Harris
Date: Mon, 30 Aug 2021 12:59:04 +0100
Subject: [PATCH 073/214] Preload menu REST API requests on new navigation
editor. (#34364)
* Preload menu data
* Fix lint.
---
lib/navigation-page.php | 7 +++++++
packages/edit-navigation/src/hooks/use-menu-locations.js | 2 +-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/lib/navigation-page.php b/lib/navigation-page.php
index a751ae32d4c607..31133a90d7ee90 100644
--- a/lib/navigation-page.php
+++ b/lib/navigation-page.php
@@ -32,6 +32,12 @@ function gutenberg_navigation_init( $hook ) {
return;
}
+ $preload_paths = array(
+ '/__experimental/menu-locations',
+ array( '/wp/v2/pages', 'OPTIONS' ),
+ array( '/wp/v2/posts', 'OPTIONS' ),
+ );
+
$settings = array_merge(
gutenberg_get_default_block_editor_settings(),
array(
@@ -46,6 +52,7 @@ function gutenberg_navigation_init( $hook ) {
array(
'initializer_name' => 'initialize',
'editor_settings' => $settings,
+ 'preload_paths' => $preload_paths,
)
);
diff --git a/packages/edit-navigation/src/hooks/use-menu-locations.js b/packages/edit-navigation/src/hooks/use-menu-locations.js
index 1b9b50a456efc0..b9c5a8872a7c53 100644
--- a/packages/edit-navigation/src/hooks/use-menu-locations.js
+++ b/packages/edit-navigation/src/hooks/use-menu-locations.js
@@ -29,7 +29,7 @@ export default function useMenuLocations() {
const fetchMenuLocationsByName = async () => {
const newMenuLocationsByName = await apiFetch( {
method: 'GET',
- path: '/__experimental/menu-locations/',
+ path: '/__experimental/menu-locations',
} );
if ( isMounted ) {
From 476d89cc65194621bfdc18fb6606c21ad01e635c Mon Sep 17 00:00:00 2001
From: Kyle Nel <22053773+kdevnel@users.noreply.github.com>
Date: Mon, 30 Aug 2021 15:44:57 +0200
Subject: [PATCH 074/214] Documentation: Update Inner Blocks Template section
copy (#34383)
Updated some of the documentation language for clarity in the Template section.
---
docs/how-to-guides/block-tutorial/nested-blocks-inner-blocks.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/how-to-guides/block-tutorial/nested-blocks-inner-blocks.md b/docs/how-to-guides/block-tutorial/nested-blocks-inner-blocks.md
index 3c6e8cb2418aa9..c7e28057671701 100644
--- a/docs/how-to-guides/block-tutorial/nested-blocks-inner-blocks.md
+++ b/docs/how-to-guides/block-tutorial/nested-blocks-inner-blocks.md
@@ -137,7 +137,7 @@ const MY_TEMPLATE = [
{% end %}
-Use the `templateLock` property to lock down the template. Using `all` locks the template complete, no changes can be made. Using `insert` prevents additional blocks to be inserted, but existing blocks can be reordered. See [templateLock documentation](https://github.com/WordPress/gutenberg/tree/HEAD/packages/block-editor/src/components/inner-blocks/README.md#templatelock) for additional information.
+Use the `templateLock` property to lock down the template. Using `all` locks the template completely so no changes can be made. Using `insert` prevents additional blocks from being inserted, but existing blocks can be reordered. See [templateLock documentation](https://github.com/WordPress/gutenberg/tree/HEAD/packages/block-editor/src/components/inner-blocks/README.md#templatelock) for additional information.
### Post Template
From 9b5a40106bd1814a03bbdb6544217402556b0327 Mon Sep 17 00:00:00 2001
From: Joen A <1204802+jasmussen@users.noreply.github.com>
Date: Mon, 30 Aug 2021 17:08:01 +0200
Subject: [PATCH 075/214] Try: Fix so submenus only take up space when visible.
(#34382)
---
.../block-library/src/navigation-link/editor.scss | 3 +++
packages/block-library/src/navigation/style.scss | 11 ++++++++++-
2 files changed, 13 insertions(+), 1 deletion(-)
diff --git a/packages/block-library/src/navigation-link/editor.scss b/packages/block-library/src/navigation-link/editor.scss
index 8f3c08717e5dd4..48d71e40d7150d 100644
--- a/packages/block-library/src/navigation-link/editor.scss
+++ b/packages/block-library/src/navigation-link/editor.scss
@@ -32,6 +32,9 @@
// We use important here because if the parent block is selected and submenus are present, they should always be visible.
visibility: visible !important;
opacity: 1 !important;
+ min-width: 200px !important;
+ height: auto !important;
+ width: auto !important;
}
}
}
diff --git a/packages/block-library/src/navigation/style.scss b/packages/block-library/src/navigation/style.scss
index 59edade44dcfa3..b96353903e7d6e 100644
--- a/packages/block-library/src/navigation/style.scss
+++ b/packages/block-library/src/navigation/style.scss
@@ -107,13 +107,16 @@
display: flex;
flex-direction: column;
align-items: normal;
- min-width: 200px;
// Hide until hover or focus within.
opacity: 0;
transition: opacity 0.1s linear;
visibility: hidden;
+ // Don't take up space when the menu is collapsed.
+ width: 0;
+ height: 0;
+
// Submenu items.
> .wp-block-navigation-item {
> a {
@@ -173,12 +176,18 @@
&:hover > .wp-block-navigation__submenu-container {
visibility: visible;
opacity: 1;
+ width: auto;
+ height: auto;
+ min-width: 200px;
}
// Keep submenus open when focus is within.
&:focus-within > .wp-block-navigation__submenu-container {
visibility: visible;
opacity: 1;
+ width: auto;
+ height: auto;
+ min-width: 200px;
}
}
From b72adf8aaa24afd1b1777c641806ad738c523486 Mon Sep 17 00:00:00 2001
From: David Calhoun <438664+dcalhoun@users.noreply.github.com>
Date: Mon, 30 Aug 2021 13:34:25 -0500
Subject: [PATCH 076/214] Add Dark Mode-specific help section images (#34361)
* Add Dark Mode-specific images to Help section
Reduce the harshness of visual illustrations while Dark Mode is enabled.
* Avoid spreading props on React component
Spreading props can lead to performance degradations that are difficult
to identify later.
* Add Dark Mode-specific image support to HelpDetailImage
Create abstraction to avoid repeated pattern for most editor help
images.
---
.../editor-help/add-blocks.native.js | 5 +++-
.../editor-help/customize-blocks.native.js | 3 ++-
.../editor-help/images/add-blocks.png | Bin 45166 -> 0 bytes
.../editor-help/images/add-blocks@2x.png | Bin 147462 -> 0 bytes
.../editor-help/images/add-blocks@3x.png | Bin 292865 -> 0 bytes
.../editor-help/images/add-dark.png | Bin 0 -> 46934 bytes
.../editor-help/images/add-dark@2x.png | Bin 0 -> 147489 bytes
.../editor-help/images/add-dark@3x.png | Bin 0 -> 276215 bytes
.../editor-help/images/add-light.png | Bin 0 -> 46916 bytes
.../editor-help/images/add-light@2x.png | Bin 0 -> 147534 bytes
.../editor-help/images/add-light@3x.png | Bin 0 -> 276083 bytes
...-blocks-1.png => block-layout-collage.png} | Bin
...s-1@2x.png => block-layout-collage@2x.png} | Bin
...s-1@3x.png => block-layout-collage@3x.png} | Bin
.../editor-help/images/build-layouts-dark.png | Bin 0 -> 69554 bytes
.../images/build-layouts-dark@2x.png | Bin 0 -> 211526 bytes
.../images/build-layouts-dark@3x.png | Bin 0 -> 387432 bytes
.../images/build-layouts-light.png | Bin 0 -> 69956 bytes
.../images/build-layouts-light@2x.png | Bin 0 -> 212780 bytes
.../images/build-layouts-light@3x.png | Bin 0 -> 389392 bytes
.../editor-help/images/customize-blocks.png | Bin 47037 -> 0 bytes
.../images/customize-blocks@2x.png | Bin 147823 -> 0 bytes
.../images/customize-blocks@3x.png | Bin 279441 -> 0 bytes
.../images/cut-copy-duplicate-blocks.png | Bin 47074 -> 0 bytes
.../images/cut-copy-duplicate-blocks@2x.png | Bin 147898 -> 0 bytes
.../images/cut-copy-duplicate-blocks@3x.png | Bin 279479 -> 0 bytes
.../editor-help/images/edit-media-dark.png | Bin 0 -> 92084 bytes
.../editor-help/images/edit-media-dark@2x.png | Bin 0 -> 301696 bytes
.../editor-help/images/edit-media-dark@3x.png | Bin 0 -> 574572 bytes
.../editor-help/images/edit-media-light.png | Bin 0 -> 92096 bytes
.../images/edit-media-light@2x.png | Bin 0 -> 301835 bytes
.../images/edit-media-light@3x.png | Bin 0 -> 574663 bytes
.../images/edit-or-replace-media.png | Bin 53979 -> 0 bytes
.../images/edit-or-replace-media@2x.png | Bin 169722 -> 0 bytes
.../images/edit-or-replace-media@3x.png | Bin 319793 -> 0 bytes
.../editor-help/images/embed-media-dark.png | Bin 0 -> 55298 bytes
.../images/embed-media-dark@2x.png | Bin 0 -> 172387 bytes
.../images/embed-media-dark@3x.png | Bin 0 -> 325077 bytes
.../editor-help/images/embed-media-light.png | Bin 0 -> 55038 bytes
.../images/embed-media-light@2x.png | Bin 0 -> 172284 bytes
.../images/embed-media-light@3x.png | Bin 0 -> 324970 bytes
.../editor-help/images/intro-blocks-2.png | Bin 11880 -> 0 bytes
.../editor-help/images/intro-blocks-2@2x.png | Bin 29521 -> 0 bytes
.../editor-help/images/intro-blocks-2@3x.png | Bin 53321 -> 0 bytes
.../editor-help/images/intro-blocks-3.png | Bin 60108 -> 0 bytes
.../editor-help/images/intro-blocks-3@2x.png | Bin 207435 -> 0 bytes
.../editor-help/images/intro-blocks-3@3x.png | Bin 427631 -> 0 bytes
.../editor-help/images/intro-blocks-4.png | Bin 93333 -> 0 bytes
.../editor-help/images/intro-blocks-4@2x.png | Bin 321181 -> 0 bytes
.../editor-help/images/intro-blocks-4@3x.png | Bin 659816 -> 0 bytes
.../editor-help/images/move-blocks.png | Bin 47022 -> 0 bytes
.../editor-help/images/move-blocks@2x.png | Bin 147790 -> 0 bytes
.../editor-help/images/move-blocks@3x.png | Bin 279425 -> 0 bytes
.../editor-help/images/move-dark.png | Bin 0 -> 45200 bytes
.../editor-help/images/move-dark@2x.png | Bin 0 -> 138109 bytes
.../editor-help/images/move-dark@3x.png | Bin 0 -> 256145 bytes
.../editor-help/images/move-light.png | Bin 0 -> 45116 bytes
.../editor-help/images/move-light@2x.png | Bin 0 -> 138054 bytes
.../editor-help/images/move-light@3x.png | Bin 0 -> 255883 bytes
.../editor-help/images/options-dark.png | Bin 0 -> 45209 bytes
.../editor-help/images/options-dark@2x.png | Bin 0 -> 138146 bytes
.../editor-help/images/options-dark@3x.png | Bin 0 -> 256146 bytes
.../editor-help/images/options-light.png | Bin 0 -> 45126 bytes
.../editor-help/images/options-light@2x.png | Bin 0 -> 138087 bytes
.../editor-help/images/options-light@3x.png | Bin 0 -> 255876 bytes
.../editor-help/images/remove-blocks.png | Bin 47074 -> 0 bytes
.../editor-help/images/remove-blocks@2x.png | Bin 147903 -> 0 bytes
.../editor-help/images/remove-blocks@3x.png | Bin 279632 -> 0 bytes
.../editor-help/images/rich-text-dark.png | Bin 0 -> 11863 bytes
.../editor-help/images/rich-text-dark@2x.png | Bin 0 -> 28780 bytes
.../editor-help/images/rich-text-dark@3x.png | Bin 0 -> 48368 bytes
.../editor-help/images/rich-text-light.png | Bin 0 -> 11492 bytes
.../editor-help/images/rich-text-light@2x.png | Bin 0 -> 28188 bytes
.../editor-help/images/rich-text-light@3x.png | Bin 0 -> 47782 bytes
.../editor-help/images/settings-dark.png | Bin 0 -> 45203 bytes
.../editor-help/images/settings-dark@2x.png | Bin 0 -> 138128 bytes
.../editor-help/images/settings-dark@3x.png | Bin 0 -> 256137 bytes
.../editor-help/images/settings-light.png | Bin 0 -> 45112 bytes
.../editor-help/images/settings-light@2x.png | Bin 0 -> 138041 bytes
.../editor-help/images/settings-light@3x.png | Bin 0 -> 255887 bytes
.../editor-help/intro-to-blocks.native.js | 11 +++++---
.../editor-help/move-blocks.native.js | 5 +++-
.../editor-help/remove-blocks.native.js | 3 ++-
.../editor-help/view-sections.native.js | 24 +++++++++++++++---
84 files changed, 40 insertions(+), 11 deletions(-)
delete mode 100644 packages/editor/src/components/editor-help/images/add-blocks.png
delete mode 100644 packages/editor/src/components/editor-help/images/add-blocks@2x.png
delete mode 100644 packages/editor/src/components/editor-help/images/add-blocks@3x.png
create mode 100644 packages/editor/src/components/editor-help/images/add-dark.png
create mode 100644 packages/editor/src/components/editor-help/images/add-dark@2x.png
create mode 100644 packages/editor/src/components/editor-help/images/add-dark@3x.png
create mode 100644 packages/editor/src/components/editor-help/images/add-light.png
create mode 100644 packages/editor/src/components/editor-help/images/add-light@2x.png
create mode 100644 packages/editor/src/components/editor-help/images/add-light@3x.png
rename packages/editor/src/components/editor-help/images/{intro-blocks-1.png => block-layout-collage.png} (100%)
rename packages/editor/src/components/editor-help/images/{intro-blocks-1@2x.png => block-layout-collage@2x.png} (100%)
rename packages/editor/src/components/editor-help/images/{intro-blocks-1@3x.png => block-layout-collage@3x.png} (100%)
create mode 100644 packages/editor/src/components/editor-help/images/build-layouts-dark.png
create mode 100644 packages/editor/src/components/editor-help/images/build-layouts-dark@2x.png
create mode 100644 packages/editor/src/components/editor-help/images/build-layouts-dark@3x.png
create mode 100644 packages/editor/src/components/editor-help/images/build-layouts-light.png
create mode 100644 packages/editor/src/components/editor-help/images/build-layouts-light@2x.png
create mode 100644 packages/editor/src/components/editor-help/images/build-layouts-light@3x.png
delete mode 100644 packages/editor/src/components/editor-help/images/customize-blocks.png
delete mode 100644 packages/editor/src/components/editor-help/images/customize-blocks@2x.png
delete mode 100644 packages/editor/src/components/editor-help/images/customize-blocks@3x.png
delete mode 100644 packages/editor/src/components/editor-help/images/cut-copy-duplicate-blocks.png
delete mode 100644 packages/editor/src/components/editor-help/images/cut-copy-duplicate-blocks@2x.png
delete mode 100644 packages/editor/src/components/editor-help/images/cut-copy-duplicate-blocks@3x.png
create mode 100644 packages/editor/src/components/editor-help/images/edit-media-dark.png
create mode 100644 packages/editor/src/components/editor-help/images/edit-media-dark@2x.png
create mode 100644 packages/editor/src/components/editor-help/images/edit-media-dark@3x.png
create mode 100644 packages/editor/src/components/editor-help/images/edit-media-light.png
create mode 100644 packages/editor/src/components/editor-help/images/edit-media-light@2x.png
create mode 100644 packages/editor/src/components/editor-help/images/edit-media-light@3x.png
delete mode 100644 packages/editor/src/components/editor-help/images/edit-or-replace-media.png
delete mode 100644 packages/editor/src/components/editor-help/images/edit-or-replace-media@2x.png
delete mode 100644 packages/editor/src/components/editor-help/images/edit-or-replace-media@3x.png
create mode 100644 packages/editor/src/components/editor-help/images/embed-media-dark.png
create mode 100644 packages/editor/src/components/editor-help/images/embed-media-dark@2x.png
create mode 100644 packages/editor/src/components/editor-help/images/embed-media-dark@3x.png
create mode 100644 packages/editor/src/components/editor-help/images/embed-media-light.png
create mode 100644 packages/editor/src/components/editor-help/images/embed-media-light@2x.png
create mode 100644 packages/editor/src/components/editor-help/images/embed-media-light@3x.png
delete mode 100644 packages/editor/src/components/editor-help/images/intro-blocks-2.png
delete mode 100644 packages/editor/src/components/editor-help/images/intro-blocks-2@2x.png
delete mode 100644 packages/editor/src/components/editor-help/images/intro-blocks-2@3x.png
delete mode 100644 packages/editor/src/components/editor-help/images/intro-blocks-3.png
delete mode 100644 packages/editor/src/components/editor-help/images/intro-blocks-3@2x.png
delete mode 100644 packages/editor/src/components/editor-help/images/intro-blocks-3@3x.png
delete mode 100644 packages/editor/src/components/editor-help/images/intro-blocks-4.png
delete mode 100644 packages/editor/src/components/editor-help/images/intro-blocks-4@2x.png
delete mode 100644 packages/editor/src/components/editor-help/images/intro-blocks-4@3x.png
delete mode 100644 packages/editor/src/components/editor-help/images/move-blocks.png
delete mode 100644 packages/editor/src/components/editor-help/images/move-blocks@2x.png
delete mode 100644 packages/editor/src/components/editor-help/images/move-blocks@3x.png
create mode 100644 packages/editor/src/components/editor-help/images/move-dark.png
create mode 100644 packages/editor/src/components/editor-help/images/move-dark@2x.png
create mode 100644 packages/editor/src/components/editor-help/images/move-dark@3x.png
create mode 100644 packages/editor/src/components/editor-help/images/move-light.png
create mode 100644 packages/editor/src/components/editor-help/images/move-light@2x.png
create mode 100644 packages/editor/src/components/editor-help/images/move-light@3x.png
create mode 100644 packages/editor/src/components/editor-help/images/options-dark.png
create mode 100644 packages/editor/src/components/editor-help/images/options-dark@2x.png
create mode 100644 packages/editor/src/components/editor-help/images/options-dark@3x.png
create mode 100644 packages/editor/src/components/editor-help/images/options-light.png
create mode 100644 packages/editor/src/components/editor-help/images/options-light@2x.png
create mode 100644 packages/editor/src/components/editor-help/images/options-light@3x.png
delete mode 100644 packages/editor/src/components/editor-help/images/remove-blocks.png
delete mode 100644 packages/editor/src/components/editor-help/images/remove-blocks@2x.png
delete mode 100644 packages/editor/src/components/editor-help/images/remove-blocks@3x.png
create mode 100644 packages/editor/src/components/editor-help/images/rich-text-dark.png
create mode 100644 packages/editor/src/components/editor-help/images/rich-text-dark@2x.png
create mode 100644 packages/editor/src/components/editor-help/images/rich-text-dark@3x.png
create mode 100644 packages/editor/src/components/editor-help/images/rich-text-light.png
create mode 100644 packages/editor/src/components/editor-help/images/rich-text-light@2x.png
create mode 100644 packages/editor/src/components/editor-help/images/rich-text-light@3x.png
create mode 100644 packages/editor/src/components/editor-help/images/settings-dark.png
create mode 100644 packages/editor/src/components/editor-help/images/settings-dark@2x.png
create mode 100644 packages/editor/src/components/editor-help/images/settings-dark@3x.png
create mode 100644 packages/editor/src/components/editor-help/images/settings-light.png
create mode 100644 packages/editor/src/components/editor-help/images/settings-light@2x.png
create mode 100644 packages/editor/src/components/editor-help/images/settings-light@3x.png
diff --git a/packages/editor/src/components/editor-help/add-blocks.native.js b/packages/editor/src/components/editor-help/add-blocks.native.js
index cb3e971503a7f0..e9e110a4134ea1 100644
--- a/packages/editor/src/components/editor-help/add-blocks.native.js
+++ b/packages/editor/src/components/editor-help/add-blocks.native.js
@@ -17,7 +17,10 @@ import { HelpDetailBodyText, HelpDetailImage } from './view-sections';
const AddBlocks = () => {
return (
<>
-
+
{
return (
<>
^
zMY!b1a{YginUbpNGE>7a!ynAdyfHJgz4U(P{myLf&GzkR<`Bl%7JhzLMBt7`lEQ+;PllO`hR_(0aVzx98U=A5HzX)Nu3jIt`pe87ofmc~g4
zA+WIP%(J~%>$=lI;G
z{*(vrxswz3|01=YMXit4U~vzv6vS|ukQD{q_Ye(4{|0BD`4q#0Yy9Ak{UJAMm$%RJ
z`Wr7W938Q_xytzquW{wdS@w4?GpZu%8>he=;}IO}9da-{;Qj|5U}brOoolvj~5TlV|7hcMg+q-
zp{i??gx}Q0JJ(_@gg{-_sqDR{nP2JboO>ts)lyqiMNO&eNC+P11LCB?vEjW-zV5vH
zZvOPo{*)}wC_=yiA`TG{e1jE1083*mspFWs8lzR2`j1*umK8cG**W(T&ph@q7Vr{48Ji
z@{{zJHu;gC{{vj_1V+F_8D2WW!TB?+oxYESTOZ;^?e*8+WO-$Y4`CMgFS6rEok?;R
zLueRy@>++u)1N6IsHV0ZQf>c}uHziw+R0-kfUvr{%GA^pB5smAF~Ht~NV^2y5O6AY
z$8$3#B9jxRt-IOh?wmXR9$LeTLnhjVETl;?9*@(Z&3MbQN|Q8V1j*j3S=2;Gbyafl;ssuQ=_O`o`^?O4Qt#|=us7mpG~(;N?i<;=w!^ThSXx|SI4qM0
zn3`T-G#pW85JHd9cu244;UvRq!AZfm8Zk37&9!US==TdYHa0ka?s6j3xrKQyUAn}=
z%mSlwNQ|0DMH~sQ=?@_9nmN_@jfwnIK*I^%`xGQn8x%}gU0KF?
zmweQ!WX?kqU~t+DuL)X>5Yt!@V~NEYjY1X2Nz~O&`&
zUPgUjYvVM7K|mm3z^GA6*iYjLAtU1PL6Fi=bIEU1;ryGI`M$6FHV(G0u()-CIyuSd
z^%ptf!ha>j@?T2s4IomPR(NQuvPt*F7PKh1mbhup324OR3);3V_?oIV`bPtgYZZp!
zSX@|OZf=gE$f@c`mD)O5a=*bK1+-&(zx$3S>~X_6it
z9g-9rAnl}cjLI?neh)8^cvP};@e0}06usFTOZR~YfPnerOHIL)G~q+Q{DAfKyLj&L
zM|kP^f8l|Le;?s0PSYXJj<8?mw)b9Ltm^K&!I
z&Chc8-4Af>>Sg8@rZ{opBxN<^kw?DD7eD_A@_fLl(|4dMN%?K9uLHux%iGu6Z&H@R
z{=t~c_YeX`Ady>uJnOTyc`~h9x3BE5u&|KIYinz%T-OzIvkPor@7p<_`fyHLf;2O#
zs(N1>B-jh|dwphRX4u`?2T0@>yhp1VLogG}T5<;7Cfs)M25Rkm4I#8-F9KiKg@j<;r$aqR@?g1>P!$K$({Fir^cPYR8-WqB$Xl
zQU|PTKFljGe}U(o`7}#2|DWZJZ-LN9?Fey#^Eo0e1rebl9-ZT>kN!Ph|Mfq@IBw8G
zxN$RzB5*W3WH=hq>-CwQn`L|ZQo_coubyFRbCd0>SFfKp2+c&_+F0h&r7KCrpFDMn
zy~At7+Tnvy#xcQV2?Ism$7x_^XFmnNg@q;d_xD?}JUTjJadDCD?d{Zep7p5f5)p7B
zKq6Fny+$FE|qxS5}#wn?qff$ffmr19oiAyMypP!%S;Nal;d4V_I
ze68Jg(x_xvNWow@9Ma^u(-C9ryu%iM3HNL3YgA>`5MfP;B1p5xXLd5WUIaG1D`Mi)3{L$nLHwyr7vdz*-KmGp7M+?@a)
zl;AslTTzDqu1N=k5YQMC*#MMP1qRN$L`rjWbBx9#27^9j%7u<`6=Z$@W>gwM61gy`
z#4Nq5K;ea=pRuv^Enx7%Qy=5Sul_UVp8YKACmv#Y^;Y`*Sw?$1oIC#{=g&XQgAaWZ
zcisMdm@Z=R<{(|<1FEqwJy>LQ9Dm`#e_G^W7goTIK_Z+Do~zft2H6Xfm?9H8l%nF5|uCr)5g?MDbs
z-X>;Ht(nA>)-r)}n-naQbD+CgI2NCi>C?&J(4;<6oAvcIP$h`N)B5WAYlDPZg%eM@
zE(SEXQU^{TK-Qn)Xh$#&XeDG~^fTdW9=wYO9=MI5Ly!uU3J{D8vK*sE)$p}TcqB%m
zD9%N+GPaiIS^Cy_*5?c2c%LjU2x1J6F5m{6xM(<02GavDKC)?<&daxUIq3kIi25CJ
zojf;(05t6dnDA+Wh^OdfEUhf3rEME9T9XeiBHm
z1>l?z>pJC6Z46~B(HN7G?DzZB>C1~Ty|>C$MV{x3%Mps9TH<`bW37S*+KG-ThzHUt
zf&R=Qr|6chqSYl8FpkQa`@VaXIDiX#_PvzWx>nWan{#o)~pS$k8H*GQx
zk489OF*Q8^k)-xA-)mEc&DSQ0%-`BnedF~v84RWv4oB?o?=U+%!_LkgOG}G@G)nyK
ze78%_H3f;_67KU{sOyMXt4msQ;#gZ-#W_gzRoG4Hkffk#@!MWIPPlYeU^lv&
z_1>qxS65flGfw`bvt`l=8tsZj0=TsDXm1uL7!JWDtPN&nxOToy%3EunR#FRt!1D4s
z)1jtr1fP135Qr)`F_P++3N&Jx5&eMZ3cL@DZN$=MpS9&Va$lkX&Xmko?C)G)cCkY6
zU`Ej^7?;`(=p#h#hFR>SLln%ArYId^f3GiUT5EFZAnDJU5*1wV%+1X+J2Q(pp;8cW
zEs#2@w{vdoeF+=5DYEYRycr@shR~1Av45})*0xPc1|fu&n44>9B{VKeoc93f9DJUL
z-XtRC@kNHIqZ^A_GI0*^kb6&sXS%qLsm0qkanBB=?%=8lpL_Cr8t0aAZjlnjJ4IXs
zF>b~*LI^#)&k-aMVCDl4-~WHuzH*JKEa?xXxaaPNnVXyC%xh0DE)RL*wU-f@CKP=t
z=Q(})R`7j_{#0tG3e&So#9&Mn1tI{XK$vpvhvW1KR=(p{<;%%~RyXmS%j0P=%NUFme<~-JH;;IQ{jFi=gx+)x;BcrzW2%ZRd2MAs&oGZ|5iagGfQ6r`xCE^Vur+Q0irBqCf(-hKgIvD<2+5#pP
zfsBtvOb=#K&N>88SFpKpJA30XaZ7yp&L>rieSNwTjB1%Otzy`4Glz4z{?
z?-YoLRp+ex}tj^dL}Gw=Xj?8VXU{+}2#I>0tzd6a;`^nU`5FUnb5l-*h-Wy(h7p
zdNh&%-0A5lnr$a58+v?$aB6yRQ)EbcQGz%bjxf8rL_Of@fGV03Y&MO^9@(BbN1n&e
zy)jZjFGcR1VAnx`SI3kBA#ieX%#{^$5_XQ;9bUOnJ#TRicFSycU;id|Z(8}|lVg6?
z@#U}Ip8@-BwV0}=G_vbeF3Qi&i(^4m6Z`TFHIiQQXFBFG
zT5B?jAPrrrAT_CQmfVe>P9OJwn
z8t37A$hn&?-8$SnZzTeEJ7BkiFM+%lL{-3{T7&Yv$U$Ksi0dHUPr$J2?g^?lmYcon
z?D9%&klyM+@6X%AuJty++Dj4h)&Q=vIJZOAeFSdtF75X-5Xko-_vJUzxtKJ;sabEN
z*CT0>4e)$j|ef}lRKK~SllOsHO@C-$$v0AN#Z?EeT
ztJOxl^2vDermr)U7Kl+Ki>u`V)9Dyji#4ihDO63@C5dA!mvaF?Gp087__-*I=Aaj^
zs-|t5VFuxFdLY-hxVW^jyNC1QZ^pIyPEp2N67n36w>jP)vv1}@PC^Ggefq37_tdZ`
z*z;VwS8rp*zF(!H(L)tj`X5ufaK%^;Mo2kexo&V!4!Ppfb0iSWHjK!Q$2!&6CmM$e
zVQ_$7`}M!YVDcfV;UiS_6m4vQX03OT1KPI6x`}x7;oo92JjJKq`FG^DLAPDP4Icp6
zX&Z#_K636}b)bMWs)Ks#766629gva?S{+QLf{9rzw<`+K2_GCBNc+a#ieMM`aS-kJ
zo_)aeR?Z!`{k!_--vZP-J^7wNvClh?-NPX64eb5pbmtB1911w27U-dyM`$O&$#H7b
zir|GZ2w|vFyzGH4ntDcoTu(E@dn4E?{Hm$;Bsgh?ra*?*tW588Z}IN#2Dg4&+x0So
zcLn6zy0ij(!f14ipMLVW8eV6Lm0s{P6HGnNH?LS_jQKiscYJsZI0fOR*-#~QeSAXu$ysg*
z3Mii+5lRQ=J%jCPpafV;{O#ZTB?_T798%Zn`2`T^Av@0XT32(ziL2LL1V>}69(P?y
zc4}ZtHZ6*zppP)b7C_i`;#3raQgA1?5t$zgha`O*5W#!N0BSsV@~7~_mnce#E=K55
zhbC?$vC4_#8G+y=xP7tO;P}z+V!ZemUw!$XXs%vkJbZ!ZpsE>Hy^r8-d|B${9l5=-
zRvnz2mY|eMisWj6(Rf5)C)f2e3k>i3>IbZT+N7qtdh2(URa#G(hs7<$*q3+Oeo2#8
z8m9!ZrmuTPPpQx#U;0T2V#&P79rPLBbu0kx?!U?Lp39!0wLVZ!Sbu8}?>$N|v&72}
ze*->bELJld93A5F@(T6f$M09K5nN3QMI?^3fP00q9!lAQ$z%jaH3c)FQ9wE5#I}*l
z){H`Q;hW7$+H$?}^3Ha&m(dtTZ|KVs@7_%BA|zCm|8Wk$pW))-+}sJYT`R^%V<-uQ
zQ}qhZhw}TX#)0;gg136OJXXi=MEhF!d)||?zUs>%1<13@s8q^Hib!O$MHw)fOeFQ+
zxeiV=_7D|J+OCn?B|?$Vv~$$s1Gq3kVvGSE1rl^6QKBfa0y;``+ZL`!$TS885L1bi
zYrMW%h~lV?35!iqV>&E()2L&_hzg}DAXEn!PajGyMRw5dP~r2s
zss1*>_XW`XDV@8kSoT>d>?nP(L&LsHlbmmGr}jDH+6uv_7Xlc;ORuf%22*n^mrHtf
z!Xxw40r$tKAd(_blmbLW*1+GsB^YpfdfB`8yPT~2D__^u9k4N_L9(V1hvMk?0ls?u
z71pW4bb9#XEra;`!|(q9AH4ikQY`eiRqcW#S+KL&MvUA2`}eU}E>SXoE1oFeda7zyDCUcL0=|a-6f>d7kk3{Gau!z8T-%A<^q>wvu7{E5GtW%0$Gj)l5#9
zJdvv-D6nT}OiE~zDD`i$?t_C;DqMA04vH^={JugAdQcg%Q7_44i#jeOMq{*>(}4SU
zG{WbfeTLX>;X=?LDTAyoq4E(&mB&1G;-$N4jF>X?CX)cJ7b+^t>acJLT{%L=1}U@%
ztl#4*+<){O6Sqczjg~VB9=Z
zfG|`Kl@tX5D@87EI|T#)=`HyKyD6)$eMI&tj$3jYGAc=qY558FA3VcgIu%ckMZ?gs
zu-Ht3q^vn(flLL_P7;xpOZDE{ZHN0OkHq68Ws#Cn71Y3!x|mGHCYv-P%y&`K5a8Ly
zOo%d?hUeNUz_PYuRB&(G4&(6@i^W%Bbhq0^c>b88g0yo2+Fhr`$#`9YGgn+Haos}a
zTmYcKTLygF7{$BgZ;iV8VE@XsS{)bido@;20)WJ2Hrp+NFYpil@b{Qq%(2}xNI~gV
zkAN9f|CrwRfX3heX?%>|{o}tyY*r{;%d1KZ
z2ZhQ>fh_fIN`4*=kxGwP9!hrbmiJx+sV6iTOvC|EyQ#Efm#IEVaM6oetEtBLwLkqA
zF&YWEAK7~kX_?#y`K&w}a(`0o(%I?;$4MjHr4|U1eZ86!`?slGcTZq9Z}+VLzYkdN
zVQ7@Y?t?R&4jv^(byKg)yzM=MuIhR9udTcCElME3nO0iw1FlzM!DM@zMu8mwL5QF&
z^07R~2L1>^3y*o3XPO~-TTJBZHh_Ee!Hy&v8(XlrLsg0jV>mfRIhjgafD^qQRTvG&
z2q8nWN~s7bfvj~_BKH+R+JfLcUo54v;kI2Or%qNmNDkX|gDn%77?ku^C@??>g_J^I
zVLJKNSS%S-9tzFWY*qd9`B!J+gt7XnOF@j>cGCj26W%+S
zRFs~x8)`+?Z1rolGDaf`&8~%JqG}AF;XbJq6G{yz|JI-Xn~rO#QIo}R`LaYI=jxaa
zQsN<^iyOT9@)bgwB6eG(n)KBMRUAO2)j*D&^pg1JbD7I@1CkMFq!LMW4
z6&Mslp*#qX+ii!cEEIrJR0*okk)0?&w7+iFo1r0i_3DhjQ49nG;T*DGm*(Wpj>Tdda$lgw(oMP;s%A?~x2(!CL_
zRCEkUt2iQeT5zmuh^DAXw)&aY-z=K^)D8SSad==>J**O4G!x;rS^cc{L-t_e00up>3GQO{0v@C;%N
z>Y7V_f(zee>5k+?vEVZH%`f=c=@~P^yNqMMcDbUw#)%L!4n`Bqmkl;c20wZKW|WmC
zi0U=+6n+qCBl+Eev`J2YP#IYQi;K%vkIe+ngvIOk
zIy|0j%g@|L<<4R;7lYTfTcLcK%}PoWgMiBbtOk!cK7{fK3D~5L|5M}XoXIWa+U7`I
zk0a%qjv1f^1iBh=9*8ZFeMd@4Wz?MOW4PyWZqM|t%P35=p
z)uptXGI&3A?)lctH|wnIJVry7Ej>UH3iHbOznxz7{uIpqnW4Ay=sUsshUVSAXJ2E|
zKVFx^2{}dq_n~-Pjd)3pfh;MZs@{`bSXKux(cq{>eV4?tjdLlqqbnTn=Nf5*2H65M%_KE}Corm9B#bkh?-a7~`
zKuwOCUT;|=bu?~kkr`Hl8cu5*2{`dxgK-79Z;oY^B0Ba}Ql8tfis1lgl1Tc{(c=fc
z{N($1@oT?_4K!fcbuI6K*VTuB#1-;2I&)VaDF6als!q}?P*62TQtwuH?-$QsisHt`4bKf;HS0V!OAN`2By!st>}f0}mGBlJTAa
zMBQbMiBgeHgUrN-T33oY`lwJt4FbLen>E8ZbsMB^iME|%v!0=8mU8{+c#5hhRq6?q
zcKYCvihxaYh>nyfF(@F&Do@)L{0yj*
z(5Jr>9l(A2)@tFP+YRsrY!)E3vd2k-Km_9Xe1ZG-lS&BzdCxh@W7`goPVmX6pR#@q
zC!?xQj75;o4$vVe-cT1i3FuwTS6ue02cxaAyTn4$C<)|R$<|(g9CQ75cLMIgxK;tX
zX0wqAeQ|Y(`ErTzc!Eu{#b{7Vz_rU;gy^84X+~0k>?f^|zRuTe{ktns$oB)S3N!$c
z7MJQaLP=HQfy&}MgUus6esE7f%Viof%k*g>rOI51Emt!jKvcqQ`)-ZOb+|bD1ehM6
zs>af$=Vur{)lFwd2J^wha(<1yT52)_8@3pD_P0cKZMc>3glsE>4I
zt`t_FB5AXbxv!b5yf!p2s(ociT)ZDEM}4C&z1&ZRIyM^Ah5-Clt_u_xmt)O%F077{
z8U;DGED;$n9XOm$hjNV~R9aU*lit)7j*W?!zoBJzKac{RmE1Upbdqt~qvG7Vfb{;n
z?SATwT~+knIT0yy84Apo3siLlhfkm4mA_2WEC_&`xFl!{~BUc{rPY-
zz~$9k9`J#r-fT)L4b+67c;kUFK?B}+^5ii~5eR70!zN(!-RKiK2lns~lW}s4S(#$~
zyC)Tpu7h*0+_%S5rvc{u8>uV
zh};8sTQTm++|ID1t_W|>h*0eB&7z
z2Se%aO^m8_&%Ih!J(`#A-+;Szj0}*`ux!y#i1pA^~NAYA_*Cst0O8b-qLO?XgGM7_i3J3b30jl^pw{M~`G2
zRh4?A1aXUz5Tps%JkAQl(QwlNBk#_B7^JGCv8+Hz2Sj+FccMy`13h}yOZ>FK!kebw@ZGllysrMjf^g51fLNRfn2CT=u3^g
z<9|fA{vV(H2p?Zv04d<{@dJGL_$f}NM<~6919I$oV+QDXMBjMs)}$c>@^o5+3IS
z=i$Rg`1q5LaCkUDAtRBV7N6?>L?$GQSG_(v69chNNqgt42o&2|ABv#&*`s`Rya)ok
zM=MW|^dy#vPzj|EvJ_sgmh$ik*R12;z|Rc4ab8SaeCpF
zbY=lbZdRDg>Ia!phWqG@@!7950^G;*3HSthj!hoJYtXy5fG4kGGFaW0JB%kaGLi(E
zk)3S3e|psLLFA!{HD*9%OMW9Wbk+v9*NIY!SBuTD4TI1wDn3XqA+vmM8!=2-0UO%K
zp$s^j9>RqIo;`Sum-imwknK>Ac8QvBnfsF_?{e7QV{mtlgMfp>26|r`Y{%?XD&S}N
z+CN=>FMYj&L`qOvf}UIf)gw2!xSHYqy?Zjz=pk{kY3=WUP#HXzlY&&u@zD|18}glF
z4rqO7MvnFjOTJSx&2zLih;u&?+%4rB`030=Wc%mT>
zQoF>V0Fd-vcd3)U_GPa<%kv#dC-0odk!=iZQ@vlmv)!BvvfnNNt9I#Y0Wec_*i%jm
zGo^AZzk@02^^sC&B1?tH8wWDyMk8*|>8;D(^qL9Gq+H00lTW9^WnMOqvv(WMpMCb3
zDWR-SOkRmkKKX>J0lDtCzV$5zVFmOVgth0!@-vM?D4>RCtFq3Rfs!rfgT$F)>#$nP
zQ2G|`V5DvBl}C?hOC!O3w?1Q7BM$+pjFCOMMs0yuc4(W3)q0Kbc!=OjnMbt`_>&KQ
zT|N)WF>0^R>($`3$|uw953B#ibFU{uxZr@O%bE^JgGITQfFT~xt?8ye*A073rU_?z
z?03mN4M;-YP5Ynv#kZ)g_yC`O{yCmJek#l9`D~8o&tGCTpJTn*qO67roI1GqE&;dP
zWl63uu0^~yI1D5mUinh40FI7MpaINIJZU(0Lqci6C~a#S(CC-!z0I@b{g{rrm)Q%}
zSrKrjd@zI{_cR<$P=-Pu_+iy2a~7b?J$dJCKx}Go97|iaG}8^DCUadWB}&
z;^m8%SP5uzRksnEjX`dn&%T&13aM|Cd+IN%F{44{oAD<0vpH-v6*beTlo|-mY3-Pl
zFdWn@-ykcs5dpO-1M(EF`e=&h9U2wl`iK*rPwH}A!$q@7D$
zubrl*^?e3+8Mdi~)7qQrnP|trp;Mr;fa*II`udq$R`cMmE#W}VnuA$Nx#l;}Zt2ik
zpW4~ejfN<^f;T75#l;LKC-*Tu(E8~hpRLPu$g6+`RO>@iC8^FCj%nvInPR7bFM3$?
z*t(7$yed_Yfw&XFA{24@6iDy=_LpVrT7XS8)RDokC@Tx3e3si*t@QkFmsaNm)LKu@mQSD~2F>pC>+NVTkK^|wu5E~)zpFiK5nFiy@a6exR5
zndCf6OtOKIalIP$E<@^ce^P_slAxJZeJmhZmB0JDzm1$3Abnt^nicS3mLgt@^^!(O
zy!*!w@AW02x`{^}p!*9b9U}kdD$*Y0qN*SyQB4){0~1OqD3^^}*IGM@!boy$k4!MF
z9I`K^CcZCgT%28DdNe=|9$F^3C49pd97Ag<`w+X0QZIusTuGIZ7KAQ&O+dD&R1Q?v
zRH;NVWR$|`E2RnEccJCTyO=bF5u+lO69=?c?>_bLthf4p-#z!&AAf@BpoAZfMLray
z2U?)$1l&^>;X_Sc@m*z%H)^2&EM8s)Z0ZA@E{Fe*y}tmGB)PKv;h(!lL~=1TbNBR+
zW;7^`q#ZG=mhtiX=+Df|jE|X_-&=mt(}-cE0S!}6Ggem@Cr5<)w|&jsDl9F#t0vX6
zYk!-Lwy?;`s*a3|^t^uk+;h*VR_V0cR0MyfAd~7ydtKHy)@5mIjFF<$>guX2WhW=6
zQNb8ktMFwRYCciaj%kbujZJX(Fkx0aZYr)yNqGk?5e4&vVj7Fumfjn%+CXhoUiPiKKj{4$9+VAvz1Ibp#8?w{)ikcg;UU`i|2JH}?m;vZxz(_nye1-YJTKuFL
z`NuAFMS{GR#>xvgfvNJ)^MM+X*6UCMUZ_sm=u={&DUH?n(34Mi%AZ4mR^Y)qQEx=9
z%EZX)vmXg~imm#LKUy2cD?_{mgf5HCQwiQm%+D3dQ)gutY+qx;>MqX(chB<_mB+%I
z>b2MCE?;Hk+7*)07*h*lWZIAkPR>#rpT%K3A^^f9DryD+
z+7S#tgtM-22u&Gb7kM^~6vDAv0cC`Q@%`7tB+I2Y-+Yra>yx@3043YQZCvLc{*AxL
zmw)TmP~^C6q+PYv+b+`wn^Fcb-1mAj#sr8Wbn?maFYEQOX(oX~qdeER&)WJrOG`_f
zJ$shGB#PtMQ`IDMB@Zz~Gvpo>Iu(%yqMLZCz&eDkS76t|f=n9SUXND01?pB!7z&$v
zuDcU6VIY#nU?gy5DDvC0k|e+@wRJy?mL@03+}E3%NU^WiBe%IUELgwNeimIT;B7y}C0Ef{?$3YzeJDcDvz
zU*Oh5nLyQFiL~5!De@ZEBWvD3byj%pnP1`ZYu}@y
zVQpm@6UUNGlR>-F6q;;OGBg@x%9V&x_2#i6wWK^x5!KAJkC=yNxg?O<(`%gyUE~_4
z3{GoukVG@JR*sp?L>)4-xjfFSE!+ottNVX9bB`0l^{eNYos5LDyV=cf-8SF)%2)Us
zf8+1arpC$p9%KKJqo5cGa@mHh^1GJRhx2DyCIzcjtL4q34Mt1$Ce%cf1b%Vt*|lr8
z6qznxzRcdedj%s02yN`BpeF 2A-!RP9=YfMj0&}h^J21$~{cPvKC&Ck3=EDblP*
zzt^T*Er~!ENU*$9H6Ib2)3{LO39FD|4Z|CZ8`9iEd2$WgGS7y~e@K6YLfBB+VU%Cd
zXhUEPTIJO>{a7;|&rd~L#(*)Rw{!i%>o{@rs-xqGdQ=5#(LIF~7-j;ikd+5UhV#8^^{FN_B0rp`OBno3l31
zgx{aReLU%Lc)ZVr*S^EiV<#!sC#cU=DVYu@5A5cfFP-Jf|KcnBe~uhO6%+^ul?ubp
z?7oI3S3)k>9;sZp+1q+?H7
z_M1&<{t3Q}!T>0AvdR~6NY<{9;tv~}8_dtnFf}#J;`Qt7-LnU!M5~0!@d>WqSfaVH
ziNXj?(hY6;lAmtDAaOW3Xe^c>OgzZ3L`i`6PCrH%3VGfTSf*4evAB3$9D1r{BTS!a
zQo^PRtb;5^1q~7DSk&)H@!Lw~UVvr1^Fm>2L4nj3aC_xHBPTBSKIjScF2`yE
zo@%Fjl*`jhf?B)PrapO-q0&aw2Gv&4(#nEKW30?D9tHwU(SMlWP35oGe{Q~@ZS59D
zrFYdb4IjS^gs<`fX=Bb&K0Y6Huc;q9Wr=&hjP9|X9$U%gJRxq+@3ZmeBrCR40-4NrXX)7;pwJn@;I<5R!zOITq(F{rh@Q+|7K
z0vM^$XmsX<3)XOwJu4uWY{E+0_~pyjn46zNTCyjnS-QT&!rVMjsYI{SLZOku=wwY~
zT3y5E4yssGv!H@aVNqk=dQA}t9AZ7z?e}HLnrFE<097hgDPZ+8VNTHPr_xk1NR=sS
zncoJ}2sxn)_8{ksWKL?Zw?P`0qDUAKGMPvldpDB_Y;9$gWHtsMH(K1A`rTB5t|Xj+
zb>q16R7jfzemF|5-OBF5=P3}3gV2o_!l~9pj1!kzUqdk%S)nO8DkZFt5Md!FfWLw_
z$3A#T!xspoV~jZYOWV9d%j6-diCFN(TIIhZp^u>0{Dtz#fS)7rbql8{CQac4A-IP`
z#jipXD7_WFB;e^nrt5|l;9YSdbSl(Oa1162MxL`)%ebs+Y5u1&xgfPS6C26^N;;a6
zk3X05NHJ9#>Dnb$@*3D+wC($74j($gANT`*h^Kz+LtMFjnNw%aqIJwGue{9buf4%f
z{nSsgYknRF7$YkioObeh_b
znSDg%27mb9dIaJMnNBdq2S-`zSs0-M^!Mt1S55+FHFPnOv~>(o%@?0VH%2SqDM9Nc3h}i1Se*O=7IAt}?%{
zi-U&_@x~jk2cajCTU8p$NsQJ$>w9-5CWXvShl$O1#JgMR^b0jpq!n}|%#3~{fect<
zZT+Tz)fDZ1m+{(|Kp_GdSqm0~&49(-;psR8a|z=9aj4&hKqbkB$HlP@MacG)53UFt
z5yxfuyl>Z!;k0MCXi@&8-|f<<*4S8Chb$M3^lqn3tGOX{nC51asksFndh&64g^W=R
zEZGJ&pS6cP8ZbUE2919#gUx92vtZ$PoZb58OyTd8-v>Pc!U89kNgO3V-!e&1%6ZYX
z9z+TW;*t<4G1dqZiPU^>A`>igFS$=HfA|mB
zy>BoR@Df9_~tFc`TGmr`YVY`AdKP&+_u?Z}T7jm;VLFPo9wT7!@NE
z1D0=m&jAMrn$#*Pw
z8obkj^%;C&yBpl6XBH@Z@F_M>xMoV{%2ir7t~0T4kUko;McY16B>Zfe%`VmPNf^Ei
z997HxJ!8zs;5Aw@&Oqbqi_KU~^g!0uSD2U>6D<*O*Xebov14U*g)Hlfhi0u-m;bl4
zbe)-*S)2nopHhMo;&Ox;f#u?b^Bg~MTxgU^DQ2f+wTKn<4s4bxu#e#T8w_
zg7+*BKrou0`uU&X|Fdg9uf6#;Mn&YVk5j^M
z5^vWRUwVaq^WXT_DJLb8a?Jn!$Nmp6ic1%-O2&Wv`VxC~FYq7yTmKrr@bkaGAN-^L
zFYt!(M%WDQZinjN)=D&M)>3j+EJ&ODt1mvsQ=eV{&mu@{kF}*m{@m{rLl#$C{I~z}
z|Bg0Me
zGY{}a5la=49pR@U4j+6kqiR)@DxGx_fDlnDLp4d{Iz=&2MUX_Y)OKkGD#rLpLA!_?
z1ScJNQ%-`pEU(EuoMuslqACs`5~arSSe?&&@uy{V<+Q;mB|AbxWI%2pux*B@hRV_&
zzXGwM(O#-l*l4EGg=sN3e67J*Ok4td1CgioS?9&Dv?UZsaejQ`$b2DK`LUi$p%-LF
z`<0SG$+-eNMF_}6%)l*HCXXc=X8+v$5G?Zf26Nf9)AQ
z@ZbZCPmHs4eUb0~_V*=VYk7UBRO-yk?viBd$k7HT?|tBRGXFo%!w-Itw;p+mv8ib=
zhFtm;Ecx)F{@vgn#TC}qyG&Ip^dpUp%NREK+Hd{?KJw9zve|CZTwmd(XTQt$zVz$7
zb9tS|pZG98^$Wj*Z0bkK(!&1kx*G*6?jaekE{R6Bgugh)+hn{>KO
zX^$2wGcU5VYxiCe@v77el8NaOnoLBTk|d#CYe-vowNa;9tBcg{(Zh#5H097nNilY6
zYDxxttzPB&(h>&`9-{ByO-i;{+ySM7FsSS$Xt5^UqxAYVAil&sJc
zaRoj5zzJuV3U1+9`5UPLFvurzD72FQBoI@Qls$((7c-1Fmck-S*Or->n1o14FgG|P
zTXi|cN&!teT`9c35jO93m7!1+>lrTh?;9;Of^w-QpQQ_dGQbWYSn8sLfMS3lIAl&y
zo^vg$BIa*ZtAl*#j#fARP67yiPZ=cx~Uh|mA{Pmno?
zA|vMqdpEcb+hS{|TEohP^GxoULdPi!jrtqIL-Vqsc>
z7)~)YIZ0j&j8+P-K?7TwT%@xzGBPQMgsby-y0ucAednFi0`E-E%y8ktC7P|aWHb0L
zez{r`+c#wSIP_h~c?+_+vKtd|7V_Ukj=NIM)%~)Cl%ToINp7d56J9dm8Jo^J4d+c$62lG5*a%zGHANl}G%gb2#
z9HQ-#z`Mcy>e;vX!LR;(RMzE#AASfTMRRSL*+#^<*I(f9gC8VH_Ok!pM|i@G@!3E4
zZ*b`32XMIU)fcz-#~jt3PqNu=nlm;wMW@>loLrV^GN5uP3gUv?sue{%9cgr&Fg{rh
z`ArBC#dh%^iz>le+>ww$=`G46$cc==;)O*Syax^*@*0N^9p=)d%Urv94d!M@N+l%A
z_cE&}?wo*^b0WQ3DVM!aTIMlfDNNJr_GPlERx89_W88Us-u3#Jk~lbFMhxy61zAo_
zlqt(-9eYgKcbpoJP0K;<@OvUX3`$fP8x!M#`3r>>ClHizp-D=3_5`2YEbVgb$|X9z
zChcB_q*7sFVIOfaMjY2Tbaay42ab|rJt7|{o03V(bCDJ;6+HPyw#Wz@BosV@2d}Iu
zQo->xaveq?6O2r_4#CQUMoTWdad}RfwxqVymBOfX668rUC+9LzBIAE-VnU>LrLY<_
z-bIGO(eHOXd}nq-gO-URbYvG3K<9UXiGZYBW~x-;=}&w@pwTNAF3M{@{fUobl7y!|
z`Y}*DN(k=;_vNcsdG7h=*t=&pCr%z0ocPAIHWTv;l*V&@@Vy`M>Elm`lATbOFkm%W
zgE+?9+y_YIvsH@Qoj2}KQd}c0Rp|F~I=v1ObUJ;mE?$)&Yg8o1&E^Kp%}w_2-zR}e
zu3dz(6gJqfIRydZ^j2MY){`R9@8E)x@dI4Bd|9~9S_WrM#~T(qANZ}c()h7=PZ^X7
zi6@qV$X1cxHn8H+h>5X>IWhpjHP==*MG|=L-aWEBy>R{_d-v}bfh&<_maKIL6R14a
z;6~ouhgO)9krw-i7+uzkKJgn_
zAt@q4Q4&>P8G`r}x7-Yf&{x{&(Wq8gy08NMw#d=CD8Wf>A;+iy
zp%_}7z6j9G?p}~<-`r?&?a~F>%^U39bC9X2-9i)WT1##m%0+C6O&SledF#toI1tBk39is{D>IQRcGhfX5es7&rGwrvcmY-7$ycq&c?R8JHkN9vs_*q
z)WD>uZa0>;T?vLJyr9<~0*^6f*jZ^c+tSHwt)t$kW8w<7-61Y#ND-C@$N_v0#d%7N
zx^V1k6SM5E)wy`-Ex!BxuTf4S4jw+no_)tD>v8hX?1uAu2GfK)+nXp9wOWHcd-kC)NV5lntA)@9>M=@ZWf#T-
zP_NgedsXbrDpkqml~Tg4FxZvb>*4jd|$ndN%0*r&myB!5y^u+kM@ZF7(
zj7(M_zw@(9Vp*O^@ph~+R!{&OjvWtZ{>Z+Qm6R<6ick#GMi?@Tjg8ao1e>?MESqIA
z0GSAtk_i=;WfELQ3+_3hB$)Sob+u^TvHg1}LIL6%8z_Xx5uEco0w;A^Z3$SzHiH(1
zOB5MO5c$fsi-qLiepCtI)L@;8DX5IslcO!iFH^;
z?QH@z{j^K7xlX6sLaF?A-+wvB;QN11i@g2Pv&>IU
zbNu0lS#>S;9-8FEFaI4r{9~VFwcW(_yIg(ab=J?kLDXsU$NrE1ga7l-`~_J?ZNCk8
zEsk!Q?V*qgmo8u8p85%VUJ^}o?E|FV;>Qiarxigw2{}quq9mh|jO4*+ss8lBF_0TZ_ZH*e-v%HH0j`Egnd2UB5zAK;I0!V;zkoQwL$~`wRX{SpR*9lwD
zd)H3Ua~Z96OL`!d7MHM9hbh-kfxWCqGEu?W2=O&S9cIeX?3S*jQxpCO8?I0}U4;`!V_TesH$*FctLk|Fo|eZqCj&fV0Wxh@(k
zK***gL*2V?p9EjQ-Hil0g5Xnd2^zLZtBVz#a_Nv=y0Ivd!d{A3vh$7gb@}21ugiL^
z1_*-&2C?N^uYv}CE?}JOWRoD_6(pT^aY{gmsRflvMc#An%_eeVa7irqJCPo#gV~1@
z;hDQ&$blF9dYAnZVO4>32v@tG%26vVO<3Jd2P4J#8URJej?e>uqup+a>lP?sm8jY{
zd1VYIGP-?`VW#But}iVzv#_5-_k56r{RfH430JON<_9nQ3r?T?AsekWmBtLU$!YfN
zT9Dvtl!joN2V2LG#Ue-08rjv>&&rrB*#?_oT#oJc=xuJYe*Ffm#T&R*mpF^4L^Y%y
zk~z`OdGoc`S-HN<>9^jXy}ZQYKsEF1&NC>#fT
z2n=ylA&G19eKk4>A6D4kwQ}e-+uh8)+3NGPFMpHqnJLja$rq-0`?cq}eC`yrQlCS|
z4zbp5Qz?yc;mqqa#>;e~IZ9I#JoMSm@z78HGP8&75uI=OP+==eChS84{)k#Ls-S=f
zmHHTmj|q<*k#N--S*nW3gq6qIXKBXCa~`7%?cxNEvhapi*H)<1t5S$cbIZc~F5Y_U
zP0Ho61lq<}!@niz=9BY93K{rUu3lq&dUO2TT0~QWqrF0NlB;bVk00zocEm|%r6vDhDYo-A7NF8oUF2>6JkU&9()`L>Vg(7hw^V3pzlMhs|
ze}f`RTZo}g>cD2waoNj3nOJHUrCJ4N0+mofL48x8XSA?LbW)-^F;277q~Fb%9iKpv
zV1zxA;SjA8>F%6~szjAjeFjAPj5c6Uwz%8&pLsl*U#}0VE5h-22N0C4f@>oQ>^vIIG)`>X?-EIqGiut@7P>(EN
z>|3*_Fm|%EPru#ql8=zYS_Hr%a@Lox(rd0zuat!K5&94Ca9qHcLp8=)p@)jz&+_sL
zosCT*5ZI>Zk{!nhv-1m_IsXP58|Nt{T`HA?qlX{n$dM=5Y{ksZ?qhahils~E(Jp6v
zd<>;104xLV(Km(39)h}(dVy&0v^F={SXrjIx<WpY>KlN
zSD8AzLA|z{Ojl4bSR5rK>Kj6hw8~+8aD&^T$hv3V}y
zPdH1KrD9HfGh5zlHs$C2`}Rq*#Kj92*|TT2FRV7$wM%(>Iy0!@fj|b%vU~3?t}k5^
zWyvTp7$a;2&oIa(kXvh+5-pA@&1O>|n6;G^CT3>YfB1-;SzKv=N@I+21Nsi%)BmAt)?ltZ&`m3=8WSZ{OJ&h~aiiMsxxk{xB+%5V)d9v#fj1L4
z=2`Bu^_*_n!vSfhgX^V~%4LC)Vx#FcH(6b|!OHckJpAb6^fFDV33Vb6&Nh*d;4Da(oiC6kCG7|uG$=!@ej1nBTR
z95(J!UwkbVN<$HL&~6h2TJAq#n%lO~>~7|Mn{8%xo_p_qP^$bTqq%(kH1jhPeD?F7
z=3C!?mZfHosoe*eTsVqTbIi={V>!YQ~&q>POsYvOH8y=
zqiD^%>!n$-S|5HkTCuXcgw8TiY19UiQUo~JwGkymHd`(B?A;>}$=UN4&`L|e)cd4*
z6YIK|Vp~_tgo_UlO6JD;n#leln7ecZVsH{%)>l@fIJ>g4BE{I>x#zN4=yW=sei@-m
zghR_Df-)$=V?ErkxtPgpYg;%v(;(0zgTZzbM{*3T9)NbMBPI?x8a2Ads*kExw19G(
z1H&nevg-2wx8j4FJK0^9G0~_ZZuR4bvd%5aI$V|thQ7MAM0axo`h6x!WyVWoYDpaE
ziWm%X52OYZ5#QXUK)Ev#I-z(hlu)6lBuH>^Ss
zA8O|p0&NKL#RBV~%tHw3X`0IO#qm>Y{F7a&(J}YC!5!~l5=pn)^{b0AXb`CEVe
zZwMsv9y_9j0}7!h3T3d@?S+6WnNFo#5`MNe8jWNUQanC?{w!(QmrN9ErGR-eLqBo+
z7}^(*N?w>s6}ZH*j1PPU4-FOb%0mYaa_00I{3d@N=v?#jbFAFB!M=TaDVHk};1?Da
zgn=Vx8Afd!koyh$@Zc`jb6W;dF>5CTB(`=?x6j_i^f;H`;j{K2*C4Qj7;9%Kj#0NT
zK{@*Uj%2OHNvp6)ffR4RlJ+G)Qm@viR?0Nj)@g67(OzAly}2%`oAZ13VB-?A`;L&C
zGFG5OTi|pP8e}{ZDacm{y^vOWlku@}I?Wa;sO8Jw6|6d(0c9~Ul#*EvA9{ojf9TU>
z-F060?XPh8${EgGy~M))L!7wxBr7X7
z(C9aL=;(faAr6Siy{Dz}UYgey
zmqa6^-_5Ai>ljqPYeR8U7$mc^Gh)JV&pr3By1FWKNv-uw=8Y_YaYl@ROL2)y7cO)7
z$RR2883%b__zV;e2bQ8c;4@!id&E%{SGcC24yhs|6NyeDN^vY5pW0bEn=MqHQ>xd=`i?_;
z57BJ5iB$z@HnS;22GNO+4Vfu$sI@B8Cv;I|Q)DjYW@pG^jkRL!My3^NOTYzfTqyQp
zqaGND%@p@P`8n3smpFaqHFix##I8@Lvq?3Hh;-zWEQ=EJ?u_N7MR_l^T1_(TklXe}
zi
z-_6{I-5{-`P-KX>dS#Kt8=L(4Z#~0r{PTYyQl0lc_yB9mBKu3#b(v6Yp1N-rH{SR<
zWBCe+vCQv3#4rB8|0O>6#h>JV{Gb14W@l#6e#ts~a|1i?x=7--0+}evfdp51EV}I0
z3ceR5i98O0Z+d!0+;&dha}Vu~m};*!;@Dh=j-*l;uh2Fw9tBM8LtZB>0YEv
z3Z~btU6bn}yf+YS8YKlQD>@nn4jth9`ST(04sJsyyTSe4unC;IJ-fy#2~5SEum!4X
zz~94?T5Ihanzk~sH0|GkwVCLud)~Q0`CWU1>(Hhya?1W%6-Y5PE|)1c8YGQ6BnkD&
zNeOruF~-K?q!1pJk^(GnOZX~K5=E45a%!4Rw-c
zW~~kT(CoeVyw*ElS?!E+eK&Jg-avR}*8-<1-4+M;
z%u_GNY+kuQzqigzt<2kRza*N@yYG3Nq_!YN4!{4=PoiseI_MDkhWqxaVR$g_%4gLg
z(UhedO9Bh{rV0r(4bMMEDUtkLUS1a2fGo=d9_jT`$=DC<-zPzMeSKXRD*m+x@&-#B
z8M>X8bSu_t6*`@^DCj}JB6HfEwqU?{p0luP7jL}&hVZ}-95@h~KMIsKq}W=oR;1H*
zb#+yQ$k682`u5vTfP-|jK^%U&EI*{FgLJ&X&C3&{h&+LFh@xe)848jjy7i-PPUxZn
z&6sG*eF;#6iM2?LwNmRbiDB`^5(keQCqa=Dj63l7u>_$|=-Xm3-QpgHK&G9h-RvH^6~G4qnZ%SmYaI`52Tgi}2o_JvH|1I)uZ^7pNF5xVXh4eGD>wd#xr(y&fEv
z5P#AF+!+F9fKJ4?BG0_cw3G3rR50ZThBgMUC?ZU$D)j@KMU)yfmM&kSlUq)#KETwz
z6SSLc;z|QKhgVy51LMr|+~ruv%mbT79tU_PJRX#}7$ij~9Jp=SGTX(8yP3O|tV0pk
zDja|K5w31_IDO$N-~RS@#air<51i!FpZ++Nu^QKwmS}f-j5VfccT)Bpd4QKsFA`53
z!qw(T#^<5jpr30bYridqYX^2WLcveIbmERwuh&^!T`PY0vZR0K^l8y+znQ5AmIoks
zx*udWo06o++3j_Q!1_)szOuY08uHd<(y`g@wg8Lrv`_1DR+g7hN=ZP<(v-u84Zei-&4qJbBnfVBn469sm$KB#}0vBEUGUHeptnve(#vzhS2z~3)KRUE
zGc_{SI&v+q;)ithjRiGJT?qs&YwRgCIi1SNl2$@xm=b8B$N`4d=e*t
z?IODfI*BntBCXi1c9(Ls>e(>2hhmDqyG_>qBe9WeP}~{V3nvOoYq{Ufn{&!`}S|eeZXn<8cdPU|eNkFnTU%mvd6~4^LlLy*Rgv8iAQ*Z5
zTRE#0DU!EqS`6?^ICuDtj=tRu?mpn?EiA4+ff}#lDiMix+_-dssj(^#J@5cu`|4Mj
z*u9$rCm$w_>yT8K8n3f){S5uh6|zi0+9!5RlFkzAXJ6vK`A_~$E}VV`Q5tojb=ux;
zxi!Fl9oT}Wq<6;8dVMKa-psrg=0uZ)e!nkJi`Gg^HEt~4U}9{X)<&CNs|UIBUv`HB
zX-?|)dNM)ux;0{stvkQ87E((S%o=2)2P@WWRMcumS>r
z>|}S6!4tM3$KQ*KWj=su${zn7HFFofwnZ@Z2#v8hX?q<_4q`~8P)>Gm2GKGPAPt&K
z_JrE_q)hN(vs#fG*>SKV4RQtx+90&WcBknlmMv+3p_%?5EQS;R1f}xOLMPV`2GBmJ
z1s+yJwLT`a+7KKS2J6i>3JpVkVoh*P)9+jIT%mO=iG#^45mNgicZys)D8uCoYSNJAl<4!Ly|`Vm2-^3~WVafRgX|e#kU0~u
zdf!K)0>2-5P5*yK@P4?9xrbs4P6rkRxr<~lEMB`o+P54%a)9Sve1*?{_KVaTW4!Uk
zTU@?;m8U-S3B*e?>vQ4lmpOXxgP=MrU0tNRyu#Oi<7>S1)vxn^t#tXn|IDAolxkRD
zxCfismhquf&|&vVbFzFbi7niXZFNn(tNyrD*o%U3S5dtsNHyHqL*EOT=*nOj)EDJ8Bl
za&OgbtNoJcj$R}pe1Qh>$Z#ACTHA=Tse;JrP>%WFGm^cBtS)?6N8O5-5PA*MQ)M6?`$f#d{k`^S2pPNTb#T2
zrW9IV|Kan@?ApuX#U+lNd;qCs_{1c<=3paI0aFh@4@)%U`QjKX7GQ_t>TY2C-p$;1
zJeVwaK_VlwzakcF@Xfd0;mF}*y#D%IeDKi^bNR{=fBSF#9bSInhmzHAtZk4OM?+`i
z8<$x+^&IQx&eBkhMgk?>;-Qnfc=?5AdF%DpFah$w0XppRnxRo*M_LkEA^I1_NDxKC
z^wbm^>l?yUiQ|~5$tkX0xe8j#z^VDJxKb$@#6ks+C#Wr^X(&>KpeX@)d-IcMP{JK5xgO8OWvv5f=@F%vb@p=h=q<
zPw{=+0Tx%FYWCB<=gwQd>a#<&;KE8nX*nW8x^TX599hUt#;?>_#DXu&`nQ4_Mh`}g
zLYK9YghDn{$Z(4pahOo0&>stwql4QLCNeSxE44c1TAf&Ai({;cNikTRfGLUjh%VJo
zah=0QPf{&cF}*hJ8`rq+=m9ios1xDbaLV%FO0&qMDZ)A7x(A!%!tVpcHoT4+`0U=5
z$QdBN%^~d`}R|=RFO>tzIGO@2jQ0yHSj~jNLcR59`5HbXr=(s
z4DBTd`%VkAp?lSY;@c=&k#Z+`>>B5U66xuDNRZcRumwG6;u9Dmz9`Eb>(ULcVe?ej
zQsR2#?9hN-ge6AZjERKG+v#+qs5+P}7a3RxZbSb7(uM(BZn50DNpqE>^Sr&AO
zB=DPX%_hc_8>mtpQxX$)CQ61&Z@qpvG&1WAFeO3lEU8%YSRqL
zWylyR;`*-eH}AHC{Vo;K%auASRd&z@a8&CJp8V+3y!PyO_|#{Iz7#)Pa5D(SDco626JkCWW6LO3OOoSm1sD
zLI?wmv2qb=3G&lL96nr6Q6+M?Qsm&OQ;yK>w2A5sze@6*;iGy!+zsx*2*7(9MiDqm
zA4`4ze)?~{!B?MqiAXD92z=r5KTf@(xO(Xnue|;Sk34uE)3XyaH&-bqWiFk$&VdIe
zaMc;|sERd)C{tw0k|=3ABvZN9<}kr3V<6~kL-E5E9(jj%6f-mPA_SJiWt=mJNKvI8
zWJW`#FMFXxhIGnViv%TOxO8ce-Mf{*Mb_h!kl!@imO|~=SY0$bN~M^C2W~bYT@Y#D
za!updqS`4K!E$iN&);gPDv#fdCXe3=O*um>0hJ?{BYty5GmP+>65xdzSvHKeX(pbsfF{G^{h&;;CxsWx6CMqeIS1T3DwW_dE
zFp-GO6$^|*wvoChoiD6nN<@+I;$hk^T&?Ho8@Ub~;B{`C6|-`3&mWJY7TTz}Z)5
z10sv8MS%yw
z`X-{=rKCc+
zRAXgjO^UDxt{$`h;2{KN8V%1KWv~v*jNdH;aN8Bq_M0kxa-ax>O3|`U%9YV+?#7^n
z)@aBvXf3kN^m}dMs0`R!<-DNWXzWWAc0jL4`|PJutx&DhC?ye_E9?BjU;Pyxe)0)U
zoV*X`hTr>Q#y-k@mCdt`s?`RqPK$cAERUOhGhyPv&
zK75{|tRprCa*K7KaYA?0k;ar0-Z^!SO07b5dYbi>W#Z{F&DOfCj-#+LaFP)1cmf+(
zsSa5|YUhr<*Q#|
z*W4`k-v1~|8%^fM#)unh#A%mPFa40i4?HPFo7kkNev@}zeTo0`|M+8k^b0@1FZ}*L
zZGq-}m~eumZ6W#;DQF-m#)
z0V_VOvvc#DJAV$0A+FYtAP^-%l2`V@YaP`ryhv@l9d~{E4F8tY$k%Cm9Q&;sL~f)51ds#RHQu2I)clCDT6NYNh!9vTTrnu+4Drj@_J
zvzKz4qy4?rMtLfOB6BHuKNV*tN$#{3tp50Y_mTG6T)%pi>g;9q%q&n!G+K-7Fd}bY
z)lmP`@R@{;)vyJ~Zjd?|{>BiIR2o?8HJgGT!bo+Ky9L#uF8INFR5>M*0*Q(!TgB?~
z3X3ai96x@P*Pi`04?pw>)3fvZvtRjDzV)?d=rz}IiDrDf!j)66!TME9>pB}(-r?#S
z&+_WG{yB?h-{vp;nLp39#cQCg&$KKsyv2T}>TdxuaKYRlXmH5xaKj6L!gT4UX;CYM
zndvFk)>nlMVIn|5YAx2AChR|Okowpd!Z$|JreG{RxQ}WMzT@Cq3~k<2|JinK6PARPi7g-6>rcn$x(l59~}TRNiA7-x2Vm*~-S
zvW#ojuW{>ljzWwcQ;R<-Ea&~01><|tt0XH4|Vh@EQ!YV~{JOY(Z{7@q!+UyrD
zUI4tEn6v2c|D+u}4gDH;)wEXN0l-U8-`?B3T_b|vp2&~Ozt
zcXIxTsVU~?7O2!3Y&6?kUA!ifd<--aL&Yc(v7oac(B%L_WZ?6^Q-%^+8!6(8?!Uj+
zpbDyr$gY*e*<5zHK2Ix*#O=soGf83uHtTnLB%VGg-v{Y(Rp?R~v>~a~c;tx>F*!EP
zm2>CWSh~vLgL}OEL*${`22`Ib7c5(BVV0)~+)i
zr@Bc1bJ~P3W01epxv23Bv4~asZ?ikV-;mIBucV)XA9W1-&GiQ)`~-wk|x94
zcM|6WGj5HRfG*-T^E}
zs)yV^x-h4pU#p3F_yPtOps)Oox4ls%>
ztrG*P(%>VX`66Hcjeo}egS$C%=?1_4TmPJ0Qw<*d(34D#)nwVXeC7>o*)ca>7l)ko
z(h{@Bp2U@>g^BXTLl0ofbr9Br!YJu+#X7S?X2PODH*(e3vTD8l9MkvmX`b50-=MMRz#Y7UM-1C=A;9^|>)FKn?(l;AlWXpDlx
z8*yE7zIjg=Y(#Nc?pd{7>OBcqlEr`w
z`o5P1R#