diff --git a/.eslintrc.js b/.eslintrc.js
index caf01b7cbd71d4..2e92b495691873 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -216,6 +216,12 @@ module.exports = {
},
],
'no-restricted-syntax': [ 'error', ...restrictedSyntax ],
+ 'jsdoc/check-tag-names': [
+ 'error',
+ {
+ definedTags: [ 'jest-environment' ],
+ },
+ ],
},
overrides: [
{
@@ -315,6 +321,7 @@ module.exports = {
...[
'BorderBoxControl',
'BorderControl',
+ 'BoxControl',
'ComboboxControl',
'CustomSelectControl',
'DimensionControl',
diff --git a/.github/workflows/bundle-size.yml b/.github/workflows/bundle-size.yml
index 6106eee492c32a..499a2c020255cb 100644
--- a/.github/workflows/bundle-size.yml
+++ b/.github/workflows/bundle-size.yml
@@ -52,5 +52,5 @@ jobs:
- uses: preactjs/compressed-size-action@f780fd104362cfce9e118f9198df2ee37d12946c # v2.6.0
with:
repo-token: '${{ secrets.GITHUB_TOKEN }}'
- pattern: '{build/**/*.min.js,build/**/*.css}'
+ pattern: '{build/**/*.min.js,build/**/*.css,build-module/**/*.min.js}'
clean-script: 'distclean'
diff --git a/.github/workflows/rnmobile-android-runner.yml b/.github/workflows/rnmobile-android-runner.yml
index 3efd7d79ee2276..2c3998c2952808 100644
--- a/.github/workflows/rnmobile-android-runner.yml
+++ b/.github/workflows/rnmobile-android-runner.yml
@@ -28,7 +28,7 @@ jobs:
show-progress: ${{ runner.debug == '1' && 'true' || 'false' }}
- name: Use desired version of Java
- uses: actions/setup-java@6a0805fcefea3d4657a47ac4c165951e33482018 # v4.2.2
+ uses: actions/setup-java@2dfa2011c5b2a0f1489bf9e433881c92c1631f88 # v4.3.0
with:
distribution: 'corretto'
java-version: '17'
@@ -47,7 +47,7 @@ jobs:
run: npm run native test:e2e:setup
- name: Gradle cache
- uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0
+ uses: gradle/actions/setup-gradle@d156388eb19639ec20ade50009f3d199ce1e2808 # v4.1.0
- name: AVD cache
uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2
diff --git a/.stylelintrc.json b/.stylelintrc.json
index 663befa2e4ce06..557376e02c4062 100644
--- a/.stylelintrc.json
+++ b/.stylelintrc.json
@@ -1,5 +1,5 @@
{
- "extends": "@wordpress/stylelint-config/scss",
+ "extends": "@wordpress/stylelint-config/scss-stylistic",
"rules": {
"at-rule-empty-line-before": null,
"at-rule-no-unknown": null,
@@ -21,7 +21,7 @@
}
],
"font-weight-notation": null,
- "max-line-length": null,
+ "@stylistic/max-line-length": null,
"no-descending-specificity": null,
"property-disallowed-list": [
[ "order" ],
@@ -34,7 +34,7 @@
"value-keyword-case": null,
"scss/operator-no-unspaced": null,
"scss/selector-no-redundant-nesting-selector": null,
- "scss/at-import-partial-extension": null,
+ "scss/load-partial-extension": null,
"scss/no-global-function-names": null,
"scss/comment-no-empty": null,
"scss/at-extend-no-missing-placeholder": null,
diff --git a/backport-changelog/6.7/7314.md b/backport-changelog/6.7/7314.md
new file mode 100644
index 00000000000000..7d75cdff0f9075
--- /dev/null
+++ b/backport-changelog/6.7/7314.md
@@ -0,0 +1,3 @@
+https://github.com/WordPress/wordpress-develop/pull/7314
+
+* https://github.com/WordPress/gutenberg/pull/64167
diff --git a/bin/build-plugin-zip.sh b/bin/build-plugin-zip.sh
index 4ba931c4a4aeb6..c823ca6a8017f1 100755
--- a/bin/build-plugin-zip.sh
+++ b/bin/build-plugin-zip.sh
@@ -78,26 +78,16 @@ npm run build
php bin/generate-gutenberg-php.php > gutenberg.tmp.php
mv gutenberg.tmp.php gutenberg.php
-build_files=$(
- ls build/*/*.{js,js.map,css,asset.php} \
- build/block-library/blocks/*.php \
- build/block-library/blocks/*/block.json \
- build/block-library/blocks/*/*.{js,js.map,css,asset.php} \
- build/edit-widgets/blocks/*/block.json \
- build/widgets/blocks/*.php \
- build/widgets/blocks/*/block.json \
- build/style-engine/*.php \
-)
-
-
# Generate the plugin zip file.
status "Creating archive... 🎁"
-zip -r gutenberg.zip \
+zip --recurse-paths --no-dir-entries \
+ gutenberg.zip \
gutenberg.php \
lib \
packages/block-serialization-default-parser/*.php \
post-content.php \
- $build_files \
+ build \
+ build-module \
readme.txt \
changelog.txt \
README.md
diff --git a/changelog.txt b/changelog.txt
index dc0a2487f725ff..b0e6c8e907582e 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,7 +1,6 @@
== Changelog ==
-= 19.2.0-rc.1 =
-
+= 19.2.0 =
## Changelog
@@ -40,6 +39,12 @@
- Rely on `Text` component instead of `Truncate` in bindings panel. ([65007](https://github.com/WordPress/gutenberg/pull/65007))
- Remove `getPlaceholder` API and rely on `key` argument or source label. ([64910](https://github.com/WordPress/gutenberg/pull/64910))
+#### Data Views
+- Add: Reorder control at the field level on the new view configuration UI. ([64381](https://github.com/WordPress/gutenberg/pull/64381))
+- Dataviews Filter search widget: Do not use Composite store. ([64985](https://github.com/WordPress/gutenberg/pull/64985))
+- Dataviews list view: Do not use Composite store. ([64987](https://github.com/WordPress/gutenberg/pull/64987))
+- Move bulk actions menu to the Footer, consolidate with floating toolbar and total items display. ([64268](https://github.com/WordPress/gutenberg/pull/64268))
+
#### Block Editor
- Add 'Reset' option to MediaReplaceFlow component. ([64826](https://github.com/WordPress/gutenberg/pull/64826))
- Block Patterns List: Do not use Composite store. ([64983](https://github.com/WordPress/gutenberg/pull/64983))
@@ -106,12 +111,14 @@
- Add safeguard to `mediaUploadMiddleware`. ([64843](https://github.com/WordPress/gutenberg/pull/64843))
- Allow multi-select on iOS Safari/touch devices. ([63671](https://github.com/WordPress/gutenberg/pull/63671))
+- Core Data: Fix the 'query._fields' property check inside 'getEntityRecord' resolver. ([65079](https://github.com/WordPress/gutenberg/pull/65079))
- Fix Modify content-locked menu item not showing if the block is not selected. ([61605](https://github.com/WordPress/gutenberg/pull/61605))
- Fix editor error in Safari due to availability of checkVisibility method. ([65069](https://github.com/WordPress/gutenberg/pull/65069))
- Fix: Pagination arrows are pointing in the wrong direction in RTL languages. ([64962](https://github.com/WordPress/gutenberg/pull/64962))
- Footnotes: Only replace attribute if footnotes were detected. ([63935](https://github.com/WordPress/gutenberg/pull/63935))
- Paste: Fix image paste from Google Forms. ([64502](https://github.com/WordPress/gutenberg/pull/64502))
- Revert Focus pattern inserter search when activating zoom out inserter. ([64748](https://github.com/WordPress/gutenberg/pull/64748))
+- Try: Update block warnings. ([64997](https://github.com/WordPress/gutenberg/pull/64997))
#### Block Library
- De-duplicate block toolbar icons for patterns. ([65054](https://github.com/WordPress/gutenberg/pull/65054))
@@ -175,6 +182,9 @@
#### Site Editor
- DataViews: Fix pattern title direction in RTL languages. ([64967](https://github.com/WordPress/gutenberg/pull/64967))
+#### Typography
+- Site Title, Post Title: Fix typography for blocks with `a` children. ([64911](https://github.com/WordPress/gutenberg/pull/64911))
+
#### NUX
- Fix visibility of the template Welcome Guide in the Site Editor. ([64789](https://github.com/WordPress/gutenberg/pull/64789))
@@ -223,6 +233,9 @@
- Add 'OPTIONS /page' to preloaded paths. ([64890](https://github.com/WordPress/gutenberg/pull/64890))
- Editor: Don't use selector shortcuts for the Site data. ([64884](https://github.com/WordPress/gutenberg/pull/64884))
+#### Interactivity API
+- Prevent calling `proxifyContext` with context proxies inside `wp-context`. ([65090](https://github.com/WordPress/gutenberg/pull/65090))
+
#### Block Library
- Media & Text: Don't use background-image. ([64981](https://github.com/WordPress/gutenberg/pull/64981))
@@ -353,7 +366,7 @@ The following PRs were merged by first-time contributors:
The following contributors merged PRs in this release:
-@aaronrobertshaw @afercia @akasunil @Aljullu @andrewserong @atachibana @benoitchantre @carolinan @cbravobernal @ciampo @DAreRodz @dcalhoun @desrosj @dsas @ellatrix @fullofcaffeine @getdave @gziolo @Imran92 @imrraaj @jacobcassidy @jameskoster @jasmussen @jawadmalikdev @jeryj @jorgefilipecosta @jsnajdr @juanmaguitar @kevin940726 @lezama @Mamaduka @matiasbenedetto @mirka @noisysocks @ntsekouras @oandregal @ockham @ramonjd @richtabor @rithik56 @rohitmathur-7 @ryanwelcher @SantosGuillamot @scruffian @sgomes @shail-mehta @spacedmonkey @stokesman @swissspidy @t-hamano @talldan @tjcafferkey @tyxla
+@aaronrobertshaw @afercia @akasunil @Aljullu @andrewserong @atachibana @benoitchantre @carolinan @cbravobernal @ciampo @DAreRodz @dcalhoun @desrosj @dsas @ellatrix @fullofcaffeine @getdave @gziolo @Imran92 @imrraaj @jacobcassidy @jameskoster @jasmussen @jawadmalikdev @jeryj @jorgefilipecosta @jsnajdr @juanmaguitar @kevin940726 @lezama @Mamaduka @matiasbenedetto @mirka @noisysocks @ntsekouras @oandregal @ockham @rafaelgallani @ramonjd @richtabor @rithik56 @rohitmathur-7 @ryanwelcher @SantosGuillamot @scruffian @sgomes @shail-mehta @spacedmonkey @stokesman @swissspidy @t-hamano @talldan @tjcafferkey @tyxla
= 19.1.0 =
diff --git a/docs/reference-guides/block-api/block-api-versions.md b/docs/reference-guides/block-api/block-api-versions.md
index b4b11e7c23c7cc..d89362777ca58c 100644
--- a/docs/reference-guides/block-api/block-api-versions.md
+++ b/docs/reference-guides/block-api/block-api-versions.md
@@ -3,7 +3,7 @@
This document lists the changes made between the different API versions.
## Version 3 (>= WordPress 6.3)
-- The post editor will be iframed if all registered blocks have a Block API version 3 or higher and the editor has no classic meta boxes below the blocks. Adding version 3 support means that the block should work inside an iframe, though the block may still be rendered outside the iframe if not all blocks support version 3.
+- The post editor will be iframed if all registered blocks have a Block API version 3 or higher. Adding version 3 support means that the block should work inside an iframe, though the block may still be rendered outside the iframe if not all blocks support version 3.
## Version 2 (>= WordPress 5.6)
diff --git a/docs/reference-guides/block-api/block-context.md b/docs/reference-guides/block-api/block-context.md
index 5fdc670fe60403..09c33dfb71b7c3 100644
--- a/docs/reference-guides/block-api/block-context.md
+++ b/docs/reference-guides/block-api/block-context.md
@@ -141,7 +141,7 @@ export default function Edit( props ) {
return (
setAttributes( { recordId: Number( val ) } )
diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md
index b9cae44550181c..0e0de9d4f8a507 100644
--- a/docs/reference-guides/core-blocks.md
+++ b/docs/reference-guides/core-blocks.md
@@ -493,7 +493,7 @@ Add a submenu to your navigation. ([Source](https://github.com/WordPress/gutenbe
- **Name:** core/navigation-submenu
- **Category:** design
- **Parent:** core/navigation
-- **Supports:** interactivity (clientNavigation), ~~html~~, ~~reusable~~
+- **Supports:** interactivity (clientNavigation), typography (fontSize, lineHeight), ~~html~~, ~~reusable~~
- **Attributes:** description, id, isTopLevelItem, kind, label, opensInNewTab, rel, title, type, url
## Page Break
diff --git a/docs/reference-guides/slotfills/README.md b/docs/reference-guides/slotfills/README.md
index bab08dc34c40c1..874a3a69096b81 100644
--- a/docs/reference-guides/slotfills/README.md
+++ b/docs/reference-guides/slotfills/README.md
@@ -166,7 +166,7 @@ import { __ } from '@wordpress/i18n';
*/
const SiteEditorDocumentSettingPanel = () => {
// Retrieve information about the current post type.
- const { isViewable } = useSelect( ( select ) => {
+ const isViewable = useSelect( ( select ) => {
const postTypeName = select( editorStore ).getCurrentPostType();
const postTypeObject = select( coreStore ).getPostType( postTypeName );
diff --git a/gutenberg.php b/gutenberg.php
index 117f4168524d8a..342c61fb56cd13 100644
--- a/gutenberg.php
+++ b/gutenberg.php
@@ -5,7 +5,7 @@
* Description: Printing since 1440. This is the development plugin for the block editor, site editor, and other future WordPress core functionality.
* Requires at least: 6.5
* Requires PHP: 7.2
- * Version: 19.2.0-rc.1
+ * Version: 19.2.0
* Author: Gutenberg Team
* Text Domain: gutenberg
*
@@ -15,6 +15,8 @@
### BEGIN AUTO-GENERATED DEFINES
defined( 'GUTENBERG_DEVELOPMENT_MODE' ) or define( 'GUTENBERG_DEVELOPMENT_MODE', true );
### END AUTO-GENERATED DEFINES
+defined( 'GUTENBERG_MINIMUM_WP_VERSION' ) or define( 'GUTENBERG_MINIMUM_WP_VERSION', '6.5' );
+
gutenberg_pre_init();
@@ -26,7 +28,7 @@
function gutenberg_wordpress_version_notice() {
echo '';
/* translators: %s: Minimum required version */
- printf( __( 'Gutenberg requires WordPress %s or later to function properly. Please upgrade WordPress before activating Gutenberg.', 'gutenberg' ), '5.9' );
+ printf( __( 'Gutenberg requires WordPress %s or later to function properly. Please upgrade WordPress before activating Gutenberg.', 'gutenberg' ), GUTENBERG_MINIMUM_WP_VERSION );
echo '
';
deactivate_plugins( array( 'gutenberg/gutenberg.php' ) );
@@ -67,7 +69,7 @@ function gutenberg_pre_init() {
// Compare against major release versions (X.Y) rather than minor (X.Y.Z)
// unless a minor release is the actual minimum requirement. WordPress reports
// X.Y for its major releases.
- if ( version_compare( $version, '5.9', '<' ) ) {
+ if ( version_compare( $version, GUTENBERG_MINIMUM_WP_VERSION, '<' ) ) {
add_action( 'admin_notices', 'gutenberg_wordpress_version_notice' );
return;
}
diff --git a/lib/class-wp-rest-global-styles-controller-gutenberg.php b/lib/class-wp-rest-global-styles-controller-gutenberg.php
index 421408e6f20b4a..e33304e596e129 100644
--- a/lib/class-wp-rest-global-styles-controller-gutenberg.php
+++ b/lib/class-wp-rest-global-styles-controller-gutenberg.php
@@ -13,25 +13,30 @@
/**
* Base Global Styles REST API Controller.
*/
-class WP_REST_Global_Styles_Controller_Gutenberg extends WP_REST_Controller {
+class WP_REST_Global_Styles_Controller_Gutenberg extends WP_REST_Posts_Controller {
/**
- * Post type.
+ * Whether the controller supports batching.
*
- * @since 5.9.0
- * @var string
+ * @since 6.6.0
+ * @var array
*/
- protected $post_type;
+ protected $allow_batch = array( 'v1' => false );
/**
* Constructor.
*
* @since 5.9.0
*/
- public function __construct() {
- $this->namespace = 'wp/v2';
- $this->rest_base = 'global-styles';
- $this->post_type = 'wp_global_styles';
+ /**
+ * Constructor.
+ *
+ * @since 6.6.0
+ *
+ * @param string $post_type Post type.
+ */
+ public function __construct( $post_type = 'wp_global_styles' ) {
+ parent::__construct( $post_type );
}
/**
@@ -54,8 +59,14 @@ public function register_routes() {
'type' => 'string',
),
),
+ 'allow_batch' => $this->allow_batch,
),
- )
+ ),
+ /*
+ * $override is set to true to avoid conflicts with the core endpoint.
+ * Do not sync to WordPress core.
+ */
+ true
);
// List themes global styles.
@@ -65,8 +76,10 @@ public function register_routes() {
sprintf(
'/%s/themes/(?P%s)',
$this->rest_base,
- // Matches theme's directory: `/themes///` or `/themes//`.
- // Excludes invalid directory name characters: `/:<>*?"|`.
+ /*
+ * Matches theme's directory: `/themes///` or `/themes//`.
+ * Excludes invalid directory name characters: `/:<>*?"|`.
+ */
'[^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?'
),
array(
@@ -81,8 +94,14 @@ public function register_routes() {
'sanitize_callback' => array( $this, '_sanitize_global_styles_callback' ),
),
),
+ 'allow_batch' => $this->allow_batch,
),
- )
+ ),
+ /*
+ * $override is set to true to avoid conflicts with the core endpoint.
+ * Do not sync to WordPress core.
+ */
+ true
);
// Lists/updates a single global style variation based on the given id.
@@ -108,8 +127,14 @@ public function register_routes() {
'permission_callback' => array( $this, 'update_item_permissions_check' ),
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
),
- 'schema' => array( $this, 'get_public_item_schema' ),
- )
+ 'schema' => array( $this, 'get_public_item_schema' ),
+ 'allow_batch' => $this->allow_batch,
+ ),
+ /*
+ * $override is set to true to avoid conflicts with the core endpoint.
+ * Do not sync to WordPress core.
+ */
+ true
);
}
@@ -196,28 +221,10 @@ public function get_item_permissions_check( $request ) {
* @param WP_Post $post Post object.
* @return bool Whether the post can be read.
*/
- protected function check_read_permission( $post ) {
+ public function check_read_permission( $post ) {
return current_user_can( 'read_post', $post->ID );
}
- /**
- * Returns the given global styles config.
- *
- * @since 5.9.0
- *
- * @param WP_REST_Request $request The request instance.
- *
- * @return WP_REST_Response|WP_Error
- */
- public function get_item( $request ) {
- $post = $this->get_post( $request['id'] );
- if ( is_wp_error( $post ) ) {
- return $post;
- }
-
- return $this->prepare_item_for_response( $post, $request );
- }
-
/**
* Checks if a given request has access to write a single global styles config.
*
@@ -243,61 +250,12 @@ public function update_item_permissions_check( $request ) {
return true;
}
- /**
- * Checks if a global style can be edited.
- *
- * @since 5.9.0
- *
- * @param WP_Post $post Post object.
- * @return bool Whether the post can be edited.
- */
- protected function check_update_permission( $post ) {
- return current_user_can( 'edit_post', $post->ID );
- }
-
- /**
- * Updates a single global style config.
- *
- * @since 5.9.0
- * @since 6.2.0 Added validation of styles.css property.
- *
- * @param WP_REST_Request $request Full details about the request.
- * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
- */
- public function update_item( $request ) {
- $post_before = $this->get_post( $request['id'] );
- if ( is_wp_error( $post_before ) ) {
- return $post_before;
- }
-
- $changes = $this->prepare_item_for_database( $request );
- if ( is_wp_error( $changes ) ) {
- return $changes;
- }
-
- $result = wp_update_post( wp_slash( (array) $changes ), true, false );
- if ( is_wp_error( $result ) ) {
- return $result;
- }
-
- $post = get_post( $request['id'] );
- $fields_update = $this->update_additional_fields_for_object( $post, $request );
- if ( is_wp_error( $fields_update ) ) {
- return $fields_update;
- }
-
- wp_after_insert_post( $post, true, $post_before );
-
- $response = $this->prepare_item_for_response( $post, $request );
-
- return rest_ensure_response( $response );
- }
-
/**
* Prepares a single global styles config for update.
*
* @since 5.9.0
* @since 6.2.0 Added validation of styles.css property.
+ * @since 6.6.0 Added registration of block style variations from theme.json sources (theme.json, user theme.json, partials).
*
* @param WP_REST_Request $request Request object.
* @return stdClass|WP_Error Prepared item on success. WP_Error on when the custom CSS is not valid.
@@ -394,10 +352,12 @@ public function prepare_item_for_response( $post, $request ) { // phpcs:ignore V
}
if ( rest_is_field_included( 'title.rendered', $fields ) ) {
add_filter( 'protected_title_format', array( $this, 'protected_title_format' ) );
+ add_filter( 'private_title_format', array( $this, 'protected_title_format' ) );
$data['title']['rendered'] = get_the_title( $post->ID );
remove_filter( 'protected_title_format', array( $this, 'protected_title_format' ) );
+ remove_filter( 'private_title_format', array( $this, 'protected_title_format' ) );
}
if ( rest_is_field_included( 'settings', $fields ) ) {
@@ -426,7 +386,7 @@ public function prepare_item_for_response( $post, $request ) { // phpcs:ignore V
}
$response->add_links( $links );
if ( ! empty( $links['self']['href'] ) ) {
- $actions = $this->get_available_actions();
+ $actions = $this->get_available_actions( $post, $request );
$self = $links['self']['href'];
foreach ( $actions as $rel ) {
$response->add_link( $rel, $self );
@@ -450,9 +410,12 @@ protected function prepare_links( $id ) {
$base = sprintf( '%s/%s', $this->namespace, $this->rest_base );
$links = array(
- 'self' => array(
+ 'self' => array(
'href' => rest_url( trailingslashit( $base ) . $id ),
),
+ 'about' => array(
+ 'href' => rest_url( 'wp/v2/types/' . $this->post_type ),
+ ),
);
if ( post_type_supports( $this->post_type, 'revisions' ) ) {
@@ -473,13 +436,16 @@ protected function prepare_links( $id ) {
*
* @since 5.9.0
* @since 6.2.0 Added 'edit-css' action.
+ * @since 6.6.0 Added $post and $request parameters.
*
+ * @param WP_Post $post Post object.
+ * @param WP_REST_Request $request Request object.
* @return array List of link relations.
*/
- protected function get_available_actions() {
+ protected function get_available_actions( $post, $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
$rels = array();
- $post_type = get_post_type_object( $this->post_type );
+ $post_type = get_post_type_object( $post->post_type );
if ( current_user_can( $post_type->cap->publish_posts ) ) {
$rels[] = 'https://api.w.org/action-publish';
}
@@ -491,21 +457,6 @@ protected function get_available_actions() {
return $rels;
}
- /**
- * Overwrites the default protected title format.
- *
- * By default, WordPress will show password protected posts with a title of
- * "Protected: %s", as the REST API communicates the protected status of a post
- * in a machine readable format, we remove the "Protected: " prefix.
- *
- * @since 5.9.0
- *
- * @return string Protected title format.
- */
- public function protected_title_format() {
- return '%s';
- }
-
/**
* Retrieves the query params for the global styles collection.
*
@@ -589,7 +540,7 @@ public function get_theme_item_permissions_check( $request ) { // phpcs:ignore V
/*
* Verify if the current user has edit_theme_options capability.
- * This capability is required to edit/view/delete templates.
+ * This capability is required to edit/view/delete global styles.
*/
if ( ! current_user_can( 'edit_theme_options' ) ) {
return new WP_Error(
@@ -623,8 +574,8 @@ public function get_theme_item( $request ) {
}
$theme = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data( 'theme' );
- $data = array();
$fields = $this->get_fields_for_response( $request );
+ $data = array();
if ( rest_is_field_included( 'settings', $fields ) ) {
$data['settings'] = $theme->get_settings();
@@ -669,7 +620,7 @@ public function get_theme_items_permissions_check( $request ) { // phpcs:ignore
/*
* Verify if the current user has edit_theme_options capability.
- * This capability is required to edit/view/delete templates.
+ * This capability is required to edit/view/delete global styles.
*/
if ( ! current_user_can( 'edit_theme_options' ) ) {
return new WP_Error(
diff --git a/lib/compat/wordpress-6.6/rest-api.php b/lib/compat/wordpress-6.6/rest-api.php
index fee9c71b86c070..eadd3b1d376a72 100644
--- a/lib/compat/wordpress-6.6/rest-api.php
+++ b/lib/compat/wordpress-6.6/rest-api.php
@@ -88,76 +88,116 @@ function gutenberg_register_global_styles_revisions_endpoints() {
add_action( 'rest_api_init', 'gutenberg_register_global_styles_revisions_endpoints' );
-if ( ! function_exists( 'gutenberg_register_wp_rest_themes_stylesheet_directory_uri_field' ) ) {
- /**
- * Adds `stylesheet_uri` fields to WP_REST_Themes_Controller class.
- */
- function gutenberg_register_wp_rest_themes_stylesheet_directory_uri_field() {
- register_rest_field(
- 'theme',
- 'stylesheet_uri',
- array(
- 'get_callback' => function ( $item ) {
- if ( ! empty( $item['stylesheet'] ) ) {
- $theme = wp_get_theme( $item['stylesheet'] );
- $current_theme = wp_get_theme();
- if ( $theme->get_stylesheet() === $current_theme->get_stylesheet() ) {
- return get_stylesheet_directory_uri();
- } else {
- return $theme->get_stylesheet_directory_uri();
- }
+/**
+ * Adds `stylesheet_uri` fields to WP_REST_Themes_Controller class.
+ */
+function gutenberg_register_wp_rest_themes_stylesheet_directory_uri_field() {
+ register_rest_field(
+ 'theme',
+ 'stylesheet_uri',
+ array(
+ 'get_callback' => function ( $item ) {
+ if ( ! empty( $item['stylesheet'] ) ) {
+ $theme = wp_get_theme( $item['stylesheet'] );
+ $current_theme = wp_get_theme();
+ if ( $theme->get_stylesheet() === $current_theme->get_stylesheet() ) {
+ return get_stylesheet_directory_uri();
+ } else {
+ return $theme->get_stylesheet_directory_uri();
}
+ }
- return null;
- },
- 'schema' => array(
- 'type' => 'string',
- 'description' => __( 'The uri for the theme\'s stylesheet directory.', 'gutenberg' ),
- 'format' => 'uri',
- 'readonly' => true,
- 'context' => array( 'view', 'edit', 'embed' ),
- ),
- )
- );
- }
+ return null;
+ },
+ 'schema' => array(
+ 'type' => 'string',
+ 'description' => __( 'The uri for the theme\'s stylesheet directory.', 'gutenberg' ),
+ 'format' => 'uri',
+ 'readonly' => true,
+ 'context' => array( 'view', 'edit', 'embed' ),
+ ),
+ )
+ );
}
add_action( 'rest_api_init', 'gutenberg_register_wp_rest_themes_stylesheet_directory_uri_field' );
-if ( ! function_exists( 'gutenberg_register_wp_rest_themes_template_directory_uri_field' ) ) {
- /**
- * Adds `template_uri` fields to WP_REST_Themes_Controller class.
- */
- function gutenberg_register_wp_rest_themes_template_directory_uri_field() {
- register_rest_field(
- 'theme',
- 'template_uri',
- array(
- 'get_callback' => function ( $item ) {
- if ( ! empty( $item['stylesheet'] ) ) {
- $theme = wp_get_theme( $item['stylesheet'] );
- $current_theme = wp_get_theme();
- if ( $theme->get_stylesheet() === $current_theme->get_stylesheet() ) {
- return get_template_directory_uri();
- } else {
- return $theme->get_template_directory_uri();
- }
+/**
+ * Adds `template_uri` fields to WP_REST_Themes_Controller class.
+ */
+function gutenberg_register_wp_rest_themes_template_directory_uri_field() {
+ register_rest_field(
+ 'theme',
+ 'template_uri',
+ array(
+ 'get_callback' => function ( $item ) {
+ if ( ! empty( $item['stylesheet'] ) ) {
+ $theme = wp_get_theme( $item['stylesheet'] );
+ $current_theme = wp_get_theme();
+ if ( $theme->get_stylesheet() === $current_theme->get_stylesheet() ) {
+ return get_template_directory_uri();
+ } else {
+ return $theme->get_template_directory_uri();
}
+ }
- return null;
- },
- 'schema' => array(
- 'type' => 'string',
- 'description' => __( 'The uri for the theme\'s template directory. If this is a child theme, this refers to the parent theme, otherwise this is the same as the theme\'s stylesheet directory.', 'gutenberg' ),
- 'format' => 'uri',
- 'readonly' => true,
- 'context' => array( 'view', 'edit', 'embed' ),
- ),
- )
- );
- }
+ return null;
+ },
+ 'schema' => array(
+ 'type' => 'string',
+ 'description' => __( 'The uri for the theme\'s template directory. If this is a child theme, this refers to the parent theme, otherwise this is the same as the theme\'s stylesheet directory.', 'gutenberg' ),
+ 'format' => 'uri',
+ 'readonly' => true,
+ 'context' => array( 'view', 'edit', 'embed' ),
+ ),
+ )
+ );
}
add_action( 'rest_api_init', 'gutenberg_register_wp_rest_themes_template_directory_uri_field' );
+/**
+ * Adds `template` and `template_lock` fields to WP_REST_Post_Types_Controller class.
+ */
+function gutenberg_register_wp_rest_post_types_controller_fields() {
+ register_rest_field(
+ 'type',
+ 'template',
+ array(
+ 'get_callback' => function ( $item ) {
+ $post_type = get_post_type_object( $item['slug'] );
+ if ( ! empty( $post_type ) ) {
+ return $post_type->template ?? array();
+ }
+ },
+ 'schema' => array(
+ 'type' => 'array',
+ 'description' => __( 'The block template associated with the post type.', 'gutenberg' ),
+ 'readonly' => true,
+ 'context' => array( 'view', 'edit', 'embed' ),
+ ),
+ )
+ );
+ register_rest_field(
+ 'type',
+ 'template_lock',
+ array(
+ 'get_callback' => function ( $item ) {
+ $post_type = get_post_type_object( $item['slug'] );
+ if ( ! empty( $post_type ) ) {
+ return ! empty( $post_type->template_lock ) ? $post_type->template_lock : false;
+ }
+ },
+ 'schema' => array(
+ 'type' => array( 'string', 'boolean' ),
+ 'enum' => array( 'all', 'insert', 'contentOnly', false ),
+ 'description' => __( 'The template_lock associated with the post type, or false if none.', 'gutenberg' ),
+ 'readonly' => true,
+ 'context' => array( 'view', 'edit', 'embed' ),
+ ),
+ )
+ );
+}
+add_action( 'rest_api_init', 'gutenberg_register_wp_rest_post_types_controller_fields' );
+
/**
* Preload theme and global styles paths to avoid flash of variation styles in post editor.
*
diff --git a/lib/compat/wordpress-6.7/blocks.php b/lib/compat/wordpress-6.7/blocks.php
index 18d21621be7197..6b9526f8056fd3 100644
--- a/lib/compat/wordpress-6.7/blocks.php
+++ b/lib/compat/wordpress-6.7/blocks.php
@@ -43,3 +43,63 @@ function gutenberg_filter_block_type_metadata_settings_allow_variations_php_file
return $settings;
}
add_filter( 'block_type_metadata_settings', 'gutenberg_filter_block_type_metadata_settings_allow_variations_php_file', 10, 2 );
+
+/**
+ * Adds post format query vars to the query loop block's WP_Query when the block's attributes call for them.
+ *
+ * @see 'query_loop_block_query_vars'
+ *
+ * @param array $query The query vars.
+ * @param WP_Block $block Block instance.
+ * @return array The filtered query vars.
+ */
+function gutenberg_add_format_query_vars_to_query_loop_block( $query, $block ) {
+ // Return early if there is no format or if the format is not an array.
+ if ( empty( $block->context['query']['format'] ) || ! is_array( $block->context['query']['format'] ) ) {
+ return $query;
+ }
+
+ $formats = $block->context['query']['format'];
+ $tax_query = array( 'relation' => 'OR' );
+
+ // The default post format, 'standard', is not stored in the database.
+ // If 'standard' is part of the request, the query needs to exclude all post items that
+ // have a format assigned.
+ if ( in_array( 'standard', $formats, true ) ) {
+ $tax_query[] = array(
+ 'taxonomy' => 'post_format',
+ 'field' => 'slug',
+ 'terms' => array(),
+ 'operator' => 'NOT EXISTS',
+ );
+ // Remove the standard format, since it cannot be queried.
+ unset( $formats[ array_search( 'standard', $formats, true ) ] );
+ }
+
+ // Add any remaining formats to the tax query.
+ if ( ! empty( $formats ) ) {
+ // Add the post-format- prefix.
+ $terms = array_map(
+ static function ( $format ) {
+ return 'post-format-' . $format;
+ },
+ $formats
+ );
+
+ $tax_query[] = array(
+ 'taxonomy' => 'post_format',
+ 'field' => 'slug',
+ 'terms' => $terms,
+ 'operator' => 'IN',
+ );
+ }
+
+ // This condition is intended to prevent $tax_query from being added to $query
+ // if it only contains the relation.
+ if ( count( $tax_query ) > 1 ) {
+ $query['tax_query'][] = $tax_query;
+ }
+
+ return $query;
+}
+add_filter( 'query_loop_block_query_vars', 'gutenberg_add_format_query_vars_to_query_loop_block', 10, 2 );
diff --git a/lib/compat/wordpress-6.7/class-gutenberg-rest-posts-controller-6-7.php b/lib/compat/wordpress-6.7/class-gutenberg-rest-posts-controller-6-7.php
new file mode 100644
index 00000000000000..c7de4371c94f56
--- /dev/null
+++ b/lib/compat/wordpress-6.7/class-gutenberg-rest-posts-controller-6-7.php
@@ -0,0 +1,698 @@
+ 400 )
+ );
+ }
+
+ // Ensure an include parameter is set in case the orderby is set to 'include'.
+ if ( ! empty( $request['orderby'] ) && 'include' === $request['orderby'] && empty( $request['include'] ) ) {
+ return new WP_Error(
+ 'rest_orderby_include_missing_include',
+ __( 'You need to define an include parameter to order by include.' ),
+ array( 'status' => 400 )
+ );
+ }
+
+ // Retrieve the list of registered collection query parameters.
+ $registered = $this->get_collection_params();
+ $args = array();
+
+ /*
+ * This array defines mappings between public API query parameters whose
+ * values are accepted as-passed, and their internal WP_Query parameter
+ * name equivalents (some are the same). Only values which are also
+ * present in $registered will be set.
+ */
+ $parameter_mappings = array(
+ 'author' => 'author__in',
+ 'author_exclude' => 'author__not_in',
+ 'exclude' => 'post__not_in',
+ 'include' => 'post__in',
+ 'menu_order' => 'menu_order',
+ 'offset' => 'offset',
+ 'order' => 'order',
+ 'orderby' => 'orderby',
+ 'page' => 'paged',
+ 'parent' => 'post_parent__in',
+ 'parent_exclude' => 'post_parent__not_in',
+ 'search' => 's',
+ 'search_columns' => 'search_columns',
+ 'slug' => 'post_name__in',
+ 'status' => 'post_status',
+ );
+
+ /*
+ * For each known parameter which is both registered and present in the request,
+ * set the parameter's value on the query $args.
+ */
+ foreach ( $parameter_mappings as $api_param => $wp_param ) {
+ if ( isset( $registered[ $api_param ], $request[ $api_param ] ) ) {
+ $args[ $wp_param ] = $request[ $api_param ];
+ }
+ }
+
+ // Check for & assign any parameters which require special handling or setting.
+ $args['date_query'] = array();
+
+ if ( isset( $registered['before'], $request['before'] ) ) {
+ $args['date_query'][] = array(
+ 'before' => $request['before'],
+ 'column' => 'post_date',
+ );
+ }
+
+ if ( isset( $registered['modified_before'], $request['modified_before'] ) ) {
+ $args['date_query'][] = array(
+ 'before' => $request['modified_before'],
+ 'column' => 'post_modified',
+ );
+ }
+
+ if ( isset( $registered['after'], $request['after'] ) ) {
+ $args['date_query'][] = array(
+ 'after' => $request['after'],
+ 'column' => 'post_date',
+ );
+ }
+
+ if ( isset( $registered['modified_after'], $request['modified_after'] ) ) {
+ $args['date_query'][] = array(
+ 'after' => $request['modified_after'],
+ 'column' => 'post_modified',
+ );
+ }
+
+ // Ensure our per_page parameter overrides any provided posts_per_page filter.
+ if ( isset( $registered['per_page'] ) ) {
+ $args['posts_per_page'] = $request['per_page'];
+ }
+
+ if ( isset( $registered['sticky'], $request['sticky'] ) ) {
+ $sticky_posts = get_option( 'sticky_posts', array() );
+ if ( ! is_array( $sticky_posts ) ) {
+ $sticky_posts = array();
+ }
+ if ( $request['sticky'] ) {
+ /*
+ * As post__in will be used to only get sticky posts,
+ * we have to support the case where post__in was already
+ * specified.
+ */
+ $args['post__in'] = $args['post__in'] ? array_intersect( $sticky_posts, $args['post__in'] ) : $sticky_posts;
+
+ /*
+ * If we intersected, but there are no post IDs in common,
+ * WP_Query won't return "no posts" for post__in = array()
+ * so we have to fake it a bit.
+ */
+ if ( ! $args['post__in'] ) {
+ $args['post__in'] = array( 0 );
+ }
+ } elseif ( $sticky_posts ) {
+ /*
+ * As post___not_in will be used to only get posts that
+ * are not sticky, we have to support the case where post__not_in
+ * was already specified.
+ */
+ $args['post__not_in'] = array_merge( $args['post__not_in'], $sticky_posts );
+ }
+ }
+
+ $args = $this->prepare_tax_query( $args, $request );
+
+ if ( ! empty( $request['format'] ) ) {
+ $formats = $request['format'];
+ $tax_query = array( 'relation' => 'OR' );
+
+ // The default post format, 'standard', is not stored in the database.
+ // If 'standard' is part of the request, the query needs to exclude all post items that
+ // have a format assigned.
+ if ( in_array( 'standard', $formats, true ) ) {
+ $tax_query[] = array(
+ 'taxonomy' => 'post_format',
+ 'field' => 'slug',
+ 'terms' => array(),
+ 'operator' => 'NOT EXISTS',
+ );
+ // Remove the standard format, since it cannot be queried.
+ unset( $formats[ array_search( 'standard', $formats, true ) ] );
+ }
+
+ // Add any remaining formats to the tax query.
+ if ( ! empty( $formats ) ) {
+ // Add the post-format- prefix.
+ $terms = array_map(
+ static function ( $format ) {
+ return 'post-format-' . $format;
+ },
+ $formats
+ );
+
+ $tax_query[] = array(
+ 'taxonomy' => 'post_format',
+ 'field' => 'slug',
+ 'terms' => $terms,
+ 'operator' => 'IN',
+ );
+ }
+
+ // Enable filtering by both post formats and other taxonomies by combining them with AND.
+ if ( isset( $args['tax_query'] ) ) {
+ $args['tax_query'][] = array(
+ 'relation' => 'AND',
+ $tax_query,
+ );
+ } else {
+ $args['tax_query'] = $tax_query;
+ }
+ }
+
+ // Force the post_type argument, since it's not a user input variable.
+ $args['post_type'] = $this->post_type;
+
+ /**
+ * Filters WP_Query arguments when querying posts via the REST API.
+ *
+ * The dynamic portion of the hook name, `$this->post_type`, refers to the post type slug.
+ *
+ * Possible hook names include:
+ *
+ * - `rest_post_query`
+ * - `rest_page_query`
+ * - `rest_attachment_query`
+ *
+ * Enables adding extra arguments or setting defaults for a post collection request.
+ *
+ * @since 4.7.0
+ * @since 5.7.0 Moved after the `tax_query` query arg is generated.
+ *
+ * @link https://developer.wordpress.org/reference/classes/wp_query/
+ *
+ * @param array $args Array of arguments for WP_Query.
+ * @param WP_REST_Request $request The REST API request.
+ */
+ $args = apply_filters( "rest_{$this->post_type}_query", $args, $request );
+ $query_args = $this->prepare_items_query( $args, $request );
+
+ $posts_query = new WP_Query();
+ $query_result = $posts_query->query( $query_args );
+
+ // Allow access to all password protected posts if the context is edit.
+ if ( 'edit' === $request['context'] ) {
+ add_filter( 'post_password_required', array( $this, 'check_password_required' ), 10, 2 );
+ }
+
+ $posts = array();
+
+ update_post_author_caches( $query_result );
+ update_post_parent_caches( $query_result );
+
+ if ( post_type_supports( $this->post_type, 'thumbnail' ) ) {
+ update_post_thumbnail_cache( $posts_query );
+ }
+
+ foreach ( $query_result as $post ) {
+ if ( ! $this->check_read_permission( $post ) ) {
+ continue;
+ }
+
+ $data = $this->prepare_item_for_response( $post, $request );
+ $posts[] = $this->prepare_response_for_collection( $data );
+ }
+
+ // Reset filter.
+ if ( 'edit' === $request['context'] ) {
+ remove_filter( 'post_password_required', array( $this, 'check_password_required' ) );
+ }
+
+ $page = (int) $query_args['paged'];
+ $total_posts = $posts_query->found_posts;
+
+ if ( $total_posts < 1 && $page > 1 ) {
+ // Out-of-bounds, run the query again without LIMIT for total count.
+ unset( $query_args['paged'] );
+
+ $count_query = new WP_Query();
+ $count_query->query( $query_args );
+ $total_posts = $count_query->found_posts;
+ }
+
+ $max_pages = (int) ceil( $total_posts / (int) $posts_query->query_vars['posts_per_page'] );
+
+ if ( $page > $max_pages && $total_posts > 0 ) {
+ return new WP_Error(
+ 'rest_post_invalid_page_number',
+ __( 'The page number requested is larger than the number of pages available.' ),
+ array( 'status' => 400 )
+ );
+ }
+
+ $response = rest_ensure_response( $posts );
+
+ $response->header( 'X-WP-Total', (int) $total_posts );
+ $response->header( 'X-WP-TotalPages', (int) $max_pages );
+
+ $request_params = $request->get_query_params();
+ $collection_url = rest_url( rest_get_route_for_post_type_items( $this->post_type ) );
+ $base = add_query_arg( urlencode_deep( $request_params ), $collection_url );
+
+ if ( $page > 1 ) {
+ $prev_page = $page - 1;
+
+ if ( $prev_page > $max_pages ) {
+ $prev_page = $max_pages;
+ }
+
+ $prev_link = add_query_arg( 'page', $prev_page, $base );
+ $response->link_header( 'prev', $prev_link );
+ }
+ if ( $max_pages > $page ) {
+ $next_page = $page + 1;
+ $next_link = add_query_arg( 'page', $next_page, $base );
+
+ $response->link_header( 'next', $next_link );
+ }
+
+ return $response;
+ }
+
+ /**
+ * Retrieves the query params for the posts collection.
+ *
+ * @since 4.7.0
+ * @since 5.4.0 The `tax_relation` query parameter was added.
+ * @since 5.7.0 The `modified_after` and `modified_before` query parameters were added.
+ * @since 6.7.0 The `format` query parameter was added.
+ *
+ * @return array Collection parameters.
+ */
+ public function get_collection_params() {
+ $query_params = parent::get_collection_params();
+
+ $query_params['context']['default'] = 'view';
+
+ $query_params['after'] = array(
+ 'description' => __( 'Limit response to posts published after a given ISO8601 compliant date.' ),
+ 'type' => 'string',
+ 'format' => 'date-time',
+ );
+
+ $query_params['modified_after'] = array(
+ 'description' => __( 'Limit response to posts modified after a given ISO8601 compliant date.' ),
+ 'type' => 'string',
+ 'format' => 'date-time',
+ );
+
+ if ( post_type_supports( $this->post_type, 'author' ) ) {
+ $query_params['author'] = array(
+ 'description' => __( 'Limit result set to posts assigned to specific authors.' ),
+ 'type' => 'array',
+ 'items' => array(
+ 'type' => 'integer',
+ ),
+ 'default' => array(),
+ );
+ $query_params['author_exclude'] = array(
+ 'description' => __( 'Ensure result set excludes posts assigned to specific authors.' ),
+ 'type' => 'array',
+ 'items' => array(
+ 'type' => 'integer',
+ ),
+ 'default' => array(),
+ );
+ }
+
+ $query_params['before'] = array(
+ 'description' => __( 'Limit response to posts published before a given ISO8601 compliant date.' ),
+ 'type' => 'string',
+ 'format' => 'date-time',
+ );
+
+ $query_params['modified_before'] = array(
+ 'description' => __( 'Limit response to posts modified before a given ISO8601 compliant date.' ),
+ 'type' => 'string',
+ 'format' => 'date-time',
+ );
+
+ $query_params['exclude'] = array(
+ 'description' => __( 'Ensure result set excludes specific IDs.' ),
+ 'type' => 'array',
+ 'items' => array(
+ 'type' => 'integer',
+ ),
+ 'default' => array(),
+ );
+
+ $query_params['include'] = array(
+ 'description' => __( 'Limit result set to specific IDs.' ),
+ 'type' => 'array',
+ 'items' => array(
+ 'type' => 'integer',
+ ),
+ 'default' => array(),
+ );
+
+ if ( 'page' === $this->post_type || post_type_supports( $this->post_type, 'page-attributes' ) ) {
+ $query_params['menu_order'] = array(
+ 'description' => __( 'Limit result set to posts with a specific menu_order value.' ),
+ 'type' => 'integer',
+ );
+ }
+
+ $query_params['offset'] = array(
+ 'description' => __( 'Offset the result set by a specific number of items.' ),
+ 'type' => 'integer',
+ );
+
+ $query_params['order'] = array(
+ 'description' => __( 'Order sort attribute ascending or descending.' ),
+ 'type' => 'string',
+ 'default' => 'desc',
+ 'enum' => array( 'asc', 'desc' ),
+ );
+
+ $query_params['orderby'] = array(
+ 'description' => __( 'Sort collection by post attribute.' ),
+ 'type' => 'string',
+ 'default' => 'date',
+ 'enum' => array(
+ 'author',
+ 'date',
+ 'id',
+ 'include',
+ 'modified',
+ 'parent',
+ 'relevance',
+ 'slug',
+ 'include_slugs',
+ 'title',
+ ),
+ );
+
+ if ( 'page' === $this->post_type || post_type_supports( $this->post_type, 'page-attributes' ) ) {
+ $query_params['orderby']['enum'][] = 'menu_order';
+ }
+
+ $post_type = get_post_type_object( $this->post_type );
+
+ if ( $post_type->hierarchical || 'attachment' === $this->post_type ) {
+ $query_params['parent'] = array(
+ 'description' => __( 'Limit result set to items with particular parent IDs.' ),
+ 'type' => 'array',
+ 'items' => array(
+ 'type' => 'integer',
+ ),
+ 'default' => array(),
+ );
+ $query_params['parent_exclude'] = array(
+ 'description' => __( 'Limit result set to all items except those of a particular parent ID.' ),
+ 'type' => 'array',
+ 'items' => array(
+ 'type' => 'integer',
+ ),
+ 'default' => array(),
+ );
+ }
+
+ $query_params['search_columns'] = array(
+ 'default' => array(),
+ 'description' => __( 'Array of column names to be searched.' ),
+ 'type' => 'array',
+ 'items' => array(
+ 'enum' => array( 'post_title', 'post_content', 'post_excerpt' ),
+ 'type' => 'string',
+ ),
+ );
+
+ $query_params['slug'] = array(
+ 'description' => __( 'Limit result set to posts with one or more specific slugs.' ),
+ 'type' => 'array',
+ 'items' => array(
+ 'type' => 'string',
+ ),
+ );
+
+ $query_params['status'] = array(
+ 'default' => 'publish',
+ 'description' => __( 'Limit result set to posts assigned one or more statuses.' ),
+ 'type' => 'array',
+ 'items' => array(
+ 'enum' => array_merge( array_keys( get_post_stati() ), array( 'any' ) ),
+ 'type' => 'string',
+ ),
+ 'sanitize_callback' => array( $this, 'sanitize_post_statuses' ),
+ );
+
+ $query_params = $this->prepare_taxonomy_limit_schema( $query_params );
+
+ if ( 'post' === $this->post_type ) {
+ $query_params['sticky'] = array(
+ 'description' => __( 'Limit result set to items that are sticky.' ),
+ 'type' => 'boolean',
+ );
+ }
+
+ if ( post_type_supports( $this->post_type, 'post-formats' ) ) {
+ $query_params['format'] = array(
+ 'description' => __( 'Limit result set to items assigned one or more given formats.' ),
+ 'type' => 'array',
+ 'uniqueItems' => true,
+ 'items' => array(
+ 'enum' => array_values( get_post_format_slugs() ),
+ 'type' => 'string',
+ ),
+ );
+ }
+
+ /**
+ * Filters collection parameters for the posts controller.
+ *
+ * The dynamic part of the filter `$this->post_type` refers to the post
+ * type slug for the controller.
+ *
+ * This filter registers the collection parameter, but does not map the
+ * collection parameter to an internal WP_Query parameter. Use the
+ * `rest_{$this->post_type}_query` filter to set WP_Query parameters.
+ *
+ * @since 4.7.0
+ *
+ * @param array $query_params JSON Schema-formatted collection parameters.
+ * @param WP_Post_Type $post_type Post type object.
+ */
+ return apply_filters( "rest_{$this->post_type}_collection_params", $query_params, $post_type );
+ }
+
+ /**
+ * Prepares the 'tax_query' for a collection of posts.
+ *
+ * @since 5.7.0
+ *
+ * @param array $args WP_Query arguments.
+ * @param WP_REST_Request $request Full details about the request.
+ * @return array Updated query arguments.
+ */
+ private function prepare_tax_query( array $args, WP_REST_Request $request ) {
+ $relation = $request['tax_relation'];
+
+ if ( $relation ) {
+ $args['tax_query'] = array( 'relation' => $relation );
+ }
+
+ $taxonomies = wp_list_filter(
+ get_object_taxonomies( $this->post_type, 'objects' ),
+ array( 'show_in_rest' => true )
+ );
+
+ foreach ( $taxonomies as $taxonomy ) {
+ $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name;
+
+ $tax_include = $request[ $base ];
+ $tax_exclude = $request[ $base . '_exclude' ];
+
+ if ( $tax_include ) {
+ $terms = array();
+ $include_children = false;
+ $operator = 'IN';
+
+ if ( rest_is_array( $tax_include ) ) {
+ $terms = $tax_include;
+ } elseif ( rest_is_object( $tax_include ) ) {
+ $terms = empty( $tax_include['terms'] ) ? array() : $tax_include['terms'];
+ $include_children = ! empty( $tax_include['include_children'] );
+
+ if ( isset( $tax_include['operator'] ) && 'AND' === $tax_include['operator'] ) {
+ $operator = 'AND';
+ }
+ }
+
+ if ( $terms ) {
+ $args['tax_query'][] = array(
+ 'taxonomy' => $taxonomy->name,
+ 'field' => 'term_id',
+ 'terms' => $terms,
+ 'include_children' => $include_children,
+ 'operator' => $operator,
+ );
+ }
+ }
+
+ if ( $tax_exclude ) {
+ $terms = array();
+ $include_children = false;
+
+ if ( rest_is_array( $tax_exclude ) ) {
+ $terms = $tax_exclude;
+ } elseif ( rest_is_object( $tax_exclude ) ) {
+ $terms = empty( $tax_exclude['terms'] ) ? array() : $tax_exclude['terms'];
+ $include_children = ! empty( $tax_exclude['include_children'] );
+ }
+
+ if ( $terms ) {
+ $args['tax_query'][] = array(
+ 'taxonomy' => $taxonomy->name,
+ 'field' => 'term_id',
+ 'terms' => $terms,
+ 'include_children' => $include_children,
+ 'operator' => 'NOT IN',
+ );
+ }
+ }
+ }
+
+ return $args;
+ }
+
+ /**
+ * Prepares the collection schema for including and excluding items by terms.
+ *
+ * @since 5.7.0
+ *
+ * @param array $query_params Collection schema.
+ * @return array Updated schema.
+ */
+ private function prepare_taxonomy_limit_schema( array $query_params ) {
+ $taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) );
+
+ if ( ! $taxonomies ) {
+ return $query_params;
+ }
+
+ $query_params['tax_relation'] = array(
+ 'description' => __( 'Limit result set based on relationship between multiple taxonomies.' ),
+ 'type' => 'string',
+ 'enum' => array( 'AND', 'OR' ),
+ );
+
+ $limit_schema = array(
+ 'type' => array( 'object', 'array' ),
+ 'oneOf' => array(
+ array(
+ 'title' => __( 'Term ID List' ),
+ 'description' => __( 'Match terms with the listed IDs.' ),
+ 'type' => 'array',
+ 'items' => array(
+ 'type' => 'integer',
+ ),
+ ),
+ array(
+ 'title' => __( 'Term ID Taxonomy Query' ),
+ 'description' => __( 'Perform an advanced term query.' ),
+ 'type' => 'object',
+ 'properties' => array(
+ 'terms' => array(
+ 'description' => __( 'Term IDs.' ),
+ 'type' => 'array',
+ 'items' => array(
+ 'type' => 'integer',
+ ),
+ 'default' => array(),
+ ),
+ 'include_children' => array(
+ 'description' => __( 'Whether to include child terms in the terms limiting the result set.' ),
+ 'type' => 'boolean',
+ 'default' => false,
+ ),
+ ),
+ 'additionalProperties' => false,
+ ),
+ ),
+ );
+
+ $include_schema = array_merge(
+ array(
+ /* translators: %s: Taxonomy name. */
+ 'description' => __( 'Limit result set to items with specific terms assigned in the %s taxonomy.' ),
+ ),
+ $limit_schema
+ );
+ // 'operator' is supported only for 'include' queries.
+ $include_schema['oneOf'][1]['properties']['operator'] = array(
+ 'description' => __( 'Whether items must be assigned all or any of the specified terms.' ),
+ 'type' => 'string',
+ 'enum' => array( 'AND', 'OR' ),
+ 'default' => 'OR',
+ );
+
+ $exclude_schema = array_merge(
+ array(
+ /* translators: %s: Taxonomy name. */
+ 'description' => __( 'Limit result set to items except those with specific terms assigned in the %s taxonomy.' ),
+ ),
+ $limit_schema
+ );
+
+ foreach ( $taxonomies as $taxonomy ) {
+ $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name;
+ $base_exclude = $base . '_exclude';
+
+ $query_params[ $base ] = $include_schema;
+ $query_params[ $base ]['description'] = sprintf( $query_params[ $base ]['description'], $base );
+
+ $query_params[ $base_exclude ] = $exclude_schema;
+ $query_params[ $base_exclude ]['description'] = sprintf( $query_params[ $base_exclude ]['description'], $base );
+
+ if ( ! $taxonomy->hierarchical ) {
+ unset( $query_params[ $base ]['oneOf'][1]['properties']['include_children'] );
+ unset( $query_params[ $base_exclude ]['oneOf'][1]['properties']['include_children'] );
+ }
+ }
+
+ return $query_params;
+ }
+}
diff --git a/lib/compat/wordpress-6.7/post-formats.php b/lib/compat/wordpress-6.7/post-formats.php
new file mode 100644
index 00000000000000..d3de5b83957e29
--- /dev/null
+++ b/lib/compat/wordpress-6.7/post-formats.php
@@ -0,0 +1,24 @@
+register( $name, $style_properties ) ) {
- $result = false;
- }
+ foreach ( $block_names as $name ) {
+ if ( ! WP_Block_Styles_Registry::get_instance()->register( $name, $style_properties ) ) {
+ $result = false;
}
-
- return $result;
}
+
+ return $result;
}
diff --git a/lib/experimental/script-modules.php b/lib/experimental/script-modules.php
index 5a14e1418ed6de..a113df02b9d758 100644
--- a/lib/experimental/script-modules.php
+++ b/lib/experimental/script-modules.php
@@ -200,3 +200,30 @@ function gutenberg_dequeue_module( $module_identifier ) {
_deprecated_function( __FUNCTION__, 'Gutenberg 17.6.0', 'wp_dequeue_script_module' );
wp_script_modules()->dequeue( $module_identifier );
}
+
+/**
+ * Registers Gutenberg Script Modules.
+ *
+ * @since 19.3
+ */
+function gutenberg_register_script_modules() {
+ // When in production, use the plugin's version as the default asset version;
+ // else (for development or test) default to use the current time.
+ $default_version = defined( 'GUTENBERG_VERSION' ) && ! SCRIPT_DEBUG ? GUTENBERG_VERSION : time();
+
+ wp_deregister_script_module( '@wordpress/a11y' );
+ wp_register_script_module(
+ '@wordpress/a11y',
+ gutenberg_url( 'build-module/a11y/index.min.js' ),
+ array(),
+ $default_version
+ );
+ add_filter(
+ 'script_module_data_@wordpress/a11y',
+ function ( $data ) {
+ $data['i18n'] = array( 'Notifications' => __( 'Notifications', 'default' ) );
+ return $data;
+ }
+ );
+}
+add_action( 'init', 'gutenberg_register_script_modules' );
diff --git a/lib/interactivity-api.php b/lib/interactivity-api.php
index 6f04a3ba8fc927..90535f1ebaa42f 100644
--- a/lib/interactivity-api.php
+++ b/lib/interactivity-api.php
@@ -16,14 +16,14 @@ function gutenberg_reregister_interactivity_script_modules() {
wp_register_script_module(
'@wordpress/interactivity',
- gutenberg_url( '/build/interactivity/' . ( SCRIPT_DEBUG ? 'debug.min.js' : 'index.min.js' ) ),
+ gutenberg_url( '/build-module/' . ( SCRIPT_DEBUG ? 'interactivity/debug.min.js' : 'interactivity/index.min.js' ) ),
array(),
$default_version
);
wp_register_script_module(
'@wordpress/interactivity-router',
- gutenberg_url( '/build/interactivity/router.min.js' ),
+ gutenberg_url( '/build-module/interactivity-router/index.min.js' ),
array( '@wordpress/interactivity' ),
$default_version
);
diff --git a/lib/load.php b/lib/load.php
index 6ac2bd61f1de49..c26160eba2b67d 100644
--- a/lib/load.php
+++ b/lib/load.php
@@ -41,6 +41,7 @@ function gutenberg_is_experiment_enabled( $name ) {
require __DIR__ . '/compat/wordpress-6.6/rest-api.php';
// WordPress 6.7 compat.
+ require __DIR__ . '/compat/wordpress-6.7/class-gutenberg-rest-posts-controller-6-7.php';
require __DIR__ . '/compat/wordpress-6.7/class-gutenberg-rest-templates-controller-6-7.php';
require __DIR__ . '/compat/wordpress-6.7/class-gutenberg-rest-server.php';
require __DIR__ . '/compat/wordpress-6.7/rest-api.php';
@@ -109,6 +110,7 @@ function gutenberg_is_experiment_enabled( $name ) {
require __DIR__ . '/compat/wordpress-6.7/script-modules.php';
require __DIR__ . '/compat/wordpress-6.7/class-wp-block-templates-registry.php';
require __DIR__ . '/compat/wordpress-6.7/compat.php';
+require __DIR__ . '/compat/wordpress-6.7/post-formats.php';
// Experimental features.
require __DIR__ . '/experimental/block-editor-settings-mobile.php';
diff --git a/lib/rest-api.php b/lib/rest-api.php
index ea87f424637048..ac020e243ec056 100644
--- a/lib/rest-api.php
+++ b/lib/rest-api.php
@@ -11,68 +11,30 @@
}
/**
- * Registers the Global Styles REST API routes.
+ * Overrides the REST controller for the `wp_global_styles` post type.
+ *
+ * @param array $args Array of arguments for registering a post type.
+ * See the register_post_type() function for accepted arguments.
+ * @param string $post_type Post type key.
+ *
+ * @return array Array of arguments for registering a post type.
*/
-function gutenberg_register_global_styles_endpoints() {
- $global_styles_controller = new WP_REST_Global_Styles_Controller_Gutenberg();
- $global_styles_controller->register_routes();
-}
-add_action( 'rest_api_init', 'gutenberg_register_global_styles_endpoints' );
+function gutenberg_override_global_styles_endpoint( array $args ): array {
+ $args['rest_controller_class'] = 'WP_REST_Global_Styles_Controller_Gutenberg';
+ $args['revisions_rest_controller_class'] = 'Gutenberg_REST_Global_Styles_Revisions_Controller_6_6';
+ $args['late_route_registration'] = true;
+ $args['show_in_rest'] = true;
+ $args['rest_base'] = 'global-styles';
-if ( ! function_exists( 'gutenberg_register_edit_site_export_controller_endpoints' ) ) {
- /**
- * Registers the Edit Site Export REST API routes.
- */
- function gutenberg_register_edit_site_export_controller_endpoints() {
- $edit_site_export_controller = new WP_REST_Edit_Site_Export_Controller_Gutenberg();
- $edit_site_export_controller->register_routes();
- }
+ return $args;
}
+add_filter( 'register_wp_global_styles_post_type_args', 'gutenberg_override_global_styles_endpoint', 10, 2 );
-add_action( 'rest_api_init', 'gutenberg_register_edit_site_export_controller_endpoints' );
-
-if ( ! function_exists( 'gutenberg_register_wp_rest_post_types_controller_fields' ) ) {
- /**
- * Adds `template` and `template_lock` fields to WP_REST_Post_Types_Controller class.
- */
- function gutenberg_register_wp_rest_post_types_controller_fields() {
- register_rest_field(
- 'type',
- 'template',
- array(
- 'get_callback' => function ( $item ) {
- $post_type = get_post_type_object( $item['slug'] );
- if ( ! empty( $post_type ) ) {
- return $post_type->template ?? array();
- }
- },
- 'schema' => array(
- 'type' => 'array',
- 'description' => __( 'The block template associated with the post type.', 'gutenberg' ),
- 'readonly' => true,
- 'context' => array( 'view', 'edit', 'embed' ),
- ),
- )
- );
- register_rest_field(
- 'type',
- 'template_lock',
- array(
- 'get_callback' => function ( $item ) {
- $post_type = get_post_type_object( $item['slug'] );
- if ( ! empty( $post_type ) ) {
- return ! empty( $post_type->template_lock ) ? $post_type->template_lock : false;
- }
- },
- 'schema' => array(
- 'type' => array( 'string', 'boolean' ),
- 'enum' => array( 'all', 'insert', 'contentOnly', false ),
- 'description' => __( 'The template_lock associated with the post type, or false if none.', 'gutenberg' ),
- 'readonly' => true,
- 'context' => array( 'view', 'edit', 'embed' ),
- ),
- )
- );
- }
+/**
+ * Registers the Edit Site Export REST API routes.
+ */
+function gutenberg_register_edit_site_export_controller_endpoints() {
+ $edit_site_export_controller = new WP_REST_Edit_Site_Export_Controller_Gutenberg();
+ $edit_site_export_controller->register_routes();
}
-add_action( 'rest_api_init', 'gutenberg_register_wp_rest_post_types_controller_fields' );
+add_action( 'rest_api_init', 'gutenberg_register_edit_site_export_controller_endpoints' );
diff --git a/package-lock.json b/package-lock.json
index 4ca6d143acd4be..0bf382361797d6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "gutenberg",
- "version": "19.2.0-rc.1",
+ "version": "19.2.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "gutenberg",
- "version": "19.2.0-rc.1",
+ "version": "19.2.0",
"hasInstallScript": true,
"license": "GPL-2.0-or-later",
"dependencies": {
@@ -47,6 +47,7 @@
"@wordpress/i18n": "file:packages/i18n",
"@wordpress/icons": "file:packages/icons",
"@wordpress/interactivity": "file:packages/interactivity",
+ "@wordpress/interactivity-router": "file:packages/interactivity-router",
"@wordpress/interface": "file:packages/interface",
"@wordpress/is-shallow-equal": "file:packages/is-shallow-equal",
"@wordpress/keyboard-shortcuts": "file:packages/keyboard-shortcuts",
@@ -244,9 +245,9 @@
"storybook-source-link": "2.0.9",
"strip-json-comments": "5.0.0",
"style-loader": "3.2.1",
+ "terser": "5.32.0",
"terser-webpack-plugin": "5.3.9",
"typescript": "5.5.3",
- "uglify-js": "3.13.7",
"uuid": "9.0.1",
"webdriverio": "8.16.20",
"webpack": "5.88.2",
@@ -4098,6 +4099,92 @@
"node": ">=0.1.90"
}
},
+ "node_modules/@csstools/css-parser-algorithms": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.1.tgz",
+ "integrity": "sha512-lSquqZCHxDfuTg/Sk2hiS0mcSFCEBuj49JfzPHJogDBT0mGCyY5A1AQzBWngitrp7i1/HAZpIgzF/VjhOEIJIg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@csstools/css-tokenizer": "^3.0.1"
+ }
+ },
+ "node_modules/@csstools/css-tokenizer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.1.tgz",
+ "integrity": "sha512-UBqaiu7kU0lfvaP982/o3khfXccVlHPWp0/vwwiIgDF0GmqqqxoiXC/6FCjlS9u92f7CoEz6nXKQnrn1kIAkOw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@csstools/media-query-list-parser": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-3.0.1.tgz",
+ "integrity": "sha512-HNo8gGD02kHmcbX6PvCoUuOQvn4szyB9ca63vZHKX5A81QytgDG4oxG4IaEfHTlEZSZ6MjPEMWIVU+zF2PZcgw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@csstools/css-parser-algorithms": "^3.0.1",
+ "@csstools/css-tokenizer": "^3.0.1"
+ }
+ },
+ "node_modules/@csstools/selector-specificity": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-4.0.0.tgz",
+ "integrity": "sha512-189nelqtPd8++phaHNwYovKZI0FOzH1vQEE3QhHHkNIGrg5fSs9CbYP3RvfEH5geztnIA9Jwq91wyOIwAW5JIQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/csstools"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/csstools"
+ }
+ ],
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "postcss-selector-parser": "^6.1.0"
+ }
+ },
"node_modules/@dabh/diagnostics": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz",
@@ -4118,6 +4205,16 @@
"node": ">=10.0.0"
}
},
+ "node_modules/@dual-bundle/import-meta-resolve": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz",
+ "integrity": "sha512-+nxncfwHM5SgAtrVzgpzJOI1ol0PkumhVo469KCf9lUi21IGcY90G98VuHm9VRrUypmAzawAHO9bs6hqeADaVg==",
+ "dev": true,
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/wooorm"
+ }
+ },
"node_modules/@egjs/hammerjs": {
"version": "2.0.17",
"resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz",
@@ -13363,6 +13460,34 @@
"url": "https://opencollective.com/storybook"
}
},
+ "node_modules/@stylistic/stylelint-plugin": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-3.0.1.tgz",
+ "integrity": "sha512-j3mH8HSw2Rob/KJFWZ627w3CQ8gQqVHtzCdPeEffUg5vOgpz4rgrR+Xw2kU0OQCDcdW8Y1nKfdXKKjM5Rn8X0g==",
+ "dev": true,
+ "dependencies": {
+ "@csstools/css-parser-algorithms": "^3.0.0",
+ "@csstools/css-tokenizer": "^3.0.0",
+ "@csstools/media-query-list-parser": "^3.0.0",
+ "is-plain-object": "^5.0.0",
+ "postcss-selector-parser": "^6.1.2",
+ "postcss-value-parser": "^4.2.0",
+ "style-search": "^0.1.0",
+ "stylelint": "^16.8.2"
+ },
+ "engines": {
+ "node": "^18.12 || >=20.9"
+ },
+ "peerDependencies": {
+ "stylelint": "^16.8.0"
+ }
+ },
+ "node_modules/@stylistic/stylelint-plugin/node_modules/postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+ "dev": true
+ },
"node_modules/@svgr/babel-plugin-add-jsx-attribute": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz",
@@ -21020,27 +21145,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/clone-regexp": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-2.2.0.tgz",
- "integrity": "sha512-beMpP7BOtTipFuW8hrJvREQ2DrRu3BE7by0ZpibtfBA+qfHYvMGTc2Yb1JMYPKg/JUw0CHYvpg796aNTSW9z7Q==",
- "dev": true,
- "dependencies": {
- "is-regexp": "^2.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/clone-regexp/node_modules/is-regexp": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-2.1.0.tgz",
- "integrity": "sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/clone-response": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz",
@@ -22653,6 +22757,15 @@
"postcss": "^8.0.9"
}
},
+ "node_modules/css-functions-list": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.2.tgz",
+ "integrity": "sha512-c+N0v6wbKVxTu5gOBBFkr9BEdBWaqqjQeiJ8QvSRIJOf+UxlJh930m8e6/WNeODIK0mYLFkoONrnj16i2EcvfQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=12 || >=16"
+ }
+ },
"node_modules/css-loader": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.2.0.tgz",
@@ -26048,18 +26161,6 @@
"node": ">= 8"
}
},
- "node_modules/execall": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/execall/-/execall-2.0.0.tgz",
- "integrity": "sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow==",
- "dev": true,
- "dependencies": {
- "clone-regexp": "^2.1.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/exit": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
@@ -26564,10 +26665,13 @@
}
},
"node_modules/fastest-levenshtein": {
- "version": "1.0.12",
- "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz",
- "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==",
- "dev": true
+ "version": "1.0.16",
+ "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
+ "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4.9.1"
+ }
},
"node_modules/fastq": {
"version": "1.6.0",
@@ -27058,9 +27162,9 @@
}
},
"node_modules/flatted": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.0.tgz",
- "integrity": "sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA==",
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz",
+ "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
"dev": true
},
"node_modules/flow-enums-runtime": {
@@ -28992,12 +29096,15 @@
}
},
"node_modules/html-tags": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz",
- "integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==",
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz",
+ "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==",
"dev": true,
"engines": {
"node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/html-webpack-plugin": {
@@ -29457,15 +29564,6 @@
"node": ">=4"
}
},
- "node_modules/import-lazy": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz",
- "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/import-local": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz",
@@ -32389,9 +32487,9 @@
}
},
"node_modules/keyv": {
- "version": "4.5.3",
- "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz",
- "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==",
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
"dev": true,
"dependencies": {
"json-buffer": "3.0.1"
@@ -32441,9 +32539,9 @@
}
},
"node_modules/known-css-properties": {
- "version": "0.24.0",
- "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.24.0.tgz",
- "integrity": "sha512-RTSoaUAfLvpR357vWzAz/50Q/BmHfmE6ETSWfutT0AJiw10e6CmcdYRQJlLRd95B53D0Y2aD1jSxD3V3ySF+PA==",
+ "version": "0.34.0",
+ "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.34.0.tgz",
+ "integrity": "sha512-tBECoUqNFbyAY4RrbqsBQqDFpGXAEbdD5QKr8kACx3+rnArmuuR22nKQWKazvp07N9yjTyDZaw/20UIH8tL9DQ==",
"dev": true
},
"node_modules/kuler": {
@@ -37967,12 +38065,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/normalize-selector": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/normalize-selector/-/normalize-selector-0.2.0.tgz",
- "integrity": "sha1-0LFF62kRicY6eNIB3E/bEpPvDAM=",
- "dev": true
- },
"node_modules/normalize-url": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
@@ -40996,9 +41088,9 @@
}
},
"node_modules/picocolors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
+ "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew=="
},
"node_modules/picomatch": {
"version": "2.3.1",
@@ -41821,31 +41913,67 @@
"dev": true
},
"node_modules/postcss-resolve-nested-selector": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz",
- "integrity": "sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw==",
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.6.tgz",
+ "integrity": "sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw==",
"dev": true
},
"node_modules/postcss-safe-parser": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz",
- "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.0.tgz",
+ "integrity": "sha512-ovehqRNVCpuFzbXoTb4qLtyzK3xn3t/CUBxOs8LsnQjQrShaB4lKiHoVqY8ANaC0hBMHq5QVWk77rwGklFUDrg==",
"dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
"engines": {
- "node": ">=12.0"
+ "node": ">=18.0"
},
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
+ "peerDependencies": {
+ "postcss": "^8.4.31"
+ }
+ },
+ "node_modules/postcss-scss": {
+ "version": "4.0.9",
+ "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz",
+ "integrity": "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss-scss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "engines": {
+ "node": ">=12.0"
},
"peerDependencies": {
- "postcss": "^8.3.3"
+ "postcss": "^8.4.29"
}
},
"node_modules/postcss-selector-parser": {
- "version": "6.0.13",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
- "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==",
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
+ "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
"dev": true,
"dependencies": {
"cssesc": "^3.0.0",
@@ -47313,128 +47441,135 @@
}
},
"node_modules/stylelint": {
- "version": "14.2.0",
- "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.2.0.tgz",
- "integrity": "sha512-i0DrmDXFNpDsWiwx6SPRs4/pyw4kvZgqpDGvsTslQMY7hpUl6r33aQvNSn6cnTg2wtZ9rreFElI7XAKpOWi1vQ==",
+ "version": "16.8.2",
+ "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.8.2.tgz",
+ "integrity": "sha512-fInKATippQhcSm7AB+T32GpI+626yohrg33GkFT/5jzliUw5qhlwZq2UQQwgl3HsHrf09oeARi0ZwgY/UWEv9A==",
"dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/stylelint"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/stylelint"
+ }
+ ],
"dependencies": {
+ "@csstools/css-parser-algorithms": "^3.0.0",
+ "@csstools/css-tokenizer": "^3.0.0",
+ "@csstools/media-query-list-parser": "^3.0.0",
+ "@csstools/selector-specificity": "^4.0.0",
+ "@dual-bundle/import-meta-resolve": "^4.1.0",
"balanced-match": "^2.0.0",
- "colord": "^2.9.2",
- "cosmiconfig": "^7.0.1",
- "debug": "^4.3.3",
- "execall": "^2.0.0",
- "fast-glob": "^3.2.7",
- "fastest-levenshtein": "^1.0.12",
- "file-entry-cache": "^6.0.1",
- "get-stdin": "^8.0.0",
+ "colord": "^2.9.3",
+ "cosmiconfig": "^9.0.0",
+ "css-functions-list": "^3.2.2",
+ "css-tree": "^2.3.1",
+ "debug": "^4.3.6",
+ "fast-glob": "^3.3.2",
+ "fastest-levenshtein": "^1.0.16",
+ "file-entry-cache": "^9.0.0",
"global-modules": "^2.0.0",
- "globby": "^11.0.4",
+ "globby": "^11.1.0",
"globjoin": "^0.1.4",
- "html-tags": "^3.1.0",
- "ignore": "^5.2.0",
- "import-lazy": "^4.0.0",
+ "html-tags": "^3.3.1",
+ "ignore": "^5.3.2",
"imurmurhash": "^0.1.4",
"is-plain-object": "^5.0.0",
- "known-css-properties": "^0.24.0",
+ "known-css-properties": "^0.34.0",
"mathml-tag-names": "^2.1.3",
- "meow": "^9.0.0",
- "micromatch": "^4.0.4",
+ "meow": "^13.2.0",
+ "micromatch": "^4.0.7",
"normalize-path": "^3.0.0",
- "normalize-selector": "^0.2.0",
- "picocolors": "^1.0.0",
- "postcss": "^8.3.11",
- "postcss-media-query-parser": "^0.2.3",
- "postcss-resolve-nested-selector": "^0.1.1",
- "postcss-safe-parser": "^6.0.0",
- "postcss-selector-parser": "^6.0.7",
- "postcss-value-parser": "^4.1.0",
+ "picocolors": "^1.0.1",
+ "postcss": "^8.4.41",
+ "postcss-resolve-nested-selector": "^0.1.6",
+ "postcss-safe-parser": "^7.0.0",
+ "postcss-selector-parser": "^6.1.2",
+ "postcss-value-parser": "^4.2.0",
"resolve-from": "^5.0.0",
- "specificity": "^0.4.1",
"string-width": "^4.2.3",
- "strip-ansi": "^6.0.1",
- "style-search": "^0.1.0",
+ "strip-ansi": "^7.1.0",
+ "supports-hyperlinks": "^3.0.0",
"svg-tags": "^1.0.0",
- "table": "^6.7.5",
- "v8-compile-cache": "^2.3.0",
- "write-file-atomic": "^3.0.3"
+ "table": "^6.8.2",
+ "write-file-atomic": "^5.0.1"
},
"bin": {
- "stylelint": "bin/stylelint.js"
+ "stylelint": "bin/stylelint.mjs"
},
"engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/stylelint"
+ "node": ">=18.12.0"
}
},
- "node_modules/stylelint-config-recommended": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-6.0.0.tgz",
- "integrity": "sha512-ZorSSdyMcxWpROYUvLEMm0vSZud2uB7tX1hzBZwvVY9SV/uly4AvvJPPhCcymZL3fcQhEQG5AELmrxWqtmzacw==",
- "dev": true,
- "peerDependencies": {
- "stylelint": "^14.0.0"
- }
+ "node_modules/stylelint/node_modules/argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
},
- "node_modules/stylelint-config-recommended-scss": {
- "version": "5.0.2",
- "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-5.0.2.tgz",
- "integrity": "sha512-b14BSZjcwW0hqbzm9b0S/ScN2+3CO3O4vcMNOw2KGf8lfVSwJ4p5TbNEXKwKl1+0FMtgRXZj6DqVUe/7nGnuBg==",
+ "node_modules/stylelint/node_modules/balanced-match": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz",
+ "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==",
+ "dev": true
+ },
+ "node_modules/stylelint/node_modules/cosmiconfig": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz",
+ "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==",
"dev": true,
"dependencies": {
- "postcss-scss": "^4.0.2",
- "stylelint-config-recommended": "^6.0.0",
- "stylelint-scss": "^4.0.0"
+ "env-paths": "^2.2.1",
+ "import-fresh": "^3.3.0",
+ "js-yaml": "^4.1.0",
+ "parse-json": "^5.2.0"
},
- "peerDependencies": {
- "stylelint": "^14.0.0"
- }
- },
- "node_modules/stylelint-config-recommended-scss/node_modules/postcss-scss": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.3.tgz",
- "integrity": "sha512-j4KxzWovfdHsyxwl1BxkUal/O4uirvHgdzMKS1aWJBAV0qh2qj5qAZqpeBfVUYGWv+4iK9Az7SPyZ4fyNju1uA==",
- "dev": true,
"engines": {
- "node": ">=12.0"
+ "node": ">=14"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
+ "url": "https://github.com/sponsors/d-fischer"
},
"peerDependencies": {
- "postcss": "^8.3.3"
+ "typescript": ">=4.9.5"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
}
},
- "node_modules/stylelint-scss": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-4.1.0.tgz",
- "integrity": "sha512-BNYTo7MMamhFOlcaAWp2dMpjg6hPyM/FFqfDIYzmYVLMmQJqc8lWRIiTqP4UX5bresj9Vo0dKC6odSh43VP2NA==",
+ "node_modules/stylelint/node_modules/css-tree": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
+ "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
"dev": true,
"dependencies": {
- "lodash": "^4.17.21",
- "postcss-media-query-parser": "^0.2.3",
- "postcss-resolve-nested-selector": "^0.1.1",
- "postcss-selector-parser": "^6.0.6",
- "postcss-value-parser": "^4.1.0"
+ "mdn-data": "2.0.30",
+ "source-map-js": "^1.0.1"
},
- "peerDependencies": {
- "stylelint": "^14.0.0"
+ "engines": {
+ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
}
},
- "node_modules/stylelint-scss/node_modules/postcss-value-parser": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
- "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
- "dev": true
- },
- "node_modules/stylelint/node_modules/balanced-match": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz",
- "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==",
- "dev": true
+ "node_modules/stylelint/node_modules/debug": {
+ "version": "4.3.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
+ "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
},
"node_modules/stylelint/node_modules/emoji-regex": {
"version": "8.0.0",
@@ -47442,16 +47577,75 @@
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
- "node_modules/stylelint/node_modules/get-stdin": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz",
- "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==",
+ "node_modules/stylelint/node_modules/fast-glob": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+ "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
"dev": true,
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.4"
+ },
"engines": {
- "node": ">=10"
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/stylelint/node_modules/file-entry-cache": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-9.0.0.tgz",
+ "integrity": "sha512-6MgEugi8p2tiUhqO7GnPsmbCCzj0YRCwwaTbpGRyKZesjRSzkqkAE9fPp7V2yMs5hwfgbQLgdvSSkGNg1s5Uvw==",
+ "dev": true,
+ "dependencies": {
+ "flat-cache": "^5.0.0"
},
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/stylelint/node_modules/flat-cache": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-5.0.0.tgz",
+ "integrity": "sha512-JrqFmyUl2PnPi1OvLyTVHnQvwQ0S+e6lGSwu8OkAZlSaNIZciTY2H/cOOROxsBA1m/LZNHDsqAgDZt6akWcjsQ==",
+ "dev": true,
+ "dependencies": {
+ "flatted": "^3.3.1",
+ "keyv": "^4.5.4"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/stylelint/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/stylelint/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/stylelint/node_modules/ignore": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
}
},
"node_modules/stylelint/node_modules/is-fullwidth-code-point": {
@@ -47463,45 +47657,68 @@
"node": ">=8"
}
},
- "node_modules/stylelint/node_modules/meow": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz",
- "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==",
+ "node_modules/stylelint/node_modules/js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"dependencies": {
- "@types/minimist": "^1.2.0",
- "camelcase-keys": "^6.2.2",
- "decamelize": "^1.2.0",
- "decamelize-keys": "^1.1.0",
- "hard-rejection": "^2.1.0",
- "minimist-options": "4.1.0",
- "normalize-package-data": "^3.0.0",
- "read-pkg-up": "^7.0.1",
- "redent": "^3.0.0",
- "trim-newlines": "^3.0.0",
- "type-fest": "^0.18.0",
- "yargs-parser": "^20.2.3"
+ "argparse": "^2.0.1"
},
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/stylelint/node_modules/mdn-data": {
+ "version": "2.0.30",
+ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
+ "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
+ "dev": true
+ },
+ "node_modules/stylelint/node_modules/meow": {
+ "version": "13.2.0",
+ "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz",
+ "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==",
+ "dev": true,
"engines": {
- "node": ">=10"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/stylelint/node_modules/normalize-package-data": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz",
- "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==",
+ "node_modules/stylelint/node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "node_modules/stylelint/node_modules/postcss": {
+ "version": "8.4.41",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz",
+ "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==",
"dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
"dependencies": {
- "hosted-git-info": "^4.0.1",
- "is-core-module": "^2.5.0",
- "semver": "^7.3.4",
- "validate-npm-package-license": "^3.0.1"
+ "nanoid": "^3.3.7",
+ "picocolors": "^1.0.1",
+ "source-map-js": "^1.2.0"
},
"engines": {
- "node": ">=10"
+ "node": "^10 || ^12 || >=14"
}
},
"node_modules/stylelint/node_modules/postcss-value-parser": {
@@ -47519,6 +47736,27 @@
"node": ">=8"
}
},
+ "node_modules/stylelint/node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "dev": true,
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/stylelint/node_modules/source-map-js": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
+ "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/stylelint/node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@@ -47533,28 +47771,84 @@
"node": ">=8"
}
},
- "node_modules/stylelint/node_modules/type-fest": {
- "version": "0.18.1",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz",
- "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==",
+ "node_modules/stylelint/node_modules/string-width/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
"engines": {
- "node": ">=10"
+ "node": ">=8"
+ }
+ },
+ "node_modules/stylelint/node_modules/strip-ansi": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+ "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
+ "node_modules/stylelint/node_modules/strip-ansi/node_modules/ansi-regex": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
+ "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/stylelint/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/stylelint/node_modules/supports-hyperlinks": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.1.0.tgz",
+ "integrity": "sha512-2rn0BZ+/f7puLOHZm1HOJfwBggfaHXUpPUSSG/SWM4TWp5KCfmNYwnC3hruy2rZlMnmWZ+QAGpZfchu3f3695A==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0",
+ "supports-color": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=14.18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/stylelint/node_modules/write-file-atomic": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
- "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz",
+ "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==",
"dev": true,
"dependencies": {
"imurmurhash": "^0.1.4",
- "is-typedarray": "^1.0.0",
- "signal-exit": "^3.0.2",
- "typedarray-to-buffer": "^3.1.5"
+ "signal-exit": "^4.0.1"
+ },
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
}
},
"node_modules/stylis": {
@@ -47747,9 +48041,9 @@
}
},
"node_modules/table": {
- "version": "6.8.0",
- "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz",
- "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==",
+ "version": "6.8.2",
+ "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz",
+ "integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==",
"dev": true,
"dependencies": {
"ajv": "^8.0.1",
@@ -48137,10 +48431,9 @@
}
},
"node_modules/terser": {
- "version": "5.31.2",
- "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.2.tgz",
- "integrity": "sha512-LGyRZVFm/QElZHy/CPr/O4eNZOZIzsrQ92y4v9UJe/pFJjypje2yI3C2FmPtvUEnhadlSbmG2nXtdcjHOjCfxw==",
- "license": "BSD-2-Clause",
+ "version": "5.32.0",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-5.32.0.tgz",
+ "integrity": "sha512-v3Gtw3IzpBJ0ugkxEX8U0W6+TnPKRRCWGh1jC/iM/e3Ki5+qvO1L1EAZ56bZasc64aXHwRHNIQEzm6//i5cemQ==",
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.8.2",
@@ -48973,6 +49266,7 @@
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.7.tgz",
"integrity": "sha512-1Psi2MmnZJbnEsgJJIlfnd7tFlJfitusmR7zDI8lXlFI0ACD4/Rm/xdrU8bh6zF0i74aiVoBtkRiFulkrmh3AA==",
"dev": true,
+ "optional": true,
"bin": {
"uglifyjs": "bin/uglifyjs"
},
@@ -53539,6 +53833,7 @@
"@wordpress/editor": "file:../editor",
"@wordpress/element": "file:../element",
"@wordpress/escape-html": "file:../escape-html",
+ "@wordpress/fields": "file:../fields",
"@wordpress/hooks": "file:../hooks",
"@wordpress/html-entities": "file:../html-entities",
"@wordpress/i18n": "file:../i18n",
@@ -53639,6 +53934,7 @@
"@wordpress/deprecated": "file:../deprecated",
"@wordpress/dom": "file:../dom",
"@wordpress/element": "file:../element",
+ "@wordpress/fields": "file:../fields",
"@wordpress/hooks": "file:../hooks",
"@wordpress/html-entities": "file:../html-entities",
"@wordpress/i18n": "file:../i18n",
@@ -53900,7 +54196,27 @@
"version": "0.0.1",
"license": "GPL-2.0-or-later",
"dependencies": {
- "@babel/runtime": "^7.16.0"
+ "@babel/runtime": "^7.16.0",
+ "@wordpress/blob": "file:../blob",
+ "@wordpress/blocks": "file:../blocks",
+ "@wordpress/components": "file:../components",
+ "@wordpress/compose": "file:../compose",
+ "@wordpress/core-data": "file:../core-data",
+ "@wordpress/data": "file:../data",
+ "@wordpress/dataviews": "file:../dataviews",
+ "@wordpress/element": "file:../element",
+ "@wordpress/hooks": "file:../hooks",
+ "@wordpress/html-entities": "file:../html-entities",
+ "@wordpress/i18n": "file:../i18n",
+ "@wordpress/icons": "file:../icons",
+ "@wordpress/notices": "file:../notices",
+ "@wordpress/patterns": "file:../patterns",
+ "@wordpress/primitives": "file:../primitives",
+ "@wordpress/private-apis": "file:../private-apis",
+ "@wordpress/url": "file:../url",
+ "@wordpress/warning": "file:../warning",
+ "change-case": "4.1.2",
+ "client-zip": "^2.4.5"
},
"engines": {
"node": ">=18.12.0",
@@ -54832,7 +55148,7 @@
"sass-loader": "^12.1.0",
"schema-utils": "^4.2.0",
"source-map-loader": "^3.0.0",
- "stylelint": "^14.2.0",
+ "stylelint": "^16.8.2",
"terser-webpack-plugin": "^5.3.9",
"url-loader": "^4.1.1",
"webpack": "^5.88.2",
@@ -55286,15 +55602,116 @@
"dev": true,
"license": "MIT",
"dependencies": {
- "stylelint-config-recommended": "^6.0.0",
- "stylelint-config-recommended-scss": "^5.0.2"
+ "@stylistic/stylelint-plugin": "^3.0.1",
+ "stylelint-config-recommended": "^14.0.1",
+ "stylelint-config-recommended-scss": "^14.1.0"
},
"engines": {
"node": ">=18.12.0",
"npm": ">=8.19.2"
},
"peerDependencies": {
- "stylelint": "^14.2"
+ "stylelint": "^16.8.2"
+ }
+ },
+ "packages/stylelint-config/node_modules/css-tree": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
+ "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
+ "dev": true,
+ "dependencies": {
+ "mdn-data": "2.0.30",
+ "source-map-js": "^1.0.1"
+ },
+ "engines": {
+ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
+ }
+ },
+ "packages/stylelint-config/node_modules/mdn-data": {
+ "version": "2.0.30",
+ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
+ "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
+ "dev": true
+ },
+ "packages/stylelint-config/node_modules/postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+ "dev": true
+ },
+ "packages/stylelint-config/node_modules/source-map-js": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
+ "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "packages/stylelint-config/node_modules/stylelint-config-recommended": {
+ "version": "14.0.1",
+ "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-14.0.1.tgz",
+ "integrity": "sha512-bLvc1WOz/14aPImu/cufKAZYfXs/A/owZfSMZ4N+16WGXLoX5lOir53M6odBxvhgmgdxCVnNySJmZKx73T93cg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/stylelint"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/stylelint"
+ }
+ ],
+ "engines": {
+ "node": ">=18.12.0"
+ },
+ "peerDependencies": {
+ "stylelint": "^16.1.0"
+ }
+ },
+ "packages/stylelint-config/node_modules/stylelint-config-recommended-scss": {
+ "version": "14.1.0",
+ "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-14.1.0.tgz",
+ "integrity": "sha512-bhaMhh1u5dQqSsf6ri2GVWWQW5iUjBYgcHkh7SgDDn92ijoItC/cfO/W+fpXshgTQWhwFkP1rVcewcv4jaftRg==",
+ "dev": true,
+ "dependencies": {
+ "postcss-scss": "^4.0.9",
+ "stylelint-config-recommended": "^14.0.1",
+ "stylelint-scss": "^6.4.0"
+ },
+ "engines": {
+ "node": ">=18.12.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.3.3",
+ "stylelint": "^16.6.1"
+ },
+ "peerDependenciesMeta": {
+ "postcss": {
+ "optional": true
+ }
+ }
+ },
+ "packages/stylelint-config/node_modules/stylelint-scss": {
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-6.5.1.tgz",
+ "integrity": "sha512-ZLqdqihm6uDYkrsOeD6YWb+stZI8Wn92kUNDhE4M+g9g1aCnRv0JlOrttFiAJJwaNzpdQgX3YJb5vDQXVuO9Ww==",
+ "dev": true,
+ "dependencies": {
+ "css-tree": "2.3.1",
+ "is-plain-object": "5.0.0",
+ "known-css-properties": "^0.34.0",
+ "postcss-media-query-parser": "^0.2.3",
+ "postcss-resolve-nested-selector": "^0.1.4",
+ "postcss-selector-parser": "^6.1.1",
+ "postcss-value-parser": "^4.2.0"
+ },
+ "engines": {
+ "node": ">=18.12.0"
+ },
+ "peerDependencies": {
+ "stylelint": "^16.0.2"
}
},
"packages/sync": {
@@ -58170,6 +58587,30 @@
"integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==",
"dev": true
},
+ "@csstools/css-parser-algorithms": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.1.tgz",
+ "integrity": "sha512-lSquqZCHxDfuTg/Sk2hiS0mcSFCEBuj49JfzPHJogDBT0mGCyY5A1AQzBWngitrp7i1/HAZpIgzF/VjhOEIJIg==",
+ "dev": true
+ },
+ "@csstools/css-tokenizer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.1.tgz",
+ "integrity": "sha512-UBqaiu7kU0lfvaP982/o3khfXccVlHPWp0/vwwiIgDF0GmqqqxoiXC/6FCjlS9u92f7CoEz6nXKQnrn1kIAkOw==",
+ "dev": true
+ },
+ "@csstools/media-query-list-parser": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-3.0.1.tgz",
+ "integrity": "sha512-HNo8gGD02kHmcbX6PvCoUuOQvn4szyB9ca63vZHKX5A81QytgDG4oxG4IaEfHTlEZSZ6MjPEMWIVU+zF2PZcgw==",
+ "dev": true
+ },
+ "@csstools/selector-specificity": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-4.0.0.tgz",
+ "integrity": "sha512-189nelqtPd8++phaHNwYovKZI0FOzH1vQEE3QhHHkNIGrg5fSs9CbYP3RvfEH5geztnIA9Jwq91wyOIwAW5JIQ==",
+ "dev": true
+ },
"@dabh/diagnostics": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz",
@@ -58187,6 +58628,12 @@
"integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==",
"dev": true
},
+ "@dual-bundle/import-meta-resolve": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz",
+ "integrity": "sha512-+nxncfwHM5SgAtrVzgpzJOI1ol0PkumhVo469KCf9lUi21IGcY90G98VuHm9VRrUypmAzawAHO9bs6hqeADaVg==",
+ "dev": true
+ },
"@egjs/hammerjs": {
"version": "2.0.17",
"resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz",
@@ -64754,6 +65201,30 @@
"file-system-cache": "2.3.0"
}
},
+ "@stylistic/stylelint-plugin": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@stylistic/stylelint-plugin/-/stylelint-plugin-3.0.1.tgz",
+ "integrity": "sha512-j3mH8HSw2Rob/KJFWZ627w3CQ8gQqVHtzCdPeEffUg5vOgpz4rgrR+Xw2kU0OQCDcdW8Y1nKfdXKKjM5Rn8X0g==",
+ "dev": true,
+ "requires": {
+ "@csstools/css-parser-algorithms": "^3.0.0",
+ "@csstools/css-tokenizer": "^3.0.0",
+ "@csstools/media-query-list-parser": "^3.0.0",
+ "is-plain-object": "^5.0.0",
+ "postcss-selector-parser": "^6.1.2",
+ "postcss-value-parser": "^4.2.0",
+ "style-search": "^0.1.0",
+ "stylelint": "^16.8.2"
+ },
+ "dependencies": {
+ "postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+ "dev": true
+ }
+ }
+ },
"@svgr/babel-plugin-add-jsx-attribute": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz",
@@ -68209,6 +68680,7 @@
"@wordpress/editor": "file:../editor",
"@wordpress/element": "file:../element",
"@wordpress/escape-html": "file:../escape-html",
+ "@wordpress/fields": "file:../fields",
"@wordpress/hooks": "file:../hooks",
"@wordpress/html-entities": "file:../html-entities",
"@wordpress/i18n": "file:../i18n",
@@ -68289,6 +68761,7 @@
"@wordpress/deprecated": "file:../deprecated",
"@wordpress/dom": "file:../dom",
"@wordpress/element": "file:../element",
+ "@wordpress/fields": "file:../fields",
"@wordpress/hooks": "file:../hooks",
"@wordpress/html-entities": "file:../html-entities",
"@wordpress/i18n": "file:../i18n",
@@ -68470,7 +68943,27 @@
"@wordpress/fields": {
"version": "file:packages/fields",
"requires": {
- "@babel/runtime": "^7.16.0"
+ "@babel/runtime": "^7.16.0",
+ "@wordpress/blob": "file:../blob",
+ "@wordpress/blocks": "file:../blocks",
+ "@wordpress/components": "file:../components",
+ "@wordpress/compose": "file:../compose",
+ "@wordpress/core-data": "file:../core-data",
+ "@wordpress/data": "file:../data",
+ "@wordpress/dataviews": "file:../dataviews",
+ "@wordpress/element": "file:../element",
+ "@wordpress/hooks": "file:../hooks",
+ "@wordpress/html-entities": "file:../html-entities",
+ "@wordpress/i18n": "file:../i18n",
+ "@wordpress/icons": "file:../icons",
+ "@wordpress/notices": "file:../notices",
+ "@wordpress/patterns": "file:../patterns",
+ "@wordpress/primitives": "file:../primitives",
+ "@wordpress/private-apis": "file:../private-apis",
+ "@wordpress/url": "file:../url",
+ "@wordpress/warning": "file:../warning",
+ "change-case": "4.1.2",
+ "client-zip": "^2.4.5"
}
},
"@wordpress/format-library": {
@@ -69016,7 +69509,7 @@
"sass-loader": "^12.1.0",
"schema-utils": "^4.2.0",
"source-map-loader": "^3.0.0",
- "stylelint": "^14.2.0",
+ "stylelint": "^16.8.2",
"terser-webpack-plugin": "^5.3.9",
"url-loader": "^4.1.1",
"webpack": "^5.88.2",
@@ -69330,8 +69823,71 @@
"@wordpress/stylelint-config": {
"version": "file:packages/stylelint-config",
"requires": {
- "stylelint-config-recommended": "^6.0.0",
- "stylelint-config-recommended-scss": "^5.0.2"
+ "@stylistic/stylelint-plugin": "^3.0.1",
+ "stylelint-config-recommended": "^14.0.1",
+ "stylelint-config-recommended-scss": "^14.1.0"
+ },
+ "dependencies": {
+ "css-tree": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
+ "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
+ "dev": true,
+ "requires": {
+ "mdn-data": "2.0.30",
+ "source-map-js": "^1.0.1"
+ }
+ },
+ "mdn-data": {
+ "version": "2.0.30",
+ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
+ "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
+ "dev": true
+ },
+ "postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+ "dev": true
+ },
+ "source-map-js": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
+ "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
+ "dev": true
+ },
+ "stylelint-config-recommended": {
+ "version": "14.0.1",
+ "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-14.0.1.tgz",
+ "integrity": "sha512-bLvc1WOz/14aPImu/cufKAZYfXs/A/owZfSMZ4N+16WGXLoX5lOir53M6odBxvhgmgdxCVnNySJmZKx73T93cg==",
+ "dev": true
+ },
+ "stylelint-config-recommended-scss": {
+ "version": "14.1.0",
+ "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-14.1.0.tgz",
+ "integrity": "sha512-bhaMhh1u5dQqSsf6ri2GVWWQW5iUjBYgcHkh7SgDDn92ijoItC/cfO/W+fpXshgTQWhwFkP1rVcewcv4jaftRg==",
+ "dev": true,
+ "requires": {
+ "postcss-scss": "^4.0.9",
+ "stylelint-config-recommended": "^14.0.1",
+ "stylelint-scss": "^6.4.0"
+ }
+ },
+ "stylelint-scss": {
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-6.5.1.tgz",
+ "integrity": "sha512-ZLqdqihm6uDYkrsOeD6YWb+stZI8Wn92kUNDhE4M+g9g1aCnRv0JlOrttFiAJJwaNzpdQgX3YJb5vDQXVuO9Ww==",
+ "dev": true,
+ "requires": {
+ "css-tree": "2.3.1",
+ "is-plain-object": "5.0.0",
+ "known-css-properties": "^0.34.0",
+ "postcss-media-query-parser": "^0.2.3",
+ "postcss-resolve-nested-selector": "^0.1.4",
+ "postcss-selector-parser": "^6.1.1",
+ "postcss-value-parser": "^4.2.0"
+ }
+ }
}
},
"@wordpress/sync": {
@@ -72327,23 +72883,6 @@
}
}
},
- "clone-regexp": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-2.2.0.tgz",
- "integrity": "sha512-beMpP7BOtTipFuW8hrJvREQ2DrRu3BE7by0ZpibtfBA+qfHYvMGTc2Yb1JMYPKg/JUw0CHYvpg796aNTSW9z7Q==",
- "dev": true,
- "requires": {
- "is-regexp": "^2.0.0"
- },
- "dependencies": {
- "is-regexp": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-2.1.0.tgz",
- "integrity": "sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA==",
- "dev": true
- }
- }
- },
"clone-response": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz",
@@ -73620,6 +74159,12 @@
"integrity": "sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==",
"dev": true
},
+ "css-functions-list": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.2.tgz",
+ "integrity": "sha512-c+N0v6wbKVxTu5gOBBFkr9BEdBWaqqjQeiJ8QvSRIJOf+UxlJh930m8e6/WNeODIK0mYLFkoONrnj16i2EcvfQ==",
+ "dev": true
+ },
"css-loader": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.2.0.tgz",
@@ -76155,15 +76700,6 @@
}
}
},
- "execall": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/execall/-/execall-2.0.0.tgz",
- "integrity": "sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow==",
- "dev": true,
- "requires": {
- "clone-regexp": "^2.1.0"
- }
- },
"exit": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
@@ -76576,9 +77112,9 @@
}
},
"fastest-levenshtein": {
- "version": "1.0.12",
- "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz",
- "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==",
+ "version": "1.0.16",
+ "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
+ "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==",
"dev": true
},
"fastq": {
@@ -76967,9 +77503,9 @@
}
},
"flatted": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.0.tgz",
- "integrity": "sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA==",
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz",
+ "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
"dev": true
},
"flow-enums-runtime": {
@@ -78433,9 +78969,9 @@
}
},
"html-tags": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz",
- "integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==",
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz",
+ "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==",
"dev": true
},
"html-webpack-plugin": {
@@ -78757,12 +79293,6 @@
}
}
},
- "import-lazy": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz",
- "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==",
- "dev": true
- },
"import-local": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz",
@@ -80916,9 +81446,9 @@
}
},
"keyv": {
- "version": "4.5.3",
- "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz",
- "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==",
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
"dev": true,
"requires": {
"json-buffer": "3.0.1"
@@ -80956,9 +81486,9 @@
"dev": true
},
"known-css-properties": {
- "version": "0.24.0",
- "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.24.0.tgz",
- "integrity": "sha512-RTSoaUAfLvpR357vWzAz/50Q/BmHfmE6ETSWfutT0AJiw10e6CmcdYRQJlLRd95B53D0Y2aD1jSxD3V3ySF+PA==",
+ "version": "0.34.0",
+ "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.34.0.tgz",
+ "integrity": "sha512-tBECoUqNFbyAY4RrbqsBQqDFpGXAEbdD5QKr8kACx3+rnArmuuR22nKQWKazvp07N9yjTyDZaw/20UIH8tL9DQ==",
"dev": true
},
"kuler": {
@@ -85266,12 +85796,6 @@
"integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
"dev": true
},
- "normalize-selector": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/normalize-selector/-/normalize-selector-0.2.0.tgz",
- "integrity": "sha1-0LFF62kRicY6eNIB3E/bEpPvDAM=",
- "dev": true
- },
"normalize-url": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz",
@@ -87529,9 +88053,9 @@
"integrity": "sha512-SO+NP5argMoJVCWcYiOofPUeEWDIM47FNCBJtp6uJ8PpjtBcudYJTzCbCMit5dzmfSLCoijzEwIXOqPqD45xQg=="
},
"picocolors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
+ "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew=="
},
"picomatch": {
"version": "2.3.1",
@@ -88121,21 +88645,27 @@
}
},
"postcss-resolve-nested-selector": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz",
- "integrity": "sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw==",
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.6.tgz",
+ "integrity": "sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw==",
"dev": true
},
"postcss-safe-parser": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz",
- "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.0.tgz",
+ "integrity": "sha512-ovehqRNVCpuFzbXoTb4qLtyzK3xn3t/CUBxOs8LsnQjQrShaB4lKiHoVqY8ANaC0hBMHq5QVWk77rwGklFUDrg==",
+ "dev": true
+ },
+ "postcss-scss": {
+ "version": "4.0.9",
+ "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz",
+ "integrity": "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==",
"dev": true
},
"postcss-selector-parser": {
- "version": "6.0.13",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
- "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==",
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
+ "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
"dev": true,
"requires": {
"cssesc": "^3.0.0",
@@ -92311,68 +92841,152 @@
}
},
"stylelint": {
- "version": "14.2.0",
- "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.2.0.tgz",
- "integrity": "sha512-i0DrmDXFNpDsWiwx6SPRs4/pyw4kvZgqpDGvsTslQMY7hpUl6r33aQvNSn6cnTg2wtZ9rreFElI7XAKpOWi1vQ==",
+ "version": "16.8.2",
+ "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.8.2.tgz",
+ "integrity": "sha512-fInKATippQhcSm7AB+T32GpI+626yohrg33GkFT/5jzliUw5qhlwZq2UQQwgl3HsHrf09oeARi0ZwgY/UWEv9A==",
"dev": true,
"requires": {
+ "@csstools/css-parser-algorithms": "^3.0.0",
+ "@csstools/css-tokenizer": "^3.0.0",
+ "@csstools/media-query-list-parser": "^3.0.0",
+ "@csstools/selector-specificity": "^4.0.0",
+ "@dual-bundle/import-meta-resolve": "^4.1.0",
"balanced-match": "^2.0.0",
- "colord": "^2.9.2",
- "cosmiconfig": "^7.0.1",
- "debug": "^4.3.3",
- "execall": "^2.0.0",
- "fast-glob": "^3.2.7",
- "fastest-levenshtein": "^1.0.12",
- "file-entry-cache": "^6.0.1",
- "get-stdin": "^8.0.0",
+ "colord": "^2.9.3",
+ "cosmiconfig": "^9.0.0",
+ "css-functions-list": "^3.2.2",
+ "css-tree": "^2.3.1",
+ "debug": "^4.3.6",
+ "fast-glob": "^3.3.2",
+ "fastest-levenshtein": "^1.0.16",
+ "file-entry-cache": "^9.0.0",
"global-modules": "^2.0.0",
- "globby": "^11.0.4",
+ "globby": "^11.1.0",
"globjoin": "^0.1.4",
- "html-tags": "^3.1.0",
- "ignore": "^5.2.0",
- "import-lazy": "^4.0.0",
+ "html-tags": "^3.3.1",
+ "ignore": "^5.3.2",
"imurmurhash": "^0.1.4",
"is-plain-object": "^5.0.0",
- "known-css-properties": "^0.24.0",
+ "known-css-properties": "^0.34.0",
"mathml-tag-names": "^2.1.3",
- "meow": "^9.0.0",
- "micromatch": "^4.0.4",
+ "meow": "^13.2.0",
+ "micromatch": "^4.0.7",
"normalize-path": "^3.0.0",
- "normalize-selector": "^0.2.0",
- "picocolors": "^1.0.0",
- "postcss": "^8.3.11",
- "postcss-media-query-parser": "^0.2.3",
- "postcss-resolve-nested-selector": "^0.1.1",
- "postcss-safe-parser": "^6.0.0",
- "postcss-selector-parser": "^6.0.7",
- "postcss-value-parser": "^4.1.0",
+ "picocolors": "^1.0.1",
+ "postcss": "^8.4.41",
+ "postcss-resolve-nested-selector": "^0.1.6",
+ "postcss-safe-parser": "^7.0.0",
+ "postcss-selector-parser": "^6.1.2",
+ "postcss-value-parser": "^4.2.0",
"resolve-from": "^5.0.0",
- "specificity": "^0.4.1",
"string-width": "^4.2.3",
- "strip-ansi": "^6.0.1",
- "style-search": "^0.1.0",
+ "strip-ansi": "^7.1.0",
+ "supports-hyperlinks": "^3.0.0",
"svg-tags": "^1.0.0",
- "table": "^6.7.5",
- "v8-compile-cache": "^2.3.0",
- "write-file-atomic": "^3.0.3"
+ "table": "^6.8.2",
+ "write-file-atomic": "^5.0.1"
},
"dependencies": {
+ "argparse": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
+ },
"balanced-match": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz",
"integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==",
"dev": true
},
+ "cosmiconfig": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz",
+ "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==",
+ "dev": true,
+ "requires": {
+ "env-paths": "^2.2.1",
+ "import-fresh": "^3.3.0",
+ "js-yaml": "^4.1.0",
+ "parse-json": "^5.2.0"
+ }
+ },
+ "css-tree": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
+ "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
+ "dev": true,
+ "requires": {
+ "mdn-data": "2.0.30",
+ "source-map-js": "^1.0.1"
+ }
+ },
+ "debug": {
+ "version": "4.3.6",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz",
+ "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==",
+ "dev": true,
+ "requires": {
+ "ms": "2.1.2"
+ }
+ },
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
- "get-stdin": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz",
- "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==",
+ "fast-glob": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+ "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
+ "dev": true,
+ "requires": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.4"
+ }
+ },
+ "file-entry-cache": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-9.0.0.tgz",
+ "integrity": "sha512-6MgEugi8p2tiUhqO7GnPsmbCCzj0YRCwwaTbpGRyKZesjRSzkqkAE9fPp7V2yMs5hwfgbQLgdvSSkGNg1s5Uvw==",
+ "dev": true,
+ "requires": {
+ "flat-cache": "^5.0.0"
+ }
+ },
+ "flat-cache": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-5.0.0.tgz",
+ "integrity": "sha512-JrqFmyUl2PnPi1OvLyTVHnQvwQ0S+e6lGSwu8OkAZlSaNIZciTY2H/cOOROxsBA1m/LZNHDsqAgDZt6akWcjsQ==",
+ "dev": true,
+ "requires": {
+ "flatted": "^3.3.1",
+ "keyv": "^4.5.4"
+ }
+ },
+ "glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "requires": {
+ "is-glob": "^4.0.1"
+ }
+ },
+ "has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
+ },
+ "ignore": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+ "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
"dev": true
},
"is-fullwidth-code-point": {
@@ -92381,36 +92995,42 @@
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true
},
- "meow": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz",
- "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==",
+ "js-yaml": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
"requires": {
- "@types/minimist": "^1.2.0",
- "camelcase-keys": "^6.2.2",
- "decamelize": "^1.2.0",
- "decamelize-keys": "^1.1.0",
- "hard-rejection": "^2.1.0",
- "minimist-options": "4.1.0",
- "normalize-package-data": "^3.0.0",
- "read-pkg-up": "^7.0.1",
- "redent": "^3.0.0",
- "trim-newlines": "^3.0.0",
- "type-fest": "^0.18.0",
- "yargs-parser": "^20.2.3"
+ "argparse": "^2.0.1"
}
},
- "normalize-package-data": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz",
- "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==",
+ "mdn-data": {
+ "version": "2.0.30",
+ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
+ "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
+ "dev": true
+ },
+ "meow": {
+ "version": "13.2.0",
+ "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz",
+ "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==",
+ "dev": true
+ },
+ "ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "postcss": {
+ "version": "8.4.41",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.41.tgz",
+ "integrity": "sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==",
"dev": true,
"requires": {
- "hosted-git-info": "^4.0.1",
- "is-core-module": "^2.5.0",
- "semver": "^7.3.4",
- "validate-npm-package-license": "^3.0.1"
+ "nanoid": "^3.3.7",
+ "picocolors": "^1.0.1",
+ "source-map-js": "^1.2.0"
}
},
"postcss-value-parser": {
@@ -92425,6 +93045,18 @@
"integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
"dev": true
},
+ "signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "dev": true
+ },
+ "source-map-js": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
+ "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
+ "dev": true
+ },
"string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
@@ -92434,74 +93066,67 @@
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
+ },
+ "dependencies": {
+ "strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^5.0.1"
+ }
+ }
}
},
- "type-fest": {
- "version": "0.18.1",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz",
- "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==",
- "dev": true
+ "strip-ansi": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+ "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^6.0.1"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
+ "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+ "dev": true
+ }
+ }
+ },
+ "supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ },
+ "supports-hyperlinks": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.1.0.tgz",
+ "integrity": "sha512-2rn0BZ+/f7puLOHZm1HOJfwBggfaHXUpPUSSG/SWM4TWp5KCfmNYwnC3hruy2rZlMnmWZ+QAGpZfchu3f3695A==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^4.0.0",
+ "supports-color": "^7.0.0"
+ }
},
"write-file-atomic": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
- "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz",
+ "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==",
"dev": true,
"requires": {
"imurmurhash": "^0.1.4",
- "is-typedarray": "^1.0.0",
- "signal-exit": "^3.0.2",
- "typedarray-to-buffer": "^3.1.5"
+ "signal-exit": "^4.0.1"
}
}
}
},
- "stylelint-config-recommended": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-6.0.0.tgz",
- "integrity": "sha512-ZorSSdyMcxWpROYUvLEMm0vSZud2uB7tX1hzBZwvVY9SV/uly4AvvJPPhCcymZL3fcQhEQG5AELmrxWqtmzacw==",
- "dev": true
- },
- "stylelint-config-recommended-scss": {
- "version": "5.0.2",
- "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-5.0.2.tgz",
- "integrity": "sha512-b14BSZjcwW0hqbzm9b0S/ScN2+3CO3O4vcMNOw2KGf8lfVSwJ4p5TbNEXKwKl1+0FMtgRXZj6DqVUe/7nGnuBg==",
- "dev": true,
- "requires": {
- "postcss-scss": "^4.0.2",
- "stylelint-config-recommended": "^6.0.0",
- "stylelint-scss": "^4.0.0"
- },
- "dependencies": {
- "postcss-scss": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.3.tgz",
- "integrity": "sha512-j4KxzWovfdHsyxwl1BxkUal/O4uirvHgdzMKS1aWJBAV0qh2qj5qAZqpeBfVUYGWv+4iK9Az7SPyZ4fyNju1uA==",
- "dev": true
- }
- }
- },
- "stylelint-scss": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-4.1.0.tgz",
- "integrity": "sha512-BNYTo7MMamhFOlcaAWp2dMpjg6hPyM/FFqfDIYzmYVLMmQJqc8lWRIiTqP4UX5bresj9Vo0dKC6odSh43VP2NA==",
- "dev": true,
- "requires": {
- "lodash": "^4.17.21",
- "postcss-media-query-parser": "^0.2.3",
- "postcss-resolve-nested-selector": "^0.1.1",
- "postcss-selector-parser": "^6.0.6",
- "postcss-value-parser": "^4.1.0"
- },
- "dependencies": {
- "postcss-value-parser": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
- "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
- "dev": true
- }
- }
- },
"stylis": {
"version": "4.0.13",
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz",
@@ -92646,9 +93271,9 @@
}
},
"table": {
- "version": "6.8.0",
- "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz",
- "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==",
+ "version": "6.8.2",
+ "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz",
+ "integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==",
"dev": true,
"requires": {
"ajv": "^8.0.1",
@@ -92950,9 +93575,9 @@
}
},
"terser": {
- "version": "5.31.2",
- "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.2.tgz",
- "integrity": "sha512-LGyRZVFm/QElZHy/CPr/O4eNZOZIzsrQ92y4v9UJe/pFJjypje2yI3C2FmPtvUEnhadlSbmG2nXtdcjHOjCfxw==",
+ "version": "5.32.0",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-5.32.0.tgz",
+ "integrity": "sha512-v3Gtw3IzpBJ0ugkxEX8U0W6+TnPKRRCWGh1jC/iM/e3Ki5+qvO1L1EAZ56bZasc64aXHwRHNIQEzm6//i5cemQ==",
"requires": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.8.2",
@@ -93574,7 +94199,8 @@
"version": "3.13.7",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.7.tgz",
"integrity": "sha512-1Psi2MmnZJbnEsgJJIlfnd7tFlJfitusmR7zDI8lXlFI0ACD4/Rm/xdrU8bh6zF0i74aiVoBtkRiFulkrmh3AA==",
- "dev": true
+ "dev": true,
+ "optional": true
},
"unbox-primitive": {
"version": "1.0.2",
diff --git a/package.json b/package.json
index 63d42613c31978..46d2b42f267abb 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "gutenberg",
- "version": "19.2.0-rc.1",
+ "version": "19.2.0",
"private": true,
"description": "A new WordPress editor experience.",
"author": "The WordPress Contributors",
@@ -59,6 +59,7 @@
"@wordpress/i18n": "file:packages/i18n",
"@wordpress/icons": "file:packages/icons",
"@wordpress/interactivity": "file:packages/interactivity",
+ "@wordpress/interactivity-router": "file:packages/interactivity-router",
"@wordpress/interface": "file:packages/interface",
"@wordpress/is-shallow-equal": "file:packages/is-shallow-equal",
"@wordpress/keyboard-shortcuts": "file:packages/keyboard-shortcuts",
@@ -256,9 +257,9 @@
"storybook-source-link": "2.0.9",
"strip-json-comments": "5.0.0",
"style-loader": "3.2.1",
+ "terser": "5.32.0",
"terser-webpack-plugin": "5.3.9",
"typescript": "5.5.3",
- "uglify-js": "3.13.7",
"uuid": "9.0.1",
"webdriverio": "8.16.20",
"webpack": "5.88.2",
diff --git a/packages/a11y/README.md b/packages/a11y/README.md
index 0f40d9edd010ed..755396d2bb8f09 100644
--- a/packages/a11y/README.md
+++ b/packages/a11y/README.md
@@ -39,7 +39,7 @@ speak( 'The message you want to send to the ARIA live region', 'assertive' );
_Parameters_
- _message_ `string`: The message to be announced by assistive technologies.
-- _ariaLive_ `[string]`: The politeness level for aria-live; default: 'polite'.
+- _ariaLive_ `['polite'|'assertive']`: The politeness level for aria-live; default: 'polite'.
diff --git a/packages/a11y/package.json b/packages/a11y/package.json
index 88123b3c6c7126..327d6b9ff07167 100644
--- a/packages/a11y/package.json
+++ b/packages/a11y/package.json
@@ -28,6 +28,7 @@
"module": "build-module/index.js",
"react-native": "src/index",
"types": "build-types",
+ "wpScriptModuleExports": "./build-module/module/index.js",
"dependencies": {
"@babel/runtime": "^7.16.0",
"@wordpress/dom-ready": "file:../dom-ready",
diff --git a/packages/a11y/src/index.js b/packages/a11y/src/index.js
index 957c76500c4344..59e93da780bd81 100644
--- a/packages/a11y/src/index.js
+++ b/packages/a11y/src/index.js
@@ -2,87 +2,20 @@
* WordPress dependencies
*/
import domReady from '@wordpress/dom-ready';
+import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
*/
-import addIntroText from './add-intro-text';
-import addContainer from './add-container';
-import clear from './clear';
-import filterMessage from './filter-message';
+import { makeSetupFunction } from './shared/index';
+export { speak } from './shared/index';
/**
* Create the live regions.
*/
-export function setup() {
- const introText = document.getElementById( 'a11y-speak-intro-text' );
- const containerAssertive = document.getElementById(
- 'a11y-speak-assertive'
- );
- const containerPolite = document.getElementById( 'a11y-speak-polite' );
-
- if ( introText === null ) {
- addIntroText();
- }
-
- if ( containerAssertive === null ) {
- addContainer( 'assertive' );
- }
-
- if ( containerPolite === null ) {
- addContainer( 'polite' );
- }
-}
+export const setup = makeSetupFunction( __( 'Notifications' ) );
/**
* Run setup on domReady.
*/
domReady( setup );
-
-/**
- * Allows you to easily announce dynamic interface updates to screen readers using ARIA live regions.
- * This module is inspired by the `speak` function in `wp-a11y.js`.
- *
- * @param {string} message The message to be announced by assistive technologies.
- * @param {string} [ariaLive] The politeness level for aria-live; default: 'polite'.
- *
- * @example
- * ```js
- * import { speak } from '@wordpress/a11y';
- *
- * // For polite messages that shouldn't interrupt what screen readers are currently announcing.
- * speak( 'The message you want to send to the ARIA live region' );
- *
- * // For assertive messages that should interrupt what screen readers are currently announcing.
- * speak( 'The message you want to send to the ARIA live region', 'assertive' );
- * ```
- */
-export function speak( message, ariaLive ) {
- /*
- * Clear previous messages to allow repeated strings being read out and hide
- * the explanatory text from assistive technologies.
- */
- clear();
-
- message = filterMessage( message );
-
- const introText = document.getElementById( 'a11y-speak-intro-text' );
- const containerAssertive = document.getElementById(
- 'a11y-speak-assertive'
- );
- const containerPolite = document.getElementById( 'a11y-speak-polite' );
-
- if ( containerAssertive && ariaLive === 'assertive' ) {
- containerAssertive.textContent = message;
- } else if ( containerPolite ) {
- containerPolite.textContent = message;
- }
-
- /*
- * Make the explanatory text available to assistive technologies by removing
- * the 'hidden' HTML attribute.
- */
- if ( introText ) {
- introText.removeAttribute( 'hidden' );
- }
-}
diff --git a/packages/a11y/src/index.native.js b/packages/a11y/src/index.native.js
index f6f53b6343adb0..e17597a8b2747d 100644
--- a/packages/a11y/src/index.native.js
+++ b/packages/a11y/src/index.native.js
@@ -1,7 +1,7 @@
/**
* Internal dependencies
*/
-import filterMessage from './filter-message';
+import filterMessage from './shared/filter-message';
/**
* Update the ARIA live notification area text node.
diff --git a/packages/a11y/src/module/index.ts b/packages/a11y/src/module/index.ts
new file mode 100644
index 00000000000000..a2c87f397f4875
--- /dev/null
+++ b/packages/a11y/src/module/index.ts
@@ -0,0 +1,25 @@
+/**
+ * Internal dependencies
+ */
+import { makeSetupFunction } from '../shared/index';
+export { speak } from '../shared/index';
+
+// Without an i18n Script Module, "Notifications" (the only localized text used in this module)
+// will be translated on the server and provided as script-module data.
+let notificationsText = 'Notifications';
+try {
+ const textContent = document.getElementById(
+ 'wp-script-module-data-@wordpress/a11y'
+ )?.textContent;
+ if ( textContent ) {
+ const parsed = JSON.parse( textContent );
+ notificationsText = parsed?.i18n?.Notifications ?? notificationsText;
+ }
+} catch {}
+
+/**
+ * Create the live regions.
+ */
+export const setup = makeSetupFunction( notificationsText );
+
+setup();
diff --git a/packages/a11y/src/add-container.js b/packages/a11y/src/shared/add-container.js
similarity index 100%
rename from packages/a11y/src/add-container.js
rename to packages/a11y/src/shared/add-container.js
diff --git a/packages/a11y/src/add-intro-text.js b/packages/a11y/src/shared/add-intro-text.ts
similarity index 83%
rename from packages/a11y/src/add-intro-text.js
rename to packages/a11y/src/shared/add-intro-text.ts
index 2bcf453ec44c8e..6bd97c887664d3 100644
--- a/packages/a11y/src/add-intro-text.js
+++ b/packages/a11y/src/shared/add-intro-text.ts
@@ -1,22 +1,18 @@
-/**
- * WordPress dependencies
- */
-import { __ } from '@wordpress/i18n';
-
/**
* Build the explanatory text to be placed before the aria live regions.
*
* This text is initially hidden from assistive technologies by using a `hidden`
* HTML attribute which is then removed once a message fills the aria-live regions.
*
+ * @param {string} introTextContent The translated intro text content.
* @return {HTMLParagraphElement} The explanatory text HTML element.
*/
-export default function addIntroText() {
+export default function addIntroText( introTextContent: string ) {
const introText = document.createElement( 'p' );
introText.id = 'a11y-speak-intro-text';
introText.className = 'a11y-speak-intro-text';
- introText.textContent = __( 'Notifications' );
+ introText.textContent = introTextContent;
introText.setAttribute(
'style',
diff --git a/packages/a11y/src/clear.js b/packages/a11y/src/shared/clear.js
similarity index 100%
rename from packages/a11y/src/clear.js
rename to packages/a11y/src/shared/clear.js
diff --git a/packages/a11y/src/filter-message.js b/packages/a11y/src/shared/filter-message.js
similarity index 100%
rename from packages/a11y/src/filter-message.js
rename to packages/a11y/src/shared/filter-message.js
diff --git a/packages/a11y/src/shared/index.js b/packages/a11y/src/shared/index.js
new file mode 100644
index 00000000000000..a05f891f428561
--- /dev/null
+++ b/packages/a11y/src/shared/index.js
@@ -0,0 +1,81 @@
+/**
+ * Internal dependencies
+ */
+import addContainer from './add-container';
+import addIntroText from './add-intro-text';
+import clear from './clear';
+import filterMessage from './filter-message';
+
+/**
+ * Create the live regions.
+ * @param {string} introTextContent The intro text content.
+ */
+export function makeSetupFunction( introTextContent ) {
+ return function setup() {
+ const introText = document.getElementById( 'a11y-speak-intro-text' );
+ const containerAssertive = document.getElementById(
+ 'a11y-speak-assertive'
+ );
+ const containerPolite = document.getElementById( 'a11y-speak-polite' );
+
+ if ( introText === null ) {
+ addIntroText( introTextContent );
+ }
+
+ if ( containerAssertive === null ) {
+ addContainer( 'assertive' );
+ }
+
+ if ( containerPolite === null ) {
+ addContainer( 'polite' );
+ }
+ };
+}
+
+/**
+ * Allows you to easily announce dynamic interface updates to screen readers using ARIA live regions.
+ * This module is inspired by the `speak` function in `wp-a11y.js`.
+ *
+ * @param {string} message The message to be announced by assistive technologies.
+ * @param {'polite'|'assertive'} [ariaLive] The politeness level for aria-live; default: 'polite'.
+ *
+ * @example
+ * ```js
+ * import { speak } from '@wordpress/a11y';
+ *
+ * // For polite messages that shouldn't interrupt what screen readers are currently announcing.
+ * speak( 'The message you want to send to the ARIA live region' );
+ *
+ * // For assertive messages that should interrupt what screen readers are currently announcing.
+ * speak( 'The message you want to send to the ARIA live region', 'assertive' );
+ * ```
+ */
+export function speak( message, ariaLive ) {
+ /*
+ * Clear previous messages to allow repeated strings being read out and hide
+ * the explanatory text from assistive technologies.
+ */
+ clear();
+
+ message = filterMessage( message );
+
+ const introText = document.getElementById( 'a11y-speak-intro-text' );
+ const containerAssertive = document.getElementById(
+ 'a11y-speak-assertive'
+ );
+ const containerPolite = document.getElementById( 'a11y-speak-polite' );
+
+ if ( containerAssertive && ariaLive === 'assertive' ) {
+ containerAssertive.textContent = message;
+ } else if ( containerPolite ) {
+ containerPolite.textContent = message;
+ }
+
+ /*
+ * Make the explanatory text available to assistive technologies by removing
+ * the 'hidden' HTML attribute.
+ */
+ if ( introText ) {
+ introText.removeAttribute( 'hidden' );
+ }
+}
diff --git a/packages/a11y/src/test/add-container.test.js b/packages/a11y/src/shared/test/add-container.test.js
similarity index 100%
rename from packages/a11y/src/test/add-container.test.js
rename to packages/a11y/src/shared/test/add-container.test.js
diff --git a/packages/a11y/src/test/clear.test.js b/packages/a11y/src/shared/test/clear.test.js
similarity index 100%
rename from packages/a11y/src/test/clear.test.js
rename to packages/a11y/src/shared/test/clear.test.js
diff --git a/packages/a11y/src/test/filter-message.test.js b/packages/a11y/src/shared/test/filter-message.test.js
similarity index 100%
rename from packages/a11y/src/test/filter-message.test.js
rename to packages/a11y/src/shared/test/filter-message.test.js
diff --git a/packages/a11y/src/test/index.test.js b/packages/a11y/src/test/index.test.js
index 4815baa2205047..0f6b9d0bd572ed 100644
--- a/packages/a11y/src/test/index.test.js
+++ b/packages/a11y/src/test/index.test.js
@@ -7,10 +7,10 @@ import domReady from '@wordpress/dom-ready';
* Internal dependencies
*/
import { setup, speak } from '../';
-import clear from '../clear';
-import filterMessage from '../filter-message';
+import clear from '../shared/clear';
+import filterMessage from '../shared/filter-message';
-jest.mock( '../clear', () => {
+jest.mock( '../shared/clear', () => {
return jest.fn();
} );
jest.mock( '@wordpress/dom-ready', () => {
@@ -18,7 +18,7 @@ jest.mock( '@wordpress/dom-ready', () => {
callback();
} );
} );
-jest.mock( '../filter-message', () => {
+jest.mock( '../shared/filter-message', () => {
return jest.fn( ( message ) => {
return message;
} );
diff --git a/packages/babel-preset-default/bin/index.js b/packages/babel-preset-default/bin/index.js
index 54c35564d43d74..0e0e66b450c1d6 100755
--- a/packages/babel-preset-default/bin/index.js
+++ b/packages/babel-preset-default/bin/index.js
@@ -4,7 +4,7 @@
* External dependencies
*/
const builder = require( 'core-js-builder' );
-const { minify } = require( 'uglify-js' );
+const { minify } = require( 'terser' );
const { writeFile } = require( 'fs' ).promises;
builder( {
@@ -18,15 +18,15 @@ builder( {
targets: require( '@wordpress/browserslist-config' ),
filename: './build/polyfill.js',
} )
- .then( async ( code ) => {
- const output = minify( code, {
+ .then( ( code ) =>
+ minify( code, {
output: {
comments: ( node, comment ) =>
- comment.value.indexOf( 'License' ) >= 0,
+ comment.value.toLowerCase().includes( 'license' ),
},
- } );
- await writeFile( './build/polyfill.min.js', output.code );
- } )
+ } )
+ )
+ .then( ( output ) => writeFile( './build/polyfill.min.js', output.code ) )
.catch( ( error ) => {
// eslint-disable-next-line no-console
console.log( error );
diff --git a/packages/base-styles/_animations.scss b/packages/base-styles/_animations.scss
index ce1f935b7d4d5b..8706d185aa221b 100644
--- a/packages/base-styles/_animations.scss
+++ b/packages/base-styles/_animations.scss
@@ -1,5 +1,37 @@
-@mixin edit-post__fade-in-animation($speed: 0.08s, $delay: 0s) {
- animation: edit-post__fade-in-animation $speed linear $delay;
+@mixin keyframes($name) {
+ @keyframes #{$name} {
+ @content;
+ }
+}
+
+@mixin animation__fade-in($speed: 0.08s, $delay: 0s) {
+ @include keyframes(__wp-base-styles-fade-in) {
+ from {
+ opacity: 0;
+ }
+ to {
+ opacity: 1;
+ }
+ }
+
+
+ animation: __wp-base-styles-fade-in $speed linear $delay;
+ animation-fill-mode: forwards;
+ @include reduce-motion("animation");
+}
+
+@mixin animation__fade-out($speed: 0.08s, $delay: 0s) {
+ @include keyframes(__wp-base-styles-fade-out) {
+ from {
+ opacity: 1;
+ }
+ to {
+ opacity: 0;
+ }
+ }
+
+
+ animation: __wp-base-styles-fade-out $speed linear $delay;
animation-fill-mode: forwards;
@include reduce-motion("animation");
}
@@ -8,3 +40,9 @@
transition: all 0.5s cubic-bezier(0.65, 0, 0.45, 1);
@include reduce-motion("transition");
}
+
+// Deprecated
+@mixin edit-post__fade-in-animation($speed: 0.08s, $delay: 0s) {
+ @warn "The `edit-post__fade-in-animation` mixin is deprecated. Use `animation__fade-in` instead.";
+ @include animation__fade-in($speed, $delay);
+}
diff --git a/packages/base-styles/_mixins.scss b/packages/base-styles/_mixins.scss
index ebccbe0e5e8aee..91017c8bb99320 100644
--- a/packages/base-styles/_mixins.scss
+++ b/packages/base-styles/_mixins.scss
@@ -512,7 +512,7 @@
@mixin gradient-colors-deprecated() {
// Our classes uses the same values we set for gradient value attributes.
- /* stylelint-disable function-comma-space-after -- We can not use spacing because of WP multi site kses rule. */
+ /* stylelint-disable @stylistic/function-comma-space-after -- We can not use spacing because of WP multi site kses rule. */
.has-vivid-green-cyan-to-vivid-cyan-blue-gradient-background {
background: linear-gradient(135deg,rgba(0,208,132,1) 0%,rgba(6,147,227,1) 100%);
}
@@ -540,7 +540,7 @@
.has-midnight-gradient-background {
background: linear-gradient(135deg,rgb(2,3,129) 0%,rgb(40,116,252) 100%);
}
- /* stylelint-enable function-comma-space-after */
+ /* stylelint-enable @stylistic/function-comma-space-after */
}
@mixin custom-scrollbars-on-hover($handle-color, $handle-color-hover) {
diff --git a/packages/block-editor/src/components/background-image-control/index.js b/packages/block-editor/src/components/background-image-control/index.js
new file mode 100644
index 00000000000000..2703aa3988d64e
--- /dev/null
+++ b/packages/block-editor/src/components/background-image-control/index.js
@@ -0,0 +1,741 @@
+/**
+ * External dependencies
+ */
+import clsx from 'clsx';
+
+/**
+ * WordPress dependencies
+ */
+import {
+ ToggleControl,
+ __experimentalToggleGroupControl as ToggleGroupControl,
+ __experimentalToggleGroupControlOption as ToggleGroupControlOption,
+ __experimentalUnitControl as UnitControl,
+ __experimentalVStack as VStack,
+ DropZone,
+ FlexItem,
+ FocalPointPicker,
+ MenuItem,
+ VisuallyHidden,
+ __experimentalItemGroup as ItemGroup,
+ __experimentalHStack as HStack,
+ __experimentalTruncate as Truncate,
+ Dropdown,
+ Placeholder,
+ Spinner,
+ __experimentalDropdownContentWrapper as DropdownContentWrapper,
+} from '@wordpress/components';
+import { __, _x, sprintf } from '@wordpress/i18n';
+import { store as noticesStore } from '@wordpress/notices';
+import { getFilename } from '@wordpress/url';
+import { useRef, useState, useEffect, useMemo } from '@wordpress/element';
+import { useDispatch, useSelect } from '@wordpress/data';
+import { focus } from '@wordpress/dom';
+import { isBlobURL } from '@wordpress/blob';
+
+/**
+ * Internal dependencies
+ */
+import { getResolvedValue } from '../global-styles/utils';
+import { hasBackgroundImageValue } from '../global-styles/background-panel';
+import { setImmutably } from '../../utils/object';
+import MediaReplaceFlow from '../media-replace-flow';
+import { store as blockEditorStore } from '../../store';
+
+import {
+ globalStylesDataKey,
+ globalStylesLinksDataKey,
+} from '../../store/private-keys';
+
+const IMAGE_BACKGROUND_TYPE = 'image';
+
+const BACKGROUND_POPOVER_PROPS = {
+ placement: 'left-start',
+ offset: 36,
+ shift: true,
+ className: 'block-editor-global-styles-background-panel__popover',
+};
+const noop = () => {};
+
+/**
+ * Get the help text for the background size control.
+ *
+ * @param {string} value backgroundSize value.
+ * @return {string} Translated help text.
+ */
+function backgroundSizeHelpText( value ) {
+ if ( value === 'cover' || value === undefined ) {
+ return __( 'Image covers the space evenly.' );
+ }
+ if ( value === 'contain' ) {
+ return __( 'Image is contained without distortion.' );
+ }
+ return __( 'Image has a fixed width.' );
+}
+
+/**
+ * Converts decimal x and y coords from FocalPointPicker to percentage-based values
+ * to use as backgroundPosition value.
+ *
+ * @param {{x?:number, y?:number}} value FocalPointPicker coords.
+ * @return {string} backgroundPosition value.
+ */
+export const coordsToBackgroundPosition = ( value ) => {
+ if ( ! value || ( isNaN( value.x ) && isNaN( value.y ) ) ) {
+ return undefined;
+ }
+
+ const x = isNaN( value.x ) ? 0.5 : value.x;
+ const y = isNaN( value.y ) ? 0.5 : value.y;
+
+ return `${ x * 100 }% ${ y * 100 }%`;
+};
+
+/**
+ * Converts backgroundPosition value to x and y coords for FocalPointPicker.
+ *
+ * @param {string} value backgroundPosition value.
+ * @return {{x?:number, y?:number}} FocalPointPicker coords.
+ */
+export const backgroundPositionToCoords = ( value ) => {
+ if ( ! value ) {
+ return { x: undefined, y: undefined };
+ }
+
+ let [ x, y ] = value.split( ' ' ).map( ( v ) => parseFloat( v ) / 100 );
+ x = isNaN( x ) ? undefined : x;
+ y = isNaN( y ) ? x : y;
+
+ return { x, y };
+};
+
+function InspectorImagePreviewItem( {
+ as = 'span',
+ imgUrl,
+ toggleProps = {},
+ filename,
+ label,
+ className,
+ onToggleCallback = noop,
+} ) {
+ useEffect( () => {
+ if ( typeof toggleProps?.isOpen !== 'undefined' ) {
+ onToggleCallback( toggleProps?.isOpen );
+ }
+ }, [ toggleProps?.isOpen, onToggleCallback ] );
+ return (
+
+
+ { imgUrl && (
+
+
+
+ ) }
+
+
+ { label }
+
+
+ { imgUrl
+ ? sprintf(
+ /* translators: %s: file name */
+ __( 'Background image: %s' ),
+ filename || label
+ )
+ : __( 'No background image selected' ) }
+
+
+
+
+ );
+}
+
+function BackgroundControlsPanel( {
+ label,
+ filename,
+ url: imgUrl,
+ children,
+ onToggle: onToggleCallback = noop,
+ hasImageValue,
+} ) {
+ if ( ! hasImageValue ) {
+ return;
+ }
+
+ const imgLabel =
+ label || getFilename( imgUrl ) || __( 'Add background image' );
+
+ return (
+ {
+ const toggleProps = {
+ onClick: onToggle,
+ className:
+ 'block-editor-global-styles-background-panel__dropdown-toggle',
+ 'aria-expanded': isOpen,
+ 'aria-label': __(
+ 'Background size, position and repeat options.'
+ ),
+ isOpen,
+ };
+ return (
+
+ );
+ } }
+ renderContent={ () => (
+
+ { children }
+
+ ) }
+ />
+ );
+}
+
+function LoadingSpinner() {
+ return (
+
+
+
+ );
+}
+
+function BackgroundImageControls( {
+ onChange,
+ style,
+ inheritedValue,
+ onRemoveImage = noop,
+ onResetImage = noop,
+ displayInPanel,
+ defaultValues,
+} ) {
+ const [ isUploading, setIsUploading ] = useState( false );
+ const { getSettings } = useSelect( blockEditorStore );
+
+ const { id, title, url } = style?.background?.backgroundImage || {
+ ...inheritedValue?.background?.backgroundImage,
+ };
+ const replaceContainerRef = useRef();
+ const { createErrorNotice } = useDispatch( noticesStore );
+ const onUploadError = ( message ) => {
+ createErrorNotice( message, { type: 'snackbar' } );
+ setIsUploading( false );
+ };
+
+ const resetBackgroundImage = () =>
+ onChange(
+ setImmutably(
+ style,
+ [ 'background', 'backgroundImage' ],
+ undefined
+ )
+ );
+
+ const onSelectMedia = ( media ) => {
+ if ( ! media || ! media.url ) {
+ resetBackgroundImage();
+ setIsUploading( false );
+ return;
+ }
+
+ if ( isBlobURL( media.url ) ) {
+ setIsUploading( true );
+ return;
+ }
+
+ // For media selections originated from a file upload.
+ if (
+ ( media.media_type &&
+ media.media_type !== IMAGE_BACKGROUND_TYPE ) ||
+ ( ! media.media_type &&
+ media.type &&
+ media.type !== IMAGE_BACKGROUND_TYPE )
+ ) {
+ onUploadError(
+ __( 'Only images can be used as a background image.' )
+ );
+ return;
+ }
+
+ const sizeValue =
+ style?.background?.backgroundSize || defaultValues?.backgroundSize;
+ const positionValue = style?.background?.backgroundPosition;
+ onChange(
+ setImmutably( style, [ 'background' ], {
+ ...style?.background,
+ backgroundImage: {
+ url: media.url,
+ id: media.id,
+ source: 'file',
+ title: media.title || undefined,
+ },
+ backgroundPosition:
+ /*
+ * A background image uploaded and set in the editor receives a default background position of '50% 0',
+ * when the background image size is the equivalent of "Tile".
+ * This is to increase the chance that the image's focus point is visible.
+ * This is in-editor only to assist with the user experience.
+ */
+ ! positionValue && ( 'auto' === sizeValue || ! sizeValue )
+ ? '50% 0'
+ : positionValue,
+ backgroundSize: sizeValue,
+ } )
+ );
+ setIsUploading( false );
+ };
+
+ // Drag and drop callback, restricting image to one.
+ const onFilesDrop = ( filesList ) => {
+ if ( filesList?.length > 1 ) {
+ onUploadError(
+ __( 'Only one image can be used as a background image.' )
+ );
+ return;
+ }
+ getSettings().mediaUpload( {
+ allowedTypes: [ IMAGE_BACKGROUND_TYPE ],
+ filesList,
+ onFileChange( [ image ] ) {
+ onSelectMedia( image );
+ },
+ onError: onUploadError,
+ } );
+ };
+
+ const hasValue = hasBackgroundImageValue( style );
+
+ const closeAndFocus = () => {
+ const [ toggleButton ] = focus.tabbable.find(
+ replaceContainerRef.current
+ );
+ // Focus the toggle button and close the dropdown menu.
+ // This ensures similar behaviour as to selecting an image, where the dropdown is
+ // closed and focus is redirected to the dropdown toggle button.
+ toggleButton?.focus();
+ toggleButton?.click();
+ };
+
+ const onRemove = () =>
+ onChange(
+ setImmutably( style, [ 'background' ], {
+ backgroundImage: 'none',
+ } )
+ );
+ const canRemove = ! hasValue && hasBackgroundImageValue( inheritedValue );
+ const imgLabel =
+ title || getFilename( url ) || __( 'Add background image' );
+
+ return (
+
+ { isUploading && }
+
+ }
+ variant="secondary"
+ onError={ onUploadError }
+ onReset={ () => {
+ closeAndFocus();
+ onResetImage();
+ } }
+ >
+ { canRemove && (
+ {
+ closeAndFocus();
+ onRemove();
+ onRemoveImage();
+ } }
+ >
+ { __( 'Remove' ) }
+
+ ) }
+
+
+
+ );
+}
+
+function BackgroundSizeControls( {
+ onChange,
+ style,
+ inheritedValue,
+ defaultValues,
+} ) {
+ const sizeValue =
+ style?.background?.backgroundSize ||
+ inheritedValue?.background?.backgroundSize;
+ const repeatValue =
+ style?.background?.backgroundRepeat ||
+ inheritedValue?.background?.backgroundRepeat;
+ const imageValue =
+ style?.background?.backgroundImage?.url ||
+ inheritedValue?.background?.backgroundImage?.url;
+ const isUploadedImage = style?.background?.backgroundImage?.id;
+ const positionValue =
+ style?.background?.backgroundPosition ||
+ inheritedValue?.background?.backgroundPosition;
+ const attachmentValue =
+ style?.background?.backgroundAttachment ||
+ inheritedValue?.background?.backgroundAttachment;
+
+ /*
+ * Set default values for uploaded images.
+ * The default values are passed by the consumer.
+ * Block-level controls may have different defaults to root-level controls.
+ * A falsy value is treated by default as `auto` (Tile).
+ */
+ let currentValueForToggle =
+ ! sizeValue && isUploadedImage
+ ? defaultValues?.backgroundSize
+ : sizeValue || 'auto';
+ /*
+ * The incoming value could be a value + unit, e.g. '20px'.
+ * In this case set the value to 'tile'.
+ */
+ currentValueForToggle = ! [ 'cover', 'contain', 'auto' ].includes(
+ currentValueForToggle
+ )
+ ? 'auto'
+ : currentValueForToggle;
+ /*
+ * If the current value is `cover` and the repeat value is `undefined`, then
+ * the toggle should be unchecked as the default state. Otherwise, the toggle
+ * should reflect the current repeat value.
+ */
+ const repeatCheckedValue = ! (
+ repeatValue === 'no-repeat' ||
+ ( currentValueForToggle === 'cover' && repeatValue === undefined )
+ );
+
+ const updateBackgroundSize = ( next ) => {
+ // When switching to 'contain' toggle the repeat off.
+ let nextRepeat = repeatValue;
+ let nextPosition = positionValue;
+
+ if ( next === 'contain' ) {
+ nextRepeat = 'no-repeat';
+ nextPosition = undefined;
+ }
+
+ if ( next === 'cover' ) {
+ nextRepeat = undefined;
+ nextPosition = undefined;
+ }
+
+ if (
+ ( currentValueForToggle === 'cover' ||
+ currentValueForToggle === 'contain' ) &&
+ next === 'auto'
+ ) {
+ nextRepeat = undefined;
+ /*
+ * A background image uploaded and set in the editor (an image with a record id),
+ * receives a default background position of '50% 0',
+ * when the toggle switches to "Tile". This is to increase the chance that
+ * the image's focus point is visible.
+ * This is in-editor only to assist with the user experience.
+ */
+ if ( !! style?.background?.backgroundImage?.id ) {
+ nextPosition = '50% 0';
+ }
+ }
+
+ /*
+ * Next will be null when the input is cleared,
+ * in which case the value should be 'auto'.
+ */
+ if ( ! next && currentValueForToggle === 'auto' ) {
+ next = 'auto';
+ }
+
+ onChange(
+ setImmutably( style, [ 'background' ], {
+ ...style?.background,
+ backgroundPosition: nextPosition,
+ backgroundRepeat: nextRepeat,
+ backgroundSize: next,
+ } )
+ );
+ };
+
+ const updateBackgroundPosition = ( next ) => {
+ onChange(
+ setImmutably(
+ style,
+ [ 'background', 'backgroundPosition' ],
+ coordsToBackgroundPosition( next )
+ )
+ );
+ };
+
+ const toggleIsRepeated = () =>
+ onChange(
+ setImmutably(
+ style,
+ [ 'background', 'backgroundRepeat' ],
+ repeatCheckedValue === true ? 'no-repeat' : 'repeat'
+ )
+ );
+
+ const toggleScrollWithPage = () =>
+ onChange(
+ setImmutably(
+ style,
+ [ 'background', 'backgroundAttachment' ],
+ attachmentValue === 'fixed' ? 'scroll' : 'fixed'
+ )
+ );
+
+ // Set a default background position for non-site-wide, uploaded images with a size of 'contain'.
+ const backgroundPositionValue =
+ ! positionValue && isUploadedImage && 'contain' === sizeValue
+ ? defaultValues?.backgroundPosition
+ : positionValue;
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+export default function BackgroundImagePanel( {
+ value,
+ onChange,
+ inheritedValue = value,
+ settings,
+ defaultValues = {},
+} ) {
+ /*
+ * Resolve any inherited "ref" pointers.
+ * Should the block editor need resolved, inherited values
+ * across all controls, this could be abstracted into a hook,
+ * e.g., useResolveGlobalStyle
+ */
+ const { globalStyles, _links } = useSelect( ( select ) => {
+ const { getSettings } = select( blockEditorStore );
+ const _settings = getSettings();
+ return {
+ globalStyles: _settings[ globalStylesDataKey ],
+ _links: _settings[ globalStylesLinksDataKey ],
+ };
+ }, [] );
+ const resolvedInheritedValue = useMemo( () => {
+ const resolvedValues = {
+ background: {},
+ };
+
+ if ( ! inheritedValue?.background ) {
+ return inheritedValue;
+ }
+
+ Object.entries( inheritedValue?.background ).forEach(
+ ( [ key, backgroundValue ] ) => {
+ resolvedValues.background[ key ] = getResolvedValue(
+ backgroundValue,
+ {
+ styles: globalStyles,
+ _links,
+ }
+ );
+ }
+ );
+ return resolvedValues;
+ }, [ globalStyles, _links, inheritedValue ] );
+
+ const resetBackground = () =>
+ onChange( setImmutably( value, [ 'background' ], {} ) );
+
+ const { title, url } = value?.background?.backgroundImage || {
+ ...resolvedInheritedValue?.background?.backgroundImage,
+ };
+ const hasImageValue =
+ hasBackgroundImageValue( value ) ||
+ hasBackgroundImageValue( resolvedInheritedValue );
+
+ const imageValue =
+ value?.background?.backgroundImage ||
+ inheritedValue?.background?.backgroundImage;
+
+ const shouldShowBackgroundImageControls =
+ hasImageValue &&
+ 'none' !== imageValue &&
+ ( settings?.background?.backgroundSize ||
+ settings?.background?.backgroundPosition ||
+ settings?.background?.backgroundRepeat );
+
+ const [ isDropDownOpen, setIsDropDownOpen ] = useState( false );
+
+ return (
+
+ { shouldShowBackgroundImageControls ? (
+
+
+ {
+ setIsDropDownOpen( false );
+ resetBackground();
+ } }
+ onRemoveImage={ () => setIsDropDownOpen( false ) }
+ defaultValues={ defaultValues }
+ />
+
+
+
+ ) : (
+ {
+ setIsDropDownOpen( false );
+ resetBackground();
+ } }
+ onRemoveImage={ () => setIsDropDownOpen( false ) }
+ />
+ ) }
+
+ );
+}
diff --git a/packages/block-editor/src/components/background-image-control/style.scss b/packages/block-editor/src/components/background-image-control/style.scss
new file mode 100644
index 00000000000000..cde8044c24c121
--- /dev/null
+++ b/packages/block-editor/src/components/background-image-control/style.scss
@@ -0,0 +1,170 @@
+.block-editor-global-styles-background-panel__inspector-media-replace-container {
+ border: $border-width solid $gray-300;
+ border-radius: $radius-small;
+ // Full width. ToolsPanel lays out children in a grid.
+ grid-column: 1 / -1;
+
+ &.is-open {
+ background-color: $gray-100;
+ }
+
+ .block-editor-global-styles-background-panel__image-tools-panel-item {
+ flex-grow: 1;
+ border: 0;
+
+ .components-dropdown {
+ display: block;
+ }
+ }
+
+ .block-editor-global-styles-background-panel__inspector-preview-inner {
+ height: 100%;
+ }
+
+ .components-dropdown {
+ display: block;
+ height: 36px;
+ }
+}
+
+.block-editor-global-styles-background-panel__image-tools-panel-item {
+ border: $border-width solid $gray-300;
+
+ // Full width. ToolsPanel lays out children in a grid.
+ grid-column: 1 / -1;
+
+ // Ensure the dropzone is positioned to the size of the item.
+ position: relative;
+
+ // Since there is no option to skip rendering the drag'n'drop icon in drop
+ // zone, we hide it for now.
+ .components-drop-zone__content-icon {
+ display: none;
+ }
+
+ .components-dropdown {
+ display: block;
+ height: 36px;
+ }
+
+ button.components-button {
+ color: $gray-900;
+ width: 100%;
+ display: block;
+
+ &:hover {
+ color: var(--wp-admin-theme-color);
+ }
+
+ &:focus {
+ box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
+ }
+ }
+
+ .block-editor-global-styles-background-panel__loading {
+ height: 100%;
+ position: absolute;
+ z-index: 1;
+ width: 100%;
+ padding: 10px 0 0 0;
+
+ svg {
+ margin: 0;
+ }
+ }
+}
+
+.block-editor-global-styles-background-panel__image-preview-content,
+.block-editor-global-styles-background-panel__dropdown-toggle {
+ height: 100%;
+ width: 100%;
+ padding-left: $grid-unit-15;
+}
+
+.block-editor-global-styles-background-panel__dropdown-toggle {
+ cursor: pointer;
+ background: transparent;
+ border: none;
+}
+
+.block-editor-global-styles-background-panel__inspector-media-replace-title {
+ word-break: break-all;
+ // The Button component is white-space: nowrap, and that won't work with line-clamp.
+ white-space: normal;
+
+ // Without this, the ellipsis can sometimes be partially hidden by the Button padding.
+ text-align: start;
+ text-align-last: center;
+}
+
+.block-editor-global-styles-background-panel__inspector-preview-inner {
+ .block-editor-global-styles-background-panel__inspector-image-indicator-wrapper {
+ width: 20px;
+ height: 20px;
+ min-width: auto;
+ }
+}
+
+.block-editor-global-styles-background-panel__inspector-image-indicator {
+ background-size: cover;
+ border-radius: $radius-round;
+ width: 20px;
+ height: 20px;
+ display: block;
+ position: relative;
+}
+
+.block-editor-global-styles-background-panel__inspector-image-indicator::after {
+ content: "";
+ position: absolute;
+ top: -1px;
+ left: -1px;
+ bottom: -1px;
+ right: -1px;
+ border-radius: $radius-round;
+ box-shadow: inset 0 0 0 $border-width rgba(0, 0, 0, 0.2);
+ // Show a thin outline in Windows high contrast mode, otherwise the button is invisible.
+ border: 1px solid transparent;
+ box-sizing: inherit;
+}
+
+.block-editor-global-styles-background-panel__dropdown-content-wrapper {
+ min-width: 260px;
+ overflow-x: hidden;
+
+ .components-focal-point-picker-wrapper {
+ background-color: $gray-100;
+ width: 100%;
+ border-radius: $radius-small;
+ border: $border-width solid $gray-300;
+ }
+
+ .components-focal-point-picker__media--image {
+ max-height: 180px;
+ }
+
+ // Override focal picker to avoid a double border.
+ .components-focal-point-picker::after {
+ content: none;
+ }
+}
+
+// Push control panel into the background when the media modal is open.
+.modal-open .block-editor-global-styles-background-panel__popover {
+ z-index: z-index(".block-editor-global-styles-background-panel__popover");
+}
+
+.block-editor-global-styles-background-panel__media-replace-popover {
+ .components-popover__content {
+ // width of block-editor-global-styles-background-panel__dropdown-content-wrapper minus padding.
+ width: 226px;
+ }
+
+ .components-button {
+ padding: 0 $grid-unit-10;
+ }
+
+ .components-button .components-menu-items__item-icon.has-icon-right {
+ margin-left: $grid-unit-30 - $grid-unit-10;
+ }
+}
diff --git a/packages/block-editor/src/components/background-image-control/test/index.js b/packages/block-editor/src/components/background-image-control/test/index.js
new file mode 100644
index 00000000000000..ebadad97eda022
--- /dev/null
+++ b/packages/block-editor/src/components/background-image-control/test/index.js
@@ -0,0 +1,47 @@
+/**
+ * Internal dependencies
+ */
+
+import { backgroundPositionToCoords, coordsToBackgroundPosition } from '../';
+
+describe( 'backgroundPositionToCoords', () => {
+ it( 'should return the correct coordinates for a percentage value using 2-value syntax', () => {
+ expect( backgroundPositionToCoords( '25% 75%' ) ).toEqual( {
+ x: 0.25,
+ y: 0.75,
+ } );
+ } );
+
+ it( 'should return the correct coordinates for a percentage using 1-value syntax', () => {
+ expect( backgroundPositionToCoords( '50%' ) ).toEqual( {
+ x: 0.5,
+ y: 0.5,
+ } );
+ } );
+
+ it( 'should return undefined coords in given an empty value', () => {
+ expect( backgroundPositionToCoords( '' ) ).toEqual( {
+ x: undefined,
+ y: undefined,
+ } );
+ } );
+
+ it( 'should return undefined coords in given a string that cannot be converted', () => {
+ expect( backgroundPositionToCoords( 'apples' ) ).toEqual( {
+ x: undefined,
+ y: undefined,
+ } );
+ } );
+} );
+
+describe( 'coordsToBackgroundPosition', () => {
+ it( 'should return the correct background position for a set of coordinates', () => {
+ expect( coordsToBackgroundPosition( { x: 0.25, y: 0.75 } ) ).toBe(
+ '25% 75%'
+ );
+ } );
+
+ it( 'should return undefined if no coordinates are provided', () => {
+ expect( coordsToBackgroundPosition( {} ) ).toBeUndefined();
+ } );
+} );
diff --git a/packages/block-editor/src/components/block-inspector/style.scss b/packages/block-editor/src/components/block-inspector/style.scss
index cf7131722722c1..bdbf3660d9619e 100644
--- a/packages/block-editor/src/components/block-inspector/style.scss
+++ b/packages/block-editor/src/components/block-inspector/style.scss
@@ -11,10 +11,8 @@
}
.components-base-control {
- margin-bottom: #{ $grid-unit-30 };
-
- &:last-child {
- margin-bottom: $grid-unit-10;
+ &:where(:not(:last-child)) {
+ margin-bottom: $grid-unit-20;
}
}
diff --git a/packages/block-editor/src/components/block-list/use-block-props/use-zoom-out-mode-exit.js b/packages/block-editor/src/components/block-list/use-block-props/use-zoom-out-mode-exit.js
index bb6edd066f06f1..d0001bd3b33c68 100644
--- a/packages/block-editor/src/components/block-list/use-block-props/use-zoom-out-mode-exit.js
+++ b/packages/block-editor/src/components/block-list/use-block-props/use-zoom-out-mode-exit.js
@@ -1,7 +1,7 @@
/**
* WordPress dependencies
*/
-import { useDispatch } from '@wordpress/data';
+import { useSelect, useDispatch } from '@wordpress/data';
import { useRefEffect } from '@wordpress/compose';
/**
@@ -16,6 +16,7 @@ import { unlock } from '../../../lock-unlock';
* @param {string} clientId Block client ID.
*/
export function useZoomOutModeExit( { editorMode } ) {
+ const { getSettings } = useSelect( blockEditorStore );
const { __unstableSetEditorMode } = unlock(
useDispatch( blockEditorStore )
);
@@ -29,6 +30,14 @@ export function useZoomOutModeExit( { editorMode } ) {
function onDoubleClick( event ) {
if ( ! event.defaultPrevented ) {
event.preventDefault();
+
+ const { __experimentalSetIsInserterOpened } = getSettings();
+
+ if (
+ typeof __experimentalSetIsInserterOpened === 'function'
+ ) {
+ __experimentalSetIsInserterOpened( false );
+ }
__unstableSetEditorMode( 'edit' );
}
}
@@ -39,6 +48,6 @@ export function useZoomOutModeExit( { editorMode } ) {
node.removeEventListener( 'dblclick', onDoubleClick );
};
},
- [ editorMode, __unstableSetEditorMode ]
+ [ editorMode, getSettings, __unstableSetEditorMode ]
);
}
diff --git a/packages/block-editor/src/components/block-switcher/style.scss b/packages/block-editor/src/components/block-switcher/style.scss
index 823a656668a621..3dc2a7d591c926 100644
--- a/packages/block-editor/src/components/block-switcher/style.scss
+++ b/packages/block-editor/src/components/block-switcher/style.scss
@@ -55,30 +55,6 @@
}
}
-// Style this the same as the block buttons in the library.
-// Needs specificity to override the icon button.
-.block-editor-block-toolbar .components-toolbar-group .components-button.block-editor-block-switcher__no-switcher-icon.has-icon.has-icon,
-.block-editor-block-toolbar .components-toolbar .components-button.block-editor-block-switcher__no-switcher-icon.has-icon.has-icon,
-.block-editor-block-toolbar .components-toolbar-group .components-button.block-editor-block-switcher__toggle.has-icon.has-icon,
-.block-editor-block-toolbar .components-toolbar .components-button.block-editor-block-switcher__toggle.has-icon.has-icon {
- .block-editor-block-icon {
- height: 100%;
- position: relative;
- margin: 0 auto;
- display: flex;
- align-items: center;
- min-width: 100%;
- }
-
- // Position the focus style correctly.
- &::before {
- top: $grid-unit-10;
- right: $grid-unit-10;
- bottom: $grid-unit-10;
- left: $grid-unit-10;
- }
-}
-
.components-popover.block-editor-block-switcher__popover .components-popover__content {
min-width: 300px;
}
diff --git a/packages/block-editor/src/components/block-tools/zoom-out-toolbar.js b/packages/block-editor/src/components/block-tools/zoom-out-toolbar.js
index 0d3df9e20dfc54..a3c46c4b4c970a 100644
--- a/packages/block-editor/src/components/block-tools/zoom-out-toolbar.js
+++ b/packages/block-editor/src/components/block-tools/zoom-out-toolbar.js
@@ -31,7 +31,12 @@ export default function ZoomOutToolbar( { clientId, __unstableContentRef } ) {
getPreviousBlockClientId,
canRemoveBlock,
canMoveBlock,
+ getSettings,
} = select( blockEditorStore );
+
+ const { __experimentalSetIsInserterOpened: setIsInserterOpened } =
+ getSettings();
+
const { getBlockType } = select( blocksStore );
const { name } = getBlock( clientId );
const blockType = getBlockType( name );
@@ -63,6 +68,7 @@ export default function ZoomOutToolbar( { clientId, __unstableContentRef } ) {
isPrevBlockTemplatePart,
canRemove: canRemoveBlock( clientId ),
canMove: canMoveBlock( clientId ),
+ setIsInserterOpened,
};
},
[ clientId ]
@@ -75,6 +81,7 @@ export default function ZoomOutToolbar( { clientId, __unstableContentRef } ) {
isPrevBlockTemplatePart,
canRemove,
canMove,
+ setIsInserterOpened,
} = selected;
const { removeBlock, __unstableSetEditorMode } =
@@ -132,6 +139,10 @@ export default function ZoomOutToolbar( { clientId, __unstableContentRef } ) {
icon={ edit }
label={ __( 'Edit' ) }
onClick={ () => {
+ // Setting may be undefined.
+ if ( typeof setIsInserterOpened === 'function' ) {
+ setIsInserterOpened( false );
+ }
__unstableSetEditorMode( 'edit' );
__unstableContentRef.current?.focus();
} }
diff --git a/packages/block-editor/src/components/global-styles/background-panel.js b/packages/block-editor/src/components/global-styles/background-panel.js
index 93fed5780e454d..c66ea01bce5498 100644
--- a/packages/block-editor/src/components/global-styles/background-panel.js
+++ b/packages/block-editor/src/components/global-styles/background-panel.js
@@ -1,71 +1,22 @@
-/**
- * External dependencies
- */
-import clsx from 'clsx';
-
/**
* WordPress dependencies
*/
import {
__experimentalToolsPanel as ToolsPanel,
__experimentalToolsPanelItem as ToolsPanelItem,
- ToggleControl,
- __experimentalToggleGroupControl as ToggleGroupControl,
- __experimentalToggleGroupControlOption as ToggleGroupControlOption,
- __experimentalUnitControl as UnitControl,
- __experimentalVStack as VStack,
- DropZone,
- FlexItem,
- FocalPointPicker,
- MenuItem,
- VisuallyHidden,
- __experimentalItemGroup as ItemGroup,
- __experimentalHStack as HStack,
- __experimentalTruncate as Truncate,
- Dropdown,
- Placeholder,
- Spinner,
- __experimentalDropdownContentWrapper as DropdownContentWrapper,
} from '@wordpress/components';
-import { __, _x, sprintf } from '@wordpress/i18n';
-import { store as noticesStore } from '@wordpress/notices';
-import { getFilename } from '@wordpress/url';
-import {
- useCallback,
- Platform,
- useRef,
- useState,
- useEffect,
- useMemo,
-} from '@wordpress/element';
-import { useDispatch, useSelect } from '@wordpress/data';
-import { focus } from '@wordpress/dom';
-import { isBlobURL } from '@wordpress/blob';
-
+import { useCallback, Platform } from '@wordpress/element';
/**
* Internal dependencies
*/
-import { useToolsPanelDropdownMenuProps, getResolvedValue } from './utils';
+import BackgroundImageControl from '../background-image-control';
+import { useToolsPanelDropdownMenuProps } from './utils';
import { setImmutably } from '../../utils/object';
-import MediaReplaceFlow from '../media-replace-flow';
-import { store as blockEditorStore } from '../../store';
-
-import {
- globalStylesDataKey,
- globalStylesLinksDataKey,
-} from '../../store/private-keys';
+import { __ } from '@wordpress/i18n';
-const IMAGE_BACKGROUND_TYPE = 'image';
const DEFAULT_CONTROLS = {
backgroundImage: true,
};
-const BACKGROUND_POPOVER_PROPS = {
- placement: 'left-start',
- offset: 36,
- shift: true,
- className: 'block-editor-global-styles-background-panel__popover',
-};
-const noop = () => {};
/**
* Checks site settings to see if the background panel may be used.
@@ -110,567 +61,6 @@ export function hasBackgroundImageValue( style ) {
);
}
-/**
- * Get the help text for the background size control.
- *
- * @param {string} value backgroundSize value.
- * @return {string} Translated help text.
- */
-function backgroundSizeHelpText( value ) {
- if ( value === 'cover' || value === undefined ) {
- return __( 'Image covers the space evenly.' );
- }
- if ( value === 'contain' ) {
- return __( 'Image is contained without distortion.' );
- }
- return __( 'Image has a fixed width.' );
-}
-
-/**
- * Converts decimal x and y coords from FocalPointPicker to percentage-based values
- * to use as backgroundPosition value.
- *
- * @param {{x?:number, y?:number}} value FocalPointPicker coords.
- * @return {string} backgroundPosition value.
- */
-export const coordsToBackgroundPosition = ( value ) => {
- if ( ! value || ( isNaN( value.x ) && isNaN( value.y ) ) ) {
- return undefined;
- }
-
- const x = isNaN( value.x ) ? 0.5 : value.x;
- const y = isNaN( value.y ) ? 0.5 : value.y;
-
- return `${ x * 100 }% ${ y * 100 }%`;
-};
-
-/**
- * Converts backgroundPosition value to x and y coords for FocalPointPicker.
- *
- * @param {string} value backgroundPosition value.
- * @return {{x?:number, y?:number}} FocalPointPicker coords.
- */
-export const backgroundPositionToCoords = ( value ) => {
- if ( ! value ) {
- return { x: undefined, y: undefined };
- }
-
- let [ x, y ] = value.split( ' ' ).map( ( v ) => parseFloat( v ) / 100 );
- x = isNaN( x ) ? undefined : x;
- y = isNaN( y ) ? x : y;
-
- return { x, y };
-};
-
-function InspectorImagePreviewItem( {
- as = 'span',
- imgUrl,
- toggleProps = {},
- filename,
- label,
- className,
- onToggleCallback = noop,
-} ) {
- useEffect( () => {
- if ( typeof toggleProps?.isOpen !== 'undefined' ) {
- onToggleCallback( toggleProps?.isOpen );
- }
- }, [ toggleProps?.isOpen, onToggleCallback ] );
- return (
-
-
- { imgUrl && (
-
-
-
- ) }
-
-
- { label }
-
-
- { imgUrl
- ? sprintf(
- /* translators: %s: file name */
- __( 'Background image: %s' ),
- filename || label
- )
- : __( 'No background image selected' ) }
-
-
-
-
- );
-}
-
-function BackgroundControlsPanel( {
- label,
- filename,
- url: imgUrl,
- children,
- onToggle: onToggleCallback = noop,
- hasImageValue,
-} ) {
- if ( ! hasImageValue ) {
- return;
- }
-
- const imgLabel =
- label || getFilename( imgUrl ) || __( 'Add background image' );
-
- return (
- {
- const toggleProps = {
- onClick: onToggle,
- className:
- 'block-editor-global-styles-background-panel__dropdown-toggle',
- 'aria-expanded': isOpen,
- 'aria-label': __(
- 'Background size, position and repeat options.'
- ),
- isOpen,
- };
- return (
-
- );
- } }
- renderContent={ () => (
-
- { children }
-
- ) }
- />
- );
-}
-
-function LoadingSpinner() {
- return (
-
-
-
- );
-}
-
-function BackgroundImageControls( {
- onChange,
- style,
- inheritedValue,
- onRemoveImage = noop,
- onResetImage = noop,
- displayInPanel,
- defaultValues,
-} ) {
- const [ isUploading, setIsUploading ] = useState( false );
- const { getSettings } = useSelect( blockEditorStore );
-
- const { id, title, url } = style?.background?.backgroundImage || {
- ...inheritedValue?.background?.backgroundImage,
- };
- const replaceContainerRef = useRef();
- const { createErrorNotice } = useDispatch( noticesStore );
- const onUploadError = ( message ) => {
- createErrorNotice( message, { type: 'snackbar' } );
- setIsUploading( false );
- };
-
- const resetBackgroundImage = () =>
- onChange(
- setImmutably(
- style,
- [ 'background', 'backgroundImage' ],
- undefined
- )
- );
-
- const onSelectMedia = ( media ) => {
- if ( ! media || ! media.url ) {
- resetBackgroundImage();
- setIsUploading( false );
- return;
- }
-
- if ( isBlobURL( media.url ) ) {
- setIsUploading( true );
- return;
- }
-
- // For media selections originated from a file upload.
- if (
- ( media.media_type &&
- media.media_type !== IMAGE_BACKGROUND_TYPE ) ||
- ( ! media.media_type &&
- media.type &&
- media.type !== IMAGE_BACKGROUND_TYPE )
- ) {
- onUploadError(
- __( 'Only images can be used as a background image.' )
- );
- return;
- }
-
- const sizeValue =
- style?.background?.backgroundSize || defaultValues?.backgroundSize;
- const positionValue = style?.background?.backgroundPosition;
- onChange(
- setImmutably( style, [ 'background' ], {
- ...style?.background,
- backgroundImage: {
- url: media.url,
- id: media.id,
- source: 'file',
- title: media.title || undefined,
- },
- backgroundPosition:
- /*
- * A background image uploaded and set in the editor receives a default background position of '50% 0',
- * when the background image size is the equivalent of "Tile".
- * This is to increase the chance that the image's focus point is visible.
- * This is in-editor only to assist with the user experience.
- */
- ! positionValue && ( 'auto' === sizeValue || ! sizeValue )
- ? '50% 0'
- : positionValue,
- backgroundSize: sizeValue,
- } )
- );
- setIsUploading( false );
- };
-
- // Drag and drop callback, restricting image to one.
- const onFilesDrop = ( filesList ) => {
- if ( filesList?.length > 1 ) {
- onUploadError(
- __( 'Only one image can be used as a background image.' )
- );
- return;
- }
- getSettings().mediaUpload( {
- allowedTypes: [ IMAGE_BACKGROUND_TYPE ],
- filesList,
- onFileChange( [ image ] ) {
- onSelectMedia( image );
- },
- onError: onUploadError,
- } );
- };
-
- const hasValue = hasBackgroundImageValue( style );
-
- const closeAndFocus = () => {
- const [ toggleButton ] = focus.tabbable.find(
- replaceContainerRef.current
- );
- // Focus the toggle button and close the dropdown menu.
- // This ensures similar behaviour as to selecting an image, where the dropdown is
- // closed and focus is redirected to the dropdown toggle button.
- toggleButton?.focus();
- toggleButton?.click();
- };
-
- const onRemove = () =>
- onChange(
- setImmutably( style, [ 'background' ], {
- backgroundImage: 'none',
- } )
- );
- const canRemove = ! hasValue && hasBackgroundImageValue( inheritedValue );
- const imgLabel =
- title || getFilename( url ) || __( 'Add background image' );
-
- return (
-
- { isUploading && }
-
- }
- variant="secondary"
- onError={ onUploadError }
- onReset={ () => {
- closeAndFocus();
- onResetImage();
- } }
- >
- { canRemove && (
- {
- closeAndFocus();
- onRemove();
- onRemoveImage();
- } }
- >
- { __( 'Remove' ) }
-
- ) }
-
-
-
- );
-}
-
-function BackgroundSizeControls( {
- onChange,
- style,
- inheritedValue,
- defaultValues,
-} ) {
- const sizeValue =
- style?.background?.backgroundSize ||
- inheritedValue?.background?.backgroundSize;
- const repeatValue =
- style?.background?.backgroundRepeat ||
- inheritedValue?.background?.backgroundRepeat;
- const imageValue =
- style?.background?.backgroundImage?.url ||
- inheritedValue?.background?.backgroundImage?.url;
- const isUploadedImage = style?.background?.backgroundImage?.id;
- const positionValue =
- style?.background?.backgroundPosition ||
- inheritedValue?.background?.backgroundPosition;
- const attachmentValue =
- style?.background?.backgroundAttachment ||
- inheritedValue?.background?.backgroundAttachment;
-
- /*
- * Set default values for uploaded images.
- * The default values are passed by the consumer.
- * Block-level controls may have different defaults to root-level controls.
- * A falsy value is treated by default as `auto` (Tile).
- */
- let currentValueForToggle =
- ! sizeValue && isUploadedImage
- ? defaultValues?.backgroundSize
- : sizeValue || 'auto';
- /*
- * The incoming value could be a value + unit, e.g. '20px'.
- * In this case set the value to 'tile'.
- */
- currentValueForToggle = ! [ 'cover', 'contain', 'auto' ].includes(
- currentValueForToggle
- )
- ? 'auto'
- : currentValueForToggle;
- /*
- * If the current value is `cover` and the repeat value is `undefined`, then
- * the toggle should be unchecked as the default state. Otherwise, the toggle
- * should reflect the current repeat value.
- */
- const repeatCheckedValue = ! (
- repeatValue === 'no-repeat' ||
- ( currentValueForToggle === 'cover' && repeatValue === undefined )
- );
-
- const updateBackgroundSize = ( next ) => {
- // When switching to 'contain' toggle the repeat off.
- let nextRepeat = repeatValue;
- let nextPosition = positionValue;
-
- if ( next === 'contain' ) {
- nextRepeat = 'no-repeat';
- nextPosition = undefined;
- }
-
- if ( next === 'cover' ) {
- nextRepeat = undefined;
- nextPosition = undefined;
- }
-
- if (
- ( currentValueForToggle === 'cover' ||
- currentValueForToggle === 'contain' ) &&
- next === 'auto'
- ) {
- nextRepeat = undefined;
- /*
- * A background image uploaded and set in the editor (an image with a record id),
- * receives a default background position of '50% 0',
- * when the toggle switches to "Tile". This is to increase the chance that
- * the image's focus point is visible.
- * This is in-editor only to assist with the user experience.
- */
- if ( !! style?.background?.backgroundImage?.id ) {
- nextPosition = '50% 0';
- }
- }
-
- /*
- * Next will be null when the input is cleared,
- * in which case the value should be 'auto'.
- */
- if ( ! next && currentValueForToggle === 'auto' ) {
- next = 'auto';
- }
-
- onChange(
- setImmutably( style, [ 'background' ], {
- ...style?.background,
- backgroundPosition: nextPosition,
- backgroundRepeat: nextRepeat,
- backgroundSize: next,
- } )
- );
- };
-
- const updateBackgroundPosition = ( next ) => {
- onChange(
- setImmutably(
- style,
- [ 'background', 'backgroundPosition' ],
- coordsToBackgroundPosition( next )
- )
- );
- };
-
- const toggleIsRepeated = () =>
- onChange(
- setImmutably(
- style,
- [ 'background', 'backgroundRepeat' ],
- repeatCheckedValue === true ? 'no-repeat' : 'repeat'
- )
- );
-
- const toggleScrollWithPage = () =>
- onChange(
- setImmutably(
- style,
- [ 'background', 'backgroundAttachment' ],
- attachmentValue === 'fixed' ? 'scroll' : 'fixed'
- )
- );
-
- // Set a default background position for non-site-wide, uploaded images with a size of 'contain'.
- const backgroundPositionValue =
- ! positionValue && isUploadedImage && 'contain' === sizeValue
- ? defaultValues?.backgroundPosition
- : positionValue;
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
-}
-
function BackgroundToolsPanel( {
resetAllFilter,
onChange,
@@ -697,54 +87,20 @@ function BackgroundToolsPanel( {
);
}
-export default function BackgroundPanel( {
+export default function BackgroundImagePanel( {
as: Wrapper = BackgroundToolsPanel,
value,
onChange,
- inheritedValue = value,
+ inheritedValue,
settings,
panelId,
defaultControls = DEFAULT_CONTROLS,
defaultValues = {},
headerLabel = __( 'Background image' ),
} ) {
- /*
- * Resolve any inherited "ref" pointers.
- * Should the block editor need resolved, inherited values
- * across all controls, this could be abstracted into a hook,
- * e.g., useResolveGlobalStyle
- */
- const { globalStyles, _links } = useSelect( ( select ) => {
- const { getSettings } = select( blockEditorStore );
- const _settings = getSettings();
- return {
- globalStyles: _settings[ globalStylesDataKey ],
- _links: _settings[ globalStylesLinksDataKey ],
- };
- }, [] );
- const resolvedInheritedValue = useMemo( () => {
- const resolvedValues = {
- background: {},
- };
-
- if ( ! inheritedValue?.background ) {
- return inheritedValue;
- }
-
- Object.entries( inheritedValue?.background ).forEach(
- ( [ key, backgroundValue ] ) => {
- resolvedValues.background[ key ] = getResolvedValue(
- backgroundValue,
- {
- styles: globalStyles,
- _links,
- }
- );
- }
- );
- return resolvedValues;
- }, [ globalStyles, _links, inheritedValue ] );
-
+ const showBackgroundImageControl = useHasBackgroundPanel( settings );
+ const resetBackground = () =>
+ onChange( setImmutably( value, [ 'background' ], {} ) );
const resetAllFilter = useCallback( ( previousValue ) => {
return {
...previousValue,
@@ -752,29 +108,6 @@ export default function BackgroundPanel( {
};
}, [] );
- const resetBackground = () =>
- onChange( setImmutably( value, [ 'background' ], {} ) );
-
- const { title, url } = value?.background?.backgroundImage || {
- ...resolvedInheritedValue?.background?.backgroundImage,
- };
- const hasImageValue =
- hasBackgroundImageValue( value ) ||
- hasBackgroundImageValue( resolvedInheritedValue );
-
- const imageValue =
- value?.background?.backgroundImage ||
- inheritedValue?.background?.backgroundImage;
-
- const shouldShowBackgroundImageControls =
- hasImageValue &&
- 'none' !== imageValue &&
- ( settings?.background?.backgroundSize ||
- settings?.background?.backgroundPosition ||
- settings?.background?.backgroundRepeat );
-
- const [ isDropDownOpen, setIsDropDownOpen ] = useState( false );
-
return (
-
+ { showBackgroundImageControl && (
!! value?.background }
label={ __( 'Image' ) }
@@ -798,53 +124,16 @@ export default function BackgroundPanel( {
isShownByDefault={ defaultControls.backgroundImage }
panelId={ panelId }
>
- { shouldShowBackgroundImageControls ? (
-
-
- {
- setIsDropDownOpen( false );
- resetBackground();
- } }
- onRemoveImage={ () =>
- setIsDropDownOpen( false )
- }
- defaultValues={ defaultValues }
- />
-
-
-
- ) : (
- {
- setIsDropDownOpen( false );
- resetBackground();
- } }
- onRemoveImage={ () => setIsDropDownOpen( false ) }
- />
- ) }
+
-
+ ) }
);
}
diff --git a/packages/block-editor/src/components/global-styles/dimensions-panel.js b/packages/block-editor/src/components/global-styles/dimensions-panel.js
index 8430703aec966d..ce508a5ebc89e5 100644
--- a/packages/block-editor/src/components/global-styles/dimensions-panel.js
+++ b/packages/block-editor/src/components/global-styles/dimensions-panel.js
@@ -531,6 +531,7 @@ export default function DimensionsPanel( {
>
{ ! showSpacingPresetsControl && (
{ ! showSpacingPresetsControl && (
{
- it( 'should return the correct coordinates for a percentage value using 2-value syntax', () => {
- expect( backgroundPositionToCoords( '25% 75%' ) ).toEqual( {
- x: 0.25,
- y: 0.75,
- } );
- } );
-
- it( 'should return the correct coordinates for a percentage using 1-value syntax', () => {
- expect( backgroundPositionToCoords( '50%' ) ).toEqual( {
- x: 0.5,
- y: 0.5,
- } );
- } );
-
- it( 'should return undefined coords in given an empty value', () => {
- expect( backgroundPositionToCoords( '' ) ).toEqual( {
- x: undefined,
- y: undefined,
- } );
- } );
-
- it( 'should return undefined coords in given a string that cannot be converted', () => {
- expect( backgroundPositionToCoords( 'apples' ) ).toEqual( {
- x: undefined,
- y: undefined,
- } );
- } );
-} );
-
-describe( 'coordsToBackgroundPosition', () => {
- it( 'should return the correct background position for a set of coordinates', () => {
- expect( coordsToBackgroundPosition( { x: 0.25, y: 0.75 } ) ).toBe(
- '25% 75%'
- );
- } );
-
- it( 'should return undefined if no coordinates are provided', () => {
- expect( coordsToBackgroundPosition( {} ) ).toBeUndefined();
- } );
-} );
+import { hasBackgroundImageValue } from '../background-panel';
describe( 'hasBackgroundImageValue', () => {
it( 'should return `true` when id and url exist', () => {
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 da3eb824fe92e5..1277ac2a239531 100644
--- a/packages/block-editor/src/components/grid/grid-item-resizer.js
+++ b/packages/block-editor/src/components/grid/grid-item-resizer.js
@@ -73,8 +73,8 @@ function GridItemResizerInner( {
}, [ blockElement, rootBlockElement ] );
const justification = {
- right: 'flex-start',
- left: 'flex-end',
+ right: 'left',
+ left: 'right',
};
const alignment = {
diff --git a/packages/block-editor/src/components/image-editor/use-save-image.js b/packages/block-editor/src/components/image-editor/use-save-image.js
index ff91a9794ca158..094ce1600545b5 100644
--- a/packages/block-editor/src/components/image-editor/use-save-image.js
+++ b/packages/block-editor/src/components/image-editor/use-save-image.js
@@ -54,6 +54,13 @@ export default function useSaveImage( {
} );
}
+ if ( modifiers.length === 0 ) {
+ // No changes to apply.
+ setIsInProgress( false );
+ onFinishEditing();
+ return;
+ }
+
apiFetch( {
path: `/wp/v2/media/${ id }/edit`,
method: 'POST',
diff --git a/packages/block-editor/src/components/inserter/style.scss b/packages/block-editor/src/components/inserter/style.scss
index 289acecb5c1c33..e772a67a131388 100644
--- a/packages/block-editor/src/components/inserter/style.scss
+++ b/packages/block-editor/src/components/inserter/style.scss
@@ -155,15 +155,6 @@ $block-inserter-tabs-height: 44px;
text-align: right;
}
-.block-editor-inserter__manage-reusable-blocks-container {
- margin: auto $grid-unit-20 $grid-unit-20;
-}
-
-.block-editor-inserter__manage-reusable-blocks {
- justify-content: center;
- width: 100%;
-}
-
.block-editor-inserter__no-results,
.block-editor-inserter__patterns-loading {
padding: $grid-unit-40;
diff --git a/packages/block-editor/src/components/list-view/index.js b/packages/block-editor/src/components/list-view/index.js
index 1493fa655a5aac..87599ea870913b 100644
--- a/packages/block-editor/src/components/list-view/index.js
+++ b/packages/block-editor/src/components/list-view/index.js
@@ -119,20 +119,16 @@ function ListViewComponent(
const blockIndexes = useListViewBlockIndexes( clientIdsTree );
const { getBlock } = useSelect( blockEditorStore );
- const { visibleBlockCount, shouldShowInnerBlocks } = useSelect(
+ const { visibleBlockCount } = useSelect(
( select ) => {
- const {
- getGlobalBlockCount,
- getClientIdsOfDescendants,
- __unstableGetEditorMode,
- } = select( blockEditorStore );
+ const { getGlobalBlockCount, getClientIdsOfDescendants } =
+ select( blockEditorStore );
const draggedBlockCount =
draggedClientIds?.length > 0
? getClientIdsOfDescendants( draggedClientIds ).length + 1
: 0;
return {
visibleBlockCount: getGlobalBlockCount() - draggedBlockCount,
- shouldShowInnerBlocks: __unstableGetEditorMode() !== 'zoom-out',
};
},
[ draggedClientIds ]
@@ -397,7 +393,6 @@ function ListViewComponent(
fixedListWindow={ fixedListWindow }
selectedClientIds={ selectedClientIds }
isExpanded={ isExpanded }
- shouldShowInnerBlocks={ shouldShowInnerBlocks }
showAppender={ showAppender }
/>
diff --git a/packages/block-editor/src/components/list-view/style.scss b/packages/block-editor/src/components/list-view/style.scss
index 3d25597d2af904..05a04abfd110b4 100644
--- a/packages/block-editor/src/components/list-view/style.scss
+++ b/packages/block-editor/src/components/list-view/style.scss
@@ -272,7 +272,7 @@
&.is-visible .block-editor-list-view-block-contents {
opacity: 1;
- @include edit-post__fade-in-animation;
+ @include animation__fade-in;
}
.block-editor-block-icon {
diff --git a/packages/block-editor/src/components/spacing-sizes-control/index.js b/packages/block-editor/src/components/spacing-sizes-control/index.js
index 6886670f541155..6ca143d14706ac 100644
--- a/packages/block-editor/src/components/spacing-sizes-control/index.js
+++ b/packages/block-editor/src/components/spacing-sizes-control/index.js
@@ -7,7 +7,7 @@ import {
__experimentalVStack as VStack,
} from '@wordpress/components';
import { useState } from '@wordpress/element';
-import { __, _x, sprintf } from '@wordpress/i18n';
+import { __, sprintf } from '@wordpress/i18n';
/**
* Internal dependencies
@@ -15,7 +15,7 @@ import { __, _x, sprintf } from '@wordpress/i18n';
import AxialInputControls from './input-controls/axial';
import SeparatedInputControls from './input-controls/separated';
import SingleInputControl from './input-controls/single';
-import SidesDropdown from './sides-dropdown';
+import LinkedButton from './linked-button';
import useSpacingSizes from './hooks/use-spacing-sizes';
import {
ALL_SIDES,
@@ -47,6 +47,10 @@ export default function SpacingSizesControl( {
const [ view, setView ] = useState( getInitialView( inputValues, sides ) );
+ const toggleLinked = () => {
+ setView( view === VIEWS.axial ? VIEWS.custom : VIEWS.axial );
+ };
+
const handleOnChange = ( nextValue ) => {
const newValues = { ...values, ...nextValue };
onChange( newValues );
@@ -91,12 +95,6 @@ export default function SpacingSizesControl( {
sideLabel
).trim();
- const dropdownLabelText = sprintf(
- // translators: %s: The current spacing property e.g. "Padding", "Margin".
- _x( '%s options', 'Button label to reveal side configuration options' ),
- labelProp
- );
-
return (
@@ -107,11 +105,10 @@ export default function SpacingSizesControl( {
{ label }
{ ! hasOneSide && ! hasOnlyAxialSides && (
-
) }
diff --git a/packages/block-editor/src/components/spacing-sizes-control/linked-button.js b/packages/block-editor/src/components/spacing-sizes-control/linked-button.js
new file mode 100644
index 00000000000000..e9ca68aaa2b31d
--- /dev/null
+++ b/packages/block-editor/src/components/spacing-sizes-control/linked-button.js
@@ -0,0 +1,32 @@
+/**
+ * WordPress dependencies
+ */
+import { Button, Tooltip } from '@wordpress/components';
+import { link, linkOff } from '@wordpress/icons';
+import { __, sprintf } from '@wordpress/i18n';
+
+export default function LinkedButton( { isLinked, ...props } ) {
+ const label = isLinked
+ ? sprintf(
+ // translators: 1. Type of spacing being modified (padding, margin, etc).
+ __( 'Unlink %1$s' ),
+ props.label.toLowerCase()
+ ).trim()
+ : sprintf(
+ // translators: 1. Type of spacing being modified (padding, margin, etc).
+ __( 'Link %1$s' ),
+ props.label.toLowerCase()
+ ).trim();
+
+ return (
+
+
+
+ );
+}
diff --git a/packages/block-editor/src/components/spacing-sizes-control/sides-dropdown/index.js b/packages/block-editor/src/components/spacing-sizes-control/sides-dropdown/index.js
deleted file mode 100644
index e399efa5b44674..00000000000000
--- a/packages/block-editor/src/components/spacing-sizes-control/sides-dropdown/index.js
+++ /dev/null
@@ -1,91 +0,0 @@
-/**
- * WordPress dependencies
- */
-import { DropdownMenu, Icon, MenuGroup, MenuItem } from '@wordpress/components';
-import { check } from '@wordpress/icons';
-
-/**
- * Internal dependencies
- */
-import { getSupportedMenuItems, VIEWS } from '../utils';
-
-const checkIcon = ;
-
-export default function SidesDropdown( {
- label: labelProp,
- onChange,
- sides,
- value,
-} ) {
- if ( ! sides || ! sides.length ) {
- return;
- }
-
- const supportedItems = getSupportedMenuItems( sides );
- const sideIcon = supportedItems[ value ].icon;
- const { custom: customItem, ...menuItems } = supportedItems;
-
- return (
-
- { ( { onClose } ) => {
- return (
- <>
-
- { Object.entries( menuItems ).map(
- ( [ slug, { label, icon } ] ) => {
- const isSelected = value === slug;
- return (
- {
- onChange( slug );
- onClose();
- } }
- suffix={
- isSelected
- ? checkIcon
- : undefined
- }
- >
- { label }
-
- );
- }
- ) }
-
- { !! customItem && (
-
- {
- onChange( VIEWS.custom );
- onClose();
- } }
- suffix={
- value === VIEWS.custom
- ? checkIcon
- : undefined
- }
- >
- { customItem.label }
-
-
- ) }
- >
- );
- } }
-
- );
-}
diff --git a/packages/block-editor/src/components/spacing-sizes-control/test/utils.js b/packages/block-editor/src/components/spacing-sizes-control/test/utils.js
index a631cbfcff3ef1..22191b4e1a8de9 100644
--- a/packages/block-editor/src/components/spacing-sizes-control/test/utils.js
+++ b/packages/block-editor/src/components/spacing-sizes-control/test/utils.js
@@ -373,8 +373,8 @@ describe( 'getInitialView', () => {
getInitialView( { top: '1em', right: '10px' }, ALL_SIDES )
).toBe( VIEWS.custom );
} );
- it( 'should not return custom view if there is only a single side value', () => {
- expect( getInitialView( { top: '1em' }, ALL_SIDES ) ).not.toBe(
+ it( 'should return custom view if there is only a single side value', () => {
+ expect( getInitialView( { top: '1em' }, ALL_SIDES ) ).toBe(
VIEWS.custom
);
} );
@@ -387,20 +387,19 @@ describe( 'getInitialView', () => {
);
} );
- it( 'should return the single side view if there is only a single side value set and supported sides > 1', () => {
- expect( getInitialView( { top: '1em' }, ALL_SIDES ) ).toBe(
- VIEWS.top
- );
- expect( getInitialView( { right: '1em' }, ALL_SIDES ) ).toBe(
- VIEWS.right
- );
- expect( getInitialView( { bottom: '1em' }, ALL_SIDES ) ).toBe(
- VIEWS.bottom
- );
- expect( getInitialView( { left: '1em' }, ALL_SIDES ) ).toBe(
- VIEWS.left
- );
+ it( 'should return single side when only single side supported and no value defined', () => {
+ expect( getInitialView( {}, [ 'top' ] ) ).toBe( VIEWS.top );
+ } );
+
+ it( 'should return single side when only single side supported and all values defined', () => {
+ expect(
+ getInitialView(
+ { top: '1em', right: '2em', bottom: '1em', left: '2em' },
+ [ 'top' ]
+ )
+ ).toBe( VIEWS.top );
} );
+
it( 'should return single side view when only one side is supported', () => {
expect( getInitialView( { top: '1em' }, [ 'top' ] ) ).toBe(
VIEWS.top
diff --git a/packages/block-editor/src/components/spacing-sizes-control/utils.js b/packages/block-editor/src/components/spacing-sizes-control/utils.js
index 91c5a91934f6e3..df2da0d93d0609 100644
--- a/packages/block-editor/src/components/spacing-sizes-control/utils.js
+++ b/packages/block-editor/src/components/spacing-sizes-control/utils.js
@@ -364,6 +364,11 @@ export function getInitialView( values = {}, sides ) {
const hasNoValuesAndBalancedSides =
! sideValues.length && hasBalancedSidesSupport( sides );
+ // Only single side supported and no value defined.
+ if ( sides?.length === 1 ) {
+ return sides[ 0 ];
+ }
+
if (
hasAxisSupport( sides ) &&
( hasMatchingAxialValues || hasNoValuesAndBalancedSides )
@@ -371,24 +376,6 @@ export function getInitialView( values = {}, sides ) {
return VIEWS.axial;
}
- // Single side.
- // - Ensure the side returned is the first side that has a value.
- if ( sideValues.length === 1 ) {
- let side;
-
- Object.entries( values ).some( ( [ key, value ] ) => {
- side = key;
- return value !== undefined;
- } );
-
- return side;
- }
-
- // Only single side supported and no value defined.
- if ( sides?.length === 1 && ! sideValues.length ) {
- return sides[ 0 ];
- }
-
// Default to the Custom (separated sides) view.
return VIEWS.custom;
}
diff --git a/packages/block-editor/src/hooks/block-bindings.js b/packages/block-editor/src/hooks/block-bindings.js
index 3b59de2238b968..be632cd4db3a25 100644
--- a/packages/block-editor/src/hooks/block-bindings.js
+++ b/packages/block-editor/src/hooks/block-bindings.js
@@ -98,7 +98,7 @@ function BlockBindingsAttribute( { attribute, binding } ) {
unlock( blocksPrivateApis ).getBlockBindingsSource( sourceName );
const isSourceInvalid = ! sourceProps;
return (
-
+
{ attribute }
{ !! binding && (
- { showColumnsControl && (
-
- ) }
- { showMinWidthControl && (
-
- ) }
+
+ { showColumnsControl && (
+
+ ) }
+ { showMinWidthControl && (
+
+ ) }
+
>
);
},
@@ -317,7 +321,7 @@ function GridLayoutColumnsAndRowsControl( {
const defaultNewColumnCount =
isManualPlacement ? 1 : undefined;
const newColumnCount =
- value === ''
+ value === '' || value === '0'
? defaultNewColumnCount
: parseInt( value, 10 );
onChange( {
@@ -327,7 +331,7 @@ function GridLayoutColumnsAndRowsControl( {
} else {
// Don't allow unsetting the column count.
const newColumnCount =
- value === ''
+ value === '' || value === '0'
? 1
: parseInt( value, 10 );
onChange( {
@@ -337,7 +341,7 @@ function GridLayoutColumnsAndRowsControl( {
}
} }
value={ columnCount }
- min={ 0 }
+ min={ 1 }
label={ __( 'Columns' ) }
hideLabelFromVision={
! window.__experimentalEnableGridInteractivity ||
@@ -355,7 +359,7 @@ function GridLayoutColumnsAndRowsControl( {
onChange={ ( value ) => {
// Don't allow unsetting the row count.
const newRowCount =
- value === ''
+ value === '' || value === '0'
? 1
: parseInt( value, 10 );
onChange( {
@@ -364,21 +368,24 @@ function GridLayoutColumnsAndRowsControl( {
} );
} }
value={ rowCount }
- min={ 0 }
+ min={ 1 }
label={ __( 'Rows' ) }
/>
) : (
onChange( {
...layout,
- columnCount: value,
+ columnCount:
+ value === '' || value === '0'
+ ? 1
+ : value,
} )
}
- min={ 0 }
+ min={ 1 }
max={ 16 }
withInputField={ false }
label={ __( 'Columns' ) }
diff --git a/packages/block-editor/src/store/private-selectors.js b/packages/block-editor/src/store/private-selectors.js
index b72ebd18183377..01ad8f69febc9e 100644
--- a/packages/block-editor/src/store/private-selectors.js
+++ b/packages/block-editor/src/store/private-selectors.js
@@ -114,6 +114,7 @@ export const getEnabledClientIdsTree = createSelector(
state.blockEditingModes,
state.settings.templateLock,
state.blockListSettings,
+ state.editorMode,
]
);
@@ -547,6 +548,15 @@ export function isZoomOutMode( state ) {
return state.editorMode === 'zoom-out';
}
+/**
+ * Retrieves the client ID of the block which contains the blocks
+ * acting as "sections" in the editor. This is typically the "main content"
+ * of the template/post.
+ *
+ * @param {Object} state Editor state.
+ *
+ * @return {string|undefined} The section root client ID or undefined if not set.
+ */
export function getSectionRootClientId( state ) {
return state.settings?.[ sectionRootClientIdKey ];
}
diff --git a/packages/block-editor/src/style.scss b/packages/block-editor/src/style.scss
index feaabbbda94426..e6ec77b55a0ec5 100644
--- a/packages/block-editor/src/style.scss
+++ b/packages/block-editor/src/style.scss
@@ -1,4 +1,5 @@
@import "./autocompleters/style.scss";
+@import "./components/background-image-control/style.scss";
@import "./components/block-alignment-control/style.scss";
@import "./components/block-canvas/style.scss";
@import "./components/block-icon/style.scss";
diff --git a/packages/block-editor/src/utils/test/transform-styles.js b/packages/block-editor/src/utils/test/transform-styles.js
index 3a68cc63c248ec..efe92cea63d0ff 100644
--- a/packages/block-editor/src/utils/test/transform-styles.js
+++ b/packages/block-editor/src/utils/test/transform-styles.js
@@ -293,7 +293,7 @@ describe( 'transformStyles', () => {
it( 'should ignore keyframes', () => {
const input = `
- @keyframes edit-post__fade-in-animation {
+ @keyframes __wp-base-styles-fade-in {
from {
opacity: 0;
}
diff --git a/packages/block-library/package.json b/packages/block-library/package.json
index 4d0212490858c9..1353ef24c77d89 100644
--- a/packages/block-library/package.json
+++ b/packages/block-library/package.json
@@ -30,6 +30,13 @@
"src/**/*.scss",
"{src,build,build-module}/*/init.js"
],
+ "wpScriptModuleExports": {
+ "./file/view": "./build-module/file/view.js",
+ "./image/view": "./build-module/image/view.js",
+ "./navigation/view": "./build-module/navigation/view.js",
+ "./query/view": "./build-module/query/view.js",
+ "./search/view": "./build-module/search/view.js"
+ },
"dependencies": {
"@babel/runtime": "^7.16.0",
"@wordpress/a11y": "file:../a11y",
diff --git a/packages/block-library/src/archives/edit.js b/packages/block-library/src/archives/edit.js
index ee9bf60fb77ec0..60b8715988ed94 100644
--- a/packages/block-library/src/archives/edit.js
+++ b/packages/block-library/src/archives/edit.js
@@ -53,7 +53,7 @@ export default function ArchivesEdit( { attributes, setAttributes } ) {
{
// This is called onMouseUp on the overlay. We can't respond to the `isSelected` prop
// changing, because that happens on mouse down, and the overlay immediately disappears,
// and the mouse event can end up in the preview content. We can't use onClick on
// the overlay to hide it either, because then the editor misses the mouseup event, and
// thinks we're multi-selecting blocks.
- this.setState( { interactive: true } );
- }
+ setInteractive( true );
+ };
- render() {
- const {
- preview,
- previewable,
- url,
- type,
- className,
- icon,
- label,
- insertBlocksAfter,
- attributes,
- setAttributes,
- isSelected,
- } = this.props;
- const { scripts } = preview;
- const { interactive } = this.state;
+ const { scripts } = preview;
- const html = 'photo' === type ? getPhotoHtml( preview ) : preview.html;
- const embedSourceUrl = getAuthority( url );
- const iframeTitle = sprintf(
- // translators: %s: host providing embed content e.g: www.youtube.com
- __( 'Embedded content from %s' ),
- embedSourceUrl
- );
- const sandboxClassnames = clsx(
- type,
- className,
- 'wp-block-embed__wrapper'
- );
+ const html = 'photo' === type ? getPhotoHtml( preview ) : preview.html;
+ const embedSourceUrl = getAuthority( url );
+ const iframeTitle = sprintf(
+ // translators: %s: host providing embed content e.g: www.youtube.com
+ __( 'Embedded content from %s' ),
+ embedSourceUrl
+ );
+ const sandboxClassnames = clsx(
+ type,
+ className,
+ 'wp-block-embed__wrapper'
+ );
- // Disabled because the overlay div doesn't actually have a role or functionality
- // as far as the user is concerned. We're just catching the first click so that
- // the block can be selected without interacting with the embed preview that the overlay covers.
- /* eslint-disable jsx-a11y/no-static-element-interactions */
- const embedWrapper =
- 'wp-embed' === type ? (
-
- ) : (
-
-
+ ) : (
+
+
+ { ! interactive && (
+
- { ! interactive && (
-
- ) }
-
- );
- /* eslint-enable jsx-a11y/no-static-element-interactions */
-
- return (
-
- { previewable ? (
- embedWrapper
- ) : (
- }
- label={ label }
- >
-
- { url }
-
-
- { sprintf(
- /* translators: %s: host providing embed content e.g: www.youtube.com */
- __(
- "Embedded content from %s can't be previewed in the editor."
- ),
- embedSourceUrl
- ) }
-
-
) }
-
-
+
);
- }
-}
+ /* eslint-enable jsx-a11y/no-static-element-interactions */
-export default EmbedPreview;
+ return (
+
+ { previewable ? (
+ embedWrapper
+ ) : (
+ }
+ label={ label }
+ >
+
+ { url }
+
+
+ { sprintf(
+ /* translators: %s: host providing embed content e.g: www.youtube.com */
+ __(
+ "Embedded content from %s can't be previewed in the editor."
+ ),
+ embedSourceUrl
+ ) }
+
+
+ ) }
+
+
+ );
+}
diff --git a/packages/block-library/src/file/index.php b/packages/block-library/src/file/index.php
index 87910f0e66a0cf..85cc840201da59 100644
--- a/packages/block-library/src/file/index.php
+++ b/packages/block-library/src/file/index.php
@@ -21,7 +21,7 @@ function render_block_core_file( $attributes, $content ) {
if ( ! empty( $attributes['displayPreview'] ) ) {
$suffix = wp_scripts_get_suffix();
if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) {
- $module_url = gutenberg_url( '/build/interactivity/file.min.js' );
+ $module_url = gutenberg_url( '/build-module/block-library/file/view.min.js' );
}
wp_register_script_module(
diff --git a/packages/block-library/src/file/transforms.js b/packages/block-library/src/file/transforms.js
index b925e80e595033..c381a62f783866 100644
--- a/packages/block-library/src/file/transforms.js
+++ b/packages/block-library/src/file/transforms.js
@@ -24,12 +24,32 @@ const transforms = {
const blobURL = createBlobURL( file );
// File will be uploaded in componentDidMount()
- blocks.push(
- createBlock( 'core/file', {
- blob: blobURL,
- fileName: file.name,
- } )
- );
+ if ( file.type.startsWith( 'video/' ) ) {
+ blocks.push(
+ createBlock( 'core/video', {
+ blob: createBlobURL( file ),
+ } )
+ );
+ } else if ( file.type.startsWith( 'image/' ) ) {
+ blocks.push(
+ createBlock( 'core/image', {
+ blob: createBlobURL( file ),
+ } )
+ );
+ } else if ( file.type.startsWith( 'audio/' ) ) {
+ blocks.push(
+ createBlock( 'core/audio', {
+ blob: createBlobURL( file ),
+ } )
+ );
+ } else {
+ blocks.push(
+ createBlock( 'core/file', {
+ blob: blobURL,
+ fileName: file.name,
+ } )
+ );
+ }
} );
return blocks;
diff --git a/packages/block-library/src/form-input/deprecated.js b/packages/block-library/src/form-input/deprecated.js
index 9cd49d5b0011be..451cc704a42d55 100644
--- a/packages/block-library/src/form-input/deprecated.js
+++ b/packages/block-library/src/form-input/deprecated.js
@@ -9,6 +9,7 @@ import removeAccents from 'remove-accents';
*/
import {
RichText,
+ useBlockProps,
__experimentalGetBorderClassesAndStyles as getBorderClassesAndStyles,
__experimentalGetColorClassesAndStyles as getColorClassesAndStyles,
} from '@wordpress/block-editor';
@@ -26,6 +27,118 @@ const getNameFromLabelV1 = ( content ) => {
);
};
+const v2 = {
+ attributes: {
+ type: {
+ type: 'string',
+ default: 'text',
+ },
+ name: {
+ type: 'string',
+ },
+ label: {
+ type: 'string',
+ default: 'Label',
+ selector: '.wp-block-form-input__label-content',
+ source: 'html',
+ __experimentalRole: 'content',
+ },
+ inlineLabel: {
+ type: 'boolean',
+ default: false,
+ },
+ required: {
+ type: 'boolean',
+ default: false,
+ selector: '.wp-block-form-input__input',
+ source: 'attribute',
+ attribute: 'required',
+ },
+ placeholder: {
+ type: 'string',
+ selector: '.wp-block-form-input__input',
+ source: 'attribute',
+ attribute: 'placeholder',
+ __experimentalRole: 'content',
+ },
+ value: {
+ type: 'string',
+ default: '',
+ selector: 'input',
+ source: 'attribute',
+ attribute: 'value',
+ },
+ visibilityPermissions: {
+ type: 'string',
+ default: 'all',
+ },
+ },
+ supports: {
+ anchor: true,
+ reusable: false,
+ spacing: {
+ margin: [ 'top', 'bottom' ],
+ },
+ __experimentalBorder: {
+ radius: true,
+ __experimentalSkipSerialization: true,
+ __experimentalDefaultControls: {
+ radius: true,
+ },
+ },
+ },
+ save( { attributes } ) {
+ const { type, name, label, inlineLabel, required, placeholder, value } =
+ attributes;
+
+ const borderProps = getBorderClassesAndStyles( attributes );
+ const colorProps = getColorClassesAndStyles( attributes );
+
+ const inputStyle = {
+ ...borderProps.style,
+ ...colorProps.style,
+ };
+
+ const inputClasses = clsx(
+ 'wp-block-form-input__input',
+ colorProps.className,
+ borderProps.className
+ );
+ const TagName = type === 'textarea' ? 'textarea' : 'input';
+
+ const blockProps = useBlockProps.save();
+
+ if ( 'hidden' === type ) {
+ return ;
+ }
+
+ return (
+
+ { /* eslint-disable jsx-a11y/label-has-associated-control */ }
+
+
+
+
+
+
+ { /* eslint-enable jsx-a11y/label-has-associated-control */ }
+
+ );
+ },
+};
+
// Version without wrapper div in saved markup
// See: https://github.com/WordPress/gutenberg/pull/56507
const v1 = {
@@ -137,6 +250,6 @@ const v1 = {
},
};
-const deprecated = [ v1 ];
+const deprecated = [ v2, v1 ];
export default deprecated;
diff --git a/packages/block-library/src/form-input/edit.js b/packages/block-library/src/form-input/edit.js
index 6939443011ee5b..5f3713e83975f1 100644
--- a/packages/block-library/src/form-input/edit.js
+++ b/packages/block-library/src/form-input/edit.js
@@ -31,6 +31,9 @@ function InputFieldBlock( { attributes, setAttributes, className } ) {
ref.current.focus();
}
+ // Note: radio inputs aren't implemented yet.
+ const isCheckboxOrRadio = type === 'checkbox' || type === 'radio';
+
const controls = (
<>
{ 'hidden' !== type && (
@@ -81,6 +84,18 @@ function InputFieldBlock( { attributes, setAttributes, className } ) {
>
);
+ const content = (
+ setAttributes( { label: newLabel } ) }
+ aria-label={ label ? __( 'Label' ) : __( 'Empty label' ) }
+ data-empty={ ! label }
+ placeholder={ __( 'Type the label for this input' ) }
+ />
+ );
+
if ( 'hidden' === type ) {
return (
<>
@@ -111,17 +126,7 @@ function InputFieldBlock( { attributes, setAttributes, className } ) {
'is-label-inline': inlineLabel || 'checkbox' === type,
} ) }
>
-
- setAttributes( { label: newLabel } )
- }
- aria-label={ label ? __( 'Label' ) : __( 'Empty label' ) }
- data-empty={ label ? false : true }
- placeholder={ __( 'Type the label for this input' ) }
- />
+ { ! isCheckboxOrRadio && content }
+ { isCheckboxOrRadio && content }
);
diff --git a/packages/block-library/src/form-input/save.js b/packages/block-library/src/form-input/save.js
index c408e06923ca9f..941c23dc2014d1 100644
--- a/packages/block-library/src/form-input/save.js
+++ b/packages/block-library/src/form-input/save.js
@@ -55,6 +55,9 @@ export default function save( { attributes } ) {
const blockProps = useBlockProps.save();
+ // Note: radio inputs aren't implemented yet.
+ const isCheckboxOrRadio = type === 'checkbox' || type === 'radio';
+
if ( 'hidden' === type ) {
return ;
}
@@ -67,9 +70,11 @@ export default function save( { attributes } ) {
'is-label-inline': inlineLabel,
} ) }
>
-
-
-
+ { ! isCheckboxOrRadio && (
+
+
+
+ ) }
+ { isCheckboxOrRadio && (
+
+
+
+ ) }
{ /* eslint-enable jsx-a11y/label-has-associated-control */ }
diff --git a/packages/block-library/src/form-input/style.scss b/packages/block-library/src/form-input/style.scss
index f9e1753cf0a7b7..7b1ac53cc89c01 100644
--- a/packages/block-library/src/form-input/style.scss
+++ b/packages/block-library/src/form-input/style.scss
@@ -15,16 +15,17 @@
}
}
- /*
- Small tweak to left-align the checkbox.
- Even though `:has` is not currently supported in Firefox, this is a small tweak
- and does not affect the functionality of the block or the user's experience.
- There will be a minor inconsistency between browsers. However, it's more important to provide
- a better experience for 80+% of users, until Firefox catches up and supports `:has`.
- */
&:has(input[type="checkbox"]) {
+ flex-direction: row;
width: fit-content;
- /* stylelint-disable-next-line declaration-property-value-allowed-list -- This should be refactored to not use the row-reverse value. */
+
+ .wp-block-form-input__label-content {
+ margin: 0;
+ }
+ }
+
+ &:has(.wp-block-form-input__label-content + input[type="checkbox"]) {
+ /* stylelint-disable-next-line declaration-property-value-allowed-list -- This style is required for old markup. */
flex-direction: row-reverse;
}
}
diff --git a/packages/block-library/src/image/edit.js b/packages/block-library/src/image/edit.js
index f9aed8d93f95a0..d44dc73abfd855 100644
--- a/packages/block-library/src/image/edit.js
+++ b/packages/block-library/src/image/edit.js
@@ -12,8 +12,8 @@ import { Placeholder } from '@wordpress/components';
import { useDispatch, useSelect } from '@wordpress/data';
import {
BlockIcon,
- MediaPlaceholder,
useBlockProps,
+ MediaPlaceholder,
store as blockEditorStore,
__experimentalUseBorderProps as useBorderProps,
__experimentalGetShadowClassesAndStyles as getShadowClassesAndStyles,
@@ -32,6 +32,7 @@ import { unlock } from '../lock-unlock';
import { useUploadMediaFromBlobURL } from '../utils/hooks';
import Image from './image';
import { isValidFileType } from './utils';
+import { useMaxWidthObserver } from './use-max-width-observer';
/**
* Module constants
@@ -109,12 +110,23 @@ export function ImageEdit( {
align,
metadata,
} = attributes;
+
const [ temporaryURL, setTemporaryURL ] = useState( attributes.blob );
- const figureRef = useRef();
- const [ contentResizeListener, { width: containerWidth } ] =
+ const containerRef = useRef();
+ // Only observe the max width from the parent container when the parent layout is not flex nor grid.
+ // This won't work for them because the container width changes with the image.
+ // TODO: Find a way to observe the container width for flex and grid layouts.
+ const isMaxWidthContainerWidth =
+ ! parentLayout ||
+ ( parentLayout.type !== 'flex' && parentLayout.type !== 'grid' );
+ const [ maxWidthObserver, maxContentWidth ] = useMaxWidthObserver();
+
+ const [ placeholderResizeListener, { width: placeholderWidth } ] =
useResizeObserver();
+ const isSmallContainer = placeholderWidth && placeholderWidth < 160;
+
const altRef = useRef();
useEffect( () => {
altRef.current = alt;
@@ -160,7 +172,7 @@ export function ImageEdit( {
}
function onSelectImagesList( images ) {
- const win = figureRef.current?.ownerDocument.defaultView;
+ const win = containerRef.current?.ownerDocument.defaultView;
if ( images.every( ( file ) => file instanceof win.File ) ) {
/** @type {File[]} */
@@ -348,7 +360,10 @@ export function ImageEdit( {
Object.keys( borderProps.style ).length > 0 ),
} );
- const blockProps = useBlockProps( { ref: figureRef, className: classes } );
+ const blockProps = useBlockProps( {
+ ref: containerRef,
+ className: classes,
+ } );
// Much of this description is duplicated from MediaPlaceholder.
const { lockUrlControls = false, lockUrlControlsMessage } = useSelect(
@@ -387,11 +402,15 @@ export function ImageEdit( {
[ borderProps.className ]:
!! borderProps.className && ! isSingleSelected,
} ) }
- withIllustration
- icon={ lockUrlControls ? pluginsIcon : icon }
- label={ __( 'Image' ) }
+ icon={
+ ! isSmallContainer &&
+ ( lockUrlControls ? pluginsIcon : icon )
+ }
+ withIllustration={ ! isSingleSelected || isSmallContainer }
+ label={ ! isSmallContainer && __( 'Image' ) }
instructions={
! lockUrlControls &&
+ ! isSmallContainer &&
__(
'Upload or drag an image file here, or pick one from your library.'
)
@@ -408,13 +427,12 @@ export function ImageEdit( {
...shadowProps.style,
} }
>
- { lockUrlControls ? (
-
- { lockUrlControlsMessage }
-
- ) : (
- content
- ) }
+ { lockUrlControls &&
+ ! isSmallContainer &&
+ lockUrlControlsMessage }
+
+ { ! lockUrlControls && ! isSmallContainer && content }
+ { placeholderResizeListener }
);
};
@@ -436,7 +454,7 @@ export function ImageEdit( {
clientId={ clientId }
blockEditingMode={ blockEditingMode }
parentLayoutType={ parentLayout?.type }
- containerWidth={ containerWidth }
+ maxContentWidth={ maxContentWidth }
/>
}
@@ -455,7 +473,7 @@ export function ImageEdit( {
{
// The listener cannot be placed as the first element as it will break the in-between inserter.
// See https://github.com/WordPress/gutenberg/blob/71134165868298fc15e22896d0c28b41b3755ff7/packages/block-editor/src/components/block-list/use-in-between-inserter.js#L120
- contentResizeListener
+ isSingleSelected && isMaxWidthContainerWidth && maxWidthObserver
}
>
);
diff --git a/packages/block-library/src/image/editor.scss b/packages/block-library/src/image/editor.scss
index 636741c7d9ddbb..34f65d690d3d74 100644
--- a/packages/block-library/src/image/editor.scss
+++ b/packages/block-library/src/image/editor.scss
@@ -1,44 +1,8 @@
// Provide special styling for the placeholder.
// @todo this particular minimal style of placeholder could be componentized further.
.wp-block-image.wp-block-image {
-
- // Show Placeholder style on-select.
- &.is-selected .block-editor-media-placeholder {
- // Block UI appearance.
- color: $gray-900;
- background-color: $white;
- box-shadow: inset 0 0 0 $border-width $gray-900;
- border: none;
-
- // Disable any duotone filter applied in the selected state.
- filter: none !important;
-
- > svg {
- opacity: 0;
- }
-
- .components-placeholder__illustration {
- display: none;
- }
-
- &::before {
- opacity: 0;
- }
- }
- .block-bindings-media-placeholder-message {
- opacity: 0;
- }
- &.is-selected .block-bindings-media-placeholder-message {
- opacity: 1;
- }
-
- // Remove the transition while we still have a legacy placeholder style.
- // Otherwise the content jumps between the 1px placeholder border, and any inherited custom
- // parent border that may get applied when you deselect.
- .components-placeholder__label,
- .components-placeholder__instructions,
- .components-button {
- transition: none;
+ .block-editor-media-placeholder.is-small {
+ min-height: 60px;
}
}
@@ -149,6 +113,11 @@ figure.wp-block-image:not(.wp-block) {
text-align: center;
}
+// Relatively position the alignment container to support the content resizer.
+.wp-block[data-align]:has(> .wp-block-image) {
+ position: relative;
+}
+
.wp-block-image__crop-area {
position: relative;
max-width: 100%;
diff --git a/packages/block-library/src/image/image.js b/packages/block-library/src/image/image.js
index 2de316f78ba5d8..1673d36e463d5a 100644
--- a/packages/block-library/src/image/image.js
+++ b/packages/block-library/src/image/image.js
@@ -108,7 +108,7 @@ export default function Image( {
clientId,
blockEditingMode,
parentLayoutType,
- containerWidth,
+ maxContentWidth,
} ) {
const {
url = '',
@@ -556,6 +556,25 @@ export default function Image( {
const showBlockControls = showUrlInput || allowCrop || showCoverControls;
+ const mediaReplaceFlow = isSingleSelected &&
+ ! isEditingImage &&
+ ! lockUrlControls && (
+ // For contentOnly mode, put this button in its own area so it has borders around it.
+
+ onSelectImage( undefined ) }
+ />
+
+ );
+
const controls = (
<>
{ showBlockControls && (
@@ -592,20 +611,6 @@ export default function Image( {
) }
) }
- { isSingleSelected && ! isEditingImage && ! lockUrlControls && (
-
- onSelectImage( undefined ) }
- />
-
- ) }
{ isSingleSelected && externalBlob && (
@@ -934,7 +939,7 @@ export default function Image( {
// @todo It would be good to revisit this once a content-width variable
// becomes available.
const maxWidthBuffer = maxWidth * 2.5;
- const maxContentWidth = containerWidth || maxWidthBuffer;
+ const maxResizeWidth = maxContentWidth || maxWidthBuffer;
let showRightHandle = false;
let showLeftHandle = false;
@@ -980,9 +985,9 @@ export default function Image( {
} }
showHandle={ isSingleSelected }
minWidth={ minWidth }
- maxWidth={ maxContentWidth }
+ maxWidth={ maxResizeWidth }
minHeight={ minHeight }
- maxHeight={ maxContentWidth / ratio }
+ maxHeight={ maxResizeWidth / ratio }
lockAspectRatio={ ratio }
enable={ {
top: false,
@@ -996,6 +1001,7 @@ export default function Image( {
// Clear hardcoded width if the resized width is close to the max-content width.
if (
+ maxContentWidth &&
// Only do this if the image is bigger than the container to prevent it from being squished.
// TODO: Remove this check if the image support setting 100% width.
naturalWidth >= maxContentWidth &&
@@ -1029,12 +1035,18 @@ export default function Image( {
}
if ( ! url && ! temporaryURL ) {
- // Add all controls if the image attributes are connected.
- return metadata?.bindings ? controls : sizeControls;
+ return (
+ <>
+ { mediaReplaceFlow }
+ { /* Add all controls if the image attributes are connected. */ }
+ { metadata?.bindings ? controls : sizeControls }
+ >
+ );
}
return (
<>
+ { mediaReplaceFlow }
{ controls }
{ img }
diff --git a/packages/block-library/src/image/index.php b/packages/block-library/src/image/index.php
index 75f0d404e4820c..abbb03c0952452 100644
--- a/packages/block-library/src/image/index.php
+++ b/packages/block-library/src/image/index.php
@@ -72,7 +72,7 @@ function render_block_core_image( $attributes, $content, $block ) {
) {
$suffix = wp_scripts_get_suffix();
if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) {
- $module_url = gutenberg_url( '/build/interactivity/image.min.js' );
+ $module_url = gutenberg_url( '/build-module/block-library/image/view.min.js' );
}
wp_register_script_module(
diff --git a/packages/block-library/src/image/transforms.js b/packages/block-library/src/image/transforms.js
index 0e1dfb6ee9da44..347d2408280170 100644
--- a/packages/block-library/src/image/transforms.js
+++ b/packages/block-library/src/image/transforms.js
@@ -3,9 +3,6 @@
*/
import { createBlobURL, isBlobURL } from '@wordpress/blob';
import { createBlock, getBlockAttributes } from '@wordpress/blocks';
-import { dispatch } from '@wordpress/data';
-import { store as noticesStore } from '@wordpress/notices';
-import { __ } from '@wordpress/i18n';
export function stripFirstImage( attributes, { shortcode } ) {
const { body } = document.implementation.createHTMLDocument( '' );
@@ -138,26 +135,6 @@ const transforms = {
// creating a new gallery.
type: 'files',
isMatch( files ) {
- // The following check is intended to catch non-image files when dropped together with images.
- if (
- files.some(
- ( file ) => file.type.indexOf( 'image/' ) === 0
- ) &&
- files.some(
- ( file ) => file.type.indexOf( 'image/' ) !== 0
- )
- ) {
- const { createErrorNotice } = dispatch( noticesStore );
- createErrorNotice(
- __(
- 'If uploading to a gallery all files need to be image formats'
- ),
- {
- id: 'gallery-transform-invalid-file',
- type: 'snackbar',
- }
- );
- }
return files.every(
( file ) => file.type.indexOf( 'image/' ) === 0
);
diff --git a/packages/block-library/src/image/use-max-width-observer.js b/packages/block-library/src/image/use-max-width-observer.js
new file mode 100644
index 00000000000000..684392537fac7a
--- /dev/null
+++ b/packages/block-library/src/image/use-max-width-observer.js
@@ -0,0 +1,32 @@
+/**
+ * WordPress dependencies
+ */
+import { useRef } from '@wordpress/element';
+import { useResizeObserver } from '@wordpress/compose';
+
+function useMaxWidthObserver() {
+ const [ contentResizeListener, { width } ] = useResizeObserver();
+ const observerRef = useRef();
+
+ const maxWidthObserver = (
+
+ { contentResizeListener }
+
+ );
+
+ return [ maxWidthObserver, width ];
+}
+
+export { useMaxWidthObserver };
diff --git a/packages/block-library/src/latest-posts/edit.js b/packages/block-library/src/latest-posts/edit.js
index b02747bb1c1d8e..ab792ae0e353db 100644
--- a/packages/block-library/src/latest-posts/edit.js
+++ b/packages/block-library/src/latest-posts/edit.js
@@ -243,7 +243,7 @@ export default function LatestPostsEdit( { attributes, setAttributes } ) {
{ displayPostContent && (
- { createInterpolateElement(
- __(
- 'Navigation Menu has been deleted or is unavailable. Create a new Menu? '
- ),
- {
- button: (
-
- ),
- }
- ) }
-
+function DeletedNavigationWarning( { onCreateNew, isNotice = false } ) {
+ const message = createInterpolateElement(
+ __(
+ 'Navigation Menu has been deleted or is unavailable. Create a new Menu? '
+ ),
+ {
+ button: (
+
+ ),
+ }
+ );
+
+ return isNotice ? (
+
+ { message }
+
+ ) : (
+ { message }
);
}
diff --git a/packages/block-library/src/navigation/edit/menu-inspector-controls.js b/packages/block-library/src/navigation/edit/menu-inspector-controls.js
index e21655eef90715..8f6c2e47fe7759 100644
--- a/packages/block-library/src/navigation/edit/menu-inspector-controls.js
+++ b/packages/block-library/src/navigation/edit/menu-inspector-controls.js
@@ -94,7 +94,9 @@ const MainContent = ( {
const { navigationMenu } = useNavigationMenu( currentMenuId );
if ( currentMenuId && isNavigationMenuMissing ) {
- return ;
+ return (
+
+ );
}
if ( isLoading ) {
diff --git a/packages/block-library/src/navigation/index.php b/packages/block-library/src/navigation/index.php
index ccadd5c4a222d4..ec72b03b6906f0 100644
--- a/packages/block-library/src/navigation/index.php
+++ b/packages/block-library/src/navigation/index.php
@@ -624,7 +624,7 @@ private static function handle_view_script_module_loading( $attributes, $block,
if ( static::is_interactive( $attributes, $inner_blocks ) ) {
$suffix = wp_scripts_get_suffix();
if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) {
- $module_url = gutenberg_url( '/build/interactivity/navigation.min.js' );
+ $module_url = gutenberg_url( '/build-module/block-library/navigation/view.min.js' );
}
wp_register_script_module(
diff --git a/packages/block-library/src/post-template/edit.js b/packages/block-library/src/post-template/edit.js
index 70f960a2197430..a9e279ee2c3052 100644
--- a/packages/block-library/src/post-template/edit.js
+++ b/packages/block-library/src/post-template/edit.js
@@ -90,6 +90,7 @@ export default function PostTemplateEdit( {
taxQuery,
parents,
pages,
+ format,
// We gather extra query args to pass to the REST API call.
// This way extenders of Query Loop can add their own query args,
// and have accurate previews in the editor.
@@ -163,6 +164,10 @@ export default function PostTemplateEdit( {
if ( parents?.length ) {
query.parent = parents;
}
+ if ( format?.length ) {
+ query.format = format;
+ }
+
// If sticky is not set, it will return all posts in the results.
// If sticky is set to `only`, it will limit the results to sticky posts only.
// If it is anything else, it will exclude sticky posts from results. For the record the value stored is `exclude`.
@@ -205,6 +210,7 @@ export default function PostTemplateEdit( {
templateSlug,
taxQuery,
parents,
+ format,
restQueryArgs,
previewPostType,
]
diff --git a/packages/block-library/src/query/block.json b/packages/block-library/src/query/block.json
index b602032df36005..9eb84959638236 100644
--- a/packages/block-library/src/query/block.json
+++ b/packages/block-library/src/query/block.json
@@ -25,7 +25,8 @@
"sticky": "",
"inherit": true,
"taxQuery": null,
- "parents": []
+ "parents": [],
+ "format": []
}
},
"tagName": {
diff --git a/packages/block-library/src/query/edit/inspector-controls/format-controls.js b/packages/block-library/src/query/edit/inspector-controls/format-controls.js
new file mode 100644
index 00000000000000..d26fd9d81ce6f7
--- /dev/null
+++ b/packages/block-library/src/query/edit/inspector-controls/format-controls.js
@@ -0,0 +1,90 @@
+/**
+ * WordPress dependencies
+ */
+import { FormTokenField } from '@wordpress/components';
+import { useSelect } from '@wordpress/data';
+import { store as coreStore } from '@wordpress/core-data';
+import { __ } from '@wordpress/i18n';
+
+// All WP post formats, sorted alphabetically by translated name.
+// Value is the post format slug. Label is the name.
+const POST_FORMATS = [
+ { value: 'aside', label: __( 'Aside' ) },
+ { value: 'audio', label: __( 'Audio' ) },
+ { value: 'chat', label: __( 'Chat' ) },
+ { value: 'gallery', label: __( 'Gallery' ) },
+ { value: 'image', label: __( 'Image' ) },
+ { value: 'link', label: __( 'Link' ) },
+ { value: 'quote', label: __( 'Quote' ) },
+ { value: 'standard', label: __( 'Standard' ) },
+ { value: 'status', label: __( 'Status' ) },
+ { value: 'video', label: __( 'Video' ) },
+].sort( ( a, b ) => {
+ const normalizedA = a.label.toUpperCase();
+ const normalizedB = b.label.toUpperCase();
+
+ if ( normalizedA < normalizedB ) {
+ return -1;
+ }
+ if ( normalizedA > normalizedB ) {
+ return 1;
+ }
+ return 0;
+} );
+
+// A helper function to convert translatable post format names into their static values.
+function formatNamesToValues( names, formats ) {
+ return names
+ .map( ( name ) => {
+ return formats.find(
+ ( item ) =>
+ item.label.toLocaleLowerCase() === name.toLocaleLowerCase()
+ )?.value;
+ } )
+ .filter( Boolean );
+}
+
+export default function FormatControls( { onChange, query: { format } } ) {
+ // 'format' is expected to be an array. If it is not an array, for example
+ // if a user has manually entered an invalid value in the block markup,
+ // convert it to an array to prevent JavaScript errors.
+ const normalizedFormats = Array.isArray( format ) ? format : [ format ];
+
+ const { supportedFormats } = useSelect( ( select ) => {
+ const themeSupports = select( coreStore ).getThemeSupports();
+ return {
+ supportedFormats: themeSupports.formats,
+ };
+ }, [] );
+
+ const formats = POST_FORMATS.filter( ( item ) =>
+ supportedFormats.includes( item.value )
+ );
+
+ const values = normalizedFormats
+ .map(
+ ( name ) => formats.find( ( item ) => item.value === name )?.label
+ )
+ .filter( Boolean );
+
+ const suggestions = formats
+ .filter( ( item ) => ! format.includes( item.value ) )
+ .map( ( item ) => item.label );
+
+ return (
+ {
+ onChange( {
+ format: formatNamesToValues( newValues, formats ),
+ } );
+ } }
+ __experimentalShowHowTo={ false }
+ __experimentalExpandOnFocus
+ __nextHasNoMarginBottom
+ __next40pxDefaultSize
+ />
+ );
+}
diff --git a/packages/block-library/src/query/edit/inspector-controls/index.js b/packages/block-library/src/query/edit/inspector-controls/index.js
index 010e57b2da4fc6..6c246ab89b3b37 100644
--- a/packages/block-library/src/query/edit/inspector-controls/index.js
+++ b/packages/block-library/src/query/edit/inspector-controls/index.js
@@ -12,6 +12,8 @@ import {
__experimentalToolsPanel as ToolsPanel,
__experimentalToolsPanelItem as ToolsPanelItem,
} from '@wordpress/components';
+import { useSelect } from '@wordpress/data';
+import { store as coreStore } from '@wordpress/core-data';
import { __ } from '@wordpress/i18n';
import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor';
import { debounce } from '@wordpress/compose';
@@ -24,6 +26,7 @@ import OrderControl from './order-control';
import AuthorControl from './author-control';
import ParentControl from './parent-control';
import { TaxonomyControls } from './taxonomy-controls';
+import FormatControls from './format-controls';
import StickyControl from './sticky-control';
import CreateNewPostLink from './create-new-post-link';
import PerPageControl from './per-page-control';
@@ -56,10 +59,15 @@ export default function QueryInspectorControls( props ) {
inherit,
taxQuery,
parents,
+ format,
} = query;
const allowedControls = useAllowedControls( attributes );
const [ showSticky, setShowSticky ] = useState( postType === 'post' );
- const { postTypesTaxonomiesMap, postTypesSelectOptions } = usePostTypes();
+ const {
+ postTypesTaxonomiesMap,
+ postTypesSelectOptions,
+ postTypeFormatSupportMap,
+ } = usePostTypes();
const taxonomies = useTaxonomies( postType );
const isPostTypeHierarchical = useIsPostTypeHierarchical( postType );
useEffect( () => {
@@ -88,6 +96,13 @@ export default function QueryInspectorControls( props ) {
}
// We need to reset `parents` because they are tied to each post type.
updateQuery.parents = [];
+ // Post types can register post format support with `add_post_type_support`.
+ // But we need to reset the `format` property when switching to post types
+ // that do not support post formats.
+ const hasFormatSupport = postTypeFormatSupportMap[ newValue ];
+ if ( ! hasFormatSupport ) {
+ updateQuery.format = [];
+ }
setQuery( updateQuery );
};
const [ querySearch, setQuerySearch ] = useState( query.search );
@@ -132,11 +147,36 @@ export default function QueryInspectorControls( props ) {
isControlAllowed( allowedControls, 'parents' ) &&
isPostTypeHierarchical;
+ const postTypeHasFormatSupport = postTypeFormatSupportMap[ postType ];
+ const showFormatControl = useSelect(
+ ( select ) => {
+ // Check if the post type supports post formats and if the control is allowed.
+ if (
+ ! postTypeHasFormatSupport ||
+ ! isControlAllowed( allowedControls, 'format' )
+ ) {
+ return false;
+ }
+
+ const themeSupports = select( coreStore ).getThemeSupports();
+
+ // If there are no supported formats, getThemeSupports still includes the default 'standard' format,
+ // and in this case the control should not be shown since the user has no other formats to choose from.
+ return (
+ themeSupports.formats &&
+ themeSupports.formats.length > 0 &&
+ themeSupports.formats.some( ( type ) => type !== 'standard' )
+ );
+ },
+ [ allowedControls, postTypeHasFormatSupport ]
+ );
+
const showFiltersPanel =
showTaxControl ||
showAuthorControl ||
showSearchControl ||
- showParentControl;
+ showParentControl ||
+ showFormatControl;
const dropdownMenuProps = useToolsPanelDropdownMenuProps();
const showPostCountControl = isControlAllowed(
@@ -313,6 +353,7 @@ export default function QueryInspectorControls( props ) {
parents: [],
search: '',
taxQuery: null,
+ format: [],
} );
setQuerySearch( '' );
} }
@@ -374,6 +415,18 @@ export default function QueryInspectorControls( props ) {
/>
) }
+ { showFormatControl && (
+ !! format?.length }
+ label={ __( 'Formats' ) }
+ onDeselect={ () => setQuery( { format: [] } ) }
+ >
+
+
+ ) }
) }
>
diff --git a/packages/block-library/src/query/index.php b/packages/block-library/src/query/index.php
index 6cc57dc08388c6..d10db26529854e 100644
--- a/packages/block-library/src/query/index.php
+++ b/packages/block-library/src/query/index.php
@@ -26,7 +26,7 @@ function render_block_core_query( $attributes, $content, $block ) {
if ( $is_interactive ) {
$suffix = wp_scripts_get_suffix();
if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) {
- $module_url = gutenberg_url( '/build/interactivity/query.min.js' );
+ $module_url = gutenberg_url( '/build-module/block-library/query/view.min.js' );
}
wp_register_script_module(
diff --git a/packages/block-library/src/query/utils.js b/packages/block-library/src/query/utils.js
index 2e9412b1683cb0..68da2573bab0f6 100644
--- a/packages/block-library/src/query/utils.js
+++ b/packages/block-library/src/query/utils.js
@@ -94,6 +94,7 @@ export const mapToIHasNameAndId = ( entities, path ) => {
* Returns a helper object that contains:
* 1. An `options` object from the available post types, to be passed to a `SelectControl`.
* 2. A helper map with available taxonomies per post type.
+ * 3. A helper map with post format support per post type.
*
* @return {Object} The helper object related to post types.
*/
@@ -124,7 +125,21 @@ export const usePostTypes = () => {
} ) ),
[ postTypes ]
);
- return { postTypesTaxonomiesMap, postTypesSelectOptions };
+ const postTypeFormatSupportMap = useMemo( () => {
+ if ( ! postTypes?.length ) {
+ return {};
+ }
+ return postTypes.reduce( ( accumulator, type ) => {
+ accumulator[ type.slug ] =
+ type.supports?.[ 'post-formats' ] || false;
+ return accumulator;
+ }, {} );
+ }, [ postTypes ] );
+ return {
+ postTypesTaxonomiesMap,
+ postTypesSelectOptions,
+ postTypeFormatSupportMap,
+ };
};
/**
diff --git a/packages/block-library/src/search/index.php b/packages/block-library/src/search/index.php
index 39b8591c86600f..fb09cdd36406e8 100644
--- a/packages/block-library/src/search/index.php
+++ b/packages/block-library/src/search/index.php
@@ -82,7 +82,7 @@ function render_block_core_search( $attributes ) {
if ( $is_expandable_searchfield ) {
$suffix = wp_scripts_get_suffix();
if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) {
- $module_url = gutenberg_url( '/build/interactivity/search.min.js' );
+ $module_url = gutenberg_url( '/build-module/block-library/search/view.min.js' );
}
wp_register_script_module(
diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md
index 8c656f4adb48bb..1473cf5f5df40e 100644
--- a/packages/components/CHANGELOG.md
+++ b/packages/components/CHANGELOG.md
@@ -2,6 +2,11 @@
## Unreleased
+### Bug Fixes
+
+- `Tabs`: indicator positioning under RTL direction ([#64926](https://github.com/WordPress/gutenberg/pull/64926)).
+- `Popover`: Update `toolbar` variant radius to match block toolbar ([#65263](https://github.com/WordPress/gutenberg/pull/65263)).
+
### Deprecations
- Deprecate `__unstableComposite`, `__unstableCompositeGroup`, `__unstableCompositeItem` and `__unstableUseCompositeState`. Consumers of the package should use the stable `Composite` component instead ([#63572](https://github.com/WordPress/gutenberg/pull/63572)).
@@ -12,12 +17,20 @@
### Enhancements
+- `Navigator`: warn if a screen's `path` doesn't follow a URL-like scheme ([#65231](https://github.com/WordPress/gutenberg/pull/65231)).
- `Modal`: Decrease close button size and remove horizontal offset ([#65131](https://github.com/WordPress/gutenberg/pull/65131)).
+- `Card`: Adopt radius scale ([#65053](https://github.com/WordPress/gutenberg/pull/65053)).
+
+### Bug Fixes
+
+- `DatePicker`: better hover/focus styles ([#65117](https://github.com/WordPress/gutenberg/pull/65117)).
### Internal
+- `Tabs`: improved performance of the indicator animation ([#64926](https://github.com/WordPress/gutenberg/pull/64926)).
- `Composite`: Remove from private APIs ([#63569](https://github.com/WordPress/gutenberg/pull/63569)).
- use local copy of `use-lilius` instead of `npm` dependency ([#65097](https://github.com/WordPress/gutenberg/pull/65097)).
+- `BoxControl`: Fix critical error when null value is passed ([#65287](https://github.com/WordPress/gutenberg/pull/65287)).
## 28.7.0 (2024-09-05)
diff --git a/packages/components/src/box-control/README.md b/packages/components/src/box-control/README.md
index 2fd214b79157f7..b03b03a85466ae 100644
--- a/packages/components/src/box-control/README.md
+++ b/packages/components/src/box-control/README.md
@@ -100,3 +100,10 @@ A handler for onMouseOver events.
A handler for onMouseOut events.
- Required: No
+
+### `__next40pxDefaultSize`: `boolean`
+
+Start opting into the larger default size that will become the default size in a future version.
+
+- Required: No
+- Default: `false`
diff --git a/packages/components/src/box-control/utils.ts b/packages/components/src/box-control/utils.ts
index e480c9a9f4674a..73c7f4a6a46cfb 100644
--- a/packages/components/src/box-control/utils.ts
+++ b/packages/components/src/box-control/utils.ts
@@ -179,7 +179,7 @@ export function isValuesMixed(
*/
export function isValuesDefined( values?: BoxControlValue ) {
return (
- values !== undefined &&
+ values &&
Object.values( values ).filter(
// Switching units when input is empty causes values only
// containing units. This gives false positive on mixed values
diff --git a/packages/components/src/button-group/stories/index.story.tsx b/packages/components/src/button-group/stories/index.story.tsx
index 958a0d137763e9..f6af2416977f40 100644
--- a/packages/components/src/button-group/stories/index.story.tsx
+++ b/packages/components/src/button-group/stories/index.story.tsx
@@ -1,7 +1,7 @@
/**
* External dependencies
*/
-import type { Meta, StoryFn } from '@storybook/react';
+import type { Meta, StoryObj } from '@storybook/react';
/**
* Internal dependencies
@@ -22,18 +22,13 @@ const meta: Meta< typeof ButtonGroup > = {
};
export default meta;
-const Template: StoryFn< typeof ButtonGroup > = ( args ) => {
- const style = { margin: '0 4px' };
- return (
-
-
- Button 1
-
-
- Button 2
-
-
- );
+export const Default: StoryObj< typeof ButtonGroup > = {
+ args: {
+ children: (
+ <>
+ Button 1
+ Button 2
+ >
+ ),
+ },
};
-
-export const Default: StoryFn< typeof ButtonGroup > = Template.bind( {} );
diff --git a/packages/components/src/card/card/component.tsx b/packages/components/src/card/card/component.tsx
index 8fefc33bd48027..e459f9abb9275b 100644
--- a/packages/components/src/card/card/component.tsx
+++ b/packages/components/src/card/card/component.tsx
@@ -34,7 +34,7 @@ function UnconnectedCard(
size,
...otherProps
} = useCard( props );
- const elevationBorderRadius = isRounded ? CONFIG.cardBorderRadius : 0;
+ const elevationBorderRadius = isRounded ? CONFIG.radiusLarge : 0;
const cx = useCx();
diff --git a/packages/components/src/card/styles.ts b/packages/components/src/card/styles.ts
index fa70b19054e2fc..df0fe4eb7ed720 100644
--- a/packages/components/src/card/styles.ts
+++ b/packages/components/src/card/styles.ts
@@ -12,7 +12,7 @@ import { COLORS, CONFIG } from '../utils';
// (as opposed to the `border` property), the value of the border radius needs
// to be adjusted by removing 1px (this is because the `box-shadow` renders
// as an "outer radius").
-const adjustedBorderRadius = `calc(${ CONFIG.cardBorderRadius } - 1px)`;
+const adjustedBorderRadius = `calc(${ CONFIG.radiusLarge } - 1px)`;
export const Card = css`
box-shadow: 0 0 0 1px ${ CONFIG.surfaceBorderColor };
diff --git a/packages/components/src/card/test/__snapshots__/index.tsx.snap b/packages/components/src/card/test/__snapshots__/index.tsx.snap
index cc1a754e1d37c9..e9073edba3e3e4 100644
--- a/packages/components/src/card/test/__snapshots__/index.tsx.snap
+++ b/packages/components/src/card/test/__snapshots__/index.tsx.snap
@@ -8,8 +8,8 @@ Snapshot Diff:
@@ -1,8 +1,8 @@
@@ -25,8 +25,8 @@ Snapshot Diff:
@@ -1,8 +1,8 @@
@@ -42,8 +42,8 @@ Snapshot Diff:
@@ -1,8 +1,8 @@