diff --git a/lib/compat/wordpress-6.4/block-patterns.php b/lib/compat/wordpress-6.4/block-patterns.php index bbb910ff400d0..922dea910b47a 100644 --- a/lib/compat/wordpress-6.4/block-patterns.php +++ b/lib/compat/wordpress-6.4/block-patterns.php @@ -16,21 +16,20 @@ */ function gutenberg_register_taxonomy_patterns() { $args = array( - 'public' => true, - 'publicly_queryable' => false, - 'hierarchical' => false, - 'labels' => array( + 'public' => true, + 'publicly_queryable' => false, + 'hierarchical' => false, + 'labels' => array( 'name' => _x( 'Pattern Categories', 'taxonomy general name' ), 'singular_name' => _x( 'Pattern Category', 'taxonomy singular name' ), ), - 'query_var' => false, - 'rewrite' => false, - 'show_ui' => true, - '_builtin' => true, - 'show_in_nav_menus' => false, - 'show_in_rest' => true, - 'show_admin_column' => true, - 'rest_controller_class' => 'Gutenberg_REST_Pattern_Categories_Controller', + 'query_var' => false, + 'rewrite' => false, + 'show_ui' => true, + '_builtin' => true, + 'show_in_nav_menus' => false, + 'show_in_rest' => true, + 'show_admin_column' => true, ); register_taxonomy( 'wp_pattern_category', array( 'wp_block' ), $args ); } diff --git a/lib/compat/wordpress-6.4/blocks.php b/lib/compat/wordpress-6.4/blocks.php index 073302dbab65f..74fa9253e45d5 100644 --- a/lib/compat/wordpress-6.4/blocks.php +++ b/lib/compat/wordpress-6.4/blocks.php @@ -21,27 +21,3 @@ function gutenberg_add_custom_capabilities_to_wp_block( $args ) { return $args; } add_filter( 'register_wp_block_post_type_args', 'gutenberg_add_custom_capabilities_to_wp_block', 10, 1 ); - -/** - * Updates the wp_block REST enpoint in order to modify the wp_pattern_category action - * links that are returned because as although the taxonomy is flat Author level users - * are only allowed to assign categories. - * - * Note: This should be removed when the minimum required WP version is >= 6.4. - * - * @see https://github.com/WordPress/gutenberg/pull/55379 - * - * @param array $args Register post type args. - * @param string $post_type The post type string. - * - * @return array Register post type args. - */ -function gutenberg_update_patterns_block_rest_controller_class( $args, $post_type ) { - if ( 'wp_block' === $post_type ) { - $args['rest_controller_class'] = 'Gutenberg_REST_Blocks_Controller_6_4'; - } - - return $args; -} - -add_filter( 'register_post_type_args', 'gutenberg_update_patterns_block_rest_controller_class', 11, 2 ); diff --git a/lib/compat/wordpress-6.4/class-gutenberg-rest-blocks-controller-6-4.php b/lib/compat/wordpress-6.4/class-gutenberg-rest-blocks-controller-6-4.php deleted file mode 100644 index bc91492e26979..0000000000000 --- a/lib/compat/wordpress-6.4/class-gutenberg-rest-blocks-controller-6-4.php +++ /dev/null @@ -1,75 +0,0 @@ -post_type ); - - if ( 'attachment' !== $this->post_type && current_user_can( $post_type->cap->publish_posts ) ) { - $rels[] = 'https://api.w.org/action-publish'; - } - - if ( current_user_can( 'unfiltered_html' ) ) { - $rels[] = 'https://api.w.org/action-unfiltered-html'; - } - - if ( 'post' === $post_type->name ) { - if ( current_user_can( $post_type->cap->edit_others_posts ) && current_user_can( $post_type->cap->publish_posts ) ) { - $rels[] = 'https://api.w.org/action-sticky'; - } - } - - if ( post_type_supports( $post_type->name, 'author' ) ) { - if ( current_user_can( $post_type->cap->edit_others_posts ) ) { - $rels[] = 'https://api.w.org/action-assign-author'; - } - } - - $taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) ); - - foreach ( $taxonomies as $tax ) { - $tax_base = ! empty( $tax->rest_base ) ? $tax->rest_base : $tax->name; - - if ( current_user_can( $tax->cap->edit_terms ) ) { - $rels[] = 'https://api.w.org/action-create-' . $tax_base; - } - - if ( current_user_can( $tax->cap->assign_terms ) ) { - $rels[] = 'https://api.w.org/action-assign-' . $tax_base; - } - } - - return $rels; - } -} diff --git a/lib/compat/wordpress-6.4/class-gutenberg-rest-pattern-categories-controller.php b/lib/compat/wordpress-6.4/class-gutenberg-rest-pattern-categories-controller.php deleted file mode 100644 index e249d67e8acaa..0000000000000 --- a/lib/compat/wordpress-6.4/class-gutenberg-rest-pattern-categories-controller.php +++ /dev/null @@ -1,45 +0,0 @@ -check_is_taxonomy_allowed( $this->taxonomy ) ) { - return false; - } - - $taxonomy_obj = get_taxonomy( $this->taxonomy ); - - // Patterns categories are a flat hierarchy (like tags), but work more like post categories in terms of permissions. - if ( ! current_user_can( $taxonomy_obj->cap->edit_terms ) ) { - return new WP_Error( - 'rest_cannot_create', - __( 'Sorry, you are not allowed to create terms in this taxonomy.' ), - array( 'status' => rest_authorization_required_code() ) - ); - } - - return true; - } -} diff --git a/lib/load.php b/lib/load.php index 381248e0f44bf..2b178af5fb9bf 100644 --- a/lib/load.php +++ b/lib/load.php @@ -53,8 +53,6 @@ function gutenberg_is_experiment_enabled( $name ) { // WordPress 6.4 compat. require_once __DIR__ . '/compat/wordpress-6.4/class-gutenberg-rest-global-styles-revisions-controller-6-4.php'; require_once __DIR__ . '/compat/wordpress-6.4/class-gutenberg-rest-block-patterns-controller.php'; - require_once __DIR__ . '/compat/wordpress-6.4/class-gutenberg-rest-blocks-controller-6-4.php'; - require_once __DIR__ . '/compat/wordpress-6.4/class-gutenberg-rest-pattern-categories-controller.php'; require_once __DIR__ . '/compat/wordpress-6.4/rest-api.php'; require_once __DIR__ . '/compat/wordpress-6.4/theme-previews.php'; diff --git a/package-lock.json b/package-lock.json index ed33a0a19a48e..7603e03b936bf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46332,6 +46332,14 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, + "node_modules/postcss-prefixwrap": { + "version": "1.41.0", + "resolved": "https://registry.npmjs.org/postcss-prefixwrap/-/postcss-prefixwrap-1.41.0.tgz", + "integrity": "sha512-gmwwAEE+ci3/ZKjUZppTETINlh1QwihY8gCstInuS7ohk353KYItU4d64hvnUvO2GUy29hBGPHz4Ce+qJRi90A==", + "peerDependencies": { + "postcss": "*" + } + }, "node_modules/postcss-reduce-initial": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.0.0.tgz", @@ -46441,6 +46449,22 @@ "postcss": "^8.2.15" } }, + "node_modules/postcss-urlrebase": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/postcss-urlrebase/-/postcss-urlrebase-1.3.0.tgz", + "integrity": "sha512-LOFN43n1IewKriXiypMNNinXeptttSyGGRLPbBMdQzuTvvCEo5mz/gG06y/HqrkN7p3ayHQf2R2bTBv639FOaQ==", + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "peerDependencies": { + "postcss": "^8.3.0" + } + }, + "node_modules/postcss-urlrebase/node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, "node_modules/postcss-value-parser": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", @@ -52850,11 +52874,6 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "dev": true }, - "node_modules/traverse": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", - "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=" - }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -56066,13 +56085,14 @@ "diff": "^4.0.2", "dom-scroll-into-view": "^1.2.1", "fast-deep-equal": "^3.1.3", - "inherits": "^2.0.3", "memize": "^2.1.0", + "postcss": "^8.4.21", + "postcss-prefixwrap": "^1.41.0", + "postcss-urlrebase": "^1.0.0", "react-autosize-textarea": "^7.1.0", "react-easy-crop": "^4.5.1", "rememo": "^4.0.2", - "remove-accents": "^0.5.0", - "traverse": "^0.6.6" + "remove-accents": "^0.5.0" }, "engines": { "node": ">=12" @@ -56082,6 +56102,41 @@ "react-dom": "^18.0.0" } }, + "packages/block-editor/node_modules/postcss": { + "version": "8.4.30", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.30.tgz", + "integrity": "sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "packages/block-editor/node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, "packages/block-library": { "name": "@wordpress/block-library", "version": "8.21.0", @@ -69479,13 +69534,31 @@ "diff": "^4.0.2", "dom-scroll-into-view": "^1.2.1", "fast-deep-equal": "^3.1.3", - "inherits": "^2.0.3", "memize": "^2.1.0", + "postcss": "^8.4.21", + "postcss-prefixwrap": "^1.41.0", + "postcss-urlrebase": "^1.0.0", "react-autosize-textarea": "^7.1.0", "react-easy-crop": "^4.5.1", "rememo": "^4.0.2", - "remove-accents": "^0.5.0", - "traverse": "^0.6.6" + "remove-accents": "^0.5.0" + }, + "dependencies": { + "postcss": { + "version": "8.4.30", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.30.tgz", + "integrity": "sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g==", + "requires": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + } } }, "@wordpress/block-library": { @@ -95672,6 +95745,11 @@ } } }, + "postcss-prefixwrap": { + "version": "1.41.0", + "resolved": "https://registry.npmjs.org/postcss-prefixwrap/-/postcss-prefixwrap-1.41.0.tgz", + "integrity": "sha512-gmwwAEE+ci3/ZKjUZppTETINlh1QwihY8gCstInuS7ohk353KYItU4d64hvnUvO2GUy29hBGPHz4Ce+qJRi90A==" + }, "postcss-reduce-initial": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.0.0.tgz", @@ -95748,6 +95826,21 @@ "postcss-selector-parser": "^6.0.5" } }, + "postcss-urlrebase": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/postcss-urlrebase/-/postcss-urlrebase-1.3.0.tgz", + "integrity": "sha512-LOFN43n1IewKriXiypMNNinXeptttSyGGRLPbBMdQzuTvvCEo5mz/gG06y/HqrkN7p3ayHQf2R2bTBv639FOaQ==", + "requires": { + "postcss-value-parser": "^4.2.0" + }, + "dependencies": { + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + } + } + }, "postcss-value-parser": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", @@ -100640,11 +100733,6 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "dev": true }, - "traverse": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", - "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=" - }, "tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", diff --git a/packages/base-styles/_mixins.scss b/packages/base-styles/_mixins.scss index b621c34551da5..b988c0499f1fb 100644 --- a/packages/base-styles/_mixins.scss +++ b/packages/base-styles/_mixins.scss @@ -64,7 +64,7 @@ */ @mixin block-toolbar-button-style__focus() { - box-shadow: inset 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color), inset 0 0 0 4px $white; + box-shadow: inset 0 0 0 $border-width var(--wp-components-color-background, $white), 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9)); // Windows High Contrast mode will show this outline, but not the box-shadow. outline: 2px solid transparent; diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md index 02671d5dca0e3..9c7a72f089714 100644 --- a/packages/block-editor/README.md +++ b/packages/block-editor/README.md @@ -789,13 +789,23 @@ Applies a series of CSS rule transforms to wrap selectors inside a given class a _Parameters_ -- _styles_ `Object|Array`: CSS rules. -- _wrapperClassName_ `string`: Wrapper Class Name. +- _styles_ `EditorStyle[]`: CSS rules. +- _wrapperSelector_ `string`: Wrapper selector. _Returns_ - `Array`: converted rules. +_Type Definition_ + +- _EditorStyle_ `Object` + +_Properties_ + +- _css_ `string`: the CSS block(s), as a single string. +- _baseURL_ `?string`: the base URL to be used as the reference when rewritting urls. +- _ignoredSelectors_ `?string[]`: the selectors not to wrap. + ### Typewriter Ensures that the text selection keeps the same vertical distance from the viewport during keyboard events within this component. The vertical distance can vary. It is the last clicked or scrolled to position. diff --git a/packages/block-editor/package.json b/packages/block-editor/package.json index 225d9c987638a..5abf843b85f51 100644 --- a/packages/block-editor/package.json +++ b/packages/block-editor/package.json @@ -71,13 +71,14 @@ "diff": "^4.0.2", "dom-scroll-into-view": "^1.2.1", "fast-deep-equal": "^3.1.3", - "inherits": "^2.0.3", "memize": "^2.1.0", + "postcss": "^8.4.21", + "postcss-prefixwrap": "^1.41.0", + "postcss-urlrebase": "^1.0.0", "react-autosize-textarea": "^7.1.0", "react-easy-crop": "^4.5.1", "rememo": "^4.0.2", - "remove-accents": "^0.5.0", - "traverse": "^0.6.6" + "remove-accents": "^0.5.0" }, "peerDependencies": { "react": "^18.0.0", diff --git a/packages/block-editor/src/components/block-styles/style.scss b/packages/block-editor/src/components/block-styles/style.scss index 9e80e93b0cd64..ab2a4b0c9ac98 100644 --- a/packages/block-editor/src/components/block-styles/style.scss +++ b/packages/block-editor/src/components/block-styles/style.scss @@ -58,7 +58,7 @@ &:focus, &.is-active:focus { - box-shadow: inset 0 0 0 $border-width var(--wp-components-color-background, #fff), 0 0 0 var(--wp-admin-border-width-focus) var(--wp-components-color-accent, var(--wp-admin-theme-color, #3858e9)); + @include block-toolbar-button-style__focus(); } } diff --git a/packages/block-editor/src/utils/test/__snapshots__/transform-styles.js.snap b/packages/block-editor/src/utils/test/__snapshots__/transform-styles.js.snap new file mode 100644 index 0000000000000..28c4202f414a9 --- /dev/null +++ b/packages/block-editor/src/utils/test/__snapshots__/transform-styles.js.snap @@ -0,0 +1,103 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`transformStyles URL rewrite should not replace absolute paths 1`] = ` +[ + "h1 { background: url(/images/test.png); }", +] +`; + +exports[`transformStyles URL rewrite should not replace remote paths 1`] = ` +[ + "h1 { background: url(http://wp.org/images/test.png); }", +] +`; + +exports[`transformStyles URL rewrite should replace complex relative paths 1`] = ` +[ + "h1 { background: url(http://wp-site.local/themes/gut/images/test.png); }", +] +`; + +exports[`transformStyles URL rewrite should rewrite relative paths 1`] = ` +[ + "h1 { background: url(http://wp-site.local/themes/gut/css/images/test.png); }", +] +`; + +exports[`transformStyles selector wrap should ignore font-face selectors 1`] = ` +[ + " + @font-face { + font-family: myFirstFont; + src: url(sansation_light.woff); + }", +] +`; + +exports[`transformStyles selector wrap should ignore keyframes 1`] = ` +[ + " + @keyframes edit-post__fade-in-animation { + from { + opacity: 0; + } + }", +] +`; + +exports[`transformStyles selector wrap should ignore selectors 1`] = ` +[ + ".my-namespace h1, body { color: red; }", +] +`; + +exports[`transformStyles selector wrap should not double wrap selectors 1`] = ` +[ + " .my-namespace h1, .my-namespace .red { color: red; }", +] +`; + +exports[`transformStyles selector wrap should replace :root selectors 1`] = ` +[ + " + .my-namespace { + --my-color: #ff0000; + }", +] +`; + +exports[`transformStyles selector wrap should replace root tags 1`] = ` +[ + ".my-namespace, .my-namespace h1 { color: red; }", +] +`; + +exports[`transformStyles selector wrap should wrap multiple selectors 1`] = ` +[ + ".my-namespace h1, .my-namespace h2 { color: red; }", +] +`; + +exports[`transformStyles selector wrap should wrap regular selectors 1`] = ` +[ + ".my-namespace h1 { color: red; }", +] +`; + +exports[`transformStyles selector wrap should wrap selectors inside container queries 1`] = ` +[ + " + @container (width > 400px) { + .my-namespace h1 { color: red; } + }", +] +`; + +exports[`transformStyles should not break with data urls 1`] = ` +[ + ".wp-block-group { + background-image: url("data:image/svg+xml,%3Csvg%3E.b%7Bclip-path:url(test);%7D%3C/svg%3E"); + color: red !important; + }", +] +`; diff --git a/packages/block-editor/src/utils/test/transform-styles.js b/packages/block-editor/src/utils/test/transform-styles.js new file mode 100644 index 0000000000000..f162a0b2f6048 --- /dev/null +++ b/packages/block-editor/src/utils/test/transform-styles.js @@ -0,0 +1,217 @@ +/** + * Internal dependencies + */ +import transformStyles from '../transform-styles'; + +describe( 'transformStyles', () => { + describe( 'selector wrap', () => { + it( 'should wrap regular selectors', () => { + const input = `h1 { color: red; }`; + const output = transformStyles( + [ + { + css: input, + }, + ], + '.my-namespace' + ); + + expect( output ).toMatchSnapshot(); + } ); + + it( 'should wrap multiple selectors', () => { + const input = `h1, h2 { color: red; }`; + const output = transformStyles( + [ + { + css: input, + }, + ], + '.my-namespace' + ); + + expect( output ).toMatchSnapshot(); + } ); + + it( 'should ignore selectors', () => { + const input = `h1, body { color: red; }`; + const output = transformStyles( + [ + { + css: input, + ignoredSelectors: [ 'body' ], + }, + ], + '.my-namespace' + ); + + expect( output ).toMatchSnapshot(); + } ); + + it( 'should replace root tags', () => { + const input = `body, h1 { color: red; }`; + const output = transformStyles( + [ + { + css: input, + }, + ], + '.my-namespace' + ); + + expect( output ).toMatchSnapshot(); + } ); + + it( 'should ignore keyframes', () => { + const input = ` + @keyframes edit-post__fade-in-animation { + from { + opacity: 0; + } + }`; + const output = transformStyles( + [ + { + css: input, + }, + ], + '.my-namespace' + ); + + expect( output ).toMatchSnapshot(); + } ); + + it( 'should wrap selectors inside container queries', () => { + const input = ` + @container (width > 400px) { + h1 { color: red; } + }`; + const output = transformStyles( + [ + { + css: input, + }, + ], + '.my-namespace' + ); + + expect( output ).toMatchSnapshot(); + } ); + + it( 'should ignore font-face selectors', () => { + const input = ` + @font-face { + font-family: myFirstFont; + src: url(sansation_light.woff); + }`; + const output = transformStyles( + [ + { + css: input, + }, + ], + '.my-namespace' + ); + + expect( output ).toMatchSnapshot(); + } ); + + it( 'should replace :root selectors', () => { + const input = ` + :root { + --my-color: #ff0000; + }`; + const output = transformStyles( + [ + { + css: input, + }, + ], + '.my-namespace' + ); + + expect( output ).toMatchSnapshot(); + } ); + + it( 'should not double wrap selectors', () => { + const input = ` .my-namespace h1, .red { color: red; }`; + + const output = transformStyles( + [ + { + css: input, + }, + ], + '.my-namespace' + ); + + expect( output ).toMatchSnapshot(); + } ); + } ); + + it( 'should not break with data urls', () => { + const input = `.wp-block-group { + background-image: url("data:image/svg+xml,%3Csvg%3E.b%7Bclip-path:url(test);%7D%3C/svg%3E"); + color: red !important; + }`; + + const output = transformStyles( [ + { + css: input, + baseURL: 'http://wp-site.local/themes/gut/css/', + }, + ] ); + + expect( output ).toMatchSnapshot(); + } ); + + describe( 'URL rewrite', () => { + it( 'should rewrite relative paths', () => { + const input = `h1 { background: url(images/test.png); }`; + const output = transformStyles( [ + { + css: input, + baseURL: 'http://wp-site.local/themes/gut/css/', + }, + ] ); + + expect( output ).toMatchSnapshot(); + } ); + + it( 'should replace complex relative paths', () => { + const input = `h1 { background: url(../images/test.png); }`; + const output = transformStyles( [ + { + css: input, + baseURL: 'http://wp-site.local/themes/gut/css/', + }, + ] ); + + expect( output ).toMatchSnapshot(); + } ); + + it( 'should not replace absolute paths', () => { + const input = `h1 { background: url(/images/test.png); }`; + const output = transformStyles( [ + { + css: input, + baseURL: 'http://wp-site.local/themes/gut/css/', + }, + ] ); + + expect( output ).toMatchSnapshot(); + } ); + + it( 'should not replace remote paths', () => { + const input = `h1 { background: url(http://wp.org/images/test.png); }`; + const output = transformStyles( [ + { + css: input, + baseURL: 'http://wp-site.local/themes/gut/css/', + }, + ] ); + + expect( output ).toMatchSnapshot(); + } ); + } ); +} ); diff --git a/packages/block-editor/src/utils/transform-styles/ast/index.js b/packages/block-editor/src/utils/transform-styles/ast/index.js deleted file mode 100644 index b4dc1de499f47..0000000000000 --- a/packages/block-editor/src/utils/transform-styles/ast/index.js +++ /dev/null @@ -1,5 +0,0 @@ -// Adapted from https://github.com/reworkcss/css -// because we needed to remove source map support. - -export { default as parse } from './parse'; -export { default as stringify } from './stringify'; diff --git a/packages/block-editor/src/utils/transform-styles/ast/parse.js b/packages/block-editor/src/utils/transform-styles/ast/parse.js deleted file mode 100644 index 8f7d227d61442..0000000000000 --- a/packages/block-editor/src/utils/transform-styles/ast/parse.js +++ /dev/null @@ -1,732 +0,0 @@ -/* eslint-disable @wordpress/no-unused-vars-before-return */ - -// Adapted from https://github.com/reworkcss/css -// because we needed to remove source map support. - -// http://www.w3.org/TR/CSS21/grammar.htm -// https://github.com/visionmedia/css-parse/pull/49#issuecomment-30088027 -const commentre = /\/\*[^*]*\*+([^/*][^*]*\*+)*\//g; - -export default function ( css, options ) { - options = options || {}; - - /** - * Positional. - */ - - let lineno = 1; - let column = 1; - - /** - * Update lineno and column based on `str`. - */ - - function updatePosition( str ) { - const lines = str.match( /\n/g ); - if ( lines ) { - lineno += lines.length; - } - const i = str.lastIndexOf( '\n' ); - // eslint-disable-next-line no-bitwise - column = ~i ? str.length - i : column + str.length; - } - - /** - * Mark position and patch `node.position`. - */ - - function position() { - const start = { line: lineno, column }; - return function ( node ) { - node.position = new Position( start ); - whitespace(); - return node; - }; - } - - /** - * Store position information for a node - */ - - function Position( start ) { - this.start = start; - this.end = { line: lineno, column }; - this.source = options.source; - } - - /** - * Non-enumerable source string - */ - - Position.prototype.content = css; - - /** - * Error `msg`. - */ - - const errorsList = []; - - function error( msg ) { - const err = new Error( - options.source + ':' + lineno + ':' + column + ': ' + msg - ); - err.reason = msg; - err.filename = options.source; - err.line = lineno; - err.column = column; - err.source = css; - - if ( options.silent ) { - errorsList.push( err ); - } else { - throw err; - } - } - - /** - * Parse stylesheet. - */ - - function stylesheet() { - const rulesList = rules(); - - return { - type: 'stylesheet', - stylesheet: { - source: options.source, - rules: rulesList, - parsingErrors: errorsList, - }, - }; - } - - /** - * Opening brace. - */ - - function open() { - return match( /^{\s*/ ); - } - - /** - * Closing brace. - */ - - function close() { - return match( /^}/ ); - } - - /** - * Parse ruleset. - */ - - function rules() { - let node; - const accumulator = []; - whitespace(); - comments( accumulator ); - while ( - css.length && - css.charAt( 0 ) !== '}' && - ( node = atrule() || rule() ) - ) { - if ( node !== false ) { - accumulator.push( node ); - comments( accumulator ); - } - } - return accumulator; - } - - /** - * Match `re` and return captures. - */ - - function match( re ) { - const m = re.exec( css ); - if ( ! m ) { - return; - } - const str = m[ 0 ]; - updatePosition( str ); - css = css.slice( str.length ); - return m; - } - - /** - * Parse whitespace. - */ - - function whitespace() { - match( /^\s*/ ); - } - - /** - * Parse comments; - */ - - function comments( accumulator ) { - let c; - accumulator = accumulator || []; - // eslint-disable-next-line no-cond-assign - while ( ( c = comment() ) ) { - if ( c !== false ) { - accumulator.push( c ); - } - } - return accumulator; - } - - /** - * Parse comment. - */ - - function comment() { - const pos = position(); - if ( '/' !== css.charAt( 0 ) || '*' !== css.charAt( 1 ) ) { - return; - } - - let i = 2; - while ( - '' !== css.charAt( i ) && - ( '*' !== css.charAt( i ) || '/' !== css.charAt( i + 1 ) ) - ) { - ++i; - } - i += 2; - - if ( '' === css.charAt( i - 1 ) ) { - return error( 'End of comment missing' ); - } - - const str = css.slice( 2, i - 2 ); - column += 2; - updatePosition( str ); - css = css.slice( i ); - column += 2; - - return pos( { - type: 'comment', - comment: str, - } ); - } - - /** - * Parse selector. - */ - - function selector() { - const m = match( /^([^{]+)/ ); - if ( ! m ) { - return; - } - // FIXME: Remove all comments from selectors http://ostermiller.org/findcomment.html - return trim( m[ 0 ] ) - .replace( /\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*\/+/g, '' ) - .replace( /"(?:\\"|[^"])*"|'(?:\\'|[^'])*'/g, function ( matched ) { - return matched.replace( /,/g, '\u200C' ); - } ) - .split( /\s*(?![^(]*\)),\s*/ ) - .map( function ( s ) { - return s.replace( /\u200C/g, ',' ); - } ); - } - - /** - * Parse declaration. - */ - - function declaration() { - const pos = position(); - - // prop. - let prop = match( /^(\*?[-#\/\*\\\w]+(\[[0-9a-z_-]+\])?)\s*/ ); - if ( ! prop ) { - return; - } - prop = trim( prop[ 0 ] ); - - // : - if ( ! match( /^:\s*/ ) ) { - return error( "property missing ':'" ); - } - - // val. - const val = match( - /^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+)/ - ); - - const ret = pos( { - type: 'declaration', - property: prop.replace( commentre, '' ), - value: val ? trim( val[ 0 ] ).replace( commentre, '' ) : '', - } ); - - // ; - match( /^[;\s]*/ ); - - return ret; - } - - /** - * Parse declarations. - */ - - function declarations() { - const decls = []; - - if ( ! open() ) { - return error( "missing '{'" ); - } - comments( decls ); - - // declarations. - let decl; - // eslint-disable-next-line no-cond-assign - while ( ( decl = declaration() ) ) { - if ( decl !== false ) { - decls.push( decl ); - comments( decls ); - } - } - - if ( ! close() ) { - return error( "missing '}'" ); - } - return decls; - } - - /** - * Parse keyframe. - */ - - function keyframe() { - let m; - const vals = []; - const pos = position(); - - // eslint-disable-next-line no-cond-assign - while ( ( m = match( /^((\d+\.\d+|\.\d+|\d+)%?|[a-z]+)\s*/ ) ) ) { - vals.push( m[ 1 ] ); - match( /^,\s*/ ); - } - - if ( ! vals.length ) { - return; - } - - return pos( { - type: 'keyframe', - values: vals, - declarations: declarations(), - } ); - } - - /** - * Parse keyframes. - */ - - function atkeyframes() { - const pos = position(); - let m = match( /^@([-\w]+)?keyframes\s*/ ); - - if ( ! m ) { - return; - } - const vendor = m[ 1 ]; - - // identifier - m = match( /^([-\w]+)\s*/ ); - if ( ! m ) { - return error( '@keyframes missing name' ); - } - const name = m[ 1 ]; - - if ( ! open() ) { - return error( "@keyframes missing '{'" ); - } - - let frame; - let frames = comments(); - // eslint-disable-next-line no-cond-assign - while ( ( frame = keyframe() ) ) { - frames.push( frame ); - frames = frames.concat( comments() ); - } - - if ( ! close() ) { - return error( "@keyframes missing '}'" ); - } - - return pos( { - type: 'keyframes', - name, - vendor, - keyframes: frames, - } ); - } - - /** - * Parse supports. - */ - - function atsupports() { - const pos = position(); - const m = match( /^@supports *([^{]+)/ ); - - if ( ! m ) { - return; - } - const supports = trim( m[ 1 ] ); - - if ( ! open() ) { - return error( "@supports missing '{'" ); - } - - const style = comments().concat( rules() ); - - if ( ! close() ) { - return error( "@supports missing '}'" ); - } - - return pos( { - type: 'supports', - supports, - rules: style, - } ); - } - - /** - * Parse host. - */ - - function athost() { - const pos = position(); - const m = match( /^@host\s*/ ); - - if ( ! m ) { - return; - } - - if ( ! open() ) { - return error( "@host missing '{'" ); - } - - const style = comments().concat( rules() ); - - if ( ! close() ) { - return error( "@host missing '}'" ); - } - - return pos( { - type: 'host', - rules: style, - } ); - } - - /** - * Parse media. - */ - - function atmedia() { - const pos = position(); - const m = match( /^@media *([^{]+)/ ); - - if ( ! m ) { - return; - } - const media = trim( m[ 1 ] ); - - if ( ! open() ) { - return error( "@media missing '{'" ); - } - - const style = comments().concat( rules() ); - - if ( ! close() ) { - return error( "@media missing '}'" ); - } - - return pos( { - type: 'media', - media, - rules: style, - } ); - } - - /** - * Parse container. - */ - - function atcontainer() { - const pos = position(); - const m = match( /^@container *([^{]+)/ ); - - if ( ! m ) { - return; - } - const container = trim( m[ 1 ] ); - - if ( ! open() ) { - return error( "@container missing '{'" ); - } - - const style = comments().concat( rules() ); - - if ( ! close() ) { - return error( "@container missing '}'" ); - } - - return pos( { - type: 'container', - container, - rules: style, - } ); - } - - /** - * Parse custom-media. - */ - - function atcustommedia() { - const pos = position(); - const m = match( /^@custom-media\s+(--[^\s]+)\s*([^{;]+);/ ); - if ( ! m ) { - return; - } - - return pos( { - type: 'custom-media', - name: trim( m[ 1 ] ), - media: trim( m[ 2 ] ), - } ); - } - - /** - * Parse paged media. - */ - - function atpage() { - const pos = position(); - const m = match( /^@page */ ); - if ( ! m ) { - return; - } - - const sel = selector() || []; - - if ( ! open() ) { - return error( "@page missing '{'" ); - } - let decls = comments(); - - // declarations. - let decl; - // eslint-disable-next-line no-cond-assign - while ( ( decl = declaration() ) ) { - decls.push( decl ); - decls = decls.concat( comments() ); - } - - if ( ! close() ) { - return error( "@page missing '}'" ); - } - - return pos( { - type: 'page', - selectors: sel, - declarations: decls, - } ); - } - - /** - * Parse document. - */ - - function atdocument() { - const pos = position(); - const m = match( /^@([-\w]+)?document *([^{]+)/ ); - if ( ! m ) { - return; - } - - const vendor = trim( m[ 1 ] ); - const doc = trim( m[ 2 ] ); - - if ( ! open() ) { - return error( "@document missing '{'" ); - } - - const style = comments().concat( rules() ); - - if ( ! close() ) { - return error( "@document missing '}'" ); - } - - return pos( { - type: 'document', - document: doc, - vendor, - rules: style, - } ); - } - - /** - * Parse font-face. - */ - - function atfontface() { - const pos = position(); - const m = match( /^@font-face\s*/ ); - if ( ! m ) { - return; - } - - if ( ! open() ) { - return error( "@font-face missing '{'" ); - } - let decls = comments(); - - // declarations. - let decl; - // eslint-disable-next-line no-cond-assign - while ( ( decl = declaration() ) ) { - decls.push( decl ); - decls = decls.concat( comments() ); - } - - if ( ! close() ) { - return error( "@font-face missing '}'" ); - } - - return pos( { - type: 'font-face', - declarations: decls, - } ); - } - - /** - * Parse import - */ - - const atimport = _compileAtrule( 'import' ); - - /** - * Parse charset - */ - - const atcharset = _compileAtrule( 'charset' ); - - /** - * Parse namespace - */ - - const atnamespace = _compileAtrule( 'namespace' ); - - /** - * Parse non-block at-rules - */ - - function _compileAtrule( name ) { - const re = new RegExp( '^@' + name + '\\s*([^;]+);' ); - return function () { - const pos = position(); - const m = match( re ); - if ( ! m ) { - return; - } - const ret = { type: name }; - ret[ name ] = m[ 1 ].trim(); - return pos( ret ); - }; - } - - /** - * Parse at rule. - */ - - function atrule() { - if ( css[ 0 ] !== '@' ) { - return; - } - - return ( - atkeyframes() || - atmedia() || - atcontainer() || - atcustommedia() || - atsupports() || - atimport() || - atcharset() || - atnamespace() || - atdocument() || - atpage() || - athost() || - atfontface() - ); - } - - /** - * Parse rule. - */ - - function rule() { - const pos = position(); - const sel = selector(); - - if ( ! sel ) { - return error( 'selector missing' ); - } - comments(); - - return pos( { - type: 'rule', - selectors: sel, - declarations: declarations(), - } ); - } - - return addParent( stylesheet() ); -} - -/** - * Trim `str`. - */ - -function trim( str ) { - return str ? str.replace( /^\s+|\s+$/g, '' ) : ''; -} - -/** - * Adds non-enumerable parent node reference to each node. - */ - -function addParent( obj, parent ) { - const isNode = obj && typeof obj.type === 'string'; - const childParent = isNode ? obj : parent; - - for ( const k in obj ) { - const value = obj[ k ]; - if ( Array.isArray( value ) ) { - value.forEach( function ( v ) { - addParent( v, childParent ); - } ); - } else if ( value && typeof value === 'object' ) { - addParent( value, childParent ); - } - } - - if ( isNode ) { - Object.defineProperty( obj, 'parent', { - configurable: true, - writable: true, - enumerable: false, - value: parent || null, - } ); - } - - return obj; -} - -/* eslint-enable @wordpress/no-unused-vars-before-return */ diff --git a/packages/block-editor/src/utils/transform-styles/ast/stringify/compiler.js b/packages/block-editor/src/utils/transform-styles/ast/stringify/compiler.js deleted file mode 100644 index d2500b730424f..0000000000000 --- a/packages/block-editor/src/utils/transform-styles/ast/stringify/compiler.js +++ /dev/null @@ -1,50 +0,0 @@ -// Adapted from https://github.com/reworkcss/css -// because we needed to remove source map support. - -/** - * Expose `Compiler`. - */ - -export default Compiler; - -/** - * Initialize a compiler. - */ - -function Compiler( opts ) { - this.options = opts || {}; -} - -/** - * Emit `str` - */ - -Compiler.prototype.emit = function ( str ) { - return str; -}; - -/** - * Visit `node`. - */ - -Compiler.prototype.visit = function ( node ) { - return this[ node.type ]( node ); -}; - -/** - * Map visit over array of `nodes`, optionally using a `delim` - */ - -Compiler.prototype.mapVisit = function ( nodes, delim ) { - let buf = ''; - delim = delim || ''; - - for ( let i = 0, length = nodes.length; i < length; i++ ) { - buf += this.visit( nodes[ i ] ); - if ( delim && i < length - 1 ) { - buf += this.emit( delim ); - } - } - - return buf; -}; diff --git a/packages/block-editor/src/utils/transform-styles/ast/stringify/compress.js b/packages/block-editor/src/utils/transform-styles/ast/stringify/compress.js deleted file mode 100644 index 6a2a3af3769be..0000000000000 --- a/packages/block-editor/src/utils/transform-styles/ast/stringify/compress.js +++ /dev/null @@ -1,238 +0,0 @@ -// Adapted from https://github.com/reworkcss/css -// because we needed to remove source map support. - -/** - * External dependencies - */ -import inherits from 'inherits'; - -/** - * Internal dependencies - */ -import Base from './compiler'; - -/** - * Expose compiler. - */ - -export default Compiler; - -/** - * Initialize a new `Compiler`. - */ - -function Compiler( options ) { - Base.call( this, options ); -} - -/** - * Inherit from `Base.prototype`. - */ - -inherits( Compiler, Base ); - -/** - * Compile `node`. - */ - -Compiler.prototype.compile = function ( node ) { - return node.stylesheet.rules.map( this.visit, this ).join( '' ); -}; - -/** - * Visit comment node. - */ - -Compiler.prototype.comment = function ( node ) { - return this.emit( '', node.position ); -}; - -/** - * Visit import node. - */ - -Compiler.prototype.import = function ( node ) { - return this.emit( '@import ' + node.import + ';', node.position ); -}; - -/** - * Visit media node. - */ - -Compiler.prototype.media = function ( node ) { - return ( - this.emit( '@media ' + node.media, node.position ) + - this.emit( '{' ) + - this.mapVisit( node.rules ) + - this.emit( '}' ) - ); -}; - -/** - * Visit container node. - */ - -Compiler.prototype.container = function ( node ) { - return ( - this.emit( '@container ' + node.container, node.position ) + - this.emit( '{' ) + - this.mapVisit( node.rules ) + - this.emit( '}' ) - ); -}; - -/** - * Visit document node. - */ - -Compiler.prototype.document = function ( node ) { - const doc = '@' + ( node.vendor || '' ) + 'document ' + node.document; - - return ( - this.emit( doc, node.position ) + - this.emit( '{' ) + - this.mapVisit( node.rules ) + - this.emit( '}' ) - ); -}; - -/** - * Visit charset node. - */ - -Compiler.prototype.charset = function ( node ) { - return this.emit( '@charset ' + node.charset + ';', node.position ); -}; - -/** - * Visit namespace node. - */ - -Compiler.prototype.namespace = function ( node ) { - return this.emit( '@namespace ' + node.namespace + ';', node.position ); -}; - -/** - * Visit supports node. - */ - -Compiler.prototype.supports = function ( node ) { - return ( - this.emit( '@supports ' + node.supports, node.position ) + - this.emit( '{' ) + - this.mapVisit( node.rules ) + - this.emit( '}' ) - ); -}; - -/** - * Visit keyframes node. - */ - -Compiler.prototype.keyframes = function ( node ) { - return ( - this.emit( - '@' + ( node.vendor || '' ) + 'keyframes ' + node.name, - node.position - ) + - this.emit( '{' ) + - this.mapVisit( node.keyframes ) + - this.emit( '}' ) - ); -}; - -/** - * Visit keyframe node. - */ - -Compiler.prototype.keyframe = function ( node ) { - const decls = node.declarations; - - return ( - this.emit( node.values.join( ',' ), node.position ) + - this.emit( '{' ) + - this.mapVisit( decls ) + - this.emit( '}' ) - ); -}; - -/** - * Visit page node. - */ - -Compiler.prototype.page = function ( node ) { - const sel = node.selectors.length ? node.selectors.join( ', ' ) : ''; - - return ( - this.emit( '@page ' + sel, node.position ) + - this.emit( '{' ) + - this.mapVisit( node.declarations ) + - this.emit( '}' ) - ); -}; - -/** - * Visit font-face node. - */ - -Compiler.prototype[ 'font-face' ] = function ( node ) { - return ( - this.emit( '@font-face', node.position ) + - this.emit( '{' ) + - this.mapVisit( node.declarations ) + - this.emit( '}' ) - ); -}; - -/** - * Visit host node. - */ - -Compiler.prototype.host = function ( node ) { - return ( - this.emit( '@host', node.position ) + - this.emit( '{' ) + - this.mapVisit( node.rules ) + - this.emit( '}' ) - ); -}; - -/** - * Visit custom-media node. - */ - -Compiler.prototype[ 'custom-media' ] = function ( node ) { - return this.emit( - '@custom-media ' + node.name + ' ' + node.media + ';', - node.position - ); -}; - -/** - * Visit rule node. - */ - -Compiler.prototype.rule = function ( node ) { - const decls = node.declarations; - if ( ! decls.length ) { - return ''; - } - - return ( - this.emit( node.selectors.join( ',' ), node.position ) + - this.emit( '{' ) + - this.mapVisit( decls ) + - this.emit( '}' ) - ); -}; - -/** - * Visit declaration node. - */ - -Compiler.prototype.declaration = function ( node ) { - return ( - this.emit( node.property + ':' + node.value, node.position ) + - this.emit( ';' ) - ); -}; diff --git a/packages/block-editor/src/utils/transform-styles/ast/stringify/identity.js b/packages/block-editor/src/utils/transform-styles/ast/stringify/identity.js deleted file mode 100644 index 760ca4044631e..0000000000000 --- a/packages/block-editor/src/utils/transform-styles/ast/stringify/identity.js +++ /dev/null @@ -1,286 +0,0 @@ -/* eslint-disable @wordpress/no-unused-vars-before-return */ - -// Adapted from https://github.com/reworkcss/css -// because we needed to remove source map support. - -/** - * External dependencies - */ -import inherits from 'inherits'; - -/** - * Internal dependencies - */ -import Base from './compiler'; - -/** - * Expose compiler. - */ - -export default Compiler; - -/** - * Initialize a new `Compiler`. - */ - -function Compiler( options ) { - options = options || {}; - Base.call( this, options ); - this.indentation = options.indent; -} - -/** - * Inherit from `Base.prototype`. - */ - -inherits( Compiler, Base ); - -/** - * Compile `node`. - */ - -Compiler.prototype.compile = function ( node ) { - return this.stylesheet( node ); -}; - -/** - * Visit stylesheet node. - */ - -Compiler.prototype.stylesheet = function ( node ) { - return this.mapVisit( node.stylesheet.rules, '\n\n' ); -}; - -/** - * Visit comment node. - */ - -Compiler.prototype.comment = function ( node ) { - return this.emit( - this.indent() + '/*' + node.comment + '*/', - node.position - ); -}; - -/** - * Visit import node. - */ - -Compiler.prototype.import = function ( node ) { - return this.emit( '@import ' + node.import + ';', node.position ); -}; - -/** - * Visit media node. - */ - -Compiler.prototype.media = function ( node ) { - return ( - this.emit( '@media ' + node.media, node.position ) + - this.emit( ' {\n' + this.indent( 1 ) ) + - this.mapVisit( node.rules, '\n\n' ) + - this.emit( this.indent( -1 ) + '\n}' ) - ); -}; - -/** - * Visit container node. - */ - -Compiler.prototype.container = function ( node ) { - return ( - this.emit( '@container ' + node.container, node.position ) + - this.emit( ' {\n' + this.indent( 1 ) ) + - this.mapVisit( node.rules, '\n\n' ) + - this.emit( this.indent( -1 ) + '\n}' ) - ); -}; - -/** - * Visit document node. - */ - -Compiler.prototype.document = function ( node ) { - const doc = '@' + ( node.vendor || '' ) + 'document ' + node.document; - - return ( - this.emit( doc, node.position ) + - this.emit( ' ' + ' {\n' + this.indent( 1 ) ) + - this.mapVisit( node.rules, '\n\n' ) + - this.emit( this.indent( -1 ) + '\n}' ) - ); -}; - -/** - * Visit charset node. - */ - -Compiler.prototype.charset = function ( node ) { - return this.emit( '@charset ' + node.charset + ';', node.position ); -}; - -/** - * Visit namespace node. - */ - -Compiler.prototype.namespace = function ( node ) { - return this.emit( '@namespace ' + node.namespace + ';', node.position ); -}; - -/** - * Visit supports node. - */ - -Compiler.prototype.supports = function ( node ) { - return ( - this.emit( '@supports ' + node.supports, node.position ) + - this.emit( ' {\n' + this.indent( 1 ) ) + - this.mapVisit( node.rules, '\n\n' ) + - this.emit( this.indent( -1 ) + '\n}' ) - ); -}; - -/** - * Visit keyframes node. - */ - -Compiler.prototype.keyframes = function ( node ) { - return ( - this.emit( - '@' + ( node.vendor || '' ) + 'keyframes ' + node.name, - node.position - ) + - this.emit( ' {\n' + this.indent( 1 ) ) + - this.mapVisit( node.keyframes, '\n' ) + - this.emit( this.indent( -1 ) + '}' ) - ); -}; - -/** - * Visit keyframe node. - */ - -Compiler.prototype.keyframe = function ( node ) { - const decls = node.declarations; - - return ( - this.emit( this.indent() ) + - this.emit( node.values.join( ', ' ), node.position ) + - this.emit( ' {\n' + this.indent( 1 ) ) + - this.mapVisit( decls, '\n' ) + - this.emit( this.indent( -1 ) + '\n' + this.indent() + '}\n' ) - ); -}; - -/** - * Visit page node. - */ - -Compiler.prototype.page = function ( node ) { - const sel = node.selectors.length ? node.selectors.join( ', ' ) + ' ' : ''; - - return ( - this.emit( '@page ' + sel, node.position ) + - this.emit( '{\n' ) + - this.emit( this.indent( 1 ) ) + - this.mapVisit( node.declarations, '\n' ) + - this.emit( this.indent( -1 ) ) + - this.emit( '\n}' ) - ); -}; - -/** - * Visit font-face node. - */ - -Compiler.prototype[ 'font-face' ] = function ( node ) { - return ( - this.emit( '@font-face ', node.position ) + - this.emit( '{\n' ) + - this.emit( this.indent( 1 ) ) + - this.mapVisit( node.declarations, '\n' ) + - this.emit( this.indent( -1 ) ) + - this.emit( '\n}' ) - ); -}; - -/** - * Visit host node. - */ - -Compiler.prototype.host = function ( node ) { - return ( - this.emit( '@host', node.position ) + - this.emit( ' {\n' + this.indent( 1 ) ) + - this.mapVisit( node.rules, '\n\n' ) + - this.emit( this.indent( -1 ) + '\n}' ) - ); -}; - -/** - * Visit custom-media node. - */ - -Compiler.prototype[ 'custom-media' ] = function ( node ) { - return this.emit( - '@custom-media ' + node.name + ' ' + node.media + ';', - node.position - ); -}; - -/** - * Visit rule node. - */ - -Compiler.prototype.rule = function ( node ) { - const indent = this.indent(); - const decls = node.declarations; - if ( ! decls.length ) { - return ''; - } - - return ( - this.emit( - node.selectors - .map( function ( s ) { - return indent + s; - } ) - .join( ',\n' ), - node.position - ) + - this.emit( ' {\n' ) + - this.emit( this.indent( 1 ) ) + - this.mapVisit( decls, '\n' ) + - this.emit( this.indent( -1 ) ) + - this.emit( '\n' + this.indent() + '}' ) - ); -}; - -/** - * Visit declaration node. - */ - -Compiler.prototype.declaration = function ( node ) { - return ( - this.emit( this.indent() ) + - this.emit( node.property + ': ' + node.value, node.position ) + - this.emit( ';' ) - ); -}; - -/** - * Increase, decrease or return current indentation. - */ - -Compiler.prototype.indent = function ( level ) { - this.level = this.level || 1; - - if ( null !== level ) { - this.level += level; - return ''; - } - - return Array( this.level ).join( this.indentation || ' ' ); -}; - -/* eslint-enable @wordpress/no-unused-vars-before-return */ diff --git a/packages/block-editor/src/utils/transform-styles/ast/stringify/index.js b/packages/block-editor/src/utils/transform-styles/ast/stringify/index.js deleted file mode 100644 index 2f332cdb52bec..0000000000000 --- a/packages/block-editor/src/utils/transform-styles/ast/stringify/index.js +++ /dev/null @@ -1,32 +0,0 @@ -// Adapted from https://github.com/reworkcss/css -// because we needed to remove source map support. - -/** - * Internal dependencies - */ -import Compressed from './compress'; -import Identity from './identity'; - -/** - * Stringfy the given AST `node`. - * - * Options: - * - * - `compress` space-optimized output - * - `sourcemap` return an object with `.code` and `.map` - * - * @param {Object} node - * @param {Object} [options] - * @return {string} - */ - -export default function ( node, options ) { - options = options || {}; - - const compiler = options.compress - ? new Compressed( options ) - : new Identity( options ); - - const code = compiler.compile( node ); - return code; -} diff --git a/packages/block-editor/src/utils/transform-styles/index.js b/packages/block-editor/src/utils/transform-styles/index.js index c43e816d401e9..8f5e1702307a4 100644 --- a/packages/block-editor/src/utils/transform-styles/index.js +++ b/packages/block-editor/src/utils/transform-styles/index.js @@ -1,36 +1,36 @@ /** - * WordPress dependencies + * External dependencies */ -import { compose } from '@wordpress/compose'; - -/** - * Internal dependencies - */ -import traverse from './traverse'; -import urlRewrite from './transforms/url-rewrite'; -import wrap from './transforms/wrap'; +import postcss from 'postcss'; +import wrap from 'postcss-prefixwrap'; +import rebaseUrl from 'postcss-urlrebase'; /** * Applies a series of CSS rule transforms to wrap selectors inside a given class and/or rewrite URLs depending on the parameters passed. * - * @param {Object|Array} styles CSS rules. - * @param {string} wrapperClassName Wrapper Class Name. + * @typedef {Object} EditorStyle + * @property {string} css the CSS block(s), as a single string. + * @property {?string} baseURL the base URL to be used as the reference when rewritting urls. + * @property {?string[]} ignoredSelectors the selectors not to wrap. + * + * @param {EditorStyle[]} styles CSS rules. + * @param {string} wrapperSelector Wrapper selector. * @return {Array} converted rules. */ -const transformStyles = ( styles, wrapperClassName = '' ) => { - return Object.values( styles ?? [] ).map( ( { css, baseURL } ) => { - const transforms = []; - if ( wrapperClassName ) { - transforms.push( wrap( wrapperClassName ) ); - } - if ( baseURL ) { - transforms.push( urlRewrite( baseURL ) ); - } - if ( transforms.length ) { - return traverse( css, compose( transforms ) ); - } - - return css; +const transformStyles = ( styles, wrapperSelector = '' ) => { + return styles.map( ( { css, ignoredSelectors = [], baseURL } ) => { + return postcss( + [ + wrapperSelector && + wrap( wrapperSelector, { + ignoredSelectors: [ + ...ignoredSelectors, + wrapperSelector, + ], + } ), + baseURL && rebaseUrl( { rootUrl: baseURL } ), + ].filter( Boolean ) + ).process( css, {} ).css; // use sync PostCSS API } ); }; diff --git a/packages/block-editor/src/utils/transform-styles/test/__snapshots__/traverse.js.snap b/packages/block-editor/src/utils/transform-styles/test/__snapshots__/traverse.js.snap deleted file mode 100644 index 1ff3cab7d6336..0000000000000 --- a/packages/block-editor/src/utils/transform-styles/test/__snapshots__/traverse.js.snap +++ /dev/null @@ -1,7 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`CSS traverse Should traverse the CSS 1`] = ` -"namespace h1 { -color: red; -}" -`; diff --git a/packages/block-editor/src/utils/transform-styles/test/traverse.js b/packages/block-editor/src/utils/transform-styles/test/traverse.js deleted file mode 100644 index bb1be2635fe53..0000000000000 --- a/packages/block-editor/src/utils/transform-styles/test/traverse.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Internal dependencies - */ -import traverse from '../traverse'; - -describe( 'CSS traverse', () => { - it( 'Should traverse the CSS', () => { - const input = `h1 { color: red; }`; - const output = traverse( input, ( node ) => { - if ( node.type === 'rule' ) { - return { - ...node, - selectors: node.selectors.map( - ( selector ) => 'namespace ' + selector - ), - }; - } - - return node; - } ); - - expect( output ).toMatchSnapshot(); - } ); -} ); diff --git a/packages/block-editor/src/utils/transform-styles/transforms/test/__snapshots__/url-rewrite.js.snap b/packages/block-editor/src/utils/transform-styles/transforms/test/__snapshots__/url-rewrite.js.snap deleted file mode 100644 index 48aaf43221e7d..0000000000000 --- a/packages/block-editor/src/utils/transform-styles/transforms/test/__snapshots__/url-rewrite.js.snap +++ /dev/null @@ -1,25 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`URL rewrite should not replace absolute paths 1`] = ` -"h1 { -background: url(/images/test.png); -}" -`; - -exports[`URL rewrite should not replace remote paths 1`] = ` -"h1 { -background: url(http://wp.org/images/test.png); -}" -`; - -exports[`URL rewrite should replace complex relative paths 1`] = ` -"h1 { -background: url(http://wp-site.local/themes/gut/images/test.png); -}" -`; - -exports[`URL rewrite should replace relative paths 1`] = ` -"h1 { -background: url(http://wp-site.local/themes/gut/css/images/test.png); -}" -`; diff --git a/packages/block-editor/src/utils/transform-styles/transforms/test/__snapshots__/wrap.js.snap b/packages/block-editor/src/utils/transform-styles/transforms/test/__snapshots__/wrap.js.snap deleted file mode 100644 index b9815cdc700b3..0000000000000 --- a/packages/block-editor/src/utils/transform-styles/transforms/test/__snapshots__/wrap.js.snap +++ /dev/null @@ -1,64 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`CSS selector wrap should ignore font-face selectors 1`] = ` -"@font-face { -font-family: myFirstFont; -src: url(sansation_light.woff); -}" -`; - -exports[`CSS selector wrap should ignore keyframes 1`] = ` -"@keyframes edit-post__fade-in-animation { -from { -opacity: 0; -} -}" -`; - -exports[`CSS selector wrap should ignore selectors 1`] = ` -".my-namespace h1, -body { -color: red; -}" -`; - -exports[`CSS selector wrap should not double wrap selectors 1`] = ` -".my-namespace h1, -.my-namespace .red { -color: red; -}" -`; - -exports[`CSS selector wrap should replace :root selectors 1`] = ` -".my-namespace { ---my-color: #ff0000; -}" -`; - -exports[`CSS selector wrap should replace root tags 1`] = ` -".my-namespace, -.my-namespace h1 { -color: red; -}" -`; - -exports[`CSS selector wrap should wrap multiple selectors 1`] = ` -".my-namespace h1, -.my-namespace h2 { -color: red; -}" -`; - -exports[`CSS selector wrap should wrap regular selectors 1`] = ` -".my-namespace h1 { -color: red; -}" -`; - -exports[`CSS selector wrap should wrap selectors inside container queries 1`] = ` -"@container (width > 400px) { -.my-namespace h1 { -color: red; -} -}" -`; diff --git a/packages/block-editor/src/utils/transform-styles/transforms/test/url-rewrite.js b/packages/block-editor/src/utils/transform-styles/transforms/test/url-rewrite.js deleted file mode 100644 index abbbf0754187e..0000000000000 --- a/packages/block-editor/src/utils/transform-styles/transforms/test/url-rewrite.js +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Internal dependencies - */ -import traverse from '../../traverse'; -import rewrite from '../url-rewrite'; - -describe( 'URL rewrite', () => { - it( 'should replace relative paths', () => { - const callback = rewrite( 'http://wp-site.local/themes/gut/css/' ); - const input = `h1 { background: url(images/test.png); }`; - const output = traverse( input, callback ); - - expect( output ).toMatchSnapshot(); - } ); - - it( 'should replace complex relative paths', () => { - const callback = rewrite( 'http://wp-site.local/themes/gut/css/' ); - const input = `h1 { background: url(../images/test.png); }`; - const output = traverse( input, callback ); - - expect( output ).toMatchSnapshot(); - } ); - - it( 'should not replace absolute paths', () => { - const callback = rewrite( 'http://wp-site.local/themes/gut/css/' ); - const input = `h1 { background: url(/images/test.png); }`; - const output = traverse( input, callback ); - - expect( output ).toMatchSnapshot(); - } ); - - it( 'should not replace remote paths', () => { - const callback = rewrite( 'http://wp-site.local/themes/gut/css/' ); - const input = `h1 { background: url(http://wp.org/images/test.png); }`; - const output = traverse( input, callback ); - - expect( output ).toMatchSnapshot(); - } ); -} ); diff --git a/packages/block-editor/src/utils/transform-styles/transforms/test/wrap.js b/packages/block-editor/src/utils/transform-styles/transforms/test/wrap.js deleted file mode 100644 index a1f4f141d21c9..0000000000000 --- a/packages/block-editor/src/utils/transform-styles/transforms/test/wrap.js +++ /dev/null @@ -1,95 +0,0 @@ -/** - * Internal dependencies - */ -import traverse from '../../traverse'; -import wrap from '../wrap'; - -describe( 'CSS selector wrap', () => { - it( 'should wrap regular selectors', () => { - const callback = wrap( '.my-namespace' ); - const input = `h1 { color: red; }`; - const output = traverse( input, callback ); - - expect( output ).toMatchSnapshot(); - } ); - - it( 'should wrap multiple selectors', () => { - const callback = wrap( '.my-namespace' ); - const input = `h1, h2 { color: red; }`; - const output = traverse( input, callback ); - - expect( output ).toMatchSnapshot(); - } ); - - it( 'should ignore selectors', () => { - const callback = wrap( '.my-namespace', [ 'body' ] ); - const input = `h1, body { color: red; }`; - const output = traverse( input, callback ); - - expect( output ).toMatchSnapshot(); - } ); - - it( 'should replace root tags', () => { - const callback = wrap( '.my-namespace' ); - const input = `body, h1 { color: red; }`; - const output = traverse( input, callback ); - - expect( output ).toMatchSnapshot(); - } ); - - it( 'should ignore keyframes', () => { - const callback = wrap( '.my-namespace' ); - const input = ` - @keyframes edit-post__fade-in-animation { - from { - opacity: 0; - } - }`; - const output = traverse( input, callback ); - - expect( output ).toMatchSnapshot(); - } ); - - it( 'should wrap selectors inside container queries', () => { - const callback = wrap( '.my-namespace' ); - const input = ` - @container (width > 400px) { - h1 { color: red; } - }`; - const output = traverse( input, callback ); - - expect( output ).toMatchSnapshot(); - } ); - - it( 'should ignore font-face selectors', () => { - const callback = wrap( '.my-namespace' ); - const input = ` - @font-face { - font-family: myFirstFont; - src: url(sansation_light.woff); - }`; - const output = traverse( input, callback ); - - expect( output ).toMatchSnapshot(); - } ); - - it( 'should replace :root selectors', () => { - const callback = wrap( '.my-namespace' ); - const input = ` - :root { - --my-color: #ff0000; - }`; - const output = traverse( input, callback ); - - expect( output ).toMatchSnapshot(); - } ); - - it( 'should not double wrap selectors', () => { - const callback = wrap( '.my-namespace' ); - const input = ` .my-namespace h1, .red { color: red; }`; - - const output = traverse( input, callback ); - - expect( output ).toMatchSnapshot(); - } ); -} ); diff --git a/packages/block-editor/src/utils/transform-styles/transforms/url-rewrite.js b/packages/block-editor/src/utils/transform-styles/transforms/url-rewrite.js deleted file mode 100644 index e3461cb1088d7..0000000000000 --- a/packages/block-editor/src/utils/transform-styles/transforms/url-rewrite.js +++ /dev/null @@ -1,139 +0,0 @@ -/** - * Return `true` if the given path is http/https. - * - * @param {string} filePath path - * - * @return {boolean} is remote path. - */ -function isRemotePath( filePath ) { - return /^(?:https?:)?\/\//.test( filePath ); -} - -/** - * Return `true` if the given filePath is an absolute url. - * - * @param {string} filePath path - * - * @return {boolean} is absolute path. - */ -function isAbsolutePath( filePath ) { - return /^\/(?!\/)/.test( filePath ); -} - -/** - * Whether or not the url should be inluded. - * - * @param {Object} meta url meta info - * - * @return {boolean} is valid. - */ -function isValidURL( meta ) { - // Ignore hashes or data uris. - if ( - meta.value.indexOf( 'data:' ) === 0 || - meta.value.indexOf( '#' ) === 0 - ) { - return false; - } - - if ( isAbsolutePath( meta.value ) ) { - return false; - } - - // Do not handle the http/https urls if `includeRemote` is false. - if ( isRemotePath( meta.value ) ) { - return false; - } - - return true; -} - -/** - * Get the absolute path of the url, relative to the basePath - * - * @param {string} str the url - * @param {string} baseURL base URL - * - * @return {string} the full path to the file - */ -function getResourcePath( str, baseURL ) { - return new URL( str, baseURL ).toString(); -} - -/** - * Process the single `url()` pattern - * - * @param {string} baseURL the base URL for relative URLs. - * - * @return {Promise} the Promise. - */ -function processURL( baseURL ) { - return ( meta ) => ( { - ...meta, - newUrl: - 'url(' + - meta.before + - meta.quote + - getResourcePath( meta.value, baseURL ) + - meta.quote + - meta.after + - ')', - } ); -} - -/** - * Get all `url()`s, and return the meta info - * - * @param {string} value decl.value. - * - * @return {Array} the urls. - */ -function getURLs( value ) { - const reg = /url\((\s*)(['"]?)(.+?)\2(\s*)\)/g; - let match; - const URLs = []; - - while ( ( match = reg.exec( value ) ) !== null ) { - const meta = { - source: match[ 0 ], - before: match[ 1 ], - quote: match[ 2 ], - value: match[ 3 ], - after: match[ 4 ], - }; - if ( isValidURL( meta ) ) { - URLs.push( meta ); - } - } - return URLs; -} - -/** - * Replace the raw value's `url()` segment to the new value - * - * @param {string} raw the raw value. - * @param {Array} URLs the URLs to replace. - * - * @return {string} the new value. - */ -function replaceURLs( raw, URLs ) { - URLs.forEach( ( item ) => { - raw = raw.replace( item.source, item.newUrl ); - } ); - - return raw; -} - -const rewrite = ( rootURL ) => ( node ) => { - if ( node.type === 'declaration' ) { - const updatedURLs = getURLs( node.value ).map( processURL( rootURL ) ); - return { - ...node, - value: replaceURLs( node.value, updatedURLs ), - }; - } - - return node; -}; - -export default rewrite; diff --git a/packages/block-editor/src/utils/transform-styles/transforms/wrap.js b/packages/block-editor/src/utils/transform-styles/transforms/wrap.js deleted file mode 100644 index 74b940f80352b..0000000000000 --- a/packages/block-editor/src/utils/transform-styles/transforms/wrap.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @constant string IS_ROOT_TAG Regex to check if the selector is a root tag selector. - */ -const IS_ROOT_TAG = /^(body|html|:root).*$/; - -/** - * Creates a callback to modify selectors so they only apply within a certain - * namespace. - * - * @param {string} namespace Namespace to prefix selectors with. - * @param {string[]} ignore Selectors to not prefix. - * - * @return {(node: Object) => Object} Callback to wrap selectors. - */ -const wrap = - ( namespace, ignore = [] ) => - ( node ) => { - /** - * Updates selector if necessary. - * - * @param {string} selector Selector to modify. - * - * @return {string} Updated selector. - */ - const updateSelector = ( selector ) => { - if ( ignore.includes( selector.trim() ) ) { - return selector; - } - - // Skip the update when a selector already has a namespace + space (" "). - if ( selector.trim().startsWith( `${ namespace } ` ) ) { - return selector; - } - - // Anything other than a root tag is always prefixed. - { - if ( ! selector.match( IS_ROOT_TAG ) ) { - return namespace + ' ' + selector; - } - } - - // HTML and Body elements cannot be contained within our container so lets extract their styles. - return selector.replace( /^(body|html|:root)/, namespace ); - }; - - if ( node.type === 'rule' ) { - return { - ...node, - selectors: node.selectors.map( updateSelector ), - }; - } - - return node; - }; - -export default wrap; diff --git a/packages/block-editor/src/utils/transform-styles/traverse.js b/packages/block-editor/src/utils/transform-styles/traverse.js deleted file mode 100644 index 28ad59b4ea799..0000000000000 --- a/packages/block-editor/src/utils/transform-styles/traverse.js +++ /dev/null @@ -1,32 +0,0 @@ -/** - * External dependencies - */ -import traverse from 'traverse'; - -/** - * Internal dependencies - */ -import { parse, stringify } from './ast'; - -function traverseCSS( css, callback ) { - try { - const parsed = parse( css ); - - const updated = traverse.map( parsed, function ( node ) { - if ( ! node ) { - return node; - } - const updatedNode = callback( node ); - return this.update( updatedNode ); - } ); - - return stringify( updated ); - } catch ( err ) { - // eslint-disable-next-line no-console - console.warn( 'Error while traversing the CSS: ' + err ); - - return null; - } -} - -export default traverseCSS; diff --git a/packages/block-library/src/block/edit-title.native.js b/packages/block-library/src/block/edit-title.native.js index 0a574f2f0cfa8..d0c7d981202d9 100644 --- a/packages/block-library/src/block/edit-title.native.js +++ b/packages/block-library/src/block/edit-title.native.js @@ -6,7 +6,7 @@ import { Text, View } from 'react-native'; /** * WordPress dependencies */ -import { Icon } from '@wordpress/components'; +import { Icon, useGlobalStyles } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; import { withPreferredColorScheme } from '@wordpress/compose'; import { help, lock } from '@wordpress/icons'; @@ -17,18 +17,21 @@ import { help, lock } from '@wordpress/icons'; import styles from './editor.scss'; function EditTitle( { getStylesFromColorScheme, title } ) { - const lockIconStyle = getStylesFromColorScheme( - styles.lockIcon, - styles.lockIconDark - ); - const titleStyle = getStylesFromColorScheme( - styles.title, - styles.titleDark - ); - const infoIconStyle = getStylesFromColorScheme( - styles.infoIcon, - styles.infoIconDark - ); + const globalStyles = useGlobalStyles(); + const baseColors = globalStyles?.baseColors?.color; + + const lockIconStyle = [ + getStylesFromColorScheme( styles.lockIcon, styles.lockIconDark ), + baseColors && { color: baseColors.text }, + ]; + const titleStyle = [ + getStylesFromColorScheme( styles.title, styles.titleDark ), + baseColors && { color: baseColors.text }, + ]; + const infoIconStyle = [ + getStylesFromColorScheme( styles.infoIcon, styles.infoIconDark ), + baseColors && { color: baseColors.text }, + ]; const separatorStyle = getStylesFromColorScheme( styles.separator, styles.separatorDark diff --git a/packages/block-library/src/html/preview.js b/packages/block-library/src/html/preview.js index 4d3fe5f41915a..d515c0119aa8d 100644 --- a/packages/block-library/src/html/preview.js +++ b/packages/block-library/src/html/preview.js @@ -22,12 +22,17 @@ const DEFAULT_STYLES = ` `; export default function HTMLEditPreview( { content, isSelected } ) { - const settingStyles = useSelect( ( select ) => { - return select( blockEditorStore ).getSettings()?.styles; - }, [] ); + const settingStyles = useSelect( + ( select ) => select( blockEditorStore ).getSettings().styles + ); const styles = useMemo( - () => [ DEFAULT_STYLES, ...transformStyles( settingStyles ) ], + () => [ + DEFAULT_STYLES, + ...transformStyles( + settingStyles.filter( ( style ) => style.css ) + ), + ], [ settingStyles ] ); diff --git a/packages/block-library/src/image/index.php b/packages/block-library/src/image/index.php index f29202fe63d19..c465677a986e0 100644 --- a/packages/block-library/src/image/index.php +++ b/packages/block-library/src/image/index.php @@ -235,6 +235,7 @@ function block_core_image_render_lightbox( $block_content, $block ) { $button = $img[0] . ''; @@ -319,12 +320,13 @@ function block_core_image_render_lightbox( $block_content, $block ) { data-wp-on--touchmove="actions.core.image.handleTouchMove" data-wp-on--touchend="actions.core.image.handleTouchEnd" data-wp-on--click="actions.core.image.hideLightbox" + tabindex="-1" >
Add views ui here
; + // TODO: add views UI. + return null; } diff --git a/packages/editor/src/components/index.js b/packages/editor/src/components/index.js index 99de8c83c6fbe..39b562806c109 100644 --- a/packages/editor/src/components/index.js +++ b/packages/editor/src/components/index.js @@ -62,7 +62,6 @@ export { export { default as PostTaxonomies } from './post-taxonomies'; export { FlatTermSelector as PostTaxonomiesFlatTermSelector } from './post-taxonomies/flat-term-selector'; export { HierarchicalTermSelector as PostTaxonomiesHierarchicalTermSelector } from './post-taxonomies/hierarchical-term-selector'; -export { PatternCategoriesSelector as PostPatternCategoriesSelector } from './post-taxonomies/pattern-categories-selector'; export { default as PostTaxonomiesCheck } from './post-taxonomies/check'; export { default as PostTextEditor } from './post-text-editor'; export { default as PostTitle } from './post-title'; diff --git a/packages/editor/src/components/post-taxonomies/pattern-categories-selector.js b/packages/editor/src/components/post-taxonomies/pattern-categories-selector.js deleted file mode 100644 index ac6a60aa00934..0000000000000 --- a/packages/editor/src/components/post-taxonomies/pattern-categories-selector.js +++ /dev/null @@ -1,119 +0,0 @@ -/** - * WordPress dependencies - */ -import { useSelect, useDispatch } from '@wordpress/data'; -import { store as coreStore } from '@wordpress/core-data'; -import { addFilter } from '@wordpress/hooks'; -import { privateApis as patternsPrivateApis } from '@wordpress/patterns'; - -/** - * Internal dependencies - */ -import { unlock } from '../../lock-unlock'; -import { store as editorStore } from '../../store'; - -const { CategorySelector } = unlock( patternsPrivateApis ); - -const EMPTY_ARRAY = []; - -const DEFAULT_QUERY = { - per_page: -1, - orderby: 'name', - order: 'asc', - _fields: 'id,name,parent', - context: 'view', -}; - -/* - * Pattern categories are a flat taxonomy but do not allow Author users and below to create - * new categories, so this selector overrides the default flat taxonomy selector for - * wp_block post types and users without 'create' capability for wp_pattern_category. - */ -export function PatternCategoriesSelector( { slug } ) { - const { hasAssignAction, terms, availableTerms, taxonomy, loading } = - useSelect( - ( select ) => { - const { getCurrentPost, getEditedPostAttribute } = - select( editorStore ); - const { getTaxonomy, getEntityRecords, isResolving } = - select( coreStore ); - const _taxonomy = getTaxonomy( slug ); - const post = getCurrentPost(); - - return { - hasAssignAction: _taxonomy - ? post._links?.[ - 'wp:action-assign-' + _taxonomy.rest_base - ] ?? false - : false, - terms: _taxonomy - ? getEditedPostAttribute( _taxonomy.rest_base ) - : EMPTY_ARRAY, - loading: isResolving( 'getEntityRecords', [ - 'taxonomy', - slug, - DEFAULT_QUERY, - ] ), - availableTerms: - getEntityRecords( 'taxonomy', slug, DEFAULT_QUERY ) || - EMPTY_ARRAY, - taxonomy: _taxonomy, - }; - }, - [ slug ] - ); - - const { editPost } = useDispatch( editorStore ); - - if ( ! hasAssignAction || loading || availableTerms.length === 0 ) { - return null; - } - - const onUpdateTerms = ( termIds ) => { - editPost( { [ taxonomy.rest_base ]: termIds } ); - }; - - const onChange = ( term ) => { - const hasTerm = terms.includes( term.id ); - const newTerms = hasTerm - ? terms.filter( ( id ) => id !== term.id ) - : [ ...terms, term.id ]; - onUpdateTerms( newTerms ); - }; - - const isCategorySelected = ( term ) => terms.includes( term.id ); - - const categoryOptions = availableTerms.map( ( term ) => ( { - ...term, - label: term.name, - } ) ); - - return ( -