From da15655558aff873820c47d641b227b1fa7f80f0 Mon Sep 17 00:00:00 2001 From: Bruno Ribaric Date: Wed, 11 Jan 2023 16:05:56 +0100 Subject: [PATCH 1/6] Global styles variations PHP changes --- ...class-wp-theme-json-resolver-gutenberg.php | 150 +++++- ...berg-rest-global-styles-controller-6-2.php | 428 +++++++++++++++++- ...s-gutenberg-rest-themes-controller-6-2.php | 51 +++ lib/compat/wordpress-6.2/rest-api.php | 9 + lib/load.php | 1 + ...erg-rest-global-styles-controller-test.php | 70 ++- 6 files changed, 673 insertions(+), 36 deletions(-) create mode 100644 lib/compat/wordpress-6.2/class-gutenberg-rest-themes-controller-6-2.php diff --git a/lib/class-wp-theme-json-resolver-gutenberg.php b/lib/class-wp-theme-json-resolver-gutenberg.php index 8733fd13bf2c7..19c3f50e660a0 100644 --- a/lib/class-wp-theme-json-resolver-gutenberg.php +++ b/lib/class-wp-theme-json-resolver-gutenberg.php @@ -432,7 +432,7 @@ public static function get_user_data_from_wp_global_styles( $theme, $create_post $args = array( 'posts_per_page' => 1, 'orderby' => 'date', - 'order' => 'desc', + 'order' => 'asc', 'post_type' => $post_type_filter, 'post_status' => $post_status_filter, 'ignore_sticky_posts' => true, @@ -453,19 +453,14 @@ public static function get_user_data_from_wp_global_styles( $theme, $create_post if ( count( $recent_posts ) === 1 ) { $user_cpt = get_object_vars( $recent_posts[0] ); } elseif ( $create_post ) { - $cpt_post_id = wp_insert_post( + $cpt_post_id = self::add_user_global_styles_variation( array( - 'post_content' => '{"version": ' . WP_Theme_JSON_Gutenberg::LATEST_SCHEMA . ', "isGlobalStylesUserThemeJSON": true }', - 'post_status' => 'publish', - 'post_title' => 'Custom Styles', // Do not make string translatable, see https://core.trac.wordpress.org/ticket/54518. - 'post_type' => $post_type_filter, - 'post_name' => sprintf( 'wp-global-styles-%s', urlencode( $stylesheet ) ), - 'tax_input' => array( - 'wp_theme' => array( $stylesheet ), - ), - ), - true + 'title' => 'Custom Styles', // Do not make string translatable, see https://core.trac.wordpress.org/ticket/54518. + 'global_styles' => '{"version": ' . WP_Theme_JSON_Gutenberg::LATEST_SCHEMA . ', "isGlobalStylesUserThemeJSON": true }', + 'stylesheet' => $stylesheet, + ) ); + if ( ! is_wp_error( $cpt_post_id ) ) { $user_cpt = get_object_vars( get_post( $cpt_post_id ) ); } @@ -474,6 +469,94 @@ public static function get_user_data_from_wp_global_styles( $theme, $create_post return $user_cpt; } + // @codingStandardsIgnoreStart Squiz.Commenting.FunctionComment.ParamCommentFullStop + /** + * Saves a new user variation into the database. + * + * + * @param array $args Arguments. All are required. + * { + * @type string title Global styles variation name. + * @type string global_styles Global styles settings as a JSON string. + * @type string $stylesheet Slug of the theme associated with these global styles. + * } + * + * @return int|WP_Error Post ID of the new variation or error if insertion failed. + */ + public static function add_user_global_styles_variation( $args ) { + $theme = wp_get_theme(); + + /* + * Bail early if the theme does not support a theme.json. + * + * Since wp_theme_has_theme_json only supports the active + * theme, the extra condition for whether $theme is the active theme is + * present here. + */ + if ( $theme->get_stylesheet() === $args['stylesheet'] && ! wp_theme_has_theme_json() ) { + return new WP_Error( __( 'Theme does not have theme.json', 'gutenberg' ) ); + } + + $post_id = wp_insert_post( + array( + 'post_content' => $args['global_styles'], + 'post_status' => 'publish', + 'post_title' => $args['title'], + 'post_type' => 'wp_global_styles', + 'post_name' => sprintf( 'wp-global-styles-%s', urlencode( $args['stylesheet'] ) ), + 'tax_input' => array( + 'wp_theme' => array( $args['stylesheet'] ), + ), + ), + true + ); + + return $post_id; + } + // @codingStandardsIgnoreEnd Squiz.Commenting.FunctionComment.ParamCommentFullStop + + /** + * Make an association between post $id and post containing current user + * global styles + * + * @since 6.2 + * + * @param int|null $id ID of the associated post. Null to delete the asociation. + * @return int|false Meta ID on success, false on failure. + */ + public static function associate_user_variation_with_global_styles_post( $id ) { + $current_gs_id = static::get_user_global_styles_post_id(); + + if ( $id === $current_gs_id ) { + return false; + } + + $prev_id = get_post_meta( $current_gs_id, 'associated_user_variation', true ); + + if ( empty( $prev_id ) && ! empty( $id ) ) { + return add_post_meta( $current_gs_id, 'associated_user_variation', $id, true ); + } + + if ( empty( $id ) ) { + return delete_post_meta( $current_gs_id, 'associated_user_variation' ); + } + + return update_post_meta( $current_gs_id, 'associated_user_variation', $id ); + } + + /** + * Get associated variation ID. + * + * @since 6.2 + * + * @return int|null|false Meta ID or null on success, false on failure. + */ + public static function get_associated_user_variation_id() { + $current_gs_id = static::get_user_global_styles_post_id(); + + return get_post_meta( $current_gs_id, 'associated_user_variation', true ); + } + /** * Returns the user's origin config. * @@ -698,4 +781,47 @@ public static function get_style_variations() { return $variations; } + /** + * Returns all style variations. + * + * @since 6.2.0 + * + * @return array + */ + public static function get_user_style_variations() { + $stylesheet = get_stylesheet(); + + $args = array( + 'posts_per_page' => -1, + 'orderby' => 'date', + 'order' => 'desc', + 'post_type' => 'wp_global_styles', + 'post_status' => 'publish', + 'ignore_sticky_posts' => true, + 'no_found_rows' => true, + 'update_post_meta_cache' => false, + 'update_post_term_cache' => false, + 'tax_query' => array( + array( + 'taxonomy' => 'wp_theme', + 'field' => 'name', + 'terms' => $stylesheet, + ), + ), + ); + + $global_style_query = new WP_Query(); + $variation_posts = $global_style_query->query( $args ); + $variations = array(); + + foreach ( $variation_posts as $variation_post ) { + $decoded = json_decode( $variation_post->post_content, true ); + $variation = ( new WP_Theme_JSON_Gutenberg( $decoded ) )->get_raw_data(); + $variation['title'] = $variation_post->post_title; + $variation['id'] = $variation_post->ID; + $variations[] = $variation; + } + + return $variations; + } } diff --git a/lib/compat/wordpress-6.2/class-gutenberg-rest-global-styles-controller-6-2.php b/lib/compat/wordpress-6.2/class-gutenberg-rest-global-styles-controller-6-2.php index 643374aba490c..26e408e29ebf9 100644 --- a/lib/compat/wordpress-6.2/class-gutenberg-rest-global-styles-controller-6-2.php +++ b/lib/compat/wordpress-6.2/class-gutenberg-rest-global-styles-controller-6-2.php @@ -16,7 +16,288 @@ class Gutenberg_REST_Global_Styles_Controller_6_2 extends WP_REST_Global_Styles_ * @return void */ public function register_routes() { - parent::register_routes(); + register_rest_route( + $this->namespace, + '/' . $this->rest_base, + array( + array( + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => array( $this, 'create_item' ), + 'permission_callback' => array( $this, 'create_item_permissions_check' ), + 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), + ), + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_items' ), + 'permission_callback' => array( $this, 'get_items_permissions_check' ), + ), + 'schema' => array( $this, 'get_public_item_schema' ), + ) + ); + + register_rest_route( + $this->namespace, + '/' . $this->rest_base . '/themes/(?P[\/\s%\w\.\(\)\[\]\@_\-]+)/variations', + array( + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_theme_items' ), + 'permission_callback' => array( $this, 'get_theme_items_permissions_check' ), + 'args' => array( + 'stylesheet' => array( + 'description' => __( 'The theme identifier', 'gutenberg' ), + 'type' => 'string', + ), + ), + ), + ) + ); + + // List themes global styles. + register_rest_route( + $this->namespace, + // The route. + sprintf( + '/%s/themes/(?P%s)', + $this->rest_base, + // Matches theme's directory: `/themes///` or `/themes//`. + // Excludes invalid directory name characters: `/:<>*?"|`. + '[^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?' + ), + array( + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_theme_item' ), + 'permission_callback' => array( $this, 'get_theme_item_permissions_check' ), + 'args' => array( + 'stylesheet' => array( + 'description' => __( 'The theme identifier', 'gutenberg' ), + 'type' => 'string', + 'sanitize_callback' => array( $this, '_sanitize_global_styles_callback' ), + ), + ), + ), + ) + ); + + register_rest_route( + $this->namespace, + '/' . $this->rest_base . '/(?P[\/\w-]+)', + array( + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_item' ), + 'permission_callback' => array( $this, 'get_item_permissions_check' ), + 'args' => array( + 'id' => array( + 'description' => __( 'The id of a template', 'gutenberg' ), + 'type' => 'string', + 'sanitize_callback' => array( $this, '_sanitize_global_styles_callback' ), + ), + ), + ), + array( + 'methods' => WP_REST_Server::DELETABLE, + 'callback' => array( $this, 'delete_item' ), + 'permission_callback' => array( $this, 'delete_item_permissions_check' ), + 'args' => array( + 'id' => array( + 'description' => __( 'The id of a template', 'gutenberg' ), + 'type' => 'string', + 'sanitize_callback' => array( $this, '_sanitize_global_styles_callback' ), + ), + ), + ), + array( + 'methods' => WP_REST_Server::EDITABLE, + 'callback' => array( $this, 'update_item' ), + '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' ), + ) + ); + + } + + /** + * Checks if a given request has access to read all theme global styles configs. + * + * @since 6.0.0 + * + * @param WP_REST_Request $request Full details about the request. + * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. + */ + public function get_items_permissions_check( $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable + // Verify if the current user has edit_theme_options capability. + // This capability is required to edit/view/delete templates. + if ( ! current_user_can( 'edit_theme_options' ) ) { + return new WP_Error( + 'rest_cannot_manage_global_styles', + __( 'Sorry, you are not allowed to access the global styles on this site.', 'gutenberg' ), + array( + 'status' => rest_authorization_required_code(), + ) + ); + } + + return true; + } + + /** + * Deletes the given global styles config. + * + * @since 6.2 + * + * @param WP_REST_Request $request The request instance. + * + * @return WP_REST_Response|WP_Error + */ + public function get_items( $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable + $variations = WP_Theme_JSON_Resolver_Gutenberg::get_user_style_variations(); + $response = rest_ensure_response( $variations ); + return $response; + } + + /** + * Checks if a given request has access to delete a single global style. + * + * @since 6.2 + * + * @param WP_REST_Request $request Full details about the request. + * @return true|WP_Error True if the request has read access, WP_Error object otherwise. + */ + public function delete_item_permissions_check( $request ) { + $post = $this->get_post( $request['id'] ); + if ( is_wp_error( $post ) ) { + return $post; + } + + if ( $post && $this->check_delete_permission( $post ) ) { + return new WP_Error( + 'rest_forbidden_context', + __( 'Sorry, you are not allowed to delete this global style.', 'gutenberg' ), + array( 'status' => rest_authorization_required_code() ) + ); + } + + return true; + } + + /** + * Deletes the given global styles config. + * + * @since 6.2 + * + * @param WP_REST_Request $request The request instance. + * + * @return WP_REST_Response|WP_Error + */ + public function delete_item( $request ) { + $post = $this->get_post( $request['id'] ); + if ( is_wp_error( $post ) ) { + return $post; + } + + $previous = $this->prepare_item_for_response( $post, $request ); + $result = wp_delete_post( $post->ID, true ); + $response = new WP_REST_Response(); + $response->set_data( + array( + 'deleted' => true, + 'previous' => $previous->get_data(), + ) + ); + + $association_result = true; + + // Delete association if we're deleting an associated style. + if ( WP_Theme_JSON_Resolver_Gutenberg::get_associated_user_variation_id() === $post->ID ) { + $association_result = WP_Theme_JSON_Resolver_Gutenberg::associate_user_variation_with_global_styles_post( null ); + } + + if ( ! $result || ! $association_result ) { + return new WP_Error( + 'rest_cannot_delete', + __( 'The global style cannot be deleted.', 'gutenberg' ), + array( 'status' => 500 ) + ); + } + + return $response; + } + + /** + * Checks if a given request has access to write a single global styles config. + * + * @since 6.2 + * + * @param WP_REST_Request $request Full details about the request. + * @return true|WP_Error True if the request has write access for the item, WP_Error object otherwise. + */ + public function create_item_permissions_check( $request ) { + if ( ! empty( $request['id'] ) ) { + return new WP_Error( + 'rest_post_exists', + __( 'Cannot create existing style variation.', 'gutenberg' ), + array( 'status' => 400 ) + ); + } + + $post_type = get_post_type_object( $this->post_type ); + + if ( ! current_user_can( $post_type->cap->create_posts ) ) { + return new WP_Error( + 'rest_cannot_create', + __( 'Sorry, you are not allowed to create global style variations as this user.', 'gutenberg' ), + array( 'status' => rest_authorization_required_code() ) + ); + } + + return true; + } + + /** + * Adds a single global style config. + * + * @since 6.2 + * + * @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 create_item( $request ) { + $changes = $this->prepare_item_for_database( $request ); + + if ( is_wp_error( $changes ) ) { + return $changes; + } + + $stylesheet = get_stylesheet(); + + $post_id = WP_Theme_JSON_Resolver_Gutenberg::add_user_global_styles_variation( + array( + 'title' => sanitize_text_field( $request['title'] ), + 'global_styles' => $changes->post_content, + 'stylesheet' => $stylesheet, + ) + ); + + if ( is_wp_error( $post_id ) ) { + + if ( 'db_insert_error' === $post_id->get_error_code() ) { + $post_id->add_data( array( 'status' => 500 ) ); + } else { + $post_id->add_data( array( 'status' => 400 ) ); + } + + return $post_id; + } + + $post = get_post( $post_id ); + + $response = $this->prepare_item_for_response( $post, $request ); + + return rest_ensure_response( $response ); } /** @@ -67,6 +348,16 @@ public function prepare_item_for_response( $post, $request ) { // phpcs:ignore V $data['styles'] = ! empty( $config['styles'] ) && $is_global_styles_user_theme_json ? $config['styles'] : new stdClass(); } + if ( rest_is_field_included( 'associated_style_id', $fields ) ) { + $associated_style_id = get_post_meta( $post->ID, 'associated_user_variation', true ); + + if ( ! empty( $associated_style_id ) ) { + $data['associated_style_id'] = (int) $associated_style_id; + } else { + $data['associated_style_id'] = null; + } + } + $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); @@ -109,6 +400,24 @@ public function update_item( $request ) { return $changes; } + if ( isset( $request['associated_style_id'] ) ) { + if ( ( (int) $request['id'] ) !== WP_Theme_JSON_Resolver_Gutenberg::get_user_global_styles_post_id() ) { + return new WP_Error( + 'rest_cannot_edit', + __( 'Sorry, you are not allowed to add an associated style id to this global style.', 'gutenberg' ), + array( 'status' => 400 ) + ); + } + + if ( is_numeric( $request['associated_style_id'] ) && $request['associated_style_id'] <= 0 ) { + $id = null; + } else { + $id = $request['associated_style_id']; + } + + WP_Theme_JSON_Resolver_Gutenberg::associate_user_variation_with_global_styles_post( $id ); + } + $result = wp_update_post( wp_slash( (array) $changes ), true, false ); if ( is_wp_error( $result ) ) { return $result; @@ -136,10 +445,16 @@ public function update_item( $request ) { * @return stdClass Changes to pass to wp_update_post. */ protected function prepare_item_for_database( $request ) { - $changes = new stdClass(); - $changes->ID = $request['id']; - $post = get_post( $request['id'] ); + $changes = new stdClass(); + if ( ! empty( $request['id'] ) ) { + $changes->ID = $request['id']; + $post = get_post( $request['id'] ); + } else { + $post = null; + } + $existing_config = array(); + if ( $post ) { $existing_config = json_decode( $post->post_content, true ); $json_decoding_error = json_last_error(); @@ -178,6 +493,7 @@ protected function prepare_item_for_database( $request ) { $changes->post_title = $request['title']['raw']; } } + return $changes; } @@ -252,4 +568,108 @@ public function get_theme_item( $request ) { return $response; } + + /** + * Checks if a global style can be deleted. + * + * @since 6.2 + * + * @param WP_Post $post Post object. + * @return bool Whether the post can be deleted. + */ + protected function check_delete_permission( $post ) { + $post_type = get_post_type_object( $post->post_type ); + + if ( ! $this->check_is_post_type_allowed( $post_type ) ) { + return false; + } + + return current_user_can( 'delete_post', $post->ID ); + } + + /** + * Checks if a given post type can be viewed or managed. + * + * @since 6.2 + * + * @param WP_Post_Type|string $post_type Post type name or object. + * @return bool Whether the post type is allowed in REST. + */ + protected function check_is_post_type_allowed( $post_type ) { + if ( ! is_object( $post_type ) ) { + $post_type = get_post_type_object( $post_type ); + } + + if ( ! empty( $post_type ) && ! empty( $post_type->show_in_rest ) ) { + return true; + } + + return false; + } + + /** + * Retrieves the global styles type' schema, conforming to JSON Schema. + * + * @since 5.9.0 + * + * @return array Item schema data. + */ + public function get_item_schema() { + if ( $this->schema ) { + return $this->add_additional_fields_schema( $this->schema ); + } + + $schema = array( + '$schema' => 'http://json-schema.org/draft-04/schema#', + 'title' => $this->post_type, + 'type' => 'object', + 'properties' => array( + 'id' => array( + 'description' => __( 'ID of global styles config.', 'gutenberg' ), + 'type' => 'string', + 'context' => array( 'embed', 'view', 'edit' ), + 'readonly' => true, + ), + 'styles' => array( + 'description' => __( 'Global styles.', 'gutenberg' ), + 'type' => array( 'object' ), + 'context' => array( 'view', 'edit' ), + ), + 'settings' => array( + 'description' => __( 'Global settings.', 'gutenberg' ), + 'type' => array( 'object' ), + 'context' => array( 'view', 'edit' ), + ), + 'title' => array( + 'description' => __( 'Title of the global styles variation.', 'gutenberg' ), + 'type' => array( 'object', 'string' ), + 'default' => '', + 'context' => array( 'embed', 'view', 'edit' ), + 'properties' => array( + 'raw' => array( + 'description' => __( 'Title for the global styles variation, as it exists in the database.', 'gutenberg' ), + 'type' => 'string', + 'context' => array( 'view', 'edit', 'embed' ), + ), + 'rendered' => array( + 'description' => __( 'HTML title for the post, transformed for display.', 'gutenberg' ), + 'type' => 'string', + 'context' => array( 'view', 'edit', 'embed' ), + 'readonly' => true, + ), + ), + ), + 'associated_style_id' => array( + 'description' => __( 'ID of the associated variation style.', 'gutenberg' ), + 'type' => array( 'null', 'integer' ), + 'context' => array( 'view', 'edit' ), + ), + ), + ); + + $this->schema = $schema; + + return $this->add_additional_fields_schema( $this->schema ); + } + } diff --git a/lib/compat/wordpress-6.2/class-gutenberg-rest-themes-controller-6-2.php b/lib/compat/wordpress-6.2/class-gutenberg-rest-themes-controller-6-2.php new file mode 100644 index 0000000000000..0eb91ee88ff74 --- /dev/null +++ b/lib/compat/wordpress-6.2/class-gutenberg-rest-themes-controller-6-2.php @@ -0,0 +1,51 @@ + array( + 'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $theme->get_stylesheet() ) ), + ), + 'collection' => array( + 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ), + ), + ); + + if ( $this->is_same_theme( $theme, wp_get_theme() ) ) { + // This creates a record for the active theme if not existent. + $id = WP_Theme_JSON_Resolver_Gutenberg::get_user_global_styles_post_id(); + } else { + $user_cpt = WP_Theme_JSON_Resolver_Gutenberg::get_user_data_from_wp_global_styles( $theme ); + $id = isset( $user_cpt['ID'] ) ? $user_cpt['ID'] : null; + } + + if ( $id ) { + $links['https://api.w.org/user-global-styles'] = array( + 'href' => rest_url( 'wp/v2/global-styles/' . $id ), + ); + } + + return $links; + } +} diff --git a/lib/compat/wordpress-6.2/rest-api.php b/lib/compat/wordpress-6.2/rest-api.php index 12f7afda3b4d5..4315936bfc0a2 100644 --- a/lib/compat/wordpress-6.2/rest-api.php +++ b/lib/compat/wordpress-6.2/rest-api.php @@ -102,6 +102,15 @@ function gutenberg_register_global_styles_endpoints() { } add_action( 'rest_api_init', 'gutenberg_register_global_styles_endpoints' ); +/** + * Registers the themes REST API routes. + */ +function gutenberg_register_themes_endpoints() { + $controller = new Gutenberg_REST_Themes_Controller_6_2(); + $controller->register_routes(); +} +add_action( 'rest_api_init', 'gutenberg_register_themes_endpoints' ); + /** * Updates REST API response for the sidebars and marks them as 'inactive'. * diff --git a/lib/load.php b/lib/load.php index 1b29605396531..71584336f439a 100644 --- a/lib/load.php +++ b/lib/load.php @@ -44,6 +44,7 @@ function gutenberg_is_experiment_enabled( $name ) { require_once __DIR__ . '/compat/wordpress-6.2/class-gutenberg-rest-block-patterns-controller-6-2.php'; require_once __DIR__ . '/compat/wordpress-6.2/class-gutenberg-rest-block-pattern-categories-controller.php'; require_once __DIR__ . '/compat/wordpress-6.2/class-gutenberg-rest-pattern-directory-controller-6-2.php'; + require_once __DIR__ . '/compat/wordpress-6.2/class-gutenberg-rest-themes-controller-6-2.php'; require_once __DIR__ . '/compat/wordpress-6.2/rest-api.php'; require_once __DIR__ . '/compat/wordpress-6.2/block-patterns.php'; require_once __DIR__ . '/compat/wordpress-6.2/class-gutenberg-rest-global-styles-controller-6-2.php'; diff --git a/phpunit/class-gutenberg-rest-global-styles-controller-test.php b/phpunit/class-gutenberg-rest-global-styles-controller-test.php index 01063aa7e51bc..eba7910dad598 100644 --- a/phpunit/class-gutenberg-rest-global-styles-controller-test.php +++ b/phpunit/class-gutenberg-rest-global-styles-controller-test.php @@ -24,7 +24,6 @@ private function find_and_normalize_global_styles_by_id( $global_styles, $id ) { public function set_up() { parent::set_up(); - switch_theme( 'emptytheme' ); } /** @@ -38,20 +37,11 @@ public static function wpSetupBeforeClass( $factory ) { 'role' => 'administrator', ) ); + + switch_theme( 'emptytheme' ); + // This creates the global styles for the current theme. - self::$global_styles_id = wp_insert_post( - array( - 'post_content' => '{"version": ' . WP_Theme_JSON_Gutenberg::LATEST_SCHEMA . ', "isGlobalStylesUserThemeJSON": true }', - 'post_status' => 'publish', - 'post_title' => __( 'Custom Styles', 'default' ), - 'post_type' => 'wp_global_styles', - 'post_name' => 'wp-global-styles-emptytheme', - 'tax_input' => array( - 'wp_theme' => 'emptytheme', - ), - ), - true - ); + self::$global_styles_id = WP_Theme_JSON_Resolver_Gutenberg::get_user_global_styles_post_id(); } @@ -129,20 +119,44 @@ public function test_get_item() { $this->assertEquals( array( - 'id' => self::$global_styles_id, - 'title' => array( + 'id' => self::$global_styles_id, + 'title' => array( 'raw' => 'Custom Styles', 'rendered' => 'Custom Styles', ), - 'settings' => new stdClass(), - 'styles' => new stdClass(), + 'settings' => new stdClass(), + 'styles' => new stdClass(), + 'associated_style_id' => null, ), $data ); } public function test_create_item() { - $this->markTestIncomplete(); + wp_set_current_user( self::$admin_id ); + $request = new WP_REST_Request( 'POST', '/wp/v2/global-styles' ); + $request->set_body_params( + array( + 'title' => 'Custom user variation', + 'settings' => new stdClass(), + 'styles' => new stdClass(), + ) + ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + unset( $data['_links'] ); + + $this->assertEquals( + array( + 'title' => array( + 'raw' => 'Custom user variation', + 'rendered' => 'Custom user variation', + ), + ), + array( + 'title' => $data['title'], + ) + ); } public function test_update_item() { @@ -159,7 +173,23 @@ public function test_update_item() { } public function test_delete_item() { - $this->markTestIncomplete(); + wp_set_current_user( self::$admin_id ); + $post_id = WP_Theme_JSON_Resolver_Gutenberg::add_user_global_styles_variation( + array( + 'title' => 'Title', + 'global_styles' => \wp_json_encode( + array( + 'settings' => new stdClass, + 'styles' => new stdClass, + ) + ), + 'stylesheet' => get_stylesheet(), + ) + ); + $request = new WP_REST_Request( 'DELETE', '/wp/v2/global-styles/' . $post_id ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + $this->assertTrue( $data['deleted'] ); } public function test_prepare_item() { From 0e0ae987aaef937abf582536f9c6dfa541ffc3ac Mon Sep 17 00:00:00 2001 From: Bruno Ribaric Date: Fri, 13 Jan 2023 16:26:47 +0100 Subject: [PATCH 2/6] Fixes --- lib/class-wp-theme-json-resolver-gutenberg.php | 2 +- .../class-gutenberg-rest-global-styles-controller-6-2.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/class-wp-theme-json-resolver-gutenberg.php b/lib/class-wp-theme-json-resolver-gutenberg.php index 19c3f50e660a0..1d06b3219b4d3 100644 --- a/lib/class-wp-theme-json-resolver-gutenberg.php +++ b/lib/class-wp-theme-json-resolver-gutenberg.php @@ -527,7 +527,7 @@ public static function add_user_global_styles_variation( $args ) { public static function associate_user_variation_with_global_styles_post( $id ) { $current_gs_id = static::get_user_global_styles_post_id(); - if ( $id === $current_gs_id ) { + if ( ( (int) $id ) === $current_gs_id ) { return false; } diff --git a/lib/compat/wordpress-6.2/class-gutenberg-rest-global-styles-controller-6-2.php b/lib/compat/wordpress-6.2/class-gutenberg-rest-global-styles-controller-6-2.php index 26e408e29ebf9..a7b5df5ab357f 100644 --- a/lib/compat/wordpress-6.2/class-gutenberg-rest-global-styles-controller-6-2.php +++ b/lib/compat/wordpress-6.2/class-gutenberg-rest-global-styles-controller-6-2.php @@ -145,7 +145,7 @@ public function get_items_permissions_check( $request ) { // phpcs:ignore Variab } /** - * Deletes the given global styles config. + * Gets all user global styles. * * @since 6.2 * From 88147e54f73eb3e03d63cb4a159dc264f1cf865a Mon Sep 17 00:00:00 2001 From: Bruno Ribaric Date: Fri, 20 Jan 2023 18:15:41 +0100 Subject: [PATCH 3/6] Merge trunk --- .cache/.gitkeep | 0 .eslintrc.js | 4 + .github/CODEOWNERS | 3 + .github/workflows/build-plugin-zip.yml | 4 +- .github/workflows/bundle-size.yml | 2 +- .github/workflows/create-block.yml | 2 +- .github/workflows/end2end-test.yml | 6 +- .github/workflows/performance.yml | 2 +- .github/workflows/publish-npm-packages.yml | 2 +- .github/workflows/pull-request-automation.yml | 2 +- .github/workflows/rnmobile-android-runner.yml | 2 +- .github/workflows/rnmobile-ios-runner.yml | 2 +- .github/workflows/static-checks.yml | 2 +- .github/workflows/storybook-pages.yml | 2 +- .github/workflows/unit-test.yml | 168 ++- .gitignore | 7 + changelog.txt | 124 +- docs/contributors/code/coding-guidelines.md | 310 ++++- .../data/data-core-block-editor.md | 31 + .../theme-json-reference/theme-json-living.md | 2 +- gutenberg.php | 2 +- lib/block-supports/border.php | 16 +- lib/block-supports/colors.php | 8 +- lib/block-supports/dimensions.php | 4 +- lib/block-supports/elements.php | 4 +- lib/block-supports/layout.php | 2 +- lib/block-supports/shadow.php | 77 ++ lib/block-supports/spacing.php | 6 +- lib/block-supports/typography.php | 18 +- lib/block-supports/utils.php | 31 - lib/class-wp-theme-json-gutenberg.php | 15 +- ...class-wp-theme-json-resolver-gutenberg.php | 61 +- lib/compat/wordpress-6.2/blocks.php | 1 + ...berg-rest-global-styles-controller-6-2.php | 47 + lib/compat/wordpress-6.2/script-loader.php | 22 +- lib/experimental/editor-settings.php | 3 - .../class-wp-fonts-provider-local.php | 242 ++++ .../class-wp-fonts-provider.php} | 41 +- .../class-wp-fonts-utils.php} | 10 +- lib/experimental/fonts-api/class-wp-fonts.php | 744 ++++++++++++ .../deprecations}/class-wp-web-fonts.php | 63 +- .../class-wp-webfonts-provider-local.php | 27 +- .../class-wp-webfonts-provider.php | 66 ++ .../deprecations/class-wp-webfonts-utils.php | 85 ++ .../deprecations}/class-wp-webfonts.php | 56 +- .../deprecations/webfonts-deprecations.php | 254 +++++ .../{webfonts.php => fonts-api/fonts-api.php} | 96 +- .../register-fonts-from-theme-json.php} | 40 +- .../html/class-wp-html-tag-processor.php | 28 +- lib/experimental/kses.php | 3 +- lib/experimental/webfonts-deprecations.php | 100 -- lib/experiments-page.php | 16 - lib/load.php | 21 +- lib/theme.json | 2 +- package-lock.json | 1002 +---------------- package.json | 3 +- packages/a11y/CHANGELOG.md | 2 + packages/a11y/package.json | 2 +- packages/annotations/CHANGELOG.md | 2 + packages/annotations/package.json | 2 +- packages/api-fetch/CHANGELOG.md | 2 + packages/api-fetch/package.json | 2 +- packages/autop/CHANGELOG.md | 2 + packages/autop/package.json | 2 +- .../CHANGELOG.md | 2 + .../package.json | 2 +- packages/babel-plugin-makepot/CHANGELOG.md | 2 + packages/babel-plugin-makepot/package.json | 2 +- packages/babel-preset-default/CHANGELOG.md | 2 + packages/babel-preset-default/package.json | 2 +- packages/base-styles/CHANGELOG.md | 2 + packages/base-styles/package.json | 2 +- packages/blob/CHANGELOG.md | 2 + packages/blob/package.json | 2 +- packages/blob/src/index.js | 9 +- packages/block-directory/CHANGELOG.md | 2 + packages/block-directory/package.json | 2 +- .../test/index.js | 6 +- packages/block-editor/CHANGELOG.md | 4 + packages/block-editor/README.md | 4 + packages/block-editor/package.json | 3 +- .../alignment-control/test/index.js | 18 +- .../src/components/autocomplete/index.js | 9 +- .../block-alignment-control/test/index.js | 14 +- .../block-list/use-in-between-inserter.js | 5 + .../components/block-pattern-setup/index.js | 5 +- .../block-pattern-setup/use-patterns-setup.js | 7 +- .../src/components/block-preview/README.md | 18 +- .../src/components/block-preview/auto.js | 20 +- .../src/components/block-preview/index.js | 34 +- .../block-settings-menu-controls/index.js | 12 +- .../src/components/block-tools/style.scss | 1 - .../test/index.js | 14 +- .../src/components/colors/test/with-colors.js | 10 +- .../default-block-appender/content.scss | 18 + .../default-block-appender/test/index.js | 10 +- .../src/components/global-styles/README.md | 78 ++ .../src/components/global-styles/context.js | 0 .../src/components/global-styles/hooks.js | 157 +++ .../src/components/global-styles/index.js | 7 + .../global-styles/test/typography-utils.js | 0 .../test/use-global-styles-output.js | 0 .../components/global-styles/test/utils.js | 0 .../global-styles/typography-utils.js | 4 +- .../global-styles/use-global-styles-output.js | 12 +- .../src/components/global-styles/utils.js | 366 ++++++ .../src/components/image-editor/context.js | 14 +- .../src/components/image-editor/cropper.js | 4 +- .../src/components/image-editor/index.js | 17 +- .../image-editor/use-transform-image.js | 69 +- packages/block-editor/src/components/index.js | 5 +- .../inner-blocks/get-block-context.js | 39 - .../src/components/inner-blocks/index.js | 27 +- .../components/inner-blocks/index.native.js | 74 +- .../inner-blocks/use-block-context.js | 47 + .../components/inserter/block-types-tab.js | 7 +- .../inserter/hooks/use-patterns-state.js | 7 +- .../src/components/inserter/index.js | 5 +- .../src/components/inserter/preview-panel.js | 6 +- .../components/inspector-controls/README.md | 10 +- .../src/components/link-control/index.js | 55 +- .../src/components/link-control/style.scss | 29 +- .../src/components/link-control/test/index.js | 139 ++- .../src/components/list-view/block.js | 2 +- .../media-replace-flow/test/index.js | 16 +- .../responsive-block-control/test/index.js | 6 +- .../src/components/url-input/test/button.js | 18 +- .../url-popover/image-url-input-ui.js | 7 +- .../src/components/warning/test/index.js | 6 +- packages/block-editor/src/content.scss | 1 + packages/block-editor/src/experiments.js | 23 + packages/block-editor/src/hooks/anchor.js | 1 + .../src/hooks/custom-class-name.js | 1 + packages/block-editor/src/hooks/layout.scss | 4 + packages/block-editor/src/hooks/test/utils.js | 104 ++ packages/block-editor/src/hooks/utils.js | 70 +- packages/block-editor/src/index.js | 1 + .../block-editor/src/layouts/constrained.js | 2 + packages/block-editor/src/store/selectors.js | 73 +- .../block-editor/src/store/test/selectors.js | 17 +- packages/block-editor/src/style.scss | 1 - .../src/utils/transform-styles/index.js | 7 +- packages/block-library/CHANGELOG.md | 2 + packages/block-library/package.json | 2 +- .../test/__snapshots__/edit.native.js.snap | 2 - packages/block-library/src/block/edit.js | 1 + packages/block-library/src/button/edit.js | 1 + .../block-library/src/column/edit.native.js | 7 +- .../test/__snapshots__/edit.native.js.snap | 4 - .../block-library/src/gallery/deprecated.js | 5 +- packages/block-library/src/gallery/v1/edit.js | 17 +- packages/block-library/src/image/image.js | 37 +- .../src/list/ordered-list-settings.js | 1 + packages/block-library/src/media-text/edit.js | 10 +- .../block-library/src/navigation-link/edit.js | 19 +- .../src/navigation-submenu/edit.js | 4 + .../src/navigation/edit/index.js | 13 +- .../edit/navigation-menu-name-control.js | 1 + .../src/post-author-name/block.json | 1 - .../src/post-featured-image/edit.js | 73 +- .../block-library/src/post-template/edit.js | 7 +- packages/block-library/src/post-terms/edit.js | 1 + packages/block-library/src/post-title/edit.js | 1 + .../test/__snapshots__/edit.native.js.snap | 4 - .../query/edit/inspector-controls/index.js | 1 + .../src/query/edit/query-placeholder.js | 12 +- .../src/query/edit/query-toolbar.js | 11 +- packages/block-library/src/query/utils.js | 11 +- .../test/__snapshots__/edit.native.js.snap | 7 - packages/block-library/src/site-logo/edit.js | 25 +- packages/block-library/src/table/edit.js | 2 + packages/block-library/src/table/editor.scss | 6 - packages/block-library/src/tag-cloud/edit.js | 14 +- .../template-part/edit/advanced-controls.js | 1 + .../src/template-part/edit/utils/hooks.js | 11 +- .../CHANGELOG.md | 2 + .../package.json | 2 +- .../CHANGELOG.md | 2 + .../package.json | 2 +- packages/blocks/CHANGELOG.md | 2 + packages/blocks/package.json | 2 +- packages/blocks/src/store/reducer.js | 4 +- packages/blocks/src/store/selectors.js | 11 +- packages/browserslist-config/CHANGELOG.md | 2 + packages/browserslist-config/package.json | 2 +- packages/components/CHANGELOG.md | 15 +- packages/components/CONTRIBUTING.md | 2 +- packages/components/package.json | 2 +- .../src/alignment-matrix-control/utils.tsx | 4 +- .../src/autocomplete/autocompleter-ui.js | 3 +- packages/components/src/button/style.scss | 5 +- .../src/color-palette/index.native.js | 15 +- .../components/src/color-palette/index.tsx | 29 +- .../components/src/dropdown-menu/README.md | 2 +- .../src/dropdown-menu/stories/index.js | 123 +- packages/components/src/h-stack/component.tsx | 1 - .../src/keyboard-shortcuts/index.js | 27 +- packages/components/src/tab-panel/style.scss | 8 + .../components/src/toolbar/stories/index.js | 147 +-- .../src/toolbar/stories/toolbar-button.js | 32 - .../src/toolbar/stories/toolbar-group.js | 33 - packages/compose/CHANGELOG.md | 2 + packages/compose/package.json | 2 +- .../src/higher-order/pure/test/index.js | 6 +- .../src/higher-order/with-state/test/index.js | 6 +- .../src/hooks/use-focus-outside/test/index.js | 24 +- .../compose/src/utils/debounce/test/index.ts | 8 - packages/core-data/CHANGELOG.md | 2 + packages/core-data/package.json | 2 +- packages/core-data/src/entities.js | 6 +- .../src/hooks/test/use-entity-record.js | 51 +- .../src/hooks/test/use-entity-records.js | 21 +- .../src/hooks/test/use-query-select.js | 28 +- .../hooks/test/use-resource-permissions.js | 55 +- .../core-data/src/queried-data/reducer.js | 4 +- packages/core-data/src/reducer.js | 7 +- packages/core-data/src/selectors.ts | 6 +- packages/core-data/src/test/actions.js | 18 - packages/core-data/src/test/entities.js | 6 - packages/core-data/src/test/resolvers.js | 12 - .../CHANGELOG.md | 2 + .../package.json | 2 +- packages/create-block/CHANGELOG.md | 2 + packages/create-block/package.json | 2 +- .../CHANGELOG.md | 2 + .../package.json | 2 +- packages/customize-widgets/CHANGELOG.md | 2 + packages/customize-widgets/package.json | 2 +- packages/data-controls/CHANGELOG.md | 2 + packages/data-controls/package.json | 2 +- packages/data/CHANGELOG.md | 2 + packages/data/package.json | 3 +- packages/data/src/experiments.js | 10 + packages/data/src/redux-store/index.js | 46 +- packages/data/src/test/privateAPIs.js | 228 ++++ packages/date/CHANGELOG.md | 2 + packages/date/package.json | 2 +- .../CHANGELOG.md | 2 + .../package.json | 2 +- packages/deprecated/CHANGELOG.md | 2 + packages/deprecated/package.json | 2 +- packages/docgen/CHANGELOG.md | 2 + packages/docgen/package.json | 2 +- packages/dom-ready/CHANGELOG.md | 2 + packages/dom-ready/package.json | 2 +- packages/dom/CHANGELOG.md | 2 + packages/dom/package.json | 2 +- packages/e2e-test-utils/CHANGELOG.md | 2 + packages/e2e-test-utils/package.json | 2 +- packages/e2e-tests/CHANGELOG.md | 2 + packages/e2e-tests/package.json | 2 +- .../specs/editor/blocks/cover.test.js | 16 +- .../various/__snapshots__/links.test.js.snap | 2 +- .../specs/editor/various/a11y.test.js | 74 -- .../specs/editor/various/links.test.js | 4 + .../various/multi-block-selection.test.js | 17 +- .../specs/editor/various/rich-text.test.js | 4 + .../site-editor/multi-entity-saving.test.js | 9 +- .../src/components/sidebar/style.scss | 8 + packages/edit-post/CHANGELOG.md | 2 + packages/edit-post/package.json | 2 +- .../src/components/block-manager/category.js | 13 +- .../template-title/edit-template-title.js | 1 + .../header/template-title/style.scss | 5 +- .../src/components/meta-boxes/index.js | 7 +- .../preferences-modal/meta-boxes-section.js | 7 +- .../options/test/enable-custom-fields.js | 14 +- .../sidebar/post-template/create-modal.js | 41 +- .../sidebar/settings-header/style.scss | 8 + .../components/start-page-options/index.js | 8 +- packages/edit-post/src/editor.js | 7 +- packages/edit-post/src/editor.native.js | 3 +- packages/edit-site/CHANGELOG.md | 2 + packages/edit-site/package.json | 3 +- .../add-custom-generic-template-modal.js | 47 +- .../add-new-template/new-template-part.js | 2 +- .../components/add-new-template/style.scss | 4 - .../src/components/block-editor/index.js | 2 +- .../src/components/block-editor/style.scss | 26 +- .../src/components/canvas-spinner/index.js | 12 + .../src/components/canvas-spinner/style.scss | 7 + .../edit-site/src/components/editor/index.js | 3 +- .../global-styles-renderer/index.js | 7 +- .../src/components/global-styles/README.md | 76 +- .../global-styles/block-preview-panel.js | 4 +- .../components/global-styles/border-panel.js | 32 +- .../global-styles/color-palette-panel.js | 17 +- .../components/global-styles/custom-css.js | 9 +- .../global-styles/dimensions-panel.js | 42 +- .../global-styles/global-styles-provider.js | 8 +- .../global-styles/gradients-palette-panel.js | 28 +- .../src/components/global-styles/hooks.js | 181 +-- .../src/components/global-styles/index.js | 2 - .../src/components/global-styles/palette.js | 14 +- .../src/components/global-styles/preview.js | 32 +- .../global-styles/screen-background-color.js | 44 +- .../global-styles/screen-button-color.js | 32 +- .../components/global-styles/screen-colors.js | 24 +- .../global-styles/screen-heading-color.js | 37 +- .../global-styles/screen-link-color.js | 34 +- .../components/global-styles/screen-root.js | 24 +- .../global-styles/screen-style-variations.js | 9 +- .../global-styles/screen-text-color.js | 28 +- .../global-styles/screen-typography.js | 31 +- .../src/components/global-styles/style.scss | 3 +- .../global-styles/typography-panel.js | 54 +- .../global-styles/typography-preview.js | 37 +- .../src/components/global-styles/utils.js | 367 ------ .../edit-site/src/components/layout/index.js | 7 + .../src/components/layout/style.scss | 9 +- .../list/actions/rename-menu-item.js | 36 +- .../edit-site/src/components/list/style.scss | 4 - .../global-styles-sidebar.js | 6 +- .../settings-header/style.scss | 8 + .../src/components/site-hub/index.js | 1 + .../src/components/site-hub/style.scss | 8 +- .../src/components/site-icon/index.js | 2 +- .../src/components/site-icon/style.scss | 4 +- .../src/components/style-book/index.js | 15 +- .../convert-to-template-part.js | 2 +- packages/edit-site/src/experiments.js | 10 + .../push-changes-to-global-styles/index.js | 68 +- packages/edit-site/src/style.scss | 1 + .../src/utils/test/template-part-create.js | 63 ++ packages/edit-widgets/CHANGELOG.md | 2 + packages/edit-widgets/package.json | 2 +- .../src/components/sidebar/style.scss | 8 + packages/editor/CHANGELOG.md | 2 + packages/editor/package.json | 2 +- .../components/page-attributes/test/order.js | 18 +- .../post-preview-button/test/index.js | 22 +- .../post-publish-button/test/index.js | 22 +- .../post-publish-panel/postpublish.js | 1 + .../components/post-publish-panel/style.scss | 6 +- .../test/__snapshots__/index.js.snap | 20 +- .../components/post-saved-state/test/index.js | 6 +- .../editor/src/components/post-slug/index.js | 1 + .../src/components/post-template/index.js | 7 +- .../editor/src/components/post-url/index.js | 1 + .../src/hooks/default-autocompleters.js | 7 +- packages/editor/src/utils/terms.js | 4 +- packages/element/CHANGELOG.md | 2 + packages/element/package.json | 2 +- packages/element/src/raw-html.js | 1 - packages/env/CHANGELOG.md | 10 + .../env/lib/build-docker-compose-config.js | 6 +- packages/env/package.json | 2 +- packages/escape-html/CHANGELOG.md | 2 + packages/escape-html/package.json | 2 +- packages/eslint-plugin/CHANGELOG.md | 6 +- packages/eslint-plugin/package.json | 2 +- packages/experiments/CHANGELOG.md | 2 + packages/experiments/README.md | 90 +- packages/experiments/package.json | 2 +- packages/experiments/src/implementation.js | 188 ++++ packages/experiments/src/index.js | 86 +- packages/experiments/src/test/index.js | 283 ++++- packages/format-library/CHANGELOG.md | 2 + packages/format-library/package.json | 2 +- packages/hooks/CHANGELOG.md | 2 + packages/hooks/package.json | 2 +- packages/html-entities/CHANGELOG.md | 2 + packages/html-entities/package.json | 2 +- packages/i18n/CHANGELOG.md | 2 + packages/i18n/package.json | 2 +- packages/icons/CHANGELOG.md | 2 + packages/icons/package.json | 2 +- packages/interface/CHANGELOG.md | 2 + packages/interface/package.json | 2 +- packages/is-shallow-equal/CHANGELOG.md | 2 + packages/is-shallow-equal/package.json | 2 +- packages/jest-console/CHANGELOG.md | 2 + packages/jest-console/package.json | 2 +- packages/jest-preset-default/CHANGELOG.md | 2 + packages/jest-preset-default/package.json | 2 +- packages/jest-puppeteer-axe/CHANGELOG.md | 2 + packages/jest-puppeteer-axe/package.json | 2 +- packages/keyboard-shortcuts/CHANGELOG.md | 2 + packages/keyboard-shortcuts/package.json | 2 +- packages/keycodes/CHANGELOG.md | 2 + packages/keycodes/package.json | 2 +- packages/lazy-import/CHANGELOG.md | 2 + packages/lazy-import/package.json | 2 +- .../CHANGELOG.md | 2 + .../package.json | 2 +- packages/list-reusable-blocks/CHANGELOG.md | 2 + packages/list-reusable-blocks/package.json | 2 +- packages/media-utils/CHANGELOG.md | 2 + packages/media-utils/package.json | 2 +- .../src/components/media-upload/index.js | 17 +- packages/notices/CHANGELOG.md | 2 + packages/notices/package.json | 2 +- .../npm-package-json-lint-config/CHANGELOG.md | 2 + .../npm-package-json-lint-config/package.json | 2 +- packages/plugins/CHANGELOG.md | 2 + packages/plugins/package.json | 2 +- packages/postcss-plugins-preset/CHANGELOG.md | 2 + packages/postcss-plugins-preset/package.json | 2 +- packages/postcss-themes/CHANGELOG.md | 2 + packages/postcss-themes/package.json | 2 +- packages/preferences-persistence/CHANGELOG.md | 2 + packages/preferences-persistence/package.json | 2 +- packages/preferences/CHANGELOG.md | 2 + packages/preferences/package.json | 2 +- packages/prettier-config/CHANGELOG.md | 2 + packages/prettier-config/lib/index.js | 2 - packages/prettier-config/package.json | 2 +- packages/primitives/CHANGELOG.md | 2 + packages/primitives/package.json | 2 +- packages/priority-queue/CHANGELOG.md | 2 + packages/priority-queue/package.json | 2 +- .../CHANGELOG.md | 2 + .../package.json | 2 +- packages/react-i18n/CHANGELOG.md | 2 + packages/react-i18n/package.json | 2 +- packages/react-native-aztec/package.json | 2 +- packages/react-native-aztec/src/AztecView.js | 9 + packages/react-native-bridge/package.json | 2 +- packages/react-native-editor/CHANGELOG.md | 7 + packages/react-native-editor/ios/Gemfile.lock | 4 +- packages/react-native-editor/ios/Podfile.lock | 8 +- packages/react-native-editor/package.json | 2 +- .../CHANGELOG.md | 2 + .../package.json | 2 +- packages/redux-routine/CHANGELOG.md | 2 + packages/redux-routine/package.json | 2 +- packages/reusable-blocks/CHANGELOG.md | 2 + packages/reusable-blocks/package.json | 2 +- .../reusable-block-convert-button.js | 29 +- .../reusable-blocks-menu-items/style.scss | 4 - packages/rich-text/CHANGELOG.md | 2 + packages/rich-text/package.json | 2 +- .../rich-text/src/component/index.native.js | 77 +- .../test/__snapshots__/index.native.js.snap | 2 - packages/rich-text/src/test/index.native.js | 33 +- packages/scripts/CHANGELOG.md | 2 + packages/scripts/package.json | 2 +- packages/server-side-render/CHANGELOG.md | 2 + packages/server-side-render/package.json | 2 +- packages/shortcode/CHANGELOG.md | 2 + packages/shortcode/package.json | 2 +- packages/style-engine/CHANGELOG.md | 2 + .../style-engine/class-wp-style-engine.php | 11 + packages/style-engine/package.json | 2 +- packages/stylelint-config/CHANGELOG.md | 2 + packages/stylelint-config/package.json | 2 +- packages/token-list/CHANGELOG.md | 2 + packages/token-list/package.json | 2 +- packages/url/CHANGELOG.md | 2 + packages/url/package.json | 2 +- packages/url/src/get-query-args.js | 3 +- packages/url/src/test/index.js | 10 + packages/viewport/CHANGELOG.md | 2 + packages/viewport/package.json | 2 +- packages/warning/CHANGELOG.md | 2 + packages/warning/package.json | 2 +- packages/widgets/CHANGELOG.md | 2 + packages/widgets/package.json | 2 +- packages/wordcount/CHANGELOG.md | 2 + packages/wordcount/package.json | 2 +- phpcs.xml.dist | 3 + phpunit/block-supports/layout-test.php | 15 + ...ock-pattern-categories-controller-test.php | 27 +- phpunit/class-wp-theme-json-resolver-test.php | 81 ++ phpunit/class-wp-theme-json-test.php | 103 +- .../block-theme-child/styles/variation-a.json | 18 + .../themedir1/block-theme-child/theme.json | 2 +- .../block-theme/styles/variation-a.json | 18 + .../block-theme/styles/variation-b.json | 18 + phpunit/data/themedir1/block-theme/theme.json | 2 +- phpunit/fixtures/mock-provider.php | 6 +- .../wp-fonts-testcase.php} | 98 +- .../wp-fonts-tests-dataset.php} | 73 +- .../wpDeregisterFontFamily-test.php | 14 +- .../wpDeregisterFontVariation-test.php} | 106 +- .../wpEnqueueFontVariations-test.php} | 18 +- .../wpEnqueueFonts-test.php} | 28 +- phpunit/fonts-api/wpFonts-test.php | 38 + .../wpFonts}/add-test.php | 20 +- .../wpFonts}/addFontFamily-test.php | 20 +- .../wpFonts}/addVariation-test.php | 76 +- .../wpFonts}/dequeue-test.php | 42 +- .../wpFonts}/doItem-test.php | 94 +- .../wpFonts}/doItems-test.php | 52 +- .../wpFonts}/enqueue-test.php | 30 +- .../wpFonts}/getEnqueued-test.php | 30 +- .../wpFonts}/getProviders-test.php | 26 +- .../wpFonts}/getRegistered-test.php | 32 +- .../wpFonts}/query-test.php | 50 +- .../wpFonts}/registerProvider-test.php | 36 +- .../wpFonts}/remove-test.php | 28 +- .../wpFonts/removeFontFamily-test.php | 89 ++ .../wpFonts}/removeVariation-test.php | 110 +- .../wpFontsProviderLocal-test.php} | 60 +- .../convertFontFamilyIntoHandle-test.php | 18 +- .../convertVariationIntoHandle-test.php | 16 +- .../getFontFamilyFromVariation-test.php | 16 +- .../wpFontsUtils}/isDefined-test.php | 16 +- .../wpPrintFonts-test.php} | 54 +- .../wpRegisterFontProvider-test.php} | 18 +- .../wpRegisterFonts-test.php} | 105 +- phpunit/webfonts/wpWebfonts-test.php | 38 - .../wpWebfonts/removeFontFamily-test.php | 89 -- phpunit/wp-theme-json-test.php | 14 + schemas/json/theme.json | 2 +- storybook/main.js | 1 - storybook/preview.js | 5 - test/e2e/specs/editor/blocks/image.spec.js | 2 +- test/e2e/specs/editor/various/a11y.spec.js | 96 ++ 509 files changed, 7266 insertions(+), 4770 deletions(-) create mode 100644 .cache/.gitkeep create mode 100644 lib/block-supports/shadow.php delete mode 100644 lib/block-supports/utils.php create mode 100644 lib/experimental/fonts-api/class-wp-fonts-provider-local.php rename lib/experimental/{class-wp-webfonts-provider.php => fonts-api/class-wp-fonts-provider.php} (63%) rename lib/experimental/{class-wp-webfonts-utils.php => fonts-api/class-wp-fonts-utils.php} (94%) create mode 100644 lib/experimental/fonts-api/class-wp-fonts.php rename lib/experimental/{ => fonts-api/deprecations}/class-wp-web-fonts.php (93%) rename lib/experimental/{ => fonts-api/deprecations}/class-wp-webfonts-provider-local.php (90%) create mode 100644 lib/experimental/fonts-api/deprecations/class-wp-webfonts-provider.php create mode 100644 lib/experimental/fonts-api/deprecations/class-wp-webfonts-utils.php rename lib/experimental/{ => fonts-api/deprecations}/class-wp-webfonts.php (76%) create mode 100644 lib/experimental/fonts-api/deprecations/webfonts-deprecations.php rename lib/experimental/{webfonts.php => fonts-api/fonts-api.php} (60%) rename lib/experimental/{register-webfonts-from-theme-json.php => fonts-api/register-fonts-from-theme-json.php} (79%) delete mode 100644 lib/experimental/webfonts-deprecations.php create mode 100644 packages/block-editor/src/components/global-styles/README.md rename packages/{edit-site => block-editor}/src/components/global-styles/context.js (100%) create mode 100644 packages/block-editor/src/components/global-styles/hooks.js create mode 100644 packages/block-editor/src/components/global-styles/index.js rename packages/{edit-site => block-editor}/src/components/global-styles/test/typography-utils.js (100%) rename packages/{edit-site => block-editor}/src/components/global-styles/test/use-global-styles-output.js (100%) rename packages/{edit-site => block-editor}/src/components/global-styles/test/utils.js (100%) rename packages/{edit-site => block-editor}/src/components/global-styles/typography-utils.js (96%) rename packages/{edit-site => block-editor}/src/components/global-styles/use-global-styles-output.js (99%) create mode 100644 packages/block-editor/src/components/global-styles/utils.js delete mode 100644 packages/block-editor/src/components/inner-blocks/get-block-context.js create mode 100644 packages/block-editor/src/components/inner-blocks/use-block-context.js create mode 100644 packages/block-editor/src/experiments.js delete mode 100644 packages/components/src/toolbar/stories/toolbar-button.js delete mode 100644 packages/components/src/toolbar/stories/toolbar-group.js create mode 100644 packages/data/src/experiments.js create mode 100644 packages/data/src/test/privateAPIs.js delete mode 100644 packages/e2e-tests/specs/editor/various/a11y.test.js create mode 100644 packages/edit-site/src/components/canvas-spinner/index.js create mode 100644 packages/edit-site/src/components/canvas-spinner/style.scss create mode 100644 packages/edit-site/src/experiments.js create mode 100644 packages/edit-site/src/utils/test/template-part-create.js create mode 100644 packages/experiments/src/implementation.js create mode 100644 phpunit/data/themedir1/block-theme-child/styles/variation-a.json create mode 100644 phpunit/data/themedir1/block-theme/styles/variation-a.json create mode 100644 phpunit/data/themedir1/block-theme/styles/variation-b.json rename phpunit/{webfonts/wp-webfonts-testcase.php => fonts-api/wp-fonts-testcase.php} (67%) rename phpunit/{webfonts/wp-webfonts-tests-dataset.php => fonts-api/wp-fonts-tests-dataset.php} (93%) rename phpunit/{webfonts => fonts-api}/wpDeregisterFontFamily-test.php (88%) rename phpunit/{webfonts/wpDeregisterWebfontVariation-test.php => fonts-api/wpDeregisterFontVariation-test.php} (59%) rename phpunit/{webfonts/wpEnqueueWebfontVariations-test.php => fonts-api/wpEnqueueFontVariations-test.php} (84%) rename phpunit/{webfonts/wpEnqueueWebfonts-test.php => fonts-api/wpEnqueueFonts-test.php} (86%) create mode 100644 phpunit/fonts-api/wpFonts-test.php rename phpunit/{webfonts/wpWebfonts => fonts-api/wpFonts}/add-test.php (51%) rename phpunit/{webfonts/wpWebfonts => fonts-api/wpFonts}/addFontFamily-test.php (69%) rename phpunit/{webfonts/wpWebfonts => fonts-api/wpFonts}/addVariation-test.php (62%) rename phpunit/{webfonts/wpWebfonts => fonts-api/wpFonts}/dequeue-test.php (50%) rename phpunit/{webfonts/wpWebfonts => fonts-api/wpFonts}/doItem-test.php (71%) rename phpunit/{webfonts/wpWebfonts => fonts-api/wpFonts}/doItems-test.php (77%) rename phpunit/{webfonts/wpWebfonts => fonts-api/wpFonts}/enqueue-test.php (52%) rename phpunit/{webfonts/wpWebfonts => fonts-api/wpFonts}/getEnqueued-test.php (57%) rename phpunit/{webfonts/wpWebfonts => fonts-api/wpFonts}/getProviders-test.php (60%) rename phpunit/{webfonts/wpWebfonts => fonts-api/wpFonts}/getRegistered-test.php (70%) rename phpunit/{webfonts/wpWebfonts => fonts-api/wpFonts}/query-test.php (65%) rename phpunit/{webfonts/wpWebfonts => fonts-api/wpFonts}/registerProvider-test.php (58%) rename phpunit/{webfonts/wpWebfonts => fonts-api/wpFonts}/remove-test.php (73%) create mode 100644 phpunit/fonts-api/wpFonts/removeFontFamily-test.php rename phpunit/{webfonts/wpWebfonts => fonts-api/wpFonts}/removeVariation-test.php (56%) rename phpunit/{webfonts/wpWebfontsProviderLocal-test.php => fonts-api/wpFontsProviderLocal-test.php} (65%) rename phpunit/{webfonts/wpWebfontsUtils => fonts-api/wpFontsUtils}/convertFontFamilyIntoHandle-test.php (75%) rename phpunit/{webfonts/wpWebfontsUtils => fonts-api/wpFontsUtils}/convertVariationIntoHandle-test.php (85%) rename phpunit/{webfonts/wpWebfontsUtils => fonts-api/wpFontsUtils}/getFontFamilyFromVariation-test.php (87%) rename phpunit/{webfonts/wpWebfontsUtils => fonts-api/wpFontsUtils}/isDefined-test.php (72%) rename phpunit/{webfonts/wpPrintWebfonts-test.php => fonts-api/wpPrintFonts-test.php} (66%) rename phpunit/{webfonts/wpRegisterWebfontProvider-test.php => fonts-api/wpRegisterFontProvider-test.php} (75%) rename phpunit/{webfonts/wpRegisterWebfonts-test.php => fonts-api/wpRegisterFonts-test.php} (75%) delete mode 100644 phpunit/webfonts/wpWebfonts-test.php delete mode 100644 phpunit/webfonts/wpWebfonts/removeFontFamily-test.php create mode 100644 test/e2e/specs/editor/various/a11y.spec.js diff --git a/.cache/.gitkeep b/.cache/.gitkeep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/.eslintrc.js b/.eslintrc.js index d784fc94c5542..7c89b96e997f6 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -50,6 +50,7 @@ const restrictedImports = [ 'castArray', 'chunk', 'clamp', + 'clone', 'cloneDeep', 'compact', 'concat', @@ -101,6 +102,7 @@ const restrictedImports = [ 'keys', 'last', 'lowerCase', + 'map', 'mapKeys', 'maxBy', 'memoize', @@ -121,6 +123,7 @@ const restrictedImports = [ 'reject', 'repeat', 'reverse', + 'setWith', 'size', 'snakeCase', 'some', @@ -368,6 +371,7 @@ module.exports = { 'packages/react-native-*/**/*.[tj]s?(x)', 'test/native/**/*.[tj]s?(x)', 'test/e2e/**/*.[tj]s?(x)', + 'test/storybook-playwright/**/*.[tj]s?(x)', ], extends: [ 'plugin:jest-dom/recommended', diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 6427516035a5e..ebddac0375d4d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -71,6 +71,7 @@ /packages/docgen /packages/e2e-test-utils @ntwb @nerrad @ajitbohra /packages/e2e-tests @ntwb @nerrad @ajitbohra +/packages/e2e-test-utils-playwright @kevin940726 /packages/eslint-plugin @gziolo @ntwb @nerrad @ajitbohra /packages/jest-console @gziolo @ntwb @nerrad @ajitbohra /packages/jest-preset-default @gziolo @ntwb @nerrad @ajitbohra @@ -81,6 +82,7 @@ /packages/prettier-config @ntwb @gziolo /packages/scripts @gziolo @ntwb @nerrad @ajitbohra @ryanwelcher /packages/stylelint-config @ntwb +/test/e2e @kevin940726 # UI Components /packages/components @ajitbohra @@ -124,6 +126,7 @@ # Project Management /.github /packages/project-management-automation +/packages/report-flaky-tests @kevin940726 # wp-env /packages/env @noahtallen diff --git a/.github/workflows/build-plugin-zip.yml b/.github/workflows/build-plugin-zip.yml index c738026529315..b6a6dfdc2a9d8 100644 --- a/.github/workflows/build-plugin-zip.yml +++ b/.github/workflows/build-plugin-zip.yml @@ -169,7 +169,7 @@ jobs: ref: ${{ needs.bump-version.outputs.release_branch || github.ref }} - name: Use desired version of NodeJS - uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 with: node-version-file: '.nvmrc' cache: npm @@ -327,7 +327,7 @@ jobs: git config user.email gutenberg@wordpress.org - name: Setup Node (for CLI) - uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 with: node-version-file: 'main/.nvmrc' registry-url: 'https://registry.npmjs.org' diff --git a/.github/workflows/bundle-size.yml b/.github/workflows/bundle-size.yml index 5a07b367ffa11..a212b708f5183 100644 --- a/.github/workflows/bundle-size.yml +++ b/.github/workflows/bundle-size.yml @@ -42,7 +42,7 @@ jobs: fetch-depth: 1 - name: Use desired version of NodeJS - uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 with: node-version-file: '.nvmrc' cache: npm diff --git a/.github/workflows/create-block.yml b/.github/workflows/create-block.yml index 9b98d3d9d4116..0a8b94cc87779 100644 --- a/.github/workflows/create-block.yml +++ b/.github/workflows/create-block.yml @@ -27,7 +27,7 @@ jobs: - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 - name: Use desired version of NodeJS - uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 with: node-version: ${{ matrix.node }} cache: npm diff --git a/.github/workflows/end2end-test.yml b/.github/workflows/end2end-test.yml index 46278d6384a5b..f5a798795397f 100644 --- a/.github/workflows/end2end-test.yml +++ b/.github/workflows/end2end-test.yml @@ -29,7 +29,7 @@ jobs: - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 - name: Use desired version of NodeJS - uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 with: node-version-file: '.nvmrc' cache: npm @@ -75,7 +75,7 @@ jobs: - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 - name: Use desired version of NodeJS - uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 with: node-version-file: '.nvmrc' cache: npm @@ -135,7 +135,7 @@ jobs: - name: Use desired version of NodeJS if: ${{ steps.download_artifact.outcome == 'success' }} - uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 with: node-version-file: '.nvmrc' cache: npm diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index 675642df3c26c..b3ccb118820b0 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -24,7 +24,7 @@ jobs: - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 - name: Use desired version of NodeJS - uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 with: node-version-file: '.nvmrc' cache: npm diff --git a/.github/workflows/publish-npm-packages.yml b/.github/workflows/publish-npm-packages.yml index 5a8249e1d1be9..25569e6487bc5 100644 --- a/.github/workflows/publish-npm-packages.yml +++ b/.github/workflows/publish-npm-packages.yml @@ -50,7 +50,7 @@ jobs: git config user.email gutenberg@wordpress.org - name: Setup Node (for CLI) - uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 with: node-version-file: 'main/.nvmrc' registry-url: 'https://registry.npmjs.org' diff --git a/.github/workflows/pull-request-automation.yml b/.github/workflows/pull-request-automation.yml index 98ff14fbac7ee..e9441f3a4e7e2 100644 --- a/.github/workflows/pull-request-automation.yml +++ b/.github/workflows/pull-request-automation.yml @@ -20,7 +20,7 @@ jobs: ref: trunk - name: Use desired version of NodeJS - uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 with: node-version: ${{ matrix.node }} diff --git a/.github/workflows/rnmobile-android-runner.yml b/.github/workflows/rnmobile-android-runner.yml index dba62b04dd708..832c42c9a5b40 100644 --- a/.github/workflows/rnmobile-android-runner.yml +++ b/.github/workflows/rnmobile-android-runner.yml @@ -32,7 +32,7 @@ jobs: java-version: '11' - name: Use desired version of NodeJS - uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 with: node-version-file: '.nvmrc' cache: npm diff --git a/.github/workflows/rnmobile-ios-runner.yml b/.github/workflows/rnmobile-ios-runner.yml index 0494928ad1b0d..352395bf8eda7 100644 --- a/.github/workflows/rnmobile-ios-runner.yml +++ b/.github/workflows/rnmobile-ios-runner.yml @@ -26,7 +26,7 @@ jobs: - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 - name: Use desired version of NodeJS - uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 with: node-version-file: '.nvmrc' cache: npm diff --git a/.github/workflows/static-checks.yml b/.github/workflows/static-checks.yml index 4abc1f1a354d8..57fcc381aeece 100644 --- a/.github/workflows/static-checks.yml +++ b/.github/workflows/static-checks.yml @@ -25,7 +25,7 @@ jobs: - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 - name: Use desired version of NodeJS - uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 with: node-version-file: '.nvmrc' cache: npm diff --git a/.github/workflows/storybook-pages.yml b/.github/workflows/storybook-pages.yml index da1f3c446ed76..c613e5b3637e2 100644 --- a/.github/workflows/storybook-pages.yml +++ b/.github/workflows/storybook-pages.yml @@ -17,7 +17,7 @@ jobs: ref: trunk - name: Use desired version of NodeJS - uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 with: node-version-file: '.nvmrc' cache: npm diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index c1fd9850191da..e893920ae01d5 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -9,6 +9,8 @@ on: - trunk - 'release/**' - 'wp/**' + # Allow manually triggering the workflow. + workflow_dispatch: # Cancels all previous workflow runs for pull requests that have not completed. concurrency: @@ -32,7 +34,7 @@ jobs: - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 - name: Use desired version of NodeJS - uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 with: node-version: ${{ matrix.node }} cache: npm @@ -51,39 +53,179 @@ jobs: - name: Running the date tests run: npm run test:unit:date -- --ci --maxWorkers=2 --cacheDirectory="$HOME/.jest-cache" - unit-php: - name: PHP + test-php: + name: PHP ${{ matrix.php }}${{ matrix.multisite && ' multisite' || '' }} on ubuntu-latest runs-on: ubuntu-latest + timeout-minutes: 20 if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} + strategy: + fail-fast: true + matrix: + php: + - '5.6' + - '7.0' + - '7.1' + - '7.2' + - '7.3' + - '7.4' + - '8.0' + - '8.1' + - '8.2' + multisite: [false, true] + + env: + WP_ENV_PHP_VERSION: ${{ matrix.php }} steps: - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 - - name: Use desired version of NodeJS - uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 + - name: Set up Node.js + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 with: node-version-file: '.nvmrc' cache: npm - - name: Npm install and build + ## + # This allows Composer dependencies to be installed using a single step. + # + # Since the tests are currently run within the Docker containers where the PHP version varies, + # the same PHP version needs to be configured for the action runner machine so that the correct + # dependency versions are installed and cached. + ## + - name: Set up PHP + uses: shivammathur/setup-php@8e2ac35f639d3e794c1da1f28999385ab6fdf0fc # v2.23.0 + with: + php-version: '${{ matrix.php }}' + ini-file: development + coverage: none + + # Ensure that Composer installs the correct versions of packages. + - name: Override PHP version in composer.json + run: composer config platform.php ${{ matrix.php }} + + # The spatie/phpunit-watcher package is not compatible with PHP < 7.2. + # It must be removed before running the tests. + - name: Remove incompatible Composer packages + if: ${{ matrix.php < '7.2' }} + run: composer remove spatie/phpunit-watcher --dev --no-update + + # Since Composer dependencies are installed using `composer update` and no lock file is in version control, + # passing a custom cache suffix ensures that the cache is flushed at least once per week. + - name: Install Composer dependencies + uses: ramsey/composer-install@83af392bf5f031813d25e6fe4cd626cdba9a2df6 # v2.2.0 + with: + custom-cache-suffix: $(/bin/date -u --date='last Mon' "+%F") + + - name: Install npm dependencies run: | npm ci npm run build - - name: Install WordPress + - name: Docker debug information run: | - npm run wp-env start + docker -v + docker-compose -v - - name: Running lint check - run: npm run lint:php + - name: General debug information + run: | + npm --version + node --version + curl --version + git --version + svn --version + locale -a + + - name: Start Docker environment + run: npm run wp-env start + + - name: Log running Docker containers + run: docker ps -a + + - name: Docker container debug information + run: | + npm run wp-env run tests-mysql "mysql --version" + npm run wp-env run tests-wordpress "php --version" + npm run wp-env run tests-wordpress "php -m" + npm run wp-env run tests-wordpress "php -i" + npm run wp-env run tests-wordpress "/var/www/html/wp-content/plugins/gutenberg/vendor/bin/phpunit --version" + npm run wp-env run tests-wordpress "locale -a" - name: Running single site unit tests + if: ${{ ! matrix.multisite }} run: npm run test:unit:php - if: ${{ success() || failure() }} - name: Running multisite unit tests + if: ${{ matrix.multisite }} run: npm run test:unit:php:multisite - if: ${{ success() || failure() }} + + phpcs: + name: PHP coding standards + runs-on: ubuntu-latest + timeout-minutes: 20 + if: ${{ github.repository == 'WordPress/gutenberg' || github.event_name == 'pull_request' }} + + steps: + - name: Checkout repository + uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 + + - name: Set up PHP + uses: shivammathur/setup-php@8e2ac35f639d3e794c1da1f28999385ab6fdf0fc # v2.23.0 + with: + php-version: '7.4' + coverage: none + tools: cs2pr + + # This date is used to ensure that the PHPCS cache is cleared at least once every week. + # http://man7.org/linux/man-pages/man1/date.1.html + - name: "Get last Monday's date" + id: get-date + run: echo "date=$(/bin/date -u --date='last Mon' "+%F")" >> $GITHUB_OUTPUT + + - name: Cache PHPCS scan cache + uses: actions/cache@9b0c1fce7a93df8e3bb8926b0d6e9d89e92f20a7 # v3.0.11 + with: + path: .cache/phpcs.json + key: ${{ runner.os }}-date-${{ steps.get-date.outputs.date }}-phpcs-cache-${{ hashFiles('**/composer.json', 'phpcs.xml.dist') }} + + # Since Composer dependencies are installed using `composer update` and no lock file is in version control, + # passing a custom cache suffix ensures that the cache is flushed at least once per week. + - name: Install Composer dependencies + uses: ramsey/composer-install@83af392bf5f031813d25e6fe4cd626cdba9a2df6 # v2.2.0 + with: + custom-cache-suffix: ${{ steps.get-date.outputs.date }} + + - name: Make Composer packages available globally + run: echo "${PWD}/vendor/bin" >> $GITHUB_PATH + + - name: Run PHPCS on all Gutenberg files + id: phpcs-gutenberg + run: phpcs --report-full --report-checkstyle=./.cache/phpcs-report.xml + + - name: Show PHPCS results in PR + if: ${{ always() && steps.phpcs-gutenberg.outcome == 'failure' }} + run: cs2pr ./.cache/phpcs-report.xml + + - name: Ensure version-controlled files are not modified during the tests + run: git diff --exit-code + + # This job is deprecated but be present for compatibility reasons. + unit-php: + name: PHP + runs-on: ubuntu-latest + needs: [test-php, phpcs] + if: ${{ always() }} + steps: + - name: Fail the job if the PHPUnit tests fail + if: ${{ needs.test-php.result != 'success' }} + run: exit 1 + + - name: "Fail the job if the code doesn't conform to the coding standards" + if: ${{ needs.phpcs.result != 'success' }} + run: exit 1 + + - name: Mark the job as passed if all the checks pass + if: ${{ needs.test-php.result == 'success' && needs.phpcs.result == 'success' }} + run: exit 0 mobile-unit-js: name: Mobile @@ -94,7 +236,7 @@ jobs: - uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0 - name: Use desired version of NodeJS - uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516 # v3.5.1 + uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0 with: node-version-file: '.nvmrc' cache: npm diff --git a/.gitignore b/.gitignore index aebfcd623ad2f..71ffc1c5bbb25 100644 --- a/.gitignore +++ b/.gitignore @@ -16,7 +16,14 @@ yarn.lock /perf-envs /composer.lock +# The /.cache folder is needed for phpcs to cache results between runs, while other .cache folders must be ignored +# It is not possible to re-include a file if a parent directory of that file is excluded +# So, both /.cache and /.cache./.gitkeep must be re-included .cache +!/.cache/ +/.cache/** +!/.cache/.gitkeep + .eslintcache *.tsbuildinfo diff --git a/changelog.txt b/changelog.txt index 65bb846e47371..76a59d3c8785f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,6 +1,6 @@ == Changelog == -= 15.0.0-rc.1 = += 15.0.0 = @@ -8,45 +8,60 @@ ### Enhancements -- Add help text on the HTML element for the Comments and Query Loop blocks. ([46989](https://github.com/WordPress/gutenberg/pull/46989)) -- URLInput: Deprecate bottom margin. ([46692](https://github.com/WordPress/gutenberg/pull/46692)) - #### Site Editor - Allow resizing the sidebar and frame of the site editor. ([46903](https://github.com/WordPress/gutenberg/pull/46903)) - Remove the editor notices from the site editor frame. ([46931](https://github.com/WordPress/gutenberg/pull/46931)) - Synchronize the canvas mode with the site editor URL. ([47002](https://github.com/WordPress/gutenberg/pull/47002)) +- Site Editor: Enable copy/cut shortcut. ([45752](https://github.com/WordPress/gutenberg/pull/45752)) #### Block Library - Add paste styles to the block settings. ([45477](https://github.com/WordPress/gutenberg/pull/45477)) - Prevent the image from being resized larger than its container. ([45775](https://github.com/WordPress/gutenberg/pull/45775)) - Replace block settings menu with a custom menu in off canvas editor. ([46675](https://github.com/WordPress/gutenberg/pull/46675)) +- Add help text on the HTML element for the Comments and Query Loop blocks. ([46989](https://github.com/WordPress/gutenberg/pull/46989)) +- Navigation: Add an icon to the add submenu item option. ([46884](https://github.com/WordPress/gutenberg/pull/46884)) +- Navigation: Remove ghost inserter. ([46919](https://github.com/WordPress/gutenberg/pull/46919)) +- Navigation: Show the loading indictor when users add a new navigation menu. ([46855](https://github.com/WordPress/gutenberg/pull/46855)) +- Page List Block: Fix warning error when the parent page has no child pages. ([46829](https://github.com/WordPress/gutenberg/pull/46829)) +- Page List Item: Disable block toolbar. ([46950](https://github.com/WordPress/gutenberg/pull/46950)) +- Template Parts: Avoid duplicate titles on creation. ([46996](https://github.com/WordPress/gutenberg/pull/46996)) +- Navigation: Add more explicit labels to the Navigation Menu Selector. ([47015](https://github.com/WordPress/gutenberg/pull/47015)) + +#### Block Editor +- URLInput: Deprecate bottom margin. ([46692](https://github.com/WordPress/gutenberg/pull/46692)) +- Block editor: Move content styles to avoid triggering iframe compat mode. ([46728](https://github.com/WordPress/gutenberg/pull/46728)) +- Iframe: Preload style assets to avoid flash of unstyled content. ([46706](https://github.com/WordPress/gutenberg/pull/46706)) #### Inspector Controls - Sidebar Tabs: Add text only mode for block inspector tabs. ([46968](https://github.com/WordPress/gutenberg/pull/46968)) - Sidebar Tabs: Stabilize the block inspector tabs experiment. ([47045](https://github.com/WordPress/gutenberg/pull/47045)) +- Remove Block Inspector Button. ([46709](https://github.com/WordPress/gutenberg/pull/46709)) #### Global Styles - Update push changes to global styles label text to "apply globally". ([46965](https://github.com/WordPress/gutenberg/pull/46965)) +- Edit block style variations from global styles. ([46343](https://github.com/WordPress/gutenberg/pull/46343)) #### Accessibility - TabPanel: Add prop to allow disabling of a tab button. ([46471](https://github.com/WordPress/gutenberg/pull/46471)) #### Components - SelectControl: Remove margin overrides and add new opt-in prop. ([46448](https://github.com/WordPress/gutenberg/pull/46448)) +- Use data URI for `FocalPointPicker` video story. ([42377](https://github.com/WordPress/gutenberg/pull/42377)) +#### List View +- Update template part children background color. ([46708](https://github.com/WordPress/gutenberg/pull/46708)) +- Update template part hover style in list view. ([46707](https://github.com/WordPress/gutenberg/pull/46707)) -### Bug Fixes -- Docs: Fix typos. ([46912](https://github.com/WordPress/gutenberg/pull/46912)) -- Fix offsite navigation editor component loading issue. ([46937](https://github.com/WordPress/gutenberg/pull/46937)) -- Iframe: compat styles: Check for ownerNode === null. ([46932](https://github.com/WordPress/gutenberg/pull/46932)) -- Tabs in preferences: Fix regression from horizontal tabs. ([46796](https://github.com/WordPress/gutenberg/pull/46796)) +### Bug Fixes #### Block Editor - Align labels on Link Control. ([46936](https://github.com/WordPress/gutenberg/pull/46936)) - Remove the border property from the body element on previews. ([46946](https://github.com/WordPress/gutenberg/pull/46946)) - [Inserter]: Don't show empty `reusable` tab if not allowed to insert reusable blocks. ([46922](https://github.com/WordPress/gutenberg/pull/46922)) - [Inserter]: Hide empty pattern categories. ([46923](https://github.com/WordPress/gutenberg/pull/46923)) +- Fix offsite navigation editor component loading issue. ([46937](https://github.com/WordPress/gutenberg/pull/46937)) +- Iframe: compat styles: Check for ownerNode === null. ([46932](https://github.com/WordPress/gutenberg/pull/46932)) #### Block Library - Navigation Block: Properly decode URL-encoded links. ([46435](https://github.com/WordPress/gutenberg/pull/46435)) @@ -57,20 +72,23 @@ - ComboboxControl: Fix unexpected behaviour in IME Composition. ([46827](https://github.com/WordPress/gutenberg/pull/46827)) - Fix TreeGrid keyboard nav skipping Edit Block button in off canvas editor. ([46998](https://github.com/WordPress/gutenberg/pull/46998)) - [Placeholder]: Set fixed right margin for label's icon. ([46918](https://github.com/WordPress/gutenberg/pull/46918)) +- Tabs in preferences: Fix regression from horizontal tabs. ([46796](https://github.com/WordPress/gutenberg/pull/46796)) #### Global Styles - Fix the 'test_remove_invalid_element_pseudo_selectors' test case. ([47049](https://github.com/WordPress/gutenberg/pull/47049)) - Fixed Global Styles variables for colors, font family, gradient, fontSize. ([46944](https://github.com/WordPress/gutenberg/pull/46944)) +#### Inspector Controls +- Block Inspector: Fix browser warning error when block is not selected. ([46875](https://github.com/WordPress/gutenberg/pull/46875)) -### Performance -- Lodash: Remove `_.pickBy()` from block editor and deprecate. ([46999](https://github.com/WordPress/gutenberg/pull/46999)) -- Optimize keydown event handlers. ([46653](https://github.com/WordPress/gutenberg/pull/46653)) +### Performance #### Post Editor - Lodash: Remove `_.pickBy()` from editor hooks. ([46982](https://github.com/WordPress/gutenberg/pull/46982)) - Lodash: Remove `_.pickBy()` from template deletion. ([46975](https://github.com/WordPress/gutenberg/pull/46975)) +- Lodash: Remove `_.pickBy()` from block editor and deprecate. ([46999](https://github.com/WordPress/gutenberg/pull/46999)) +- Optimize keydown event handlers. ([46653](https://github.com/WordPress/gutenberg/pull/46653)) #### Global Styles - Lodash: Remove `_.pickBy()` from `getNodesWithStyles()`. ([46980](https://github.com/WordPress/gutenberg/pull/46980)) @@ -81,9 +99,11 @@ ### Experiments -- Update last inserted block state to track multiple blocks. ([46885](https://github.com/WordPress/gutenberg/pull/46885)) - WP_HTML_Tag_Processor: Add `get_attribute_names_with_prefix()` method. ([46840](https://github.com/WordPress/gutenberg/pull/46840)) +#### Block Editor +- Update last inserted block state to track multiple blocks. ([46885](https://github.com/WordPress/gutenberg/pull/46885)) + #### Block Library - Alternative Nav Offcanvas show link UI for submenu creation. ([46857](https://github.com/WordPress/gutenberg/pull/46857)) - Nav offcanvas disable direct insertion. ([46898](https://github.com/WordPress/gutenberg/pull/46898)) @@ -101,25 +121,36 @@ - Remove stack exchange from new issue templates. ([36158](https://github.com/WordPress/gutenberg/pull/36158)) - Revise NPM to npm. ([46963](https://github.com/WordPress/gutenberg/pull/46963)) - Update legacy-widget-block.md. ([44343](https://github.com/WordPress/gutenberg/pull/44343)) +- Updating missing shortcut in FAQ section. ([44968](https://github.com/WordPress/gutenberg/pull/44968)) - [RFC] Add documentation for snapshot testing in Playwright end-to-end tests. ([45709](https://github.com/WordPress/gutenberg/pull/45709)) - +- Update copyright year to 2023 in `license.md`. ([46910](https://github.com/WordPress/gutenberg/pull/46910)) +- Docs: Fix typos. ([46912](https://github.com/WordPress/gutenberg/pull/46912)) ### Code Quality -- Chore: Fix incorrect usage of map instead of forEach. ([46853](https://github.com/WordPress/gutenberg/pull/46853)) -- Chore: Remove unreachable line from phpunit/fixtures/mock-provider.php. ([46843](https://github.com/WordPress/gutenberg/pull/46843)) -- Fix number of arguments passed to hasBlockMetadataSupport. ([46842](https://github.com/WordPress/gutenberg/pull/46842)) -- Fix: Use of array index instead of post id on latest posts. ([46911](https://github.com/WordPress/gutenberg/pull/46911)) - #### Components - Dashicon: Remove unnecessary type for `className` prop. ([46849](https://github.com/WordPress/gutenberg/pull/46849)) - ItemGroup: Migrate Storybook to controls, refactor to TypeScript. ([46945](https://github.com/WordPress/gutenberg/pull/46945)) - Toolbar: Move all subcomponents under the same folder. ([46951](https://github.com/WordPress/gutenberg/pull/46951)) +- ColorPicker: Remove knobs in stories. ([46772](https://github.com/WordPress/gutenberg/pull/46772)) +- Guide: Remove knobs in stories. ([46773](https://github.com/WordPress/gutenberg/pull/46773)) +- Notice: Remove knobs in stories. ([46956](https://github.com/WordPress/gutenberg/pull/46956)) +- Panel: Remove knobs from stories. ([46958](https://github.com/WordPress/gutenberg/pull/46958)) +- ResizableBox: Remove knobs in stories. ([46774](https://github.com/WordPress/gutenberg/pull/46774)) +- ResponsiveWrapper: Convert to TypeScript. ([46480](https://github.com/WordPress/gutenberg/pull/46480)) +- SandBox: Convert to TypeScript. ([46478](https://github.com/WordPress/gutenberg/pull/46478)) +- SlotFill: Remove knobs in stories. ([46957](https://github.com/WordPress/gutenberg/pull/46957)) +- useSelect: Implement with useSyncExternalStore. ([46538](https://github.com/WordPress/gutenberg/pull/46538)) #### Block Library - Navigation Link: Fix PHP notices in unit tests. ([47070](https://github.com/WordPress/gutenberg/pull/47070)) - Video Block: Fix browser warning error when settings are toggled. ([46835](https://github.com/WordPress/gutenberg/pull/46835)) +- Adds an identifier prop to the RichText component for captions, allowing annotation. ([46917](https://github.com/WordPress/gutenberg/pull/46917)) +- Fix: Use of array index instead of post id on latest posts. ([46911](https://github.com/WordPress/gutenberg/pull/46911)) +#### Block Editor +- Simplify the way we create a link UI control in the offcanvas editor. ([46744](https://github.com/WordPress/gutenberg/pull/46744)) +- Fix number of arguments passed to hasBlockMetadataSupport. ([46842](https://github.com/WordPress/gutenberg/pull/46842)) ### Tools @@ -129,63 +160,14 @@ - Migrate Post Visibility Test to Playwright. ([44488](https://github.com/WordPress/gutenberg/pull/44488)) - Navigation block end-to-end tests: Default to a list of pages if there are no menus. ([45070](https://github.com/WordPress/gutenberg/pull/45070)) - Only use a single comment for the flakiness report on PRs. ([46785](https://github.com/WordPress/gutenberg/pull/46785)) +- Mobile - Move the `gutenberg-editor-block-insertion-2` end-to-end tests to integration tests. ([46882](https://github.com/WordPress/gutenberg/pull/46882)) +- Chore: Fix incorrect usage of map instead of forEach. ([46853](https://github.com/WordPress/gutenberg/pull/46853)) +- Chore: Remove unreachable line from phpunit/fixtures/mock-provider.php. ([46843](https://github.com/WordPress/gutenberg/pull/46843)) #### Build Tooling - package.json: Add script to profile unit tests. ([46909](https://github.com/WordPress/gutenberg/pull/46909)) -### Various - -- Block editor: Move content styles to avoid triggering iframe compat mode. ([46728](https://github.com/WordPress/gutenberg/pull/46728)) -- Iframe: Preload style assets to avoid flash of unstyled content. ([46706](https://github.com/WordPress/gutenberg/pull/46706)) -- Mobile - Move the `gutenberg-editor-block-insertion-2` end-to-end tests to integration tests. ([46882](https://github.com/WordPress/gutenberg/pull/46882)) -- Update copyright year to 2023 in `license.md`. ([46910](https://github.com/WordPress/gutenberg/pull/46910)) -- Updating missing shortcut in FAQ section. ([44968](https://github.com/WordPress/gutenberg/pull/44968)) - -#### Components -- ColorPicker: Remove knobs in stories. ([46772](https://github.com/WordPress/gutenberg/pull/46772)) -- Guide: Remove knobs in stories. ([46773](https://github.com/WordPress/gutenberg/pull/46773)) -- Notice: Remove knobs in stories. ([46956](https://github.com/WordPress/gutenberg/pull/46956)) -- Panel: Remove knobs from stories. ([46958](https://github.com/WordPress/gutenberg/pull/46958)) -- ResizableBox: Remove knobs in stories. ([46774](https://github.com/WordPress/gutenberg/pull/46774)) -- ResponsiveWrapper: Convert to TypeScript. ([46480](https://github.com/WordPress/gutenberg/pull/46480)) -- SandBox: Convert to TypeScript. ([46478](https://github.com/WordPress/gutenberg/pull/46478)) -- SlotFill: Remove knobs in stories. ([46957](https://github.com/WordPress/gutenberg/pull/46957)) -- Use data URI for `FocalPointPicker` video story. ([42377](https://github.com/WordPress/gutenberg/pull/42377)) - -#### Block Library -- Navigation: Add an icon to the add submenu item option. ([46884](https://github.com/WordPress/gutenberg/pull/46884)) -- Navigation: Remove ghost inserter. ([46919](https://github.com/WordPress/gutenberg/pull/46919)) -- Navigation: Show the loading indictor when users add a new navigation menu. ([46855](https://github.com/WordPress/gutenberg/pull/46855)) -- Page List Block: Fix warning error when the parent page has no child pages. ([46829](https://github.com/WordPress/gutenberg/pull/46829)) -- Page List Item: Disable block toolbar. ([46950](https://github.com/WordPress/gutenberg/pull/46950)) -- Simplify the way we create a link UI control in the offcanvas editor. ([46744](https://github.com/WordPress/gutenberg/pull/46744)) -- Template Parts: Avoid duplicate titles on creation. ([46996](https://github.com/WordPress/gutenberg/pull/46996)) - -#### Inspector Controls -- Block Inspector: Fix browser warning error when block is not selected. ([46875](https://github.com/WordPress/gutenberg/pull/46875)) -- Remove Block Inspector Button. ([46709](https://github.com/WordPress/gutenberg/pull/46709)) - -#### List View -- Update template part children background color. ([46708](https://github.com/WordPress/gutenberg/pull/46708)) -- Update template part hover style in list view. ([46707](https://github.com/WordPress/gutenberg/pull/46707)) - -#### Accessibility -- Navigation: Add more explicit labels to the Navigation Menu Selector. ([47015](https://github.com/WordPress/gutenberg/pull/47015)) - -#### Rich Text -- Adds an identifier prop to the RichText component for captions, allowing annotation. ([46917](https://github.com/WordPress/gutenberg/pull/46917)) - -#### Data Layer -- useSelect: Implement with useSyncExternalStore. ([46538](https://github.com/WordPress/gutenberg/pull/46538)) - -#### Global Styles -- Edit block style variations from global styles. ([46343](https://github.com/WordPress/gutenberg/pull/46343)) - -#### Block Editor -- Site Editor: Enable copy/cut shortcut. ([45752](https://github.com/WordPress/gutenberg/pull/45752)) - - ## First time contributors The following PRs were merged by first time contributors: diff --git a/docs/contributors/code/coding-guidelines.md b/docs/contributors/code/coding-guidelines.md index 556833ca89b7e..9fc115b8eb9e3 100644 --- a/docs/contributors/code/coding-guidelines.md +++ b/docs/contributors/code/coding-guidelines.md @@ -136,10 +136,318 @@ export { __unstableDoTerribleAwfulAction } from './api'; - An **experimental API** is one which is planned for eventual public availability, but is subject to further experimentation, testing, and discussion. - An **unstable API** is one which serves as a means to an end. It is not desired to ever be converted into a public API. -In both cases, the API should be made stable or removed at the earliest opportunity. +In both cases, the API should be made stable or removed at the earliest opportunity. While an experimental API may often stabilize into a publicly-available API, there is no guarantee that it will. The conversion to a stable API will inherently be considered a breaking change by the mere fact that the function name must be changed to remove the `__experimental` prefix. +#### Experimental APIs merged into WordPress Core become a liability + +**Avoid introducing public experimental APIs.** + +As of June 2022, WordPress Core contains 280 publicly exported experimental APIs. They got merged from the Gutenberg +plugin during the major WordPress releases. Many plugins and themes rely on these experimental APIs for essential +features that can't be accessed in any other way. Naturally, these APIs can't be removed without a warning anymore. +They are a part of the WordPress public API and fall under the +[WordPress Backwards Compatibility policy](https://developer.wordpress.org/block-editor/contributors/code/backward-compatibility/). +Removing them involves a deprecation process. It may be relatively easy for some APIs, but it may require effort and +span multiple WordPress releases for others. + +**Use private experimental APIs instead.** + +Make your experimental APIs private and don't expose them to WordPress extenders. + +This way they'll remain internal implementation details that can be changed or removed + without a warning and without breaking WordPress plugins. + +The tactical guidelines below will help you write code without introducing new experimental APIs. + +#### General guidelines + +Some `__experimental` functions are exported in *package A* and only used in a single *package B* and nowhere else. Consider removing such functions from *package A* and making them private and non-exported members of *package B*. + +If your experimental API is only meant for the Gutenberg Plugin but not for the next WordPress major release, consider limiting the export to the plugin environment. For example, `@wordpress/components` could do that to receive early feedback about a new Component, but avoid bringing that component to WordPress core: + +```js +if ( IS_GUTENBERG_PLUGIN ) { + export { __experimentalFunction } from './experiments'; +} +``` + +#### Replace experimental selectors with hooks + +Sometimes a non-exported React hook suffices as a substitute for introducing a new experimental selectors: + +```js +// Instead of this: + // selectors.js: + export function __unstableHasActiveBlockOverlayActive( state, parent ) { /* ... */ } + export function __unstableIsWithinBlockOverlay( state, clientId ) { + let parent = state.blocks.parents[ clientId ]; + while ( !! parent ) { + if ( __unstableHasActiveBlockOverlayActive( state, parent ) ) { + return true; + } + parent = state.blocks.parents[ parent ]; + } + return false; + } + // MyComponent.js: + function MyComponent({ clientId }) { + const { __unstableIsWithinBlockOverlay } = useSelect( myStore ); + const isWithinBlockOverlay = __unstableIsWithinBlockOverlay( clientId ); + // ... + } + +// Consider this: + // MyComponent.js: + function hasActiveBlockOverlayActive ( selectors, parent ) { /* ... */ } + function useIsWithinBlockOverlay( clientId ) { + return useSelect( ( select ) => { + const selectors = select( blockEditorStore ); + let parent = selectors.getBlockRootClientId( clientId ); + while ( !!parent ) { + if ( hasActiveBlockOverlayActive( selectors, parent ) ) { + return true; + } + parent = selectors.getBlockRootClientId( parent ); + } + return false; + }); + } + function MyComponent({ clientId }) { + const isWithinBlockOverlay = useIsWithinBlockOverlay( clientId ); + // ... + } +``` + +#### Dispatch experimental actions in thunks + +Turning an existing public action into a [thunk](/docs/how-to-guides/thunks.md) +enables dispatching private actions inline: + +```js +export function toggleFeature( scope, featureName ) { + return function ( { dispatch } ) { + dispatch({ type: '__experimental_BEFORE_TOGGLE' }) + // ... + }; +} +``` + +#### Use the `lock()` and `unlock()` API from `@wordpress/experiments` to privately export almost anything + +Each `@wordpress` package wanting to privately access or expose experimental APIs can +do so by opting-in to `@wordpress/experiments`: + +```js +// In packages/block-editor/experiments.js: +import { __dangerousOptInToUnstableAPIsOnlyForCoreModules } from '@wordpress/experiments'; +export const { lock, unlock } = + __dangerousOptInToUnstableAPIsOnlyForCoreModules( + 'I know using unstable features means my plugin or theme will inevitably break on the next WordPress release.', + '@wordpress/block-editor' // Name of the package calling __dangerousOptInToUnstableAPIsOnlyForCoreModules, + // (not the name of the package whose APIs you want to access) + ); +``` + +Each `@wordpress` package may only opt-in once. The process clearly communicates the extenders are not supposed +to use it. This document will focus on the usage examples, but you can [find out more about the `@wordpress/experiments` package in the its README.md](/packages/experiments/README.md). + +Once the package opted-in, you can use the `lock()` and `unlock()` utilities: + +```js +// Say this object is exported from a package: +export const publicObject = {}; + +// However, this string is internal and should not be publicly available: +const __experimentalString = '__experimental information'; + +// Solution: lock the string "inside" of the object: +lock( publicObject, __experimentalString ); + +// The string is not nested in the object and cannot be extracted from it: +console.log( publicObject ); +// {} + +// The only way to access the string is by "unlocking" the object: +console.log( unlock( publicObject ) ); +// "__experimental information" + +// lock() accepts all data types, not just strings: +export const anotherObject = {}; +lock( anotherObject, function __experimentalFn() {} ); +console.log( unlock( anotherObject ) ); +// function __experimentalFn() {} +``` + +Keep reading to learn how to use `lock()` and `unlock()` to avoid publicly exporting +different kinds of `__experimental` APIs. + +##### Experimental selectors and actions + +You can attach private selectors and actions to a public store: + +```js +// In packages/package1/store.js: +import { experiments as dataExperiments } from '@wordpress/data'; +import { __experimentalHasContentRoleAttribute, ...selectors } from './selectors'; +import { __experimentalToggleFeature, ...actions } from './selectors'; +// The `lock` function is exported from the internal experiments.js file where +// the opt-in function was called. +import { lock, unlock } from './experiments'; + +export const store = registerStore(/* ... */); +// Attach a private action to the exported store: +unlock( store ).registerPrivateActions({ + __experimentalToggleFeature +} ); + +// Attach a private action to the exported store: +unlock( store ).registerPrivateSelectors({ + __experimentalHasContentRoleAttribute +} ); + + +// In packages/package2/MyComponent.js: +import { store } from '@wordpress/package1'; +import { useSelect } from '@wordpress/data'; +// The `unlock` function is exported from the internal experiments.js file where +// the opt-in function was called. +import { unlock } from './experiments'; + +function MyComponent() { + const hasRole = useSelect( ( select ) => ( + // Use the private selector: + unlock( select( store ) ).__experimentalHasContentRoleAttribute() + // Note the unlock() is required. This line wouldn't work: + // select( store ).__experimentalHasContentRoleAttribute() + ) ); + + // Use the private action: + unlock( useDispatch( store ) ).__experimentalToggleFeature(); + + // ... +} +``` + +##### Experimental functions, classes, and variables + +```js +// In packages/package1/index.js: +import { lock } from './experiments'; + +export const experiments = {}; +/* Attach private data to the exported object */ +lock(experiments, { + __experimentalCallback: function() {}, + __experimentalReactComponent: function ExperimentalComponent() { return
; }, + __experimentalClass: class Experiment{}, + __experimentalVariable: 5, +}); + + +// In packages/package2/index.js: +import { experiments } from '@wordpress/package1'; +import { unlock } from './experiments'; + +const { + __experimentalCallback, + __experimentalReactComponent, + __experimentalClass, + __experimentalVariable +} = unlock( experiments ); +``` + +#### Experimental function arguments + +To add an experimental argument to a stable function you'll need +to prepare a stable and an experimental version of that function. +Then, export the stable function and `lock()` the unstable function +inside it: + +```js +// In @wordpress/package1/index.js: +import { lock } from './experiments'; + +// The experimental function contains all the logic +function __experimentalValidateBlocks(formula, __experimentalIsStrict) { + let isValid = false; + // ...complex logic we don't want to duplicate... + if ( __experimentalIsStrict ) { + // ... + } + // ...complex logic we don't want to duplicate... + + return isValid; +} + +// The stable public function is a thin wrapper that calls the +// experimental function with the experimental features disabled +export function validateBlocks(blocks) { + __experimentalValidateBlocks(blocks, false); +} +lock( validateBlocks, __experimentalValidateBlocks ); + + +// In @wordpress/package2/index.js: +import { validateBlocks } from '@wordpress/package1'; +import { unlock } from './experiments'; + +// The experimental function may be "unlocked" given the stable function: +const __experimentalValidateBlocks = unlock(validateBlocks); +__experimentalValidateBlocks(blocks, true); +``` + +#### Experimental React Component properties + +To add an experimental argument to a stable component you'll need +to prepare a stable and an experimental version of that component. +Then, export the stable function and `lock()` the unstable function +inside it: + +```js +// In @wordpress/package1/index.js: +import { lock } from './experiments'; + +// The experimental component contains all the logic +const ExperimentalMyButton = ( { title, __experimentalShowIcon = true } ) => { + // ...complex logic we don't want to duplicate... + + return ( + + ); +} + +// The stable public component is a thin wrapper that calls the +// experimental component with the experimental features disabled +export const MyButton = ( { title } ) => + + +lock(MyButton, ExperimentalMyButton); + + +// In @wordpress/package2/index.js: +import { MyButton } from '@wordpress/package1'; +import { unlock } from './experiments'; + +// The experimental component may be "unlocked" given the stable component: +const ExperimentalMyButton = unlock(MyButton); +export function MyComponent() { + return ( + + ) +} +``` + +#### Experimental block.json and theme.json APIs + +As of today, there is no way to restrict the `block.json` and `theme.json` APIs +to the Gutenberg codebase. In the future, however, the new `__experimental` APIs +will only apply to the core WordPress blocks and plugins and themes will not be +able to access them. + ### Objects When possible, use [shorthand notation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#New_notations_in_ECMAScript_2015) when defining object property values: diff --git a/docs/reference-guides/data/data-core-block-editor.md b/docs/reference-guides/data/data-core-block-editor.md index 1b9da160f0f6f..37c44d3b6a893 100644 --- a/docs/reference-guides/data/data-core-block-editor.md +++ b/docs/reference-guides/data/data-core-block-editor.md @@ -159,6 +159,19 @@ _Returns_ - `?string`: Return the client ID of the block, or null if none exists. +### getAllowedBlocks + +Returns the list of allowed inserter blocks for inner blocks children. + +_Parameters_ + +- _state_ `Object`: Editor state. +- _rootClientId_ `?string`: Optional root client ID of block list. + +_Returns_ + +- `Array?`: The list of allowed block types. + ### getBlock Returns a block given its client ID. This is a parsed copy of the block, @@ -673,6 +686,24 @@ _Returns_ - `?string`: Adjacent block's client ID, or null if none exists. +### getPatternsByBlockTypes + +Returns the list of patterns based on their declared `blockTypes` +and a block's name. +Patterns can use `blockTypes` to integrate in work flows like +suggesting appropriate patterns in a Placeholder state(during insertion) +or blocks transformations. + +_Parameters_ + +- _state_ `Object`: Editor state. +- _blockNames_ `string|string[]`: Block's name or array of block names to find matching pattens. +- _rootClientId_ `?string`: Optional target root client ID. + +_Returns_ + +- `Array`: The list of matched block patterns based on declared `blockTypes` and block name. + ### getPreviousBlockClientId Returns the previous block's client ID from the given reference start ID. diff --git a/docs/reference-guides/theme-json-reference/theme-json-living.md b/docs/reference-guides/theme-json-reference/theme-json-living.md index 24b060605da71..913b012a3695f 100644 --- a/docs/reference-guides/theme-json-reference/theme-json-living.md +++ b/docs/reference-guides/theme-json-reference/theme-json-living.md @@ -58,7 +58,7 @@ Settings related to shadows. | Property | Type | Default | Props | | --- | --- | --- |--- | -| palette | array | | name, shadow, slug | +| presets | array | | name, shadow, slug | --- diff --git a/gutenberg.php b/gutenberg.php index 3546a9674f86d..f346773ebc220 100644 --- a/gutenberg.php +++ b/gutenberg.php @@ -5,7 +5,7 @@ * Description: Printing since 1440. This is the development plugin for the new block editor in core. * Requires at least: 6.0 * Requires PHP: 5.6 - * Version: 15.0.0-rc.1 + * Version: 15.0.0 * Author: Gutenberg Team * Text Domain: gutenberg * diff --git a/lib/block-supports/border.php b/lib/block-supports/border.php index 09e8727743342..486f6d99b6489 100644 --- a/lib/block-supports/border.php +++ b/lib/block-supports/border.php @@ -40,7 +40,7 @@ function gutenberg_register_border_support( $block_type ) { * @return array Border CSS classes and inline styles. */ function gutenberg_apply_border_support( $block_type, $block_attributes ) { - if ( gutenberg_should_skip_block_supports_serialization( $block_type, 'border' ) ) { + if ( wp_should_skip_block_supports_serialization( $block_type, 'border' ) ) { return array(); } @@ -52,7 +52,7 @@ function gutenberg_apply_border_support( $block_type, $block_attributes ) { if ( gutenberg_has_border_feature_support( $block_type, 'radius' ) && isset( $block_attributes['style']['border']['radius'] ) && - ! gutenberg_should_skip_block_supports_serialization( $block_type, '__experimentalBorder', 'radius' ) + ! wp_should_skip_block_supports_serialization( $block_type, '__experimentalBorder', 'radius' ) ) { $border_radius = $block_attributes['style']['border']['radius']; @@ -67,7 +67,7 @@ function gutenberg_apply_border_support( $block_type, $block_attributes ) { if ( gutenberg_has_border_feature_support( $block_type, 'style' ) && isset( $block_attributes['style']['border']['style'] ) && - ! gutenberg_should_skip_block_supports_serialization( $block_type, '__experimentalBorder', 'style' ) + ! wp_should_skip_block_supports_serialization( $block_type, '__experimentalBorder', 'style' ) ) { $border_block_styles['style'] = $block_attributes['style']['border']['style']; } @@ -76,7 +76,7 @@ function gutenberg_apply_border_support( $block_type, $block_attributes ) { if ( $has_border_width_support && isset( $block_attributes['style']['border']['width'] ) && - ! gutenberg_should_skip_block_supports_serialization( $block_type, '__experimentalBorder', 'width' ) + ! wp_should_skip_block_supports_serialization( $block_type, '__experimentalBorder', 'width' ) ) { $border_width = $block_attributes['style']['border']['width']; @@ -91,7 +91,7 @@ function gutenberg_apply_border_support( $block_type, $block_attributes ) { // Border color. if ( $has_border_color_support && - ! gutenberg_should_skip_block_supports_serialization( $block_type, '__experimentalBorder', 'color' ) + ! wp_should_skip_block_supports_serialization( $block_type, '__experimentalBorder', 'color' ) ) { $preset_border_color = array_key_exists( 'borderColor', $block_attributes ) ? "var:preset|color|{$block_attributes['borderColor']}" : null; $custom_border_color = _wp_array_get( $block_attributes, array( 'style', 'border', 'color' ), null ); @@ -103,9 +103,9 @@ function gutenberg_apply_border_support( $block_type, $block_attributes ) { foreach ( array( 'top', 'right', 'bottom', 'left' ) as $side ) { $border = _wp_array_get( $block_attributes, array( 'style', 'border', $side ), null ); $border_side_values = array( - 'width' => isset( $border['width'] ) && ! gutenberg_should_skip_block_supports_serialization( $block_type, '__experimentalBorder', 'width' ) ? $border['width'] : null, - 'color' => isset( $border['color'] ) && ! gutenberg_should_skip_block_supports_serialization( $block_type, '__experimentalBorder', 'color' ) ? $border['color'] : null, - 'style' => isset( $border['style'] ) && ! gutenberg_should_skip_block_supports_serialization( $block_type, '__experimentalBorder', 'style' ) ? $border['style'] : null, + 'width' => isset( $border['width'] ) && ! wp_should_skip_block_supports_serialization( $block_type, '__experimentalBorder', 'width' ) ? $border['width'] : null, + 'color' => isset( $border['color'] ) && ! wp_should_skip_block_supports_serialization( $block_type, '__experimentalBorder', 'color' ) ? $border['color'] : null, + 'style' => isset( $border['style'] ) && ! wp_should_skip_block_supports_serialization( $block_type, '__experimentalBorder', 'style' ) ? $border['style'] : null, ); $border_block_styles[ $side ] = $border_side_values; } diff --git a/lib/block-supports/colors.php b/lib/block-supports/colors.php index 8b9702ae44533..7ec32bf14d753 100644 --- a/lib/block-supports/colors.php +++ b/lib/block-supports/colors.php @@ -65,7 +65,7 @@ function gutenberg_apply_colors_support( $block_type, $block_attributes ) { if ( is_array( $color_support ) && - gutenberg_should_skip_block_supports_serialization( $block_type, 'color' ) + wp_should_skip_block_supports_serialization( $block_type, 'color' ) ) { return array(); } @@ -77,14 +77,14 @@ function gutenberg_apply_colors_support( $block_type, $block_attributes ) { // Text colors. // Check support for text colors. - if ( $has_text_colors_support && ! gutenberg_should_skip_block_supports_serialization( $block_type, 'color', 'text' ) ) { + if ( $has_text_colors_support && ! wp_should_skip_block_supports_serialization( $block_type, 'color', 'text' ) ) { $preset_text_color = array_key_exists( 'textColor', $block_attributes ) ? "var:preset|color|{$block_attributes['textColor']}" : null; $custom_text_color = _wp_array_get( $block_attributes, array( 'style', 'color', 'text' ), null ); $color_block_styles['text'] = $preset_text_color ? $preset_text_color : $custom_text_color; } // Background colors. - if ( $has_background_colors_support && ! gutenberg_should_skip_block_supports_serialization( $block_type, 'color', 'background' ) ) { + if ( $has_background_colors_support && ! wp_should_skip_block_supports_serialization( $block_type, 'color', 'background' ) ) { $preset_background_color = array_key_exists( 'backgroundColor', $block_attributes ) ? "var:preset|color|{$block_attributes['backgroundColor']}" : null; $custom_background_color = _wp_array_get( $block_attributes, array( 'style', 'color', 'background' ), null ); $color_block_styles['background'] = $preset_background_color ? $preset_background_color : $custom_background_color; @@ -92,7 +92,7 @@ function gutenberg_apply_colors_support( $block_type, $block_attributes ) { // Gradients. - if ( $has_gradients_support && ! gutenberg_should_skip_block_supports_serialization( $block_type, 'color', 'gradients' ) ) { + if ( $has_gradients_support && ! wp_should_skip_block_supports_serialization( $block_type, 'color', 'gradients' ) ) { $preset_gradient_color = array_key_exists( 'gradient', $block_attributes ) ? "var:preset|gradient|{$block_attributes['gradient']}" : null; $custom_gradient_color = _wp_array_get( $block_attributes, array( 'style', 'color', 'gradient' ), null ); $color_block_styles['gradient'] = $preset_gradient_color ? $preset_gradient_color : $custom_gradient_color; diff --git a/lib/block-supports/dimensions.php b/lib/block-supports/dimensions.php index 5776a2701d53b..d4d15cd609e63 100644 --- a/lib/block-supports/dimensions.php +++ b/lib/block-supports/dimensions.php @@ -44,7 +44,7 @@ function gutenberg_register_dimensions_support( $block_type ) { * @return array Block dimensions CSS classes and inline styles. */ function gutenberg_apply_dimensions_support( $block_type, $block_attributes ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable - if ( gutenberg_should_skip_block_supports_serialization( $block_type, 'dimensions' ) ) { + if ( wp_should_skip_block_supports_serialization( $block_type, 'dimensions' ) ) { return array(); } @@ -59,7 +59,7 @@ function gutenberg_apply_dimensions_support( $block_type, $block_attributes ) { return $attributes; } - $skip_min_height = gutenberg_should_skip_block_supports_serialization( $block_type, 'dimensions', 'minHeight' ); + $skip_min_height = wp_should_skip_block_supports_serialization( $block_type, 'dimensions', 'minHeight' ); $dimensions_block_styles = array(); $dimensions_block_styles['minHeight'] = $has_min_height_support && ! $skip_min_height ? _wp_array_get( $block_styles, array( 'dimensions', 'minHeight' ), null ) : null; $styles = gutenberg_style_engine_get_styles( array( 'dimensions' => $dimensions_block_styles ) ); diff --git a/lib/block-supports/elements.php b/lib/block-supports/elements.php index f55f087b0be82..5391478010964 100644 --- a/lib/block-supports/elements.php +++ b/lib/block-supports/elements.php @@ -28,7 +28,7 @@ function gutenberg_render_elements_support( $block_content, $block ) { } $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] ); - $skip_link_color_serialization = gutenberg_should_skip_block_supports_serialization( $block_type, 'color', 'link' ); + $skip_link_color_serialization = wp_should_skip_block_supports_serialization( $block_type, 'color', 'link' ); if ( $skip_link_color_serialization ) { return $block_content; @@ -78,7 +78,7 @@ function gutenberg_render_elements_support_styles( $pre_render, $block ) { /* * For now we only care about link color. */ - $skip_link_color_serialization = gutenberg_should_skip_block_supports_serialization( $block_type, 'color', 'link' ); + $skip_link_color_serialization = wp_should_skip_block_supports_serialization( $block_type, 'color', 'link' ); if ( $skip_link_color_serialization ) { return null; diff --git a/lib/block-supports/layout.php b/lib/block-supports/layout.php index 39869baa4e516..968ba799efcf3 100644 --- a/lib/block-supports/layout.php +++ b/lib/block-supports/layout.php @@ -458,7 +458,7 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) { * If a block's block.json skips serialization for spacing or spacing.blockGap, * don't apply the user-defined value to the styles. */ - $should_skip_gap_serialization = gutenberg_should_skip_block_supports_serialization( $block_type, 'spacing', 'blockGap' ); + $should_skip_gap_serialization = wp_should_skip_block_supports_serialization( $block_type, 'spacing', 'blockGap' ); $style = gutenberg_get_layout_style( ".$container_class.$container_class", diff --git a/lib/block-supports/shadow.php b/lib/block-supports/shadow.php new file mode 100644 index 0000000000000..4a28c98b79325 --- /dev/null +++ b/lib/block-supports/shadow.php @@ -0,0 +1,77 @@ +attributes ) { + $block_type->attributes = array(); + } + + if ( $has_shadow_support && ! array_key_exists( 'style', $block_type->attributes ) ) { + $block_type->attributes['style'] = array( + 'type' => 'object', + ); + } + + if ( $has_shadow_support && ! array_key_exists( 'shadow', $block_type->attributes ) ) { + $block_type->attributes['shadow'] = array( + 'type' => 'string', + ); + } +} + +/** + * Add CSS classes and inline styles for shadow features to the incoming attributes array. + * This will be applied to the block markup in + * the front-end. + * + * @param WP_Block_Type $block_type Block type. + * @param array $block_attributes Block attributes. + * + * @return array Shadow CSS classes and inline styles. + */ +function gutenberg_apply_shadow_support( $block_type, $block_attributes ) { + $has_shadow_support = block_has_support( $block_type, array( 'shadow' ), false ); + + if ( ! $has_shadow_support ) { + return array(); + } + + $shadow_block_styles = array(); + + $preset_shadow = array_key_exists( 'shadow', $block_attributes ) ? "var:preset|shadow|{$block_attributes['shadow']}" : null; + $custom_shadow = isset( $block_attributes['style']['shadow'] ) ? $block_attributes['style']['shadow'] : null; + $shadow_block_styles['shadow'] = $preset_shadow ? $preset_shadow : $custom_shadow; + + $attributes = array(); + $styles = gutenberg_style_engine_get_styles( $shadow_block_styles ); + + if ( ! empty( $styles['css'] ) ) { + $attributes['style'] = $styles['css']; + } + + return $attributes; +} + +// Register the block support. +WP_Block_Supports::get_instance()->register( + 'shadow', + array( + 'register_attribute' => 'gutenberg_register_shadow_support', + 'apply' => 'gutenberg_apply_shadow_support', + ) +); diff --git a/lib/block-supports/spacing.php b/lib/block-supports/spacing.php index 46ba2863a9682..e78fac6d62419 100644 --- a/lib/block-supports/spacing.php +++ b/lib/block-supports/spacing.php @@ -39,7 +39,7 @@ function gutenberg_register_spacing_support( $block_type ) { * @return array Block spacing CSS classes and inline styles. */ function gutenberg_apply_spacing_support( $block_type, $block_attributes ) { - if ( gutenberg_should_skip_block_supports_serialization( $block_type, 'spacing' ) ) { + if ( wp_should_skip_block_supports_serialization( $block_type, 'spacing' ) ) { return array(); } @@ -52,8 +52,8 @@ function gutenberg_apply_spacing_support( $block_type, $block_attributes ) { return $attributes; } - $skip_padding = gutenberg_should_skip_block_supports_serialization( $block_type, 'spacing', 'padding' ); - $skip_margin = gutenberg_should_skip_block_supports_serialization( $block_type, 'spacing', 'margin' ); + $skip_padding = wp_should_skip_block_supports_serialization( $block_type, 'spacing', 'padding' ); + $skip_margin = wp_should_skip_block_supports_serialization( $block_type, 'spacing', 'margin' ); $spacing_block_styles = array(); $spacing_block_styles['padding'] = $has_padding_support && ! $skip_padding ? _wp_array_get( $block_styles, array( 'spacing', 'padding' ), null ) : null; $spacing_block_styles['margin'] = $has_margin_support && ! $skip_margin ? _wp_array_get( $block_styles, array( 'spacing', 'margin' ), null ) : null; diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php index aa6c74a5d2e73..c2e033eb17677 100644 --- a/lib/block-supports/typography.php +++ b/lib/block-supports/typography.php @@ -81,7 +81,7 @@ function gutenberg_apply_typography_support( $block_type, $block_attributes ) { return array(); } - if ( gutenberg_should_skip_block_supports_serialization( $block_type, 'typography' ) ) { + if ( wp_should_skip_block_supports_serialization( $block_type, 'typography' ) ) { return array(); } @@ -95,14 +95,14 @@ function gutenberg_apply_typography_support( $block_type, $block_attributes ) { $has_text_transform_support = _wp_array_get( $typography_supports, array( '__experimentalTextTransform' ), false ); // Whether to skip individual block support features. - $should_skip_font_size = gutenberg_should_skip_block_supports_serialization( $block_type, 'typography', 'fontSize' ); - $should_skip_font_family = gutenberg_should_skip_block_supports_serialization( $block_type, 'typography', 'fontFamily' ); - $should_skip_font_style = gutenberg_should_skip_block_supports_serialization( $block_type, 'typography', 'fontStyle' ); - $should_skip_font_weight = gutenberg_should_skip_block_supports_serialization( $block_type, 'typography', 'fontWeight' ); - $should_skip_line_height = gutenberg_should_skip_block_supports_serialization( $block_type, 'typography', 'lineHeight' ); - $should_skip_text_decoration = gutenberg_should_skip_block_supports_serialization( $block_type, 'typography', 'textDecoration' ); - $should_skip_text_transform = gutenberg_should_skip_block_supports_serialization( $block_type, 'typography', 'textTransform' ); - $should_skip_letter_spacing = gutenberg_should_skip_block_supports_serialization( $block_type, 'typography', 'letterSpacing' ); + $should_skip_font_size = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'fontSize' ); + $should_skip_font_family = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'fontFamily' ); + $should_skip_font_style = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'fontStyle' ); + $should_skip_font_weight = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'fontWeight' ); + $should_skip_line_height = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'lineHeight' ); + $should_skip_text_decoration = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'textDecoration' ); + $should_skip_text_transform = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'textTransform' ); + $should_skip_letter_spacing = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'letterSpacing' ); $typography_block_styles = array(); if ( $has_font_size_support && ! $should_skip_font_size ) { diff --git a/lib/block-supports/utils.php b/lib/block-supports/utils.php deleted file mode 100644 index 89199ac644cb0..0000000000000 --- a/lib/block-supports/utils.php +++ /dev/null @@ -1,31 +0,0 @@ -supports, $path, false ); - - if ( is_array( $skip_serialization ) ) { - return in_array( $feature, $skip_serialization, true ); - } - - return $skip_serialization; -} diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php index 9acef6006d4e6..506ef0e3ceeff 100644 --- a/lib/class-wp-theme-json-gutenberg.php +++ b/lib/class-wp-theme-json-gutenberg.php @@ -118,8 +118,8 @@ class WP_Theme_JSON_Gutenberg { */ const PRESETS_METADATA = array( array( - 'path' => array( 'shadow', 'palette' ), - 'prevent_override' => array( 'shadow', 'defaultPalette' ), + 'path' => array( 'shadow', 'presets' ), + 'prevent_override' => array( 'shadow', 'defaultPresets' ), 'use_default_names' => false, 'value_key' => 'shadow', 'css_vars' => '--wp--preset--shadow--$slug', @@ -343,8 +343,8 @@ class WP_Theme_JSON_Gutenberg { 'width' => null, ), 'shadow' => array( - 'palette' => null, - 'defaultPalette' => null, + 'presets' => null, + 'defaultPresets' => null, ), 'color' => array( 'background' => null, @@ -2818,7 +2818,12 @@ public static function remove_insecure_properties( $theme_json ) { continue; } - $output = static::remove_insecure_styles( $input ); + // The global styles custom CSS is not sanitized, but can only be edited by users with 'edit_css' capability. + if ( isset( $input['css'] ) && current_user_can( 'edit_css' ) ) { + $output = $input; + } else { + $output = static::remove_insecure_styles( $input ); + } /* * Get a reference to element name from path. diff --git a/lib/class-wp-theme-json-resolver-gutenberg.php b/lib/class-wp-theme-json-resolver-gutenberg.php index 1d06b3219b4d3..f661632141c68 100644 --- a/lib/class-wp-theme-json-resolver-gutenberg.php +++ b/lib/class-wp-theme-json-resolver-gutenberg.php @@ -246,7 +246,7 @@ public static function get_theme_data( $deprecated = array(), $options = array() $theme_json_data = array(); } // BEGIN OF EXPERIMENTAL CODE. Not to backport to core. - $theme_json_data = gutenberg_add_registered_webfonts_to_theme_json( $theme_json_data ); + $theme_json_data = gutenberg_add_registered_fonts_to_theme_json( $theme_json_data ); // END OF EXPERIMENTAL CODE. /** @@ -267,7 +267,7 @@ public static function get_theme_data( $deprecated = array(), $options = array() $parent_theme_json_data = static::read_json_file( $parent_theme_json_file ); $parent_theme_json_data = static::translate( $parent_theme_json_data, $wp_theme->parent()->get( 'TextDomain' ) ); // BEGIN OF EXPERIMENTAL CODE. Not to backport to core. - $parent_theme_json_data = gutenberg_add_registered_webfonts_to_theme_json( $parent_theme_json_data ); + $parent_theme_json_data = gutenberg_add_registered_fonts_to_theme_json( $parent_theme_json_data ); // END OF EXPERIMENTAL CODE. $parent_theme = new WP_Theme_JSON_Gutenberg( $parent_theme_json_data ); @@ -753,30 +753,57 @@ public static function clean_cached_data() { } /** - * Returns the style variations defined by the theme. + * Returns an array of all nested json files within a given directory. * - * @since 6.0.0 + * @since 6.2.0 + * + * @param dir $dir The directory to recursively iterate and list files of. + * @return array The merged array. + */ + private static function recursively_iterate_json( $dir ) { + $nested_files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $dir ) ); + $nested_json_files = iterator_to_array( new RegexIterator( $nested_files, '/^.+\.json$/i', RecursiveRegexIterator::GET_MATCH ) ); + return $nested_json_files; + } + + /** + * Returns the style variations defined by the theme (parent and child). + * + * @since 6.2.0 Returns parent theme variations if theme is a child. * * @return array */ public static function get_style_variations() { - $variations = array(); - $base_directory = get_stylesheet_directory() . '/styles'; + $variation_files = array(); + $variations = array(); + $base_directory = get_stylesheet_directory() . '/styles'; + $template_directory = get_template_directory() . '/styles'; if ( is_dir( $base_directory ) ) { - $nested_files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $base_directory ) ); - $nested_html_files = iterator_to_array( new RegexIterator( $nested_files, '/^.+\.json$/i', RecursiveRegexIterator::GET_MATCH ) ); - ksort( $nested_html_files ); - foreach ( $nested_html_files as $path => $file ) { - $decoded_file = wp_json_file_decode( $path, array( 'associative' => true ) ); - if ( is_array( $decoded_file ) ) { - $translated = static::translate( $decoded_file, wp_get_theme()->get( 'TextDomain' ) ); - $variation = ( new WP_Theme_JSON_Gutenberg( $translated ) )->get_raw_data(); - if ( empty( $variation['title'] ) ) { - $variation['title'] = basename( $path, '.json' ); + $variation_files = static::recursively_iterate_json( $base_directory ); + } + if ( is_dir( $template_directory ) && $template_directory !== $base_directory ) { + $variation_files_parent = static::recursively_iterate_json( $template_directory ); + // If the child and parent variation file basename are the same, only include the child theme's. + foreach ( $variation_files_parent as $parent_path => $parent ) { + foreach ( $variation_files as $child_path => $child ) { + if ( basename( $parent_path ) === basename( $child_path ) ) { + unset( $variation_files_parent[ $parent_path ] ); } - $variations[] = $variation; } } + $variation_files = array_merge( $variation_files, $variation_files_parent ); + } + ksort( $variation_files ); + foreach ( $variation_files as $path => $file ) { + $decoded_file = wp_json_file_decode( $path, array( 'associative' => true ) ); + if ( is_array( $decoded_file ) ) { + $translated = static::translate( $decoded_file, wp_get_theme()->get( 'TextDomain' ) ); + $variation = ( new WP_Theme_JSON_Gutenberg( $translated ) )->get_raw_data(); + if ( empty( $variation['title'] ) ) { + $variation['title'] = basename( $path, '.json' ); + } + $variations[] = $variation; + } } return $variations; } diff --git a/lib/compat/wordpress-6.2/blocks.php b/lib/compat/wordpress-6.2/blocks.php index 250ed70ff9b98..c409e4212cf0d 100644 --- a/lib/compat/wordpress-6.2/blocks.php +++ b/lib/compat/wordpress-6.2/blocks.php @@ -20,6 +20,7 @@ function gutenberg_safe_style_attrs_6_2( $attrs ) { $attrs[] = 'bottom'; $attrs[] = 'left'; $attrs[] = 'z-index'; + $attrs[] = 'box-shadow'; return $attrs; } diff --git a/lib/compat/wordpress-6.2/class-gutenberg-rest-global-styles-controller-6-2.php b/lib/compat/wordpress-6.2/class-gutenberg-rest-global-styles-controller-6-2.php index a7b5df5ab357f..0e29d60992050 100644 --- a/lib/compat/wordpress-6.2/class-gutenberg-rest-global-styles-controller-6-2.php +++ b/lib/compat/wordpress-6.2/class-gutenberg-rest-global-styles-controller-6-2.php @@ -380,6 +380,29 @@ public function prepare_item_for_response( $post, $request ) { // phpcs:ignore V return $response; } + /** + * Get the link relations available for the post and current user. + * + * @since 5.9.0 + * @since 6.2.0 Added 'edit-css' action. + * + * @return array List of link relations. + */ + protected function get_available_actions() { + $rels = array(); + + $post_type = get_post_type_object( $this->post_type ); + if ( current_user_can( $post_type->cap->publish_posts ) ) { + $rels[] = 'https://api.w.org/action-publish'; + } + + if ( current_user_can( 'edit_css' ) ) { + $rels[] = 'https://api.w.org/action-edit-css'; + } + + return $rels; + } + /** * Updates a single global style config. * @@ -672,4 +695,28 @@ public function get_item_schema() { return $this->add_additional_fields_schema( $this->schema ); } + * Returns the given theme global styles variations. + * + * @since 6.0.0 + * @since 6.2.0 Returns parent theme variations, if they exist. + * + * @param WP_REST_Request $request The request instance. + * + * @return WP_REST_Response|WP_Error + */ + public function get_theme_items( $request ) { + if ( get_stylesheet() !== $request['stylesheet'] ) { + // This endpoint only supports the active or parent theme for now. + return new WP_Error( + sprintf( '%s', $request['template'] ), + __( 'Theme not found.', 'gutenberg' ), + array( 'status' => 404 ) + ); + } + + $variations = WP_Theme_JSON_Resolver_Gutenberg::get_style_variations(); + $response = rest_ensure_response( $variations ); + + return $response; + } } diff --git a/lib/compat/wordpress-6.2/script-loader.php b/lib/compat/wordpress-6.2/script-loader.php index e3e11d9cf1f56..6ad6b2b9ec78b 100644 --- a/lib/compat/wordpress-6.2/script-loader.php +++ b/lib/compat/wordpress-6.2/script-loader.php @@ -128,26 +128,26 @@ function gutenberg_resolve_assets_override() { $scripts = ob_get_clean(); /* - * Generate web font @font-face styles for the site editor iframe. + * Generate font @font-face styles for the site editor iframe. * Use the registered font families for printing. */ - if ( class_exists( 'WP_Web_Fonts' ) ) { - $wp_webfonts = wp_webfonts(); - $registered = $wp_webfonts->get_registered_font_families(); + if ( class_exists( 'WP_Fonts' ) ) { + $wp_fonts = wp_fonts(); + $registered = $wp_fonts->get_registered_font_families(); if ( ! empty( $registered ) ) { - $queue = $wp_webfonts->queue; - $done = $wp_webfonts->done; + $queue = $wp_fonts->queue; + $done = $wp_fonts->done; - $wp_webfonts->done = array(); - $wp_webfonts->queue = $registered; + $wp_fonts->done = array(); + $wp_fonts->queue = $registered; ob_start(); - $wp_webfonts->do_items(); + $wp_fonts->do_items(); $styles .= ob_get_clean(); // Reset the Web Fonts API. - $wp_webfonts->done = $done; - $wp_webfonts->queue = $queue; + $wp_fonts->done = $done; + $wp_fonts->queue = $queue; } } diff --git a/lib/experimental/editor-settings.php b/lib/experimental/editor-settings.php index d5e6393711118..b0c05544d6b19 100644 --- a/lib/experimental/editor-settings.php +++ b/lib/experimental/editor-settings.php @@ -86,9 +86,6 @@ function gutenberg_enable_experiments() { if ( $gutenberg_experiments && array_key_exists( 'gutenberg-off-canvas-navigation-editor', $gutenberg_experiments ) ) { wp_add_inline_script( 'wp-block-editor', 'window.__experimentalEnableOffCanvasNavigationEditor = true', 'before' ); } - if ( $gutenberg_experiments && array_key_exists( 'gutenberg-global-styles-custom-css', $gutenberg_experiments ) ) { - wp_add_inline_script( 'wp-block-editor', 'window.__experimentalEnableGlobalStylesCustomCSS = true', 'before' ); - } } add_action( 'admin_init', 'gutenberg_enable_experiments' ); diff --git a/lib/experimental/fonts-api/class-wp-fonts-provider-local.php b/lib/experimental/fonts-api/class-wp-fonts-provider-local.php new file mode 100644 index 0000000000000..cea74c16a95f4 --- /dev/null +++ b/lib/experimental/fonts-api/class-wp-fonts-provider-local.php @@ -0,0 +1,242 @@ +style_tag_atts = array( 'type' => 'text/css' ); + } + } + + /** + * Gets the `@font-face` CSS styles for locally-hosted font files. + * + * This method does the following processing tasks: + * 1. Orchestrates an optimized `src` (with format) for browser support. + * 2. Generates the `@font-face` for all its fonts. + * + * @since X.X.X + * + * @return string The `@font-face` CSS. + */ + public function get_css() { + $css = ''; + + foreach ( $this->fonts as $font ) { + // Order the font's `src` items to optimize for browser support. + $font = $this->order_src( $font ); + + // Build the @font-face CSS for this font. + $css .= '@font-face{' . $this->build_font_face_css( $font ) . '}'; + } + + return $css; + } + + /** + * Order `src` items to optimize for browser support. + * + * @since X.X.X + * + * @param array $font Font to process. + * @return array + */ + private function order_src( array $font ) { + if ( ! is_array( $font['src'] ) ) { + $font['src'] = (array) $font['src']; + } + + $src = array(); + $src_ordered = array(); + + foreach ( $font['src'] as $url ) { + // Add data URIs first. + if ( str_starts_with( trim( $url ), 'data:' ) ) { + $src_ordered[] = array( + 'url' => $url, + 'format' => 'data', + ); + continue; + } + $format = pathinfo( $url, PATHINFO_EXTENSION ); + $src[ $format ] = $url; + } + + // Add woff2. + if ( ! empty( $src['woff2'] ) ) { + $src_ordered[] = array( + 'url' => $src['woff2'], + 'format' => 'woff2', + ); + } + + // Add woff. + if ( ! empty( $src['woff'] ) ) { + $src_ordered[] = array( + 'url' => $src['woff'], + 'format' => 'woff', + ); + } + + // Add ttf. + if ( ! empty( $src['ttf'] ) ) { + $src_ordered[] = array( + 'url' => $src['ttf'], + 'format' => 'truetype', + ); + } + + // Add eot. + if ( ! empty( $src['eot'] ) ) { + $src_ordered[] = array( + 'url' => $src['eot'], + 'format' => 'embedded-opentype', + ); + } + + // Add otf. + if ( ! empty( $src['otf'] ) ) { + $src_ordered[] = array( + 'url' => $src['otf'], + 'format' => 'opentype', + ); + } + $font['src'] = $src_ordered; + + return $font; + } + + /** + * Builds the font-family's CSS. + * + * @since X.X.X + * + * @param array $font Font to process. + * @return string This font-family's CSS. + */ + private function build_font_face_css( array $font ) { + $css = ''; + + // Wrap font-family in quotes if it contains spaces + // and is not already wrapped in quotes. + if ( + str_contains( $font['font-family'], ' ' ) && + ! str_contains( $font['font-family'], '"' ) && + ! str_contains( $font['font-family'], "'" ) + ) { + $font['font-family'] = '"' . $font['font-family'] . '"'; + } + + foreach ( $font as $key => $value ) { + + // Skip "provider", since it's for internal API use, + // and not a valid CSS property. + if ( 'provider' === $key ) { + continue; + } + + // Compile the "src" parameter. + if ( 'src' === $key ) { + $value = $this->compile_src( $font['font-family'], $value ); + } + + // If font-variation-settings is an array, convert it to a string. + if ( 'font-variation-settings' === $key && is_array( $value ) ) { + $value = $this->compile_variations( $value ); + } + + if ( ! empty( $value ) ) { + $css .= "$key:$value;"; + } + } + + return $css; + } + + /** + * Compiles the `src` into valid CSS. + * + * @since X.X.X + * + * @param string $font_family Font family. + * @param array $value Value to process. + * @return string The CSS. + */ + private function compile_src( $font_family, array $value ) { + $src = ''; + + foreach ( $value as $item ) { + + if ( str_starts_with( $item['url'], get_site_url() ) ) { + $item['url'] = wp_make_link_relative( $item['url'] ); + } + + $src .= ( 'data' === $item['format'] ) + ? ", url({$item['url']})" + : ", url('{$item['url']}') format('{$item['format']}')"; + } + + $src = ltrim( $src, ', ' ); + return $src; + } + + /** + * Compiles the font variation settings. + * + * @since X.X.X + * + * @param array $font_variation_settings Array of font variation settings. + * @return string The CSS. + */ + private function compile_variations( array $font_variation_settings ) { + $variations = ''; + + foreach ( $font_variation_settings as $key => $value ) { + $variations .= "$key $value"; + } + + return $variations; + } +} diff --git a/lib/experimental/class-wp-webfonts-provider.php b/lib/experimental/fonts-api/class-wp-fonts-provider.php similarity index 63% rename from lib/experimental/class-wp-webfonts-provider.php rename to lib/experimental/fonts-api/class-wp-fonts-provider.php index 8fcbd76a76d3c..b59c59d6b8938 100644 --- a/lib/experimental/class-wp-webfonts-provider.php +++ b/lib/experimental/fonts-api/class-wp-fonts-provider.php @@ -1,22 +1,22 @@ webfonts = $webfonts; + public function set_fonts( array $fonts ) { + $this->fonts = $fonts; } /** @@ -90,10 +87,10 @@ public function print_styles() { } /** - * Gets the `@font-face` CSS for the provider's webfonts. + * Gets the `@font-face` CSS for the provider's fonts. * * This method is where the provider does it processing to build the - * needed `@font-face` CSS for all of its webfonts. Specifics of how + * needed `@font-face` CSS for all of its fonts. Specifics of how * this processing is done is contained in each provider. * * @since X.X.X @@ -112,7 +109,7 @@ abstract public function get_css(); protected function get_style_element() { $attributes = $this->generate_style_element_attributes(); - return "\n"; + return "\n"; } /** diff --git a/lib/experimental/class-wp-webfonts-utils.php b/lib/experimental/fonts-api/class-wp-fonts-utils.php similarity index 94% rename from lib/experimental/class-wp-webfonts-utils.php rename to lib/experimental/fonts-api/class-wp-fonts-utils.php index 3c086a974ab9d..8204dc965fc8b 100644 --- a/lib/experimental/class-wp-webfonts-utils.php +++ b/lib/experimental/fonts-api/class-wp-fonts-utils.php @@ -1,22 +1,22 @@ 'local', + 'font-family' => '', + 'font-style' => 'normal', + 'font-weight' => '400', + 'font-display' => 'fallback', + ); + + /** + * Constructor. + * + * @since X.X.X + */ + public function __construct() { + /** + * Filters the font variation's property defaults. + * + * @since X.X.X + * + * @param array $defaults { + * An array of required font properties and defaults. + * + * @type string $provider The provider ID. Default 'local'. + * @type string $font-family The font-family property. Default empty string. + * @type string $font-style The font-style property. Default 'normal'. + * @type string $font-weight The font-weight property. Default '400'. + * @type string $font-display The font-display property. Default 'fallback'. + * } + */ + $this->variation_property_defaults = apply_filters( 'wp_font_variation_defaults', $this->variation_property_defaults ); + + /** + * Fires when the WP_Fonts instance is initialized. + * + * @since X.X.X + * + * @param WP_Fonts $wp_fonts WP_Fonts instance (passed by reference). + */ + do_action_ref_array( 'wp_default_fonts', array( &$this ) ); + } + + /** + * Get the list of registered providers. + * + * @since X.X.X + * + * @return array $providers { + * An associative array of registered providers, keyed by their unique ID. + * + * @type string $provider_id => array { + * An associate array of provider's class name and fonts. + * + * @type string $class Fully qualified name of the provider's class. + * @type string[] $fonts An array of enqueued font handles for this provider. + * } + * } + */ + public function get_providers() { + return $this->providers; + } + + /** + * Register a provider. + * + * @since X.X.X + * + * @param string $provider_id The provider's unique ID. + * @param string $class The provider class name. + * @return bool True if successfully registered, else false. + */ + public function register_provider( $provider_id, $class ) { + if ( empty( $provider_id ) || empty( $class ) || ! class_exists( $class ) ) { + return false; + } + + $this->providers[ $provider_id ] = array( + 'class' => $class, + 'fonts' => array(), + ); + return true; + } + + /** + * Get the list of all registered font family handles. + * + * @since X.X.X + * + * @return string[] + */ + public function get_registered_font_families() { + $font_families = array(); + foreach ( $this->registered as $handle => $obj ) { + if ( $obj->extra['is_font_family'] ) { + $font_families[] = $handle; + } + } + return $font_families; + } + + /** + * Get the list of all registered font families and their variations. + * + * @since X.X.X + * + * @return string[] + */ + public function get_registered() { + return array_keys( $this->registered ); + } + + /** + * Get the list of enqueued font families and their variations. + * + * @since X.X.X + * + * @return array[] + */ + public function get_enqueued() { + return $this->queue; + } + + /** + * Registers a font family. + * + * @since X.X.X + * + * @param string $font_family Font family name to register. + * @return string|null Font family handle when registration successes. Null on failure. + */ + public function add_font_family( $font_family ) { + $font_family_handle = WP_Fonts_Utils::convert_font_family_into_handle( $font_family ); + if ( ! $font_family_handle ) { + return null; + } + + if ( isset( $this->registered[ $font_family_handle ] ) ) { + return $font_family_handle; + } + + $registered = $this->add( $font_family_handle, false ); + if ( ! $registered ) { + return null; + } + + $this->add_data( $font_family_handle, 'font-properties', array( 'font-family' => $font_family ) ); + $this->add_data( $font_family_handle, 'is_font_family', true ); + + return $font_family_handle; + } + + /** + * Removes a font family and all registered variations. + * + * @since X.X.X + * + * @param string $font_family_handle The font family to remove. + */ + public function remove_font_family( $font_family_handle ) { + if ( ! isset( $this->registered[ $font_family_handle ] ) ) { + return; + } + + $variations = $this->registered[ $font_family_handle ]->deps; + + foreach ( $variations as $variation ) { + $this->remove( $variation ); + } + + $this->remove( $font_family_handle ); + } + + /** + * Add a variation to an existing family or register family if none exists. + * + * @since X.X.X + * + * @param string $font_family_handle The font family's handle for this variation. + * @param array $variation An array of variation properties to add. + * @param string $variation_handle Optional. The variation's handle. When none is provided, the + * handle will be dynamically generated. + * Default empty string. + * @return string|null Variation handle on success. Else null. + */ + public function add_variation( $font_family_handle, array $variation, $variation_handle = '' ) { + if ( ! WP_Fonts_Utils::is_defined( $font_family_handle ) ) { + trigger_error( 'Font family handle must be a non-empty string.' ); + return null; + } + + // When there is a variation handle, check it. + if ( '' !== $variation_handle && ! WP_Fonts_Utils::is_defined( $variation_handle ) ) { + trigger_error( 'Variant handle must be a non-empty string.' ); + return null; + } + + // Register the font family when it does not yet exist. + if ( ! isset( $this->registered[ $font_family_handle ] ) ) { + if ( ! $this->add_font_family( $font_family_handle ) ) { + return null; + } + } + + $variation = $this->validate_variation( $variation ); + + // Variation validation failed. + if ( ! $variation ) { + return null; + } + + // When there's no variation handle, attempt to create one. + if ( '' === $variation_handle ) { + $variation_handle = WP_Fonts_Utils::convert_variation_into_handle( $font_family_handle, $variation ); + if ( is_null( $variation_handle ) ) { + return null; + } + } + + // Bail out if the variant is already registered. + if ( $this->is_variation_registered( $font_family_handle, $variation_handle ) ) { + return $variation_handle; + } + + $variation_src = array_key_exists( 'src', $variation ) ? $variation['src'] : false; + $result = $this->add( $variation_handle, $variation_src ); + + // Bail out if the registration failed. + if ( ! $result ) { + return null; + } + + $this->add_data( $variation_handle, 'font-properties', $variation ); + $this->add_data( $variation_handle, 'is_font_family', false ); + + // Add the font variation as a dependency to the registered font family. + $this->add_dependency( $font_family_handle, $variation_handle ); + + $this->providers[ $variation['provider'] ]['fonts'][] = $variation_handle; + + return $variation_handle; + } + + /** + * Removes a variation. + * + * @since X.X.X + * + * @param string $font_family_handle The font family for this variation. + * @param string $variation_handle The variation's handle to remove. + */ + public function remove_variation( $font_family_handle, $variation_handle ) { + if ( isset( $this->registered[ $variation_handle ] ) ) { + $this->remove( $variation_handle ); + } + + if ( ! $this->is_variation_registered( $font_family_handle, $variation_handle ) ) { + return; + } + + // Remove the variation as a dependency from its font family. + $this->registered[ $font_family_handle ]->deps = array_values( + array_diff( + $this->registered[ $font_family_handle ]->deps, + array( $variation_handle ) + ) + ); + } + + /** + * Checks if the variation is registered. + * + * @since X.X.X + * + * @param string $font_family_handle The font family's handle for this variation. + * @param string $variation_handle Variation's handle. + * @return bool True when registered to the given font family. Else false. + */ + private function is_variation_registered( $font_family_handle, $variation_handle ) { + if ( ! isset( $this->registered[ $font_family_handle ] ) ) { + return false; + } + + return in_array( $variation_handle, $this->registered[ $font_family_handle ]->deps, true ); + } + + /** + * Adds a variation as a dependency to the given font family. + * + * @since X.X.X + * + * @param string $font_family_handle The font family's handle for this variation. + * @param string $variation_handle The variation's handle. + */ + private function add_dependency( $font_family_handle, $variation_handle ) { + $this->registered[ $font_family_handle ]->deps[] = $variation_handle; + } + + /** + * Validates and sanitizes a variation. + * + * @since X.X.X + * + * @param array $variation Variation properties to add. + * @return false|array Validated variation on success. Else, false. + */ + private function validate_variation( $variation ) { + $variation = wp_parse_args( $variation, $this->variation_property_defaults ); + + // Check the font-family. + if ( empty( $variation['font-family'] ) || ! is_string( $variation['font-family'] ) ) { + trigger_error( 'Webfont font-family must be a non-empty string.' ); + return false; + } + + // Local fonts need a "src". + if ( 'local' === $variation['provider'] ) { + // Make sure that local fonts have 'src' defined. + if ( empty( $variation['src'] ) || ( ! is_string( $variation['src'] ) && ! is_array( $variation['src'] ) ) ) { + trigger_error( 'Webfont src must be a non-empty string or an array of strings.' ); + return false; + } + } elseif ( ! isset( $this->providers[ $variation['provider'] ] ) ) { + trigger_error( sprintf( 'The provider "%s" is not registered', $variation['provider'] ) ); + return false; + } elseif ( ! class_exists( $this->providers[ $variation['provider'] ]['class'] ) ) { + trigger_error( sprintf( 'The provider class "%s" does not exist', $variation['provider'] ) ); + return false; + } + + // Validate the 'src' property. + if ( ! empty( $variation['src'] ) ) { + foreach ( (array) $variation['src'] as $src ) { + if ( empty( $src ) || ! is_string( $src ) ) { + trigger_error( 'Each font src must be a non-empty string.' ); + return false; + } + } + } + + // Check the font-weight. + if ( ! is_string( $variation['font-weight'] ) && ! is_int( $variation['font-weight'] ) ) { + trigger_error( 'Webfont font-weight must be a properly formatted string or integer.' ); + return false; + } + + // Check the font-display. + if ( ! in_array( $variation['font-display'], array( 'auto', 'block', 'fallback', 'swap', 'optional' ), true ) ) { + $variation['font-display'] = 'fallback'; + } + + $valid_props = array( + 'ascent-override', + 'descent-override', + 'font-display', + 'font-family', + 'font-stretch', + 'font-style', + 'font-weight', + 'font-variant', + 'font-feature-settings', + 'font-variation-settings', + 'line-gap-override', + 'size-adjust', + 'src', + 'unicode-range', + + // Exceptions. + 'provider', + ); + + foreach ( $variation as $prop => $value ) { + if ( ! in_array( $prop, $valid_props, true ) ) { + unset( $variation[ $prop ] ); + } + } + + return $variation; + } + + /** + * Processes the items and dependencies. + * + * Processes the items passed to it or the queue, and their dependencies. + * + * @since X.X.X + * + * @param string|string[]|bool $handles Optional. Items to be processed: queue (false), + * single item (string), or multiple items (array of strings). + * Default false. + * @param int|false $group Optional. Group level: level (int), no group (false). + * + * @return array|string[] Array of font handles that have been processed. + * An empty array if none were processed. + */ + public function do_items( $handles = false, $group = false ) { + $handles = $this->prepare_handles_for_printing( $handles ); + + if ( empty( $handles ) ) { + return $this->done; + } + + $this->all_deps( $handles ); + if ( empty( $this->to_do ) ) { + return $this->done; + } + + $this->to_do_keyed_handles = array_flip( $this->to_do ); + + foreach ( $this->get_providers() as $provider_id => $provider ) { + // Alert and skip if the provider class does not exist. + if ( ! class_exists( $provider['class'] ) ) { + /* translators: %s is the provider name. */ + trigger_error( + sprintf( + 'Class "%s" not found for "%s" font provider', + $provider['class'], + $provider_id + ) + ); + continue; + } + + $this->do_item( $provider_id, $group ); + } + + $this->process_font_families_after_printing( $handles ); + + return $this->done; + } + + /** + * Prepares the given handles for printing. + * + * @since X.X.X + * + * @param string|string[]|bool $handles Optional. Handles to prepare. + * Default false. + * @return array Array of handles. + */ + private function prepare_handles_for_printing( $handles = false ) { + if ( false !== $handles ) { + $handles = $this->validate_handles( $handles ); + // Bail out when invalid. + if ( empty( $handles ) ) { + return array(); + } + } + + // Use the enqueued queue. + if ( empty( $handles ) ) { + if ( empty( $this->queue ) ) { + return array(); + } + $handles = $this->queue; + } + + return $handles; + } + + /** + * Validates handle(s) to ensure each is a non-empty string. + * + * @since X.X.X + * + * @param string|string[] $handles Handles to prepare. + * @return string[]|null Array of handles on success. Else null. + */ + private function validate_handles( $handles ) { + // Validate each element is a non-empty string handle. + $handles = array_filter( (array) $handles, array( WP_Fonts_Utils::class, 'is_defined' ) ); + + if ( empty( $handles ) ) { + trigger_error( 'Handles must be a non-empty string or array of non-empty strings' ); + return null; + } + + return $handles; + } + + /** + * Invokes each provider to process and print its styles. + * + * @since X.X.X + * + * @see WP_Dependencies::do_item() + * + * @param string $provider_id The provider to process. + * @param int|false $group Not used. + * @return bool + */ + public function do_item( $provider_id, $group = false ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable + // Bail out if the provider is not registered. + if ( ! isset( $this->providers[ $provider_id ] ) ) { + return false; + } + + $font_handles = $this->get_enqueued_fonts_for_provider( $provider_id ); + if ( empty( $font_handles ) ) { + return false; + } + + $properties_by_font = $this->get_font_properties_for_provider( $font_handles ); + if ( empty( $properties_by_font ) ) { + return false; + } + + // Invoke provider to print its styles. + $provider = $this->get_provider_instance( $provider_id ); + $provider->set_fonts( $properties_by_font ); + $provider->print_styles(); + + // Clean up. + $this->update_queues_for_printed_fonts( $font_handles ); + + return true; + } + + /** + * Retrieves a list of enqueued font variations for a provider. + * + * @since X.X.X + * + * @param string $provider_id The provider to process. + * @return array[] Webfonts organized by providers. + */ + private function get_enqueued_fonts_for_provider( $provider_id ) { + $providers = $this->get_providers(); + + if ( empty( $providers[ $provider_id ] ) ) { + return array(); + } + + return array_intersect( + $providers[ $provider_id ]['fonts'], + $this->to_do + ); + } + + /** + * Gets a list of font properties for each of the given font handles. + * + * @since X.X.X + * + * @param array $font_handles Font handles to get properties. + * @return array A list of fonts with each font's properties. + */ + private function get_font_properties_for_provider( array $font_handles ) { + $font_properties = array(); + + foreach ( $font_handles as $font_handle ) { + $properties = $this->get_data( $font_handle, 'font-properties' ); + if ( ! $properties ) { + continue; + } + $font_properties[ $font_handle ] = $properties; + } + + return $font_properties; + } + + /** + * Gets the instance of the provider from the WP_Webfonts::$provider_instance store. + * + * @since X.X.X + * + * @param string $provider_id The provider to get. + * @return object Instance of the provider. + */ + private function get_provider_instance( $provider_id ) { + if ( ! isset( $this->provider_instances[ $provider_id ] ) ) { + $this->provider_instances[ $provider_id ] = new $this->providers[ $provider_id ]['class'](); + } + return $this->provider_instances[ $provider_id ]; + } + + /** + * Update queues for the given printed fonts. + * + * @since X.X.X + * + * @param array $font_handles Font handles to get properties. + */ + private function update_queues_for_printed_fonts( array $font_handles ) { + foreach ( $font_handles as $font_handle ) { + $this->set_as_done( $font_handle ); + $this->remove_from_to_do_queues( $font_handle ); + } + } + + /** + * Processes the font families after printing the variations. + * + * For each queued font family: + * + * a. if any of their variations were printed, the font family is added to the `done` list. + * b. removes each from the to_do queues. + * + * @since X.X.X + * + * @param array $handles Handles to process. + */ + private function process_font_families_after_printing( array $handles ) { + foreach ( $handles as $handle ) { + if ( + ! $this->get_data( $handle, 'is_font_family' ) || + ! isset( $this->to_do_keyed_handles[ $handle ] ) + ) { + continue; + } + $font_family = $this->registered[ $handle ]; + + // Add the font family to `done` list if any of its variations were printed. + if ( ! empty( $font_family->deps ) ) { + $processed = array_intersect( $font_family->deps, $this->done ); + if ( ! empty( $processed ) ) { + $this->set_as_done( $handle ); + } + } + + $this->remove_from_to_do_queues( $handle ); + } + } + + /** + * Removes the handle from the `to_do` and `to_do_keyed_handles` lists. + * + * @since X.X.X + * + * @param string $handle Handle to remove. + */ + private function remove_from_to_do_queues( $handle ) { + unset( + $this->to_do[ $this->to_do_keyed_handles[ $handle ] ], + $this->to_do_keyed_handles[ $handle ] + ); + } + + /** + * Sets the given handle to done by adding it to the `done` list. + * + * @since X.X.X + * + * @param string $handle Handle to set as done. + */ + private function set_as_done( $handle ) { + if ( ! is_array( $this->done ) ) { + $this->done = array(); + } + $this->done[] = $handle; + } + + /** + * Converts the font family and its variations into theme.json structural format. + * + * @since X.X.X + * + * @param string $font_family_handle Font family to convert. + * @return array Webfonts in theme.json structural format. + */ + public function to_theme_json( $font_family_handle ) { + if ( ! isset( $this->registered[ $font_family_handle ] ) ) { + return array(); + } + + $font_family_name = $this->registered[ $font_family_handle ]->extra['font-properties']['font-family']; + $theme_json_format = array( + 'fontFamily' => str_contains( $font_family_name, ' ' ) ? "'{$font_family_name}'" : $font_family_name, + 'name' => $font_family_name, + 'slug' => $font_family_handle, + 'fontFace' => array(), + ); + + foreach ( $this->registered[ $font_family_handle ]->deps as $variation_handle ) { + if ( ! isset( $this->registered[ $variation_handle ] ) ) { + continue; + } + + $variation_obj = $this->registered[ $variation_handle ]; + $variation_properties = array( 'origin' => 'gutenberg_wp_fonts_api' ); + foreach ( $variation_obj->extra['font-properties'] as $property_name => $property_value ) { + $property_in_camelcase = lcfirst( str_replace( '-', '', ucwords( $property_name, '-' ) ) ); + $variation_properties[ $property_in_camelcase ] = $property_value; + } + $theme_json_format['fontFace'][ $variation_obj->handle ] = $variation_properties; + } + + return $theme_json_format; + } +} diff --git a/lib/experimental/class-wp-web-fonts.php b/lib/experimental/fonts-api/deprecations/class-wp-web-fonts.php similarity index 93% rename from lib/experimental/class-wp-web-fonts.php rename to lib/experimental/fonts-api/deprecations/class-wp-web-fonts.php index 15df7ecf47e5c..bdf06bb317e3a 100644 --- a/lib/experimental/class-wp-web-fonts.php +++ b/lib/experimental/fonts-api/deprecations/class-wp-web-fonts.php @@ -3,7 +3,7 @@ * Web Fonts API class. * * @package WordPress - * @subpackage WebFonts + * @subpackage Fonts API * @since X.X.X */ @@ -14,60 +14,19 @@ /** * Class WP_Web_Fonts * - * @since X.X.X + * @since GB 14.9.1 + * @deprecated GB 15.1 Use WP_Fonts instead. */ class WP_Web_Fonts extends WP_Webfonts { - /** - * An array of registered providers. - * - * @since X.X.X - * - * @var array - */ - private $providers = array(); - - /** - * The flipped $to_do array of web font handles. - * - * Used for a faster lookup of the web font handles. - * - * @since X.X.X - * - * @var string[] - */ - private $to_do_keyed_handles; - - /** - * Provider instance store, keyed by provider ID. - * - * @since X.X.X - * - * @var array - */ - private $provider_instances = array(); - - /** - * Variation property defaults. - * - * @since X.X.X - * - * @var array - */ - private $variation_property_defaults = array( - 'provider' => 'local', - 'font-family' => '', - 'font-style' => 'normal', - 'font-weight' => '400', - 'font-display' => 'fallback', - ); - /** * Constructor. * * @since X.X.X */ public function __construct() { + _deprecated_function( __METHOD__, 'GB 15.1', 'WP_Fonts' ); + /** * Filters the web font variation's property defaults. * @@ -184,7 +143,7 @@ public function get_enqueued() { * @return string|null Font family handle when registration successes. Null on failure. */ public function add_font_family( $font_family ) { - $font_family_handle = WP_Webfonts_Utils::convert_font_family_into_handle( $font_family ); + $font_family_handle = WP_Fonts_Utils::convert_font_family_into_handle( $font_family ); if ( ! $font_family_handle ) { return null; } @@ -238,13 +197,13 @@ public function remove_font_family( $font_family_handle ) { * @return string|null Variation handle on success. Else null. */ public function add_variation( $font_family_handle, array $variation, $variation_handle = '' ) { - if ( ! WP_Webfonts_Utils::is_defined( $font_family_handle ) ) { + if ( ! WP_Fonts_Utils::is_defined( $font_family_handle ) ) { trigger_error( 'Font family handle must be a non-empty string.' ); return null; } // When there is a variation handle, check it. - if ( '' !== $variation_handle && ! WP_Webfonts_Utils::is_defined( $variation_handle ) ) { + if ( '' !== $variation_handle && ! WP_Fonts_Utils::is_defined( $variation_handle ) ) { trigger_error( 'Variant handle must be a non-empty string.' ); return null; } @@ -265,7 +224,7 @@ public function add_variation( $font_family_handle, array $variation, $variation // When there's no variation handle, attempt to create one. if ( '' === $variation_handle ) { - $variation_handle = WP_Webfonts_Utils::convert_variation_into_handle( $font_family_handle, $variation ); + $variation_handle = WP_Fonts_Utils::convert_variation_into_handle( $font_family_handle, $variation ); if ( is_null( $variation_handle ) ) { return null; } @@ -522,7 +481,7 @@ private function prepare_handles_for_printing( $handles = false ) { */ private function validate_handles( $handles ) { // Validate each element is a non-empty string handle. - $handles = array_filter( (array) $handles, array( WP_Webfonts_Utils::class, 'is_defined' ) ); + $handles = array_filter( (array) $handles, array( WP_Fonts_Utils::class, 'is_defined' ) ); if ( empty( $handles ) ) { trigger_error( 'Handles must be a non-empty string or array of non-empty strings' ); @@ -561,7 +520,7 @@ public function do_item( $provider_id, $group = false ) { // phpcs:ignore Variab // Invoke provider to print its styles. $provider = $this->get_provider_instance( $provider_id ); - $provider->set_webfonts( $properties_by_font ); + $provider->set_fonts( $properties_by_font ); $provider->print_styles(); // Clean up. diff --git a/lib/experimental/class-wp-webfonts-provider-local.php b/lib/experimental/fonts-api/deprecations/class-wp-webfonts-provider-local.php similarity index 90% rename from lib/experimental/class-wp-webfonts-provider-local.php rename to lib/experimental/fonts-api/deprecations/class-wp-webfonts-provider-local.php index 3950ebcd624c3..b6fd5d78a1435 100644 --- a/lib/experimental/class-wp-webfonts-provider-local.php +++ b/lib/experimental/fonts-api/deprecations/class-wp-webfonts-provider-local.php @@ -1,10 +1,17 @@ webfonts = $this->fonts; + } + + /** + * This method is here to wire WP_Fonts_Provider::do_item() to this + * deprecated class to ensure the fonts get set. + * + * @param array[] $fonts Fonts to be processed. + */ + public function set_fonts( array $fonts ) { + parent::set_fonts( $fonts ); + $this->webfonts = $this->fonts; + } +} diff --git a/lib/experimental/fonts-api/deprecations/class-wp-webfonts-utils.php b/lib/experimental/fonts-api/deprecations/class-wp-webfonts-utils.php new file mode 100644 index 0000000000000..d0242acf9a2b6 --- /dev/null +++ b/lib/experimental/fonts-api/deprecations/class-wp-webfonts-utils.php @@ -0,0 +1,85 @@ +get_registered(). + * @deprecated 14.9.1 Use wp_fonts()->get_registered(). * * @return array[] */ public function get_registered_webfonts() { - _deprecated_function( __METHOD__, 'X.X.X', 'wp_webfonts()->get_registered()' ); + _deprecated_function( __METHOD__, '14.9.1', 'wp_fonts()->get_registered()' ); return $this->_get_registered_webfonts(); } @@ -72,12 +72,12 @@ public function get_registered_webfonts() { * Gets the list of enqueued fonts. * * @since 6.0.0 - * @deprecated X.X.X Use wp_webfonts()->get_enqueued(). + * @deprecated GB 14.9.1 Use wp_fonts()->get_enqueued(). * * @return array[] */ public function get_enqueued_webfonts() { - _deprecated_function( __METHOD__, 'X.X.X', 'wp_webfonts()->get_enqueued()' ); + _deprecated_function( __METHOD__, 'GB 14.9.1', 'wp_fonts()->get_enqueued()' ); return $this->queue; } @@ -86,12 +86,12 @@ public function get_enqueued_webfonts() { * Gets the list of all fonts. * * @since 6.0.0 - * @deprecated X.X.X Use wp_webfonts()->get_registered(). + * @deprecated GB 14.9.1 Use wp_fonts()->get_registered(). * * @return array[] */ public function get_all_webfonts() { - _deprecated_function( __METHOD__, 'X.X.X', 'wp_webfonts()->get_registered()' ); + _deprecated_function( __METHOD__, 'GB 14.9.1', 'wp_fonts()->get_registered()' ); return $this->_get_registered_webfonts(); } @@ -100,7 +100,7 @@ public function get_all_webfonts() { * Registers a webfont. * * @since 6.0.0 - * @deprecated X.X.X Use wp_register_webfonts(). + * @deprecated GB 14.9.1 Use wp_register_fonts(). * * @param array $webfont Web font to register. * @param string $font_family_handle Optional. Font family handle for the given variation. @@ -111,14 +111,14 @@ public function get_all_webfonts() { */ public function register_webfont( array $webfont, $font_family_handle = '', $variation_handle = '', $silence_deprecation = false ) { if ( ! $silence_deprecation ) { - _deprecated_function( __METHOD__, 'X.X.X', 'wp_register_webfonts()' ); + _deprecated_function( __METHOD__, 'GB 14.9.1', 'wp_register_fonts()' ); } // When font family's handle is not passed, attempt to get it from the variation. - if ( ! WP_Webfonts_Utils::is_defined( $font_family_handle ) ) { - $font_family = WP_Webfonts_Utils::get_font_family_from_variation( $webfont ); + if ( ! WP_Fonts_Utils::is_defined( $font_family_handle ) ) { + $font_family = WP_Fonts_Utils::get_font_family_from_variation( $webfont ); if ( $font_family ) { - $font_family_handle = WP_Webfonts_Utils::convert_font_family_into_handle( $font_family ); + $font_family_handle = WP_Fonts_Utils::convert_font_family_into_handle( $font_family ); } } @@ -135,15 +135,15 @@ public function register_webfont( array $webfont, $font_family_handle = '', $var * Enqueue a font-family that has been already registered. * * @since 6.0.0 - * @deprecated X.X.X Use wp_enqueue_webfonts(). + * @deprecated GB 14.9.1 Use wp_enqueue_fonts(). * * @param string $font_family_name The font family name to be enqueued. * @return bool True if successfully enqueued, else false. */ public function enqueue_webfont( $font_family_name ) { - _deprecated_function( __METHOD__, 'X.X.X', 'wp_enqueue_webfonts()' ); + _deprecated_function( __METHOD__, 'GB 14.9.1', 'wp_enqueue_fonts()' ); - wp_enqueue_webfonts( array( $font_family_name ) ); + wp_enqueue_fonts( array( $font_family_name ) ); return true; } @@ -155,13 +155,13 @@ public function enqueue_webfont( $font_family_name ) { * @return array */ public function migrate_deprecated_structure( array $webfonts ) { - $message = 'A deprecated web fonts array structure passed to wp_register_webfonts(). ' . + $message = 'A deprecated fonts array structure passed to wp_register_fonts(). ' . 'Variations must be grouped and keyed by their font family.'; trigger_error( $message, E_USER_DEPRECATED ); $new_webfonts = array(); foreach ( $webfonts as $webfont ) { - $font_family = WP_Webfonts_Utils::get_font_family_from_variation( $webfont ); + $font_family = WP_Fonts_Utils::get_font_family_from_variation( $webfont ); if ( ! $font_family ) { continue; } @@ -185,7 +185,7 @@ public function migrate_deprecated_structure( array $webfonts ) { public function is_deprecated_structure( array $webfonts ) { // Checks the first key to determine if it's empty or non-string. foreach ( $webfonts as $font_family => $variations ) { - return ! WP_Webfonts_Utils::is_defined( $font_family ); + return ! WP_Fonts_Utils::is_defined( $font_family ); } } @@ -199,12 +199,12 @@ public function is_deprecated_structure( array $webfonts ) { protected function extract_font_family_from_deprecated_webfonts_structure( array $webfont, $message ) { trigger_error( $message, E_USER_DEPRECATED ); - $font_family = WP_Webfonts_Utils::get_font_family_from_variation( $webfont ); + $font_family = WP_Fonts_Utils::get_font_family_from_variation( $webfont ); if ( ! $font_family ) { return null; } - return WP_Webfonts_Utils::convert_font_family_into_handle( $font_family ); + return WP_Fonts_Utils::convert_font_family_into_handle( $font_family ); } /** @@ -217,9 +217,9 @@ protected function extract_font_family_from_deprecated_webfonts_structure( array * @return string|false The font slug on success, or false if the font-family cannot be determined. */ private static function _get_font_slug( $to_convert ) { - $font_family_name = is_array( $to_convert ) ? WP_Webfonts_Utils::get_font_family_from_variation( $to_convert ) : $to_convert; + $font_family_name = is_array( $to_convert ) ? WP_Fonts_Utils::get_font_family_from_variation( $to_convert ) : $to_convert; return ! empty( $font_family_name ) - ? WP_Webfonts_Utils::convert_font_family_into_handle( $font_family_name ) + ? WP_Fonts_Utils::convert_font_family_into_handle( $font_family_name ) : false; } diff --git a/lib/experimental/fonts-api/deprecations/webfonts-deprecations.php b/lib/experimental/fonts-api/deprecations/webfonts-deprecations.php new file mode 100644 index 0000000000000..7179370471ad1 --- /dev/null +++ b/lib/experimental/fonts-api/deprecations/webfonts-deprecations.php @@ -0,0 +1,254 @@ + array[] $variations { + * An array of web font variations for this font-family. + * Each variation has the following structure. + * + * @type array $variation { + * @type string $provider The provider ID. Default 'local'. + * @type string $font-style The font-style property. Default 'normal'. + * @type string $font-weight The font-weight property. Default '400'. + * @type string $font-display The font-display property. Default 'fallback'. + * } + * } + * } + * @return string[] Array of registered font family handles. + */ + function wp_register_webfonts( array $webfonts ) { + _deprecated_function( __FUNCTION__, 'GB 15.1', 'wp_register_fonts()' ); + + return wp_register_fonts( $webfonts ); + } +} + +if ( ! function_exists( 'wp_register_webfont' ) ) { + /** + * Registers a single webfont. + * + * Example of how to register Source Serif Pro font with font-weight range of 200-900: + * + * If the font file is contained within the theme: + * + * + * wp_register_webfont( + * array( + * 'provider' => 'local', + * 'font-family' => 'Source Serif Pro', + * 'font-weight' => '200 900', + * 'font-style' => 'normal', + * 'src' => get_theme_file_uri( 'assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2' ), + * ) + * ); + * + * + * @since 6.0.0 + * @deprecated 14.9.1 Use wp_register_fonts(). + * + * @param array $webfont Webfont to be registered. + * @return string|false The font family slug if successfully registered, else false. + */ + function wp_register_webfont( array $webfont ) { + _deprecated_function( __FUNCTION__, '14.9.1', 'wp_register_fonts()' ); + + return wp_fonts()->register_webfont( $webfont, '', '', false ); + } +} + +if ( ! function_exists( 'wp_enqueue_webfonts' ) ) { + /** + * Enqueues one or more font family and all of its variations. + * + * @since X.X.X + * @since GB 15.1 Use wp_enqueue_fonts() ihstead. + * + * @param string[] $font_families Font family(ies) to enqueue. + */ + function wp_enqueue_webfonts( array $font_families ) { + _deprecated_function( __FUNCTION__, 'GB 15.1', 'wp_enqueue_fonts()' ); + + wp_enqueue_fonts( $font_families ); + } +} + +if ( ! function_exists( 'wp_enqueue_webfont' ) ) { + /** + * Enqueue a single font family that has been registered beforehand. + * + * Example of how to enqueue Source Serif Pro font: + * + * + * wp_enqueue_webfont( 'Source Serif Pro' ); + * + * + * Font families should be enqueued from the `init` hook or later. + * + * @since 6.0.0 + * @deprecated GB 14.9.1 Use wp_enqueue_fonts() instead. + * + * @param string $font_family_name The font family name to be enqueued. + * @return bool True if successfully enqueued, else false. + */ + function wp_enqueue_webfont( $font_family_name ) { + _deprecated_function( __FUNCTION__, 'GB 14.9.1', 'wp_enqueue_fonts()' ); + + wp_enqueue_fonts( array( $font_family_name ) ); + return true; + } +} + +if ( ! function_exists( 'wp_enqueue_webfont_variations' ) ) { + /** + * Enqueues a specific set of web font variations. + * + * @since X.X.X + * @deprecated GB 15.1 Use wp_enqueue_font_variations() instead. + * + * @param string|string[] $variation_handles Variation handle (string) or handles (array of strings). + */ + function wp_enqueue_webfont_variations( $variation_handles ) { + _deprecated_function( __FUNCTION__, 'GB 15.1', 'wp_enqueue_font_variations()' ); + + wp_enqueue_font_variations( $variation_handles ); + } +} + +if ( ! function_exists( 'wp_deregister_webfont_variation' ) ) { + /** + * Deregisters a font variation. + * + * @since GB 14.9.1 + * @deprecated GB 15.1 Use wp_deregister_font_variation() instead. + * + * @param string $font_family_handle The font family for this variation. + * @param string $variation_handle The variation's handle to remove. + */ + function wp_deregister_webfont_variation( $font_family_handle, $variation_handle ) { + _deprecated_function( __FUNCTION__, 'GB 15.1', 'wp_deregister_font_variation()' ); + + wp_deregister_font_variation( $font_family_handle, $variation_handle ); + } +} + +if ( ! function_exists( 'wp_get_webfont_providers' ) ) { + /** + * Gets all registered providers. + * + * Return an array of providers, each keyed by their unique + * ID (i.e. the `$id` property in the provider's object) with + * an instance of the provider (object): + * ID => provider instance + * + * Each provider contains the business logic for how to + * process its specific font service (i.e. local or remote) + * and how to generate the `@font-face` styles for its service. + * + * @since X.X.X + * @deprecated GB 14.9.1 Use wp_fonts()->get_providers(). + * + * @return string[] All registered providers, each keyed by their unique ID. + */ + function wp_get_webfont_providers() { + _deprecated_function( __FUNCTION__, '14.9.1', 'wp_fonts()->get_providers()' ); + + $providers = array(); + foreach ( wp_fonts()->get_providers() as $id => $config ) { + $providers[ $id ] = $config['class']; + } + + return $providers; + } +} + +if ( ! function_exists( 'wp_register_webfont_provider' ) ) { + /** + * Registers a custom font service provider. + * + * A webfont provider contains the business logic for how to + * interact with a remote font service and how to generate + * the `@font-face` styles for that remote service. + * + * How to register a custom font service provider: + * 1. Load its class file into memory before registration. + * 2. Pass the class' name to this function. + * + * For example, for a class named `My_Custom_Font_Service_Provider`: + * ``` + * wp_register_webfont_provider( My_Custom_Font_Service_Provider::class ); + * ``` + * + * @since X.X.X + * @deprecated GB 15.1 Use wp_register_font_provider() instead. + * + * @param string $name The provider's name. + * @param string $classname The provider's class name. + * The class should be a child of `WP_Webfonts_Provider`. + * See {@see WP_Webfonts_Provider}. + * + * @return bool True if successfully registered, else false. + */ + function wp_register_webfont_provider( $name, $classname ) { + _deprecated_function( __FUNCTION__, 'GB 15.1', 'wp_register_font_provider' ); + + return wp_register_font_provider( $name, $classname ); + } +} + +if ( ! function_exists( 'wp_print_webfonts' ) ) { + /** + * Invokes each provider to process and print its styles. + * + * @since GB 14.9.1 + * @deprecated GB 15.1 Use wp_print_fonts() instead. + * + * @param string|string[]|false $handles Optional. Items to be processed: queue (false), + * single item (string), or multiple items (array of strings). + * Default false. + * @return array|string[] Array of web font handles that have been processed. + * An empty array if none were processed. + */ + function wp_print_webfonts( $handles = false ) { + return wp_print_fonts( $handles ); + } +} diff --git a/lib/experimental/webfonts.php b/lib/experimental/fonts-api/fonts-api.php similarity index 60% rename from lib/experimental/webfonts.php rename to lib/experimental/fonts-api/fonts-api.php index c4ccc1640d9c8..49b45392d3306 100644 --- a/lib/experimental/webfonts.php +++ b/lib/experimental/fonts-api/fonts-api.php @@ -1,42 +1,42 @@ register_provider( 'local', 'WP_Webfonts_Provider_Local' ); + if ( ! ( $wp_fonts instanceof WP_Fonts ) ) { + $wp_fonts = new WP_Fonts(); + $wp_fonts->register_provider( 'local', 'WP_Fonts_Provider_Local' ); } - return $wp_webfonts; + return $wp_fonts; } } -if ( ! function_exists( 'wp_register_webfonts' ) ) { +if ( ! function_exists( 'wp_register_fonts' ) ) { /** * Registers one or more font-families and each of their variations. * * @since X.X.X * - * @param array[] $webfonts { - * Web fonts to be registered, grouped by each font-family. + * @param array[] $fonts { + * Fonts to be registered, grouped by each font-family. * * @type string $font-family => array[] $variations { * An array of web font variations for this font-family. @@ -52,29 +52,29 @@ function wp_webfonts() { * } * @return string[] Array of registered font family handles. */ - function wp_register_webfonts( array $webfonts ) { - $registered = array(); - $wp_webfonts = wp_webfonts(); + function wp_register_fonts( array $fonts ) { + $registered = array(); + $wp_fonts = wp_fonts(); // BACKPORT NOTE: Do not backport this code block to Core. - if ( $wp_webfonts->is_deprecated_structure( $webfonts ) ) { - $webfonts = $wp_webfonts->migrate_deprecated_structure( $webfonts ); + if ( $wp_fonts->is_deprecated_structure( $fonts ) ) { + $fonts = $wp_fonts->migrate_deprecated_structure( $fonts ); } // BACKPORT NOTE: end of code block. - foreach ( $webfonts as $font_family => $variations ) { - $font_family_handle = $wp_webfonts->add_font_family( $font_family ); + foreach ( $fonts as $font_family => $variations ) { + $font_family_handle = $wp_fonts->add_font_family( $font_family ); if ( ! $font_family_handle ) { continue; } // Register each of the variations for this font family. foreach ( $variations as $variation_handle => $variation ) { - if ( ! WP_Webfonts_Utils::is_defined( $variation_handle ) ) { + if ( ! WP_Fonts_Utils::is_defined( $variation_handle ) ) { $variation_handle = ''; } - $wp_webfonts->add_variation( $font_family_handle, $variation, $variation_handle ); + $wp_fonts->add_variation( $font_family_handle, $variation, $variation_handle ); } $registered[] = $font_family_handle; @@ -84,7 +84,7 @@ function wp_register_webfonts( array $webfonts ) { } } -if ( ! function_exists( 'wp_enqueue_webfonts' ) ) { +if ( ! function_exists( 'wp_enqueue_fonts' ) ) { /** * Enqueues one or more font family and all of its variations. * @@ -92,23 +92,23 @@ function wp_register_webfonts( array $webfonts ) { * * @param string[] $font_families Font family(ies) to enqueue. */ - function wp_enqueue_webfonts( array $font_families ) { - $handles = array_map( array( WP_Webfonts_Utils::class, 'convert_font_family_into_handle' ), $font_families ); + function wp_enqueue_fonts( array $font_families ) { + $handles = array_map( array( WP_Fonts_Utils::class, 'convert_font_family_into_handle' ), $font_families ); - wp_webfonts()->enqueue( $handles ); + wp_fonts()->enqueue( $handles ); } } -if ( ! function_exists( 'wp_enqueue_webfont_variations' ) ) { +if ( ! function_exists( 'wp_enqueue_font_variations' ) ) { /** - * Enqueues a specific set of web font variations. + * Enqueues a specific set of font variations. * * @since X.X.X * * @param string|string[] $variation_handles Variation handle (string) or handles (array of strings). */ - function wp_enqueue_webfont_variations( $variation_handles ) { - wp_webfonts()->enqueue( $variation_handles ); + function wp_enqueue_font_variations( $variation_handles ) { + wp_fonts()->enqueue( $variation_handles ); } } @@ -121,11 +121,11 @@ function wp_enqueue_webfont_variations( $variation_handles ) { * @param string $font_family_handle The font family to remove. */ function wp_deregister_font_family( $font_family_handle ) { - wp_webfonts()->remove_font_family( $font_family_handle ); + wp_fonts()->remove_font_family( $font_family_handle ); } } -if ( ! function_exists( 'wp_deregister_webfont_variation' ) ) { +if ( ! function_exists( 'wp_deregister_font_variation' ) ) { /** * Deregisters a font variation. * @@ -134,12 +134,12 @@ function wp_deregister_font_family( $font_family_handle ) { * @param string $font_family_handle The font family for this variation. * @param string $variation_handle The variation's handle to remove. */ - function wp_deregister_webfont_variation( $font_family_handle, $variation_handle ) { - wp_webfonts()->remove_variation( $font_family_handle, $variation_handle ); + function wp_deregister_font_variation( $font_family_handle, $variation_handle ) { + wp_fonts()->remove_variation( $font_family_handle, $variation_handle ); } } -if ( ! function_exists( 'wp_register_webfont_provider' ) ) { +if ( ! function_exists( 'wp_register_font_provider' ) ) { /** * Registers a custom font service provider. * @@ -153,7 +153,7 @@ function wp_deregister_webfont_variation( $font_family_handle, $variation_handle * * For example, for a class named `My_Custom_Font_Service_Provider`: * ``` - * wp_register_webfont_provider( My_Custom_Font_Service_Provider::class ); + * wp_register_font_provider( My_Custom_Font_Service_Provider::class ); * ``` * * @since 6.0.0 @@ -165,12 +165,12 @@ function wp_deregister_webfont_variation( $font_family_handle, $variation_handle * * @return bool True if successfully registered, else false. */ - function wp_register_webfont_provider( $name, $classname ) { - return wp_webfonts()->register_provider( $name, $classname ); + function wp_register_font_provider( $name, $classname ) { + return wp_fonts()->register_provider( $name, $classname ); } } -if ( ! function_exists( 'wp_print_webfonts' ) ) { +if ( ! function_exists( 'wp_print_fonts' ) ) { /** * Invokes each provider to process and print its styles. * @@ -179,11 +179,11 @@ function wp_register_webfont_provider( $name, $classname ) { * @param string|string[]|false $handles Optional. Items to be processed: queue (false), * single item (string), or multiple items (array of strings). * Default false. - * @return array|string[] Array of web font handles that have been processed. + * @return array|string[] Array of font handles that have been processed. * An empty array if none were processed. */ - function wp_print_webfonts( $handles = false ) { - global $wp_webfonts; + function wp_print_fonts( $handles = false ) { + global $wp_fonts; if ( empty( $handles ) ) { $handles = false; @@ -191,18 +191,18 @@ function wp_print_webfonts( $handles = false ) { _wp_scripts_maybe_doing_it_wrong( __FUNCTION__ ); - if ( ! ( $wp_webfonts instanceof WP_Web_Fonts ) ) { + if ( ! ( $wp_fonts instanceof WP_Fonts ) ) { if ( ! $handles ) { return array(); // No need to instantiate if nothing is there. } } - return wp_webfonts()->do_items( $handles ); + return wp_fonts()->do_items( $handles ); } } -add_action( 'admin_print_styles', 'wp_print_webfonts', 50 ); -add_action( 'wp_head', 'wp_print_webfonts', 50 ); +add_action( 'admin_print_styles', 'wp_print_fonts', 50 ); +add_action( 'wp_head', 'wp_print_fonts', 50 ); /** * Add webfonts mime types. diff --git a/lib/experimental/register-webfonts-from-theme-json.php b/lib/experimental/fonts-api/register-fonts-from-theme-json.php similarity index 79% rename from lib/experimental/register-webfonts-from-theme-json.php rename to lib/experimental/fonts-api/register-fonts-from-theme-json.php index 4b49f6e0534fa..cf943111963fd 100644 --- a/lib/experimental/register-webfonts-from-theme-json.php +++ b/lib/experimental/fonts-api/register-fonts-from-theme-json.php @@ -5,11 +5,11 @@ * @package gutenberg */ -if ( ! function_exists( 'gutenberg_register_webfonts_from_theme_json' ) ) { +if ( ! function_exists( 'gutenberg_register_fonts_from_theme_json' ) ) { /** - * Register webfonts defined in theme.json. + * Register fonts defined in theme.json. */ - function gutenberg_register_webfonts_from_theme_json() { + function gutenberg_register_fonts_from_theme_json() { // Get settings. $settings = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()->get_settings(); @@ -44,8 +44,8 @@ function gutenberg_register_webfonts_from_theme_json() { return; } - $webfonts = array(); - $handles = array(); + $fonts = array(); + $handles = array(); // Look for fontFamilies. foreach ( $settings['typography']['fontFamilies'] as $font_families ) { @@ -86,41 +86,41 @@ function gutenberg_register_webfonts_from_theme_json() { } } - $font_family_handle = WP_Webfonts_Utils::get_font_family_from_variation( $font_face ); + $font_family_handle = WP_Fonts_Utils::get_font_family_from_variation( $font_face ); if ( empty( $font_family_handle ) && isset( $font_family['slug'] ) ) { $font_family_handle = $font_family['slug']; } if ( ! empty( $font_family_handle ) ) { - $font_family_handle = WP_Webfonts_Utils::convert_font_family_into_handle( $font_family_handle ); + $font_family_handle = WP_Fonts_Utils::convert_font_family_into_handle( $font_family_handle ); } if ( empty( $font_family_handle ) ) { _doing_it_wrong( __FUNCTION__, __( 'Font family not defined in the variation or "slug".', 'gutenberg' ), '6.1.0' ); } $handles[] = $font_family_handle; - if ( ! array_key_exists( $font_family_handle, $webfonts ) ) { - $webfonts[ $font_family_handle ] = array(); + if ( ! array_key_exists( $font_family_handle, $fonts ) ) { + $fonts[ $font_family_handle ] = array(); } - $webfonts[ $font_family_handle ][] = $font_face; + $fonts[ $font_family_handle ][] = $font_face; } } } - wp_register_webfonts( $webfonts ); - wp_enqueue_webfonts( $handles ); + wp_register_fonts( $fonts ); + wp_enqueue_fonts( $handles ); } } -if ( ! function_exists( 'gutenberg_add_registered_webfonts_to_theme_json' ) ) { +if ( ! function_exists( 'gutenberg_add_registered_fonts_to_theme_json' ) ) { /** * Add missing fonts data to the global styles. * * @param array $data The global styles. * @return array The global styles with missing fonts data. */ - function gutenberg_add_registered_webfonts_to_theme_json( $data ) { - $font_families_registered = wp_webfonts()->get_registered_font_families(); + function gutenberg_add_registered_fonts_to_theme_json( $data ) { + $font_families_registered = wp_fonts()->get_registered_font_families(); $font_families_from_theme = ! empty( $data['settings']['typography']['fontFamilies'] ) ? $data['settings']['typography']['fontFamilies'] : array(); @@ -134,8 +134,8 @@ function gutenberg_add_registered_webfonts_to_theme_json( $data ) { $get_families = static function ( $families_data ) { $families = array(); foreach ( $families_data as $family ) { - $font_family = WP_Webfonts_Utils::get_font_family_from_variation( $family ); - $handle = WP_Webfonts_Utils::convert_font_family_into_handle( $font_family ); + $font_family = WP_Fonts_Utils::get_font_family_from_variation( $family ); + $handle = WP_Fonts_Utils::convert_font_family_into_handle( $font_family ); if ( ! empty( $handle ) ) { $families[ $handle ] = true; } @@ -168,16 +168,16 @@ function gutenberg_add_registered_webfonts_to_theme_json( $data ) { } foreach ( $to_add as $font_family_handle ) { - $data['settings']['typography']['fontFamilies'][] = wp_webfonts()->to_theme_json( $font_family_handle ); + $data['settings']['typography']['fontFamilies'][] = wp_fonts()->to_theme_json( $font_family_handle ); } return $data; } } -// `gutenberg_register_webfonts_from_theme_json()` calls `WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()`, which instantiates `WP_Theme_JSON_Gutenberg()`; +// `gutenberg_register_fonts_from_theme_json()` calls `WP_Theme_JSON_Resolver_Gutenberg::get_merged_data()`, which instantiates `WP_Theme_JSON_Gutenberg()`; // Gutenberg server-side blocks are registered via the init hook with a priority value of `20`. E.g., `add_action( 'init', 'register_block_core_image', 20 )`; // This priority value is added dynamically during the build. See: tools/webpack/blocks.js. // We want to make sure Gutenberg blocks are re-registered before any Theme_JSON operations take place // so that we have access to updated merged data. -add_action( 'init', 'gutenberg_register_webfonts_from_theme_json', 21 ); +add_action( 'init', 'gutenberg_register_fonts_from_theme_json', 21 ); diff --git a/lib/experimental/html/class-wp-html-tag-processor.php b/lib/experimental/html/class-wp-html-tag-processor.php index 9539f0d626e9d..c7bb67ba2788f 100644 --- a/lib/experimental/html/class-wp-html-tag-processor.php +++ b/lib/experimental/html/class-wp-html-tag-processor.php @@ -422,7 +422,7 @@ class WP_HTML_Tag_Processor { * @since 6.2.0 * @var WP_HTML_Text_Replacement[] */ - private $attribute_updates = array(); + private $lexical_updates = array(); /** * Tracks how many times we've performed a `seek()` @@ -1123,10 +1123,10 @@ private function after_tag() { * @since 6.2.0 * * @see $classname_updates - * @see $attribute_updates + * @see $lexical_updates */ private function class_name_updates_to_attributes_updates() { - if ( count( $this->classname_updates ) === 0 || isset( $this->attribute_updates['class'] ) ) { + if ( count( $this->classname_updates ) === 0 || isset( $this->lexical_updates['class'] ) ) { $this->classname_updates = array(); return; } @@ -1247,7 +1247,7 @@ private function class_name_updates_to_attributes_updates() { * @since 6.2.0 */ private function apply_attributes_updates() { - if ( ! count( $this->attribute_updates ) ) { + if ( ! count( $this->lexical_updates ) ) { return; } @@ -1261,9 +1261,9 @@ private function apply_attributes_updates() { * out of order, which could otherwise lead to mangled output, * partially-duplicate attributes, and overwritten attributes. */ - usort( $this->attribute_updates, array( self::class, 'sort_start_ascending' ) ); + usort( $this->lexical_updates, array( self::class, 'sort_start_ascending' ) ); - foreach ( $this->attribute_updates as $diff ) { + foreach ( $this->lexical_updates as $diff ) { $this->updated_html .= substr( $this->html, $this->updated_bytes, $diff->start - $this->updated_bytes ); $this->updated_html .= $diff->text; $this->updated_bytes = $diff->end; @@ -1271,7 +1271,7 @@ private function apply_attributes_updates() { foreach ( $this->bookmarks as $bookmark ) { /** - * As we loop through $this->attribute_updates, we keep comparing + * As we loop through $this->lexical_updates, we keep comparing * $bookmark->start and $bookmark->end to $diff->start. We can't * change it and still expect the correct result, so let's accumulate * the deltas separately and apply them all at once after the loop. @@ -1279,7 +1279,7 @@ private function apply_attributes_updates() { $head_delta = 0; $tail_delta = 0; - foreach ( $this->attribute_updates as $diff ) { + foreach ( $this->lexical_updates as $diff ) { $update_head = $bookmark->start >= $diff->start; $update_tail = $bookmark->end >= $diff->start; @@ -1302,7 +1302,7 @@ private function apply_attributes_updates() { $bookmark->end += $tail_delta; } - $this->attribute_updates = array(); + $this->lexical_updates = array(); } /** @@ -1604,8 +1604,8 @@ public function set_attribute( $name, $value ) { * * Result:
*/ - $existing_attribute = $this->attributes[ $comparable_name ]; - $this->attribute_updates[ $name ] = new WP_HTML_Text_Replacement( + $existing_attribute = $this->attributes[ $comparable_name ]; + $this->lexical_updates[ $name ] = new WP_HTML_Text_Replacement( $existing_attribute->start, $existing_attribute->end, $updated_attribute @@ -1622,7 +1622,7 @@ public function set_attribute( $name, $value ) { * * Result:
*/ - $this->attribute_updates[ $comparable_name ] = new WP_HTML_Text_Replacement( + $this->lexical_updates[ $comparable_name ] = new WP_HTML_Text_Replacement( $this->tag_name_starts_at + $this->tag_name_length, $this->tag_name_starts_at + $this->tag_name_length, ' ' . $updated_attribute @@ -1662,7 +1662,7 @@ public function remove_attribute( $name ) { * * Result:
*/ - $this->attribute_updates[ $name ] = new WP_HTML_Text_Replacement( + $this->lexical_updates[ $name ] = new WP_HTML_Text_Replacement( $this->attributes[ $name ]->start, $this->attributes[ $name ]->end, '' @@ -1724,7 +1724,7 @@ public function __toString() { */ public function get_updated_html() { // Short-circuit if there are no new updates to apply. - if ( ! count( $this->classname_updates ) && ! count( $this->attribute_updates ) ) { + if ( ! count( $this->classname_updates ) && ! count( $this->lexical_updates ) ) { return $this->updated_html . substr( $this->html, $this->updated_bytes ); } diff --git a/lib/experimental/kses.php b/lib/experimental/kses.php index fd7531617939f..830ac01c2ab0b 100644 --- a/lib/experimental/kses.php +++ b/lib/experimental/kses.php @@ -62,5 +62,6 @@ function gutenberg_override_core_kses_init_filters() { } } -add_action( 'init', 'gutenberg_override_core_kses_init_filters' ); +// The 'kses_init_filters' is usually initialized with default priority. Use higher priority to override. +add_action( 'init', 'gutenberg_override_core_kses_init_filters', 20 ); add_action( 'set_current_user', 'gutenberg_override_core_kses_init_filters' ); diff --git a/lib/experimental/webfonts-deprecations.php b/lib/experimental/webfonts-deprecations.php deleted file mode 100644 index bd50b0f476d96..0000000000000 --- a/lib/experimental/webfonts-deprecations.php +++ /dev/null @@ -1,100 +0,0 @@ - - * wp_enqueue_webfont( 'Source Serif Pro' ); - * - * - * Font families should be enqueued from the `init` hook or later. - * - * @since 6.0.0 - * @deprecated X.X.X Use wp_enqueue_webfonts(). - * - * @param string $font_family_name The font family name to be enqueued. - * @return bool True if successfully enqueued, else false. - */ - function wp_enqueue_webfont( $font_family_name ) { - _deprecated_function( __FUNCTION__, 'X.X.X', 'wp_enqueue_webfonts()' ); - - wp_enqueue_webfonts( array( $font_family_name ) ); - return true; - } -} - -if ( ! function_exists( 'wp_register_webfont' ) ) { - /** - * Registers a single webfont. - * - * Example of how to register Source Serif Pro font with font-weight range of 200-900: - * - * If the font file is contained within the theme: - * - * - * wp_register_webfont( - * array( - * 'provider' => 'local', - * 'font-family' => 'Source Serif Pro', - * 'font-weight' => '200 900', - * 'font-style' => 'normal', - * 'src' => get_theme_file_uri( 'assets/fonts/source-serif-pro/SourceSerif4Variable-Roman.ttf.woff2' ), - * ) - * ); - * - * - * @since 6.0.0 - * @deprecated X.X.X Use wp_register_webfonts(). - * - * @param array $webfont Webfont to be registered. - * @return string|false The font family slug if successfully registered, else false. - */ - function wp_register_webfont( array $webfont ) { - _deprecated_function( __FUNCTION__, 'X.X.X', 'wp_register_webfonts()' ); - - return wp_webfonts()->register_webfont( $webfont, '', '', false ); - } -} - -if ( ! function_exists( 'wp_get_webfont_providers' ) ) { - /** - * Gets all registered providers. - * - * Return an array of providers, each keyed by their unique - * ID (i.e. the `$id` property in the provider's object) with - * an instance of the provider (object): - * ID => provider instance - * - * Each provider contains the business logic for how to - * process its specific font service (i.e. local or remote) - * and how to generate the `@font-face` styles for its service. - * - * @since X.X.X - * @deprecated X.X.X Use wp_webfonts()->get_providers(). - * - * @return string[] All registered providers, each keyed by their unique ID. - */ - function wp_get_webfont_providers() { - _deprecated_function( __FUNCTION__, 'X.X.X', 'wp_webfonts()->get_providers()' ); - - $providers = array(); - foreach ( wp_webfonts()->get_providers() as $id => $config ) { - $providers[ $id ] = $config['class']; - } - - return $providers; - } -} diff --git a/lib/experiments-page.php b/lib/experiments-page.php index ea16a526b7cc5..09746caa559f2 100644 --- a/lib/experiments-page.php +++ b/lib/experiments-page.php @@ -77,22 +77,6 @@ function gutenberg_initialize_experiments_settings() { ) ); - add_settings_field( - 'gutenberg-global-styles-custom-css', - __( 'Global styles custom css ', 'gutenberg' ), - 'gutenberg_display_experiment_field', - 'gutenberg-experiments', - 'gutenberg_experiments_section', - array( - 'label' => sprintf( - /* translators: %s: WordPress documentation for roles and capabilities. */ - __( 'Test the Global Styles custom CSS field in the site editor. This requires a user to have unfiltered html capabilities.', 'gutenberg' ), - 'https://wordpress.org/support/article/roles-and-capabilities/#unfiltered_html' - ), - 'id' => 'gutenberg-global-styles-custom-css', - ) - ); - register_setting( 'gutenberg-experiments', 'gutenberg-experiments' diff --git a/lib/load.php b/lib/load.php index 51f53956b22b8..73d88454d37ef 100644 --- a/lib/load.php +++ b/lib/load.php @@ -98,15 +98,16 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/experimental/navigation-page.php'; require __DIR__ . '/experimental/kses.php'; -// Web Fonts API. -require __DIR__ . '/experimental/webfonts-deprecations.php'; // Temporary deprecated functions. -require __DIR__ . '/experimental/class-wp-webfonts.php'; // Temporary deprecated class. -require __DIR__ . '/experimental/class-wp-webfonts-utils.php'; -require __DIR__ . '/experimental/register-webfonts-from-theme-json.php'; -require __DIR__ . '/experimental/class-wp-web-fonts.php'; -require __DIR__ . '/experimental/class-wp-webfonts-provider.php'; -require __DIR__ . '/experimental/class-wp-webfonts-provider-local.php'; -require __DIR__ . '/experimental/webfonts.php'; +// Fonts API. +require __DIR__ . '/experimental/fonts-api/class-wp-fonts-provider.php'; +require __DIR__ . '/experimental/fonts-api/deprecations/webfonts-deprecations.php'; +require __DIR__ . '/experimental/fonts-api/deprecations/class-wp-webfonts-provider.php'; +require __DIR__ . '/experimental/fonts-api/deprecations/class-wp-webfonts.php'; +require __DIR__ . '/experimental/fonts-api/class-wp-fonts-utils.php'; +require __DIR__ . '/experimental/fonts-api/register-fonts-from-theme-json.php'; +require __DIR__ . '/experimental/fonts-api/class-wp-fonts.php'; +require __DIR__ . '/experimental/fonts-api/class-wp-fonts-provider-local.php'; +require __DIR__ . '/experimental/fonts-api/fonts-api.php'; // Plugin specific code. require __DIR__ . '/class-wp-theme-json-gutenberg.php'; @@ -127,7 +128,6 @@ function gutenberg_is_experiment_enabled( $name ) { } // Block supports overrides. -require __DIR__ . '/block-supports/utils.php'; require __DIR__ . '/block-supports/settings.php'; require __DIR__ . '/block-supports/elements.php'; require __DIR__ . '/block-supports/colors.php'; @@ -138,3 +138,4 @@ function gutenberg_is_experiment_enabled( $name ) { require __DIR__ . '/block-supports/spacing.php'; require __DIR__ . '/block-supports/dimensions.php'; require __DIR__ . '/block-supports/duotone.php'; +require __DIR__ . '/block-supports/shadow.php'; diff --git a/lib/theme.json b/lib/theme.json index 6221873a03297..d280f1bea45c4 100644 --- a/lib/theme.json +++ b/lib/theme.json @@ -187,7 +187,7 @@ "text": true }, "shadow": { - "palette": [ + "presets": [ { "name": "Natural", "slug": "natural", diff --git a/package-lock.json b/package-lock.json index 3a6d70fe60f86..c196eed47005e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "15.0.0-rc.1", + "version": "15.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1897,70 +1897,6 @@ } } }, - "@emotion/core": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/@emotion/core/-/core-10.1.1.tgz", - "integrity": "sha512-ZMLG6qpXR8x031NXD8HJqugy/AZSkAuMxxqB46pmAR7ze47MhNJ56cdoX243QPZdGctrdfo+s08yZTiwaUcRKA==", - "dev": true, - "requires": { - "@babel/runtime": "^7.5.5", - "@emotion/cache": "^10.0.27", - "@emotion/css": "^10.0.27", - "@emotion/serialize": "^0.11.15", - "@emotion/sheet": "0.9.4", - "@emotion/utils": "0.11.3" - }, - "dependencies": { - "@emotion/cache": { - "version": "10.0.29", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz", - "integrity": "sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==", - "dev": true, - "requires": { - "@emotion/sheet": "0.9.4", - "@emotion/stylis": "0.8.5", - "@emotion/utils": "0.11.3", - "@emotion/weak-memoize": "0.2.5" - } - }, - "@emotion/css": { - "version": "10.0.27", - "resolved": "https://registry.npmjs.org/@emotion/css/-/css-10.0.27.tgz", - "integrity": "sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw==", - "dev": true, - "requires": { - "@emotion/serialize": "^0.11.15", - "@emotion/utils": "0.11.3", - "babel-plugin-emotion": "^10.0.27" - } - }, - "@emotion/serialize": { - "version": "0.11.16", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", - "integrity": "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==", - "dev": true, - "requires": { - "@emotion/hash": "0.8.0", - "@emotion/memoize": "0.7.4", - "@emotion/unitless": "0.7.5", - "@emotion/utils": "0.11.3", - "csstype": "^2.5.7" - } - }, - "@emotion/utils": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", - "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==", - "dev": true - }, - "csstype": { - "version": "2.6.19", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.19.tgz", - "integrity": "sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ==", - "dev": true - } - } - }, "@emotion/css": { "version": "11.7.1", "resolved": "https://registry.npmjs.org/@emotion/css/-/css-11.7.1.tgz", @@ -2142,12 +2078,6 @@ "csstype": "^3.0.2" } }, - "@emotion/sheet": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-0.9.4.tgz", - "integrity": "sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==", - "dev": true - }, "@emotion/styled": { "version": "11.6.0", "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.6.0.tgz", @@ -2170,66 +2100,6 @@ } } }, - "@emotion/styled-base": { - "version": "10.0.31", - "resolved": "https://registry.npmjs.org/@emotion/styled-base/-/styled-base-10.0.31.tgz", - "integrity": "sha512-wTOE1NcXmqMWlyrtwdkqg87Mu6Rj1MaukEoEmEkHirO5IoHDJ8LgCQL4MjJODgxWxXibGR3opGp1p7YvkNEdXQ==", - "dev": true, - "requires": { - "@babel/runtime": "^7.5.5", - "@emotion/is-prop-valid": "0.8.8", - "@emotion/serialize": "^0.11.15", - "@emotion/utils": "0.11.3" - }, - "dependencies": { - "@emotion/is-prop-valid": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", - "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", - "dev": true, - "requires": { - "@emotion/memoize": "0.7.4" - } - }, - "@emotion/memoize": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", - "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", - "dev": true - }, - "@emotion/serialize": { - "version": "0.11.16", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", - "integrity": "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==", - "dev": true, - "requires": { - "@emotion/hash": "0.8.0", - "@emotion/memoize": "0.7.4", - "@emotion/unitless": "0.7.5", - "@emotion/utils": "0.11.3", - "csstype": "^2.5.7" - } - }, - "@emotion/utils": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", - "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==", - "dev": true - }, - "csstype": { - "version": "2.6.19", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.19.tgz", - "integrity": "sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ==", - "dev": true - } - } - }, - "@emotion/stylis": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", - "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==", - "dev": true - }, "@emotion/unitless": { "version": "0.7.5", "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", @@ -8229,18 +8099,6 @@ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.6.0.tgz", "integrity": "sha512-cPqjjzuFWNK3BSKLm0abspP0sp/IGOli4p5I5fKFAzdS8fvjdOwDCfZqAaIiXd9lPkOWi3SUUfZof3hEb7J/uw==" }, - "@reach/router": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/@reach/router/-/router-1.3.4.tgz", - "integrity": "sha512-+mtn9wjlB9NN2CNnnC/BRYtwdKBfSyyasPYraNAyvaV1occr/5NnB4CVzjEZipNHwYebQwcndGUmpFzxAUoqSA==", - "dev": true, - "requires": { - "create-react-context": "0.3.0", - "invariant": "^2.2.3", - "prop-types": "^15.6.1", - "react-lifecycles-compat": "^3.0.4" - } - }, "@react-native-clipboard/clipboard": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/@react-native-clipboard/clipboard/-/clipboard-1.9.0.tgz", @@ -9765,348 +9623,6 @@ } } }, - "@storybook/addon-knobs": { - "version": "6.2.9", - "resolved": "https://registry.npmjs.org/@storybook/addon-knobs/-/addon-knobs-6.2.9.tgz", - "integrity": "sha512-ic3xXy9uWPfIGP4x3VuGnrUmg/Jn9rHKIqZMhRcC7mFDRVlgbekvQxaruC6VY9LW6o8jV/miReSZkJf7M8o0aQ==", - "dev": true, - "requires": { - "@storybook/addons": "6.2.9", - "@storybook/api": "6.2.9", - "@storybook/channels": "6.2.9", - "@storybook/client-api": "6.2.9", - "@storybook/components": "6.2.9", - "@storybook/core-events": "6.2.9", - "@storybook/theming": "6.2.9", - "copy-to-clipboard": "^3.3.1", - "core-js": "^3.8.2", - "escape-html": "^1.0.3", - "fast-deep-equal": "^3.1.3", - "global": "^4.4.0", - "lodash": "^4.17.20", - "prop-types": "^15.7.2", - "qs": "^6.10.0", - "react-colorful": "^5.0.1", - "react-lifecycles-compat": "^3.0.4", - "react-select": "^3.2.0", - "regenerator-runtime": "^0.13.7" - }, - "dependencies": { - "@emotion/is-prop-valid": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", - "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", - "dev": true, - "requires": { - "@emotion/memoize": "0.7.4" - } - }, - "@emotion/memoize": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", - "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", - "dev": true - }, - "@emotion/styled": { - "version": "10.0.27", - "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-10.0.27.tgz", - "integrity": "sha512-iK/8Sh7+NLJzyp9a5+vIQIXTYxfT4yB/OJbjzQanB2RZpvmzBQOHZWhpAMZWYEKRNNbsD6WfBw5sVWkb6WzS/Q==", - "dev": true, - "requires": { - "@emotion/styled-base": "^10.0.27", - "babel-plugin-emotion": "^10.0.27" - } - }, - "@storybook/addons": { - "version": "6.2.9", - "resolved": "https://registry.npmjs.org/@storybook/addons/-/addons-6.2.9.tgz", - "integrity": "sha512-GnmEKbJwiN1jncN9NSA8CuR1i2XAlasPcl/Zn0jkfV9WitQeczVcJCPw86SGH84AD+tTBCyF2i9UC0KaOV1YBQ==", - "dev": true, - "requires": { - "@storybook/api": "6.2.9", - "@storybook/channels": "6.2.9", - "@storybook/client-logger": "6.2.9", - "@storybook/core-events": "6.2.9", - "@storybook/router": "6.2.9", - "@storybook/theming": "6.2.9", - "core-js": "^3.8.2", - "global": "^4.4.0", - "regenerator-runtime": "^0.13.7" - } - }, - "@storybook/api": { - "version": "6.2.9", - "resolved": "https://registry.npmjs.org/@storybook/api/-/api-6.2.9.tgz", - "integrity": "sha512-okkA3HAScE9tGnYBrjTOcgzT+L1lRHNoEh3ZfGgh1u/XNEyHGNkj4grvkd6nX7BzRcYQ/l2VkcKCqmOjUnSkVQ==", - "dev": true, - "requires": { - "@reach/router": "^1.3.4", - "@storybook/channels": "6.2.9", - "@storybook/client-logger": "6.2.9", - "@storybook/core-events": "6.2.9", - "@storybook/csf": "0.0.1", - "@storybook/router": "6.2.9", - "@storybook/semver": "^7.3.2", - "@storybook/theming": "6.2.9", - "@types/reach__router": "^1.3.7", - "core-js": "^3.8.2", - "fast-deep-equal": "^3.1.3", - "global": "^4.4.0", - "lodash": "^4.17.20", - "memoizerific": "^1.11.3", - "qs": "^6.10.0", - "regenerator-runtime": "^0.13.7", - "store2": "^2.12.0", - "telejson": "^5.1.0", - "ts-dedent": "^2.0.0", - "util-deprecate": "^1.0.2" - } - }, - "@storybook/channel-postmessage": { - "version": "6.2.9", - "resolved": "https://registry.npmjs.org/@storybook/channel-postmessage/-/channel-postmessage-6.2.9.tgz", - "integrity": "sha512-OqV+gLeeCHR0KExsIz0B7gD17Cjd9D+I75qnBsLWM9inWO5kc/WZ5svw8Bvjlcm6snWpvxUaT8L+svuqcPSmww==", - "dev": true, - "requires": { - "@storybook/channels": "6.2.9", - "@storybook/client-logger": "6.2.9", - "@storybook/core-events": "6.2.9", - "core-js": "^3.8.2", - "global": "^4.4.0", - "qs": "^6.10.0", - "telejson": "^5.1.0" - } - }, - "@storybook/channels": { - "version": "6.2.9", - "resolved": "https://registry.npmjs.org/@storybook/channels/-/channels-6.2.9.tgz", - "integrity": "sha512-6dC8Fb2ipNyOQXnUZMDeEUaJGH5DMLzyHlGLhVyDtrO5WR6bO8mQdkzf4+5dSKXgCBNX0BSkssXth4pDjn18rg==", - "dev": true, - "requires": { - "core-js": "^3.8.2", - "ts-dedent": "^2.0.0", - "util-deprecate": "^1.0.2" - } - }, - "@storybook/client-api": { - "version": "6.2.9", - "resolved": "https://registry.npmjs.org/@storybook/client-api/-/client-api-6.2.9.tgz", - "integrity": "sha512-aLvEUVkbvv6Qo/2mF4rFCecdqi2CGOUDdsV1a6EFIVS/9gXFdpirsOwKHo9qNjacGdWPlBYGCUcbrw+DvNaSFA==", - "dev": true, - "requires": { - "@storybook/addons": "6.2.9", - "@storybook/channel-postmessage": "6.2.9", - "@storybook/channels": "6.2.9", - "@storybook/client-logger": "6.2.9", - "@storybook/core-events": "6.2.9", - "@storybook/csf": "0.0.1", - "@types/qs": "^6.9.5", - "@types/webpack-env": "^1.16.0", - "core-js": "^3.8.2", - "global": "^4.4.0", - "lodash": "^4.17.20", - "memoizerific": "^1.11.3", - "qs": "^6.10.0", - "regenerator-runtime": "^0.13.7", - "stable": "^0.1.8", - "store2": "^2.12.0", - "ts-dedent": "^2.0.0", - "util-deprecate": "^1.0.2" - } - }, - "@storybook/client-logger": { - "version": "6.2.9", - "resolved": "https://registry.npmjs.org/@storybook/client-logger/-/client-logger-6.2.9.tgz", - "integrity": "sha512-IfOQZuvpjh66qBInQCJOb9S0dTGpzZ/Cxlcvokp+PYt95KztaWN3mPm+HaDQCeRsrWNe0Bpm1zuickcJ6dBOXg==", - "dev": true, - "requires": { - "core-js": "^3.8.2", - "global": "^4.4.0" - } - }, - "@storybook/components": { - "version": "6.2.9", - "resolved": "https://registry.npmjs.org/@storybook/components/-/components-6.2.9.tgz", - "integrity": "sha512-hnV1MI2aB2g1sJ7NJphpxi7TwrMZQ/tpCJeHnkjmzyC6ez1MXqcBXGrEEdSXzRfAxjQTOEpu6H1mnns0xMP0Ag==", - "dev": true, - "requires": { - "@popperjs/core": "^2.6.0", - "@storybook/client-logger": "6.2.9", - "@storybook/csf": "0.0.1", - "@storybook/theming": "6.2.9", - "@types/color-convert": "^2.0.0", - "@types/overlayscrollbars": "^1.12.0", - "@types/react-syntax-highlighter": "11.0.5", - "color-convert": "^2.0.1", - "core-js": "^3.8.2", - "fast-deep-equal": "^3.1.3", - "global": "^4.4.0", - "lodash": "^4.17.20", - "markdown-to-jsx": "^7.1.0", - "memoizerific": "^1.11.3", - "overlayscrollbars": "^1.13.1", - "polished": "^4.0.5", - "prop-types": "^15.7.2", - "react-colorful": "^5.0.1", - "react-popper-tooltip": "^3.1.1", - "react-syntax-highlighter": "^13.5.3", - "react-textarea-autosize": "^8.3.0", - "regenerator-runtime": "^0.13.7", - "ts-dedent": "^2.0.0", - "util-deprecate": "^1.0.2" - } - }, - "@storybook/core-events": { - "version": "6.2.9", - "resolved": "https://registry.npmjs.org/@storybook/core-events/-/core-events-6.2.9.tgz", - "integrity": "sha512-xQmbX/oYQK1QsAGN8hriXX5SUKOoTUe3L4dVaVHxJqy7MReRWJpprJmCpbAPJzWS6WCbDFfCM5kVEexHLOzJlQ==", - "dev": true, - "requires": { - "core-js": "^3.8.2" - } - }, - "@storybook/router": { - "version": "6.2.9", - "resolved": "https://registry.npmjs.org/@storybook/router/-/router-6.2.9.tgz", - "integrity": "sha512-7Bn1OFoItCl8whXRT8N1qp1Lky7kzXJ3aslWp5E8HcM8rxh4OYXfbaeiyJEJxBTGC5zxgY+tAEXHFjsAviFROg==", - "dev": true, - "requires": { - "@reach/router": "^1.3.4", - "@storybook/client-logger": "6.2.9", - "@types/reach__router": "^1.3.7", - "core-js": "^3.8.2", - "fast-deep-equal": "^3.1.3", - "global": "^4.4.0", - "lodash": "^4.17.20", - "memoizerific": "^1.11.3", - "qs": "^6.10.0", - "ts-dedent": "^2.0.0" - } - }, - "@storybook/semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/@storybook/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-SWeszlsiPsMI0Ps0jVNtH64cI5c0UF3f7KgjVKJoNP30crQ6wUSddY2hsdeczZXEKVJGEn50Q60flcGsQGIcrg==", - "dev": true, - "requires": { - "core-js": "^3.6.5", - "find-up": "^4.1.0" - } - }, - "@storybook/theming": { - "version": "6.2.9", - "resolved": "https://registry.npmjs.org/@storybook/theming/-/theming-6.2.9.tgz", - "integrity": "sha512-183oJW7AD7Fhqg5NT4ct3GJntwteAb9jZnQ6yhf9JSdY+fk8OhxRbPf7ov0au2gYACcGrWDd9K5pYQsvWlP5gA==", - "dev": true, - "requires": { - "@emotion/core": "^10.1.1", - "@emotion/is-prop-valid": "^0.8.6", - "@emotion/styled": "^10.0.27", - "@storybook/client-logger": "6.2.9", - "core-js": "^3.8.2", - "deep-object-diff": "^1.1.0", - "emotion-theming": "^10.0.27", - "global": "^4.4.0", - "memoizerific": "^1.11.3", - "polished": "^4.0.5", - "resolve-from": "^5.0.0", - "ts-dedent": "^2.0.0" - } - }, - "@types/qs": { - "version": "6.9.6", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.6.tgz", - "integrity": "sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA==", - "dev": true - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - } - } - }, "@storybook/addon-toolbars": { "version": "6.5.7", "resolved": "https://registry.npmjs.org/@storybook/addon-toolbars/-/addon-toolbars-6.5.7.tgz", @@ -13205,15 +12721,6 @@ } } }, - "@storybook/csf": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/@storybook/csf/-/csf-0.0.1.tgz", - "integrity": "sha512-USTLkZze5gkel8MYCujSRBVIrUQ3YPBrLOx7GNk/0wttvVtlzWXAq9eLbQ4p/NicGxP+3T7KPEMVV//g+yubpw==", - "dev": true, - "requires": { - "lodash": "^4.17.15" - } - }, "@storybook/csf-tools": { "version": "6.5.7", "resolved": "https://registry.npmjs.org/@storybook/csf-tools/-/csf-tools-6.5.7.tgz", @@ -16367,15 +15874,6 @@ "classnames": "*" } }, - "@types/color-convert": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/color-convert/-/color-convert-2.0.0.tgz", - "integrity": "sha512-m7GG7IKKGuJUXvkZ1qqG3ChccdIM/qBBo913z+Xft0nKCX4hAU/IxKwZBU4cpRZ7GS5kV4vOblUkILtSShCPXQ==", - "dev": true, - "requires": { - "@types/color-name": "*" - } - }, "@types/color-name": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", @@ -16839,12 +16337,6 @@ "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.0.tgz", "integrity": "sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg==" }, - "@types/overlayscrollbars": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/@types/overlayscrollbars/-/overlayscrollbars-1.12.0.tgz", - "integrity": "sha512-h/pScHNKi4mb+TrJGDon8Yb06ujFG0mSg12wIO0sWMUF3dQIe2ExRRdNRviaNt9IjxIiOfnRr7FsQAdHwK4sMg==", - "dev": true - }, "@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", @@ -16879,15 +16371,6 @@ "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", "dev": true }, - "@types/reach__router": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/@types/reach__router/-/reach__router-1.3.8.tgz", - "integrity": "sha512-cjjT0FPdwuvhLWpCDt2WCh4sdBqNzJe3XhxXmRQGsY3IvT58M8sE4E7A0QaFYuJs3ar+McSJTiJxdYKWAXbBhw==", - "dev": true, - "requires": { - "@types/react": "*" - } - }, "@types/react": { "version": "18.0.21", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.21.tgz", @@ -17933,6 +17416,7 @@ "@wordpress/dom": "file:packages/dom", "@wordpress/element": "file:packages/element", "@wordpress/escape-html": "file:packages/escape-html", + "@wordpress/experiments": "file:packages/experiments", "@wordpress/hooks": "file:packages/hooks", "@wordpress/html-entities": "file:packages/html-entities", "@wordpress/i18n": "file:packages/i18n", @@ -18206,6 +17690,7 @@ "@wordpress/compose": "file:packages/compose", "@wordpress/deprecated": "file:packages/deprecated", "@wordpress/element": "file:packages/element", + "@wordpress/experiments": "file:packages/experiments", "@wordpress/is-shallow-equal": "file:packages/is-shallow-equal", "@wordpress/priority-queue": "file:packages/priority-queue", "@wordpress/redux-routine": "file:packages/redux-routine", @@ -18402,6 +17887,7 @@ "@wordpress/deprecated": "file:packages/deprecated", "@wordpress/editor": "file:packages/editor", "@wordpress/element": "file:packages/element", + "@wordpress/experiments": "file:packages/experiments", "@wordpress/hooks": "file:packages/hooks", "@wordpress/html-entities": "file:packages/html-entities", "@wordpress/i18n": "file:packages/i18n", @@ -19969,7 +19455,7 @@ "app-root-dir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/app-root-dir/-/app-root-dir-1.0.2.tgz", - "integrity": "sha512-jlpIfsOoNoafl92Sz//64uQHGSyMrD2vYG5d8o2a4qGvyNCvXur7bzIsWtAC/6flI2RYAp3kv8rsfBtaLm7w0g==", + "integrity": "sha1-OBh+wt6nV3//Az/8sSFyaS/24Rg=", "dev": true }, "app-root-path": { @@ -26627,7 +26113,7 @@ "array-ify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", - "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", "dev": true }, "array-includes": { @@ -28262,7 +27748,7 @@ "babel-plugin-add-react-displayname": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/babel-plugin-add-react-displayname/-/babel-plugin-add-react-displayname-0.0.5.tgz", - "integrity": "sha512-LY3+Y0XVDYcShHHorshrDbt4KFWL4bSeniCtl4SYZbask+Syngk1uMPCeN9+nSiZo6zX5s0RTq/J9Pnaaf/KHw==", + "integrity": "sha1-M51M3be2X9YtHfnbn+BN4TQSK9U=", "dev": true }, "babel-plugin-apply-mdx-type-prop": { @@ -28291,51 +27777,6 @@ "object.assign": "^4.1.0" } }, - "babel-plugin-emotion": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-10.2.2.tgz", - "integrity": "sha512-SMSkGoqTbTyUTDeuVuPIWifPdUGkTk1Kf9BWRiXIOIcuyMfsdp2EjeiiFvOzX8NOBvEh/ypKYvUh2rkgAJMCLA==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.0.0", - "@emotion/hash": "0.8.0", - "@emotion/memoize": "0.7.4", - "@emotion/serialize": "^0.11.16", - "babel-plugin-macros": "^2.0.0", - "babel-plugin-syntax-jsx": "^6.18.0", - "convert-source-map": "^1.5.0", - "escape-string-regexp": "^1.0.5", - "find-root": "^1.1.0", - "source-map": "^0.5.7" - }, - "dependencies": { - "@emotion/serialize": { - "version": "0.11.16", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", - "integrity": "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==", - "dev": true, - "requires": { - "@emotion/hash": "0.8.0", - "@emotion/memoize": "0.7.4", - "@emotion/unitless": "0.7.5", - "@emotion/utils": "0.11.3", - "csstype": "^2.5.7" - } - }, - "@emotion/utils": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", - "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==", - "dev": true - }, - "csstype": { - "version": "2.6.19", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.19.tgz", - "integrity": "sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ==", - "dev": true - } - } - }, "babel-plugin-extract-import-names": { "version": "1.6.22", "resolved": "https://registry.npmjs.org/babel-plugin-extract-import-names/-/babel-plugin-extract-import-names-1.6.22.tgz", @@ -28529,12 +27970,6 @@ "@babel/template": "^7.0.0-beta.49" } }, - "babel-plugin-syntax-jsx": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", - "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=", - "dev": true - }, "babel-plugin-syntax-trailing-function-commas": { "version": "7.0.0-beta.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz", @@ -28685,7 +28120,7 @@ "batch-processor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/batch-processor/-/batch-processor-1.0.0.tgz", - "integrity": "sha512-xoLQD8gmmR32MeuBHgH0Tzd5PuSZx71ZsbhVxOCRbgktZEPe4SQy7s9Z50uPp0F/f7iw2XmkHN2xkgbMfckMDA==", + "integrity": "sha1-dclcMrdI4IUNEMKxaPa9vpiRrOg=", "dev": true }, "bcrypt-pbkdf": { @@ -29469,6 +28904,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz", "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==", + "dev": true, "requires": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.0" @@ -31115,15 +30551,6 @@ "integrity": "sha512-Q4+qBFnN4bwGwvtXXzbp4P/4iNk0MaiGAzvQ8OiMtlLjkIKjmNN689uVzShSM0908q7GoFHXIPx4zi75ocoaHw==", "dev": true }, - "copy-to-clipboard": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz", - "integrity": "sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw==", - "dev": true, - "requires": { - "toggle-selection": "^1.0.6" - } - }, "copy-webpack-plugin": { "version": "10.2.0", "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-10.2.0.tgz", @@ -31599,16 +31026,6 @@ "sha.js": "^2.4.8" } }, - "create-react-context": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.3.0.tgz", - "integrity": "sha512-dNldIoSuNSvlTJ7slIKC/ZFGKexBMBrrcc+TTe1NdmROnaASuLPvqpwj9v4XS4uXZ8+YPu0sNmShX2rXI5LNsw==", - "dev": true, - "requires": { - "gud": "^1.0.0", - "warning": "^4.0.3" - } - }, "cross-env": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-3.2.4.tgz", @@ -32020,7 +31437,7 @@ "debuglog": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=", + "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", "dev": true }, "decache": { @@ -32129,12 +31546,6 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, - "deep-object-diff": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/deep-object-diff/-/deep-object-diff-1.1.0.tgz", - "integrity": "sha512-b+QLs5vHgS+IoSNcUE4n9HP2NwcHj7aqnJWsjPtuG75Rh5TOaGt0OjAYInh77d5T16V5cRDC+Pw/6ZZZiETBGw==", - "dev": true - }, "deepmerge": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", @@ -32760,24 +32171,6 @@ "utila": "~0.4" } }, - "dom-helpers": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", - "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", - "dev": true, - "requires": { - "@babel/runtime": "^7.8.7", - "csstype": "^3.0.2" - }, - "dependencies": { - "csstype": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz", - "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==", - "dev": true - } - } - }, "dom-scroll-into-view": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/dom-scroll-into-view/-/dom-scroll-into-view-1.2.1.tgz", @@ -33005,17 +32398,6 @@ "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", "dev": true }, - "emotion-theming": { - "version": "10.0.27", - "resolved": "https://registry.npmjs.org/emotion-theming/-/emotion-theming-10.0.27.tgz", - "integrity": "sha512-MlF1yu/gYh8u+sLUqA0YuA9JX0P4Hb69WlKc/9OLo+WCXuX6sy/KoIa+qJimgmr2dWqnypYKYPX37esjDBbhdw==", - "dev": true, - "requires": { - "@babel/runtime": "^7.5.5", - "@emotion/weak-memoize": "0.2.5", - "hoist-non-react-statics": "^3.3.0" - } - }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", @@ -36766,6 +36148,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.2.tgz", "integrity": "sha512-aeX0vrFm21ILl3+JpFFRNe9aUvp6VFZb2/CTbgLb8j75kOhvoNYjt9d8KA/tJG4gSo8nzEDedRl0h7vDmBYRVg==", + "dev": true, "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -36775,7 +36158,8 @@ "has-symbols": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true } } }, @@ -36957,7 +36341,7 @@ "git-remote-origin-url": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz", - "integrity": "sha1-UoJlna4hBxRaERJhEq0yFuxfpl8=", + "integrity": "sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw==", "dev": true, "requires": { "gitconfiglocal": "^1.0.0", @@ -37004,7 +36388,7 @@ "gitconfiglocal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz", - "integrity": "sha1-QdBF84UaXqiPA/JMocYXgRRGS5s=", + "integrity": "sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ==", "dev": true, "requires": { "ini": "^1.3.2" @@ -37250,12 +36634,6 @@ "resolved": "https://registry.npmjs.org/gradient-parser/-/gradient-parser-0.1.5.tgz", "integrity": "sha1-DH4heVWeXOfY1x9EI6+TcQCyJIw=" }, - "gud": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz", - "integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==", - "dev": true - }, "handle-thing": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", @@ -37358,7 +36736,7 @@ "has-glob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-glob/-/has-glob-1.0.0.tgz", - "integrity": "sha512-D+8A457fBShSEI3tFCj65PAbT++5sKiFtdCdOam0gnfBgw9D277OERk+HM9qYJXmdVLZ/znez10SqHN0BBQ50g==", + "integrity": "sha1-mqqe7b/7G6OZCnsAEPtnjuAIEgc=", "dev": true, "requires": { "is-glob": "^3.0.0" @@ -37367,7 +36745,7 @@ "is-glob": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", "dev": true, "requires": { "is-extglob": "^2.1.0" @@ -38213,7 +37591,7 @@ "humanize-ms": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", "dev": true, "requires": { "ms": "^2.0.0" @@ -39230,7 +38608,7 @@ "is-text-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", - "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=", + "integrity": "sha512-xFuJpne9oFz5qDaodwmmG08e3CawH/2ZV8Qqza1Ko7Sk8POWbkRdwIoAWVhqvq0XeUzANEhKo2n0IXUGBm7A/w==", "dev": true, "requires": { "text-extensions": "^1.0.0" @@ -39542,7 +38920,7 @@ "is-window": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-window/-/is-window-1.0.2.tgz", - "integrity": "sha512-uj00kdXyZb9t9RcAUAwMZAnkBUwdYGhYlt7djMXhfyhUCzwNba50tIiBKR7q0l7tdoBtFVw/3JmLY6fI3rmZmg==", + "integrity": "sha1-LIlspT25feRdPDMTOmXYyfVjSA0=", "dev": true }, "is-windows": { @@ -42942,7 +42320,7 @@ "js-string-escape": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", - "integrity": "sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==", + "integrity": "sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8=", "dev": true }, "js-tokens": { @@ -43333,7 +42711,7 @@ "jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", "dev": true }, "jsprim": { @@ -44414,7 +43792,7 @@ "lodash.ismatch": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", - "integrity": "sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc=", + "integrity": "sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==", "dev": true }, "lodash.isplainobject": { @@ -44941,12 +44319,6 @@ "integrity": "sha512-NcWuJFHDA8V3wkDgR/j4+gZx+YQwstPgfQDV8ndUeWWzta3dnDTBxpVzqS9lkmJAuV5YX35lmyojl6HO5JXAgw==", "dev": true }, - "markdown-to-jsx": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/markdown-to-jsx/-/markdown-to-jsx-7.1.3.tgz", - "integrity": "sha512-jtQ6VyT7rMT5tPV0g2EJakEnXLiPksnvlYtwQsVVZ611JsWGN8bQ1tVSDX4s6JllfEH6wmsYxNjTUAMrPmNA8w==", - "dev": true - }, "markdownlint": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.25.1.tgz", @@ -48148,7 +47520,7 @@ "num2fraction": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", - "integrity": "sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg==", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", "dev": true }, "number-is-nan": { @@ -48612,7 +47984,8 @@ "object-inspect": { "version": "1.10.3", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", - "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==" + "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==", + "dev": true }, "object-is": { "version": "1.1.5", @@ -49590,12 +48963,6 @@ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, - "overlayscrollbars": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/overlayscrollbars/-/overlayscrollbars-1.13.1.tgz", - "integrity": "sha512-gIQfzgGgu1wy80EB4/6DaJGHMEGmizq27xHIESrzXq0Y/J0Ay1P3DWk6tuVmEPIZH15zaBlxeEJOqdJKmowHCQ==", - "dev": true - }, "p-all": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/p-all/-/p-all-2.1.0.tgz", @@ -49622,7 +48989,7 @@ "p-defer": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==", + "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=", "dev": true }, "p-event": { @@ -50419,26 +49786,6 @@ "ts-pnp": "^1.1.6" } }, - "polished": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/polished/-/polished-4.1.3.tgz", - "integrity": "sha512-ocPAcVBUOryJEKe0z2KLd1l9EBa1r5mSwlKpExmrLzsnIzJo4axsoU9O2BjOTkDGDT4mZ0WFE5XKTlR3nLnZOA==", - "dev": true, - "requires": { - "@babel/runtime": "^7.14.0" - }, - "dependencies": { - "@babel/runtime": { - "version": "7.14.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.14.6.tgz", - "integrity": "sha512-/PCB2uJ7oM44tz8YhC4Z/6PeOKXp4K588f+5M3clr1M4zbqztlo0XEfJ2LEzj/FgwfgGcIdl8n7YYjTCI0BYwg==", - "dev": true, - "requires": { - "regenerator-runtime": "^0.13.4" - } - } - } - }, "popmotion": { "version": "11.0.5", "resolved": "https://registry.npmjs.org/popmotion/-/popmotion-11.0.5.tgz", @@ -51198,13 +50545,7 @@ "pretty-hrtime": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==", - "dev": true - }, - "prismjs": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.24.1.tgz", - "integrity": "sha512-mNPsedLuk90RVJioIky8ANZEwYm5w9LcvCXrxHlwf4fNVSn8jEipMybMkWUyyF0JhnC+C4VcOVSBuHRKs1L5Ow==", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", "dev": true }, "private": { @@ -51763,7 +51104,7 @@ "promzard": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz", - "integrity": "sha1-JqXW7ox97kyxIggwWs+5O6OCqe4=", + "integrity": "sha512-JZeYqd7UAcHCwI+sTOeUDYkvEU+1bQ7iE0UT1MgB/tERkAPkesW46MrpIySzODi+owTjZtiF8Ay5j9m60KmMBw==", "dev": true, "requires": { "read": "1" @@ -51797,7 +51138,7 @@ "proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", "dev": true }, "protocols": { @@ -52335,21 +51676,6 @@ } } }, - "react-fast-compare": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", - "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==", - "dev": true - }, - "react-input-autosize": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-3.0.0.tgz", - "integrity": "sha512-nL9uS7jEs/zu8sqwFE5MAPx6pPkNAriACQ2rGLlqmKr2sPGtN7TXTyDdQt4lbNXVx7Uzadb40x8qotIuru6Rhg==", - "dev": true, - "requires": { - "prop-types": "^15.5.8" - } - }, "react-inspector": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/react-inspector/-/react-inspector-5.1.1.tgz", @@ -52366,12 +51692,6 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.4.tgz", "integrity": "sha512-PVadd+WaUDOAciICm/J1waJaSvgq+4rHE/K70j0PFqKhkTBsPv/82UGQJNXAngz1fOQLLxI6z1sEDmJDQhCTAA==" }, - "react-lifecycles-compat": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", - "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==", - "dev": true - }, "react-native": { "version": "0.69.4", "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.69.4.tgz", @@ -53190,101 +52510,12 @@ } } }, - "react-popper": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.2.5.tgz", - "integrity": "sha512-kxGkS80eQGtLl18+uig1UIf9MKixFSyPxglsgLBxlYnyDf65BiY9B3nZSc6C9XUNDgStROB0fMQlTEz1KxGddw==", - "dev": true, - "requires": { - "react-fast-compare": "^3.0.1", - "warning": "^4.0.2" - } - }, - "react-popper-tooltip": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/react-popper-tooltip/-/react-popper-tooltip-3.1.1.tgz", - "integrity": "sha512-EnERAnnKRptQBJyaee5GJScWNUKQPDD2ywvzZyUjst/wj5U64C8/CnSYLNEmP2hG0IJ3ZhtDxE8oDN+KOyavXQ==", - "dev": true, - "requires": { - "@babel/runtime": "^7.12.5", - "@popperjs/core": "^2.5.4", - "react-popper": "^2.2.4" - } - }, "react-refresh": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.10.0.tgz", "integrity": "sha512-PgidR3wST3dDYKr6b4pJoqQFpPGNKDSCDx4cZoshjXipw3LzO7mG1My2pwEzz2JVkF+inx3xRpDeQLFQGH/hsQ==", "dev": true }, - "react-select": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/react-select/-/react-select-3.2.0.tgz", - "integrity": "sha512-B/q3TnCZXEKItO0fFN/I0tWOX3WJvi/X2wtdffmwSQVRwg5BpValScTO1vdic9AxlUgmeSzib2hAZAwIUQUZGQ==", - "dev": true, - "requires": { - "@babel/runtime": "^7.4.4", - "@emotion/cache": "^10.0.9", - "@emotion/core": "^10.0.9", - "@emotion/css": "^10.0.9", - "memoize-one": "^5.0.0", - "prop-types": "^15.6.0", - "react-input-autosize": "^3.0.0", - "react-transition-group": "^4.3.0" - }, - "dependencies": { - "@emotion/cache": { - "version": "10.0.29", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz", - "integrity": "sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==", - "dev": true, - "requires": { - "@emotion/sheet": "0.9.4", - "@emotion/stylis": "0.8.5", - "@emotion/utils": "0.11.3", - "@emotion/weak-memoize": "0.2.5" - } - }, - "@emotion/css": { - "version": "10.0.27", - "resolved": "https://registry.npmjs.org/@emotion/css/-/css-10.0.27.tgz", - "integrity": "sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw==", - "dev": true, - "requires": { - "@emotion/serialize": "^0.11.15", - "@emotion/utils": "0.11.3", - "babel-plugin-emotion": "^10.0.27" - }, - "dependencies": { - "@emotion/serialize": { - "version": "0.11.16", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", - "integrity": "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==", - "dev": true, - "requires": { - "@emotion/hash": "0.8.0", - "@emotion/memoize": "0.7.4", - "@emotion/unitless": "0.7.5", - "@emotion/utils": "0.11.3", - "csstype": "^2.5.7" - } - } - } - }, - "@emotion/utils": { - "version": "0.11.3", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", - "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==", - "dev": true - }, - "csstype": { - "version": "2.6.19", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.19.tgz", - "integrity": "sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ==", - "dev": true - } - } - }, "react-shallow-renderer": { "version": "16.15.0", "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz", @@ -53313,19 +52544,6 @@ "throttle-debounce": "^3.0.1" } }, - "react-syntax-highlighter": { - "version": "13.5.3", - "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-13.5.3.tgz", - "integrity": "sha512-crPaF+QGPeHNIblxxCdf2Lg936NAHKhNhuMzRL3F9ct6aYXL3NcZtCL0Rms9+qVo6Y1EQLdXGypBNSbPL/r+qg==", - "dev": true, - "requires": { - "@babel/runtime": "^7.3.1", - "highlight.js": "^10.1.1", - "lowlight": "^1.14.0", - "prismjs": "^1.21.0", - "refractor": "^3.1.0" - } - }, "react-test-renderer": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-18.2.0.tgz", @@ -53345,33 +52563,10 @@ } } }, - "react-textarea-autosize": { - "version": "8.3.3", - "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.3.3.tgz", - "integrity": "sha512-2XlHXK2TDxS6vbQaoPbMOfQ8GK7+irc2fVK6QFIcC8GOnH3zI/v481n+j1L0WaPVvKxwesnY93fEfH++sus2rQ==", - "dev": true, - "requires": { - "@babel/runtime": "^7.10.2", - "use-composed-ref": "^1.0.0", - "use-latest": "^1.0.0" - } - }, - "react-transition-group": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz", - "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==", - "dev": true, - "requires": { - "@babel/runtime": "^7.5.5", - "dom-helpers": "^5.0.1", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2" - } - }, "read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", - "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", + "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", "dev": true, "requires": { "mute-stream": "~0.0.4" @@ -53736,33 +52931,6 @@ "@babel/runtime": "^7.9.2" } }, - "refractor": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.4.0.tgz", - "integrity": "sha512-dBeD02lC5eytm9Gld2Mx0cMcnR+zhSnsTfPpWqFaMgUMJfC9A6bcN3Br/NaXrnBJcuxnLFR90k1jrkaSyV8umg==", - "dev": true, - "requires": { - "hastscript": "^6.0.0", - "parse-entities": "^2.0.0", - "prismjs": "~1.24.0" - }, - "dependencies": { - "parse-entities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", - "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", - "dev": true, - "requires": { - "character-entities": "^1.0.0", - "character-entities-legacy": "^1.0.0", - "character-reference-invalid": "^1.0.0", - "is-alphanumerical": "^1.0.0", - "is-decimal": "^1.0.0", - "is-hexadecimal": "^1.0.0" - } - } - } - }, "regenerate": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", @@ -53963,7 +53131,7 @@ "relateurl": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", "dev": true }, "remark": { @@ -58997,65 +58165,6 @@ } } }, - "telejson": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/telejson/-/telejson-5.3.3.tgz", - "integrity": "sha512-PjqkJZpzEggA9TBpVtJi1LVptP7tYtXB6rEubwlHap76AMjzvOdKX41CxyaW7ahhzDU1aftXnMCx5kAPDZTQBA==", - "dev": true, - "requires": { - "@types/is-function": "^1.0.0", - "global": "^4.4.0", - "is-function": "^1.0.2", - "is-regex": "^1.1.2", - "is-symbol": "^1.0.3", - "isobject": "^4.0.0", - "lodash": "^4.17.21", - "memoizerific": "^1.11.3" - }, - "dependencies": { - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true - }, - "is-regex": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", - "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-symbols": "^1.0.2" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "isobject": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-4.0.0.tgz", - "integrity": "sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==", - "dev": true - } - } - }, "temp": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz", @@ -59075,7 +58184,7 @@ "temp-dir": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", - "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=", + "integrity": "sha512-xZFXEGbG7SNC3itwBzI3RYjq/cEhBkx2hJuKGIUOcEULmkQExXiHat2z/qkISYsuR+IKumhEfKKbV5qXmhICFQ==", "dev": true }, "terminal-link": { @@ -59440,12 +58549,6 @@ "repeat-string": "^1.6.1" } }, - "toggle-selection": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", - "integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI=", - "dev": true - }, "totalist": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz", @@ -59533,12 +58636,6 @@ "integrity": "sha512-riHuwnzAUCfdIeTBNUq7+Yj+ANnrMXo/7+Z74dIdudS7ys2k8aSGMzpJRMFDF7CLwUTbtvi1ZZff/Wl+XxmqIA==", "dev": true }, - "ts-essentials": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-2.0.12.tgz", - "integrity": "sha512-3IVX4nI6B5cc31/GFFE+i8ey/N2eA0CZDbo6n0yrz0zDX8ZJ8djmU1p+XRz7G3is0F3bB3pu2pAroFdAWQKU3w==", - "dev": true - }, "ts-pnp": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz", @@ -60183,30 +59280,6 @@ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" }, - "use-composed-ref": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.1.0.tgz", - "integrity": "sha512-my1lNHGWsSDAhhVAT4MKs6IjBUtG6ZG11uUqexPH9PptiIZDQOzaF4f5tEbJ2+7qvNbtXNBbU3SfmN+fXlWDhg==", - "dev": true, - "requires": { - "ts-essentials": "^2.0.3" - } - }, - "use-isomorphic-layout-effect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz", - "integrity": "sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ==", - "dev": true - }, - "use-latest": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.0.tgz", - "integrity": "sha512-d2TEuG6nSLKQLAfW3By8mKr8HurOlTkul0sOpxbClIv4SQ4iOd7BYr7VIzdbktUCnv7dua/60xzd8igMU6jmyw==", - "dev": true, - "requires": { - "use-isomorphic-layout-effect": "^1.0.0" - } - }, "use-lilius": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/use-lilius/-/use-lilius-2.0.1.tgz", @@ -60506,15 +59579,6 @@ "makeerror": "1.0.x" } }, - "warning": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", - "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, "watchpack": { "version": "1.7.5", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", diff --git a/package.json b/package.json index 7aec41677a0ab..43cd9d61c3f7b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gutenberg", - "version": "15.0.0-rc.1", + "version": "15.0.0", "private": true, "description": "A new WordPress editor experience.", "author": "The WordPress Contributors", @@ -105,7 +105,6 @@ "@storybook/addon-actions": "6.5.7", "@storybook/addon-controls": "6.5.7", "@storybook/addon-docs": "6.5.7", - "@storybook/addon-knobs": "6.2.9", "@storybook/addon-toolbars": "6.5.7", "@storybook/addon-viewport": "6.5.7", "@storybook/builder-webpack5": "6.5.7", diff --git a/packages/a11y/CHANGELOG.md b/packages/a11y/CHANGELOG.md index 86caff427ea23..e11684e90ca6a 100644 --- a/packages/a11y/CHANGELOG.md +++ b/packages/a11y/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.25.0 (2023-01-11) + ## 3.24.0 (2023-01-02) ## 3.23.0 (2022-12-14) diff --git a/packages/a11y/package.json b/packages/a11y/package.json index 0ac96681d151d..7190cb0ca02bd 100644 --- a/packages/a11y/package.json +++ b/packages/a11y/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/a11y", - "version": "3.24.0", + "version": "3.25.0", "description": "Accessibility (a11y) utilities for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/annotations/CHANGELOG.md b/packages/annotations/CHANGELOG.md index 64f7561229f61..60f179d24753a 100644 --- a/packages/annotations/CHANGELOG.md +++ b/packages/annotations/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 2.25.0 (2023-01-11) + ## 2.24.0 (2023-01-02) ## 2.23.0 (2022-12-14) diff --git a/packages/annotations/package.json b/packages/annotations/package.json index f9ad4fec99643..ab9b1f78b8cc9 100644 --- a/packages/annotations/package.json +++ b/packages/annotations/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/annotations", - "version": "2.24.0", + "version": "2.25.0", "description": "Annotate content in the Gutenberg editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/api-fetch/CHANGELOG.md b/packages/api-fetch/CHANGELOG.md index d1f1f674e5350..8d48d99d67f5b 100644 --- a/packages/api-fetch/CHANGELOG.md +++ b/packages/api-fetch/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 6.22.0 (2023-01-11) + ## 6.21.0 (2023-01-02) ## 6.20.0 (2022-12-14) diff --git a/packages/api-fetch/package.json b/packages/api-fetch/package.json index 2771a15b30282..d2fa74350a19a 100644 --- a/packages/api-fetch/package.json +++ b/packages/api-fetch/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/api-fetch", - "version": "6.21.0", + "version": "6.22.0", "description": "Utility to make WordPress REST API requests.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/autop/CHANGELOG.md b/packages/autop/CHANGELOG.md index 687feb89f5edd..52b85418a1f0b 100644 --- a/packages/autop/CHANGELOG.md +++ b/packages/autop/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.25.0 (2023-01-11) + ## 3.24.0 (2023-01-02) ## 3.23.0 (2022-12-14) diff --git a/packages/autop/package.json b/packages/autop/package.json index bcccc5d2a258a..0808d9a3d52d3 100644 --- a/packages/autop/package.json +++ b/packages/autop/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/autop", - "version": "3.24.0", + "version": "3.25.0", "description": "WordPress's automatic paragraph functions `autop` and `removep`.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/babel-plugin-import-jsx-pragma/CHANGELOG.md b/packages/babel-plugin-import-jsx-pragma/CHANGELOG.md index 67f2fbc0e360a..bde87838d2c2d 100644 --- a/packages/babel-plugin-import-jsx-pragma/CHANGELOG.md +++ b/packages/babel-plugin-import-jsx-pragma/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.8.0 (2023-01-11) + ## 4.7.0 (2023-01-02) ## 4.6.0 (2022-12-14) diff --git a/packages/babel-plugin-import-jsx-pragma/package.json b/packages/babel-plugin-import-jsx-pragma/package.json index 1349a5e0f2157..11a617e9e21b7 100644 --- a/packages/babel-plugin-import-jsx-pragma/package.json +++ b/packages/babel-plugin-import-jsx-pragma/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-plugin-import-jsx-pragma", - "version": "4.7.0", + "version": "4.8.0", "description": "Babel transform plugin for automatically injecting an import to be used as the pragma for the React JSX Transform plugin.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/babel-plugin-makepot/CHANGELOG.md b/packages/babel-plugin-makepot/CHANGELOG.md index 31025d83896f4..4ea7fc6a46686 100644 --- a/packages/babel-plugin-makepot/CHANGELOG.md +++ b/packages/babel-plugin-makepot/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 5.9.0 (2023-01-11) + ## 5.8.0 (2023-01-02) ## 5.7.0 (2022-12-14) diff --git a/packages/babel-plugin-makepot/package.json b/packages/babel-plugin-makepot/package.json index b3bebe6261b41..3a707c8da1ada 100644 --- a/packages/babel-plugin-makepot/package.json +++ b/packages/babel-plugin-makepot/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-plugin-makepot", - "version": "5.8.0", + "version": "5.9.0", "description": "WordPress Babel internationalization (i18n) plugin.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/babel-preset-default/CHANGELOG.md b/packages/babel-preset-default/CHANGELOG.md index 0662e856e4d37..de89008292f55 100644 --- a/packages/babel-preset-default/CHANGELOG.md +++ b/packages/babel-preset-default/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 7.9.0 (2023-01-11) + ## 7.8.0 (2023-01-02) ## 7.7.0 (2022-12-14) diff --git a/packages/babel-preset-default/package.json b/packages/babel-preset-default/package.json index 8f56582968bc5..6bafd04aa9195 100644 --- a/packages/babel-preset-default/package.json +++ b/packages/babel-preset-default/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/babel-preset-default", - "version": "7.8.0", + "version": "7.9.0", "description": "Default Babel preset for WordPress development.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/base-styles/CHANGELOG.md b/packages/base-styles/CHANGELOG.md index 1fe735ffe9b41..7686c47e6bd62 100644 --- a/packages/base-styles/CHANGELOG.md +++ b/packages/base-styles/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.16.0 (2023-01-11) + ## 4.15.0 (2023-01-02) ## 4.14.0 (2022-12-14) diff --git a/packages/base-styles/package.json b/packages/base-styles/package.json index cb1c248813064..3112841b6b106 100644 --- a/packages/base-styles/package.json +++ b/packages/base-styles/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/base-styles", - "version": "4.15.0", + "version": "4.16.0", "description": "Base SCSS utilities and variables for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/blob/CHANGELOG.md b/packages/blob/CHANGELOG.md index 927b4b6722233..136953e371145 100644 --- a/packages/blob/CHANGELOG.md +++ b/packages/blob/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.25.0 (2023-01-11) + ## 3.24.0 (2023-01-02) ## 3.23.0 (2022-12-14) diff --git a/packages/blob/package.json b/packages/blob/package.json index 49e059052a9c0..cef6487dc0dfc 100644 --- a/packages/blob/package.json +++ b/packages/blob/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/blob", - "version": "3.24.0", + "version": "3.25.0", "description": "Blob utilities for WordPress.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/blob/src/index.js b/packages/blob/src/index.js index 3af66755c011e..67a48e0003150 100644 --- a/packages/blob/src/index.js +++ b/packages/blob/src/index.js @@ -1,8 +1,3 @@ -/** - * Browser dependencies - */ -const { createObjectURL, revokeObjectURL } = window.URL; - /** * @type {Record} */ @@ -16,7 +11,7 @@ const cache = {}; * @return {string} The blob URL. */ export function createBlobURL( file ) { - const url = createObjectURL( file ); + const url = window.URL.createObjectURL( file ); cache[ url ] = file; @@ -56,7 +51,7 @@ export function getBlobTypeByURL( url ) { */ export function revokeBlobURL( url ) { if ( cache[ url ] ) { - revokeObjectURL( url ); + window.URL.revokeObjectURL( url ); } delete cache[ url ]; diff --git a/packages/block-directory/CHANGELOG.md b/packages/block-directory/CHANGELOG.md index 753de64194b23..5d55df809729d 100644 --- a/packages/block-directory/CHANGELOG.md +++ b/packages/block-directory/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 4.2.0 (2023-01-11) + ## 4.1.0 (2023-01-02) ## 4.0.0 (2022-12-14) diff --git a/packages/block-directory/package.json b/packages/block-directory/package.json index 7f982c2503ba8..43755eeafd5c0 100644 --- a/packages/block-directory/package.json +++ b/packages/block-directory/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-directory", - "version": "4.1.0", + "version": "4.2.0", "description": "Extend editor with block directory features to search, download and install blocks.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", diff --git a/packages/block-directory/src/components/downloadable-block-list-item/test/index.js b/packages/block-directory/src/components/downloadable-block-list-item/test/index.js index 3e22334aeb6a6..b1a6d10cf9673 100644 --- a/packages/block-directory/src/components/downloadable-block-list-item/test/index.js +++ b/packages/block-directory/src/components/downloadable-block-list-item/test/index.js @@ -15,8 +15,6 @@ import { useSelect } from '@wordpress/data'; import DownloadableBlockListItem from '../'; import { plugin } from '../../test/fixtures'; -jest.useFakeTimers(); - jest.mock( '@wordpress/data/src/components/use-select', () => { // This allows us to tweak the returned value on each test. const mock = jest.fn(); @@ -68,9 +66,7 @@ describe( 'DownloadableBlockListItem', () => { } ); it( 'should try to install the block plugin', async () => { - const user = userEvent.setup( { - advanceTimers: jest.advanceTimersByTime, - } ); + const user = userEvent.setup(); useSelect.mockImplementation( () => ( { isInstalling: false, diff --git a/packages/block-editor/CHANGELOG.md b/packages/block-editor/CHANGELOG.md index ff61da68ae832..370f123119cdc 100644 --- a/packages/block-editor/CHANGELOG.md +++ b/packages/block-editor/CHANGELOG.md @@ -2,10 +2,14 @@ ## Unreleased +## 11.2.0 (2023-01-11) + ### Bug Fix - `BlockInspector`: Fix browser warning error when block is not selected ([#46875](https://github.com/WordPress/gutenberg/pull/46875)). - Move component styles needed for iframes to content styles ([#47103](https://github.com/WordPress/gutenberg/pull/47103)). +- Block Inserter: Correctly apply style to the default inserter ([#47166](https://github.com/WordPress/gutenberg/pull/47166)). +- List View: Fix crash when the first template-parts is deleted width del key ([#47227](https://github.com/WordPress/gutenberg/pull/47227)). ## 11.1.0 (2023-01-02) diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md index 5a861eaa1acad..7ccac465a336a 100644 --- a/packages/block-editor/README.md +++ b/packages/block-editor/README.md @@ -348,6 +348,10 @@ _Returns_ Undocumented declaration. +### experiments + +Experimental @wordpress/block-editor APIs. + ### FontSizePicker _Related_ diff --git a/packages/block-editor/package.json b/packages/block-editor/package.json index 7673886369ab9..00e570a3fefc4 100644 --- a/packages/block-editor/package.json +++ b/packages/block-editor/package.json @@ -1,6 +1,6 @@ { "name": "@wordpress/block-editor", - "version": "11.1.0", + "version": "11.2.0", "description": "Generic block editor.", "author": "The WordPress Contributors", "license": "GPL-2.0-or-later", @@ -45,6 +45,7 @@ "@wordpress/dom": "file:../dom", "@wordpress/element": "file:../element", "@wordpress/escape-html": "file:../escape-html", + "@wordpress/experiments": "file:../experiments", "@wordpress/hooks": "file:../hooks", "@wordpress/html-entities": "file:../html-entities", "@wordpress/i18n": "file:../i18n", diff --git a/packages/block-editor/src/components/alignment-control/test/index.js b/packages/block-editor/src/components/alignment-control/test/index.js index 2383d6c952932..de72e92489be3 100644 --- a/packages/block-editor/src/components/alignment-control/test/index.js +++ b/packages/block-editor/src/components/alignment-control/test/index.js @@ -14,8 +14,6 @@ import { alignLeft, alignCenter } from '@wordpress/icons'; */ import AlignmentUI from '../ui'; -jest.useFakeTimers(); - describe( 'AlignmentUI', () => { const alignment = 'left'; const onChangeSpy = jest.fn(); @@ -50,9 +48,7 @@ describe( 'AlignmentUI', () => { } ); test( 'should expand controls when toggled', async () => { - const user = userEvent.setup( { - advanceTimers: jest.advanceTimersByTime, - } ); + const user = userEvent.setup(); const { unmount } = render( { } ); test( 'should call on change with undefined when a control is already active', async () => { - const user = userEvent.setup( { - advanceTimers: jest.advanceTimersByTime, - } ); + const user = userEvent.setup(); render( { } ); test( 'should call on change a new value when the control is not active', async () => { - const user = userEvent.setup( { - advanceTimers: jest.advanceTimersByTime, - } ); + const user = userEvent.setup(); render( { } ); test( 'should allow custom alignment controls to be specified', async () => { - const user = userEvent.setup( { - advanceTimers: jest.advanceTimersByTime, - } ); + const user = userEvent.setup(); const { container } = render( ( { ...completer } ) + ); } filteredCompleters = applyFilters( diff --git a/packages/block-editor/src/components/block-alignment-control/test/index.js b/packages/block-editor/src/components/block-alignment-control/test/index.js index 58846a04cd1c4..c8cd686e06954 100644 --- a/packages/block-editor/src/components/block-alignment-control/test/index.js +++ b/packages/block-editor/src/components/block-alignment-control/test/index.js @@ -9,8 +9,6 @@ import userEvent from '@testing-library/user-event'; */ import BlockAlignmentUI from '../ui'; -jest.useFakeTimers(); - describe( 'BlockAlignmentUI', () => { const alignment = 'left'; const onChange = jest.fn(); @@ -45,9 +43,7 @@ describe( 'BlockAlignmentUI', () => { } ); test( 'should expand controls when toggled', async () => { - const user = userEvent.setup( { - advanceTimers: jest.advanceTimersByTime, - } ); + const user = userEvent.setup(); const { unmount } = render( { } ); test( 'should call onChange with undefined, when the control is already active', async () => { - const user = userEvent.setup( { - advanceTimers: jest.advanceTimersByTime, - } ); + const user = userEvent.setup(); render( { } ); test( 'should call onChange with alignment value when the control is inactive', async () => { - const user = userEvent.setup( { - advanceTimers: jest.advanceTimersByTime, - } ); + const user = userEvent.setup(); render( - + { !! description && ( { description } diff --git a/packages/block-editor/src/components/block-pattern-setup/use-patterns-setup.js b/packages/block-editor/src/components/block-pattern-setup/use-patterns-setup.js index 1b6a90b87457a..1ad94c5385c6c 100644 --- a/packages/block-editor/src/components/block-pattern-setup/use-patterns-setup.js +++ b/packages/block-editor/src/components/block-pattern-setup/use-patterns-setup.js @@ -13,7 +13,7 @@ function usePatternsSetup( clientId, blockName, filterPatternsFn ) { ( select ) => { const { getBlockRootClientId, - __experimentalGetPatternsByBlockTypes, + getPatternsByBlockTypes, __experimentalGetAllowedPatterns, } = select( blockEditorStore ); const rootClientId = getBlockRootClientId( clientId ); @@ -22,10 +22,7 @@ function usePatternsSetup( clientId, blockName, filterPatternsFn ) { filterPatternsFn ); } - return __experimentalGetPatternsByBlockTypes( - blockName, - rootClientId - ); + return getPatternsByBlockTypes( blockName, rootClientId ); }, [ clientId, blockName, filterPatternsFn ] ); diff --git a/packages/block-editor/src/components/block-preview/README.md b/packages/block-editor/src/components/block-preview/README.md index 6ae8cfe97514a..5cce2e45cb54f 100644 --- a/packages/block-editor/src/components/block-preview/README.md +++ b/packages/block-editor/src/components/block-preview/README.md @@ -30,26 +30,26 @@ Width of the preview container in pixels. Controls at what size the blocks will Set `viewportWidth` to `0` to make the viewport the same width as the container. -### `__experimentalPadding` +### minHeight -- **Type** `Int` -- **Default** `undefined` +Minimum height of the preview iframe in pixels. -Padding for the preview container body. +- **Type:** `Int` +- **Default:** `undefined` -### `__experimentalStyles` +### `additionalStyles` List of additional editor styles to load into the preview iframe. Each object should contain a `css` attribute. See `EditorStyles` for more info. ```jsx ``` -- **Type** `Int` +- **Type** `Array` - **Default** `[]` diff --git a/packages/block-editor/src/components/block-preview/auto.js b/packages/block-editor/src/components/block-preview/auto.js index fb763ed466629..287bcd5b18566 100644 --- a/packages/block-editor/src/components/block-preview/auto.js +++ b/packages/block-editor/src/components/block-preview/auto.js @@ -23,9 +23,8 @@ const MAX_HEIGHT = 2000; function ScaledBlockPreview( { viewportWidth, containerWidth, - __experimentalPadding, - __experimentalMinHeight, - __experimentalStyles, + minHeight, + additionalStyles = [], } ) { if ( ! viewportWidth ) { viewportWidth = containerWidth; @@ -46,16 +45,16 @@ function ScaledBlockPreview( { if ( styles ) { return [ ...styles, - ...__experimentalStyles, { - css: 'body{height:auto;overflow:hidden;border:none;}', + css: 'body{height:auto;overflow:hidden;border:none;padding:0;}', __unstableType: 'presets', }, + ...additionalStyles, ]; } return styles; - }, [ styles, __experimentalStyles ] ); + }, [ styles, additionalStyles ] ); const svgFilters = useMemo( () => { return [ ...( duotone?.default ?? [] ), ...( duotone?.theme ?? [] ) ]; @@ -73,7 +72,7 @@ function ScaledBlockPreview( { height: contentHeight * scale, maxHeight: contentHeight > MAX_HEIGHT ? MAX_HEIGHT * scale : undefined, - minHeight: __experimentalMinHeight, + minHeight, } } >