diff --git a/.github/workflows/build-plugin-zip.yml b/.github/workflows/build-plugin-zip.yml index fef2b196e954ca..7facf92e00dd4f 100644 --- a/.github/workflows/build-plugin-zip.yml +++ b/.github/workflows/build-plugin-zip.yml @@ -69,7 +69,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: token: ${{ secrets.GUTENBERG_TOKEN }} show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} @@ -165,7 +165,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: ${{ needs.bump-version.outputs.release_branch || github.ref }} show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} @@ -222,7 +222,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 2 ref: ${{ needs.bump-version.outputs.release_branch }} @@ -311,14 +311,14 @@ jobs: if: ${{ endsWith( needs.bump-version.outputs.new_version, '-rc.1' ) }} steps: - name: Checkout (for CLI) - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: path: main ref: trunk show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} - name: Checkout (for publishing) - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: path: publish # Later, we switch this branch in the script that publishes packages. diff --git a/.github/workflows/bundle-size.yml b/.github/workflows/bundle-size.yml index 8c8a5da8eb62ad..a1c66221a76aff 100644 --- a/.github/workflows/bundle-size.yml +++ b/.github/workflows/bundle-size.yml @@ -37,7 +37,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 1 show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} diff --git a/.github/workflows/check-components-changelog.yml b/.github/workflows/check-components-changelog.yml index fece5aa3a9d9ad..8af0dc05f41087 100644 --- a/.github/workflows/check-components-changelog.yml +++ b/.github/workflows/check-components-changelog.yml @@ -20,7 +20,7 @@ jobs: - name: 'Get PR commit count' run: echo "PR_COMMIT_COUNT=$(( ${{ github.event.pull_request.commits }} + 1 ))" >> "${GITHUB_ENV}" - name: Checkout code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: ${{ github.event.pull_request.head.ref }} repository: ${{ github.event.pull_request.head.repo.full_name }} diff --git a/.github/workflows/create-block.yml b/.github/workflows/create-block.yml index d817ac1e0be976..5fec67935cdf0c 100644 --- a/.github/workflows/create-block.yml +++ b/.github/workflows/create-block.yml @@ -24,7 +24,7 @@ jobs: os: ['macos-latest', 'ubuntu-latest', 'windows-latest'] steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} diff --git a/.github/workflows/end2end-test.yml b/.github/workflows/end2end-test.yml index cd393854c40308..870885898eedc8 100644 --- a/.github/workflows/end2end-test.yml +++ b/.github/workflows/end2end-test.yml @@ -22,7 +22,7 @@ jobs: if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} @@ -63,7 +63,7 @@ jobs: totalParts: [8] steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} @@ -111,7 +111,7 @@ jobs: steps: # Checkout defaults to using the branch which triggered the event, which # isn't necessarily `trunk` (e.g. in the case of a merge). - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: trunk show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml index ade7ecd3e9a060..12f8517e2a5f5c 100644 --- a/.github/workflows/gradle-wrapper-validation.yml +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -6,7 +6,7 @@ jobs: name: 'Validation' runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} - uses: gradle/wrapper-validation-action@v2 diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index b84e8c569dc51a..143bf71ab2e3af 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -32,7 +32,7 @@ jobs: WP_ARTIFACTS_PATH: ${{ github.workspace }}/artifacts steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} diff --git a/.github/workflows/php-changes-detection.yml b/.github/workflows/php-changes-detection.yml index d238265a1aa646..46774044c3c24f 100644 --- a/.github/workflows/php-changes-detection.yml +++ b/.github/workflows/php-changes-detection.yml @@ -10,14 +10,14 @@ jobs: if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} steps: - name: Check out code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: fetch-depth: 0 show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} - name: Get changed PHP files id: changed-files-php - uses: tj-actions/changed-files@800a2825992141ddde1a8bca8ad394cec34d3188 # v42.0.5 + uses: tj-actions/changed-files@77af4bed286740ef1a6387dc4e4e4dec39f96054 # v43.0.0 with: files: | **.{php} diff --git a/.github/workflows/publish-npm-packages.yml b/.github/workflows/publish-npm-packages.yml index c9de22a5c31955..038d8de8ed2e18 100644 --- a/.github/workflows/publish-npm-packages.yml +++ b/.github/workflows/publish-npm-packages.yml @@ -31,7 +31,7 @@ jobs: steps: - name: Checkout (for CLI) if: ${{ github.event.inputs.release_type != 'wp' }} - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: path: cli ref: trunk @@ -39,7 +39,7 @@ jobs: - name: Checkout (for publishing) if: ${{ github.event.inputs.release_type != 'wp' }} - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: path: publish # Later, we switch this branch in the script that publishes packages. @@ -49,7 +49,7 @@ jobs: - name: Checkout (for publishing WP major version) if: ${{ github.event.inputs.release_type == 'wp' && github.event.inputs.wp_version }} - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: path: publish ref: wp/${{ github.event.inputs.wp_version }} diff --git a/.github/workflows/pull-request-automation.yml b/.github/workflows/pull-request-automation.yml index ccf0502ba21dac..a876aa1c794a22 100644 --- a/.github/workflows/pull-request-automation.yml +++ b/.github/workflows/pull-request-automation.yml @@ -12,7 +12,7 @@ jobs: steps: # Checkout defaults to using the branch which triggered the event, which # isn't necessarily `trunk` (e.g. in the case of a merge). - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: trunk show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} diff --git a/.github/workflows/rnmobile-android-runner.yml b/.github/workflows/rnmobile-android-runner.yml index 4fb327d21eaa7b..6d94088ba46d51 100644 --- a/.github/workflows/rnmobile-android-runner.yml +++ b/.github/workflows/rnmobile-android-runner.yml @@ -23,7 +23,7 @@ jobs: steps: - name: checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} diff --git a/.github/workflows/rnmobile-ios-runner.yml b/.github/workflows/rnmobile-ios-runner.yml index 80b651709045e7..ee523ce0f73e11 100644 --- a/.github/workflows/rnmobile-ios-runner.yml +++ b/.github/workflows/rnmobile-ios-runner.yml @@ -23,11 +23,11 @@ jobs: native-test-name: [gutenberg-editor-rendering] steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} - - uses: ruby/setup-ruby@22fdc77bf4148f810455b226c90fb81b5cbc00a7 # v1.171.0 + - uses: ruby/setup-ruby@d4526a55538b775af234ba4af27118ed6f8f6677 # v1.172.0 with: # `.ruby-version` file location working-directory: packages/react-native-editor/ios diff --git a/.github/workflows/static-checks.yml b/.github/workflows/static-checks.yml index 789e64a25fa205..fb8f33a103293d 100644 --- a/.github/workflows/static-checks.yml +++ b/.github/workflows/static-checks.yml @@ -22,7 +22,7 @@ jobs: if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} diff --git a/.github/workflows/storybook-pages.yml b/.github/workflows/storybook-pages.yml index 5117e2fc9fe6ec..1f79fb208094c2 100644 --- a/.github/workflows/storybook-pages.yml +++ b/.github/workflows/storybook-pages.yml @@ -12,7 +12,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: trunk show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index d5be172578d43e..ab0f2c25c7d5e7 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -30,7 +30,7 @@ jobs: node: ['20', '21'] steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} @@ -110,7 +110,7 @@ jobs: WP_ENV_CORE: ${{ matrix.wordpress == '' && 'WordPress/WordPress' || format( 'https://wordpress.org/wordpress-{0}.zip', matrix.wordpress ) }} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} @@ -220,7 +220,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} @@ -289,7 +289,7 @@ jobs: if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: show-progress: ${{ runner.debug == '1' && 'true' || 'false' }} diff --git a/.github/workflows/upload-release-to-plugin-repo.yml b/.github/workflows/upload-release-to-plugin-repo.yml index 6f0eb31adcc407..7ca7283f9cfdec 100644 --- a/.github/workflows/upload-release-to-plugin-repo.yml +++ b/.github/workflows/upload-release-to-plugin-repo.yml @@ -96,7 +96,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2 with: ref: ${{ matrix.branch }} token: ${{ secrets.GUTENBERG_TOKEN }} diff --git a/bin/cherry-pick.mjs b/bin/cherry-pick.mjs index f0ca37d10f30cb..d81bc017fc0be6 100644 --- a/bin/cherry-pick.mjs +++ b/bin/cherry-pick.mjs @@ -113,15 +113,18 @@ function cli( command, args, pipe = false ) { */ async function fetchPRs() { const { items } = await GitHubFetch( - `/search/issues?q=is:pr state:closed sort:updated label:"${ LABEL }" repo:WordPress/gutenberg` + `/search/issues?per_page=100&q=is:pr state:closed sort:updated label:"${ LABEL }" repo:WordPress/gutenberg` ); const PRs = items - .map( ( { id, number, title, pull_request, closed_at } ) => ( { + // eslint-disable-next-line camelcase + .map( ( { id, number, title, pull_request } ) => ( { id, number, title, + // eslint-disable-next-line camelcase pull_request, } ) ) + // eslint-disable-next-line camelcase .filter( ( { pull_request } ) => !! pull_request?.merged_at ) .sort( ( a, b ) => diff --git a/docs/reference-guides/block-api/block-supports.md b/docs/reference-guides/block-api/block-supports.md index feea0466dbbf6c..3eac1530075132 100644 --- a/docs/reference-guides/block-api/block-supports.md +++ b/docs/reference-guides/block-api/block-supports.md @@ -7,30 +7,29 @@ Opting into any of these features will register additional attributes on the blo In order for the attribute to get applied to the block the generated properties get added to the wrapping element of the block. They get added to the object you get returned from the `useBlockProps` hook. `BlockEdit` function: + ```js function BlockEdit() { const blockProps = useBlockProps(); - return ( -
Hello World!
- ); + return
Hello World!
; } ``` `save` function: + ```js function BlockEdit() { const blockProps = useBlockProps.save(); - return ( -
Hello World!
- ); + return
Hello World!
; } ``` For dynamic blocks that get rendered via a `render_callback` in PHP you can use the `get_block_wrapper_attributes()` function. It returns a string containing all the generated properties and needs to get output in the opening tag of the wrapping block element. `render_callback` function: + ```php function render_block() { $wrapper_attributes = get_block_wrapper_attributes(); @@ -107,8 +106,8 @@ supports: { ## ariaLabel -- Type: `boolean` -- Default value: `false` +- Type: `boolean` +- Default value: `false` ARIA-labels let you define an accessible label for elements. This property allows enabling the definition of an aria-label for the block, without exposing a UI field. @@ -119,6 +118,62 @@ supports: { } ``` +## background + +_**Note:** Since WordPress 6.5._ + +- Type: `Object` +- Default value: `null` +- Subproperties + - `backgroundImage`: type `boolean`, default value `false` + - `backgroundSize`: type `boolean`, default value `false` + +This value signals that a block supports some of the CSS style properties related to background. When it does, the block editor will show UI controls for the user to set their values if [the theme declares support](/docs/how-to-guides/themes/global-settings-and-styles.md#opt-in-into-ui-controls). + +`backgroundImage` adds UI controls which allow the user to select a background image. +`backgroundSize` adds the FocalPointPicker to pick the position of the background image and allow the user to select the background size (cover, contain, fixed). + +```js +supports: { + background: { + backgroundImage: true // Enable background image control. + backgroundSize: true // Enable background image + size control. + } +} +``` + +When a block declares support for a specific background property, its attributes definition is extended to include the `style` attribute. + +When a background image is selected, the image data is stored in the `style.background.backgroundImage`. + +When a background images is selected and its position or size are changed, the background-position is stored in the `style.background.backgroundPosition` and its background-size in `style.background.backgroundSize` attribute. + +- `style`: an attribute of `object` type with no default assigned. This is added when `backgroundImage` or `backgroundSize` support is declared. It stores the custom values set by the user. + - `background`: an attribute of `object` type. + - `backgroundImage`: an attribute of `object` type, containing information about the selected image + - `url`: type `string`, URL to the image + - `id`: type `int`, media attachment ID + - `source`: type `string`, at the moment the only value is `file` + - `title`: type `string`, title of the media attachment + - `backgroundPosition`: an attribute of `string` type, defining the background images position, selected by FocalPointPicker and used in CSS as the [`background-position`](https://developer.mozilla.org/en-US/docs/Web/CSS/background-position) value. + - `backgroundSize`: an attribute of `string` type. defining the CSS [`background-size`](https://developer.mozilla.org/en-US/docs/Web/CSS/background-size) value. + +The block can apply a default background image, position and size by specifying its own attribute with a default. For example: + +```js +attributes: { + style: { + background: { + backgroundImage: { + "url":"IMAGE_URL" + } + backgroundPosition:"50% 50%", + backgroundSize: "cover" + } + } +} +``` + ## className - Type: `boolean` @@ -139,7 +194,10 @@ supports: { - Default value: null - Subproperties: - `background`: type `boolean`, default value `true` + - `button`: type `boolean`, default value `false` + - `enableContrastChecker`: type `boolean`, default value `true` - `gradients`: type `boolean`, default value `false` + - `heading`: type `boolean`, default value `false` - `link`: type `boolean`, default value `false` - `text`: type `boolean`, default value `true` @@ -192,43 +250,103 @@ supports: { When the block declares support for `color.background`, the attributes definition is extended to include two new attributes: `backgroundColor` and `style`: -- `backgroundColor`: an attribute of `string` type with no default assigned. +- `backgroundColor`: an attribute of `string` type with no default assigned. + + When a user chooses from the list of preset background colors, the preset slug is stored in the `backgroundColor` attribute. + + Background color presets are sourced from the `editor-color-palette` [theme support](/docs/how-to-guides/themes/theme-support.md#block-color-palettes). + + The block can apply a default preset background color by specifying its own attribute with a default. For example: + + ```js + attributes: { + backgroundColor: { + type: 'string', + default: 'some-preset-background-slug', + } + } + ``` + +- `style`: attribute of `object` type with no default assigned. + + When a custom background color is selected (i.e. using the custom color picker), the custom color value is stored in the `style.color.background` attribute. + + The block can apply a default custom background color by specifying its own attribute with a default. For example: + + ```js + attributes: { + style: { + type: 'object', + default: { + color: { + background: '#aabbcc', + } + } + } + } + ``` + +### color.button + +_**Note:** Since WordPress 6.5._ + +This property adds block controls which allow the user to set button colors (text, background) in a block. Button colors are disabled by default. - When a user chooses from the list of preset background colors, the preset slug is stored in the `backgroundColor` attribute. +To enable button color support, set `color.button` to `true`. - Background color presets are sourced from the `editor-color-palette` [theme support](/docs/how-to-guides/themes/theme-support.md#block-color-palettes). +```js +supports: { + color: { + button: true + } +} +``` - The block can apply a default preset background color by specifying its own attribute with a default. For example: +Button color presets are sourced from the `editor-color-palette` [theme support](/docs/how-to-guides/themes/theme-support.md#block-color-palettes). - ```js - attributes: { - backgroundColor: { - type: 'string', - default: 'some-preset-background-slug', - } - } - ``` +When the block declares support for `color.button`, the attributes definition is extended to include the `style` attribute: -- `style`: attribute of `object` type with no default assigned. +- `style`: an attribute of `object` type with no default assigned. - When a custom background color is selected (i.e. using the custom color picker), the custom color value is stored in the `style.color.background` attribute. + When a button color is selected, the color value is stored in the `style.elements.button.color.text` and `style.elements.button.color.background` attribute. - The block can apply a default custom background color by specifying its own attribute with a default. For example: + The block can apply a default button colors by specifying its own attribute with a default. For example: - ```js - attributes: { - style: { - type: 'object', - default: { - color: { - background: '#aabbcc', - } - } - } - } - ``` + ```js + attributes: { + style: { + type: 'object', + default: { + elements: { + button: { + color: { + text: 'var:preset|color|contrast', + background: '#000000', + } + } + } + } + } + } + ``` + +### color.enableContrastChecker -### color.__experimentalDuotone +_**Note:** Since WordPress 6.5._ + +Determines whether the contrast checker widget displays in the block editor UI. + +The contrast checker appears only if the block declares support for color. It tests the readability of color combinations and warns if there is a potential issue. The property is enabled by default. Set to `false` to explicitly disable: + +```js +supports: { + color: { + enableContrastChecker: false + } +} +``` + +### color.\_\_experimentalDuotone _**Note:** Deprecated since WordPress 6.3._ @@ -251,91 +369,132 @@ supports: { Gradient presets are sourced from `editor-gradient-presets` [theme support](/docs/how-to-guides/themes/theme-support.md#block-gradient-presets). - When the block declares support for `color.gradient`, the attributes definition is extended to include two new attributes: `gradient` and `style`: -- `gradient`: an attribute of `string` type with no default assigned. +- `gradient`: an attribute of `string` type with no default assigned. - When a user chooses from the list of preset gradients, the preset slug is stored in the `gradient` attribute. + When a user chooses from the list of preset gradients, the preset slug is stored in the `gradient` attribute. - The block can apply a default preset gradient by specifying its own attribute with a default. For example: + The block can apply a default preset gradient by specifying its own attribute with a default. For example: - ```js - attributes: { - gradient: { - type: 'string', - default: 'some-preset-gradient-slug', - } - } - ``` + ```js + attributes: { + gradient: { + type: 'string', + default: 'some-preset-gradient-slug', + } + } + ``` -- `style`: an attribute of `object` type with no default assigned. +- `style`: an attribute of `object` type with no default assigned. - When a custom gradient is selected (i.e. using the custom gradient picker), the custom gradient value is stored in the `style.color.gradient` attribute. + When a custom gradient is selected (i.e. using the custom gradient picker), the custom gradient value is stored in the `style.color.gradient` attribute. - The block can apply a default custom gradient by specifying its own attribute with a default. For example: + The block can apply a default custom gradient by specifying its own attribute with a default. For example: - ```js - attributes: { - style: { - type: 'object', - default: { - color: { - gradient: 'linear-gradient(135deg,rgb(170,187,204) 0%,rgb(17,34,51) 100%)', - } - } - } - } - ``` + ```js + attributes: { + style: { + type: 'object', + default: { + color: { + gradient: 'linear-gradient(135deg,rgb(170,187,204) 0%,rgb(17,34,51) 100%)', + } + } + } + } + ``` -### color.link +### color.heading + +_**Note:** Since WordPress 6.5._ -This property adds block controls which allow the user to set link color in a block. Link color is disabled by default. +This property adds block controls which allow the user to set heading colors in a block. Heading colors are disabled by default. +To enable heading color support, set `color.heading` to `true`. ```js supports: { - color: true // Enables only background and text + color: { + // Enable heading color support. + heading: true + } } ``` +Heading color presets are sourced from the `editor-color-palette` [theme support](/docs/how-to-guides/themes/theme-support.md#block-color-palettes). + +When the block declares support for `color.heading`, the attributes definition is extended to include the `style` attribute: + +- `style`: an attribute of `object` type with no default assigned. + + When a heading color is selected, the color value is stored in the `style.elements.heading.color.text` and `style.elements.heading.color.background` attribute. + + The block can apply default heading colors by specifying its own attribute with a default. For example: + + ```js + attributes: { + style: { + type: 'object', + default: { + elements: { + heading: { + color: { + text: 'var:preset|color|contrast', + background: '#000000', + } + } + } + } + } + } + ``` + +### color.link + +This property adds block controls which allow the user to set link colors in a block. Link colors are disabled by default. + To enable link color support, set `color.link` to `true`. ```js supports: { - color: { - link: true - } + color: { + link: true + } } ``` Link color presets are sourced from the `editor-color-palette` [theme support](/docs/how-to-guides/themes/theme-support.md#block-color-palettes). - When the block declares support for `color.link`, the attributes definition is extended to include the `style` attribute: -- `style`: an attribute of `object` type with no default assigned. - - When a link color is selected, the color value is stored in the `style.elements.link.color.text` attribute. - - The block can apply a default link color by specifying its own attribute with a default. For example: - - ```js - attributes: { - style: { - type: 'object', - default: { - elements: { - link: { - color: { - text: '#ff0000', - } - } - } - } - } - } - ``` +- `style`: an attribute of `object` type with no default assigned. + + When a link color is selected, the color value is stored in the `style.elements.link.color.text` and `style.elements.link.:hover.color.text` attribute. + + The block can apply default link colors by specifying its own attribute with a default. For example: + + ```js + attributes: { + style: { + type: 'object', + default: { + elements: { + link: { + color: { + text: 'var:preset|color|contrast', + }, + ":hover": { + color: { + text: "#000000" + } + } + } + } + } + } + } + ``` ### color.text @@ -345,7 +504,7 @@ When color support is declared, this property is enabled by default (along with ```js supports: { - color: true // Enables background and text, but not link. + color: true // Enables background and text, but not link. } ``` @@ -353,51 +512,50 @@ To disable text color support while keeping other color supports enabled, set `c ```js supports: { - color: { - // Disable text color support. - text: false - } + color: { + // Disable text color support. + text: false + } } ``` Text color presets are sourced from the `editor-color-palette` [theme support](/docs/how-to-guides/themes/theme-support.md#block-color-palettes). - When the block declares support for `color.text`, the attributes definition is extended to include two new attributes: `textColor` and `style`: -- `textColor`: an attribute of `string` type with no default assigned. +- `textColor`: an attribute of `string` type with no default assigned. - When a user chooses from the list of preset text colors, the preset slug is stored in the `textColor` attribute. + When a user chooses from the list of preset text colors, the preset slug is stored in the `textColor` attribute. - The block can apply a default preset text color by specifying its own attribute with a default. For example: + The block can apply a default preset text color by specifying its own attribute with a default. For example: - ```js - attributes: { - textColor: { - type: 'string', - default: 'some-preset-text-color-slug', - } - } - ``` + ```js + attributes: { + textColor: { + type: 'string', + default: 'some-preset-text-color-slug', + } + } + ``` -- `style`: an attribute of `object` type with no default assigned. +- `style`: an attribute of `object` type with no default assigned. - When a custom text color is selected (i.e. using the custom color picker), the custom color value is stored in the `style.color.text` attribute. + When a custom text color is selected (i.e. using the custom color picker), the custom color value is stored in the `style.color.text` attribute. - The block can apply a default custom text color by specifying its own attribute with a default. For example: + The block can apply a default custom text color by specifying its own attribute with a default. For example: - ```js - attributes: { - style: { - type: 'object', - default: { - color: { - text: '#aabbcc', - } - } - } - } - ``` + ```js + attributes: { + style: { + type: 'object', + default: { + color: { + text: '#aabbcc', + } + } + } + } + ``` ## customClassName @@ -426,16 +584,16 @@ This value signals that a block supports some of the CSS style properties relate ```js supports: { - dimensions: { - aspectRatio: true // Enable aspect ratio control. - minHeight: true // Enable min height control. - } + dimensions: { + aspectRatio: true // Enable aspect ratio control. + minHeight: true // Enable min height control. + } } ``` When a block declares support for a specific dimensions property, its attributes definition is extended to include the `style` attribute. -- `style`: an attribute of `object` type with no default assigned. This is added when `aspectRatio` or `minHeight` support is declared. It stores the custom values set by the user. For example.: +- `style`: an attribute of `object` type with no default assigned. This is added when `aspectRatio` or `minHeight` support is declared. It stores the custom values set by the user. For example: ```js attributes: { @@ -449,6 +607,7 @@ attributes: { ``` ## filter + - Type: `Object` - Default value: null - Subproperties: @@ -482,25 +641,25 @@ Duotone presets are sourced from `color.duotone` in [theme.json](/docs/how-to-gu When the block declares support for `filter.duotone`, the attributes definition is extended to include the attribute `style`: -- `style`: an attribute of `object` type with no default assigned. - - The block can apply a default duotone color by specifying its own attribute with a default. For example: - - ```js - attributes: { - style: { - type: 'object', - default: { - color: { - duotone: [ - '#FFF', - '#000' - ] - } - } - } - } - ``` +- `style`: an attribute of `object` type with no default assigned. + + The block can apply a default duotone color by specifying its own attribute with a default. For example: + + ```js + attributes: { + style: { + type: 'object', + default: { + color: { + duotone: [ + '#FFF', + '#000' + ] + } + } + } + } + ``` ## html @@ -625,46 +784,31 @@ For the `flex` layout type only, determines display of the orientation control i For the `constrained` layout type only, determines display of the custom content and wide size controls in the block sidebar. - -## multiple - -- Type: `boolean` -- Default value: `true` - -A non-multiple block can be inserted into each post, one time only. For example, the built-in 'More' block cannot be inserted again if it already exists in the post being edited. A non-multiple block's icon is automatically dimmed (unclickable) to prevent multiple instances. - -```js -supports: { - // Use the block just once per post - multiple: false -} -``` - -## reusable +## lock - Type: `boolean` - Default value: `true` -A block may want to disable the ability of being converted into a reusable block. By default all blocks can be converted to a reusable block. If supports reusable is set to false, the option to convert the block into a reusable block will not appear. +A block may want to disable the ability to toggle the lock state. It can be locked/unlocked by a user from the block "Options" dropdown by default. To disable this behavior, set `lock` to `false`. ```js supports: { - // Don't allow the block to be converted into a reusable block. - reusable: false, + // Remove support for locking UI. + lock: false } ``` -## lock +## multiple - Type: `boolean` - Default value: `true` -A block may want to disable the ability to toggle the lock state. It can be locked/unlocked by a user from the block "Options" dropdown by default. To disable this behavior, set `lock` to `false`. +A non-multiple block can be inserted into each post, one time only. For example, the built-in 'More' block cannot be inserted again if it already exists in the post being edited. A non-multiple block's icon is automatically dimmed (unclickable) to prevent multiple instances. ```js supports: { - // Remove support for locking UI. - lock: false + // Use the block just once per post + multiple: false } ``` @@ -683,15 +827,15 @@ Note that sticky position controls are currently only available for blocks set a ```js supports: { - position: { - sticky: true // Enable selecting sticky position. - } + position: { + sticky: true // Enable selecting sticky position. + } } ``` When the block declares support for a specific position property, its attributes definition is extended to include the `style` attribute. -- `style`: an attribute of `object` type with no default assigned. This is added when `sticky` support is declared. It stores the custom values set by the user. For example: +- `style`: an attribute of `object` type with no default assigned. This is added when `sticky` support is declared. It stores the custom values set by the user. For example: ```js attributes: { @@ -704,6 +848,72 @@ attributes: { } ``` +## renaming + +_**Note:** Since WordPress 6.5._ + +- Type: `boolean` +- Default value: `true` + +By default, a block can be renamed by a user from the block 'Options' dropdown or the 'Advanced' panel. To disable this behavior, set renaming to false. + +```js +supports: { + // Don't allow the block to be renamed in the editor. + renaming: false, +} +``` + +## reusable + +- Type: `boolean` +- Default value: `true` + +A block may want to disable the ability of being converted into a reusable block. By default all blocks can be converted to a reusable block. If supports reusable is set to false, the option to convert the block into a reusable block will not appear. + +```js +supports: { + // Don't allow the block to be converted into a reusable block. + reusable: false, +} +``` + +## shadow + +_**Note:** Since WordPress 6.5._ + +- Type: `boolean` +- Default value: `false` + +This property adds block controls which allow the user to set a box shadow for a block. Shadows are disabled by default. + +```js +supports: { + shadow: true // Enable the box-shadow picker. +} +``` + +Shadow presets are sourced from the shadow presets defined in `theme.json`. + +When the block declares support for `shadow`, the attributes definition is extended to include the `style` attribute: + +- `style`: an attribute of `object` type with no default assigned. + + When a shadow is selected, the color value is stored in the `style.shadow`. + + The block can apply a default shadow by specifying its own attribute with a default. For example: + + ```js + attributes: { + style: { + type: 'object', + default: { + shadow: "var:preset|shadow|deep" + } + } + } + ``` + ## spacing - Type: `Object` @@ -727,7 +937,7 @@ supports: { When the block declares support for a specific spacing property, its attributes definition is extended to include the `style` attribute. -- `style`: an attribute of `object` type with no default assigned. This is added when `margin` or `padding` support is declared. It stores the custom values set by the user. For example: +- `style`: an attribute of `object` type with no default assigned. This is added when `margin` or `padding` support is declared. It stores the custom values set by the user. For example: ```js attributes: { @@ -761,8 +971,8 @@ supports: { - Type: `Object` - Default value: `null` - Subproperties: - - `fontSize`: type `boolean`, default value `false` - - `lineHeight`: type `boolean`, default value `false` + - `fontSize`: type `boolean`, default value `false` + - `lineHeight`: type `boolean`, default value `false` The presence of this object signals that a block supports some typography related properties. When it does, the block editor will show a typography UI allowing the user to control their values. @@ -778,6 +988,7 @@ supports: { ``` ### typography.fontSize + - Type: `boolean` - Default value: `false` diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md index cf70a7d8193ef8..4c8df25bc24f74 100644 --- a/docs/reference-guides/core-blocks.md +++ b/docs/reference-guides/core-blocks.md @@ -642,7 +642,7 @@ Display a post's featured image. ([Source](https://github.com/WordPress/gutenber - **Name:** core/post-featured-image - **Category:** theme -- **Supports:** align (center, full, left, right, wide), color (~~background~~, ~~text~~), interactivity (clientNavigation), spacing (margin, padding), ~~html~~ +- **Supports:** align (center, full, left, right, wide), color (~~background~~, ~~text~~), interactivity (clientNavigation), shadow (), spacing (margin, padding), ~~html~~ - **Attributes:** aspectRatio, customGradient, customOverlayColor, dimRatio, gradient, height, isLink, linkTarget, overlayColor, rel, scale, sizeSlug, useFirstImageFromPost, width ## Post Navigation Link diff --git a/lib/block-supports/shadow.php b/lib/block-supports/shadow.php index 87258930faf10e..25c365067e0c32 100644 --- a/lib/block-supports/shadow.php +++ b/lib/block-supports/shadow.php @@ -47,7 +47,10 @@ function gutenberg_register_shadow_support( $block_type ) { function gutenberg_apply_shadow_support( $block_type, $block_attributes ) { $has_shadow_support = block_has_support( $block_type, array( 'shadow' ), false ); - if ( ! $has_shadow_support ) { + if ( + ! $has_shadow_support || + wp_should_skip_block_supports_serialization( $block_type, 'shadow' ) + ) { return array(); } diff --git a/lib/compat/wordpress-6.5/interactivity-api/interactivity-api.php b/lib/compat/wordpress-6.5/interactivity-api/interactivity-api.php index c4c0ac37519f41..aa0f66a54fb656 100644 --- a/lib/compat/wordpress-6.5/interactivity-api/interactivity-api.php +++ b/lib/compat/wordpress-6.5/interactivity-api/interactivity-api.php @@ -182,3 +182,24 @@ function wp_interactivity_data_wp_context( array $context, string $store_namespa '\''; } } + +if ( ! function_exists( 'data_wp_context' ) ) { + /** + * `data_wp_context()` was renamed to follow WordPress Core naming schemes. + * + * @link https://github.com/WordPress/gutenberg/pull/59465/ + * @link https://core.trac.wordpress.org/ticket/60575 + * + * @since 6.5.0 + * @deprecated 6.5.0 + * + * @param array $context The array of context data to encode. + * @param string $store_namespace Optional. The unique store namespace identifier. + * @return string A complete `data-wp-context` directive with a JSON encoded value representing the context array and + * the store namespace if specified. + */ + function data_wp_context( array $context, string $store_namespace = '' ): string { + _deprecated_function( __FUNCTION__, '6.5', 'wp_interactivity_data_wp_context()' ); + return wp_interactivity_data_wp_context( $context, $store_namespace ); + } +} diff --git a/lib/load.php b/lib/load.php index dc3a6533a5c4be..a9ce52385ab48f 100644 --- a/lib/load.php +++ b/lib/load.php @@ -124,10 +124,8 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/compat/wordpress-6.5/block-bindings/post-meta.php'; require __DIR__ . '/compat/wordpress-6.5/script-loader.php'; -// Not to be included in WordPress 6.5. -if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) { - require __DIR__ . '/compat/wordpress-6.6/block-bindings/pattern-overrides.php'; -} +// WordPress 6.6 compat. +require __DIR__ . '/compat/wordpress-6.6/block-bindings/pattern-overrides.php'; // Experimental features. require __DIR__ . '/experimental/block-editor-settings-mobile.php'; diff --git a/packages/block-editor/src/components/block-settings/container.native.js b/packages/block-editor/src/components/block-settings/container.native.js index d9d9cda9eadd96..bb31bf0bc2bb84 100644 --- a/packages/block-editor/src/components/block-settings/container.native.js +++ b/packages/block-editor/src/components/block-settings/container.native.js @@ -16,6 +16,7 @@ import styles from './container.native.scss'; import InspectorControls from '../inspector-controls'; import ImageLinkDestinationsScreen from '../image-link-destinations'; import useMultipleOriginColorsAndGradients from '../colors-gradients/use-multiple-origin-colors-and-gradients'; +import AdvancedControls from '../inspector-controls-tabs/advanced-controls-panel'; export const blockSettingsScreens = { settings: 'Settings', @@ -46,7 +47,10 @@ export default function BottomSheetSettings( props ) { - + <> + + + { it( "doesn't render the block settings button if there aren't any settings for the current selected block", async () => { // Arrange const screen = await initializeEditor(); - await addBlock( screen, 'Image' ); - - // Act - fireEvent( - screen.getByTestId( 'media-options-picker' ), - 'backdropPress' - ); + await addBlock( screen, 'Shortcode' ); // Assert expect( screen.queryByLabelText( 'Open Settings' ) ).toBeNull(); diff --git a/packages/block-editor/src/components/inspector-controls-tabs/advanced-controls-panel.native.js b/packages/block-editor/src/components/inspector-controls-tabs/advanced-controls-panel.native.js new file mode 100644 index 00000000000000..f0403139f271ae --- /dev/null +++ b/packages/block-editor/src/components/inspector-controls-tabs/advanced-controls-panel.native.js @@ -0,0 +1,31 @@ +/** + * WordPress dependencies + */ +import { PanelBody } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import groups from '../inspector-controls/groups'; + +export default function AdvancedControls( props ) { + const Slot = groups.advanced?.Slot; + if ( ! Slot ) { + return null; + } + + return ( + + { ( fills ) => { + if ( ! fills.length ) { + return null; + } + + return ( + { fills } + ); + } } + + ); +} diff --git a/packages/block-editor/src/hooks/anchor.js b/packages/block-editor/src/hooks/anchor.js index 2e79a9d9db17b2..92cb7f7a1b42ca 100644 --- a/packages/block-editor/src/hooks/anchor.js +++ b/packages/block-editor/src/hooks/anchor.js @@ -2,7 +2,7 @@ * WordPress dependencies */ import { addFilter } from '@wordpress/hooks'; -import { PanelBody, TextControl, ExternalLink } from '@wordpress/components'; +import { TextControl, ExternalLink } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { hasBlockSupport } from '@wordpress/blocks'; import { Platform } from '@wordpress/element'; @@ -51,71 +51,51 @@ export function addAttribute( settings ) { return settings; } -function BlockEditAnchorControlPure( { - name: blockName, - anchor, - setAttributes, -} ) { +function BlockEditAnchorControlPure( { anchor, setAttributes } ) { const blockEditingMode = useBlockEditingMode(); - const isWeb = Platform.OS === 'web'; - const textControl = ( - - { __( - 'Enter a word or two — without spaces — to make a unique web address just for this block, called an “anchor.” Then, you’ll be able to link directly to this section of your page.' - ) } + if ( blockEditingMode !== 'default' ) { + return null; + } - { isWeb && ( - - { __( 'Learn more about anchors' ) } - - ) } - - } - value={ anchor || '' } - placeholder={ ! isWeb ? __( 'Add an anchor' ) : null } - onChange={ ( nextValue ) => { - nextValue = nextValue.replace( ANCHOR_REGEX, '-' ); - setAttributes( { - anchor: nextValue, - } ); - } } - autoCapitalize="none" - autoComplete="off" - /> - ); + const isWeb = Platform.OS === 'web'; return ( - <> - { isWeb && blockEditingMode === 'default' && ( - - { textControl } - - ) } - { /* - * We plan to remove scoping anchors to 'core/heading' to support - * anchors for all eligble blocks. Additionally we plan to explore - * leveraging InspectorAdvancedControls instead of a custom - * PanelBody title. https://github.com/WordPress/gutenberg/issues/28363 - */ } - { ! isWeb && blockName === 'core/heading' && ( - - - { textControl } - - - ) } - + + + { __( + 'Enter a word or two — without spaces — to make a unique web address just for this block, called an “anchor.” Then, you’ll be able to link directly to this section of your page.' + ) } + + { isWeb && ( + + { __( 'Learn more about anchors' ) } + + ) } + + } + value={ anchor || '' } + placeholder={ ! isWeb ? __( 'Add an anchor' ) : null } + onChange={ ( nextValue ) => { + nextValue = nextValue.replace( ANCHOR_REGEX, '-' ); + setAttributes( { + anchor: nextValue, + } ); + } } + autoCapitalize="none" + autoComplete="off" + /> + ); } diff --git a/packages/block-editor/src/hooks/position.js b/packages/block-editor/src/hooks/position.js index e1e26d54aa2420..89b7a2d6b23b44 100644 --- a/packages/block-editor/src/hooks/position.js +++ b/packages/block-editor/src/hooks/position.js @@ -152,7 +152,7 @@ export function hasPositionValue( props ) { * @return {boolean} Whether or not the block is set to a sticky or fixed position. */ export function hasStickyOrFixedPositionValue( attributes ) { - const positionType = attributes.style?.position?.type; + const positionType = attributes?.style?.position?.type; return positionType === 'sticky' || positionType === 'fixed'; } diff --git a/packages/block-editor/src/hooks/test/__snapshots__/anchor.native.js.snap b/packages/block-editor/src/hooks/test/__snapshots__/anchor.native.js.snap new file mode 100644 index 00000000000000..03407a1fe55d85 --- /dev/null +++ b/packages/block-editor/src/hooks/test/__snapshots__/anchor.native.js.snap @@ -0,0 +1,7 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`anchor should set the ID attribute on the block 1`] = ` +" +

+" +`; diff --git a/packages/block-editor/src/hooks/test/anchor.native.js b/packages/block-editor/src/hooks/test/anchor.native.js new file mode 100644 index 00000000000000..d6d2de845cbf48 --- /dev/null +++ b/packages/block-editor/src/hooks/test/anchor.native.js @@ -0,0 +1,32 @@ +/** + * External dependencies + */ +import { + addBlock, + changeTextOfTextInput, + getEditorHtml, + initializeEditor, + openBlockSettings, + screen, + setupCoreBlocks, +} from 'test/helpers'; + +setupCoreBlocks( [ 'core/paragraph' ] ); + +describe( 'anchor', () => { + it( 'should set the ID attribute on the block', async () => { + // Arrange + await initializeEditor(); + const block = await addBlock( screen, 'Paragraph' ); + await openBlockSettings( screen, block ); + + // Act + await changeTextOfTextInput( + await screen.getByPlaceholderText( 'Add an anchor' ), + 'my-anchor' + ); + + // Assert + expect( getEditorHtml() ).toMatchSnapshot(); + } ); +} ); diff --git a/packages/block-library/src/image/editor.scss b/packages/block-library/src/image/editor.scss index 8382ad1e7da32d..f09f5ffc8b619d 100644 --- a/packages/block-library/src/image/editor.scss +++ b/packages/block-library/src/image/editor.scss @@ -2,11 +2,6 @@ // @todo: this particular minimal style of placeholder could be componentized further. .wp-block-image.wp-block-image { - &:not(.is-selected) .components-placeholder__fieldset { - // Show only is selected. - display: none; - } - // Show Placeholder style on-select. &.is-selected .components-placeholder { // Block UI appearance. diff --git a/packages/block-library/src/navigation-link/edit.js b/packages/block-library/src/navigation-link/edit.js index e2a18c4bec8d23..bcb1076baed54a 100644 --- a/packages/block-library/src/navigation-link/edit.js +++ b/packages/block-library/src/navigation-link/edit.js @@ -333,6 +333,9 @@ export default function NavigationLinkEdit( { isKeyboardEvent.primary( event, 'k' ) || ( ( ! url || isDraft || isInvalid ) && event.keyCode === ENTER ) ) { + // Required to prevent the command center from opening, + // as it shares the CMD+K shortcut. + // See https://github.com/WordPress/gutenberg/pull/59845. event.preventDefault(); setIsLinkOpen( true ); } diff --git a/packages/block-library/src/navigation-submenu/edit.js b/packages/block-library/src/navigation-submenu/edit.js index 401d9512797b09..f8d9b0eaaedb84 100644 --- a/packages/block-library/src/navigation-submenu/edit.js +++ b/packages/block-library/src/navigation-submenu/edit.js @@ -279,6 +279,9 @@ export default function NavigationSubmenuEdit( { function onKeyDown( event ) { if ( isKeyboardEvent.primary( event, 'k' ) ) { + // Required to prevent the command center from opening, + // as it shares the CMD+K shortcut. + // See https://github.com/WordPress/gutenberg/pull/59845. event.preventDefault(); setIsLinkOpen( true ); } diff --git a/packages/block-library/src/navigation/edit/index.js b/packages/block-library/src/navigation/edit/index.js index dc2850df12e04a..3b526ddb85dc69 100644 --- a/packages/block-library/src/navigation/edit/index.js +++ b/packages/block-library/src/navigation/edit/index.js @@ -342,16 +342,7 @@ function Navigation( { const [ detectedOverlayColor, setDetectedOverlayColor ] = useState(); const onSelectClassicMenu = async ( classicMenu ) => { - const navMenu = await convertClassicMenu( - classicMenu.id, - classicMenu.name, - 'draft' - ); - if ( navMenu ) { - handleUpdateMenu( navMenu.id, { - focusNavigationBlock: true, - } ); - } + return convertClassicMenu( classicMenu.id, classicMenu.name, 'draft' ); }; const onSelectNavigationMenu = ( menuId ) => { @@ -402,6 +393,9 @@ function Navigation( { showClassicMenuConversionNotice( __( 'Classic menu imported successfully.' ) ); + handleUpdateMenu( createNavigationMenuPost?.id, { + focusNavigationBlock: true, + } ); } if ( classicMenuConversionStatus === CLASSIC_MENU_CONVERSION_ERROR ) { @@ -414,6 +408,8 @@ function Navigation( { classicMenuConversionError, hideClassicMenuConversionNotice, showClassicMenuConversionNotice, + createNavigationMenuPost?.id, + handleUpdateMenu, ] ); useEffect( () => { @@ -866,50 +862,52 @@ function Navigation( { ) } - { isLoading && ( - + + { isLoading && (
-
- ) } + ) } - { ! isLoading && ( - - - - { isEntityAvailable && ( - - ) } - - - ) } + { ! isLoading && ( + <> + + + { isEntityAvailable && ( + + ) } + + + ) } +
); diff --git a/packages/block-library/src/post-featured-image/block.json b/packages/block-library/src/post-featured-image/block.json index 75f5bec3ff451d..05c2fb1f28b135 100644 --- a/packages/block-library/src/post-featured-image/block.json +++ b/packages/block-library/src/post-featured-image/block.json @@ -77,6 +77,9 @@ "width": true } }, + "shadow": { + "__experimentalSkipSerialization": true + }, "html": false, "spacing": { "margin": true, @@ -86,6 +89,9 @@ "clientNavigation": true } }, + "selectors": { + "shadow": ".wp-block-post-featured-image img, .wp-block-post-featured-image .components-placeholder" + }, "editorStyle": "wp-block-post-featured-image-editor", "style": "wp-block-post-featured-image" } diff --git a/packages/block-library/src/post-featured-image/edit.js b/packages/block-library/src/post-featured-image/edit.js index 5e3843fcedbaeb..a37322467d1f52 100644 --- a/packages/block-library/src/post-featured-image/edit.js +++ b/packages/block-library/src/post-featured-image/edit.js @@ -24,6 +24,7 @@ import { useBlockProps, store as blockEditorStore, __experimentalUseBorderProps as useBorderProps, + __experimentalGetShadowClassesAndStyles as getShadowClassesAndStyles, useBlockEditingMode, } from '@wordpress/block-editor'; import { useMemo } from '@wordpress/element'; @@ -144,6 +145,7 @@ export default function PostFeaturedImageEdit( { style: { width, height, aspectRatio }, } ); const borderProps = useBorderProps( attributes ); + const shadowProps = getShadowClassesAndStyles( attributes ); const blockEditingMode = useBlockEditingMode(); const placeholder = ( content ) => { @@ -158,6 +160,7 @@ export default function PostFeaturedImageEdit( { height: !! aspectRatio && '100%', width: !! aspectRatio && '100%', ...borderProps.style, + ...shadowProps.style, } } > { content } @@ -267,6 +270,7 @@ export default function PostFeaturedImageEdit( { const label = __( 'Add a featured image' ); const imageStyles = { ...borderProps.style, + ...shadowProps.style, height: aspectRatio ? '100%' : height, width: !! aspectRatio && '100%', objectFit: !! ( height || aspectRatio ) && scale, diff --git a/packages/block-library/src/post-featured-image/index.php b/packages/block-library/src/post-featured-image/index.php index 347425c23a4a08..815da4ee63fe19 100644 --- a/packages/block-library/src/post-featured-image/index.php +++ b/packages/block-library/src/post-featured-image/index.php @@ -50,6 +50,13 @@ function render_block_core_post_featured_image( $attributes, $content, $block ) if ( ! empty( $attributes['scale'] ) ) { $extra_styles .= "object-fit:{$attributes['scale']};"; } + if ( ! empty( $attributes['style']['shadow'] ) ) { + $shadow_styles = wp_style_engine_get_styles( array( 'shadow' => $attributes['style']['shadow'] ) ); + + if ( ! empty( $shadow_styles['css'] ) ) { + $extra_styles .= $shadow_styles['css']; + } + } if ( ! empty( $extra_styles ) ) { $attr['style'] = empty( $attr['style'] ) ? $extra_styles : $attr['style'] . $extra_styles; diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md index e788f62c1eff1b..cfb9d418ffbaa8 100644 --- a/packages/components/CHANGELOG.md +++ b/packages/components/CHANGELOG.md @@ -1,7 +1,8 @@ ## Unreleased -- `Drowdown` : Add styling support for `MenuGroup` ([#59723](https://github.com/WordPress/gutenberg/pull/59723)). +- `Dropdown` : Add styling support for `MenuGroup` ([#59723](https://github.com/WordPress/gutenberg/pull/59723)). +- `Placeholder` : Allow overflow but only when placeholder is selected, to fix a layout shift. `MenuGroup` ([#59857](https://github.com/WordPress/gutenberg/pull/59857)). ### Enhancements diff --git a/packages/components/src/placeholder/style.scss b/packages/components/src/placeholder/style.scss index 8c6ca721123004..eda0dd3329d39c 100644 --- a/packages/components/src/placeholder/style.scss +++ b/packages/components/src/placeholder/style.scss @@ -212,7 +212,11 @@ // By painting the borders here, we enable them to be replaced by the Border control. @include placeholder-style(); - overflow: auto; + + overflow: hidden; + .is-selected & { + overflow: auto; + } } // Position the spinner. diff --git a/packages/e2e-tests/plugins/interactive-blocks/deferred-store/block.json b/packages/e2e-tests/plugins/interactive-blocks/deferred-store/block.json new file mode 100644 index 00000000000000..088572086f000c --- /dev/null +++ b/packages/e2e-tests/plugins/interactive-blocks/deferred-store/block.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "test/deferred-store", + "title": "E2E Interactivity tests - deferred store", + "category": "text", + "icon": "heart", + "description": "", + "supports": { + "interactivity": true + }, + "textdomain": "e2e-interactivity", + "viewScriptModule": "file:./view.js", + "render": "file:./render.php" +} diff --git a/packages/e2e-tests/plugins/interactive-blocks/deferred-store/render.php b/packages/e2e-tests/plugins/interactive-blocks/deferred-store/render.php new file mode 100644 index 00000000000000..0d8c2cbeb5125d --- /dev/null +++ b/packages/e2e-tests/plugins/interactive-blocks/deferred-store/render.php @@ -0,0 +1,15 @@ + + +
'!dlrow ,olleH' ) ); ?> +> + + +
diff --git a/packages/e2e-tests/plugins/interactive-blocks/deferred-store/view.asset.php b/packages/e2e-tests/plugins/interactive-blocks/deferred-store/view.asset.php new file mode 100644 index 00000000000000..db23afdf657a19 --- /dev/null +++ b/packages/e2e-tests/plugins/interactive-blocks/deferred-store/view.asset.php @@ -0,0 +1 @@ + array( '@wordpress/interactivity' ) ); diff --git a/packages/e2e-tests/plugins/interactive-blocks/deferred-store/view.js b/packages/e2e-tests/plugins/interactive-blocks/deferred-store/view.js new file mode 100644 index 00000000000000..8474757a0bd8bf --- /dev/null +++ b/packages/e2e-tests/plugins/interactive-blocks/deferred-store/view.js @@ -0,0 +1,20 @@ +/** + * WordPress dependencies + */ +import { store, getContext } from '@wordpress/interactivity'; + +document.addEventListener( 'DOMContentLoaded', () => { + setTimeout( () => { + store( 'test/deferred-store', { + state: { + reversedText() { + return [ ...getContext().text ].reverse().join( '' ); + }, + + get reversedTextGetter() { + return [ ...getContext().text ].reverse().join( '' ); + }, + }, + } ); + }, 50 ); +} ); diff --git a/packages/editor/src/components/error-boundary/index.native.js b/packages/editor/src/components/error-boundary/index.native.js index 6f76a4fbdccfe5..d627bfa0e7893c 100644 --- a/packages/editor/src/components/error-boundary/index.native.js +++ b/packages/editor/src/components/error-boundary/index.native.js @@ -147,7 +147,7 @@ class ErrorBoundary extends Component { { __( - 'The editor has encountered an unexpected error.' + 'The editor has encountered an unexpected error' ) } diff --git a/packages/editor/src/components/error-boundary/style.native.scss b/packages/editor/src/components/error-boundary/style.native.scss index 6c461207768679..f3f26ba4c0b200 100644 --- a/packages/editor/src/components/error-boundary/style.native.scss +++ b/packages/editor/src/components/error-boundary/style.native.scss @@ -32,7 +32,7 @@ } .error-boundary__icon-container--dark { - background-color: $gray-20; + background-color: rgba(235, 235, 245, 0.3); } .error-boundary__icon { @@ -64,7 +64,7 @@ } .error-boundary__message--dark { - color: $white; + color: rgba(235, 235, 245, 0.6); } .error-boundary__actions-container { @@ -82,7 +82,7 @@ } .copy-button__container--dark { - background-color: $gray-20; + background-color: $white; } .copy-button__container--secondary { @@ -91,6 +91,7 @@ } .copy-button__container--secondary-dark { + border-color: rgba(255, 255, 255, 0.3); background-color: $black; } diff --git a/packages/interactivity/CHANGELOG.md b/packages/interactivity/CHANGELOG.md index cb3f2fc97dac1d..c8e3432e862c89 100644 --- a/packages/interactivity/CHANGELOG.md +++ b/packages/interactivity/CHANGELOG.md @@ -4,6 +4,7 @@ ### Bug Fixes +- Ensure that stores are available for subscription before hydration. ([#59842](https://github.com/WordPress/gutenberg/pull/59842)) - Ensure scope is restored when catching exceptions thrown in async generator actions. ([#59708](https://github.com/WordPress/gutenberg/pull/59708)) ## 5.2.0 (2024-03-06) diff --git a/packages/interactivity/docs/api-reference.md b/packages/interactivity/docs/api-reference.md index 78aefe7823d0fa..c8ffc64fbac3eb 100644 --- a/packages/interactivity/docs/api-reference.md +++ b/packages/interactivity/docs/api-reference.md @@ -1011,7 +1011,7 @@ It returns an object with two keys: ##### ref -`ref` is the reference to the DOM element as an [HTMLElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement) +`ref` is the reference to the DOM element as an [HTMLElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement). It is equivalent to `useRef` in Preact or React, so it can be `null` when `ref` has not been attached to the actual DOM element yet, i.e., when it is being hydrated or mounted. ##### attributes diff --git a/packages/interactivity/src/hooks.tsx b/packages/interactivity/src/hooks.tsx index 0b869dee4fda8e..00c3c0d6d1729d 100644 --- a/packages/interactivity/src/hooks.tsx +++ b/packages/interactivity/src/hooks.tsx @@ -15,7 +15,7 @@ import type { VNode, Context, RefObject } from 'preact'; /** * Internal dependencies */ -import { stores } from './store'; +import { store, stores, universalUnlock } from './store'; interface DirectiveEntry { value: string | Object; namespace: string; @@ -259,8 +259,14 @@ export const directive = ( // Resolve the path to some property of the store object. const resolve = ( path, namespace ) => { + let resolvedStore = stores.get( namespace ); + if ( typeof resolvedStore === 'undefined' ) { + resolvedStore = store( namespace, undefined, { + lock: universalUnlock, + } ); + } let current = { - ...stores.get( namespace ), + ...resolvedStore, context: getScope().context[ namespace ], }; path.split( '.' ).forEach( ( p ) => ( current = current[ p ] ) ); diff --git a/packages/interactivity/src/store.ts b/packages/interactivity/src/store.ts index 055e6e3cc99ff4..2cd8ddd9e3fb23 100644 --- a/packages/interactivity/src/store.ts +++ b/packages/interactivity/src/store.ts @@ -202,7 +202,7 @@ interface StoreOptions { lock?: boolean | string; } -const universalUnlock = +export const universalUnlock = 'I acknowledge that using a private store means my plugin will inevitably break on the next store release.'; /** diff --git a/packages/react-native-editor/CHANGELOG.md b/packages/react-native-editor/CHANGELOG.md index 70c636da4dccbd..a5d73156bf5571 100644 --- a/packages/react-native-editor/CHANGELOG.md +++ b/packages/react-native-editor/CHANGELOG.md @@ -15,6 +15,7 @@ For each user feature we should also add a importance categorization label to i - [**] [internal] Upgrade React Native to version 0.73.3 [#58475] - [**] Add error boundary components and exception logging [#59221] - [**] Fix crash occurring when the URL associated with a Video block is changed too quickly [#59841] +- [**] Enable setting HTML anchor IDs for all supported block types [#59802] ## 1.114.1 - [**] Fix a crash produced when the content of a synced pattern is updated [#59632] diff --git a/schemas/json/block.json b/schemas/json/block.json index a39cec0e78c5d0..672de711be79f3 100644 --- a/schemas/json/block.json +++ b/schemas/json/block.json @@ -294,12 +294,12 @@ }, "heading": { "type": "boolean", - "description": "This property adds block controls which allow the user to set heading colors in a block, heading color is disabled by default.\n\nHeading color presets are sourced from the editor-color-palette theme support.\n\nWhen the block declares support for color.heading, its attributes definition is extended to include the style attribute", + "description": "This property adds block controls which allow the user to set heading colors in a block. Heading color is disabled by default.\n\nHeading color presets are sourced from the editor-color-palette theme support.\n\nWhen the block declares support for color.heading, its attributes definition is extended to include the style attribute", "default": false }, "button": { "type": "boolean", - "description": "This property adds block controls which allow the user to set button colors in a block, button color is disabled by default.\n\nButton color presets are sourced from the editor-color-palette theme support.\n\nWhen the block declares support for color.heading, its attributes definition is extended to include the style attribute", + "description": "This property adds block controls which allow the user to set button colors in a block. Button color is disabled by default.\n\nButton color presets are sourced from the editor-color-palette theme support.\n\nWhen the block declares support for color.button, its attributes definition is extended to include the style attribute", "default": false }, "enableContrastChecker": { diff --git a/test/e2e/specs/editor/blocks/navigation-list-view.spec.js b/test/e2e/specs/editor/blocks/navigation-list-view.spec.js index fd7113fe170959..c97ea3f1b17b51 100644 --- a/test/e2e/specs/editor/blocks/navigation-list-view.spec.js +++ b/test/e2e/specs/editor/blocks/navigation-list-view.spec.js @@ -543,6 +543,48 @@ test.describe( 'Navigation block - List view editing', () => { // we have unmounted the list view and then remounted it). await expect( linkControl.getSearchInput() ).toBeHidden(); } ); + + test( `can create a new menu without losing focus`, async ( { + page, + editor, + requestUtils, + } ) => { + await requestUtils.createNavigationMenu( navMenuBlocksFixture ); + + await editor.insertBlock( { name: 'core/navigation' } ); + + await editor.openDocumentSettingsSidebar(); + + await page.getByLabel( 'Test Menu' ).click(); + + await page.keyboard.press( 'ArrowUp' ); + + await expect( + page.getByRole( 'menuitem', { name: 'Create new menu' } ) + ).toBeFocused(); + + await page.keyboard.press( 'Enter' ); + + // Check that the menu was created + await expect( + page + .getByTestId( 'snackbar' ) + .getByText( 'Navigation Menu successfully created.' ) + ).toBeVisible(); + await expect( + page.getByText( 'This navigation menu is empty.' ) + ).toBeVisible(); + + // Move focus to the appender + await page.keyboard.press( 'ArrowDown' ); + await expect( + editor.canvas + .getByRole( 'document', { + name: 'Block: Navigation', + } ) + .getByLabel( 'Add block' ) + ).toBeFocused(); + } ); } ); class LinkControl { diff --git a/test/e2e/specs/interactivity/deferred-store.spec.ts b/test/e2e/specs/interactivity/deferred-store.spec.ts new file mode 100644 index 00000000000000..4521322e61dfc9 --- /dev/null +++ b/test/e2e/specs/interactivity/deferred-store.spec.ts @@ -0,0 +1,36 @@ +/** + * Internal dependencies + */ +import { test, expect } from './fixtures'; + +test.describe( 'deferred store', () => { + test.beforeAll( async ( { interactivityUtils: utils } ) => { + await utils.activatePlugins(); + await utils.addPostWithBlock( 'test/deferred-store' ); + } ); + test.beforeEach( async ( { interactivityUtils: utils, page } ) => { + await page.goto( utils.getLink( 'test/deferred-store' ) ); + } ); + test.afterAll( async ( { interactivityUtils: utils } ) => { + await utils.deactivatePlugins(); + await utils.deleteAllPosts(); + } ); + + test( 'Ensure that a store can be subscribed to before it is initialized', async ( { + page, + } ) => { + const resultInput = page.getByTestId( 'result' ); + await expect( resultInput ).toHaveText( '' ); + await expect( resultInput ).toHaveText( 'Hello, world!' ); + } ); + + // There is a known issue for deferred getters right now. + // eslint-disable-next-line playwright/no-skipped-test + test.skip( 'Ensure that a state getter can be subscribed to before it is initialized', async ( { + page, + } ) => { + const resultInput = page.getByTestId( 'result-getter' ); + await expect( resultInput ).toHaveText( '' ); + await expect( resultInput ).toHaveText( 'Hello, world!' ); + } ); +} );