diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml
index 288bef1580038f..98615b93b8a176 100644
--- a/.github/workflows/performance.yml
+++ b/.github/workflows/performance.yml
@@ -69,13 +69,13 @@ jobs:
- name: Compare performance with base branch
if: github.event_name == 'push'
# The base hash used here need to be a commit that is compatible with the current WP version
- # The current one is 9725060a5b18904c6cc5fdbe4b06fbde7419e02c and it needs to be updated every WP major release.
+ # The current one is 5f4c9c853b15092ed885d5280edefb973c37d9e9 and it needs to be updated every WP major release.
# It is used as a base comparison point to avoid fluctuation in the performance metrics.
run: |
WP_VERSION=$(awk -F ': ' '/^Tested up to/{print $2}' readme.txt)
IFS=. read -ra WP_VERSION_ARRAY <<< "$WP_VERSION"
WP_MAJOR="${WP_VERSION_ARRAY[0]}.${WP_VERSION_ARRAY[1]}"
- ./bin/plugin/cli.js perf $GITHUB_SHA 9725060a5b18904c6cc5fdbe4b06fbde7419e02c --tests-branch $GITHUB_SHA --wp-version "$WP_MAJOR"
+ ./bin/plugin/cli.js perf $GITHUB_SHA 5f4c9c853b15092ed885d5280edefb973c37d9e9 --tests-branch $GITHUB_SHA --wp-version "$WP_MAJOR"
- name: Compare performance with custom branches
if: github.event_name == 'workflow_dispatch'
@@ -101,7 +101,7 @@ jobs:
CODEHEALTH_PROJECT_TOKEN: ${{ secrets.CODEHEALTH_PROJECT_TOKEN }}
run: |
COMMITTED_AT=$(git show -s $GITHUB_SHA --format="%cI")
- ./bin/log-performance-results.js $CODEHEALTH_PROJECT_TOKEN trunk $GITHUB_SHA 9725060a5b18904c6cc5fdbe4b06fbde7419e02c $COMMITTED_AT
+ ./bin/log-performance-results.js $CODEHEALTH_PROJECT_TOKEN trunk $GITHUB_SHA 5f4c9c853b15092ed885d5280edefb973c37d9e9 $COMMITTED_AT
- name: Archive debug artifacts (screenshots, HTML snapshots)
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
diff --git a/changelog.txt b/changelog.txt
index 412d6184d76604..b7bbdf821f374e 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,40 +1,14 @@
== Changelog ==
-= 18.9.0-rc.1 =
-
+= 18.9.0 =
## Changelog
-### Features
-
-- change: Updated soundcloud icon for social link block. ([63504](https://github.com/WordPress/gutenberg/pull/63504))
-
-#### Global Styles
-- Adding Font size presets UI. ([63057](https://github.com/WordPress/gutenberg/pull/63057))
-
-
### Enhancements
-- Background tool: Fix double border. ([63559](https://github.com/WordPress/gutenberg/pull/63559))
-- Core Data: Mark 'canUser' related actions resolvers as resolved. ([63435](https://github.com/WordPress/gutenberg/pull/63435))
-- Core Data: Resolve user capabilities when fetching an entity. ([63430](https://github.com/WordPress/gutenberg/pull/63430))
-- Core Data: Support entities in the 'canUser' selector. ([63322](https://github.com/WordPress/gutenberg/pull/63322))
-- Core Data: Support entity queries in the 'useResourcePermissions' hook. ([63653](https://github.com/WordPress/gutenberg/pull/63653))
-- DataViews: Update pagination icons. ([63594](https://github.com/WordPress/gutenberg/pull/63594))
-- Embeds: Add 'Embed' to title for clarity. ([63371](https://github.com/WordPress/gutenberg/pull/63371))
-- Polish "Delete" modal. ([63392](https://github.com/WordPress/gutenberg/pull/63392))
-- Run sync when issue is labeled with Sync Backport Changelog. ([63793](https://github.com/WordPress/gutenberg/pull/63793))
-- Update JSON Schemas to Draft 7. ([63583](https://github.com/WordPress/gutenberg/pull/63583))
-- Update: Grid layout: Allow users to adjust grid density. ([63367](https://github.com/WordPress/gutenberg/pull/63367))
-- Update: Include avatars on list view. ([63309](https://github.com/WordPress/gutenberg/pull/63309))
-- Update: List / Table layout – selected item stroke should be tinted blue. ([63312](https://github.com/WordPress/gutenberg/pull/63312))
-- Update: Make changing order an action on the ellipsis menu. ([62189](https://github.com/WordPress/gutenberg/pull/62189))
-- Update: Pages: Trash view should default to table layout try 2. ([63652](https://github.com/WordPress/gutenberg/pull/63652))
-- Update: Simplify some permission checks. ([63812](https://github.com/WordPress/gutenberg/pull/63812))
-- Use entity details when calling 'canUser' selectors. ([63415](https://github.com/WordPress/gutenberg/pull/63415))
-
#### Block Library
- Add Clear button for Overlay color option in Cover Block. ([63580](https://github.com/WordPress/gutenberg/pull/63580))
+- Embeds: Add 'Embed' to title for clarity. ([63371](https://github.com/WordPress/gutenberg/pull/63371))
- Columns block: Fix block preview. ([63609](https://github.com/WordPress/gutenberg/pull/63609))
- Gallery: Add border block support. ([63428](https://github.com/WordPress/gutenberg/pull/63428))
- Image block: Show placeholder when uploading HEIC files. ([63643](https://github.com/WordPress/gutenberg/pull/63643))
@@ -50,21 +24,10 @@
- Query Loop: Change default query loop variations. ([63353](https://github.com/WordPress/gutenberg/pull/63353))
- Set query loop to have the inherit value by default. ([63362](https://github.com/WordPress/gutenberg/pull/63362))
- Social Links: Add border block support. ([63629](https://github.com/WordPress/gutenberg/pull/63629))
+- Social Links: Updated soundcloud icon for social link block. ([63504](https://github.com/WordPress/gutenberg/pull/63504))
+- Social Links: Update Facebook's color to match brand guidelines. ([60424](https://github.com/WordPress/gutenberg/pull/60424))
- Term Description: Add border block support. ([63630](https://github.com/WordPress/gutenberg/pull/63630))
-#### Components
-- CustomSelectControl V2 legacy adapter: Stabilize experimental props. ([63248](https://github.com/WordPress/gutenberg/pull/63248))
-- CustomSelectControl: Switch to ariakit-based implementation. ([63258](https://github.com/WordPress/gutenberg/pull/63258))
-- CustomSelectControlV2: Animate select popover appearance. ([63343](https://github.com/WordPress/gutenberg/pull/63343))
-- CustomSelectControlV2: Do not flip popover if legacy adapter. ([63357](https://github.com/WordPress/gutenberg/pull/63357))
-- DropdownMenuV2: Invert animation direction. ([63443](https://github.com/WordPress/gutenberg/pull/63443))
-- FontSizePicker: Tidy up internal logic. ([63553](https://github.com/WordPress/gutenberg/pull/63553))
-- FormTokenField: Deprecate bottom margin. ([63491](https://github.com/WordPress/gutenberg/pull/63491))
-- SelectControl: Add "minimal" variant. ([63265](https://github.com/WordPress/gutenberg/pull/63265))
-- Tabs: Hyphenate tab labels. ([63337](https://github.com/WordPress/gutenberg/pull/63337))
-- Tabs: Keep full opacity of focus ring on disabled tabs. ([63754](https://github.com/WordPress/gutenberg/pull/63754))
-- Update HeightControl component to label inputs. ([63761](https://github.com/WordPress/gutenberg/pull/63761))
-
#### Design Tools
- Background Image: Make panel appear in a consistent location. ([63551](https://github.com/WordPress/gutenberg/pull/63551))
- Buttons: Add border, color, and padding block supports. ([63538](https://github.com/WordPress/gutenberg/pull/63538))
@@ -77,15 +40,21 @@
#### Data Views
- DataViews: Allow column re-ordering. ([63416](https://github.com/WordPress/gutenberg/pull/63416))
+- DataViews: Update pagination icons. ([63594](https://github.com/WordPress/gutenberg/pull/63594))
- DataViews: Rename the header property of fields to label. ([63843](https://github.com/WordPress/gutenberg/pull/63843))
- DataViews: Support combined fields. ([63236](https://github.com/WordPress/gutenberg/pull/63236))
- Dataviews List: Update item layout. ([63299](https://github.com/WordPress/gutenberg/pull/63299))
- Increase column-gap between fields in List layout. ([63603](https://github.com/WordPress/gutenberg/pull/63603))
-- Pages: Trash view should default to table layout. ([63138](https://github.com/WordPress/gutenberg/pull/63138))
- Update 'Front page' badge. ([63752](https://github.com/WordPress/gutenberg/pull/63752))
+- Update: Pages: Trash view should default to table layout try 2. ([63652](https://github.com/WordPress/gutenberg/pull/63652))
+- Update: Grid layout: Allow users to adjust grid density. ([63367](https://github.com/WordPress/gutenberg/pull/63367))
+- Update: Include avatars on list view. ([63309](https://github.com/WordPress/gutenberg/pull/63309))
+- Update: List / Table layout – selected item stroke should be tinted blue. ([63312](https://github.com/WordPress/gutenberg/pull/63312))
+- Update: Make changing order an action on the ellipsis menu. ([62189](https://github.com/WordPress/gutenberg/pull/62189))
#### Global Styles
- Add colors and typograpghy to the browse styles section. ([63173](https://github.com/WordPress/gutenberg/pull/63173))
+- Adding Font size presets UI. ([63057](https://github.com/WordPress/gutenberg/pull/63057))
- Apply same styles to block previews on inserter and Global Styles. ([63177](https://github.com/WordPress/gutenberg/pull/63177))
- Background: Add background attachment to top level styles. ([61382](https://github.com/WordPress/gutenberg/pull/61382))
- Move background panel under color panel. ([63888](https://github.com/WordPress/gutenberg/pull/63888))
@@ -112,55 +81,60 @@
#### Block Locking
- Tweak Block Locking UI. ([63881](https://github.com/WordPress/gutenberg/pull/63881))
-#### Icons
+#### General UI
+- Polish "Delete" modal. ([63392](https://github.com/WordPress/gutenberg/pull/63392))
- Update close icon. ([63597](https://github.com/WordPress/gutenberg/pull/63597))
+- Site Editor: Reduce navigation sidebar width. ([63431](https://github.com/WordPress/gutenberg/pull/63431))
#### Block bindings
- Bootstrap sources defined in the server. ([63470](https://github.com/WordPress/gutenberg/pull/63470))
-#### Site Editor
-- Reduce navigation sidebar width. ([63431](https://github.com/WordPress/gutenberg/pull/63431))
-
#### Patterns
- Limit pattern shuffling to theme and user patterns only. ([62677](https://github.com/WordPress/gutenberg/pull/62677))
+#### Components
+- CustomSelectControl V2 legacy adapter: Stabilize experimental props. ([63248](https://github.com/WordPress/gutenberg/pull/63248))
+- CustomSelectControl: Switch to ariakit-based implementation. ([63258](https://github.com/WordPress/gutenberg/pull/63258))
+- CustomSelectControlV2: Animate select popover appearance. ([63343](https://github.com/WordPress/gutenberg/pull/63343))
+- CustomSelectControlV2: Do not flip popover if legacy adapter. ([63357](https://github.com/WordPress/gutenberg/pull/63357))
+- DropdownMenuV2: Invert animation direction. ([63443](https://github.com/WordPress/gutenberg/pull/63443))
+- FontSizePicker: Tidy up internal logic. ([63553](https://github.com/WordPress/gutenberg/pull/63553))
+- FormTokenField: Deprecate bottom margin. ([63491](https://github.com/WordPress/gutenberg/pull/63491))
+- SelectControl: Add "minimal" variant. ([63265](https://github.com/WordPress/gutenberg/pull/63265))
+- Tabs: Hyphenate tab labels. ([63337](https://github.com/WordPress/gutenberg/pull/63337))
+- Tabs: Keep full opacity of focus ring on disabled tabs. ([63754](https://github.com/WordPress/gutenberg/pull/63754))
+- Update HeightControl component to label inputs. ([63761](https://github.com/WordPress/gutenberg/pull/63761))
+
+#### Core Data
+- Core Data: Mark 'canUser' related actions resolvers as resolved. ([63435](https://github.com/WordPress/gutenberg/pull/63435))
+- Core Data: Resolve user capabilities when fetching an entity. ([63430](https://github.com/WordPress/gutenberg/pull/63430))
+- Core Data: Support entities in the 'canUser' selector. ([63322](https://github.com/WordPress/gutenberg/pull/63322))
+- Core Data: Support entity queries in the 'useResourcePermissions' hook. ([63653](https://github.com/WordPress/gutenberg/pull/63653))
+
+#### JSON Schemas
+- Update JSON Schemas to Draft 7. ([63583](https://github.com/WordPress/gutenberg/pull/63583))
### New APIs
#### Block bindings
- Unify `getValue`/`getValues` and `setValue`/`setValues` APIs. ([63185](https://github.com/WordPress/gutenberg/pull/63185))
-
### Bug Fixes
-- Add: Permission checks to avoid 403 errors on non admin roles. ([63296](https://github.com/WordPress/gutenberg/pull/63296))
-- DataViews: Do not render bulk actions Dropdown if no actions are available. ([63575](https://github.com/WordPress/gutenberg/pull/63575))
-- DataViews: Fix uncontrolled selection. ([63741](https://github.com/WordPress/gutenberg/pull/63741))
-- Disallow scrolling the block preview. ([63558](https://github.com/WordPress/gutenberg/pull/63558))
-- Discussions panel: Distinguish between verb and adjective form of open for internationalization. ([63791](https://github.com/WordPress/gutenberg/pull/63791))
-- Fix canvas issues by removing VisualEditor’s height. ([63724](https://github.com/WordPress/gutenberg/pull/63724))
-- Fix mobile styles for inserter pattern and media tab navigation. ([63451](https://github.com/WordPress/gutenberg/pull/63451))
-- Fix: Error while Calling edit-site getCurrentTemplateTemplateParts selector. ([63818](https://github.com/WordPress/gutenberg/pull/63818))
-- Footnotes: Register format within the init function. ([63554](https://github.com/WordPress/gutenberg/pull/63554))
-- InnerBlocks: Make sure blockType is set before trying to use it. ([63351](https://github.com/WordPress/gutenberg/pull/63351))
-- Prepare JSON schemas for Draft 7 update. ([63582](https://github.com/WordPress/gutenberg/pull/63582))
-- Revert "Pages: Trash view should default to table layout.". ([63481](https://github.com/WordPress/gutenberg/pull/63481))
-- Sync backport changelog action: Use outputs instead of env. ([63792](https://github.com/WordPress/gutenberg/pull/63792))
-- core-data: Fix `canUser` allowed methods handling. ([63615](https://github.com/WordPress/gutenberg/pull/63615))
-- useBlockElement: Return null until ref callback has time to clean up the old element. ([63565](https://github.com/WordPress/gutenberg/pull/63565))
-
#### Data Views
+- DataViews: Do not render bulk actions Dropdown if no actions are available. ([63575](https://github.com/WordPress/gutenberg/pull/63575))
- DataViews: Fix default layouts in the pages data views. ([63427](https://github.com/WordPress/gutenberg/pull/63427))
- DataViews: Fix featured image height regression. ([63424](https://github.com/WordPress/gutenberg/pull/63424))
- DataViews: Fix field rendering. ([63452](https://github.com/WordPress/gutenberg/pull/63452))
- DataViews: Fix pattens list selection. ([63733](https://github.com/WordPress/gutenberg/pull/63733))
+- DataViews: Fix uncontrolled selection. ([63741](https://github.com/WordPress/gutenberg/pull/63741))
- DataViews: Only show elligible actions in the bulk editing menu. ([63473](https://github.com/WordPress/gutenberg/pull/63473))
- Fix patterns sorting by `title`. ([63710](https://github.com/WordPress/gutenberg/pull/63710))
- Fix selected row styles in table layout. ([63811](https://github.com/WordPress/gutenberg/pull/63811))
- Fix: DataViews: Layout resets for patterns each time a new pattern category is selected. ([63711](https://github.com/WordPress/gutenberg/pull/63711))
- Fix: Inconsistent field spacing in Grid layout. ([63363](https://github.com/WordPress/gutenberg/pull/63363))
- Templates DataViews: Set the right context for the preview field. ([63488](https://github.com/WordPress/gutenberg/pull/63488))
-
+-
#### Block Editor
- Fix user patterns disabling sync filter. ([63828](https://github.com/WordPress/gutenberg/pull/63828))
- ImageURLInputUI: Make onSetLightbox and resetLightbox optional. ([63573](https://github.com/WordPress/gutenberg/pull/63573))
@@ -169,11 +143,14 @@
- Prevent empty void at the bottom of editor when block directory results are present. ([63397](https://github.com/WordPress/gutenberg/pull/63397))
- Remove double shadow on Inserter category panel when zoomed out. ([63516](https://github.com/WordPress/gutenberg/pull/63516))
- Tabs: Vertical Tabs should be 40px min height. ([63446](https://github.com/WordPress/gutenberg/pull/63446))
-- Zoom out mode: Translate toolbar delete button. ([63476](https://github.com/WordPress/gutenberg/pull/63476))
+- Fix mobile styles for inserter pattern and media tab navigation. ([63451](https://github.com/WordPress/gutenberg/pull/63451))
+- useBlockElement: Return null until ref callback has time to clean up the old element. ([63565](https://github.com/WordPress/gutenberg/pull/63565))
+- Remove hint in the Settings tab. ([63515](https://github.com/WordPress/gutenberg/pull/63515))
#### Block Library
- Avoid stripping attributes via group block migration when no layout is specified. ([63837](https://github.com/WordPress/gutenberg/pull/63837))
- Fix default unit issue for tag cloud block. ([59122](https://github.com/WordPress/gutenberg/pull/59122))
+- Footnotes: Register format within the init function. ([63554](https://github.com/WordPress/gutenberg/pull/63554))
- Image lightbox: Remove duplicate image when lightbox is opened. ([63381](https://github.com/WordPress/gutenberg/pull/63381))
- Query Loop: Fix 'block' scoped variations to get the `query` defaults. ([63477](https://github.com/WordPress/gutenberg/pull/63477))
- Query Loop: Fix passing of `namespace` when selecting from suggested patterns. ([63402](https://github.com/WordPress/gutenberg/pull/63402))
@@ -181,6 +158,7 @@
- Update Inherited Query Loop value from Template Settings changes. ([63358](https://github.com/WordPress/gutenberg/pull/63358))
#### Site Editor
+- Fix: Error while Calling edit-site getCurrentTemplateTemplateParts selector. ([63818](https://github.com/WordPress/gutenberg/pull/63818))
- Fix error when duplicating a template part. ([63663](https://github.com/WordPress/gutenberg/pull/63663))
- Fix: Add Template Modal layout in mobile view. ([63627](https://github.com/WordPress/gutenberg/pull/63627))
- Make hover block outlines not present in Distraction Free. ([63819](https://github.com/WordPress/gutenberg/pull/63819))
@@ -192,6 +170,7 @@
- Ensure that we only enter zoom out mode if the experiment is enabled. ([63417](https://github.com/WordPress/gutenberg/pull/63417))
- Fix crash due to absence of selected block. ([63642](https://github.com/WordPress/gutenberg/pull/63642))
- Fix vertical toolbar position. ([63745](https://github.com/WordPress/gutenberg/pull/63745))
+- Translate toolbar delete button. ([63476](https://github.com/WordPress/gutenberg/pull/63476))
#### Components
- Button: Never apply `aria-disabled` to anchor. ([63376](https://github.com/WordPress/gutenberg/pull/63376))
@@ -201,6 +180,7 @@
#### Global Styles
- Disable "Reset styles" button when there are no changes. ([63562](https://github.com/WordPress/gutenberg/pull/63562))
+- Disallow scrolling the block preview. ([63558](https://github.com/WordPress/gutenberg/pull/63558))
- Ensure root selector (body) is not wrapped in :root :Where(). ([63726](https://github.com/WordPress/gutenberg/pull/63726))
- Global styles block previews: Fix scaling. ([63596](https://github.com/WordPress/gutenberg/pull/63596))
- Style variations: Don't display the default if its the only variation. ([63555](https://github.com/WordPress/gutenberg/pull/63555))
@@ -219,9 +199,11 @@
#### Design Tools
- Background image block support: Fix dropzone size. ([63588](https://github.com/WordPress/gutenberg/pull/63588))
+- Background tool: Fix double border. ([63559](https://github.com/WordPress/gutenberg/pull/63559))
-#### Layout
-- Don't remount the block when rendering grid tools. ([63557](https://github.com/WordPress/gutenberg/pull/63557))
+#### General interface
+- Discussions panel: Distinguish between verb and adjective form of open for internationalization. ([63791](https://github.com/WordPress/gutenberg/pull/63791))
+- Fix canvas issues by removing VisualEditor’s height. ([63724](https://github.com/WordPress/gutenberg/pull/63724))
#### Block Transforms
- Block Switcher Preview: Adjust the position and enable pattern list preview in mobile viewport. ([63512](https://github.com/WordPress/gutenberg/pull/63512))
@@ -232,6 +214,9 @@
#### Block Directory
- Memoize store selectors. ([63346](https://github.com/WordPress/gutenberg/pull/63346))
+#### Inner blocks
+- InnerBlocks: Make sure blockType is set before trying to use it. ([63351](https://github.com/WordPress/gutenberg/pull/63351))
+
#### Widgets Editor
- Widgets: Memoize 'getWidgets' store selector. ([63338](https://github.com/WordPress/gutenberg/pull/63338))
@@ -244,12 +229,16 @@
#### Media
- Lock post saving during image uploads. ([41120](https://github.com/WordPress/gutenberg/pull/41120))
+#### JSON Schemas
+- Prepare JSON schemas for Draft 7 update. ([63582](https://github.com/WordPress/gutenberg/pull/63582))
-### Accessibility
+#### Security
+- Add: Permission checks to avoid 403 errors on non admin roles. ([63296](https://github.com/WordPress/gutenberg/pull/63296))
-- Align checkbox, radio, and toggle input design. ([63490](https://github.com/WordPress/gutenberg/pull/63490))
+### Accessibility
#### Components
+- Align checkbox, radio, and toggle input design. ([63490](https://github.com/WordPress/gutenberg/pull/63490))
- Fix ComboboxControl reset button when using the keyboard. ([63410](https://github.com/WordPress/gutenberg/pull/63410))
#### Post Editor
@@ -267,18 +256,17 @@
### Experiments
-#### Layout
+#### Grid layout
- Disable in-between inserter in Manual grids. ([63391](https://github.com/WordPress/gutenberg/pull/63391))
- Don't display default appender inside Manual grid. ([63395](https://github.com/WordPress/gutenberg/pull/63395))
- Fix responsive behaviour so both column start and column span are taken into account. ([63464](https://github.com/WordPress/gutenberg/pull/63464))
-- Grid: Better looking block movers. ([63394](https://github.com/WordPress/gutenberg/pull/63394))
-- Grid: Place new block after currently selected block when using slash inserter and splitting text. ([63333](https://github.com/WordPress/gutenberg/pull/63333))
+- Better looking block movers. ([63394](https://github.com/WordPress/gutenberg/pull/63394))
+- Place new block after currently selected block when using slash inserter and splitting text. ([63333](https://github.com/WordPress/gutenberg/pull/63333))
- Move visualizer popover to slot under the canvas. ([63389](https://github.com/WordPress/gutenberg/pull/63389))
+- Don't remount the block when rendering grid tools. ([63557](https://github.com/WordPress/gutenberg/pull/63557))
#### Data Views
- Quick Edit: Support bulk selection. ([63841](https://github.com/WordPress/gutenberg/pull/63841))
-
-#### Site Editor
- DataViews: Bootstrap Quick Edit. ([63600](https://github.com/WordPress/gutenberg/pull/63600))
@@ -314,11 +302,15 @@
- Block editor settings: Add missing global styles links dependencies. ([63823](https://github.com/WordPress/gutenberg/pull/63823))
- Core Data: Remove leftover 'todo' comment. ([63842](https://github.com/WordPress/gutenberg/pull/63842))
- Core Data: Use meta-store actions for resolution status. ([63469](https://github.com/WordPress/gutenberg/pull/63469))
+- core-data: Fix `canUser` allowed methods handling. ([63615](https://github.com/WordPress/gutenberg/pull/63615))
- DataViews: Move PostList component to its own folder. ([63334](https://github.com/WordPress/gutenberg/pull/63334))
- JSON Schema Reorganization and Fixes. ([63591](https://github.com/WordPress/gutenberg/pull/63591))
- Update: Simplify and do not pass renderingMode on editor SidebarContent. ([63814](https://github.com/WordPress/gutenberg/pull/63814))
- Use Base Focus Styles for Region Focus. ([62881](https://github.com/WordPress/gutenberg/pull/62881))
- Use static 'key' when filtering BlockEdit components. ([63590](https://github.com/WordPress/gutenberg/pull/63590))
+- Update: Simplify some permission checks. ([63812](https://github.com/WordPress/gutenberg/pull/63812))
+- Use entity details when calling 'canUser' selectors. ([63415](https://github.com/WordPress/gutenberg/pull/63415))
+- HTML API: Backport updates from Core. ([63723](https://github.com/WordPress/gutenberg/pull/63723))
#### Block Library
- Image block: Remove unnecessary variables on expand on click implementation. ([63290](https://github.com/WordPress/gutenberg/pull/63290))
@@ -375,34 +367,25 @@
#### Block Directory
- Remove 'edit-post' package dependency. ([63349](https://github.com/WordPress/gutenberg/pull/63349))
-
### Tools
-- Bug: Eslint `recommended-with-formatting` allows for unnecessary spaces. ([63549](https://github.com/WordPress/gutenberg/pull/63549))
+#### Project Management
- Issue template: Use checkboxes instead of dropdown. ([63523](https://github.com/WordPress/gutenberg/pull/63523))
-- Scripts: Include variations paths in build. ([63098](https://github.com/WordPress/gutenberg/pull/63098))
-- Scripts: Remove now-obsolete `getRenderPropPaths()`. ([63661](https://github.com/WordPress/gutenberg/pull/63661))
+- Sync backport changelog action: Use outputs instead of env. ([63792](https://github.com/WordPress/gutenberg/pull/63792))
+- Run sync when issue is labeled with Sync Backport Changelog. ([63793](https://github.com/WordPress/gutenberg/pull/63793))
#### Testing
- Downgrade node 22(.5) unit tests to 22.4. ([63728](https://github.com/WordPress/gutenberg/pull/63728))
- Font Library: Fix flaky end-to-end tests. ([63904](https://github.com/WordPress/gutenberg/pull/63904))
- Upgrade Playwright to v1.45. ([61443](https://github.com/WordPress/gutenberg/pull/61443))
+- Bug: Eslint `recommended-with-formatting` allows for unnecessary spaces. ([63549](https://github.com/WordPress/gutenberg/pull/63549))
-#### Build Tooling
+#### Build Tooling & Plugin
- Fix broken license check script. ([61868](https://github.com/WordPress/gutenberg/pull/61868))
- React: Restore umd builds. ([63602](https://github.com/WordPress/gutenberg/pull/63602))
-
-
-### Various
-
-- HTML API: Backport updates from Core. ([63723](https://github.com/WordPress/gutenberg/pull/63723))
- Upgrade TypeScript to 5.5. ([63012](https://github.com/WordPress/gutenberg/pull/63012))
-
-#### Block Editor
-- Remove hint in the Settings tab. ([63515](https://github.com/WordPress/gutenberg/pull/63515))
-
-#### Block Library
-- Social Links: Update Facebook's color to match brand guidelines. ([60424](https://github.com/WordPress/gutenberg/pull/60424))
+- Scripts: Remove now-obsolete `getRenderPropPaths()`. ([63661](https://github.com/WordPress/gutenberg/pull/63661))
+- Scripts: Include variations paths in build. ([63098](https://github.com/WordPress/gutenberg/pull/63098))
## First-time contributors
diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md
index dfe0f224c8f360..72281a53c3dd18 100644
--- a/docs/reference-guides/core-blocks.md
+++ b/docs/reference-guides/core-blocks.md
@@ -237,7 +237,7 @@ Displays a title with the number of comments. ([Source](https://github.com/WordP
- **Category:** theme
- **Ancestor:** core/comments
- **Supports:** align, color (background, gradients, text), interactivity (clientNavigation), spacing (margin, padding), typography (fontSize, lineHeight), ~~anchor~~, ~~html~~
-- **Attributes:** level, showCommentsCount, showPostTitle, textAlign
+- **Attributes:** level, levelOptions, showCommentsCount, showPostTitle, textAlign
## Cover
@@ -410,7 +410,7 @@ Display a list of your most recent posts. ([Source](https://github.com/WordPress
## List
-Create a bulleted or numbered list. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/list))
+An organized collection of items displayed in a specific order. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/list))
- **Name:** core/list
- **Category:** text
@@ -420,7 +420,7 @@ Create a bulleted or numbered list. ([Source](https://github.com/WordPress/guten
## List item
-Create a list item. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/list-item))
+An individual item within a list. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/list-item))
- **Name:** core/list-item
- **Category:** text
@@ -689,7 +689,7 @@ Displays the title of a post, page, or any other content-type. ([Source](https:/
- **Name:** core/post-title
- **Category:** theme
- **Supports:** align (full, wide), color (background, gradients, link, text), interactivity (clientNavigation), spacing (margin, padding), typography (fontSize, lineHeight), ~~html~~
-- **Attributes:** isLink, level, linkTarget, rel, textAlign
+- **Attributes:** isLink, level, levelOptions, linkTarget, rel, textAlign
## Preformatted
@@ -775,7 +775,7 @@ Display the query title. ([Source](https://github.com/WordPress/gutenberg/tree/t
- **Name:** core/query-title
- **Category:** theme
- **Supports:** align (full, wide), color (background, gradients, text), interactivity (clientNavigation), spacing (margin, padding), typography (fontSize, lineHeight), ~~html~~
-- **Attributes:** level, showPrefix, showSearchTerm, textAlign, type
+- **Attributes:** level, levelOptions, showPrefix, showSearchTerm, textAlign, type
## Quote
@@ -847,7 +847,7 @@ Describe in a few words what the site is about. The tagline can be used in searc
- **Name:** core/site-tagline
- **Category:** theme
- **Supports:** align (full, wide), color (background, gradients, text), interactivity (clientNavigation), spacing (margin, padding), typography (fontSize, lineHeight), ~~html~~
-- **Attributes:** level, textAlign
+- **Attributes:** level, levelOptions, textAlign
## Site Title
@@ -856,7 +856,7 @@ Displays the name of this site. Update the block, and the changes apply everywhe
- **Name:** core/site-title
- **Category:** theme
- **Supports:** align (full, wide), color (background, gradients, link, text), interactivity (clientNavigation), spacing (margin, padding), typography (fontSize, lineHeight), ~~html~~
-- **Attributes:** isLink, level, linkTarget, textAlign
+- **Attributes:** isLink, level, levelOptions, linkTarget, textAlign
## Social Icon
@@ -908,7 +908,7 @@ Summarize your post with a list of headings. Add HTML anchors to Heading blocks
## Tag Cloud
-A cloud of your most used tags. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/tag-cloud))
+A cloud of popular keywords, each sized by how often it appears. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/tag-cloud))
- **Name:** core/tag-cloud
- **Category:** widgets
diff --git a/lib/class-wp-theme-json-resolver-gutenberg.php b/lib/class-wp-theme-json-resolver-gutenberg.php
index a2153e639db3ba..2231cb0f11538f 100644
--- a/lib/class-wp-theme-json-resolver-gutenberg.php
+++ b/lib/class-wp-theme-json-resolver-gutenberg.php
@@ -764,8 +764,18 @@ private static function style_variation_has_scope( $variation, $scope ) {
* @return array
*/
public static function get_style_variations( $scope = 'theme' ) {
+ return static::get_style_variations_from_directory( get_stylesheet_directory(), $scope );
+ }
+
+ /**
+ * Returns the style variation files defined by the theme (parent and child).
+ *
+ * @since 6.7.0
+ *
+ * @return array An array of style variation files.
+ */
+ protected static function get_style_variation_files_from_current_theme() {
$variation_files = array();
- $variations = array();
$base_directory = get_stylesheet_directory() . '/styles';
$template_directory = get_template_directory() . '/styles';
if ( is_dir( $base_directory ) ) {
@@ -783,6 +793,29 @@ public static function get_style_variations( $scope = 'theme' ) {
}
$variation_files = array_merge( $variation_files, $variation_files_parent );
}
+
+ return $variation_files;
+ }
+
+ /**
+ * Returns the style variations in the given directory.
+ *
+ * @since 6.7.0
+ *
+ * @param string $directory The directory to get the style variations from.
+ * @param string $scope The scope or type of style variation to retrieve e.g. theme, block etc.
+ * @return array
+ */
+ public static function get_style_variations_from_directory( $directory, $scope = 'theme' ) {
+ $variation_files = array();
+ $variations = array();
+ if ( is_dir( $directory ) ) {
+ if ( get_stylesheet_directory() === $directory ) {
+ $variation_files = static::get_style_variation_files_from_current_theme();
+ } else {
+ $variation_files = static::recursively_iterate_json( $directory );
+ }
+ }
ksort( $variation_files );
foreach ( $variation_files as $path => $file ) {
$decoded_file = self::read_json_file( $path );
diff --git a/lib/experimental/editor-settings.php b/lib/experimental/editor-settings.php
index 065264fd124e8c..c34984baa0a619 100644
--- a/lib/experimental/editor-settings.php
+++ b/lib/experimental/editor-settings.php
@@ -43,12 +43,28 @@ function gutenberg_enable_experiments() {
/**
* Sets a global JS variable used to trigger the availability of form & input blocks.
+ *
+ * @deprecated 19.0.0 Use gutenberg_enable_block_experiments().
*/
function gutenberg_enable_form_input_blocks() {
+ _deprecated_function( __FUNCTION__, 'Gutenberg 19.0.0', 'gutenberg_enable_block_experiments' );
+}
+
+/**
+ * Sets global JS variables used to enable various block experiments.
+ */
+function gutenberg_enable_block_experiments() {
$gutenberg_experiments = get_option( 'gutenberg-experiments' );
+
+ // Experimental form blocks.
if ( $gutenberg_experiments && array_key_exists( 'gutenberg-form-blocks', $gutenberg_experiments ) ) {
wp_add_inline_script( 'wp-block-editor', 'window.__experimentalEnableFormBlocks = true', 'before' );
}
+
+ // General experimental blocks that are not in the default block library.
+ if ( $gutenberg_experiments && array_key_exists( 'gutenberg-block-experiments', $gutenberg_experiments ) ) {
+ wp_add_inline_script( 'wp-block-editor', 'window.__experimentalEnableBlockExperiments = true', 'before' );
+ }
}
-add_action( 'admin_init', 'gutenberg_enable_form_input_blocks' );
+add_action( 'admin_init', 'gutenberg_enable_block_experiments' );
diff --git a/lib/experiments-page.php b/lib/experiments-page.php
index acb095b47fde30..b27f6fc2726a2a 100644
--- a/lib/experiments-page.php
+++ b/lib/experiments-page.php
@@ -79,6 +79,18 @@ function gutenberg_initialize_experiments_settings() {
)
);
+ add_settings_field(
+ 'gutenberg-block-experiments',
+ __( 'Experimental blocks', 'gutenberg' ),
+ 'gutenberg_display_experiment_field',
+ 'gutenberg-experiments',
+ 'gutenberg_experiments_section',
+ array(
+ 'label' => __( 'Enable experimental blocks.
(Warning: these blocks may have significant changes during development that cause validation errors and display issues.)
', 'gutenberg' ),
+ 'id' => 'gutenberg-block-experiments',
+ )
+ );
+
add_settings_field(
'gutenberg-form-blocks',
__( 'Form and input blocks ', 'gutenberg' ),
diff --git a/package-lock.json b/package-lock.json
index 6680025d768bef..4e7e660619249b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "gutenberg",
- "version": "18.9.0-rc.1",
+ "version": "18.9.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "gutenberg",
- "version": "18.9.0-rc.1",
+ "version": "18.9.0",
"hasInstallScript": true,
"license": "GPL-2.0-or-later",
"dependencies": {
diff --git a/package.json b/package.json
index 412ff34b91d8c1..9234bf92cc9172 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "gutenberg",
- "version": "18.9.0-rc.1",
+ "version": "18.9.0",
"private": true,
"description": "A new WordPress editor experience.",
"author": "The WordPress Contributors",
diff --git a/packages/base-styles/_variables.scss b/packages/base-styles/_variables.scss
index b26d70b7299f9f..97eb513cf38aeb 100644
--- a/packages/base-styles/_variables.scss
+++ b/packages/base-styles/_variables.scss
@@ -90,7 +90,7 @@ $sidebar-width: 280px;
$content-width: 840px;
$wide-content-width: 1100px;
$widget-area-width: 700px;
-
+$secondary-sidebar-width: 350px;
/**
* Block & Editor UI.
diff --git a/packages/block-editor/src/components/grid/grid-item-resizer.js b/packages/block-editor/src/components/grid/grid-item-resizer.js
index 28d9678772f76c..da3eb824fe92e5 100644
--- a/packages/block-editor/src/components/grid/grid-item-resizer.js
+++ b/packages/block-editor/src/components/grid/grid-item-resizer.js
@@ -119,6 +119,15 @@ function GridItemResizerInner( {
} }
bounds={ bounds }
boundsByDirection
+ onPointerDown={ ( { target, pointerId } ) => {
+ /*
+ * Captures the pointer to avoid hiccups while dragging over objects
+ * like iframes and ensures that the event to end the drag is
+ * captured by the target (resize handle) whether or not it’s under
+ * the pointer.
+ */
+ target.setPointerCapture( pointerId );
+ } }
onResizeStart={ ( event, direction ) => {
/*
* The container justification and alignment need to be set
@@ -126,21 +135,6 @@ function GridItemResizerInner( {
* so that it resizes in the right direction.
*/
setResizeDirection( direction );
-
- /*
- * The mouseup event on the resize handle doesn't trigger if the mouse
- * isn't directly above the handle, so we try to detect if it happens
- * outside the grid and dispatch a mouseup event on the handle.
- */
- blockElement.ownerDocument.addEventListener(
- 'mouseup',
- () => {
- event.target.dispatchEvent(
- new Event( 'mouseup', { bubbles: true } )
- );
- },
- { once: true }
- );
} }
onResizeStop={ ( event, direction, boxElement ) => {
const columnGap = parseFloat(
diff --git a/packages/block-editor/src/components/inserter/category-tabs/index.js b/packages/block-editor/src/components/inserter/category-tabs/index.js
index a379f4719556b2..6a02cf1a170c45 100644
--- a/packages/block-editor/src/components/inserter/category-tabs/index.js
+++ b/packages/block-editor/src/components/inserter/category-tabs/index.js
@@ -1,11 +1,13 @@
/**
* WordPress dependencies
*/
+import { usePrevious, useReducedMotion } from '@wordpress/compose';
import { isRTL } from '@wordpress/i18n';
import {
__experimentalHStack as HStack,
FlexBlock,
privateApis as componentsPrivateApis,
+ __unstableMotion as motion,
} from '@wordpress/components';
import { Icon, chevronRight, chevronLeft } from '@wordpress/icons';
@@ -22,6 +24,17 @@ function CategoryTabs( {
onSelectCategory,
children,
} ) {
+ // Copied from InterfaceSkeleton.
+ const ANIMATION_DURATION = 0.25;
+ const disableMotion = useReducedMotion();
+ const defaultTransition = {
+ type: 'tween',
+ duration: disableMotion ? 0 : ANIMATION_DURATION,
+ ease: [ 0.6, 0, 0.4, 1 ],
+ };
+
+ const previousSelectedCategory = usePrevious( selectedCategory );
+
return (
- { children }
+
+ { children }
+
) ) }
diff --git a/packages/block-editor/src/components/inserter/style.scss b/packages/block-editor/src/components/inserter/style.scss
index c7398aadb56ba5..960ca8b48cdf90 100644
--- a/packages/block-editor/src/components/inserter/style.scss
+++ b/packages/block-editor/src/components/inserter/style.scss
@@ -1,5 +1,5 @@
$block-inserter-preview-height: 350px;
-$block-inserter-width: 350px;
+$block-quick-inserter-width: 350px;
$block-inserter-tabs-height: 44px;
.block-editor-inserter {
@@ -24,6 +24,12 @@ $block-inserter-tabs-height: 44px;
&.show-as-tabs {
gap: 0;
}
+
+ .block-editor-tabbed-sidebar {
+ @include break-medium() {
+ width: $secondary-sidebar-width;
+ }
+ }
}
.block-editor-inserter__popover.is-quick {
@@ -85,6 +91,12 @@ $block-inserter-tabs-height: 44px;
height: 100%;
position: relative;
overflow: visible;
+
+ &.show-panel {
+ @include break-medium() {
+ width: $secondary-sidebar-width + $sidebar-width;
+ }
+ }
}
.block-editor-inserter__inline-elements {
@@ -299,14 +311,13 @@ $block-inserter-tabs-height: 44px;
@include break-medium {
border-left: $border-width solid $gray-200;
padding: 0;
- left: 100%;
- width: 300px;
+ left: $secondary-sidebar-width;
+ width: $sidebar-width;
position: absolute;
top: -$border-width;
height: calc(100% + #{$border-width});
background: $gray-100;
border-top: $border-width solid $gray-200;
- box-shadow: $border-width $border-width 0 0 rgba($color: #000, $alpha: 0.133); // 0.133 = $gray-200 but with alpha.
.block-editor-inserter__media-list,
.block-editor-block-patterns-list {
@@ -366,7 +377,7 @@ $block-inserter-tabs-height: 44px;
max-width: 100%;
@include break-medium {
- width: $block-inserter-width;
+ width: $block-quick-inserter-width;
}
}
@@ -679,12 +690,6 @@ $block-inserter-tabs-height: 44px;
height: 100%;
}
}
-
- // Remove doubled-up shadow that occurs when categories panel is opened, only in zoom out.
- // Shadow cannot be removed from the source, as it is required when not zoomed out.
- .block-editor-inserter__category-panel {
- box-shadow: none;
- }
}
.show-icon-labels {
diff --git a/packages/block-editor/src/components/tabbed-sidebar/style.scss b/packages/block-editor/src/components/tabbed-sidebar/style.scss
index e392cf955ed06c..374a012173e230 100644
--- a/packages/block-editor/src/components/tabbed-sidebar/style.scss
+++ b/packages/block-editor/src/components/tabbed-sidebar/style.scss
@@ -1,13 +1,10 @@
.block-editor-tabbed-sidebar {
+ background-color: $white;
height: 100%;
display: flex;
flex-direction: column;
flex-grow: 1;
overflow: hidden;
-
- @include break-medium() {
- width: 350px;
- }
}
.block-editor-tabbed-sidebar__tablist-and-close-button {
diff --git a/packages/block-library/src/comments-title/block.json b/packages/block-library/src/comments-title/block.json
index f8a02f2e5089b5..b66b741e1916a0 100644
--- a/packages/block-library/src/comments-title/block.json
+++ b/packages/block-library/src/comments-title/block.json
@@ -23,6 +23,9 @@
"level": {
"type": "number",
"default": 2
+ },
+ "levelOptions": {
+ "type": "array"
}
},
"supports": {
diff --git a/packages/block-library/src/comments-title/edit.js b/packages/block-library/src/comments-title/edit.js
index 07149607bfc393..f2a9d23ddf6cae 100644
--- a/packages/block-library/src/comments-title/edit.js
+++ b/packages/block-library/src/comments-title/edit.js
@@ -23,7 +23,13 @@ import apiFetch from '@wordpress/api-fetch';
import { addQueryArgs } from '@wordpress/url';
export default function Edit( {
- attributes: { textAlign, showPostTitle, showCommentsCount, level },
+ attributes: {
+ textAlign,
+ showPostTitle,
+ showCommentsCount,
+ level,
+ levelOptions,
+ },
setAttributes,
context: { postType, postId },
} ) {
@@ -95,6 +101,7 @@ export default function Edit( {
/>
setAttributes( { level: newLevel } )
}
diff --git a/packages/block-library/src/list-item/block.json b/packages/block-library/src/list-item/block.json
index 6110df530bf5e0..32a552c3779cd3 100644
--- a/packages/block-library/src/list-item/block.json
+++ b/packages/block-library/src/list-item/block.json
@@ -6,7 +6,7 @@
"category": "text",
"parent": [ "core/list" ],
"allowedBlocks": [ "core/list" ],
- "description": "Create a list item.",
+ "description": "An individual item within a list.",
"textdomain": "default",
"attributes": {
"placeholder": {
@@ -25,8 +25,8 @@
"color": {
"gradients": true,
"link": true,
+ "background": true,
"__experimentalDefaultControls": {
- "background": true,
"text": true
}
},
diff --git a/packages/block-library/src/list/block.json b/packages/block-library/src/list/block.json
index 157aaf7c0cf633..8b100071c15ea9 100644
--- a/packages/block-library/src/list/block.json
+++ b/packages/block-library/src/list/block.json
@@ -5,7 +5,7 @@
"title": "List",
"category": "text",
"allowedBlocks": [ "core/list-item" ],
- "description": "Create a bulleted or numbered list.",
+ "description": "An organized collection of items displayed in a specific order.",
"keywords": [ "bullet list", "ordered list", "numbered list" ],
"textdomain": "default",
"attributes": {
diff --git a/packages/block-library/src/list/ordered-list-settings.js b/packages/block-library/src/list/ordered-list-settings.js
index 8c433a465638ff..66817669806233 100644
--- a/packages/block-library/src/list/ordered-list-settings.js
+++ b/packages/block-library/src/list/ordered-list-settings.js
@@ -13,25 +13,10 @@ import {
const OrderedListSettings = ( { setAttributes, reversed, start, type } ) => (
- {
- const int = parseInt( value, 10 );
-
- setAttributes( {
- // It should be possible to unset the value,
- // e.g. with an empty string.
- start: isNaN( int ) ? undefined : int,
- } );
- } }
- value={ Number.isInteger( start ) ? start.toString( 10 ) : '' }
- step="1"
- />
(
value={ type }
onChange={ ( newValue ) => setAttributes( { type: newValue } ) }
/>
+ {
+ const int = parseInt( value, 10 );
+
+ setAttributes( {
+ // It should be possible to unset the value,
+ // e.g. with an empty string.
+ start: isNaN( int ) ? undefined : int,
+ } );
+ } }
+ value={ Number.isInteger( start ) ? start.toString( 10 ) : '' }
+ step="1"
+ />
{
setAttributes( {
diff --git a/packages/block-library/src/list/test/edit.native.js b/packages/block-library/src/list/test/edit.native.js
index a33bce32e5bca0..2393f2820cfc2e 100644
--- a/packages/block-library/src/list/test/edit.native.js
+++ b/packages/block-library/src/list/test/edit.native.js
@@ -289,9 +289,7 @@ describe( 'List block', () => {
() => screen.getByTestId( 'block-settings-modal' ).props.isVisible
);
- const reverseButton = screen.getByLabelText(
- /Reverse list numbering\. Off/
- );
+ const reverseButton = screen.getByLabelText( /Reverse order\. Off/ );
fireEvent.press( reverseButton );
expect( getEditorHtml() ).toMatchSnapshot();
diff --git a/packages/block-library/src/post-content/block.json b/packages/block-library/src/post-content/block.json
index 5ca3892f567a54..1b9de707cb3220 100644
--- a/packages/block-library/src/post-content/block.json
+++ b/packages/block-library/src/post-content/block.json
@@ -54,5 +54,6 @@
}
}
},
+ "style": "wp-block-post-content",
"editorStyle": "wp-block-post-content-editor"
}
diff --git a/packages/block-library/src/post-content/style.scss b/packages/block-library/src/post-content/style.scss
new file mode 100644
index 00000000000000..96e27d04679d44
--- /dev/null
+++ b/packages/block-library/src/post-content/style.scss
@@ -0,0 +1,5 @@
+.wp-block-post-content::after {
+ content: "";
+ display: table;
+ clear: both;
+}
diff --git a/packages/block-library/src/post-title/block.json b/packages/block-library/src/post-title/block.json
index 9c3ba3e214e4b1..ecb5053d6cd39e 100644
--- a/packages/block-library/src/post-title/block.json
+++ b/packages/block-library/src/post-title/block.json
@@ -15,6 +15,9 @@
"type": "number",
"default": 2
},
+ "levelOptions": {
+ "type": "array"
+ },
"isLink": {
"type": "boolean",
"default": false
diff --git a/packages/block-library/src/post-title/edit.js b/packages/block-library/src/post-title/edit.js
index 3963016e342822..d24455f0956358 100644
--- a/packages/block-library/src/post-title/edit.js
+++ b/packages/block-library/src/post-title/edit.js
@@ -22,7 +22,7 @@ import { useEntityProp, store as coreStore } from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';
export default function PostTitleEdit( {
- attributes: { level, textAlign, isLink, rel, linkTarget },
+ attributes: { level, levelOptions, textAlign, isLink, rel, linkTarget },
setAttributes,
context: { postType, postId, queryId },
insertBlocksAfter,
@@ -125,6 +125,7 @@ export default function PostTitleEdit( {
setAttributes( { level: newLevel } )
}
diff --git a/packages/block-library/src/query-title/block.json b/packages/block-library/src/query-title/block.json
index 674daadee3bb69..2a3c7d9f236995 100644
--- a/packages/block-library/src/query-title/block.json
+++ b/packages/block-library/src/query-title/block.json
@@ -17,6 +17,9 @@
"type": "number",
"default": 1
},
+ "levelOptions": {
+ "type": "array"
+ },
"showPrefix": {
"type": "boolean",
"default": true
diff --git a/packages/block-library/src/query-title/edit.js b/packages/block-library/src/query-title/edit.js
index 71f0e26d706842..845809a9300137 100644
--- a/packages/block-library/src/query-title/edit.js
+++ b/packages/block-library/src/query-title/edit.js
@@ -25,7 +25,14 @@ import { useArchiveLabel } from './use-archive-label';
const SUPPORTED_TYPES = [ 'archive', 'search' ];
export default function QueryTitleEdit( {
- attributes: { type, level, textAlign, showPrefix, showSearchTerm },
+ attributes: {
+ type,
+ level,
+ levelOptions,
+ textAlign,
+ showPrefix,
+ showSearchTerm,
+ },
setAttributes,
} ) {
const { archiveTypeLabel, archiveNameLabel } = useArchiveLabel();
@@ -130,6 +137,7 @@ export default function QueryTitleEdit( {
setAttributes( { level: newLevel } )
}
diff --git a/packages/block-library/src/query/edit/inspector-controls/sticky-control.js b/packages/block-library/src/query/edit/inspector-controls/sticky-control.js
index 98bec75ad933b6..ee7ee31ba977a9 100644
--- a/packages/block-library/src/query/edit/inspector-controls/sticky-control.js
+++ b/packages/block-library/src/query/edit/inspector-controls/sticky-control.js
@@ -20,7 +20,7 @@ export default function StickyControl( { value, onChange } ) {
value={ value }
onChange={ onChange }
help={ __(
- 'Blog posts can be “stickied”, a feature that places them at the top of the front page of posts, keeping it there until new sticky posts are published.'
+ 'Sticky posts always appear first, regardless of their publish date.'
) }
/>
);
diff --git a/packages/block-library/src/site-tagline/block.json b/packages/block-library/src/site-tagline/block.json
index 25b3840cd663a0..d42b7bcd4bed64 100644
--- a/packages/block-library/src/site-tagline/block.json
+++ b/packages/block-library/src/site-tagline/block.json
@@ -14,6 +14,10 @@
"level": {
"type": "number",
"default": 0
+ },
+ "levelOptions": {
+ "type": "array",
+ "default": [ 0, 1, 2, 3, 4, 5, 6 ]
}
},
"example": {
diff --git a/packages/block-library/src/site-tagline/edit.js b/packages/block-library/src/site-tagline/edit.js
index 15f8a789dfbe99..52b9c761ba4f54 100644
--- a/packages/block-library/src/site-tagline/edit.js
+++ b/packages/block-library/src/site-tagline/edit.js
@@ -18,14 +18,12 @@ import {
import { __ } from '@wordpress/i18n';
import { createBlock, getDefaultBlockName } from '@wordpress/blocks';
-const HEADING_LEVELS = [ 0, 1, 2, 3, 4, 5, 6 ];
-
export default function SiteTaglineEdit( {
attributes,
setAttributes,
insertBlocksAfter,
} ) {
- const { textAlign, level } = attributes;
+ const { textAlign, level, levelOptions } = attributes;
const { canUserEdit, tagline } = useSelect( ( select ) => {
const { canUser, getEntityRecord, getEditedEntityRecord } =
select( coreStore );
@@ -82,8 +80,8 @@ export default function SiteTaglineEdit( {
<>
setAttributes( { level: newLevel } )
}
diff --git a/packages/block-library/src/site-title/block.json b/packages/block-library/src/site-title/block.json
index 95d8deb1e43b9d..c75b1bc229beb9 100644
--- a/packages/block-library/src/site-title/block.json
+++ b/packages/block-library/src/site-title/block.json
@@ -11,6 +11,10 @@
"type": "number",
"default": 1
},
+ "levelOptions": {
+ "type": "array",
+ "default": [ 0, 1, 2, 3, 4, 5, 6 ]
+ },
"textAlign": {
"type": "string"
},
diff --git a/packages/block-library/src/site-title/edit.js b/packages/block-library/src/site-title/edit.js
index 76519ac1297b14..82e3c1d7f7bb40 100644
--- a/packages/block-library/src/site-title/edit.js
+++ b/packages/block-library/src/site-title/edit.js
@@ -21,14 +21,12 @@ import { ToggleControl, PanelBody } from '@wordpress/components';
import { createBlock, getDefaultBlockName } from '@wordpress/blocks';
import { decodeEntities } from '@wordpress/html-entities';
-const HEADING_LEVELS = [ 0, 1, 2, 3, 4, 5, 6 ];
-
export default function SiteTitleEdit( {
attributes,
setAttributes,
insertBlocksAfter,
} ) {
- const { level, textAlign, isLink, linkTarget } = attributes;
+ const { level, levelOptions, textAlign, isLink, linkTarget } = attributes;
const { canUserEdit, title } = useSelect( ( select ) => {
const { canUser, getEntityRecord, getEditedEntityRecord } =
select( coreStore );
@@ -97,8 +95,8 @@ export default function SiteTitleEdit( {
<>
setAttributes( { level: newLevel } )
}
diff --git a/packages/block-library/src/style.scss b/packages/block-library/src/style.scss
index db9d033d915db8..8f17cd7a50f55c 100644
--- a/packages/block-library/src/style.scss
+++ b/packages/block-library/src/style.scss
@@ -30,6 +30,7 @@
@import "./paragraph/style.scss";
@import "./post-author/style.scss";
@import "./post-comments-form/style.scss";
+@import "./post-content/style.scss";
@import "./post-date/style.scss";
@import "./post-excerpt/style.scss";
@import "./post-featured-image/style.scss";
diff --git a/packages/block-library/src/tag-cloud/block.json b/packages/block-library/src/tag-cloud/block.json
index b95e02204faa29..0c2095bff2a152 100644
--- a/packages/block-library/src/tag-cloud/block.json
+++ b/packages/block-library/src/tag-cloud/block.json
@@ -4,7 +4,7 @@
"name": "core/tag-cloud",
"title": "Tag Cloud",
"category": "widgets",
- "description": "A cloud of your most used tags.",
+ "description": "A cloud of popular keywords, each sized by how often it appears.",
"textdomain": "default",
"attributes": {
"numberOfTags": {
diff --git a/packages/block-library/src/tag-cloud/edit.js b/packages/block-library/src/tag-cloud/edit.js
index 29f4823a19b425..17ca150bc4d75f 100644
--- a/packages/block-library/src/tag-cloud/edit.js
+++ b/packages/block-library/src/tag-cloud/edit.js
@@ -12,6 +12,7 @@ import {
__experimentalUseCustomUnits as useCustomUnits,
__experimentalParseQuantityAndUnitFromRawValue as parseQuantityAndUnitFromRawValue,
Disabled,
+ BaseControl,
} from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';
@@ -111,6 +112,7 @@ function TagCloudEdit( { attributes, setAttributes } ) {
-
- setAttributes( { showTagCounts: ! showTagCounts } )
- }
- />
+
+
+
+ {
+ onFontSizeChange(
+ 'smallestFontSize',
+ value
+ );
+ } }
+ units={ units }
+ min={ MIN_FONT_SIZE }
+ max={ MAX_FONT_SIZE }
+ size="__unstable-large"
+ />
+
+
+ {
+ onFontSizeChange(
+ 'largestFontSize',
+ value
+ );
+ } }
+ units={ units }
+ min={ MIN_FONT_SIZE }
+ max={ MAX_FONT_SIZE }
+ size="__unstable-large"
+ />
+
+
+
-
-
- {
- onFontSizeChange( 'smallestFontSize', value );
- } }
- units={ units }
- min={ MIN_FONT_SIZE }
- max={ MAX_FONT_SIZE }
- />
-
-
- {
- onFontSizeChange( 'largestFontSize', value );
- } }
- units={ units }
- min={ MIN_FONT_SIZE }
- max={ MAX_FONT_SIZE }
- />
-
-
+
+ setAttributes( { showTagCounts: ! showTagCounts } )
+ }
+ />
);
diff --git a/packages/block-library/src/template-part/edit/index.js b/packages/block-library/src/template-part/edit/index.js
index 0cb6cfc8996ce9..ba3e8f57136d60 100644
--- a/packages/block-library/src/template-part/edit/index.js
+++ b/packages/block-library/src/template-part/edit/index.js
@@ -128,7 +128,7 @@ export default function TemplatePartEdit( {
area,
onNavigateToEntityRecord,
title,
- canEditTemplate,
+ canUserEdit,
} = useSelect(
( select ) => {
const { getEditedEntityRecord, hasFinishedResolution } =
@@ -151,10 +151,13 @@ export default function TemplatePartEdit( {
)
: false;
- const _canEditTemplate = select( coreStore ).canUser( 'create', {
- kind: 'postType',
- name: 'wp_template_part',
- } );
+ const _canUserEdit = hasResolvedEntity
+ ? select( coreStore ).canUser( 'update', {
+ kind: 'postType',
+ name: 'wp_template_part',
+ id: templatePartId,
+ } )
+ : false;
return {
hasInnerBlocks: getBlockCount( clientId ) > 0,
@@ -167,7 +170,7 @@ export default function TemplatePartEdit( {
onNavigateToEntityRecord:
getSettings().onNavigateToEntityRecord,
title: entityRecord?.title,
- canEditTemplate: !! _canEditTemplate,
+ canUserEdit: !! _canUserEdit,
};
},
[ templatePartId, attributes.area, clientId ]
@@ -237,7 +240,7 @@ export default function TemplatePartEdit( {
{ isEntityAvailable &&
onNavigateToEntityRecord &&
- canEditTemplate && (
+ canUserEdit && (
diff --git a/packages/block-library/src/template-part/edit/inner-blocks.js b/packages/block-library/src/template-part/edit/inner-blocks.js
index ef7d85948626dd..2c246809ab2d49 100644
--- a/packages/block-library/src/template-part/edit/inner-blocks.js
+++ b/packages/block-library/src/template-part/edit/inner-blocks.js
@@ -129,15 +129,17 @@ export default function TemplatePartInnerBlocks( {
return {
canViewTemplatePart: !! select( coreStore ).canUser( 'read', {
kind: 'postType',
- name: 'wp_template',
+ name: 'wp_template_part',
+ id,
} ),
- canEditTemplatePart: !! select( coreStore ).canUser( 'create', {
+ canEditTemplatePart: !! select( coreStore ).canUser( 'update', {
kind: 'postType',
- name: 'wp_template',
+ name: 'wp_template_part',
+ id,
} ),
};
},
- []
+ [ id ]
);
if ( ! canViewTemplatePart ) {
diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md
index 7de4fcf90b0e95..e6e1dbbf50a1f5 100644
--- a/packages/components/CHANGELOG.md
+++ b/packages/components/CHANGELOG.md
@@ -6,9 +6,11 @@
- `ColorPalette`: Remove extra bottom margin when `CircularOptionPicker` is unneeded ([#63961](https://github.com/WordPress/gutenberg/pull/63961)).
- `CustomSelectControl`: Restore `describedBy` functionality ([#63957](https://github.com/WordPress/gutenberg/pull/63957)).
+- `Modal`: Fix the dismissal logic for React development mode ([#64132](https://github.com/WordPress/gutenberg/pull/64132)).
### Enhancements
+- `TimeInput`: Expose as subcomponent of `TimePicker` ([#63145](https://github.com/WordPress/gutenberg/pull/63145)).
- `RadioControl`: add support for option help text ([#63751](https://github.com/WordPress/gutenberg/pull/63751)).
### Internal
diff --git a/packages/components/src/button/stories/e2e/index.story.tsx b/packages/components/src/button/stories/e2e/index.story.tsx
index a4fcfdeac5ca48..d2651e8df1ec18 100644
--- a/packages/components/src/button/stories/e2e/index.story.tsx
+++ b/packages/components/src/button/stories/e2e/index.story.tsx
@@ -31,28 +31,110 @@ export const VariantStates: StoryFn< typeof Button > = (
'link',
];
- return (
-
- { variants.map( ( variant ) => (
-
{
+ return (
+
+
-
- { /* eslint-disable-next-line no-restricted-syntax */ }
-
-
-
-
-
-
- ) ) }
-
+ { name }
+
+ { variants.map( ( variant ) => (
+
+
+
+ ) ) }
+
+ );
+ };
+
+ return (
+
+
+
+
+ { variants.map( ( variant ) => (
+
+ { variant ?? '(default)' }
+
+ ) ) }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
};
VariantStates.args = {
diff --git a/packages/components/src/button/style.scss b/packages/components/src/button/style.scss
index ae242c38634180..3541699a08eefd 100644
--- a/packages/components/src/button/style.scss
+++ b/packages/components/src/button/style.scss
@@ -1,3 +1,10 @@
+/**
+ * For easier testing of potential regressions, you can use a Button variant matrix
+ * available in a special Storybook instance by running `npm run storybook:e2e:dev`.
+ *
+ * @see https://github.com/WordPress/gutenberg/blob/trunk/test/storybook-playwright/README.md
+ */
+
.components-button {
display: inline-flex;
text-decoration: none;
diff --git a/packages/components/src/date-time/index.ts b/packages/components/src/date-time/index.ts
index 8335366bcbb73b..a103bac0d30efb 100644
--- a/packages/components/src/date-time/index.ts
+++ b/packages/components/src/date-time/index.ts
@@ -3,8 +3,7 @@
*/
import { default as DatePicker } from './date';
import { default as TimePicker } from './time';
-import { default as TimeInput } from './time-input';
import { default as DateTimePicker } from './date-time';
-export { DatePicker, TimePicker, TimeInput };
+export { DatePicker, TimePicker };
export default DateTimePicker;
diff --git a/packages/components/src/date-time/stories/time-input.story.tsx b/packages/components/src/date-time/stories/time-input.story.tsx
deleted file mode 100644
index c74d886e82477c..00000000000000
--- a/packages/components/src/date-time/stories/time-input.story.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-/**
- * External dependencies
- */
-import type { Meta, StoryFn } from '@storybook/react';
-import { action } from '@storybook/addon-actions';
-
-/**
- * Internal dependencies
- */
-import { TimeInput } from '../time-input';
-
-const meta: Meta< typeof TimeInput > = {
- title: 'Components/TimeInput',
- component: TimeInput,
- argTypes: {
- onChange: { action: 'onChange', control: { type: null } },
- },
- tags: [ 'status-wip' ],
- parameters: {
- controls: { expanded: true },
- docs: { canvas: { sourceState: 'shown' } },
- },
- args: {
- onChange: action( 'onChange' ),
- },
-};
-export default meta;
-
-const Template: StoryFn< typeof TimeInput > = ( args ) => {
- return
;
-};
-
-export const Default: StoryFn< typeof TimeInput > = Template.bind( {} );
-Default.args = {
- label: 'Time',
-};
diff --git a/packages/components/src/date-time/stories/time.story.tsx b/packages/components/src/date-time/stories/time.story.tsx
index c48b8fb1d15922..947b5bd64d5eb1 100644
--- a/packages/components/src/date-time/stories/time.story.tsx
+++ b/packages/components/src/date-time/stories/time.story.tsx
@@ -16,6 +16,8 @@ import TimePicker from '../time';
const meta: Meta< typeof TimePicker > = {
title: 'Components/TimePicker',
component: TimePicker,
+ // @ts-expect-error - See https://github.com/storybookjs/storybook/issues/23170
+ subcomponents: { 'TimePicker.TimeInput': TimePicker.TimeInput },
argTypes: {
currentTime: { control: 'date' },
onChange: { action: 'onChange', control: { type: null } },
@@ -49,3 +51,18 @@ const Template: StoryFn< typeof TimePicker > = ( {
};
export const Default: StoryFn< typeof TimePicker > = Template.bind( {} );
+
+const TimeInputTemplate: StoryFn< typeof TimePicker.TimeInput > = ( args ) => {
+ return
;
+};
+
+/**
+ * The time input can be used in isolation as `
`. In this case, the `value` will be passed
+ * as an object in 24-hour format (`{ hours: number, minutes: number }`).
+ */
+export const TimeInput = TimeInputTemplate.bind( {} );
+TimeInput.args = {
+ label: 'Time',
+};
+// Hide TimePicker controls because they don't apply to TimeInput
+TimeInput.parameters = { controls: { include: [] } };
diff --git a/packages/components/src/date-time/time/index.tsx b/packages/components/src/date-time/time/index.tsx
index e2877a1ded5e1f..809376d99d3036 100644
--- a/packages/components/src/date-time/time/index.tsx
+++ b/packages/components/src/date-time/time/index.tsx
@@ -32,7 +32,7 @@ import {
validateInputElementTarget,
} from '../utils';
import { TIMEZONELESS_FORMAT } from '../constants';
-import { TimeInput } from '../time-input';
+import { TimeInput } from './time-input';
const VALID_DATE_ORDERS = [ 'dmy', 'mdy', 'ymd' ];
@@ -252,4 +252,29 @@ export function TimePicker( {
);
}
+/**
+ * A component to input a time.
+ *
+ * Values are passed as an object in 24-hour format (`{ hours: number, minutes: number }`).
+ *
+ * ```jsx
+ * import { TimePicker } from '@wordpress/components';
+ * import { useState } from '@wordpress/element';
+ *
+ * const MyTimeInput = () => {
+ * const [ time, setTime ] = useState( { hours: 13, minutes: 30 } );
+ *
+ * return (
+ *
+ * );
+ * };
+ * ```
+ */
+TimePicker.TimeInput = TimeInput;
+Object.assign( TimePicker.TimeInput, { displayName: 'TimePicker.TimeInput' } );
+
export default TimePicker;
diff --git a/packages/components/src/date-time/time/styles.ts b/packages/components/src/date-time/time/styles.ts
index bba0cc500e0c8a..066c8fb1d1d3cd 100644
--- a/packages/components/src/date-time/time/styles.ts
+++ b/packages/components/src/date-time/time/styles.ts
@@ -62,6 +62,7 @@ export const HoursInput = styled( NumberControl )`
export const TimeSeparator = styled.span`
border-top: ${ CONFIG.borderWidth } solid ${ COLORS.gray[ 700 ] };
border-bottom: ${ CONFIG.borderWidth } solid ${ COLORS.gray[ 700 ] };
+ font-size: ${ CONFIG.fontSize };
line-height: calc(
${ CONFIG.controlHeight } - ${ CONFIG.borderWidth } * 2
);
diff --git a/packages/components/src/date-time/time-input/index.tsx b/packages/components/src/date-time/time/time-input/index.tsx
similarity index 91%
rename from packages/components/src/date-time/time-input/index.tsx
rename to packages/components/src/date-time/time/time-input/index.tsx
index bfac1e2b604c23..b4421c601b1d6d 100644
--- a/packages/components/src/date-time/time-input/index.tsx
+++ b/packages/components/src/date-time/time/time-input/index.tsx
@@ -18,20 +18,20 @@ import {
HoursInput,
MinutesInput,
Fieldset,
-} from '../time/styles';
-import { HStack } from '../../h-stack';
-import Button from '../../button';
-import ButtonGroup from '../../button-group';
+} from '../styles';
+import { HStack } from '../../../h-stack';
+import Button from '../../../button';
+import ButtonGroup from '../../../button-group';
import {
from12hTo24h,
from24hTo12h,
buildPadInputStateReducer,
validateInputElementTarget,
-} from '../utils';
-import type { TimeInputProps } from '../types';
-import type { InputChangeCallback } from '../../input-control/types';
-import { useControlledValue } from '../../utils';
-import BaseControl from '../../base-control';
+} from '../../utils';
+import type { TimeInputProps } from '../../types';
+import type { InputChangeCallback } from '../../../input-control/types';
+import { useControlledValue } from '../../../utils';
+import BaseControl from '../../../base-control';
export function TimeInput( {
value: valueProp,
diff --git a/packages/components/src/date-time/time-input/test/index.tsx b/packages/components/src/date-time/time/time-input/test/index.tsx
similarity index 100%
rename from packages/components/src/date-time/time-input/test/index.tsx
rename to packages/components/src/date-time/time/time-input/test/index.tsx
diff --git a/packages/components/src/modal/index.tsx b/packages/components/src/modal/index.tsx
index 42ba2d78db57a8..b18217cdbaadcb 100644
--- a/packages/components/src/modal/index.tsx
+++ b/packages/components/src/modal/index.tsx
@@ -2,12 +2,7 @@
* External dependencies
*/
import clsx from 'clsx';
-import type {
- ForwardedRef,
- KeyboardEvent,
- MutableRefObject,
- UIEvent,
-} from 'react';
+import type { ForwardedRef, KeyboardEvent, RefObject, UIEvent } from 'react';
/**
* WordPress dependencies
@@ -44,9 +39,10 @@ import type { ModalProps } from './types';
import { withIgnoreIMEEvents } from '../utils/with-ignore-ime-events';
// Used to track and dismiss the prior modal when another opens unless nested.
-const ModalContext = createContext<
- MutableRefObject< ModalProps[ 'onRequestClose' ] | undefined >[]
->( [] );
+type Dismissers = Set<
+ RefObject< ModalProps[ 'onRequestClose' ] | undefined >
+>;
+const ModalContext = createContext< Dismissers >( new Set() );
// Used to track body class names applied while modals are open.
const bodyOpenClasses = new Map< string, number >();
@@ -147,23 +143,28 @@ function UnforwardedModal(
// one should remain open at a time and the list enables closing prior ones.
const dismissers = useContext( ModalContext );
// Used for the tracking and dismissing any nested modals.
- const nestedDismissers = useRef< typeof dismissers >( [] );
+ const [ nestedDismissers ] = useState< Dismissers >( () => new Set() );
// Updates the stack tracking open modals at this level and calls
// onRequestClose for any prior and/or nested modals as applicable.
useEffect( () => {
- dismissers.push( refOnRequestClose );
- const [ first, second ] = dismissers;
- if ( second ) {
- first?.current?.();
+ // add this modal instance to the dismissers set
+ dismissers.add( refOnRequestClose );
+ // request that all the other modals close themselves
+ for ( const dismisser of dismissers ) {
+ if ( dismisser !== refOnRequestClose ) {
+ dismisser.current?.();
+ }
}
-
- const nested = nestedDismissers.current;
return () => {
- nested[ 0 ]?.current?.();
- dismissers.shift();
+ // request that all the nested modals close themselves
+ for ( const dismisser of nestedDismissers ) {
+ dismisser.current?.();
+ }
+ // remove this modal instance from the dismissers set
+ dismissers.delete( refOnRequestClose );
};
- }, [ dismissers ] );
+ }, [ dismissers, nestedDismissers ] );
// Adds/removes the value of bodyOpenClassName to body element.
useEffect( () => {
@@ -350,7 +351,7 @@ function UnforwardedModal(
);
return createPortal(
-
+
{ modal }
,
document.body
diff --git a/packages/components/src/utils/config-values.js b/packages/components/src/utils/config-values.js
index 2e102b8b0b77cc..ba92813bdbfb0f 100644
--- a/packages/components/src/utils/config-values.js
+++ b/packages/components/src/utils/config-values.js
@@ -42,6 +42,12 @@ export default Object.assign( {}, CONTROL_PROPS, TOGGLE_GROUP_CONTROL_PROPS, {
colorScrollbarThumbHover: 'rgba(0, 0, 0, 0.5)',
colorScrollbarTrack: 'rgba(0, 0, 0, 0.04)',
elevationIntensity: 1,
+ radiusXSmall: '1px',
+ radiusSmall: '2px',
+ radiusMedium: '4px',
+ radiusLarge: '8px',
+ radiusFull: '9999px',
+ radiusRound: '50%',
radiusBlockUi: '2px',
borderWidth: '1px',
borderWidthFocus: '1.5px',
diff --git a/packages/edit-site/src/components/add-new-template/utils.js b/packages/edit-site/src/components/add-new-template/utils.js
index 1e544aeaadfe1b..a2644ec4ad4da9 100644
--- a/packages/edit-site/src/components/add-new-template/utils.js
+++ b/packages/edit-site/src/components/add-new-template/utils.js
@@ -166,9 +166,11 @@ export function usePostTypeArchiveMenuItems() {
// `icon` is the `menu_icon` property of a post type. We
// only handle `dashicons` for now, even if the `menu_icon`
// also supports urls and svg as values.
- icon: postType.icon?.startsWith( 'dashicons-' )
- ? postType.icon.slice( 10 )
- : archive,
+ icon:
+ typeof postType.icon === 'string' &&
+ postType.icon.startsWith( 'dashicons-' )
+ ? postType.icon.slice( 10 )
+ : archive,
templatePrefix: 'archive',
};
} ) || [],
@@ -272,9 +274,11 @@ export const usePostTypeMenuItems = ( onClickMenuItem ) => {
// `icon` is the `menu_icon` property of a post type. We
// only handle `dashicons` for now, even if the `menu_icon`
// also supports urls and svg as values.
- icon: icon?.startsWith( 'dashicons-' )
- ? icon.slice( 10 )
- : post,
+ icon:
+ typeof icon === 'string' &&
+ icon.startsWith( 'dashicons-' )
+ ? icon.slice( 10 )
+ : post,
templatePrefix: templatePrefixes[ slug ],
};
const hasEntities = postTypesInfo?.[ slug ]?.hasEntities;
diff --git a/packages/edit-site/src/components/editor/index.js b/packages/edit-site/src/components/editor/index.js
index b11a9c56c9c50c..d0c63a9db5cad6 100644
--- a/packages/edit-site/src/components/editor/index.js
+++ b/packages/edit-site/src/components/editor/index.js
@@ -7,8 +7,8 @@ import clsx from 'clsx';
* WordPress dependencies
*/
import { useDispatch, useSelect } from '@wordpress/data';
-import { Button } from '@wordpress/components';
-import { useInstanceId } from '@wordpress/compose';
+import { Button, __unstableMotion as motion } from '@wordpress/components';
+import { useInstanceId, useReducedMotion } from '@wordpress/compose';
import {
EditorKeyboardShortcutsRegister,
privateApis as editorPrivateApis,
@@ -22,6 +22,7 @@ import { store as noticesStore } from '@wordpress/notices';
import { privateApis as routerPrivateApis } from '@wordpress/router';
import { store as preferencesStore } from '@wordpress/preferences';
import { decodeEntities } from '@wordpress/html-entities';
+import { Icon, chevronLeft } from '@wordpress/icons';
/**
* Internal dependencies
@@ -51,7 +52,32 @@ const { Editor, BackButton } = unlock( editorPrivateApis );
const { useHistory, useLocation } = unlock( routerPrivateApis );
const { BlockKeyboardShortcuts } = unlock( blockLibraryPrivateApis );
+const toggleHomeIconVariants = {
+ edit: {
+ opacity: 0,
+ scale: 0.2,
+ },
+ hover: {
+ opacity: 1,
+ scale: 1,
+ clipPath: 'inset( 22% round 2px )',
+ },
+};
+
+const siteIconVariants = {
+ edit: {
+ clipPath: 'inset(0% round 0)',
+ },
+ hover: {
+ clipPath: 'inset( 22% round 2px )',
+ },
+ tap: {
+ clipPath: 'inset(0% round 0)',
+ },
+};
+
export default function EditSiteEditor( { isPostsList = false } ) {
+ const disableMotion = useReducedMotion();
const { params } = useLocation();
const isLoading = useIsSiteEditorLoading();
const {
@@ -65,6 +91,7 @@ export default function EditSiteEditor( { isPostsList = false } ) {
showIconLabels,
editorCanvasView,
currentPostIsTrashed,
+ hasSiteIcon,
} = useSelect( ( select ) => {
const {
getEditorCanvasContainerView,
@@ -75,8 +102,9 @@ export default function EditSiteEditor( { isPostsList = false } ) {
getEditedPostId,
} = unlock( select( editSiteStore ) );
const { get } = select( preferencesStore );
- const { getCurrentTheme } = select( coreDataStore );
+ const { getCurrentTheme, getEntityRecord } = select( coreDataStore );
const _context = getEditedPostContext();
+ const siteData = getEntityRecord( 'root', '__unstableBase', undefined );
// The currently selected entity to display.
// Typically template or template part in the site editor.
@@ -93,6 +121,7 @@ export default function EditSiteEditor( { isPostsList = false } ) {
currentPostIsTrashed:
select( editorStore ).getCurrentPostAttribute( 'status' ) ===
'trash',
+ hasSiteIcon: !! siteData?.site_icon_url,
};
}, [] );
useEditorTitle();
@@ -179,6 +208,9 @@ export default function EditSiteEditor( { isPostsList = false } ) {
getEditorCanvasContainerTitleAndIcon( editorCanvasView );
const isReady = ! isLoading;
+ const transition = {
+ duration: disableMotion ? 0 : 0.2,
+ };
return (
<>
@@ -217,26 +249,52 @@ export default function EditSiteEditor( { isPostsList = false } ) {
{ ( { length } ) =>
length <= 1 && (
- {
- setCanvasMode( 'view' );
- // TODO: this is a temporary solution to navigate to the posts list if we are
- // come here through `posts list` and are in focus mode editing a template, template part etc..
- if (
- isPostsList &&
- params?.focusMode
- ) {
- history.push( {
- page: 'gutenberg-posts-dashboard',
- postType: 'post',
- } );
- }
- } }
+
-
-
+ {
+ setCanvasMode( 'view' );
+ // TODO: this is a temporary solution to navigate to the posts list if we are
+ // come here through `posts list` and are in focus mode editing a template, template part etc..
+ if (
+ isPostsList &&
+ params?.focusMode
+ ) {
+ history.push( {
+ page: 'gutenberg-posts-dashboard',
+ postType: 'post',
+ } );
+ }
+ } }
+ >
+
+
+
+
+
+
+
+
)
}
diff --git a/packages/edit-site/src/components/editor/style.scss b/packages/edit-site/src/components/editor/style.scss
index b157057062c9d1..0e2e85ba9f72dd 100644
--- a/packages/edit-site/src/components/editor/style.scss
+++ b/packages/edit-site/src/components/editor/style.scss
@@ -1,7 +1,7 @@
.edit-site-editor__editor-interface {
opacity: 1;
transition: opacity 0.1s ease-out;
- @include reduce-motion("transition");
+ @include reduce-motion( "transition" );
&.is-loading {
opacity: 0;
@@ -17,3 +17,60 @@
display: flex;
justify-content: center;
}
+
+.edit-site-editor__view-mode-toggle {
+ /* stylelint-disable -- Disable reason: View Transitions not supported properly by stylelint. */
+ view-transition-name: toggle;
+ /* stylelint-enable */
+ position: fixed;
+ top: 0;
+ left: 0;
+ height: $header-height;
+ width: $header-height;
+ z-index: 100;
+
+ .components-button {
+ color: $white;
+ height: 100%;
+ width: 100%;
+ border-radius: 0;
+ overflow: hidden;
+ padding: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ &:hover,
+ &:active {
+ color: $white;
+ }
+
+ &:focus {
+ box-shadow: none;
+ }
+ }
+
+ .edit-site-editor__view-mode-toggle-icon {
+ svg,
+ img {
+ background: $gray-900;
+ display: block;
+ }
+ }
+}
+
+.edit-site-editor__back-icon {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 60px;
+ height: 60px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background-color: hsla(0, 0%, 80%);
+ pointer-events: none;
+
+ &.has-site-icon {
+ background-color: hsla(0, 0%, 100%, 0.6);
+ }
+}
diff --git a/packages/edit-site/src/components/global-styles/font-families.js b/packages/edit-site/src/components/global-styles/font-families.js
index f6610d0457bbae..6a554b136317dd 100644
--- a/packages/edit-site/src/components/global-styles/font-families.js
+++ b/packages/edit-site/src/components/global-styles/font-families.js
@@ -26,7 +26,7 @@ import { unlock } from '../../lock-unlock';
const { useGlobalSetting } = unlock( blockEditorPrivateApis );
function FontFamilies() {
- const { baseCustomFonts, modalTabOpen, setModalTabOpen, setNotice } =
+ const { baseCustomFonts, modalTabOpen, setModalTabOpen } =
useContext( FontLibraryContext );
const [ fontFamilies ] = useGlobalSetting( 'typography.fontFamilies' );
const [ baseFontFamilies ] = useGlobalSetting(
@@ -112,8 +112,6 @@ function FontFamilies() {
variant="secondary"
__next40pxDefaultSize
onClick={ () => {
- // Reset notice when opening the modal.
- setNotice( null );
setModalTabOpen(
hasInstalledFonts
? 'installed-fonts'
diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/context.js b/packages/edit-site/src/components/global-styles/font-library-modal/context.js
index e02dcb2e8a0af5..abfb5484e44bf5 100644
--- a/packages/edit-site/src/components/global-styles/font-library-modal/context.js
+++ b/packages/edit-site/src/components/global-styles/font-library-modal/context.js
@@ -54,7 +54,6 @@ function FontLibraryProvider( { children } ) {
const [ isInstalling, setIsInstalling ] = useState( false );
const [ refreshKey, setRefreshKey ] = useState( 0 );
- const [ notice, setNotice ] = useState( null );
const refreshLibrary = () => {
setRefreshKey( Date.now() );
@@ -139,8 +138,6 @@ function FontLibraryProvider( { children } ) {
}, [ modalTabOpen ] );
const handleSetLibraryFontSelected = ( font ) => {
- setNotice( null );
-
// If font is null, reset the selected font
if ( ! font ) {
setLibraryFontSelected( null );
@@ -527,8 +524,6 @@ function FontLibraryProvider( { children } ) {
modalTabOpen,
setModalTabOpen,
refreshLibrary,
- notice,
- setNotice,
saveFontFamilies,
isResolvingLibrary,
isInstalling,
diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/font-collection.js b/packages/edit-site/src/components/global-styles/font-library-modal/font-collection.js
index cf6857b30c59e6..6f8a27a8aa8927 100644
--- a/packages/edit-site/src/components/global-styles/font-library-modal/font-collection.js
+++ b/packages/edit-site/src/components/global-styles/font-library-modal/font-collection.js
@@ -63,20 +63,15 @@ function FontCollection( { slug } ) {
};
const [ selectedFont, setSelectedFont ] = useState( null );
+ const [ notice, setNotice ] = useState( false );
const [ fontsToInstall, setFontsToInstall ] = useState( [] );
const [ page, setPage ] = useState( 1 );
const [ filters, setFilters ] = useState( {} );
const [ renderConfirmDialog, setRenderConfirmDialog ] = useState(
requiresPermission && ! getGoogleFontsPermissionFromStorage()
);
- const {
- collections,
- getFontCollection,
- installFonts,
- isInstalling,
- notice,
- setNotice,
- } = useContext( FontLibraryContext );
+ const { collections, getFontCollection, installFonts, isInstalling } =
+ useContext( FontLibraryContext );
const selectedCollection = collections.find(
( collection ) => collection.slug === slug
);
@@ -116,8 +111,7 @@ function FontCollection( { slug } ) {
useEffect( () => {
setSelectedFont( null );
- setNotice( null );
- }, [ slug, setNotice ] );
+ }, [ slug ] );
useEffect( () => {
// If the selected fonts change, reset the selected fonts to install
diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/index.js b/packages/edit-site/src/components/global-styles/font-library-modal/index.js
index 80edc1596f08cd..5af4be90fecdcf 100644
--- a/packages/edit-site/src/components/global-styles/font-library-modal/index.js
+++ b/packages/edit-site/src/components/global-styles/font-library-modal/index.js
@@ -44,7 +44,7 @@ function FontLibraryModal( {
onRequestClose,
defaultTabId = 'installed-fonts',
} ) {
- const { collections, setNotice } = useContext( FontLibraryContext );
+ const { collections } = useContext( FontLibraryContext );
const canUserCreate = useSelect( ( select ) => {
return select( coreStore ).canUser( 'create', {
kind: 'postType',
@@ -59,11 +59,6 @@ function FontLibraryModal( {
tabs.push( ...tabsFromCollections( collections || [] ) );
}
- // Reset notice when new tab is selected.
- const onSelect = () => {
- setNotice( null );
- };
-
return (
-
+
{ tabs.map( ( { id, title } ) => (
diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/installed-fonts.js b/packages/edit-site/src/components/global-styles/font-library-modal/installed-fonts.js
index 6602a778dc66c3..7ca2a9218c3bb0 100644
--- a/packages/edit-site/src/components/global-styles/font-library-modal/installed-fonts.js
+++ b/packages/edit-site/src/components/global-styles/font-library-modal/installed-fonts.js
@@ -53,14 +53,13 @@ function InstalledFonts() {
isInstalling,
saveFontFamilies,
getFontFacesActivated,
- notice,
- setNotice,
} = useContext( FontLibraryContext );
const [ fontFamilies, setFontFamilies ] = useGlobalSetting(
'typography.fontFamilies'
);
const [ isConfirmDeleteOpen, setIsConfirmDeleteOpen ] = useState( false );
+ const [ notice, setNotice ] = useState( false );
const [ baseFontFamilies ] = useGlobalSetting(
'typography.fontFamilies',
undefined,
@@ -120,6 +119,24 @@ function InstalledFonts() {
setIsConfirmDeleteOpen( true );
};
+ const handleUpdate = async () => {
+ setNotice( null );
+ try {
+ await saveFontFamilies( fontFamilies );
+ setNotice( {
+ type: 'success',
+ message: __( 'Font family updated successfully.' ),
+ } );
+ } catch ( error ) {
+ setNotice( {
+ type: 'error',
+ message:
+ __( 'There was an error updating the font family. ' ) +
+ error.message,
+ } );
+ }
+ };
+
const getFontFacesToDisplay = ( font ) => {
if ( ! font ) {
return [];
@@ -265,6 +282,7 @@ function InstalledFonts() {
font
) }
onClick={ () => {
+ setNotice( null );
handleSetLibraryFontSelected(
font
);
@@ -305,6 +323,7 @@ function InstalledFonts() {
font
) }
onClick={ () => {
+ setNotice( null );
handleSetLibraryFontSelected(
font
);
@@ -337,6 +356,7 @@ function InstalledFonts() {
size="small"
onClick={ () => {
handleSetLibraryFontSelected( null );
+ setNotice( null );
} }
label={ __( 'Back' ) }
/>
@@ -406,9 +426,7 @@ function InstalledFonts() {
) }
{
- saveFontFamilies( fontFamilies );
- } }
+ onClick={ handleUpdate }
disabled={ ! fontFamiliesHasChanges }
accessibleWhenDisabled
>
diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/upload-fonts.js b/packages/edit-site/src/components/global-styles/font-library-modal/upload-fonts.js
index 5e8cfdec215175..0f6331a54304de 100644
--- a/packages/edit-site/src/components/global-styles/font-library-modal/upload-fonts.js
+++ b/packages/edit-site/src/components/global-styles/font-library-modal/upload-fonts.js
@@ -25,9 +25,9 @@ import makeFamiliesFromFaces from './utils/make-families-from-faces';
import { loadFontFaceInBrowser } from './utils';
function UploadFonts() {
- const { installFonts, notice, setNotice } =
- useContext( FontLibraryContext );
+ const { installFonts } = useContext( FontLibraryContext );
const [ isUploading, setIsUploading ] = useState( false );
+ const [ notice, setNotice ] = useState( false );
const handleDropZone = ( files ) => {
handleFilesUpload( files );
diff --git a/packages/edit-site/src/components/layout/style.scss b/packages/edit-site/src/components/layout/style.scss
index 09898a530e445a..e4c95fed8b88b7 100644
--- a/packages/edit-site/src/components/layout/style.scss
+++ b/packages/edit-site/src/components/layout/style.scss
@@ -148,6 +148,14 @@
html.canvas-mode-edit-transition::view-transition-group(toggle) {
animation-delay: 255ms;
}
+
+@media (prefers-reduced-motion) {
+ ::view-transition-group(*),
+ ::view-transition-old(*),
+ ::view-transition-new(*) {
+ animation: none !important;
+ }
+}
/* stylelint-enable */
.edit-site-layout.is-full-canvas .edit-site-layout__sidebar-region .edit-site-layout__view-mode-toggle {
diff --git a/packages/edit-site/src/components/page-templates/index.js b/packages/edit-site/src/components/page-templates/index.js
index 05c3b9673eaf98..01b17ae76fc9dc 100644
--- a/packages/edit-site/src/components/page-templates/index.js
+++ b/packages/edit-site/src/components/page-templates/index.js
@@ -54,8 +54,7 @@ const defaultLayouts = {
minWidth: 320,
},
preview: {
- minWidth: 120,
- maxWidth: 120,
+ width: '1%',
},
author: {
width: '1%',
diff --git a/packages/edit-site/src/components/page-templates/style.scss b/packages/edit-site/src/components/page-templates/style.scss
index 067720ad9a1e97..0313da00f89944 100644
--- a/packages/edit-site/src/components/page-templates/style.scss
+++ b/packages/edit-site/src/components/page-templates/style.scss
@@ -37,6 +37,8 @@
.dataviews-view-table & {
border-radius: $radius-block-ui;
position: relative;
+ width: 120px;
+ max-height: 160px;
&::after {
content: "";
diff --git a/packages/edit-site/src/components/site-icon/style.scss b/packages/edit-site/src/components/site-icon/style.scss
index a461b43476fe52..a6cc7ad27fe5df 100644
--- a/packages/edit-site/src/components/site-icon/style.scss
+++ b/packages/edit-site/src/components/site-icon/style.scss
@@ -1,9 +1,11 @@
.edit-site-site-icon__icon {
fill: currentColor;
+ width: 100%;
+ height: 100%;
.edit-site-layout.is-full-canvas & {
// Make the WordPress icon not so big in full canvas.
- padding: $grid-unit-15 * 0.5; // 6px.
+ padding: $grid-unit-15;
}
}
@@ -12,6 +14,7 @@
height: 100%;
object-fit: cover;
background: #333;
+ aspect-ratio: 1 / 1;
.edit-site-layout.is-full-canvas & {
border-radius: 0;
diff --git a/packages/editor/src/components/list-view-sidebar/style.scss b/packages/editor/src/components/list-view-sidebar/style.scss
index 3bf56b2c80760c..54c7376d374853 100644
--- a/packages/editor/src/components/list-view-sidebar/style.scss
+++ b/packages/editor/src/components/list-view-sidebar/style.scss
@@ -1,5 +1,9 @@
.editor-list-view-sidebar {
height: 100%;
+
+ @include break-medium {
+ width: $secondary-sidebar-width;
+ }
}
.editor-list-view-sidebar__list-view-panel-content,
diff --git a/packages/editor/src/components/post-actions/actions.js b/packages/editor/src/components/post-actions/actions.js
index 0d5ac4764c37da..92a5cd0eec87d8 100644
--- a/packages/editor/src/components/post-actions/actions.js
+++ b/packages/editor/src/components/post-actions/actions.js
@@ -1,7 +1,7 @@
/**
* WordPress dependencies
*/
-import { external, backup } from '@wordpress/icons';
+import { external } from '@wordpress/icons';
import { addQueryArgs } from '@wordpress/url';
import { useDispatch, useSelect } from '@wordpress/data';
import { decodeEntities } from '@wordpress/html-entities';
@@ -81,113 +81,6 @@ function isTemplateRemovable( template ) {
);
}
-const restorePostAction = {
- id: 'restore',
- label: __( 'Restore' ),
- isPrimary: true,
- icon: backup,
- supportsBulk: true,
- isEligible( { status, permissions } ) {
- return status === 'trash' && permissions?.update;
- },
- async callback( posts, { registry, onActionPerformed } ) {
- const { createSuccessNotice, createErrorNotice } =
- registry.dispatch( noticesStore );
- const { editEntityRecord, saveEditedEntityRecord } =
- registry.dispatch( coreStore );
- await Promise.allSettled(
- posts.map( ( post ) => {
- return editEntityRecord( 'postType', post.type, post.id, {
- status: 'draft',
- } );
- } )
- );
- const promiseResult = await Promise.allSettled(
- posts.map( ( post ) => {
- return saveEditedEntityRecord( 'postType', post.type, post.id, {
- throwOnError: true,
- } );
- } )
- );
-
- if ( promiseResult.every( ( { status } ) => status === 'fulfilled' ) ) {
- let successMessage;
- if ( posts.length === 1 ) {
- successMessage = sprintf(
- /* translators: The number of posts. */
- __( '"%s" has been restored.' ),
- getItemTitle( posts[ 0 ] )
- );
- } else if ( posts[ 0 ].type === 'page' ) {
- successMessage = sprintf(
- /* translators: The number of posts. */
- __( '%d pages have been restored.' ),
- posts.length
- );
- } else {
- successMessage = sprintf(
- /* translators: The number of posts. */
- __( '%d posts have been restored.' ),
- posts.length
- );
- }
- createSuccessNotice( successMessage, {
- type: 'snackbar',
- id: 'restore-post-action',
- } );
- if ( onActionPerformed ) {
- onActionPerformed( posts );
- }
- } else {
- // If there was at lease one failure.
- let errorMessage;
- // If we were trying to move a single post to the trash.
- if ( promiseResult.length === 1 ) {
- if ( promiseResult[ 0 ].reason?.message ) {
- errorMessage = promiseResult[ 0 ].reason.message;
- } else {
- errorMessage = __(
- 'An error occurred while restoring the post.'
- );
- }
- // If we were trying to move multiple posts to the trash
- } else {
- const errorMessages = new Set();
- const failedPromises = promiseResult.filter(
- ( { status } ) => status === 'rejected'
- );
- for ( const failedPromise of failedPromises ) {
- if ( failedPromise.reason?.message ) {
- errorMessages.add( failedPromise.reason.message );
- }
- }
- if ( errorMessages.size === 0 ) {
- errorMessage = __(
- 'An error occurred while restoring the posts.'
- );
- } else if ( errorMessages.size === 1 ) {
- errorMessage = sprintf(
- /* translators: %s: an error message */
- __( 'An error occurred while restoring the posts: %s' ),
- [ ...errorMessages ][ 0 ]
- );
- } else {
- errorMessage = sprintf(
- /* translators: %s: a list of comma separated error messages */
- __(
- 'Some errors occurred while restoring the posts: %s'
- ),
- [ ...errorMessages ].join( ',' )
- );
- }
- }
- createErrorNotice( errorMessage, {
- type: 'snackbar',
- } );
- }
- },
-};
-
const viewPostAction = {
id: 'view-post',
label: __( 'View' ),
@@ -726,7 +619,6 @@ export function usePostActions( { postType, onActionPerformed, context } ) {
isPattern && userCanCreatePostType && duplicatePatternAction,
supportsTitle && renamePostAction,
reorderPagesAction,
- ! isTemplateOrTemplatePart && ! isPattern && restorePostAction,
...defaultActions,
].filter( Boolean );
// Filter actions based on provided context. If not provided
diff --git a/packages/editor/src/components/post-status/index.js b/packages/editor/src/components/post-status/index.js
index d0b5ac93977330..ca89e40366b238 100644
--- a/packages/editor/src/components/post-status/index.js
+++ b/packages/editor/src/components/post-status/index.js
@@ -254,6 +254,7 @@ export default function PostStatus() {
id={ passwordInputId }
__next40pxDefaultSize
__nextHasNoMarginBottom
+ maxLength={ 255 }
/>
) }
diff --git a/packages/editor/src/components/post-url/panel.js b/packages/editor/src/components/post-url/panel.js
index be32b40eaf1046..aca36566c04727 100644
--- a/packages/editor/src/components/post-url/panel.js
+++ b/packages/editor/src/components/post-url/panel.js
@@ -3,7 +3,11 @@
*/
import { useMemo, useState } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
-import { Dropdown, Button } from '@wordpress/components';
+import {
+ Dropdown,
+ Button,
+ __experimentalTruncate as Truncate,
+} from '@wordpress/components';
import { __, sprintf } from '@wordpress/i18n';
import { safeDecodeURIComponent } from '@wordpress/url';
import { store as coreStore } from '@wordpress/core-data';
@@ -86,7 +90,9 @@ function PostURLToggle( { isOpen, onClick } ) {
aria-label={ sprintf( __( 'Change link: %s' ), decodedSlug ) }
onClick={ onClick }
>
- { isFrontPage ? postLink : <>/{ decodedSlug }> }
+
+ { isFrontPage ? postLink : `/${ decodedSlug }` }
+
);
}
diff --git a/packages/editor/src/components/visual-editor/style.scss b/packages/editor/src/components/visual-editor/style.scss
index 18a61827d573da..fae61eda6b8013 100644
--- a/packages/editor/src/components/visual-editor/style.scss
+++ b/packages/editor/src/components/visual-editor/style.scss
@@ -1,6 +1,6 @@
.editor-visual-editor {
position: relative;
- display: block;
+ display: flex;
background-color: $gray-300;
// Centralize the editor horizontally (flex-direction is column).
diff --git a/packages/editor/src/dataviews/actions/index.ts b/packages/editor/src/dataviews/actions/index.ts
index 6679b2d7d1b8f1..04addcb1cde4d2 100644
--- a/packages/editor/src/dataviews/actions/index.ts
+++ b/packages/editor/src/dataviews/actions/index.ts
@@ -11,6 +11,7 @@ import exportPattern from './export-pattern';
import resetPost from './reset-post';
import trashPost from './trash-post';
import permanentlyDeletePost from './permanently-delete-post';
+import restorePost from './restore-post';
// @ts-ignore
import { store as editorStore } from '../../store';
@@ -23,6 +24,7 @@ export default function registerDefaultActions() {
registerEntityAction( 'postType', 'wp_block', exportPattern );
registerEntityAction( 'postType', '*', resetPost );
+ registerEntityAction( 'postType', '*', restorePost );
registerEntityAction( 'postType', '*', deletePost );
registerEntityAction( 'postType', '*', trashPost );
registerEntityAction( 'postType', '*', permanentlyDeletePost );
diff --git a/packages/editor/src/dataviews/actions/restore-post.tsx b/packages/editor/src/dataviews/actions/restore-post.tsx
new file mode 100644
index 00000000000000..874eca91fee113
--- /dev/null
+++ b/packages/editor/src/dataviews/actions/restore-post.tsx
@@ -0,0 +1,134 @@
+/**
+ * WordPress dependencies
+ */
+import { backup } from '@wordpress/icons';
+import { store as coreStore } from '@wordpress/core-data';
+import { __, sprintf } from '@wordpress/i18n';
+import { store as noticesStore } from '@wordpress/notices';
+import type { Action } from '@wordpress/dataviews';
+
+/**
+ * Internal dependencies
+ */
+import { getItemTitle, isTemplateOrTemplatePart } from './utils';
+import type { CoreDataError, PostWithPermissions } from '../types';
+
+const restorePost: Action< PostWithPermissions > = {
+ id: 'restore',
+ label: __( 'Restore' ),
+ isPrimary: true,
+ icon: backup,
+ supportsBulk: true,
+ isEligible( item ) {
+ return (
+ ! isTemplateOrTemplatePart( item ) &&
+ item.type !== 'wp_block' &&
+ item.status === 'trash' &&
+ item.permissions?.update
+ );
+ },
+ async callback( posts, { registry, onActionPerformed } ) {
+ const { createSuccessNotice, createErrorNotice } =
+ registry.dispatch( noticesStore );
+ const { editEntityRecord, saveEditedEntityRecord } =
+ registry.dispatch( coreStore );
+ await Promise.allSettled(
+ posts.map( ( post ) => {
+ return editEntityRecord( 'postType', post.type, post.id, {
+ status: 'draft',
+ } );
+ } )
+ );
+ const promiseResult = await Promise.allSettled(
+ posts.map( ( post ) => {
+ return saveEditedEntityRecord( 'postType', post.type, post.id, {
+ throwOnError: true,
+ } );
+ } )
+ );
+
+ if ( promiseResult.every( ( { status } ) => status === 'fulfilled' ) ) {
+ let successMessage;
+ if ( posts.length === 1 ) {
+ successMessage = sprintf(
+ /* translators: The number of posts. */
+ __( '"%s" has been restored.' ),
+ getItemTitle( posts[ 0 ] )
+ );
+ } else if ( posts[ 0 ].type === 'page' ) {
+ successMessage = sprintf(
+ /* translators: The number of posts. */
+ __( '%d pages have been restored.' ),
+ posts.length
+ );
+ } else {
+ successMessage = sprintf(
+ /* translators: The number of posts. */
+ __( '%d posts have been restored.' ),
+ posts.length
+ );
+ }
+ createSuccessNotice( successMessage, {
+ type: 'snackbar',
+ id: 'restore-post-action',
+ } );
+ if ( onActionPerformed ) {
+ onActionPerformed( posts );
+ }
+ } else {
+ // If there was at lease one failure.
+ let errorMessage;
+ // If we were trying to move a single post to the trash.
+ if ( promiseResult.length === 1 ) {
+ const typedError = promiseResult[ 0 ] as {
+ reason?: CoreDataError;
+ };
+ if ( typedError.reason?.message ) {
+ errorMessage = typedError.reason.message;
+ } else {
+ errorMessage = __(
+ 'An error occurred while restoring the post.'
+ );
+ }
+ // If we were trying to move multiple posts to the trash
+ } else {
+ const errorMessages = new Set();
+ const failedPromises = promiseResult.filter(
+ ( { status } ) => status === 'rejected'
+ );
+ for ( const failedPromise of failedPromises ) {
+ const typedError = failedPromise as {
+ reason?: CoreDataError;
+ };
+ if ( typedError.reason?.message ) {
+ errorMessages.add( typedError.reason.message );
+ }
+ }
+ if ( errorMessages.size === 0 ) {
+ errorMessage = __(
+ 'An error occurred while restoring the posts.'
+ );
+ } else if ( errorMessages.size === 1 ) {
+ errorMessage = sprintf(
+ /* translators: %s: an error message */
+ __( 'An error occurred while restoring the posts: %s' ),
+ [ ...errorMessages ][ 0 ]
+ );
+ } else {
+ errorMessage = sprintf(
+ /* translators: %s: a list of comma separated error messages */
+ __(
+ 'Some errors occurred while restoring the posts: %s'
+ ),
+ [ ...errorMessages ].join( ',' )
+ );
+ }
+ }
+ createErrorNotice( errorMessage, {
+ type: 'snackbar',
+ } );
+ }
+ },
+};
+
+export default restorePost;
diff --git a/packages/editor/src/store/private-selectors.js b/packages/editor/src/store/private-selectors.js
index ed4672bc435cdc..6a6c8702a02217 100644
--- a/packages/editor/src/store/private-selectors.js
+++ b/packages/editor/src/store/private-selectors.js
@@ -110,7 +110,10 @@ export const getPostIcon = createRegistrySelector(
// `icon` is the `menu_icon` property of a post type. We
// only handle `dashicons` for now, even if the `menu_icon`
// also supports urls and svg as values.
- if ( postTypeEntity?.icon?.startsWith( 'dashicons-' ) ) {
+ if (
+ typeof postTypeEntity?.icon === 'string' &&
+ postTypeEntity.icon.startsWith( 'dashicons-' )
+ ) {
return postTypeEntity.icon.slice( 10 );
}
return pageIcon;
diff --git a/packages/format-library/src/image/index.js b/packages/format-library/src/image/index.js
index 794af776c88e76..7f8e33550770d0 100644
--- a/packages/format-library/src/image/index.js
+++ b/packages/format-library/src/image/index.js
@@ -6,8 +6,11 @@ import {
SVG,
Popover,
Button,
- __experimentalNumberControl as NumberControl,
+ ExternalLink,
__experimentalHStack as HStack,
+ __experimentalVStack as VStack,
+ __experimentalNumberControl as NumberControl,
+ TextareaControl,
} from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useState } from '@wordpress/element';
@@ -17,7 +20,6 @@ import {
RichTextToolbarButton,
MediaUploadCheck,
} from '@wordpress/block-editor';
-import { keyboardReturn } from '@wordpress/icons';
const ALLOWED_MEDIA_TYPES = [ 'image' ];
@@ -41,8 +43,11 @@ export const image = {
};
function InlineUI( { value, onChange, activeObjectAttributes, contentRef } ) {
- const { style } = activeObjectAttributes;
- const [ width, setWidth ] = useState( style?.replace( /\D/g, '' ) );
+ const { style, alt } = activeObjectAttributes;
+ const width = style?.replace( /\D/g, '' );
+ const [ editedWidth, setEditedWidth ] = useState( width );
+ const [ editedAlt, setEditedAlt ] = useState( alt );
+ const hasChanged = editedWidth !== width || editedAlt !== alt;
const popoverAnchor = useAnchor( {
editableContentElement: contentRef.current,
settings: image,
@@ -64,7 +69,8 @@ function InlineUI( { value, onChange, activeObjectAttributes, contentRef } ) {
type: name,
attributes: {
...activeObjectAttributes,
- style: width ? `width: ${ width }px;` : '',
+ style: width ? `width: ${ editedWidth }px;` : '',
+ alt: editedAlt,
},
};
@@ -76,21 +82,54 @@ function InlineUI( { value, onChange, activeObjectAttributes, contentRef } ) {
event.preventDefault();
} }
>
-
+
setWidth( newWidth ) }
- size="__unstable-large"
+ onChange={ ( newWidth ) => {
+ setEditedWidth( newWidth );
+ } }
/>
- {
+ setEditedAlt( newAlt );
+ } }
+ help={
+ <>
+
+ { __(
+ 'Describe the purpose of the image.'
+ ) }
+
+
+ { __( 'Leave empty if decorative.' ) }
+ >
+ }
/>
-
+
+
+ { __( 'Apply' ) }
+
+
+
);
diff --git a/packages/format-library/src/image/style.scss b/packages/format-library/src/image/style.scss
index 7e9809e52f3bf2..1e0b922fdf4c8f 100644
--- a/packages/format-library/src/image/style.scss
+++ b/packages/format-library/src/image/style.scss
@@ -2,7 +2,7 @@
z-index: z-index(".block-editor-format-toolbar__image-popover");
.block-editor-format-toolbar__image-container-content {
- width: 200px;
+ width: 260px;
padding: $grid-unit-20;
}
}
diff --git a/packages/interface/src/components/interface-skeleton/index.js b/packages/interface/src/components/interface-skeleton/index.js
index ed4d98cdf7637f..14b2a87ba5203d 100644
--- a/packages/interface/src/components/interface-skeleton/index.js
+++ b/packages/interface/src/components/interface-skeleton/index.js
@@ -182,30 +182,32 @@ function InterfaceSkeleton(
ariaLabel={ mergedLabels.secondarySidebar }
as={ motion.div }
initial="closed"
- animate={
- isMobileViewport ? 'mobileOpen' : 'open'
- }
+ animate="open"
exit="closed"
variants={ {
open: { width: secondarySidebarSize.width },
closed: { width: 0 },
- mobileOpen: { width: '100vw' },
} }
transition={ defaultTransition }
>
-
{ secondarySidebarResizeListener }
{ secondarySidebar }
-
+
) }
diff --git a/phpunit/bootstrap.php b/phpunit/bootstrap.php
index 295d02978f120f..55319a752b61e6 100644
--- a/phpunit/bootstrap.php
+++ b/phpunit/bootstrap.php
@@ -95,6 +95,7 @@ function fail_if_died( $message ) {
'gutenberg-widget-experiments' => '1',
'gutenberg-full-site-editing' => 1,
'gutenberg-form-blocks' => 1,
+ 'gutenberg-block-experiments' => 1,
),
);
diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php
index 36b8218785f216..8d2f470efe60fe 100644
--- a/phpunit/class-wp-theme-json-test.php
+++ b/phpunit/class-wp-theme-json-test.php
@@ -46,6 +46,52 @@ public static function set_up_before_class() {
static::$user_id = self::factory()->user->create();
}
+ /**
+ * Pretty print CSS in test assertions so that it provides a better diff when a test fails.
+ * Without this: the failing test outputs the entire css string as being different.
+ * With this: the failing test only highlights the specific CSS rule that is different.
+ *
+ * @param string $css A string of raw css with no line breaks.
+ * @return string The css with line breaks.
+ */
+ private static function pretty_print_css( $css ) {
+ $css = str_replace( '{', " {\n", $css );
+ $css = str_replace( '}', "}\n\n", $css );
+ $css = str_replace( ';', ";\n", $css );
+ return $css;
+ }
+
+ /**
+ * Asserts that two CSS strings are equivalent, but outputs
+ * pretty printed test failures along with the raw css.
+ *
+ * - The pretty printed assertions are useful for understanding what actually changed.
+ * - The raw css is included as it's useful for updating the test case's expected CSS.
+ *
+ * Inspired by:
+ * https://stackoverflow.com/questions/6832263/phpunit-assertion-failed-but-i-want-to-continue-testing
+ *
+ * @param string $expected The expected CSS.
+ * @param string $actual The actual CSS.
+ */
+ private function assertSameCSS( $expected, $actual, $message = '' ) {
+ $pretty_expected = self::pretty_print_css( $expected );
+ $pretty_actual = self::pretty_print_css( $actual );
+
+ try {
+ $this->assertSame( $pretty_expected, $pretty_actual, $message );
+ } catch ( PHPUnit_Framework_ExpectationFailedException $e ) {
+ // Test failures are thrown as exceptions by PHPUnit.
+ // Catch the exception and re-throw it, but with the
+ // raw css appended.
+ $raw_actual_output =
+ "\n\nIf the change is expected, update the test case to this CSS:\n$actual";
+ throw new PHPUnit_Framework_ExpectationFailedException(
+ "$e$raw_actual_output"
+ );
+ }
+ }
+
public function test_get_settings() {
$theme_json = new WP_Theme_JSON_Gutenberg(
array(
@@ -556,10 +602,10 @@ public function test_get_stylesheet() {
$presets = '.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}.has-custom-gradient-gradient-background{background: var(--wp--preset--gradient--custom-gradient) !important;}.has-small-font-size{font-size: var(--wp--preset--font-size--small) !important;}.has-big-font-size{font-size: var(--wp--preset--font-size--big) !important;}.has-arial-font-family{font-family: var(--wp--preset--font-family--arial) !important;}';
$all = $variables . $styles . $presets;
- $this->assertSame( $variables, $theme_json->get_stylesheet( array( 'variables' ) ) );
- $this->assertSame( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) );
- $this->assertSame( $presets, $theme_json->get_stylesheet( array( 'presets' ) ) );
- $this->assertSame( $all, $theme_json->get_stylesheet() );
+ $this->assertSameCSS( $variables, $theme_json->get_stylesheet( array( 'variables' ) ) );
+ $this->assertSameCSS( $styles, $theme_json->get_stylesheet( array( 'styles' ) ) );
+ $this->assertSameCSS( $presets, $theme_json->get_stylesheet( array( 'presets' ) ) );
+ $this->assertSameCSS( $all, $theme_json->get_stylesheet() );
}
public function test_get_styles_for_block_support_for_shorthand_and_longhand_values() {
@@ -618,8 +664,8 @@ public function test_get_styles_for_block_support_for_shorthand_and_longhand_val
$group_styles = ':root :where(.wp-block-group){border-radius: 10px;margin: 1em;padding: 24px;}';
$image_styles = ':root :where(.wp-block-image){margin-bottom: 30px;padding-top: 15px;}:root :where(.wp-block-image img, .wp-block-image .wp-block-image__crop-area, .wp-block-image .components-placeholder){border-top-left-radius: 10px;border-bottom-right-radius: 1em;}';
- $this->assertSame( $group_styles, $theme_json->get_styles_for_block( $group_node ) );
- $this->assertSame( $image_styles, $theme_json->get_styles_for_block( $image_node ) );
+ $this->assertSameCSS( $group_styles, $theme_json->get_styles_for_block( $group_node ) );
+ $this->assertSameCSS( $image_styles, $theme_json->get_styles_for_block( $image_node ) );
}
public function test_get_stylesheet_skips_disabled_protected_properties() {
@@ -647,8 +693,8 @@ public function test_get_stylesheet_skips_disabled_protected_properties() {
);
$expected = static::$base_styles . ':where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;}';
- $this->assertSame( $expected, $theme_json->get_stylesheet() );
- $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
+ $this->assertSameCSS( $expected, $theme_json->get_stylesheet() );
+ $this->assertSameCSS( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
}
public function test_get_stylesheet_renders_enabled_protected_properties() {
@@ -669,8 +715,8 @@ public function test_get_stylesheet_renders_enabled_protected_properties() {
);
$expected = ':where(body) { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.wp-site-blocks) > * { margin-block-start: 1em; margin-block-end: 0; }:where(.wp-site-blocks) > :first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child { margin-block-end: 0; }:root { --wp--style--block-gap: 1em; }.is-layout-flow > :first-child{margin-block-start: 0;}.is-layout-flow > :last-child{margin-block-end: 0;}.is-layout-flow > *{margin-block-start: 1em;margin-block-end: 0;}.is-layout-constrained > :first-child{margin-block-start: 0;}.is-layout-constrained > :last-child{margin-block-end: 0;}.is-layout-constrained > *{margin-block-start: 1em;margin-block-end: 0;}.is-layout-flex {gap: 1em;}.is-layout-grid {gap: 1em;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}';
- $this->assertSame( $expected, $theme_json->get_stylesheet() );
- $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
+ $this->assertSameCSS( $expected, $theme_json->get_stylesheet() );
+ $this->assertSameCSS( $expected, $theme_json->get_stylesheet( array( 'styles' ) ) );
}
public function test_get_stylesheet_preset_classes_work_with_compounded_selectors() {
@@ -694,7 +740,7 @@ public function test_get_stylesheet_preset_classes_work_with_compounded_selector
)
);
- $this->assertSame(
+ $this->assertSameCSS(
'.wp-block-heading.has-white-color{color: var(--wp--preset--color--white) !important;}.wp-block-heading.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.wp-block-heading.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}',
$theme_json->get_stylesheet( array( 'presets' ) )
);
@@ -736,10 +782,10 @@ public function test_get_stylesheet_preset_rules_come_after_block_rules() {
$all = $variables . $styles . $presets;
- $this->assertSame( $all, $theme_json->get_stylesheet( array( 'styles', 'presets', 'variables' ), null, array( 'skip_root_layout_styles' => true ) ) );
- $this->assertSame( $styles, $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) ) );
- $this->assertSame( $presets, $theme_json->get_stylesheet( array( 'presets' ) ) );
- $this->assertSame( $variables, $theme_json->get_stylesheet( array( 'variables' ) ) );
+ $this->assertSameCSS( $all, $theme_json->get_stylesheet( array( 'styles', 'presets', 'variables' ), null, array( 'skip_root_layout_styles' => true ) ) );
+ $this->assertSameCSS( $styles, $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) ) );
+ $this->assertSameCSS( $presets, $theme_json->get_stylesheet( array( 'presets' ) ) );
+ $this->assertSameCSS( $variables, $theme_json->get_stylesheet( array( 'variables' ) ) );
}
public function test_get_stylesheet_generates_proper_classes_and_css_vars_from_slugs() {
@@ -774,11 +820,11 @@ public function test_get_stylesheet_generates_proper_classes_and_css_vars_from_s
)
);
- $this->assertSame(
+ $this->assertSameCSS(
'.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-dark-grey-color{color: var(--wp--preset--color--dark-grey) !important;}.has-light-grey-color{color: var(--wp--preset--color--light-grey) !important;}.has-white-2-black-color{color: var(--wp--preset--color--white-2-black) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-dark-grey-background-color{background-color: var(--wp--preset--color--dark-grey) !important;}.has-light-grey-background-color{background-color: var(--wp--preset--color--light-grey) !important;}.has-white-2-black-background-color{background-color: var(--wp--preset--color--white-2-black) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}.has-dark-grey-border-color{border-color: var(--wp--preset--color--dark-grey) !important;}.has-light-grey-border-color{border-color: var(--wp--preset--color--light-grey) !important;}.has-white-2-black-border-color{border-color: var(--wp--preset--color--white-2-black) !important;}',
$theme_json->get_stylesheet( array( 'presets' ) )
);
- $this->assertSame(
+ $this->assertSameCSS(
':root{--wp--preset--color--grey: grey;--wp--preset--color--dark-grey: grey;--wp--preset--color--light-grey: grey;--wp--preset--color--white-2-black: grey;--wp--custom--white-2-black: value;}',
$theme_json->get_stylesheet( array( 'variables' ) )
);
@@ -834,9 +880,9 @@ public function test_get_styles_for_block_handles_whitelisted_element_pseudo_sel
$hover_style = ':root :where(a:where(:not(.wp-element-button)):hover){background-color: green;color: red;font-size: 10em;text-transform: uppercase;}';
$focus_style = ':root :where(a:where(:not(.wp-element-button)):focus){background-color: black;color: yellow;}';
- $this->assertSame( $link_style, $theme_json->get_styles_for_block( $link_node ) );
- $this->assertSame( $hover_style, $theme_json->get_styles_for_block( $hover_node ) );
- $this->assertSame( $focus_style, $theme_json->get_styles_for_block( $focus_node ) );
+ $this->assertSameCSS( $link_style, $theme_json->get_styles_for_block( $link_node ) );
+ $this->assertSameCSS( $hover_style, $theme_json->get_styles_for_block( $hover_node ) );
+ $this->assertSameCSS( $focus_style, $theme_json->get_styles_for_block( $focus_node ) );
}
/**
@@ -872,8 +918,7 @@ public function test_get_stylesheet_handles_only_pseudo_selector_rules_for_given
);
$expected = ':root :where(a:where(:not(.wp-element-button)):hover){background-color: green;color: red;font-size: 10em;text-transform: uppercase;}:root :where(a:where(:not(.wp-element-button)):focus){background-color: black;color: yellow;}';
-
- $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) ) );
+ $this->assertSameCSS( $expected, $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) ) );
}
public function test_get_stylesheet_ignores_pseudo_selectors_on_non_whitelisted_elements() {
@@ -906,8 +951,7 @@ public function test_get_stylesheet_ignores_pseudo_selectors_on_non_whitelisted_
);
$expected = 'h4{background-color: red;color: green;}';
-
- $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) ) );
+ $this->assertSameCSS( $expected, $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) ) );
}
public function test_get_stylesheet_ignores_non_whitelisted_pseudo_selectors() {
@@ -940,8 +984,7 @@ public function test_get_stylesheet_ignores_non_whitelisted_pseudo_selectors() {
);
$expected = 'a:where(:not(.wp-element-button)){background-color: red;color: green;}:root :where(a:where(:not(.wp-element-button)):hover){background-color: green;color: red;}';
-
- $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) ) );
+ $this->assertSameCSS( $expected, $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) ) );
$this->assertStringNotContainsString( 'a:levitate{', $theme_json->get_stylesheet( array( 'styles' ) ) );
}
@@ -987,8 +1030,7 @@ public function test_get_stylesheet_handles_priority_of_elements_vs_block_elemen
);
$expected = ':root :where(.wp-block-group a:where(:not(.wp-element-button))){background-color: red;color: green;}:root :where(.wp-block-group a:where(:not(.wp-element-button)):hover){background-color: green;color: red;font-size: 10em;text-transform: uppercase;}:root :where(.wp-block-group a:where(:not(.wp-element-button)):focus){background-color: black;color: yellow;}';
-
- $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) ) );
+ $this->assertSameCSS( $expected, $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) ) );
}
/**
@@ -1032,8 +1074,7 @@ public function test_get_stylesheet_with_deprecated_feature_level_selectors() {
$block_styles = ':root :where(.wp-block-calendar){font-size: 3em;}:root :where(.wp-block-calendar table, .wp-block-calendar th){color: green;}';
$preset_styles = '.has-green-color{color: var(--wp--preset--color--green) !important;}.has-green-background-color{background-color: var(--wp--preset--color--green) !important;}.has-green-border-color{border-color: var(--wp--preset--color--green) !important;}';
$expected = $base_styles . $block_styles . $preset_styles;
-
- $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles', 'presets', 'variables' ), null, array( 'skip_root_layout_styles' => true ) ) );
+ $this->assertSameCSS( $expected, $theme_json->get_stylesheet( array( 'styles', 'presets', 'variables' ), null, array( 'skip_root_layout_styles' => true ) ) );
}
@@ -1063,8 +1104,7 @@ public function test_get_stylesheet_with_block_json_selectors() {
);
$expected = ':root :where(.wp-block-image img, .wp-block-image .wp-block-image__crop-area, .wp-block-image .components-placeholder){border-radius: 374px;}';
-
- $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles', 'presets', 'variables' ), null, array( 'skip_root_layout_styles' => true ) ) );
+ $this->assertSameCSS( $expected, $theme_json->get_stylesheet( array( 'styles', 'presets', 'variables' ), null, array( 'skip_root_layout_styles' => true ) ) );
}
public function test_get_stylesheet_generates_layout_styles() {
@@ -1090,7 +1130,7 @@ public function test_get_stylesheet_generates_layout_styles() {
);
// Results also include root site blocks styles.
- $this->assertSame(
+ $this->assertSameCSS(
':root { --wp--style--global--content-size: 640px;--wp--style--global--wide-size: 1200px; }:where(body) { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.wp-site-blocks) > * { margin-block-start: 1em; margin-block-end: 0; }:where(.wp-site-blocks) > :first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child { margin-block-end: 0; }:root { --wp--style--block-gap: 1em; }.is-layout-flow > :first-child{margin-block-start: 0;}.is-layout-flow > :last-child{margin-block-end: 0;}.is-layout-flow > *{margin-block-start: 1em;margin-block-end: 0;}.is-layout-constrained > :first-child{margin-block-start: 0;}.is-layout-constrained > :last-child{margin-block-end: 0;}.is-layout-constrained > *{margin-block-start: 1em;margin-block-end: 0;}.is-layout-flex {gap: 1em;}.is-layout-grid {gap: 1em;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}',
$theme_json->get_stylesheet( array( 'styles' ) )
);
@@ -1119,7 +1159,7 @@ public function test_get_stylesheet_generates_layout_styles_with_spacing_presets
);
// Results also include root site blocks styles.
- $this->assertSame(
+ $this->assertSameCSS(
':root { --wp--style--global--content-size: 640px;--wp--style--global--wide-size: 1200px; }:where(body) { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.wp-site-blocks) > * { margin-block-start: var(--wp--preset--spacing--60); margin-block-end: 0; }:where(.wp-site-blocks) > :first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child { margin-block-end: 0; }:root { --wp--style--block-gap: var(--wp--preset--spacing--60); }.is-layout-flow > :first-child{margin-block-start: 0;}.is-layout-flow > :last-child{margin-block-end: 0;}.is-layout-flow > *{margin-block-start: var(--wp--preset--spacing--60);margin-block-end: 0;}.is-layout-constrained > :first-child{margin-block-start: 0;}.is-layout-constrained > :last-child{margin-block-end: 0;}.is-layout-constrained > *{margin-block-start: var(--wp--preset--spacing--60);margin-block-end: 0;}.is-layout-flex {gap: var(--wp--preset--spacing--60);}.is-layout-grid {gap: var(--wp--preset--spacing--60);}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}',
$theme_json->get_stylesheet( array( 'styles' ) )
);
@@ -1149,7 +1189,7 @@ public function test_get_stylesheet_generates_fallback_gap_layout_styles() {
$stylesheet = $theme_json->get_stylesheet( array( 'styles' ) );
// Results also include root site blocks styles.
- $this->assertSame(
+ $this->assertSameCSS(
':root { --wp--style--global--content-size: 640px;--wp--style--global--wide-size: 1200px; }:where(body) { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}',
$stylesheet
);
@@ -1170,7 +1210,7 @@ public function test_get_stylesheet_generates_base_fallback_gap_layout_styles()
$stylesheet = $theme_json->get_stylesheet( array( 'base-layout-styles' ) );
// Note the `base-layout-styles` includes a fallback gap for the Columns block for backwards compatibility.
- $this->assertSame(
+ $this->assertSameCSS(
':where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}:where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;}:where(.wp-block-post-template.is-layout-flex){gap: 1.25em;}:where(.wp-block-post-template.is-layout-grid){gap: 1.25em;}',
$stylesheet
);
@@ -1193,7 +1233,7 @@ public function test_get_stylesheet_skips_layout_styles() {
remove_theme_support( 'disable-layout-styles' );
// All Layout styles should be skipped.
- $this->assertSame(
+ $this->assertSameCSS(
'',
$stylesheet
);
@@ -1243,7 +1283,7 @@ public function test_get_stylesheet_generates_valid_block_gap_values_and_skips_n
'default'
);
- $this->assertSame(
+ $this->assertSameCSS(
':root { --wp--style--global--content-size: 640px;--wp--style--global--wide-size: 1200px; }:where(body) { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.wp-site-blocks) > * { margin-block-start: 1rem; margin-block-end: 0; }:where(.wp-site-blocks) > :first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child { margin-block-end: 0; }:root { --wp--style--block-gap: 1rem; }.is-layout-flow > :first-child{margin-block-start: 0;}.is-layout-flow > :last-child{margin-block-end: 0;}.is-layout-flow > *{margin-block-start: 1rem;margin-block-end: 0;}.is-layout-constrained > :first-child{margin-block-start: 0;}.is-layout-constrained > :last-child{margin-block-end: 0;}.is-layout-constrained > *{margin-block-start: 1rem;margin-block-end: 0;}.is-layout-flex {gap: 1rem;}.is-layout-grid {gap: 1rem;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}' .
':root :where(.wp-block-post-content){color: gray;}.wp-block-social-links-is-layout-flow > :first-child{margin-block-start: 0;}.wp-block-social-links-is-layout-flow > :last-child{margin-block-end: 0;}.wp-block-social-links-is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}.wp-block-social-links-is-layout-constrained > :first-child{margin-block-start: 0;}.wp-block-social-links-is-layout-constrained > :last-child{margin-block-end: 0;}.wp-block-social-links-is-layout-constrained > *{margin-block-start: 0;margin-block-end: 0;}.wp-block-social-links-is-layout-flex {gap: 0;}.wp-block-social-links-is-layout-grid {gap: 0;}.wp-block-buttons-is-layout-flow > :first-child{margin-block-start: 0;}.wp-block-buttons-is-layout-flow > :last-child{margin-block-end: 0;}.wp-block-buttons-is-layout-flow > *{margin-block-start: 0;margin-block-end: 0;}.wp-block-buttons-is-layout-constrained > :first-child{margin-block-start: 0;}.wp-block-buttons-is-layout-constrained > :last-child{margin-block-end: 0;}.wp-block-buttons-is-layout-constrained > *{margin-block-start: 0;margin-block-end: 0;}.wp-block-buttons-is-layout-flex {gap: 0;}.wp-block-buttons-is-layout-grid {gap: 0;}',
$theme_json->get_stylesheet()
@@ -1279,7 +1319,7 @@ public function test_get_stylesheet_returns_outline_styles() {
$expected = ':root :where(.wp-element-button, .wp-block-button__link){outline-color: red;outline-offset: 3px;outline-style: dashed;outline-width: 3px;}:root :where(.wp-element-button:hover, .wp-block-button__link:hover){outline-color: blue;outline-offset: 3px;outline-style: solid;outline-width: 3px;}';
- $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) ) );
+ $this->assertSameCSS( $expected, $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) ) );
}
public function test_get_stylesheet_custom_root_selector() {
@@ -1302,7 +1342,7 @@ public function test_get_stylesheet_custom_root_selector() {
);
$actual = $theme_json->get_stylesheet( array( 'styles' ), null, $options );
- $this->assertSame(
+ $this->assertSameCSS(
':root :where(.custom){color: teal;}',
$actual
);
@@ -1360,7 +1400,7 @@ public function test_get_stylesheet_generates_fluid_typography_values() {
unregister_block_type( 'test/clamp-me' );
- $this->assertSame(
+ $this->assertSameCSS(
':root{--wp--preset--font-size--pickles: clamp(14px, 0.875rem + ((1vw - 3.2px) * 0.156), 16px);--wp--preset--font-size--toast: clamp(14.642px, 0.915rem + ((1vw - 3.2px) * 0.575), 22px);}body{font-size: clamp(0.875em, 0.875rem + ((1vw - 0.2em) * 0.156), 1em);}h1{font-size: clamp(50.171px, 3.136rem + ((1vw - 3.2px) * 3.893), 100px);}:root :where(.wp-block-test-clamp-me){font-size: clamp(27.894px, 1.743rem + ((1vw - 3.2px) * 1.571), 48px);}.has-pickles-font-size{font-size: var(--wp--preset--font-size--pickles) !important;}.has-toast-font-size{font-size: var(--wp--preset--font-size--toast) !important;}',
$theme_json->get_stylesheet( array( 'styles', 'variables', 'presets' ), null, array( 'skip_root_layout_styles' => true ) )
);
@@ -3419,7 +3459,7 @@ public function test_get_property_value_valid() {
);
$expected = 'body{background-color: #ffffff;color: #000000;}:root :where(.wp-element-button, .wp-block-button__link){background-color: #000000;color: #ffffff;}';
- $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) ) );
+ $this->assertSameCSS( $expected, $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) ) );
}
/**
@@ -3496,7 +3536,7 @@ public function test_get_property_value_loop() {
);
$expected = 'body{background-color: #ffffff;}:root :where(.wp-element-button, .wp-block-button__link){color: #ffffff;}';
- $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) ) );
+ $this->assertSameCSS( $expected, $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) ) );
}
/**
@@ -3528,7 +3568,7 @@ public function test_get_property_value_recursion() {
);
$expected = 'body{background-color: #ffffff;color: #ffffff;}:root :where(.wp-element-button, .wp-block-button__link){color: #ffffff;}';
- $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) ) );
+ $this->assertSameCSS( $expected, $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) ) );
}
/**
@@ -3551,7 +3591,7 @@ public function test_get_property_value_self() {
);
$expected = 'body{background-color: #ffffff;}';
- $this->assertSame( $expected, $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) ) );
+ $this->assertSameCSS( $expected, $theme_json->get_stylesheet( array( 'styles' ), null, array( 'skip_root_layout_styles' => true ) ) );
}
public function test_get_styles_for_block_with_padding_aware_alignments() {
@@ -3582,7 +3622,7 @@ public function test_get_styles_for_block_with_padding_aware_alignments() {
$expected = ':where(body) { margin: 0; }.wp-site-blocks { padding-top: var(--wp--style--root--padding-top); padding-bottom: var(--wp--style--root--padding-bottom); }.has-global-padding { padding-right: var(--wp--style--root--padding-right); padding-left: var(--wp--style--root--padding-left); }.has-global-padding > .alignfull { margin-right: calc(var(--wp--style--root--padding-right) * -1); margin-left: calc(var(--wp--style--root--padding-left) * -1); }.has-global-padding :where(:not(.alignfull.is-layout-flow) > .has-global-padding:not(.wp-block-block, .alignfull)) { padding-right: 0; padding-left: 0; }.has-global-padding :where(:not(.alignfull.is-layout-flow) > .has-global-padding:not(.wp-block-block, .alignfull)) > .alignfull { margin-left: 0; margin-right: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}body{--wp--style--root--padding-top: 10px;--wp--style--root--padding-right: 12px;--wp--style--root--padding-bottom: 10px;--wp--style--root--padding-left: 12px;}';
$root_rules = $theme_json->get_root_layout_rules( WP_Theme_JSON_Gutenberg::ROOT_BLOCK_SELECTOR, $metadata );
$style_rules = $theme_json->get_styles_for_block( $metadata );
- $this->assertSame( $expected, $root_rules . $style_rules );
+ $this->assertSameCSS( $expected, $root_rules . $style_rules );
}
public function test_get_styles_for_block_without_padding_aware_alignments() {
@@ -3610,7 +3650,7 @@ public function test_get_styles_for_block_without_padding_aware_alignments() {
$expected = static::$base_styles . 'body{padding-top: 10px;padding-right: 12px;padding-bottom: 10px;padding-left: 12px;}';
$root_rules = $theme_json->get_root_layout_rules( WP_Theme_JSON_Gutenberg::ROOT_BLOCK_SELECTOR, $metadata );
$style_rules = $theme_json->get_styles_for_block( $metadata );
- $this->assertSame( $expected, $root_rules . $style_rules );
+ $this->assertSameCSS( $expected, $root_rules . $style_rules );
}
public function test_get_styles_with_content_width() {
@@ -3632,7 +3672,7 @@ public function test_get_styles_with_content_width() {
);
$expected = ':root { --wp--style--global--content-size: 800px;--wp--style--global--wide-size: 1000px; }:where(body) { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}';
- $this->assertSame( $expected, $theme_json->get_root_layout_rules( WP_Theme_JSON::ROOT_BLOCK_SELECTOR, $metadata ) );
+ $this->assertSameCSS( $expected, $theme_json->get_root_layout_rules( WP_Theme_JSON::ROOT_BLOCK_SELECTOR, $metadata ) );
}
public function test_get_styles_with_appearance_tools() {
@@ -3651,7 +3691,7 @@ public function test_get_styles_with_appearance_tools() {
);
$expected = ':where(body) { margin: 0; }.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }:where(.wp-site-blocks) > * { margin-block-start: ; margin-block-end: 0; }:where(.wp-site-blocks) > :first-child { margin-block-start: 0; }:where(.wp-site-blocks) > :last-child { margin-block-end: 0; }:root { --wp--style--block-gap: ; }.is-layout-flow > :first-child{margin-block-start: 0;}.is-layout-flow > :last-child{margin-block-end: 0;}.is-layout-flow > *{margin-block-start: 1;margin-block-end: 0;}.is-layout-constrained > :first-child{margin-block-start: 0;}.is-layout-constrained > :last-child{margin-block-end: 0;}.is-layout-constrained > *{margin-block-start: 1;margin-block-end: 0;}.is-layout-flex {gap: 1;}.is-layout-grid {gap: 1;}.is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}.is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}.is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){margin-left: auto !important;margin-right: auto !important;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}';
- $this->assertSame( $expected, $theme_json->get_root_layout_rules( WP_Theme_JSON_Gutenberg::ROOT_BLOCK_SELECTOR, $metadata ) );
+ $this->assertSameCSS( $expected, $theme_json->get_root_layout_rules( WP_Theme_JSON_Gutenberg::ROOT_BLOCK_SELECTOR, $metadata ) );
}
public function test_sanitization() {
@@ -4717,8 +4757,8 @@ public function test_shadow_preset_styles() {
);
$expected_styles = ':root{--wp--preset--shadow--natural: 5px 5px 5px 0 black;--wp--preset--shadow--sharp: 5px 5px black;}';
- $this->assertSame( $expected_styles, $theme_json->get_stylesheet(), 'Styles returned from "::get_stylesheet()" does not match expectations' );
- $this->assertSame( $expected_styles, $theme_json->get_stylesheet( array( 'variables' ) ), 'Styles returned from "::get_stylesheet()" when requiring "variables" type does not match expectations' );
+ $this->assertSameCSS( $expected_styles, $theme_json->get_stylesheet(), 'Styles returned from "::get_stylesheet()" does not match expectations' );
+ $this->assertSameCSS( $expected_styles, $theme_json->get_stylesheet( array( 'variables' ) ), 'Styles returned from "::get_stylesheet()" when requiring "variables" type does not match expectations' );
}
public function test_get_shadow_styles_for_blocks() {
@@ -4756,7 +4796,7 @@ public function test_get_shadow_styles_for_blocks() {
$variable_styles = ':root{--wp--preset--shadow--natural: 5px 5px 0 0 black;}';
$element_styles = 'a:where(:not(.wp-element-button)){box-shadow: var(--wp--preset--shadow--natural);}:root :where(.wp-element-button, .wp-block-button__link){box-shadow: var(--wp--preset--shadow--natural);}:root :where(p){box-shadow: var(--wp--preset--shadow--natural);}';
$expected_styles = $variable_styles . $element_styles;
- $this->assertSame( $expected_styles, $theme_json->get_stylesheet( array( 'styles', 'presets', 'variables' ), null, array( 'skip_root_layout_styles' => true ) ) );
+ $this->assertSameCSS( $expected_styles, $theme_json->get_stylesheet( array( 'styles', 'presets', 'variables' ), null, array( 'skip_root_layout_styles' => true ) ) );
}
public function test_get_top_level_background_image_styles() {
@@ -4783,7 +4823,7 @@ public function test_get_top_level_background_image_styles() {
);
$expected_styles = "html{min-height: calc(100% - var(--wp-admin--admin-bar--height, 0px));}body{background-image: url('http://example.org/image.png');background-position: center center;background-repeat: no-repeat;background-size: contain;background-attachment: fixed;}";
- $this->assertSame( $expected_styles, $theme_json->get_styles_for_block( $body_node ), 'Styles returned from "::get_styles_for_block()" with top-level background styles do not match expectations' );
+ $this->assertSameCSS( $expected_styles, $theme_json->get_styles_for_block( $body_node ), 'Styles returned from "::get_styles_for_block()" with top-level background styles do not match expectations' );
$theme_json = new WP_Theme_JSON_Gutenberg(
array(
@@ -4801,7 +4841,7 @@ public function test_get_top_level_background_image_styles() {
);
$expected_styles = "html{min-height: calc(100% - var(--wp-admin--admin-bar--height, 0px));}body{background-image: url('http://example.org/image.png');background-position: center center;background-repeat: no-repeat;background-size: contain;background-attachment: fixed;}";
- $this->assertSame( $expected_styles, $theme_json->get_styles_for_block( $body_node ), 'Styles returned from "::get_styles_for_block()" with top-level background image as string type do not match expectations' );
+ $this->assertSameCSS( $expected_styles, $theme_json->get_styles_for_block( $body_node ), 'Styles returned from "::get_styles_for_block()" with top-level background image as string type do not match expectations' );
}
public function test_get_block_background_image_styles() {
@@ -4844,7 +4884,7 @@ public function test_get_block_background_image_styles() {
);
$quote_styles = ":root :where(.wp-block-quote){background-image: url('http://example.org/quote.png');background-position: center center;background-repeat: no-repeat;background-size: cover;}";
- $this->assertSame( $quote_styles, $theme_json->get_styles_for_block( $quote_node ), 'Styles returned from "::get_styles_for_block()" with block-level background styles do not match expectations' );
+ $this->assertSameCSS( $quote_styles, $theme_json->get_styles_for_block( $quote_node ), 'Styles returned from "::get_styles_for_block()" with block-level background styles do not match expectations' );
$group_node = array(
'name' => 'core/group',
@@ -4856,7 +4896,7 @@ public function test_get_block_background_image_styles() {
);
$group_styles = ":root :where(.wp-block-group){background-image: url('http://example.org/group.png');background-position: center center;background-repeat: no-repeat;background-size: cover;background-attachment: fixed;}";
- $this->assertSame( $group_styles, $theme_json->get_styles_for_block( $group_node ), 'Styles returned from "::get_styles_for_block()" with block-level background styles as string type do not match expectations' );
+ $this->assertSameCSS( $group_styles, $theme_json->get_styles_for_block( $group_node ), 'Styles returned from "::get_styles_for_block()" with block-level background styles as string type do not match expectations' );
}
/**
diff --git a/readme.txt b/readme.txt
index 3fe6e3aaf1dc4d..c5ef1231b183ee 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,6 +1,6 @@
=== Gutenberg ===
Contributors: matveb, joen, karmatosed
-Tested up to: 6.5
+Tested up to: 6.6
Stable tag: V.V.V
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
diff --git a/test/e2e/specs/editor/various/adding-inline-tokens.spec.js b/test/e2e/specs/editor/various/adding-inline-tokens.spec.js
index 15f9d9ea877320..c7826ebf262822 100644
--- a/test/e2e/specs/editor/various/adding-inline-tokens.spec.js
+++ b/test/e2e/specs/editor/various/adding-inline-tokens.spec.js
@@ -64,13 +64,16 @@ test.describe( 'adding inline tokens', () => {
await pageUtils.pressKeys( 'shift+ArrowLeft' );
await page.keyboard.press( 'Tab' );
- await page.keyboard.press( 'Tab' );
- await page.fill( 'role=spinbutton[name="WIDTH"i]', '20' );
+ await expect(
+ page.locator( 'role=spinbutton[name="Width"i]' )
+ ).toBeFocused();
+ await page.fill( 'role=spinbutton[name="Width"i]', '20' );
+ await page.fill( 'role=textbox[name="Alternative text"i]', 'Alt' );
await page.click( 'role=button[name="Apply"i]' );
// Check the content.
const contentRegex2 = new RegExp(
- `a `
+ `a `
);
await expect.poll( editor.getBlocks ).toMatchObject( [
diff --git a/test/integration/fixtures/blocks/core__site-tagline.json b/test/integration/fixtures/blocks/core__site-tagline.json
index e504bc75df30c7..fe837d41df43bf 100644
--- a/test/integration/fixtures/blocks/core__site-tagline.json
+++ b/test/integration/fixtures/blocks/core__site-tagline.json
@@ -3,7 +3,8 @@
"name": "core/site-tagline",
"isValid": true,
"attributes": {
- "level": 0
+ "level": 0,
+ "levelOptions": [ 0, 1, 2, 3, 4, 5, 6 ]
},
"innerBlocks": []
}
diff --git a/test/integration/fixtures/blocks/core__site-title.json b/test/integration/fixtures/blocks/core__site-title.json
index 12f32615473cc8..8ca7091f30d5e7 100644
--- a/test/integration/fixtures/blocks/core__site-title.json
+++ b/test/integration/fixtures/blocks/core__site-title.json
@@ -4,6 +4,7 @@
"isValid": true,
"attributes": {
"level": 1,
+ "levelOptions": [ 0, 1, 2, 3, 4, 5, 6 ],
"isLink": true,
"linkTarget": "_self"
},