@wordpress/block-editor 13.0.6 → 13.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,8 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { parse } from '@wordpress/blocks';
5
+
1
6
  /**
2
7
  * Internal dependencies
3
8
  */
@@ -5,6 +10,36 @@ import { selectBlockPatternsKey } from './private-keys';
5
10
  import { unlock } from '../lock-unlock';
6
11
  import { STORE_NAME } from './constants';
7
12
  export const withRootClientIdOptionKey = Symbol('withRootClientId');
13
+ const parsedPatternCache = new WeakMap();
14
+ function parsePattern(pattern) {
15
+ const blocks = parse(pattern.content, {
16
+ __unstableSkipMigrationLogs: true
17
+ });
18
+ if (blocks.length === 1) {
19
+ blocks[0].attributes = {
20
+ ...blocks[0].attributes,
21
+ metadata: {
22
+ ...(blocks[0].attributes.metadata || {}),
23
+ categories: pattern.categories,
24
+ patternName: pattern.name,
25
+ name: blocks[0].attributes.metadata?.name || pattern.title
26
+ }
27
+ };
28
+ }
29
+ return {
30
+ ...pattern,
31
+ blocks
32
+ };
33
+ }
34
+ export function getParsedPattern(pattern) {
35
+ let parsedPattern = parsedPatternCache.get(pattern);
36
+ if (parsedPattern) {
37
+ return parsedPattern;
38
+ }
39
+ parsedPattern = parsePattern(pattern);
40
+ parsedPatternCache.set(pattern, parsedPattern);
41
+ return parsedPattern;
42
+ }
8
43
  export const checkAllowList = (list, item, defaultResult = null) => {
9
44
  if (typeof list === 'boolean') {
10
45
  return list;
@@ -1 +1 @@
1
- {"version":3,"names":["selectBlockPatternsKey","unlock","STORE_NAME","withRootClientIdOptionKey","Symbol","checkAllowList","list","item","defaultResult","Array","isArray","includes","checkAllowListRecursive","blocks","allowedBlockTypes","blocksQueue","length","block","shift","isAllowed","name","blockName","innerBlocks","forEach","innerBlock","push","getAllPatternsDependants","select","state","settings","__experimentalBlockPatterns","__experimentalUserPatternCategories","__experimentalReusableBlocks","blockPatterns","getReusableBlocks","getInsertBlockTypeDependants","rootClientId","blockListSettings","byClientId","get","templateLock","blockEditingModes"],"sources":["@wordpress/block-editor/src/store/utils.js"],"sourcesContent":["/**\n * Internal dependencies\n */\nimport { selectBlockPatternsKey } from './private-keys';\nimport { unlock } from '../lock-unlock';\nimport { STORE_NAME } from './constants';\n\nexport const withRootClientIdOptionKey = Symbol( 'withRootClientId' );\n\nexport const checkAllowList = ( list, item, defaultResult = null ) => {\n\tif ( typeof list === 'boolean' ) {\n\t\treturn list;\n\t}\n\tif ( Array.isArray( list ) ) {\n\t\t// TODO: when there is a canonical way to detect that we are editing a post\n\t\t// the following check should be changed to something like:\n\t\t// if ( list.includes( 'core/post-content' ) && getEditorMode() === 'post-content' && item === null )\n\t\tif ( list.includes( 'core/post-content' ) && item === null ) {\n\t\t\treturn true;\n\t\t}\n\t\treturn list.includes( item );\n\t}\n\treturn defaultResult;\n};\n\nexport const checkAllowListRecursive = ( blocks, allowedBlockTypes ) => {\n\tif ( typeof allowedBlockTypes === 'boolean' ) {\n\t\treturn allowedBlockTypes;\n\t}\n\n\tconst blocksQueue = [ ...blocks ];\n\twhile ( blocksQueue.length > 0 ) {\n\t\tconst block = blocksQueue.shift();\n\n\t\tconst isAllowed = checkAllowList(\n\t\t\tallowedBlockTypes,\n\t\t\tblock.name || block.blockName,\n\t\t\ttrue\n\t\t);\n\t\tif ( ! isAllowed ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tblock.innerBlocks?.forEach( ( innerBlock ) => {\n\t\t\tblocksQueue.push( innerBlock );\n\t\t} );\n\t}\n\n\treturn true;\n};\n\nexport const getAllPatternsDependants = ( select ) => ( state ) => {\n\treturn [\n\t\tstate.settings.__experimentalBlockPatterns,\n\t\tstate.settings.__experimentalUserPatternCategories,\n\t\tstate.settings.__experimentalReusableBlocks,\n\t\tstate.settings[ selectBlockPatternsKey ]?.( select ),\n\t\tstate.blockPatterns,\n\t\tunlock( select( STORE_NAME ) ).getReusableBlocks(),\n\t];\n};\n\nexport function getInsertBlockTypeDependants( state, rootClientId ) {\n\treturn [\n\t\tstate.blockListSettings[ rootClientId ],\n\t\tstate.blocks.byClientId.get( rootClientId ),\n\t\tstate.settings.allowedBlockTypes,\n\t\tstate.settings.templateLock,\n\t\tstate.blockEditingModes,\n\t];\n}\n"],"mappings":"AAAA;AACA;AACA;AACA,SAASA,sBAAsB,QAAQ,gBAAgB;AACvD,SAASC,MAAM,QAAQ,gBAAgB;AACvC,SAASC,UAAU,QAAQ,aAAa;AAExC,OAAO,MAAMC,yBAAyB,GAAGC,MAAM,CAAE,kBAAmB,CAAC;AAErE,OAAO,MAAMC,cAAc,GAAGA,CAAEC,IAAI,EAAEC,IAAI,EAAEC,aAAa,GAAG,IAAI,KAAM;EACrE,IAAK,OAAOF,IAAI,KAAK,SAAS,EAAG;IAChC,OAAOA,IAAI;EACZ;EACA,IAAKG,KAAK,CAACC,OAAO,CAAEJ,IAAK,CAAC,EAAG;IAC5B;IACA;IACA;IACA,IAAKA,IAAI,CAACK,QAAQ,CAAE,mBAAoB,CAAC,IAAIJ,IAAI,KAAK,IAAI,EAAG;MAC5D,OAAO,IAAI;IACZ;IACA,OAAOD,IAAI,CAACK,QAAQ,CAAEJ,IAAK,CAAC;EAC7B;EACA,OAAOC,aAAa;AACrB,CAAC;AAED,OAAO,MAAMI,uBAAuB,GAAGA,CAAEC,MAAM,EAAEC,iBAAiB,KAAM;EACvE,IAAK,OAAOA,iBAAiB,KAAK,SAAS,EAAG;IAC7C,OAAOA,iBAAiB;EACzB;EAEA,MAAMC,WAAW,GAAG,CAAE,GAAGF,MAAM,CAAE;EACjC,OAAQE,WAAW,CAACC,MAAM,GAAG,CAAC,EAAG;IAChC,MAAMC,KAAK,GAAGF,WAAW,CAACG,KAAK,CAAC,CAAC;IAEjC,MAAMC,SAAS,GAAGd,cAAc,CAC/BS,iBAAiB,EACjBG,KAAK,CAACG,IAAI,IAAIH,KAAK,CAACI,SAAS,EAC7B,IACD,CAAC;IACD,IAAK,CAAEF,SAAS,EAAG;MAClB,OAAO,KAAK;IACb;IAEAF,KAAK,CAACK,WAAW,EAAEC,OAAO,CAAIC,UAAU,IAAM;MAC7CT,WAAW,CAACU,IAAI,CAAED,UAAW,CAAC;IAC/B,CAAE,CAAC;EACJ;EAEA,OAAO,IAAI;AACZ,CAAC;AAED,OAAO,MAAME,wBAAwB,GAAKC,MAAM,IAAQC,KAAK,IAAM;EAClE,OAAO,CACNA,KAAK,CAACC,QAAQ,CAACC,2BAA2B,EAC1CF,KAAK,CAACC,QAAQ,CAACE,mCAAmC,EAClDH,KAAK,CAACC,QAAQ,CAACG,4BAA4B,EAC3CJ,KAAK,CAACC,QAAQ,CAAE7B,sBAAsB,CAAE,GAAI2B,MAAO,CAAC,EACpDC,KAAK,CAACK,aAAa,EACnBhC,MAAM,CAAE0B,MAAM,CAAEzB,UAAW,CAAE,CAAC,CAACgC,iBAAiB,CAAC,CAAC,CAClD;AACF,CAAC;AAED,OAAO,SAASC,4BAA4BA,CAAEP,KAAK,EAAEQ,YAAY,EAAG;EACnE,OAAO,CACNR,KAAK,CAACS,iBAAiB,CAAED,YAAY,CAAE,EACvCR,KAAK,CAACf,MAAM,CAACyB,UAAU,CAACC,GAAG,CAAEH,YAAa,CAAC,EAC3CR,KAAK,CAACC,QAAQ,CAACf,iBAAiB,EAChCc,KAAK,CAACC,QAAQ,CAACW,YAAY,EAC3BZ,KAAK,CAACa,iBAAiB,CACvB;AACF","ignoreList":[]}
1
+ {"version":3,"names":["parse","selectBlockPatternsKey","unlock","STORE_NAME","withRootClientIdOptionKey","Symbol","parsedPatternCache","WeakMap","parsePattern","pattern","blocks","content","__unstableSkipMigrationLogs","length","attributes","metadata","categories","patternName","name","title","getParsedPattern","parsedPattern","get","set","checkAllowList","list","item","defaultResult","Array","isArray","includes","checkAllowListRecursive","allowedBlockTypes","blocksQueue","block","shift","isAllowed","blockName","innerBlocks","forEach","innerBlock","push","getAllPatternsDependants","select","state","settings","__experimentalBlockPatterns","__experimentalUserPatternCategories","__experimentalReusableBlocks","blockPatterns","getReusableBlocks","getInsertBlockTypeDependants","rootClientId","blockListSettings","byClientId","templateLock","blockEditingModes"],"sources":["@wordpress/block-editor/src/store/utils.js"],"sourcesContent":["/**\n * WordPress dependencies\n */\nimport { parse } from '@wordpress/blocks';\n\n/**\n * Internal dependencies\n */\nimport { selectBlockPatternsKey } from './private-keys';\nimport { unlock } from '../lock-unlock';\nimport { STORE_NAME } from './constants';\n\nexport const withRootClientIdOptionKey = Symbol( 'withRootClientId' );\n\nconst parsedPatternCache = new WeakMap();\n\nfunction parsePattern( pattern ) {\n\tconst blocks = parse( pattern.content, {\n\t\t__unstableSkipMigrationLogs: true,\n\t} );\n\tif ( blocks.length === 1 ) {\n\t\tblocks[ 0 ].attributes = {\n\t\t\t...blocks[ 0 ].attributes,\n\t\t\tmetadata: {\n\t\t\t\t...( blocks[ 0 ].attributes.metadata || {} ),\n\t\t\t\tcategories: pattern.categories,\n\t\t\t\tpatternName: pattern.name,\n\t\t\t\tname: blocks[ 0 ].attributes.metadata?.name || pattern.title,\n\t\t\t},\n\t\t};\n\t}\n\treturn {\n\t\t...pattern,\n\t\tblocks,\n\t};\n}\n\nexport function getParsedPattern( pattern ) {\n\tlet parsedPattern = parsedPatternCache.get( pattern );\n\tif ( parsedPattern ) {\n\t\treturn parsedPattern;\n\t}\n\tparsedPattern = parsePattern( pattern );\n\tparsedPatternCache.set( pattern, parsedPattern );\n\treturn parsedPattern;\n}\n\nexport const checkAllowList = ( list, item, defaultResult = null ) => {\n\tif ( typeof list === 'boolean' ) {\n\t\treturn list;\n\t}\n\tif ( Array.isArray( list ) ) {\n\t\t// TODO: when there is a canonical way to detect that we are editing a post\n\t\t// the following check should be changed to something like:\n\t\t// if ( list.includes( 'core/post-content' ) && getEditorMode() === 'post-content' && item === null )\n\t\tif ( list.includes( 'core/post-content' ) && item === null ) {\n\t\t\treturn true;\n\t\t}\n\t\treturn list.includes( item );\n\t}\n\treturn defaultResult;\n};\n\nexport const checkAllowListRecursive = ( blocks, allowedBlockTypes ) => {\n\tif ( typeof allowedBlockTypes === 'boolean' ) {\n\t\treturn allowedBlockTypes;\n\t}\n\n\tconst blocksQueue = [ ...blocks ];\n\twhile ( blocksQueue.length > 0 ) {\n\t\tconst block = blocksQueue.shift();\n\n\t\tconst isAllowed = checkAllowList(\n\t\t\tallowedBlockTypes,\n\t\t\tblock.name || block.blockName,\n\t\t\ttrue\n\t\t);\n\t\tif ( ! isAllowed ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tblock.innerBlocks?.forEach( ( innerBlock ) => {\n\t\t\tblocksQueue.push( innerBlock );\n\t\t} );\n\t}\n\n\treturn true;\n};\n\nexport const getAllPatternsDependants = ( select ) => ( state ) => {\n\treturn [\n\t\tstate.settings.__experimentalBlockPatterns,\n\t\tstate.settings.__experimentalUserPatternCategories,\n\t\tstate.settings.__experimentalReusableBlocks,\n\t\tstate.settings[ selectBlockPatternsKey ]?.( select ),\n\t\tstate.blockPatterns,\n\t\tunlock( select( STORE_NAME ) ).getReusableBlocks(),\n\t];\n};\n\nexport function getInsertBlockTypeDependants( state, rootClientId ) {\n\treturn [\n\t\tstate.blockListSettings[ rootClientId ],\n\t\tstate.blocks.byClientId.get( rootClientId ),\n\t\tstate.settings.allowedBlockTypes,\n\t\tstate.settings.templateLock,\n\t\tstate.blockEditingModes,\n\t];\n}\n"],"mappings":"AAAA;AACA;AACA;AACA,SAASA,KAAK,QAAQ,mBAAmB;;AAEzC;AACA;AACA;AACA,SAASC,sBAAsB,QAAQ,gBAAgB;AACvD,SAASC,MAAM,QAAQ,gBAAgB;AACvC,SAASC,UAAU,QAAQ,aAAa;AAExC,OAAO,MAAMC,yBAAyB,GAAGC,MAAM,CAAE,kBAAmB,CAAC;AAErE,MAAMC,kBAAkB,GAAG,IAAIC,OAAO,CAAC,CAAC;AAExC,SAASC,YAAYA,CAAEC,OAAO,EAAG;EAChC,MAAMC,MAAM,GAAGV,KAAK,CAAES,OAAO,CAACE,OAAO,EAAE;IACtCC,2BAA2B,EAAE;EAC9B,CAAE,CAAC;EACH,IAAKF,MAAM,CAACG,MAAM,KAAK,CAAC,EAAG;IAC1BH,MAAM,CAAE,CAAC,CAAE,CAACI,UAAU,GAAG;MACxB,GAAGJ,MAAM,CAAE,CAAC,CAAE,CAACI,UAAU;MACzBC,QAAQ,EAAE;QACT,IAAKL,MAAM,CAAE,CAAC,CAAE,CAACI,UAAU,CAACC,QAAQ,IAAI,CAAC,CAAC,CAAE;QAC5CC,UAAU,EAAEP,OAAO,CAACO,UAAU;QAC9BC,WAAW,EAAER,OAAO,CAACS,IAAI;QACzBA,IAAI,EAAER,MAAM,CAAE,CAAC,CAAE,CAACI,UAAU,CAACC,QAAQ,EAAEG,IAAI,IAAIT,OAAO,CAACU;MACxD;IACD,CAAC;EACF;EACA,OAAO;IACN,GAAGV,OAAO;IACVC;EACD,CAAC;AACF;AAEA,OAAO,SAASU,gBAAgBA,CAAEX,OAAO,EAAG;EAC3C,IAAIY,aAAa,GAAGf,kBAAkB,CAACgB,GAAG,CAAEb,OAAQ,CAAC;EACrD,IAAKY,aAAa,EAAG;IACpB,OAAOA,aAAa;EACrB;EACAA,aAAa,GAAGb,YAAY,CAAEC,OAAQ,CAAC;EACvCH,kBAAkB,CAACiB,GAAG,CAAEd,OAAO,EAAEY,aAAc,CAAC;EAChD,OAAOA,aAAa;AACrB;AAEA,OAAO,MAAMG,cAAc,GAAGA,CAAEC,IAAI,EAAEC,IAAI,EAAEC,aAAa,GAAG,IAAI,KAAM;EACrE,IAAK,OAAOF,IAAI,KAAK,SAAS,EAAG;IAChC,OAAOA,IAAI;EACZ;EACA,IAAKG,KAAK,CAACC,OAAO,CAAEJ,IAAK,CAAC,EAAG;IAC5B;IACA;IACA;IACA,IAAKA,IAAI,CAACK,QAAQ,CAAE,mBAAoB,CAAC,IAAIJ,IAAI,KAAK,IAAI,EAAG;MAC5D,OAAO,IAAI;IACZ;IACA,OAAOD,IAAI,CAACK,QAAQ,CAAEJ,IAAK,CAAC;EAC7B;EACA,OAAOC,aAAa;AACrB,CAAC;AAED,OAAO,MAAMI,uBAAuB,GAAGA,CAAErB,MAAM,EAAEsB,iBAAiB,KAAM;EACvE,IAAK,OAAOA,iBAAiB,KAAK,SAAS,EAAG;IAC7C,OAAOA,iBAAiB;EACzB;EAEA,MAAMC,WAAW,GAAG,CAAE,GAAGvB,MAAM,CAAE;EACjC,OAAQuB,WAAW,CAACpB,MAAM,GAAG,CAAC,EAAG;IAChC,MAAMqB,KAAK,GAAGD,WAAW,CAACE,KAAK,CAAC,CAAC;IAEjC,MAAMC,SAAS,GAAGZ,cAAc,CAC/BQ,iBAAiB,EACjBE,KAAK,CAAChB,IAAI,IAAIgB,KAAK,CAACG,SAAS,EAC7B,IACD,CAAC;IACD,IAAK,CAAED,SAAS,EAAG;MAClB,OAAO,KAAK;IACb;IAEAF,KAAK,CAACI,WAAW,EAAEC,OAAO,CAAIC,UAAU,IAAM;MAC7CP,WAAW,CAACQ,IAAI,CAAED,UAAW,CAAC;IAC/B,CAAE,CAAC;EACJ;EAEA,OAAO,IAAI;AACZ,CAAC;AAED,OAAO,MAAME,wBAAwB,GAAKC,MAAM,IAAQC,KAAK,IAAM;EAClE,OAAO,CACNA,KAAK,CAACC,QAAQ,CAACC,2BAA2B,EAC1CF,KAAK,CAACC,QAAQ,CAACE,mCAAmC,EAClDH,KAAK,CAACC,QAAQ,CAACG,4BAA4B,EAC3CJ,KAAK,CAACC,QAAQ,CAAE5C,sBAAsB,CAAE,GAAI0C,MAAO,CAAC,EACpDC,KAAK,CAACK,aAAa,EACnB/C,MAAM,CAAEyC,MAAM,CAAExC,UAAW,CAAE,CAAC,CAAC+C,iBAAiB,CAAC,CAAC,CAClD;AACF,CAAC;AAED,OAAO,SAASC,4BAA4BA,CAAEP,KAAK,EAAEQ,YAAY,EAAG;EACnE,OAAO,CACNR,KAAK,CAACS,iBAAiB,CAAED,YAAY,CAAE,EACvCR,KAAK,CAAClC,MAAM,CAAC4C,UAAU,CAAChC,GAAG,CAAE8B,YAAa,CAAC,EAC3CR,KAAK,CAACC,QAAQ,CAACb,iBAAiB,EAChCY,KAAK,CAACC,QAAQ,CAACU,YAAY,EAC3BX,KAAK,CAACY,iBAAiB,CACvB;AACF","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wordpress/block-editor",
3
- "version": "13.0.6",
3
+ "version": "13.0.7",
4
4
  "description": "Generic block editor.",
5
5
  "author": "The WordPress Contributors",
6
6
  "license": "GPL-2.0-or-later",
@@ -73,7 +73,7 @@
73
73
  "fast-deep-equal": "^3.1.3",
74
74
  "memize": "^2.1.0",
75
75
  "postcss": "^8.4.21",
76
- "postcss-prefixwrap": "^1.41.0",
76
+ "postcss-prefixwrap": "^1.51.0",
77
77
  "postcss-urlrebase": "^1.0.0",
78
78
  "react-autosize-textarea": "^7.1.0",
79
79
  "react-easy-crop": "^5.0.6",
@@ -86,5 +86,5 @@
86
86
  "publishConfig": {
87
87
  "access": "public"
88
88
  },
89
- "gitHead": "5c1d6bb774e6f78f0bbd4cdc85c4a7087da2f8a0"
89
+ "gitHead": "a74a70ed203bbcbb5f3d34335df9631178647acb"
90
90
  }
@@ -60,7 +60,8 @@ function createBlockCompleter() {
60
60
  }, [] );
61
61
  const [ items, categories, collections ] = useBlockTypesState(
62
62
  rootClientId,
63
- noop
63
+ noop,
64
+ true
64
65
  );
65
66
 
66
67
  const filteredItems = useMemo( () => {
@@ -107,6 +107,7 @@ describe( 'global styles renderer', () => {
107
107
  },
108
108
  },
109
109
  selector: ROOT_BLOCK_SELECTOR,
110
+ skipSelectorWrapper: true,
110
111
  },
111
112
  {
112
113
  styles: {
@@ -481,7 +482,7 @@ describe( 'global styles renderer', () => {
481
482
  };
482
483
 
483
484
  expect( toStyles( tree, blockSelectors ) ).toEqual(
484
- ':where(body) {margin: 0;}.is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }.is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }.is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }.is-layout-constrained > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }.is-layout-constrained > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }.is-layout-constrained > .aligncenter { margin-left: auto !important; margin-right: auto !important; }.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)) { max-width: var(--wp--style--global--content-size); margin-left: auto !important; margin-right: auto !important; }.is-layout-constrained > .alignwide { max-width: var(--wp--style--global--wide-size); }body .is-layout-flex { display:flex; }.is-layout-flex { flex-wrap: wrap; align-items: center; }.is-layout-flex > :is(*, div) { margin: 0; }body .is-layout-grid { display:grid; }.is-layout-grid > :is(*, div) { margin: 0; }:root :where(body){background-color: red;margin: 10px;padding: 10px;}a:where(:not(.wp-element-button)){color: blue;}:root :where(a:where(:not(.wp-element-button)):hover){color: orange;}:root :where(a:where(:not(.wp-element-button)):focus){color: orange;}h1{font-size: 42px;}:root :where(.wp-block-group){margin-top: 10px;margin-right: 20px;margin-bottom: 30px;margin-left: 40px;padding-top: 11px;padding-right: 22px;padding-bottom: 33px;padding-left: 44px;}:root :where(h1,h2,h3,h4,h5,h6){color: orange;}:root :where(h1 a:where(:not(.wp-element-button)),h2 a:where(:not(.wp-element-button)),h3 a:where(:not(.wp-element-button)),h4 a:where(:not(.wp-element-button)),h5 a:where(:not(.wp-element-button)),h6 a:where(:not(.wp-element-button))){color: hotpink;}:root :where(h1 a:where(:not(.wp-element-button)):hover,h2 a:where(:not(.wp-element-button)):hover,h3 a:where(:not(.wp-element-button)):hover,h4 a:where(:not(.wp-element-button)):hover,h5 a:where(:not(.wp-element-button)):hover,h6 a:where(:not(.wp-element-button)):hover){color: red;}:root :where(h1 a:where(:not(.wp-element-button)):focus,h2 a:where(:not(.wp-element-button)):focus,h3 a:where(:not(.wp-element-button)):focus,h4 a:where(:not(.wp-element-button)):focus,h5 a:where(:not(.wp-element-button)):focus,h6 a:where(:not(.wp-element-button)):focus){color: red;}:root :where(.wp-block-image img, .wp-block-image .wp-crop-area){border-radius: 9999px;}:root :where(.wp-block-image){color: red;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.has-white-color{color: var(--wp--preset--color--white) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}h1.has-blue-color,h2.has-blue-color,h3.has-blue-color,h4.has-blue-color,h5.has-blue-color,h6.has-blue-color{color: var(--wp--preset--color--blue) !important;}h1.has-blue-background-color,h2.has-blue-background-color,h3.has-blue-background-color,h4.has-blue-background-color,h5.has-blue-background-color,h6.has-blue-background-color{background-color: var(--wp--preset--color--blue) !important;}h1.has-blue-border-color,h2.has-blue-border-color,h3.has-blue-border-color,h4.has-blue-border-color,h5.has-blue-border-color,h6.has-blue-border-color{border-color: var(--wp--preset--color--blue) !important;}'
485
+ ':where(body) {margin: 0;}.is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }.is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }.is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }.is-layout-constrained > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }.is-layout-constrained > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }.is-layout-constrained > .aligncenter { margin-left: auto !important; margin-right: auto !important; }.is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)) { max-width: var(--wp--style--global--content-size); margin-left: auto !important; margin-right: auto !important; }.is-layout-constrained > .alignwide { max-width: var(--wp--style--global--wide-size); }body .is-layout-flex { display:flex; }.is-layout-flex { flex-wrap: wrap; align-items: center; }.is-layout-flex > :is(*, div) { margin: 0; }body .is-layout-grid { display:grid; }.is-layout-grid > :is(*, div) { margin: 0; }body{background-color: red;margin: 10px;padding: 10px;}a:where(:not(.wp-element-button)){color: blue;}:root :where(a:where(:not(.wp-element-button)):hover){color: orange;}:root :where(a:where(:not(.wp-element-button)):focus){color: orange;}h1{font-size: 42px;}:root :where(.wp-block-group){margin-top: 10px;margin-right: 20px;margin-bottom: 30px;margin-left: 40px;padding-top: 11px;padding-right: 22px;padding-bottom: 33px;padding-left: 44px;}:root :where(h1,h2,h3,h4,h5,h6){color: orange;}:root :where(h1 a:where(:not(.wp-element-button)),h2 a:where(:not(.wp-element-button)),h3 a:where(:not(.wp-element-button)),h4 a:where(:not(.wp-element-button)),h5 a:where(:not(.wp-element-button)),h6 a:where(:not(.wp-element-button))){color: hotpink;}:root :where(h1 a:where(:not(.wp-element-button)):hover,h2 a:where(:not(.wp-element-button)):hover,h3 a:where(:not(.wp-element-button)):hover,h4 a:where(:not(.wp-element-button)):hover,h5 a:where(:not(.wp-element-button)):hover,h6 a:where(:not(.wp-element-button)):hover){color: red;}:root :where(h1 a:where(:not(.wp-element-button)):focus,h2 a:where(:not(.wp-element-button)):focus,h3 a:where(:not(.wp-element-button)):focus,h4 a:where(:not(.wp-element-button)):focus,h5 a:where(:not(.wp-element-button)):focus,h6 a:where(:not(.wp-element-button)):focus){color: red;}:root :where(.wp-block-image img, .wp-block-image .wp-crop-area){border-radius: 9999px;}:root :where(.wp-block-image){color: red;}.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }.has-white-color{color: var(--wp--preset--color--white) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}h1.has-blue-color,h2.has-blue-color,h3.has-blue-color,h4.has-blue-color,h5.has-blue-color,h6.has-blue-color{color: var(--wp--preset--color--blue) !important;}h1.has-blue-background-color,h2.has-blue-background-color,h3.has-blue-background-color,h4.has-blue-background-color,h5.has-blue-background-color,h6.has-blue-background-color{background-color: var(--wp--preset--color--blue) !important;}h1.has-blue-border-color,h2.has-blue-border-color,h3.has-blue-border-color,h4.has-blue-border-color,h5.has-blue-border-color,h6.has-blue-border-color{border-color: var(--wp--preset--color--blue) !important;}'
485
486
  );
486
487
  } );
487
488
 
@@ -762,7 +763,7 @@ describe( 'global styles renderer', () => {
762
763
  } );
763
764
 
764
765
  expect( layoutStyles ).toEqual(
765
- '.is-layout-flow > * { margin-block-start: 0; margin-block-end: 0; }.is-layout-flow > * + * { margin-block-start: 0.5em; margin-block-end: 0; }.is-layout-flex { gap: 0.5em; }:root { --wp--style--block-gap: 0.5em; }.is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }.is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }.is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }body .is-layout-flex { display:flex; }.is-layout-flex { flex-wrap: wrap; align-items: center; }.is-layout-flex > * { margin: 0; }'
766
+ ':root :where(.is-layout-flow) > * { margin-block-start: 0; margin-block-end: 0; }:root :where(.is-layout-flow) > * + * { margin-block-start: 0.5em; margin-block-end: 0; }:root :where(.is-layout-flex) { gap: 0.5em; }:root { --wp--style--block-gap: 0.5em; }.is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }.is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }.is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }body .is-layout-flex { display:flex; }.is-layout-flex { flex-wrap: wrap; align-items: center; }.is-layout-flex > * { margin: 0; }'
766
767
  );
767
768
  } );
768
769
 
@@ -779,7 +780,7 @@ describe( 'global styles renderer', () => {
779
780
  } );
780
781
 
781
782
  expect( layoutStyles ).toEqual(
782
- '.is-layout-flow > * { margin-block-start: 0; margin-block-end: 0; }.is-layout-flow > * + * { margin-block-start: 12px; margin-block-end: 0; }.is-layout-flex { gap: 12px; }:root { --wp--style--block-gap: 12px; }.is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }.is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }.is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }body .is-layout-flex { display:flex; }.is-layout-flex { flex-wrap: wrap; align-items: center; }.is-layout-flex > * { margin: 0; }'
783
+ ':root :where(.is-layout-flow) > * { margin-block-start: 0; margin-block-end: 0; }:root :where(.is-layout-flow) > * + * { margin-block-start: 12px; margin-block-end: 0; }:root :where(.is-layout-flex) { gap: 12px; }:root { --wp--style--block-gap: 12px; }.is-layout-flow > .alignleft { float: left; margin-inline-start: 0; margin-inline-end: 2em; }.is-layout-flow > .alignright { float: right; margin-inline-start: 2em; margin-inline-end: 0; }.is-layout-flow > .aligncenter { margin-left: auto !important; margin-right: auto !important; }body .is-layout-flex { display:flex; }.is-layout-flex { flex-wrap: wrap; align-items: center; }.is-layout-flex > * { margin: 0; }'
783
784
  );
784
785
  } );
785
786
 
@@ -796,7 +797,7 @@ describe( 'global styles renderer', () => {
796
797
  } );
797
798
 
798
799
  expect( layoutStyles ).toEqual(
799
- '.wp-block-group-is-layout-flow > * { margin-block-start: 0; margin-block-end: 0; }.wp-block-group-is-layout-flow > * + * { margin-block-start: 12px; margin-block-end: 0; }.wp-block-group-is-layout-flex { gap: 12px; }'
800
+ ':root :where(.wp-block-group-is-layout-flow) > * { margin-block-start: 0; margin-block-end: 0; }:root :where(.wp-block-group-is-layout-flow) > * + * { margin-block-start: 12px; margin-block-end: 0; }:root :where(.wp-block-group-is-layout-flex) { gap: 12px; }'
800
801
  );
801
802
  } );
802
803
 
@@ -1030,11 +1031,19 @@ describe( 'global styles renderer', () => {
1030
1031
  } );
1031
1032
 
1032
1033
  describe( 'processCSSNesting', () => {
1034
+ it( 'should return empty string when supplied css is empty', () => {
1035
+ expect( processCSSNesting( '', '.foo' ) ).toEqual( '' );
1036
+ } );
1033
1037
  it( 'should return processed CSS without any nested selectors', () => {
1034
1038
  expect(
1035
1039
  processCSSNesting( 'color: red; margin: auto;', '.foo' )
1036
1040
  ).toEqual( ':root :where(.foo){color: red; margin: auto;}' );
1037
1041
  } );
1042
+ it( 'should return processed CSS when there are no root selectors', () => {
1043
+ expect(
1044
+ processCSSNesting( '&::before{color: red;}', '.foo' )
1045
+ ).toEqual( ':root :where(.foo)::before{color: red;}' );
1046
+ } );
1038
1047
  it( 'should return processed CSS with nested selectors', () => {
1039
1048
  expect(
1040
1049
  processCSSNesting(
@@ -1048,21 +1057,21 @@ describe( 'global styles renderer', () => {
1048
1057
  it( 'should return processed CSS with pseudo elements', () => {
1049
1058
  expect(
1050
1059
  processCSSNesting(
1051
- 'color: red; margin: auto; &::before{color: blue;} & ::before{color: green;} &.one::before{color: yellow;} & .two::before{color: purple;}',
1060
+ 'color: red; margin: auto; &::before{color: blue;} & ::before{color: green;} &.one::before{color: yellow;} & .two::before{color: purple;} & > ::before{color: darkseagreen;}',
1052
1061
  '.foo'
1053
1062
  )
1054
1063
  ).toEqual(
1055
- ':root :where(.foo){color: red; margin: auto;}:root :where(.foo::before){color: blue;}:root :where(.foo ::before){color: green;}:root :where(.foo.one::before){color: yellow;}:root :where(.foo .two::before){color: purple;}'
1064
+ ':root :where(.foo){color: red; margin: auto;}:root :where(.foo)::before{color: blue;}:root :where(.foo) ::before{color: green;}:root :where(.foo.one)::before{color: yellow;}:root :where(.foo .two)::before{color: purple;}:root :where(.foo) > ::before{color: darkseagreen;}'
1056
1065
  );
1057
1066
  } );
1058
1067
  it( 'should return processed CSS with multiple root selectors', () => {
1059
1068
  expect(
1060
1069
  processCSSNesting(
1061
- 'color: red; margin: auto; &.one{color: blue;} & .two{color: green;} &::before{color: yellow;} & ::before{color: purple;} &.three::before{color: orange;} & .four::before{color: skyblue;}',
1070
+ 'color: red; margin: auto; &.one{color: blue;} & .two{color: green;} &::before{color: yellow;} & ::before{color: purple;} &.three::before{color: orange;} & .four::before{color: skyblue;} & > ::before{color: darkseagreen;}',
1062
1071
  '.foo, .bar'
1063
1072
  )
1064
1073
  ).toEqual(
1065
- ':root :where(.foo, .bar){color: red; margin: auto;}:root :where(.foo.one, .bar.one){color: blue;}:root :where(.foo .two, .bar .two){color: green;}:root :where(.foo::before, .bar::before){color: yellow;}:root :where(.foo ::before, .bar ::before){color: purple;}:root :where(.foo.three::before, .bar.three::before){color: orange;}:root :where(.foo .four::before, .bar .four::before){color: skyblue;}'
1074
+ ':root :where(.foo, .bar){color: red; margin: auto;}:root :where(.foo.one, .bar.one){color: blue;}:root :where(.foo .two, .bar .two){color: green;}:root :where(.foo, .bar)::before{color: yellow;}:root :where(.foo, .bar) ::before{color: purple;}:root :where(.foo.three, .bar.three)::before{color: orange;}:root :where(.foo .four, .bar .four)::before{color: skyblue;}:root :where(.foo, .bar) > ::before{color: darkseagreen;}'
1066
1075
  );
1067
1076
  } );
1068
1077
  } );
@@ -529,10 +529,10 @@ export function getLayoutStyles( {
529
529
  } else {
530
530
  combinedSelector =
531
531
  selector === ROOT_BLOCK_SELECTOR
532
- ? `.${ className }${
532
+ ? `:root :where(.${ className })${
533
533
  spacingStyle?.selector || ''
534
534
  }`
535
- : `${ selector }-${ className }${
535
+ : `:root :where(${ selector }-${ className })${
536
536
  spacingStyle?.selector || ''
537
537
  }`;
538
538
  }
@@ -634,6 +634,9 @@ export const getNodesWithStyles = ( tree, blockSelectors ) => {
634
634
  nodes.push( {
635
635
  styles,
636
636
  selector: ROOT_BLOCK_SELECTOR,
637
+ // Root selector (body) styles should not be wrapped in `:root where()` to keep
638
+ // specificity at (0,0,1) and maintain backwards compatibility.
639
+ skipSelectorWrapper: true,
637
640
  } );
638
641
  }
639
642
 
@@ -1309,9 +1312,17 @@ function updateConfigWithSeparator( config ) {
1309
1312
  export function processCSSNesting( css, blockSelector ) {
1310
1313
  let processedCSS = '';
1311
1314
 
1315
+ if ( ! css || css.trim() === '' ) {
1316
+ return processedCSS;
1317
+ }
1318
+
1312
1319
  // Split CSS nested rules.
1313
1320
  const parts = css.split( '&' );
1314
1321
  parts.forEach( ( part ) => {
1322
+ if ( ! part || part.trim() === '' ) {
1323
+ return;
1324
+ }
1325
+
1315
1326
  const isRootCss = ! part.includes( '{' );
1316
1327
  if ( isRootCss ) {
1317
1328
  // If the part doesn't contain braces, it applies to the root level.
@@ -1324,11 +1335,32 @@ export function processCSSNesting( css, blockSelector ) {
1324
1335
  }
1325
1336
 
1326
1337
  const [ nestedSelector, cssValue ] = splittedPart;
1327
- const combinedSelector = nestedSelector.startsWith( ' ' )
1328
- ? scopeSelector( blockSelector, nestedSelector )
1329
- : appendToSelector( blockSelector, nestedSelector );
1330
1338
 
1331
- processedCSS += `:root :where(${ combinedSelector }){${ cssValue.trim() }}`;
1339
+ // Handle pseudo elements such as ::before, ::after, etc. Regex will also
1340
+ // capture any leading combinator such as >, +, or ~, as well as spaces.
1341
+ // This allows pseudo elements as descendants e.g. `.parent ::before`.
1342
+ const matches = nestedSelector.match( /([>+~\s]*::[a-zA-Z-]+)/ );
1343
+ const pseudoPart = matches ? matches[ 1 ] : '';
1344
+ const withoutPseudoElement = matches
1345
+ ? nestedSelector.replace( pseudoPart, '' ).trim()
1346
+ : nestedSelector.trim();
1347
+
1348
+ let combinedSelector;
1349
+ if ( withoutPseudoElement === '' ) {
1350
+ // Only contained a pseudo element to use the block selector to form
1351
+ // the final `:root :where()` selector.
1352
+ combinedSelector = blockSelector;
1353
+ } else {
1354
+ // If the nested selector is a descendant of the block scope it with the
1355
+ // block selector. Otherwise append it to the block selector.
1356
+ combinedSelector = nestedSelector.startsWith( ' ' )
1357
+ ? scopeSelector( blockSelector, withoutPseudoElement )
1358
+ : appendToSelector( blockSelector, withoutPseudoElement );
1359
+ }
1360
+
1361
+ // Build final rule, re-adding any pseudo element outside the `:where()`
1362
+ // to maintain valid CSS selector.
1363
+ processedCSS += `:root :where(${ combinedSelector })${ pseudoPart }{${ cssValue.trim() }}`;
1332
1364
  }
1333
1365
  } );
1334
1366
  return processedCSS;
@@ -20,6 +20,7 @@ import {
20
20
  checkAllowListRecursive,
21
21
  getAllPatternsDependants,
22
22
  getInsertBlockTypeDependants,
23
+ getParsedPattern,
23
24
  } from './utils';
24
25
  import { INSERTER_PATTERN_TYPES } from '../components/inserter/block-patterns-tab/utils';
25
26
  import { STORE_NAME } from './constants';
@@ -291,16 +292,15 @@ export const getInserterMediaCategories = createSelector(
291
292
  export const hasAllowedPatterns = createRegistrySelector( ( select ) =>
292
293
  createSelector(
293
294
  ( state, rootClientId = null ) => {
294
- const { getAllPatterns, __experimentalGetParsedPattern } = unlock(
295
- select( STORE_NAME )
296
- );
295
+ const { getAllPatterns } = unlock( select( STORE_NAME ) );
297
296
  const patterns = getAllPatterns();
298
297
  const { allowedBlockTypes } = getSettings( state );
299
- return patterns.some( ( { name, inserter = true } ) => {
298
+ return patterns.some( ( pattern ) => {
299
+ const { inserter = true } = pattern;
300
300
  if ( ! inserter ) {
301
301
  return false;
302
302
  }
303
- const { blocks } = __experimentalGetParsedPattern( name );
303
+ const { blocks } = getParsedPattern( pattern );
304
304
  return (
305
305
  checkAllowListRecursive( blocks, allowedBlockTypes ) &&
306
306
  blocks.every( ( { name: blockName } ) =>
@@ -7,7 +7,6 @@ import {
7
7
  getBlockVariations,
8
8
  hasBlockSupport,
9
9
  getPossibleBlockTransformations,
10
- parse,
11
10
  switchToBlockType,
12
11
  store as blocksStore,
13
12
  } from '@wordpress/blocks';
@@ -27,6 +26,7 @@ import {
27
26
  checkAllowList,
28
27
  getAllPatternsDependants,
29
28
  getInsertBlockTypeDependants,
29
+ getParsedPattern,
30
30
  } from './utils';
31
31
  import { orderBy } from '../utils/sorting';
32
32
  import { STORE_NAME } from './constants';
@@ -2349,40 +2349,12 @@ export function __experimentalGetDirectInsertBlock(
2349
2349
  }
2350
2350
 
2351
2351
  export const __experimentalGetParsedPattern = createRegistrySelector(
2352
- ( select ) =>
2353
- createSelector(
2354
- ( state, patternName ) => {
2355
- const pattern = unlock( select( STORE_NAME ) ).getPatternBySlug(
2356
- patternName
2357
- );
2358
- if ( ! pattern ) {
2359
- return null;
2360
- }
2361
- const blocks = parse( pattern.content, {
2362
- __unstableSkipMigrationLogs: true,
2363
- } );
2364
- if ( blocks.length === 1 ) {
2365
- blocks[ 0 ].attributes = {
2366
- ...blocks[ 0 ].attributes,
2367
- metadata: {
2368
- ...( blocks[ 0 ].attributes.metadata || {} ),
2369
- categories: pattern.categories,
2370
- patternName: pattern.name,
2371
- name:
2372
- blocks[ 0 ].attributes.metadata?.name ||
2373
- pattern.title,
2374
- },
2375
- };
2376
- }
2377
- return {
2378
- ...pattern,
2379
- blocks,
2380
- };
2381
- },
2382
- ( state, patternName ) => [
2383
- unlock( select( STORE_NAME ) ).getPatternBySlug( patternName ),
2384
- ]
2385
- )
2352
+ ( select ) => ( state, patternName ) => {
2353
+ const pattern = unlock( select( STORE_NAME ) ).getPatternBySlug(
2354
+ patternName
2355
+ );
2356
+ return pattern ? getParsedPattern( pattern ) : null;
2357
+ }
2386
2358
  );
2387
2359
 
2388
2360
  const getAllowedPatternsDependants = ( select ) => ( state, rootClientId ) => [
@@ -2401,16 +2373,13 @@ const getAllowedPatternsDependants = ( select ) => ( state, rootClientId ) => [
2401
2373
  export const __experimentalGetAllowedPatterns = createRegistrySelector(
2402
2374
  ( select ) => {
2403
2375
  return createSelector( ( state, rootClientId = null ) => {
2404
- const {
2405
- getAllPatterns,
2406
- __experimentalGetParsedPattern: getParsedPattern,
2407
- } = unlock( select( STORE_NAME ) );
2376
+ const { getAllPatterns } = unlock( select( STORE_NAME ) );
2408
2377
  const patterns = getAllPatterns();
2409
2378
  const { allowedBlockTypes } = getSettings( state );
2410
2379
 
2411
2380
  const parsedPatterns = patterns
2412
2381
  .filter( ( { inserter = true } ) => !! inserter )
2413
- .map( ( { name } ) => getParsedPattern( name ) );
2382
+ .map( getParsedPattern );
2414
2383
  const availableParsedPatterns = parsedPatterns.filter(
2415
2384
  ( { blocks } ) =>
2416
2385
  checkAllowListRecursive( blocks, allowedBlockTypes )
@@ -1,3 +1,8 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { parse } from '@wordpress/blocks';
5
+
1
6
  /**
2
7
  * Internal dependencies
3
8
  */
@@ -7,6 +12,39 @@ import { STORE_NAME } from './constants';
7
12
 
8
13
  export const withRootClientIdOptionKey = Symbol( 'withRootClientId' );
9
14
 
15
+ const parsedPatternCache = new WeakMap();
16
+
17
+ function parsePattern( pattern ) {
18
+ const blocks = parse( pattern.content, {
19
+ __unstableSkipMigrationLogs: true,
20
+ } );
21
+ if ( blocks.length === 1 ) {
22
+ blocks[ 0 ].attributes = {
23
+ ...blocks[ 0 ].attributes,
24
+ metadata: {
25
+ ...( blocks[ 0 ].attributes.metadata || {} ),
26
+ categories: pattern.categories,
27
+ patternName: pattern.name,
28
+ name: blocks[ 0 ].attributes.metadata?.name || pattern.title,
29
+ },
30
+ };
31
+ }
32
+ return {
33
+ ...pattern,
34
+ blocks,
35
+ };
36
+ }
37
+
38
+ export function getParsedPattern( pattern ) {
39
+ let parsedPattern = parsedPatternCache.get( pattern );
40
+ if ( parsedPattern ) {
41
+ return parsedPattern;
42
+ }
43
+ parsedPattern = parsePattern( pattern );
44
+ parsedPatternCache.set( pattern, parsedPattern );
45
+ return parsedPattern;
46
+ }
47
+
10
48
  export const checkAllowList = ( list, item, defaultResult = null ) => {
11
49
  if ( typeof list === 'boolean' ) {
12
50
  return list;
@@ -125,6 +125,21 @@ describe( 'transformStyles', () => {
125
125
  expect( output ).toMatchSnapshot();
126
126
  } );
127
127
 
128
+ it( `should not try to replace 'body' in the middle of a classname`, () => {
129
+ const prefix = '.my-namespace';
130
+ const input = `.has-body-text { color: red; }`;
131
+ const output = transformStyles(
132
+ [
133
+ {
134
+ css: input,
135
+ },
136
+ ],
137
+ prefix
138
+ );
139
+
140
+ expect( output ).toEqual( [ `${ prefix } ${ input }` ] );
141
+ } );
142
+
128
143
  it( 'should ignore keyframes', () => {
129
144
  const input = `
130
145
  @keyframes edit-post__fade-in-animation {
@@ -210,6 +225,40 @@ describe( 'transformStyles', () => {
210
225
 
211
226
  expect( output ).toMatchSnapshot();
212
227
  } );
228
+
229
+ it( 'should not try to wrap items within `:where` selectors', () => {
230
+ const input = `:where(.wp-element-button:active, .wp-block-button__link:active) { color: blue; }`;
231
+ const prefix = '.my-namespace';
232
+ const expected = [ `${ prefix } ${ input }` ];
233
+
234
+ const output = transformStyles(
235
+ [
236
+ {
237
+ css: input,
238
+ },
239
+ ],
240
+ prefix
241
+ );
242
+
243
+ expect( output ).toEqual( expected );
244
+ } );
245
+
246
+ it( 'should not try to prefix pseudo elements on `:where` selectors', () => {
247
+ const input = `:where(.wp-element-button, .wp-block-button__link)::before { color: blue; }`;
248
+ const prefix = '.my-namespace';
249
+ const expected = [ `${ prefix } ${ input }` ];
250
+
251
+ const output = transformStyles(
252
+ [
253
+ {
254
+ css: input,
255
+ },
256
+ ],
257
+ prefix
258
+ );
259
+
260
+ expect( output ).toEqual( expected );
261
+ } );
213
262
  } );
214
263
 
215
264
  it( 'should not break with data urls', () => {