From c8eb847a1b78bb84d126f3acff1819bb24755299 Mon Sep 17 00:00:00 2001 From: Jon Desrosiers Date: Tue, 6 Apr 2021 02:18:00 -0400 Subject: [PATCH 001/125] Update the objectFitPolyfill. (#30507) --- lib/client-assets.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/client-assets.php b/lib/client-assets.php index 6ffb733fc6a9b2..c1814fc858385c 100644 --- a/lib/client-assets.php +++ b/lib/client-assets.php @@ -217,9 +217,9 @@ function gutenberg_register_vendor_scripts( $scripts ) { gutenberg_register_vendor_script( $scripts, 'object-fit-polyfill', - 'https://unpkg.com/objectFitPolyfill@2.3.0/dist/objectFitPolyfill.min.js', + 'https://unpkg.com/objectFitPolyfill@2.3.5/dist/objectFitPolyfill.min.js', array(), - '2.3.0' + '2.3.5' ); } add_action( 'wp_default_scripts', 'gutenberg_register_vendor_scripts' ); From 176748c729522cb09191246ddc9678acf0bd5000 Mon Sep 17 00:00:00 2001 From: Nik Tsekouras Date: Tue, 6 Apr 2021 10:19:57 +0300 Subject: [PATCH 002/125] Fix Post Excerpt warnings for inline elements in RichText (#30498) --- .../block-library/src/post-excerpt/block.json | 3 +- .../block-library/src/post-excerpt/edit.js | 33 ++++++++----------- .../block-library/src/post-excerpt/index.php | 10 +++--- .../block-library/src/post-excerpt/style.scss | 3 ++ packages/block-library/src/style.scss | 1 + 5 files changed, 25 insertions(+), 25 deletions(-) create mode 100644 packages/block-library/src/post-excerpt/style.scss diff --git a/packages/block-library/src/post-excerpt/block.json b/packages/block-library/src/post-excerpt/block.json index 2e2690d398625f..a1e3a1bc7be4df 100644 --- a/packages/block-library/src/post-excerpt/block.json +++ b/packages/block-library/src/post-excerpt/block.json @@ -31,5 +31,6 @@ }, "lineHeight": true }, - "editorStyle": "wp-block-post-excerpt-editor" + "editorStyle": "wp-block-post-excerpt-editor", + "style": "wp-block-post-excerpt" } diff --git a/packages/block-library/src/post-excerpt/edit.js b/packages/block-library/src/post-excerpt/edit.js index 749a988e7ed55f..f515b992b423f4 100644 --- a/packages/block-library/src/post-excerpt/edit.js +++ b/packages/block-library/src/post-excerpt/edit.js @@ -72,7 +72,18 @@ export default function PostExcerptEditor( { ); } - + const readMoreLink = ( + + setAttributes( { moreText: newMoreText } ) + } + /> + ); return ( <> @@ -124,26 +135,10 @@ export default function PostExcerptEditor( { { ! showMoreOnNewLine && ' ' } { showMoreOnNewLine ? (

- - setAttributes( { moreText: newMoreText } ) - } - /> + { readMoreLink }

) : ( - - setAttributes( { moreText: newMoreText } ) - } - /> + readMoreLink ) } diff --git a/packages/block-library/src/post-excerpt/index.php b/packages/block-library/src/post-excerpt/index.php index cf84a2341a1355..c2a0e9d27f561e 100644 --- a/packages/block-library/src/post-excerpt/index.php +++ b/packages/block-library/src/post-excerpt/index.php @@ -18,7 +18,7 @@ function render_block_core_post_excerpt( $attributes, $content, $block ) { return ''; } - $more_text = isset( $attributes['moreText'] ) ? '' . $attributes['moreText'] . '' : ''; + $more_text = isset( $attributes['moreText'] ) ? '' . $attributes['moreText'] . '' : ''; $filter_excerpt_length = function() use ( $attributes ) { return isset( $attributes['wordCount'] ) ? $attributes['wordCount'] : 55; @@ -34,11 +34,11 @@ function render_block_core_post_excerpt( $attributes, $content, $block ) { } $wrapper_attributes = get_block_wrapper_attributes( array( 'class' => $classes ) ); - $output = sprintf( '
', $wrapper_attributes ) . '

' . get_the_excerpt( $block->context['postId'] ); + $content = '

' . get_the_excerpt( $block->context['postId'] ); if ( ! isset( $attributes['showMoreOnNewLine'] ) || $attributes['showMoreOnNewLine'] ) { - $output .= '

' . '

' . $more_text . '

'; + $content .= '

' . $more_text . '

'; } else { - $output .= ' ' . $more_text . '

' . ''; + $content .= " $more_text

"; } remove_filter( @@ -46,7 +46,7 @@ function render_block_core_post_excerpt( $attributes, $content, $block ) { $filter_excerpt_length ); - return $output; + return sprintf( '
%2$s
', $wrapper_attributes, $content ); } /** diff --git a/packages/block-library/src/post-excerpt/style.scss b/packages/block-library/src/post-excerpt/style.scss new file mode 100644 index 00000000000000..e7b3e18491177e --- /dev/null +++ b/packages/block-library/src/post-excerpt/style.scss @@ -0,0 +1,3 @@ +.wp-block-post-excerpt__more-link { + display: inline-block; +} diff --git a/packages/block-library/src/style.scss b/packages/block-library/src/style.scss index 61735577c88258..50a06336c25b62 100644 --- a/packages/block-library/src/style.scss +++ b/packages/block-library/src/style.scss @@ -27,6 +27,7 @@ @import "./paragraph/style.scss"; @import "./post-author/style.scss"; @import "./post-comments-form/style.scss"; +@import "./post-excerpt/style.scss"; @import "./preformatted/style.scss"; @import "./pullquote/style.scss"; @import "./query-loop/style.scss"; From f2fb0b9966ef0d55a9ffd7313233f1337eb70cc8 Mon Sep 17 00:00:00 2001 From: Joen A <1204802+jasmussen@users.noreply.github.com> Date: Tue, 6 Apr 2021 10:20:53 +0200 Subject: [PATCH 003/125] Fix fullwide regression. (#30520) --- packages/block-library/src/reset.scss | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/block-library/src/reset.scss b/packages/block-library/src/reset.scss index 2890fde40b8a0d..8e9894f81b14f4 100644 --- a/packages/block-library/src/reset.scss +++ b/packages/block-library/src/reset.scss @@ -17,10 +17,11 @@ line-height: initial; color: initial; - // For full-wide blocks, we compensate for these 10px. + // For full-wide blocks, we compensate for the base padding. + // These margins should match the padding value above. .block-editor-block-list__layout.is-root-container > .wp-block[data-align="full"] { - margin-left: -10px; - margin-right: -10px; + margin-left: -8px; + margin-right: -8px; } .wp-align-wrapper { From b5293ff7ceddea77f18d56357fe2cc7251a8beb4 Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Tue, 6 Apr 2021 10:08:11 +0200 Subject: [PATCH 004/125] Update changelog files --- packages/api-fetch/CHANGELOG.md | 2 ++ packages/api-fetch/package.json | 2 +- packages/babel-preset-default/CHANGELOG.md | 2 ++ packages/babel-preset-default/package.json | 2 +- packages/create-block-tutorial-template/CHANGELOG.md | 2 ++ packages/create-block-tutorial-template/package.json | 2 +- packages/create-block/CHANGELOG.md | 2 ++ packages/create-block/package.json | 2 +- packages/date/CHANGELOG.md | 2 ++ packages/date/package.json | 2 +- packages/interface/CHANGELOG.md | 2 ++ packages/interface/package.json | 2 +- packages/scripts/CHANGELOG.md | 2 ++ packages/scripts/package.json | 2 +- 14 files changed, 21 insertions(+), 7 deletions(-) diff --git a/packages/api-fetch/CHANGELOG.md b/packages/api-fetch/CHANGELOG.md index b69ef5840fe9e4..713c493ab63115 100644 --- a/packages/api-fetch/CHANGELOG.md +++ b/packages/api-fetch/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.23.0 (2021-04-06) + ### New Feature - Publish TypeScript definitions. diff --git a/packages/api-fetch/package.json b/packages/api-fetch/package.json index d19dedf66ab44d..c608af64bafd55 100644 --- a/packages/api-fetch/package.json +++ b/packages/api-fetch/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/api-fetch", - "version": "3.22.0", + "version": "3.23.0-prerelease", "description": "Utility to make WordPress REST API requests.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/babel-preset-default/CHANGELOG.md b/packages/babel-preset-default/CHANGELOG.md index b966b9757147ea..d8f5f0130a2c2a 100644 --- a/packages/babel-preset-default/CHANGELOG.md +++ b/packages/babel-preset-default/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.2.0 (2021-04-06) + ### Enhancements - The bundled `@babel/core` dependency has been updated from requiring `^7.12.9` to requiring `^7.13.10` ([#30018](https://github.com/WordPress/gutenberg/pull/30018)). diff --git a/packages/babel-preset-default/package.json b/packages/babel-preset-default/package.json index 9757bf5caa02fd..52e24d2d97fb36 100644 --- a/packages/babel-preset-default/package.json +++ b/packages/babel-preset-default/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-preset-default", - "version": "5.1.0", + "version": "5.2.0-prerelease", "description": "Default Babel preset for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/create-block-tutorial-template/CHANGELOG.md b/packages/create-block-tutorial-template/CHANGELOG.md index 004a0c6cacbda9..1044355d6a91c2 100644 --- a/packages/create-block-tutorial-template/CHANGELOG.md +++ b/packages/create-block-tutorial-template/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 1.2.0 (2021-04-06) + ### Enhancement - Scaffolded plugin requires WordPress 5.7 now ([#29757](https://github.com/WordPress/gutenberg/pull/29757). diff --git a/packages/create-block-tutorial-template/package.json b/packages/create-block-tutorial-template/package.json index 5a60c5887d3099..4c846606b470d8 100644 --- a/packages/create-block-tutorial-template/package.json +++ b/packages/create-block-tutorial-template/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/create-block-tutorial-template", - "version": "1.1.0", + "version": "1.2.0-prerelease", "description": "Template for @wordpress/create-block used in the official WordPress tutorial.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/create-block/CHANGELOG.md b/packages/create-block/CHANGELOG.md index 0f1f8eb155ee95..f5f440220b8c0b 100644 --- a/packages/create-block/CHANGELOG.md +++ b/packages/create-block/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 2.2.0 (2021-04-06) + ### Enhancement - Scaffolded plugin requires WordPress 5.7 now ([#29757](https://github.com/WordPress/gutenberg/pull/29757)). diff --git a/packages/create-block/package.json b/packages/create-block/package.json index c42d64d4b29329..7c6df7aa7d5a73 100644 --- a/packages/create-block/package.json +++ b/packages/create-block/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/create-block", - "version": "2.1.0", + "version": "2.2.0-prerelease", "description": "Generates PHP, JS and CSS code for registering a block for a WordPress plugin.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/date/CHANGELOG.md b/packages/date/CHANGELOG.md index 831375aefd6a12..37d9c84498cbd6 100644 --- a/packages/date/CHANGELOG.md +++ b/packages/date/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.15.0 (2021-04-06) + ### New Feature - Bundle type definitions. diff --git a/packages/date/package.json b/packages/date/package.json index 94df3dbcfbd620..ef0ef2a082f334 100644 --- a/packages/date/package.json +++ b/packages/date/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/date", - "version": "3.14.0", + "version": "3.15.0-prerelease", "description": "Date module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/interface/CHANGELOG.md b/packages/interface/CHANGELOG.md index 8fe1eb16ff1a96..13392b234397a4 100644 --- a/packages/interface/CHANGELOG.md +++ b/packages/interface/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 2.0.0 (2021-04-06) + ### Breaking Changes - Passing a tuple of components with `as` prop to `ActionItem.Slot` component is no longer supported. Please pass a component with `as` prop instead ([#30417](https://github.com/WordPress/gutenberg/pull/30417)). diff --git a/packages/interface/package.json b/packages/interface/package.json index cb73744455a39b..578d7d83d5e923 100644 --- a/packages/interface/package.json +++ b/packages/interface/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/interface", - "version": "1.1.0", + "version": "2.0.0-prerelease", "description": "Interface module for WordPress. The package contains shared functionality across the modern JavaScript-based WordPress screens.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/scripts/CHANGELOG.md b/packages/scripts/CHANGELOG.md index d246897734a572..7ca1dce263b8bb 100644 --- a/packages/scripts/CHANGELOG.md +++ b/packages/scripts/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 14.1.0 (2021-04-06) + ### Enhancements - The bundled `babel-loader` dependency has been updated from requiring `^8.1.0` to requiring `^8.2.2` ([#30018](https://github.com/WordPress/gutenberg/pull/30018)). diff --git a/packages/scripts/package.json b/packages/scripts/package.json index c2573c916e54dc..3b59a505f3f61e 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/scripts", - "version": "14.0.1", + "version": "14.1.0-prerelease", "description": "Collection of reusable scripts for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", From 899286307be533a5643dd1dc168f32d92a204b64 Mon Sep 17 00:00:00 2001 From: Grzegorz Ziolkowski Date: Tue, 6 Apr 2021 10:12:10 +0200 Subject: [PATCH 005/125] chore(release): publish - @wordpress/a11y@2.15.1 - @wordpress/annotations@1.25.1 - @wordpress/api-fetch@3.23.0 - @wordpress/autop@2.12.1 - @wordpress/babel-plugin-import-jsx-pragma@3.0.2 - @wordpress/babel-plugin-makepot@4.1.1 - @wordpress/babel-preset-default@5.2.0 - @wordpress/base-styles@3.4.1 - @wordpress/blob@2.13.1 - @wordpress/block-directory@1.19.1 - @wordpress/block-editor@5.3.1 - @wordpress/block-library@2.29.1 - @wordpress/block-serialization-default-parser@3.10.1 - @wordpress/block-serialization-spec-parser@3.8.1 - @wordpress/blocks@8.0.1 - @wordpress/browserslist-config@3.0.2 - @wordpress/components@13.0.1 - @wordpress/compose@3.25.1 - @wordpress/core-data@2.26.1 - @wordpress/create-block-tutorial-template@1.2.0 - @wordpress/create-block@2.2.0 - @wordpress/custom-templated-path-webpack-plugin@2.0.2 - @wordpress/data-controls@1.21.1 - @wordpress/data@4.27.1 - @wordpress/date@3.15.0 - @wordpress/dependency-extraction-webpack-plugin@3.1.1 - @wordpress/deprecated@2.12.1 - @wordpress/docgen@1.16.1 - @wordpress/dom-ready@2.13.1 - @wordpress/dom@2.17.1 - @wordpress/e2e-test-utils@5.1.1 - @wordpress/e2e-tests@2.1.2 - @wordpress/edit-post@3.27.1 - @wordpress/edit-site@1.17.1 - @wordpress/edit-widgets@1.3.1 - @wordpress/editor@9.26.1 - @wordpress/element@2.20.1 - @wordpress/env@4.0.1 - @wordpress/escape-html@1.12.1 - @wordpress/eslint-plugin@9.0.2 - @wordpress/format-library@1.27.1 - @wordpress/hooks@2.12.1 - @wordpress/html-entities@2.11.1 - @wordpress/i18n@3.19.1 - @wordpress/icons@2.10.1 - @wordpress/interface@2.0.0 - @wordpress/is-shallow-equal@3.1.1 - @wordpress/jest-console@4.0.2 - @wordpress/jest-preset-default@7.0.2 - @wordpress/jest-puppeteer-axe@3.0.2 - @wordpress/keyboard-shortcuts@1.14.1 - @wordpress/keycodes@2.19.1 - @wordpress/lazy-import@1.2.2 - @wordpress/library-export-default-webpack-plugin@2.0.2 - @wordpress/list-reusable-blocks@1.26.1 - @wordpress/media-utils@1.20.1 - @wordpress/notices@2.13.1 - @wordpress/npm-package-json-lint-config@4.0.2 - @wordpress/nux@3.25.1 - @wordpress/plugins@2.25.1 - @wordpress/postcss-plugins-preset@2.1.1 - @wordpress/postcss-themes@3.0.2 - @wordpress/prettier-config@1.0.2 - @wordpress/primitives@1.12.1 - @wordpress/priority-queue@1.11.1 - @wordpress/project-management-automation@1.12.1 - @wordpress/react-i18n@1.0.1 - @wordpress/redux-routine@3.14.1 - @wordpress/reusable-blocks@1.2.1 - @wordpress/rich-text@3.25.1 - @wordpress/scripts@14.1.0 - @wordpress/server-side-render@1.21.1 - @wordpress/shortcode@2.13.1 - @wordpress/stylelint-config@19.0.2 - @wordpress/token-list@1.15.1 - @wordpress/url@2.22.1 - @wordpress/viewport@2.26.1 - @wordpress/warning@1.4.1 - @wordpress/wordcount@2.15.1 --- packages/a11y/package.json | 2 +- packages/annotations/package.json | 2 +- packages/api-fetch/package.json | 2 +- packages/autop/package.json | 2 +- packages/babel-plugin-import-jsx-pragma/package.json | 2 +- packages/babel-plugin-makepot/package.json | 2 +- packages/babel-preset-default/package.json | 2 +- packages/base-styles/package.json | 2 +- packages/blob/package.json | 2 +- packages/block-directory/package.json | 2 +- packages/block-editor/package.json | 2 +- packages/block-library/package.json | 2 +- packages/block-serialization-default-parser/package.json | 2 +- packages/block-serialization-spec-parser/package.json | 2 +- packages/blocks/package.json | 2 +- packages/browserslist-config/package.json | 2 +- packages/components/package.json | 2 +- packages/compose/package.json | 2 +- packages/core-data/package.json | 2 +- packages/create-block-tutorial-template/package.json | 2 +- packages/create-block/package.json | 2 +- packages/custom-templated-path-webpack-plugin/package.json | 2 +- packages/data-controls/package.json | 2 +- packages/data/package.json | 2 +- packages/date/package.json | 2 +- packages/dependency-extraction-webpack-plugin/package.json | 2 +- packages/deprecated/package.json | 2 +- packages/docgen/package.json | 2 +- packages/dom-ready/package.json | 2 +- packages/dom/package.json | 2 +- packages/e2e-test-utils/package.json | 2 +- packages/e2e-tests/package.json | 2 +- packages/edit-post/package.json | 2 +- packages/edit-site/package.json | 2 +- packages/edit-widgets/package.json | 2 +- packages/editor/package.json | 2 +- packages/element/package.json | 2 +- packages/env/package.json | 2 +- packages/escape-html/package.json | 2 +- packages/eslint-plugin/package.json | 2 +- packages/format-library/package.json | 2 +- packages/hooks/package.json | 2 +- packages/html-entities/package.json | 2 +- packages/i18n/package.json | 2 +- packages/icons/package.json | 2 +- packages/interface/package.json | 2 +- packages/is-shallow-equal/package.json | 2 +- packages/jest-console/package.json | 2 +- packages/jest-preset-default/package.json | 2 +- packages/jest-puppeteer-axe/package.json | 2 +- packages/keyboard-shortcuts/package.json | 2 +- packages/keycodes/package.json | 2 +- packages/lazy-import/package.json | 2 +- packages/library-export-default-webpack-plugin/package.json | 2 +- packages/list-reusable-blocks/package.json | 2 +- packages/media-utils/package.json | 2 +- packages/notices/package.json | 2 +- packages/npm-package-json-lint-config/package.json | 2 +- packages/nux/package.json | 2 +- packages/plugins/package.json | 2 +- packages/postcss-plugins-preset/package.json | 2 +- packages/postcss-themes/package.json | 2 +- packages/prettier-config/package.json | 2 +- packages/primitives/package.json | 2 +- packages/priority-queue/package.json | 2 +- packages/project-management-automation/package.json | 2 +- packages/react-i18n/package.json | 2 +- packages/redux-routine/package.json | 2 +- packages/reusable-blocks/package.json | 2 +- packages/rich-text/package.json | 2 +- packages/scripts/package.json | 2 +- packages/server-side-render/package.json | 2 +- packages/shortcode/package.json | 2 +- packages/stylelint-config/package.json | 2 +- packages/token-list/package.json | 2 +- packages/url/package.json | 2 +- packages/viewport/package.json | 2 +- packages/warning/package.json | 2 +- packages/wordcount/package.json | 2 +- 79 files changed, 79 insertions(+), 79 deletions(-) diff --git a/packages/a11y/package.json b/packages/a11y/package.json index 90a10c4e5172f4..c7d0fb8216b510 100644 --- a/packages/a11y/package.json +++ b/packages/a11y/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/a11y", - "version": "2.15.0", + "version": "2.15.1", "description": "Accessibility (a11y) utilities for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/annotations/package.json b/packages/annotations/package.json index 88aa5eb0bc0a82..a8fbd8d65f1f74 100644 --- a/packages/annotations/package.json +++ b/packages/annotations/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/annotations", - "version": "1.25.0", + "version": "1.25.1", "description": "Annotate content in the Gutenberg editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/api-fetch/package.json b/packages/api-fetch/package.json index c608af64bafd55..4a253d7c61181a 100644 --- a/packages/api-fetch/package.json +++ b/packages/api-fetch/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/api-fetch", - "version": "3.23.0-prerelease", + "version": "3.23.0", "description": "Utility to make WordPress REST API requests.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/autop/package.json b/packages/autop/package.json index b798cca499b356..2b496fdfc98e43 100644 --- a/packages/autop/package.json +++ b/packages/autop/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/autop", - "version": "2.12.0", + "version": "2.12.1", "description": "WordPress's automatic paragraph functions `autop` and `removep`.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/babel-plugin-import-jsx-pragma/package.json b/packages/babel-plugin-import-jsx-pragma/package.json index 911417bd509ca6..f8cfd18cd043a6 100644 --- a/packages/babel-plugin-import-jsx-pragma/package.json +++ b/packages/babel-plugin-import-jsx-pragma/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-plugin-import-jsx-pragma", - "version": "3.0.1", + "version": "3.0.2", "description": "Babel transform plugin for automatically injecting an import to be used as the pragma for the React JSX Transform plugin.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/babel-plugin-makepot/package.json b/packages/babel-plugin-makepot/package.json index 84cf5c9d4b011b..bd58664eae8b01 100644 --- a/packages/babel-plugin-makepot/package.json +++ b/packages/babel-plugin-makepot/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-plugin-makepot", - "version": "4.1.0", + "version": "4.1.1", "description": "WordPress Babel internationalization (i18n) plugin.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/babel-preset-default/package.json b/packages/babel-preset-default/package.json index 52e24d2d97fb36..ee497208fd5fa0 100644 --- a/packages/babel-preset-default/package.json +++ b/packages/babel-preset-default/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-preset-default", - "version": "5.2.0-prerelease", + "version": "5.2.0", "description": "Default Babel preset for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/base-styles/package.json b/packages/base-styles/package.json index 98820fdd73634e..e48030208b4866 100644 --- a/packages/base-styles/package.json +++ b/packages/base-styles/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/base-styles", - "version": "3.4.0", + "version": "3.4.1", "description": "Base SCSS utilities and variables for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/blob/package.json b/packages/blob/package.json index 8e6afc34e1ce81..1e992112231450 100644 --- a/packages/blob/package.json +++ b/packages/blob/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/blob", - "version": "2.13.0", + "version": "2.13.1", "description": "Blob utilities for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-directory/package.json b/packages/block-directory/package.json index 3842faaf1688dd..8030c99ad45250 100644 --- a/packages/block-directory/package.json +++ b/packages/block-directory/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-directory", - "version": "1.19.0", + "version": "1.19.1", "description": "Extend editor with block directory features to search, download and install blocks.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-editor/package.json b/packages/block-editor/package.json index ca8c954dc53e2d..f2a1c71191c5f8 100644 --- a/packages/block-editor/package.json +++ b/packages/block-editor/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-editor", - "version": "5.3.0", + "version": "5.3.1", "description": "Generic block editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-library/package.json b/packages/block-library/package.json index a08d7dbdf1d435..b3c877980084a7 100644 --- a/packages/block-library/package.json +++ b/packages/block-library/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-library", - "version": "2.29.0", + "version": "2.29.1", "description": "Block library for the WordPress editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-serialization-default-parser/package.json b/packages/block-serialization-default-parser/package.json index 6840b77e78a28d..971f2e699ff030 100644 --- a/packages/block-serialization-default-parser/package.json +++ b/packages/block-serialization-default-parser/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-serialization-default-parser", - "version": "3.10.0", + "version": "3.10.1", "description": "Block serialization specification parser for WordPress posts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-serialization-spec-parser/package.json b/packages/block-serialization-spec-parser/package.json index 9e31cfd05d4e20..98b5d9215df539 100644 --- a/packages/block-serialization-spec-parser/package.json +++ b/packages/block-serialization-spec-parser/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-serialization-spec-parser", - "version": "3.8.0", + "version": "3.8.1", "description": "Block serialization specification parser for WordPress posts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/blocks/package.json b/packages/blocks/package.json index f85da354ec8ee4..90fbe55e5724ff 100644 --- a/packages/blocks/package.json +++ b/packages/blocks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/blocks", - "version": "8.0.0", + "version": "8.0.1", "description": "Block API for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/browserslist-config/package.json b/packages/browserslist-config/package.json index c77ef09ee229f8..49247cfa5b6e85 100644 --- a/packages/browserslist-config/package.json +++ b/packages/browserslist-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/browserslist-config", - "version": "3.0.1", + "version": "3.0.2", "description": "WordPress Browserslist shared configuration.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/components/package.json b/packages/components/package.json index 94a149c75f907a..aae55b5eea34ca 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/components", - "version": "13.0.0", + "version": "13.0.1", "description": "UI components for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/compose/package.json b/packages/compose/package.json index 9165672206d97b..1bd92b05d76715 100644 --- a/packages/compose/package.json +++ b/packages/compose/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/compose", - "version": "3.25.0", + "version": "3.25.1", "description": "WordPress higher-order components (HOCs).", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/core-data/package.json b/packages/core-data/package.json index cf26b01a42e066..c045146b1eff43 100644 --- a/packages/core-data/package.json +++ b/packages/core-data/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/core-data", - "version": "2.26.0", + "version": "2.26.1", "description": "Access to and manipulation of core WordPress entities.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/create-block-tutorial-template/package.json b/packages/create-block-tutorial-template/package.json index 4c846606b470d8..25878b301a718e 100644 --- a/packages/create-block-tutorial-template/package.json +++ b/packages/create-block-tutorial-template/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/create-block-tutorial-template", - "version": "1.2.0-prerelease", + "version": "1.2.0", "description": "Template for @wordpress/create-block used in the official WordPress tutorial.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/create-block/package.json b/packages/create-block/package.json index 7c6df7aa7d5a73..af92fef98d09b9 100644 --- a/packages/create-block/package.json +++ b/packages/create-block/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/create-block", - "version": "2.2.0-prerelease", + "version": "2.2.0", "description": "Generates PHP, JS and CSS code for registering a block for a WordPress plugin.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/custom-templated-path-webpack-plugin/package.json b/packages/custom-templated-path-webpack-plugin/package.json index 52a7c6b311c4f7..a0ca1f46660be1 100644 --- a/packages/custom-templated-path-webpack-plugin/package.json +++ b/packages/custom-templated-path-webpack-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/custom-templated-path-webpack-plugin", - "version": "2.0.1", + "version": "2.0.2", "description": "Webpack plugin for creating custom path template tags.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/data-controls/package.json b/packages/data-controls/package.json index 75d94c55c37c3c..c07169187ff0b3 100644 --- a/packages/data-controls/package.json +++ b/packages/data-controls/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/data-controls", - "version": "1.21.0", + "version": "1.21.1", "description": "A set of common controls for the @wordpress/data api.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/data/package.json b/packages/data/package.json index f601037fff3216..58bb49e8e7b4d0 100644 --- a/packages/data/package.json +++ b/packages/data/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/data", - "version": "4.27.0", + "version": "4.27.1", "description": "Data module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/date/package.json b/packages/date/package.json index ef0ef2a082f334..339a16efc89c4a 100644 --- a/packages/date/package.json +++ b/packages/date/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/date", - "version": "3.15.0-prerelease", + "version": "3.15.0", "description": "Date module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/dependency-extraction-webpack-plugin/package.json b/packages/dependency-extraction-webpack-plugin/package.json index 95097596f2f4aa..1638be3898b68b 100644 --- a/packages/dependency-extraction-webpack-plugin/package.json +++ b/packages/dependency-extraction-webpack-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/dependency-extraction-webpack-plugin", - "version": "3.1.0", + "version": "3.1.1", "description": "Extract WordPress script dependencies from webpack bundles.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/deprecated/package.json b/packages/deprecated/package.json index 6a9a552ac0863f..f17158b8905ad8 100644 --- a/packages/deprecated/package.json +++ b/packages/deprecated/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/deprecated", - "version": "2.12.0", + "version": "2.12.1", "description": "Deprecation utility for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/docgen/package.json b/packages/docgen/package.json index e6846fde1d4184..c516c61ef60292 100644 --- a/packages/docgen/package.json +++ b/packages/docgen/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/docgen", - "version": "1.16.0", + "version": "1.16.1", "description": "Autogenerate public API documentation from exports and JSDoc comments.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/dom-ready/package.json b/packages/dom-ready/package.json index 0f16aa2adb3e55..1e833be3ac99dd 100644 --- a/packages/dom-ready/package.json +++ b/packages/dom-ready/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/dom-ready", - "version": "2.13.0", + "version": "2.13.1", "description": "Execute callback after the DOM is loaded.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/dom/package.json b/packages/dom/package.json index 2fabf1204c0e64..066598d9ba49bc 100644 --- a/packages/dom/package.json +++ b/packages/dom/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/dom", - "version": "2.17.0", + "version": "2.17.1", "description": "DOM utilities module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/e2e-test-utils/package.json b/packages/e2e-test-utils/package.json index 89e25d997e5c99..7fb0bd843c98fc 100644 --- a/packages/e2e-test-utils/package.json +++ b/packages/e2e-test-utils/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/e2e-test-utils", - "version": "5.1.0", + "version": "5.1.1", "description": "End-To-End (E2E) test utils for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/e2e-tests/package.json b/packages/e2e-tests/package.json index e7f28f8137126a..511874e6021943 100644 --- a/packages/e2e-tests/package.json +++ b/packages/e2e-tests/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/e2e-tests", - "version": "2.1.1", + "version": "2.1.2", "description": "End-To-End (E2E) tests for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/edit-post/package.json b/packages/edit-post/package.json index 2d5f7af3c145d9..535240e3950aac 100644 --- a/packages/edit-post/package.json +++ b/packages/edit-post/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/edit-post", - "version": "3.27.0", + "version": "3.27.1", "description": "Edit Post module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/edit-site/package.json b/packages/edit-site/package.json index c24367cff3fc56..cb69cd56dbd3b3 100644 --- a/packages/edit-site/package.json +++ b/packages/edit-site/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/edit-site", - "version": "1.17.0", + "version": "1.17.1", "description": "Edit Site Page module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/edit-widgets/package.json b/packages/edit-widgets/package.json index 6daa7221451ebf..8842784ed0b474 100644 --- a/packages/edit-widgets/package.json +++ b/packages/edit-widgets/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/edit-widgets", - "version": "1.3.0", + "version": "1.3.1", "description": "Widgets Page module for WordPress..", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/editor/package.json b/packages/editor/package.json index 07de55c5868861..4d34408ad1d939 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/editor", - "version": "9.26.0", + "version": "9.26.1", "description": "Enhanced block editor for WordPress posts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/element/package.json b/packages/element/package.json index b072325d18283a..a6902344fec291 100644 --- a/packages/element/package.json +++ b/packages/element/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/element", - "version": "2.20.0", + "version": "2.20.1", "description": "Element React module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/env/package.json b/packages/env/package.json index 39e1c32e2a75e0..35a39702fdebf3 100644 --- a/packages/env/package.json +++ b/packages/env/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/env", - "version": "4.0.0", + "version": "4.0.1", "description": "A zero-config, self contained local WordPress environment for development and testing.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/escape-html/package.json b/packages/escape-html/package.json index cbbf3119984f67..9fbf57f03b8710 100644 --- a/packages/escape-html/package.json +++ b/packages/escape-html/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/escape-html", - "version": "1.12.0", + "version": "1.12.1", "description": "Escape HTML utils.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index f05aa17fae5b01..14f9aa62d91315 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/eslint-plugin", - "version": "9.0.1", + "version": "9.0.2", "description": "ESLint plugin for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/format-library/package.json b/packages/format-library/package.json index 53a0f38e57a395..6a9afd017ccb76 100644 --- a/packages/format-library/package.json +++ b/packages/format-library/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/format-library", - "version": "1.27.0", + "version": "1.27.1", "description": "Format library for the WordPress editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/hooks/package.json b/packages/hooks/package.json index cc3eea4f6f8787..adffe4477a29e4 100644 --- a/packages/hooks/package.json +++ b/packages/hooks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/hooks", - "version": "2.12.0", + "version": "2.12.1", "description": "WordPress hooks library.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/html-entities/package.json b/packages/html-entities/package.json index 094f0ddfc81e67..4fb9d4a6b895b0 100644 --- a/packages/html-entities/package.json +++ b/packages/html-entities/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/html-entities", - "version": "2.11.0", + "version": "2.11.1", "description": "HTML entity utilities for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/i18n/package.json b/packages/i18n/package.json index 72e169346cffd9..d08084e6a655ed 100644 --- a/packages/i18n/package.json +++ b/packages/i18n/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/i18n", - "version": "3.19.0", + "version": "3.19.1", "description": "WordPress internationalization (i18n) library.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/icons/package.json b/packages/icons/package.json index 423a4ecdf7630e..c3bb1a1ee86086 100644 --- a/packages/icons/package.json +++ b/packages/icons/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/icons", - "version": "2.10.0", + "version": "2.10.1", "description": "WordPress Icons package, based on dashicon.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/interface/package.json b/packages/interface/package.json index 578d7d83d5e923..36f66c0fe3e0b8 100644 --- a/packages/interface/package.json +++ b/packages/interface/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/interface", - "version": "2.0.0-prerelease", + "version": "2.0.0", "description": "Interface module for WordPress. The package contains shared functionality across the modern JavaScript-based WordPress screens.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/is-shallow-equal/package.json b/packages/is-shallow-equal/package.json index 16f14b78d6c94b..41015ebbb29014 100644 --- a/packages/is-shallow-equal/package.json +++ b/packages/is-shallow-equal/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/is-shallow-equal", - "version": "3.1.0", + "version": "3.1.1", "description": "Test for shallow equality between two objects or arrays.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/jest-console/package.json b/packages/jest-console/package.json index 71b592a5cf401a..d488edef91eff6 100644 --- a/packages/jest-console/package.json +++ b/packages/jest-console/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/jest-console", - "version": "4.0.1", + "version": "4.0.2", "description": "Custom Jest matchers for the Console object.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/jest-preset-default/package.json b/packages/jest-preset-default/package.json index 4e04d66575bac2..2d39d055adaed8 100644 --- a/packages/jest-preset-default/package.json +++ b/packages/jest-preset-default/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/jest-preset-default", - "version": "7.0.1", + "version": "7.0.2", "description": "Default Jest preset for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/jest-puppeteer-axe/package.json b/packages/jest-puppeteer-axe/package.json index e1e4fd1f2327dc..607ea7447afee0 100644 --- a/packages/jest-puppeteer-axe/package.json +++ b/packages/jest-puppeteer-axe/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/jest-puppeteer-axe", - "version": "3.0.1", + "version": "3.0.2", "description": "Axe API integration with Jest and Puppeteer.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/keyboard-shortcuts/package.json b/packages/keyboard-shortcuts/package.json index 5e25e4829cc2ef..0723873ad6e203 100644 --- a/packages/keyboard-shortcuts/package.json +++ b/packages/keyboard-shortcuts/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/keyboard-shortcuts", - "version": "1.14.0", + "version": "1.14.1", "description": "Handling keyboard shortcuts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/keycodes/package.json b/packages/keycodes/package.json index 835b65df347ec6..715dc24c293eff 100644 --- a/packages/keycodes/package.json +++ b/packages/keycodes/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/keycodes", - "version": "2.19.0", + "version": "2.19.1", "description": "Keycodes utilities for WordPress. Used to check for keyboard events across browsers/operating systems.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/lazy-import/package.json b/packages/lazy-import/package.json index cdabf38f10e2d8..63adc1811da0ae 100644 --- a/packages/lazy-import/package.json +++ b/packages/lazy-import/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/lazy-import", - "version": "1.2.1", + "version": "1.2.2", "description": "Lazily import a module, installing it automatically if missing.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/library-export-default-webpack-plugin/package.json b/packages/library-export-default-webpack-plugin/package.json index 0ab9346677be94..4232c777b812d0 100644 --- a/packages/library-export-default-webpack-plugin/package.json +++ b/packages/library-export-default-webpack-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/library-export-default-webpack-plugin", - "version": "2.0.1", + "version": "2.0.2", "description": "Webpack plugin for exporting default property for selected libraries.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/list-reusable-blocks/package.json b/packages/list-reusable-blocks/package.json index ad54ffa8027a13..2d79b7b0823f7a 100644 --- a/packages/list-reusable-blocks/package.json +++ b/packages/list-reusable-blocks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/list-reusable-blocks", - "version": "1.26.0", + "version": "1.26.1", "description": "Adding Export/Import support to the reusable blocks listing.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/media-utils/package.json b/packages/media-utils/package.json index 8fd428398f3c20..eb1c9fbe6a323a 100644 --- a/packages/media-utils/package.json +++ b/packages/media-utils/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/media-utils", - "version": "1.20.0", + "version": "1.20.1", "description": "WordPress Media Upload Utils.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/notices/package.json b/packages/notices/package.json index b03242933a39f0..cf4a505b64c43e 100644 --- a/packages/notices/package.json +++ b/packages/notices/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/notices", - "version": "2.13.0", + "version": "2.13.1", "description": "State management for notices.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/npm-package-json-lint-config/package.json b/packages/npm-package-json-lint-config/package.json index 52d2d789c460de..c374dcb7d12f0a 100644 --- a/packages/npm-package-json-lint-config/package.json +++ b/packages/npm-package-json-lint-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/npm-package-json-lint-config", - "version": "4.0.1", + "version": "4.0.2", "description": "WordPress npm-package-json-lint shareable configuration.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/nux/package.json b/packages/nux/package.json index 3bfa3d24319c0a..388a688f882078 100644 --- a/packages/nux/package.json +++ b/packages/nux/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/nux", - "version": "3.25.0", + "version": "3.25.1", "description": "NUX (New User eXperience) module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/plugins/package.json b/packages/plugins/package.json index 1b29f991433ffe..5e6f877f112749 100644 --- a/packages/plugins/package.json +++ b/packages/plugins/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/plugins", - "version": "2.25.0", + "version": "2.25.1", "description": "Plugins module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/postcss-plugins-preset/package.json b/packages/postcss-plugins-preset/package.json index e771d7c2abb6a3..c23581582b5e7a 100644 --- a/packages/postcss-plugins-preset/package.json +++ b/packages/postcss-plugins-preset/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/postcss-plugins-preset", - "version": "2.1.0", + "version": "2.1.1", "description": "PostCSS sharable plugins preset for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/postcss-themes/package.json b/packages/postcss-themes/package.json index feeddd53ef1f5d..a7525a70143328 100644 --- a/packages/postcss-themes/package.json +++ b/packages/postcss-themes/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/postcss-themes", - "version": "3.0.1", + "version": "3.0.2", "description": "PostCSS plugin to generate theme colors.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/prettier-config/package.json b/packages/prettier-config/package.json index 0b6e79149c4fb6..07a487e74633e4 100644 --- a/packages/prettier-config/package.json +++ b/packages/prettier-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/prettier-config", - "version": "1.0.1", + "version": "1.0.2", "description": "WordPress Prettier shared configuration.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/primitives/package.json b/packages/primitives/package.json index e6a22c9fb34064..09eed904263576 100644 --- a/packages/primitives/package.json +++ b/packages/primitives/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/primitives", - "version": "1.12.0", + "version": "1.12.1", "description": "WordPress cross-platform primitives.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/priority-queue/package.json b/packages/priority-queue/package.json index 50a9d7d9e1414d..934abadc7e510f 100644 --- a/packages/priority-queue/package.json +++ b/packages/priority-queue/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/priority-queue", - "version": "1.11.0", + "version": "1.11.1", "description": "Generic browser priority queue.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/project-management-automation/package.json b/packages/project-management-automation/package.json index d9feff55a0c8fa..9fa55f873de621 100644 --- a/packages/project-management-automation/package.json +++ b/packages/project-management-automation/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/project-management-automation", - "version": "1.12.0", + "version": "1.12.1", "description": "GitHub Action that implements various automation to assist with managing the Gutenberg GitHub repository.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/react-i18n/package.json b/packages/react-i18n/package.json index 6b93601635c721..0ede28f0433136 100644 --- a/packages/react-i18n/package.json +++ b/packages/react-i18n/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/react-i18n", - "version": "1.0.0", + "version": "1.0.1", "description": "React bindings for @wordpress/i18n.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/redux-routine/package.json b/packages/redux-routine/package.json index baca540dee7df9..2a48bd93d4b1a6 100644 --- a/packages/redux-routine/package.json +++ b/packages/redux-routine/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/redux-routine", - "version": "3.14.0", + "version": "3.14.1", "description": "Redux middleware for generator coroutines.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/reusable-blocks/package.json b/packages/reusable-blocks/package.json index 3571fbaf791879..dddf1fc75fb9e4 100644 --- a/packages/reusable-blocks/package.json +++ b/packages/reusable-blocks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/reusable-blocks", - "version": "1.2.0", + "version": "1.2.1", "description": "Reusable blocks utilities.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/rich-text/package.json b/packages/rich-text/package.json index 969604faf28b79..bb8237be5123d0 100644 --- a/packages/rich-text/package.json +++ b/packages/rich-text/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/rich-text", - "version": "3.25.0", + "version": "3.25.1", "description": "Rich text value and manipulation API.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/scripts/package.json b/packages/scripts/package.json index 3b59a505f3f61e..d77fc29cadfe8c 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/scripts", - "version": "14.1.0-prerelease", + "version": "14.1.0", "description": "Collection of reusable scripts for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/server-side-render/package.json b/packages/server-side-render/package.json index 41c4df74b4a2d5..5199c0929d07d7 100644 --- a/packages/server-side-render/package.json +++ b/packages/server-side-render/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/server-side-render", - "version": "1.21.0", + "version": "1.21.1", "description": "The component used with WordPress to server-side render a preview of dynamic blocks to display in the editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/shortcode/package.json b/packages/shortcode/package.json index 866e44031d6c27..f57fcf672d98b1 100644 --- a/packages/shortcode/package.json +++ b/packages/shortcode/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/shortcode", - "version": "2.13.0", + "version": "2.13.1", "description": "Shortcode module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/stylelint-config/package.json b/packages/stylelint-config/package.json index c67d85d287400c..7bedb0062e090d 100644 --- a/packages/stylelint-config/package.json +++ b/packages/stylelint-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/stylelint-config", - "version": "19.0.1", + "version": "19.0.2", "description": "stylelint config for WordPress development.", "author": "The WordPress Contributors", "license": "MIT", diff --git a/packages/token-list/package.json b/packages/token-list/package.json index 7447295f485208..cbf2d21fc7f6b5 100644 --- a/packages/token-list/package.json +++ b/packages/token-list/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/token-list", - "version": "1.15.0", + "version": "1.15.1", "description": "Constructable, plain JavaScript DOMTokenList implementation, supporting non-browser runtimes.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/url/package.json b/packages/url/package.json index 5dffbea26b43d4..4b6e45992a99a7 100644 --- a/packages/url/package.json +++ b/packages/url/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/url", - "version": "2.22.0", + "version": "2.22.1", "description": "WordPress URL utilities.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/viewport/package.json b/packages/viewport/package.json index f6d3f1d1e31dfb..7befbacb490770 100644 --- a/packages/viewport/package.json +++ b/packages/viewport/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/viewport", - "version": "2.26.0", + "version": "2.26.1", "description": "Viewport module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/warning/package.json b/packages/warning/package.json index 6ea1a0670cffa9..a8cc6b296ef0d1 100644 --- a/packages/warning/package.json +++ b/packages/warning/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/warning", - "version": "1.4.0", + "version": "1.4.1", "description": "Warning utility for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/wordcount/package.json b/packages/wordcount/package.json index feb5680bd5d111..38384c3488f19a 100644 --- a/packages/wordcount/package.json +++ b/packages/wordcount/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/wordcount", - "version": "2.15.0", + "version": "2.15.1", "description": "WordPress word count utility.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", From efd90deb58fd04aa1e342cb377c9ff8158022f8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Tue, 6 Apr 2021 12:47:56 +0200 Subject: [PATCH 006/125] Use "Custom Styles" title to signal there are global styles changes in the saving panel of the site editor (#30521) * Set title in the global styles CPT * Enable title for CPT --- lib/class-wp-theme-json-resolver.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/class-wp-theme-json-resolver.php b/lib/class-wp-theme-json-resolver.php index 6815dc68ecca2e..bacadea73bb7a2 100644 --- a/lib/class-wp-theme-json-resolver.php +++ b/lib/class-wp-theme-json-resolver.php @@ -362,6 +362,7 @@ private static function get_user_data_from_custom_post_type( $should_create_cpt array( 'post_content' => '{}', 'post_status' => 'publish', + 'post_title' => __( 'Custom Styles' ), 'post_type' => $post_type_filter, 'post_name' => $post_name_filter, ), @@ -471,6 +472,7 @@ public static function register_user_custom_post_type() { ), 'map_meta_cap' => true, 'supports' => array( + 'title', 'editor', 'revisions', ), From b28dc9e69ed475c6969e5a3f9261ab9895de4ce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20Szab=C3=B3?= Date: Tue, 6 Apr 2021 13:05:12 +0200 Subject: [PATCH 007/125] Server side renderer: Fix errors in template part editor context (#29246) --- packages/server-side-render/src/index.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/server-side-render/src/index.js b/packages/server-side-render/src/index.js index 30af329d429a5f..5797d784743dd1 100644 --- a/packages/server-side-render/src/index.js +++ b/packages/server-side-render/src/index.js @@ -19,7 +19,11 @@ const ExportedServerSideRender = withSelect( ( select ) => { const coreEditorSelect = select( 'core/editor' ); if ( coreEditorSelect ) { const currentPostId = coreEditorSelect.getCurrentPostId(); - if ( currentPostId ) { + // For templates and template parts we use a custom ID format. + // Since they aren't real posts, we don't want to use their ID + // for server-side rendering. Since they use a string based ID, + // we can assume real post IDs are numbers. + if ( currentPostId && typeof currentPostId.id === 'number' ) { return { currentPostId, }; From ea2f6f83152f21beb4914e38f91825479acf4769 Mon Sep 17 00:00:00 2001 From: Grzegorz Date: Tue, 6 Apr 2021 13:17:22 +0200 Subject: [PATCH 008/125] revert #27717 (#30524) Co-authored-by: grzim --- .../src/components/post-text-editor/index.js | 18 +++----------- .../components/post-text-editor/test/index.js | 24 ++----------------- 2 files changed, 5 insertions(+), 37 deletions(-) diff --git a/packages/editor/src/components/post-text-editor/index.js b/packages/editor/src/components/post-text-editor/index.js index 577f4741927018..b764c02014f44f 100644 --- a/packages/editor/src/components/post-text-editor/index.js +++ b/packages/editor/src/components/post-text-editor/index.js @@ -7,13 +7,12 @@ import Textarea from 'react-autosize-textarea'; * WordPress dependencies */ import { __ } from '@wordpress/i18n'; -import { useState, useEffect } from '@wordpress/element'; +import { useState } from '@wordpress/element'; import { parse } from '@wordpress/blocks'; import { useDispatch, useSelect } from '@wordpress/data'; import { useInstanceId } from '@wordpress/compose'; import { VisuallyHidden } from '@wordpress/components'; -export const DEBOUNCE_TIME = 300; export default function PostTextEditor() { const postContent = useSelect( ( select ) => select( 'core/editor' ).getEditedPostContent(), @@ -30,18 +29,6 @@ export default function PostTextEditor() { setValue( postContent ); } - const saveText = () => { - const blocks = parse( value ); - resetEditorBlocks( blocks ); - }; - - useEffect( () => { - const timeoutId = setTimeout( saveText, DEBOUNCE_TIME ); - return () => { - clearTimeout( timeoutId ); - }; - }, [ value ] ); - /** * Handles a textarea change event to notify the onChange prop callback and * reflect the new value in the component's own state. This marks the start @@ -67,7 +54,8 @@ export default function PostTextEditor() { */ const stopEditing = () => { if ( isDirty ) { - saveText(); + const blocks = parse( value ); + resetEditorBlocks( blocks ); setIsDirty( false ); } }; diff --git a/packages/editor/src/components/post-text-editor/test/index.js b/packages/editor/src/components/post-text-editor/test/index.js index c6f8492a1fb58d..d132c3b47cd79a 100644 --- a/packages/editor/src/components/post-text-editor/test/index.js +++ b/packages/editor/src/components/post-text-editor/test/index.js @@ -7,14 +7,13 @@ import Textarea from 'react-autosize-textarea'; /** * WordPress dependencies */ -import * as wp from '@wordpress/data'; +import { useSelect } from '@wordpress/data'; /** * Internal dependencies */ -import PostTextEditor, { DEBOUNCE_TIME } from '../'; +import PostTextEditor from '../'; -const useSelect = wp.useSelect; // "Downgrade" ReactAutosizeTextarea to a regular textarea. Assumes aligned // props interface. jest.mock( 'react-autosize-textarea', () => ( props ) => ( @@ -176,23 +175,4 @@ describe( 'PostTextEditor', () => { expect( textarea.props.value ).toBe( 'Goodbye World' ); } ); - it( 'debounce value update after given time', () => { - let wrapper; - act( () => { - wrapper = create( ); - } ); - const mockDispatchFn = jest.fn(); - jest.mock( '@wordpress/data/src/components/use-dispatch', () => ( { - useDispatch: () => ( { - editPost: jest.fn(), - resetEditorBlocks: mockDispatchFn, - } ), - } ) ); - - const textarea = wrapper.root.findByType( Textarea ); - act( () => textarea.props.onChange( { target: { value: 'text' } } ) ); - setTimeout( () => { - expect( mockDispatchFn ).toHaveBeenCalled(); - }, DEBOUNCE_TIME ); - } ); } ); From 3882276868b98d0e3ae4fd5a8d81b404ba2fc616 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Tue, 6 Apr 2021 12:54:27 +0100 Subject: [PATCH 009/125] Remove the default block margins from themes with theme.json file (#30375) --- lib/client-assets.php | 14 +++ packages/block-library/src/editor.scss | 7 -- packages/block-library/src/spacer/editor.scss | 1 - packages/edit-post/src/classic.scss | 113 ++++++++++++++++++ .../edit-post/src/components/layout/index.js | 3 - .../src/components/layout/style.scss | 109 ----------------- 6 files changed, 127 insertions(+), 120 deletions(-) create mode 100644 packages/edit-post/src/classic.scss diff --git a/lib/client-assets.php b/lib/client-assets.php index c1814fc858385c..15c752bf88504a 100644 --- a/lib/client-assets.php +++ b/lib/client-assets.php @@ -360,6 +360,11 @@ function gutenberg_register_packages_styles( $styles ) { 'wp-reusable-blocks', ); + // Only load the default layout and margin styles for themes without theme.json file. + if ( ! WP_Theme_JSON_Resolver::theme_has_support() ) { + $wp_edit_blocks_dependencies[] = 'wp-editor-classic-layout-styles'; + } + global $editor_styles; if ( ! is_array( $editor_styles ) || count( $editor_styles ) === 0 ) { // Include opinionated block styles if no $editor_styles are declared, so the editor never appears broken. @@ -375,6 +380,15 @@ function gutenberg_register_packages_styles( $styles ) { ); $styles->add_data( 'wp-reset-editor-styles', 'rtl', 'replace' ); + gutenberg_override_style( + $styles, + 'wp-editor-classic-layout-styles', + gutenberg_url( 'build/edit-post/classic.css' ), + array(), + $version + ); + $styles->add_data( 'wp-editor-classic-layout-styles', 'rtl', 'replace' ); + gutenberg_override_style( $styles, 'wp-edit-blocks', diff --git a/packages/block-library/src/editor.scss b/packages/block-library/src/editor.scss index 7e466ee3d54a1b..9cd49fb82cfed7 100644 --- a/packages/block-library/src/editor.scss +++ b/packages/block-library/src/editor.scss @@ -97,13 +97,6 @@ * This allows us to create normalization styles that are easily overridden by editor styles. */ -// Provide every block with a default base margin. This margin provides a consistent spacing -// between blocks in the editor. -.block-editor-block-list__block { - margin-top: $default-block-margin; - margin-bottom: $default-block-margin; -} - // This tag marks the end of the styles that apply to editing canvas contents and need to be manipulated when we resize the editor. #end-resizable-editor-section { display: none; diff --git a/packages/block-library/src/spacer/editor.scss b/packages/block-library/src/spacer/editor.scss index 3d80b997668702..c1c1aec88e38d7 100644 --- a/packages/block-library/src/spacer/editor.scss +++ b/packages/block-library/src/spacer/editor.scss @@ -21,7 +21,6 @@ .block-library-spacer__resize-container { clear: both; - margin-bottom: $default-block-margin; // Don't show the horizontal indicator. .components-resizable-box__handle::before { diff --git a/packages/edit-post/src/classic.scss b/packages/edit-post/src/classic.scss new file mode 100644 index 00000000000000..a58b9b07052b90 --- /dev/null +++ b/packages/edit-post/src/classic.scss @@ -0,0 +1,113 @@ +// This needs specificity to override the editor styles. +.editor-styles-wrapper .wp-block { + margin-left: auto; + margin-right: auto; +} + +// Depreacted style needed for the block widths and alignments. +// for themes that don't support the new layout (theme.json) +.wp-block { + max-width: $content-width; + + // Provide every block with a default base margin. This margin provides a consistent spacing + // between blocks in the editor. + margin-top: $default-block-margin; + margin-bottom: $default-block-margin; + + &[data-align="wide"] { + max-width: $wide-content-width; + } + + &[data-align="full"] { + max-width: none; + } + + // Alignments. + &[data-align="left"], + &[data-align="right"] { + width: 100%; + + // When images are floated, the block itself should collapse to zero height. + height: 0; + + &::before { + content: none; + } + } + + // Left. + &[data-align="left"] > * { + /*!rtl:begin:ignore*/ + float: left; + margin-right: 2em; + /*!rtl:end:ignore*/ + } + + // Right. + &[data-align="right"] > * { + /*!rtl:begin:ignore*/ + float: right; + margin-left: 2em; + /*!rtl:end:ignore*/ + } + + // Wide and full-wide. + &[data-align="full"], + &[data-align="wide"] { + clear: both; + } +} + +// Full Width Blocks +// specificity required to only target immediate child Blocks of a Group +.wp-block-group > [data-align="full"] { + margin-left: auto; + margin-right: auto; +} + +// Full Width Blocks with a background (ie: has padding) +.wp-block-group.has-background > [data-align="full"] { + // note: using position `left` causes hoz scrollbars so + // we opt to use margin instead + // the 30px matches the hoz padding applied in `theme.scss` + // added when the Block has a background set + margin-left: -30px; + + // 60px here is x2 the hoz padding from `theme.scss` added when + // the Block has a background set + // note: also duplicated below for full width Groups + width: calc(100% + 60px); +} + +/** +* Group: Full Width Alignment +*/ +[data-align="full"] .wp-block-group { + // Non-full Width Blocks + // specificity required to only target immediate child Blocks of Group + > .wp-block { + padding-left: $block-padding; + padding-right: $block-padding; + + @include break-small() { + padding-left: 0; + padding-right: 0; + } + } + + // Full Width Blocks + // specificity required to only target immediate child Blocks of Group + > [data-align="full"] { + padding-right: 0; + padding-left: 0; + left: 0; + width: 100%; + max-width: none; + } + + // Full Width Blocks with a background (ie: has padding) + // note: also duplicated above for all Group widths + &.has-background > [data-align="full"] { + width: calc(100% + 60px); + } +} diff --git a/packages/edit-post/src/components/layout/index.js b/packages/edit-post/src/components/layout/index.js index 0c9da0ae76a82e..e65447be8cb6bc 100644 --- a/packages/edit-post/src/components/layout/index.js +++ b/packages/edit-post/src/components/layout/index.js @@ -94,7 +94,6 @@ function Layout( { styles } ) { showIconLabels, hasReducedUI, showBlockBreadcrumbs, - supportsLayout, } = useSelect( ( select ) => { const editorSettings = select( 'core/editor' ).getEditorSettings(); return { @@ -115,7 +114,6 @@ function Layout( { styles } ) { isInserterOpened: select( editPostStore ).isInserterOpened(), mode: select( editPostStore ).getEditorMode(), isRichEditingEnabled: editorSettings.richEditingEnabled, - supportsLayout: editorSettings.supportsLayout, hasActiveMetaboxes: select( editPostStore ).hasMetaBoxes(), previousShortcut: select( keyboardShortcutsStore @@ -141,7 +139,6 @@ function Layout( { styles } ) { 'has-fixed-toolbar': hasFixedToolbar, 'has-metaboxes': hasActiveMetaboxes, 'show-icon-labels': showIconLabels, - 'supports-layout': supportsLayout, } ); const openSidebarPanel = () => openGeneralSidebar( diff --git a/packages/edit-post/src/components/layout/style.scss b/packages/edit-post/src/components/layout/style.scss index 3a5fee6452b076..f1d29371aad63b 100644 --- a/packages/edit-post/src/components/layout/style.scss +++ b/packages/edit-post/src/components/layout/style.scss @@ -115,112 +115,3 @@ height: 100%; } } - -// Depreacted style needed for the block widths and alignments. -// for themes that don't support the new layout (theme.json) -.edit-post-layout:not(.supports-layout) { - .wp-block { - max-width: $content-width; - margin-left: auto; - margin-right: auto; - - &[data-align="wide"] { - max-width: $wide-content-width; - } - - &[data-align="full"] { - max-width: none; - } - - // Alignments. - &[data-align="left"], - &[data-align="right"] { - width: 100%; - - // When images are floated, the block itself should collapse to zero height. - height: 0; - - &::before { - content: none; - } - } - - // Left. - &[data-align="left"] > * { - /*!rtl:begin:ignore*/ - float: left; - margin-right: 2em; - /*!rtl:end:ignore*/ - } - - // Right. - &[data-align="right"] > * { - /*!rtl:begin:ignore*/ - float: right; - margin-left: 2em; - /*!rtl:end:ignore*/ - } - - // Wide and full-wide. - &[data-align="full"], - &[data-align="wide"] { - clear: both; - } - - } - - // Full Width Blocks - // specificity required to only target immediate child Blocks of a Group - .wp-block-group > [data-align="full"] { - margin-left: auto; - margin-right: auto; - } - - // Full Width Blocks with a background (ie: has padding) - .wp-block-group.has-background > [data-align="full"] { - // note: using position `left` causes hoz scrollbars so - // we opt to use margin instead - // the 30px matches the hoz padding applied in `theme.scss` - // added when the Block has a background set - margin-left: -30px; - - // 60px here is x2 the hoz padding from `theme.scss` added when - // the Block has a background set - // note: also duplicated below for full width Groups - width: calc(100% + 60px); - } - - /** - * Group: Full Width Alignment - */ - [data-align="full"] .wp-block-group { - - // Non-full Width Blocks - // specificity required to only target immediate child Blocks of Group - > .wp-block { - padding-left: $block-padding; - padding-right: $block-padding; - - @include break-small() { - padding-left: 0; - padding-right: 0; - } - } - - // Full Width Blocks - // specificity required to only target immediate child Blocks of Group - > [data-align="full"] { - padding-right: 0; - padding-left: 0; - left: 0; - width: 100%; - max-width: none; - } - - // Full Width Blocks with a background (ie: has padding) - // note: also duplicated above for all Group widths - &.has-background > [data-align="full"] { - width: calc(100% + 60px); - } - } -} From fc3a5a173195674df64b6f8a99838b736b4662df Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Tue, 6 Apr 2021 16:20:02 +0400 Subject: [PATCH 010/125] Use getAuthors for 'showCombobox' check (#30218) * Use getAuthors for 'showCombobox' check * Add inline comment --- packages/editor/src/components/post-author/index.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/editor/src/components/post-author/index.js b/packages/editor/src/components/post-author/index.js index 90affecc2291e0..0739d75e5e9ed9 100644 --- a/packages/editor/src/components/post-author/index.js +++ b/packages/editor/src/components/post-author/index.js @@ -2,6 +2,7 @@ * WordPress dependencies */ import { useSelect } from '@wordpress/data'; +import { store as coreStore } from '@wordpress/core-data'; /** * Internal dependencies @@ -13,10 +14,8 @@ const minimumUsersForCombobox = 25; function PostAuthor() { const showCombobox = useSelect( ( select ) => { - const authors = select( 'core' ).getUsers( { - who: 'authors', - per_page: minimumUsersForCombobox + 1, - } ); + // Not using `getUsers()` because it requires `list_users` capability. + const authors = select( coreStore ).getAuthors(); return authors?.length >= minimumUsersForCombobox; }, [] ); From 07abb2b515ff73805eb48bb879ceeee1366192c7 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Tue, 6 Apr 2021 16:21:21 +0400 Subject: [PATCH 011/125] Gallery: Set 'addToGallery' prop to false when images don't have IDs. (#30122) This also sets MediaPlaceholder value to an empty object. With both props set to "falsy" values, the gallery media frame is initialized in the "Create Gallery" state. This lets users replace placeholder images from patterns. --- packages/block-library/src/gallery/edit.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/gallery/edit.js b/packages/block-library/src/gallery/edit.js index a0ffc6ed9bc332..a888ead72fbb9c 100644 --- a/packages/block-library/src/gallery/edit.js +++ b/packages/block-library/src/gallery/edit.js @@ -324,10 +324,11 @@ function GalleryEdit( props ) { }, [ linkTo ] ); const hasImages = !! images.length; + const hasImageIds = hasImages && images.some( ( image ) => !! image.id ); const mediaPlaceholder = ( Date: Tue, 6 Apr 2021 08:29:55 -0400 Subject: [PATCH 012/125] Docs: Fix typos in block-controls-toolbar-and-sidebar.md (#30513) --- .../block-tutorial/block-controls-toolbar-and-sidebar.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/how-to-guides/block-tutorial/block-controls-toolbar-and-sidebar.md b/docs/how-to-guides/block-tutorial/block-controls-toolbar-and-sidebar.md index eecbd3d0977c15..5e50c08322c9bd 100644 --- a/docs/how-to-guides/block-tutorial/block-controls-toolbar-and-sidebar.md +++ b/docs/how-to-guides/block-tutorial/block-controls-toolbar-and-sidebar.md @@ -229,8 +229,8 @@ registerBlockType( 'create-block/gutenpride', { return (
- -
+ +
{ __( 'Background color', 'gutenpride' ) } From 8be7a8d0ee338c9d4668dab08733266a325f713f Mon Sep 17 00:00:00 2001 From: sarayourfriend Date: Tue, 6 Apr 2021 05:49:45 -0700 Subject: [PATCH 013/125] dom: Add types to clean-node-list (#30412) * dom: Type dependencies of clean-node-list * dom: Add types to clean-node-list * Fix property descriptions --- packages/dom/README.md | 6 ++--- packages/dom/src/dom/clean-node-list.js | 34 ++++++++++++++++++++----- packages/dom/src/dom/insert-after.js | 10 ++++++-- packages/dom/src/dom/is-element.js | 9 +++++++ packages/dom/src/dom/is-empty.js | 6 +++-- packages/dom/src/dom/remove.js | 8 +++++- packages/dom/src/dom/unwrap.js | 7 +++++ packages/dom/tsconfig.json | 6 +++++ 8 files changed, 71 insertions(+), 15 deletions(-) create mode 100644 packages/dom/src/dom/is-element.js diff --git a/packages/dom/README.md b/packages/dom/README.md index 75bfd1e2e2ba20..d3a80a51ac699f 100644 --- a/packages/dom/README.md +++ b/packages/dom/README.md @@ -151,8 +151,8 @@ the latter. _Parameters_ -- _newNode_ `Element`: Node to be inserted. -- _referenceNode_ `Element`: Node after which to perform the insertion. +- _newNode_ `Node`: Node to be inserted. +- _referenceNode_ `Node`: Node after which to perform the insertion. _Returns_ @@ -291,7 +291,7 @@ Given a DOM node, removes it from the DOM. _Parameters_ -- _node_ `Element`: Node to be removed. +- _node_ `Node`: Node to be removed. _Returns_ diff --git a/packages/dom/src/dom/clean-node-list.js b/packages/dom/src/dom/clean-node-list.js index 45bea2becdffd0..0ac9f7dd622712 100644 --- a/packages/dom/src/dom/clean-node-list.js +++ b/packages/dom/src/dom/clean-node-list.js @@ -11,6 +11,21 @@ import remove from './remove'; import unwrap from './unwrap'; import { isPhrasingContent } from '../phrasing-content'; import insertAfter from './insert-after'; +import isElement from './is-element'; + +/* eslint-disable jsdoc/valid-types */ +/** + * @typedef SchemaItem + * @property {string[]} [attributes] Attributes. + * @property {(string | RegExp)[]} [classes] Classnames or RegExp to test against. + * @property {'*' | { [tag: string]: SchemaItem }} [children] Child schemas. + * @property {string[]} [require] Selectors to test required children against. Leave empty or undefined if there are no requirements. + * @property {boolean} allowEmpty Whether to allow nodes without children. + * @property {(node: Node) => boolean} [isMatch] Function to test whether a node is a match. If left undefined any node will be assumed to match. + */ + +/** @typedef {{ [tag: string]: SchemaItem }} Schema */ +/* eslint-enable jsdoc/valid-types */ /** * Given a schema, unwraps or removes nodes, attributes and classes on a node @@ -18,20 +33,22 @@ import insertAfter from './insert-after'; * * @param {NodeList} nodeList The nodeList to filter. * @param {Document} doc The document of the nodeList. - * @param {Object} schema An array of functions that can mutate with the provided node. - * @param {Object} inline Whether to clean for inline mode. + * @param {Schema} schema An array of functions that can mutate with the provided node. + * @param {boolean} inline Whether to clean for inline mode. */ export default function cleanNodeList( nodeList, doc, schema, inline ) { - Array.from( nodeList ).forEach( ( node ) => { + Array.from( nodeList ).forEach( ( + /** @type {Node & { nextElementSibling?: unknown }} */ node + ) => { const tag = node.nodeName.toLowerCase(); // It's a valid child, if the tag exists in the schema without an isMatch // function, or with an isMatch function that matches the node. if ( schema.hasOwnProperty( tag ) && - ( ! schema[ tag ].isMatch || schema[ tag ].isMatch( node ) ) + ( ! schema[ tag ].isMatch || schema[ tag ].isMatch?.( node ) ) ) { - if ( node.nodeType === node.ELEMENT_NODE ) { + if ( isElement( node ) ) { const { attributes = [], classes = [], @@ -64,9 +81,11 @@ export default function cleanNodeList( nodeList, doc, schema, inline ) { if ( node.classList && node.classList.length ) { const mattchers = classes.map( ( item ) => { if ( typeof item === 'string' ) { - return ( className ) => className === item; + return ( /** @type {string} */ className ) => + className === item; } else if ( item instanceof RegExp ) { - return ( className ) => item.test( className ); + return ( /** @type {string} */ className ) => + item.test( className ); } return noop; @@ -113,6 +132,7 @@ export default function cleanNodeList( nodeList, doc, schema, inline ) { // contains children that are block content, unwrap // the node because it is invalid. } else if ( + node.parentNode && node.parentNode.nodeName === 'BODY' && isPhrasingContent( node ) ) { diff --git a/packages/dom/src/dom/insert-after.js b/packages/dom/src/dom/insert-after.js index c81cd0276c3f1a..6ae8b9a8744a96 100644 --- a/packages/dom/src/dom/insert-after.js +++ b/packages/dom/src/dom/insert-after.js @@ -1,11 +1,17 @@ +/** + * Internal dependencies + */ +import { assertIsDefined } from '../utils/assert-is-defined'; + /** * Given two DOM nodes, inserts the former in the DOM as the next sibling of * the latter. * - * @param {Element} newNode Node to be inserted. - * @param {Element} referenceNode Node after which to perform the insertion. + * @param {Node} newNode Node to be inserted. + * @param {Node} referenceNode Node after which to perform the insertion. * @return {void} */ export default function insertAfter( newNode, referenceNode ) { + assertIsDefined( referenceNode.parentNode, 'referenceNode.parentNode' ); referenceNode.parentNode.insertBefore( newNode, referenceNode.nextSibling ); } diff --git a/packages/dom/src/dom/is-element.js b/packages/dom/src/dom/is-element.js new file mode 100644 index 00000000000000..e90a88173a3380 --- /dev/null +++ b/packages/dom/src/dom/is-element.js @@ -0,0 +1,9 @@ +/* eslint-disable jsdoc/valid-types */ +/** + * @param {Node | null | undefined} node + * @return {node is Element} True if node is an Element node + */ +export default function isElement( node ) { + /* eslint-enable jsdoc/valid-types */ + return !! node && node.nodeType === node.ELEMENT_NODE; +} diff --git a/packages/dom/src/dom/is-empty.js b/packages/dom/src/dom/is-empty.js index cffe10ec9ad0cd..b524acb1a54c74 100644 --- a/packages/dom/src/dom/is-empty.js +++ b/packages/dom/src/dom/is-empty.js @@ -11,7 +11,7 @@ export default function isEmpty( element ) { case element.TEXT_NODE: // We cannot use \s since it includes special spaces which we want // to preserve. - return /^[ \f\n\r\t\v\u00a0]*$/.test( element.nodeValue ); + return /^[ \f\n\r\t\v\u00a0]*$/.test( element.nodeValue || '' ); case element.ELEMENT_NODE: if ( element.hasAttributes() ) { return false; @@ -19,7 +19,9 @@ export default function isEmpty( element ) { return true; } - return Array.from( element.childNodes ).every( isEmpty ); + return /** @type {Element[]} */ ( Array.from( + element.childNodes + ) ).every( isEmpty ); default: return true; } diff --git a/packages/dom/src/dom/remove.js b/packages/dom/src/dom/remove.js index 2e22108a08045e..0cec141fa03957 100644 --- a/packages/dom/src/dom/remove.js +++ b/packages/dom/src/dom/remove.js @@ -1,9 +1,15 @@ +/** + * Internal dependencies + */ +import { assertIsDefined } from '../utils/assert-is-defined'; + /** * Given a DOM node, removes it from the DOM. * - * @param {Element} node Node to be removed. + * @param {Node} node Node to be removed. * @return {void} */ export default function remove( node ) { + assertIsDefined( node.parentNode, 'node.parentNode' ); node.parentNode.removeChild( node ); } diff --git a/packages/dom/src/dom/unwrap.js b/packages/dom/src/dom/unwrap.js index 6a93a40625477c..9f58f2d801cac3 100644 --- a/packages/dom/src/dom/unwrap.js +++ b/packages/dom/src/dom/unwrap.js @@ -1,3 +1,8 @@ +/** + * Internal dependencies + */ +import { assertIsDefined } from '../utils/assert-is-defined'; + /** * Unwrap the given node. This means any child nodes are moved to the parent. * @@ -8,6 +13,8 @@ export default function unwrap( node ) { const parent = node.parentNode; + assertIsDefined( parent, 'node.parentNode' ); + while ( node.firstChild ) { parent.insertBefore( node.firstChild, node ); } diff --git a/packages/dom/tsconfig.json b/packages/dom/tsconfig.json index bb25bca0da0eb1..e03e5e0af0eaa8 100644 --- a/packages/dom/tsconfig.json +++ b/packages/dom/tsconfig.json @@ -7,8 +7,14 @@ "include": [ "src/data-transfer.js", "src/dom/caret-range-from-point.js", + "src/dom/clean-node-list.js", "src/dom/compute-caret-rect.js", "src/dom/get-rectangle-from-range.js", + "src/dom/is-empty.js", + "src/dom/is-element.js", + "src/dom/insert-after.js", + "src/dom/remove.js", + "src/dom/unwrap.js", "src/utils/**/*", "src/focusable.js", "src/phrasing-content.js", From 4333b5ac0f1c13e0750472cb2236bfb9498979b2 Mon Sep 17 00:00:00 2001 From: Joen A <1204802+jasmussen@users.noreply.github.com> Date: Tue, 6 Apr 2021 16:25:51 +0200 Subject: [PATCH 014/125] Try: Flip orientation of submenus that are towards the right of the viewport. (#30342) --- .../src/navigation-link/style.scss | 23 ++++++++++++++++++- .../block-library/src/navigation/editor.scss | 6 +++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/packages/block-library/src/navigation-link/style.scss b/packages/block-library/src/navigation-link/style.scss index 5c8a7c1f5d7b7c..eefef7bbb41bfd 100644 --- a/packages/block-library/src/navigation-link/style.scss +++ b/packages/block-library/src/navigation-link/style.scss @@ -15,7 +15,7 @@ } } - // Margin when justified right or space-between. + // Margin of right-most margin should be zero, for right aligned or justified items. .wp-block-navigation__container > .wp-block-pages-list__item:last-child, .wp-block-navigation__container > .wp-block-navigation-link:last-child { margin-right: 0; @@ -181,6 +181,27 @@ } } } + + + // When justified space-between, open submenus leftward for last menu item. + // When justified right, open all submenus leftwards. + &.items-justified-space-between > .submenu-container > .has-child:last-child, + &.items-justified-space-between > .wp-block-navigation__container > .has-child:last-child, + &.items-justified-right .has-child { + // First submenu. + .submenu-container, + .wp-block-navigation-link__container { + left: auto; + right: 0; + + // Nested submenus. + .submenu-container, + .wp-block-navigation-link__container { + left: auto; + right: 100%; + } + } + } } // Default background and font color. diff --git a/packages/block-library/src/navigation/editor.scss b/packages/block-library/src/navigation/editor.scss index 6f7b05130c71a7..1dacf5f63d195d 100644 --- a/packages/block-library/src/navigation/editor.scss +++ b/packages/block-library/src/navigation/editor.scss @@ -27,6 +27,12 @@ &.has-child .block-editor-block-list__block.wp-block-navigation-link { margin: 0; } + + // Margin of right-most margin should be zero, for right aligned or justified items. + &.wp-block-pages-list__item:last-child, + &.wp-block-navigation-link:last-child { + margin-right: 0; + } } } From 8d4eef89b7caaea5db569a2e3c8fd66c7946631f Mon Sep 17 00:00:00 2001 From: Edi Amin Date: Tue, 6 Apr 2021 21:39:53 +0600 Subject: [PATCH 015/125] Docs: Fix example code for apiFetch middlewares (#30534) --- packages/api-fetch/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/api-fetch/README.md b/packages/api-fetch/README.md index 52134d56039113..7e6341e950eb20 100644 --- a/packages/api-fetch/README.md +++ b/packages/api-fetch/README.md @@ -67,7 +67,7 @@ apiFetch.use( ( options, next ) => { const start = Date.now(); const result = next( options ); result.then( () => { - console.log( 'The request took ' + Date.now() - start ); + console.log( 'The request took ' + ( Date.now() - start ) + 'ms' ); } ); return result; } ); From 564a6c02ca3305a536550d551db43311dd25b00a Mon Sep 17 00:00:00 2001 From: Joel Dean Date: Tue, 6 Apr 2021 13:08:28 -0500 Subject: [PATCH 016/125] [RNMobile] Error Notice Improvements (#30273) * added error notice styling. * made notice style a success variant to differentiate. * simplified notice implementation for audio block * removed background styling and used text styling for error notice. * utilized noticeStore for notice instead of HOC within the media container. * utilized withDispatch instead of useDispatch since this is a class comp. * Removed onError is not supported on MediaPlaceholder native. * Removed the onUploadError function and utilized createErrorNotice. * Updated error messages for the audio and media component. * Simplified text styles logic. --- .../block-library/src/audio/edit.native.js | 19 ++++------- .../src/media-text/media-container.native.js | 33 +++++++++---------- .../components/src/notice/index.native.js | 18 +++++++--- .../components/src/notice/style.native.scss | 15 +++++++-- 4 files changed, 48 insertions(+), 37 deletions(-) diff --git a/packages/block-library/src/audio/edit.native.js b/packages/block-library/src/audio/edit.native.js index 6ae68300e14199..cd80c1e172e7cf 100644 --- a/packages/block-library/src/audio/edit.native.js +++ b/packages/block-library/src/audio/edit.native.js @@ -12,7 +12,6 @@ import { PanelBody, SelectControl, ToggleControl, - withNotices, ToolbarButton, ToolbarGroup, AudioPlayer, @@ -29,6 +28,8 @@ import { import { __, sprintf } from '@wordpress/i18n'; import { audio as icon, replace } from '@wordpress/icons'; import { useState } from '@wordpress/element'; +import { useDispatch } from '@wordpress/data'; +import { store as noticesStore } from '@wordpress/notices'; /** * Internal dependencies @@ -39,10 +40,8 @@ const ALLOWED_MEDIA_TYPES = [ 'audio' ]; function AudioEdit( { attributes, - noticeOperations, setAttributes, isSelected, - noticeUI, insertBlocksAfter, onFocus, onBlur, @@ -56,9 +55,10 @@ function AudioEdit( { setAttributes( { id: mediaId, src: mediaUrl } ); }; + const { createErrorNotice } = useDispatch( noticesStore ); + const onError = () => { - // TODO: Set up error state - onUploadError( __( 'Error' ) ); + createErrorNotice( __( 'Failed to insert audio file.' ) ); }; function toggleAttribute( attribute ) { @@ -71,11 +71,6 @@ function AudioEdit( { // TODO: Set up add audio from URL flow } - function onUploadError( message ) { - noticeOperations.removeAllNotices(); - noticeOperations.createErrorNotice( message ); - } - function onSelectAudio( media ) { if ( ! media || ! media.url ) { // in this case there was an error and we should continue in the editing state @@ -108,8 +103,6 @@ function AudioEdit( { accept="audio/*" allowedTypes={ ALLOWED_MEDIA_TYPES } value={ attributes } - notices={ noticeUI } - onError={ onUploadError } onFocus={ onFocus } /> @@ -232,4 +225,4 @@ function AudioEdit( { ); } -export default withNotices( AudioEdit ); +export default AudioEdit; diff --git a/packages/block-library/src/media-text/media-container.native.js b/packages/block-library/src/media-text/media-container.native.js index 14301037bd4822..ae4cbff8a27c49 100644 --- a/packages/block-library/src/media-text/media-container.native.js +++ b/packages/block-library/src/media-text/media-container.native.js @@ -12,12 +12,7 @@ import { requestImageUploadCancelDialog, requestImageFullscreenPreview, } from '@wordpress/react-native-bridge'; -import { - Icon, - Image, - IMAGE_DEFAULT_FOCAL_POINT, - withNotices, -} from '@wordpress/components'; +import { Icon, Image, IMAGE_DEFAULT_FOCAL_POINT } from '@wordpress/components'; import { MEDIA_TYPE_IMAGE, MEDIA_TYPE_VIDEO, @@ -31,6 +26,8 @@ import { Component } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { isURL, getProtocol } from '@wordpress/url'; import { compose, withPreferredColorScheme } from '@wordpress/compose'; +import { withDispatch } from '@wordpress/data'; +import { store as noticesStore } from '@wordpress/notices'; /** * Internal dependencies @@ -54,7 +51,6 @@ export { imageFillStyles } from './media-container.js'; class MediaContainer extends Component { constructor() { super( ...arguments ); - this.onUploadError = this.onUploadError.bind( this ); this.updateMediaProgress = this.updateMediaProgress.bind( this ); this.finishMediaUploadWithSuccess = this.finishMediaUploadWithSuccess.bind( this @@ -83,12 +79,6 @@ class MediaContainer extends Component { } } - onUploadError( message ) { - const { noticeOperations } = this.props; - noticeOperations.removeAllNotices(); - noticeOperations.createErrorNotice( message ); - } - onSelectMediaUploadOption( params ) { const { id, url, type } = params; const { onSelectMedia } = this.props; @@ -162,6 +152,10 @@ class MediaContainer extends Component { } finishMediaUploadWithFailure() { + const { createErrorNotice } = this.props; + + createErrorNotice( __( 'Failed to insert media.' ) ); + this.setState( { isUploadInProgress: false } ); } @@ -333,7 +327,6 @@ class MediaContainer extends Component { onSelect={ this.onSelectMediaUploadOption } allowedTypes={ ALLOWED_MEDIA_TYPES } onFocus={ this.props.onFocus } - onError={ this.onUploadError } /> ); } @@ -388,7 +381,11 @@ class MediaContainer extends Component { } } -export default compose( - withNotices, - withPreferredColorScheme -)( MediaContainer ); +export default compose( [ + withDispatch( ( dispatch ) => { + const { createErrorNotice } = dispatch( noticesStore ); + + return { createErrorNotice }; + } ), + withPreferredColorScheme, +] )( MediaContainer ); diff --git a/packages/components/src/notice/index.native.js b/packages/components/src/notice/index.native.js index 6224d9cfd6928d..ea29835134c19a 100644 --- a/packages/components/src/notice/index.native.js +++ b/packages/components/src/notice/index.native.js @@ -23,7 +23,7 @@ import { usePreferredColorSchemeStyle } from '@wordpress/compose'; */ import styles from './style.scss'; -const Notice = ( { onNoticeHidden, content, id } ) => { +const Notice = ( { onNoticeHidden, content, id, status } ) => { const [ width, setWidth ] = useState( Dimensions.get( 'window' ).width ); const [ visible, setVisible ] = useState( true ); @@ -77,11 +77,21 @@ const Notice = ( { onNoticeHidden, content, id } ) => { styles.noticeSolidDark ); - const textStyles = usePreferredColorSchemeStyle( - styles.text, - styles.textDark + const successTextStyles = usePreferredColorSchemeStyle( + styles.successText, + styles.successTextDark ); + const errorTextStyles = usePreferredColorSchemeStyle( + styles.errorText, + styles.errorTextDark + ); + + const textStyles = [ + status === 'success' && successTextStyles, + status === 'error' && errorTextStyles, + ]; + return ( <> Date: Wed, 7 Apr 2021 11:31:16 +1000 Subject: [PATCH 017/125] Search Block: Add border radius support using skip serialization feature (#30227) * Add border radius support to the search block --- packages/block-library/src/search/block.json | 4 ++ packages/block-library/src/search/edit.js | 23 ++++++ packages/block-library/src/search/index.php | 74 +++++++++++++++++--- 3 files changed, 90 insertions(+), 11 deletions(-) diff --git a/packages/block-library/src/search/block.json b/packages/block-library/src/search/block.json index 534be0e97cb5fa..d6399a0857397e 100644 --- a/packages/block-library/src/search/block.json +++ b/packages/block-library/src/search/block.json @@ -34,6 +34,10 @@ }, "supports": { "align": [ "left", "center", "right" ], + "__experimentalBorder": { + "radius": true, + "__experimentalSkipSerialization": true + }, "html": false }, "editorStyle": "wp-block-search-editor", diff --git a/packages/block-library/src/search/edit.js b/packages/block-library/src/search/edit.js index 91923b3a78ee7a..06b2c62ad3941d 100644 --- a/packages/block-library/src/search/edit.js +++ b/packages/block-library/src/search/edit.js @@ -48,6 +48,10 @@ import { MIN_WIDTH_UNIT, } from './utils.js'; +// Used to calculate border radius adjustment to avoid "fat" corners when +// button is placed inside wrapper. +const DEFAULT_INNER_PADDING = 4; + export default function SearchEdit( { className, attributes, @@ -65,8 +69,10 @@ export default function SearchEdit( { buttonText, buttonPosition, buttonUseIcon, + style, } = attributes; + const borderRadius = style?.border?.radius; const unitControlInstanceId = useInstanceId( UnitControl ); const unitControlInputId = `wp-block-search__width-${ unitControlInstanceId }`; @@ -122,6 +128,7 @@ export default function SearchEdit( { return ( ) } { ! buttonUseIcon && ( ); + const getWrapperStyles = () => { + if ( 'button-inside' === buttonPosition && style?.border?.radius ) { + // We have button inside wrapper and a border radius value to apply. + // Add default padding so we don't get "fat" corners. + const outerRadius = + parseInt( style?.border?.radius, 10 ) + DEFAULT_INNER_PADDING; + + return { borderRadius: `${ outerRadius }px` }; + } + + return undefined; + }; + const blockProps = useBlockProps( { className: getBlockClassNames(), } ); @@ -327,6 +349,7 @@ export default function SearchEdit( { width: `${ width }${ widthUnit }`, } } className="wp-block-search__inside-wrapper" + style={ getWrapperStyles() } minWidth={ MIN_WIDTH } enable={ getResizableSides() } onResizeStart={ ( event, direction, elt ) => { diff --git a/packages/block-library/src/search/index.php b/packages/block-library/src/search/index.php index c988ae3b93e408..eba67deeecdce6 100644 --- a/packages/block-library/src/search/index.php +++ b/packages/block-library/src/search/index.php @@ -36,7 +36,7 @@ function render_block_core_search( $attributes ) { $label_markup = ''; $input_markup = ''; $button_markup = ''; - $width_styles = ''; + $inline_styles = styles_for_block_core_search( $attributes ); if ( $show_label ) { if ( ! empty( $attributes['label'] ) ) { @@ -56,10 +56,11 @@ function render_block_core_search( $attributes ) { if ( $show_input ) { $input_markup = sprintf( - '', + '', $input_id, esc_attr( get_search_query() ), - esc_attr( $attributes['placeholder'] ) + esc_attr( $attributes['placeholder'] ), + $inline_styles['shared'] ); } @@ -80,20 +81,16 @@ function render_block_core_search( $attributes ) { } $button_markup = sprintf( - '', + '', + $button_classes, + $inline_styles['shared'], $button_internal_markup ); } - if ( ! empty( $attributes['width'] ) && ! empty( $attributes['widthUnit'] ) ) { - if ( ! empty( $attributes['buttonPosition'] ) && 'button-only' !== $attributes['buttonPosition'] ) { - $width_styles = ' style="width: ' . $attributes['width'] . $attributes['widthUnit'] . ';"'; - } - } - $field_markup = sprintf( '
%s
', - $width_styles, + $inline_styles['wrapper'], $input_markup . $button_markup ); $wrapper_attributes = get_block_wrapper_attributes( array( 'class' => $classnames ) ); @@ -159,3 +156,58 @@ function classnames_for_block_core_search( $attributes ) { return implode( ' ', $classnames ); } + +/** + * Builds an array of inline styles for the search block. + * + * The result will contain one entry for shared styles such as those for the + * inner input or button and a second for the inner wrapper should the block + * be positioning the button "inside". + * + * @param array $attributes The block attributes. + * + * @return array Style HTML attribute. + */ +function styles_for_block_core_search( $attributes ) { + $shared_styles = array(); + $wrapper_styles = array(); + + // Add width styles. + $has_width = ! empty( $attributes['width'] ) && ! empty( $attributes['widthUnit'] ); + $button_only = ! empty( $attributes['buttonPosition'] ) && 'button-only' === $attributes['buttonPosition']; + + if ( $has_width && ! $button_only ) { + $wrapper_styles[] = sprintf( + 'width: %d%s;', + esc_attr( $attributes['width'] ), + esc_attr( $attributes['widthUnit'] ) + ); + } + + // Add border radius styles. + $has_border_radius = ! empty( $attributes['style']['border']['radius'] ); + + if ( $has_border_radius ) { + // Shared style for button and input radius values. + $border_radius = $attributes['style']['border']['radius']; + $shared_styles[] = sprintf( 'border-radius: %spx;', esc_attr( $border_radius ) ); + + // Apply wrapper border radius if button placed inside. + $button_inside = ! empty( $attributes['buttonPosition'] ) && + 'button-inside' === $attributes['buttonPosition']; + + if ( $button_inside ) { + // We adjust the border radius value for the outer wrapper element + // to make it visually consistent with the radius applied to inner + // elements. + $default_padding = 4; + $adjusted_radius = $border_radius + $default_padding; + $wrapper_styles[] = sprintf( 'border-radius: %dpx;', esc_attr( $adjusted_radius ) ); + } + } + + return array( + 'shared' => ! empty( $shared_styles ) ? sprintf( ' style="%s"', implode( ' ', $shared_styles ) ) : '', + 'wrapper' => ! empty( $wrapper_styles ) ? sprintf( ' style="%s"', implode( ' ', $wrapper_styles ) ) : '', + ); +} From 7ba86d2284b85134d752fb058d37306b0af1e034 Mon Sep 17 00:00:00 2001 From: Joen A <1204802+jasmussen@users.noreply.github.com> Date: Wed, 7 Apr 2021 09:41:02 +0200 Subject: [PATCH 018/125] Make the navigation placeholder clearer. (#30281) --- .../block-library/src/navigation/editor.scss | 33 ++++++++++++++++++- .../src/navigation/placeholder.js | 19 ++++++++--- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/packages/block-library/src/navigation/editor.scss b/packages/block-library/src/navigation/editor.scss index 1dacf5f63d195d..fdc50a010e89e3 100644 --- a/packages/block-library/src/navigation/editor.scss +++ b/packages/block-library/src/navigation/editor.scss @@ -282,6 +282,31 @@ $color-control-label-height: 20px; margin-right: $grid-unit-15; height: $button-size; // Prevents jumpiness. } + + // Block title + .wp-block-navigation-placeholder__actions__indicator { + margin-right: $grid-unit-15; + padding: ($grid-unit-15 / 2) 0; + align-items: center; + justify-content: flex-start; + display: none; + + // line up with the icon in the toolbar. + margin-left: $grid-unit-05 + $border-width; + + svg { + margin-right: $grid-unit-05; + } + + .is-vertical & { + margin-bottom: $grid-unit-05; + margin-left: 0; + } + + @include break-small { + display: inline-flex; + } + } } // When block is vertical. @@ -302,8 +327,14 @@ $color-control-label-height: 20px; font-size: $default-font-size; .components-button.components-dropdown-menu__toggle.has-icon { - padding: ($grid-unit-15 / 2) $grid-unit-15; + padding: ($grid-unit-15 / 2) $grid-unit-05 ($grid-unit-15 / 2) $grid-unit-15; display: flex; flex-direction: row-reverse; // This puts the chevron, which is hidden from screen readers, on the right. } + + // Margins. + .components-dropdown, + > .components-button { + margin-right: $grid-unit-15; + } } diff --git a/packages/block-library/src/navigation/placeholder.js b/packages/block-library/src/navigation/placeholder.js index 0ab80bc0e777bc..c0ac1b6ff4c301 100644 --- a/packages/block-library/src/navigation/placeholder.js +++ b/packages/block-library/src/navigation/placeholder.js @@ -22,7 +22,7 @@ import { useEffect, } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; -import { chevronDown } from '@wordpress/icons'; +import { navigation, chevronDown, Icon } from '@wordpress/icons'; import { store as coreStore } from '@wordpress/core-data'; /** @@ -212,6 +212,10 @@ function NavigationPlaceholder( { onCreate }, ref ) { } }, [ isCreatingFromMenu, hasResolvedMenuItems ] ); + const toggleProps = { + isPrimary: true, + className: 'wp-block-navigation-placeholder__actions__dropdown', + }; return (
@@ -227,11 +231,14 @@ function NavigationPlaceholder( { onCreate }, ref ) { ref={ ref } className="wp-block-navigation-placeholder__actions" > +
+ { __( 'Navigation' ) } +
{ hasMenus ? ( { ( { onClose } ) => ( @@ -256,11 +263,15 @@ function NavigationPlaceholder( { onCreate }, ref ) { ) : undefined } { hasPages ? ( - ) : undefined } -
From e94c993680d4a2459d518b94516904a9f1d2f498 Mon Sep 17 00:00:00 2001 From: Grzegorz Date: Wed, 7 Apr 2021 10:23:51 +0200 Subject: [PATCH 019/125] Fix snackbar list component blocking clicks to UI it overlaps (#30381) * add pointer events in order to control the behaviout of snackbars * remove styles from #21000 * Move implementation entirely to snackbar component and add some comments Co-authored-by: grzim Co-authored-by: Daniel Richards --- packages/components/src/snackbar/style.scss | 9 +++++++++ packages/editor/src/components/editor-notices/style.scss | 7 ------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/components/src/snackbar/style.scss b/packages/components/src/snackbar/style.scss index bfc5c9b7480ace..74d786133f11a4 100644 --- a/packages/components/src/snackbar/style.scss +++ b/packages/components/src/snackbar/style.scss @@ -11,6 +11,10 @@ box-sizing: border-box; cursor: pointer; + // Re-enable pointer events, which are disabled by the + // .components-snackbar-list styles. + pointer-events: auto; + @include break-small() { width: fit-content; } @@ -77,6 +81,11 @@ z-index: z-index(".components-snackbar-list"); width: 100%; box-sizing: border-box; + + // Disable pointer events, so that clicking this area + // outside of an individual notice still allows the UI + // underneath to be clicked. + pointer-events: none; } .components-snackbar-list__notice-container { diff --git a/packages/editor/src/components/editor-notices/style.scss b/packages/editor/src/components/editor-notices/style.scss index 86a1013b9b48ac..8ce8fb9004e33c 100644 --- a/packages/editor/src/components/editor-notices/style.scss +++ b/packages/editor/src/components/editor-notices/style.scss @@ -32,10 +32,3 @@ } } } - -.components-editor-notices__snackbar { - width: 100%; - @include break-medium() { - width: fit-content; - } -} From 9be1cef6258cc15ba5e51df83bb5c08a94de0ea9 Mon Sep 17 00:00:00 2001 From: Joen A <1204802+jasmussen@users.noreply.github.com> Date: Wed, 7 Apr 2021 11:25:39 +0200 Subject: [PATCH 020/125] Polish the Site Logo block. (#30526) * Better description. * Start size around 120. * Polish placeholder. * Address feedback and restore sidebar control. --- packages/block-library/src/site-logo/edit.js | 6 +-- .../block-library/src/site-logo/editor.scss | 54 +++++++++++++++++++ packages/block-library/src/site-logo/index.js | 2 +- .../block-library/src/site-logo/style.scss | 9 ++++ 4 files changed, 65 insertions(+), 6 deletions(-) diff --git a/packages/block-library/src/site-logo/edit.js b/packages/block-library/src/site-logo/edit.js index c2daa2e9ceefd5..9c6c52022efad9 100644 --- a/packages/block-library/src/site-logo/edit.js +++ b/packages/block-library/src/site-logo/edit.js @@ -173,7 +173,7 @@ const SiteLogo = ( { return ( <> - + @@ -181,10 +181,6 @@ const SiteLogo = ( { } min={ minWidth } max={ maxWidthBuffer } - initialPosition={ Math.min( - naturalWidth, - maxWidthBuffer - ) } value={ width || '' } disabled={ ! isResizable } /> diff --git a/packages/block-library/src/site-logo/editor.scss b/packages/block-library/src/site-logo/editor.scss index 8cb4592480eca7..bb2ba56d62d159 100644 --- a/packages/block-library/src/site-logo/editor.scss +++ b/packages/block-library/src/site-logo/editor.scss @@ -5,10 +5,25 @@ } .wp-block-site-logo { + // Make the block selectable. + a { + pointer-events: none; + } + &.is-resized { display: table; } + // Provide a sane starting point for the size. + &:not(.is-resized) { + width: 120px; + + img { + width: 100%; + } + } + + .custom-logo-link { cursor: inherit; @@ -25,4 +40,43 @@ display: block; max-width: 100%; } + + // Placeholder improvements. + .components-placeholder { + min-height: auto; + height: 120px; + padding: $grid-unit-10; + + // Massage the label. + .components-placeholder__label { + white-space: nowrap; + } + + .components-placeholder__label .block-editor-block-icon { + margin-right: $grid-unit-05; + } + + // Hide the upload button, as it's also available in the media library. + .components-form-file-upload { + display: none; + } + + // Position the spinner. + .components-placeholder__preview { + position: absolute; + top: $grid-unit-05; + right: $grid-unit-05; + bottom: $grid-unit-05; + left: $grid-unit-05; + background: rgba($white, 0.8); + display: flex; + align-items: center; + justify-content: center; + } + + // Hide drag and drop text. + .components-drop-zone__content-text { + display: none; + } + } } diff --git a/packages/block-library/src/site-logo/index.js b/packages/block-library/src/site-logo/index.js index 8c7b7d04719387..3ce71eacd2e25f 100644 --- a/packages/block-library/src/site-logo/index.js +++ b/packages/block-library/src/site-logo/index.js @@ -15,7 +15,7 @@ export { metadata, name }; export const settings = { title: _x( 'Site Logo', 'block title' ), - description: __( 'Show a site logo' ), + description: __( 'Displays and enables editing of the site logo.' ), icon, styles: [ { diff --git a/packages/block-library/src/site-logo/style.scss b/packages/block-library/src/site-logo/style.scss index a7f69e834055ac..774a701f6fc6e3 100644 --- a/packages/block-library/src/site-logo/style.scss +++ b/packages/block-library/src/site-logo/style.scss @@ -1,6 +1,15 @@ .wp-block-site-logo { line-height: 0; + a { + display: inline-block; + } + + // Provide a sane starting point for the size. + &:not(.is-resized) img { + width: 120px; + } + .aligncenter { display: table; } From f436298db36f057c18a2634979fbeb4b99f8ccf0 Mon Sep 17 00:00:00 2001 From: Bart Kalisz Date: Wed, 7 Apr 2021 11:32:58 +0200 Subject: [PATCH 021/125] Components: Query autocomplete by the term from last trigger prefix (#30540) --- packages/components/src/autocomplete/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/components/src/autocomplete/index.js b/packages/components/src/autocomplete/index.js index 8138d355285fa6..af1b9a7c611b7f 100644 --- a/packages/components/src/autocomplete/index.js +++ b/packages/components/src/autocomplete/index.js @@ -472,9 +472,9 @@ function Autocomplete( { } const safeTrigger = escapeRegExp( completer.triggerPrefix ); - const match = text.match( - new RegExp( `${ safeTrigger }([\u0000-\uFFFF]*)$` ) - ); + const match = text + .slice( text.lastIndexOf( completer.triggerPrefix ) ) + .match( new RegExp( `${ safeTrigger }([\u0000-\uFFFF]*)$` ) ); const query = match && match[ 1 ]; setAutocompleter( completer ); From 106bbaaa81edeabfdcacb06787e893a6c7a62d35 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Wed, 7 Apr 2021 12:08:22 +0100 Subject: [PATCH 022/125] Site title block: Remove custom theme.json selector (#30558) --- packages/block-library/src/site-title/block.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/block-library/src/site-title/block.json b/packages/block-library/src/site-title/block.json index b237bc8cafc84c..d0c03447e14609 100644 --- a/packages/block-library/src/site-title/block.json +++ b/packages/block-library/src/site-title/block.json @@ -22,7 +22,6 @@ "fontSize": true, "lineHeight": true, "__experimentalFontFamily": true, - "__experimentalSelector": ".wp-block-site-title, .wp-block-site-title > a", "__experimentalTextTransform": true } } From 8fafc51e60270eaa982d6ed10844a29dac351472 Mon Sep 17 00:00:00 2001 From: Gutenberg Repository Automation Date: Wed, 7 Apr 2021 11:20:52 +0000 Subject: [PATCH 023/125] Bump plugin version to 10.3.2 --- gutenberg.php | 2 +- package-lock.json | 2 +- package.json | 2 +- readme.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gutenberg.php b/gutenberg.php index 06561f7d0b06b6..6f10a976f80587 100644 --- a/gutenberg.php +++ b/gutenberg.php @@ -5,7 +5,7 @@ * Description: Printing since 1440. This is the development plugin for the new block editor in core. * Requires at least: 5.6 * Requires PHP: 5.6 - * Version: 10.3.1 + * Version: 10.3.2 * Author: Gutenberg Team * Text Domain: gutenberg * diff --git a/package-lock.json b/package-lock.json index df3e2ebd8825dc..512c6c8f9d3645 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "10.3.1", + "version": "10.3.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index a65896086d3acc..3d255eba0bf4a6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "10.3.1", + "version": "10.3.2", "private": true, "description": "A new WordPress editor experience.", "author": "The WordPress Contributors", diff --git a/readme.txt b/readme.txt index 55143c81c6ddd2..7b6fd1e59260c5 100644 --- a/readme.txt +++ b/readme.txt @@ -55,4 +55,4 @@ View release page. +To read the changelog for Gutenberg 10.3.2, please navigate to the release page. From 886b96137875e7e865ebe11d7c30b0060aedde29 Mon Sep 17 00:00:00 2001 From: Gutenberg Repository Automation Date: Wed, 7 Apr 2021 11:32:31 +0000 Subject: [PATCH 024/125] Update Changelog for 10.3.2 --- changelog.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/changelog.txt b/changelog.txt index 2fb596dc5c402c..acdac28a5fc0cf 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,21 @@ == Changelog == += 10.3.2 = + +### Enhancements + +- Remove the default block margins from themes with theme.json file. ([30375](https://github.com/WordPress/gutenberg/pull/30375)) + +### Bug Fixes + +- Site title block: Remove custom theme.json selector. ([30558](https://github.com/WordPress/gutenberg/pull/30558)) +- Components: Query autocomplete by the term from last trigger prefix character. ([30540](https://github.com/WordPress/gutenberg/pull/30540)) +- Bug fixes backported in WordPress minor release. ([30528](https://github.com/WordPress/gutenberg/pull/30528)) +- Rich Text: Fix multi-select copy. ([30197](https://github.com/WordPress/gutenberg/pull/30197)) + + + + = 10.3.1 = ### Bug Fixes From 3542708084769041425c14e38031ab4206816be5 Mon Sep 17 00:00:00 2001 From: Jon Desrosiers Date: Wed, 7 Apr 2021 07:41:19 -0400 Subject: [PATCH 025/125] Include NodeJS version in the cache key when multiple versions of NodeJS are tested. (#30512) --- .github/workflows/create-block.yml | 2 +- .github/workflows/unit-test.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/create-block.yml b/.github/workflows/create-block.yml index d76c2077c3a819..ac1c8230b08e67 100644 --- a/.github/workflows/create-block.yml +++ b/.github/workflows/create-block.yml @@ -25,7 +25,7 @@ jobs: - name: Cache node modules uses: actions/cache@26968a09c0ea4f3e233fdddbafd1166051a095f6 # v2.1.4 env: - cache-name: cache-node-modules + cache-name: cache-node-modules-${{ matrix.node }} with: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 9181981db99b0e..509acf8d941f69 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -29,7 +29,7 @@ jobs: - name: Cache node modules uses: actions/cache@26968a09c0ea4f3e233fdddbafd1166051a095f6 # v2.1.4 env: - cache-name: cache-node-modules + cache-name: cache-node-modules-${{ matrix.node }} with: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm From 3a7ef4c0e1955acb6b5ecb1e74bc9f40eaf7f1fa Mon Sep 17 00:00:00 2001 From: Jon Desrosiers Date: Wed, 7 Apr 2021 08:00:36 -0400 Subject: [PATCH 026/125] Testing: Remove cache `restore-keys`. (#30510) * Remove cache `restore-keys`. While specifying backup `restore-keys` is great in theory, it results in cache snowballing. * Make a small dependency update to change the package-lock.json file. --- .github/workflows/build-plugin-zip.yml | 4 ---- .github/workflows/create-block.yml | 4 ---- .github/workflows/end2end-test.yml | 4 ---- .github/workflows/performance.yml | 4 ---- .github/workflows/rnmobile-android-runner.yml | 3 --- .github/workflows/rnmobile-ios-runner.yml | 7 ------- .github/workflows/static-checks.yml | 4 ---- .github/workflows/storybook-pages.yml | 4 ---- .github/workflows/unit-test.yml | 12 ------------ package-lock.json | 6 +++--- package.json | 2 +- 11 files changed, 4 insertions(+), 50 deletions(-) diff --git a/.github/workflows/build-plugin-zip.yml b/.github/workflows/build-plugin-zip.yml index 0e753ce816e21d..19cf5ca106a040 100644 --- a/.github/workflows/build-plugin-zip.yml +++ b/.github/workflows/build-plugin-zip.yml @@ -122,10 +122,6 @@ jobs: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- - ${{ runner.os }}-build- - ${{ runner.os }}- - name: Build Gutenberg plugin ZIP file run: ./bin/build-plugin-zip.sh diff --git a/.github/workflows/create-block.yml b/.github/workflows/create-block.yml index ac1c8230b08e67..167dcd061c0a84 100644 --- a/.github/workflows/create-block.yml +++ b/.github/workflows/create-block.yml @@ -30,10 +30,6 @@ jobs: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- - ${{ runner.os }}-build- - ${{ runner.os }}- - name: npm install, build, format and lint run: | diff --git a/.github/workflows/end2end-test.yml b/.github/workflows/end2end-test.yml index 11a3bdd4385756..2d7cc32f96ddef 100644 --- a/.github/workflows/end2end-test.yml +++ b/.github/workflows/end2end-test.yml @@ -34,10 +34,6 @@ jobs: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- - ${{ runner.os }}-build- - ${{ runner.os }}- - name: Npm install and build run: | diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index 5dd89194808e17..c9d068b53f3765 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -27,10 +27,6 @@ jobs: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- - ${{ runner.os }}-build- - ${{ runner.os }}- - name: Npm install run: | diff --git a/.github/workflows/rnmobile-android-runner.yml b/.github/workflows/rnmobile-android-runner.yml index f639570acc38d3..a247dc6aa35d7d 100644 --- a/.github/workflows/rnmobile-android-runner.yml +++ b/.github/workflows/rnmobile-android-runner.yml @@ -26,8 +26,6 @@ jobs: with: path: ~/.npm key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }} - restore-keys: | - ${{ runner.os }}-npm- - run: npm ci @@ -36,7 +34,6 @@ jobs: with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} - restore-keys: ${{ runner.os }}-gradle - uses: reactivecircus/android-emulator-runner@d2799957d660add41c61a5103e2fbb9e2889eb73 # v2.15.0 with: diff --git a/.github/workflows/rnmobile-ios-runner.yml b/.github/workflows/rnmobile-ios-runner.yml index f9c42242709b81..56503aa72edf71 100644 --- a/.github/workflows/rnmobile-ios-runner.yml +++ b/.github/workflows/rnmobile-ios-runner.yml @@ -26,8 +26,6 @@ jobs: with: path: ~/.npm key: ${{ runner.os }}-npm-${{ hashFiles('package-lock.json') }} - restore-keys: | - ${{ runner.os }}-npm- - run: npm ci @@ -51,11 +49,6 @@ jobs: ~/.cocoapods/repos/trunk packages/react-native-editor/ios/vendor key: ${{ runner.os }}-pods-${{ hashFiles('packages/react-native-editor/ios/Gemfile.lock') }}-${{ hashFiles('packages/react-native-editor/ios/Podfile.lock') }}-${{ hashFiles('package-lock.json') }} - restore-keys: | - ${{ runner.os }}-pods-${{ hashFiles('packages/react-native-editor/ios/Gemfile.lock') }}-${{ hashFiles('packages/react-native-editor/ios/Podfile.lock') }}-${{ hashFiles('package-lock.json') }} - ${{ runner.os }}-pods-${{ hashFiles('packages/react-native-editor/ios/Gemfile.lock') }}-${{ hashFiles('packages/react-native-editor/ios/Podfile.lock') }}- - ${{ runner.os }}-pods-${{ hashFiles('packages/react-native-editor/ios/Gemfile.lock') }}- - ${{ runner.os }}-pods- - name: Bundle iOS run: npm run native test:e2e:bundle:ios diff --git a/.github/workflows/static-checks.yml b/.github/workflows/static-checks.yml index 2c3baf15d59573..26c56de20ac881 100644 --- a/.github/workflows/static-checks.yml +++ b/.github/workflows/static-checks.yml @@ -29,10 +29,6 @@ jobs: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- - ${{ runner.os }}-build- - ${{ runner.os }}- - name: Npm install and build # A "full" install is executed, since `npm ci` does not always exit diff --git a/.github/workflows/storybook-pages.yml b/.github/workflows/storybook-pages.yml index fa5cbc86ab2662..5d9de94c4267b5 100644 --- a/.github/workflows/storybook-pages.yml +++ b/.github/workflows/storybook-pages.yml @@ -27,10 +27,6 @@ jobs: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- - ${{ runner.os }}-build- - ${{ runner.os }}- - name: Install Dependencies run: npm ci diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 509acf8d941f69..01d11cb8090485 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -34,10 +34,6 @@ jobs: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- - ${{ runner.os }}-build- - ${{ runner.os }}- - name: Npm install and build # It's not necessary to run the full build, since Jest can interpret @@ -74,10 +70,6 @@ jobs: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- - ${{ runner.os }}-build- - ${{ runner.os }}- - name: Npm install and build run: | @@ -121,10 +113,6 @@ jobs: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.os }}-build-${{ env.cache-name }}- - ${{ runner.os }}-build- - ${{ runner.os }}- - name: Npm install and build # It's not necessary to run the full build, since Jest can interpret diff --git a/package-lock.json b/package-lock.json index 512c6c8f9d3645..877db828a4e677 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50106,9 +50106,9 @@ } }, "sass": { - "version": "1.26.11", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.26.11.tgz", - "integrity": "sha512-W1l/+vjGjIamsJ6OnTe0K37U2DBO/dgsv2Z4c89XQ8ZOO6l/VwkqwLSqoYzJeJs6CLuGSTRWc91GbQFL3lvrvw==", + "version": "1.26.12", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.26.12.tgz", + "integrity": "sha512-hmSwtBOWoS9zwe0yAS+QmaseVCUELiGV22gXHDR7+9stEsVuEuxfY1GhC8XmUpC+Ir3Hwq7NxSUNbnmkznnF7g==", "dev": true, "requires": { "chokidar": ">=2.0.0 <4.0.0" diff --git a/package.json b/package.json index 3d255eba0bf4a6..8adc33279b9650 100644 --- a/package.json +++ b/package.json @@ -193,7 +193,7 @@ "react-test-renderer": "16.13.1", "rimraf": "3.0.2", "rtlcss": "2.6.2", - "sass": "1.26.11", + "sass": "1.26.12", "sass-loader": "8.0.2", "semver": "7.3.2", "simple-git": "^2.35.0", From 88745a96210a1a182c81c35a2d45e4c2a79cda7e Mon Sep 17 00:00:00 2001 From: Nik Tsekouras Date: Wed, 7 Apr 2021 15:16:16 +0300 Subject: [PATCH 027/125] return nothing if empty content (#30554) --- packages/block-library/src/query-pagination-numbers/index.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/block-library/src/query-pagination-numbers/index.php b/packages/block-library/src/query-pagination-numbers/index.php index 14be314b322822..34472a5e741f76 100644 --- a/packages/block-library/src/query-pagination-numbers/index.php +++ b/packages/block-library/src/query-pagination-numbers/index.php @@ -55,6 +55,9 @@ function render_block_core_query_pagination_numbers( $attributes, $content, $blo wp_reset_postdata(); // Restore original Post Data. $wp_query = $prev_wp_query; } + if ( empty( $content ) ) { + return ''; + } return sprintf( '
%2$s
', $wrapper_attributes, From 3041158595d2c92a218bd8c1b1641ca338f7c697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Wrede?= Date: Wed, 7 Apr 2021 14:19:42 +0200 Subject: [PATCH 028/125] Fix Typos (#30537) --- lib/block-supports/layout.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index a5ab0dbf261a59..cf02cf5fb877ad 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -88,8 +88,8 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { Date: Wed, 7 Apr 2021 08:16:17 -0500 Subject: [PATCH 029/125] Transform Blocks (#28453) * WC: WIP: Adding transform block ability with no filters. Also refactored options picker for block settings to have options in one object for better filtering and separated out props to the three different types. * Moving getPossibleBLockTransformations to block menu so that we can tell if there are no valid transformation options and if so, not pop up transform option. * Adding filter hook to modify transform.isMatch for each registered block depending on if they are allowed to transform. * Separating out transform logic into transforms.native.js. Adding all block transformation categories in. * Removing extraneous transforms.native.js file. Adding a fix for transforming group -> column block that resulted in crash. * Adding ' blocks' to end of transformations which split one block into multiple. Co-authored-by: Wendy Chen --- .../src/components/block-list/index.native.js | 2 +- .../block-actions-menu.native.js | 276 ++++++++++-------- .../block-transformations-menu.native.js | 91 ++++++ .../src/audio/transforms.native.js | 12 + .../src/buttons/transforms.native.js | 12 + .../src/code/transforms.native.js | 12 + .../block-library/src/column/edit.native.js | 4 + .../src/columns/transforms.native.js | 12 + .../src/cover/transforms.native.js | 12 + .../src/embed/transforms.native.js | 12 + .../src/file/transforms.native.js | 12 + .../src/gallery/transforms.native.js | 12 + .../src/heading/transforms.native.js | 12 + .../src/html/transforms.native.js | 11 + .../src/image/transforms.native.js | 12 + packages/block-library/src/index.native.js | 24 ++ .../src/list/transforms.native.js | 12 + .../src/media-text/transforms.native.js | 12 + .../src/more/transforms.native.js | 12 + .../src/nextpage/transforms.native.js | 12 + .../src/paragraph/transforms.native.js | 12 + .../src/preformatted/transforms.native.js | 12 + .../src/pullquote/transforms.native.js | 12 + .../src/quote/transforms.native.js | 12 + .../src/separator/transforms.native.js | 12 + .../src/shortcode/transforms.native.js | 12 + .../src/table/transforms.native.js | 11 + .../src/text-columns/transforms.native.js | 12 + .../src/transformationCategories.native.js | 46 +++ .../src/verse/transforms.native.js | 12 + .../src/video/transforms.native.js | 12 + packages/blocks/src/api/factory.js | 33 ++- 32 files changed, 646 insertions(+), 128 deletions(-) create mode 100644 packages/block-editor/src/components/block-switcher/block-transformations-menu.native.js create mode 100644 packages/block-library/src/audio/transforms.native.js create mode 100644 packages/block-library/src/buttons/transforms.native.js create mode 100644 packages/block-library/src/code/transforms.native.js create mode 100644 packages/block-library/src/columns/transforms.native.js create mode 100644 packages/block-library/src/cover/transforms.native.js create mode 100644 packages/block-library/src/embed/transforms.native.js create mode 100644 packages/block-library/src/file/transforms.native.js create mode 100644 packages/block-library/src/gallery/transforms.native.js create mode 100644 packages/block-library/src/heading/transforms.native.js create mode 100644 packages/block-library/src/html/transforms.native.js create mode 100644 packages/block-library/src/image/transforms.native.js create mode 100644 packages/block-library/src/list/transforms.native.js create mode 100644 packages/block-library/src/media-text/transforms.native.js create mode 100644 packages/block-library/src/more/transforms.native.js create mode 100644 packages/block-library/src/nextpage/transforms.native.js create mode 100644 packages/block-library/src/paragraph/transforms.native.js create mode 100644 packages/block-library/src/preformatted/transforms.native.js create mode 100644 packages/block-library/src/pullquote/transforms.native.js create mode 100644 packages/block-library/src/quote/transforms.native.js create mode 100644 packages/block-library/src/separator/transforms.native.js create mode 100644 packages/block-library/src/shortcode/transforms.native.js create mode 100644 packages/block-library/src/table/transforms.native.js create mode 100644 packages/block-library/src/text-columns/transforms.native.js create mode 100644 packages/block-library/src/transformationCategories.native.js create mode 100644 packages/block-library/src/verse/transforms.native.js create mode 100644 packages/block-library/src/video/transforms.native.js diff --git a/packages/block-editor/src/components/block-list/index.native.js b/packages/block-editor/src/components/block-list/index.native.js index 9ca43f790e5b82..c60163cf9a3bee 100644 --- a/packages/block-editor/src/components/block-list/index.native.js +++ b/packages/block-editor/src/components/block-list/index.native.js @@ -60,7 +60,7 @@ export class BlockList extends Component { renderFooterAppender: this.props.renderFooterAppender, renderAppender: this.props.renderAppender, onDeleteBlock: this.props.onDeleteBlock, - contentStyle: this.props.contentstyle, + contentStyle: this.props.contentStyle, }; this.renderItem = this.renderItem.bind( this ); this.renderBlockListFooter = this.renderBlockListFooter.bind( this ); diff --git a/packages/block-editor/src/components/block-mobile-toolbar/block-actions-menu.native.js b/packages/block-editor/src/components/block-mobile-toolbar/block-actions-menu.native.js index 735abb833e4fee..a5cc68adaf85e3 100644 --- a/packages/block-editor/src/components/block-mobile-toolbar/block-actions-menu.native.js +++ b/packages/block-editor/src/components/block-mobile-toolbar/block-actions-menu.native.js @@ -31,31 +31,37 @@ import { store as noticesStore } from '@wordpress/notices'; */ import { getMoversSetup } from '../block-mover/mover-description'; import { store as blockEditorStore } from '../../store'; +import BlockTransformationsMenu from '../block-switcher/block-transformations-menu'; const BlockActionsMenu = ( { - onDelete, - isStackedHorizontally, - wrapBlockSettings, - wrapBlockMover, - openGeneralSidebar, - onMoveDown, - onMoveUp, - isFirst, - isLast, + // Select blockTitle, - isEmptyDefaultBlock, - anchorNodeRef, + canInsertBlockType, getBlocksByClientId, + isEmptyDefaultBlock, + isFirst, + isLast, + rootClientId, selectedBlockClientId, + selectedBlockPossibleTransformations, + // Dispatch createSuccessNotice, duplicateBlock, - removeBlocks, + onMoveDown, + onMoveUp, + openGeneralSidebar, pasteBlock, - canInsertBlockType, - rootClientId, + removeBlocks, + // Passed in + anchorNodeRef, + isStackedHorizontally, + onDelete, + wrapBlockMover, + wrapBlockSettings, } ) => { const [ clipboard, setCurrentClipboard ] = useState( getClipboard() ); - const pickerRef = useRef(); + const blockActionsMenuPickerRef = useRef(); + const blockTransformationMenuPickerRef = useRef(); const moversOptions = { keys: [ 'icon', 'actionTitle' ] }; const clipboardBlock = clipboard && rawHandler( { HTML: clipboard } )[ 0 ]; const isPasteEnabled = @@ -69,134 +75,137 @@ const BlockActionsMenu = ( { }, } = getMoversSetup( isStackedHorizontally, moversOptions ); - const deleteOption = { - id: 'deleteOption', - label: __( 'Remove block' ), - value: 'deleteOption', - separated: true, - disabled: isEmptyDefaultBlock, - }; - - const settingsOption = { - id: 'settingsOption', - label: __( 'Block settings' ), - value: 'settingsOption', - }; - - const backwardButtonOption = { - id: 'backwardButtonOption', - label: backwardButtonTitle, - value: 'backwardButtonOption', - disabled: isFirst, - }; - - const forwardButtonOption = { - id: 'forwardButtonOption', - label: forwardButtonTitle, - value: 'forwardButtonOption', - disabled: isLast, - }; - - const copyButtonOption = { - id: 'copyButtonOption', - label: __( 'Copy block' ), - value: 'copyButtonOption', - }; - - const cutButtonOption = { - id: 'cutButtonOption', - label: __( 'Cut block' ), - value: 'cutButtonOption', - }; - - const pasteButtonOption = { - id: 'pasteButtonOption', - label: __( 'Paste block after' ), - value: 'pasteButtonOption', - }; - - const duplicateButtonOption = { - id: 'duplicateButtonOption', - label: __( 'Duplicate block' ), - value: 'duplicateButtonOption', - }; - - const options = compact( [ - wrapBlockMover && backwardButtonOption, - wrapBlockMover && forwardButtonOption, - wrapBlockSettings && settingsOption, - copyButtonOption, - cutButtonOption, - isPasteEnabled && pasteButtonOption, - duplicateButtonOption, - deleteOption, - ] ); - - function onPasteBlock() { - if ( ! clipboard ) { - return; - } - - pasteBlock( rawHandler( { HTML: clipboard } )[ 0 ] ); - } - - function onPickerSelect( value ) { - switch ( value ) { - case deleteOption.value: + const allOptions = { + settings: { + id: 'settingsOption', + label: __( 'Block settings' ), + value: 'settingsOption', + onSelect: openGeneralSidebar, + }, + backwardButton: { + id: 'backwardButtonOption', + label: backwardButtonTitle, + value: 'backwardButtonOption', + disabled: isFirst, + onSelect: onMoveUp, + }, + forwardButton: { + id: 'forwardButtonOption', + label: forwardButtonTitle, + value: 'forwardButtonOption', + disabled: isLast, + onSelect: onMoveDown, + }, + delete: { + id: 'deleteOption', + label: __( 'Remove block' ), + value: 'deleteOption', + separated: true, + disabled: isEmptyDefaultBlock, + onSelect: () => { onDelete(); createSuccessNotice( // translators: displayed right after the block is removed. __( 'Block removed' ) ); - break; - case settingsOption.value: - openGeneralSidebar(); - break; - case forwardButtonOption.value: - onMoveDown(); - break; - case backwardButtonOption.value: - onMoveUp(); - break; - case copyButtonOption.value: - const copyBlock = getBlocksByClientId( selectedBlockClientId ); - const serializedBlock = serialize( copyBlock ); + }, + }, + transformButton: { + id: 'transformButtonOption', + label: __( 'Transform block…' ), + value: 'transformButtonOption', + onSelect: () => { + if ( blockTransformationMenuPickerRef.current ) { + blockTransformationMenuPickerRef.current.presentPicker(); + } + }, + }, + copyButton: { + id: 'copyButtonOption', + label: __( 'Copy block' ), + value: 'copyButtonOption', + onSelect: () => { + const serializedBlock = serialize( + getBlocksByClientId( selectedBlockClientId ) + ); setCurrentClipboard( serializedBlock ); setClipboard( serializedBlock ); createSuccessNotice( // translators: displayed right after the block is copied. __( 'Block copied' ) ); - break; - case cutButtonOption.value: - const cutBlock = getBlocksByClientId( selectedBlockClientId ); - setClipboard( serialize( cutBlock ) ); + }, + }, + cutButton: { + id: 'cutButtonOption', + label: __( 'Cut block' ), + value: 'cutButtonOption', + onSelect: () => { + setClipboard( + serialize( getBlocksByClientId( selectedBlockClientId ) ) + ); removeBlocks( selectedBlockClientId ); createSuccessNotice( // translators: displayed right after the block is cut. __( 'Block cut' ) ); - break; - case pasteButtonOption.value: + }, + }, + pasteButton: { + id: 'pasteButtonOption', + label: __( 'Paste block after' ), + value: 'pasteButtonOption', + onSelect: () => { onPasteBlock(); createSuccessNotice( // translators: displayed right after the block is pasted. __( 'Block pasted' ) ); - break; - case duplicateButtonOption.value: + }, + }, + duplicateButton: { + id: 'duplicateButtonOption', + label: __( 'Duplicate block' ), + value: 'duplicateButtonOption', + onSelect: () => { duplicateBlock(); createSuccessNotice( // translators: displayed right after the block is duplicated. __( 'Block duplicated' ) ); - break; + }, + }, + }; + + const options = compact( [ + wrapBlockMover && allOptions.backwardButton, + wrapBlockMover && allOptions.forwardButton, + wrapBlockSettings && allOptions.settings, + selectedBlockPossibleTransformations.length && + allOptions.transformButton, + allOptions.copyButton, + allOptions.cutButton, + isPasteEnabled && allOptions.pasteButton, + allOptions.duplicateButton, + allOptions.delete, + ] ); + + function onPasteBlock() { + if ( ! clipboard ) { + return; } + + pasteBlock( rawHandler( { HTML: clipboard } )[ 0 ] ); + } + + function onPickerSelect( value ) { + const selectedItem = options.find( ( item ) => item.value === value ); + selectedItem.onSelect(); } function onPickerPresent() { - if ( pickerRef.current ) { - pickerRef.current.presentPicker(); + if ( blockActionsMenuPickerRef.current ) { + blockActionsMenuPickerRef.current.presentPicker(); } } @@ -223,7 +232,7 @@ const BlockActionsMenu = ( { } } /> + ); }; @@ -245,6 +262,7 @@ export default compose( getBlockRootClientId, getBlockOrder, getBlockName, + getBlockTransformItems, getBlock, getBlocksByClientId, getSelectedBlockClientIds, @@ -271,16 +289,24 @@ export default compose( const isEmptyDefaultBlock = isExactlyOneBlock && isDefaultBlock && isEmptyContent; + const selectedBlockClientId = getSelectedBlockClientIds(); + const selectedBlock = getBlocksByClientId( selectedBlockClientId ); + const selectedBlockPossibleTransformations = getBlockTransformItems( + selectedBlock, + rootClientId + ); + return { + blockTitle, + canInsertBlockType, + currentIndex: firstIndex, + getBlocksByClientId, + isEmptyDefaultBlock, isFirst: firstIndex === 0, isLast: lastIndex === blockOrder.length - 1, rootClientId, - blockTitle, - isEmptyDefaultBlock, - getBlocksByClientId, - selectedBlockClientId: getSelectedBlockClientIds(), - currentIndex: firstIndex, - canInsertBlockType, + selectedBlockClientId, + selectedBlockPossibleTransformations, }; } ), withDispatch( @@ -300,15 +326,14 @@ export default compose( const { createSuccessNotice } = dispatch( noticesStore ); return { - onMoveDown: partial( moveBlocksDown, clientIds, rootClientId ), - onMoveUp: partial( moveBlocksUp, clientIds, rootClientId ), - openGeneralSidebar: () => - openGeneralSidebar( 'edit-post/block' ), createSuccessNotice, duplicateBlock() { return duplicateBlocks( clientIds ); }, - removeBlocks, + onMoveDown: partial( moveBlocksDown, clientIds, rootClientId ), + onMoveUp: partial( moveBlocksUp, clientIds, rootClientId ), + openGeneralSidebar: () => + openGeneralSidebar( 'edit-post/block' ), pasteBlock: ( clipboardBlock ) => { const canReplaceBlock = isUnmodifiedDefaultBlock( getBlock( getBlockSelectionEnd() ) @@ -330,6 +355,7 @@ export default compose( replaceBlocks( clientIds, clipboardBlock ); } }, + removeBlocks, }; } ), diff --git a/packages/block-editor/src/components/block-switcher/block-transformations-menu.native.js b/packages/block-editor/src/components/block-switcher/block-transformations-menu.native.js new file mode 100644 index 00000000000000..ce2822d0c6dbc9 --- /dev/null +++ b/packages/block-editor/src/components/block-switcher/block-transformations-menu.native.js @@ -0,0 +1,91 @@ +/** + * External dependencies + */ +import { findNodeHandle, Platform } from 'react-native'; + +/** + * WordPress dependencies + */ +import { __, sprintf } from '@wordpress/i18n'; +import { switchToBlockType } from '@wordpress/blocks'; +import { Picker } from '@wordpress/components'; +import { useDispatch } from '@wordpress/data'; +import { store as noticesStore } from '@wordpress/notices'; + +/** + * Internal dependencies + */ +import { store as blockEditorStore } from '../../store'; + +const BlockTransformationsMenu = ( { + anchorNodeRef, + blockTitle, + pickerRef, + possibleTransformations, + selectedBlock, + selectedBlockClientId, +} ) => { + const { replaceBlocks } = useDispatch( blockEditorStore ); + const { createSuccessNotice } = useDispatch( noticesStore ); + + const pickerOptions = () => { + const selectedBlockName = + ( selectedBlock.length && selectedBlock[ 0 ].name ) || ''; + const blocksThatSplitWhenTransformed = { + 'core/list': [ 'core/paragraph', 'core/heading' ], + 'core/quote': [ 'core/paragraph' ], + 'core/pullquote': [ 'core/paragraph' ], + }; + + return possibleTransformations.map( ( item ) => { + const label = + selectedBlockName.length && + blocksThatSplitWhenTransformed[ selectedBlockName ] && + blocksThatSplitWhenTransformed[ selectedBlockName ].includes( + item.id + ) + ? `${ item.title } blocks` + : item.title; + return { + label, + value: item.id, + }; + } ); + }; + + const getAnchor = () => + anchorNodeRef ? findNodeHandle( anchorNodeRef ) : undefined; + + function onPickerSelect( value ) { + replaceBlocks( + selectedBlockClientId, + switchToBlockType( selectedBlock, value ) + ); + + const selectedItem = pickerOptions().find( + ( item ) => item.value === value + ); + const successNotice = sprintf( + /* translators: 1: From block title, e.g. Paragraph. 2: To block title, e.g. Header. */ + __( '%1$s transformed to %2$s' ), + blockTitle, + selectedItem.label + ); + createSuccessNotice( successNotice ); + } + + return ( + + ); +}; + +export default BlockTransformationsMenu; diff --git a/packages/block-library/src/audio/transforms.native.js b/packages/block-library/src/audio/transforms.native.js new file mode 100644 index 00000000000000..839cdfe3c93810 --- /dev/null +++ b/packages/block-library/src/audio/transforms.native.js @@ -0,0 +1,12 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; +import transformationCategories from '../transformationCategories'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: transformationCategories.media, +}; + +export default transforms; diff --git a/packages/block-library/src/buttons/transforms.native.js b/packages/block-library/src/buttons/transforms.native.js new file mode 100644 index 00000000000000..0816b765fee290 --- /dev/null +++ b/packages/block-library/src/buttons/transforms.native.js @@ -0,0 +1,12 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; +import transformationCategories from '../transformationCategories'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: transformationCategories.other, +}; + +export default transforms; diff --git a/packages/block-library/src/code/transforms.native.js b/packages/block-library/src/code/transforms.native.js new file mode 100644 index 00000000000000..21b6405a15030a --- /dev/null +++ b/packages/block-library/src/code/transforms.native.js @@ -0,0 +1,12 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; +import transformationCategories from '../transformationCategories'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: transformationCategories.richText, +}; + +export default transforms; diff --git a/packages/block-library/src/column/edit.native.js b/packages/block-library/src/column/edit.native.js index 2532629f91616f..bb3bbe045eec43 100644 --- a/packages/block-library/src/column/edit.native.js +++ b/packages/block-library/src/column/edit.native.js @@ -52,6 +52,10 @@ function ColumnEdit( { clientId, blockWidth, } ) { + if ( ! contentStyle ) { + contentStyle = { [ clientId ]: {} }; + } + const { verticalAlignment, width } = attributes; const { valueUnit = '%' } = getValueAndUnit( width ) || {}; diff --git a/packages/block-library/src/columns/transforms.native.js b/packages/block-library/src/columns/transforms.native.js new file mode 100644 index 00000000000000..032a3464258944 --- /dev/null +++ b/packages/block-library/src/columns/transforms.native.js @@ -0,0 +1,12 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; +import transformationCategories from '../transformationCategories'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: transformationCategories.grouped, +}; + +export default transforms; diff --git a/packages/block-library/src/cover/transforms.native.js b/packages/block-library/src/cover/transforms.native.js new file mode 100644 index 00000000000000..839cdfe3c93810 --- /dev/null +++ b/packages/block-library/src/cover/transforms.native.js @@ -0,0 +1,12 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; +import transformationCategories from '../transformationCategories'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: transformationCategories.media, +}; + +export default transforms; diff --git a/packages/block-library/src/embed/transforms.native.js b/packages/block-library/src/embed/transforms.native.js new file mode 100644 index 00000000000000..839cdfe3c93810 --- /dev/null +++ b/packages/block-library/src/embed/transforms.native.js @@ -0,0 +1,12 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; +import transformationCategories from '../transformationCategories'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: transformationCategories.media, +}; + +export default transforms; diff --git a/packages/block-library/src/file/transforms.native.js b/packages/block-library/src/file/transforms.native.js new file mode 100644 index 00000000000000..839cdfe3c93810 --- /dev/null +++ b/packages/block-library/src/file/transforms.native.js @@ -0,0 +1,12 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; +import transformationCategories from '../transformationCategories'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: transformationCategories.media, +}; + +export default transforms; diff --git a/packages/block-library/src/gallery/transforms.native.js b/packages/block-library/src/gallery/transforms.native.js new file mode 100644 index 00000000000000..839cdfe3c93810 --- /dev/null +++ b/packages/block-library/src/gallery/transforms.native.js @@ -0,0 +1,12 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; +import transformationCategories from '../transformationCategories'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: transformationCategories.media, +}; + +export default transforms; diff --git a/packages/block-library/src/heading/transforms.native.js b/packages/block-library/src/heading/transforms.native.js new file mode 100644 index 00000000000000..21b6405a15030a --- /dev/null +++ b/packages/block-library/src/heading/transforms.native.js @@ -0,0 +1,12 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; +import transformationCategories from '../transformationCategories'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: transformationCategories.richText, +}; + +export default transforms; diff --git a/packages/block-library/src/html/transforms.native.js b/packages/block-library/src/html/transforms.native.js new file mode 100644 index 00000000000000..9e7c243a6d8cd5 --- /dev/null +++ b/packages/block-library/src/html/transforms.native.js @@ -0,0 +1,11 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: [], +}; + +export default transforms; diff --git a/packages/block-library/src/image/transforms.native.js b/packages/block-library/src/image/transforms.native.js new file mode 100644 index 00000000000000..839cdfe3c93810 --- /dev/null +++ b/packages/block-library/src/image/transforms.native.js @@ -0,0 +1,12 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; +import transformationCategories from '../transformationCategories'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: transformationCategories.media, +}; + +export default transforms; diff --git a/packages/block-library/src/index.native.js b/packages/block-library/src/index.native.js index d7d9b1e4bbf646..c16a19709ea15b 100644 --- a/packages/block-library/src/index.native.js +++ b/packages/block-library/src/index.native.js @@ -63,6 +63,8 @@ import * as buttons from './buttons'; import * as socialLink from './social-link'; import * as socialLinks from './social-links'; +import { transformationCategory } from './transformationCategories'; + export const coreBlocks = [ // Common blocks are grouped at the top to prioritize their display // in various contexts — like the inserter and auto-complete components. @@ -180,6 +182,28 @@ addFilter( } ); +addFilter( + 'blocks.registerBlockType', + 'core/react-native-editor', + ( settings, name ) => { + if ( ! settings.transforms ) { + return settings; + } + + if ( ! settings.transforms.supportedMobileTransforms ) { + return { + ...settings, + transforms: { + ...settings.transforms, + supportedMobileTransforms: transformationCategory( name ), + }, + }; + } + + return settings; + } +); + /** * Function to register core blocks provided by the block editor. * diff --git a/packages/block-library/src/list/transforms.native.js b/packages/block-library/src/list/transforms.native.js new file mode 100644 index 00000000000000..21b6405a15030a --- /dev/null +++ b/packages/block-library/src/list/transforms.native.js @@ -0,0 +1,12 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; +import transformationCategories from '../transformationCategories'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: transformationCategories.richText, +}; + +export default transforms; diff --git a/packages/block-library/src/media-text/transforms.native.js b/packages/block-library/src/media-text/transforms.native.js new file mode 100644 index 00000000000000..839cdfe3c93810 --- /dev/null +++ b/packages/block-library/src/media-text/transforms.native.js @@ -0,0 +1,12 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; +import transformationCategories from '../transformationCategories'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: transformationCategories.media, +}; + +export default transforms; diff --git a/packages/block-library/src/more/transforms.native.js b/packages/block-library/src/more/transforms.native.js new file mode 100644 index 00000000000000..0816b765fee290 --- /dev/null +++ b/packages/block-library/src/more/transforms.native.js @@ -0,0 +1,12 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; +import transformationCategories from '../transformationCategories'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: transformationCategories.other, +}; + +export default transforms; diff --git a/packages/block-library/src/nextpage/transforms.native.js b/packages/block-library/src/nextpage/transforms.native.js new file mode 100644 index 00000000000000..0816b765fee290 --- /dev/null +++ b/packages/block-library/src/nextpage/transforms.native.js @@ -0,0 +1,12 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; +import transformationCategories from '../transformationCategories'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: transformationCategories.other, +}; + +export default transforms; diff --git a/packages/block-library/src/paragraph/transforms.native.js b/packages/block-library/src/paragraph/transforms.native.js new file mode 100644 index 00000000000000..21b6405a15030a --- /dev/null +++ b/packages/block-library/src/paragraph/transforms.native.js @@ -0,0 +1,12 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; +import transformationCategories from '../transformationCategories'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: transformationCategories.richText, +}; + +export default transforms; diff --git a/packages/block-library/src/preformatted/transforms.native.js b/packages/block-library/src/preformatted/transforms.native.js new file mode 100644 index 00000000000000..21b6405a15030a --- /dev/null +++ b/packages/block-library/src/preformatted/transforms.native.js @@ -0,0 +1,12 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; +import transformationCategories from '../transformationCategories'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: transformationCategories.richText, +}; + +export default transforms; diff --git a/packages/block-library/src/pullquote/transforms.native.js b/packages/block-library/src/pullquote/transforms.native.js new file mode 100644 index 00000000000000..21b6405a15030a --- /dev/null +++ b/packages/block-library/src/pullquote/transforms.native.js @@ -0,0 +1,12 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; +import transformationCategories from '../transformationCategories'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: transformationCategories.richText, +}; + +export default transforms; diff --git a/packages/block-library/src/quote/transforms.native.js b/packages/block-library/src/quote/transforms.native.js new file mode 100644 index 00000000000000..21b6405a15030a --- /dev/null +++ b/packages/block-library/src/quote/transforms.native.js @@ -0,0 +1,12 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; +import transformationCategories from '../transformationCategories'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: transformationCategories.richText, +}; + +export default transforms; diff --git a/packages/block-library/src/separator/transforms.native.js b/packages/block-library/src/separator/transforms.native.js new file mode 100644 index 00000000000000..0816b765fee290 --- /dev/null +++ b/packages/block-library/src/separator/transforms.native.js @@ -0,0 +1,12 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; +import transformationCategories from '../transformationCategories'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: transformationCategories.other, +}; + +export default transforms; diff --git a/packages/block-library/src/shortcode/transforms.native.js b/packages/block-library/src/shortcode/transforms.native.js new file mode 100644 index 00000000000000..21b6405a15030a --- /dev/null +++ b/packages/block-library/src/shortcode/transforms.native.js @@ -0,0 +1,12 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; +import transformationCategories from '../transformationCategories'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: transformationCategories.richText, +}; + +export default transforms; diff --git a/packages/block-library/src/table/transforms.native.js b/packages/block-library/src/table/transforms.native.js new file mode 100644 index 00000000000000..9e7c243a6d8cd5 --- /dev/null +++ b/packages/block-library/src/table/transforms.native.js @@ -0,0 +1,11 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: [], +}; + +export default transforms; diff --git a/packages/block-library/src/text-columns/transforms.native.js b/packages/block-library/src/text-columns/transforms.native.js new file mode 100644 index 00000000000000..032a3464258944 --- /dev/null +++ b/packages/block-library/src/text-columns/transforms.native.js @@ -0,0 +1,12 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; +import transformationCategories from '../transformationCategories'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: transformationCategories.grouped, +}; + +export default transforms; diff --git a/packages/block-library/src/transformationCategories.native.js b/packages/block-library/src/transformationCategories.native.js new file mode 100644 index 00000000000000..9fa4c09cc9bb1a --- /dev/null +++ b/packages/block-library/src/transformationCategories.native.js @@ -0,0 +1,46 @@ +const transformationCategories = { + richText: [ + 'core/paragraph', + 'core/heading', + 'core/list', + 'core/quote', + 'core/pullquote', + 'core/preformatted', + 'core/verse', + 'core/shortcode', + 'core/code', + ], + media: [ + 'core/image', + 'core/video', + 'core/gallery', + 'core/cover', + 'core/file', + 'core/audio', + 'core/media-text', + 'core/embed', + ], + grouped: [ 'core/columns', 'core/group', 'core/text-columns' ], + other: [ + 'core/more', + 'core/nextpage', + 'core/separator', + 'core/spacer', + 'core/latest-posts', + 'core/buttons', + ], +}; + +export const transformationCategory = ( blockName ) => { + const found = Object.entries( + transformationCategories + ).find( ( [ , value ] ) => value.includes( blockName ) ); + if ( ! found ) { + return []; + } + + const group = found[ 0 ]; + return transformationCategories[ group ]; +}; + +export default transformationCategories; diff --git a/packages/block-library/src/verse/transforms.native.js b/packages/block-library/src/verse/transforms.native.js new file mode 100644 index 00000000000000..21b6405a15030a --- /dev/null +++ b/packages/block-library/src/verse/transforms.native.js @@ -0,0 +1,12 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; +import transformationCategories from '../transformationCategories'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: transformationCategories.richText, +}; + +export default transforms; diff --git a/packages/block-library/src/video/transforms.native.js b/packages/block-library/src/video/transforms.native.js new file mode 100644 index 00000000000000..839cdfe3c93810 --- /dev/null +++ b/packages/block-library/src/video/transforms.native.js @@ -0,0 +1,12 @@ +/** + * Internal dependencies + */ +import webTransforms from './transforms.js'; +import transformationCategories from '../transformationCategories'; + +const transforms = { + ...webTransforms, + supportedMobileTransforms: transformationCategories.media, +}; + +export default transforms; diff --git a/packages/blocks/src/api/factory.js b/packages/blocks/src/api/factory.js index 2432597a7ca3ee..5831cfff3e86ef 100644 --- a/packages/blocks/src/api/factory.js +++ b/packages/blocks/src/api/factory.js @@ -229,6 +229,14 @@ const isPossibleTransformForSource = ( transform, direction, blocks ) => { } } + if ( + transform.usingMobileTransformations && + isWildcardBlockTransform( transform ) && + ! isContainerGroupBlock( sourceBlock.name ) + ) { + return false; + } + return true; }; @@ -252,7 +260,6 @@ const getBlockTypesForPossibleFromTransforms = ( blocks ) => { allBlockTypes, ( blockType ) => { const fromTransforms = getBlockTransforms( 'from', blockType.name ); - return !! findTransform( fromTransforms, ( transform ) => { return isPossibleTransformForSource( transform, @@ -412,10 +419,32 @@ export function getBlockTransforms( direction, blockTypeOrName ) { return []; } + const usingMobileTransformations = + transforms.supportedMobileTransforms && + Array.isArray( transforms.supportedMobileTransforms ); + const filteredTransforms = usingMobileTransformations + ? filter( transforms[ direction ], ( t ) => { + if ( ! t.blocks || ! t.blocks.length ) { + return false; + } + + if ( isWildcardBlockTransform( t ) ) { + return true; + } + + return every( t.blocks, ( transformBlockName ) => + transforms.supportedMobileTransforms.includes( + transformBlockName + ) + ); + } ) + : transforms[ direction ]; + // Map transforms to normal form. - return transforms[ direction ].map( ( transform ) => ( { + return filteredTransforms.map( ( transform ) => ( { ...transform, blockName, + usingMobileTransformations, } ) ); } From 8406fc2ee3d4e0ac42aef01f4eff335c75db7d9c Mon Sep 17 00:00:00 2001 From: James Koster Date: Wed, 7 Apr 2021 14:17:15 +0100 Subject: [PATCH 030/125] Update the save button label (#30439) --- packages/edit-site/src/components/save-button/index.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/edit-site/src/components/save-button/index.js b/packages/edit-site/src/components/save-button/index.js index 4c8b4038ea3ca1..f1636a57b8561c 100644 --- a/packages/edit-site/src/components/save-button/index.js +++ b/packages/edit-site/src/components/save-button/index.js @@ -9,7 +9,6 @@ import { some } from 'lodash'; import { useSelect } from '@wordpress/data'; import { Button } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { useViewportMatch } from '@wordpress/compose'; export default function SaveButton( { openEntitiesSavedStates } ) { const { isDirty, isSaving } = useSelect( ( select ) => { @@ -27,7 +26,6 @@ export default function SaveButton( { openEntitiesSavedStates } ) { } ); const disabled = ! isDirty || isSaving; - const isMobile = useViewportMatch( 'medium', '<' ); return ( <> @@ -39,7 +37,7 @@ export default function SaveButton( { openEntitiesSavedStates } ) { isBusy={ isSaving } onClick={ disabled ? undefined : openEntitiesSavedStates } > - { isMobile ? __( 'Update' ) : __( 'Update Design' ) } + { __( 'Save' ) } ); From d17ac7750bb82546a52f5287fb5598615a2f9050 Mon Sep 17 00:00:00 2001 From: sarayourfriend Date: Wed, 7 Apr 2021 06:58:48 -0700 Subject: [PATCH 031/125] Export all types from api-fetch (#30539) --- packages/api-fetch/src/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/api-fetch/src/index.js b/packages/api-fetch/src/index.js index 2b2c6b3508defe..e4ee02b01f65ea 100644 --- a/packages/api-fetch/src/index.js +++ b/packages/api-fetch/src/index.js @@ -43,6 +43,9 @@ const DEFAULT_OPTIONS = { credentials: 'include', }; +/** @typedef {import('./types').ApiFetchMiddleware} ApiFetchMiddleware */ +/** @typedef {import('./types').ApiFetchRequestProps} ApiFetchRequestProps */ + /** * @type {import('./types').ApiFetchMiddleware[]} */ From b76432d46488c3a60eb7e0ac6821029e689ef830 Mon Sep 17 00:00:00 2001 From: Gutenberg Repository Automation Date: Wed, 7 Apr 2021 14:02:10 +0000 Subject: [PATCH 032/125] Bump plugin version to 10.4.0-rc.1 --- gutenberg.php | 2 +- package-lock.json | 2 +- package.json | 2 +- readme.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gutenberg.php b/gutenberg.php index 6f10a976f80587..151de8a8d613e6 100644 --- a/gutenberg.php +++ b/gutenberg.php @@ -5,7 +5,7 @@ * Description: Printing since 1440. This is the development plugin for the new block editor in core. * Requires at least: 5.6 * Requires PHP: 5.6 - * Version: 10.3.2 + * Version: 10.4.0-rc.1 * Author: Gutenberg Team * Text Domain: gutenberg * diff --git a/package-lock.json b/package-lock.json index 877db828a4e677..51db58af73c7c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "10.3.2", + "version": "10.4.0-rc.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 8adc33279b9650..38e92787ab6d7a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "10.3.2", + "version": "10.4.0-rc.1", "private": true, "description": "A new WordPress editor experience.", "author": "The WordPress Contributors", diff --git a/readme.txt b/readme.txt index 7b6fd1e59260c5..aae305cf3cf332 100644 --- a/readme.txt +++ b/readme.txt @@ -55,4 +55,4 @@ View release page. +To read the changelog for Gutenberg 10.4.0-rc.1, please navigate to the release page. From e917cdb515f1ae1e557e92e08df90ab0a6296c82 Mon Sep 17 00:00:00 2001 From: Gutenberg Repository Automation Date: Wed, 7 Apr 2021 14:20:26 +0000 Subject: [PATCH 033/125] Update Changelog for 10.4.0-rc.1 --- changelog.txt | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/changelog.txt b/changelog.txt index acdac28a5fc0cf..c4acfd41d9d259 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,162 @@ == Changelog == += 10.4.0-rc.1 = + + + +### Enhancements + +- Block Library: Add option to make PostDate a link. ([30499](https://github.com/WordPress/gutenberg/pull/30499)) +- Block Library: Update placeholder text across blocks. ([30404](https://github.com/WordPress/gutenberg/pull/30404)) +- RichText: Always show placholder on focus. ([30393](https://github.com/WordPress/gutenberg/pull/30393)) +- List View: Update the hover, focus, select colors. ([30303](https://github.com/WordPress/gutenberg/pull/30303)) +- Try: Darker canvas color. ([30282](https://github.com/WordPress/gutenberg/pull/30282)) +- Make the default padding match the browser's default padding. ([30277](https://github.com/WordPress/gutenberg/pull/30277)) +- Fix separator styles. ([30255](https://github.com/WordPress/gutenberg/pull/30255)) +- Try: Add site icon and name to the publish flow. ([30231](https://github.com/WordPress/gutenberg/pull/30231)) +- Block Library - Quote: Fix the editor/frontend style parity. ([30190](https://github.com/WordPress/gutenberg/pull/30190)) +- Themes: Fix the archives block frontend/editor parity. ([30141](https://github.com/WordPress/gutenberg/pull/30141)) +- Remove latest comments editor styles. ([30134](https://github.com/WordPress/gutenberg/pull/30134)) +- Icons: Update "close small" icon so that its shape matches the "add" icon dimensionally. ([30014](https://github.com/WordPress/gutenberg/pull/30014)) +- Inserter: Clarify that when the Inserter is open clicking the + button in the top bar will close it again. ([29759](https://github.com/WordPress/gutenberg/pull/29759)) +- Writing Flow: Shorter writing prompt. ([29611](https://github.com/WordPress/gutenberg/pull/29611)) +- Latest Comments Block: Remove list padding and margin. ([29402](https://github.com/WordPress/gutenberg/pull/29402)) +- Navigation Screen: Indicate when a menu is deleted and show the menu switcher afterwards. ([29201](https://github.com/WordPress/gutenberg/pull/29201)) + +### Bug Fixes + +- Block Library - Query Pagination Numbers: Print nothing if content is empty. ([30554](https://github.com/WordPress/gutenberg/pull/30554)) +- Code Editor: Revert save editors value on change (#27717). ([30524](https://github.com/WordPress/gutenberg/pull/30524)) +- Block Library: Fix fullwide regression. ([30520](https://github.com/WordPress/gutenberg/pull/30520)) +- Writing flow: Fix horizontal caret placing for empty editable with placeholder. ([30463](https://github.com/WordPress/gutenberg/pull/30463)) +- Block Library: Revert column-gap property for spacing between custom-sized buttons. ([30449](https://github.com/WordPress/gutenberg/pull/30449)) +- Site Editor: Load block-editor scripts & styles. ([30448](https://github.com/WordPress/gutenberg/pull/30448)) +- Block Library: Fix search block alignment issues. ([30444](https://github.com/WordPress/gutenberg/pull/30444)) +- Site editor: Add allowedMimeTypes to site editor settings to fix media upload behaviour and error state. ([30436](https://github.com/WordPress/gutenberg/pull/30436)) +- Build: Ensure non-JS changes are processed in the watch mode. ([30343](https://github.com/WordPress/gutenberg/pull/30343)) +- Navigation: Save theme location on button click. ([30340](https://github.com/WordPress/gutenberg/pull/30340)) +- Inner blocks: Memoize allowedBlocks to prevent needlessly updating settings. ([30311](https://github.com/WordPress/gutenberg/pull/30311)) +- Block Editor: Show only the allowed patterns from top level blocks. ([30300](https://github.com/WordPress/gutenberg/pull/30300)) +- Prevent overlapping button blocks in the frontend. ([30253](https://github.com/WordPress/gutenberg/pull/30253)) +- Block Library: Add 'object-position' to allowed inline style attributes list. ([30243](https://github.com/WordPress/gutenberg/pull/30243)) +- Fix mover position. ([30242](https://github.com/WordPress/gutenberg/pull/30242)) +- Plugin: Ensure that plugin does not error with older versions of WordPress. ([30230](https://github.com/WordPress/gutenberg/pull/30230)) +- Prevent the columns block from having a width > 100%. ([30229](https://github.com/WordPress/gutenberg/pull/30229)) +- Writing Flow: Fix copy pasting non textual blocks. ([30225](https://github.com/WordPress/gutenberg/pull/30225)) +- Fix adding blocks in the widgets customizer. ([30221](https://github.com/WordPress/gutenberg/pull/30221)) +- Editor: Use getAuthors for 'showCombobox' check. ([30218](https://github.com/WordPress/gutenberg/pull/30218)) +- RichText: Fix arrow navigation around emoji. ([30206](https://github.com/WordPress/gutenberg/pull/30206)) +- Block editor - Writing Flow: Fix multi-selection copying in Safari. ([30202](https://github.com/WordPress/gutenberg/pull/30202)) +- Block Library - Gallery: Set 'addToGallery' prop to false when images don't have IDs. ([30122](https://github.com/WordPress/gutenberg/pull/30122)) +- docgen: Fix arrow functions and TS index module support. ([30028](https://github.com/WordPress/gutenberg/pull/30028)) +- Editor: Avoid focus attempt on a non-existent post title in code editor. ([29922](https://github.com/WordPress/gutenberg/pull/29922)) +- Image: Manually update resizable box state when we don't have dimenssions. ([29919](https://github.com/WordPress/gutenberg/pull/29919)) +- Server side renderer: Fix errors in template part editor context. ([29246](https://github.com/WordPress/gutenberg/pull/29246)) + +### Performance + +- Navigation: Add src/navigation-link/index to side effect whitelist. ([30200](https://github.com/WordPress/gutenberg/pull/30200)) + +### Experiments + +- Polish the Site Logo block. ([30526](https://github.com/WordPress/gutenberg/pull/30526)) +- Global Styles: Use "Custom Styles" title to signal there are global styles changes in the saving panel of the site editor. ([30521](https://github.com/WordPress/gutenberg/pull/30521)) +- Block Patterns: Remove `scope` from Query patterns and introduce `blockTypes`. ([30471](https://github.com/WordPress/gutenberg/pull/30471)) +- List View: Update list view icon size and spacing. ([30455](https://github.com/WordPress/gutenberg/pull/30455)) +- Block Library: Delete sitelogo option when custom logo does not exist or was removed. ([30427](https://github.com/WordPress/gutenberg/pull/30427)) +- Block Library - Query: Use a WordPress loop for the query block. ([30405](https://github.com/WordPress/gutenberg/pull/30405)) +- Navigation: Add post format variation to navigation link block. ([30403](https://github.com/WordPress/gutenberg/pull/30403)) +- Site editor: Switch to proper settings tab based on the selection. ([30387](https://github.com/WordPress/gutenberg/pull/30387)) +- Block Library - Navigation: Fix hardcoded color in navigation submenu icon. ([30385](https://github.com/WordPress/gutenberg/pull/30385)) +- Fix snackbar list component blocking clicks to UI it overlaps. ([30381](https://github.com/WordPress/gutenberg/pull/30381)) +- Navigation Block: Avoid creating a new array/object on every render. ([30374](https://github.com/WordPress/gutenberg/pull/30374)) +- Try: Flip orientation of submenus that are towards the right of the viewport. ([30342](https://github.com/WordPress/gutenberg/pull/30342)) +- Polish navigation menu submenus. ([30335](https://github.com/WordPress/gutenberg/pull/30335)) +- Global Styles: Add padding server-side block support. ([30332](https://github.com/WordPress/gutenberg/pull/30332)) +- Widgets Customizer: Add Legacy Widget block. ([30321](https://github.com/WordPress/gutenberg/pull/30321)) +- Block Library - Navigation: Fix arrow inheritance, polish. ([30287](https://github.com/WordPress/gutenberg/pull/30287)) +- Apply mover tweaks to navigation and widgets. ([30284](https://github.com/WordPress/gutenberg/pull/30284)) +- Make the navigation placeholder clearer. ([30281](https://github.com/WordPress/gutenberg/pull/30281)) +- Block Library - Post Excerpt: Fix toolbar for post excerpt warning. ([30280](https://github.com/WordPress/gutenberg/pull/30280)) +- Fix Navigation Link block constantly updating its inner block list settings. ([30274](https://github.com/WordPress/gutenberg/pull/30274)) +- Fix navigation link block dragging error. ([30219](https://github.com/WordPress/gutenberg/pull/30219)) +- Widget block: Handle when $instance is empty and use str_replace instead of sprintf. ([30217](https://github.com/WordPress/gutenberg/pull/30217)) +- Icons: Update site-logo block icon. ([30211](https://github.com/WordPress/gutenberg/pull/30211)) +- Post Title Block - fix "'length' of undefined" error. ([30208](https://github.com/WordPress/gutenberg/pull/30208)) +- Block Library: Fix Query block undo trap during creation. ([30203](https://github.com/WordPress/gutenberg/pull/30203)) +- Navigation: Replace arrow with chevron. ([30180](https://github.com/WordPress/gutenberg/pull/30180)) +- Navigation Block: De-emphasize "Link" block. ([30172](https://github.com/WordPress/gutenberg/pull/30172)) +- Templates: Fix empty block templates output string. ([30145](https://github.com/WordPress/gutenberg/pull/30145)) +- Docs: Add description for `templateParts` in theme json. ([30118](https://github.com/WordPress/gutenberg/pull/30118)) +- Navigation: Use same default implementation of __experimentalFetchLinkSuggestions in post, site, navigation, widget editor. ([29993](https://github.com/WordPress/gutenberg/pull/29993)) +- Iterate on Legacy Widget block. ([29960](https://github.com/WordPress/gutenberg/pull/29960)) +- Block Library - Template Part: Add padding support to template parts. ([29779](https://github.com/WordPress/gutenberg/pull/29779)) +- Site Editor: Revert custom templates to their original theme-provided files. ([28141](https://github.com/WordPress/gutenberg/pull/28141)) + +### Documentation + +- Docs: Fix typos in layout supports comment. ([30537](https://github.com/WordPress/gutenberg/pull/30537)) +- Fix example code for apiFetch middlewares. ([30534](https://github.com/WordPress/gutenberg/pull/30534)) +- Fix typos in block-controls-toolbar-and-sidebar.md. ([30513](https://github.com/WordPress/gutenberg/pull/30513)) +- Handbook: Rename, changed URL Link. ([30483](https://github.com/WordPress/gutenberg/pull/30483)) +- Block Editor: Fix block-editor typo. ([30401](https://github.com/WordPress/gutenberg/pull/30401)) +- Handbook: Added a practical example of adding a component to the sidebar. ([30379](https://github.com/WordPress/gutenberg/pull/30379)) +- Handbook: Fix code snippet for disabling the block directory. ([30365](https://github.com/WordPress/gutenberg/pull/30365)) +- Handbook: Updated documentation to reflect the output created currently by npx @wordpress/create-block gutenpride. ([30353](https://github.com/WordPress/gutenberg/pull/30353)) +- Fixed formatting. ([30309](https://github.com/WordPress/gutenberg/pull/30309)) +- Handbook: Add instructions for finding attributes for use in templates. ([30258](https://github.com/WordPress/gutenberg/pull/30258)) +- Handbook: Update feature deprecation guide. ([30220](https://github.com/WordPress/gutenberg/pull/30220)) +- Handbook: Fix broken links to typescript documentation. ([30188](https://github.com/WordPress/gutenberg/pull/30188)) +- Components: Update CustomSelectControl component README.md. ([29854](https://github.com/WordPress/gutenberg/pull/29854)) +- Rich Text Docs: Add section for disabling specific format types. ([29383](https://github.com/WordPress/gutenberg/pull/29383)) +- Components: Remove references to __experimental* in the DateTimePicker component documentation. ([29322](https://github.com/WordPress/gutenberg/pull/29322)) + +### Code Quality + +- Gutenberg Plugin: Update the `objectFitPolyfill` vendor library. ([30507](https://github.com/WordPress/gutenberg/pull/30507)) +- Block Library: Fix Post Excerpt warnings for RichText in inline containers. ([30498](https://github.com/WordPress/gutenberg/pull/30498)) +- Gutenberg Plugin: Remove deprecations planned for 10.3 release. ([30417](https://github.com/WordPress/gutenberg/pull/30417)) +- dom: Add types to clean-node-list. ([30412](https://github.com/WordPress/gutenberg/pull/30412)) +- PHP Coding Standards fixes. ([30346](https://github.com/WordPress/gutenberg/pull/30346)) +- Public API: Remove small APIs deprecated in WordPress 5.2. ([30283](https://github.com/WordPress/gutenberg/pull/30283)) +- dom: Add types progressively to dom modules. ([30103](https://github.com/WordPress/gutenberg/pull/30103)) +- dom: Add types to phrasing-content. ([30102](https://github.com/WordPress/gutenberg/pull/30102)) +- Components: Simplify ScrollLock, adding types. ([29634](https://github.com/WordPress/gutenberg/pull/29634)) + +### Tools + +- Testing: Include NodeJS version in the cache key. ([30512](https://github.com/WordPress/gutenberg/pull/30512)) +- Testing: Remove cache `restore-keys`. ([30510](https://github.com/WordPress/gutenberg/pull/30510)) +- Gutenberg Plugin: Prettify YAML scripts. ([30409](https://github.com/WordPress/gutenberg/pull/30409)) +- Testing: Skip flaky end-to-end tests. ([30344](https://github.com/WordPress/gutenberg/pull/30344)) +- Add `/packages/stylelint-config` to `CODEOWNERS`. ([30264](https://github.com/WordPress/gutenberg/pull/30264)) +- Remove button from forbidden elements. ([30223](https://github.com/WordPress/gutenberg/pull/30223)) +- End-to-end tests for navigation menu name editor. ([29774](https://github.com/WordPress/gutenberg/pull/29774)) +- Testing: Some GHA workflow improvements when setting up NodeJS. ([29078](https://github.com/WordPress/gutenberg/pull/29078)) +- Build Tooling: Update development tools to work with PostCSS 8. ([27821](https://github.com/WordPress/gutenberg/pull/27821)) + +### Various + +- Export all types from api-fetch. ([30539](https://github.com/WordPress/gutenberg/pull/30539)) +- Update the save button label. ([30439](https://github.com/WordPress/gutenberg/pull/30439)) +- Revert "Build Tooling: Update development tools to work with PostCSS 8 (#27821)". ([30320](https://github.com/WordPress/gutenberg/pull/30320)) +- Clarify what is meant by "block wrapper". ([30315](https://github.com/WordPress/gutenberg/pull/30315)) +- Icons: Polish media & text icons. ([30239](https://github.com/WordPress/gutenberg/pull/30239)) +- Reset wp admin styles for hr. ([30235](https://github.com/WordPress/gutenberg/pull/30235)) +- Search Block: Add border radius support using skip serialization feature. ([30227](https://github.com/WordPress/gutenberg/pull/30227)) +- RichText: Add min width to show caret for empty inline container. ([30224](https://github.com/WordPress/gutenberg/pull/30224)) +- Block editor: Use proper insertion point for drop. ([29933](https://github.com/WordPress/gutenberg/pull/29933)) +- Add manage with live preview link. ([29839](https://github.com/WordPress/gutenberg/pull/29839)) +- Components: Add types to Draggable. ([29792](https://github.com/WordPress/gutenberg/pull/29792)) +- Add customize widgets inserter. ([29549](https://github.com/WordPress/gutenberg/pull/29549)) +- React native composite and binary build support. ([29488](https://github.com/WordPress/gutenberg/pull/29488)) +- Try using the column-gap property to improve spacing between custom-sized buttons. ([29165](https://github.com/WordPress/gutenberg/pull/29165)) +- Transform Blocks. ([28453](https://github.com/WordPress/gutenberg/pull/28453)) +- Preformatted block: Add color controls. ([28396](https://github.com/WordPress/gutenberg/pull/28396)) + + + + = 10.3.2 = ### Enhancements From 6604dd34d877ad8fb6c3b21211384e6555d07e99 Mon Sep 17 00:00:00 2001 From: Luke Carbis Date: Thu, 8 Apr 2021 01:09:54 +1000 Subject: [PATCH 034/125] Button block: Add Typography support (#30394) * Button block: Add support for font size * Use block style for has-custom-font-size class * Add has-custom-font-size class to save --- packages/block-library/src/button/block.json | 2 ++ packages/block-library/src/button/edit.js | 1 + packages/block-library/src/button/save.js | 3 +++ packages/block-library/src/button/style.scss | 6 ++++++ 4 files changed, 12 insertions(+) diff --git a/packages/block-library/src/button/block.json b/packages/block-library/src/button/block.json index 9b33ee27d6c418..01097b424462fa 100644 --- a/packages/block-library/src/button/block.json +++ b/packages/block-library/src/button/block.json @@ -65,7 +65,9 @@ "__experimentalSkipSerialization": true, "gradients": true }, + "fontSize": true, "reusable": false, + "__experimentalFontFamily": true, "__experimentalSelector": ".wp-block-button__link" }, "editorStyle": "wp-block-button-editor", diff --git a/packages/block-library/src/button/edit.js b/packages/block-library/src/button/edit.js index b0fcc297d6b9ed..714554e2ffdc96 100644 --- a/packages/block-library/src/button/edit.js +++ b/packages/block-library/src/button/edit.js @@ -241,6 +241,7 @@ function ButtonEdit( props ) { { ...blockProps } className={ classnames( blockProps.className, { [ `has-custom-width wp-block-button__width-${ width }` ]: width, + [ `has-custom-font-size` ]: blockProps.style.fontSize, } ) } > Date: Wed, 7 Apr 2021 12:56:39 -0400 Subject: [PATCH 035/125] Navigation Link: Limit Nesting Depth to 5 (#30199) Removes the ability to nest submenus beyond 5 to avoid scrolling off the screen. Closes #21691 --- .../block-library/src/navigation-link/edit.js | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/packages/block-library/src/navigation-link/edit.js b/packages/block-library/src/navigation-link/edit.js index 0348ec76cfd31d..eb236b3febd3d5 100644 --- a/packages/block-library/src/navigation-link/edit.js +++ b/packages/block-library/src/navigation-link/edit.js @@ -46,9 +46,12 @@ import { store as coreStore } from '@wordpress/core-data'; * Internal dependencies */ import { ItemSubmenuIcon } from './icons'; +import { name } from './block.json'; const ALLOWED_BLOCKS = [ 'core/navigation-link', 'core/spacer' ]; +const MAX_NESTING = 5; + /** * A React hook to determine if it's dragging within the target element. * @@ -164,6 +167,7 @@ export default function NavigationLinkEdit( { const ref = useRef(); const { + isAtMaxNesting, isParentOfSelectedBlock, isImmediateParentOfSelectedBlock, hasDescendants, @@ -177,6 +181,7 @@ export default function NavigationLinkEdit( { getClientIdsOfDescendants, hasSelectedInnerBlock, getSelectedBlockClientId, + getBlockParentsByBlockName, } = select( blockEditorStore ); const selectedBlockId = getSelectedBlockClientId(); @@ -185,6 +190,9 @@ export default function NavigationLinkEdit( { .length; return { + isAtMaxNesting: + getBlockParentsByBlockName( clientId, name ).length >= + MAX_NESTING, isParentOfSelectedBlock: hasSelectedInnerBlock( clientId, true @@ -382,12 +390,14 @@ export default function NavigationLinkEdit( { shortcut={ displayShortcut.primary( 'k' ) } onClick={ () => setIsLinkOpen( true ) } /> - + { ! isAtMaxNesting && ( + + ) } From 060abf48b9f4e53e4c57073838e10ffaa86edfb6 Mon Sep 17 00:00:00 2001 From: Edi Amin Date: Wed, 7 Apr 2021 23:01:51 +0600 Subject: [PATCH 036/125] Docs: Fix Block Editor Accessibility link (#30569) --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index 26cdbe393ad49e..ab5f7f2a4dc726 100644 --- a/docs/README.md +++ b/docs/README.md @@ -33,7 +33,7 @@ Whether you want to extend the functionality of the block editor, or create a pl - [Creating Block Patterns](/docs/reference-guides/block-api/block-patterns.md) - [Theming for the Block Editor](/docs/how-to-guides/themes/README.md) - [Block API Reference](/docs/reference-guides/block-api/README.md) -- [Block Editor Accessibility](/docs/reference-guides/accessibility.md) +- [Block Editor Accessibility](/docs/how-to-guides/accessibility.md) - [Internationalization](/docs/how-to-guides/internationalization.md) ### Contribute to the block editor From 8de9985dc00ce81b66aed124ab2f11ae65668765 Mon Sep 17 00:00:00 2001 From: Kerry Liu Date: Wed, 7 Apr 2021 10:25:53 -0700 Subject: [PATCH 037/125] Navigation: nav created drafts should not render on frontend (#29692) --- .../block-library/src/navigation-link/edit.js | 13 +++++++- .../navigation-link/fallback-variations.js | 8 ++--- .../test/__snapshots__/hooks.js.snap | 4 +++ .../__experimental-fetch-link-suggestions.js | 30 +++++++++++++++++-- .../__experimental-fetch-link-suggestions.js | 8 +++++ .../__snapshots__/navigation.test.js.snap | 4 +-- 6 files changed, 58 insertions(+), 9 deletions(-) diff --git a/packages/block-library/src/navigation-link/edit.js b/packages/block-library/src/navigation-link/edit.js index eb236b3febd3d5..a1ce7bb2781d9c 100644 --- a/packages/block-library/src/navigation-link/edit.js +++ b/packages/block-library/src/navigation-link/edit.js @@ -297,9 +297,10 @@ export default function NavigationLinkEdit( { return { id: page.id, - postType, + type: postType, title: page.title.rendered, url: page.link, + kind: 'post-type', }; } @@ -523,6 +524,8 @@ export default function NavigationLinkEdit( { url: newURL = '', opensInNewTab: newOpensInNewTab, id, + kind: newKind = '', + type: newType = '', } = {} ) => setAttributes( { url: encodeURI( newURL ), @@ -550,6 +553,14 @@ export default function NavigationLinkEdit( { } )(), opensInNewTab: newOpensInNewTab, id, + ...( newKind && { + kind: newKind, + } ), + ...( newType && + newType !== 'URL' && + newType !== 'post-format' && { + type: newType, + } ), } ) } /> diff --git a/packages/block-library/src/navigation-link/fallback-variations.js b/packages/block-library/src/navigation-link/fallback-variations.js index 1214102801922c..5f8d44702a1157 100644 --- a/packages/block-library/src/navigation-link/fallback-variations.js +++ b/packages/block-library/src/navigation-link/fallback-variations.js @@ -26,28 +26,28 @@ const fallbackVariations = [ icon: postIcon, title: __( 'Post Link' ), description: __( 'A link to a post.' ), - attributes: { type: 'post' }, + attributes: { type: 'post', kind: 'post-type' }, }, { name: 'page', icon: pageIcon, title: __( 'Page Link' ), description: __( 'A link to a page.' ), - attributes: { type: 'page' }, + attributes: { type: 'page', kind: 'post-type' }, }, { name: 'category', icon: categoryIcon, title: __( 'Category Link' ), description: __( 'A link to a category.' ), - attributes: { type: 'category' }, + attributes: { type: 'category', kind: 'taxonomy' }, }, { name: 'tag', icon: tagIcon, title: __( 'Tag Link' ), description: __( 'A link to a tag.' ), - attributes: { type: 'tag' }, + attributes: { type: 'tag', kind: 'taxonomy' }, }, ]; diff --git a/packages/block-library/src/navigation-link/test/__snapshots__/hooks.js.snap b/packages/block-library/src/navigation-link/test/__snapshots__/hooks.js.snap index dc1669c095e524..93ed87117d9355 100644 --- a/packages/block-library/src/navigation-link/test/__snapshots__/hooks.js.snap +++ b/packages/block-library/src/navigation-link/test/__snapshots__/hooks.js.snap @@ -17,6 +17,7 @@ Object { }, Object { "attributes": Object { + "kind": "post-type", "type": "post", }, "description": "A link to a post.", @@ -34,6 +35,7 @@ Object { }, Object { "attributes": Object { + "kind": "post-type", "type": "page", }, "description": "A link to a page.", @@ -51,6 +53,7 @@ Object { }, Object { "attributes": Object { + "kind": "taxonomy", "type": "category", }, "description": "A link to a category.", @@ -70,6 +73,7 @@ Object { }, Object { "attributes": Object { + "kind": "taxonomy", "type": "tag", }, "description": "A link to a tag.", diff --git a/packages/core-data/src/fetch/__experimental-fetch-link-suggestions.js b/packages/core-data/src/fetch/__experimental-fetch-link-suggestions.js index ef1a80c95c2437..10252f736bb2ff 100644 --- a/packages/core-data/src/fetch/__experimental-fetch-link-suggestions.js +++ b/packages/core-data/src/fetch/__experimental-fetch-link-suggestions.js @@ -12,6 +12,12 @@ import { __ } from '@wordpress/i18n'; * @typedef { 'post' | 'term' | 'post-format' } WPLinkSearchType */ +/** + * A link with an id may be of kind post-type or taxonomy + * + * @typedef { 'post-type' | 'taxonomy' } WPKind + */ + /** * @typedef WPLinkSearchOptions * @@ -29,6 +35,7 @@ import { __ } from '@wordpress/i18n'; * @property {string} url Link url. * @property {string} title Title of the link. * @property {string} type The taxonomy or post type slug or type URL. + * @property {WPKind} [kind] Link kind of post-type or taxonomy */ /** @@ -87,7 +94,16 @@ const fetchLinkSuggestions = async ( type: 'post', subtype, } ), - } ).catch( () => [] ) // fail by returning no results + } ) + .then( ( results ) => { + return results.map( ( result ) => { + return { + ...result, + meta: { kind: 'post-type', subtype }, + }; + } ); + } ) + .catch( () => [] ) // fail by returning no results ); } @@ -101,7 +117,16 @@ const fetchLinkSuggestions = async ( type: 'term', subtype, } ), - } ).catch( () => [] ) + } ) + .then( ( results ) => { + return results.map( ( result ) => { + return { + ...result, + meta: { kind: 'taxonomy', subtype }, + }; + } ); + } ) + .catch( () => [] ) ); } @@ -146,6 +171,7 @@ const fetchLinkSuggestions = async ( decodeEntities( result.title || '' ) || __( '(no title)' ), type: result.subtype || result.type, + kind: result?.meta?.kind, }; } ); diff --git a/packages/core-data/src/fetch/test/__experimental-fetch-link-suggestions.js b/packages/core-data/src/fetch/test/__experimental-fetch-link-suggestions.js index 82a68cc7974396..5270b43cfc082c 100644 --- a/packages/core-data/src/fetch/test/__experimental-fetch-link-suggestions.js +++ b/packages/core-data/src/fetch/test/__experimental-fetch-link-suggestions.js @@ -93,6 +93,7 @@ describe( 'fetchLinkSuggestions', () => { title: 'Contact Page', type: 'page', url: 'http://wordpress.local/contact-page/', + kind: 'post-type', }, ] ) ); @@ -108,12 +109,14 @@ describe( 'fetchLinkSuggestions', () => { title: 'Cats', url: 'http://wordpress.local/category/cats/', type: 'category', + kind: 'taxonomy', }, { id: 1, title: 'Uncategorized', url: 'http://wordpress.local/category/uncategorized/', type: 'category', + kind: 'taxonomy', }, ] ) ); @@ -155,18 +158,21 @@ describe( 'fetchLinkSuggestions', () => { title: 'Contact Page', url: 'http://wordpress.local/contact-page/', type: 'page', + kind: 'post-type', }, { id: 9, title: 'Cats', url: 'http://wordpress.local/category/cats/', type: 'category', + kind: 'taxonomy', }, { id: 1, title: 'Uncategorized', url: 'http://wordpress.local/category/uncategorized/', type: 'category', + kind: 'taxonomy', }, { id: 'gallery', @@ -195,6 +201,7 @@ describe( 'fetchLinkSuggestions', () => { title: 'Limit Case', url: 'http://wordpress.local/limit-case/', type: 'page', + kind: 'post-type', }, ] ) ); @@ -211,6 +218,7 @@ describe( 'fetchLinkSuggestions', () => { title: 'Page Case', url: 'http://wordpress.local/page-case/', type: 'page', + kind: 'post-type', }, ] ) ); diff --git a/packages/e2e-tests/specs/experiments/blocks/__snapshots__/navigation.test.js.snap b/packages/e2e-tests/specs/experiments/blocks/__snapshots__/navigation.test.js.snap index de0c4f8531459b..74860922357e8d 100644 --- a/packages/e2e-tests/specs/experiments/blocks/__snapshots__/navigation.test.js.snap +++ b/packages/e2e-tests/specs/experiments/blocks/__snapshots__/navigation.test.js.snap @@ -48,12 +48,12 @@ exports[`Navigation allows an empty navigation block to be created and manually " - + " `; exports[`Navigation allows pages to be created from the navigation block and their links added to menu 1`] = ` " - + " `; From 8c8feab644f147c5ddcec188ad646f5a2a378bf5 Mon Sep 17 00:00:00 2001 From: Janw Oostendorp Date: Wed, 7 Apr 2021 19:39:54 +0200 Subject: [PATCH 038/125] Fixed a type and made the whole explaination more clear. (#30487) * Fixed a type and made the whole explaination more clear. * Update docs/getting-started/tutorials/create-block/block-code.md Co-authored-by: Marcus Kazmierczak --- docs/getting-started/tutorials/create-block/block-code.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/tutorials/create-block/block-code.md b/docs/getting-started/tutorials/create-block/block-code.md index 03e2ba676e486a..441d847e582515 100644 --- a/docs/getting-started/tutorials/create-block/block-code.md +++ b/docs/getting-started/tutorials/create-block/block-code.md @@ -17,7 +17,7 @@ function create_block_gutenpride_block_init() { add_action( 'init', 'create_block_gutenpride_block_init' ); ``` -This function handles that all style en js files in the `build` folder get handles that are passed on to the `wp_register_style` function. +This function checks the `block.json` file for js and css files, and will pass them on to [enqueue](https://developer.wordpress.org/themes/basics/including-css-javascript/) these files, so they are loaded on the appropriate pages. The `build/index.css` is compiled from `src/editor.scss` and loads only within the editor, and after the `style-index.css`. The `build/style-index.css` is compiled from `src/style.scss` and loads in both the editor and front-end — published post view. From 9c09a52f34822c61b264d25f3e8e87c3f3a2d3c5 Mon Sep 17 00:00:00 2001 From: Allison Levine Date: Wed, 7 Apr 2021 15:03:23 -0400 Subject: [PATCH 039/125] Change publish posts popover anchor ref to row (#30298) Fix Post Publishing popover glitch by changing the popover anchor ref to the containing div (PanelRow). Requires changing PanelRow to accept a forwarding ref. --- packages/components/src/panel/README.md | 6 ++++++ packages/components/src/panel/row.js | 16 ++++++++++++---- .../components/sidebar/post-schedule/index.js | 6 +++++- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/packages/components/src/panel/README.md b/packages/components/src/panel/README.md index 6b944732381ede..58e59a4f85a04c 100644 --- a/packages/components/src/panel/README.md +++ b/packages/components/src/panel/README.md @@ -172,6 +172,12 @@ The class that will be added with `components-panel__row`. to the classes of the - Type: `String` - Required: No +##### Ref + +PanelRow accepts a forwarded ref that will be added to the wrapper div. Usage: + +`` + --- #### PanelHeader diff --git a/packages/components/src/panel/row.js b/packages/components/src/panel/row.js index 8600b8b03306bb..9da08b06c84ba3 100644 --- a/packages/components/src/panel/row.js +++ b/packages/components/src/panel/row.js @@ -3,10 +3,18 @@ */ import classnames from 'classnames'; -function PanelRow( { className, children } ) { - const classes = classnames( 'components-panel__row', className ); +/** + * WordPress dependencies + */ +import { forwardRef } from '@wordpress/element'; - return
{ children }
; -} +const PanelRow = forwardRef( ( { className, children }, ref ) => ( +
+ { children } +
+) ); export default PanelRow; diff --git a/packages/edit-post/src/components/sidebar/post-schedule/index.js b/packages/edit-post/src/components/sidebar/post-schedule/index.js index cf644bc9a6ae1e..6d99ccf506141a 100644 --- a/packages/edit-post/src/components/sidebar/post-schedule/index.js +++ b/packages/edit-post/src/components/sidebar/post-schedule/index.js @@ -3,6 +3,7 @@ */ import { __ } from '@wordpress/i18n'; import { PanelRow, Dropdown, Button } from '@wordpress/components'; +import { useRef } from '@wordpress/element'; import { PostSchedule as PostScheduleForm, PostScheduleLabel, @@ -10,11 +11,14 @@ import { } from '@wordpress/editor'; export function PostSchedule() { + const anchorRef = useRef(); + return ( - + { __( 'Publish' ) } ( From f84d26e41a6b253b853d591eb040219a11c042cb Mon Sep 17 00:00:00 2001 From: sarayourfriend Date: Wed, 7 Apr 2021 15:14:50 -0700 Subject: [PATCH 040/125] api-fetch: Align exported type names with DefinitelyTyped types (#30570) * api-fetch: Align exported type names with DefinitelyTyped types * Update changelog --- packages/api-fetch/CHANGELOG.md | 4 ++++ packages/api-fetch/src/index.js | 12 ++++++------ .../src/middlewares/fetch-all-middleware.js | 8 ++++---- packages/api-fetch/src/middlewares/http-v1.js | 2 +- packages/api-fetch/src/middlewares/media-upload.js | 2 +- .../api-fetch/src/middlewares/namespace-endpoint.js | 2 +- packages/api-fetch/src/middlewares/nonce.js | 4 ++-- packages/api-fetch/src/middlewares/preloading.js | 2 +- packages/api-fetch/src/middlewares/root-url.js | 2 +- packages/api-fetch/src/middlewares/user-locale.js | 2 +- packages/api-fetch/src/types.ts | 8 ++++---- 11 files changed, 26 insertions(+), 22 deletions(-) diff --git a/packages/api-fetch/CHANGELOG.md b/packages/api-fetch/CHANGELOG.md index 713c493ab63115..d93d9693f5d3d5 100644 --- a/packages/api-fetch/CHANGELOG.md +++ b/packages/api-fetch/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Bug Fixes + +- Align exported type names with the DefinitelyTyped type names and actually export those types. + ## 3.23.0 (2021-04-06) ### New Feature diff --git a/packages/api-fetch/src/index.js b/packages/api-fetch/src/index.js index e4ee02b01f65ea..4ede2d0083286d 100644 --- a/packages/api-fetch/src/index.js +++ b/packages/api-fetch/src/index.js @@ -43,11 +43,11 @@ const DEFAULT_OPTIONS = { credentials: 'include', }; -/** @typedef {import('./types').ApiFetchMiddleware} ApiFetchMiddleware */ -/** @typedef {import('./types').ApiFetchRequestProps} ApiFetchRequestProps */ +/** @typedef {import('./types').APIFetchMiddleware} APIFetchMiddleware */ +/** @typedef {import('./types').APIFetchOptions} APIFetchOptions */ /** - * @type {import('./types').ApiFetchMiddleware[]} + * @type {import('./types').APIFetchMiddleware[]} */ const middlewares = [ userLocaleMiddleware, @@ -59,7 +59,7 @@ const middlewares = [ /** * Register a middleware * - * @param {import('./types').ApiFetchMiddleware} middleware + * @param {import('./types').APIFetchMiddleware} middleware */ function registerMiddleware( middleware ) { middlewares.unshift( middleware ); @@ -80,7 +80,7 @@ const checkStatus = ( response ) => { throw response; }; -/** @typedef {(options: import('./types').ApiFetchRequestProps) => Promise} FetchHandler*/ +/** @typedef {(options: import('./types').APIFetchOptions) => Promise} FetchHandler*/ /** * @type {FetchHandler} @@ -149,7 +149,7 @@ function setFetchHandler( newFetchHandler ) { /** * @template T - * @param {import('./types').ApiFetchRequestProps} options + * @param {import('./types').APIFetchOptions} options * @return {Promise} A promise representing the request processed via the registered middlewares. */ function apiFetch( options ) { diff --git a/packages/api-fetch/src/middlewares/fetch-all-middleware.js b/packages/api-fetch/src/middlewares/fetch-all-middleware.js index a7779c9e925942..851829f64a18b9 100644 --- a/packages/api-fetch/src/middlewares/fetch-all-middleware.js +++ b/packages/api-fetch/src/middlewares/fetch-all-middleware.js @@ -11,9 +11,9 @@ import apiFetch from '..'; /** * Apply query arguments to both URL and Path, whichever is present. * - * @param {import('../types').ApiFetchRequestProps} props + * @param {import('../types').APIFetchOptions} props * @param {Record} queryArgs - * @return {import('../types').ApiFetchRequestProps} The request with the modified query args + * @return {import('../types').APIFetchOptions} The request with the modified query args */ const modifyQuery = ( { path, url, ...options }, queryArgs ) => ( { ...options, @@ -56,7 +56,7 @@ const getNextPageUrl = ( response ) => { }; /** - * @param {import('../types').ApiFetchRequestProps} options + * @param {import('../types').APIFetchOptions} options * @return {boolean} True if the request contains an unbounded query. */ const requestContainsUnboundedQuery = ( options ) => { @@ -72,7 +72,7 @@ const requestContainsUnboundedQuery = ( options ) => { * collections, apiFetch consumers can pass `per_page=-1`; this middleware will * then recursively assemble a full response array from all available pages. * - * @type {import('../types').ApiFetchMiddleware} + * @type {import('../types').APIFetchMiddleware} */ const fetchAllMiddleware = async ( options, next ) => { if ( options.parse === false ) { diff --git a/packages/api-fetch/src/middlewares/http-v1.js b/packages/api-fetch/src/middlewares/http-v1.js index 8f8ced80c34152..953fc26ff70c8a 100644 --- a/packages/api-fetch/src/middlewares/http-v1.js +++ b/packages/api-fetch/src/middlewares/http-v1.js @@ -21,7 +21,7 @@ const DEFAULT_METHOD = 'GET'; * API Fetch middleware which overrides the request method for HTTP v1 * compatibility leveraging the REST API X-HTTP-Method-Override header. * - * @type {import('../types').ApiFetchMiddleware} + * @type {import('../types').APIFetchMiddleware} */ const httpV1Middleware = ( options, next ) => { const { method = DEFAULT_METHOD } = options; diff --git a/packages/api-fetch/src/middlewares/media-upload.js b/packages/api-fetch/src/middlewares/media-upload.js index fbfdeef9323291..2ba4f2953dabff 100644 --- a/packages/api-fetch/src/middlewares/media-upload.js +++ b/packages/api-fetch/src/middlewares/media-upload.js @@ -14,7 +14,7 @@ import { /** * Middleware handling media upload failures and retries. * - * @type {import('../types').ApiFetchMiddleware} + * @type {import('../types').APIFetchMiddleware} */ const mediaUploadMiddleware = ( options, next ) => { const isMediaUploadRequest = diff --git a/packages/api-fetch/src/middlewares/namespace-endpoint.js b/packages/api-fetch/src/middlewares/namespace-endpoint.js index f6428c89a7f468..bfb0e824187f35 100644 --- a/packages/api-fetch/src/middlewares/namespace-endpoint.js +++ b/packages/api-fetch/src/middlewares/namespace-endpoint.js @@ -1,5 +1,5 @@ /** - * @type {import('../types').ApiFetchMiddleware} + * @type {import('../types').APIFetchMiddleware} */ const namespaceAndEndpointMiddleware = ( options, next ) => { let path = options.path; diff --git a/packages/api-fetch/src/middlewares/nonce.js b/packages/api-fetch/src/middlewares/nonce.js index 703fb0dab981cf..60914823661ed9 100644 --- a/packages/api-fetch/src/middlewares/nonce.js +++ b/packages/api-fetch/src/middlewares/nonce.js @@ -1,10 +1,10 @@ /** * @param {string} nonce - * @return {import('../types').ApiFetchMiddleware & { nonce: string }} A middleware to enhance a request with a nonce. + * @return {import('../types').APIFetchMiddleware & { nonce: string }} A middleware to enhance a request with a nonce. */ function createNonceMiddleware( nonce ) { /** - * @type {import('../types').ApiFetchMiddleware & { nonce: string }} + * @type {import('../types').APIFetchMiddleware & { nonce: string }} */ const middleware = ( options, next ) => { const { headers = {} } = options; diff --git a/packages/api-fetch/src/middlewares/preloading.js b/packages/api-fetch/src/middlewares/preloading.js index a0868de8f341ae..7af89a7139c216 100644 --- a/packages/api-fetch/src/middlewares/preloading.js +++ b/packages/api-fetch/src/middlewares/preloading.js @@ -35,7 +35,7 @@ export function getStablePath( path ) { /** * @param {Record} preloadedData - * @return {import('../types').ApiFetchMiddleware} Preloading middleware. + * @return {import('../types').APIFetchMiddleware} Preloading middleware. */ function createPreloadingMiddleware( preloadedData ) { const cache = Object.keys( preloadedData ).reduce( ( result, path ) => { diff --git a/packages/api-fetch/src/middlewares/root-url.js b/packages/api-fetch/src/middlewares/root-url.js index 3c73c5e4666650..cde855f3f9504f 100644 --- a/packages/api-fetch/src/middlewares/root-url.js +++ b/packages/api-fetch/src/middlewares/root-url.js @@ -5,7 +5,7 @@ import namespaceAndEndpointMiddleware from './namespace-endpoint'; /** * @param {string} rootURL - * @return {import('../types').ApiFetchMiddleware} Root URL middleware. + * @return {import('../types').APIFetchMiddleware} Root URL middleware. */ const createRootURLMiddleware = ( rootURL ) => ( options, next ) => { return namespaceAndEndpointMiddleware( options, ( optionsWithPath ) => { diff --git a/packages/api-fetch/src/middlewares/user-locale.js b/packages/api-fetch/src/middlewares/user-locale.js index 81fb7ebb25aad6..18057cb41fa06e 100644 --- a/packages/api-fetch/src/middlewares/user-locale.js +++ b/packages/api-fetch/src/middlewares/user-locale.js @@ -4,7 +4,7 @@ import { addQueryArgs, hasQueryArg } from '@wordpress/url'; /** - * @type {import('../types').ApiFetchMiddleware} + * @type {import('../types').APIFetchMiddleware} */ const userLocaleMiddleware = ( options, next ) => { if ( diff --git a/packages/api-fetch/src/types.ts b/packages/api-fetch/src/types.ts index 93c466e8cd916b..e7f478d69a1d26 100644 --- a/packages/api-fetch/src/types.ts +++ b/packages/api-fetch/src/types.ts @@ -1,4 +1,4 @@ -export interface ApiFetchRequestProps extends RequestInit { +export interface APIFetchOptions extends RequestInit { // Override headers, we only accept it as an object due to the `nonce` middleware headers?: Record< string, string >; path?: string; @@ -12,7 +12,7 @@ export interface ApiFetchRequestProps extends RequestInit { endpoint?: string; } -export type ApiFetchMiddleware = ( - options: ApiFetchRequestProps, - next: ( nextOptions: ApiFetchRequestProps ) => Promise< any > +export type APIFetchMiddleware = ( + options: APIFetchOptions, + next: ( nextOptions: APIFetchOptions ) => Promise< any > ) => Promise< any >; From 4a78eaeacc623141b7ad76b0c8c1b2720654358a Mon Sep 17 00:00:00 2001 From: Vicente Canales <1157901+vcanales@users.noreply.github.com> Date: Wed, 7 Apr 2021 23:01:40 -0400 Subject: [PATCH 041/125] build core blocks' frontend.js files (#30341) --- packages/block-library/README.md | 56 +++++++++++++++++ webpack.config.js | 101 +++++++++++++++++++------------ 2 files changed, 117 insertions(+), 40 deletions(-) diff --git a/packages/block-library/README.md b/packages/block-library/README.md index a08824d9747957..356e4778653d1b 100644 --- a/packages/block-library/README.md +++ b/packages/block-library/README.md @@ -12,6 +12,62 @@ npm install @wordpress/block-library --save _This package assumes that your code will run in an **ES2015+** environment. If you're using an environment that has limited or no support for ES2015+ such as lower versions of IE then using [core-js](https://github.com/zloirock/core-js) or [@babel/polyfill](https://babeljs.io/docs/en/next/babel-polyfill) will add support for these methods. Learn more about it in [Babel docs](https://babeljs.io/docs/en/next/caveats)._ +## Building JavaScript for the browser + +If a `frontend.js` file is present in the block's directory, this file will be built along other assets, making it available to load from the browser. + +This enables us to, for instance, load this file when the block is present on the page in two ways: + +1. Using the block's `render_callback`: + +```php +function render_my_block() { + $script_path = __DIR__ . '/block-name/frontend.js'; + + if ( file_exists( $script_path ) ) { + wp_enqueue_script( + 'my_block_frontend_script', + plugins_url( 'frontend.js', $script_path ), + array(), + false, + true + ); + } +} + +function register_block_my_block() { + register_block_type_from_metadata( + __DIR__ . '/block-name', + array( + 'render_callback' => 'render_my_block', + ) + ); +} + + +add_action( 'init', 'register_block_my_block' ); +``` + +2. Using the `render_block` filter: + +```php +function render_my_block() { + $script_path = __DIR__ . '/block-name/frontend.js'; + + if ( file_exists( $script_path ) ) { + wp_enqueue_script( + 'my_block_frontend_script', + plugins_url( 'frontend.js', $script_path ), + array(), + false, + true + ); + } +} + +apply_filter( 'render_block', 'render_my_block' ); +``` + ## API diff --git a/webpack.config.js b/webpack.config.js index c7bac6324baf1b..36d7d102035d04 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -6,8 +6,9 @@ const { DefinePlugin } = require( 'webpack' ); const CopyWebpackPlugin = require( 'copy-webpack-plugin' ); const TerserPlugin = require( 'terser-webpack-plugin' ); const postcss = require( 'postcss' ); -const { get, escapeRegExp, compact } = require( 'lodash' ); -const { basename, sep } = require( 'path' ); +const { escapeRegExp, compact } = require( 'lodash' ); +const { sep } = require( 'path' ); +const fastGlob = require( 'fast-glob' ); /** * WordPress dependencies @@ -64,6 +65,35 @@ const stylesTransform = ( content ) => { return content; }; +const blockNameRegex = new RegExp( /(?<=src\/).*(?=(\/frontend))/g ); + +const createEntrypoints = () => { + const scriptPaths = fastGlob.sync( + './packages/block-library/src/**/frontend.js', + { + ignore: [ '**/build*/**' ], + } + ); + + const scriptEntries = scriptPaths.reduce( ( entries, scriptPath ) => { + const [ blockName ] = scriptPath.match( blockNameRegex ) || []; + + return { + ...entries, + [ blockName ]: scriptPath, + }; + }, {} ); + + const packageEntries = gutenbergPackages.reduce( ( memo, packageName ) => { + return { + ...memo, + [ packageName ]: `./packages/${ packageName }`, + }; + }, {} ); + + return { ...packageEntries, ...scriptEntries }; +}; + module.exports = { optimization: { // Only concatenate modules in production, when not analyzing bundles. @@ -90,16 +120,26 @@ module.exports = { ], }, mode, - entry: gutenbergPackages.reduce( ( memo, packageName ) => { - const name = camelCaseDash( packageName ); - memo[ name ] = `./packages/${ packageName }`; - return memo; - }, {} ), + entry: createEntrypoints(), output: { devtoolNamespace: 'wp', - filename: './build/[basename]/index.js', + filename: ( data ) => { + const { chunk } = data; + const { entryModule } = chunk; + const { rawRequest } = entryModule; + + /* + * If the file being built is a Core Block's frontend file, + * we build it in the block's directory. + */ + if ( rawRequest && rawRequest.includes( '/frontend.js' ) ) { + return `./build/block-library/blocks/[name]/frontend.js`; + } + + return './build/[name]/index.js'; + }, path: __dirname, - library: [ 'wp', '[name]' ], + library: [ 'wp', '[camelName]' ], libraryTarget: 'window', }, module: { @@ -135,39 +175,20 @@ module.exports = { ), } ), new CustomTemplatedPathPlugin( { - basename( path, data ) { - let rawRequest; - - const entryModule = get( data, [ 'chunk', 'entryModule' ], {} ); - switch ( entryModule.type ) { - case 'javascript/auto': - rawRequest = entryModule.rawRequest; - break; - - case 'javascript/esm': - rawRequest = entryModule.rootModule.rawRequest; - break; - } - - if ( rawRequest ) { - return basename( rawRequest ); - } - - return path; + camelName( path, data ) { + return camelCaseDash( data.chunk.name ); }, } ), - new LibraryExportDefaultPlugin( - [ - 'api-fetch', - 'deprecated', - 'dom-ready', - 'redux-routine', - 'token-list', - 'server-side-render', - 'shortcode', - 'warning', - ].map( camelCaseDash ) - ), + new LibraryExportDefaultPlugin( [ + 'api-fetch', + 'deprecated', + 'dom-ready', + 'redux-routine', + 'token-list', + 'server-side-render', + 'shortcode', + 'warning', + ] ), new CopyWebpackPlugin( gutenbergPackages.map( ( packageName ) => ( { from: `./packages/${ packageName }/build-style/*.css`, From 3dc3322c20cabb9a72fbf9e209842f57f9b54a38 Mon Sep 17 00:00:00 2001 From: Kai Hao Date: Thu, 8 Apr 2021 13:35:50 +0800 Subject: [PATCH 042/125] Refactor the inspector in Widgets Customizer to use core's controls (#30431) --- .../block-inspector-button/index.js | 38 ++++++ .../block-inspector-button/style.scss | 21 +++ .../src/components/inserter/style.scss | 2 +- .../inspector/block-inspector-button.js | 15 --- .../src/components/inspector/index.js | 122 ------------------ .../src/components/inspector/style.scss | 25 ---- .../components/sidebar-block-editor/index.js | 99 +++++--------- .../src/controls/inserter-outer-section.js | 2 + .../src/controls/inspector-section.js | 58 +++++++++ .../src/controls/sidebar-control.js | 35 +++-- .../src/controls/sidebar-section.js | 75 ++++++++++- packages/customize-widgets/src/style.scss | 2 +- 12 files changed, 247 insertions(+), 247 deletions(-) create mode 100644 packages/customize-widgets/src/components/block-inspector-button/index.js create mode 100644 packages/customize-widgets/src/components/block-inspector-button/style.scss delete mode 100644 packages/customize-widgets/src/components/inspector/block-inspector-button.js delete mode 100644 packages/customize-widgets/src/components/inspector/index.js delete mode 100644 packages/customize-widgets/src/components/inspector/style.scss create mode 100644 packages/customize-widgets/src/controls/inspector-section.js diff --git a/packages/customize-widgets/src/components/block-inspector-button/index.js b/packages/customize-widgets/src/components/block-inspector-button/index.js new file mode 100644 index 00000000000000..c68c2f46c7468c --- /dev/null +++ b/packages/customize-widgets/src/components/block-inspector-button/index.js @@ -0,0 +1,38 @@ +/** + * WordPress dependencies + */ +import { useMemo } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; +import { MenuItem } from '@wordpress/components'; +import { useSelect } from '@wordpress/data'; +import { store as blockEditorStore } from '@wordpress/block-editor'; + +function BlockInspectorButton( { inspector, closeMenu, ...props } ) { + const selectedBlockClientId = useSelect( + ( select ) => select( blockEditorStore ).getSelectedBlockClientId(), + [] + ); + + const selectedBlock = useMemo( + () => document.getElementById( `block-${ selectedBlockClientId }` ), + [ selectedBlockClientId ] + ); + + return ( + { + // Open the inspector. + inspector.open( { + returnFocusWhenClose: selectedBlock, + } ); + // Then close the dropdown menu. + closeMenu(); + } } + { ...props } + > + { __( 'Show more settings' ) } + + ); +} + +export default BlockInspectorButton; diff --git a/packages/customize-widgets/src/components/block-inspector-button/style.scss b/packages/customize-widgets/src/components/block-inspector-button/style.scss new file mode 100644 index 00000000000000..b9a4f0f85d13a0 --- /dev/null +++ b/packages/customize-widgets/src/components/block-inspector-button/style.scss @@ -0,0 +1,21 @@ +#customize-theme-controls .customize-pane-child.accordion-section-content.customize-widgets-layout__inspector { + background: $white; + box-sizing: border-box; + + * { + box-sizing: inherit; + } + + .block-editor-block-inspector { + margin: -$grid-unit-15; + + // To override the style in block-editor/block-inspector. + h3 { + margin-bottom: 0; + } + } +} + +#customize-theme-controls .customize-pane-child.control-section-sidebar.is-sub-section-open { + transform: translateX(-100%); +} diff --git a/packages/customize-widgets/src/components/inserter/style.scss b/packages/customize-widgets/src/components/inserter/style.scss index 946c6f455a886b..bca7ddd2472806 100644 --- a/packages/customize-widgets/src/components/inserter/style.scss +++ b/packages/customize-widgets/src/components/inserter/style.scss @@ -5,7 +5,7 @@ min-width: 100%; } -#customize-outer-theme-controls #sub-accordion-section-widgets-inserter { +#customize-outer-theme-controls .widgets-inserter { padding: 0; .customize-section-description-container { diff --git a/packages/customize-widgets/src/components/inspector/block-inspector-button.js b/packages/customize-widgets/src/components/inspector/block-inspector-button.js deleted file mode 100644 index bbf45103063f62..00000000000000 --- a/packages/customize-widgets/src/components/inspector/block-inspector-button.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; -import { MenuItem } from '@wordpress/components'; - -function BlockInspectorButton( { isInspectorOpened = false, ...props } ) { - const label = isInspectorOpened - ? __( 'Hide more settings' ) - : __( 'Show more settings' ); - - return { label }; -} - -export default BlockInspectorButton; diff --git a/packages/customize-widgets/src/components/inspector/index.js b/packages/customize-widgets/src/components/inspector/index.js deleted file mode 100644 index 6a362ab9a338f4..00000000000000 --- a/packages/customize-widgets/src/components/inspector/index.js +++ /dev/null @@ -1,122 +0,0 @@ -/** - * External dependencies - */ -import classnames from 'classnames'; - -/** - * WordPress dependencies - */ -import { useEffect, useRef } from '@wordpress/element'; -import { useSelect } from '@wordpress/data'; -import { - BlockInspector, - store as blockEditorStore, -} from '@wordpress/block-editor'; -import { __ } from '@wordpress/i18n'; -import { useInstanceId } from '@wordpress/compose'; - -export { default as BlockInspectorButton } from './block-inspector-button'; - -function InspectorSectionMeta( { closeInspector, inspectorTitleId } ) { - return ( -
-
- -

- - { __( 'Customizing ▸ Widgets' ) } - - { __( 'Block Settings' ) } -

-
-
- ); -} - -export default function Inspector( { - isOpened, - isAnimating, - setInspectorOpenState, -} ) { - const selectedBlockClientId = useSelect( ( select ) => - select( blockEditorStore ).getSelectedBlockClientId() - ); - const selectedBlockRef = useRef(); - - useEffect( () => { - selectedBlockRef.current = document.querySelector( - `[data-block="${ selectedBlockClientId }"]` - ); - }, [ selectedBlockClientId ] ); - - const inspectorTitleId = useInstanceId( - Inspector, - 'customize-widgets-block-settings' - ); - - useEffect( () => { - const openedSidebarSection = document.querySelector( - '.control-section-sidebar.open' - ); - - if ( isOpened ) { - openedSidebarSection.classList.add( 'is-inspector-open' ); - } else { - openedSidebarSection.classList.remove( 'is-inspector-open' ); - } - - // In case the "transitionend" event for some reasons doesn't fire. - // (Like when it's set to "display: none", or when the transition property is removed.) - // See https://github.com/w3c/csswg-drafts/issues/3043 - const timer = setTimeout( () => { - setInspectorOpenState( 'TRANSITION_END' ); - }, 180 ); - - return () => { - openedSidebarSection.classList.remove( 'is-inspector-open' ); - clearTimeout( timer ); - }; - }, [ isOpened, setInspectorOpenState ] ); - - return ( -
{ - setInspectorOpenState( 'TRANSITION_END' ); - } } - > - { - setInspectorOpenState( 'CLOSE' ); - - // Wait a tick so that the block editor can transition back from being hidden. - window.requestAnimationFrame( () => { - selectedBlockRef.current?.focus(); - } ); - } } - inspectorTitleId={ inspectorTitleId } - /> - - -
- ); -} diff --git a/packages/customize-widgets/src/components/inspector/style.scss b/packages/customize-widgets/src/components/inspector/style.scss deleted file mode 100644 index 42b284a9b466a7..00000000000000 --- a/packages/customize-widgets/src/components/inspector/style.scss +++ /dev/null @@ -1,25 +0,0 @@ -// To override the style in block-editor/block-inspector. -.block-editor-block-inspector h3 { - margin-bottom: 0; -} - -#customize-theme-controls .customize-pane-child.accordion-section-content.customize-widgets-layout__inspector { - background: $white; - box-sizing: border-box; - - * { - box-sizing: inherit; - } - - .block-editor-block-inspector { - margin: -$grid-unit-15; - } -} - -#customize-theme-controls .customize-pane-child.accordion-section-content.control-section-sidebar.open { - transition: 0.18s transform cubic-bezier(0.645, 0.045, 0.355, 1); /* easeInOutCubic */ - - &.is-inspector-open { - transform: translateX(-100%); - } -} diff --git a/packages/customize-widgets/src/components/sidebar-block-editor/index.js b/packages/customize-widgets/src/components/sidebar-block-editor/index.js index cddd59ce80096b..1b9c0660bbc354 100644 --- a/packages/customize-widgets/src/components/sidebar-block-editor/index.js +++ b/packages/customize-widgets/src/components/sidebar-block-editor/index.js @@ -1,11 +1,12 @@ /** * WordPress dependencies */ -import { useReducer, createPortal, useMemo } from '@wordpress/element'; +import { createPortal, useMemo } from '@wordpress/element'; import { BlockEditorProvider, BlockList, BlockSelectionClearer, + BlockInspector, ObserveTyping, WritingFlow, BlockEditorKeyboardShortcuts, @@ -20,39 +21,13 @@ import { /** * Internal dependencies */ -import Inspector, { BlockInspectorButton } from '../inspector'; +import BlockInspectorButton from '../block-inspector-button'; import Header from '../header'; import useSidebarBlockEditor from './use-sidebar-block-editor'; import useInserter from '../inserter/use-inserter'; -const inspectorOpenStateReducer = ( state, action ) => { - switch ( action ) { - case 'OPEN': - return { - open: true, - busy: true, - }; - case 'TRANSITION_END': - return { - ...state, - busy: false, - }; - case 'CLOSE': - return { - open: false, - busy: true, - }; - default: - throw new Error( 'Unexpected action' ); - } -}; - -export default function SidebarBlockEditor( { sidebar, inserter } ) { +export default function SidebarBlockEditor( { sidebar, inserter, inspector } ) { const [ blocks, onInput, onChange ] = useSidebarBlockEditor( sidebar ); - const [ - { open: isInspectorOpened, busy: isInspectorAnimating }, - setInspectorOpenState, - ] = useReducer( inspectorOpenStateReducer, { open: false, busy: false } ); const parentContainer = document.getElementById( 'customize-theme-controls' ); @@ -69,52 +44,46 @@ export default function SidebarBlockEditor( { sidebar, inserter } ) { - + { createPortal( - , - parentContainer + // This is a temporary hack to prevent button component inside + // from submitting form when type="button" is not specified. +
event.preventDefault() }> + + , + inspector.contentContainer[ 0 ] ) } <__experimentalBlockSettingsMenuFirstItem> { ( { onClose } ) => ( { - // Open the inspector, - setInspectorOpenState( 'OPEN' ); - // Then close the dropdown menu. - onClose(); - } } + inspector={ inspector } + closeMenu={ onClose } /> ) } diff --git a/packages/customize-widgets/src/controls/inserter-outer-section.js b/packages/customize-widgets/src/controls/inserter-outer-section.js index 7021106afeeb6a..5d09cc193f66ff 100644 --- a/packages/customize-widgets/src/controls/inserter-outer-section.js +++ b/packages/customize-widgets/src/controls/inserter-outer-section.js @@ -62,6 +62,8 @@ class InserterOuterSection extends customize.OuterSection { // Use capture mode to make this run before other event listeners. true ); + + this.contentContainer.addClass( 'widgets-inserter' ); } get isOpen() { return this.expanded(); diff --git a/packages/customize-widgets/src/controls/inspector-section.js b/packages/customize-widgets/src/controls/inspector-section.js new file mode 100644 index 00000000000000..7c74c1085b2141 --- /dev/null +++ b/packages/customize-widgets/src/controls/inspector-section.js @@ -0,0 +1,58 @@ +const { + wp: { customize }, +} = window; + +class InspectorSection extends customize.Section { + constructor( id, options ) { + super( id, options ); + + this.parentSection = options.parentSection; + + this.returnFocusWhenClose = null; + } + ready() { + this.contentContainer[ 0 ].classList.add( + 'customize-widgets-layout__inspector' + ); + } + onChangeExpanded( expanded, args ) { + super.onChangeExpanded( expanded, args ); + + if ( this.parentSection && ! args.unchanged ) { + if ( expanded ) { + this.parentSection.collapse( { + manualTransition: true, + } ); + } else { + this.parentSection.expand( { + manualTransition: true, + completeCallback: () => { + // Return focus after finishing the transition. + if ( + this.returnFocusWhenClose && + ! this.contentContainer[ 0 ].contains( + this.returnFocusWhenClose + ) + ) { + this.returnFocusWhenClose.focus(); + } + }, + } ); + } + } + } + open( { returnFocusWhenClose } = {} ) { + this.returnFocusWhenClose = returnFocusWhenClose; + + this.expand( { + allowMultiple: true, + } ); + } + close() { + this.collapse( { + allowMultiple: true, + } ); + } +} + +export default InspectorSection; diff --git a/packages/customize-widgets/src/controls/sidebar-control.js b/packages/customize-widgets/src/controls/sidebar-control.js index 32d3fe0823894f..e64bf945fd04f6 100644 --- a/packages/customize-widgets/src/controls/sidebar-control.js +++ b/packages/customize-widgets/src/controls/sidebar-control.js @@ -14,34 +14,45 @@ const { wp: { customize }, } = window; -const inserterId = 'widgets-inserter'; +const getInserterId = ( controlId ) => `widgets-inserter-${ controlId }`; class SidebarControl extends customize.Control { ready() { - this.inserter = new InserterOuterSection( inserterId, {} ); + this.inserter = new InserterOuterSection( + getInserterId( this.id ), + {} + ); customize.section.add( this.inserter ); + + this.sectionInstance = customize.section( this.section() ); + + this.inspector = this.sectionInstance.inspector; + this.render(); } - onChangeExpanded() { - this.render(); - } - expanded() { - return customize.section( this.section() ).expanded(); + onChangeSectionExpanded( expanded, args ) { + if ( ! args.unchanged ) { + // Close the inserter when the section collapses. + if ( ! expanded ) { + this.inserter.close(); + } + + this.render(); + } } render() { - if ( this.expanded() ) { + if ( this.sectionInstance.expanded() ) { render( , this.container[ 0 ] ); - } else { + } else if ( ! this.sectionInstance.hasSubSectionOpened() ) { + // Don't unmount the node when the sub section (inspector) is opened. unmountComponentAtNode( this.container[ 0 ] ); - - // Close the inserter when the section collapses. - this.inserter.close(); } } } diff --git a/packages/customize-widgets/src/controls/sidebar-section.js b/packages/customize-widgets/src/controls/sidebar-section.js index 3cc165f4c3fbd5..7c67a12a629c60 100644 --- a/packages/customize-widgets/src/controls/sidebar-section.js +++ b/packages/customize-widgets/src/controls/sidebar-section.js @@ -1,15 +1,78 @@ +/** + * WordPress dependencies + */ +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import InspectorSection from './inspector-section'; + const { wp: { customize }, } = window; -class SidebarSection extends customize.Section { - onChangeExpanded( expanded, args ) { - super.onChangeExpanded( expanded, args ); +const getInspectorSectionId = ( sidebarId ) => + `widgets-inspector-${ sidebarId }`; +class SidebarSection extends customize.Section { + ready() { + this.inspector = new InspectorSection( + getInspectorSectionId( this.id ), + { + title: __( 'Block Settings' ), + parentSection: this, + customizeAction: [ + __( 'Customizing' ), + __( 'Widgets' ), + this.params.title, + ].join( ' ▸ ' ), + } + ); + customize.section.add( this.inspector ); + } + hasSubSectionOpened() { + return this.inspector.expanded(); + } + onChangeExpanded( expanded, _args ) { const controls = this.controls(); - controls.forEach( ( control ) => { - control.onChangeExpanded( expanded, args ); - } ); + const args = { + ..._args, + completeCallback() { + controls.forEach( ( control ) => { + control.onChangeSectionExpanded( expanded, args ); + } ); + }, + }; + + if ( args.manualTransition ) { + if ( expanded ) { + this.contentContainer.addClass( [ 'busy', 'open' ] ); + this.contentContainer.removeClass( 'is-sub-section-open' ); + this.contentContainer + .closest( '.wp-full-overlay' ) + .addClass( 'section-open' ); + this.contentContainer.one( 'transitionend', () => { + this.contentContainer.removeClass( 'busy' ); + args.completeCallback(); + } ); + } else { + this.contentContainer.addClass( [ + 'busy', + 'is-sub-section-open', + ] ); + this.contentContainer + .closest( '.wp-full-overlay' ) + .addClass( 'section-open' ); + this.contentContainer.removeClass( 'open' ); + this.contentContainer.one( 'transitionend', () => { + this.contentContainer.removeClass( 'busy' ); + args.completeCallback(); + } ); + } + } else { + super.onChangeExpanded( expanded, args ); + } } } diff --git a/packages/customize-widgets/src/style.scss b/packages/customize-widgets/src/style.scss index 13b614322b10e9..96954c02100975 100644 --- a/packages/customize-widgets/src/style.scss +++ b/packages/customize-widgets/src/style.scss @@ -1,3 +1,3 @@ -@import "./components/inspector/style.scss"; +@import "./components/block-inspector-button/style.scss"; @import "./components/header/style.scss"; @import "./components/inserter/style.scss"; From 030dce856593b6ecb85cdf07ba6c2a1a05ec2131 Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Thu, 8 Apr 2021 08:49:07 +0300 Subject: [PATCH 043/125] Add do_block_template_part function (#30345) * Add do_block_template_part function * Add functions for the header & footer template-parts * rename functions * rename functions --- lib/full-site-editing/template-parts.php | 33 ++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/lib/full-site-editing/template-parts.php b/lib/full-site-editing/template-parts.php index a64416cfc39f9c..8e21622c03e874 100644 --- a/lib/full-site-editing/template-parts.php +++ b/lib/full-site-editing/template-parts.php @@ -201,3 +201,36 @@ function gutenberg_filter_template_part_area( $type ) { trigger_error( $warning_message, E_USER_NOTICE ); return WP_TEMPLATE_PART_AREA_UNCATEGORIZED; } + +/** + * Print a template-part. + * + * @param string $part The template-part to print. Use "header" or "footer". + * + * @return void + */ +function gutenberg_block_template_part( $part ) { + $template_part = gutenberg_get_block_template( get_stylesheet() . '//' . $part, 'wp_template_part' ); + if ( ! $template_part || empty( $template_part->content ) ) { + return; + } + echo do_blocks( $template_part->content ); +} + +/** + * Print the header template-part. + * + * @return void + */ +function gutenberg_block_header_area() { + gutenberg_block_template_part( 'header' ); +} + +/** + * Print the footer template-part. + * + * @return void + */ +function gutenberg_block_footer_area() { + gutenberg_block_template_part( 'footer' ); +} From 9585a456428467ca5d23e446dde995ee0ff61107 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Wrede?= Date: Thu, 8 Apr 2021 09:42:32 +0200 Subject: [PATCH 044/125] Replace older-style PHP type conversion functions with typecasts (#30531) --- lib/block-supports/border.php | 2 +- lib/class-wp-rest-menu-items-controller.php | 2 +- packages/block-library/src/site-logo/index.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/block-supports/border.php b/lib/block-supports/border.php index 951efaf92e452f..0a29d3753cecc2 100644 --- a/lib/block-supports/border.php +++ b/lib/block-supports/border.php @@ -55,7 +55,7 @@ function gutenberg_apply_border_support( $block_type, $block_attributes ) { $has_border_radius_support = gutenberg_block_has_support( $block_type, array( '__experimentalBorder', 'radius' ), false ); if ( $has_border_radius_support ) { if ( isset( $block_attributes['style']['border']['radius'] ) ) { - $border_radius = intval( $block_attributes['style']['border']['radius'] ); + $border_radius = (int) $block_attributes['style']['border']['radius']; $styles[] = sprintf( 'border-radius: %dpx;', $border_radius ); } } diff --git a/lib/class-wp-rest-menu-items-controller.php b/lib/class-wp-rest-menu-items-controller.php index afe122d4fc60fe..fc25c26a324181 100644 --- a/lib/class-wp-rest-menu-items-controller.php +++ b/lib/class-wp-rest-menu-items-controller.php @@ -571,7 +571,7 @@ protected function prepare_item_for_database( $request ) { foreach ( array( 'menu-item-object-id', 'menu-item-parent-id' ) as $key ) { // Note we need to allow negative-integer IDs for previewed objects not inserted yet. - $prepared_nav_item[ $key ] = intval( $prepared_nav_item[ $key ] ); + $prepared_nav_item[ $key ] = (int) $prepared_nav_item[ $key ]; } foreach ( array( 'menu-item-type', 'menu-item-object', 'menu-item-target' ) as $key ) { diff --git a/packages/block-library/src/site-logo/index.php b/packages/block-library/src/site-logo/index.php index 62a046aca9e080..902daad001457d 100644 --- a/packages/block-library/src/site-logo/index.php +++ b/packages/block-library/src/site-logo/index.php @@ -17,8 +17,8 @@ function render_block_core_site_logo( $attributes ) { if ( empty( $attributes['width'] ) ) { return $image; } - $height = floatval( $attributes['width'] ) / ( floatval( $image[1] ) / floatval( $image[2] ) ); - return array( $image[0], intval( $attributes['width'] ), intval( $height ) ); + $height = (float) $attributes['width'] / ( (float) $image[1] / (float) $image[2] ); + return array( $image[0], (int) $attributes['width'], (int) $height ); }; add_filter( 'wp_get_attachment_image_src', $adjust_width_height_filter ); From a2e284d98a156593e41d174ebfa412a86dbb541a Mon Sep 17 00:00:00 2001 From: Constantin Piber <59023762+cpiber@users.noreply.github.com> Date: Thu, 8 Apr 2021 10:32:43 +0200 Subject: [PATCH 045/125] Scripts: Allow CSS modules in the build commands (#29182) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * packages/scripts: config allow css modules * README and CHANGELOG Co-authored-by: Greg Ziółkowski --- packages/scripts/CHANGELOG.md | 4 ++++ packages/scripts/README.md | 2 ++ packages/scripts/config/webpack.config.js | 5 ++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/scripts/CHANGELOG.md b/packages/scripts/CHANGELOG.md index 7ca1dce263b8bb..9412afc3d1ad8f 100644 --- a/packages/scripts/CHANGELOG.md +++ b/packages/scripts/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### New Features + +- `build` and `start` command now bundle files ending with `.module.css` as CSS modules and extracts `style.module.css` ([#29182](https://github.com/WordPress/gutenberg/pull/29182)). + ## 14.1.0 (2021-04-06) ### Enhancements diff --git a/packages/scripts/README.md b/packages/scripts/README.md index 4eddc4f55bffc1..bd1d8b480873fd 100644 --- a/packages/scripts/README.md +++ b/packages/scripts/README.md @@ -540,6 +540,8 @@ If you do so, then CSS files generated will follow the names of the entry points Avoid using `style` keyword in an entry point name, this might break your build process. +You can also bundle CSS modules by prefixing `.module` to the extension, e.g. `style.module.scss`. Otherwise, these files are handled like all other `style.scss`. They will also be extracted into `style-index.css`. + #### Using fonts and images It is possible to reference font (`woff`, `woff2`, `eot`, `ttf` and `otf`) and image (`bmp`, `png`, `jpg`, `jpeg` and `gif`) files from CSS that is controlled by webpack as explained in the previous section. diff --git a/packages/scripts/config/webpack.config.js b/packages/scripts/config/webpack.config.js index 0ef7128a04f3d6..f03eca896eb069 100644 --- a/packages/scripts/config/webpack.config.js +++ b/packages/scripts/config/webpack.config.js @@ -35,6 +35,9 @@ const cssLoaders = [ loader: require.resolve( 'css-loader' ), options: { sourceMap: ! isProduction, + modules: { + auto: true, + }, }, }, { @@ -107,7 +110,7 @@ const config = { splitChunks: { cacheGroups: { style: { - test: /[\\/]style\.(sc|sa|c)ss$/, + test: /[\\/]style(\.module)?\.(sc|sa|c)ss$/, chunks: 'all', enforce: true, automaticNameDelimiter: '-', From 4f051fbef6b14abbd3cb99becd24cc033d8a907f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 8 Apr 2021 11:16:52 +0200 Subject: [PATCH 046/125] Global Styles: Make the dependency of the star matcher explicit when translating theme.json (#30604) --- lib/class-wp-theme-json-resolver.php | 33 ++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/lib/class-wp-theme-json-resolver.php b/lib/class-wp-theme-json-resolver.php index bacadea73bb7a2..cac6a576dddfc9 100644 --- a/lib/class-wp-theme-json-resolver.php +++ b/lib/class-wp-theme-json-resolver.php @@ -191,24 +191,39 @@ private static function translate( $theme_json, $domain = 'default' ) { $path = $field['path']; $key = $field['key']; $context = $field['context']; - if ( 'settings' === $path[0] ) { - if ( empty( $theme_json['settings'] ) ) { - continue; - } - $path = array_slice( $path, 2 ); - foreach ( $theme_json['settings'] as $setting_key => $setting ) { - $array_to_translate = _wp_array_get( $setting, $path, null ); + + /* + * We need to process the paths that include '*' separately. + * One example of such a path would be: + * [ 'settings', '*', 'color', 'palette' ] + */ + $nodes_to_iterate = array_keys( $path, '*', true ); + if ( ! empty( $nodes_to_iterate ) ) { + /* + * At the moment, we only need to support one '*' in the path, so take it directly. + * - base will be [ 'settings' ] + * - data will be [ 'color', 'palette' ] + */ + $base_path = array_slice( $path, 0, $nodes_to_iterate[0] ); + $data_path = array_slice( $path, $nodes_to_iterate[0] + 1 ); + $base_tree = _wp_array_get( $theme_json, $base_path, array() ); + foreach ( $base_tree as $node_name => $node_data ) { + $array_to_translate = _wp_array_get( $node_data, $data_path, null ); if ( is_null( $array_to_translate ) ) { continue; } + + // Whole path will be [ 'settings', 'core/paragraph', 'color', 'palette' ]. + $whole_path = array_merge( $base_path, array( $node_name ), $data_path ); $translated_array = self::translate_theme_json_chunk( $array_to_translate, $key, $context, $domain ); - gutenberg_experimental_set( $theme_json['settings'][ $setting_key ], $path, $translated_array ); + gutenberg_experimental_set( $theme_json, $whole_path, $translated_array ); } } else { $array_to_translate = _wp_array_get( $theme_json, $path, null ); if ( is_null( $array_to_translate ) ) { continue; } + $translated_array = self::translate_theme_json_chunk( $array_to_translate, $key, $context, $domain ); gutenberg_experimental_set( $theme_json, $path, $translated_array ); } @@ -362,7 +377,7 @@ private static function get_user_data_from_custom_post_type( $should_create_cpt array( 'post_content' => '{}', 'post_status' => 'publish', - 'post_title' => __( 'Custom Styles' ), + 'post_title' => __( 'Custom Styles', 'default' ), 'post_type' => $post_type_filter, 'post_name' => $post_name_filter, ), From a2b36aa19df74a3d8315ad6614abf117fec0727a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 8 Apr 2021 11:17:17 +0200 Subject: [PATCH 047/125] Global Styles: Remove no longer needed translations handled in PHP for settings (#30605) --- lib/class-wp-theme-json-resolver.php | 56 ---------------------------- 1 file changed, 56 deletions(-) diff --git a/lib/class-wp-theme-json-resolver.php b/lib/class-wp-theme-json-resolver.php index cac6a576dddfc9..94944aaea54737 100644 --- a/lib/class-wp-theme-json-resolver.php +++ b/lib/class-wp-theme-json-resolver.php @@ -245,62 +245,6 @@ public static function get_core_data() { $all_blocks = WP_Theme_JSON::ALL_BLOCKS_NAME; $config = self::read_json_file( __DIR__ . '/experimental-default-theme.json' ); $config = self::translate( $config ); - - // Start i18n logic to remove when JSON i18 strings are extracted. - $default_colors_i18n = array( - 'black' => __( 'Black', 'gutenberg' ), - 'cyan-bluish-gray' => __( 'Cyan bluish gray', 'gutenberg' ), - 'white' => __( 'White', 'gutenberg' ), - 'pale-pink' => __( 'Pale pink', 'gutenberg' ), - 'vivid-red' => __( 'Vivid red', 'gutenberg' ), - 'luminous-vivid-orange' => __( 'Luminous vivid orange', 'gutenberg' ), - 'luminous-vivid-amber' => __( 'Luminous vivid amber', 'gutenberg' ), - 'light-green-cyan' => __( 'Light green cyan', 'gutenberg' ), - 'vivid-green-cyan' => __( 'Vivid green cyan', 'gutenberg' ), - 'pale-cyan-blue' => __( 'Pale cyan blue', 'gutenberg' ), - 'vivid-cyan-blue' => __( 'Vivid cyan blue', 'gutenberg' ), - 'vivid-purple' => __( 'Vivid purple', 'gutenberg' ), - ); - if ( ! empty( $config['settings'][ $all_blocks ]['color']['palette'] ) ) { - foreach ( $config['settings'][ $all_blocks ]['color']['palette'] as $color_key => $color ) { - $config['settings'][ $all_blocks ]['color']['palette'][ $color_key ]['name'] = $default_colors_i18n[ $color['slug'] ]; - } - } - - $default_gradients_i18n = array( - 'vivid-cyan-blue-to-vivid-purple' => __( 'Vivid cyan blue to vivid purple', 'gutenberg' ), - 'light-green-cyan-to-vivid-green-cyan' => __( 'Light green cyan to vivid green cyan', 'gutenberg' ), - 'luminous-vivid-amber-to-luminous-vivid-orange' => __( 'Luminous vivid amber to luminous vivid orange', 'gutenberg' ), - 'luminous-vivid-orange-to-vivid-red' => __( 'Luminous vivid orange to vivid red', 'gutenberg' ), - 'very-light-gray-to-cyan-bluish-gray' => __( 'Very light gray to cyan bluish gray', 'gutenberg' ), - 'cool-to-warm-spectrum' => __( 'Cool to warm spectrum', 'gutenberg' ), - 'blush-light-purple' => __( 'Blush light purple', 'gutenberg' ), - 'blush-bordeaux' => __( 'Blush bordeaux', 'gutenberg' ), - 'luminous-dusk' => __( 'Luminous dusk', 'gutenberg' ), - 'pale-ocean' => __( 'Pale ocean', 'gutenberg' ), - 'electric-grass' => __( 'Electric grass', 'gutenberg' ), - 'midnight' => __( 'Midnight', 'gutenberg' ), - ); - if ( ! empty( $config['settings'][ $all_blocks ]['color']['gradients'] ) ) { - foreach ( $config['settings'][ $all_blocks ]['color']['gradients'] as $gradient_key => $gradient ) { - $config['settings'][ $all_blocks ]['color']['gradients'][ $gradient_key ]['name'] = $default_gradients_i18n[ $gradient['slug'] ]; - } - } - - $default_font_sizes_i18n = array( - 'small' => __( 'Small', 'gutenberg' ), - 'normal' => __( 'Normal', 'gutenberg' ), - 'medium' => __( 'Medium', 'gutenberg' ), - 'large' => __( 'Large', 'gutenberg' ), - 'huge' => __( 'Huge', 'gutenberg' ), - ); - if ( ! empty( $config['settings'][ $all_blocks ]['typography']['fontSizes'] ) ) { - foreach ( $config['settings'][ $all_blocks ]['typography']['fontSizes'] as $font_size_key => $font_size ) { - $config['settings'][ $all_blocks ]['typography']['fontSizes'][ $font_size_key ]['name'] = $default_font_sizes_i18n[ $font_size['slug'] ]; - } - } - // End i18n logic to remove when JSON i18 strings are extracted. - self::$core = new WP_Theme_JSON( $config ); return self::$core; From 1a74e9a4c8feafb3608a61fb19ca6d077f6cd2c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Wrede?= Date: Thu, 8 Apr 2021 12:48:51 +0200 Subject: [PATCH 048/125] Docs: Fix return type of `construct_wp_query_args()` (#30611) * Fix return type * Fix type --- lib/query-utils.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/query-utils.php b/lib/query-utils.php index 477772728ab6a2..42b88fca83a102 100644 --- a/lib/query-utils.php +++ b/lib/query-utils.php @@ -7,15 +7,15 @@ */ /** - * Helper function that constructs a WP_Query args object from + * Helper function that constructs a WP_Query args array from * a `Query` block properties. * * It's used in QueryLoop, QueryPaginationNumbers and QueryPaginationNext blocks. * * @param WP_Block $block Block instance. - * @param int $page Curren query's page. + * @param int $page Current query's page. * - * @return object Returns the constructed WP_Query object. + * @return array Returns the constructed WP_Query arguments. */ function construct_wp_query_args( $block, $page ) { $query = array( From 7c134eb66f1e5ed67db646e19234d9edf6e3090e Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Thu, 8 Apr 2021 12:01:16 +0100 Subject: [PATCH 049/125] Allow creating custom block templates in classic themes (#30438) * Allow creating custom block templates in classic themes * Fix template fetching * Restore PHP callback * Take into account custom templates (#30464) * Change the prefix for custom templates (#30467) * Change the prefix for custom templates * Update comment * Add gutenberg_supports_block_templates (#30465) * Introduce gutenberg_is_fse_enabled * typo & reverse logic * update filter name * Remove filter * Rename function * don't use "disable"theme-supports * rename theme-support * Missed renaming the theme-support * Add a modal to edit the template's title before creating it * Fix design and enable for FSE themes * Add e2e test * Add documentation * Add some site blocks to the default template Co-authored-by: Ari Stathopoulos --- .../themes/block-based-themes.md | 10 + lib/client-assets.php | 4 +- lib/compat.php | 2 +- lib/editor-settings.php | 4 +- lib/full-site-editing/full-site-editing.php | 9 + lib/full-site-editing/page-templates.php | 18 +- lib/full-site-editing/template-loader.php | 13 +- lib/full-site-editing/template-parts.php | 6 +- lib/full-site-editing/templates.php | 6 +- lib/global-styles.php | 4 +- lib/init.php | 1 + package-lock.json | 3 +- packages/core-data/src/resolvers.js | 26 ++- packages/e2e-test-utils/src/preview.js | 3 + .../post-editor-template-mode.test.js.snap | 21 ++ .../post-editor-template-mode.test.js | 77 ++++++- packages/edit-post/package.json | 3 +- .../components/header/template-title/index.js | 13 +- .../components/sidebar/post-template/index.js | 189 ++++++++++++------ .../sidebar/post-template/style.scss | 13 ++ packages/edit-post/src/editor.js | 21 +- packages/edit-post/src/store/actions.js | 42 ++++ packages/edit-post/src/store/selectors.js | 29 +++ 23 files changed, 390 insertions(+), 127 deletions(-) create mode 100644 packages/e2e-tests/specs/experiments/__snapshots__/post-editor-template-mode.test.js.snap diff --git a/docs/how-to-guides/themes/block-based-themes.md b/docs/how-to-guides/themes/block-based-themes.md index 3368d80fcfff33..6eb8608b0e02fe 100644 --- a/docs/how-to-guides/themes/block-based-themes.md +++ b/docs/how-to-guides/themes/block-based-themes.md @@ -124,6 +124,16 @@ As we're still early in the process, the number of blocks specifically dedicated One of the most important aspects of themes (if not the most important) is the styling. While initially you'll be able to provide styles and enqueue them using the same hooks themes have always used, the [Global Styles](/docs/how-to-guides/themes/theme-json.md) effort will provide a scaffolding for adding many theme styles in the future. +## Classic Themes + +Users of classic themes can also build custom block templates and use theme in their Pages and Custom Post Types that supports Page Templates. + +Theme authors can opt-out of this feature by removing the `block-templates` theme support in their `functions.php` file. + +```php +remove_theme_support( 'block-templates' ); +``` + ## Resources - [Full Site Editing](https://github.com/WordPress/gutenberg/labels/%5BFeature%5D%20Full%20Site%20Editing) label. diff --git a/lib/client-assets.php b/lib/client-assets.php index 15c752bf88504a..34bbbb227412fb 100644 --- a/lib/client-assets.php +++ b/lib/client-assets.php @@ -660,7 +660,7 @@ function gutenberg_extend_block_editor_styles( $settings ) { } // Remove the default font editor styles for FSE themes. - if ( gutenberg_is_fse_theme() ) { + if ( gutenberg_supports_block_templates() ) { foreach ( $settings['styles'] as $j => $style ) { if ( 0 === strpos( $style['css'], 'body { font-family:' ) ) { unset( $settings['styles'][ $j ] ); @@ -680,7 +680,7 @@ function gutenberg_extend_block_editor_styles( $settings ) { * @return array Filtered editor settings. */ function gutenberg_extend_block_editor_settings_with_fse_theme_flag( $settings ) { - $settings['isFSETheme'] = gutenberg_is_fse_theme(); + $settings['supportsTemplateMode'] = gutenberg_supports_block_templates(); // Enable the new layout options for themes with a theme.json file. $settings['supportsLayout'] = WP_Theme_JSON_Resolver::theme_has_support(); diff --git a/lib/compat.php b/lib/compat.php index a67bdce1de8ccc..84956857c262df 100644 --- a/lib/compat.php +++ b/lib/compat.php @@ -14,7 +14,7 @@ * @return bool */ function gutenberg_should_load_separate_block_assets() { - $load_separate_styles = gutenberg_is_fse_theme(); + $load_separate_styles = gutenberg_supports_block_templates(); /** * Determine if separate styles will be loaded for blocks on-render or not. * diff --git a/lib/editor-settings.php b/lib/editor-settings.php index 59e1b8fb804496..d6db710e797bd8 100644 --- a/lib/editor-settings.php +++ b/lib/editor-settings.php @@ -39,7 +39,7 @@ function gutenberg_get_common_block_editor_settings() { }; $settings = array( - '__unstableEnableFullSiteEditingBlocks' => gutenberg_is_fse_theme(), + '__unstableEnableFullSiteEditingBlocks' => gutenberg_supports_block_templates(), 'disableCustomColors' => get_theme_support( 'disable-custom-colors' ), 'disableCustomFontSizes' => get_theme_support( 'disable-custom-font-sizes' ), 'disableCustomGradients' => get_theme_support( 'disable-custom-gradients' ), @@ -82,7 +82,7 @@ function gutenberg_extend_post_editor_settings( $settings ) { $image_sizes = wp_list_pluck( $settings['imageSizes'], 'slug' ); $settings['imageDefaultSize'] = in_array( $image_default_size, $image_sizes, true ) ? $image_default_size : 'large'; - $settings['__unstableEnableFullSiteEditingBlocks'] = gutenberg_is_fse_theme(); + $settings['__unstableEnableFullSiteEditingBlocks'] = gutenberg_supports_block_templates(); return $settings; } diff --git a/lib/full-site-editing/full-site-editing.php b/lib/full-site-editing/full-site-editing.php index 28f91a9792265e..564332bbf6896f 100644 --- a/lib/full-site-editing/full-site-editing.php +++ b/lib/full-site-editing/full-site-editing.php @@ -14,6 +14,15 @@ function gutenberg_is_fse_theme() { return is_readable( get_stylesheet_directory() . '/block-templates/index.html' ); } +/** + * Returns whether the current theme is FSE-enabled or not. + * + * @return boolean Whether the current theme is FSE-enabled or not. + */ +function gutenberg_supports_block_templates() { + return gutenberg_is_fse_theme() || current_theme_supports( 'block-templates' ); +} + /** * Show a notice when a Full Site Editing theme is used. */ diff --git a/lib/full-site-editing/page-templates.php b/lib/full-site-editing/page-templates.php index 6c5a11c8a40e23..e868d963e5aaf4 100644 --- a/lib/full-site-editing/page-templates.php +++ b/lib/full-site-editing/page-templates.php @@ -15,22 +15,16 @@ * @return array (Maybe) modified page templates array. */ function gutenberg_load_block_page_templates( $templates, $theme, $post, $post_type ) { - if ( ! gutenberg_is_fse_theme() ) { + if ( ! gutenberg_supports_block_templates() ) { return $templates; } - $data = WP_Theme_JSON_Resolver::get_theme_data()->get_custom_templates(); - $custom_templates = array(); - if ( isset( $data ) ) { - foreach ( $data as $key => $template ) { - if ( ( ! isset( $template['postTypes'] ) && 'page' === $post_type ) || - ( isset( $template['postTypes'] ) && in_array( $post_type, $template['postTypes'], true ) ) - ) { - $custom_templates[ $key ] = $template['title']; - } - } + $block_templates = gutenberg_get_block_templates( array(), 'wp_template' ); + foreach ( $block_templates as $template ) { + // TODO: exclude templates that are not concerned by the current post type. + $templates[ $template->slug ] = $template->title; } - return $custom_templates; + return $templates; } add_filter( 'theme_templates', 'gutenberg_load_block_page_templates', 10, 4 ); diff --git a/lib/full-site-editing/template-loader.php b/lib/full-site-editing/template-loader.php index c828a27c99a7bd..c02ebf78b96a19 100644 --- a/lib/full-site-editing/template-loader.php +++ b/lib/full-site-editing/template-loader.php @@ -9,7 +9,7 @@ * Adds necessary filters to use 'wp_template' posts instead of theme template files. */ function gutenberg_add_template_loader_filters() { - if ( ! gutenberg_is_fse_theme() ) { + if ( ! gutenberg_supports_block_templates() ) { return; } @@ -71,9 +71,18 @@ function gutenberg_override_query_template( $template, $type, array $templates = foreach ( $templates as $template_item ) { $template_item_slug = gutenberg_strip_php_suffix( $template_item ); + // Is this a custom template? + // This check should be removed when merged in core. + // Instead, wp_templates should be considered valid in locate_template. + $is_custom_template = 0 === strpos( $current_block_template_slug, 'wp-custom-template-' ); + // Don't override the template if we find a template matching the slug we look for // and which does not match a block template slug. - if ( $current_template_slug !== $current_block_template_slug && $current_template_slug === $template_item_slug ) { + if ( + ! $is_custom_template && + $current_template_slug !== $current_block_template_slug && + $current_template_slug === $template_item_slug + ) { return $template; } } diff --git a/lib/full-site-editing/template-parts.php b/lib/full-site-editing/template-parts.php index 8e21622c03e874..8d23e3f774a834 100644 --- a/lib/full-site-editing/template-parts.php +++ b/lib/full-site-editing/template-parts.php @@ -9,7 +9,7 @@ * Registers block editor 'wp_template_part' post type. */ function gutenberg_register_template_part_post_type() { - if ( ! gutenberg_is_fse_theme() ) { + if ( ! gutenberg_supports_block_templates() ) { return; } @@ -64,7 +64,7 @@ function gutenberg_register_template_part_post_type() { * Registers the 'wp_template_part_area' taxonomy. */ function gutenberg_register_wp_template_part_area_taxonomy() { - if ( ! gutenberg_is_fse_theme() ) { + if ( ! gutenberg_supports_block_templates() ) { return; } @@ -107,7 +107,7 @@ function gutenberg_register_wp_template_part_area_taxonomy() { * Fixes the label of the 'wp_template_part' admin menu entry. */ function gutenberg_fix_template_part_admin_menu_entry() { - if ( ! gutenberg_is_fse_theme() ) { + if ( ! gutenberg_supports_block_templates() ) { return; } diff --git a/lib/full-site-editing/templates.php b/lib/full-site-editing/templates.php index 6362d7716c3c1c..0ecfcc9a68d8e6 100644 --- a/lib/full-site-editing/templates.php +++ b/lib/full-site-editing/templates.php @@ -28,7 +28,7 @@ function gutenberg_get_template_paths() { * Registers block editor 'wp_template' post type. */ function gutenberg_register_template_post_type() { - if ( ! gutenberg_is_fse_theme() ) { + if ( ! gutenberg_supports_block_templates() ) { return; } @@ -84,7 +84,7 @@ function gutenberg_register_template_post_type() { * Registers block editor 'wp_theme' taxonomy. */ function gutenberg_register_wp_theme_taxonomy() { - if ( ! gutenberg_is_fse_theme() ) { + if ( ! gutenberg_supports_block_templates() ) { return; } @@ -139,7 +139,7 @@ function gutenberg_grant_template_caps( array $allcaps ) { * Fixes the label of the 'wp_template' admin menu entry. */ function gutenberg_fix_template_admin_menu_entry() { - if ( ! gutenberg_is_fse_theme() ) { + if ( ! gutenberg_supports_block_templates() ) { return; } global $submenu; diff --git a/lib/global-styles.php b/lib/global-styles.php index 7a7225f4bf816c..2158fe96726f1c 100644 --- a/lib/global-styles.php +++ b/lib/global-styles.php @@ -200,7 +200,7 @@ function gutenberg_experimental_global_styles_settings( $settings ) { $origin = 'theme'; if ( WP_Theme_JSON_Resolver::theme_has_support() && - gutenberg_is_fse_theme() + gutenberg_supports_block_templates() ) { // Only lookup for the user data if we need it. $origin = 'user'; @@ -226,7 +226,7 @@ function gutenberg_experimental_global_styles_settings( $settings ) { function_exists( 'gutenberg_is_edit_site_page' ) && gutenberg_is_edit_site_page( $screen->id ) && WP_Theme_JSON_Resolver::theme_has_support() && - gutenberg_is_fse_theme() + gutenberg_supports_block_templates() ) { $user_cpt_id = WP_Theme_JSON_Resolver::get_user_custom_post_type_id(); $base_styles = WP_Theme_JSON_Resolver::get_merged_data( $theme_support_data, 'theme' )->get_raw_data(); diff --git a/lib/init.php b/lib/init.php index d532a620e0de29..d320d3bffaf242 100644 --- a/lib/init.php +++ b/lib/init.php @@ -177,3 +177,4 @@ function register_site_icon_url( $response ) { add_filter( 'rest_index', 'register_site_icon_url' ); add_theme_support( 'widgets-block-editor' ); +add_theme_support( 'block-templates' ); diff --git a/package-lock.json b/package-lock.json index 51db58af73c7c8..b4632ec138116f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12784,7 +12784,8 @@ "classnames": "^2.2.5", "lodash": "^4.17.19", "memize": "^1.1.0", - "rememo": "^3.0.0" + "rememo": "^3.0.0", + "uuid": "8.3.0" } }, "@wordpress/edit-site": { diff --git a/packages/core-data/src/resolvers.js b/packages/core-data/src/resolvers.js index dcbf37d93b2b8a..df7228676b05e9 100644 --- a/packages/core-data/src/resolvers.js +++ b/packages/core-data/src/resolvers.js @@ -385,13 +385,18 @@ export function* __experimentalGetTemplateForLink( link ) { // Ideally this should be using an apiFetch call // We could potentially do so by adding a "filter" to the `wp_template` end point. // Also it seems the returned object is not a regular REST API post type. - const template = yield regularFetch( - addQueryArgs( link, { - '_wp-find-template': true, - } ) - ); + let template; + try { + template = yield regularFetch( + addQueryArgs( link, { + '_wp-find-template': true, + } ) + ); + } catch ( e ) { + // For non-FSE themes, it is possible that this request returns an error. + } - if ( template === null ) { + if ( ! template ) { return; } @@ -410,3 +415,12 @@ export function* __experimentalGetTemplateForLink( link ) { } ); } } + +__experimentalGetTemplateForLink.shouldInvalidate = ( action ) => { + return ( + ( action.type === 'RECEIVE_ITEMS' || action.type === 'REMOVE_ITEMS' ) && + action.invalidateCache && + action.kind === 'postType' && + action.name === 'wp_template' + ); +}; diff --git a/packages/e2e-test-utils/src/preview.js b/packages/e2e-test-utils/src/preview.js index f1f5a8747b46bd..789ca761b6ca20 100644 --- a/packages/e2e-test-utils/src/preview.js +++ b/packages/e2e-test-utils/src/preview.js @@ -14,6 +14,9 @@ import { last } from 'lodash'; export async function openPreviewPage( editorPage = page ) { let openTabs = await browser.pages(); const expectedTabsCount = openTabs.length + 1; + await page.waitForSelector( + '.block-editor-post-preview__button-toggle:not([disabled])' + ); await editorPage.click( '.block-editor-post-preview__button-toggle' ); await editorPage.waitForSelector( '.edit-post-header-preview__button-external' diff --git a/packages/e2e-tests/specs/experiments/__snapshots__/post-editor-template-mode.test.js.snap b/packages/e2e-tests/specs/experiments/__snapshots__/post-editor-template-mode.test.js.snap new file mode 100644 index 00000000000000..641ad5cc979217 --- /dev/null +++ b/packages/e2e-tests/specs/experiments/__snapshots__/post-editor-template-mode.test.js.snap @@ -0,0 +1,21 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Post Editor Template mode Allow creating custom block templates in classic themes 1`] = ` +"

gutenberg

+ +

Just another WordPress site

+ + +
+ + +

Another FSE Post

+ +
+

Hello World

+
+ + +

Just a random paragraph added to the template

+" +`; diff --git a/packages/e2e-tests/specs/experiments/post-editor-template-mode.test.js b/packages/e2e-tests/specs/experiments/post-editor-template-mode.test.js index 140f567e4d74fe..858ef67ac807ea 100644 --- a/packages/e2e-tests/specs/experiments/post-editor-template-mode.test.js +++ b/packages/e2e-tests/specs/experiments/post-editor-template-mode.test.js @@ -13,7 +13,6 @@ import { describe( 'Post Editor Template mode', () => { beforeAll( async () => { - await activateTheme( 'tt1-blocks' ); await trashAllPosts( 'wp_template' ); await trashAllPosts( 'wp_template_part' ); } ); @@ -22,11 +21,9 @@ describe( 'Post Editor Template mode', () => { await activateTheme( 'twentytwentyone' ); } ); - beforeEach( async () => { - await createNewPost(); - } ); - it( 'Allow to switch to template mode, edit the template and check the result', async () => { + await activateTheme( 'tt1-blocks' ); + await createNewPost(); // Create a random post. await page.type( '.editor-post-title__input', 'Just an FSE Post' ); await page.keyboard.press( 'Enter' ); @@ -45,9 +42,9 @@ describe( 'Post Editor Template mode', () => { // Switch to template mode. await openDocumentSettingsSidebar(); - const switchLink = await page.waitForSelector( - '.edit-post-post-template button' - ); + const editTemplateXPath = + "//*[contains(@class, 'edit-post-post-template__actions')]//button[contains(text(), 'Edit')]"; + const switchLink = await page.waitForXPath( editTemplateXPath ); await switchLink.click(); // Check that we switched properly to edit mode. @@ -82,4 +79,68 @@ describe( 'Post Editor Template mode', () => { '//p[contains(text(), "Just a random paragraph added to the template")]' ); } ); + + it( 'Allow creating custom block templates in classic themes', async () => { + await activateTheme( 'twentytwentyone' ); + await createNewPost(); + // Create a random post. + await page.type( '.editor-post-title__input', 'Another FSE Post' ); + await page.keyboard.press( 'Enter' ); + await page.keyboard.type( 'Hello World' ); + + // Unselect the blocks. + await page.evaluate( () => { + wp.data.dispatch( 'core/block-editor' ).clearSelectedBlock(); + } ); + + // Save the post + // Saving shouldn't be necessary but unfortunately, + // there's a template resolution bug forcing us to do so. + await saveDraft(); + await page.reload(); + + // Create a new custom template. + await openDocumentSettingsSidebar(); + const newTemplateXPath = + "//*[contains(@class, 'edit-post-post-template__actions')]//button[contains(text(), 'New')]"; + const newButton = await page.waitForXPath( newTemplateXPath ); + await newButton.click(); + + // Fill the template title and submit. + const templateNameInputSelector = + '.edit-post-post-template__modal .components-text-control__input'; + await page.click( templateNameInputSelector ); + await page.keyboard.type( 'Blank Template' ); + await page.keyboard.press( 'Enter' ); + + // Check that we switched properly to edit mode. + await page.waitForXPath( + '//*[contains(@class, "components-snackbar")]/*[text()="Custom template created. You\'re in template mode now."]' + ); + + // Edit the template + await insertBlock( 'Paragraph' ); + await page.keyboard.type( + 'Just a random paragraph added to the template' + ); + + // Save changes + const doneButton = await page.waitForXPath( + `//button[contains(text(), 'Apply')]` + ); + await doneButton.click(); + const saveButton = await page.waitForXPath( + `//div[contains(@class, "entities-saved-states__panel-header")]/button[contains(text(), 'Save')]` + ); + await saveButton.click(); + + // Preview changes + const previewPage = await openPreviewPage(); + await previewPage.waitForSelector( '.wp-site-blocks' ); + const content = await previewPage.evaluate( + () => document.querySelector( '.wp-site-blocks' ).innerHTML + ); + + expect( content ).toMatchSnapshot(); + } ); } ); diff --git a/packages/edit-post/package.json b/packages/edit-post/package.json index 535240e3950aac..70fe724b6347e8 100644 --- a/packages/edit-post/package.json +++ b/packages/edit-post/package.json @@ -52,7 +52,8 @@ "classnames": "^2.2.5", "lodash": "^4.17.19", "memize": "^1.1.0", - "rememo": "^3.0.0" + "rememo": "^3.0.0", + "uuid": "8.3.0" }, "publishConfig": { "access": "public" diff --git a/packages/edit-post/src/components/header/template-title/index.js b/packages/edit-post/src/components/header/template-title/index.js index deb2b905ee9e34..877c48ccf50da0 100644 --- a/packages/edit-post/src/components/header/template-title/index.js +++ b/packages/edit-post/src/components/header/template-title/index.js @@ -3,8 +3,6 @@ */ import { __, sprintf } from '@wordpress/i18n'; import { useSelect } from '@wordpress/data'; -import { store as editorStore } from '@wordpress/editor'; -import { store as coreStore } from '@wordpress/core-data'; /** * Internal dependencies @@ -13,15 +11,12 @@ import { store as editPostStore } from '../../../store'; function TemplateTitle() { const { template, isEditing } = useSelect( ( select ) => { - const { getEditedPostAttribute } = select( editorStore ); - const { __experimentalGetTemplateForLink } = select( coreStore ); - const { isEditingTemplate } = select( editPostStore ); - const link = getEditedPostAttribute( 'link' ); + const { isEditingTemplate, getEditedPostTemplate } = select( + editPostStore + ); const _isEditing = isEditingTemplate(); return { - template: _isEditing - ? __experimentalGetTemplateForLink( link ) - : null, + template: _isEditing ? getEditedPostTemplate() : null, isEditing: _isEditing, }; }, [] ); diff --git a/packages/edit-post/src/components/sidebar/post-template/index.js b/packages/edit-post/src/components/sidebar/post-template/index.js index 806f49fa04edb3..05eef4febd9b8f 100644 --- a/packages/edit-post/src/components/sidebar/post-template/index.js +++ b/packages/edit-post/src/components/sidebar/post-template/index.js @@ -1,51 +1,61 @@ +/** + * External dependencies + */ +import { kebabCase } from 'lodash'; + /** * WordPress dependencies */ -import { __, sprintf } from '@wordpress/i18n'; -import { PanelRow, Button } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { + PanelRow, + Button, + Modal, + TextControl, + Flex, + FlexItem, +} from '@wordpress/components'; import { useSelect, useDispatch } from '@wordpress/data'; -import { createInterpolateElement } from '@wordpress/element'; +import { useState } from '@wordpress/element'; import { store as editorStore } from '@wordpress/editor'; import { store as coreStore } from '@wordpress/core-data'; -import { store as noticesStore } from '@wordpress/notices'; /** * Internal dependencies */ import { store as editPostStore } from '../../../store'; +import { createBlock, serialize } from '@wordpress/blocks'; function PostTemplate() { - const { template, isEditing, isFSETheme } = useSelect( ( select ) => { - const { - getEditedPostAttribute, - getCurrentPostType, - getCurrentPost, - } = select( editorStore ); - const { __experimentalGetTemplateForLink, getPostType } = select( - coreStore - ); - const { isEditingTemplate } = select( editPostStore ); - const link = getEditedPostAttribute( 'link' ); - const isFSEEnabled = select( editorStore ).getEditorSettings() - .isFSETheme; - const isViewable = - getPostType( getCurrentPostType() )?.viewable ?? false; - return { - template: - isFSEEnabled && - isViewable && - link && - getCurrentPost().status !== 'auto-draft' - ? __experimentalGetTemplateForLink( link ) - : null, - isEditing: isEditingTemplate(), - isFSETheme: isFSEEnabled, - }; - }, [] ); - const { setIsEditingTemplate } = useDispatch( editPostStore ); - const { createSuccessNotice } = useDispatch( noticesStore ); + const [ isModalOpen, setIsModalOpen ] = useState( false ); + const [ title, setTitle ] = useState( '' ); + const { template, isEditing, supportsTemplateMode } = useSelect( + ( select ) => { + const { getCurrentPostType } = select( editorStore ); + const { getPostType } = select( coreStore ); + const { isEditingTemplate, getEditedPostTemplate } = select( + editPostStore + ); + const _supportsTemplateMode = select( + editorStore + ).getEditorSettings().supportsTemplateMode; + const isViewable = + getPostType( getCurrentPostType() )?.viewable ?? false; + + return { + template: + supportsTemplateMode && + isViewable && + getEditedPostTemplate(), + isEditing: isEditingTemplate(), + supportsTemplateMode: _supportsTemplateMode, + }; + }, + [] + ); + const { __unstableSwitchToTemplateMode } = useDispatch( editPostStore ); - if ( ! isFSETheme || ! template ) { + if ( ! supportsTemplateMode ) { return null; } @@ -53,40 +63,95 @@ function PostTemplate() { { __( 'Template' ) } { ! isEditing && ( +
+
+ { !! template && template?.title?.raw } + { !! template && + ! template?.title?.raw && + template.slug } + { ! template && __( 'Default' ) } +
+
+ { !! template && ( + + ) } + +
+
+ ) } + { isEditing && ( - { createInterpolateElement( - sprintf( - /* translators: 1: Template name. */ - __( '%s (Edit)' ), - template.slug - ), - { - a: ( + { template?.slug } + + ) } + { isModalOpen && ( + { + setIsModalOpen( false ); + setTitle( '' ); + } } + overlayClassName="edit-post-post-template__modal" + > +
{ + event.preventDefault(); + const defaultTitle = __( 'Custom Template' ); + const templateContent = [ + createBlock( 'core/site-title' ), + createBlock( 'core/site-tagline' ), + createBlock( 'core/separator' ), + createBlock( 'core/post-title' ), + createBlock( 'core/post-content' ), + ]; + __unstableSwitchToTemplateMode( { + slug: + 'wp-custom-template-' + + kebabCase( title ?? defaultTitle ), + content: serialize( templateContent ), + title: title ?? defaultTitle, + } ); + setIsModalOpen( false ); + } } + > + + + - ), - } - ) } - - ) } - { isEditing && ( - - { template.slug } - + + + + + + +
) }
); diff --git a/packages/edit-post/src/components/sidebar/post-template/style.scss b/packages/edit-post/src/components/sidebar/post-template/style.scss index d625e897224368..ed36bf1ea4d941 100644 --- a/packages/edit-post/src/components/sidebar/post-template/style.scss +++ b/packages/edit-post/src/components/sidebar/post-template/style.scss @@ -1,6 +1,7 @@ .edit-post-post-template { width: 100%; justify-content: left; + align-items: baseline; span { display: block; @@ -11,3 +12,15 @@ .edit-post-post-template__value { padding-left: 6px; } + +.edit-post-post-template__modal-actions { + padding-top: $grid-unit-15; +} + +.edit-post-post-template__actions { + margin-top: $grid-unit-10; + + button:not(:last-child) { + margin-right: $grid-unit-10; + } +} diff --git a/packages/edit-post/src/editor.js b/packages/edit-post/src/editor.js index 3f0fa4d1105c7a..12aabd865e5dc4 100644 --- a/packages/edit-post/src/editor.js +++ b/packages/edit-post/src/editor.js @@ -56,14 +56,12 @@ function Editor( { getPreference, __experimentalGetPreviewDeviceType, isEditingTemplate, + getEditedPostTemplate, } = select( editPostStore ); - const { - getEntityRecord, - __experimentalGetTemplateForLink, - getPostType, - getEntityRecords, - } = select( 'core' ); - const { getEditorSettings, getCurrentPost } = select( 'core/editor' ); + const { getEntityRecord, getPostType, getEntityRecords } = select( + 'core' + ); + const { getEditorSettings } = select( 'core/editor' ); const { getBlockTypes } = select( blocksStore ); const isTemplate = [ 'wp_template', 'wp_template_part' ].includes( postType @@ -79,7 +77,7 @@ function Editor( { } else { postObject = getEntityRecord( 'postType', postType, postId ); } - const isFSETheme = getEditorSettings().isFSETheme; + const supportsTemplateMode = getEditorSettings().supportsTemplateMode; const isViewable = getPostType( postType )?.viewable ?? false; return { @@ -100,11 +98,8 @@ function Editor( { keepCaretInsideBlock: isFeatureActive( 'keepCaretInsideBlock' ), isTemplateMode: isEditingTemplate(), template: - isFSETheme && - isViewable && - postObject && - getCurrentPost().status !== 'auto-draft' - ? __experimentalGetTemplateForLink( postObject.link ) + supportsTemplateMode && isViewable + ? getEditedPostTemplate() : null, post: postObject, }; diff --git a/packages/edit-post/src/store/actions.js b/packages/edit-post/src/store/actions.js index 61d481143e095c..e8f4d1ab12d515 100644 --- a/packages/edit-post/src/store/actions.js +++ b/packages/edit-post/src/store/actions.js @@ -11,6 +11,8 @@ import { apiFetch } from '@wordpress/data-controls'; import { store as interfaceStore } from '@wordpress/interface'; import { controls, dispatch, select, subscribe } from '@wordpress/data'; import { speak } from '@wordpress/a11y'; +import { store as noticesStore } from '@wordpress/notices'; +import { store as coreStore } from '@wordpress/core-data'; /** * Internal dependencies @@ -436,3 +438,43 @@ export function setIsEditingTemplate( value ) { value, }; } + +/** + * Potentially create a block based template and switches to the template mode. + * + * @param {Object?} template template to create and assign before switching. + */ +export function* __unstableSwitchToTemplateMode( template ) { + if ( !! template ) { + const savedTemplate = yield controls.dispatch( + coreStore, + 'saveEntityRecord', + 'postType', + 'wp_template', + template + ); + const post = yield controls.select( 'core/editor', 'getCurrentPost' ); + + yield controls.dispatch( + coreStore, + 'editEntityRecord', + 'postType', + post.type, + post.id, + { + template: savedTemplate.slug, + } + ); + } + + yield setIsEditingTemplate( true ); + + const message = !! template + ? __( "Custom template created. You're in template mode now." ) + : __( + 'Editing template. Changes made here affect all posts and pages that use the template.' + ); + yield controls.dispatch( noticesStore, 'createSuccessNotice', message, { + type: 'snackbar', + } ); +} diff --git a/packages/edit-post/src/store/selectors.js b/packages/edit-post/src/store/selectors.js index 2fb6c95a8276de..940ad34517ac82 100644 --- a/packages/edit-post/src/store/selectors.js +++ b/packages/edit-post/src/store/selectors.js @@ -9,6 +9,8 @@ import { get, includes, some, flatten, values } from 'lodash'; */ import { createRegistrySelector } from '@wordpress/data'; import { store as interfaceStore } from '@wordpress/interface'; +import { store as coreStore } from '@wordpress/core-data'; +import { store as editorStore } from '@wordpress/editor'; /** * Returns the current editing mode. * @@ -335,3 +337,30 @@ export function isInserterOpened( state ) { export function isEditingTemplate( state ) { return state.isEditingTemplate; } + +/** + * Retrieves the template of the currently edited post. + * + * @return {Object?} Post Template. + */ +export const getEditedPostTemplate = createRegistrySelector( + ( select ) => () => { + const currentTemplate = select( editorStore ).getEditedPostAttribute( + 'template' + ); + if ( currentTemplate ) { + return select( coreStore ) + .getEntityRecords( 'postType', 'wp_template' ) + ?.find( ( template ) => template.slug === currentTemplate ); + } + + const post = select( editorStore ).getCurrentPost(); + if ( post.link && post.status !== 'auto-draft' ) { + return select( coreStore ).__experimentalGetTemplateForLink( + post.link + ); + } + + return null; + } +); From 2c0ba0758d48a530596f4977c272d3a35906b215 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Thu, 8 Apr 2021 13:33:09 +0200 Subject: [PATCH 050/125] WP_Theme_JSON: absorb editor settings transformation (#30610) --- lib/class-wp-theme-json-resolver.php | 1 - lib/class-wp-theme-json.php | 100 +++++++++ lib/global-styles.php | 105 +-------- ...ass-wp-theme-json-legacy-settings-test.php | 202 ------------------ phpunit/class-wp-theme-json-test.php | 177 +++++++++++++++ 5 files changed, 279 insertions(+), 306 deletions(-) delete mode 100644 phpunit/class-wp-theme-json-legacy-settings-test.php diff --git a/lib/class-wp-theme-json-resolver.php b/lib/class-wp-theme-json-resolver.php index 94944aaea54737..7ba5b5c4a82090 100644 --- a/lib/class-wp-theme-json-resolver.php +++ b/lib/class-wp-theme-json-resolver.php @@ -242,7 +242,6 @@ public static function get_core_data() { return self::$core; } - $all_blocks = WP_Theme_JSON::ALL_BLOCKS_NAME; $config = self::read_json_file( __DIR__ . '/experimental-default-theme.json' ); $config = self::translate( $config ); self::$core = new WP_Theme_JSON( $config ); diff --git a/lib/class-wp-theme-json.php b/lib/class-wp-theme-json.php index e422d58778da0f..147725d66a19b2 100644 --- a/lib/class-wp-theme-json.php +++ b/lib/class-wp-theme-json.php @@ -1138,4 +1138,104 @@ public function get_raw_data() { return $this->theme_json; } + /** + * + * Transforms the given editor settings according the + * add_theme_support format to the theme.json format. + * + * @param array $settings Existing editor settings. + * + * @return array Config that adheres to the theme.json schema. + */ + public static function get_from_editor_settings( $settings ) { + $theme_settings = array( 'settings' => array() ); + + // Deprecated theme supports. + if ( isset( $settings['disableCustomColors'] ) ) { + if ( ! isset( $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['color'] ) ) { + $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['color'] = array(); + } + $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['color']['custom'] = ! $settings['disableCustomColors']; + } + + if ( isset( $settings['disableCustomGradients'] ) ) { + if ( ! isset( $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['color'] ) ) { + $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['color'] = array(); + } + $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['color']['customGradient'] = ! $settings['disableCustomGradients']; + } + + if ( isset( $settings['disableCustomFontSizes'] ) ) { + if ( ! isset( $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['typography'] ) ) { + $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['typography'] = array(); + } + $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['typography']['customFontSize'] = ! $settings['disableCustomFontSizes']; + } + + if ( isset( $settings['enableCustomLineHeight'] ) ) { + if ( ! isset( $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['typography'] ) ) { + $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['typography'] = array(); + } + $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['typography']['customLineHeight'] = $settings['enableCustomLineHeight']; + } + + if ( isset( $settings['enableCustomUnits'] ) ) { + if ( ! isset( $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['spacing'] ) ) { + $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['spacing'] = array(); + } + $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['spacing']['units'] = ( true === $settings['enableCustomUnits'] ) ? + array( 'px', 'em', 'rem', 'vh', 'vw' ) : + $settings['enableCustomUnits']; + } + + if ( isset( $settings['colors'] ) ) { + if ( ! isset( $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['color'] ) ) { + $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['color'] = array(); + } + $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['color']['palette'] = $settings['colors']; + } + + if ( isset( $settings['gradients'] ) ) { + if ( ! isset( $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['color'] ) ) { + $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['color'] = array(); + } + $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['color']['gradients'] = $settings['gradients']; + } + + if ( isset( $settings['fontSizes'] ) ) { + $font_sizes = $settings['fontSizes']; + // Back-compatibility for presets without units. + foreach ( $font_sizes as $key => $font_size ) { + if ( is_numeric( $font_size['size'] ) ) { + $font_sizes[ $key ]['size'] = $font_size['size'] . 'px'; + } + } + if ( ! isset( $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['typography'] ) ) { + $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['typography'] = array(); + } + $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['typography']['fontSizes'] = $font_sizes; + } + + // This allows to make the plugin work with WordPress 5.7 beta + // as well as lower versions. The second check can be removed + // as soon as the minimum WordPress version for the plugin + // is bumped to 5.7. + if ( isset( $settings['enableCustomSpacing'] ) ) { + if ( ! isset( $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['spacing'] ) ) { + $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['spacing'] = array(); + } + $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['spacing']['customPadding'] = $settings['enableCustomSpacing']; + } + + // Things that didn't land in core yet, so didn't have a setting assigned. + if ( current( (array) get_theme_support( 'experimental-link-color' ) ) ) { + if ( ! isset( $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['color'] ) ) { + $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['color'] = array(); + } + $theme_settings['settings'][ self::ALL_BLOCKS_NAME ]['color']['link'] = true; + } + + return $theme_settings; + } + } diff --git a/lib/global-styles.php b/lib/global-styles.php index 2158fe96726f1c..4bef8e7b93751c 100644 --- a/lib/global-styles.php +++ b/lib/global-styles.php @@ -5,107 +5,6 @@ * @package gutenberg */ -/** - * Returns the theme presets registered via add_theme_support, if any. - * - * @param array $settings Existing editor settings. - * - * @return array Config that adheres to the theme.json schema. - */ -function gutenberg_experimental_global_styles_get_theme_support_settings( $settings ) { - $all_blocks = WP_Theme_JSON::ALL_BLOCKS_NAME; - $theme_settings = array(); - $theme_settings['settings'] = array(); - $theme_settings['settings'][ $all_blocks ] = array(); - - // Deprecated theme supports. - if ( isset( $settings['disableCustomColors'] ) ) { - if ( ! isset( $theme_settings['settings'][ $all_blocks ]['color'] ) ) { - $theme_settings['settings'][ $all_blocks ]['color'] = array(); - } - $theme_settings['settings'][ $all_blocks ]['color']['custom'] = ! $settings['disableCustomColors']; - } - - if ( isset( $settings['disableCustomGradients'] ) ) { - if ( ! isset( $theme_settings['settings'][ $all_blocks ]['color'] ) ) { - $theme_settings['settings'][ $all_blocks ]['color'] = array(); - } - $theme_settings['settings'][ $all_blocks ]['color']['customGradient'] = ! $settings['disableCustomGradients']; - } - - if ( isset( $settings['disableCustomFontSizes'] ) ) { - if ( ! isset( $theme_settings['settings'][ $all_blocks ]['typography'] ) ) { - $theme_settings['settings'][ $all_blocks ]['typography'] = array(); - } - $theme_settings['settings'][ $all_blocks ]['typography']['customFontSize'] = ! $settings['disableCustomFontSizes']; - } - - if ( isset( $settings['enableCustomLineHeight'] ) ) { - if ( ! isset( $theme_settings['settings'][ $all_blocks ]['typography'] ) ) { - $theme_settings['settings'][ $all_blocks ]['typography'] = array(); - } - $theme_settings['settings'][ $all_blocks ]['typography']['customLineHeight'] = $settings['enableCustomLineHeight']; - } - - if ( isset( $settings['enableCustomUnits'] ) ) { - if ( ! isset( $theme_settings['settings'][ $all_blocks ]['spacing'] ) ) { - $theme_settings['settings'][ $all_blocks ]['spacing'] = array(); - } - $theme_settings['settings'][ $all_blocks ]['spacing']['units'] = ( true === $settings['enableCustomUnits'] ) ? - array( 'px', 'em', 'rem', 'vh', 'vw' ) : - $settings['enableCustomUnits']; - } - - if ( isset( $settings['colors'] ) ) { - if ( ! isset( $theme_settings['settings'][ $all_blocks ]['color'] ) ) { - $theme_settings['settings'][ $all_blocks ]['color'] = array(); - } - $theme_settings['settings'][ $all_blocks ]['color']['palette'] = $settings['colors']; - } - - if ( isset( $settings['gradients'] ) ) { - if ( ! isset( $theme_settings['settings'][ $all_blocks ]['color'] ) ) { - $theme_settings['settings'][ $all_blocks ]['color'] = array(); - } - $theme_settings['settings'][ $all_blocks ]['color']['gradients'] = $settings['gradients']; - } - - if ( isset( $settings['fontSizes'] ) ) { - $font_sizes = $settings['fontSizes']; - // Back-compatibility for presets without units. - foreach ( $font_sizes as $key => $font_size ) { - if ( is_numeric( $font_size['size'] ) ) { - $font_sizes[ $key ]['size'] = $font_size['size'] . 'px'; - } - } - if ( ! isset( $theme_settings['settings'][ $all_blocks ]['typography'] ) ) { - $theme_settings['settings'][ $all_blocks ]['typography'] = array(); - } - $theme_settings['settings'][ $all_blocks ]['typography']['fontSizes'] = $font_sizes; - } - - // This allows to make the plugin work with WordPress 5.7 beta - // as well as lower versions. The second check can be removed - // as soon as the minimum WordPress version for the plugin - // is bumped to 5.7. - if ( isset( $settings['enableCustomSpacing'] ) ) { - if ( ! isset( $theme_settings['settings'][ $all_blocks ]['spacing'] ) ) { - $theme_settings['settings'][ $all_blocks ]['spacing'] = array(); - } - $theme_settings['settings'][ $all_blocks ]['spacing']['customPadding'] = $settings['enableCustomSpacing']; - } - - // Things that didn't land in core yet, so didn't have a setting assigned. - if ( current( (array) get_theme_support( 'experimental-link-color' ) ) ) { - if ( ! isset( $theme_settings['settings'][ $all_blocks ]['color'] ) ) { - $theme_settings['settings'][ $all_blocks ]['color'] = array(); - } - $theme_settings['settings'][ $all_blocks ]['color']['link'] = true; - } - - return $theme_settings; -} - /** * Takes a tree adhering to the theme.json schema and generates * the corresponding stylesheet. @@ -165,7 +64,7 @@ function gutenberg_experimental_global_styles_enqueue_assets() { } $settings = gutenberg_get_common_block_editor_settings(); - $theme_support_data = gutenberg_experimental_global_styles_get_theme_support_settings( $settings ); + $theme_support_data = WP_Theme_JSON::get_from_editor_settings( $settings ); $all = WP_Theme_JSON_Resolver::get_merged_data( $theme_support_data ); @@ -186,7 +85,7 @@ function gutenberg_experimental_global_styles_enqueue_assets() { * @return array New block editor settings */ function gutenberg_experimental_global_styles_settings( $settings ) { - $theme_support_data = gutenberg_experimental_global_styles_get_theme_support_settings( $settings ); + $theme_support_data = WP_Theme_JSON::get_from_editor_settings( $settings ); unset( $settings['colors'] ); unset( $settings['disableCustomColors'] ); unset( $settings['disableCustomFontSizes'] ); diff --git a/phpunit/class-wp-theme-json-legacy-settings-test.php b/phpunit/class-wp-theme-json-legacy-settings-test.php deleted file mode 100644 index 3849c41ef4d188..00000000000000 --- a/phpunit/class-wp-theme-json-legacy-settings-test.php +++ /dev/null @@ -1,202 +0,0 @@ - false, - 'disableCustomColors' => false, - 'disableCustomFontSizes' => false, - 'disableCustomGradients' => false, - 'enableCustomLineHeight' => false, - 'enableCustomUnits' => false, - 'imageSizes' => array( - array( - 'slug' => 'thumbnail', - 'name' => 'Thumbnail', - ), - array( - 'slug' => 'medium', - 'name' => 'Medium', - ), - array( - 'slug' => 'large', - 'name' => 'Large', - ), - array( - 'slug' => 'full', - 'name' => 'Full Size', - ), - ), - 'isRTL' => false, - 'maxUploadFileSize' => 123, - ); - } - - function test_legacy_settings_blank() { - $all_blocks = WP_Theme_JSON::ALL_BLOCKS_NAME; - $input = array(); - $expected = array( - 'settings' => array( - $all_blocks => array(), - ), - ); - - $actual = gutenberg_experimental_global_styles_get_theme_support_settings( $input ); - - $this->assertEqualSetsWithIndex( $expected, $actual ); - } - - function test_legacy_settings_no_theme_support() { - $all_blocks = WP_Theme_JSON::ALL_BLOCKS_NAME; - $input = $this->get_editor_settings_no_theme_support(); - $expected = array( - 'settings' => array( - $all_blocks => array( - 'color' => array( - 'custom' => true, - 'customGradient' => true, - ), - 'spacing' => array( - 'units' => false, - ), - 'typography' => array( - 'customFontSize' => true, - 'customLineHeight' => false, - ), - ), - ), - ); - - $actual = gutenberg_experimental_global_styles_get_theme_support_settings( $input ); - - $this->assertEqualSetsWithIndex( $expected, $actual ); - } - - function test_legacy_settings_custom_units_can_be_disabled() { - $all_blocks = WP_Theme_JSON::ALL_BLOCKS_NAME; - add_theme_support( 'custom-units', array() ); - $input = gutenberg_get_common_block_editor_settings(); - - $expected = array( - 'units' => array( array() ), - 'customPadding' => false, - ); - - $actual = gutenberg_experimental_global_styles_get_theme_support_settings( $input ); - - $this->assertEqualSetsWithIndex( $expected, $actual['settings'][ $all_blocks ]['spacing'] ); - } - - function test_legacy_settings_custom_units_can_be_enabled() { - $all_blocks = WP_Theme_JSON::ALL_BLOCKS_NAME; - add_theme_support( 'custom-units' ); - $input = gutenberg_get_common_block_editor_settings(); - - $expected = array( - 'units' => array( 'px', 'em', 'rem', 'vh', 'vw' ), - 'customPadding' => false, - ); - - $actual = gutenberg_experimental_global_styles_get_theme_support_settings( $input ); - - $this->assertEqualSetsWithIndex( $expected, $actual['settings'][ $all_blocks ]['spacing'] ); - } - - function test_legacy_settings_custom_units_can_be_filtered() { - $all_blocks = WP_Theme_JSON::ALL_BLOCKS_NAME; - add_theme_support( 'custom-units', 'rem', 'em' ); - $input = gutenberg_get_common_block_editor_settings(); - - $expected = array( - 'units' => array( 'rem', 'em' ), - 'customPadding' => false, - ); - - $actual = gutenberg_experimental_global_styles_get_theme_support_settings( $input ); - - $this->assertEqualSetsWithIndex( $expected, $actual['settings'][ $all_blocks ]['spacing'] ); - } - - function test_legacy_settings_filled() { - $all_blocks = WP_Theme_JSON::ALL_BLOCKS_NAME; - $input = array( - 'disableCustomColors' => true, - 'disableCustomGradients' => true, - 'disableCustomFontSizes' => true, - 'enableCustomLineHeight' => true, - 'enableCustomUnits' => true, - 'colors' => array( - array( - 'slug' => 'color-slug', - 'name' => 'Color Name', - 'color' => 'colorvalue', - ), - ), - 'gradients' => array( - array( - 'slug' => 'gradient-slug', - 'name' => 'Gradient Name', - 'gradient' => 'gradientvalue', - ), - ), - 'fontSizes' => array( - array( - 'slug' => 'size-slug', - 'name' => 'Size Name', - 'size' => 'sizevalue', - ), - ), - ); - - $expected = array( - 'settings' => array( - $all_blocks => array( - 'color' => array( - 'custom' => false, - 'customGradient' => false, - 'gradients' => array( - array( - 'slug' => 'gradient-slug', - 'name' => 'Gradient Name', - 'gradient' => 'gradientvalue', - ), - ), - 'palette' => array( - array( - 'slug' => 'color-slug', - 'name' => 'Color Name', - 'color' => 'colorvalue', - ), - ), - ), - 'spacing' => array( - 'units' => array( 'px', 'em', 'rem', 'vh', 'vw' ), - ), - 'typography' => array( - 'customFontSize' => false, - 'customLineHeight' => true, - 'fontSizes' => array( - array( - 'slug' => 'size-slug', - 'name' => 'Size Name', - 'size' => 'sizevalue', - ), - ), - ), - ), - ), - ); - - $actual = gutenberg_experimental_global_styles_get_theme_support_settings( $input ); - - $this->assertEqualSetsWithIndex( $expected, $actual ); - } -} diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php index baedc89d747632..8721bbeafc956d 100644 --- a/phpunit/class-wp-theme-json-test.php +++ b/phpunit/class-wp-theme-json-test.php @@ -822,4 +822,181 @@ function test_get_template_parts() { ) ); } + + function test_get_from_editor_settings() { + $input = array( + 'disableCustomColors' => true, + 'disableCustomGradients' => true, + 'disableCustomFontSizes' => true, + 'enableCustomLineHeight' => true, + 'enableCustomUnits' => true, + 'colors' => array( + array( + 'slug' => 'color-slug', + 'name' => 'Color Name', + 'color' => 'colorvalue', + ), + ), + 'gradients' => array( + array( + 'slug' => 'gradient-slug', + 'name' => 'Gradient Name', + 'gradient' => 'gradientvalue', + ), + ), + 'fontSizes' => array( + array( + 'slug' => 'size-slug', + 'name' => 'Size Name', + 'size' => 'sizevalue', + ), + ), + ); + + $expected = array( + 'settings' => array( + 'defaults' => array( + 'color' => array( + 'custom' => false, + 'customGradient' => false, + 'gradients' => array( + array( + 'slug' => 'gradient-slug', + 'name' => 'Gradient Name', + 'gradient' => 'gradientvalue', + ), + ), + 'palette' => array( + array( + 'slug' => 'color-slug', + 'name' => 'Color Name', + 'color' => 'colorvalue', + ), + ), + ), + 'spacing' => array( + 'units' => array( 'px', 'em', 'rem', 'vh', 'vw' ), + ), + 'typography' => array( + 'customFontSize' => false, + 'customLineHeight' => true, + 'fontSizes' => array( + array( + 'slug' => 'size-slug', + 'name' => 'Size Name', + 'size' => 'sizevalue', + ), + ), + ), + ), + ), + ); + + $actual = WP_Theme_JSON::get_from_editor_settings( $input ); + + $this->assertEqualSetsWithIndex( $expected, $actual ); + } + + function test_get_editor_settings_no_theme_support() { + $input = array( + '__unstableEnableFullSiteEditingBlocks' => false, + 'disableCustomColors' => false, + 'disableCustomFontSizes' => false, + 'disableCustomGradients' => false, + 'enableCustomLineHeight' => false, + 'enableCustomUnits' => false, + 'imageSizes' => array( + array( + 'slug' => 'thumbnail', + 'name' => 'Thumbnail', + ), + array( + 'slug' => 'medium', + 'name' => 'Medium', + ), + array( + 'slug' => 'large', + 'name' => 'Large', + ), + array( + 'slug' => 'full', + 'name' => 'Full Size', + ), + ), + 'isRTL' => false, + 'maxUploadFileSize' => 123, + ); + + $expected = array( + 'settings' => array( + 'defaults' => array( + 'color' => array( + 'custom' => true, + 'customGradient' => true, + ), + 'spacing' => array( + 'units' => false, + ), + 'typography' => array( + 'customFontSize' => true, + 'customLineHeight' => false, + ), + ), + ), + ); + + $actual = WP_Theme_JSON::get_from_editor_settings( $input ); + + $this->assertEqualSetsWithIndex( $expected, $actual ); + } + + function test_get_editor_settings_blank() { + $expected = array( 'settings' => array() ); + $actual = WP_Theme_JSON::get_from_editor_settings( array() ); + + $this->assertEqualSetsWithIndex( $expected, $actual ); + } + + function test_get_editor_settings_custom_units_can_be_disabled() { + add_theme_support( 'custom-units', array() ); + $input = gutenberg_get_common_block_editor_settings(); + + $expected = array( + 'units' => array( array() ), + 'customPadding' => false, + ); + + $actual = WP_Theme_JSON::get_from_editor_settings( $input ); + + $this->assertEqualSetsWithIndex( $expected, $actual['settings']['defaults']['spacing'] ); + } + + function test_get_editor_settings_custom_units_can_be_enabled() { + add_theme_support( 'custom-units' ); + $input = gutenberg_get_common_block_editor_settings(); + + $expected = array( + 'units' => array( 'px', 'em', 'rem', 'vh', 'vw' ), + 'customPadding' => false, + ); + + $actual = WP_Theme_JSON::get_from_editor_settings( $input ); + + $this->assertEqualSetsWithIndex( $expected, $actual['settings']['defaults']['spacing'] ); + } + + function test_get_editor_settings_custom_units_can_be_filtered() { + add_theme_support( 'custom-units', 'rem', 'em' ); + $input = gutenberg_get_common_block_editor_settings(); + + $expected = array( + 'units' => array( 'rem', 'em' ), + 'customPadding' => false, + ); + + $actual = WP_Theme_JSON::get_from_editor_settings( $input ); + + $this->assertEqualSetsWithIndex( $expected, $actual['settings']['defaults']['spacing'] ); + } + } From 00aeffc3490f1eea69d40da6d5dd16a79a61d3ac Mon Sep 17 00:00:00 2001 From: Ari Stathopoulos Date: Thu, 8 Apr 2021 14:43:41 +0300 Subject: [PATCH 051/125] Themes: Fix template-hierarchy fallbacks (#30599) * fixes #30565 * don't use "we" in inline comments --- lib/full-site-editing/template-loader.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/full-site-editing/template-loader.php b/lib/full-site-editing/template-loader.php index c02ebf78b96a19..6f96427812aa60 100644 --- a/lib/full-site-editing/template-loader.php +++ b/lib/full-site-editing/template-loader.php @@ -71,6 +71,11 @@ function gutenberg_override_query_template( $template, $type, array $templates = foreach ( $templates as $template_item ) { $template_item_slug = gutenberg_strip_php_suffix( $template_item ); + // Break the loop if the block-template matches the template slug. + if ( $current_block_template_slug === $template_item_slug ) { + break; + } + // Is this a custom template? // This check should be removed when merged in core. // Instead, wp_templates should be considered valid in locate_template. From 444b0ae57c297a55d9e0960977baaedc577e20aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Wrede?= Date: Thu, 8 Apr 2021 14:54:15 +0200 Subject: [PATCH 052/125] Improve get_merged_data() (#30612) --- lib/class-wp-theme-json-resolver.php | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/class-wp-theme-json-resolver.php b/lib/class-wp-theme-json-resolver.php index 7ba5b5c4a82090..31ecb553a2ccd0 100644 --- a/lib/class-wp-theme-json-resolver.php +++ b/lib/class-wp-theme-json-resolver.php @@ -394,17 +394,14 @@ public static function get_user_data() { * @return WP_Theme_JSON */ public static function get_merged_data( $theme_support_data = array(), $origin = 'user' ) { - if ( 'theme' === $origin ) { - $result = new WP_Theme_JSON(); - $result->merge( self::get_core_data() ); - $result->merge( self::get_theme_data( $theme_support_data ) ); - return $result; - } - $result = new WP_Theme_JSON(); $result->merge( self::get_core_data() ); $result->merge( self::get_theme_data( $theme_support_data ) ); - $result->merge( self::get_user_data() ); + + if ( 'user' === $origin ) { + $result->merge( self::get_user_data() ); + } + return $result; } From b5ec4ae4f5463352b41b3b466e62ed3b59ff8190 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dami=C3=A1n=20Su=C3=A1rez?= Date: Thu, 8 Apr 2021 11:03:23 -0300 Subject: [PATCH 053/125] Post Schedule: show post events (#29716) * post-schedule: collect and pass calendar events * post-schedule: re-write component using function * date-time: remove onMonthPreviewed() and highlight * post-schedule: update current month * date-time: render day events using own component * date-time: styling when not selected day * fixing eslint issues * date-time: tweak calendar events style * post-schedule: exlude current post from evenys * date-time: decouple onMonthChange with keepFocusInside * date-time: check events before to pick events day * fix rebasing issues * date-time: events replace circles by dots * fix rebasing bug * post-schedule: split up processing post events * date-time: revert prop name change * date-time: add screen reader support * date-time: update content for screen reader * date-time: fix eslint error * post-schedule: get events by post type * date-time: rephrase events number for readers * date-time: add events to aria label * date-time: fix lint error. tidy. * date-time: set aria-label value * date-time: update e2e test * date-time: clean comment * date-time: join day-with-events string to improve its translation * date-time: remove ref as hook dependency The ref nevers changes its value * post-scheudle: use title.rendered prop for events --- packages/components/src/date-time/date.js | 93 +++++++++++++++---- packages/components/src/date-time/index.js | 5 +- packages/components/src/date-time/style.scss | 25 +++++ .../editor/various/post-visibility.test.js | 2 +- .../src/components/post-schedule/index.js | 81 ++++++++++++---- 5 files changed, 166 insertions(+), 40 deletions(-) diff --git a/packages/components/src/date-time/date.js b/packages/components/src/date-time/date.js index 9f6ff3b2691803..66c54275ea8a8e 100644 --- a/packages/components/src/date-time/date.js +++ b/packages/components/src/date-time/date.js @@ -2,6 +2,8 @@ * External dependencies */ import moment from 'moment'; +import classnames from 'classnames'; + // react-dates doesn't tree-shake correctly, so we import from the individual // component here, to avoid including too much of the library import DayPickerSingleDateController from 'react-dates/lib/components/DayPickerSingleDateController'; @@ -9,13 +11,64 @@ import DayPickerSingleDateController from 'react-dates/lib/components/DayPickerS /** * WordPress dependencies */ -import { Component, createRef } from '@wordpress/element'; -import { isRTL } from '@wordpress/i18n'; +import { Component, createRef, useEffect, useRef } from '@wordpress/element'; +import { isRTL, _n, sprintf } from '@wordpress/i18n'; /** * Module Constants */ const TIMEZONELESS_FORMAT = 'YYYY-MM-DDTHH:mm:ss'; +const ARIAL_LABEL_TIME_FORMAT = 'dddd, LL'; + +function DatePickerDay( { day, events = [] } ) { + const ref = useRef(); + + /* + * a11y hack to make the `There is/are n events` string + * available speaking for readers, + * re-defining the aria-label attribute. + * This attribute is handled by the react-dates component. + */ + useEffect( () => { + // Bail when no parent node. + if ( ! ref?.current?.parentNode ) { + return; + } + + const { parentNode } = ref.current; + const dayAriaLabel = moment( day ).format( ARIAL_LABEL_TIME_FORMAT ); + + if ( ! events.length ) { + // Set aria-label without event description. + parentNode.setAttribute( 'aria-label', dayAriaLabel ); + return; + } + + const dayWithEventsDescription = sprintf( + // translators: 1: Calendar day format, 2: Calendar event number. + _n( + '%1$s. There is %2$d event.', + '%1$s. There are %2$d events.', + events.length + ), + dayAriaLabel, + events.length + ); + + parentNode.setAttribute( 'aria-label', dayWithEventsDescription ); + }, [ events.length ] ); + + return ( +
+ { day.format( 'D' ) } +
+ ); +} class DatePicker extends Component { constructor() { @@ -23,8 +76,14 @@ class DatePicker extends Component { this.onChangeMoment = this.onChangeMoment.bind( this ); this.nodeRef = createRef(); - this.keepFocusInside = this.keepFocusInside.bind( this ); - this.isDayHighlighted = this.isDayHighlighted.bind( this ); + this.onMonthPreviewedHandler = this.onMonthPreviewedHandler.bind( + this + ); + } + + onMonthPreviewedHandler( newMonthDate ) { + this.props?.onMonthPreviewed( newMonthDate.toISOString() ); + this.keepFocusInside(); } /* @@ -89,19 +148,13 @@ class DatePicker extends Component { return currentDate ? moment( currentDate ) : moment(); } - // todo change reference to `isDayHighlighted` every time, `events` prop change - isDayHighlighted( date ) { - // Do not highlight when no events. + getEventsPerDay( day ) { if ( ! this.props.events?.length ) { - return false; - } - if ( this.props.onMonthPreviewed ) { - this.props.onMonthPreviewed( date.toDate() ); + return []; } - // Compare date against highlighted events. - return this.props.events.some( ( highlighted ) => - date.isSame( highlighted.date, 'day' ) + return this.props.events.filter( ( eventDay ) => + day.isSame( eventDay.date, 'day' ) ); } @@ -126,13 +179,19 @@ class DatePicker extends Component { onDateChange={ this.onChangeMoment } transitionDuration={ 0 } weekDayFormat="ddd" + dayAriaLabelFormat={ ARIAL_LABEL_TIME_FORMAT } isRTL={ isRTL() } isOutsideRange={ ( date ) => { return isInvalidDate && isInvalidDate( date.toDate() ); } } - isDayHighlighted={ this.isDayHighlighted } - onPrevMonthClick={ this.keepFocusInside } - onNextMonthClick={ this.keepFocusInside } + onPrevMonthClick={ this.onMonthPreviewedHandler } + onNextMonthClick={ this.onMonthPreviewedHandler } + renderDayContents={ ( day ) => ( + + ) } />
); diff --git a/packages/components/src/date-time/index.js b/packages/components/src/date-time/index.js index fecc9e302f29e1..f433011786379f 100644 --- a/packages/components/src/date-time/index.js +++ b/packages/components/src/date-time/index.js @@ -4,6 +4,7 @@ // Needed to initialise the default datepicker styles. // See: https://github.com/airbnb/react-dates#initialize import 'react-dates/initialize'; +import { noop } from 'lodash'; /** * WordPress dependencies @@ -25,7 +26,7 @@ function DateTimePicker( currentDate, is12Hour, isInvalidDate, - onMonthPreviewed, + onMonthPreviewed = noop, onChange, events, }, @@ -52,8 +53,8 @@ function DateTimePicker( currentDate={ currentDate } onChange={ onChange } isInvalidDate={ isInvalidDate } - onMonthPreviewed={ onMonthPreviewed } events={ events } + onMonthPreviewed={ onMonthPreviewed } /> ) } diff --git a/packages/components/src/date-time/style.scss b/packages/components/src/date-time/style.scss index 7c56708e1fd32b..43f95756c8d706 100644 --- a/packages/components/src/date-time/style.scss +++ b/packages/components/src/date-time/style.scss @@ -111,6 +111,31 @@ } } +.components-datetime__date .CalendarDay .components-datetime__date__day { + height: 100%; + display: flex; + justify-content: center; + align-content: center; + flex-direction: column; + position: relative; + + &.has-events::before { + content: " "; + width: 4px; + height: 4px; + border-radius: 2px; + position: absolute; + left: 50%; + margin-left: -2px; + bottom: 0; + background-color: $white; + } +} + +.components-datetime__date .CalendarDay:not(.CalendarDay__selected) .components-datetime__date__day.has-events::before { + background: var(--wp-admin-theme-color); +} + .components-datetime__time { padding-bottom: $grid-unit-20; diff --git a/packages/e2e-tests/specs/editor/various/post-visibility.test.js b/packages/e2e-tests/specs/editor/various/post-visibility.test.js index 6844b9bd97345b..c395ea87952364 100644 --- a/packages/e2e-tests/specs/editor/various/post-visibility.test.js +++ b/packages/e2e-tests/specs/editor/various/post-visibility.test.js @@ -51,7 +51,7 @@ describe( 'Post visibility', () => { ); await ( await page.$x( - '//td[contains(concat(" ", @class, " "), " CalendarDay ")][text() = "15"]' + '//td[contains(concat(" ", @class, " "), " CalendarDay ")]/div[contains(concat(" ", @class, " "), " components-datetime__date__day ")][text() = "15"]' ) )[ 0 ].click(); diff --git a/packages/editor/src/components/post-schedule/index.js b/packages/editor/src/components/post-schedule/index.js index 06266f1bd68d9f..89526384b2ba1d 100644 --- a/packages/editor/src/components/post-schedule/index.js +++ b/packages/editor/src/components/post-schedule/index.js @@ -2,14 +2,68 @@ * WordPress dependencies */ import { __experimentalGetSettings } from '@wordpress/date'; -import { withSelect, withDispatch } from '@wordpress/data'; -import { compose } from '@wordpress/compose'; +import { useDispatch, useSelect } from '@wordpress/data'; import { DateTimePicker } from '@wordpress/components'; -import { useRef } from '@wordpress/element'; +import { useRef, useState, useMemo } from '@wordpress/element'; +import { store as coreStore } from '@wordpress/core-data'; + +/** + * Internal dependencies + */ +import { store as editorStore } from '../../store'; + +function getDayOfTheMonth( date = new Date(), firstDay = true ) { + const d = new Date( date ); + return new Date( + d.getFullYear(), + d.getMonth() + ( firstDay ? 0 : 1 ), + firstDay ? 1 : 0 + ).toISOString(); +} + +export default function PostSchedule() { + const { postDate, postType } = useSelect( + ( select ) => ( { + postDate: select( editorStore ).getEditedPostAttribute( 'date' ), + postType: select( editorStore ).getCurrentPostType(), + } ), + [] + ); + + const { editPost } = useDispatch( editorStore ); + const onUpdateDate = ( date ) => editPost( { date } ); + + const [ previewedMonth, setPreviewedMonth ] = useState( + getDayOfTheMonth( postDate ) + ); + + // Pick up published and schduled site posts. + const eventsByPostType = useSelect( + ( select ) => + select( coreStore ).getEntityRecords( 'postType', postType, { + status: 'publish,future', + after: getDayOfTheMonth( previewedMonth ), + before: getDayOfTheMonth( previewedMonth, false ), + exclude: [ select( editorStore ).getCurrentPostId() ], + } ), + [ previewedMonth, postType ] + ); + + const events = useMemo( + () => + ( eventsByPostType || [] ).map( + ( { title, type, date: eventDate } ) => ( { + title: title?.rendered, + type, + date: new Date( eventDate ), + } ) + ), + [ eventsByPostType ] + ); -export function PostSchedule( { date, onUpdateDate } ) { const ref = useRef(); const settings = __experimentalGetSettings(); + // To know if the current timezone is a 12 hour time with look for "a" in the time format // We also make sure this a is not escaped by a "/" const is12HourTime = /a(?!\\)/i.test( @@ -30,24 +84,11 @@ export function PostSchedule( { date, onUpdateDate } ) { return ( ); } - -export default compose( [ - withSelect( ( select ) => { - return { - date: select( 'core/editor' ).getEditedPostAttribute( 'date' ), - }; - } ), - withDispatch( ( dispatch ) => { - return { - onUpdateDate( date ) { - dispatch( 'core/editor' ).editPost( { date } ); - }, - }; - } ), -] )( PostSchedule ); From ba4408396e0d3774564461bb7929b88c83371641 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 8 Apr 2021 16:06:06 +0200 Subject: [PATCH 054/125] Plugin Build Workflow: Pull trunk before pushing (#30615) The build workflow recently [failed to push the cherry-picked version bump commit to `trunk`](https://github.com/WordPress/gutenberg/runs/2288075442?check_suite_focus=true). Our best guess is that this happened because a [PR was merged](https://github.com/WordPress/gutenberg/pull/30539#event-4562689224) (on Apr 7 at 13:58 UTC) after the workflow [was started](https://github.com/WordPress/gutenberg/actions/runs/726230952) (on Apr 7, also at 13:58 UTC), so the workflow's checked out copy of `trunk` didn't match the remote. The remedy should be to pull `trunk` right before cherry-picking and pushing. --- .github/workflows/build-plugin-zip.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-plugin-zip.yml b/.github/workflows/build-plugin-zip.yml index 19cf5ca106a040..e2707e81f5d7cb 100644 --- a/.github/workflows/build-plugin-zip.yml +++ b/.github/workflows/build-plugin-zip.yml @@ -92,6 +92,7 @@ jobs: - name: Cherry-pick to trunk run: | git checkout trunk + git pull TRUNK_VERSION=$(jq --raw-output '.version' package.json) if [[ ${{ steps.get_version.outputs.old_version }} == "$TRUNK_VERSION" ]]; then git cherry-pick "${{ steps.get_version.outputs.release_branch }}" @@ -112,7 +113,7 @@ jobs: - name: Use Node.js 14.x uses: actions/setup-node@46071b5c7a2e0c34e49c3cb8a0e792e86e18d5ea # v2.1.5 with: - node-version: 14.x + node-version: 14.x - name: Cache node modules uses: actions/cache@26968a09c0ea4f3e233fdddbafd1166051a095f6 # v2.1.4 From c71a99778274b049e055678c88fb28584622decd Mon Sep 17 00:00:00 2001 From: Matt Chowning Date: Thu, 8 Apr 2021 10:18:04 -0400 Subject: [PATCH 055/125] Interim dual license license of future contributions (#30383) * Interim dual-license for future contributions * Fill in dates in interim license * Update PR template * Cleanup MPL and GPL references in license * Clarify PR comment that new contributions are dual-licensed * Minor cleanup * Move incorporates other work language under project license section * Update initial copyright year to match first contribution to Gutenberg repo * Clarify project license is unchaged * Remove duplicative "(or later)" clause * Fix link in license --- .github/PULL_REQUEST_TEMPLATE.md | 2 + LICENSE.md | 428 ++++++++++++++++++++++++++++++- 2 files changed, 417 insertions(+), 13 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 75b32fa346231d..45bad9c0612a1a 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,5 +1,7 @@ + + ## Description diff --git a/LICENSE.md b/LICENSE.md index a6523290d51581..12a2176511cbe2 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,20 +1,24 @@ -### WordPress - Web publishing software +## Gutenberg - Copyright 2011-2021 by the contributors + Copyright 2016-2021 by the contributors -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. +**License for Contributions (on and after April 15, 2021)** -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +All code contributed to the Gutenberg project is dual-licensed, +and released under both of the following licenses: -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +the GNU General Public License as published by the Free Software Foundation; +either version 2 of the License or (at your option) any later version (the “GPL”) +and the Mozilla Public License, Version 2.0 (the “MPL”). + +**Project License** + +The Gutenberg project license is not affected by the License for Contributions (as +discussed in the [Dual License section](#dual-license) below). The Gutenberg project +continues to be free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2 of the License or (at your option) any +later version (the “GPL”). This program incorporates work covered by the following copyright and permission notices: @@ -35,8 +39,50 @@ and WordPress is released under the GPL + +### Dual License + +**We are currently in the process of changing Gutenberg’s software license from +GPL to a dual license: GPL and MPL.** + +**This process involves two independent steps (1) obtaining permission for dual +licensing from contributors of already contributed Gutenberg code and (2) +dual licensing of all contributions to Gutenberg that are made on or after +April 15, 2021.** + +**For part (1): We’re reaching out to everyone who has contributed code, prior +to April 15, 2021, and asking that they agree to dual license their +contribution to the project. We expect this process to be completed by +mid-year, 2021.** + +**For part (2): We have changed the license for contributed code to this +repository to make clear that all contributions on or after April 15, 2021 +will be made under the dual-license.** + +**When we have received all necessary rights and permissions to dual license +the pre-April 15, 2021 code of the Gutenberg project (Part 1 above), you will +have the option to use and distribute all of the Gutenberg project under +either the GPL or MPL license. At this time we will change the “Project +License” to the following:** + + The Gutenberg project is free software; you can redistribute it and/or modify + it under the terms of either of the following licenses: + + 1. the GNU General Public License as published by the Free Software Foundation; + either version 2 of the License or (at your option) any later version (the + “GPL”) OR + + 2. the Mozilla Public License Version 2.0 (the “MPL”). + --- +## Full Text of Referenced Licenses + +1. [GNU General Public License, Version 2](#gnu-general-public-license-version-2) +2. [Mozilla Public License, Version 2.0](#mozilla-public-license-version-20) + +## GNU General Public License, Version 2 + ### GNU GENERAL PUBLIC LICENSE Version 2, June 1991 @@ -398,3 +444,359 @@ applications with the library. If this is what you want to do, use the [GNU Lesser General Public License](http://www.gnu.org/licenses/lgpl.html) instead of this License. + +--- +## Mozilla Public License, Version 2.0 + +### 1. Definitions + +**1.1. “Contributor”** + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +**1.2. “Contributor Version”** + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +**1.3. “Contribution”** + means Covered Software of a particular Contributor. + +**1.4. “Covered Software”** + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +**1.5. “Incompatible With Secondary Licenses”** + means + +* **(a)** that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or +* **(b)** that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +**1.6. “Executable Form”** + means any form of the work other than Source Code Form. + +**1.7. “Larger Work”** + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +**1.8. “License”** + means this document. + +**1.9. “Licensable”** + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +**1.10. “Modifications”** + means any of the following: + +* **(a)** any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or +* **(b)** any new file in Source Code Form that contains any Covered + Software. + +**1.11. “Patent Claims” of a Contributor** + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +**1.12. “Secondary License”** + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +**1.13. “Source Code Form”** + means the form of the work preferred for making modifications. + +**1.14. “You” (or “Your”)** + means an individual or a legal entity exercising rights under this + License. For legal entities, “You” includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, “control” means **(a)** the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or **(b)** ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + + +### 2. License Grants and Conditions + +#### 2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +* **(a)** under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and +* **(b)** under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +#### 2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +#### 2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +* **(a)** for any code that a Contributor has removed from Covered Software; + or +* **(b)** for infringements caused by: **(i)** Your and any other third party's + modifications of Covered Software, or **(ii)** the combination of its + Contributions with other software (except as part of its Contributor + Version); or +* **(c)** under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +#### 2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +#### 2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +#### 2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +#### 2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + + +### 3. Responsibilities + +#### 3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +#### 3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +* **(a)** such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +* **(b)** You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +#### 3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +#### 3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +#### 3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + + +### 4. Inability to Comply Due to Statute or Regulation + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: **(a)** comply with +the terms of this License to the maximum extent possible; and **(b)** +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + + +### 5. Termination + +**5.1.** The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated **(a)** provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and **(b)** on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +**5.2.** If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +**5.3.** In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + + +### 6. Disclaimer of Warranty + +> Covered Software is provided under this License on an “as is” +> basis, without warranty of any kind, either expressed, implied, or +> statutory, including, without limitation, warranties that the +> Covered Software is free of defects, merchantable, fit for a +> particular purpose or non-infringing. The entire risk as to the +> quality and performance of the Covered Software is with You. +> Should any Covered Software prove defective in any respect, You +> (not any Contributor) assume the cost of any necessary servicing, +> repair, or correction. This disclaimer of warranty constitutes an +> essential part of this License. No use of any Covered Software is +> authorized under this License except under this disclaimer. + +### 7. Limitation of Liability + +> Under no circumstances and under no legal theory, whether tort +> (including negligence), contract, or otherwise, shall any +> Contributor, or anyone who distributes Covered Software as +> permitted above, be liable to You for any direct, indirect, +> special, incidental, or consequential damages of any character +> including, without limitation, damages for lost profits, loss of +> goodwill, work stoppage, computer failure or malfunction, or any +> and all other commercial damages or losses, even if such party +> shall have been informed of the possibility of such damages. This +> limitation of liability shall not apply to liability for death or +> personal injury resulting from such party's negligence to the +> extent applicable law prohibits such limitation. Some +> jurisdictions do not allow the exclusion or limitation of +> incidental or consequential damages, so this exclusion and +> limitation may not apply to You. + + +### 8. Litigation + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + + +### 9. Miscellaneous + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + + +### 10. Versions of the License + +#### 10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +#### 10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +#### 10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +#### 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +## Exhibit A - Source Code Form License Notice + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +## Exhibit B - “Incompatible With Secondary Licenses” Notice + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. From 8aa446b4e6845c91c10e1fb35a23ee44c257200b Mon Sep 17 00:00:00 2001 From: sarayourfriend Date: Thu, 8 Apr 2021 07:32:18 -0700 Subject: [PATCH 056/125] Components: Add create-styles (#30509) * Components: Add create-styles * Fix disallowed syntaxes * Add missing TS resolution * Remove ThemeProvider and duplicated hooks * Clean up READMEs * Remove unnecessary deps * Remove stray `is` import * Change namespace to experimental to avoid introducing new public APIs * Remove stray mentions of g2 * Remove `css` prop and automatic prop filtering --- package-lock.json | 28 +++ packages/components/package.json | 5 + .../create-styles/create-compiler/README.md | 55 ++++++ .../create-compiler/create-compiler.js | 120 +++++++++++ .../create-compiler/create-css.js | 65 ++++++ .../ui/create-styles/create-compiler/index.js | 3 + .../create-compiler/plugins/README.md | 33 ++++ .../create-compiler/plugins/css-variables.js | 77 ++++++++ .../plugins/extra-specificity.js | 61 ++++++ .../create-compiler/plugins/index.js | 37 ++++ .../create-compiler/plugins/utils.js | 20 ++ .../create-compiler/responsive.js | 54 +++++ .../create-compiler/test/responsive.js | 34 ++++ .../ui/create-styles/create-compiler/utils.js | 15 ++ .../create-style-system/README.md | 101 ++++++++++ .../create-style-system/constants.js | 22 +++ .../create-core-element.js | 145 ++++++++++++++ .../create-core-elements.js | 34 ++++ .../create-style-system.js | 151 ++++++++++++++ .../create-styled-components.js | 175 ++++++++++++++++ .../create-style-system/generate-theme.js | 84 ++++++++ .../create-style-system/index.js | 7 + .../polymorphic-component.ts | 62 ++++++ .../create-styles/create-style-system/tags.js | 141 +++++++++++++ .../test/create-style-system.js | 89 +++++++++ .../create-style-system/types.d.ts | 1 + .../create-style-system/utils.js | 186 ++++++++++++++++++ .../create-root-store.js | 111 +++++++++++ .../css-custom-properties/get-prop-value.js | 71 +++++++ .../css-custom-properties/index.js | 2 + .../transform-content.js | 98 +++++++++ .../css-custom-properties/utils.js | 54 +++++ .../src/ui/create-styles/hooks/index.js | 1 + .../hooks/use-hydrate-global-styles.js | 52 +++++ .../components/src/ui/create-styles/index.js | 3 + .../ui/create-styles/stories/create-styles.js | 30 +++ .../style-system-string-interpolation.js | 47 +++++ packages/components/tsconfig.json | 6 +- typings/styled-griddie/index.d.ts | 10 + 39 files changed, 2289 insertions(+), 1 deletion(-) create mode 100644 packages/components/src/ui/create-styles/create-compiler/README.md create mode 100644 packages/components/src/ui/create-styles/create-compiler/create-compiler.js create mode 100644 packages/components/src/ui/create-styles/create-compiler/create-css.js create mode 100644 packages/components/src/ui/create-styles/create-compiler/index.js create mode 100644 packages/components/src/ui/create-styles/create-compiler/plugins/README.md create mode 100644 packages/components/src/ui/create-styles/create-compiler/plugins/css-variables.js create mode 100644 packages/components/src/ui/create-styles/create-compiler/plugins/extra-specificity.js create mode 100644 packages/components/src/ui/create-styles/create-compiler/plugins/index.js create mode 100644 packages/components/src/ui/create-styles/create-compiler/plugins/utils.js create mode 100644 packages/components/src/ui/create-styles/create-compiler/responsive.js create mode 100644 packages/components/src/ui/create-styles/create-compiler/test/responsive.js create mode 100644 packages/components/src/ui/create-styles/create-compiler/utils.js create mode 100644 packages/components/src/ui/create-styles/create-style-system/README.md create mode 100644 packages/components/src/ui/create-styles/create-style-system/constants.js create mode 100644 packages/components/src/ui/create-styles/create-style-system/create-core-element.js create mode 100644 packages/components/src/ui/create-styles/create-style-system/create-core-elements.js create mode 100644 packages/components/src/ui/create-styles/create-style-system/create-style-system.js create mode 100644 packages/components/src/ui/create-styles/create-style-system/create-styled-components.js create mode 100644 packages/components/src/ui/create-styles/create-style-system/generate-theme.js create mode 100644 packages/components/src/ui/create-styles/create-style-system/index.js create mode 100644 packages/components/src/ui/create-styles/create-style-system/polymorphic-component.ts create mode 100644 packages/components/src/ui/create-styles/create-style-system/tags.js create mode 100644 packages/components/src/ui/create-styles/create-style-system/test/create-style-system.js create mode 100644 packages/components/src/ui/create-styles/create-style-system/types.d.ts create mode 100644 packages/components/src/ui/create-styles/create-style-system/utils.js create mode 100644 packages/components/src/ui/create-styles/css-custom-properties/create-root-store.js create mode 100644 packages/components/src/ui/create-styles/css-custom-properties/get-prop-value.js create mode 100644 packages/components/src/ui/create-styles/css-custom-properties/index.js create mode 100644 packages/components/src/ui/create-styles/css-custom-properties/transform-content.js create mode 100644 packages/components/src/ui/create-styles/css-custom-properties/utils.js create mode 100644 packages/components/src/ui/create-styles/hooks/index.js create mode 100644 packages/components/src/ui/create-styles/hooks/use-hydrate-global-styles.js create mode 100644 packages/components/src/ui/create-styles/index.js create mode 100644 packages/components/src/ui/create-styles/stories/create-styles.js create mode 100644 packages/components/src/ui/create-styles/stories/style-system-string-interpolation.js create mode 100644 typings/styled-griddie/index.d.ts diff --git a/package-lock.json b/package-lock.json index b4632ec138116f..6a2ba428674d33 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12465,6 +12465,7 @@ "@babel/runtime": "^7.13.10", "@emotion/core": "^10.1.1", "@emotion/css": "^10.0.22", + "@emotion/hash": "^0.8.0", "@emotion/native": "^10.0.22", "@emotion/styled": "^10.0.23", "@wordpress/a11y": "file:packages/a11y", @@ -12486,12 +12487,15 @@ "@wp-g2/styles": "^0.0.160", "@wp-g2/utils": "^0.0.160", "classnames": "^2.2.5", + "create-emotion": "^10.0.27", "dom-scroll-into-view": "^1.2.1", "downshift": "^6.0.15", "gradient-parser": "^0.1.5", "highlight-words-core": "^1.2.2", + "hoist-non-react-statics": "^3.3.2", "lodash": "^4.17.19", "memize": "^1.1.0", + "mitt": "^2.1.0", "moment": "^2.22.1", "re-resizable": "^6.4.0", "react-dates": "^17.1.1", @@ -12500,8 +12504,32 @@ "react-use-gesture": "^9.0.0", "reakit": "^1.3.5", "rememo": "^3.0.0", + "styled-griddie": "^0.1.3", "tinycolor2": "^1.4.2", "uuid": "^8.3.0" + }, + "dependencies": { + "@emotion/is-prop-valid": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", + "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "requires": { + "@emotion/memoize": "0.7.4" + } + }, + "@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" + }, + "hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "requires": { + "react-is": "^16.7.0" + } + } } }, "@wordpress/compose": { diff --git a/packages/components/package.json b/packages/components/package.json index aae55b5eea34ca..ade5e6ca72d8a6 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -29,6 +29,7 @@ "@babel/runtime": "^7.13.10", "@emotion/core": "^10.1.1", "@emotion/css": "^10.0.22", + "@emotion/hash": "^0.8.0", "@emotion/native": "^10.0.22", "@emotion/styled": "^10.0.23", "@wordpress/a11y": "file:../a11y", @@ -50,12 +51,15 @@ "@wp-g2/styles": "^0.0.160", "@wp-g2/utils": "^0.0.160", "classnames": "^2.2.5", + "create-emotion": "^10.0.27", "dom-scroll-into-view": "^1.2.1", "downshift": "^6.0.15", "gradient-parser": "^0.1.5", "highlight-words-core": "^1.2.2", + "hoist-non-react-statics": "^3.3.2", "lodash": "^4.17.19", "memize": "^1.1.0", + "mitt": "^2.1.0", "moment": "^2.22.1", "re-resizable": "^6.4.0", "react-dates": "^17.1.1", @@ -64,6 +68,7 @@ "react-use-gesture": "^9.0.0", "reakit": "^1.3.5", "rememo": "^3.0.0", + "styled-griddie": "^0.1.3", "tinycolor2": "^1.4.2", "uuid": "^8.3.0" }, diff --git a/packages/components/src/ui/create-styles/create-compiler/README.md b/packages/components/src/ui/create-styles/create-compiler/README.md new file mode 100644 index 00000000000000..76773b7a2ca1de --- /dev/null +++ b/packages/components/src/ui/create-styles/create-compiler/README.md @@ -0,0 +1,55 @@ +# create-compiler + +This module creates the Emotion instance that backs the style system. It integrates plugins and creates the core `css` function that wraps Emotion's `css` function adding support for breakpoint values on each property. + +## Breakpoint values + +Breakpoint values are supported by passing an array of values to a CSS property. For example: + +```js +css({ + width: [300, 500, 700], +}); +``` + +This will dynamically respond to breakpoints and render the appropriate width for each `min-width`. The breakpoints are documented in the code in [`utils.js`](./utils.js). + +## Plugins + +`createCompiler` supports passing certain parameters to plugins. Plugin initialization should be contained to [`plugins/index.js`](./plugins/index.js). + +The individual plugins are documented in [`plugins/README.md`](./plugins/README.md). + +## Custom iframe support + +Emotion by default does not support iframe styling. This style system solves this by implementing a custom `sheet.insert` that exposes a `sheet.insert` event which can be listened to by style providers to receive styles from outside of the current iframe. + +## Interplated Components + +`css` also supports passing style system-connected components as selectors in the same style as `styled-components`. It does this _without any Babel transformations_. Interpolated components are transformed to a special interpolated class name by the `css` function. Components are given an interpolation class name (prefixed by `ic-`) by either the `contextConnect` hook or by `styled` itself. `css` then detects when a component has been passed in and transorms it into a CSS selector. + +For example: + +```js +const Text = styled.div` + color: red; +`; + +const greenText = css` + ${Text} { + color: green; + } +`; +``` + +Now any child `Text` of a component that applies the `greenText` generated class name will be targeted with the `color: green` styles. + +Psueudo selectors against the interpolated component are possible as well: + +```js +const blueText = css` + ${Text}:first-child { + color: blue; + } +`; +``` diff --git a/packages/components/src/ui/create-styles/create-compiler/create-compiler.js b/packages/components/src/ui/create-styles/create-compiler/create-compiler.js new file mode 100644 index 00000000000000..9885f59678b28f --- /dev/null +++ b/packages/components/src/ui/create-styles/create-compiler/create-compiler.js @@ -0,0 +1,120 @@ +/** + * External dependencies + */ +import createEmotion from 'create-emotion'; +import mitt from 'mitt'; + +/** + * Internal dependencies + */ +import { RootStore } from '../css-custom-properties'; +import { createCSS } from './create-css'; +import { createPlugins } from './plugins'; +import { breakpoints, generateInterpolationName } from './utils'; + +const defaultOptions = { + key: 'css', + specificityLevel: 1, + rootStore: new RootStore(), +}; + +/* eslint-disable jsdoc/valid-types */ +/** + * @typedef {import('create-emotion').Emotion & { + * breakpoints: typeof breakpoints, + * __events: import('mitt').Emitter, + * generateInterpolationName(): string, + * }} Compiler + */ +/* eslint-enable jsdoc/valid-types */ + +/** + * @typedef {import('create-emotion').Options & { + * key?: string, + * specificityLevel?: number, + * rootStore: import('../css-custom-properties').RootStore + * }} CreateCompilerOptions + */ + +/** + * @param {CreateCompilerOptions} options + * @return {Compiler} The compiler. + */ +export function createCompiler( options ) { + const mergedOptions = { + ...defaultOptions, + ...options, + }; + + const { key, rootStore, specificityLevel } = mergedOptions; + + const defaultPlugins = createPlugins( { + key, + specificityLevel, + rootStore, + } ); + + if ( options.stylisPlugins ) { + if ( Array.isArray( options.stylisPlugins ) ) { + mergedOptions.stylisPlugins = [ + ...defaultPlugins, + ...options.stylisPlugins, + ]; + } else if ( typeof options.stylisPlugins !== 'undefined' ) { + // just a single plugin was passed in, as is allowed by emotion + mergedOptions.stylisPlugins = [ + ...defaultPlugins, + options.stylisPlugins, + ]; + } else { + mergedOptions.stylisPlugins = defaultPlugins; + } + } else { + mergedOptions.stylisPlugins = defaultPlugins; + } + + /** + * We're creating a custom Emotion instance to ensure that the style system + * does not conflict with (potential) existing Emotion instances. + * + * We're also able to provide createEmotion with our custom Stylis plugins. + */ + const customEmotionInstance = { + ...createEmotion( mergedOptions ), + /** + * Exposing the breakpoints used in the internal Style system. + */ + breakpoints, + /** + * An internal custom event emitter (pub/sub) for Emotion. + * This is currently used in + * to subscribe to and sync style injection. + */ + __events: mitt(), + generateInterpolationName, + }; + + /** + * Enhance the base css function from Emotion to add features like responsive + * value handling and compiling an Array of css() calls. + */ + const { css } = customEmotionInstance; + customEmotionInstance.css = createCSS( css ); + + /** + * Modify the sheet.insert method to emit a `sheet.insert` event + * within the internal custom event emitter. + */ + const __insert = customEmotionInstance.sheet.insert; + customEmotionInstance.sheet.insert = ( + /* eslint-disable jsdoc/valid-types */ + /** @type {[rule: string]} */ ...args + ) => + /* eslint-enable jsdoc/valid-types */ + { + __insert.apply( customEmotionInstance.sheet, [ ...args ] ); + customEmotionInstance.__events.emit( 'sheet.insert', ...args ); + }; + + return customEmotionInstance; +} diff --git a/packages/components/src/ui/create-styles/create-compiler/create-css.js b/packages/components/src/ui/create-styles/create-compiler/create-css.js new file mode 100644 index 00000000000000..9fe62e7a671664 --- /dev/null +++ b/packages/components/src/ui/create-styles/create-compiler/create-css.js @@ -0,0 +1,65 @@ +/** + * External dependencies + */ +import { isPlainObject } from 'lodash'; + +/** + * Internal dependencies + */ +import { responsive } from './responsive'; + +/** + * @param {CSS} compile + * @return {CSS} The CSS function + */ +export function createCSS( compile ) { + /** + * An enhanced version of the compiler's (Emotion) CSS function. + * This enhanced CSS supports dynamic responsive (breakpoint-based) styles if + * the value is an array of values. + * + * @example + * ```js + * // The following will render a CSS rule where the widths will be: + * // 100px for mobile + * // 200px for tablet + * // 500px for desktop + * css({ + * width: [100, 200, 500] + * }) + * ``` + * @param {Parameters} args + * @return {ReturnType} The compiled CSS className associated with the styles. + */ + function css( ...args ) { + const [ arg, ...rest ] = args; + + if ( isPlainObject( arg ) ) { + return compile( + responsive( /** @type {ObjectInterpolation} */ ( arg ) ) + ); + } + + if ( Array.isArray( arg ) ) { + for ( let i = 0, len = arg.length; i < len; i++ ) { + const n = arg[ i ]; + if ( isPlainObject( n ) ) { + arg[ i ] = responsive( + /** @type {ObjectInterpolation} */ ( n ) + ); + } + } + return compile( ...[ arg, ...rest ] ); + } + + return compile( ...args ); + } + + // @ts-ignore No amount of zhuzhing will convince TypeScript that a function with the parameters and return type for CSS is in fact the same type + return css; +} + +/* eslint-disable jsdoc/valid-types */ +/** @typedef {import('create-emotion').Emotion['css']} CSS */ +/** @typedef {import('create-emotion').ObjectInterpolation} ObjectInterpolation */ +/* eslint-enable jsdoc/valid-types */ diff --git a/packages/components/src/ui/create-styles/create-compiler/index.js b/packages/components/src/ui/create-styles/create-compiler/index.js new file mode 100644 index 00000000000000..2daae99d0b6cb6 --- /dev/null +++ b/packages/components/src/ui/create-styles/create-compiler/index.js @@ -0,0 +1,3 @@ +export * from './create-compiler'; +export * from './create-css'; +export * from './responsive'; diff --git a/packages/components/src/ui/create-styles/create-compiler/plugins/README.md b/packages/components/src/ui/create-styles/create-compiler/plugins/README.md new file mode 100644 index 00000000000000..1526ad4374e120 --- /dev/null +++ b/packages/components/src/ui/create-styles/create-compiler/plugins/README.md @@ -0,0 +1,33 @@ +# plugins + +This foler contains all the applied plugins in the style system. + +**Nota bene**: All of the plugins can be removed once IE11 support is officially dropped. + +## Extra Specificity + +This plugin automatically compounds selector specificity by simply repeating the selector x number of times. For example, if a specificity of 3 is passed in, the plugin will transform: + +```css +.css-abc123 { + color: red; +} +``` + +into: + +```css +.css-abc123.css-abc123.css-abc123 { + color: red; +} +``` + +This is meant to prevent "hacks" from being applied to the component system via regular css selection (or rather to make it difficult/annoying to do so), forcing consumers to use the style system itself, for example, the `css` prop and theme variables, to apply custom styles. + +It is currently set to a specificity of 1 to disable it. This may be reversed in the future. If it isn't reversed in the future, at some point we shoiuld just remove it. + +## CSS Variable Fallback + +The [`css-variables.js` ](./css-variables.js) plugin automatically generates fallback variables to support browsers that lack CSS variable support. + +Given WordPress core is dropping IE11 support,we might be able to drop this plugin altogether. diff --git a/packages/components/src/ui/create-styles/create-compiler/plugins/css-variables.js b/packages/components/src/ui/create-styles/create-compiler/plugins/css-variables.js new file mode 100644 index 00000000000000..23771469048e7f --- /dev/null +++ b/packages/components/src/ui/create-styles/create-compiler/plugins/css-variables.js @@ -0,0 +1,77 @@ +/** + * Internal dependencies + */ +import { createRootStore } from '../../css-custom-properties'; +import { transformContent } from '../../css-custom-properties/transform-content'; +import { hasVariable } from '../../css-custom-properties/utils'; +import { STYLIS_CONTEXTS, STYLIS_TOKENS } from './utils'; + +// Detects native CSS varialble support +// https://github.com/jhildenbiddle/css-vars-ponyfill/blob/master/src/index.js +const isNativeSupport = + typeof window !== 'undefined' && window?.CSS?.supports?.( '(--a: 0)' ); + +/* + * This plugin is for the stylis library. It's the CSS compiler used by + * CSS-in-JS libraries like Emotion. + * + * https://github.com/thysultan/stylis.js + */ + +const defaultOptions = { + rootStore: createRootStore(), + skipSupportedBrowsers: true, +}; + +/* + * Generates fallback values for CSS rule declarations that contain CSS var(). + * This plugin parses uses specified fallback values within the var() + * function. If one is not provided, it will attempt to use the matching + * variable declared at the :root scope. + */ +function stylisPluginCssVariables( + /* istanbul ignore next */ + options = {} +) { + const { rootStore, skipSupportedBrowsers } = { + ...defaultOptions, + ...options, + }; + + const plugin = ( + /** @type {number} */ context, + /** @type {string} */ content, + /** @type {unknown} */ _, + /** @type {unknown} */ __, + /** @type {unknown} */ ___, + /** @type {unknown} */ ____, + /** @type {unknown} */ _____, + /** @type {number} */ type + ) => { + // Skip generating CSS variable fallbacks for supported browsers + if ( skipSupportedBrowsers && isNativeSupport ) return; + + // Borrowed guard implementation from: + // https://github.com/Andarist/stylis-plugin-extra-scope/blob/master/src/index.js#L15 + /* istanbul ignore next */ + if ( + context !== STYLIS_CONTEXTS.SELECTOR_BLOCK || + type === STYLIS_TOKENS.KEYFRAME + ) { + return; + } + + // We only need to process the content if a CSS var() is used. + if ( ! hasVariable( content ) ) return; + + // We'll parse the content to match variables to their custom properties (if possible). + const nextContent = transformContent( content, rootStore ); + + // Lastly, we'll provide stylis with our enhanced CSS variable supported content. + return nextContent; + }; + + return plugin; +} + +export default stylisPluginCssVariables; diff --git a/packages/components/src/ui/create-styles/create-compiler/plugins/extra-specificity.js b/packages/components/src/ui/create-styles/create-compiler/plugins/extra-specificity.js new file mode 100644 index 00000000000000..3449b5bcf83169 --- /dev/null +++ b/packages/components/src/ui/create-styles/create-compiler/plugins/extra-specificity.js @@ -0,0 +1,61 @@ +/** + * External dependencies + */ +import { clamp, repeat } from 'lodash'; + +const seen = new WeakSet(); +const seenMatch = new Set(); + +const defaultOptions = { + key: 'wp-css', + level: 7, +}; + +/** + * @typedef ExtraSpecificityPluginOptions + * @property {string} [key='wp-css'] The key that prefixes styles. + * @property {number} [level=7] The level of specificity to use. + */ + +/** + * Custom stylis plugin that increases the scope of generated selectors. + * The default compounding "level" is 7. + * + * For example, a selector of `.css-ah12df` would result in a final selector + * of `.css-ah12df.css-ah12df.css-ah12df.css-ah12df.css-ah12df.css-ah12df.css-ah12df`. + * + * @param {ExtraSpecificityPluginOptions} options Options to adjust the plugin + */ +function stylisExtraSpecificityPlugin( options = defaultOptions ) { + const { key, level } = { ...defaultOptions, ...options }; + const repeatLevel = clamp( level, 0, 20 ); + + return ( + /** @type {number} */ _, + /** @type {string} */ __, + /** @type {string[]} */ selectors + ) => { + if ( seen.has( selectors ) ) return; + seen.add( selectors ); + + const regex = new RegExp( `.${ key }-[\\w|\\d]*`, 'g' ); + + for ( let i = 0; i < selectors.length; i++ ) { + let item = selectors[ i ]; + const [ match ] = item.match( regex ) || []; + + if ( match ) { + if ( seenMatch.has( match ) ) return; + seenMatch.add( match ); + + item = item + .replace( new RegExp( match, 'g' ), match ) + .replace( match, repeat( match, repeatLevel ) ); + + selectors[ i ] = item; + } + } + }; +} + +export default stylisExtraSpecificityPlugin; diff --git a/packages/components/src/ui/create-styles/create-compiler/plugins/index.js b/packages/components/src/ui/create-styles/create-compiler/plugins/index.js new file mode 100644 index 00000000000000..b83b8b25c7b882 --- /dev/null +++ b/packages/components/src/ui/create-styles/create-compiler/plugins/index.js @@ -0,0 +1,37 @@ +/** + * External dependencies + */ +import cssGridPlugin from 'styled-griddie'; + +/** + * Internal dependencies + */ +import cssVariablesPlugin from './css-variables'; +import specificityPlugin from './extra-specificity'; + +const isProd = process.env.NODE_ENV === 'production'; + +/** + * A collection of custom Stylis plugins to enhance the way the compiler (Emotion) + * generates selectors and CSS rules. + * + * @param {Object} options + * @param {number} [options.specificityLevel=7] + * @param {string} [options.key='css'] + * @param {boolean} [options.skipSupportedBrowsers] + * @param {import('../../css-custom-properties').RootStore} [options.rootStore] + * @return {import('@emotion/stylis').Plugin[]} The list of stylis plugins. + */ +export function createPlugins( { + specificityLevel = 1, + key = 'css', + rootStore, + skipSupportedBrowsers = isProd, +} ) { + return [ + cssVariablesPlugin( { skipSupportedBrowsers, rootStore } ), + specificityPlugin( { level: specificityLevel, key } ), + // @ts-ignore styled-griddie imports StylisPlugin from `styled-components` which has different types from the actual one we're using here + cssGridPlugin, + ]; +} diff --git a/packages/components/src/ui/create-styles/create-compiler/plugins/utils.js b/packages/components/src/ui/create-styles/create-compiler/plugins/utils.js new file mode 100644 index 00000000000000..941f0c302e7b5c --- /dev/null +++ b/packages/components/src/ui/create-styles/create-compiler/plugins/utils.js @@ -0,0 +1,20 @@ +/** + * Plugin contexts: + * https://github.com/thysultan/stylis.js/blob/4561e9bc830fccf1cb0e9e9838488b4d1d5cebf5/stylis.js#L150 + */ +export const STYLIS_CONTEXTS = { + AT_RULE: 3, + NEWLINE: 0, + POST_PROCESS: -2, + PREPARATION: -1, + PROPERTY: 1, + SELECTOR_BLOCK: 2, +}; + +/** + * Character codes and special identifiers: + * https://github.com/thysultan/stylis.js/blob/4561e9bc830fccf1cb0e9e9838488b4d1d5cebf5/stylis.js#L92 + */ +export const STYLIS_TOKENS = { + KEYFRAME: 107, +}; diff --git a/packages/components/src/ui/create-styles/create-compiler/responsive.js b/packages/components/src/ui/create-styles/create-compiler/responsive.js new file mode 100644 index 00000000000000..f4b3c9fc526440 --- /dev/null +++ b/packages/components/src/ui/create-styles/create-compiler/responsive.js @@ -0,0 +1,54 @@ +/** + * Internal dependencies + */ +import { breakpoints } from './utils'; + +// https://github.com/system-ui/theme-ui/blob/master/packages/css/src/index.ts#L224 +/** + * A utility function that generates responsive styles if the value is an array. + * + * @param {import('@emotion/serialize').ObjectInterpolation} styles A styles object + * @param {(key: string, value: any) => any} [getScaleValue] + * @return {import('@emotion/serialize').ObjectInterpolation} An adjusted styles object with responsive styles (if applicable). + */ +export const responsive = ( + styles = {}, + getScaleValue = ( _, value ) => value +) => { + /** @type {import('@emotion/serialize').ObjectInterpolation} */ + const next = {}; + const mediaQueries = [ + null, + ...breakpoints.map( ( n ) => `@media screen and (min-width: ${ n })` ), + ]; + + for ( const k in styles ) { + const key = k; + const value = styles[ key ]; + + if ( value === null ) continue; + + if ( ! Array.isArray( value ) ) { + next[ key ] = value; + continue; + } + + for ( + let i = 0; + i < value.slice( 0, mediaQueries.length ).length; + i++ + ) { + const media = mediaQueries[ i ]; + if ( ! media ) { + next[ key ] = getScaleValue( key, value[ i ] ); + continue; + } + next[ media ] = next[ media ] || {}; + if ( value[ i ] === null ) continue; + // @ts-ignore One line above we ensure that it is not null + next[ media ][ key ] = getScaleValue( key, value[ i ] ); + } + } + + return next; +}; diff --git a/packages/components/src/ui/create-styles/create-compiler/test/responsive.js b/packages/components/src/ui/create-styles/create-compiler/test/responsive.js new file mode 100644 index 00000000000000..a67574ad7baabf --- /dev/null +++ b/packages/components/src/ui/create-styles/create-compiler/test/responsive.js @@ -0,0 +1,34 @@ +/** + * Internal dependencies + */ +import { responsive } from '../responsive'; + +describe( 'responsive', () => { + test( 'should transform responsive space values', () => { + const styles = { + gap: [ 5, null, 10 ], + }; + + expect( responsive( styles ) ).toEqual( { + gap: 5, + '@media screen and (min-width: 40em)': {}, + '@media screen and (min-width: 52em)': { + gap: 10, + }, + } ); + } ); + + test( 'should transform responsive space string values', () => { + const styles = { + gap: [ '5px', null, '10em' ], + }; + + expect( responsive( styles ) ).toEqual( { + gap: '5px', + '@media screen and (min-width: 40em)': {}, + '@media screen and (min-width: 52em)': { + gap: '10em', + }, + } ); + } ); +} ); diff --git a/packages/components/src/ui/create-styles/create-compiler/utils.js b/packages/components/src/ui/create-styles/create-compiler/utils.js new file mode 100644 index 00000000000000..65f5384fa9fbc1 --- /dev/null +++ b/packages/components/src/ui/create-styles/create-compiler/utils.js @@ -0,0 +1,15 @@ +/** + * Breakpoint values used for responsive style rendering. + */ +/** + * @type {['40em', '52em', '64em']} + */ +export const breakpoints = [ '40em', '52em', '64em' ]; + +let currentInterpolationId = 0; +/** + * @return {string} Interpolation class name. + */ +export const generateInterpolationName = () => { + return `interpolatable-component-${ currentInterpolationId++ }`; +}; diff --git a/packages/components/src/ui/create-styles/create-style-system/README.md b/packages/components/src/ui/create-styles/create-style-system/README.md new file mode 100644 index 00000000000000..a2ef57916c894d --- /dev/null +++ b/packages/components/src/ui/create-styles/create-style-system/README.md @@ -0,0 +1,101 @@ +# create-style-system + +This module creates the `styled` utility as well as the overall style system. + +## styled + +`styled` works just as Emotion's and `styled-components`'s `styled` function objects. It is able to accept a component as an argument to style as well as is a collection of "core elements" that can be used to create styled elements on the fly. + +For example: + +```js +const Text = styled.span` + color: blue; +`; +``` + +`Text` is a React component that will render a `span` with the custom styles applied. + +`styled` can also be used as a function to apply custom styles to existing components: + +```jsx +const Component = ({ className }) => { + return
My Favorite Component
; +}; + +const StyledComponent = styled(Component)` + color: green; +`; +``` + +For a component to be able to be passed to `styled`, the only requirement is that it forward the `className` prop. + +Ultimately `styled` is just an interface for `css` that automatically applies the generated class name from the CSS to a given component, whether that is one of the core elements or a passed in component. That is why passed in components must forward the `className` prop. + +`styled` also supports component interpolation. See [`css`'s documentation here](../create-compiler/README.md) for more information on how it works. A breif example is here: + +```js +const Text = styled.span` + color: red; +`; + +const Container = styled.div` + display: flex; + + ${Text} { + color: blue; + } +`; +``` + +Now any child component `Text` of `Container` will be targeted with the `color: blue` style, while `Text` itself will continue to render the `color: red` style. + +## Polymorphic Component + +This module also exposes the concept of the Polymorphic Component. This concept is not new to this style system but the style and component system use it extensively and it is one of the more powerful aspects of this style system. + +Poylmorphic components are able to accept an `as` prop that will accept any React component or JSX Element name. For example: + +```jsx + +``` + +Will render everything `View` renders but as a `span`. + +This is even more powerful when combining elements: + +```jsx + + + + Click me! + + + +``` + +As you can see, the component polymorphism allows you to powerfully compose the component system with itself and with other component systems. Even passing `as={ ReakitComponent }` for example will work, enabling powerful accessibility patterns while still maintaining the power of the style system on the core `View` component. + +Component polymorphism is documented via the `PolymorphicComponent` type in `polymorphic-component.ts`. + +The same module also exposes a `ViewOwnProps` type which gives the `as` props to a regular `Props` interface: + +```tsx +interface Props { + foo: string; +} + +function MyButton(props: ViewOwnProps) { + return ; +} +``` + +The second parameter to `ViewOwnProps` should indicate the _default_ `as` value for the component. That is, if the component renders a `button` as the example above does, it should be `button`. This will give the `props` type all of the appropriate `HTMLAttributes` for the given intrinsic element. For example, our `MyButton` component above is able to accept a strongly typed `onClick` for a `MouseEvent`. Likewise, this will automagically change if `as` is passed as a different value: + +```jsx + + Code is Poetry + +``` + +`href` will be strongly typed to the `HTMLAnchorAttributes` prop. diff --git a/packages/components/src/ui/create-styles/create-style-system/constants.js b/packages/components/src/ui/create-styles/create-style-system/constants.js new file mode 100644 index 00000000000000..ca84e8336118c2 --- /dev/null +++ b/packages/components/src/ui/create-styles/create-style-system/constants.js @@ -0,0 +1,22 @@ +/** + * Uses the the prefix for the CSS variables compiled by the system. + */ +export const NAMESPACE = '--wp-experimental'; + +export const DARK_MODE_ATTR_PROP = 'data-system-ui-mode'; +export const HIGH_CONTRAST_MODE_ATTR_PROP = 'data-system-ui-contrast-mode'; +export const COLOR_BLIND_MODE_ATTR_PROP = 'data-system-ui-color-blind-mode'; +export const REDUCED_MOTION_MODE_ATTR_PROP = + 'data-system-ui-reduced-motion-mode'; + +export const DARK_MODE_ATTR = `[${ DARK_MODE_ATTR_PROP }="dark"]`; +export const HIGH_CONTRAST_MODE_MODE_ATTR = `[${ HIGH_CONTRAST_MODE_ATTR_PROP }="high"]`; + +export const COLOR_BLIND_MODE_ATTR = `[${ COLOR_BLIND_MODE_ATTR_PROP }="true"]`; +export const REDUCED_MOTION_MODE_ATTR = `[${ REDUCED_MOTION_MODE_ATTR_PROP }="true"]`; + +export const DARK_HIGH_CONTRAST_MODE_MODE_ATTR = `${ DARK_MODE_ATTR }${ HIGH_CONTRAST_MODE_MODE_ATTR }`; + +export const MODE_SPECIFICITY_COMPOUND_LEVEL = 3; + +export const INTERPOLATION_CLASS_NAME = '__interpolationClassName__'; diff --git a/packages/components/src/ui/create-styles/create-style-system/create-core-element.js b/packages/components/src/ui/create-styles/create-style-system/create-core-element.js new file mode 100644 index 00000000000000..3ad94350b7bd6f --- /dev/null +++ b/packages/components/src/ui/create-styles/create-style-system/create-core-element.js @@ -0,0 +1,145 @@ +/** + * WordPress dependencies + */ +import { useMergeRefs } from '@wordpress/compose'; +import { forwardRef, createElement } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { useHydrateGlobalStyles } from '../hooks'; +import { + INTERPOLATION_CLASS_NAME, + REDUCED_MOTION_MODE_ATTR, +} from './constants'; +import { + DEFAULT_STYLE_SYSTEM_OPTIONS, + getInterpolatedClassName, +} from './utils'; + +const defaultOptions = DEFAULT_STYLE_SYSTEM_OPTIONS; + +/** + * @typedef CreateCoreElementOptions + * @property {import('create-emotion').ObjectInterpolation} baseStyles The baseStyles from the Style system. + * @property {import('../create-compiler').Compiler} compiler The injectGlobal from the Style system's compiler. + * @property {import('./generate-theme').GenerateThemeResults} globalStyles The globalStyles from the Style system. + */ + +/** + * Creates the core styled elements for the Style system. These elements are + * an in-between of Emotion's
solution and a styled.div`` + * solution. + * + * createCoreElement is a super light-weight higher-order wrapper that + * enhances base elements (like `div`, `input`, or even Components) with + * features provided by the Style system. + * + * A styled element also has built-in baseStyles (which can be adjusted using + * the createStyleSystem factory). + * + * @example + * ```jsx + * const alwaysBlueDiv = createCoreElement('div', { baseStyles: { background: 'blue' }}) + * ``` + * + * @template {keyof JSX.IntrinsicElements} TTagName + * @param {TTagName} tagName The HTMLElement/React.Component to connect with the Style system. + * @param {CreateCoreElementOptions} options Options to custom coreElement styles. + * @return {import('./polymorphic-component').PolymorphicComponent} The Style system wrapped HTMLElement/React.Component. + */ +export const createCoreElement = ( tagName, options ) => { + const { baseStyles, compiler, globalStyles } = { + ...defaultOptions, + ...options, + }; + + const { css, cx, injectGlobal } = compiler; + + /** + * Default baseStyles for the system. + */ + const styles = { + Base: css( { + // Automatic box-sizing resets. + boxSizing: 'border-box', + } ), + // Enforced reduced-motion preferred styles. + reduceMotion: css` + @media ( prefers-reduced-motion ) { + transition: none !important; + } + ${ REDUCED_MOTION_MODE_ATTR } & { + transition: none !important; + } + `, + }; + + const compiledBaseStyles = css( baseStyles ); + const interpolationClassName = getInterpolatedClassName( tagName ); + + /** + * @param {any} props + * @param {import('react').Ref} ref + */ + const Render = ( + { as, children, className: classNameProp, forwardedRef, ...props }, + ref + ) => { + /** + * useHydrateGlobalStyles an incredibly important hook, and is vital + * to the Style system. It automatically injects the variables Style + * system configs (configs, dark mode, etc...) on first-render. + * + * This way avoids.... + * + * 1. The need to wrap coreElements / styled components in any . + * 2. The need to use Context connectors (e.g. for ThemeProvider), which is HUGE for performance. + */ + useHydrateGlobalStyles( { globalStyles, injectGlobal } ); + + const element = as || tagName; + const className = + typeof classNameProp !== 'string' + ? cx( classNameProp ) + : classNameProp; + + /** + * Compiles all of the custom styles into classNames before binding it + * to the HTMLElement / React.Component. + */ + const classes = cx( + styles.Base, + styles.reduceMotion, + compiledBaseStyles, + className, + interpolationClassName + ); + + const refs = useMergeRefs( [ forwardedRef, ref ] ); + + return createElement( + element, + { + className: classes, + ref: refs, + ...props, + }, + children + ); + }; + + const SystemComponent = forwardRef( Render ); + + if ( process.env.NODE_ENV === 'development' ) { + const displayName = typeof tagName === 'string' ? tagName : 'Component'; + + SystemComponent.displayName = displayName; + } + + // @ts-ignore internal property + SystemComponent[ INTERPOLATION_CLASS_NAME ] = interpolationClassName; + + // @ts-ignore + return SystemComponent; +}; diff --git a/packages/components/src/ui/create-styles/create-style-system/create-core-elements.js b/packages/components/src/ui/create-styles/create-style-system/create-core-elements.js new file mode 100644 index 00000000000000..23a27aff0975c6 --- /dev/null +++ b/packages/components/src/ui/create-styles/create-style-system/create-core-elements.js @@ -0,0 +1,34 @@ +/** + * Internal dependencies + */ +import { createCoreElement } from './create-core-element'; +import { tags } from './tags'; + +/** + * @typedef CreateCoreElementProps + * @property {import('create-emotion').ObjectInterpolation} baseStyles Base styles for the coreElements. + * @property {import('../create-compiler').Compiler} compiler The injectGlobal from the Style system's compiler. + * @property {import('./generate-theme').GenerateThemeResults} globalStyles Global styles for the coreElements. + */ + +/** + * Generates a set of coreElements based on React supported HTML tags. + * + * @param {CreateCoreElementProps} props Properties to create coreElements with. + * @return {import('./polymorphic-component').CoreElements} A set of coreElements. + */ +export function createCoreElements( { baseStyles, compiler, globalStyles } ) { + /** @type {import('./polymorphic-component').CoreElements} */ + // @ts-ignore We fill in the missing properties in the loop below + const core = {}; + + const _createStyledElement = ( + /** @type {keyof JSX.IntrinsicElements} */ tagName + ) => createCoreElement( tagName, { baseStyles, compiler, globalStyles } ); + + for ( const tagName of tags ) { + core[ tagName ] = _createStyledElement( tagName ); + } + + return core; +} diff --git a/packages/components/src/ui/create-styles/create-style-system/create-style-system.js b/packages/components/src/ui/create-styles/create-style-system/create-style-system.js new file mode 100644 index 00000000000000..90c21d2c2cddc0 --- /dev/null +++ b/packages/components/src/ui/create-styles/create-style-system/create-style-system.js @@ -0,0 +1,151 @@ +/** + * Internal dependencies + */ +import { createCompiler } from '../create-compiler'; +import { createRootStore } from '../css-custom-properties'; +import { createCoreElement } from './create-core-element'; +import { createCoreElements } from './create-core-elements'; +import { createStyledComponents } from './create-styled-components'; +import { generateTheme } from './generate-theme'; +import { createToken, DEFAULT_STYLE_SYSTEM_OPTIONS } from './utils'; + +const defaultOptions = DEFAULT_STYLE_SYSTEM_OPTIONS; + +/* eslint-disable jsdoc/valid-types */ +/** + * @template {Record} TConfig + * @template {Record} TDarkConfig + * @template {Record} THCConfig + * @template {Record} TDarkHCConfig + * @template {string} TGeneratedTokens + * @typedef CreateStyleSystemObjects + * @property {import('./polymorphic-component').CoreElements} core A set of coreElements. + * @property {import('../create-compiler').Compiler} compiler The Style system compiler (a custom Emotion instance). + * @property {(tagName: keyof JSX.IntrinsicElements) => ReturnType} createCoreElement A function to create a coreElement (with settings from the Style system). + * @property {import('../create-compiler').Compiler['css']} css A function to compile CSS styles. + * @property {import('../create-compiler').Compiler['cx']} cx A function to resolve + combine classNames. + * @property {(tokenName: string) => string} createToken A function to generate a design token (CSS variable) used by the system. + * @property {(value: keyof (TConfig & TDarkConfig & THCConfig & TDarkHCConfig) | TGeneratedTokens) => string} get The primary function to retrieve Style system variables. + * @property {import('./polymorphic-component').CreateStyled} styled A set of styled components. + * @property {import('react').ComponentType} View The base component. + * @property {import('../css-custom-properties').RootStore} rootStore The root store. + */ + +/** + * @template {Record} TConfig + * @template {Record} TDarkConfig + * @template {Record} THCConfig + * @template {Record} TDarkHCConfig + * @template {string} TGeneratedTokens + * @typedef CreateStyleSystemOptions + * @property {import('create-emotion').ObjectInterpolation} baseStyles The base styles. + * @property {TConfig} config The base theme config. + * @property {TDarkConfig} darkModeConfig The dark mode theme config. + * @property {THCConfig} highContrastModeConfig The high contrast mode theme config. + * @property {TDarkHCConfig} darkHighContrastModeConfig The dark-high contrast mode theme config. + * @property {import('../create-compiler').CreateCompilerOptions} [compilerOptions] The compiler options. + */ +/* eslint-enable jsdoc/valid-types */ + +/** + * Creates a Style system using a set of baseStyles and configs. + * + * @example + * ```js + * const baseStyles = { background: 'blue' }; + * const blueStyleSystem = createStyleSystem({ baseStyles }); + * ``` + * + * @template {Record} TConfig + * @template {Record} TDarkConfig + * @template {Record} THCConfig + * @template {Record} TDarkHCConfig + * @template {string} TGeneratedTokens + * @param {CreateStyleSystemOptions} options Options to create a Style system with. + * @return {CreateStyleSystemObjects} A collection of functions and elements from the generated Style system. + */ +export function createStyleSystem( options = defaultOptions ) { + const { + baseStyles, + compilerOptions, + config, + darkHighContrastModeConfig, + darkModeConfig, + highContrastModeConfig, + } = { + ...defaultOptions, + ...options, + }; + + const globalStyles = generateTheme( { + config, + darkHighContrastModeConfig, + darkModeConfig, + highContrastModeConfig, + } ); + + const rootStore = createRootStore( globalStyles.globalVariables ); + rootStore.setState( globalStyles.globalVariables ); + + /** + * Compiler (Custom Emotion instance). + */ + const compiler = createCompiler( { + ...compilerOptions, + rootStore, + } ); + const { css, cx } = compiler; + + /** + * Core elements. + * + * @example + * ```jsx + * + * ``` + */ + const core = createCoreElements( { baseStyles, compiler, globalStyles } ); + + /** + * Styled components. + * + * @example + * ```jsx + * const StyledDiv = styled.div`` + * + * + * ``` + */ + const styled = createStyledComponents( { compiler, core } ); + + /** + * Export prebound createCoreElement factory. + * + * @param {keyof JSX.IntrinsicElements} tagName + */ + const _createCoreElement = ( tagName ) => + createCoreElement( tagName, { baseStyles, compiler, globalStyles } ); + + const View = core.div; + + const styleSystem = { + compiler, + core, + createCoreElement: _createCoreElement, + createToken, + css, + cx, + get: ( + /* eslint-disable jsdoc/no-undefined-types */ + /** @type {keyof TConfig | keyof TDarkConfig | keyof THCConfig | keyof TDarkHCConfig | TGeneratedTokens} */ key + /* eslint-enable jsdoc/no-undefined-types */ + ) => `var(${ createToken( key.toString() ) })`, + styled, + View, + rootStore, + }; + + return styleSystem; +} + +export default createStyleSystem; diff --git a/packages/components/src/ui/create-styles/create-style-system/create-styled-components.js b/packages/components/src/ui/create-styles/create-style-system/create-styled-components.js new file mode 100644 index 00000000000000..ed28c959ccee71 --- /dev/null +++ b/packages/components/src/ui/create-styles/create-style-system/create-styled-components.js @@ -0,0 +1,175 @@ +/** + * External dependencies + */ +import hoistNonReactStatics from 'hoist-non-react-statics'; + +/** + * WordPress dependencies + */ +import { forwardRef } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import { INTERPOLATION_CLASS_NAME } from './constants'; +import { tags } from './tags'; +import { compileInterpolatedStyles, getInterpolatedClassName } from './utils'; + +/** + * @typedef CreateStyledComponentsProps + * @property {import('../create-compiler').Compiler} compiler The (custom) Emotion instance. + * @property {import('./polymorphic-component').CoreElements} core The collection of coreElements. + */ + +/** + * Creates a set of styled components for the Style system. + * These styled components are similarly to Emotion's or Styled-Components styled.div``. + * + * A big difference is that the Style system's styled components do NOT require + * context connection at all. This is HUGE for performance as there are far less + * React.Component nodes within the render tree. + * + * This is thanks to how the Style system compiles and coordinates style values. + * + * @param {CreateStyledComponentsProps} props Props to create styled components with. + * @return {import('./polymorphic-component').CreateStyled} A set of styled components. + */ +export function createStyledComponents( { compiler, core } ) { + const { css, cx, generateInterpolationName } = compiler; + + /** + * That's all a is :). A core.div. + */ + const Box = core.div; + + /** + * + * @param {import('react').ElementType} tagName + * @param {any} options + */ + function createStyled( tagName, options = {} ) { + const { + /** + * A way to pass in extraProps when created a styled component. + */ + props: extraProps, + } = options; + + return ( /** @type {any[]} */ ...interpolatedProps ) => { + const interpolationClassName = getInterpolatedClassName( + generateInterpolationName() + ); + /** @type {import('react').ForwardRefRenderFunction} */ + const Render = ( { as: asProp, className, ...props }, ref ) => { + // Combine all of the props together. + const mergedProps = { ...extraProps, ...props, ref }; + + const baseTag = asProp || tagName; + + // Resolves prop interpolation. + const interpolatedStyles = compileInterpolatedStyles( + interpolatedProps, + props + ); + + const classes = cx( + css( ...interpolatedStyles ), + className, + interpolationClassName + ); + + return ( + + ); + }; + + const StyledComponent = forwardRef( Render ); + + /* + * Enhancing the displayName. + */ + if ( typeof tagName === 'string' ) { + StyledComponent.displayName = `Styled(${ getDisplayName( + tagName + ) })`; + } else if ( typeof tagName?.displayName !== 'undefined' ) { + StyledComponent.displayName = tagName.displayName; + } else { + StyledComponent.displayName = `Styled(${ getDisplayName( + tagName + ) })`; + } + + /* + * Enhancing .withComponent() + * https://github.com/emotion-js/emotion/blob/master/packages/styled-base/src/index.js#L210 + * + * This step is essential as we want styled components generated with + * .withComponent to have the correct baseStyles. + */ + // @ts-ignore + StyledComponent.withComponent = ( + /** @type {import('react').ElementType} */ nextTag, + /** @type {any} */ nextOptions + ) => { + return createStyled( + nextTag, + nextOptions !== undefined + ? { ...( options || {} ), ...nextOptions } + : options + )( ...interpolatedProps ); + }; + + // @ts-ignore internal property + StyledComponent[ + INTERPOLATION_CLASS_NAME + ] = interpolationClassName; + + if ( typeof tagName !== 'string' ) { + /* + * Hoisting statics one last time, if the tagName is a Component, + * rather than an HTML tag, like `div`. + */ + return hoistNonReactStatics( StyledComponent, tagName ); + } + return StyledComponent; + }; + } + + // Bind it to avoid mutating the original function. Just like @emotion/styled: + // https://github.com/emotion-js/emotion/blob/master/packages/styled/src/index.js + /* eslint-disable jsdoc/valid-types */ + /** @type {typeof createStyled & { [P in keyof JSX.IntrinsicElements]: ReturnType}} */ + // @ts-ignore We fill in the missing properties below + const styled = createStyled.bind( undefined ); + /* eslint-enable jsdoc/valid-types */ + + // Generating the core collection of styled[tagName], with our enhanced + // version of styled. + tags.forEach( ( tagName ) => { + styled[ tagName ] = createStyled( tagName ); + } ); + + // @ts-ignore We cannot convince TypeScript that we've taken care of everything here, we're doing too many JavaScript magics for this to work without an ignore + return styled; +} + +/** + * Gets the displayName of a React Component or element. + * + * @param {string | import('react').ComponentType} tagName + * + * @return {string} The display name of the Component / tagName. + */ +export function getDisplayName( tagName ) { + const displayName = + typeof tagName === 'string' + ? tagName + : tagName.displayName || tagName.name || 'Component'; + + return displayName; +} diff --git a/packages/components/src/ui/create-styles/create-style-system/generate-theme.js b/packages/components/src/ui/create-styles/create-style-system/generate-theme.js new file mode 100644 index 00000000000000..177664a74b7197 --- /dev/null +++ b/packages/components/src/ui/create-styles/create-style-system/generate-theme.js @@ -0,0 +1,84 @@ +/** + * External dependencies + */ +import { repeat } from 'lodash'; + +/** + * Internal dependencies + */ +import { + DARK_HIGH_CONTRAST_MODE_MODE_ATTR, + DARK_MODE_ATTR, + HIGH_CONTRAST_MODE_MODE_ATTR, + MODE_SPECIFICITY_COMPOUND_LEVEL, +} from './constants'; +import { + transformValuesToReferences, + transformValuesToVariables, + transformValuesToVariablesString, +} from './utils'; + +/** + * @typedef GenerateThemeProps + * @property {import('./utils').StyleConfigValues} config Default theme config. + * @property {import('./utils').StyleConfigValues} darkModeConfig Dark mode theme config. + * @property {import('./utils').StyleConfigValues} highContrastModeConfig High contrast mode theme config. + * @property {import('./utils').StyleConfigValues} darkHighContrastModeConfig Dark high contrast mode theme config. + */ + +/** + * @typedef GenerateThemeResults + * @property {import('./utils').StyleConfig} theme A set of theme style references. + * @property {import('./utils').StyleConfig} globalVariables A set of global variables. + * @property {string} globalCSSVariables The compiled CSS string for global variables. + * @property {string} darkModeCSSVariables The compiled CSS string for global dark variables. + * @property {string} highContrastModeCSSVariables The compiled CSS string for global high contrast variables. + * @property {string} darkHighContrastModeCSSVariables The compiled CSS string for global dark high contrast variables. + */ + +/** + * Generates theme references and compiles CSS variables to be used by the Style System. + * + * @param {GenerateThemeProps} props Props to generate a Style system theme with. + * @return {GenerateThemeResults} A set of variables and content for the System. + */ +export function generateTheme( { + config = {}, + darkModeConfig = {}, + highContrastModeConfig = {}, + darkHighContrastModeConfig = {}, +} ) { + const theme = transformValuesToReferences( config ); + const globalVariables = transformValuesToVariables( config ); + const globalCSSVariables = transformValuesToVariablesString( + ':root', + config + ); + + const darkModeCSSVariables = transformValuesToVariablesString( + repeat( DARK_MODE_ATTR, MODE_SPECIFICITY_COMPOUND_LEVEL ), + darkModeConfig + ); + + const highContrastModeCSSVariables = transformValuesToVariablesString( + repeat( HIGH_CONTRAST_MODE_MODE_ATTR, MODE_SPECIFICITY_COMPOUND_LEVEL ), + highContrastModeConfig + ); + + const darkHighContrastModeCSSVariables = transformValuesToVariablesString( + repeat( + DARK_HIGH_CONTRAST_MODE_MODE_ATTR, + MODE_SPECIFICITY_COMPOUND_LEVEL + ), + darkHighContrastModeConfig + ); + + return { + theme, + globalVariables, + globalCSSVariables, + darkModeCSSVariables, + highContrastModeCSSVariables, + darkHighContrastModeCSSVariables, + }; +} diff --git a/packages/components/src/ui/create-styles/create-style-system/index.js b/packages/components/src/ui/create-styles/create-style-system/index.js new file mode 100644 index 00000000000000..e874b6bcaa16df --- /dev/null +++ b/packages/components/src/ui/create-styles/create-style-system/index.js @@ -0,0 +1,7 @@ +export * from './constants'; +export * from './utils'; + +export * from './create-style-system'; +export * from './tags'; + +export * from './polymorphic-component'; diff --git a/packages/components/src/ui/create-styles/create-style-system/polymorphic-component.ts b/packages/components/src/ui/create-styles/create-style-system/polymorphic-component.ts new file mode 100644 index 00000000000000..2511de54a9189d --- /dev/null +++ b/packages/components/src/ui/create-styles/create-style-system/polymorphic-component.ts @@ -0,0 +1,62 @@ +/** + * External dependencies + */ +// eslint-disable-next-line no-restricted-imports +import type * as React from 'react'; +import type { As, RenderProp, ExtractHTMLAttributes } from 'reakit-utils/types'; +import type { Interpolation, ObjectInterpolation } from 'create-emotion'; + +/** + * Based on https://github.com/reakit/reakit/blob/master/packages/reakit-utils/src/types.ts + */ +export type ViewOwnProps< P, T extends As > = P & + Omit< React.ComponentPropsWithRef< T >, 'as' | 'css' | keyof P > & { + as?: T | keyof JSX.IntrinsicElements; + children?: React.ReactNode | RenderProp< ExtractHTMLAttributes< any > >; + css?: ObjectInterpolation< undefined > | string; + }; + +export type ElementTypeFromViewOwnProps< P > = P extends ViewOwnProps< + unknown, + infer T +> + ? T + : never; + +export type PropsFromViewOwnProps< P > = P extends ViewOwnProps< infer PP, any > + ? PP + : never; + +export type PolymorphicComponent< T extends As, O > = { + < TT extends As >( + props: ViewOwnProps< O, TT > & { as: TT } + ): JSX.Element | null; + ( props: ViewOwnProps< O, T > ): JSX.Element | null; + displayName?: string; + __interpolationClassName__: string; +}; + +export type CreatePolymorphicComponent< T extends As, P > = ( + template: TemplateStringsArray, + ...styles: ( + | Interpolation< undefined > + | PolymorphicComponent< any, any > + )[] +) => PolymorphicComponent< T, P >; + +export type ForwardedRef< TElement extends HTMLElement > = + | ( ( instance: TElement | null ) => void ) + | React.MutableRefObject< TElement | null > + | null; + +export type CoreElements = { + [ P in keyof JSX.IntrinsicElements ]: PolymorphicComponent< P, {} >; +}; + +type CreateStyledComponents = { + [ P in keyof JSX.IntrinsicElements ]: CreatePolymorphicComponent< P, {} >; +}; + +export type CreateStyled = CreateStyledComponents & { + < T extends As >( component: T ): CreatePolymorphicComponent< T, {} >; +}; diff --git a/packages/components/src/ui/create-styles/create-style-system/tags.js b/packages/components/src/ui/create-styles/create-style-system/tags.js new file mode 100644 index 00000000000000..1fe5adbafab223 --- /dev/null +++ b/packages/components/src/ui/create-styles/create-style-system/tags.js @@ -0,0 +1,141 @@ +/** + * A collection of React HTMLElements. + */ +/** @type {(keyof JSX.IntrinsicElements)[]} */ +export const tags = [ + 'a', + 'abbr', + 'address', + 'area', + 'article', + 'aside', + 'audio', + 'b', + 'base', + 'bdi', + 'bdo', + 'big', + 'blockquote', + 'body', + 'br', + 'button', + 'canvas', + 'caption', + 'cite', + 'code', + 'col', + 'colgroup', + 'data', + 'datalist', + 'dd', + 'del', + 'details', + 'dfn', + 'dialog', + 'div', + 'dl', + 'dt', + 'em', + 'embed', + 'fieldset', + 'figcaption', + 'figure', + 'footer', + 'form', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'head', + 'header', + 'hgroup', + 'hr', + 'html', + 'i', + 'iframe', + 'img', + 'input', + 'ins', + 'kbd', + 'keygen', + 'label', + 'legend', + 'li', + 'link', + 'main', + 'map', + 'mark', + 'menu', + 'menuitem', + 'meta', + 'meter', + 'nav', + 'noscript', + 'object', + 'ol', + 'optgroup', + 'option', + 'output', + 'p', + 'param', + 'picture', + 'pre', + 'progress', + 'q', + 'rp', + 'rt', + 'ruby', + 's', + 'samp', + 'script', + 'section', + 'select', + 'small', + 'source', + 'span', + 'strong', + 'style', + 'sub', + 'summary', + 'sup', + 'table', + 'tbody', + 'td', + 'textarea', + 'tfoot', + 'th', + 'thead', + 'time', + 'title', + 'tr', + 'track', + 'u', + 'ul', + 'var', + 'video', + 'wbr', + + // SVG + 'circle', + 'clipPath', + 'defs', + 'ellipse', + 'foreignObject', + 'g', + 'image', + 'line', + 'linearGradient', + 'mask', + 'path', + 'pattern', + 'polygon', + 'polyline', + 'radialGradient', + 'rect', + 'stop', + 'svg', + 'text', + 'tspan', +]; diff --git a/packages/components/src/ui/create-styles/create-style-system/test/create-style-system.js b/packages/components/src/ui/create-styles/create-style-system/test/create-style-system.js new file mode 100644 index 00000000000000..85b817cdf19707 --- /dev/null +++ b/packages/components/src/ui/create-styles/create-style-system/test/create-style-system.js @@ -0,0 +1,89 @@ +/** + * External dependencies + */ +import { render } from '@testing-library/react'; + +/** + * Internal dependencies + */ +import { createStyleSystem } from '../index'; + +describe( 'createStyleSystem', () => { + let compiler; + + const testCreateStyleSystem = ( ...args ) => { + const styleSystem = createStyleSystem( ...args ); + compiler = styleSystem.compiler; + return styleSystem; + }; + + afterAll( () => { + if ( compiler?.flush ) { + compiler.flush(); + } + } ); + + test( 'should include a styled element, View, and styled component that renders', () => { + const { View, core, styled } = testCreateStyleSystem(); + + const Box = styled.p` + padding: 10px; + `; + const { container } = render( + <> + + + + + ); + + expect( container.querySelector( 'input' ) ).toHaveStyle( { + boxSizing: 'border-box', + } ); + expect( container.querySelector( 'span' ) ).toHaveStyle( { + boxSizing: 'border-box', + } ); + expect( container.querySelector( 'p' ) ).toHaveStyle( { + boxSizing: 'border-box', + padding: '10px', + } ); + } ); + + test( 'should render custom baseStyles', () => { + const { View } = testCreateStyleSystem( { + baseStyles: { + background: 'blue', + }, + } ); + + const { container } = render( ); + + expect( container.querySelector( 'div' ) ).toHaveStyle( { + boxSizing: 'border-box', + background: 'blue', + } ); + } ); + + test( 'should support multiple nested style system instances', () => { + const { View } = testCreateStyleSystem(); + const { View: AnotherView } = testCreateStyleSystem( { + baseStyles: { + padding: '2em', + }, + } ); + + const { container } = render( + + + + ); + + expect( container.querySelector( 'div' ) ).toHaveStyle( { + boxSizing: 'border-box', + } ); + expect( container.querySelector( 'span' ) ).toHaveStyle( { + boxSizing: 'border-box', + padding: '2em', + } ); + } ); +} ); diff --git a/packages/components/src/ui/create-styles/create-style-system/types.d.ts b/packages/components/src/ui/create-styles/create-style-system/types.d.ts new file mode 100644 index 00000000000000..1a94ff4bb72fcd --- /dev/null +++ b/packages/components/src/ui/create-styles/create-style-system/types.d.ts @@ -0,0 +1 @@ +declare module '@wordpress/compose'; diff --git a/packages/components/src/ui/create-styles/create-style-system/utils.js b/packages/components/src/ui/create-styles/create-style-system/utils.js new file mode 100644 index 00000000000000..e8b0ca7e063137 --- /dev/null +++ b/packages/components/src/ui/create-styles/create-style-system/utils.js @@ -0,0 +1,186 @@ +/** + * External dependencies + */ +import hash from '@emotion/hash'; +import { kebabCase } from 'lodash'; + +/** + * Internal dependencies + */ +import { INTERPOLATION_CLASS_NAME, NAMESPACE } from './constants'; + +/** + * @type {{ + baseStyles: any; + config: any; + darkModeConfig: any; + highContrastModeConfig: any; + darkHighContrastModeConfig: any; + compilerOptions: any; + }} + */ +export const DEFAULT_STYLE_SYSTEM_OPTIONS = { + baseStyles: {}, + config: {}, + darkModeConfig: {}, + highContrastModeConfig: {}, + darkHighContrastModeConfig: {}, + compilerOptions: undefined, +}; + +/** + * Creates the (CSS Variable) design token used by the Style system. + * + * @param {string} key The variable (key). + * @return {string} The token (CSS variable). + */ +export function createToken( key ) { + return `${ NAMESPACE }-${ kebabCase( key ) }`; +} + +/** + * The primary mechanism to retrieve Style system configs values - values that + * have been transformed into CSS variables with a dedicated namespace. + * + * @example + * ```js + * get('colorAdmin'); // var(--wp-color-admin, 'blue'); + * ``` + * @template {Record} TConfig + * @template {Record} TDarkConfig + * @template {Record} THCConfig + * @template {Record} TDarkHCConfig + * @template {string} TGeneratedTokens + * @param {keyof (TConfig & TDarkConfig & THCConfig & TDarkHCConfig) | TGeneratedTokens} key The config variable to retrieve. + * @return {string} The compiled CSS variable associated with the config key. + */ +export function get( key ) { + return `var(${ createToken( key.toString() ) })`; +} + +/** @typedef {Record} StyleConfigValues */ +/** @typedef {Record} StyleConfig */ + +/** + * Transforms a series of config values into set of namespaced CSS + * references for the Style system. + * + * @param {StyleConfigValues} values Style config values to transform into CSS variables. + * @return {StyleConfig} The set of CSS variables, transformed from config values. + */ +export function transformValuesToReferences( values = {} ) { + /** @type {StyleConfig} */ + const next = {}; + for ( const [ key, value ] of Object.entries( values ) ) { + const ref = `var(${ createToken( key ) }, ${ value })`; + next[ key ] = ref; + } + return next; +} + +/** + * Transforms a series of config values into set of namespaced CSS + * variables for the Style system. These values can then be safely and predictable + * retrieved using the get() function. + * + * @param {StyleConfigValues} values Style config values to transform into CSS variables. + * @return {StyleConfig} The set of CSS variables, transformed from config values. + */ +export function transformValuesToVariables( values = {} ) { + /** @type {StyleConfig} */ + const next = {}; + + for ( const [ key, value ] of Object.entries( values ) ) { + const ref = value; + next[ `${ createToken( key ) }` ] = ref?.toString(); + } + + return next; +} + +/** + * Transforms a series of config values into set of namespaced CSS + * references for the Style system. These values are then transformed into + * a CSS style value (`string`) that can be injected into the DOM, within a + *