diff --git a/.eslintrc.js b/.eslintrc.js index 9240b96c033b48..177f3cf35b8ccf 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -83,6 +83,72 @@ const restrictedImports = [ }, ]; +const restrictedSyntax = [ + // NOTE: We can't include the forward slash in our regex or + // we'll get a `SyntaxError` (Invalid regular expression: \ at end of pattern) + // here. That's why we use \\u002F in the regexes below. + { + selector: + 'ImportDeclaration[source.value=/^@wordpress\\u002F.+\\u002F/]', + message: 'Path access on WordPress dependencies is not allowed.', + }, + { + selector: + 'CallExpression[callee.name="deprecated"] Property[key.name="version"][value.value=/' + + majorMinorRegExp + + '/]', + message: + 'Deprecated functions must be removed before releasing this version.', + }, + { + selector: + 'CallExpression[callee.object.name="page"][callee.property.name="waitFor"]', + message: + 'This method is deprecated. You should use the more explicit API methods available.', + }, + { + selector: + 'CallExpression[callee.object.name="page"][callee.property.name="waitForTimeout"]', + message: 'Prefer page.waitForSelector instead.', + }, + { + selector: 'JSXAttribute[name.name="id"][value.type="Literal"]', + message: + 'Do not use string literals for IDs; use withInstanceId instead.', + }, + { + // Discourage the usage of `Math.random()` as it's a code smell + // for UUID generation, for which we already have a higher-order + // component: `withInstanceId`. + selector: + 'CallExpression[callee.object.name="Math"][callee.property.name="random"]', + message: + 'Do not use Math.random() to generate unique IDs; use withInstanceId instead. (If you’re not generating unique IDs: ignore this message.)', + }, + { + selector: + 'CallExpression[callee.name="withDispatch"] > :function > BlockStatement > :not(VariableDeclaration,ReturnStatement)', + message: + 'withDispatch must return an object with consistent keys. Avoid performing logic in `mapDispatchToProps`.', + }, + { + selector: + 'LogicalExpression[operator="&&"][left.property.name="length"][right.type="JSXElement"]', + message: + 'Avoid truthy checks on length property rendering, as zero length is rendered verbatim.', + }, +]; + +/** `no-restricted-syntax` rules for components. */ +const restrictedSyntaxComponents = [ + { + selector: + 'JSXOpeningElement[name.name="Button"]:not(:has(JSXAttribute[name.name="__experimentalIsFocusable"])) JSXAttribute[name.name="disabled"]', + message: + '`disabled` used without the `__experimentalIsFocusable` prop. Disabling a control without maintaining focusability can cause accessibility issues, by hiding their presence from screen reader users, or preventing focus from returning to a trigger element. (Ignore this error if you truly mean to disable.)', + }, +]; + module.exports = { root: true, extends: [ @@ -147,63 +213,7 @@ module.exports = { disallowTypeAnnotations: false, }, ], - 'no-restricted-syntax': [ - 'error', - // NOTE: We can't include the forward slash in our regex or - // we'll get a `SyntaxError` (Invalid regular expression: \ at end of pattern) - // here. That's why we use \\u002F in the regexes below. - { - selector: - 'ImportDeclaration[source.value=/^@wordpress\\u002F.+\\u002F/]', - message: - 'Path access on WordPress dependencies is not allowed.', - }, - { - selector: - 'CallExpression[callee.name="deprecated"] Property[key.name="version"][value.value=/' + - majorMinorRegExp + - '/]', - message: - 'Deprecated functions must be removed before releasing this version.', - }, - { - selector: - 'CallExpression[callee.object.name="page"][callee.property.name="waitFor"]', - message: - 'This method is deprecated. You should use the more explicit API methods available.', - }, - { - selector: - 'CallExpression[callee.object.name="page"][callee.property.name="waitForTimeout"]', - message: 'Prefer page.waitForSelector instead.', - }, - { - selector: 'JSXAttribute[name.name="id"][value.type="Literal"]', - message: - 'Do not use string literals for IDs; use withInstanceId instead.', - }, - { - // Discourage the usage of `Math.random()` as it's a code smell - // for UUID generation, for which we already have a higher-order - // component: `withInstanceId`. - selector: - 'CallExpression[callee.object.name="Math"][callee.property.name="random"]', - message: - 'Do not use Math.random() to generate unique IDs; use withInstanceId instead. (If you’re not generating unique IDs: ignore this message.)', - }, - { - selector: - 'CallExpression[callee.name="withDispatch"] > :function > BlockStatement > :not(VariableDeclaration,ReturnStatement)', - message: - 'withDispatch must return an object with consistent keys. Avoid performing logic in `mapDispatchToProps`.', - }, - { - selector: - 'LogicalExpression[operator="&&"][left.property.name="length"][right.type="JSXElement"]', - message: - 'Avoid truthy checks on length property rendering, as zero length is rendered verbatim.', - }, - ], + 'no-restricted-syntax': [ 'error', ...restrictedSyntax ], }, overrides: [ { @@ -253,6 +263,20 @@ module.exports = { ], }, }, + { + files: [ + 'packages/*/src/**/*.[tj]s?(x)', + 'storybook/stories/**/*.[tj]s?(x)', + ], + excludedFiles: [ '**/*.native.js' ], + rules: { + 'no-restricted-syntax': [ + 'error', + ...restrictedSyntax, + ...restrictedSyntaxComponents, + ], + }, + }, { files: [ // Components package. @@ -372,6 +396,7 @@ module.exports = { rules: { 'no-restricted-syntax': [ 'error', + ...restrictedSyntax, { selector: ':matches(Literal[value=/--wp-admin-theme-/],TemplateElement[value.cooked=/--wp-admin-theme-/])', diff --git a/.github/workflows/create-block.yml b/.github/workflows/create-block.yml index ff1f1eb980347b..2a7ea040f8b493 100644 --- a/.github/workflows/create-block.yml +++ b/.github/workflows/create-block.yml @@ -20,7 +20,7 @@ jobs: strategy: fail-fast: false matrix: - node: ['20', '21'] + node: ['20', '22'] os: ['macos-latest', 'ubuntu-latest', 'windows-latest'] steps: diff --git a/.github/workflows/php-changes-detection.yml b/.github/workflows/php-changes-detection.yml index 2642485bce1ce2..2eeaea561eb7ed 100644 --- a/.github/workflows/php-changes-detection.yml +++ b/.github/workflows/php-changes-detection.yml @@ -17,7 +17,7 @@ jobs: - name: Get changed PHP files id: changed-files-php - uses: tj-actions/changed-files@03334d095e2739fa9ac4034ec16f66d5d01e9eba # v44.5.1 + uses: tj-actions/changed-files@d6babd6899969df1a11d14c368283ea4436bca78 # v44.5.2 with: files: | lib/** diff --git a/.github/workflows/rnmobile-ios-runner.yml b/.github/workflows/rnmobile-ios-runner.yml index 9640243e86629c..83228bd87b85ca 100644 --- a/.github/workflows/rnmobile-ios-runner.yml +++ b/.github/workflows/rnmobile-ios-runner.yml @@ -27,7 +27,7 @@ jobs: with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} - - uses: ruby/setup-ruby@943103cae7d3f1bb1e4951d5fcc7928b40e4b742 # v1.177.1 + - uses: ruby/setup-ruby@d5fb7a202fc07872cb44f00ba8e6197b70cb0c55 # v1.179.0 with: # `.ruby-version` file location working-directory: packages/react-native-editor/ios diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index dd50ea68e0e5d5..a813e4d2d8f5ba 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -27,7 +27,7 @@ jobs: strategy: fail-fast: false matrix: - node: ['20', '21'] + node: ['20', '22'] shard: ['1/4', '2/4', '3/4', '4/4'] steps: @@ -66,7 +66,7 @@ jobs: strategy: fail-fast: false matrix: - node: ['20', '21'] + node: ['20', '22'] steps: - name: Checkout repository @@ -185,7 +185,7 @@ jobs: # dependency versions are installed and cached. ## - name: Set up PHP - uses: shivammathur/setup-php@c665c7a15b5295c2488ac8a87af9cb806cd72198 # v2.30.4 + uses: shivammathur/setup-php@fc14643b0a99ee9db10a3c025a33d76544fa3761 # v2.30.5 with: php-version: '${{ matrix.php }}' ini-file: development @@ -286,7 +286,7 @@ jobs: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} - name: Set up PHP - uses: shivammathur/setup-php@c665c7a15b5295c2488ac8a87af9cb806cd72198 # v2.30.4 + uses: shivammathur/setup-php@fc14643b0a99ee9db10a3c025a33d76544fa3761 # v2.30.5 with: php-version: '7.4' coverage: none diff --git a/backport-changelog/6.6/6590.md b/backport-changelog/6.6/6590.md new file mode 100644 index 00000000000000..47ef89e0db40cb --- /dev/null +++ b/backport-changelog/6.6/6590.md @@ -0,0 +1,5 @@ +https://github.com/WordPress/wordpress-develop/pull/6590 + +* https://github.com/WordPress/gutenberg/pull/59531 +* https://github.com/WordPress/gutenberg/pull/61182 +* https://github.com/WordPress/gutenberg/pull/61717 diff --git a/backport-changelog/6.6/6616.md b/backport-changelog/6.6/6616.md index 91261f78fb5c7a..bb35d6c74493cf 100644 --- a/backport-changelog/6.6/6616.md +++ b/backport-changelog/6.6/6616.md @@ -2,4 +2,6 @@ https://github.com/WordPress/wordpress-develop/pull/6616 * https://github.com/WordPress/gutenberg/pull/58409 * https://github.com/WordPress/gutenberg/pull/61328 -* https://github.com/WordPress/gutenberg/pull/61842 \ No newline at end of file +* https://github.com/WordPress/gutenberg/pull/61842 +* https://github.com/WordPress/gutenberg/pull/62199 +* https://github.com/WordPress/gutenberg/pull/62252 diff --git a/backport-changelog/6.6/6694.md b/backport-changelog/6.6/6694.md new file mode 100644 index 00000000000000..a9eb5a7f37ef5b --- /dev/null +++ b/backport-changelog/6.6/6694.md @@ -0,0 +1,3 @@ +https://github.com/WordPress/wordpress-develop/pull/6694 + +* https://github.com/WordPress/gutenberg/pull/60694 diff --git a/backport-changelog/6.6/6731.md b/backport-changelog/6.6/6731.md new file mode 100644 index 00000000000000..b8671873251659 --- /dev/null +++ b/backport-changelog/6.6/6731.md @@ -0,0 +1,3 @@ +https://github.com/WordPress/wordpress-develop/pull/6731 + +* https://github.com/WordPress/gutenberg/pull/62299 diff --git a/backport-changelog/6.6/6737.md b/backport-changelog/6.6/6737.md new file mode 100644 index 00000000000000..84e2234ca4e79a --- /dev/null +++ b/backport-changelog/6.6/6737.md @@ -0,0 +1,3 @@ +https://github.com/WordPress/wordpress-develop/pull/6737 + +* https://github.com/WordPress/gutenberg/pull/62305 diff --git a/backport-changelog/6.6/6744.md b/backport-changelog/6.6/6744.md new file mode 100644 index 00000000000000..032f5420cb7184 --- /dev/null +++ b/backport-changelog/6.6/6744.md @@ -0,0 +1,3 @@ +https://github.com/WordPress/wordpress-develop/pull/6744 + +* https://github.com/WordPress/gutenberg/pull/62355 \ No newline at end of file diff --git a/changelog.txt b/changelog.txt index 5791fb711c2c43..decdb88ea9a7a4 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,477 @@ == Changelog == += 18.5.0 = + +## Changelog + +### Features + +#### Global Styles +- Add defaultSpacingSizes option (theme.json v3). ([61842](https://github.com/WordPress/gutenberg/pull/61842)) +- Edit/create shadows in global styles. ([60706](https://github.com/WordPress/gutenberg/pull/60706)) +- Relocate Background Image controls to sit under Layout. ([61886](https://github.com/WordPress/gutenberg/pull/61886)) + +#### Block Library +- Enable shadow support for cover block. ([61883](https://github.com/WordPress/gutenberg/pull/61883)) + +#### Block bindings +- Allow editing in post meta source. ([61753](https://github.com/WordPress/gutenberg/pull/61753)) + +#### Script Modules API +- Add script module data implementation. ([61658](https://github.com/WordPress/gutenberg/pull/61658)) + +#### Synced Patterns +- Add `__default` binding for pattern overrides. ([60694](https://github.com/WordPress/gutenberg/pull/60694)) + +#### Block Styles +- Extend block style variations as mechanism for achieving section styling. ([57908](https://github.com/WordPress/gutenberg/pull/57908)) + + +### Enhancements + +- Block card: Fix typographic widow. ([61438](https://github.com/WordPress/gutenberg/pull/61438)) +- Block settings: Update variant of "Apply globally" Button component to secondary. ([61850](https://github.com/WordPress/gutenberg/pull/61850)) +- Editor: Align the Post Format control design with the rest of the post sidebar controls. ([62066](https://github.com/WordPress/gutenberg/pull/62066)) +- Editor: Polish the style of some of the post summary rows. ([61645](https://github.com/WordPress/gutenberg/pull/61645)) +- Format Library: Refactor 'Inline Image' edit component. ([62135](https://github.com/WordPress/gutenberg/pull/62135)) +- Playwright end-to-end Utils: Add fullscreenMode option to createNewPost. ([61766](https://github.com/WordPress/gutenberg/pull/61766)) +- Post Sticky Toggle: Improve the design. ([62012](https://github.com/WordPress/gutenberg/pull/62012)) +- Post Summary: Move PostTemplatePanel below URL and Author. ([62137](https://github.com/WordPress/gutenberg/pull/62137)) +- Remove trash button in post/page inspector. ([61792](https://github.com/WordPress/gutenberg/pull/61792)) +- Shadows instead of borders on interface skeleton. ([61835](https://github.com/WordPress/gutenberg/pull/61835)) +- Tweak contextual block toolbar position. ([61836](https://github.com/WordPress/gutenberg/pull/61836)) +- Update: For synced entities the icon should be purple. ([62024](https://github.com/WordPress/gutenberg/pull/62024)) +- Update: Implement new author panel design. ([61362](https://github.com/WordPress/gutenberg/pull/61362)) +- Update: Implement new parent and order design. ([61918](https://github.com/WordPress/gutenberg/pull/61918)) +- Update: Move duplicate pattern and template part actions to the editor package. ([61879](https://github.com/WordPress/gutenberg/pull/61879)) + +#### Site Editor +- Block Editor: Check for multiple block usage in the block-editor package. ([62086](https://github.com/WordPress/gutenberg/pull/62086)) +- Copy custom CSS between variations when switching. ([61752](https://github.com/WordPress/gutenberg/pull/61752)) +- Data views: Align page headers. ([62115](https://github.com/WordPress/gutenberg/pull/62115)) +- Inspector summary rows: Make tooltips appear middle-left. ([61815](https://github.com/WordPress/gutenberg/pull/61815)) +- Inspector: Add '/' prefix to Link button. ([62073](https://github.com/WordPress/gutenberg/pull/62073)) +- Inspector: Display home / posts page badge. ([62071](https://github.com/WordPress/gutenberg/pull/62071)) +- Inspector: Remove revisions panel. ([61867](https://github.com/WordPress/gutenberg/pull/61867)) +- Make post meta row button treatment consistent. ([61954](https://github.com/WordPress/gutenberg/pull/61954)) +- Remove 'Manage...' prefix in Pages / Templates data views. ([62107](https://github.com/WordPress/gutenberg/pull/62107)) +- Remove the details pages. ([61741](https://github.com/WordPress/gutenberg/pull/61741)) +- Update actions order in site editor for template and template parts. ([61803](https://github.com/WordPress/gutenberg/pull/61803)) +- Use site title as a link. ([61258](https://github.com/WordPress/gutenberg/pull/61258)) +- [Site Editor]: Add create pattern button in patterns page. ([60302](https://github.com/WordPress/gutenberg/pull/60302)) +- withRegistryProvider: Prevent intermediate state with no children. ([61859](https://github.com/WordPress/gutenberg/pull/61859)) + +#### Data Views +- Add badge to title for posts & front pages. ([61718](https://github.com/WordPress/gutenberg/pull/61718)) +- Clarify `date` value in Pages. ([61709](https://github.com/WordPress/gutenberg/pull/61709)) +- DataViews: `label` prop in Actions API can be either a `string` or a `function`. ([61942](https://github.com/WordPress/gutenberg/pull/61942)) +- Fix pagination position on pages with short lists. ([61712](https://github.com/WordPress/gutenberg/pull/61712)) +- Pages data view: Add Pending and Private views. ([62138](https://github.com/WordPress/gutenberg/pull/62138)) +- Pages sidebar: Adds published & scheduled items. ([62021](https://github.com/WordPress/gutenberg/pull/62021)) +- Stop Patterns data view header shrinking. ([61801](https://github.com/WordPress/gutenberg/pull/61801)) +- Update grid layout on small screens. ([61820](https://github.com/WordPress/gutenberg/pull/61820)) +- Update list layout action styling. ([61797](https://github.com/WordPress/gutenberg/pull/61797)) +- Update page component (and some data view elements) spacing metrics. ([61333](https://github.com/WordPress/gutenberg/pull/61333)) +- Visually hide 'Actions' column header. ([61710](https://github.com/WordPress/gutenberg/pull/61710)) + +#### Global Styles +- Add block-level Text Alignment UI. ([61717](https://github.com/WordPress/gutenberg/pull/61717)) +- Add option to remove site-wide theme background image. ([61998](https://github.com/WordPress/gutenberg/pull/61998)) +- Background image: Add support for relative theme path URLs in top-level theme.json styles. ([61271](https://github.com/WordPress/gutenberg/pull/61271)) +- Background image: Update controls defaults and layout. ([62000](https://github.com/WordPress/gutenberg/pull/62000)) +- Background images: Add defaults for background size. ([62046](https://github.com/WordPress/gutenberg/pull/62046)) +- Don't filter out typography variations where the heading and body fonts are the same. ([61327](https://github.com/WordPress/gutenberg/pull/61327)) +- Make color variations fit in a bit better visually. ([61617](https://github.com/WordPress/gutenberg/pull/61617)) +- Make it clearer how to edit a site's palette. ([61364](https://github.com/WordPress/gutenberg/pull/61364)) +- Move type presets below elements. ([61863](https://github.com/WordPress/gutenberg/pull/61863)) +- Restore the default variation to the color and typography style tiles. ([61901](https://github.com/WordPress/gutenberg/pull/61901)) +- Show shadow tool by default under global styles. ([61981](https://github.com/WordPress/gutenberg/pull/61981)) + +#### Components +- Add vw and vh units to the custom font size picker. ([60607](https://github.com/WordPress/gutenberg/pull/60607)) +- CustomSelectControlV2: Use `InputBase` for styling. ([60261](https://github.com/WordPress/gutenberg/pull/60261)) +- Tabs: Indicator animation. ([60560](https://github.com/WordPress/gutenberg/pull/60560)) +- Try: Add CSS Custom Properties to CSS types. ([61872](https://github.com/WordPress/gutenberg/pull/61872)) + +#### Zoom Out +- Hide inserters behind the experiment flag. ([61866](https://github.com/WordPress/gutenberg/pull/61866)) +- Inserter: Auto-close the inserter unless the zoom out experiment is on. ([61856](https://github.com/WordPress/gutenberg/pull/61856)) +- Show the inserters only when a section is selected. ([61559](https://github.com/WordPress/gutenberg/pull/61559)) +- The patterns tab behind a new experiment. ([61601](https://github.com/WordPress/gutenberg/pull/61601)) + +#### Block Editor +- Adjust pattern list items resting, hover, focus styles. ([61831](https://github.com/WordPress/gutenberg/pull/61831)) +- Tweak pattern categories sidebar. ([62113](https://github.com/WordPress/gutenberg/pull/62113)) +- Writing flow: Remove first empty paragraph on Backspace. ([61889](https://github.com/WordPress/gutenberg/pull/61889)) + +#### Block bindings +- Add Block Bindings Panel to Block Inspector. ([61527](https://github.com/WordPress/gutenberg/pull/61527)) +- Add indicator for metadata changes to Save Panel when reviewing modified entities. ([61811](https://github.com/WordPress/gutenberg/pull/61811)) +- Lock binding editing with functions. ([61734](https://github.com/WordPress/gutenberg/pull/61734)) + +#### Block Variations +- Detect active variation correctly based on RichText attribute. ([62325](https://github.com/WordPress/gutenberg/pull/62325)) +- Have `getActiveBlockVariation` return variation with highest specificity. ([62031](https://github.com/WordPress/gutenberg/pull/62031)) +- Support dot notation in `isActive` string array. ([62088](https://github.com/WordPress/gutenberg/pull/62088)) + +#### Layout +- More consistent root padding. ([60715](https://github.com/WordPress/gutenberg/pull/60715)) +- Try using coloured overlay instead of border for grid visualiser. ([61390](https://github.com/WordPress/gutenberg/pull/61390)) + +#### Block Library +- Added Bluesky icon to the Social Icon Block. ([61372](https://github.com/WordPress/gutenberg/pull/61372)) +- Media & Text: Replace the deprecated __experimentalImageSizeControl with ResolutionTool. ([57540](https://github.com/WordPress/gutenberg/pull/57540)) + +#### Inspector Controls +- Align both "Design" pattern list panels. ([62161](https://github.com/WordPress/gutenberg/pull/62161)) + +#### Post Editor +- Add home template details to inspector controls. ([61762](https://github.com/WordPress/gutenberg/pull/61762)) + +#### Interactivity API +- Clarify some warning messages. ([61720](https://github.com/WordPress/gutenberg/pull/61720)) + +#### Patterns +- Adjust the icons and text of the binding connected blocks. ([61560](https://github.com/WordPress/gutenberg/pull/61560)) + + +### Bug Fixes + +- Editor: Only render the site logo once if there's a fill. ([62320](https://github.com/WordPress/gutenberg/pull/62320)) +- Interactivity API: Increase directive `wp-each-child` priority. ([62293](https://github.com/WordPress/gutenberg/pull/62293))w +- Compose: Fix 'useFocusOnMount' cleanup callback. ([62053](https://github.com/WordPress/gutenberg/pull/62053)) +- Do not auto save post status changes. ([62171](https://github.com/WordPress/gutenberg/pull/62171)) +- Editor: Fix canvas padding in post editor. ([61893](https://github.com/WordPress/gutenberg/pull/61893)) +- EntityProvider: Avoid remounts and simplify. ([61882](https://github.com/WordPress/gutenberg/pull/61882)) +- Fix shadow and border for pattern categories panel. ([62158](https://github.com/WordPress/gutenberg/pull/62158)) +- Image Block: Conditionally Render Block Control Based on Component Presence. ([62132](https://github.com/WordPress/gutenberg/pull/62132)) +- Interactivity API: Fix null and number strings as namespaces runtime error. ([61960](https://github.com/WordPress/gutenberg/pull/61960)) +- PostCardPanel: Fix ESLint error. ([62109](https://github.com/WordPress/gutenberg/pull/62109)) +- Remove build-types/ clean from clean:Packages. ([62008](https://github.com/WordPress/gutenberg/pull/62008)) +- Script Modules: Fix private method reflection access. ([62154](https://github.com/WordPress/gutenberg/pull/62154)) +- ServerSideRender: Fix data loading in development mode. ([62140](https://github.com/WordPress/gutenberg/pull/62140)) +- Shadow Panel: Make subtitle translatable. ([62022](https://github.com/WordPress/gutenberg/pull/62022)) +- Site Editor: Fix the Root Padding styles. ([61906](https://github.com/WordPress/gutenberg/pull/61906)) +- Writing flow: Fix heading crash on split (via paste). ([61900](https://github.com/WordPress/gutenberg/pull/61900)) +- e2e: Fix Site Editor Styles test. ([62111](https://github.com/WordPress/gutenberg/pull/62111)) + +#### Post Editor +- Consolidate and fix `delete` and `edit` post actions. ([61912](https://github.com/WordPress/gutenberg/pull/61912)) +- Consolidate and fix `rename` post action. ([61857](https://github.com/WordPress/gutenberg/pull/61857)) +- Document Bar: Decode HTML entities and take into account cases where there is no title. ([62087](https://github.com/WordPress/gutenberg/pull/62087)) +- Editor: Don't apply purple accent to the unsynced pattern title. ([61704](https://github.com/WordPress/gutenberg/pull/61704)) +- Editor: Ensure Copy button in sidebar copies whole permalink, *with* URL protocol. ([61876](https://github.com/WordPress/gutenberg/pull/61876)) +- Editor: Fix the 'DocumentBar' position for long titles. ([61691](https://github.com/WordPress/gutenberg/pull/61691)) +- Editor: Render publish date control when the status is `future`(scheduled). ([62070](https://github.com/WordPress/gutenberg/pull/62070)) +- Editor: Unify button size in pre-publish panel. ([62123](https://github.com/WordPress/gutenberg/pull/62123)) +- Editor: Use edited entity for post actions. ([61892](https://github.com/WordPress/gutenberg/pull/61892)) +- Fix read only post status styles. ([61722](https://github.com/WordPress/gutenberg/pull/61722)) +- Post Actions: Hide the trash action for auto-drafts. ([61865](https://github.com/WordPress/gutenberg/pull/61865)) + +#### Block Editor +- Inserter: Update Openverse API URLs. ([62241](https://github.com/WordPress/gutenberg/pull/62241)) +- Fix being unable to switch modes while inserter is open. ([61563](https://github.com/WordPress/gutenberg/pull/61563)) +- Fix editor inserter tabs indicator. ([61973](https://github.com/WordPress/gutenberg/pull/61973)) +- Fix positioning of close icons in panels to be consistent. ([61832](https://github.com/WordPress/gutenberg/pull/61832)) +- Fix syncing of publish date between publish and post status panel. ([62165](https://github.com/WordPress/gutenberg/pull/62165)) +- Improve link conrol preview when show button text label is enabled. ([61726](https://github.com/WordPress/gutenberg/pull/61726)) +- Inserter: Show all blocks (alternative). ([62169](https://github.com/WordPress/gutenberg/pull/62169)) +- InspectorControls: Text not displayed when "Show button text labels" is enabled. ([61949](https://github.com/WordPress/gutenberg/pull/61949)) +- Link Control: Fix focus handlers in development mode. ([62141](https://github.com/WordPress/gutenberg/pull/62141)) +- Media & Text block: Remove the link option when the featured image is used. ([60510](https://github.com/WordPress/gutenberg/pull/60510)) +- Writing flow: Fix paste for input fields. ([61389](https://github.com/WordPress/gutenberg/pull/61389)) + +#### Block Library +- Classic block: Fix content syncing effect for React StrictMode. ([62051](https://github.com/WordPress/gutenberg/pull/62051)) +- Don't steal focus when opening browse all blocks. ([61975](https://github.com/WordPress/gutenberg/pull/61975)) +- Fix: The latest post block - post titles overlapping. ([61356](https://github.com/WordPress/gutenberg/pull/61356)) +- Fixed : Update `alt text decision tree` links to be translatable. ([62076](https://github.com/WordPress/gutenberg/pull/62076)) +- Fixed: Custom HTML Block should display content in LTR layout for all languages. ([62083](https://github.com/WordPress/gutenberg/pull/62083)) +- More block: Fix React warning when adding custom text. ([61936](https://github.com/WordPress/gutenberg/pull/61936)) +- useUploadMediaFromBlobURL: Prevent duplicate uploads in StrictMode. ([62059](https://github.com/WordPress/gutenberg/pull/62059)) + +#### Global Styles +- Fix make dimensions.aspectRatios key of theme.json files translatable. ([61774](https://github.com/WordPress/gutenberg/pull/61774)) +- Hide the presets panel for when there are less or exactly one presets available. ([62074](https://github.com/WordPress/gutenberg/pull/62074)) +- Prevent Typography panel title from wrapping. ([62124](https://github.com/WordPress/gutenberg/pull/62124)) +- Shadow Panel: Generates unique shadow slugs by finding max suffix and incrementing it. ([61997](https://github.com/WordPress/gutenberg/pull/61997)) +- Styles: try wrapping with :Root to fix reset styles. ([61638](https://github.com/WordPress/gutenberg/pull/61638)) +- Transform Styles: Update selector so that styles work when custom fields panel is active. ([62121](https://github.com/WordPress/gutenberg/pull/62121)) + +#### Site Editor +- Align the template title to the center in the 'Add template' screen. ([62175](https://github.com/WordPress/gutenberg/pull/62175)) +- Close publish sidebar if not in `edit` mode. ([61707](https://github.com/WordPress/gutenberg/pull/61707)) +- Fix the site editor Admin Bar menu item. ([61851](https://github.com/WordPress/gutenberg/pull/61851)) +- Use a consistent snackbar position. ([61756](https://github.com/WordPress/gutenberg/pull/61756)) + +#### Components +- Fix: The focus styles for tabPanel. ([61317](https://github.com/WordPress/gutenberg/pull/61317)) +- InputControl: Fix z-index issue causing slider dots to appear in front of the Appearance dropdown. ([61937](https://github.com/WordPress/gutenberg/pull/61937)) +- getAutocompleterUI: Don't redefine ListBox component on every render. ([61877](https://github.com/WordPress/gutenberg/pull/61877)) + +#### Synced Patterns +- Block Bindings: Filter pattern overrides source in bindings panel. ([62015](https://github.com/WordPress/gutenberg/pull/62015)) +- Fix detaching patterns when a pattern has overrides, but there are no override values. ([62014](https://github.com/WordPress/gutenberg/pull/62014)) + +#### Block bindings +- Don't show non-existing and not supported attributes in block bindings panel. ([62183](https://github.com/WordPress/gutenberg/pull/62183)) + +#### Layout +- Remove extra bracket in the site editor root padding styles. ([62159](https://github.com/WordPress/gutenberg/pull/62159)) + +#### Block Styles +- Fix block style variation styles for blocks with complex selectors. ([62125](https://github.com/WordPress/gutenberg/pull/62125)) + +#### Code Editor +- Editor: Unify text/code editor between post and site editors. ([61934](https://github.com/WordPress/gutenberg/pull/61934)) + +#### Page Content Focus +- Remove lock icons from Content blocks inner blocks when editing a page in the site editor. ([61922](https://github.com/WordPress/gutenberg/pull/61922)) + +#### Patterns +- Templates: Only resolve patterns for REST API endpoints. ([61757](https://github.com/WordPress/gutenberg/pull/61757)) + +#### Interactivity API +- Turn named capturing groups back into numbered ones inside `toVdom`. ([61728](https://github.com/WordPress/gutenberg/pull/61728)) + +#### Block API +- Fix: Enable Text Align UI to be controlled correctly with theme.json. ([61182](https://github.com/WordPress/gutenberg/pull/61182)) + +#### REST API +- Return an empty object when no fallback templates are found (wp/v2/templates/lookup). ([60925](https://github.com/WordPress/gutenberg/pull/60925)) + + +### Accessibility + +#### Global Styles +- Shadow Panel: Improve a11y and fix browser console error. ([61980](https://github.com/WordPress/gutenberg/pull/61980)) + +#### Data Views +- Always show Actions table header. ([61847](https://github.com/WordPress/gutenberg/pull/61847)) + +#### Block Library +- Fix: Adds help props for description of Play Inline toggle. ([61310](https://github.com/WordPress/gutenberg/pull/61310)) + + +### Performance + +- Perf: Batch block list settings in single action. ([61329](https://github.com/WordPress/gutenberg/pull/61329)) +- Remove additional call to `WP_Theme_JSON_Gutenberg::__construct`. ([61262](https://github.com/WordPress/gutenberg/pull/61262)) + +#### Interactivity API +- Introduce `wp-on-async` directive as performant alternative over synchronous `wp-on` directive. ([61885](https://github.com/WordPress/gutenberg/pull/61885)) + +#### Post Editor +- DocumentBar: Only selected data needed for rendering. ([61706](https://github.com/WordPress/gutenberg/pull/61706)) + + +### Experiments + +#### Interactivity API +- Use output buffer and HTML tag processor to inject directives on BODY tag for full-page client-side navigation. ([61212](https://github.com/WordPress/gutenberg/pull/61212)) + + +### Documentation + +- Add JSDoc to PostVisibility, PostVisibilityCheck, and PostVisibilityLabel. ([61735](https://github.com/WordPress/gutenberg/pull/61735)) +- Add PostURL component documentation. ([61737](https://github.com/WordPress/gutenberg/pull/61737)) +- Add a section about block filters to the Filters and Hooks doc. ([61771](https://github.com/WordPress/gutenberg/pull/61771)) +- Add an example and improve readability of the Block Filters doc. ([61770](https://github.com/WordPress/gutenberg/pull/61770)) +- Add docblock to PostTitle and PostTitleRaw component. ([61740](https://github.com/WordPress/gutenberg/pull/61740)) +- Add documentation for DocumentBar. ([61733](https://github.com/WordPress/gutenberg/pull/61733)) +- Add documentation for PostFeaturedImage, PostFeaturedImageCheck, PostFeaturedImagePanel. ([61165](https://github.com/WordPress/gutenberg/pull/61165)) +- Add documentation for PostLastRevision, PostLastRevisionCheck, PostLastRevisionPanel components. ([61166](https://github.com/WordPress/gutenberg/pull/61166)) +- Add documentation for PostSchedule, PostScheduleCheck, PostSchedulePanel, PostScheduleLabel, usePostScheduleLabel components. ([61345](https://github.com/WordPress/gutenberg/pull/61345)) +- Add documentation for the EditorNotices component. ([61736](https://github.com/WordPress/gutenberg/pull/61736)) +- Add documentation for the EditorProvider and ExperimentalEditorProvider components. ([61739](https://github.com/WordPress/gutenberg/pull/61739)) +- Added missing @global documentation. ([61537](https://github.com/WordPress/gutenberg/pull/61537)) +- Changelog: Add note about removing legacy operators. ([62013](https://github.com/WordPress/gutenberg/pull/62013)) +- Docs: Fix spacing in PHP doc block in comments block. ([61911](https://github.com/WordPress/gutenberg/pull/61911)) +- EditorBoundary editor component. ([61950](https://github.com/WordPress/gutenberg/pull/61950)) +- Fix typo. ([61830](https://github.com/WordPress/gutenberg/pull/61830)) +- Fix: Block library README.md link. ([62081](https://github.com/WordPress/gutenberg/pull/62081)) +- Fix: Custom block editor link. ([61962](https://github.com/WordPress/gutenberg/pull/61962)) +- For `PostTextEditor` component. ([62099](https://github.com/WordPress/gutenberg/pull/62099)) +- LocalAutosaveMonitor editor component. ([61951](https://github.com/WordPress/gutenberg/pull/61951)) +- PageTemplate + PostTemplatePanel editor components. ([61961](https://github.com/WordPress/gutenberg/pull/61961)) +- PostComments editor component. ([61964](https://github.com/WordPress/gutenberg/pull/61964)) +- PostDiscussionPanel editor component. ([61966](https://github.com/WordPress/gutenberg/pull/61966)) +- PostExcerptPanel editor component. ([61967](https://github.com/WordPress/gutenberg/pull/61967)) +- PostLockedModal editor component. ([61968](https://github.com/WordPress/gutenberg/pull/61968)) +- PostPendingStatus + PostPendingStatusCheck editor components. ([61970](https://github.com/WordPress/gutenberg/pull/61970)) +- PostPingbacks editor component. ([62035](https://github.com/WordPress/gutenberg/pull/62035)) +- PostPreviewButton editor component. ([62036](https://github.com/WordPress/gutenberg/pull/62036)) +- Storybook: Add badges based on `tags`. ([61111](https://github.com/WordPress/gutenberg/pull/61111)) +- Update PostFormat, PostFormatCheck editor component documentation. ([61732](https://github.com/WordPress/gutenberg/pull/61732)) +- Update block.json file with correct links. ([61880](https://github.com/WordPress/gutenberg/pull/61880)) +- Update link to architecture key concepts. ([61965](https://github.com/WordPress/gutenberg/pull/61965)) +- Update links to correct lodash website. ([62188](https://github.com/WordPress/gutenberg/pull/62188)) +- Update plugin-document-setting-panel.md. ([61782](https://github.com/WordPress/gutenberg/pull/61782)) +- Update tutorial.md. ([62054](https://github.com/WordPress/gutenberg/pull/62054)) + + +### Code Quality + +- Add curly brace autofix commit to `.git-blame-ignore-revs`. ([62144](https://github.com/WordPress/gutenberg/pull/62144)) +- Add eslint rule for curly brace presence in JSX. ([62026](https://github.com/WordPress/gutenberg/pull/62026)) +- Blocks: Remove pipe usage and dependency on compose. ([62127](https://github.com/WordPress/gutenberg/pull/62127)) +- Clean up packages build-types when cleaning types. ([61939](https://github.com/WordPress/gutenberg/pull/61939)) +- Command Palette: Remove unused URL parameter. ([61783](https://github.com/WordPress/gutenberg/pull/61783)) +- Commands: Unify the editor context between post and site editors. ([61862](https://github.com/WordPress/gutenberg/pull/61862)) +- Dataviews: Remove unused dependencies. ([62010](https://github.com/WordPress/gutenberg/pull/62010)) +- Distraction Free: Unify the header animation. ([62167](https://github.com/WordPress/gutenberg/pull/62167)) +- Editor: Move editor toggle commands to the editor package. ([62093](https://github.com/WordPress/gutenberg/pull/62093)) +- Editor: Move the InterfaceSkeleton to the editor package. ([62118](https://github.com/WordPress/gutenberg/pull/62118)) +- Editor: Move the resizing of the editor to the EditorCanvas component. ([61896](https://github.com/WordPress/gutenberg/pull/61896)) +- Editor: Remove extra div container and unify the container between post and site editors. ([62016](https://github.com/WordPress/gutenberg/pull/62016)) +- Editor: Remove obsolete `listViewLabel` prop from DocumentTools. ([62032](https://github.com/WordPress/gutenberg/pull/62032)) +- Editor: Remove useless props from InserterSidebar component. ([62103](https://github.com/WordPress/gutenberg/pull/62103)) +- Editor: Unify the MediaUpload hook between post and site editors. ([62085](https://github.com/WordPress/gutenberg/pull/62085)) +- Editor: Unify the content area of the post and site editors. ([61860](https://github.com/WordPress/gutenberg/pull/61860)) +- Fix: React compiler error on button. ([61958](https://github.com/WordPress/gutenberg/pull/61958)) +- Fix: Remove unused css block on patterns page. ([62058](https://github.com/WordPress/gutenberg/pull/62058)) +- Fix: Remove unused css code from the navigation screen. ([62060](https://github.com/WordPress/gutenberg/pull/62060)) +- Fix: Some jsdoc return types on edit site selector. ([62061](https://github.com/WordPress/gutenberg/pull/62061)) +- Improve distclean script. ([62019](https://github.com/WordPress/gutenberg/pull/62019)) +- Interactivity API: Move all utils inside `utils.ts`. ([61721](https://github.com/WordPress/gutenberg/pull/61721)) +- Interactivity API: Move init.js to TypeScript. ([61723](https://github.com/WordPress/gutenberg/pull/61723)) +- Make onPatternCategorySelection private. ([62130](https://github.com/WordPress/gutenberg/pull/62130)) +- Remove useless clsx calls. ([61969](https://github.com/WordPress/gutenberg/pull/61969)) +- Rename backport-changelog/6279.md to backport-changelog/6.6/6279.md. ([61894](https://github.com/WordPress/gutenberg/pull/61894)) +- Update: Remove unused components. ([61955](https://github.com/WordPress/gutenberg/pull/61955)) +- end-to-end Tests: Fix React warnings triggered by test plugins. ([61935](https://github.com/WordPress/gutenberg/pull/61935)) + +#### Components +- CustomSelectControl: Fix `menuProps` mutation. ([62149](https://github.com/WordPress/gutenberg/pull/62149)) +- Fix remaining warning in ColorPanelDropdown. ([61933](https://github.com/WordPress/gutenberg/pull/61933)) +- Make the `ProgressBar` public. ([61062](https://github.com/WordPress/gutenberg/pull/61062)) +- Remove reduceMotion utility. ([61963](https://github.com/WordPress/gutenberg/pull/61963)) +- SlotFills: Use state for registry initialization. ([61802](https://github.com/WordPress/gutenberg/pull/61802)) +- Style Book: Use state to initialize examples. ([61848](https://github.com/WordPress/gutenberg/pull/61848)) +- Tooltip: Fix Ariakit tooltip store usage. ([61858](https://github.com/WordPress/gutenberg/pull/61858)) +- `ProgressBar`: Simplify default `width` implementation and make it more easily overridable. ([61976](https://github.com/WordPress/gutenberg/pull/61976)) + +#### Block Editor +- Fix `ZoomOutModeInserters` dependencies. ([61908](https://github.com/WordPress/gutenberg/pull/61908)) +- Fix wrapper props mutation in BlockListBlock. ([61789](https://github.com/WordPress/gutenberg/pull/61789)) +- Remove some utility functions. ([61784](https://github.com/WordPress/gutenberg/pull/61784)) +- Shadows: Unlock private components and hooks at the file level. ([61790](https://github.com/WordPress/gutenberg/pull/61790)) +- Unlock private setting keys at the file level. ([61813](https://github.com/WordPress/gutenberg/pull/61813)) +- Unlock the private 'kebabCase' function at a file level. ([60755](https://github.com/WordPress/gutenberg/pull/60755)) +- useBlockInspectorAnimationSettings: Remove unnecessary deps. ([61822](https://github.com/WordPress/gutenberg/pull/61822)) + +#### Data Views +- DataViews: Full type the dataviews package. ([61854](https://github.com/WordPress/gutenberg/pull/61854)) +- DataViews: Remove non-used file. ([61853](https://github.com/WordPress/gutenberg/pull/61853)) +- DataViews: Remove unnecessary dependency for pattern fields memo. ([61870](https://github.com/WordPress/gutenberg/pull/61870)) +- DataViews: Type all the filters components. ([61795](https://github.com/WordPress/gutenberg/pull/61795)) +- DataViews: Type the BulkActionsToolbar component. ([61673](https://github.com/WordPress/gutenberg/pull/61673)) +- DataViews: Type the ViewActions component. ([61729](https://github.com/WordPress/gutenberg/pull/61729)) +- DataViews: Type the ViewTable component. ([61682](https://github.com/WordPress/gutenberg/pull/61682)) + +#### Block Library +- Added unit test for post excerpt block render function. ([43451](https://github.com/WordPress/gutenberg/pull/43451)) +- Avoid using component naming conventions for non-component code. ([61793](https://github.com/WordPress/gutenberg/pull/61793)) +- Button: Fix ESLint warning. ([62126](https://github.com/WordPress/gutenberg/pull/62126)) +- Remove CSS hack for Internet Explorer 11. ([62043](https://github.com/WordPress/gutenberg/pull/62043)) +- Remove useless styles. ([62017](https://github.com/WordPress/gutenberg/pull/62017)) +- Search Block: Fix `borderRadius` mutation. ([61794](https://github.com/WordPress/gutenberg/pull/61794)) + +#### Site Editor +- History: Add getLocationWithParams method. ([61823](https://github.com/WordPress/gutenberg/pull/61823)) +- Navigation Focus Mode: Remove leftover code. ([61897](https://github.com/WordPress/gutenberg/pull/61897)) +- Remove useless onClick handler. ([61902](https://github.com/WordPress/gutenberg/pull/61902)) +- Update to use the EditorInterface component from the editor package. ([62146](https://github.com/WordPress/gutenberg/pull/62146)) + +#### Block hooks +- Navigation block: Check for insert_hooked_blocks_into_rest_response i…. ([62134](https://github.com/WordPress/gutenberg/pull/62134)) +- Navigation block: Check for update_ignored_hooked_blocks_postmeta in core. ([61903](https://github.com/WordPress/gutenberg/pull/61903)) + +#### Font Library +- Font Library Modal: Remove some contexts. ([62042](https://github.com/WordPress/gutenberg/pull/62042)) + +#### Post Editor +- Template Actions: Fix console error when resetting template. ([61921](https://github.com/WordPress/gutenberg/pull/61921)) + +#### Global Styles +- Components: Fix React Warning triggers by the new JSX transform. ([61917](https://github.com/WordPress/gutenberg/pull/61917)) + +#### Interactivity API +- Interactivity API : Refactor interactivity-router to TS. ([61730](https://github.com/WordPress/gutenberg/pull/61730)) + +#### CSS & Styling +- Fix editor view mode canvas shadow. ([61688](https://github.com/WordPress/gutenberg/pull/61688)) + + +### Tools + +- Build: Use globalThis over process.env and enable TS lib checking. ([61486](https://github.com/WordPress/gutenberg/pull/61486)) + +#### Testing +- E2E: Fix canvas waiter in visitSiteEditor. ([61816](https://github.com/WordPress/gutenberg/pull/61816)) +- PaletteEdit: Fix another flaky test. ([61818](https://github.com/WordPress/gutenberg/pull/61818)) +- PaletteEdit: Fix flaky test. ([61791](https://github.com/WordPress/gutenberg/pull/61791)) +- Shadow: Add unit tests for shadow support. ([60063](https://github.com/WordPress/gutenberg/pull/60063)) +- Skip flaky 'Zoom out' end-to-end test. ([61925](https://github.com/WordPress/gutenberg/pull/61925)) +- Synced Pattern: Wait for pattern creation in end-to-end tests. ([62174](https://github.com/WordPress/gutenberg/pull/62174)) +- Tests: Change how directives processing gets disabled. ([62095](https://github.com/WordPress/gutenberg/pull/62095)) +- Workflows: Try a backport changelog. ([61785](https://github.com/WordPress/gutenberg/pull/61785)) + +#### Build Tooling +- Add 60 minute timeout to performance job. ([61957](https://github.com/WordPress/gutenberg/pull/61957)) +- Enable parallel processing for PHPCS sniffs. ([61700](https://github.com/WordPress/gutenberg/pull/61700)) +- Fix an issue causing wp-scripts commands to fail if the file path contained a space character. ([61748](https://github.com/WordPress/gutenberg/pull/61748)) +- React: Upgrade to the new JSX transform. ([61692](https://github.com/WordPress/gutenberg/pull/61692)) +- Workflows: Test to check for label and skip backport changelog. ([61808](https://github.com/WordPress/gutenberg/pull/61808)) + + +### Various + +- Inserter: Encapsulate styles for tablist and close button. ([61760](https://github.com/WordPress/gutenberg/pull/61760)) +- Update 'Add template' screen to prefer template_name label instead of singular_name. ([60367](https://github.com/WordPress/gutenberg/pull/60367)) +- Update: Move pattern actions to the editor package. [take 2]. ([61612](https://github.com/WordPress/gutenberg/pull/61612)) + +#### Global Styles +- Update copy for color variations from "Presets" to "Palettes". ([62147](https://github.com/WordPress/gutenberg/pull/62147)) + +#### Synced Patterns +- Remove `IS_GUTENBERG_PLUGIN` check to ensure pattern overrides ship in 6.6. ([62011](https://github.com/WordPress/gutenberg/pull/62011)) + +#### npm Packages +- Packages: Increase the minimum required Node.js version to v18.12.0. ([61930](https://github.com/WordPress/gutenberg/pull/61930)) + +#### Layout +- Update child layout selector to match core. ([61777](https://github.com/WordPress/gutenberg/pull/61777)) + +#### Components +- Introduce Combobox `expandOnFocus` property. ([61705](https://github.com/WordPress/gutenberg/pull/61705)) + + +## First time contributors + +The following PRs were merged by first time contributors: + +- @akashdhawade2005: Fix: Block library README.md link. ([62081](https://github.com/WordPress/gutenberg/pull/62081)) +- @amitraj2203: Added Bluesky icon to the Social Icon Block. ([61372](https://github.com/WordPress/gutenberg/pull/61372)) +- @dbrian: Add JSDoc to PostVisibility, PostVisibilityCheck, and PostVisibilityLabel. ([61735](https://github.com/WordPress/gutenberg/pull/61735)) +- @gemkev: Update tutorial.md. ([62054](https://github.com/WordPress/gutenberg/pull/62054)) +- @kellenmace: Fix an issue causing wp-scripts commands to fail if the file path contained a space character. ([61748](https://github.com/WordPress/gutenberg/pull/61748)) +- @narenin: Fixed: Custom HTML Block should display content in LTR layout for all languages. ([62083](https://github.com/WordPress/gutenberg/pull/62083)) +- @nateinaction: Add documentation for the EditorProvider and ExperimentalEditorProvider components. ([61739](https://github.com/WordPress/gutenberg/pull/61739)) +- @paolopiaggio: Playwright end-to-end Utils: Add fullscreenMode option to createNewPost. ([61766](https://github.com/WordPress/gutenberg/pull/61766)) +- @sanjucta: Add docblock to PostTitle and PostTitleRaw component. ([61740](https://github.com/WordPress/gutenberg/pull/61740)) +- @vipul0425: Fix: The latest post block - post titles overlapping. ([61356](https://github.com/WordPress/gutenberg/pull/61356)) + + +## Contributors + +The following contributors merged PRs in this release: + +@aaronrobertshaw @abhi3315 @afercia @ajlende @akashdhawade2005 @akasunil @Aljullu @amitraj2203 @andrewserong @anton-vlasenko @anver @artemiomorales @carolinan @cbravobernal @colorful-tones @creativecoder @DaniGuardiola @DAreRodz @dbrian @draganescu @ellatrix @fabiankaegy @fullofcaffeine @gemkev @geriux @glendaviesnz @gziolo @jameskoster @jasmussen @jeryj @jorgefilipecosta @jsnajdr @kellenmace @kevin940726 @kt-12 @madhusudhand @Mamaduka @mattsherman @mcsf @michalczaplinski @mirka @narenin @nateinaction @ndiego @ntsekouras @oandregal @ockham @paolopiaggio @ramonjd @retrofox @richtabor @sanjucta @SantosGuillamot @scruffian @senadir @shail-mehta @sirreal @stokesman @t-hamano @talldan @taylorgorman @tellthemachines @tjcafferkey @twstokes @tyxla @vcanales @vipul0425 @westonruter @WunderBart @youknowriad + + + + = 18.4.1 = ## Changelog diff --git a/docs/how-to-guides/themes/global-settings-and-styles.md b/docs/how-to-guides/themes/global-settings-and-styles.md index a5c3e828a2d661..f71bd67bfaf2ec 100644 --- a/docs/how-to-guides/themes/global-settings-and-styles.md +++ b/docs/how-to-guides/themes/global-settings-and-styles.md @@ -310,20 +310,21 @@ There's one special setting property, `appearanceTools`, which is a boolean and To retain backward compatibility, the existing `add_theme_support` declarations that configure the block editor are retrofit in the proper categories for the top-level section. For example, if a theme uses `add_theme_support('disable-custom-colors')`, it'll be the same as setting `settings.color.custom` to `false`. If the `theme.json` contains any settings, these will take precedence over the values declared via `add_theme_support`. This is the complete list of equivalences: -| add_theme_support | theme.json setting | -| --------------------------- | --------------------------------------------------------- | -| `custom-line-height` | Set `typography.lineHeight` to `true`. | -| `custom-spacing` | Set `spacing.padding` to `true`. | -| `custom-units` | Provide the list of units via `spacing.units`. | -| `disable-custom-colors` | Set `color.custom` to `false`. | -| `disable-custom-font-sizes` | Set `typography.customFontSize` to `false`. | -| `disable-custom-gradients` | Set `color.customGradient` to `false`. | -| `editor-color-palette` | Provide the list of colors via `color.palette`. | -| `editor-font-sizes` | Provide the list of font size via `typography.fontSizes`. | -| `editor-gradient-presets` | Provide the list of gradients via `color.gradients`. | -| `appearance-tools` | Set `appearanceTools` to `true`. | -| `border` | Set `border: color, radius, style, width` to `true`. | -| `link-color ` | Set `color.link` to `true`. | +| add_theme_support | theme.json setting | +| --------------------------- | ------------------------------------------------------------- | +| `custom-line-height` | Set `typography.lineHeight` to `true`. | +| `custom-spacing` | Set `spacing.padding` to `true`. | +| `custom-units` | Provide the list of units via `spacing.units`. | +| `disable-custom-colors` | Set `color.custom` to `false`. | +| `disable-custom-font-sizes` | Set `typography.customFontSize` to `false`. | +| `disable-custom-gradients` | Set `color.customGradient` to `false`. | +| `editor-color-palette` | Provide the list of colors via `color.palette`. | +| `editor-font-sizes` | Provide the list of font size via `typography.fontSizes`. | +| `editor-gradient-presets` | Provide the list of gradients via `color.gradients`. | +| `editor-spacing-sizes` | Provide the list of spacing sizes via `spacing.spacingSizes`. | +| `appearance-tools` | Set `appearanceTools` to `true`. | +| `border` | Set `border: color, radius, style, width` to `true`. | +| `link-color ` | Set `color.link` to `true`. | #### Presets diff --git a/docs/reference-guides/block-api/block-styles.md b/docs/reference-guides/block-api/block-styles.md index 90b6c06d18f59d..b47b1a76a71f68 100644 --- a/docs/reference-guides/block-api/block-styles.md +++ b/docs/reference-guides/block-api/block-styles.md @@ -1,6 +1,6 @@ # Styles -Block Styles allow alternative styles to be applied to existing blocks. They work by adding a className to the block's wrapper. This className can be used to provide an alternative styling for the block if the block style is selected. See the [Getting Started with JavaScript tutorial](/docs/how-to-guides/javascript/) for a full example. +Block Styles allow alternative styles to be applied to existing blocks. They work by adding a className to the block's wrapper. This className can be used to provide an alternative styling for the block if the block style is selected. See the [Use styles and stylesheets](/docs/how-to-guides/block-tutorial/applying-styles-with-stylesheets.md) for a full example on how to apply styles to a block. _Example:_ diff --git a/docs/reference-guides/block-api/block-variations.md b/docs/reference-guides/block-api/block-variations.md index 0790b7f02641e8..ffd3cc49adda80 100644 --- a/docs/reference-guides/block-api/block-variations.md +++ b/docs/reference-guides/block-api/block-variations.md @@ -129,9 +129,9 @@ While the `isActive` property is optional, it's recommended. This API is used by If `isActive` is not set, the Editor cannot distinguish between an instance of the original block and your variation, so the original block information will be displayed. -The property can be set to either a function or an array of strings (`string[]`). +The property can be set to either an array of strings (`string[]`), or a function. It is recommended to use the string array version whenever possible. -The function version of this property accepts a block instance's `blockAttributes` as the first argument, and the `variationAttributes` declared for a variation as the second argument. These arguments can be used to determine if a variation is active by comparing them and returning a `true` or `false` (indicating whether this variation is inactive for this block instance). +The `string[]` version is used to declare which of the block instance's attributes should be compared to the given variation's. Each attribute will be checked and the variation will be active if all of them match. As an example, in the core Embed block, the `providerNameSlug` attribute is used to determine the embed provider (e.g. 'youtube' or 'twitter'). The variations may be declared like this: @@ -162,28 +162,32 @@ const variations = [ ] ``` - The `isActive` function can compare the block instance value for `providerNameSlug` to the value declared in the variation's declaration (the values in the code snippet above) to determine which embed variation is active: +The `isActive` property would then look like this: ```js -isActive: ( blockAttributes, variationAttributes ) => - blockAttributes.providerNameSlug === variationAttributes.providerNameSlug, +isActive: [ 'providerNameSlug' ] ``` -The `string[]` version is used to declare which attributes should be compared as a shorthand. Each attribute will be checked and the variation will be active if all of them match. Using the same example for the embed block, the string version would look like this: +This will cause the block instance value for `providerNameSlug` to be compared to the value declared in the variation's declaration (the values in the code snippet above) to determine which embed variation is active. + +Nested object paths are also supported. For example, consider a block variation that has a `query` object as an attribute. It is possible to determine if the variation is active solely based on that object's `postType` property (while ignoring all its other properties): ```js -isActive: [ 'providerNameSlug' ] +isActive: [ 'query.postType' ] ``` -Nested object paths are also supported. For example, consider a block variation that has a `query` object as an attribute. It is possible to determine if the variation is active solely based on that object's `postType` property (while ignoring all its other properties): +The function version of this property accepts a block instance's `blockAttributes` as the first argument, and the `variationAttributes` declared for a variation as the second argument. These arguments can be used to determine if a variation is active by comparing them and returning a `true` or `false` (indicating whether this variation is inactive for this block instance). + +Using the same example for the embed block, the function version would look like this: ```js -isActive: [ 'query.postType' ] +isActive: ( blockAttributes, variationAttributes ) => + blockAttributes.providerNameSlug === variationAttributes.providerNameSlug, ``` -### Caveats to using `isActive` +### Specificity of `isActive` matches -The `isActive` property can return false positives if multiple variations exist for a specific block and the `isActive` checks are not specific enough. To demonstrate this, consider the following example: +If there are multiple variations whose `isActive` check matches a given block instance, and all of them are string arrays, then the variation with the highest _specificity_ will be chosen. Consider the following example: ```js wp.blocks.registerBlockVariation( @@ -212,6 +216,6 @@ wp.blocks.registerBlockVariation( ); ``` -The `isActive` check on both variations tests the `textColor`, but each variations uses `vivid-red`. Since the `paragraph-red` variation is registered first, once the `paragraph-red-grey` variation is inserted into the Editor, it will have the title `Red Paragraph` instead of `Red/Grey Paragraph`. As soon as the Editor finds a match, it stops checking. +If a block instance has attributes `textColor: vivid-red` and `backgroundColor: cyan-bluish-gray`, both variations' `isActive` criterion will match that block instance. In this case, the more _specific_ match will be determined to be the active variation, where specificity is calculated as the length of each `isActive` array. This means that the `Red/Grey Paragraph` will be shown as the active variation. -There have been [discussions](https://github.com/WordPress/gutenberg/issues/41303#issuecomment-1526193087) around how the API can be improved, but as of WordPress 6.3, this remains an issue to watch out for. +Note that specificity cannot be determined for a matching variation if its `isActive` property is a function rather than a `string[]`. In this case, the first matching variation will be determined to be the active variation. For this reason, it is generally recommended to use a `string[]` rather than a `function` for the `isActive` property. diff --git a/docs/reference-guides/data/data-core-block-editor.md b/docs/reference-guides/data/data-core-block-editor.md index 862a8b2d8a06aa..f687eb79732b5a 100644 --- a/docs/reference-guides/data/data-core-block-editor.md +++ b/docs/reference-guides/data/data-core-block-editor.md @@ -1439,7 +1439,7 @@ wp.data.dispatch( 'core/block-editor' ).registerInserterMediaCategory( { per_page: 'page_size', search: 'q', }; - const url = new URL( 'https://api.openverse.engineering/v1/images/' ); + const url = new URL( 'https://api.openverse.org/v1/images/' ); Object.entries( finalQuery ).forEach( ( [ key, value ] ) => { const queryKey = mapFromInserterMediaRequest[ key ] || key; url.searchParams.set( queryKey, value ); diff --git a/docs/reference-guides/slotfills/README.md b/docs/reference-guides/slotfills/README.md index 043a50cb5186e6..ea324f71b25e83 100644 --- a/docs/reference-guides/slotfills/README.md +++ b/docs/reference-guides/slotfills/README.md @@ -33,7 +33,7 @@ registerPlugin( 'post-status-info-test', { render: PluginPostStatusInfoTest } ); SlotFills are created using `createSlotFill`. This creates two components, `Slot` and `Fill` which are then used to create a new component that is exported on the `wp.plugins` global. -**Definition of the `PluginPostStatusInfo` SlotFill** ([see core code](https://github.com/WordPress/gutenberg/blob/HEAD/packages/edit-post/src/components/sidebar/plugin-post-status-info/index.js#L54)) +**Definition of the `PluginPostStatusInfo` SlotFill** ([see core code](https://github.com/WordPress/gutenberg/blob/HEAD/packages/editor/src/components/plugin-post-status-info/index.js#L55)) ```js /** @@ -61,34 +61,70 @@ export default PluginPostStatusInfo; This new Slot is then exposed in the editor. The example below is from core and represents the Summary panel. As we can see, the `` is wrapping all of the items that will appear in the panel. -Any items that have been added via the SlotFill ( see the example above ), will be included in the `fills` parameter and be displayed between the `` and `` components. +Any items that have been added via the SlotFill ( see the example above ), will be included in the `fills` parameter and be displayed in the end of the component. -See [core code](https://github.com/WordPress/gutenberg/tree/HEAD/packages/edit-post/src/components/sidebar/post-status/index.js#L26). +See [core code](https://github.com/WordPress/gutenberg/tree/HEAD/packages/editor/src/components/sidebar/post-summary.js#L39). ```js -const PostStatus = ( { isOpened, onTogglePanel } ) => ( - - - { ( fills ) => ( - <> - - - - - - - { fills } - - - ) } - - -); +export default function PostSummary( { onActionPerformed } ) { + const { isRemovedPostStatusPanel } = useSelect( ( select ) => { + // We use isEditorPanelRemoved to hide the panel if it was programatically removed. We do + // not use isEditorPanelEnabled since this panel should not be disabled through the UI. + const { isEditorPanelRemoved, getCurrentPostType } = + select( editorStore ); + return { + isRemovedPostStatusPanel: isEditorPanelRemoved( PANEL_NAME ), + postType: getCurrentPostType(), + }; + }, [] ); + + return ( + + + { ( fills ) => ( + <> + + + } + /> + + + + + + + { ! isRemovedPostStatusPanel && ( + + + + + + + + + + + + + + + + + + { fills } + + ) } + + + ) } + + + ); +} ``` ## Currently available SlotFills and examples diff --git a/gutenberg.php b/gutenberg.php index becad26a3e9f3a..a8d9ebe7e981f0 100644 --- a/gutenberg.php +++ b/gutenberg.php @@ -5,7 +5,7 @@ * Description: Printing since 1440. This is the development plugin for the block editor, site editor, and other future WordPress core functionality. * Requires at least: 6.4 * Requires PHP: 7.2 - * Version: 18.4.1 + * Version: 18.5.0 * Author: Gutenberg Team * Text Domain: gutenberg * diff --git a/lib/block-template-utils.php b/lib/block-template-utils.php new file mode 100644 index 00000000000000..a644047d3cfdc1 --- /dev/null +++ b/lib/block-template-utils.php @@ -0,0 +1,114 @@ +open( $filename, ZipArchive::CREATE | ZipArchive::OVERWRITE ) ) { + return new WP_Error( 'unable_to_create_zip', __( 'Unable to open export file (archive) for writing.', 'gutenberg' ) ); + } + + $zip->addEmptyDir( 'templates' ); + $zip->addEmptyDir( 'parts' ); + + // Get path of the theme. + $theme_path = wp_normalize_path( get_stylesheet_directory() ); + + // Create recursive directory iterator. + $theme_files = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator( $theme_path ), + RecursiveIteratorIterator::LEAVES_ONLY + ); + + // Make a copy of the current theme. + foreach ( $theme_files as $file ) { + // Skip directories as they are added automatically. + if ( ! $file->isDir() ) { + // Get real and relative path for current file. + $file_path = wp_normalize_path( $file ); + $relative_path = substr( $file_path, strlen( $theme_path ) + 1 ); + + if ( ! wp_is_theme_directory_ignored( $relative_path ) ) { + $zip->addFile( $file_path, $relative_path ); + } + } + } + + // Load templates into the zip file. + $templates = gutenberg_get_block_templates(); + foreach ( $templates as $template ) { + $template->content = traverse_and_serialize_blocks( + parse_blocks( $template->content ), + '_remove_theme_attribute_from_template_part_block' + ); + + $zip->addFromString( + 'templates/' . $template->slug . '.html', + $template->content + ); + } + + // Load template parts into the zip file. + $template_parts = gutenberg_get_block_templates( array(), 'wp_template_part' ); + foreach ( $template_parts as $template_part ) { + $zip->addFromString( + 'parts/' . $template_part->slug . '.html', + $template_part->content + ); + } + + // Load theme.json into the zip file. + $tree = WP_Theme_JSON_Resolver_Gutenberg::get_theme_data( array(), array( 'with_supports' => false ) ); + // Merge with user data. + $tree->merge( WP_Theme_JSON_Resolver_Gutenberg::get_user_data() ); + + $theme_json_raw = $tree->get_data(); + // If a version is defined, add a schema. + if ( $theme_json_raw['version'] ) { + $theme_json_version = 'wp/' . substr( $wp_version, 0, 3 ); + $schema = array( '$schema' => 'https://schemas.wp.org/' . $theme_json_version . '/theme.json' ); + $theme_json_raw = array_merge( $schema, $theme_json_raw ); + } + + // Convert to a string. + $theme_json_encoded = wp_json_encode( $theme_json_raw, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ); + + // Replace 4 spaces with a tab. + $theme_json_tabbed = preg_replace( '~(?:^|\G)\h{4}~m', "\t", $theme_json_encoded ); + + // Add the theme.json file to the zip. + $zip->addFromString( + 'theme.json', + $theme_json_tabbed + ); + + // Save changes to the zip file. + $zip->close(); + + return $filename; +} diff --git a/lib/class-wp-rest-edit-site-export-controller-gutenberg.php b/lib/class-wp-rest-edit-site-export-controller-gutenberg.php new file mode 100644 index 00000000000000..b05de230dd0ccd --- /dev/null +++ b/lib/class-wp-rest-edit-site-export-controller-gutenberg.php @@ -0,0 +1,46 @@ +add_data( array( 'status' => 500 ) ); + + return $filename; + } + + $theme_name = basename( get_stylesheet() ); + header( 'Content-Type: application/zip' ); + header( 'Content-Disposition: attachment; filename=' . $theme_name . '.zip' ); + header( 'Content-Length: ' . filesize( $filename ) ); + flush(); + readfile( $filename ); + unlink( $filename ); + exit; + } +} diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index ad4e2fe105b0c3..a1e79a56a683bf 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -734,14 +734,14 @@ public static function get_element_class_name( $element ) { * * @param array $theme_json A structure that follows the theme.json schema. * @param string $origin Optional. What source of data this object represents. - * One of 'default', 'theme', or 'custom'. Default 'theme'. + * One of 'blocks', 'default', 'theme', or 'custom'. Default 'theme'. */ public function __construct( $theme_json = array( 'version' => WP_Theme_JSON_Gutenberg::LATEST_SCHEMA ), $origin = 'theme' ) { if ( ! in_array( $origin, static::VALID_ORIGINS, true ) ) { $origin = 'theme'; } - $this->theme_json = WP_Theme_JSON_Schema_Gutenberg::migrate( $theme_json ); + $this->theme_json = WP_Theme_JSON_Schema_Gutenberg::migrate( $theme_json, $origin ); $registry = WP_Block_Type_Registry::get_instance(); $valid_block_names = array_keys( $registry->get_all_registered() ); $valid_element_names = array_keys( static::ELEMENTS ); @@ -3278,15 +3278,21 @@ protected static function filter_slugs( $node, $slugs ) { * Removes insecure data from theme.json. * * @since 5.9.0 - * @since 6.6.0 Added support for block style variation element styles. + * @since 6.6.0 Added support for block style variation element styles and $origin parameter. * * @param array $theme_json Structure to sanitize. + * @param string $origin Optional. What source of data this object represents. + * One of 'blocks', 'default', 'theme', or 'custom'. Default 'theme'. * @return array Sanitized structure. */ - public static function remove_insecure_properties( $theme_json ) { + public static function remove_insecure_properties( $theme_json, $origin = 'theme' ) { + if ( ! in_array( $origin, static::VALID_ORIGINS, true ) ) { + $origin = 'theme'; + } + $sanitized = array(); - $theme_json = WP_Theme_JSON_Schema_Gutenberg::migrate( $theme_json ); + $theme_json = WP_Theme_JSON_Schema_Gutenberg::migrate( $theme_json, $origin ); $valid_block_names = array_keys( static::get_blocks_metadata() ); $valid_element_names = array_keys( static::ELEMENTS ); @@ -3559,53 +3565,32 @@ public static function get_from_editor_settings( $settings ) { // Deprecated theme supports. if ( isset( $settings['disableCustomColors'] ) ) { - if ( ! isset( $theme_settings['settings']['color'] ) ) { - $theme_settings['settings']['color'] = array(); - } $theme_settings['settings']['color']['custom'] = ! $settings['disableCustomColors']; } if ( isset( $settings['disableCustomGradients'] ) ) { - if ( ! isset( $theme_settings['settings']['color'] ) ) { - $theme_settings['settings']['color'] = array(); - } $theme_settings['settings']['color']['customGradient'] = ! $settings['disableCustomGradients']; } if ( isset( $settings['disableCustomFontSizes'] ) ) { - if ( ! isset( $theme_settings['settings']['typography'] ) ) { - $theme_settings['settings']['typography'] = array(); - } $theme_settings['settings']['typography']['customFontSize'] = ! $settings['disableCustomFontSizes']; } if ( isset( $settings['enableCustomLineHeight'] ) ) { - if ( ! isset( $theme_settings['settings']['typography'] ) ) { - $theme_settings['settings']['typography'] = array(); - } $theme_settings['settings']['typography']['lineHeight'] = $settings['enableCustomLineHeight']; } if ( isset( $settings['enableCustomUnits'] ) ) { - if ( ! isset( $theme_settings['settings']['spacing'] ) ) { - $theme_settings['settings']['spacing'] = array(); - } $theme_settings['settings']['spacing']['units'] = ( true === $settings['enableCustomUnits'] ) ? array( 'px', 'em', 'rem', 'vh', 'vw', '%' ) : $settings['enableCustomUnits']; } if ( isset( $settings['colors'] ) ) { - if ( ! isset( $theme_settings['settings']['color'] ) ) { - $theme_settings['settings']['color'] = array(); - } $theme_settings['settings']['color']['palette'] = $settings['colors']; } if ( isset( $settings['gradients'] ) ) { - if ( ! isset( $theme_settings['settings']['color'] ) ) { - $theme_settings['settings']['color'] = array(); - } $theme_settings['settings']['color']['gradients'] = $settings['gradients']; } @@ -3617,19 +3602,17 @@ public static function get_from_editor_settings( $settings ) { $font_sizes[ $key ]['size'] = $font_size['size'] . 'px'; } } - if ( ! isset( $theme_settings['settings']['typography'] ) ) { - $theme_settings['settings']['typography'] = array(); - } $theme_settings['settings']['typography']['fontSizes'] = $font_sizes; } if ( isset( $settings['enableCustomSpacing'] ) ) { - if ( ! isset( $theme_settings['settings']['spacing'] ) ) { - $theme_settings['settings']['spacing'] = array(); - } $theme_settings['settings']['spacing']['padding'] = $settings['enableCustomSpacing']; } + if ( isset( $settings['spacingSizes'] ) ) { + $theme_settings['settings']['spacing']['spacingSizes'] = $settings['spacingSizes']; + } + return $theme_settings; } @@ -3794,12 +3777,10 @@ public function get_data() { /** * Sets the spacingSizes array based on the spacingScale values from theme.json. * - * No longer used since theme.json version 3 as the spacingSizes are now - * automatically generated during construction and merge instead of manually - * set in the resolver. - * * @since 6.1.0 - * @deprecated 6.6.0 + * @deprecated 6.6.0 No longer used as the spacingSizes are automatically + * generated in the constructor and merge methods instead + * of manually after instantiation. * * @return null|void */ @@ -3852,6 +3833,10 @@ public function set_spacing_sizes() { * @return array The merged set of spacing sizes. */ private static function merge_spacing_sizes( $base, $incoming ) { + // Preserve the order if there are no base (spacingScale) values. + if ( empty( $base ) ) { + return $incoming; + } $merged = array(); foreach ( $base as $item ) { $merged[ $item['slug'] ] = $item; @@ -3859,6 +3844,7 @@ private static function merge_spacing_sizes( $base, $incoming ) { foreach ( $incoming as $item ) { $merged[ $item['slug'] ] = $item; } + ksort( $merged, SORT_NUMERIC ); return array_values( $merged ); } diff --git a/lib/class-wp-theme-json-resolver-gutenberg.php b/lib/class-wp-theme-json-resolver-gutenberg.php index 84f999e4e9d020..507876af4952a8 100644 --- a/lib/class-wp-theme-json-resolver-gutenberg.php +++ b/lib/class-wp-theme-json-resolver-gutenberg.php @@ -220,6 +220,7 @@ protected static function has_same_registered_blocks( $origin ) { * @since 5.8.0 * @since 5.9.0 Theme supports have been inlined and the `$theme_support_data` argument removed. * @since 6.0.0 Added an `$options` parameter to allow the theme data to be returned without theme supports. + * @since 6.6.0 Add support for 'default-font-sizes' and 'default-spacing-sizes' theme supports. * * @param array $deprecated Deprecated. Not used. * @param array $options { @@ -291,35 +292,27 @@ public static function get_theme_data( $deprecated = array(), $options = array() * So we take theme supports, transform it to theme.json shape * and merge the static::$theme upon that. */ - $theme_support_data = WP_Theme_JSON_Gutenberg::get_from_editor_settings( get_classic_theme_supports_block_editor_settings() ); + $theme_support_data = WP_Theme_JSON_Gutenberg::get_from_editor_settings( gutenberg_get_classic_theme_supports_block_editor_settings() ); if ( ! wp_theme_has_theme_json() ) { - if ( ! isset( $theme_support_data['settings']['color'] ) ) { - $theme_support_data['settings']['color'] = array(); - } - - $default_palette = false; - if ( current_theme_supports( 'default-color-palette' ) ) { - $default_palette = true; - } - if ( ! isset( $theme_support_data['settings']['color']['palette'] ) ) { - // If the theme does not have any palette, we still want to show the core one. - $default_palette = true; - } - $theme_support_data['settings']['color']['defaultPalette'] = $default_palette; - - $default_gradients = false; - if ( current_theme_supports( 'default-gradient-presets' ) ) { - $default_gradients = true; - } - if ( ! isset( $theme_support_data['settings']['color']['gradients'] ) ) { - // If the theme does not have any gradients, we still want to show the core ones. - $default_gradients = true; - } - $theme_support_data['settings']['color']['defaultGradients'] = $default_gradients; + /* + * Unlike block themes, classic themes without a theme.json disable + * default presets when custom preset theme support is added. This + * behavior can be overridden by using the corresponding default + * preset theme support. + */ + $theme_support_data['settings']['color']['defaultPalette'] = + ! isset( $theme_support_data['settings']['color']['palette'] ) || + current_theme_supports( 'default-color-palette' ); + $theme_support_data['settings']['color']['defaultGradients'] = + ! isset( $theme_support_data['settings']['color']['gradients'] ) || + current_theme_supports( 'default-gradient-presets' ); + $theme_support_data['settings']['typography']['defaultFontSizes'] = + ! isset( $theme_support_data['settings']['typography']['fontSizes'] ) || + current_theme_supports( 'default-font-sizes' ); + $theme_support_data['settings']['spacing']['defaultSpacingSizes'] = + ! isset( $theme_support_data['settings']['spacing']['spacingSizes'] ) || + current_theme_supports( 'default-spacing-sizes' ); - if ( ! isset( $theme_support_data['settings']['shadow'] ) ) { - $theme_support_data['settings']['shadow'] = array(); - } /* * Shadow presets are explicitly disabled for classic themes until a * decision is made for whether the default presets should match the @@ -541,18 +534,14 @@ public static function get_user_data() { isset( $decoded_data['isGlobalStylesUserThemeJSON'] ) && $decoded_data['isGlobalStylesUserThemeJSON'] ) { + unset( $decoded_data['isGlobalStylesUserThemeJSON'] ); $config = $decoded_data; } } /** This filter is documented in wp-includes/class-wp-theme-json-resolver.php */ - $theme_json = apply_filters( 'wp_theme_json_data_user', new WP_Theme_JSON_Data_Gutenberg( $config, 'custom' ) ); - $config = $theme_json->get_data(); - - // Needs to be set for schema migrations of user data. - $config['isGlobalStylesUserThemeJSON'] = true; - - static::$user = new WP_Theme_JSON_Gutenberg( $config, 'custom' ); + $theme_json = apply_filters( 'wp_theme_json_data_user', new WP_Theme_JSON_Data_Gutenberg( $config, 'custom' ) ); + static::$user = $theme_json->get_theme_json(); return static::$user; } diff --git a/lib/class-wp-theme-json-schema-gutenberg.php b/lib/class-wp-theme-json-schema-gutenberg.php index 0def88f86a23a7..af0977ada1b307 100644 --- a/lib/class-wp-theme-json-schema-gutenberg.php +++ b/lib/class-wp-theme-json-schema-gutenberg.php @@ -40,11 +40,13 @@ class WP_Theme_JSON_Schema_Gutenberg { * @since 5.9.0 * @since 6.6.0 Migrate up to v3. * - * @param array $theme_json The structure to migrate. + * @param array $theme_json The structure to migrate. + * @param string $origin Optional. What source of data this object represents. + * One of 'blocks', 'default', 'theme', or 'custom'. Default 'theme'. * * @return array The structure in the last version. */ - public static function migrate( $theme_json ) { + public static function migrate( $theme_json, $origin = 'theme' ) { if ( ! isset( $theme_json['version'] ) ) { $theme_json = array( 'version' => WP_Theme_JSON::LATEST_SCHEMA, @@ -55,10 +57,9 @@ public static function migrate( $theme_json ) { switch ( $theme_json['version'] ) { case 1: $theme_json = self::migrate_v1_to_v2( $theme_json ); - // no break + // Deliberate fall through. Once migrated to v2, also migrate to v3. case 2: - $theme_json = self::migrate_v2_to_v3( $theme_json ); - // no break + $theme_json = self::migrate_v2_to_v3( $theme_json, $origin ); } return $theme_json; @@ -97,15 +98,19 @@ private static function migrate_v1_to_v2( $old ) { /** * Migrates from v2 to v3. * - * - Sets settings.typography.defaultFontSizes to false. + * - Sets settings.typography.defaultFontSizes to false if settings.typography.fontSizes are defined. + * - Sets settings.spacing.defaultSpacingSizes to false if settings.spacing.spacingSizes are defined. + * - Prevents settings.spacing.spacingSizes from merging with settings.spacing.spacingScale by + * unsetting spacingScale when spacingSizes are defined. * * @since 6.6.0 * - * @param array $old Data to migrate. - * + * @param array $old Data to migrate. + * @param string $origin What source of data this object represents. + * One of 'blocks', 'default', 'theme', or 'custom'. * @return array Data with defaultFontSizes set to false. */ - private static function migrate_v2_to_v3( $old ) { + private static function migrate_v2_to_v3( $old, $origin ) { // Copy everything. $new = $old; @@ -116,10 +121,7 @@ private static function migrate_v2_to_v3( $old ) { * Remaining changes do not need to be applied to the custom origin, * as they should take on the value of the theme origin. */ - if ( - isset( $new['isGlobalStylesUserThemeJSON'] ) && - true === $new['isGlobalStylesUserThemeJSON'] - ) { + if ( 'custom' === $origin ) { return $new; } @@ -132,12 +134,6 @@ private static function migrate_v2_to_v3( $old ) { * when the theme did not provide any. */ if ( isset( $old['settings']['typography']['fontSizes'] ) ) { - if ( ! isset( $new['settings'] ) ) { - $new['settings'] = array(); - } - if ( ! isset( $new['settings']['typography'] ) ) { - $new['settings']['typography'] = array(); - } $new['settings']['typography']['defaultFontSizes'] = false; } @@ -151,12 +147,6 @@ private static function migrate_v2_to_v3( $old ) { isset( $old['settings']['spacing']['spacingSizes'] ) || isset( $old['settings']['spacing']['spacingScale'] ) ) { - if ( ! isset( $new['settings'] ) ) { - $new['settings'] = array(); - } - if ( ! isset( $new['settings']['spacing'] ) ) { - $new['settings']['spacing'] = array(); - } $new['settings']['spacing']['defaultSpacingSizes'] = false; } diff --git a/lib/compat/wordpress-6.5/blocks.php b/lib/compat/wordpress-6.5/blocks.php index d3a8b3f5571813..5c5688e7cdf43e 100644 --- a/lib/compat/wordpress-6.5/blocks.php +++ b/lib/compat/wordpress-6.5/blocks.php @@ -65,27 +65,68 @@ function gutenberg_block_bindings_replace_html( $block_content, $block_name, str switch ( $block_type->attributes[ $attribute_name ]['source'] ) { case 'html': case 'rich-text': - // Hardcode the selectors and processing until the HTML API is able to read CSS selectors and replace inner HTML. - // TODO: Use the HTML API instead. - if ( 'core/paragraph' === $block_name && 'content' === $attribute_name ) { - $selector = 'p'; - } - if ( 'core/heading' === $block_name && 'content' === $attribute_name ) { - $selector = 'h[1-6]'; + $block_reader = new WP_HTML_Tag_Processor( $block_content ); + + // TODO: Support for CSS selectors whenever they are ready in the HTML API. + // In the meantime, support comma-separated selectors by exploding them into an array. + $selectors = explode( ',', $block_type->attributes[ $attribute_name ]['selector'] ); + // Add a bookmark to the first tag to be able to iterate over the selectors. + $block_reader->next_tag(); + $block_reader->set_bookmark( 'iterate-selectors' ); + + // TODO: This shouldn't be needed when the `set_inner_html` function is ready. + // Store the parent tag and its attributes to be able to restore them later in the button. + // The button block has a wrapper while the paragraph and heading blocks don't. + if ( 'core/button' === $block_name ) { + $button_wrapper = $block_reader->get_tag(); + $button_wrapper_attribute_names = $block_reader->get_attribute_names_with_prefix( '' ); + $button_wrapper_attrs = array(); + foreach ( $button_wrapper_attribute_names as $name ) { + $button_wrapper_attrs[ $name ] = $block_reader->get_attribute( $name ); + } } - if ( 'core/button' === $block_name && 'text' === $attribute_name ) { - // Check if it is a diff --git a/packages/block-serialization-default-parser/CHANGELOG.md b/packages/block-serialization-default-parser/CHANGELOG.md index a46ea5d2d7116d..199849d08ce2ce 100644 --- a/packages/block-serialization-default-parser/CHANGELOG.md +++ b/packages/block-serialization-default-parser/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.0.0 (2024-05-31) + ### Breaking Changes - Increase the minimum required Node.js version to v18.12.0 matching long-term support releases ([#31270](https://github.com/WordPress/gutenberg/pull/61930)). Learn more about [Node.js releases](https://nodejs.org/en/about/previous-releases). diff --git a/packages/block-serialization-default-parser/package.json b/packages/block-serialization-default-parser/package.json index 123fff2580df4b..fba002addabba6 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": "4.58.0", + "version": "5.0.0", "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/CHANGELOG.md b/packages/block-serialization-spec-parser/CHANGELOG.md index f1ef290055f909..2048ba7631ee0c 100644 --- a/packages/block-serialization-spec-parser/CHANGELOG.md +++ b/packages/block-serialization-spec-parser/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.0.0 (2024-05-31) + ### Breaking Changes - Increase the minimum required Node.js version to v18.12.0 matching long-term support releases ([#31270](https://github.com/WordPress/gutenberg/pull/61930)). Learn more about [Node.js releases](https://nodejs.org/en/about/previous-releases). diff --git a/packages/block-serialization-spec-parser/package.json b/packages/block-serialization-spec-parser/package.json index 572cbe6aa95b74..b83b8ebb4b38d4 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": "4.58.0", + "version": "5.0.0", "description": "Block serialization specification parser for WordPress posts.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/blocks/CHANGELOG.md b/packages/blocks/CHANGELOG.md index 46f41ad0b6bbb9..de9f9180822d4c 100644 --- a/packages/blocks/CHANGELOG.md +++ b/packages/blocks/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 13.0.0 (2024-05-31) + ### Breaking Changes - Variables like `process.env.IS_GUTENBERG_PLUGIN` have been replaced by `globalThis.IS_GUTENBERG_PLUGIN`. Build systems using `process.env` should be updated ([#61486](https://github.com/WordPress/gutenberg/pull/61486)). diff --git a/packages/blocks/package.json b/packages/blocks/package.json index f27afe5f5033b5..8250de1fac564c 100644 --- a/packages/blocks/package.json +++ b/packages/blocks/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/blocks", - "version": "12.35.0", + "version": "13.0.0", "description": "Block API for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/blocks/src/api/parser/convert-legacy-block.js b/packages/blocks/src/api/parser/convert-legacy-block.js index 8396b98109792f..055679302efd64 100644 --- a/packages/blocks/src/api/parser/convert-legacy-block.js +++ b/packages/blocks/src/api/parser/convert-legacy-block.js @@ -88,25 +88,41 @@ export function convertLegacyBlockNameAndAttributes( name, attributes ) { ( name === 'core/paragraph' || name === 'core/heading' || name === 'core/image' || - name === 'core/button' ) + name === 'core/button' ) && + newAttributes.metadata.bindings.__default?.source !== + 'core/pattern-overrides' ) { const bindings = [ 'content', 'url', 'title', + 'id', 'alt', 'text', 'linkTarget', ]; + // Delete any existing individual bindings and add a default binding. + // It was only possible to add all the default attributes through the UI, + // So as soon as we find an attribute, we can assume all default attributes are overridable. + let hasPatternOverrides = false; bindings.forEach( ( binding ) => { if ( - newAttributes.metadata.bindings[ binding ]?.source?.name === - 'pattern_attributes' + newAttributes.metadata.bindings[ binding ]?.source === + 'core/pattern-overrides' ) { - newAttributes.metadata.bindings[ binding ].source = - 'core/pattern-overrides'; + hasPatternOverrides = true; + newAttributes.metadata = { + ...newAttributes.metadata, + bindings: { ...newAttributes.metadata.bindings }, + }; + delete newAttributes.metadata.bindings[ binding ]; } } ); + if ( hasPatternOverrides ) { + newAttributes.metadata.bindings.__default = { + source: 'core/pattern-overrides', + }; + } } } return [ name, newAttributes ]; diff --git a/packages/blocks/src/api/parser/fix-custom-classname.js b/packages/blocks/src/api/parser/fix-custom-classname.js index d72065cd59222b..78f04ea4a00fa5 100644 --- a/packages/blocks/src/api/parser/fix-custom-classname.js +++ b/packages/blocks/src/api/parser/fix-custom-classname.js @@ -42,27 +42,30 @@ export function getHTMLRootElementClasses( innerHTML ) { * @return {Object} Filtered block attributes. */ export function fixCustomClassname( blockAttributes, blockType, innerHTML ) { - if ( hasBlockSupport( blockType, 'customClassName', true ) ) { - // To determine difference, serialize block given the known set of - // attributes, with the exception of `className`. This will determine - // the default set of classes. From there, any difference in innerHTML - // can be considered as custom classes. - const { className: omittedClassName, ...attributesSansClassName } = - blockAttributes; - const serialized = getSaveContent( blockType, attributesSansClassName ); - const defaultClasses = getHTMLRootElementClasses( serialized ); - const actualClasses = getHTMLRootElementClasses( innerHTML ); + if ( ! hasBlockSupport( blockType, 'customClassName', true ) ) { + return blockAttributes; + } + + const modifiedBlockAttributes = { ...blockAttributes }; + // To determine difference, serialize block given the known set of + // attributes, with the exception of `className`. This will determine + // the default set of classes. From there, any difference in innerHTML + // can be considered as custom classes. + const { className: omittedClassName, ...attributesSansClassName } = + modifiedBlockAttributes; + const serialized = getSaveContent( blockType, attributesSansClassName ); + const defaultClasses = getHTMLRootElementClasses( serialized ); + const actualClasses = getHTMLRootElementClasses( innerHTML ); - const customClasses = actualClasses.filter( - ( className ) => ! defaultClasses.includes( className ) - ); + const customClasses = actualClasses.filter( + ( className ) => ! defaultClasses.includes( className ) + ); - if ( customClasses.length ) { - blockAttributes.className = customClasses.join( ' ' ); - } else if ( serialized ) { - delete blockAttributes.className; - } + if ( customClasses.length ) { + modifiedBlockAttributes.className = customClasses.join( ' ' ); + } else if ( serialized ) { + delete modifiedBlockAttributes.className; } - return blockAttributes; + return modifiedBlockAttributes; } diff --git a/packages/blocks/src/api/parser/index.js b/packages/blocks/src/api/parser/index.js index f8ff0c68964dc3..14a88f602987ab 100644 --- a/packages/blocks/src/api/parser/index.js +++ b/packages/blocks/src/api/parser/index.js @@ -178,7 +178,7 @@ function applyBlockValidation( unvalidatedBlock, blockType ) { ); // Attempt to validate the block once again after the built-in fixes. const [ isFixedValid, validationIssues ] = validateBlock( - unvalidatedBlock, + fixedBlock, blockType ); diff --git a/packages/blocks/src/api/parser/test/index.js b/packages/blocks/src/api/parser/test/index.js index 85e51e9d0af025..42923a7d3eeb35 100644 --- a/packages/blocks/src/api/parser/test/index.js +++ b/packages/blocks/src/api/parser/test/index.js @@ -50,6 +50,38 @@ describe( 'block parser', () => { } ); describe( 'parseRawBlock', () => { + it( 'should apply className block validation fixes', () => { + registerBlockType( 'core/test-block', { + ...defaultBlockSettings, + attributes: { + fruit: { + type: 'string', + source: 'text', + selector: 'div', + }, + }, + save: ( { attributes } ) => ( + // eslint-disable-next-line react/no-unknown-property +
+ { attributes.fruit } +
+ ), + } ); + + const block = parseRawBlock( { + blockName: 'core/test-block', + innerHTML: + '
Bananas
', + attrs: { fruit: 'Bananas' }, + } ); + + expect( block.name ).toEqual( 'core/test-block' ); + expect( block.attributes ).toEqual( { + fruit: 'Bananas', + className: 'custom-class another-custom-class', + } ); + } ); + it( 'should create the requested block if it exists', () => { registerBlockType( 'core/test-block', defaultBlockSettings ); diff --git a/packages/blocks/src/store/private-actions.js b/packages/blocks/src/store/private-actions.js index a47d9aacab37ae..dd6650338d9d1a 100644 --- a/packages/blocks/src/store/private-actions.js +++ b/packages/blocks/src/store/private-actions.js @@ -55,6 +55,6 @@ export function registerBlockBindingsSource( source ) { setValue: source.setValue, setValues: source.setValues, getPlaceholder: source.getPlaceholder, - lockAttributesEditing: source.lockAttributesEditing, + canUserEditValue: source.canUserEditValue, }; } diff --git a/packages/blocks/src/store/reducer.js b/packages/blocks/src/store/reducer.js index 1d0d8cb2e968fc..c00810c534d55d 100644 --- a/packages/blocks/src/store/reducer.js +++ b/packages/blocks/src/store/reducer.js @@ -381,10 +381,7 @@ export function blockBindingsSources( state = {}, action ) { setValue: action.setValue, setValues: action.setValues, getPlaceholder: action.getPlaceholder, - lockAttributesEditing: () => - action.lockAttributesEditing - ? action.lockAttributesEditing() - : true, + canUserEditValue: action.canUserEditValue || ( () => false ), }, }; } diff --git a/packages/blocks/src/store/selectors.js b/packages/blocks/src/store/selectors.js index 9b2beb0b8369bd..e97048e92b0c07 100644 --- a/packages/blocks/src/store/selectors.js +++ b/packages/blocks/src/store/selectors.js @@ -7,11 +7,12 @@ import removeAccents from 'remove-accents'; * WordPress dependencies */ import { createSelector } from '@wordpress/data'; +import { RichTextData } from '@wordpress/rich-text'; /** * Internal dependencies */ -import { getValueFromObjectPath } from './utils'; +import { getValueFromObjectPath, matchesAttributes } from './utils'; /** @typedef {import('../api/registration').WPBlockVariation} WPBlockVariation */ /** @typedef {import('../api/registration').WPBlockVariationScope} WPBlockVariationScope */ @@ -237,10 +238,17 @@ export const getBlockVariations = createSelector( export function getActiveBlockVariation( state, blockName, attributes, scope ) { const variations = getBlockVariations( state, blockName, scope ); - const match = variations?.find( ( variation ) => { + if ( ! variations ) { + return variations; + } + + const blockType = getBlockType( state, blockName ); + const attributeKeys = Object.keys( blockType?.attributes || {} ); + let match; + let maxMatchedAttributes = 0; + + for ( const variation of variations ) { if ( Array.isArray( variation.isActive ) ) { - const blockType = getBlockType( state, blockName ); - const attributeKeys = Object.keys( blockType?.attributes || {} ); const definedAttributes = variation.isActive.filter( ( attribute ) => { // We support nested attribute paths, e.g. `layout.type`. @@ -250,27 +258,41 @@ export function getActiveBlockVariation( state, blockName, attributes, scope ) { return attributeKeys.includes( topLevelAttribute ); } ); - if ( definedAttributes.length === 0 ) { - return false; + const definedAttributesLength = definedAttributes.length; + if ( definedAttributesLength === 0 ) { + continue; } - return definedAttributes.every( ( attribute ) => { - const attributeValue = getValueFromObjectPath( - attributes, + const isMatch = definedAttributes.every( ( attribute ) => { + const variationAttributeValue = getValueFromObjectPath( + variation.attributes, attribute ); - if ( attributeValue === undefined ) { + if ( variationAttributeValue === undefined ) { return false; } - return ( - attributeValue === - getValueFromObjectPath( variation.attributes, attribute ) + let blockAttributeValue = getValueFromObjectPath( + attributes, + attribute + ); + if ( blockAttributeValue instanceof RichTextData ) { + blockAttributeValue = blockAttributeValue.toHTMLString(); + } + return matchesAttributes( + blockAttributeValue, + variationAttributeValue ); } ); + if ( isMatch && definedAttributesLength > maxMatchedAttributes ) { + match = variation; + maxMatchedAttributes = definedAttributesLength; + } + } else if ( variation.isActive?.( attributes, variation.attributes ) ) { + // If isActive is a function, we cannot know how many attributes it matches. + // This means that we cannot compare the specificity of our matches, + // and simply return the best match we have found. + return match || variation; } - - return variation.isActive?.( attributes, variation.attributes ); - } ); - + } return match; } diff --git a/packages/blocks/src/store/test/selectors.js b/packages/blocks/src/store/test/selectors.js index 5e3a56c34cf3b1..1f95809c9674b0 100644 --- a/packages/blocks/src/store/test/selectors.js +++ b/packages/blocks/src/store/test/selectors.js @@ -17,6 +17,11 @@ import { getActiveBlockVariation, } from '../selectors'; +/** + * WordPress dependencies + */ +import { RichTextData } from '@wordpress/rich-text'; + const keyBlocksByName = ( blocks ) => blocks.reduce( ( result, block ) => ( { ...result, [ block.name ]: block } ), @@ -291,6 +296,7 @@ describe( 'selectors', () => { testAttribute: {}, firstTestAttribute: {}, secondTestAttribute: {}, + thirdTestAttribute: {}, }, }; const FIRST_VARIATION_TEST_ATTRIBUTE_VALUE = 1; @@ -451,6 +457,120 @@ describe( 'selectors', () => { } ) ).toEqual( variations[ 1 ] ); } ); + it( 'should support RichText attributes in the isActive array', () => { + const variations = [ + { + name: 'variation-1', + attributes: { + firstTestAttribute: + 'This is a RichText attribute.', + }, + isActive: [ 'firstTestAttribute' ], + }, + { + name: 'variation-2', + attributes: { + firstTestAttribute: + 'This is a RichText attribute.', + }, + isActive: [ 'firstTestAttribute' ], + }, + ]; + const state = + createBlockVariationsStateWithTestBlockType( variations ); + + expect( + getActiveBlockVariation( state, blockName, { + firstTestAttribute: RichTextData.fromHTMLString( + 'This is a RichText attribute.' + ), + } ) + ).toEqual( variations[ 0 ] ); + expect( + getActiveBlockVariation( state, blockName, { + firstTestAttribute: RichTextData.fromHTMLString( + 'This is a RichText attribute.' + ), + } ) + ).toEqual( variations[ 1 ] ); + } ); + it( 'should compare object attributes in the isActive array based on given properties', () => { + const variations = [ + { + name: 'variation-1', + attributes: { + firstTestAttribute: { + nestedProperty: 1, + secondNestedProperty: 10, + }, + secondTestAttribute: { + nestedProperty: { + firstDeeplyNestedProperty: 'a1', + secondDeeplyNestedProperty: 'a2', + }, + }, + }, + isActive: [ + 'firstTestAttribute', + 'secondTestAttribute.nestedProperty', + ], + }, + { + name: 'variation-2', + attributes: { + firstTestAttribute: { + nestedProperty: 2, + secondNestedProperty: 20, + }, + secondTestAttribute: { + nestedProperty: { + firstDeeplyNestedProperty: 'b1', + secondDeeplyNestedProperty: 'b2', + }, + }, + }, + isActive: [ + 'firstTestAttribute', + 'secondTestAttribute.nestedProperty', + ], + }, + ]; + const state = + createBlockVariationsStateWithTestBlockType( variations ); + + expect( + getActiveBlockVariation( state, blockName, { + firstTestAttribute: { + nestedProperty: 1, + secondNestedProperty: 10, + otherNestedProperty: 5555, + }, + secondTestAttribute: { + nestedProperty: { + firstDeeplyNestedProperty: 'a1', + secondDeeplyNestedProperty: 'a2', + otherDeeplyNestedProperty: 'ffff', + }, + }, + } ) + ).toEqual( variations[ 0 ] ); + expect( + getActiveBlockVariation( state, blockName, { + firstTestAttribute: { + nestedProperty: 2, + secondNestedProperty: 20, + otherNestedProperty: 5555, + }, + secondTestAttribute: { + nestedProperty: { + firstDeeplyNestedProperty: 'b1', + secondDeeplyNestedProperty: 'b2', + otherDeeplyNestedProperty: 'ffff', + }, + }, + } ) + ).toEqual( variations[ 1 ] ); + } ); it( 'should return the active variation based on the given isActive array (multiple values)', () => { const variations = [ { @@ -510,6 +630,136 @@ describe( 'selectors', () => { } ) ).toEqual( variations[ 2 ] ); } ); + it( 'should return the active variation using the match with the highest specificity for the given isActive array (multiple values)', () => { + const variations = [ + { + name: 'variation-1', + attributes: { + firstTestAttribute: 1, + secondTestAttribute: 2, + }, + isActive: [ + 'firstTestAttribute', + 'secondTestAttribute', + ], + }, + { + name: 'variation-2', + attributes: { + firstTestAttribute: 1, + secondTestAttribute: 2, + thirdTestAttribute: 3, + }, + isActive: [ + 'firstTestAttribute', + 'secondTestAttribute', + 'thirdTestAttribute', + ], + }, + { + name: 'variation-3', + attributes: { + firstTestAttribute: 1, + thirdTestAttribute: 3, + }, + isActive: [ + 'firstTestAttribute', + 'thirdTestAttribute', + ], + }, + ]; + + const state = + createBlockVariationsStateWithTestBlockType( variations ); + + expect( + getActiveBlockVariation( state, blockName, { + firstTestAttribute: 1, + secondTestAttribute: 2, + } ) + ).toEqual( variations[ 0 ] ); + // All variations match the following attributes. Since all matches have an array for their isActive + // fields, we can compare the specificity of each match and return the most specific match. + expect( + getActiveBlockVariation( state, blockName, { + firstTestAttribute: 1, + secondTestAttribute: 2, + thirdTestAttribute: 3, + } ) + ).toEqual( variations[ 1 ] ); + expect( + getActiveBlockVariation( state, blockName, { + firstTestAttribute: 1, + thirdTestAttribute: 3, + } ) + ).toEqual( variations[ 2 ] ); + } ); + it( 'should return the active variation using the first match given the isActive array (multiple values) and function', () => { + const variations = [ + { + name: 'variation-1', + attributes: { + firstTestAttribute: 1, + secondTestAttribute: 2, + }, + isActive: [ + 'firstTestAttribute', + 'secondTestAttribute', + ], + }, + { + name: 'variation-2', + attributes: { + firstTestAttribute: 1, + secondTestAttribute: 2, + thirdTestAttribute: 3, + }, + isActive: [ + 'firstTestAttribute', + 'secondTestAttribute', + 'thirdTestAttribute', + ], + }, + { + name: 'variation-3', + attributes: { + firstTestAttribute: 1, + thirdTestAttribute: 3, + }, + isActive: ( blockAttributes, variationAttributes ) => + blockAttributes.firstTestAttribute === + variationAttributes.firstTestAttribute && + blockAttributes.thirdTestAttribute === + variationAttributes.thirdTestAttribute, + }, + ]; + + const state = + createBlockVariationsStateWithTestBlockType( variations ); + + expect( + getActiveBlockVariation( state, blockName, { + firstTestAttribute: 1, + secondTestAttribute: 2, + } ) + ).toEqual( variations[ 0 ] ); + // All variations match the following attributes. However, since the third variation has a function + // for its isActive field, we cannot compare the specificity of each match, so instead we return the + // best match we've found. + expect( + getActiveBlockVariation( state, blockName, { + firstTestAttribute: 1, + secondTestAttribute: 2, + thirdTestAttribute: 3, + } ) + ).toEqual( variations[ 1 ] ); + expect( + getActiveBlockVariation( state, blockName, { + firstTestAttribute: 1, + thirdTestAttribute: 3, + } ) + ).toEqual( variations[ 2 ] ); + } ); it( 'should ignore attributes that are not defined in the block type', () => { const variations = [ { diff --git a/packages/blocks/src/store/utils.js b/packages/blocks/src/store/utils.js index 64974bd8000b27..ce9b9f9ab3be94 100644 --- a/packages/blocks/src/store/utils.js +++ b/packages/blocks/src/store/utils.js @@ -18,3 +18,33 @@ export const getValueFromObjectPath = ( object, path, defaultValue ) => { } ); return value ?? defaultValue; }; + +function isObject( candidate ) { + return ( + typeof candidate === 'object' && + candidate.constructor === Object && + candidate !== null + ); +} + +/** + * Determine whether a set of object properties matches a given object. + * + * Given an object of block attributes and an object of variation attributes, + * this function checks recursively whether all the variation attributes are + * present in the block attributes object. + * + * @param {Object} blockAttributes The object to inspect. + * @param {Object} variationAttributes The object of property values to match. + * @return {boolean} Whether the block attributes match the variation attributes. + */ +export function matchesAttributes( blockAttributes, variationAttributes ) { + if ( isObject( blockAttributes ) && isObject( variationAttributes ) ) { + return Object.entries( variationAttributes ).every( + ( [ key, value ] ) => + matchesAttributes( blockAttributes?.[ key ], value ) + ); + } + + return blockAttributes === variationAttributes; +} diff --git a/packages/browserslist-config/CHANGELOG.md b/packages/browserslist-config/CHANGELOG.md index 51aa52e81c2b44..6737bb003c1936 100644 --- a/packages/browserslist-config/CHANGELOG.md +++ b/packages/browserslist-config/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 6.0.0 (2024-05-31) + ### Breaking Changes - Increase the minimum required Node.js version to v18.12.0 matching long-term support releases ([#31270](https://github.com/WordPress/gutenberg/pull/61930)). Learn more about [Node.js releases](https://nodejs.org/en/about/previous-releases). diff --git a/packages/browserslist-config/package.json b/packages/browserslist-config/package.json index e78bf84269cb31..4f5a1773c25f9e 100644 --- a/packages/browserslist-config/package.json +++ b/packages/browserslist-config/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/browserslist-config", - "version": "5.41.0", + "version": "6.0.0", "description": "WordPress Browserslist shared configuration.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/commands/CHANGELOG.md b/packages/commands/CHANGELOG.md index a9f5a293061827..17a55cbf221dec 100644 --- a/packages/commands/CHANGELOG.md +++ b/packages/commands/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 1.0.0 (2024-05-31) + ### Breaking Changes - Increase the minimum required Node.js version to v18.12.0 matching long-term support releases ([#31270](https://github.com/WordPress/gutenberg/pull/61930)). Learn more about [Node.js releases](https://nodejs.org/en/about/previous-releases). diff --git a/packages/commands/package.json b/packages/commands/package.json index fc89c6dd2508c2..a4a8e952f3ef1c 100644 --- a/packages/commands/package.json +++ b/packages/commands/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/commands", - "version": "0.29.0", + "version": "1.0.0", "description": "Handles the commands menu.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index dfa783103c8ba4..fd89e5e01fd0f6 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -2,6 +2,16 @@ ## Unreleased +### Enhancements + +- Add `text-wrap: balance` fallback to all instances of `text-wrap: pretty` for greater cross browser compatibility. ([#62233](https://github.com/WordPress/gutenberg/pull/62233)) + +### Bug Fixes + +- `Tabs`: Prevent accidental overflow in indicator ([#61979](https://github.com/WordPress/gutenberg/pull/61979)). + +## 28.0.0 (2024-05-31) + ### Breaking Changes - Variables like `process.env.IS_GUTENBERG_PLUGIN` have been replaced by `globalThis.IS_GUTENBERG_PLUGIN`. Build systems using `process.env` should be updated ([#61486](https://github.com/WordPress/gutenberg/pull/61486)). diff --git a/packages/components/package.json b/packages/components/package.json index 79b01e5f020ee9..89ed60367d88ea 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/components", - "version": "27.6.0", + "version": "28.0.0", "description": "UI components for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/components/src/checkbox-control/stories/index.story.tsx b/packages/components/src/checkbox-control/stories/index.story.tsx index 6752ce07667cbd..2dbc14c8cde111 100644 --- a/packages/components/src/checkbox-control/stories/index.story.tsx +++ b/packages/components/src/checkbox-control/stories/index.story.tsx @@ -142,6 +142,8 @@ export const WithCustomLabel: StoryFn< typeof CheckboxControl > = ( { setChecked( v ); onChange( v ); } } + // Disable reason: For simplicity of the code snippet. + // eslint-disable-next-line no-restricted-syntax id="my-checkbox-with-custom-label" aria-describedby="my-custom-description" /> @@ -149,6 +151,7 @@ export const WithCustomLabel: StoryFn< typeof CheckboxControl > = ( { + { /* eslint-disable-next-line no-restricted-syntax */ }
A custom description.
diff --git a/packages/components/src/custom-select-control/index.js b/packages/components/src/custom-select-control/index.js index 979aa0f7bdff8d..58ca5a961a138c 100644 --- a/packages/components/src/custom-select-control/index.js +++ b/packages/components/src/custom-select-control/index.js @@ -114,7 +114,7 @@ export default function CustomSelectControl( props ) { return sprintf( __( 'Currently selected: %s' ), selectedItem.name ); } - const menuProps = getMenuProps( { + let menuProps = getMenuProps( { className: 'components-custom-select-control__menu', 'aria-hidden': ! isOpen, } ); @@ -131,7 +131,11 @@ export default function CustomSelectControl( props ) { if ( menuProps[ 'aria-activedescendant' ]?.startsWith( 'downshift-null' ) ) { - delete menuProps[ 'aria-activedescendant' ]; + const { + 'aria-activedescendant': ariaActivedescendant, + ...restMenuProps + } = menuProps; + menuProps = restMenuProps; } return (
+- ### createHigherOrderComponent @@ -145,7 +145,7 @@ This is inspired by `lodash`'s `flow` function. _Related_ -- +- ### pure @@ -247,7 +247,7 @@ Debounces a function similar to Lodash's `debounce`. A new debounced function wi _Related_ -- +- _Parameters_ @@ -535,7 +535,7 @@ Throttles a function similar to Lodash's `throttle`. A new throttled function wi _Related_ -- +- _Parameters_ diff --git a/packages/compose/package.json b/packages/compose/package.json index 0a3308e7adb0ac..7568f2f26f08dc 100644 --- a/packages/compose/package.json +++ b/packages/compose/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/compose", - "version": "6.35.0", + "version": "7.0.0", "description": "WordPress higher-order components (HOCs).", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/compose/src/higher-order/compose.ts b/packages/compose/src/higher-order/compose.ts index 2b7b598c70c958..1fcaa55eb4512b 100644 --- a/packages/compose/src/higher-order/compose.ts +++ b/packages/compose/src/higher-order/compose.ts @@ -9,7 +9,7 @@ import { basePipe } from './pipe'; * * This is inspired by `lodash`'s `flowRight` function. * - * @see https://docs-lodash.com/v4/flow-right/ + * @see https://lodash.com/docs/4#flow-right */ const compose = basePipe( true ); diff --git a/packages/compose/src/higher-order/pipe.ts b/packages/compose/src/higher-order/pipe.ts index ced7618ad81bfd..29003d818ccc3a 100644 --- a/packages/compose/src/higher-order/pipe.ts +++ b/packages/compose/src/higher-order/pipe.ts @@ -43,7 +43,7 @@ * * Allows to choose whether to perform left-to-right or right-to-left composition. * - * @see https://docs-lodash.com/v4/flow/ + * @see https://lodash.com/docs/4#flow * * @param {boolean} reverse True if right-to-left, false for left-to-right composition. */ @@ -67,7 +67,7 @@ const basePipe = * * This is inspired by `lodash`'s `flow` function. * - * @see https://docs-lodash.com/v4/flow/ + * @see https://lodash.com/docs/4#flow */ const pipe = basePipe(); diff --git a/packages/compose/src/hooks/use-debounce/index.js b/packages/compose/src/hooks/use-debounce/index.js index 5d48dba91bde6e..6da42f159a8640 100644 --- a/packages/compose/src/hooks/use-debounce/index.js +++ b/packages/compose/src/hooks/use-debounce/index.js @@ -19,7 +19,7 @@ import { debounce } from '../../utils/debounce'; * including the function to debounce, so please wrap functions created on * render in components in `useCallback`. * - * @see https://docs-lodash.com/v4/debounce/ + * @see https://lodash.com/docs/4#debounce * * @template {(...args: any[]) => void} TFunc * diff --git a/packages/compose/src/hooks/use-throttle/index.js b/packages/compose/src/hooks/use-throttle/index.js index 8cade9a8442ac8..4bf6cc6e85555a 100644 --- a/packages/compose/src/hooks/use-throttle/index.js +++ b/packages/compose/src/hooks/use-throttle/index.js @@ -19,7 +19,7 @@ import { throttle } from '../../utils/throttle'; * including the function to throttle, so please wrap functions created on * render in components in `useCallback`. * - * @see https://docs-lodash.com/v4/throttle/ + * @see https://lodash.com/docs/4#throttle * * @template {(...args: any[]) => void} TFunc * diff --git a/packages/core-commands/CHANGELOG.md b/packages/core-commands/CHANGELOG.md index 528201ee2c5664..b05dda0cca2b23 100644 --- a/packages/core-commands/CHANGELOG.md +++ b/packages/core-commands/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 1.0.0 (2024-05-31) + ### Breaking Changes - Increase the minimum required Node.js version to v18.12.0 matching long-term support releases ([#31270](https://github.com/WordPress/gutenberg/pull/61930)). Learn more about [Node.js releases](https://nodejs.org/en/about/previous-releases). diff --git a/packages/core-commands/package.json b/packages/core-commands/package.json index 3efea9abf58e48..f79adf41f48984 100644 --- a/packages/core-commands/package.json +++ b/packages/core-commands/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/core-commands", - "version": "0.27.0", + "version": "1.0.0", "description": "WordPress core reusable commands.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/core-data/CHANGELOG.md b/packages/core-data/CHANGELOG.md index bce1d9e9d520bf..810e8ab00d21c9 100644 --- a/packages/core-data/CHANGELOG.md +++ b/packages/core-data/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 7.0.0 (2024-05-31) + ### Breaking Changes - Variables like `process.env.IS_GUTENBERG_PLUGIN` have been replaced by `globalThis.IS_GUTENBERG_PLUGIN`. Build systems using `process.env` should be updated ([#61486](https://github.com/WordPress/gutenberg/pull/61486)). diff --git a/packages/core-data/package.json b/packages/core-data/package.json index ac77ad911becbe..984de2f7628ec4 100644 --- a/packages/core-data/package.json +++ b/packages/core-data/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/core-data", - "version": "6.35.0", + "version": "7.0.0", "description": "Access to and manipulation of core WordPress entities.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/core-data/src/actions.js b/packages/core-data/src/actions.js index be4d12f0cb9ef6..36b0ba5f84c9d1 100644 --- a/packages/core-data/src/actions.js +++ b/packages/core-data/src/actions.js @@ -598,10 +598,14 @@ export const saveEntityRecord = return acc; }, { + // Do not update the `status` if we have edited it when auto saving. + // It's very important to let the user explicitly save this change, + // because it can lead to unexpected results. An example would be to + // have a draft post and change the status to publish. status: data.status === 'auto-draft' ? 'draft' - : data.status, + : undefined, } ); updatedRecord = await __unstableFetch( { diff --git a/packages/core-data/src/entity-types/theme.ts b/packages/core-data/src/entity-types/theme.ts index 761c6461d4aca8..75826c9110b652 100644 --- a/packages/core-data/src/entity-types/theme.ts +++ b/packages/core-data/src/entity-types/theme.ts @@ -129,6 +129,10 @@ declare module './base-entity-records' { * Custom font sizes if defined by the theme. */ 'editor-font-sizes': boolean | FontSize[]; + /** + * Custom spacing sizes if defined by the theme. + */ + 'editor-spacing-sizes': boolean | SpacingSize[]; /** * Custom gradient presets if defined by the theme. */ @@ -212,6 +216,12 @@ declare module './base-entity-records' { slug: string; } + export interface SpacingSize { + name: string; + size: number; + slug: string; + } + export interface GradientPreset { name: string; gradient: string; diff --git a/packages/create-block-interactive-template/CHANGELOG.md b/packages/create-block-interactive-template/CHANGELOG.md index a3e1cba44c0881..223f5de7796c62 100644 --- a/packages/create-block-interactive-template/CHANGELOG.md +++ b/packages/create-block-interactive-template/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 2.0.0 (2024-05-31) + ### Breaking Changes - Increase the minimum required Node.js version to v18.12.0 matching long-term support releases ([#31270](https://github.com/WordPress/gutenberg/pull/61930)). Learn more about [Node.js releases](https://nodejs.org/en/about/previous-releases). diff --git a/packages/create-block-interactive-template/block-templates/README.md.mustache b/packages/create-block-interactive-template/block-templates/README.md.mustache index 728f37b8c0e39f..3e64ce8f629a3c 100644 --- a/packages/create-block-interactive-template/block-templates/README.md.mustache +++ b/packages/create-block-interactive-template/block-templates/README.md.mustache @@ -1,16 +1,8 @@ # Interactive Block -> **Warning** -> **This block requires Gutenberg 16.2 or superior to work**. The Interactivity API is, at the moment, not part of WordPress Core as it is still very experimental, and very likely to change. - > **Note** -> This block uses the API shared at [Proposal: The Interactivity API – A better developer experience in building interactive blocks](https://make.wordpress.org/core/2023/03/30/proposal-the-interactivity-api-a-better-developer-experience-in-building-interactive-blocks/). +> Check the [Interactivity API Reference docs in the Block Editor handbook](https://developer.wordpress.org/block-editor/reference-guides/interactivity-api/) to learn more about the Interactivity API. {{#isBasicVariant}} This block has been created with the `create-block-interactive-template` and shows a basic structure of an interactive block that uses the Interactivity API. -{{/isBasicVariant}} - -Check the following resources for more info about the Interactivity API: -- [`@wordpress/interactivity` package](https://github.com/WordPress/gutenberg/blob/trunk/packages/interactivity/README.md) -- [Proposal: The Interactivity API – A better developer experience in building interactive blocks](https://make.wordpress.org/core/2023/03/30/proposal-the-interactivity-api-a-better-developer-experience-in-building-interactive-blocks/) -- [“Interactivity API” category](https://github.com/WordPress/gutenberg/discussions/categories/interactivity-api) in Gutenberg repo discussions \ No newline at end of file +{{/isBasicVariant}} \ No newline at end of file diff --git a/packages/create-block-interactive-template/package.json b/packages/create-block-interactive-template/package.json index 337b950b0ac499..0e11939d484025 100644 --- a/packages/create-block-interactive-template/package.json +++ b/packages/create-block-interactive-template/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/create-block-interactive-template", - "version": "1.21.0", + "version": "2.0.0", "description": "Template for @wordpress/create-block to create interactive blocks with the Interactivity API.", "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 125c54356e63bd..00537097ff945a 100644 --- a/packages/create-block-tutorial-template/CHANGELOG.md +++ b/packages/create-block-tutorial-template/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.0.0 (2024-05-31) + ### Breaking Changes - Increase the minimum required Node.js version to v18.12.0 matching long-term support releases ([#31270](https://github.com/WordPress/gutenberg/pull/61930)). Learn more about [Node.js releases](https://nodejs.org/en/about/previous-releases). diff --git a/packages/create-block-tutorial-template/package.json b/packages/create-block-tutorial-template/package.json index e03355e6e6a2a4..1b2c920457641d 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": "3.12.0", + "version": "4.0.0", "description": "This is a template for @wordpress/create-block that creates an example 'Copyright Date' block. This block is used in the official WordPress block development Quick Start Guide.", "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 409c2fbcc8ec50..0362b2a6f13412 100644 --- a/packages/create-block/CHANGELOG.md +++ b/packages/create-block/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.43.0 (2024-05-31) + ## 4.42.0 (2024-05-16) ## 4.41.0 (2024-05-02) diff --git a/packages/create-block/lib/init-wp-scripts.js b/packages/create-block/lib/init-wp-scripts.js index ca0101957f47f1..531eb970d89255 100644 --- a/packages/create-block/lib/init-wp-scripts.js +++ b/packages/create-block/lib/init-wp-scripts.js @@ -16,7 +16,7 @@ module.exports = async ( { slug } ) => { info( 'Installing `@wordpress/scripts` package. It might take a couple of minutes...' ); - await command( 'npm install @wordpress/scripts --save-dev', { + await command( 'npm install @wordpress/scripts@27 --save-dev', { cwd, } ); diff --git a/packages/create-block/package.json b/packages/create-block/package.json index 8771a1064f3288..00acf80f0ac9d1 100644 --- a/packages/create-block/package.json +++ b/packages/create-block/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/create-block", - "version": "4.42.0", + "version": "4.43.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/customize-widgets/CHANGELOG.md b/packages/customize-widgets/CHANGELOG.md index 499363d1920ef2..aec25853b2914b 100644 --- a/packages/customize-widgets/CHANGELOG.md +++ b/packages/customize-widgets/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.0.0 (2024-05-31) + ### Breaking Changes - Variables like `process.env.IS_GUTENBERG_PLUGIN` have been replaced by `globalThis.IS_GUTENBERG_PLUGIN`. Build systems using `process.env` should be updated ([#61486](https://github.com/WordPress/gutenberg/pull/61486)). diff --git a/packages/customize-widgets/package.json b/packages/customize-widgets/package.json index c3fe2dbd5e0bbf..ec320eee22a43a 100644 --- a/packages/customize-widgets/package.json +++ b/packages/customize-widgets/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/customize-widgets", - "version": "4.35.0", + "version": "5.0.0", "description": "Widgets blocks in Customizer Module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/customize-widgets/src/index.js b/packages/customize-widgets/src/index.js index 9afda775a1701c..5de010fa8bd37e 100644 --- a/packages/customize-widgets/src/index.js +++ b/packages/customize-widgets/src/index.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { createRoot } from '@wordpress/element'; +import { createRoot, StrictMode } from '@wordpress/element'; import { registerCoreBlocks, __experimentalGetCoreBlocks, @@ -92,11 +92,13 @@ export function initialize( editorName, blockEditorSettings ) { } ); createRoot( container ).render( - + + + ); } ); } diff --git a/packages/data-controls/CHANGELOG.md b/packages/data-controls/CHANGELOG.md index f90608d4d8c0cd..6b94332e70db8b 100644 --- a/packages/data-controls/CHANGELOG.md +++ b/packages/data-controls/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.0.0 (2024-05-31) + ### Breaking Changes - Increase the minimum required Node.js version to v18.12.0 matching long-term support releases ([#31270](https://github.com/WordPress/gutenberg/pull/61930)). Learn more about [Node.js releases](https://nodejs.org/en/about/previous-releases). diff --git a/packages/data-controls/package.json b/packages/data-controls/package.json index f4e1f9beda2a98..88fa9ae4faf264 100644 --- a/packages/data-controls/package.json +++ b/packages/data-controls/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/data-controls", - "version": "3.27.0", + "version": "4.0.0", "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/CHANGELOG.md b/packages/data/CHANGELOG.md index 200d37efa904d9..0e72225f04c80e 100644 --- a/packages/data/CHANGELOG.md +++ b/packages/data/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 10.0.0 (2024-05-31) + ### Breaking Changes - Increase the minimum required Node.js version to v18.12.0 matching long-term support releases ([#31270](https://github.com/WordPress/gutenberg/pull/61930)). Learn more about [Node.js releases](https://nodejs.org/en/about/previous-releases). diff --git a/packages/data/package.json b/packages/data/package.json index b289f599fad018..3246870cbe52fb 100644 --- a/packages/data/package.json +++ b/packages/data/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/data", - "version": "9.28.0", + "version": "10.0.0", "description": "Data module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/data/src/registry.js b/packages/data/src/registry.js index 02a0b19136a3e0..3e7a8fdd8b5a07 100644 --- a/packages/data/src/registry.js +++ b/packages/data/src/registry.js @@ -322,9 +322,14 @@ export function createRegistry( storeConfigs = {}, parent = null ) { emitter.pause(); Object.values( stores ).forEach( ( store ) => store.emitter.pause() ); - callback(); - emitter.resume(); - Object.values( stores ).forEach( ( store ) => store.emitter.resume() ); + try { + callback(); + } finally { + emitter.resume(); + Object.values( stores ).forEach( ( store ) => + store.emitter.resume() + ); + } } let registry = { diff --git a/packages/data/src/test/registry.js b/packages/data/src/test/registry.js index df9cb774dfc8cf..46b914d776f132 100644 --- a/packages/data/src/test/registry.js +++ b/packages/data/src/test/registry.js @@ -755,6 +755,28 @@ describe( 'createRegistry', () => { } ); expect( listener ).toHaveBeenCalledTimes( 1 ); } ); + + it( 'should handle errors', () => { + const store = registry.registerStore( 'myAwesomeReducer', { + reducer: ( state = 0 ) => state + 1, + } ); + const listener = jest.fn(); + const error = new Error( 'Whoops' ); + subscribeWithUnsubscribe( listener ); + + expect( () => { + registry.batch( () => { + throw error; + } ); + } ).toThrow( error ); + expect( listener ).not.toHaveBeenCalled(); + + registry.batch( () => { + store.dispatch( { type: 'dummy' } ); + store.dispatch( { type: 'dummy' } ); + } ); + expect( listener ).toHaveBeenCalledTimes( 1 ); + } ); } ); describe( 'use', () => { diff --git a/packages/dataviews/CHANGELOG.md b/packages/dataviews/CHANGELOG.md index 1b772a002ff7be..8b3b3656258c9e 100644 --- a/packages/dataviews/CHANGELOG.md +++ b/packages/dataviews/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 2.0.0 (2024-05-31) + ### Breaking Changes - Legacy support for `in` and `notIn` operators introduced in 0.8 .0 has been removed and they no longer work. Please, convert them to `is` and `isNot` respectively. diff --git a/packages/dataviews/package.json b/packages/dataviews/package.json index 5fb67307954014..723441e0e8b81f 100644 --- a/packages/dataviews/package.json +++ b/packages/dataviews/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/dataviews", - "version": "1.2.0", + "version": "2.0.0", "description": "DataViews is a component that provides an API to render datasets using different types of layouts (table, grid, list, etc.).", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/dataviews/src/item-actions.tsx b/packages/dataviews/src/item-actions.tsx index 8a4fcf1b19f8d8..90ae74b5f74ea6 100644 --- a/packages/dataviews/src/item-actions.tsx +++ b/packages/dataviews/src/item-actions.tsx @@ -254,6 +254,7 @@ function CompactItemActions< Item extends AnyItem >( { size="compact" icon={ moreVertical } label={ __( 'Actions' ) } + __experimentalIsFocusable disabled={ ! actions.length } className="dataviews-all-actions-button" /> diff --git a/packages/dataviews/src/style.scss b/packages/dataviews/src/style.scss index bfff3786b1112c..0390a360f66d27 100644 --- a/packages/dataviews/src/style.scss +++ b/packages/dataviews/src/style.scss @@ -370,8 +370,7 @@ line-height: 16px; &:not(:empty) { - padding: $grid-unit-15 0; - padding-top: 0; + padding: 0 0 $grid-unit-15; } .dataviews-view-grid__field { @@ -603,11 +602,6 @@ } } -.dataviews-filters__custom-menu-radio-item-prefix { - display: block; - width: 24px; -} - .dataviews-bulk-edit-button.components-button { flex-shrink: 0; } @@ -892,12 +886,14 @@ } .dataviews-bulk-actions { - position: absolute; + position: sticky; display: flex; flex-direction: column; align-content: center; flex-wrap: wrap; - width: 100%; + width: fit-content; + margin-left: auto; + margin-right: auto; bottom: $grid-unit-30; z-index: z-index(".dataviews-bulk-actions"); diff --git a/packages/dataviews/src/view-list.tsx b/packages/dataviews/src/view-list.tsx index 9468d6aa2d0585..0721a9b5d8ffe7 100644 --- a/packages/dataviews/src/view-list.tsx +++ b/packages/dataviews/src/view-list.tsx @@ -255,6 +255,7 @@ function ListItem< Item extends AnyItem >( { size="compact" icon={ moreVertical } label={ __( 'Actions' ) } + __experimentalIsFocusable disabled={ ! actions.length } onKeyDown={ ( event: { key: string; diff --git a/packages/date/CHANGELOG.md b/packages/date/CHANGELOG.md index 0bdf48871145b6..b66b2983b20be8 100644 --- a/packages/date/CHANGELOG.md +++ b/packages/date/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.0.0 (2024-05-31) + ### Breaking Changes - Increase the minimum required Node.js version to v18.12.0 matching long-term support releases ([#31270](https://github.com/WordPress/gutenberg/pull/61930)). Learn more about [Node.js releases](https://nodejs.org/en/about/previous-releases). diff --git a/packages/date/package.json b/packages/date/package.json index a3790d910e3b2d..23c66ba25823d0 100644 --- a/packages/date/package.json +++ b/packages/date/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/date", - "version": "4.58.0", + "version": "5.0.0", "description": "Date module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/dependency-extraction-webpack-plugin/CHANGELOG.md b/packages/dependency-extraction-webpack-plugin/CHANGELOG.md index 27d099308df2ad..2e152793334c0d 100644 --- a/packages/dependency-extraction-webpack-plugin/CHANGELOG.md +++ b/packages/dependency-extraction-webpack-plugin/CHANGELOG.md @@ -2,8 +2,13 @@ ## Unreleased +## 6.0.0 (2024-05-31) + ### Breaking Changes +**Note** If you're using @wordpress/scripts for building JS scripts to target WordPress 6.5 or earlier, you should not upgrade to this version and continue using @wordpress/dependency-extraction-webpack-plugin@5. + +- Use React's automatic runtime to transform JSX ([#61692](https://github.com/WordPress/gutenberg/pull/61692)). - Increase the minimum required Node.js version to v18.12.0 matching long-term support releases ([#31270](https://github.com/WordPress/gutenberg/pull/61930)). Learn more about [Node.js releases](https://nodejs.org/en/about/previous-releases). ## 5.9.0 (2024-05-16) diff --git a/packages/dependency-extraction-webpack-plugin/package.json b/packages/dependency-extraction-webpack-plugin/package.json index 3ee7f0bdb7deac..a551439c6caeb8 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": "5.9.0", + "version": "6.0.0", "description": "Extract WordPress script dependencies from webpack bundles.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/deprecated/CHANGELOG.md b/packages/deprecated/CHANGELOG.md index a38f511de523dc..99322e16983dc3 100644 --- a/packages/deprecated/CHANGELOG.md +++ b/packages/deprecated/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.0.0 (2024-05-31) + ### Breaking Changes - Increase the minimum required Node.js version to v18.12.0 matching long-term support releases ([#31270](https://github.com/WordPress/gutenberg/pull/61930)). Learn more about [Node.js releases](https://nodejs.org/en/about/previous-releases). diff --git a/packages/deprecated/package.json b/packages/deprecated/package.json index 656787a875e66b..4ef4b237980024 100644 --- a/packages/deprecated/package.json +++ b/packages/deprecated/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/deprecated", - "version": "3.58.0", + "version": "4.0.0", "description": "Deprecation utility for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/docgen/CHANGELOG.md b/packages/docgen/CHANGELOG.md index 492b7035e959c5..daffb59b72f5e9 100644 --- a/packages/docgen/CHANGELOG.md +++ b/packages/docgen/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 2.0.0 (2024-05-31) + ### Breaking Changes - Increase the minimum required Node.js version to v18.12.0 matching long-term support releases ([#31270](https://github.com/WordPress/gutenberg/pull/61930)). Learn more about [Node.js releases](https://nodejs.org/en/about/previous-releases). diff --git a/packages/docgen/package.json b/packages/docgen/package.json index 0582121d16d74b..832b0fb6a2a2aa 100644 --- a/packages/docgen/package.json +++ b/packages/docgen/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/docgen", - "version": "1.67.0", + "version": "2.0.0", "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/CHANGELOG.md b/packages/dom-ready/CHANGELOG.md index 67d4e465a65edc..b83d377c11db03 100644 --- a/packages/dom-ready/CHANGELOG.md +++ b/packages/dom-ready/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.0.0 (2024-05-31) + ### Breaking Changes - Increase the minimum required Node.js version to v18.12.0 matching long-term support releases ([#31270](https://github.com/WordPress/gutenberg/pull/61930)). Learn more about [Node.js releases](https://nodejs.org/en/about/previous-releases). diff --git a/packages/dom-ready/package.json b/packages/dom-ready/package.json index 54f4842c2d93e2..bc189f6e387b98 100644 --- a/packages/dom-ready/package.json +++ b/packages/dom-ready/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/dom-ready", - "version": "3.58.0", + "version": "4.0.0", "description": "Execute callback after the DOM is loaded.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/dom/CHANGELOG.md b/packages/dom/CHANGELOG.md index dc504c46551367..878205fae89e90 100644 --- a/packages/dom/CHANGELOG.md +++ b/packages/dom/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.0.0 (2024-05-31) + ### Breaking Changes - Increase the minimum required Node.js version to v18.12.0 matching long-term support releases ([#31270](https://github.com/WordPress/gutenberg/pull/61930)). Learn more about [Node.js releases](https://nodejs.org/en/about/previous-releases). diff --git a/packages/dom/package.json b/packages/dom/package.json index 9b8c0b8ded4ae1..e059d757b2c5ca 100644 --- a/packages/dom/package.json +++ b/packages/dom/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/dom", - "version": "3.58.0", + "version": "4.0.0", "description": "DOM utilities module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/e2e-test-utils-playwright/CHANGELOG.md b/packages/e2e-test-utils-playwright/CHANGELOG.md index f327489308b648..4fe11b5ea95014 100644 --- a/packages/e2e-test-utils-playwright/CHANGELOG.md +++ b/packages/e2e-test-utils-playwright/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 1.0.0 (2024-05-31) + ### Breaking Changes - Increase the minimum required Node.js version to v18.12.0 matching long-term support releases ([#31270](https://github.com/WordPress/gutenberg/pull/61930)). Learn more about [Node.js releases](https://nodejs.org/en/about/previous-releases). diff --git a/packages/e2e-test-utils-playwright/package.json b/packages/e2e-test-utils-playwright/package.json index 5cee2f8ee1b30d..c630ac1869c7f9 100644 --- a/packages/e2e-test-utils-playwright/package.json +++ b/packages/e2e-test-utils-playwright/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/e2e-test-utils-playwright", - "version": "0.26.0", + "version": "1.0.0", "description": "End-To-End (E2E) test utils for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/e2e-test-utils-playwright/src/request-utils/rest.ts b/packages/e2e-test-utils-playwright/src/request-utils/rest.ts index 667ccc1d9294d9..79b49dc3c7b646 100644 --- a/packages/e2e-test-utils-playwright/src/request-utils/rest.ts +++ b/packages/e2e-test-utils-playwright/src/request-utils/rest.ts @@ -3,6 +3,7 @@ */ import * as fs from 'fs/promises'; import { dirname } from 'path'; +import { expect } from '@playwright/test'; import type { APIRequestContext } from '@playwright/test'; /** @@ -39,10 +40,32 @@ async function getAPIRootURL( request: APIRequestContext ) { } async function setupRest( this: RequestUtils ): Promise< StorageState > { - const [ nonce, rootURL ] = await Promise.all( [ - this.login(), - getAPIRootURL( this.request ), - ] ); + let nonce = ''; + let rootURL = ''; + + // Poll until the REST API is discovered. + // See https://github.com/WordPress/gutenberg/issues/61627 + await expect + .poll( + async () => { + try { + [ nonce, rootURL ] = await Promise.all( [ + this.login(), + getAPIRootURL( this.request ), + ] ); + } catch ( error ) { + // Prints the error if the timeout is reached. + return error; + } + + return nonce && rootURL ? true : false; + }, + { + message: 'Failed to setup REST API.', + timeout: 60_000, // 1 minute. + } + ) + .toBe( true ); const { cookies } = await this.request.storageState(); diff --git a/packages/e2e-test-utils/CHANGELOG.md b/packages/e2e-test-utils/CHANGELOG.md index cb853af4cdb213..696b6e56b02dd1 100644 --- a/packages/e2e-test-utils/CHANGELOG.md +++ b/packages/e2e-test-utils/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 11.0.0 (2024-05-31) + ### Breaking Changes - Increase the minimum required Node.js version to v18.12.0 matching long-term support releases ([#31270](https://github.com/WordPress/gutenberg/pull/61930)). Learn more about [Node.js releases](https://nodejs.org/en/about/previous-releases). diff --git a/packages/e2e-test-utils/package.json b/packages/e2e-test-utils/package.json index 1faa1848272ab2..d791e6e37d775f 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": "10.29.0", + "version": "11.0.0", "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/CHANGELOG.md b/packages/e2e-tests/CHANGELOG.md index c377e0db8a79fc..7dcde1e1cfefef 100644 --- a/packages/e2e-tests/CHANGELOG.md +++ b/packages/e2e-tests/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 8.0.0 (2024-05-31) + ### Breaking Changes - Variables like `process.env.IS_GUTENBERG_PLUGIN` have been replaced by `globalThis.IS_GUTENBERG_PLUGIN`. Build systems using `process.env` should be updated ([#61486](https://github.com/WordPress/gutenberg/pull/61486)). diff --git a/packages/e2e-tests/package.json b/packages/e2e-tests/package.json index d678f568a92a5d..312a60d670c66a 100644 --- a/packages/e2e-tests/package.json +++ b/packages/e2e-tests/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/e2e-tests", - "version": "7.29.0", + "version": "8.0.0", "description": "End-To-End (E2E) tests for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-each/render.php b/packages/e2e-tests/plugins/interactive-blocks/directive-each/render.php index 196d04f32a2537..27fd6c7d172939 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/directive-each/render.php +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-each/render.php @@ -234,3 +234,29 @@

gamma

delta

+ +
+ +
+ +
+ +
diff --git a/packages/e2e-tests/plugins/interactive-blocks/directive-each/view.js b/packages/e2e-tests/plugins/interactive-blocks/directive-each/view.js index c78be9f81200ad..129e4f61270bd8 100644 --- a/packages/e2e-tests/plugins/interactive-blocks/directive-each/view.js +++ b/packages/e2e-tests/plugins/interactive-blocks/directive-each/view.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { store, getContext } from '@wordpress/interactivity'; +import { store, getContext, useInit, privateApis } from '@wordpress/interactivity'; const { state } = store( 'directive-each' ); @@ -190,3 +190,30 @@ store( 'directive-each', { } } ); +const { directive } = privateApis( + 'I acknowledge that using private APIs means my theme or plugin will inevitably break in the next version of WordPress.' +); + +/* + * This is a high-priority version of the wp-init directive, to test directives + * with such priority or lower don't run in elements with wp-each-child. + */ +directive( + 'priority-2-init', + ( { directives: { 'priority-2-init': init }, evaluate } ) => { + init.forEach( ( entry ) => { + useInit( () => evaluate( entry ) ); + } ); + }, + { priority: 2 } +); + +store('directive-each', { + callbacks: { + updateCallbackRunCount() { + const ctx = getContext(); + ctx.callbackRunCount += 1; + } + }, +}); + diff --git a/packages/edit-post/CHANGELOG.md b/packages/edit-post/CHANGELOG.md index 7e6b861f8183ba..3934ab8cda8848 100644 --- a/packages/edit-post/CHANGELOG.md +++ b/packages/edit-post/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 8.0.0 (2024-05-31) + ### Breaking Changes - Variables like `process.env.IS_GUTENBERG_PLUGIN` have been replaced by `globalThis.IS_GUTENBERG_PLUGIN`. Build systems using `process.env` should be updated ([#61486](https://github.com/WordPress/gutenberg/pull/61486)). diff --git a/packages/edit-post/package.json b/packages/edit-post/package.json index a968caadb3191d..b3327218dfc873 100644 --- a/packages/edit-post/package.json +++ b/packages/edit-post/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/edit-post", - "version": "7.35.0", + "version": "8.0.0", "description": "Edit Post module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/edit-post/src/components/back-button/index.js b/packages/edit-post/src/components/back-button/index.js index ecce4623cea493..04e1b205051767 100644 --- a/packages/edit-post/src/components/back-button/index.js +++ b/packages/edit-post/src/components/back-button/index.js @@ -21,12 +21,19 @@ const slideX = { function BackButton( { initialPost } ) { return ( - - - + { ( { length } ) => + length <= 1 && ( + + + + ) + } ); } diff --git a/packages/edit-post/src/components/layout/index.js b/packages/edit-post/src/components/layout/index.js index b79cefa096625d..9e50d8fb9b6c24 100644 --- a/packages/edit-post/src/components/layout/index.js +++ b/packages/edit-post/src/components/layout/index.js @@ -11,6 +11,9 @@ import { LocalAutosaveMonitor, UnsavedChangesWarning, EditorKeyboardShortcutsRegister, + EditorSnackbars, + ErrorBoundary, + PostLockedModal, store as editorStore, privateApis as editorPrivateApis, } from '@wordpress/editor'; @@ -19,21 +22,26 @@ import { privateApis as blockEditorPrivateApis, store as blockEditorStore, } from '@wordpress/block-editor'; -import { useViewportMatch } from '@wordpress/compose'; import { PluginArea } from '@wordpress/plugins'; import { __, sprintf } from '@wordpress/i18n'; import { useCallback, useMemo } from '@wordpress/element'; import { store as noticesStore } from '@wordpress/notices'; import { store as preferencesStore } from '@wordpress/preferences'; -import { privateApis as commandsPrivateApis } from '@wordpress/commands'; +import { + CommandMenu, + privateApis as commandsPrivateApis, +} from '@wordpress/commands'; import { privateApis as coreCommandsPrivateApis } from '@wordpress/core-commands'; import { privateApis as blockLibraryPrivateApis } from '@wordpress/block-library'; import { addQueryArgs } from '@wordpress/url'; +import { store as coreStore } from '@wordpress/core-data'; +import { SlotFillProvider } from '@wordpress/components'; /** * Internal dependencies */ import BackButton from '../back-button'; +import EditorInitialization from '../editor-initialization'; import EditPostKeyboardShortcuts from '../keyboard-shortcuts'; import InitPatternModal from '../init-pattern-modal'; import BrowserURL from '../browser-url'; @@ -45,12 +53,12 @@ import { unlock } from '../../lock-unlock'; import useEditPostCommands from '../../commands/use-commands'; import { usePaddingAppender } from './use-padding-appender'; import { useShouldIframe } from './use-should-iframe'; +import useNavigateToEntityRecord from '../../hooks/use-navigate-to-entity-record'; const { getLayoutStyles } = unlock( blockEditorPrivateApis ); const { useCommands } = unlock( coreCommandsPrivateApis ); const { useCommandContext } = unlock( commandsPrivateApis ); -const { EditorInterface, FullscreenMode, Sidebar } = - unlock( editorPrivateApis ); +const { Editor, FullscreenMode } = unlock( editorPrivateApis ); const { BlockKeyboardShortcuts } = unlock( blockLibraryPrivateApis ); const DESIGN_POST_TYPES = [ 'wp_template', @@ -91,7 +99,7 @@ function useEditorStyles() { ) ?? []; const defaultEditorStyles = [ - ...editorSettings.defaultEditorStyles, + ...( editorSettings?.defaultEditorStyles ?? [] ), ...presetStyles, ]; @@ -140,56 +148,92 @@ function useEditorStyles() { ] ); } -function Layout( { initialPost } ) { +function Layout( { + postId: initialPostId, + postType: initialPostType, + settings, + initialEdits, +} ) { useCommands(); useEditPostCommands(); - const isWideViewport = useViewportMatch( 'large' ); const paddingAppenderRef = usePaddingAppender(); const shouldIframe = useShouldIframe(); const { createErrorNotice } = useDispatch( noticesStore ); + const { + currentPost, + onNavigateToEntityRecord, + onNavigateToPreviousEntityRecord, + } = useNavigateToEntityRecord( + initialPostId, + initialPostType, + 'post-only' + ); const { mode, isFullscreenActive, - sidebarIsOpened, hasActiveMetaboxes, hasBlockSelected, showIconLabels, isDistractionFree, - showBlockBreadcrumbs, showMetaBoxes, hasHistory, isEditingTemplate, isWelcomeGuideVisible, - } = useSelect( ( select ) => { - const { get } = select( preferencesStore ); - const { getEditorSettings } = select( editorStore ); - const { isFeatureActive } = select( editPostStore ); + templateId, + } = useSelect( + ( select ) => { + const { get } = select( preferencesStore ); + const { isFeatureActive, getEditedPostTemplateId } = unlock( + select( editPostStore ) + ); + const { canUser, getPostType } = select( coreStore ); - return { - mode: select( editorStore ).getEditorMode(), - isFullscreenActive: - select( editPostStore ).isFeatureActive( 'fullscreenMode' ), - hasActiveMetaboxes: select( editPostStore ).hasMetaBoxes(), - hasBlockSelected: - !! select( blockEditorStore ).getBlockSelectionStart(), - showIconLabels: get( 'core', 'showIconLabels' ), - isDistractionFree: get( 'core', 'distractionFree' ), - showBlockBreadcrumbs: get( 'core', 'showBlockBreadcrumbs' ), - showMetaBoxes: - select( editorStore ).getRenderingMode() === 'post-only', - hasHistory: !! getEditorSettings().onNavigateToPreviousEntityRecord, - isEditingTemplate: - select( editorStore ).getCurrentPostType() === 'wp_template', - isWelcomeGuideVisible: isFeatureActive( 'welcomeGuide' ), - }; - }, [] ); + const supportsTemplateMode = settings.supportsTemplateMode; + const isViewable = + getPostType( currentPost.postType )?.viewable ?? false; + const canViewTemplate = canUser( 'read', 'templates' ); + + return { + mode: select( editorStore ).getEditorMode(), + isFullscreenActive: + select( editPostStore ).isFeatureActive( 'fullscreenMode' ), + hasActiveMetaboxes: select( editPostStore ).hasMetaBoxes(), + hasBlockSelected: + !! select( blockEditorStore ).getBlockSelectionStart(), + showIconLabels: get( 'core', 'showIconLabels' ), + isDistractionFree: get( 'core', 'distractionFree' ), + showMetaBoxes: + select( editorStore ).getRenderingMode() === 'post-only', + isEditingTemplate: + select( editorStore ).getCurrentPostType() === + 'wp_template', + isWelcomeGuideVisible: isFeatureActive( 'welcomeGuide' ), + templateId: + supportsTemplateMode && + isViewable && + canViewTemplate && + currentPost.postType !== 'wp_template' + ? getEditedPostTemplateId() + : null, + }; + }, + [ settings.supportsTemplateMode, currentPost.postType ] + ); // Set the right context for the command palette const commandContext = hasBlockSelected ? 'block-selection-edit' : 'entity-edit'; useCommandContext( commandContext ); - + const editorSettings = useMemo( + () => ( { + ...settings, + onNavigateToEntityRecord, + onNavigateToPreviousEntityRecord, + defaultRenderingMode: 'post-only', + } ), + [ settings, onNavigateToEntityRecord, onNavigateToPreviousEntityRecord ] + ); const styles = useEditorStyles(); // We need to add the show-icon-labels class to the body element so it is applied to modals. @@ -200,11 +244,7 @@ function Layout( { initialPost } ) { } const className = clsx( 'edit-post-layout', 'is-mode-' + mode, { - 'is-sidebar-opened': sidebarIsOpened, 'has-metaboxes': hasActiveMetaboxes, - 'is-distraction-free': isDistractionFree && isWideViewport, - 'has-block-breadcrumbs': - showBlockBreadcrumbs && ! isDistractionFree && isWideViewport, } ); function onPluginAreaError( name ) { @@ -271,47 +311,63 @@ function Layout( { initialPost } ) { [ createSuccessNotice ] ); + const initialPost = useMemo( () => { + return { + type: initialPostType, + id: initialPostId, + }; + }, [ initialPostType, initialPostId ] ); return ( - <> - - - - - - - - - - - - { ! isDistractionFree && ( - + + + + } - /> - ) } - - - - { ! isDistractionFree && showMetaBoxes && ( -
- - -
- ) } -
- + extraContent={ + ! isDistractionFree && + showMetaBoxes && ( +
+ + +
+ ) + } + > + + + + + + + + + + + + + + + +
+
+ ); } diff --git a/packages/edit-post/src/components/layout/style.scss b/packages/edit-post/src/components/layout/style.scss index e1b4ff07bf30bf..2c5a035cad1447 100644 --- a/packages/edit-post/src/components/layout/style.scss +++ b/packages/edit-post/src/components/layout/style.scss @@ -9,25 +9,12 @@ } // Adjust the position of the notices -.edit-post-layout .components-editor-notices__snackbar { +.components-editor-notices__snackbar { position: fixed; right: 0; - bottom: 16px; - padding-left: 16px; - padding-right: 16px; -} - -.is-distraction-free { - .components-editor-notices__snackbar { - bottom: 16px; - } -} - -// Adjust the position of the notices when breadcrumbs are present -.has-block-breadcrumbs { - .components-editor-notices__snackbar { - bottom: 40px; - } + bottom: 24px; + padding-left: 24px; + padding-right: 24px; } @include editor-left(".edit-post-layout .components-editor-notices__snackbar"); diff --git a/packages/edit-post/src/components/preferences-modal/enable-custom-fields.js b/packages/edit-post/src/components/preferences-modal/enable-custom-fields.js index e3ba4a15684200..e655a7300c37ee 100644 --- a/packages/edit-post/src/components/preferences-modal/enable-custom-fields.js +++ b/packages/edit-post/src/components/preferences-modal/enable-custom-fields.js @@ -42,6 +42,7 @@ export function CustomFieldsConfirmation( { willEnable } ) { className="edit-post-preferences-modal__custom-fields-confirmation-button" variant="secondary" isBusy={ isReloading } + __experimentalIsFocusable disabled={ isReloading } onClick={ () => { setIsReloading( true ); diff --git a/packages/edit-post/src/components/welcome-guide/index.js b/packages/edit-post/src/components/welcome-guide/index.js index 1bd2815466d9bc..fc7039fd7a87a3 100644 --- a/packages/edit-post/src/components/welcome-guide/index.js +++ b/packages/edit-post/src/components/welcome-guide/index.js @@ -2,7 +2,6 @@ * WordPress dependencies */ import { useSelect } from '@wordpress/data'; -import { store as editorStore } from '@wordpress/editor'; /** * Internal dependencies @@ -11,21 +10,22 @@ import WelcomeGuideDefault from './default'; import WelcomeGuideTemplate from './template'; import { store as editPostStore } from '../../store'; -export default function WelcomeGuide() { - const { isActive, isEditingTemplate } = useSelect( ( select ) => { - const { isFeatureActive } = select( editPostStore ); - const { getCurrentPostType } = select( editorStore ); - const _isEditingTemplate = getCurrentPostType() === 'wp_template'; +export default function WelcomeGuide( { postType } ) { + const { isActive, isEditingTemplate } = useSelect( + ( select ) => { + const { isFeatureActive } = select( editPostStore ); + const _isEditingTemplate = postType === 'wp_template'; + const feature = _isEditingTemplate + ? 'welcomeGuideTemplate' + : 'welcomeGuide'; - const feature = _isEditingTemplate - ? 'welcomeGuideTemplate' - : 'welcomeGuide'; - - return { - isActive: isFeatureActive( feature ), - isEditingTemplate: _isEditingTemplate, - }; - }, [] ); + return { + isActive: isFeatureActive( feature ), + isEditingTemplate: _isEditingTemplate, + }; + }, + [ postType ] + ); if ( ! isActive ) { return null; diff --git a/packages/edit-post/src/editor.js b/packages/edit-post/src/editor.js deleted file mode 100644 index 378265c1927788..00000000000000 --- a/packages/edit-post/src/editor.js +++ /dev/null @@ -1,118 +0,0 @@ -/** - * WordPress dependencies - */ -import { useSelect } from '@wordpress/data'; -import { - ErrorBoundary, - PostLockedModal, - store as editorStore, - privateApis as editorPrivateApis, -} from '@wordpress/editor'; -import { useMemo } from '@wordpress/element'; -import { SlotFillProvider } from '@wordpress/components'; -import { store as coreStore } from '@wordpress/core-data'; -import { CommandMenu } from '@wordpress/commands'; - -/** - * Internal dependencies - */ -import Layout from './components/layout'; -import EditorInitialization from './components/editor-initialization'; -import { store as editPostStore } from './store'; -import { unlock } from './lock-unlock'; -import useNavigateToEntityRecord from './hooks/use-navigate-to-entity-record'; - -const { ExperimentalEditorProvider } = unlock( editorPrivateApis ); - -function Editor( { - postId: initialPostId, - postType: initialPostType, - settings, - initialEdits, - ...props -} ) { - const { - currentPost, - onNavigateToEntityRecord, - onNavigateToPreviousEntityRecord, - } = useNavigateToEntityRecord( - initialPostId, - initialPostType, - 'post-only' - ); - - const { post, template } = useSelect( - ( select ) => { - const { getEditedPostTemplate } = select( editPostStore ); - const { getEntityRecord, getPostType, canUser } = - select( coreStore ); - const { getEditorSettings } = select( editorStore ); - - const postObject = getEntityRecord( - 'postType', - currentPost.postType, - currentPost.postId - ); - - const supportsTemplateMode = - getEditorSettings().supportsTemplateMode; - const isViewable = - getPostType( currentPost.postType )?.viewable ?? false; - const canViewTemplate = canUser( 'read', 'templates' ); - return { - template: - supportsTemplateMode && - isViewable && - canViewTemplate && - currentPost.postType !== 'wp_template' - ? getEditedPostTemplate() - : null, - post: postObject, - }; - }, - [ currentPost.postType, currentPost.postId ] - ); - - const editorSettings = useMemo( - () => ( { - ...settings, - onNavigateToEntityRecord, - onNavigateToPreviousEntityRecord, - defaultRenderingMode: 'post-only', - } ), - [ settings, onNavigateToEntityRecord, onNavigateToPreviousEntityRecord ] - ); - - const initialPost = useMemo( () => { - return { - type: initialPostType, - id: initialPostId, - }; - }, [ initialPostType, initialPostId ] ); - - if ( ! post ) { - return null; - } - - return ( - - - - - - - - - - - ); -} - -export default Editor; diff --git a/packages/edit-post/src/index.js b/packages/edit-post/src/index.js index 0ec4388a9af70e..152afc294f4283 100644 --- a/packages/edit-post/src/index.js +++ b/packages/edit-post/src/index.js @@ -7,7 +7,7 @@ import { __experimentalRegisterExperimentalCoreBlocks, } from '@wordpress/block-library'; import deprecated from '@wordpress/deprecated'; -import { createRoot } from '@wordpress/element'; +import { createRoot, StrictMode } from '@wordpress/element'; import { dispatch, select } from '@wordpress/data'; import { store as preferencesStore } from '@wordpress/preferences'; import { @@ -22,7 +22,7 @@ import { /** * Internal dependencies */ -import Editor from './editor'; +import Layout from './components/layout'; import { unlock } from './lock-unlock'; const { BackButton: __experimentalMainDashboardButton } = @@ -137,12 +137,14 @@ export function initializeEditor( window.addEventListener( 'drop', ( e ) => e.preventDefault(), false ); root.render( - + + + ); return root; diff --git a/packages/edit-post/src/store/index.js b/packages/edit-post/src/store/index.js index 567c022d2eb71b..17033b759292d7 100644 --- a/packages/edit-post/src/store/index.js +++ b/packages/edit-post/src/store/index.js @@ -9,7 +9,9 @@ import { createReduxStore, register } from '@wordpress/data'; import reducer from './reducer'; import * as actions from './actions'; import * as selectors from './selectors'; +import * as privateSelectors from './private-selectors'; import { STORE_NAME } from './constants'; +import { unlock } from '../lock-unlock'; /** * Store definition for the edit post namespace. @@ -23,5 +25,5 @@ export const store = createReduxStore( STORE_NAME, { actions, selectors, } ); - register( store ); +unlock( store ).registerPrivateSelectors( privateSelectors ); diff --git a/packages/edit-post/src/store/private-selectors.js b/packages/edit-post/src/store/private-selectors.js new file mode 100644 index 00000000000000..be23227d54a19b --- /dev/null +++ b/packages/edit-post/src/store/private-selectors.js @@ -0,0 +1,52 @@ +/** + * WordPress dependencies + */ +import { createRegistrySelector } from '@wordpress/data'; +import { store as coreStore } from '@wordpress/core-data'; +import { store as editorStore } from '@wordpress/editor'; + +export const getEditedPostTemplateId = createRegistrySelector( + ( select ) => () => { + const { + id: postId, + type: postType, + slug, + } = select( editorStore ).getCurrentPost(); + const { getSite, getEntityRecords } = select( coreStore ); + const siteSettings = getSite(); + // First check if the current page is set as the posts page. + const isPostsPage = +postId === siteSettings?.page_for_posts; + if ( isPostsPage ) { + return select( coreStore ).getDefaultTemplateId( { slug: 'home' } ); + } + const currentTemplate = + select( editorStore ).getEditedPostAttribute( 'template' ); + if ( currentTemplate ) { + const templateWithSameSlug = getEntityRecords( + 'postType', + 'wp_template', + { per_page: -1 } + )?.find( ( template ) => template.slug === currentTemplate ); + if ( ! templateWithSameSlug ) { + return templateWithSameSlug; + } + return templateWithSameSlug.id; + } + let slugToCheck; + // In `draft` status we might not have a slug available, so we use the `single` + // post type templates slug(ex page, single-post, single-product etc..). + // Pages do not need the `single` prefix in the slug to be prioritized + // through template hierarchy. + if ( slug ) { + slugToCheck = + postType === 'page' + ? `${ postType }-${ slug }` + : `single-${ postType }-${ slug }`; + } else { + slugToCheck = postType === 'page' ? 'page' : `single-${ postType }`; + } + return select( coreStore ).getDefaultTemplateId( { + slug: slugToCheck, + } ); + } +); diff --git a/packages/edit-post/src/store/selectors.js b/packages/edit-post/src/store/selectors.js index 8510cbb501955e..da1f9959e32e91 100644 --- a/packages/edit-post/src/store/selectors.js +++ b/packages/edit-post/src/store/selectors.js @@ -14,6 +14,7 @@ import deprecated from '@wordpress/deprecated'; * Internal dependencies */ import { unlock } from '../lock-unlock'; +import { getEditedPostTemplateId } from './private-selectors'; const { interfaceStore } = unlock( editorPrivateApis ); const EMPTY_ARRAY = []; @@ -555,67 +556,15 @@ export function areMetaBoxesInitialized( state ) { * @return {Object?} Post Template. */ export const getEditedPostTemplate = createRegistrySelector( - ( select ) => () => { - const { - id: postId, - type: postType, - slug, - } = select( editorStore ).getCurrentPost(); - const { getSite, getEditedEntityRecord, getEntityRecords } = - select( coreStore ); - const siteSettings = getSite(); - // First check if the current page is set as the posts page. - const isPostsPage = +postId === siteSettings?.page_for_posts; - if ( isPostsPage ) { - const defaultTemplateId = select( coreStore ).getDefaultTemplateId( - { slug: 'home' } - ); - return getEditedEntityRecord( - 'postType', - 'wp_template', - defaultTemplateId - ); - } - const currentTemplate = - select( editorStore ).getEditedPostAttribute( 'template' ); - if ( currentTemplate ) { - const templateWithSameSlug = getEntityRecords( - 'postType', - 'wp_template', - { per_page: -1 } - )?.find( ( template ) => template.slug === currentTemplate ); - if ( ! templateWithSameSlug ) { - return templateWithSameSlug; - } - return getEditedEntityRecord( - 'postType', - 'wp_template', - templateWithSameSlug.id - ); - } - let slugToCheck; - // In `draft` status we might not have a slug available, so we use the `single` - // post type templates slug(ex page, single-post, single-product etc..). - // Pages do not need the `single` prefix in the slug to be prioritized - // through template hierarchy. - if ( slug ) { - slugToCheck = - postType === 'page' - ? `${ postType }-${ slug }` - : `single-${ postType }-${ slug }`; - } else { - slugToCheck = postType === 'page' ? 'page' : `single-${ postType }`; + ( select ) => ( state ) => { + const templateId = getEditedPostTemplateId( state ); + if ( ! templateId ) { + return undefined; } - const defaultTemplateId = select( coreStore ).getDefaultTemplateId( { - slug: slugToCheck, - } ); - - return defaultTemplateId - ? select( coreStore ).getEditedEntityRecord( - 'postType', - 'wp_template', - defaultTemplateId - ) - : null; + return select( coreStore ).getEditedEntityRecord( + 'postType', + 'wp_template', + templateId + ); } ); diff --git a/packages/edit-site/CHANGELOG.md b/packages/edit-site/CHANGELOG.md index 0997d17e849ede..67b5d055450f80 100644 --- a/packages/edit-site/CHANGELOG.md +++ b/packages/edit-site/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 6.0.0 (2024-05-31) + ### Breaking Changes - Variables like `process.env.IS_GUTENBERG_PLUGIN` have been replaced by `globalThis.IS_GUTENBERG_PLUGIN`. Build systems using `process.env` should be updated ([#61486](https://github.com/WordPress/gutenberg/pull/61486)). diff --git a/packages/edit-site/package.json b/packages/edit-site/package.json index 7132e67401a225..784407cd3f12ba 100644 --- a/packages/edit-site/package.json +++ b/packages/edit-site/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/edit-site", - "version": "5.35.0", + "version": "6.0.0", "description": "Edit Site Page module for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/edit-site/src/components/add-new-template/index.js b/packages/edit-site/src/components/add-new-template/index.js index 75d69f32e823d2..3705010be48533 100644 --- a/packages/edit-site/src/components/add-new-template/index.js +++ b/packages/edit-site/src/components/add-new-template/index.js @@ -128,6 +128,7 @@ function TemplateListItem( { spacing={ 0 } > diff --git a/packages/edit-site/src/components/block-editor/block-inspector-button.js b/packages/edit-site/src/components/block-editor/block-inspector-button.js deleted file mode 100644 index 0c669b21fda833..00000000000000 --- a/packages/edit-site/src/components/block-editor/block-inspector-button.js +++ /dev/null @@ -1,60 +0,0 @@ -/** - * WordPress dependencies - */ -import { __ } from '@wordpress/i18n'; -import { speak } from '@wordpress/a11y'; -import { MenuItem } from '@wordpress/components'; -import { useSelect, useDispatch } from '@wordpress/data'; -import { store as keyboardShortcutsStore } from '@wordpress/keyboard-shortcuts'; -import { privateApis as editorPrivateApis } from '@wordpress/editor'; - -/** - * Internal dependencies - */ -import { unlock } from '../../lock-unlock'; - -const { interfaceStore } = unlock( editorPrivateApis ); - -export default function BlockInspectorButton( { onClick = () => {} } ) { - const { shortcut, isBlockInspectorOpen } = useSelect( - ( select ) => ( { - shortcut: select( - keyboardShortcutsStore - ).getShortcutRepresentation( 'core/editor/toggle-sidebar' ), - isBlockInspectorOpen: - select( interfaceStore ).getActiveComplementaryArea( - 'core' - ) === 'edit-post/block', - } ), - [] - ); - const { enableComplementaryArea, disableComplementaryArea } = - useDispatch( interfaceStore ); - - const label = isBlockInspectorOpen - ? __( 'Hide more settings' ) - : __( 'Show more settings' ); - - return ( - { - if ( isBlockInspectorOpen ) { - disableComplementaryArea( 'core' ); - speak( __( 'Block settings closed' ) ); - } else { - enableComplementaryArea( 'core', 'edit-post/block' ); - speak( - __( - 'Additional settings are now available in the Editor block settings sidebar' - ) - ); - } - // Close dropdown menu. - onClick(); - } } - shortcut={ shortcut } - > - { label } - - ); -} diff --git a/packages/edit-site/src/components/block-editor/inserter-media-categories.js b/packages/edit-site/src/components/block-editor/inserter-media-categories.js deleted file mode 100644 index af591d1fa24688..00000000000000 --- a/packages/edit-site/src/components/block-editor/inserter-media-categories.js +++ /dev/null @@ -1,227 +0,0 @@ -/** - * The `edit-site` settings here need to be in sync with the corresponding ones in `site-editor` package. - * See `packages/edit-site/src/components/block-editor/inserter-media-categories.js`. - * - * In the future we could consider creating an Openvese package that can be used in both `editor` and `site-editor`. - * The rest of the settings would still need to be in sync though. - */ - -/** - * WordPress dependencies - */ -import { __, sprintf, _x } from '@wordpress/i18n'; -import { resolveSelect } from '@wordpress/data'; -import { decodeEntities } from '@wordpress/html-entities'; - -/** - * Internal dependencies - */ -import { store as coreStore } from '@wordpress/core-data'; - -/** @typedef {import('@wordpress/block-editor').InserterMediaRequest} InserterMediaRequest */ -/** @typedef {import('@wordpress/block-editor').InserterMediaItem} InserterMediaItem */ -/** @typedef {import('@wordpress/block-editor').InserterMediaCategory} InserterMediaCategory */ - -const getExternalLink = ( url, text ) => - `
${ text }`; - -const getExternalLinkAttributes = ( url ) => - `href="${ url }" target="_blank" rel="noreferrer noopener"`; - -const getOpenverseLicense = ( license, licenseVersion ) => { - let licenseName = license.trim(); - // PDM has no abbreviation - if ( license !== 'pdm' ) { - licenseName = license.toUpperCase().replace( 'SAMPLING', 'Sampling' ); - } - // If version is known, append version to the name. - // The license has to have a version to be valid. Only - // PDM (public domain mark) doesn't have a version. - if ( licenseVersion ) { - licenseName += ` ${ licenseVersion }`; - } - // For licenses other than public-domain marks, prepend 'CC' to the name. - if ( ! [ 'pdm', 'cc0' ].includes( license ) ) { - licenseName = `CC ${ licenseName }`; - } - return licenseName; -}; - -const getOpenverseCaption = ( item ) => { - const { - title, - foreign_landing_url: foreignLandingUrl, - creator, - creator_url: creatorUrl, - license, - license_version: licenseVersion, - license_url: licenseUrl, - } = item; - const fullLicense = getOpenverseLicense( license, licenseVersion ); - const _creator = decodeEntities( creator ); - let _caption; - if ( _creator ) { - _caption = title - ? sprintf( - // translators: %1s: Title of a media work from Openverse; %2s: Name of the work's creator; %3s: Work's licence e.g: "CC0 1.0". - _x( '"%1$s" by %2$s/ %3$s', 'caption' ), - getExternalLink( - foreignLandingUrl, - decodeEntities( title ) - ), - creatorUrl - ? getExternalLink( creatorUrl, _creator ) - : _creator, - licenseUrl - ? getExternalLink( - `${ licenseUrl }?ref=openverse`, - fullLicense - ) - : fullLicense - ) - : sprintf( - // translators: %1s: Link attributes for a given Openverse media work; %2s: Name of the work's creator; %3s: Works's licence e.g: "CC0 1.0". - _x( 'Work by %2$s/ %3$s', 'caption' ), - getExternalLinkAttributes( foreignLandingUrl ), - creatorUrl - ? getExternalLink( creatorUrl, _creator ) - : _creator, - licenseUrl - ? getExternalLink( - `${ licenseUrl }?ref=openverse`, - fullLicense - ) - : fullLicense - ); - } else { - _caption = title - ? sprintf( - // translators: %1s: Title of a media work from Openverse; %2s: Work's licence e.g: "CC0 1.0". - _x( '"%1$s"/ %2$s', 'caption' ), - getExternalLink( - foreignLandingUrl, - decodeEntities( title ) - ), - licenseUrl - ? getExternalLink( - `${ licenseUrl }?ref=openverse`, - fullLicense - ) - : fullLicense - ) - : sprintf( - // translators: %1s: Link attributes for a given Openverse media work; %2s: Works's licence e.g: "CC0 1.0". - _x( 'Work/ %3$s', 'caption' ), - getExternalLinkAttributes( foreignLandingUrl ), - licenseUrl - ? getExternalLink( - `${ licenseUrl }?ref=openverse`, - fullLicense - ) - : fullLicense - ); - } - return _caption.replace( /\s{2}/g, ' ' ); -}; - -const coreMediaFetch = async ( query = {} ) => { - const mediaItems = await resolveSelect( coreStore ).getMediaItems( { - ...query, - orderBy: !! query?.search ? 'relevance' : 'date', - } ); - return mediaItems.map( ( mediaItem ) => ( { - ...mediaItem, - alt: mediaItem.alt_text, - url: mediaItem.source_url, - previewUrl: mediaItem.media_details?.sizes?.medium?.source_url, - caption: mediaItem.caption?.raw, - } ) ); -}; - -/** @type {InserterMediaCategory[]} */ -const inserterMediaCategories = [ - { - name: 'images', - labels: { - name: __( 'Images' ), - search_items: __( 'Search images' ), - }, - mediaType: 'image', - async fetch( query = {} ) { - return coreMediaFetch( { ...query, media_type: 'image' } ); - }, - }, - { - name: 'videos', - labels: { - name: __( 'Videos' ), - search_items: __( 'Search videos' ), - }, - mediaType: 'video', - async fetch( query = {} ) { - return coreMediaFetch( { ...query, media_type: 'video' } ); - }, - }, - { - name: 'audio', - labels: { - name: __( 'Audio' ), - search_items: __( 'Search audio' ), - }, - mediaType: 'audio', - async fetch( query = {} ) { - return coreMediaFetch( { ...query, media_type: 'audio' } ); - }, - }, - { - name: 'openverse', - labels: { - name: __( 'Openverse' ), - search_items: __( 'Search Openverse' ), - }, - mediaType: 'image', - async fetch( query = {} ) { - const defaultArgs = { - mature: false, - excluded_source: 'flickr,inaturalist,wikimedia', - license: 'pdm,cc0', - }; - const finalQuery = { ...query, ...defaultArgs }; - const mapFromInserterMediaRequest = { - per_page: 'page_size', - search: 'q', - }; - const url = new URL( - 'https://api.openverse.engineering/v1/images/' - ); - Object.entries( finalQuery ).forEach( ( [ key, value ] ) => { - const queryKey = mapFromInserterMediaRequest[ key ] || key; - url.searchParams.set( queryKey, value ); - } ); - const response = await window.fetch( url, { - headers: { - 'User-Agent': 'WordPress/inserter-media-fetch', - }, - } ); - const jsonResponse = await response.json(); - const results = jsonResponse.results; - return results.map( ( result ) => ( { - ...result, - // This is a temp solution for better titles, until Openverse API - // completes the cleaning up of some titles of their upstream data. - title: result.title?.toLowerCase().startsWith( 'file:' ) - ? result.title.slice( 5 ) - : result.title, - sourceId: result.id, - id: undefined, - caption: getOpenverseCaption( result ), - previewUrl: result.thumbnail, - } ) ); - }, - getReportUrl: ( { sourceId } ) => - `https://wordpress.org/openverse/image/${ sourceId }/report/`, - isExternalResource: true, - }, -]; - -export default inserterMediaCategories; diff --git a/packages/edit-site/src/components/block-editor/site-editor-canvas.js b/packages/edit-site/src/components/block-editor/site-editor-canvas.js deleted file mode 100644 index 03d11dcf8237ef..00000000000000 --- a/packages/edit-site/src/components/block-editor/site-editor-canvas.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Internal dependencies - */ -import EditorCanvas from './editor-canvas'; -import EditorCanvasContainer from '../editor-canvas-container'; -import useSiteEditorSettings from './use-site-editor-settings'; - -export default function SiteEditorCanvas() { - const settings = useSiteEditorSettings(); - - return ( - - { ( [ editorCanvasView ] ) => - editorCanvasView ? ( -
- { editorCanvasView } -
- ) : ( - - ) - } -
- ); -} diff --git a/packages/edit-site/src/components/block-editor/style.scss b/packages/edit-site/src/components/block-editor/style.scss index 14f2074130d116..3849eed24a4ea3 100644 --- a/packages/edit-site/src/components/block-editor/style.scss +++ b/packages/edit-site/src/components/block-editor/style.scss @@ -1,29 +1,3 @@ -// The button element easily inherits styles that are meant for the editor style. -// These rules enhance the specificity to reduce that inheritance. -// This is duplicated in visual-editor. -.edit-site-block-editor__editor-styles-wrapper .components-button { - font-family: $default-font; - font-size: $default-font-size; - padding: 6px 12px; - - &.is-tertiary, - &.has-icon { - padding: 6px; - } -} - -.edit-site-visual-editor { - height: 100%; - background-color: $gray-300; - - // Controls height of editor and editor canvas container (style book, global styles revisions previews etc.) - iframe { - display: block; - width: 100%; - height: 100%; - } -} - .edit-site-visual-editor__editor-canvas { &.is-focused { outline: calc(2 * var(--wp-admin-border-width-focus)) solid var(--wp-admin-theme-color); diff --git a/packages/edit-site/src/components/block-editor/editor-canvas.js b/packages/edit-site/src/components/block-editor/use-editor-iframe-props.js similarity index 62% rename from packages/edit-site/src/components/block-editor/editor-canvas.js rename to packages/edit-site/src/components/block-editor/use-editor-iframe-props.js index bac51c5df7d335..3b5c9f7fe65726 100644 --- a/packages/edit-site/src/components/block-editor/editor-canvas.js +++ b/packages/edit-site/src/components/block-editor/use-editor-iframe-props.js @@ -8,12 +8,9 @@ import clsx from 'clsx'; */ import { useSelect, useDispatch } from '@wordpress/data'; import { ENTER, SPACE } from '@wordpress/keycodes'; -import { useState, useEffect, useMemo } from '@wordpress/element'; +import { useState, useEffect } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; -import { - store as editorStore, - privateApis as editorPrivateApis, -} from '@wordpress/editor'; +import { store as editorStore } from '@wordpress/editor'; /** * Internal dependencies @@ -21,9 +18,7 @@ import { import { unlock } from '../../lock-unlock'; import { store as editSiteStore } from '../../store'; -const { VisualEditor } = unlock( editorPrivateApis ); - -function EditorCanvas( { settings } ) { +export default function useEditorIframeProps() { const { canvasMode, currentPostIsTrashed } = useSelect( ( select ) => { const { getCanvasMode } = unlock( select( editSiteStore ) ); @@ -75,36 +70,10 @@ function EditorCanvas( { settings } ) { readonly: true, }; - const styles = useMemo( - () => [ - ...settings.styles, - { - // Forming a "block formatting context" to prevent margin collapsing. - // @see https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Block_formatting_context - - css: `body{${ - canvasMode === 'view' - ? `min-height: 100vh; ${ - currentPostIsTrashed ? '' : 'cursor: pointer;' - }` - : '' - }}}`, - }, - ], - [ settings.styles, canvasMode, currentPostIsTrashed ] - ); - - return ( - - ); + return { + className: clsx( 'edit-site-visual-editor__editor-canvas', { + 'is-focused': isFocused && canvasMode === 'view', + } ), + ...( canvasMode === 'view' ? viewModeIframeProps : {} ), + }; } - -export default EditorCanvas; diff --git a/packages/edit-site/src/components/editor-canvas-container/index.js b/packages/edit-site/src/components/editor-canvas-container/index.js index ca5bc3a0b34f45..baebc1bc1bc894 100644 --- a/packages/edit-site/src/components/editor-canvas-container/index.js +++ b/packages/edit-site/src/components/editor-canvas-container/index.js @@ -4,7 +4,6 @@ import { Children, cloneElement, useState } from '@wordpress/element'; import { Button, - privateApis as componentsPrivateApis, __experimentalUseSlotFills as useSlotFills, } from '@wordpress/components'; import { ESCAPE } from '@wordpress/keycodes'; @@ -24,7 +23,7 @@ import { import { unlock } from '../../lock-unlock'; import { store as editSiteStore } from '../../store'; -const { ResizableEditor } = unlock( editorPrivateApis ); +const { EditorContentSlotFill, ResizableEditor } = unlock( editorPrivateApis ); /** * Returns a translated string for the title of the editor canvas container. @@ -45,15 +44,6 @@ function getEditorCanvasContainerTitle( view ) { } } -// Creates a private slot fill. -const { createPrivateSlotFill } = unlock( componentsPrivateApis ); -const SLOT_FILL_NAME = 'EditSiteEditorCanvasContainerSlot'; -const { - privateKey, - Slot: EditorCanvasContainerSlot, - Fill: EditorCanvasContainerFill, -} = createPrivateSlotFill( SLOT_FILL_NAME ); - function EditorCanvasContainer( { children, closeButtonLabel, @@ -123,7 +113,7 @@ function EditorCanvasContainer( { const shouldShowCloseButton = onClose || closeButtonLabel; return ( - +
{ /* eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions */ } @@ -145,14 +135,13 @@ function EditorCanvasContainer( {
-
+ ); } function useHasEditorCanvasContainer() { - const fills = useSlotFills( privateKey ); + const fills = useSlotFills( EditorContentSlotFill.privateKey ); return !! fills?.length; } -EditorCanvasContainer.Slot = EditorCanvasContainerSlot; export default EditorCanvasContainer; export { useHasEditorCanvasContainer, getEditorCanvasContainerTitle }; diff --git a/packages/edit-site/src/components/editor-canvas-container/style.scss b/packages/edit-site/src/components/editor-canvas-container/style.scss index 0aca5f8045ce8a..fad566212e7328 100644 --- a/packages/edit-site/src/components/editor-canvas-container/style.scss +++ b/packages/edit-site/src/components/editor-canvas-container/style.scss @@ -1,5 +1,13 @@ .edit-site-editor-canvas-container { height: 100%; + background-color: $gray-300; + + // Controls height of editor and editor canvas container (style book, global styles revisions previews etc.) + iframe { + display: block; + width: 100%; + height: 100%; + } .edit-site-layout.is-full-canvas & { padding: $grid-unit-30 $grid-unit-30 0; diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js index 0384b3c80ab42d..779b69cdeeef21 100644 --- a/packages/edit-site/src/components/editor/index.js +++ b/packages/edit-site/src/components/editor/index.js @@ -7,189 +7,124 @@ import clsx from 'clsx'; * WordPress dependencies */ import { useDispatch, useSelect } from '@wordpress/data'; -import { Notice } from '@wordpress/components'; -import { useInstanceId, useViewportMatch } from '@wordpress/compose'; -import { store as preferencesStore } from '@wordpress/preferences'; -import { - BlockBreadcrumb, - BlockToolbar, - store as blockEditorStore, -} from '@wordpress/block-editor'; +import { useInstanceId } from '@wordpress/compose'; import { EditorKeyboardShortcutsRegister, - EditorNotices, privateApis as editorPrivateApis, store as editorStore, } from '@wordpress/editor'; import { __, sprintf } from '@wordpress/i18n'; import { store as coreDataStore } from '@wordpress/core-data'; import { privateApis as blockLibraryPrivateApis } from '@wordpress/block-library'; -import { useState, useCallback } from '@wordpress/element'; +import { useCallback, useMemo } from '@wordpress/element'; import { store as noticesStore } from '@wordpress/notices'; import { privateApis as routerPrivateApis } from '@wordpress/router'; +import { store as preferencesStore } from '@wordpress/preferences'; /** * Internal dependencies */ -import Header from '../header-edit-mode'; import WelcomeGuide from '../welcome-guide'; import { store as editSiteStore } from '../../store'; import { GlobalStylesRenderer } from '../global-styles-renderer'; -import useTitle from '../routes/use-title'; import CanvasLoader from '../canvas-loader'; import { unlock } from '../../lock-unlock'; -import useEditedEntityRecord from '../use-edited-entity-record'; -import { POST_TYPE_LABELS, TEMPLATE_POST_TYPE } from '../../utils/constants'; -import SiteEditorCanvas from '../block-editor/site-editor-canvas'; import TemplatePartConverter from '../template-part-converter'; import { useSpecificEditorSettings } from '../block-editor/use-site-editor-settings'; import PluginTemplateSettingPanel from '../plugin-template-setting-panel'; import GlobalStylesSidebar from '../global-styles-sidebar'; - -const { - ExperimentalEditorProvider: EditorProvider, - InserterSidebar, - ListViewSidebar, - InterfaceSkeleton, - ComplementaryArea, - SavePublishPanels, - Sidebar, - TextEditor, -} = unlock( editorPrivateApis ); +import { isPreviewingTheme } from '../../utils/is-previewing-theme'; +import { + getEditorCanvasContainerTitle, + useHasEditorCanvasContainer, +} from '../editor-canvas-container'; +import SaveButton from '../save-button'; +import SiteEditorMoreMenu from '../more-menu'; +import useEditorIframeProps from '../block-editor/use-editor-iframe-props'; +import useEditorTitle from './use-editor-title'; + +const { Editor } = unlock( editorPrivateApis ); const { useHistory } = unlock( routerPrivateApis ); const { BlockKeyboardShortcuts } = unlock( blockLibraryPrivateApis ); -const interfaceLabels = { - /* translators: accessibility text for the editor content landmark region. */ - body: __( 'Editor content' ), - /* translators: accessibility text for the editor settings landmark region. */ - sidebar: __( 'Editor settings' ), - /* translators: accessibility text for the editor publish landmark region. */ - actions: __( 'Editor publish' ), - /* translators: accessibility text for the editor footer landmark region. */ - footer: __( 'Editor footer' ), - /* translators: accessibility text for the editor header landmark region. */ - header: __( 'Editor top bar' ), -}; - -export default function Editor( { isLoading } ) { - const { - record: editedPost, - getTitle, - isLoaded: hasLoadedPost, - } = useEditedEntityRecord(); - - const { type: editedPostType } = editedPost; - - const isLargeViewport = useViewportMatch( 'medium' ); - +export default function EditSiteEditor( { isLoading } ) { const { - context, - contextPost, + editedPostType, + editedPostId, + contextPostType, + contextPostId, editorMode, canvasMode, - blockEditorMode, - isInserterOpen, - isListViewOpen, - isDistractionFree, - showIconLabels, - showBlockBreadcrumbs, - postTypeLabel, isEditingPage, supportsGlobalStyles, + showIconLabels, + editorCanvasView, + currentPostIsTrashed, } = useSelect( ( select ) => { - const { get } = select( preferencesStore ); - const { getEditedPostContext, getCanvasMode, isPage } = unlock( - select( editSiteStore ) - ); - const { __unstableGetEditorMode } = select( blockEditorStore ); - const { getEntityRecord, getCurrentTheme } = select( coreDataStore ); const { - isInserterOpened, - isListViewOpened, - getPostTypeLabel, - getEditorMode, - } = select( editorStore ); + getEditedPostContext, + getCanvasMode, + isPage, + getEditedPostType, + getEditedPostId, + } = unlock( select( editSiteStore ) ); + const { get } = select( preferencesStore ); + const { getCurrentTheme } = select( coreDataStore ); + const { getEditorMode } = select( editorStore ); const _context = getEditedPostContext(); // The currently selected entity to display. // Typically template or template part in the site editor. return { - context: _context, - contextPost: _context?.postId - ? getEntityRecord( - 'postType', - _context.postType, - _context.postId - ) - : undefined, + editedPostType: getEditedPostType(), + editedPostId: getEditedPostId(), + contextPostType: _context?.postId ? _context.postType : undefined, + contextPostId: _context?.postId ? _context.postId : undefined, editorMode: getEditorMode(), canvasMode: getCanvasMode(), - blockEditorMode: __unstableGetEditorMode(), - isInserterOpen: isInserterOpened(), - isListViewOpen: isListViewOpened(), - isDistractionFree: get( 'core', 'distractionFree' ), - showBlockBreadcrumbs: get( 'core', 'showBlockBreadcrumbs' ), - showIconLabels: get( 'core', 'showIconLabels' ), - postTypeLabel: getPostTypeLabel(), isEditingPage: isPage(), supportsGlobalStyles: getCurrentTheme()?.is_block_theme, + showIconLabels: get( 'core', 'showIconLabels' ), + editorCanvasView: unlock( + select( editSiteStore ) + ).getEditorCanvasContainerView(), + currentPostIsTrashed: + select( editorStore ).getCurrentPostAttribute( 'status' ) === + 'trash', }; }, [] ); - + useEditorTitle(); + const _isPreviewingTheme = isPreviewingTheme(); + const hasDefaultEditorCanvasView = ! useHasEditorCanvasContainer(); + const iframeProps = useEditorIframeProps(); const isViewMode = canvasMode === 'view'; const isEditMode = canvasMode === 'edit'; const showVisualEditor = isViewMode || editorMode === 'visual'; - const shouldShowBlockBreadcrumbs = - ! isDistractionFree && - showBlockBreadcrumbs && - isEditMode && - showVisualEditor && - blockEditorMode !== 'zoom-out'; - const shouldShowInserter = isEditMode && showVisualEditor && isInserterOpen; - const shouldShowListView = isEditMode && showVisualEditor && isListViewOpen; - const secondarySidebarLabel = isListViewOpen - ? __( 'List View' ) - : __( 'Block Library' ); - const postWithTemplate = !! context?.postId; - - let title; - if ( hasLoadedPost ) { - title = sprintf( - // translators: A breadcrumb trail for the Admin document title. %1$s: title of template being edited, %2$s: type of template (Template or Template Part). - __( '%1$s ‹ %2$s' ), - getTitle(), - POST_TYPE_LABELS[ editedPostType ] ?? - POST_TYPE_LABELS[ TEMPLATE_POST_TYPE ] - ); - } - - // Only announce the title once the editor is ready to prevent "Replace" - // action in from double-announcing. - useTitle( hasLoadedPost && title ); - + const postWithTemplate = !! contextPostId; const loadingProgressId = useInstanceId( CanvasLoader, 'edit-site-editor__loading-progress' ); const settings = useSpecificEditorSettings(); - - // Local state for save panel. - // Note 'truthy' callback implies an open panel. - const [ entitiesSavedStatesCallback, setEntitiesSavedStatesCallback ] = - useState( false ); - - const closeEntitiesSavedStates = useCallback( - ( arg ) => { - if ( typeof entitiesSavedStatesCallback === 'function' ) { - entitiesSavedStatesCallback( arg ); - } - setEntitiesSavedStatesCallback( false ); - }, - [ entitiesSavedStatesCallback ] + const styles = useMemo( + () => [ + ...settings.styles, + { + // Forming a "block formatting context" to prevent margin collapsing. + // @see https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Block_formatting_context + + css: `body{${ + canvasMode === 'view' + ? `min-height: 100vh; ${ + currentPostIsTrashed ? '' : 'cursor: pointer;' + }` + : '' + }}}`, + }, + ], + [ settings.styles, canvasMode, currentPostIsTrashed ] ); - const { createSuccessNotice } = useDispatch( noticesStore ); const history = useHistory(); const onActionPerformed = useCallback( @@ -240,10 +175,7 @@ export default function Editor( { isLoading } ) { [ history, createSuccessNotice ] ); - const isReady = - ! isLoading && - ( ( postWithTemplate && !! contextPost && !! editedPost ) || - ( ! postWithTemplate && !! editedPost ) ); + const isReady = ! isLoading; return ( <> @@ -253,100 +185,37 @@ export default function Editor( { isLoading } ) { { showVisualEditor && } { ! isReady ? : null } { isEditMode && } - { hasLoadedPost && ! editedPost && ( - - { __( - "You attempted to edit an item that doesn't exist. Perhaps it was deleted?" - ) } - - ) } { isReady && ( - + } + forceDisableBlockTools={ ! hasDefaultEditorCanvasView } + title={ + ! hasDefaultEditorCanvasView + ? getEditorCanvasContainerTitle( editorCanvasView ) + : undefined + } + iframeProps={ iframeProps } + onActionPerformed={ onActionPerformed } + extraSidebarPanels={ + ! isEditingPage && + } > - - ) - } - actions={ - - } - content={ - <> - { isEditMode && } - { editorMode === 'text' && isEditMode && ( - - ) } - { ! isLargeViewport && showVisualEditor && ( - - ) } - { showVisualEditor && } - - } - secondarySidebar={ - isEditMode && - ( ( shouldShowInserter && ) || - ( shouldShowListView && ) ) - } - sidebar={ - isEditMode && - ! isDistractionFree && ( - - ) - } - footer={ - shouldShowBlockBreadcrumbs && ( - - ) - } - labels={ { - ...interfaceLabels, - secondarySidebar: secondarySidebarLabel, - } } - /> - - ) - } - /> + { supportsGlobalStyles && } - + ) } ); diff --git a/packages/edit-site/src/components/editor/style.scss b/packages/edit-site/src/components/editor/style.scss index 92c7727be6be00..f44b5a6f02ce20 100644 --- a/packages/edit-site/src/components/editor/style.scss +++ b/packages/edit-site/src/components/editor/style.scss @@ -1,4 +1,4 @@ -.edit-site-editor__interface-skeleton { +.edit-site-editor__editor-interface { opacity: 1; transition: opacity 0.1s ease-out; @include reduce-motion("transition"); @@ -17,3 +17,7 @@ display: flex; justify-content: center; } + +.editor-header { + padding-left: $header-height; +} diff --git a/packages/edit-site/src/components/editor/use-editor-title.js b/packages/edit-site/src/components/editor/use-editor-title.js new file mode 100644 index 00000000000000..01e258a5db1073 --- /dev/null +++ b/packages/edit-site/src/components/editor/use-editor-title.js @@ -0,0 +1,35 @@ +/** + * WordPress dependencies + */ +import { __, sprintf } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import useEditedEntityRecord from '../use-edited-entity-record'; +import useTitle from '../routes/use-title'; +import { POST_TYPE_LABELS, TEMPLATE_POST_TYPE } from '../../utils/constants'; + +function useEditorTitle() { + const { + record: editedPost, + getTitle, + isLoaded: hasLoadedPost, + } = useEditedEntityRecord(); + let title; + if ( hasLoadedPost ) { + title = sprintf( + // translators: A breadcrumb trail for the Admin document title. %1$s: title of template being edited, %2$s: type of template (Template or Template Part). + __( '%1$s ‹ %2$s' ), + getTitle(), + POST_TYPE_LABELS[ editedPost.type ] ?? + POST_TYPE_LABELS[ TEMPLATE_POST_TYPE ] + ); + } + + // Only announce the title once the editor is ready to prevent "Replace" + // action in from double-announcing. + useTitle( hasLoadedPost && title ); +} + +export default useEditorTitle; diff --git a/packages/edit-site/src/components/global-styles-sidebar/index.js b/packages/edit-site/src/components/global-styles-sidebar/index.js index 436762d6bcf94f..f57cc8c417f410 100644 --- a/packages/edit-site/src/components/global-styles-sidebar/index.js +++ b/packages/edit-site/src/components/global-styles-sidebar/index.js @@ -152,6 +152,7 @@ export default function GlobalStylesSidebar() { isPressed={ isStyleBookOpened || isRevisionsStyleBookOpened } + __experimentalIsFocusable disabled={ shouldClearCanvasContainerView } onClick={ toggleStyleBook } size="compact" @@ -162,6 +163,7 @@ export default function GlobalStylesSidebar() { label={ __( 'Revisions' ) } icon={ backup } onClick={ toggleRevisions } + __experimentalIsFocusable disabled={ ! hasRevisions } isPressed={ isRevisionsOpened || isRevisionsStyleBookOpened diff --git a/packages/edit-site/src/components/global-styles-sidebar/style.scss b/packages/edit-site/src/components/global-styles-sidebar/style.scss index 1f631eb24057c9..b76192ddfcb5ca 100644 --- a/packages/edit-site/src/components/global-styles-sidebar/style.scss +++ b/packages/edit-site/src/components/global-styles-sidebar/style.scss @@ -47,7 +47,6 @@ font-weight: 500; } -.edit-site-typography-panel, .edit-site-global-styles-sidebar .block-editor-panel-color-gradient-settings { border: 0; } diff --git a/packages/edit-site/src/components/global-styles/screen-css.js b/packages/edit-site/src/components/global-styles/screen-css.js index 71d47a52a50274..e49207aaea2241 100644 --- a/packages/edit-site/src/components/global-styles/screen-css.js +++ b/packages/edit-site/src/components/global-styles/screen-css.js @@ -34,7 +34,7 @@ function ScreenCSS() { <> { description } { __( 'Learn more about CSS' ) } diff --git a/packages/edit-site/src/components/global-styles/screen-revisions/revisions-buttons.js b/packages/edit-site/src/components/global-styles/screen-revisions/revisions-buttons.js index 9c4280f2b1eb51..7f4f9896344b4f 100644 --- a/packages/edit-site/src/components/global-styles/screen-revisions/revisions-buttons.js +++ b/packages/edit-site/src/components/global-styles/screen-revisions/revisions-buttons.js @@ -163,6 +163,7 @@ function RevisionsButtons( { > ); } diff --git a/packages/editor/src/components/post-discussion/style.scss b/packages/editor/src/components/post-discussion/style.scss index b1eae851402859..b2d65c9aa7cf3f 100644 --- a/packages/editor/src/components/post-discussion/style.scss +++ b/packages/editor/src/components/post-discussion/style.scss @@ -13,9 +13,7 @@ } } .editor-post-discussion__panel-toggle { - &.components-button { - height: auto; - } + .components-text { color: inherit; } diff --git a/packages/editor/src/components/post-panel-row/style.scss b/packages/editor/src/components/post-panel-row/style.scss index 22d0cbbb644d8a..024394c3aaf331 100644 --- a/packages/editor/src/components/post-panel-row/style.scss +++ b/packages/editor/src/components/post-panel-row/style.scss @@ -11,6 +11,9 @@ min-height: $grid-unit-40; display: flex; align-items: center; + padding: 6px 0; // Matches button to ensure alignment + line-height: $grid-unit-05 * 5; + hyphens: auto; } .editor-post-panel__row-control { @@ -18,4 +21,17 @@ min-height: $grid-unit-40; display: flex; align-items: center; + + .components-button { + max-width: 100%; + text-align: left; + text-wrap: balance; // Fallback for Safari. + text-wrap: pretty; + height: auto; + min-height: $button-size-compact; + } + + .components-dropdown { + max-width: 100%; + } } diff --git a/packages/editor/src/components/post-preview-button/index.js b/packages/editor/src/components/post-preview-button/index.js index 110de5858af382..e517ac0e8a0fbc 100644 --- a/packages/editor/src/components/post-preview-button/index.js +++ b/packages/editor/src/components/post-preview-button/index.js @@ -183,6 +183,7 @@ export default function PostPreviewButton( { className={ className || 'editor-post-preview' } href={ href } target={ targetId } + __experimentalIsFocusable disabled={ ! isSaveable } onClick={ openPreviewWindow } role={ role } diff --git a/packages/editor/src/components/post-preview-button/test/index.js b/packages/editor/src/components/post-preview-button/test/index.js index e34c05caa178bd..bb51f302edf50e 100644 --- a/packages/editor/src/components/post-preview-button/test/index.js +++ b/packages/editor/src/components/post-preview-button/test/index.js @@ -139,12 +139,16 @@ describe( 'PostPreviewButton', () => { ).toBeInTheDocument(); } ); - it( 'should be disabled if post is not saveable.', () => { + it( 'should be accessibly disabled if post is not saveable.', () => { mockUseSelect( { isEditedPostSaveable: () => false } ); render( ); - expect( screen.getByRole( 'button' ) ).toBeDisabled(); + expect( screen.getByRole( 'button' ) ).toBeEnabled(); + expect( screen.getByRole( 'button' ) ).toHaveAttribute( + 'aria-disabled', + 'true' + ); } ); it( 'should not be disabled if post is saveable.', () => { @@ -153,6 +157,10 @@ describe( 'PostPreviewButton', () => { render( ); expect( screen.getByRole( 'button' ) ).toBeEnabled(); + expect( screen.getByRole( 'button' ) ).not.toHaveAttribute( + 'aria-disabled', + 'true' + ); } ); it( 'should set `href` to edited post preview link if specified.', () => { diff --git a/packages/editor/src/components/post-publish-button/index.js b/packages/editor/src/components/post-publish-button/index.js index 355986fdf509dd..8797c9d1428251 100644 --- a/packages/editor/src/components/post-publish-button/index.js +++ b/packages/editor/src/components/post-publish-button/index.js @@ -11,6 +11,7 @@ import { compose } from '@wordpress/compose'; */ import PublishButtonLabel from './label'; import { store as editorStore } from '../../store'; +import { unlock } from '../../lock-unlock'; const noop = () => {}; @@ -45,14 +46,24 @@ export class PostPublishButton extends Component { createOnClick( callback ) { return ( ...args ) => { - const { hasNonPostEntityChanges, setEntitiesSavedStatesCallback } = - this.props; + const { + hasNonPostEntityChanges, + hasPostMetaChanges, + setEntitiesSavedStatesCallback, + isPublished, + } = this.props; // If a post with non-post entities is published, but the user // elects to not save changes to the non-post entities, those // entities will still be dirty when the Publish button is clicked. // We also need to check that the `setEntitiesSavedStatesCallback` // prop was passed. See https://github.com/WordPress/gutenberg/pull/37383 - if ( hasNonPostEntityChanges && setEntitiesSavedStatesCallback ) { + // + // TODO: Explore how to manage `hasPostMetaChanges` and pre-publish workflow properly. + if ( + ( hasNonPostEntityChanges || + ( hasPostMetaChanges && isPublished ) ) && + setEntitiesSavedStatesCallback + ) { // The modal for multiple entity saving will open, // hold the callback for saving/publishing the post // so that we can call it if the post entity is checked. @@ -212,7 +223,8 @@ export default compose( [ isSavingNonPostEntityChanges, getEditedPostAttribute, getPostEdits, - } = select( editorStore ); + hasPostMetaChanges, + } = unlock( select( editorStore ) ); return { isSaving: isSavingPost(), isAutoSaving: isAutosavingPost(), @@ -229,6 +241,7 @@ export default compose( [ postStatus: getEditedPostAttribute( 'status' ), postStatusHasChanged: getPostEdits()?.status, hasNonPostEntityChanges: hasNonPostEntityChanges(), + hasPostMetaChanges: hasPostMetaChanges(), isSavingNonPostEntityChanges: isSavingNonPostEntityChanges(), }; } ), diff --git a/packages/editor/src/components/post-publish-panel/index.js b/packages/editor/src/components/post-publish-panel/index.js index 4d59133966759a..31e838575c0871 100644 --- a/packages/editor/src/components/post-publish-panel/index.js +++ b/packages/editor/src/components/post-publish-panel/index.js @@ -93,6 +93,7 @@ export class PostPublishPanel extends Component {
); } diff --git a/packages/editor/src/components/post-url/style.scss b/packages/editor/src/components/post-url/style.scss index c622cfce33f90e..a711402f1a82eb 100644 --- a/packages/editor/src/components/post-url/style.scss +++ b/packages/editor/src/components/post-url/style.scss @@ -2,15 +2,6 @@ width: 100%; } -.components-button.editor-post-url__panel-toggle { - display: block; - max-width: 100%; - overflow: hidden; - text-align: left; - text-overflow: ellipsis; - white-space: nowrap; -} - .editor-post-url__panel-dialog .editor-post-url { // sidebar width - popover padding - form margin min-width: $sidebar-width - $grid-unit-20 - $grid-unit-20; diff --git a/packages/editor/src/components/provider/README.md b/packages/editor/src/components/provider/README.md deleted file mode 100644 index deaa9375bba746..00000000000000 --- a/packages/editor/src/components/provider/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# EditorProvider - -EditorProvider is a component which establishes a new post editing context, and serves as the entry point for a new post editor (or post with template editor). - -It supports a big number of post types, including post, page, templates, custom post types, patterns, template parts. - -All modification and changes are performed to the `@wordpress/core-data` store. - -## Props - -### `post` - -- **Type:** `Object` -- **Required** `yes` - -The post object to edit - -### `__unstableTemplate` - -- **Type:** `Object` -- **Required** `no` - -The template object wrapper the edited post. This is optional and can only be used when the post type supports templates (like posts and pages). - -### `settings` - -- **Type:** `Object` -- **Required** `no` - -The settings object to use for the editor. This is optional and can be used to override the default settings. - -### `children` - -- **Type:** `Element` -- **Required** `no` - -Children elements for which the BlockEditorProvider context should apply. diff --git a/packages/editor/src/components/provider/index.js b/packages/editor/src/components/provider/index.js index 56c86968f0274f..081b1cdfa0f1b2 100644 --- a/packages/editor/src/components/provider/index.js +++ b/packages/editor/src/components/provider/index.js @@ -59,6 +59,12 @@ const NON_CONTEXTUAL_POST_TYPES = [ * @param {Array} post Block list. * @param {boolean} template Whether the page content has focus (and the surrounding template is inert). If `true` return page content blocks. Default `false`. * @param {string} mode Rendering mode. + * + * @example + * ```jsx + * const [ blocks, onInput, onChange ] = useBlockEditorProps( post, template, mode ); + * ``` + * * @return {Array} Block editor props. */ function useBlockEditorProps( post, template, mode ) { @@ -118,6 +124,32 @@ function useBlockEditorProps( post, template, mode ) { ]; } +/** + * This component provides the editor context and manages the state of the block editor. + * + * @param {Object} props The component props. + * @param {Object} props.post The post object. + * @param {Object} props.settings The editor settings. + * @param {boolean} props.recovery Indicates if the editor is in recovery mode. + * @param {Array} props.initialEdits The initial edits for the editor. + * @param {Object} props.children The child components. + * @param {Object} [props.BlockEditorProviderComponent] The block editor provider component to use. Defaults to ExperimentalBlockEditorProvider. + * @param {Object} [props.__unstableTemplate] The template object. + * + * @example + * ```jsx + * + * { children } + * + * + * @return {Object} The rendered ExperimentalEditorProvider component. + */ export const ExperimentalEditorProvider = withRegistryProvider( ( { post, @@ -293,6 +325,36 @@ export const ExperimentalEditorProvider = withRegistryProvider( } ); +/** + * This component establishes a new post editing context, and serves as the entry point for a new post editor (or post with template editor). + * + * It supports a large number of post types, including post, page, templates, + * custom post types, patterns, template parts. + * + * All modification and changes are performed to the `@wordpress/core-data` store. + * + * @param {Object} props The component props. + * @param {Object} [props.post] The post object to edit. This is required. + * @param {Object} [props.__unstableTemplate] The template object wrapper the edited post. + * This is optional and can only be used when the post type supports templates (like posts and pages). + * @param {Object} [props.settings] The settings object to use for the editor. + * This is optional and can be used to override the default settings. + * @param {Element} [props.children] Children elements for which the BlockEditorProvider context should apply. + * This is optional. + * + * @example + * ```jsx + * + * { children } + * + * ``` + * + * @return {JSX.Element} The rendered EditorProvider component. + */ export function EditorProvider( props ) { return ( ( { publishSidebarOpened: select( editorStore ).isPublishSidebarOpened(), hasNonPostEntityChanges: select( editorStore ).hasNonPostEntityChanges(), + hasPostMetaChanges: unlock( + select( editorStore ) + ).hasPostMetaChanges(), } ), [] ); @@ -54,7 +62,7 @@ export default function SavePublishPanels( { PostPublishExtension={ PluginPostPublishPanel.Slot } /> ); - } else if ( hasNonPostEntityChanges ) { + } else if ( hasNonPostEntityChanges || hasPostMetaChanges ) { unmountableContent = (