@wordpress/block-editor 15.8.1-next.dc3f6d3c1.0 → 15.9.0

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.
Files changed (205) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/components/block-list/index.js +2 -1
  3. package/build/components/block-list/index.js.map +2 -2
  4. package/build/components/block-list/use-block-props/use-selected-block-event-handlers.js +27 -5
  5. package/build/components/block-list/use-block-props/use-selected-block-event-handlers.js.map +2 -2
  6. package/build/components/block-lock/modal.js +5 -5
  7. package/build/components/block-lock/modal.js.map +2 -2
  8. package/build/components/block-lock/use-block-lock.js +10 -13
  9. package/build/components/block-lock/use-block-lock.js.map +2 -2
  10. package/build/components/block-settings-menu-controls/index.js +1 -1
  11. package/build/components/block-settings-menu-controls/index.js.map +2 -2
  12. package/build/components/block-tools/index.js +56 -45
  13. package/build/components/block-tools/index.js.map +3 -3
  14. package/build/components/block-visibility/toolbar.js +1 -1
  15. package/build/components/block-visibility/toolbar.js.map +1 -1
  16. package/build/components/content-only-controls/fields-dropdown-menu.js +66 -0
  17. package/build/components/content-only-controls/fields-dropdown-menu.js.map +7 -0
  18. package/build/components/content-only-controls/index.js +225 -44
  19. package/build/components/content-only-controls/index.js.map +3 -3
  20. package/build/components/content-only-controls/link/index.js +92 -103
  21. package/build/components/content-only-controls/link/index.js.map +3 -3
  22. package/build/components/content-only-controls/media/index.js +134 -134
  23. package/build/components/content-only-controls/media/index.js.map +3 -3
  24. package/build/components/content-only-controls/rich-text/index.js +65 -74
  25. package/build/components/content-only-controls/rich-text/index.js.map +3 -3
  26. package/build/components/font-family/index.js +1 -15
  27. package/build/components/font-family/index.js.map +2 -2
  28. package/build/components/global-styles/dimensions-panel.js +35 -2
  29. package/build/components/global-styles/dimensions-panel.js.map +2 -2
  30. package/build/components/global-styles/hooks.js +1 -1
  31. package/build/components/global-styles/hooks.js.map +2 -2
  32. package/build/components/global-styles/typography-panel.js +1 -2
  33. package/build/components/global-styles/typography-panel.js.map +2 -2
  34. package/build/components/inspector-controls-tabs/use-inspector-controls-tabs.js +1 -1
  35. package/build/components/inspector-controls-tabs/use-inspector-controls-tabs.js.map +2 -2
  36. package/build/components/link-control/index.js +15 -7
  37. package/build/components/link-control/index.js.map +2 -2
  38. package/build/components/list-view/block-select-button.js +3 -11
  39. package/build/components/list-view/block-select-button.js.map +2 -2
  40. package/build/components/list-view/block.js +9 -7
  41. package/build/components/list-view/block.js.map +2 -2
  42. package/build/components/media-placeholder/index.js +17 -4
  43. package/build/components/media-placeholder/index.js.map +2 -2
  44. package/build/components/media-placeholder/utils.js +60 -0
  45. package/build/components/media-placeholder/utils.js.map +7 -0
  46. package/build/components/media-replace-flow/index.js +20 -3
  47. package/build/components/media-replace-flow/index.js.map +2 -2
  48. package/build/components/use-block-commands/index.js +1 -1
  49. package/build/components/use-block-commands/index.js.map +2 -2
  50. package/build/components/use-block-drop-zone/index.js +1 -5
  51. package/build/components/use-block-drop-zone/index.js.map +2 -2
  52. package/build/hooks/dimensions.js +3 -3
  53. package/build/hooks/dimensions.js.map +2 -2
  54. package/build/hooks/metadata.js +1 -1
  55. package/build/hooks/metadata.js.map +2 -2
  56. package/build/hooks/utils.js +5 -1
  57. package/build/hooks/utils.js.map +2 -2
  58. package/build/store/private-selectors.js +43 -3
  59. package/build/store/private-selectors.js.map +2 -2
  60. package/build/store/reducer.js +2 -1
  61. package/build/store/reducer.js.map +2 -2
  62. package/build/store/selectors.js +6 -4
  63. package/build/store/selectors.js.map +2 -2
  64. package/build-module/components/block-list/index.js +2 -1
  65. package/build-module/components/block-list/index.js.map +2 -2
  66. package/build-module/components/block-list/use-block-props/use-selected-block-event-handlers.js +27 -5
  67. package/build-module/components/block-list/use-block-props/use-selected-block-event-handlers.js.map +2 -2
  68. package/build-module/components/block-lock/modal.js +5 -5
  69. package/build-module/components/block-lock/modal.js.map +2 -2
  70. package/build-module/components/block-lock/use-block-lock.js +10 -13
  71. package/build-module/components/block-lock/use-block-lock.js.map +2 -2
  72. package/build-module/components/block-settings-menu-controls/index.js +1 -1
  73. package/build-module/components/block-settings-menu-controls/index.js.map +2 -2
  74. package/build-module/components/block-tools/index.js +56 -45
  75. package/build-module/components/block-tools/index.js.map +2 -2
  76. package/build-module/components/block-visibility/toolbar.js +1 -1
  77. package/build-module/components/block-visibility/toolbar.js.map +1 -1
  78. package/build-module/components/content-only-controls/fields-dropdown-menu.js +45 -0
  79. package/build-module/components/content-only-controls/fields-dropdown-menu.js.map +7 -0
  80. package/build-module/components/content-only-controls/index.js +229 -46
  81. package/build-module/components/content-only-controls/index.js.map +2 -2
  82. package/build-module/components/content-only-controls/link/index.js +92 -104
  83. package/build-module/components/content-only-controls/link/index.js.map +2 -2
  84. package/build-module/components/content-only-controls/media/index.js +134 -135
  85. package/build-module/components/content-only-controls/media/index.js.map +2 -2
  86. package/build-module/components/content-only-controls/rich-text/index.js +67 -81
  87. package/build-module/components/content-only-controls/rich-text/index.js.map +2 -2
  88. package/build-module/components/font-family/index.js +1 -15
  89. package/build-module/components/font-family/index.js.map +2 -2
  90. package/build-module/components/global-styles/dimensions-panel.js +35 -2
  91. package/build-module/components/global-styles/dimensions-panel.js.map +2 -2
  92. package/build-module/components/global-styles/hooks.js +1 -1
  93. package/build-module/components/global-styles/hooks.js.map +2 -2
  94. package/build-module/components/global-styles/typography-panel.js +1 -2
  95. package/build-module/components/global-styles/typography-panel.js.map +2 -2
  96. package/build-module/components/inspector-controls-tabs/use-inspector-controls-tabs.js +1 -1
  97. package/build-module/components/inspector-controls-tabs/use-inspector-controls-tabs.js.map +2 -2
  98. package/build-module/components/link-control/index.js +16 -8
  99. package/build-module/components/link-control/index.js.map +2 -2
  100. package/build-module/components/list-view/block-select-button.js +3 -11
  101. package/build-module/components/list-view/block-select-button.js.map +2 -2
  102. package/build-module/components/list-view/block.js +9 -7
  103. package/build-module/components/list-view/block.js.map +2 -2
  104. package/build-module/components/media-placeholder/index.js +18 -5
  105. package/build-module/components/media-placeholder/index.js.map +2 -2
  106. package/build-module/components/media-placeholder/utils.js +35 -0
  107. package/build-module/components/media-placeholder/utils.js.map +7 -0
  108. package/build-module/components/media-replace-flow/index.js +20 -3
  109. package/build-module/components/media-replace-flow/index.js.map +2 -2
  110. package/build-module/components/use-block-commands/index.js +1 -1
  111. package/build-module/components/use-block-commands/index.js.map +2 -2
  112. package/build-module/components/use-block-drop-zone/index.js +1 -5
  113. package/build-module/components/use-block-drop-zone/index.js.map +2 -2
  114. package/build-module/hooks/dimensions.js +3 -3
  115. package/build-module/hooks/dimensions.js.map +2 -2
  116. package/build-module/hooks/metadata.js +1 -1
  117. package/build-module/hooks/metadata.js.map +2 -2
  118. package/build-module/hooks/utils.js +5 -1
  119. package/build-module/hooks/utils.js.map +2 -2
  120. package/build-module/store/private-selectors.js +39 -3
  121. package/build-module/store/private-selectors.js.map +2 -2
  122. package/build-module/store/reducer.js +2 -1
  123. package/build-module/store/reducer.js.map +2 -2
  124. package/build-module/store/selectors.js +6 -4
  125. package/build-module/store/selectors.js.map +2 -2
  126. package/build-style/content-rtl.css +3 -0
  127. package/build-style/content.css +3 -0
  128. package/build-style/style-rtl.css +14 -5
  129. package/build-style/style.css +14 -5
  130. package/package.json +38 -37
  131. package/src/components/block-list/content.scss +5 -0
  132. package/src/components/block-list/index.js +3 -1
  133. package/src/components/block-list/use-block-props/use-selected-block-event-handlers.js +34 -3
  134. package/src/components/block-lock/modal.js +6 -5
  135. package/src/components/block-lock/use-block-lock.js +10 -14
  136. package/src/components/block-patterns-list/stories/{index.story.js → index.story.jsx} +3 -1
  137. package/src/components/block-settings-menu-controls/index.js +1 -1
  138. package/src/components/block-tools/index.js +15 -2
  139. package/src/components/block-tools/style.scss +4 -0
  140. package/src/components/block-visibility/toolbar.js +1 -1
  141. package/src/components/content-only-controls/fields-dropdown-menu.js +53 -0
  142. package/src/components/content-only-controls/index.js +314 -50
  143. package/src/components/content-only-controls/link/index.js +62 -57
  144. package/src/components/content-only-controls/media/index.js +177 -156
  145. package/src/components/content-only-controls/rich-text/index.js +30 -44
  146. package/src/components/content-only-controls/styles.scss +10 -1
  147. package/src/components/font-family/README.md +0 -9
  148. package/src/components/font-family/index.js +1 -16
  149. package/src/components/font-family/stories/{index.story.js → index.story.jsx} +0 -1
  150. package/src/components/global-styles/dimensions-panel.js +36 -0
  151. package/src/components/global-styles/hooks.js +1 -1
  152. package/src/components/global-styles/typography-panel.js +0 -1
  153. package/src/components/inspector-controls-tabs/use-inspector-controls-tabs.js +1 -5
  154. package/src/components/link-control/index.js +36 -12
  155. package/src/components/list-view/block-select-button.js +22 -30
  156. package/src/components/list-view/block.js +9 -7
  157. package/src/components/media-placeholder/index.js +20 -5
  158. package/src/components/media-placeholder/test/get-computed-accept-attribute.js +164 -0
  159. package/src/components/media-placeholder/utils.js +65 -0
  160. package/src/components/media-replace-flow/index.js +22 -3
  161. package/src/components/use-block-commands/index.js +1 -1
  162. package/src/components/use-block-drop-zone/index.js +1 -5
  163. package/src/hooks/dimensions.js +8 -3
  164. package/src/hooks/metadata.js +1 -1
  165. package/src/hooks/test/metadata.js +1 -1
  166. package/src/hooks/utils.js +4 -0
  167. package/src/store/private-selectors.js +123 -6
  168. package/src/store/reducer.js +3 -0
  169. package/src/store/selectors.js +6 -4
  170. package/src/store/test/private-selectors.js +242 -0
  171. package/src/store/test/reducer.js +17 -7
  172. package/src/style.scss +0 -1
  173. package/tsconfig.json +1 -0
  174. package/build/components/content-only-controls/plain-text/index.js +0 -68
  175. package/build/components/content-only-controls/plain-text/index.js.map +0 -7
  176. package/build-module/components/content-only-controls/plain-text/index.js +0 -50
  177. package/build-module/components/content-only-controls/plain-text/index.js.map +0 -7
  178. package/src/components/content-only-controls/plain-text/index.js +0 -49
  179. package/src/components/font-family/style.scss +0 -7
  180. /package/src/components/alignment-control/stories/{aliginment-toolbar.story.js → aliginment-toolbar.story.jsx} +0 -0
  181. /package/src/components/alignment-control/stories/{index.story.js → index.story.jsx} +0 -0
  182. /package/src/components/block-alignment-matrix-control/stories/{index.story.js → index.story.jsx} +0 -0
  183. /package/src/components/block-draggable/stories/{index.story.js → index.story.jsx} +0 -0
  184. /package/src/components/block-heading-level-dropdown/stories/{index.story.js → index.story.jsx} +0 -0
  185. /package/src/components/block-mover/stories/{index.story.js → index.story.jsx} +0 -0
  186. /package/src/components/block-title/stories/{index.story.js → index.story.jsx} +0 -0
  187. /package/src/components/border-radius-control/stories/{index.story.js → index.story.jsx} +0 -0
  188. /package/src/components/date-format-picker/stories/{index.story.js → index.story.jsx} +0 -0
  189. /package/src/components/dimensions-tool/stories/{aspect-ratio-tool.story.js → aspect-ratio-tool.story.jsx} +0 -0
  190. /package/src/components/dimensions-tool/stories/{index.story.js → index.story.jsx} +0 -0
  191. /package/src/components/dimensions-tool/stories/{scale-tool.story.js → scale-tool.story.jsx} +0 -0
  192. /package/src/components/dimensions-tool/stories/{width-height-tool.story.js → width-height-tool.story.jsx} +0 -0
  193. /package/src/components/height-control/stories/{index.story.js → index.story.jsx} +0 -0
  194. /package/src/components/inserter/stories/{index.story.js → index.story.jsx} +0 -0
  195. /package/src/components/line-height-control/stories/{index.story.js → index.story.jsx} +0 -0
  196. /package/src/components/plain-text/stories/{index.story.js → index.story.jsx} +0 -0
  197. /package/src/components/resolution-tool/stories/{index.story.js → index.story.jsx} +0 -0
  198. /package/src/components/tabbed-sidebar/stories/{index.story.js → index.story.jsx} +0 -0
  199. /package/src/components/text-alignment-control/stories/{index.story.js → index.story.jsx} +0 -0
  200. /package/src/components/text-decoration-control/stories/{index.story.js → index.story.jsx} +0 -0
  201. /package/src/components/text-transform-control/stories/{index.story.js → index.story.jsx} +0 -0
  202. /package/src/components/unit-control/stories/{index.story.js → index.story.jsx} +0 -0
  203. /package/src/components/url-popover/stories/{index.story.js → index.story.jsx} +0 -0
  204. /package/src/components/warning/stories/{index.story.js → index.story.jsx} +0 -0
  205. /package/src/components/writing-mode-control/stories/{index.story.js → index.story.jsx} +0 -0
@@ -224,7 +224,7 @@ const getQuickActionsCommands = () =>
224
224
  const canRemove = canRemoveBlocks( clientIds );
225
225
 
226
226
  const canToggleBlockVisibility = blocks.every( ( { clientId } ) =>
227
- hasBlockSupport( getBlockName( clientId ), 'blockVisibility', true )
227
+ hasBlockSupport( getBlockName( clientId ), 'visibility', true )
228
228
  );
229
229
 
230
230
  const commands = [];
@@ -415,11 +415,7 @@ export default function useBlockDropZone( {
415
415
  // Filter out blocks that are hidden
416
416
  .filter( ( block ) => {
417
417
  return ! (
418
- hasBlockSupport(
419
- block.name,
420
- 'blockVisibility',
421
- true
422
- ) &&
418
+ hasBlockSupport( block.name, 'visibility', true ) &&
423
419
  block.attributes?.metadata?.blockVisibility ===
424
420
  false
425
421
  );
@@ -81,6 +81,7 @@ export function DimensionsPanel( { clientId, name, setAttributes, settings } ) {
81
81
  },
82
82
  [ clientId, isEnabled ]
83
83
  );
84
+
84
85
  const [ visualizedProperty, setVisualizedProperty ] = useVisualizer();
85
86
  const onChange = ( newStyle ) => {
86
87
  setAttributes( {
@@ -156,7 +157,11 @@ export function hasDimensionsSupport( blockName, feature = 'any' ) {
156
157
  }
157
158
 
158
159
  if ( feature === 'any' ) {
159
- return !! ( support?.aspectRatio || !! support?.minHeight );
160
+ return !! (
161
+ support?.aspectRatio ||
162
+ !! support?.minHeight ||
163
+ !! support?.width
164
+ );
160
165
  }
161
166
 
162
167
  return !! support?.[ feature ];
@@ -164,9 +169,9 @@ export function hasDimensionsSupport( blockName, feature = 'any' ) {
164
169
 
165
170
  export default {
166
171
  useBlockProps,
167
- attributeKeys: [ 'minHeight', 'style' ],
172
+ attributeKeys: [ 'minHeight', 'width', 'style' ],
168
173
  hasSupport( name ) {
169
- return hasDimensionsSupport( name, 'aspectRatio' );
174
+ return hasDimensionsSupport( name );
170
175
  },
171
176
  };
172
177
 
@@ -91,7 +91,7 @@ export function addTransforms( result, source, index, results ) {
91
91
  if (
92
92
  sourceMetadata.blockVisibility !== undefined &&
93
93
  ! result.attributes?.metadata?.blockVisibility &&
94
- hasBlockSupport( result.name, 'blockVisibility', true )
94
+ hasBlockSupport( result.name, 'visibility', true )
95
95
  ) {
96
96
  preservedMetadata.blockVisibility = sourceMetadata.blockVisibility;
97
97
  }
@@ -254,7 +254,7 @@ describe( 'metadata', () => {
254
254
  registerBlockType( 'core/bar', {
255
255
  title: 'Bar',
256
256
  supports: {
257
- blockVisibility: false,
257
+ visibility: false,
258
258
  },
259
259
  } );
260
260
 
@@ -263,6 +263,7 @@ export function useBlockSettings( name, parentLayout ) {
263
263
  units,
264
264
  aspectRatio,
265
265
  minHeight,
266
+ width,
266
267
  layout,
267
268
  borderColor,
268
269
  borderRadius,
@@ -321,6 +322,7 @@ export function useBlockSettings( name, parentLayout ) {
321
322
  'spacing.units',
322
323
  'dimensions.aspectRatio',
323
324
  'dimensions.minHeight',
325
+ 'dimensions.width',
324
326
  'layout',
325
327
  'border.color',
326
328
  'border.radius',
@@ -430,6 +432,7 @@ export function useBlockSettings( name, parentLayout ) {
430
432
  dimensions: {
431
433
  aspectRatio,
432
434
  minHeight,
435
+ width,
433
436
  },
434
437
  layout,
435
438
  parentLayout,
@@ -466,6 +469,7 @@ export function useBlockSettings( name, parentLayout ) {
466
469
  units,
467
470
  aspectRatio,
468
471
  minHeight,
472
+ width,
469
473
  layout,
470
474
  parentLayout,
471
475
  borderColor,
@@ -518,20 +518,31 @@ export function isSectionBlock( state, clientId ) {
518
518
  }
519
519
 
520
520
  const blockName = getBlockName( state, clientId );
521
- if (
522
- blockName === 'core/block' ||
523
- getTemplateLock( state, clientId ) === 'contentOnly'
524
- ) {
521
+ if ( blockName === 'core/block' ) {
525
522
  return true;
526
523
  }
527
524
 
528
525
  const attributes = getBlockAttributes( state, clientId );
526
+ const isTemplatePart = blockName === 'core/template-part';
529
527
  if (
530
- attributes?.metadata?.patternName &&
528
+ ( attributes?.metadata?.patternName || isTemplatePart ) &&
531
529
  !! window?.__experimentalContentOnlyPatternInsertion
532
530
  ) {
533
531
  return true;
534
532
  }
533
+
534
+ // TemplateLock cascades to all inner parent blocks. Only the top-level
535
+ // block that's contentOnly templateLocked is the true contentLocker,
536
+ // all the others are mere imitators.
537
+ const hasContentOnlyTempateLock =
538
+ getTemplateLock( state, clientId ) === 'contentOnly';
539
+ const rootClientId = getBlockRootClientId( state, clientId );
540
+ const hasRootContentOnlyTemplateLock =
541
+ getTemplateLock( state, rootClientId ) === 'contentOnly';
542
+ if ( hasContentOnlyTempateLock && ! hasRootContentOnlyTemplateLock ) {
543
+ return true;
544
+ }
545
+
535
546
  return false;
536
547
  }
537
548
 
@@ -699,7 +710,7 @@ export function getInsertionPoint( state ) {
699
710
  */
700
711
  export const isBlockHidden = ( state, clientId ) => {
701
712
  const blockName = getBlockName( state, clientId );
702
- if ( ! hasBlockSupport( state, blockName, 'blockVisibility', true ) ) {
713
+ if ( ! hasBlockSupport( state, blockName, 'visibility', true ) ) {
703
714
  return false;
704
715
  }
705
716
  const attributes = state.blocks.attributes.get( clientId );
@@ -719,3 +730,109 @@ export const isBlockHidden = ( state, clientId ) => {
719
730
  export function hasBlockSpotlight( state ) {
720
731
  return !! state.hasBlockSpotlight || !! state.editedContentOnlySection;
721
732
  }
733
+
734
+ /**
735
+ * Returns whether a block is locked to prevent editing.
736
+ *
737
+ * This selector only reasons about block lock, not associated features
738
+ * like `blockEditingMode` that might prevent user modifications to a block.
739
+ * Currently there's also no way to prevent editing via `templateLock`.
740
+ *
741
+ * This distinction is important as this selector specifically drives the block lock UI
742
+ * that a user interacts with. `blockEditingModes` aren't included as a user can't change
743
+ * them.
744
+ *
745
+ * @param {Object} state Global application state.
746
+ * @param {string} clientId ClientId of the block.
747
+ *
748
+ * @return {boolean} Whether the block is currently locked.
749
+ */
750
+ export function isEditLockedBlock( state, clientId ) {
751
+ const attributes = getBlockAttributes( state, clientId );
752
+ return !! attributes?.lock?.edit;
753
+ }
754
+
755
+ /**
756
+ * Returns whether a block is locked to prevent moving.
757
+ *
758
+ * This selector only reasons about templateLock and block lock, not associated features
759
+ * like `blockEditingMode` that might prevent user modifications to a block.
760
+ *
761
+ * This distinction is important as this selector specifically drives the block lock UI
762
+ * that a user interacts with. `blockEditingModes` are excluded as a user can't change
763
+ * them.
764
+ *
765
+ * @param {Object} state Global application state.
766
+ * @param {string} clientId ClientId of the block.
767
+ *
768
+ * @return {boolean} Whether the block is currently locked.
769
+ */
770
+ export function isMoveLockedBlock( state, clientId ) {
771
+ const attributes = getBlockAttributes( state, clientId );
772
+ // If a block explicitly has `move` set to `false`, it turns off
773
+ // any locking that might be inherited from a parent.
774
+ if ( attributes?.lock?.move !== undefined ) {
775
+ return !! attributes?.lock?.move;
776
+ }
777
+
778
+ const rootClientId = getBlockRootClientId( state, clientId );
779
+ const templateLock = getTemplateLock( state, rootClientId );
780
+
781
+ // While `contentOnly` templateLock does sometimes prevent moving, a user can't modify
782
+ // this, so don't include it in this function. See the `canMoveBlock` selector
783
+ // as an alternative.
784
+ return templateLock === 'all';
785
+ }
786
+
787
+ /**
788
+ * Returns whether a block is locked to prevent removal.
789
+ *
790
+ * This selector only reasons about templateLock and block lock, not associated features
791
+ * like `blockEditingMode` that might prevent user modifications to a block.
792
+ *
793
+ * This distinction is important as this selector specifically drives the block lock UI
794
+ * that a user interacts with. `blockEditingModes` are excluded as a user can't change
795
+ * them.
796
+ *
797
+ * @param {Object} state Global application state.
798
+ * @param {string} clientId ClientId of the block.
799
+ *
800
+ * @return {boolean} Whether the block is currently locked.
801
+ */
802
+ export function isRemoveLockedBlock( state, clientId ) {
803
+ const attributes = getBlockAttributes( state, clientId );
804
+ if ( attributes?.lock?.remove !== undefined ) {
805
+ return !! attributes?.lock?.remove;
806
+ }
807
+
808
+ const rootClientId = getBlockRootClientId( state, clientId );
809
+ const templateLock = getTemplateLock( state, rootClientId );
810
+
811
+ // While `contentOnly` templateLock does sometimes prevent removal, a user can't modify
812
+ // this, so don't include it in this function. See the `canRemoveBlock` selector
813
+ // as an alternative.
814
+ return templateLock === 'all' || templateLock === 'insert';
815
+ }
816
+
817
+ /**
818
+ * Returns whether a block is locked.
819
+ *
820
+ * This selector only reasons about templateLock and block lock, not associated features
821
+ * like `blockEditingMode` that might prevent user modifications to a block.
822
+ *
823
+ * This distinction is important as this selector specifically drives the block lock UI
824
+ * that a user interacts with. `blockEditingModes` are excluded as a user can't change
825
+ * them.
826
+ *
827
+ * @param {Object} state Global application state.
828
+ * @param {string} clientId ClientId of the block.
829
+ *
830
+ * @return {boolean} Whether the block is currently locked.
831
+ */
832
+ export function isLockedBlock( state, clientId ) {
833
+ return (
834
+ isEditLockedBlock( state, clientId ) ||
835
+ isMoveLockedBlock( state, clientId ) ||
836
+ isRemoveLockedBlock( state, clientId )
837
+ );
838
+ }
@@ -2305,6 +2305,9 @@ function getDerivedBlockEditingModesForTree( state, treeClientId = '' ) {
2305
2305
  const contentOnlyParents = [
2306
2306
  ...contentOnlyTemplateLockedClientIds,
2307
2307
  ...unsyncedPatternClientIds,
2308
+ ...( window?.__experimentalContentOnlyPatternInsertion
2309
+ ? templatePartClientIds
2310
+ : [] ),
2308
2311
  ];
2309
2312
 
2310
2313
  traverseBlockTree( state, treeClientId, ( block ) => {
@@ -1693,7 +1693,8 @@ const canInsertBlockTypeUnmemoized = (
1693
1693
  blockType = getBlockType( blockName );
1694
1694
  }
1695
1695
 
1696
- if ( getTemplateLock( state, rootClientId ) ) {
1696
+ const rootTemplateLock = getTemplateLock( state, rootClientId );
1697
+ if ( rootTemplateLock && rootTemplateLock !== 'contentOnly' ) {
1697
1698
  return false;
1698
1699
  }
1699
1700
 
@@ -1876,7 +1877,8 @@ export function canRemoveBlock( state, clientId ) {
1876
1877
  }
1877
1878
 
1878
1879
  const rootClientId = getBlockRootClientId( state, clientId );
1879
- if ( getTemplateLock( state, rootClientId ) ) {
1880
+ const rootTemplateLock = getTemplateLock( state, rootClientId );
1881
+ if ( rootTemplateLock && rootTemplateLock !== 'contentOnly' ) {
1880
1882
  return false;
1881
1883
  }
1882
1884
 
@@ -1937,8 +1939,8 @@ export function canMoveBlock( state, clientId ) {
1937
1939
  }
1938
1940
 
1939
1941
  const rootClientId = getBlockRootClientId( state, clientId );
1940
- const templateLock = getTemplateLock( state, rootClientId );
1941
- if ( templateLock === 'all' || templateLock === 'contentOnly' ) {
1942
+ const rootTemplateLock = getTemplateLock( state, rootClientId );
1943
+ if ( rootTemplateLock === 'all' ) {
1942
1944
  return false;
1943
1945
  }
1944
1946
 
@@ -10,6 +10,10 @@ import {
10
10
  getExpandedBlock,
11
11
  isDragging,
12
12
  getBlockStyles,
13
+ isEditLockedBlock,
14
+ isMoveLockedBlock,
15
+ isRemoveLockedBlock,
16
+ isLockedBlock,
13
17
  } from '../private-selectors';
14
18
  import { getBlockEditingMode } from '../selectors';
15
19
 
@@ -681,4 +685,242 @@ describe( 'private selectors', () => {
681
685
  } );
682
686
  } );
683
687
  } );
688
+
689
+ describe( 'isEditLockedBlock', () => {
690
+ it( 'returns false when block has no lock attribute', () => {
691
+ const state = {
692
+ blocks: {
693
+ byClientId: new Map( [
694
+ [ 'block-1', { clientId: 'block-1' } ],
695
+ ] ),
696
+ attributes: new Map( [ [ 'block-1', {} ] ] ),
697
+ },
698
+ };
699
+ expect( isEditLockedBlock( state, 'block-1' ) ).toBe( false );
700
+ } );
701
+
702
+ it( 'returns false when block has lock attribute but edit is false', () => {
703
+ const state = {
704
+ blocks: {
705
+ byClientId: new Map( [
706
+ [ 'block-1', { clientId: 'block-1' } ],
707
+ ] ),
708
+ attributes: new Map( [
709
+ [ 'block-1', { lock: { edit: false, move: true } } ],
710
+ ] ),
711
+ },
712
+ };
713
+ expect( isEditLockedBlock( state, 'block-1' ) ).toBe( false );
714
+ } );
715
+
716
+ it( 'returns true when block has lock attribute with edit set to true', () => {
717
+ const state = {
718
+ blocks: {
719
+ byClientId: new Map( [
720
+ [ 'block-1', { clientId: 'block-1' } ],
721
+ ] ),
722
+ attributes: new Map( [
723
+ [ 'block-1', { lock: { edit: true } } ],
724
+ ] ),
725
+ },
726
+ };
727
+ expect( isEditLockedBlock( state, 'block-1' ) ).toBe( true );
728
+ } );
729
+
730
+ it( 'returns false when block has no attributes', () => {
731
+ const state = {
732
+ blocks: {
733
+ byClientId: new Map(),
734
+ attributes: new Map(),
735
+ },
736
+ };
737
+ expect( isEditLockedBlock( state, 'block-1' ) ).toBe( false );
738
+ } );
739
+ } );
740
+
741
+ describe( 'isMoveLockedBlock', () => {
742
+ const createState = ( templateLock, blockLock ) => ( {
743
+ blocks: {
744
+ byClientId: new Map( [
745
+ [ 'block-1', { clientId: 'block-1' } ],
746
+ [ 'parent-block', { clientId: 'parent-block' } ],
747
+ ] ),
748
+ attributes: new Map( [
749
+ [ 'block-1', blockLock ? { lock: blockLock } : {} ],
750
+ [ 'parent-block', {} ],
751
+ ] ),
752
+ parents: new Map( [
753
+ [ 'block-1', 'parent-block' ],
754
+ [ 'parent-block', '' ],
755
+ ] ),
756
+ },
757
+ settings: {},
758
+ blockListSettings: {
759
+ 'parent-block': templateLock ? { templateLock } : {},
760
+ },
761
+ } );
762
+
763
+ it( 'returns false when block has no lock and no templateLock', () => {
764
+ const state = createState( null, null );
765
+ expect( isMoveLockedBlock( state, 'block-1' ) ).toBe( false );
766
+ } );
767
+
768
+ it( 'returns true when parent has templateLock set to "all"', () => {
769
+ const state = createState( 'all', null );
770
+ expect( isMoveLockedBlock( state, 'block-1' ) ).toBe( true );
771
+ } );
772
+
773
+ it( 'returns false when parent has templateLock set to "contentOnly"', () => {
774
+ const state = createState( 'contentOnly', null );
775
+ expect( isMoveLockedBlock( state, 'block-1' ) ).toBe( false );
776
+ } );
777
+
778
+ it( 'returns true when block has lock.move set to true', () => {
779
+ const state = createState( null, { move: true } );
780
+ expect( isMoveLockedBlock( state, 'block-1' ) ).toBe( true );
781
+ } );
782
+
783
+ it( 'returns false when block has lock.move set to false', () => {
784
+ const state = createState( null, { move: false } );
785
+ expect( isMoveLockedBlock( state, 'block-1' ) ).toBe( false );
786
+ } );
787
+
788
+ it( 'prioritizes block lock over template lock', () => {
789
+ const state = createState( 'all', { move: false } );
790
+ expect( isMoveLockedBlock( state, 'block-1' ) ).toBe( false );
791
+ } );
792
+ } );
793
+
794
+ describe( 'isRemoveLockedBlock', () => {
795
+ const createState = ( templateLock, blockLock ) => ( {
796
+ blocks: {
797
+ byClientId: new Map( [
798
+ [ 'block-1', { clientId: 'block-1' } ],
799
+ [ 'parent-block', { clientId: 'parent-block' } ],
800
+ ] ),
801
+ attributes: new Map( [
802
+ [ 'block-1', blockLock ? { lock: blockLock } : {} ],
803
+ [ 'parent-block', {} ],
804
+ ] ),
805
+ parents: new Map( [
806
+ [ 'block-1', 'parent-block' ],
807
+ [ 'parent-block', '' ],
808
+ ] ),
809
+ },
810
+ settings: {},
811
+ blockListSettings: {
812
+ 'parent-block': templateLock ? { templateLock } : {},
813
+ },
814
+ } );
815
+
816
+ it( 'returns false when block has no lock and no templateLock', () => {
817
+ const state = createState( null, null );
818
+ expect( isRemoveLockedBlock( state, 'block-1' ) ).toBe( false );
819
+ } );
820
+
821
+ it( 'returns true when parent has templateLock set to "all"', () => {
822
+ const state = createState( 'all', null );
823
+ expect( isRemoveLockedBlock( state, 'block-1' ) ).toBe( true );
824
+ } );
825
+
826
+ it( 'returns true when parent has templateLock set to "insert"', () => {
827
+ const state = createState( 'insert', null );
828
+ expect( isRemoveLockedBlock( state, 'block-1' ) ).toBe( true );
829
+ } );
830
+
831
+ it( 'returns false when parent has templateLock set to "contentOnly"', () => {
832
+ const state = createState( 'contentOnly', null );
833
+ expect( isRemoveLockedBlock( state, 'block-1' ) ).toBe( false );
834
+ } );
835
+
836
+ it( 'returns true when block has lock.remove set to true', () => {
837
+ const state = createState( null, { remove: true } );
838
+ expect( isRemoveLockedBlock( state, 'block-1' ) ).toBe( true );
839
+ } );
840
+
841
+ it( 'returns false when block has lock.remove set to false', () => {
842
+ const state = createState( null, { remove: false } );
843
+ expect( isRemoveLockedBlock( state, 'block-1' ) ).toBe( false );
844
+ } );
845
+
846
+ it( 'prioritizes block lock over template lock', () => {
847
+ const state = createState( 'all', { remove: false } );
848
+ expect( isRemoveLockedBlock( state, 'block-1' ) ).toBe( false );
849
+ } );
850
+ } );
851
+
852
+ describe( 'isLockedBlock', () => {
853
+ const createState = ( templateLock, blockLock ) => ( {
854
+ blocks: {
855
+ byClientId: new Map( [
856
+ [ 'block-1', { clientId: 'block-1' } ],
857
+ [ 'parent-block', { clientId: 'parent-block' } ],
858
+ ] ),
859
+ attributes: new Map( [
860
+ [ 'block-1', blockLock ? { lock: blockLock } : {} ],
861
+ [ 'parent-block', {} ],
862
+ ] ),
863
+ parents: new Map( [
864
+ [ 'block-1', 'parent-block' ],
865
+ [ 'parent-block', '' ],
866
+ ] ),
867
+ },
868
+ settings: {},
869
+ blockListSettings: {
870
+ 'parent-block': templateLock ? { templateLock } : {},
871
+ },
872
+ } );
873
+
874
+ it( 'returns false when block is not locked in any way', () => {
875
+ const state = createState( null, null );
876
+ expect( isLockedBlock( state, 'block-1' ) ).toBe( false );
877
+ } );
878
+
879
+ it( 'returns true when block has lock.edit set to true', () => {
880
+ const state = createState( null, { edit: true } );
881
+ expect( isLockedBlock( state, 'block-1' ) ).toBe( true );
882
+ } );
883
+
884
+ it( 'returns true when block has lock.move set to true', () => {
885
+ const state = createState( null, { move: true } );
886
+ expect( isLockedBlock( state, 'block-1' ) ).toBe( true );
887
+ } );
888
+
889
+ it( 'returns true when block has lock.remove set to true', () => {
890
+ const state = createState( null, { remove: true } );
891
+ expect( isLockedBlock( state, 'block-1' ) ).toBe( true );
892
+ } );
893
+
894
+ it( 'returns true when parent has templateLock set to "all"', () => {
895
+ const state = createState( 'all', null );
896
+ expect( isLockedBlock( state, 'block-1' ) ).toBe( true );
897
+ } );
898
+
899
+ it( 'returns true when block has multiple locks', () => {
900
+ const state = createState( null, {
901
+ edit: true,
902
+ move: true,
903
+ remove: true,
904
+ } );
905
+ expect( isLockedBlock( state, 'block-1' ) ).toBe( true );
906
+ } );
907
+
908
+ it( 'returns true when only one lock type is active', () => {
909
+ const state = createState( null, {
910
+ edit: false,
911
+ move: true,
912
+ remove: false,
913
+ } );
914
+ expect( isLockedBlock( state, 'block-1' ) ).toBe( true );
915
+ } );
916
+
917
+ it( 'returns false when all lock types are explicitly false', () => {
918
+ const state = createState( null, {
919
+ edit: false,
920
+ move: false,
921
+ remove: false,
922
+ } );
923
+ expect( isLockedBlock( state, 'block-1' ) ).toBe( false );
924
+ } );
925
+ } );
684
926
  } );
@@ -4540,11 +4540,16 @@ describe( 'state', () => {
4540
4540
  );
4541
4541
  } );
4542
4542
 
4543
- it( 'returns the expected block editing modes for template parts', () => {
4544
- // Currently, template parts are not considered sections, so
4545
- // child blocks are not set to contentOnly.
4543
+ it( 'returns the expected block editing modes for synced patterns', () => {
4546
4544
  expect( initialState.derivedBlockEditingModes ).toEqual(
4547
- new Map()
4545
+ new Map(
4546
+ Object.entries( {
4547
+ 'template-part-paragraph': 'contentOnly',
4548
+ 'template-part-group': 'disabled',
4549
+ 'template-part-grouped-paragraph':
4550
+ 'contentOnly',
4551
+ } )
4552
+ )
4548
4553
  );
4549
4554
  } );
4550
4555
 
@@ -4568,7 +4573,7 @@ describe( 'state', () => {
4568
4573
  expect( derivedBlockEditingModes ).toEqual( new Map() );
4569
4574
  } );
4570
4575
 
4571
- it( 'does not set contentOnly mode for children of template parts', () => {
4576
+ it( 'allows explicitly set blockEditingModes to override the template part editing modes', () => {
4572
4577
  const { derivedBlockEditingModes } = dispatchActions(
4573
4578
  [
4574
4579
  {
@@ -4582,8 +4587,13 @@ describe( 'state', () => {
4582
4587
  );
4583
4588
 
4584
4589
  expect( derivedBlockEditingModes ).toEqual(
4585
- // template-part-grouped-paragraph already has an explicit mode, so isn't set as a derived mode.
4586
- new Map()
4590
+ new Map(
4591
+ Object.entries( {
4592
+ 'template-part-paragraph': 'contentOnly',
4593
+ 'template-part-group': 'disabled',
4594
+ // template-part-grouped-paragraph already has an explicit mode, so isn't set as a derived mode.
4595
+ } )
4596
+ )
4587
4597
  );
4588
4598
  } );
4589
4599
  } );
package/src/style.scss CHANGED
@@ -33,7 +33,6 @@
33
33
  @use "./components/date-format-picker/style.scss" as *;
34
34
  @use "./components/duotone-control/style.scss" as *;
35
35
  @use "./components/font-appearance-control/style.scss" as *;
36
- @use "./components/font-family/style.scss" as *;
37
36
  @use "./components/global-styles/style.scss" as *;
38
37
  @use "./components/grid/style.scss" as *;
39
38
  @use "./components/height-control/style.scss" as *;
package/tsconfig.json CHANGED
@@ -9,6 +9,7 @@
9
9
  { "path": "../components" },
10
10
  { "path": "../compose" },
11
11
  { "path": "../data" },
12
+ { "path": "../dataviews" },
12
13
  { "path": "../date" },
13
14
  { "path": "../deprecated" },
14
15
  { "path": "../dom" },