From cf4812590b7548a09759a6f99a13dd81e4de16ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Greg=20Zi=C3=B3=C5=82kowski?= Date: Tue, 12 Jan 2021 08:28:33 +0100 Subject: [PATCH 01/76] npm Packages: Ignore private packages when updating CHANGELOG files (#28060) --- bin/plugin/commands/packages.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/bin/plugin/commands/packages.js b/bin/plugin/commands/packages.js index 6291008ae575a..7625bb8a71e27 100644 --- a/bin/plugin/commands/packages.js +++ b/bin/plugin/commands/packages.js @@ -108,8 +108,18 @@ async function updatePackages( const changelogFiles = await glob( path.resolve( gitWorkingDirectoryPath, 'packages/*/CHANGELOG.md' ) ); + const changelogFilesPublicPackages = changelogFiles.filter( + ( changelogPath ) => { + const pkg = require( path.join( + path.dirname( changelogPath ), + 'package.json' + ) ); + return pkg.private !== true; + } + ); + const processedPackages = await Promise.all( - changelogFiles.map( async ( changelogPath ) => { + changelogFilesPublicPackages.map( async ( changelogPath ) => { const fileStream = fs.createReadStream( changelogPath ); const rl = readline.createInterface( { From 6d00779ffabd8926400013895819e332c8a30e9f Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Tue, 12 Jan 2021 08:33:23 +0100 Subject: [PATCH 02/76] Docs: Fix wrong entry in CHANGELOG for Create Block package Props to @mweichert for catching it. --- packages/create-block/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/create-block/CHANGELOG.md b/packages/create-block/CHANGELOG.md index 269e4f7b49a27..ebcd2ca8de53b 100644 --- a/packages/create-block/CHANGELOG.md +++ b/packages/create-block/CHANGELOG.md @@ -18,7 +18,7 @@ ### New Feature -- Adds the `npmPackages` field to the template configuration. It allows listing remote npm packages that will be installed in the scaffolded project ([#27880](https://github.com/WordPress/gutenberg/pull/27880)). +- Adds the `npmDependencies` field to the template configuration. It allows listing remote npm dependencies that will be installed in the scaffolded project ([#27880](https://github.com/WordPress/gutenberg/pull/27880)). - Installs WordPress npm dependencies used in the `esnext` template during the scaffolding process ([#27880](https://github.com/WordPress/gutenberg/pull/27880)). ### Bug Fix From 289b7f72e426f36762dd21b1130439f1a4277135 Mon Sep 17 00:00:00 2001 From: Joen A <1204802+jasmussen@users.noreply.github.com> Date: Tue, 12 Jan 2021 08:53:50 +0100 Subject: [PATCH 03/76] Try: Transparent spacer. (#28103) Mitigates #28092. --- packages/block-library/src/spacer/editor.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/spacer/editor.scss b/packages/block-library/src/spacer/editor.scss index d5616f713e9f8..ae05db13812be 100644 --- a/packages/block-library/src/spacer/editor.scss +++ b/packages/block-library/src/spacer/editor.scss @@ -11,7 +11,7 @@ } .block-library-spacer__resize-container.has-show-handle { - background: $gray-100; + background: rgba($black, 0.1); .is-dark-theme & { background: rgba($white, 0.15); From 1936a04bc5ff31eb5c29fddaf4f304759d35a7ed Mon Sep 17 00:00:00 2001 From: andrei draganescu Date: Tue, 12 Jan 2021 11:30:02 +0200 Subject: [PATCH 04/76] Navigation block: create draft posts and don't render links to drafts (#27207) * create draft and don't render drafts on the server * check for ID existing for excluding just content not external links * linting --- packages/block-library/src/navigation-link/edit.js | 6 +++--- packages/block-library/src/navigation-link/index.php | 8 ++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/block-library/src/navigation-link/edit.js b/packages/block-library/src/navigation-link/edit.js index 4f43872339399..029def990d245 100644 --- a/packages/block-library/src/navigation-link/edit.js +++ b/packages/block-library/src/navigation-link/edit.js @@ -232,7 +232,7 @@ function NavigationLinkEdit( { const page = await saveEntityRecord( 'postType', postType, { title: pageTitle, - status: 'publish', + status: 'draft', } ); return { @@ -389,12 +389,12 @@ function NavigationLinkEdit( { if ( type === 'post' ) { /* translators: %s: search term. */ format = __( - 'Create post: %s' + 'Create draft post: %s' ); } else { /* translators: %s: search term. */ format = __( - 'Create page: %s' + 'Create draft page: %s' ); } return createInterpolateElement( diff --git a/packages/block-library/src/navigation-link/index.php b/packages/block-library/src/navigation-link/index.php index 57c4b3354fc09..c78377a3c6646 100644 --- a/packages/block-library/src/navigation-link/index.php +++ b/packages/block-library/src/navigation-link/index.php @@ -104,6 +104,14 @@ function block_core_navigation_link_render_submenu_icon() { * @return string Returns the post content with the legacy widget added. */ function render_block_core_navigation_link( $attributes, $content, $block ) { + // Don't render the block's subtree if it is a draft. + if ( is_numeric( $attributes['id'] ) ) { + $post = get_post( $attributes['id'] ); + if ( 'publish' !== $post->post_status ) { + return ''; + } + } + // Don't render the block's subtree if it has no label. if ( empty( $attributes['label'] ) ) { return ''; From 2e9b8de513899ff146bd5104e7564a6d73f9cfce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Greg=20Zi=C3=B3=C5=82kowski?= Date: Tue, 12 Jan 2021 10:57:54 +0100 Subject: [PATCH 05/76] Components: Expose composite API from Reakit (#28085) * Components: Expose composite API from Reakit * Add DisclosureContent * Make Composite components unstable --- package-lock.json | 2 -- packages/block-editor/package.json | 1 - .../src/components/block-types-list/index.js | 9 ++++----- .../src/components/inserter-list-item/index.js | 6 ++++-- packages/block-library/package.json | 1 - .../edit/selection/template-part-previews.js | 18 +++++++++++------- .../src/alignment-matrix-control/cell.js | 6 +----- .../src/alignment-matrix-control/index.js | 2 +- packages/components/src/composite/index.js | 18 ++++++++++++++++++ packages/components/src/disclosure/index.js | 10 ++++++++++ packages/components/src/index.js | 7 +++++++ .../src/blocks/widget-area/edit/index.js | 11 +++++------ 12 files changed, 61 insertions(+), 30 deletions(-) create mode 100644 packages/components/src/composite/index.js create mode 100644 packages/components/src/disclosure/index.js diff --git a/package-lock.json b/package-lock.json index cf92071bf6142..0c419639e0072 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11694,7 +11694,6 @@ "react-autosize-textarea": "^7.1.0", "react-merge-refs": "^1.0.0", "react-spring": "^8.0.19", - "reakit": "1.3.4", "redux-multi": "^0.1.12", "rememo": "^3.0.0", "tinycolor2": "^1.4.1", @@ -11739,7 +11738,6 @@ "memize": "^1.1.0", "moment": "^2.22.1", "react-easy-crop": "^3.0.0", - "reakit": "1.3.4", "tinycolor2": "^1.4.1" } }, diff --git a/packages/block-editor/package.json b/packages/block-editor/package.json index 4df1e348d459d..05841cb049ec5 100644 --- a/packages/block-editor/package.json +++ b/packages/block-editor/package.json @@ -62,7 +62,6 @@ "react-autosize-textarea": "^7.1.0", "react-merge-refs": "^1.0.0", "react-spring": "^8.0.19", - "reakit": "1.3.4", "redux-multi": "^0.1.12", "rememo": "^3.0.0", "tinycolor2": "^1.4.1", diff --git a/packages/block-editor/src/components/block-types-list/index.js b/packages/block-editor/src/components/block-types-list/index.js index a569a8c13d4bd..ca54df0d24b78 100644 --- a/packages/block-editor/src/components/block-types-list/index.js +++ b/packages/block-editor/src/components/block-types-list/index.js @@ -1,12 +1,11 @@ -/** - * External dependencies - */ -import { Composite, useCompositeState } from 'reakit'; - /** * WordPress dependencies */ import { getBlockMenuDefaultClassName } from '@wordpress/blocks'; +import { + __unstableComposite as Composite, + __unstableUseCompositeState as useCompositeState, +} from '@wordpress/components'; /** * Internal dependencies diff --git a/packages/block-editor/src/components/inserter-list-item/index.js b/packages/block-editor/src/components/inserter-list-item/index.js index 5620c31aa0b62..47e48ce8ddf29 100644 --- a/packages/block-editor/src/components/inserter-list-item/index.js +++ b/packages/block-editor/src/components/inserter-list-item/index.js @@ -2,13 +2,15 @@ * External dependencies */ import classnames from 'classnames'; -import { CompositeItem } from 'reakit'; /** * WordPress dependencies */ import { useMemo, useRef, memo } from '@wordpress/element'; -import { Button } from '@wordpress/components'; +import { + Button, + __unstableCompositeItem as CompositeItem, +} from '@wordpress/components'; import { createBlock, createBlocksFromInnerBlocksTemplate, diff --git a/packages/block-library/package.json b/packages/block-library/package.json index b3cb76e28c861..ebe3030f55ce5 100644 --- a/packages/block-library/package.json +++ b/packages/block-library/package.json @@ -61,7 +61,6 @@ "memize": "^1.1.0", "moment": "^2.22.1", "react-easy-crop": "^3.0.0", - "reakit": "1.3.4", "tinycolor2": "^1.4.1" }, "publishConfig": { diff --git a/packages/block-library/src/template-part/edit/selection/template-part-previews.js b/packages/block-library/src/template-part/edit/selection/template-part-previews.js index 812ed35907e85..e3b7b3e669926 100644 --- a/packages/block-library/src/template-part/edit/selection/template-part-previews.js +++ b/packages/block-library/src/template-part/edit/selection/template-part-previews.js @@ -1,3 +1,8 @@ +/** + * External dependencies + */ +import { groupBy, deburr } from 'lodash'; + /** * WordPress dependencies */ @@ -7,16 +12,15 @@ import { useMemo, useCallback } from '@wordpress/element'; import { ENTER, SPACE } from '@wordpress/keycodes'; import { __, sprintf } from '@wordpress/i18n'; import { BlockPreview } from '@wordpress/block-editor'; -import { Icon } from '@wordpress/components'; +import { + __unstableComposite as Composite, + __unstableCompositeItem as CompositeItem, + Icon, + __unstableUseCompositeState as useCompositeState, +} from '@wordpress/components'; import { useAsyncList } from '@wordpress/compose'; import { store as noticesStore } from '@wordpress/notices'; -/** - * External dependencies - */ -import { groupBy, deburr } from 'lodash'; -import { Composite, useCompositeState, CompositeItem } from 'reakit'; - function PreviewPlaceholder() { return (
Date: Tue, 12 Jan 2021 12:00:55 +0100 Subject: [PATCH 06/76] Bump plugin version to 9.7.1 --- changelog.txt | 7 +++++++ gutenberg.php | 2 +- package-lock.json | 2 +- package.json | 2 +- readme.txt | 2 +- 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index c335fd3bb0e1e..3e5a2be0847f3 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,12 @@ == Changelog == += 9.7.1 = + +### Bug Fixes + + - Fix styling of the verse block. + + = 9.7.0 = ### Features diff --git a/gutenberg.php b/gutenberg.php index 1f4b7c40bc37a..31f6f4bc85051 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.3 * Requires PHP: 5.6 - * Version: 9.7.0 + * Version: 9.7.1 * Author: Gutenberg Team * Text Domain: gutenberg * diff --git a/package-lock.json b/package-lock.json index 0c419639e0072..826b893cb9757 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "9.7.0", + "version": "9.7.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 35a9a07afef03..b686333a700d4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "9.7.0", + "version": "9.7.1", "private": true, "description": "A new WordPress editor experience.", "author": "The WordPress Contributors", diff --git a/readme.txt b/readme.txt index bf63a73ea87df..8f0edaa935afb 100644 --- a/readme.txt +++ b/readme.txt @@ -57,4 +57,4 @@ View release page. +To read the changelog for Gutenberg 9.7.1, please navigate to the release page. From 195a73ec7254f1e538bb4aa30651e399459be0a7 Mon Sep 17 00:00:00 2001 From: Nik Tsekouras Date: Tue, 12 Jan 2021 15:55:42 +0200 Subject: [PATCH 07/76] Fix block error when transforming blocks with Link Popover opened (#28136) --- packages/rich-text/src/component/use-anchor-ref.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/rich-text/src/component/use-anchor-ref.js b/packages/rich-text/src/component/use-anchor-ref.js index 3e9dc8554defe..4be4fdd93096a 100644 --- a/packages/rich-text/src/component/use-anchor-ref.js +++ b/packages/rich-text/src/component/use-anchor-ref.js @@ -31,8 +31,10 @@ export function useAnchorRef( { ref, value, settings = {} } ) { const activeFormat = name ? getActiveFormat( value, name ) : undefined; return useMemo( () => { - const { ownerDocument } = ref.current; - const { defaultView } = ownerDocument; + if ( ! ref.current ) return; + const { + ownerDocument: { defaultView }, + } = ref.current; const selection = defaultView.getSelection(); if ( ! selection.rangeCount ) { From 59923c119029311b1c5739412f19a285cbc0bf28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Greg=20Zi=C3=B3=C5=82kowski?= Date: Tue, 12 Jan 2021 15:43:35 +0100 Subject: [PATCH 08/76] Testing: Prevent a direct usage of Reakit (#28095) * Testing: Prevent of direct usage of Reakit * Add exceptions for Reakit usage in @wordpress/components --- .eslintrc.js | 33 ++++++++++++++------- packages/components/src/composite/index.js | 1 + packages/components/src/disclosure/index.js | 1 + 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index d9f2b3ae8e132..5e20681906c42 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -54,6 +54,29 @@ module.exports = { }, ], '@wordpress/no-unsafe-wp-apis': 'off', + 'no-restricted-imports': [ + 'error', + { + paths: [ + { + name: 'lodash', + importNames: [ 'memoize' ], + message: 'Please use `memize` instead.', + }, + { + name: 'reakit', + message: + 'Please use Reakit API through `@wordpress/components` instead.', + }, + { + name: 'redux', + importNames: [ 'combineReducers' ], + message: + 'Please use `combineReducers` from `@wordpress/data` instead.', + }, + ], + }, + ], 'no-restricted-syntax': [ 'error', // NOTE: We can't include the forward slash in our regex or @@ -79,16 +102,6 @@ module.exports = { message: 'Deprecated functions must be removed before releasing this version.', }, - { - selector: - 'ImportDeclaration[source.value="redux"] Identifier.imported[name="combineReducers"]', - message: 'Use `combineReducers` from `@wordpress/data`', - }, - { - selector: - 'ImportDeclaration[source.value="lodash"] Identifier.imported[name="memoize"]', - message: 'Use memize instead of Lodash’s memoize', - }, { selector: 'CallExpression[callee.object.name="page"][callee.property.name="waitFor"]', diff --git a/packages/components/src/composite/index.js b/packages/components/src/composite/index.js index f1101a2c852e0..ddb10fffa12ad 100644 --- a/packages/components/src/composite/index.js +++ b/packages/components/src/composite/index.js @@ -10,6 +10,7 @@ * The plan is to build own API that accounts for future breaking changes * in Reakit (https://github.com/WordPress/gutenberg/pull/28085). */ +/* eslint-disable-next-line no-restricted-imports */ export { Composite, CompositeGroup, diff --git a/packages/components/src/disclosure/index.js b/packages/components/src/disclosure/index.js index 2789ab6d307ef..5458ba053eef6 100644 --- a/packages/components/src/disclosure/index.js +++ b/packages/components/src/disclosure/index.js @@ -7,4 +7,5 @@ * The plan is to build own API that accounts for future breaking changes * in Reakit (https://github.com/WordPress/gutenberg/pull/28085). */ +/* eslint-disable-next-line no-restricted-imports */ export { DisclosureContent } from 'reakit'; From d466acc731452c20cd1e46dc9728a5238911c909 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Greg=20Zi=C3=B3=C5=82kowski?= Date: Tue, 12 Jan 2021 16:34:39 +0100 Subject: [PATCH 09/76] Create Block: Allow using locally installed packages with templates (#28105) * Create Block: Allow using locally installed packages with templates * Add CHANGELOG entry --- packages/create-block/CHANGELOG.md | 1 + packages/create-block/lib/templates.js | 72 ++++++++++++++++---------- 2 files changed, 47 insertions(+), 26 deletions(-) diff --git a/packages/create-block/CHANGELOG.md b/packages/create-block/CHANGELOG.md index ebcd2ca8de53b..342e4a13222e4 100644 --- a/packages/create-block/CHANGELOG.md +++ b/packages/create-block/CHANGELOG.md @@ -9,6 +9,7 @@ ### New Features - Add support for handling static assets with the `assetsPath` field in the external template configuration ([#28038](https://github.com/WordPress/gutenberg/pull/28038)). +- Allow using locally installed packages with templates ([#28105](https://github.com/WordPress/gutenberg/pull/28105)). ### Internal diff --git a/packages/create-block/lib/templates.js b/packages/create-block/lib/templates.js index f2e9b9ab1d007..0486659156adf 100644 --- a/packages/create-block/lib/templates.js +++ b/packages/create-block/lib/templates.js @@ -29,6 +29,7 @@ const predefinedBlockTemplates = { editorStyle: 'file:./editor.css', style: 'file:./style.css', }, + templatesPath: join( __dirname, 'templates', 'es5' ), }, esnext: { defaultValues: { @@ -43,6 +44,7 @@ const predefinedBlockTemplates = { '@wordpress/i18n', ], }, + templatesPath: join( __dirname, 'templates', 'esnext' ), }, }; @@ -94,16 +96,41 @@ const externalTemplateExists = async ( templateName ) => { return true; }; +const configToTemplate = async ( { + assetsPath, + defaultValues = {}, + templatesPath, +} ) => { + if ( ! isObject( defaultValues ) || ! templatesPath ) { + throw new CLIError( 'Template found but invalid definition provided.' ); + } + + return { + defaultValues, + outputAssets: assetsPath ? await getOutputAssets( assetsPath ) : {}, + outputTemplates: await getOutputTemplates( templatesPath ), + }; +}; + const getBlockTemplate = async ( templateName ) => { if ( predefinedBlockTemplates[ templateName ] ) { - return { - ...predefinedBlockTemplates[ templateName ], - outputTemplates: await getOutputTemplates( - join( __dirname, 'templates', templateName ) - ), - outputAssets: {}, - }; + return await configToTemplate( + predefinedBlockTemplates[ templateName ] + ); } + + try { + return await configToTemplate( require( templateName ) ); + } catch ( error ) { + if ( error instanceof CLIError ) { + throw error; + } else if ( error.code !== 'MODULE_NOT_FOUND' ) { + throw new CLIError( + `Invalid block template loaded. Error: ${ error.message }` + ); + } + } + if ( ! ( await externalTemplateExists( templateName ) ) ) { throw new CLIError( `Invalid block template type name: "${ templateName }". Allowed values: ` + @@ -126,26 +153,19 @@ const getBlockTemplate = async ( templateName ) => { cwd: tempCwd, } ); - const { - defaultValues = {}, - templatesPath, - assetsPath, - } = require( require.resolve( templateName, { - paths: [ tempCwd ], - } ) ); - if ( ! isObject( defaultValues ) || ! templatesPath ) { - throw new Error(); - } - - return { - defaultValues, - outputTemplates: await getOutputTemplates( templatesPath ), - outputAssets: assetsPath ? await getOutputAssets( assetsPath ) : {}, - }; - } catch ( error ) { - throw new CLIError( - `Invalid template definition provided in "${ templateName }" package.` + return await configToTemplate( + require( require.resolve( templateName, { + paths: [ tempCwd ], + } ) ) ); + } catch ( error ) { + if ( error instanceof CLIError ) { + throw error; + } else { + throw new CLIError( + `Invalid block template downloaded. Error: ${ error.message }` + ); + } } finally { if ( tempCwd ) { rimraf( tempCwd ); From 3de1114b4470d7e378e1e57725252eead79ad505 Mon Sep 17 00:00:00 2001 From: Jeff Ong Date: Tue, 12 Jan 2021 12:17:42 -0500 Subject: [PATCH 10/76] Remove height: 100% (#28114) --- packages/block-library/src/cover/style.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/block-library/src/cover/style.scss b/packages/block-library/src/cover/style.scss index 1f4f09f9fc9c1..264eda7ba5664 100644 --- a/packages/block-library/src/cover/style.scss +++ b/packages/block-library/src/cover/style.scss @@ -4,7 +4,6 @@ background-size: cover; background-position: center center; min-height: 430px; - height: 100%; width: 100%; display: flex; justify-content: center; From 04aec01e12b3b493347ebb648d395c5ff7c329b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Greg=20Zi=C3=B3=C5=82kowski?= Date: Tue, 12 Jan 2021 19:49:31 +0100 Subject: [PATCH 11/76] Scripts: Align default engines for `check-engines` with the package (#28143) --- packages/scripts/CHANGELOG.md | 4 ++++ packages/scripts/README.md | 2 +- packages/scripts/scripts/check-engines.js | 24 +++++++++++++++-------- 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/packages/scripts/CHANGELOG.md b/packages/scripts/CHANGELOG.md index 6910318021899..775a7ad75be58 100644 --- a/packages/scripts/CHANGELOG.md +++ b/packages/scripts/CHANGELOG.md @@ -17,6 +17,10 @@ - Make it possible to transpile `.jsx` files with `build` and `start` commands ([#28002](https://github.com/WordPress/gutenberg/pull/28002)). - Add support for static assets (fonts and images) for `build` and `start` commands ([#28043](https://github.com/WordPress/gutenberg/pull/28043)). +### Bug Fix + +- Ensure that `check-engines` uses the same default version of Node.js and npm as this package ([#28143](https://github.com/WordPress/gutenberg/pull/28143)). + ### Internal - The bundled `webpack-bundle-analyzer` dependency has been updated from requiring `^3.6.1` to requiring `^4.2.0`. diff --git a/packages/scripts/README.md b/packages/scripts/README.md index b872b54a3a8ad..0dae85bc03ba7 100644 --- a/packages/scripts/README.md +++ b/packages/scripts/README.md @@ -105,7 +105,7 @@ This is how you execute the script with presented setup: #### Advanced information -It uses [check-node-version](https://www.npmjs.com/package/check-node-version) behind the scenes with the recommended configuration provided. Similarly to this package, the default requirements are `node` 10.0.0 or later, and `npm` 6.9.0 or later. You can specify your own ranges as described in [check-node-version docs](https://www.npmjs.com/package/check-node-version). Learn more in the [Advanced Usage](#advanced-usage) section. +It uses [check-node-version](https://www.npmjs.com/package/check-node-version) behind the scenes with the recommended configuration provided. The default requirements are set to the same Node.js and npm versions as listed in the [installation](#installation) section for this package. You can specify your own ranges as described in [check-node-version docs](https://www.npmjs.com/package/check-node-version). Learn more in the [Advanced Usage](#advanced-usage) section. ### `check-licenses` diff --git a/packages/scripts/scripts/check-engines.js b/packages/scripts/scripts/check-engines.js index 38dac752c0ee2..bad2f2a619b65 100644 --- a/packages/scripts/scripts/check-engines.js +++ b/packages/scripts/scripts/check-engines.js @@ -9,18 +9,26 @@ const { sync: resolveBin } = require( 'resolve-bin' ); */ const { getArgsFromCLI, hasArgInCLI } = require( '../utils' ); -const args = getArgsFromCLI(); +const getConfig = () => { + const hasConfig = + hasArgInCLI( '--package' ) || + hasArgInCLI( '--node' ) || + hasArgInCLI( '--npm' ) || + hasArgInCLI( '--yarn' ); -const hasConfig = - hasArgInCLI( '--package' ) || - hasArgInCLI( '--node' ) || - hasArgInCLI( '--npm' ) || - hasArgInCLI( '--yarn' ); -const config = ! hasConfig ? [ '--node', '>=10.0.0', '--npm', '>=6.9.0' ] : []; + if ( hasConfig ) { + return []; + } + const { + engines: { node, npm }, + } = require( '../package.json' ); + + return [ '--node', node, '--npm', npm ]; +}; const result = spawn( resolveBin( 'check-node-version' ), - [ ...config, ...args ], + [ ...getConfig(), ...getArgsFromCLI() ], { stdio: 'inherit', } From 9c9617d20d4ebd1d1e7edf3f6019a58a17bdc90d Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Tue, 12 Jan 2021 21:48:56 +0000 Subject: [PATCH 12/76] Add theme.json i18n mechanism and JSON file specifying which theme.json paths are translatable (#27380) Co-authored-by: Miguel Fonseca Co-authored-by: Pascal Birchler --- lib/class-wp-theme-json-resolver.php | 81 ++++++++++++++++++++++++++++ lib/experimental-i18n-theme.json | 32 +++++++++++ 2 files changed, 113 insertions(+) create mode 100644 lib/experimental-i18n-theme.json diff --git a/lib/class-wp-theme-json-resolver.php b/lib/class-wp-theme-json-resolver.php index a94dbb1fde86d..3341c4071ac2b 100644 --- a/lib/class-wp-theme-json-resolver.php +++ b/lib/class-wp-theme-json-resolver.php @@ -71,6 +71,85 @@ private static function get_from_file( $file_path ) { return $config; } + /** + * Processes a tree from i18n-theme.json into a linear array + * containing the a translatable path from theme.json and an array + * of properties that are translatable. + * + * @param array $file_structure_partial A part of a theme.json i18n tree. + * @param array $current_path An array with a path on the theme.json i18n tree. + * + * @return array An array of arrays each one containing a translatable path and an array of properties that are translatable. + */ + private static function theme_json_i18_file_structure_to_preset_paths( $file_structure_partial, $current_path = array() ) { + $result = array(); + foreach ( $file_structure_partial as $property => $partial_child ) { + if ( is_numeric( $property ) ) { + return array( + array( + 'path' => $current_path, + 'translatable_keys' => $file_structure_partial, + ), + ); + } + $result = array_merge( + $result, + self::theme_json_i18_file_structure_to_preset_paths( $partial_child, array_merge( $current_path, array( $property ) ) ) + ); + } + return $result; + } + + /** + * Returns a data structure used in theme.json translation. + * + * @return array An array of theme.json paths that are translatable and the keys that are translatable + */ + private static function get_presets_to_translate() { + static $theme_json_i18n = null; + if ( null === $theme_json_i18n ) { + $file_structure = self::get_from_file( __DIR__ . '/experimental-i18n-theme.json' ); + $theme_json_i18n = self::theme_json_i18_file_structure_to_preset_paths( $file_structure ); + + } + return $theme_json_i18n; + } + + /** + * Translates a theme.json structure. + * + * @param array $theme_json_structure A theme.json structure that is going to be translatable. + * @param string $domain Optional. Text domain. Unique identifier for retrieving translated strings. + * Default 'default'. + */ + private static function translate_presets( &$theme_json_structure, $domain = 'default' ) { + $preset_to_translate = self::get_presets_to_translate(); + foreach ( $theme_json_structure as &$context_value ) { + if ( empty( $context_value ) ) { + continue; + } + foreach ( $preset_to_translate as $preset ) { + $path = $preset['path']; + $translatable_keys = $preset['translatable_keys']; + $array_to_translate = gutenberg_experimental_get( $context_value, $path, null ); + if ( null === $array_to_translate ) { + continue; + } + foreach ( $array_to_translate as &$item_to_translate ) { + foreach ( $translatable_keys as $translatable_key ) { + if ( empty( $item_to_translate[ $translatable_key ] ) ) { + continue; + } + // phpcs:ignore WordPress.WP.I18n.LowLevelTranslationFunction,WordPress.WP.I18n.NonSingularStringLiteralText,WordPress.WP.I18n.NonSingularStringLiteralDomain + $item_to_translate[ $translatable_key ] = translate( $item_to_translate[ $translatable_key ], $domain ); + // phpcs:enable + } + } + gutenberg_experimental_set( $context_value, $path, $array_to_translate ); + } + } + } + /** * Return core's origin config. * @@ -82,6 +161,7 @@ private static function get_core_origin() { } $config = self::get_from_file( __DIR__ . '/experimental-default-theme.json' ); + self::translate_presets( $config ); // Start i18n logic to remove when JSON i18 strings are extracted. $default_colors_i18n = array( @@ -155,6 +235,7 @@ private static function get_core_origin() { */ private function get_theme_origin( $theme_support_data = array() ) { $theme_json_data = self::get_from_file( locate_template( 'experimental-theme.json' ) ); + self::translate_presets( $theme_json_data, wp_get_theme()->get( 'TextDomain' ) ); /* * We want the presets and settings declared in theme.json diff --git a/lib/experimental-i18n-theme.json b/lib/experimental-i18n-theme.json new file mode 100644 index 0000000000000..4731a59df0e97 --- /dev/null +++ b/lib/experimental-i18n-theme.json @@ -0,0 +1,32 @@ +{ + "settings": { + "typography": { + "fontSizes": [ + "name" + ], + "fontStyles": [ + "name" + ], + "fontWeights": [ + "name" + ], + "fontFamilies": [ + "name" + ], + "textTransforms": [ + "name" + ], + "textDecorations": [ + "name" + ] + }, + "color": { + "palette": [ + "name" + ], + "gradients": [ + "name" + ] + } + } +} From 3b8305dcd88f08c498aa2f5e0222aa3e327b0bf3 Mon Sep 17 00:00:00 2001 From: Robert Anderson Date: Wed, 13 Jan 2021 11:59:53 +1100 Subject: [PATCH 13/76] BlockSwitcher: Fix crash due to null reference (#28122) In specific situations the mapSelect() in BlockSwitcher can run before the mapSelect() in BlockToolbar. This means that if one of the selected blocks has been deleted then there is a null reference error in BlockSwitcher. One such situation is: if a block is selected, the viewport shrinks from desktop to mobile, and then the block is deleted. --- .../src/components/block-switcher/index.js | 8 ++++++-- .../src/components/block-switcher/test/index.js | 10 ++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/components/block-switcher/index.js b/packages/block-editor/src/components/block-switcher/index.js index cc34d56aa6aa7..44b7d847201ca 100644 --- a/packages/block-editor/src/components/block-switcher/index.js +++ b/packages/block-editor/src/components/block-switcher/index.js @@ -155,9 +155,13 @@ export const BlockSwitcher = ( { clientIds } ) => { [ clientIds ] ); - return !! blocks?.length ? ( + if ( ! blocks.length || blocks.some( ( block ) => ! block ) ) { + return null; + } + + return ( - ) : null; + ); }; export default BlockSwitcher; diff --git a/packages/block-editor/src/components/block-switcher/test/index.js b/packages/block-editor/src/components/block-switcher/test/index.js index b3048a3750586..6fda7e21f2ff0 100644 --- a/packages/block-editor/src/components/block-switcher/test/index.js +++ b/packages/block-editor/src/components/block-switcher/test/index.js @@ -25,6 +25,16 @@ describe( 'BlockSwitcher', () => { const wrapper = shallow( ); expect( wrapper.html() ).toBeNull(); } ); + + test( 'should not render block switcher with null blocks', () => { + useSelect.mockImplementation( () => ( { blocks: [ null ] } ) ); + const wrapper = shallow( + + ); + expect( wrapper.html() ).toBeNull(); + } ); } ); describe( 'BlockSwitcherDropdownMenu', () => { const headingBlock1 = { From 0fa482c99be0acc9c59a6bc751188586a4be6747 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Wed, 13 Jan 2021 04:45:55 +0200 Subject: [PATCH 14/76] [Navigation Block] Check if ID exists before using it (#28134) --- packages/block-library/src/navigation-link/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/navigation-link/index.php b/packages/block-library/src/navigation-link/index.php index c78377a3c6646..1513f3034514e 100644 --- a/packages/block-library/src/navigation-link/index.php +++ b/packages/block-library/src/navigation-link/index.php @@ -105,7 +105,7 @@ function block_core_navigation_link_render_submenu_icon() { */ function render_block_core_navigation_link( $attributes, $content, $block ) { // Don't render the block's subtree if it is a draft. - if ( is_numeric( $attributes['id'] ) ) { + if ( isset( $attributes['id'] ) && is_numeric( $attributes['id'] ) ) { $post = get_post( $attributes['id'] ); if ( 'publish' !== $post->post_status ) { return ''; From f841d34a3a1a6e5a44bc71abb8c91d1d0c379f10 Mon Sep 17 00:00:00 2001 From: Shaun Andrews Date: Tue, 12 Jan 2021 21:53:59 -0500 Subject: [PATCH 15/76] List View: Reduce whitespace and always show nested blocks (#28029) * Forcing nested blocks to always show, but there's gotta be a better way. * Reducing whitespace and simplifying the descenders. * Adjusting the selected state. * Moving the hasHierarchy check into the value of blocks. * This isn't needed. Leftover from some earlier explorations. * Overriding the hover state when selected. * Simplifying the descener-lines component and moving it inside the button. This makes the whole row clickable, regardless of indentation. * Renaming the descender-lines component to indentation. --- .../components/block-navigation/appender.js | 9 +- .../block-navigation/block-select-button.js | 2 + .../src/components/block-navigation/block.js | 7 -- .../{descender-lines.js => indentation.js} | 12 +-- .../src/components/block-navigation/index.js | 25 ++--- .../components/block-navigation/style.scss | 93 ++++--------------- 6 files changed, 35 insertions(+), 113 deletions(-) rename packages/block-editor/src/components/block-navigation/{descender-lines.js => indentation.js} (58%) diff --git a/packages/block-editor/src/components/block-navigation/appender.js b/packages/block-editor/src/components/block-navigation/appender.js index 58bdb381e10e6..5ea05906062c0 100644 --- a/packages/block-editor/src/components/block-navigation/appender.js +++ b/packages/block-editor/src/components/block-navigation/appender.js @@ -15,7 +15,7 @@ import { useSelect } from '@wordpress/data'; * Internal dependencies */ import BlockNavigationLeaf from './leaf'; -import DescenderLines from './descender-lines'; +import Indentation from './indentation'; import Inserter from '../inserter'; export default function BlockNavigationAppender( { @@ -23,7 +23,6 @@ export default function BlockNavigationAppender( { position, level, rowCount, - terminatedLevels, path, } ) { const isDragging = useSelect( @@ -63,11 +62,7 @@ export default function BlockNavigationAppender( { > { ( { ref, tabIndex, onFocus } ) => (
- + + { blockDisplayName } { isSelected && ( diff --git a/packages/block-editor/src/components/block-navigation/block.js b/packages/block-editor/src/components/block-navigation/block.js index da24893d49d0d..6ae8a43a376ed 100644 --- a/packages/block-editor/src/components/block-navigation/block.js +++ b/packages/block-editor/src/components/block-navigation/block.js @@ -25,7 +25,6 @@ import { BlockMoverUpButton, BlockMoverDownButton, } from '../block-mover/button'; -import DescenderLines from './descender-lines'; import BlockNavigationBlockContents from './block-contents'; import BlockSettingsDropdown from '../block-settings-menu/block-settings-dropdown'; import { useBlockNavigationContext } from './context'; @@ -39,7 +38,6 @@ export default function BlockNavigationBlock( { rowCount, siblingBlockCount, showBlockMovers, - terminatedLevels, path, } ) { const cellRef = useRef( null ); @@ -108,11 +106,6 @@ export default function BlockNavigationBlock( { > { ( { ref, tabIndex, onFocus } ) => (
- onClick( block.clientId ) } diff --git a/packages/block-editor/src/components/block-navigation/descender-lines.js b/packages/block-editor/src/components/block-navigation/indentation.js similarity index 58% rename from packages/block-editor/src/components/block-navigation/descender-lines.js rename to packages/block-editor/src/components/block-navigation/indentation.js index 58b7144bd6dd8..6ec4e5206134c 100644 --- a/packages/block-editor/src/components/block-navigation/descender-lines.js +++ b/packages/block-editor/src/components/block-navigation/indentation.js @@ -4,15 +4,11 @@ import { times } from 'lodash'; import classnames from 'classnames'; -const lineClassName = 'block-editor-block-navigator-descender-line'; +const lineClassName = 'block-editor-block-navigator-indentation'; -export default function DescenderLines( { - level, - isLastRow, - terminatedLevels, -} ) { +export default function Indentation( { level } ) { return times( level - 1, ( index ) => { - // The first 'level' that has a descender line is level 2. + // The first 'level' that has an indentation is level 2. // Add 2 to the zero-based index below to reflect that. const currentLevel = index + 2; const hasItem = currentLevel === level; @@ -22,8 +18,6 @@ export default function DescenderLines( { aria-hidden="true" className={ classnames( lineClassName, { 'has-item': hasItem, - 'is-last-row': isLastRow, - 'is-terminated': terminatedLevels.includes( currentLevel ), } ) } /> ); diff --git a/packages/block-editor/src/components/block-navigation/index.js b/packages/block-editor/src/components/block-navigation/index.js index 4e18231de1d66..ccce62a2c3313 100644 --- a/packages/block-editor/src/components/block-navigation/index.js +++ b/packages/block-editor/src/components/block-navigation/index.js @@ -36,23 +36,14 @@ function BlockNavigation( {

{ __( 'List view' ) }

- { hasHierarchy && ( - - ) } - { ! hasHierarchy && ( - - ) } + +
); } diff --git a/packages/block-editor/src/components/block-navigation/style.scss b/packages/block-editor/src/components/block-navigation/style.scss index 9d5dfb714a4a3..546dab181208e 100644 --- a/packages/block-editor/src/components/block-navigation/style.scss +++ b/packages/block-editor/src/components/block-navigation/style.scss @@ -1,6 +1,3 @@ -$tree-border-width: 2px; -$tree-item-height: 36px; - .block-editor-block-navigation__label { margin: 0 0 $grid-unit-15; color: $gray-700; @@ -10,7 +7,7 @@ $tree-item-height: 36px; } .block-editor-block-navigation__container { - padding: $grid-unit - $border-width; + min-width: 280px; } .block-editor-block-navigation-tree { @@ -24,6 +21,13 @@ $tree-item-height: 36px; // Use position relative for row animation. position: relative; + &.is-selected .block-editor-block-navigation-block-contents, + &.is-selected:hover .block-editor-block-navigation-block-contents, + &.is-selected:focus .block-editor-block-navigation-block-contents { + background: $gray-900; + color: $white; + } + &.is-dragging { display: none; } @@ -33,15 +37,21 @@ $tree-item-height: 36px; align-items: center; width: 100%; height: auto; - padding: $grid-unit-15 ($grid-unit-15 / 2); - margin-top: auto; - margin-bottom: auto; + padding: ($grid-unit-15 / 2); text-align: left; color: $gray-900; border-radius: 2px; position: relative; white-space: nowrap; + &:hover { + background: $gray-100; + } + + &:focus { + z-index: 1; + } + &.is-dropping-before::before { content: ""; position: absolute; @@ -91,14 +101,6 @@ $tree-item-height: 36px; margin-right: 6px; } - &.is-selected .block-editor-block-icon svg, - &.is-selected:focus .block-editor-block-icon svg { - color: $white; - background: $gray-900; - box-shadow: 0 0 0 $border-width $gray-900; - border-radius: $border-width; - } - .block-editor-block-navigation-block__menu-cell, .block-editor-block-navigation-block__mover-cell, .block-editor-block-navigation-block__contents-cell { @@ -225,64 +227,9 @@ $tree-item-height: 36px; .block-editor-block-navigation-appender__container { display: flex; } - - .block-editor-block-navigation-block__contents-container { - min-height: $grid-unit-60; - } - - .block-editor-block-navigator-descender-line { - position: relative; - flex-shrink: 0; - width: ( $button-size / 2 ) + 6px; - - &:first-child { - width: ( $button-size / 2 ); - } - - &.has-item { - margin-right: 6px; - } - - // Draw a vertical line using border-right. - &::before { - content: ""; - display: block; - position: absolute; - top: 1px; - bottom: -2px; - right: -1px; - border-right: 2px solid $gray-600; - } - - // If a vertical line has terminated, don't draw it. - &.is-terminated::before { - border-color: transparent; - } - - // Make the last vertical line half-height. - &.has-item.is-last-row { - height: 26px; - } - - // Draw a horizontal line using border-bottom. - &.has-item::after { - content: ""; - display: block; - position: absolute; - top: 26px; - left: 100%; - width: 5px; - border-bottom: 2px solid $gray-600; - } - } } -// Position the horizontal line in the middle of appender's height -.block-editor-block-navigation-appender__cell .block-editor-block-navigator-descender-line { - &.has-item.is-last-row { - height: $grid-unit-20; - &::after { - top: 100%; - } - } +.block-editor-block-navigator-indentation { + flex-shrink: 0; + width: 18px; } From 84a73c4ec4bd48e82a584b616d6440ac38fb7d5c Mon Sep 17 00:00:00 2001 From: Aniruddh Gaavar <33789105+gaavar@users.noreply.github.com> Date: Wed, 13 Jan 2021 09:27:16 +0530 Subject: [PATCH 16/76] Update embed isMatch to permit multiple links to be pasted without triggering embed block (#27746) * modified isMatch to permit multiple links to be pasted without triggering embed block(#27551) * modified isMatch to permit multiple links to be pasted without triggering embed block(#27551) * modified isMatch to permit multiple links to be pasted without triggering embed block(#27551) * modified isMatch to permit multiple links to be pasted without triggering embed block(#27551) * modified isMatch to permit multiple links to be pasted without triggering embed block(#27551) * modified isMatch to permit multiple links to be pasted without triggering embed block(#27551) --- packages/block-library/src/embed/transforms.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/embed/transforms.js b/packages/block-library/src/embed/transforms.js index 1709d0ffc0893..c2db0d435b116 100644 --- a/packages/block-library/src/embed/transforms.js +++ b/packages/block-library/src/embed/transforms.js @@ -20,7 +20,8 @@ const transforms = { type: 'raw', isMatch: ( node ) => node.nodeName === 'P' && - /^\s*(https?:\/\/\S+)\s*$/i.test( node.textContent ), + /^\s*(https?:\/\/\S+)\s*$/i.test( node.textContent ) && + node.textContent?.match( /https/gi )?.length === 1, transform: ( node ) => { return createBlock( EMBED_BLOCK, { url: node.textContent.trim(), From 30919516dc7e5e0310d3c3fc5b173eef33af42ec Mon Sep 17 00:00:00 2001 From: Joen A <1204802+jasmussen@users.noreply.github.com> Date: Wed, 13 Jan 2021 09:14:36 +0100 Subject: [PATCH 17/76] Try: Fix appender margins again. (#27392) --- .../src/components/block-list-appender/style.scss | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/block-list-appender/style.scss b/packages/block-editor/src/components/block-list-appender/style.scss index 1b893c26875d7..db86e8e8da012 100644 --- a/packages/block-editor/src/components/block-list-appender/style.scss +++ b/packages/block-editor/src/components/block-list-appender/style.scss @@ -1,7 +1,11 @@ // These styles are only applied to the appender when it appears inside of a block. // Otherwise the default appender may be improperly positioned in some themes. .block-editor-block-list__block .block-list-appender { - margin: $grid-unit-10 0; + margin: 0; + + .block-editor-default-block-appender { + margin: $grid-unit-10 0; + } // Animate appearance. .block-list-appender__toggle { From c8bf7d904308ee339906827461657990d4334b50 Mon Sep 17 00:00:00 2001 From: Daniel Richards Date: Wed, 13 Jan 2021 16:31:24 +0800 Subject: [PATCH 18/76] Fix invalid cover block transforms (#28087) --- .../block-library/src/cover/transforms.js | 46 +++++++++++++------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/packages/block-library/src/cover/transforms.js b/packages/block-library/src/cover/transforms.js index 57de4c49acc88..85b340af2e9bb 100644 --- a/packages/block-library/src/cover/transforms.js +++ b/packages/block-library/src/cover/transforms.js @@ -14,26 +14,42 @@ const transforms = { type: 'block', blocks: [ 'core/image' ], transform: ( { caption, url, align, id, anchor } ) => - createBlock( 'core/cover', { - title: caption, - url, - align, - id, - anchor, - } ), + createBlock( + 'core/cover', + { + url, + align, + id, + anchor, + }, + [ + createBlock( 'core/paragraph', { + content: caption, + fontSize: 'large', + } ), + ] + ), }, { type: 'block', blocks: [ 'core/video' ], transform: ( { caption, src, align, id, anchor } ) => - createBlock( 'core/cover', { - title: caption, - url: src, - align, - id, - backgroundType: VIDEO_BACKGROUND_TYPE, - anchor, - } ), + createBlock( + 'core/cover', + { + url: src, + align, + id, + backgroundType: VIDEO_BACKGROUND_TYPE, + anchor, + }, + [ + createBlock( 'core/paragraph', { + content: caption, + fontSize: 'large', + } ), + ] + ), }, ], to: [ From d8c5deef93ce31d3775c405176af6dafa780d427 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 13 Jan 2021 10:19:48 +0100 Subject: [PATCH 19/76] Show an error message when a reusable block has gone missing. (#28126) --- packages/block-library/src/block/edit.js | 44 +++++++++++-------- packages/core-data/src/resolvers.js | 3 ++ .../editor/various/reusable-blocks.test.js | 18 ++++++++ 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/packages/block-library/src/block/edit.js b/packages/block-library/src/block/edit.js index 6e3f999ba3638..e28290836a0e8 100644 --- a/packages/block-library/src/block/edit.js +++ b/packages/block-library/src/block/edit.js @@ -22,6 +22,7 @@ import { BlockControls, InspectorControls, useBlockProps, + Warning, } from '@wordpress/block-editor'; import { store as reusableBlocksStore } from '@wordpress/reusable-blocks'; @@ -30,18 +31,25 @@ import { store as reusableBlocksStore } from '@wordpress/reusable-blocks'; */ export default function ReusableBlockEdit( { attributes: { ref }, clientId } ) { - const recordArgs = [ 'postType', 'wp_block', ref ]; - - const { reusableBlock, hasResolved } = useSelect( - ( select ) => ( { - reusableBlock: select( coreStore ).getEditedEntityRecord( - ...recordArgs - ), - hasResolved: select( coreStore ).hasFinishedResolution( - 'getEditedEntityRecord', - recordArgs - ), - } ), + const { isMissing, hasResolved } = useSelect( + ( select ) => { + const persistedBlock = select( coreStore ).getEntityRecord( + 'postType', + 'wp_block', + ref + ); + const hasResolvedBlock = select( + coreStore + ).hasFinishedResolution( 'getEntityRecord', [ + 'postType', + 'wp_block', + ref, + ] ); + return { + hasResolved: hasResolvedBlock, + isMissing: hasResolvedBlock && ! persistedBlock, + }; + }, [ ref, clientId ] ); @@ -75,21 +83,21 @@ export default function ReusableBlockEdit( { attributes: { ref }, clientId } ) { const blockProps = useBlockProps(); - if ( ! hasResolved ) { + if ( isMissing ) { return (
- - - + + { __( 'Block has been deleted or is unavailable.' ) } +
); } - if ( ! reusableBlock ) { + if ( ! hasResolved ) { return (
- { __( 'Block has been deleted or is unavailable.' ) } +
); diff --git a/packages/core-data/src/resolvers.js b/packages/core-data/src/resolvers.js index ce09f4439d8c7..f227c05fb2143 100644 --- a/packages/core-data/src/resolvers.js +++ b/packages/core-data/src/resolvers.js @@ -136,6 +136,9 @@ export function* getEntityRecord( kind, name, key = '', query ) { const record = yield apiFetch( { path } ); yield receiveEntityRecords( kind, name, record, query ); + } catch ( error ) { + // We need a way to handle and access REST API errors in state + // Until then, catching the error ensures the resolver is marked as resolved. } finally { yield* __unstableReleaseStoreLock( lock ); } diff --git a/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js b/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js index 6cd4b93e93c1d..1d3a4193a7cc6 100644 --- a/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js +++ b/packages/e2e-tests/specs/editor/various/reusable-blocks.test.js @@ -274,6 +274,24 @@ describe( 'Reusable blocks', () => { expect( console ).not.toHaveErrored(); } ); + it( 'Should show a proper message when the reusable block is missing', async () => { + // Insert a non-existant reusable block + await page.evaluate( () => { + const { createBlock } = window.wp.blocks; + const { dispatch } = window.wp.data; + dispatch( 'core/block-editor' ).resetBlocks( [ + createBlock( 'core/block', { ref: 123456 } ), + ] ); + } ); + + await page.waitForXPath( + '//*[contains(@class, "block-editor-warning")]/*[text()="Block has been deleted or is unavailable."]' + ); + + // This happens when the 404 is returned. + expect( console ).toHaveErrored(); + } ); + it( 'should be able to insert a reusable block twice', async () => { await createReusableBlock( 'Awesome Paragraph', From 24081004486a79cfe2c324b4980a20e26593d5d5 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 13 Jan 2021 10:49:16 +0100 Subject: [PATCH 20/76] Prevent link paste in RichText components in Button and Navigation blocks (#28130) --- .../rich-text/src/component/format-edit.js | 34 +----------- packages/rich-text/src/component/index.js | 6 +-- .../rich-text/src/component/index.native.js | 18 ++++--- .../src/component/use-format-types.js | 53 +++++++++++++++++-- 4 files changed, 63 insertions(+), 48 deletions(-) diff --git a/packages/rich-text/src/component/format-edit.js b/packages/rich-text/src/component/format-edit.js index 893b0af9a5c2d..1867c1ef2e4f7 100644 --- a/packages/rich-text/src/component/format-edit.js +++ b/packages/rich-text/src/component/format-edit.js @@ -4,52 +4,20 @@ import { getActiveFormat } from '../get-active-format'; import { getActiveObject } from '../get-active-object'; -/** - * Set of all interactive content tags. - * - * @see https://html.spec.whatwg.org/multipage/dom.html#interactive-content - */ -const interactiveContentTags = new Set( [ - 'a', - 'audio', - 'button', - 'details', - 'embed', - 'iframe', - 'input', - 'label', - 'select', - 'textarea', - 'video', -] ); - export default function FormatEdit( { formatTypes, onChange, onFocus, value, - allowedFormats, - withoutInteractiveFormatting, forwardedRef, } ) { return formatTypes.map( ( settings ) => { - const { name, edit: Edit, tagName } = settings; + const { name, edit: Edit } = settings; if ( ! Edit ) { return null; } - if ( allowedFormats && allowedFormats.indexOf( name ) === -1 ) { - return null; - } - - if ( - withoutInteractiveFormatting && - interactiveContentTags.has( tagName ) - ) { - return null; - } - const activeFormat = getActiveFormat( value, name ); const isActive = activeFormat !== undefined; const activeObject = getActiveObject( value ); diff --git a/packages/rich-text/src/component/index.js b/packages/rich-text/src/component/index.js index 625da9012fd05..da2505228d1d1 100644 --- a/packages/rich-text/src/component/index.js +++ b/packages/rich-text/src/component/index.js @@ -174,6 +174,8 @@ function RichText( } = useFormatTypes( { clientId, identifier, + withoutInteractiveFormatting, + allowedFormats, } ); // For backward compatibility, fall back to tagName if it's a string. @@ -1102,10 +1104,6 @@ function RichText( <> { isSelected && ( { return text.replace( / | /gi, ' ' ); @@ -799,7 +799,6 @@ export class RichText extends Component { maxWidth, formatTypes, parentBlockStyles, - withoutInteractiveFormatting, accessibilityLabel, disableEditingMenu = false, } = this.props; @@ -953,9 +952,6 @@ export class RichText extends Component { {} } /> @@ -977,6 +973,16 @@ RichText.defaultProps = { tagName: 'div', }; +const withFormatTypes = ( WrappedComponent ) => ( props ) => { + const { formatTypes } = useFormatTypes( { + clientId: props.clientId, + identifier: props.identifier, + withoutInteractiveFormatting: props.withoutInteractiveFormatting, + } ); + + return ; +}; + export default compose( [ withSelect( ( select, { clientId } ) => { const { getBlockParents, getBlock, getSettings } = select( @@ -988,7 +994,6 @@ export default compose( [ get( parentBlock, [ 'attributes', 'childrenStyles' ] ) || {}; return { - formatTypes: select( richTextStore ).getFormatTypes(), areMentionsSupported: getSettings( 'capabilities' ).mentions === true, areXPostsSupported: getSettings( 'capabilities' ).xposts === true, @@ -996,4 +1001,5 @@ export default compose( [ }; } ), withPreferredColorScheme, + withFormatTypes, ] )( RichText ); diff --git a/packages/rich-text/src/component/use-format-types.js b/packages/rich-text/src/component/use-format-types.js index c1df61ac093c1..5406e51d68b0d 100644 --- a/packages/rich-text/src/component/use-format-types.js +++ b/packages/rich-text/src/component/use-format-types.js @@ -1,6 +1,7 @@ /** * WordPress dependencies */ +import { useMemo } from '@wordpress/element'; import { useSelect, useDispatch } from '@wordpress/data'; /** * Internal dependencies @@ -11,16 +12,58 @@ function formatTypesSelector( select ) { return select( richTextStore ).getFormatTypes(); } +/** + * Set of all interactive content tags. + * + * @see https://html.spec.whatwg.org/multipage/dom.html#interactive-content + */ +const interactiveContentTags = new Set( [ + 'a', + 'audio', + 'button', + 'details', + 'embed', + 'iframe', + 'input', + 'label', + 'select', + 'textarea', + 'video', +] ); + /** * This hook provides RichText with the `formatTypes` and its derived props from * experimental format type settings. * - * @param {Object} $0 Options - * @param {string} $0.clientId Block client ID. - * @param {string} $0.identifier Block attribute. + * @param {Object} $0 Options + * @param {string} $0.clientId Block client ID. + * @param {string} $0.identifier Block attribute. + * @param {boolean} $0.withoutInteractiveFormatting Whether to clean the interactive formattings or not. + * @param {Array} $0.allowedFormats Allowed formats */ -export function useFormatTypes( { clientId, identifier } ) { - const formatTypes = useSelect( formatTypesSelector, [] ); +export function useFormatTypes( { + clientId, + identifier, + withoutInteractiveFormatting, + allowedFormats, +} ) { + const allFormatTypes = useSelect( formatTypesSelector, [] ); + const formatTypes = useMemo( () => { + return allFormatTypes.filter( ( { name, tagName } ) => { + if ( allowedFormats && allowedFormats.includes( name ) ) { + return false; + } + + if ( + withoutInteractiveFormatting && + interactiveContentTags.has( tagName ) + ) { + return false; + } + + return true; + } ); + }, [ allFormatTypes, allowedFormats, interactiveContentTags ] ); const keyedSelected = useSelect( ( select ) => formatTypes.reduce( ( accumulator, type ) => { From 7a927ac4d5238ee97bc5e9d6917b443bcec54c97 Mon Sep 17 00:00:00 2001 From: Rafael Galani Date: Wed, 13 Jan 2021 07:11:26 -0300 Subject: [PATCH 21/76] Annotations: Replace store name string with exposed store definition (#28156) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Removing 'annotations' references to the store name * Revert change in the filter usage Co-authored-by: Greg Ziółkowski --- packages/annotations/src/block/index.js | 6 +++++- packages/annotations/src/format/annotation.js | 5 ++++- packages/annotations/src/store/constants.js | 6 ++++++ packages/annotations/src/store/index.js | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 packages/annotations/src/store/constants.js diff --git a/packages/annotations/src/block/index.js b/packages/annotations/src/block/index.js index 3a5dee89607ab..8342eb8e32609 100644 --- a/packages/annotations/src/block/index.js +++ b/packages/annotations/src/block/index.js @@ -4,6 +4,10 @@ import { addFilter } from '@wordpress/hooks'; import { withSelect } from '@wordpress/data'; +/** + * Internal dependencies + */ +import { STORE_NAME } from '../store/constants'; /** * Adds annotation className to the block-list-block component. * @@ -13,7 +17,7 @@ import { withSelect } from '@wordpress/data'; const addAnnotationClassName = ( OriginalComponent ) => { return withSelect( ( select, { clientId, className } ) => { const annotations = select( - 'core/annotations' + STORE_NAME ).__experimentalGetAnnotationsForBlock( clientId ); return { diff --git a/packages/annotations/src/format/annotation.js b/packages/annotations/src/format/annotation.js index f3ea7096a3782..dd0d618f9c678 100644 --- a/packages/annotations/src/format/annotation.js +++ b/packages/annotations/src/format/annotation.js @@ -7,7 +7,10 @@ import { applyFormat, removeFormat } from '@wordpress/rich-text'; const FORMAT_NAME = 'core/annotation'; const ANNOTATION_ATTRIBUTE_PREFIX = 'annotation-text-'; -const STORE_NAME = 'core/annotations'; +/** + * Internal dependencies + */ +import { STORE_NAME } from '../store/constants'; /** * Applies given annotations to the given record. diff --git a/packages/annotations/src/store/constants.js b/packages/annotations/src/store/constants.js new file mode 100644 index 0000000000000..4b8cf0416eb92 --- /dev/null +++ b/packages/annotations/src/store/constants.js @@ -0,0 +1,6 @@ +/** + * The identifier for the data store. + * + * @type {string} + */ +export const STORE_NAME = 'core/annotations'; diff --git a/packages/annotations/src/store/index.js b/packages/annotations/src/store/index.js index 81dee6efd82b4..50c3cab06a72e 100644 --- a/packages/annotations/src/store/index.js +++ b/packages/annotations/src/store/index.js @@ -13,7 +13,7 @@ import * as actions from './actions'; /** * Module Constants */ -const STORE_NAME = 'core/annotations'; +import { STORE_NAME } from './constants'; /** * Store definition for the annotations namespace. From ed56f4bc62ad51b720f1e37209d3531354775503 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 13 Jan 2021 11:29:25 +0100 Subject: [PATCH 22/76] Remove effects test file and remove unused refx dependency (#28162) --- package-lock.json | 6 - .../block-editor/src/store/test/actions.js | 402 +++++++++++++++++- .../block-editor/src/store/test/effects.js | 372 ---------------- packages/editor/package.json | 1 - 4 files changed, 379 insertions(+), 402 deletions(-) delete mode 100644 packages/block-editor/src/store/test/effects.js diff --git a/package-lock.json b/package-lock.json index 826b893cb9757..f2cab8c1789e1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12161,7 +12161,6 @@ "lodash": "^4.17.19", "memize": "^1.1.0", "react-autosize-textarea": "^7.1.0", - "refx": "^3.0.0", "rememo": "^3.0.0" } }, @@ -47865,11 +47864,6 @@ } } }, - "refx": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/refx/-/refx-3.0.0.tgz", - "integrity": "sha512-qmd73YvYiVWfKPECtE90ujmPwwtAnmtEOkBKgfNEuqJ4trTeKbqFV2UY878yFvHBvU7BBu4/w/Q8pk/t0zDpYA==" - }, "regenerate": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", diff --git a/packages/block-editor/src/store/test/actions.js b/packages/block-editor/src/store/test/actions.js index d9598b9a7e6b8..8bbc93386e277 100644 --- a/packages/block-editor/src/store/test/actions.js +++ b/packages/block-editor/src/store/test/actions.js @@ -1,12 +1,27 @@ +/** + * External dependencies + */ +import { noop } from 'lodash'; +import deepFreeze from 'deep-freeze'; + /** * WordPress dependencies */ -import { controls } from '@wordpress/data'; +import { controls, createRegistry } from '@wordpress/data'; +import { + getBlockTypes, + unregisterBlockType, + registerBlockType, + createBlock, +} from '@wordpress/blocks'; /** * Internal dependencies */ -import { + +import * as selectors from '../selectors'; +import reducer from '../reducer'; +import actions, { clearSelectedBlock, enterFormattedText, exitFormattedText, @@ -37,9 +52,22 @@ import { updateBlock, updateBlockAttributes, updateBlockListSettings, + updateSettings, + selectionChange, + validateBlocksToTemplate, } from '../actions'; +import '../..'; describe( 'actions', () => { + const defaultBlockSettings = { + attributes: { + content: {}, + }, + save: () => 'Saved', + category: 'text', + title: 'block title', + }; + describe( 'resetBlocks', () => { it( 'should yield the RESET_BLOCKS actions', () => { const blocks = []; @@ -737,29 +765,14 @@ describe( 'actions', () => { } ); } ); - describe( 'mergeBlocks', () => { - it( 'should return MERGE_BLOCKS action', () => { - const firstBlockClientId = 'blockA'; - const secondBlockClientId = 'blockB'; - const fulfillment = mergeBlocks( - firstBlockClientId, - secondBlockClientId - ); - expect( fulfillment.next().value ).toEqual( { - type: 'MERGE_BLOCKS', - blocks: [ firstBlockClientId, secondBlockClientId ], - } ); - } ); - } ); - describe( 'removeBlocks', () => { it( 'should return REMOVE_BLOCKS action', () => { const clientId = 'clientId'; const clientIds = [ clientId ]; - const actions = Array.from( removeBlocks( clientIds ) ); + const result = Array.from( removeBlocks( clientIds ) ); - expect( actions ).toEqual( [ + expect( result ).toEqual( [ controls.select( 'core/block-editor', 'getBlockRootClientId', @@ -958,9 +971,9 @@ describe( 'actions', () => { it( 'should return REMOVE_BLOCKS action', () => { const clientId = 'myclientid'; - const actions = Array.from( removeBlock( clientId ) ); + const result = Array.from( removeBlock( clientId ) ); - expect( actions ).toEqual( [ + expect( result ).toEqual( [ controls.select( 'core/block-editor', 'getBlockRootClientId', @@ -983,9 +996,9 @@ describe( 'actions', () => { it( 'should return REMOVE_BLOCKS action, opting out of select previous', () => { const clientId = 'myclientid'; - const actions = Array.from( removeBlock( clientId, false ) ); + const result = Array.from( removeBlock( clientId, false ) ); - expect( actions ).toEqual( [ + expect( result ).toEqual( [ controls.select( 'core/block-editor', 'getBlockRootClientId', @@ -1138,4 +1151,347 @@ describe( 'actions', () => { } ); } ); } ); + + describe( 'mergeBlocks', () => { + afterEach( () => { + getBlockTypes().forEach( ( block ) => { + unregisterBlockType( block.name ); + } ); + } ); + + it( 'should return MERGE_BLOCKS action', () => { + const firstBlockClientId = 'blockA'; + const secondBlockClientId = 'blockB'; + const fulfillment = mergeBlocks( + firstBlockClientId, + secondBlockClientId + ); + expect( fulfillment.next().value ).toEqual( { + type: 'MERGE_BLOCKS', + blocks: [ firstBlockClientId, secondBlockClientId ], + } ); + } ); + + it( 'should only focus the blockA if the blockA has no merge function', () => { + registerBlockType( 'core/test-block', defaultBlockSettings ); + const blockA = deepFreeze( { + clientId: 'chicken', + name: 'core/test-block', + } ); + const blockB = deepFreeze( { + clientId: 'ribs', + name: 'core/test-block', + } ); + + const fulfillment = mergeBlocks( blockA.clientId, blockB.clientId ); + expect( fulfillment.next() ).toEqual( { + done: false, + value: { + type: 'MERGE_BLOCKS', + blocks: [ blockA.clientId, blockB.clientId ], + }, + } ); + fulfillment.next(); + expect( fulfillment.next( blockA ) ).toEqual( { + done: false, + value: selectBlock( 'chicken' ), + } ); + expect( fulfillment.next( blockA ).done ).toEqual( true ); + } ); + + it( 'should merge the blocks if blocks of the same type', () => { + registerBlockType( 'core/test-block', { + attributes: { + content: {}, + }, + merge( attributes, attributesToMerge ) { + return { + content: + attributes.content + + ' ' + + attributesToMerge.content, + }; + }, + save: noop, + category: 'text', + title: 'test block', + } ); + const blockA = deepFreeze( { + clientId: 'chicken', + name: 'core/test-block', + attributes: { content: 'chicken' }, + innerBlocks: [], + } ); + const blockB = deepFreeze( { + clientId: 'ribs', + name: 'core/test-block', + attributes: { content: 'ribs' }, + innerBlocks: [], + } ); + + const fulfillment = mergeBlocks( blockA.clientId, blockB.clientId ); + // MERGE_BLOCKS + fulfillment.next(); + // getBlock A + fulfillment.next(); + fulfillment.next( blockA ); + // getBlock B + fulfillment.next( blockB ); + // getSelectionStart + fulfillment.next( { + clientId: blockB.clientId, + attributeKey: 'content', + offset: 0, + } ); + // selectionChange + fulfillment.next( + selectionChange( + blockA.clientId, + 'content', + 'chicken'.length + 1, + 'chicken'.length + 1 + ) + ); + fulfillment.next(); + fulfillment.next(); + expect( fulfillment.next( blockA ).value ).toMatchObject( { + type: 'REPLACE_BLOCKS', + clientIds: [ 'chicken', 'ribs' ], + blocks: [ + { + clientId: 'chicken', + name: 'core/test-block', + attributes: { content: 'chicken ribs' }, + }, + ], + } ); + } ); + + it( 'should not merge the blocks have different types without transformation', () => { + registerBlockType( 'core/test-block', { + attributes: { + content: {}, + }, + merge( attributes, attributesToMerge ) { + return { + content: + attributes.content + + ' ' + + attributesToMerge.content, + }; + }, + save: noop, + category: 'text', + title: 'test block', + } ); + registerBlockType( 'core/test-block-2', defaultBlockSettings ); + const blockA = deepFreeze( { + clientId: 'chicken', + name: 'core/test-block', + attributes: { content: 'chicken' }, + innerBlocks: [], + } ); + const blockB = deepFreeze( { + clientId: 'ribs', + name: 'core/test-block-2', + attributes: { content: 'ribs' }, + innerBlocks: [], + } ); + + const fulfillment = mergeBlocks( blockA.clientId, blockB.clientId ); + // MERGE_BLOCKS + fulfillment.next(); + // getBlock A + fulfillment.next(); + fulfillment.next( blockA ); + // getBlock B + expect( fulfillment.next( blockB ).value ).toEqual( { + args: [], + selectorName: 'getSelectionStart', + storeKey: 'core/block-editor', + type: '@@data/SELECT', + } ); + // getSelectionStart + const next = fulfillment.next( { + clientId: blockB.clientId, + attributeKey: 'content', + offset: 0, + } ); + expect( next.value ).toEqual( undefined ); + expect( next.done ).toBe( true ); + } ); + + it( 'should transform and merge the blocks', () => { + registerBlockType( 'core/test-block', { + attributes: { + content: { + type: 'string', + }, + }, + merge( attributes, attributesToMerge ) { + return { + content: + attributes.content + + ' ' + + attributesToMerge.content, + }; + }, + save: noop, + category: 'text', + title: 'test block', + } ); + registerBlockType( 'core/test-block-2', { + attributes: { + content2: { + type: 'string', + }, + }, + transforms: { + to: [ + { + type: 'block', + blocks: [ 'core/test-block' ], + transform: ( { content2 } ) => { + return createBlock( 'core/test-block', { + content: content2, + } ); + }, + }, + ], + }, + save: noop, + category: 'text', + title: 'test block 2', + } ); + const blockA = deepFreeze( { + clientId: 'chicken', + name: 'core/test-block', + attributes: { content: 'chicken' }, + innerBlocks: [], + } ); + const blockB = deepFreeze( { + clientId: 'ribs', + name: 'core/test-block-2', + attributes: { content2: 'ribs' }, + innerBlocks: [], + } ); + + const fulfillment = mergeBlocks( blockA.clientId, blockB.clientId ); + // MERGE_BLOCKS + fulfillment.next(); + // getBlock A + fulfillment.next(); + fulfillment.next( blockA ); + // getBlock B + expect( fulfillment.next( blockB ).value ).toEqual( { + args: [], + selectorName: 'getSelectionStart', + storeKey: 'core/block-editor', + type: '@@data/SELECT', + } ); + expect( + fulfillment.next( { + clientId: blockB.clientId, + attributeKey: 'content2', + offset: 0, + } ).value + ).toEqual( + selectionChange( + blockA.clientId, + 'content', + 'chicken'.length + 1, + 'chicken'.length + 1 + ) + ); + + fulfillment.next(); + fulfillment.next(); + fulfillment.next(); + expect( fulfillment.next( blockA ).value ).toMatchObject( { + type: 'REPLACE_BLOCKS', + clientIds: [ 'chicken', 'ribs' ], + blocks: [ + { + clientId: 'chicken', + name: 'core/test-block', + attributes: { content: 'chicken ribs' }, + }, + ], + } ); + } ); + } ); + + describe( 'validateBlocksToTemplate', () => { + let store; + beforeEach( () => { + store = createRegistry().registerStore( 'core/block-editor', { + actions, + selectors, + reducer, + } ); + + registerBlockType( 'core/test-block', defaultBlockSettings ); + } ); + + afterEach( () => { + getBlockTypes().forEach( ( block ) => { + unregisterBlockType( block.name ); + } ); + } ); + + it( 'should return undefined if no template assigned', async () => { + const result = await store.dispatch( + validateBlocksToTemplate( + resetBlocks( [ createBlock( 'core/test-block' ) ] ), + store + ) + ); + + expect( result ).toEqual( undefined ); + } ); + + it( 'should return undefined if invalid but unlocked', async () => { + store.dispatch( + updateSettings( { + template: [ [ 'core/foo', {} ] ], + } ) + ); + + const result = await store.dispatch( + validateBlocksToTemplate( [ createBlock( 'core/test-block' ) ] ) + ); + + expect( result ).toEqual( undefined ); + } ); + + it( 'should return undefined if locked and valid', async () => { + store.dispatch( + updateSettings( { + template: [ [ 'core/test-block' ] ], + templateLock: 'all', + } ) + ); + + const result = await store.dispatch( + validateBlocksToTemplate( [ createBlock( 'core/test-block' ) ] ) + ); + + expect( result ).toEqual( undefined ); + } ); + + it( 'should return validity set action if invalid on default state', async () => { + store.dispatch( + updateSettings( { + template: [ [ 'core/foo' ] ], + templateLock: 'all', + } ) + ); + + const result = await store.dispatch( + validateBlocksToTemplate( [ createBlock( 'core/test-block' ) ] ) + ); + + expect( result ).toEqual( false ); + } ); + } ); } ); diff --git a/packages/block-editor/src/store/test/effects.js b/packages/block-editor/src/store/test/effects.js deleted file mode 100644 index 9a8ecc4980187..0000000000000 --- a/packages/block-editor/src/store/test/effects.js +++ /dev/null @@ -1,372 +0,0 @@ -/** - * External dependencies - */ -import { noop } from 'lodash'; -import deepFreeze from 'deep-freeze'; - -/** - * WordPress dependencies - */ -import { - getBlockTypes, - unregisterBlockType, - registerBlockType, - createBlock, -} from '@wordpress/blocks'; -import { createRegistry } from '@wordpress/data'; - -/** - * Internal dependencies - */ -import actions, { - updateSettings, - mergeBlocks, - resetBlocks, - selectBlock, - selectionChange, - validateBlocksToTemplate, -} from '../actions'; -import * as selectors from '../selectors'; -import reducer from '../reducer'; -import '../../'; - -describe( 'effects', () => { - const defaultBlockSettings = { - attributes: { - content: {}, - }, - save: () => 'Saved', - category: 'text', - title: 'block title', - }; - - describe( '.MERGE_BLOCKS', () => { - afterEach( () => { - getBlockTypes().forEach( ( block ) => { - unregisterBlockType( block.name ); - } ); - } ); - - it( 'should only focus the blockA if the blockA has no merge function', () => { - registerBlockType( 'core/test-block', defaultBlockSettings ); - const blockA = deepFreeze( { - clientId: 'chicken', - name: 'core/test-block', - } ); - const blockB = deepFreeze( { - clientId: 'ribs', - name: 'core/test-block', - } ); - - const fulfillment = mergeBlocks( blockA.clientId, blockB.clientId ); - expect( fulfillment.next() ).toEqual( { - done: false, - value: { - type: 'MERGE_BLOCKS', - blocks: [ blockA.clientId, blockB.clientId ], - }, - } ); - fulfillment.next(); - expect( fulfillment.next( blockA ) ).toEqual( { - done: false, - value: selectBlock( 'chicken' ), - } ); - expect( fulfillment.next( blockA ).done ).toEqual( true ); - } ); - - it( 'should merge the blocks if blocks of the same type', () => { - registerBlockType( 'core/test-block', { - attributes: { - content: {}, - }, - merge( attributes, attributesToMerge ) { - return { - content: - attributes.content + - ' ' + - attributesToMerge.content, - }; - }, - save: noop, - category: 'text', - title: 'test block', - } ); - const blockA = deepFreeze( { - clientId: 'chicken', - name: 'core/test-block', - attributes: { content: 'chicken' }, - innerBlocks: [], - } ); - const blockB = deepFreeze( { - clientId: 'ribs', - name: 'core/test-block', - attributes: { content: 'ribs' }, - innerBlocks: [], - } ); - - const fulfillment = mergeBlocks( blockA.clientId, blockB.clientId ); - // MERGE_BLOCKS - fulfillment.next(); - // getBlock A - fulfillment.next(); - fulfillment.next( blockA ); - // getBlock B - fulfillment.next( blockB ); - // getSelectionStart - fulfillment.next( { - clientId: blockB.clientId, - attributeKey: 'content', - offset: 0, - } ); - // selectionChange - fulfillment.next( - selectionChange( - blockA.clientId, - 'content', - 'chicken'.length + 1, - 'chicken'.length + 1 - ) - ); - fulfillment.next(); - fulfillment.next(); - expect( fulfillment.next( blockA ).value ).toMatchObject( { - type: 'REPLACE_BLOCKS', - clientIds: [ 'chicken', 'ribs' ], - blocks: [ - { - clientId: 'chicken', - name: 'core/test-block', - attributes: { content: 'chicken ribs' }, - }, - ], - } ); - } ); - - it( 'should not merge the blocks have different types without transformation', () => { - registerBlockType( 'core/test-block', { - attributes: { - content: {}, - }, - merge( attributes, attributesToMerge ) { - return { - content: - attributes.content + - ' ' + - attributesToMerge.content, - }; - }, - save: noop, - category: 'text', - title: 'test block', - } ); - registerBlockType( 'core/test-block-2', defaultBlockSettings ); - const blockA = deepFreeze( { - clientId: 'chicken', - name: 'core/test-block', - attributes: { content: 'chicken' }, - innerBlocks: [], - } ); - const blockB = deepFreeze( { - clientId: 'ribs', - name: 'core/test-block-2', - attributes: { content: 'ribs' }, - innerBlocks: [], - } ); - - const fulfillment = mergeBlocks( blockA.clientId, blockB.clientId ); - // MERGE_BLOCKS - fulfillment.next(); - // getBlock A - fulfillment.next(); - fulfillment.next( blockA ); - // getBlock B - expect( fulfillment.next( blockB ).value ).toEqual( { - args: [], - selectorName: 'getSelectionStart', - storeKey: 'core/block-editor', - type: '@@data/SELECT', - } ); - // getSelectionStart - const next = fulfillment.next( { - clientId: blockB.clientId, - attributeKey: 'content', - offset: 0, - } ); - expect( next.value ).toEqual( undefined ); - expect( next.done ).toBe( true ); - } ); - - it( 'should transform and merge the blocks', () => { - registerBlockType( 'core/test-block', { - attributes: { - content: { - type: 'string', - }, - }, - merge( attributes, attributesToMerge ) { - return { - content: - attributes.content + - ' ' + - attributesToMerge.content, - }; - }, - save: noop, - category: 'text', - title: 'test block', - } ); - registerBlockType( 'core/test-block-2', { - attributes: { - content2: { - type: 'string', - }, - }, - transforms: { - to: [ - { - type: 'block', - blocks: [ 'core/test-block' ], - transform: ( { content2 } ) => { - return createBlock( 'core/test-block', { - content: content2, - } ); - }, - }, - ], - }, - save: noop, - category: 'text', - title: 'test block 2', - } ); - const blockA = deepFreeze( { - clientId: 'chicken', - name: 'core/test-block', - attributes: { content: 'chicken' }, - innerBlocks: [], - } ); - const blockB = deepFreeze( { - clientId: 'ribs', - name: 'core/test-block-2', - attributes: { content2: 'ribs' }, - innerBlocks: [], - } ); - - const fulfillment = mergeBlocks( blockA.clientId, blockB.clientId ); - // MERGE_BLOCKS - fulfillment.next(); - // getBlock A - fulfillment.next(); - fulfillment.next( blockA ); - // getBlock B - expect( fulfillment.next( blockB ).value ).toEqual( { - args: [], - selectorName: 'getSelectionStart', - storeKey: 'core/block-editor', - type: '@@data/SELECT', - } ); - expect( - fulfillment.next( { - clientId: blockB.clientId, - attributeKey: 'content2', - offset: 0, - } ).value - ).toEqual( - selectionChange( - blockA.clientId, - 'content', - 'chicken'.length + 1, - 'chicken'.length + 1 - ) - ); - - fulfillment.next(); - fulfillment.next(); - fulfillment.next(); - expect( fulfillment.next( blockA ).value ).toMatchObject( { - type: 'REPLACE_BLOCKS', - clientIds: [ 'chicken', 'ribs' ], - blocks: [ - { - clientId: 'chicken', - name: 'core/test-block', - attributes: { content: 'chicken ribs' }, - }, - ], - } ); - } ); - } ); - - describe( 'validateBlocksToTemplate', () => { - let store; - beforeEach( () => { - store = createRegistry().registerStore( 'core/block-editor', { - actions, - selectors, - reducer, - } ); - - registerBlockType( 'core/test-block', defaultBlockSettings ); - } ); - - afterEach( () => { - getBlockTypes().forEach( ( block ) => { - unregisterBlockType( block.name ); - } ); - } ); - - it( 'should return undefined if no template assigned', async () => { - const result = await store.dispatch( - validateBlocksToTemplate( - resetBlocks( [ createBlock( 'core/test-block' ) ] ), - store - ) - ); - - expect( result ).toEqual( undefined ); - } ); - - it( 'should return undefined if invalid but unlocked', async () => { - store.dispatch( - updateSettings( { - template: [ [ 'core/foo', {} ] ], - } ) - ); - - const result = await store.dispatch( - validateBlocksToTemplate( [ createBlock( 'core/test-block' ) ] ) - ); - - expect( result ).toEqual( undefined ); - } ); - - it( 'should return undefined if locked and valid', async () => { - store.dispatch( - updateSettings( { - template: [ [ 'core/test-block' ] ], - templateLock: 'all', - } ) - ); - - const result = await store.dispatch( - validateBlocksToTemplate( [ createBlock( 'core/test-block' ) ] ) - ); - - expect( result ).toEqual( undefined ); - } ); - - it( 'should return validity set action if invalid on default state', async () => { - store.dispatch( - updateSettings( { - template: [ [ 'core/foo' ] ], - templateLock: 'all', - } ) - ); - - const result = await store.dispatch( - validateBlocksToTemplate( [ createBlock( 'core/test-block' ) ] ) - ); - - expect( result ).toEqual( false ); - } ); - } ); -} ); diff --git a/packages/editor/package.json b/packages/editor/package.json index 98f52a7e6c2fb..fb6e3d15491fb 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -59,7 +59,6 @@ "lodash": "^4.17.19", "memize": "^1.1.0", "react-autosize-textarea": "^7.1.0", - "refx": "^3.0.0", "rememo": "^3.0.0" }, "publishConfig": { From 312d357adb4913f38c60ad36e045dd5edf8c4135 Mon Sep 17 00:00:00 2001 From: Nik Tsekouras Date: Wed, 13 Jan 2021 13:53:38 +0200 Subject: [PATCH 23/76] Decouple query from edit site (#27972) * decouple Query Loop from site-edit * don't allow `inherit` query out of edit-site context * set templateSlug in page context on template set --- .../block-library/src/query-loop/block.json | 3 +- packages/block-library/src/query-loop/edit.js | 36 ++++++------------- .../block-library/src/query/edit/index.js | 2 +- .../edit-site/src/components/editor/index.js | 4 --- .../template-navigation-item.js | 2 +- packages/edit-site/src/store/actions.js | 33 +++++++++++++---- packages/edit-site/src/store/test/actions.js | 26 ++++++++++++-- 7 files changed, 64 insertions(+), 42 deletions(-) diff --git a/packages/block-library/src/query-loop/block.json b/packages/block-library/src/query-loop/block.json index 6059febae1dd6..724169afc851d 100644 --- a/packages/block-library/src/query-loop/block.json +++ b/packages/block-library/src/query-loop/block.json @@ -6,7 +6,8 @@ "queryId", "query", "queryContext", - "layout" + "layout", + "templateSlug" ], "supports": { "reusable": false, diff --git a/packages/block-library/src/query-loop/edit.js b/packages/block-library/src/query-loop/edit.js index 370eb45e08a7d..1606b913e260a 100644 --- a/packages/block-library/src/query-loop/edit.js +++ b/packages/block-library/src/query-loop/edit.js @@ -43,11 +43,12 @@ export default function QueryLoopEdit( { sticky, inherit, } = {}, - queryContext, + queryContext = [ {} ], + templateSlug, layout: { type: layoutType = 'flex', columns = 1 } = {}, }, } ) { - const [ { page } ] = useQueryContext() || queryContext || [ {} ]; + const [ { page } ] = useQueryContext() || queryContext; const [ activeBlockContext, setActiveBlockContext ] = useState(); const { posts, blocks } = useSelect( @@ -79,32 +80,14 @@ export default function QueryLoopEdit( { if ( sticky ) { query.sticky = sticky === 'only'; } - - // When you insert this block outside of the edit site then store - // does not exist therefore we check for its existence. - // TODO: remove this code, edit-site shouldn't be called in block-library. - // This creates a cycle dependency. - if ( inherit && select( 'core/edit-site' ) ) { - // This should be passed from the context exposed by edit site. - const { getEditedPostType, getEditedPostId } = select( - 'core/edit-site' - ); - - if ( 'wp_template' === getEditedPostType() ) { - const { slug } = select( 'core' ).getEntityRecord( - 'postType', - 'wp_template', - getEditedPostId() - ); - - // Change the post-type if needed. - if ( slug?.startsWith( 'archive-' ) ) { - query.postType = slug.replace( 'archive-', '' ); - postType = query.postType; - } + // If `inherit` is truthy, adjust conditionally the query to create a better preview. + if ( inherit ) { + // Change the post-type if needed. + if ( templateSlug?.startsWith( 'archive-' ) ) { + query.postType = templateSlug.replace( 'archive-', '' ); + postType = query.postType; } } - return { posts: getEntityRecords( 'postType', postType, query ), blocks: getBlocks( clientId ), @@ -125,6 +108,7 @@ export default function QueryLoopEdit( { exclude, sticky, inherit, + templateSlug, ] ); diff --git a/packages/block-library/src/query/edit/index.js b/packages/block-library/src/query/edit/index.js index 45be4c7f88537..495c27f71012b 100644 --- a/packages/block-library/src/query/edit/index.js +++ b/packages/block-library/src/query/edit/index.js @@ -50,7 +50,7 @@ export function QueryContent( { if ( !! Object.keys( newQuery ).length ) { updateQuery( newQuery ); } - }, [ query.perPage, query.exclude, postId ] ); + }, [ query.perPage, query.exclude, query.inherit, postId ] ); // We need this for multi-query block pagination. // Query parameters for each block are scoped to their ID. useEffect( () => { diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index 6bf6e0751a356..204f75e9b0225 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -116,13 +116,9 @@ function Editor() { setIsEntitiesSavedStatesOpen( false ); }, [] ); - // Set default query for misplaced Query Loop blocks, and - // provide the root `queryContext` for top-level Query Loop - // and Query Pagination blocks. const blockContext = useMemo( () => ( { ...page?.context, - query: page?.context.query || { categoryIds: [], tagIds: [] }, queryContext: [ page?.context.queryContext || { page: 1 }, ( newQueryContext ) => diff --git a/packages/edit-site/src/components/navigation-sidebar/navigation-panel/template-navigation-item.js b/packages/edit-site/src/components/navigation-sidebar/navigation-panel/template-navigation-item.js index b63fc942368b9..f694b66bee668 100644 --- a/packages/edit-site/src/components/navigation-sidebar/navigation-panel/template-navigation-item.js +++ b/packages/edit-site/src/components/navigation-sidebar/navigation-panel/template-navigation-item.js @@ -32,7 +32,7 @@ export default function TemplateNavigationItem( { item } ) { const onActivateItem = () => 'wp_template' === item.type - ? setTemplate( item.id ) + ? setTemplate( item.id, item.slug ) : setTemplatePart( item.id ); return ( diff --git a/packages/edit-site/src/store/actions.js b/packages/edit-site/src/store/actions.js index 11866b4c430b0..c21db62c9420b 100644 --- a/packages/edit-site/src/store/actions.js +++ b/packages/edit-site/src/store/actions.js @@ -36,13 +36,25 @@ export function __experimentalSetPreviewDeviceType( deviceType ) { * Returns an action object used to set a template. * * @param {number} templateId The template ID. - * + * @param {string} templateSlug The template slug. * @return {Object} Action object. */ -export function setTemplate( templateId ) { +export function* setTemplate( templateId, templateSlug ) { + const pageContext = { templateSlug }; + if ( ! templateSlug ) { + const template = yield controls.resolveSelect( + 'core', + 'getEntityRecord', + 'postType', + 'wp_template', + templateId + ); + pageContext.templateSlug = template?.slug; + } return { type: 'SET_TEMPLATE', templateId, + page: { context: pageContext }, }; } @@ -64,6 +76,7 @@ export function* addTemplate( template ) { return { type: 'SET_TEMPLATE', templateId: newTemplate.id, + page: { context: { templateSlug: newTemplate.slug } }, }; } @@ -124,17 +137,25 @@ export function* setPage( page ) { if ( ! page.path && page.context?.postId ) { page.path = `?p=${ page.context.postId }`; } - const template = yield controls.resolveSelect( + const { id: templateId, slug: templateSlug } = yield controls.resolveSelect( 'core', '__experimentalGetTemplateForLink', page.path ); yield { type: 'SET_PAGE', - page, - templateId: template.id, + page: ! templateSlug + ? page + : { + ...page, + context: { + ...page.context, + templateSlug, + }, + }, + templateId, }; - return template.id; + return templateId; } /** diff --git a/packages/edit-site/src/store/test/actions.js b/packages/edit-site/src/store/test/actions.js index fac4c9a0ca737..0ad8fdb4af851 100644 --- a/packages/edit-site/src/store/test/actions.js +++ b/packages/edit-site/src/store/test/actions.js @@ -24,11 +24,30 @@ describe( 'actions', () => { } ); describe( 'setTemplate', () => { - it( 'should return the SET_TEMPLATE action', () => { + it( 'should return the SET_TEMPLATE action when slug is provided', () => { const templateId = 1; - expect( setTemplate( templateId ) ).toEqual( { + const templateSlug = 'archive'; + const it = setTemplate( templateId, templateSlug ); + expect( it.next().value ).toEqual( { + type: 'SET_TEMPLATE', + templateId, + page: { context: { templateSlug } }, + } ); + } ); + it( 'should return the SET_TEMPLATE by getting the template slug', () => { + const templateId = 1; + const template = { slug: 'index' }; + const it = setTemplate( templateId ); + expect( it.next().value ).toEqual( { + type: '@@data/RESOLVE_SELECT', + storeKey: 'core', + selectorName: 'getEntityRecord', + args: [ 'postType', 'wp_template', templateId ], + } ); + expect( it.next( template ).value ).toEqual( { type: 'SET_TEMPLATE', templateId, + page: { context: { templateSlug: template.slug } }, } ); } ); } ); @@ -36,7 +55,7 @@ describe( 'actions', () => { describe( 'addTemplate', () => { it( 'should yield the DISPATCH control to create the template and return the SET_TEMPLATE action', () => { const template = { slug: 'index' }; - const newTemplate = { id: 1 }; + const newTemplate = { id: 1, slug: 'index' }; const it = addTemplate( template ); expect( it.next().value ).toEqual( { @@ -49,6 +68,7 @@ describe( 'actions', () => { value: { type: 'SET_TEMPLATE', templateId: newTemplate.id, + page: { context: { templateSlug: newTemplate.slug } }, }, done: true, } ); From e92f868a44282ac14fe42a8f96896b6434c6d1b0 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 13 Jan 2021 13:15:41 +0100 Subject: [PATCH 24/76] Hide the theme without comments.php deprecation message (#28128) --- packages/block-library/src/post-comments/index.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/block-library/src/post-comments/index.php b/packages/block-library/src/post-comments/index.php index d9629c32f0e6f..7f15d83984ee4 100644 --- a/packages/block-library/src/post-comments/index.php +++ b/packages/block-library/src/post-comments/index.php @@ -25,10 +25,13 @@ function render_block_core_post_comments( $attributes, $content, $block ) { $post = get_post( $block->context['postId'] ); setup_postdata( $post ); - // This generates a deprecate message. - // Ideally this deprecation is removed. ob_start(); + // There's a deprecation warning generated by WP Core. + // Ideally this deprecation is removed from Core. + // In the meantime, this removes it from the output. + add_filter( 'deprecated_file_trigger_error', '__return_false' ); comments_template(); + remove_filter( 'deprecated_file_trigger_error', '__return_false' ); $post = $post_before; $classes = ''; @@ -37,8 +40,9 @@ function render_block_core_post_comments( $attributes, $content, $block ) { } $wrapper_attributes = get_block_wrapper_attributes( array( 'class' => $classes ) ); - $output = sprintf( '
', $wrapper_attributes ) . ob_get_clean() . '
'; - return $output; + $output = ob_get_clean(); + + return sprintf( '
%2$s
', $wrapper_attributes, $output ); } /** From fb57def299657b82d506236a42344c3d0ff5a275 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 13 Jan 2021 14:23:05 +0100 Subject: [PATCH 25/76] Bump plugin version to 9.7.2 --- changelog.txt | 11 +++++++++++ gutenberg.php | 2 +- package-lock.json | 2 +- package.json | 2 +- readme.txt | 2 +- 5 files changed, 15 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 3e5a2be0847f3..b281976974e0e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,16 @@ == Changelog == += 9.7.2 = + +### Bug Fixes + +- Keep the inserter opened when clicking the scrollbar. + +### Various + +- Updated the "tested up to" WordPress version. + + = 9.7.1 = ### Bug Fixes diff --git a/gutenberg.php b/gutenberg.php index 31f6f4bc85051..255fa5e351c18 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.3 * Requires PHP: 5.6 - * Version: 9.7.1 + * Version: 9.7.2 * Author: Gutenberg Team * Text Domain: gutenberg * diff --git a/package-lock.json b/package-lock.json index f2cab8c1789e1..d1ee74be0a99e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "9.7.1", + "version": "9.7.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index b686333a700d4..76abf478d3db9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "9.7.1", + "version": "9.7.2", "private": true, "description": "A new WordPress editor experience.", "author": "The WordPress Contributors", diff --git a/readme.txt b/readme.txt index 8f0edaa935afb..ec9bb2d29843b 100644 --- a/readme.txt +++ b/readme.txt @@ -57,4 +57,4 @@ View release page. +To read the changelog for Gutenberg 9.7.2, please navigate to the release page. From 66a8a8a4d30026bd2b3a01f8d75be7d00fb85aa2 Mon Sep 17 00:00:00 2001 From: Shaun Andrews Date: Wed, 13 Jan 2021 11:27:39 -0500 Subject: [PATCH 26/76] Making the sidebar inspector's tabs stick when scrolling. (#28003) When scrolling the editor's inspector sidebar, the tabs at the top (post/page and block) will now "stick" to the top of the sidebar as you scroll. --- .../src/components/layout/style.scss | 5 --- .../components/complementary-area/style.scss | 42 +++++-------------- .../components/interface-skeleton/style.scss | 3 +- 3 files changed, 13 insertions(+), 37 deletions(-) diff --git a/packages/edit-post/src/components/layout/style.scss b/packages/edit-post/src/components/layout/style.scss index dfb1dc7fc4c2a..e2c3a144674b5 100644 --- a/packages/edit-post/src/components/layout/style.scss +++ b/packages/edit-post/src/components/layout/style.scss @@ -57,11 +57,6 @@ } } -.interface-interface-skeleton__sidebar > div { - height: 100%; - padding-bottom: $grid-unit-60; -} - .edit-post-layout .editor-post-publish-panel__header-publish-button { justify-content: center; } diff --git a/packages/interface/src/components/complementary-area/style.scss b/packages/interface/src/components/complementary-area/style.scss index 33be1f4c204f8..510b0006766fa 100644 --- a/packages/interface/src/components/complementary-area/style.scss +++ b/packages/interface/src/components/complementary-area/style.scss @@ -1,12 +1,8 @@ .interface-complementary-area { background: $white; color: $gray-900; - overflow: visible; @include break-small() { - z-index: auto; - height: 100%; - overflow: auto; -webkit-overflow-scrolling: touch; } @@ -14,37 +10,21 @@ width: $sidebar-width; } - > .components-panel { - border-left: none; - border-right: none; - overflow: auto; - -webkit-overflow-scrolling: touch; - height: auto; - max-height: calc(100vh - #{ $admin-bar-height-big + $panel-header-height + $panel-header-height }); - margin-top: -1px; - margin-bottom: -1px; - position: relative; - - @include break-small() { - overflow: visible; - height: auto; - max-height: none; - } + .components-panel { + border: none; } - > .components-panel .components-panel__header { - position: fixed; - z-index: z-index(".components-panel__header"); + .components-panel__header { + position: sticky; top: 0; - left: 0; - right: 0; - height: $panel-header-height; + z-index: z-index(".components-panel__header"); + + &.edit-post-sidebar__panel-tabs { + top: $panel-header-height; - @include break-small() { - position: inherit; - top: auto; - left: auto; - right: auto; + @include break-medium() { + top: 0; + } } } diff --git a/packages/interface/src/components/interface-skeleton/style.scss b/packages/interface/src/components/interface-skeleton/style.scss index 5d10bd9cb0337..9452ab5b2139f 100644 --- a/packages/interface/src/components/interface-skeleton/style.scss +++ b/packages/interface/src/components/interface-skeleton/style.scss @@ -106,8 +106,9 @@ html.interface-interface-skeleton__html-container { } .interface-interface-skeleton__sidebar { + overflow: auto; + @include break-medium() { - overflow: auto; border-left: $border-width solid $gray-200; } } From 556505024833dd815dbc365e75c2279f003cd472 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 13 Jan 2021 17:34:48 +0100 Subject: [PATCH 27/76] Delete unused options (#28164) --- lib/upgrade.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/upgrade.php b/lib/upgrade.php index fe80cc0b7e89e..2573ed6d575da 100644 --- a/lib/upgrade.php +++ b/lib/upgrade.php @@ -53,6 +53,10 @@ function _gutenberg_migrate_remove_fse_drafts() { if ( $term ) { wp_delete_term( $term->term_id, 'wp-theme' ); } + + // Delete useless options. + delete_option( 'gutenberg_last_synchronize_theme_template_checks' ); + delete_option( 'gutenberg_last_synchronize_theme_template-part_checks' ); } add_action( 'plugins_loaded', '_gutenberg_migrate_database' ); From cfe936aeee74ec4204962ae84ea5d6badc17a4e4 Mon Sep 17 00:00:00 2001 From: Joel Dean Date: Wed, 13 Jan 2021 12:34:31 -0500 Subject: [PATCH 28/76] increased driver sleep on Android to reduce test flakiness. (#28000) --- .../gutenberg-editor-file-@canary.test.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/react-native-editor/__device-tests__/gutenberg-editor-file-@canary.test.js b/packages/react-native-editor/__device-tests__/gutenberg-editor-file-@canary.test.js index 997605a454d01..8f6857f493625 100644 --- a/packages/react-native-editor/__device-tests__/gutenberg-editor-file-@canary.test.js +++ b/packages/react-native-editor/__device-tests__/gutenberg-editor-file-@canary.test.js @@ -3,6 +3,7 @@ */ import { blockNames } from './pages/editor-page'; import testData from './helpers/test-data'; +import { isAndroid } from './helpers/utils'; describe( 'Gutenberg Editor File Block tests', () => { it( 'should be able to add a file block', async () => { @@ -15,7 +16,13 @@ describe( 'Gutenberg Editor File Block tests', () => { const block = await editorPage.getFirstBlockVisible(); block.click(); - await editorPage.driver.sleep( 1000 ); + + if ( isAndroid ) { + await editorPage.driver.sleep( 5000 ); + } else { + await editorPage.driver.sleep( 1000 ); + } + await editorPage.chooseMediaLibrary(); const html = await editorPage.getHtmlContent(); From c963e4cc423f805898fab392f7135d9e8f52120c Mon Sep 17 00:00:00 2001 From: Alex Lende Date: Wed, 13 Jan 2021 10:55:34 -0700 Subject: [PATCH 29/76] Add srcset for cover image (#25171) --- lib/client-assets.php | 34 +++++ packages/base-styles/_z-index.scss | 1 + .../block-library/src/cover/deprecated.js | 130 ++++++++++++++++++ packages/block-library/src/cover/edit.js | 47 +++---- packages/block-library/src/cover/editor.scss | 6 + packages/block-library/src/cover/save.js | 62 +++++---- packages/block-library/src/cover/style.scss | 13 +- .../fixtures/blocks/core__cover.html | 6 +- .../fixtures/blocks/core__cover.json | 2 +- .../fixtures/blocks/core__cover.parsed.json | 4 +- .../blocks/core__cover.serialized.html | 2 +- .../core__cover__deprecated-1.serialized.html | 2 +- .../core__cover__deprecated-2.serialized.html | 2 +- .../core__cover__deprecated-3.serialized.html | 2 +- .../core__cover__deprecated-4.serialized.html | 2 +- .../core__cover__deprecated-5.serialized.html | 2 +- .../blocks/core__cover__deprecated-6.html | 14 ++ .../blocks/core__cover__deprecated-6.json | 32 +++++ .../core__cover__deprecated-6.parsed.json | 39 ++++++ .../core__cover__deprecated-6.serialized.html | 7 + .../blocks/core__cover__gradient-image.html | 3 +- .../blocks/core__cover__gradient-image.json | 2 +- .../core__cover__gradient-image.parsed.json | 4 +- ...ore__cover__gradient-image.serialized.html | 2 +- .../blocks/core__cover__gradient-video.html | 2 +- .../blocks/core__cover__gradient-video.json | 2 +- .../core__cover__gradient-video.parsed.json | 4 +- ...ore__cover__gradient-video.serialized.html | 2 +- .../blocks/core__cover__video-overlay.html | 3 +- .../blocks/core__cover__video-overlay.json | 2 +- .../core__cover__video-overlay.parsed.json | 4 +- ...core__cover__video-overlay.serialized.html | 2 +- .../fixtures/blocks/core__cover__video.html | 3 +- .../fixtures/blocks/core__cover__video.json | 2 +- .../blocks/core__cover__video.parsed.json | 4 +- .../blocks/core__cover__video.serialized.html | 2 +- 36 files changed, 361 insertions(+), 91 deletions(-) create mode 100644 packages/e2e-tests/fixtures/blocks/core__cover__deprecated-6.html create mode 100644 packages/e2e-tests/fixtures/blocks/core__cover__deprecated-6.json create mode 100644 packages/e2e-tests/fixtures/blocks/core__cover__deprecated-6.parsed.json create mode 100644 packages/e2e-tests/fixtures/blocks/core__cover__deprecated-6.serialized.html diff --git a/lib/client-assets.php b/lib/client-assets.php index 54c5f41d4d3a3..77c0c5fd40ce2 100644 --- a/lib/client-assets.php +++ b/lib/client-assets.php @@ -234,6 +234,14 @@ function gutenberg_register_vendor_scripts( $scripts ) { '4.17.19', true ); + + gutenberg_register_vendor_script( + $scripts, + 'object-fit-polyfill', + 'https://unpkg.com/objectFitPolyfill@2.3.0/dist/objectFitPolyfill.min.js', + array(), + '2.3.0' + ); } add_action( 'wp_default_scripts', 'gutenberg_register_vendor_scripts' ); @@ -706,3 +714,29 @@ function gutenberg_extend_block_editor_styles_html() { echo ""; } add_action( 'admin_footer-toplevel_page_gutenberg-edit-site', 'gutenberg_extend_block_editor_styles_html' ); + +/** + * Adds a polyfill for object-fit in environments which do not support it. + * + * The script registration occurs in `gutenberg_register_vendor_scripts`, which + * should be removed in coordination with this function. + * + * @see gutenberg_register_vendor_scripts + * @see https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit + * + * @since 9.1.0 + * + * @param WP_Scripts $scripts WP_Scripts object. + */ +function gutenberg_add_object_fit_polyfill( $scripts ) { + did_action( 'init' ) && $scripts->add_inline_script( + 'wp-polyfill', + wp_get_script_polyfill( + $scripts, + array( + '"objectFit" in document.documentElement.style' => 'object-fit-polyfill', + ) + ) + ); +} +add_action( 'wp_default_scripts', 'gutenberg_add_object_fit_polyfill', 20 ); diff --git a/packages/base-styles/_z-index.scss b/packages/base-styles/_z-index.scss index 14c40bdeebd86..630323a871348 100644 --- a/packages/base-styles/_z-index.scss +++ b/packages/base-styles/_z-index.scss @@ -32,6 +32,7 @@ $z-layers: ( ".block-library-button__inline-link .block-editor-url-input__suggestions": 6, // URL suggestions for button block above sibling inserter ".wp-block-cover__inner-container": 1, // InnerBlocks area inside cover image block ".wp-block-cover.has-background-dim::before": 1, // Overlay area inside block cover need to be higher than the video background. + ".wp-block-cover__image-background": 0, // Image background inside cover block. ".wp-block-cover__video-background": 0, // Video background inside cover block. ".wp-block-template-part__placeholder-preview-filter-input": 1, diff --git a/packages/block-library/src/cover/deprecated.js b/packages/block-library/src/cover/deprecated.js index 44effb065bfbf..fe08fb9cd72a8 100644 --- a/packages/block-library/src/cover/deprecated.js +++ b/packages/block-library/src/cover/deprecated.js @@ -24,6 +24,8 @@ import { VIDEO_BACKGROUND_TYPE, backgroundImageStyles, dimRatioToClass, + getPositionClassName, + isContentPositionCenter, } from './shared'; const blockAttributes = { @@ -57,6 +59,134 @@ const blockAttributes = { }; const deprecated = [ + { + attributes: { + ...blockAttributes, + title: { + type: 'string', + source: 'html', + selector: 'p', + }, + contentAlign: { + type: 'string', + default: 'center', + }, + minHeight: { + type: 'number', + }, + gradient: { + type: 'string', + }, + customGradient: { + type: 'string', + }, + }, + save( { attributes } ) { + const { + backgroundType, + gradient, + contentPosition, + customGradient, + customOverlayColor, + dimRatio, + focalPoint, + hasParallax, + overlayColor, + url, + minHeight: minHeightProp, + minHeightUnit, + } = attributes; + const overlayColorClass = getColorClassName( + 'background-color', + overlayColor + ); + const gradientClass = __experimentalGetGradientClass( gradient ); + const minHeight = minHeightUnit + ? `${ minHeightProp }${ minHeightUnit }` + : minHeightProp; + + const isImageBackground = IMAGE_BACKGROUND_TYPE === backgroundType; + const isVideoBackground = VIDEO_BACKGROUND_TYPE === backgroundType; + + const style = isImageBackground ? backgroundImageStyles( url ) : {}; + const videoStyle = {}; + + if ( ! overlayColorClass ) { + style.backgroundColor = customOverlayColor; + } + + if ( customGradient && ! url ) { + style.background = customGradient; + } + style.minHeight = minHeight || undefined; + + let positionValue; + + if ( focalPoint ) { + positionValue = `${ Math.round( + focalPoint.x * 100 + ) }% ${ Math.round( focalPoint.y * 100 ) }%`; + + if ( isImageBackground && ! hasParallax ) { + style.backgroundPosition = positionValue; + } + + if ( isVideoBackground ) { + videoStyle.objectPosition = positionValue; + } + } + + const classes = classnames( + dimRatioToClass( dimRatio ), + overlayColorClass, + { + 'has-background-dim': dimRatio !== 0, + 'has-parallax': hasParallax, + 'has-background-gradient': gradient || customGradient, + [ gradientClass ]: ! url && gradientClass, + 'has-custom-content-position': ! isContentPositionCenter( + contentPosition + ), + }, + getPositionClassName( contentPosition ) + ); + + return ( +
+ { url && + ( gradient || customGradient ) && + dimRatio !== 0 && ( +
+ ); + }, + }, { attributes: { ...blockAttributes, diff --git a/packages/block-library/src/cover/edit.js b/packages/block-library/src/cover/edit.js index 00ea5c4663320..d9b685ed300aa 100644 --- a/packages/block-library/src/cover/edit.js +++ b/packages/block-library/src/cover/edit.js @@ -331,23 +331,21 @@ function CoverEdit( { : minHeight; const style = { - ...( isImageBackground ? backgroundImageStyles( url ) : {} ), + ...( isImageBackground && hasParallax + ? backgroundImageStyles( url ) + : {} ), backgroundColor: overlayColor.color, + background: gradientValue && ! url ? gradientValue : undefined, minHeight: temporaryMinHeight || minHeightWithUnit || undefined, }; - if ( gradientValue && ! url ) { - style.background = gradientValue; - } - - let positionValue; - - if ( focalPoint ) { - positionValue = `${ focalPoint.x * 100 }% ${ focalPoint.y * 100 }%`; - if ( isImageBackground ) { - style.backgroundPosition = positionValue; - } - } + const mediaStyle = { + objectPosition: + // prettier-ignore + focalPoint && ! hasParallax + ? `${ Math.round( focalPoint.x * 100 ) }% ${ Math.round( focalPoint.y * 100) }%` + : undefined, + }; const hasBackground = !! ( url || overlayColor.color || gradientValue ); const showFocalPointPicker = @@ -587,18 +585,6 @@ function CoverEdit( { } } showHandle={ isSelected } /> - { isImageBackground && ( - // Used only to programmatically check if the image is dark or not - - ) } { url && gradientValue && dimRatio !== 0 && (