@wordpress/block-library 8.10.0 → 8.11.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 (278) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/block/edit.native.js +17 -10
  3. package/build/block/edit.native.js.map +1 -1
  4. package/build/code/index.js +1 -0
  5. package/build/code/index.js.map +1 -1
  6. package/build/column/index.js +1 -1
  7. package/build/columns/transforms.js +1 -5
  8. package/build/columns/transforms.js.map +1 -1
  9. package/build/cover/edit/resizable-cover-popover.js +3 -3
  10. package/build/cover/edit/resizable-cover-popover.js.map +1 -1
  11. package/build/file/interactivity.js +19 -0
  12. package/build/file/interactivity.js.map +1 -0
  13. package/build/file/{utils.js → utils/index.js} +1 -1
  14. package/build/file/utils/index.js.map +1 -0
  15. package/build/freeform/modal.js +20 -17
  16. package/build/freeform/modal.js.map +1 -1
  17. package/build/gallery/v1/edit.js +1 -7
  18. package/build/gallery/v1/edit.js.map +1 -1
  19. package/build/gallery/v1/gallery-image.native.js +1 -3
  20. package/build/gallery/v1/gallery-image.native.js.map +1 -1
  21. package/build/group/transforms.js +0 -5
  22. package/build/group/transforms.js.map +1 -1
  23. package/build/image/deprecated.js +2 -4
  24. package/build/image/deprecated.js.map +1 -1
  25. package/build/image/edit.js +13 -11
  26. package/build/image/edit.js.map +1 -1
  27. package/build/image/image.js +7 -12
  28. package/build/image/image.js.map +1 -1
  29. package/build/image/index.js +3 -0
  30. package/build/image/index.js.map +1 -1
  31. package/build/image/interactivity.js +102 -0
  32. package/build/image/interactivity.js.map +1 -0
  33. package/build/image/save.js +2 -4
  34. package/build/image/save.js.map +1 -1
  35. package/build/image/utils.js +10 -18
  36. package/build/image/utils.js.map +1 -1
  37. package/build/latest-posts/edit.native.js +1 -3
  38. package/build/latest-posts/edit.native.js.map +1 -1
  39. package/build/list/edit.js +1 -1
  40. package/build/list/edit.js.map +1 -1
  41. package/build/list-item/edit.native.js +1 -1
  42. package/build/list-item/edit.native.js.map +1 -1
  43. package/build/list-item/transforms.js +4 -1
  44. package/build/list-item/transforms.js.map +1 -1
  45. package/build/media-text/deprecated.js +4 -6
  46. package/build/media-text/deprecated.js.map +1 -1
  47. package/build/media-text/edit.js +13 -11
  48. package/build/media-text/edit.js.map +1 -1
  49. package/build/media-text/media-container.js +3 -3
  50. package/build/media-text/media-container.js.map +1 -1
  51. package/build/media-text/save.js +1 -3
  52. package/build/media-text/save.js.map +1 -1
  53. package/build/navigation/constants.js +3 -1
  54. package/build/navigation/constants.js.map +1 -1
  55. package/build/navigation/edit/inner-blocks.js +1 -0
  56. package/build/navigation/edit/inner-blocks.js.map +1 -1
  57. package/build/navigation/edit/leaf-more-menu.js +148 -0
  58. package/build/navigation/edit/leaf-more-menu.js.map +1 -0
  59. package/build/navigation/edit/menu-inspector-controls.js +53 -8
  60. package/build/navigation/edit/menu-inspector-controls.js.map +1 -1
  61. package/build/navigation/edit/navigation-menu-delete-control.js +6 -6
  62. package/build/navigation/edit/navigation-menu-delete-control.js.map +1 -1
  63. package/build/navigation/edit/unsaved-inner-blocks.js +8 -19
  64. package/build/navigation/edit/unsaved-inner-blocks.js.map +1 -1
  65. package/build/navigation/interactivity.js +24 -6
  66. package/build/navigation/interactivity.js.map +1 -1
  67. package/build/navigation-link/edit.js +6 -4
  68. package/build/navigation-link/edit.js.map +1 -1
  69. package/build/navigation-link/update-attributes.js +5 -5
  70. package/build/navigation-link/update-attributes.js.map +1 -1
  71. package/build/navigation-submenu/edit.js +6 -4
  72. package/build/navigation-submenu/edit.js.map +1 -1
  73. package/build/pattern/edit.js +42 -8
  74. package/build/pattern/edit.js.map +1 -1
  75. package/build/pattern/index.js +12 -5
  76. package/build/pattern/index.js.map +1 -1
  77. package/build/pattern/v1/edit.js +57 -0
  78. package/build/pattern/v1/edit.js.map +1 -0
  79. package/build/post-title/edit.js +10 -3
  80. package/build/post-title/edit.js.map +1 -1
  81. package/build/quote/transforms.js +9 -12
  82. package/build/quote/transforms.js.map +1 -1
  83. package/build/social-link/edit.js +21 -4
  84. package/build/social-link/edit.js.map +1 -1
  85. package/build/template-part/edit/index.js +1 -7
  86. package/build/template-part/edit/index.js.map +1 -1
  87. package/build/template-part/edit/utils/hooks.js +2 -2
  88. package/build/template-part/edit/utils/hooks.js.map +1 -1
  89. package/build/utils/interactivity/directives.js +50 -22
  90. package/build/utils/interactivity/directives.js.map +1 -1
  91. package/build/utils/interactivity/hooks.js +76 -12
  92. package/build/utils/interactivity/hooks.js.map +1 -1
  93. package/build/utils/interactivity/portals.js +108 -0
  94. package/build/utils/interactivity/portals.js.map +1 -0
  95. package/build-module/block/edit.native.js +7 -1
  96. package/build-module/block/edit.native.js.map +1 -1
  97. package/build-module/code/index.js +1 -0
  98. package/build-module/code/index.js.map +1 -1
  99. package/build-module/column/index.js +1 -1
  100. package/build-module/columns/transforms.js +1 -5
  101. package/build-module/columns/transforms.js.map +1 -1
  102. package/build-module/cover/edit/resizable-cover-popover.js +3 -3
  103. package/build-module/cover/edit/resizable-cover-popover.js.map +1 -1
  104. package/build-module/file/interactivity.js +15 -0
  105. package/build-module/file/interactivity.js.map +1 -0
  106. package/build-module/file/{utils.js → utils/index.js} +1 -1
  107. package/build-module/file/utils/index.js.map +1 -0
  108. package/build-module/freeform/modal.js +19 -18
  109. package/build-module/freeform/modal.js.map +1 -1
  110. package/build-module/gallery/v1/edit.js +1 -6
  111. package/build-module/gallery/v1/edit.js.map +1 -1
  112. package/build-module/gallery/v1/gallery-image.native.js +1 -2
  113. package/build-module/gallery/v1/gallery-image.native.js.map +1 -1
  114. package/build-module/group/transforms.js +0 -5
  115. package/build-module/group/transforms.js.map +1 -1
  116. package/build-module/image/deprecated.js +2 -3
  117. package/build-module/image/deprecated.js.map +1 -1
  118. package/build-module/image/edit.js +12 -11
  119. package/build-module/image/edit.js.map +1 -1
  120. package/build-module/image/image.js +7 -11
  121. package/build-module/image/image.js.map +1 -1
  122. package/build-module/image/index.js +3 -0
  123. package/build-module/image/index.js.map +1 -1
  124. package/build-module/image/interactivity.js +99 -0
  125. package/build-module/image/interactivity.js.map +1 -0
  126. package/build-module/image/save.js +2 -3
  127. package/build-module/image/save.js.map +1 -1
  128. package/build-module/image/utils.js +10 -17
  129. package/build-module/image/utils.js.map +1 -1
  130. package/build-module/latest-posts/edit.native.js +1 -2
  131. package/build-module/latest-posts/edit.native.js.map +1 -1
  132. package/build-module/list/edit.js +1 -1
  133. package/build-module/list/edit.js.map +1 -1
  134. package/build-module/list-item/edit.native.js +1 -1
  135. package/build-module/list-item/edit.native.js.map +1 -1
  136. package/build-module/list-item/transforms.js +5 -2
  137. package/build-module/list-item/transforms.js.map +1 -1
  138. package/build-module/media-text/deprecated.js +4 -5
  139. package/build-module/media-text/deprecated.js.map +1 -1
  140. package/build-module/media-text/edit.js +13 -12
  141. package/build-module/media-text/edit.js.map +1 -1
  142. package/build-module/media-text/media-container.js +3 -3
  143. package/build-module/media-text/media-container.js.map +1 -1
  144. package/build-module/media-text/save.js +1 -2
  145. package/build-module/media-text/save.js.map +1 -1
  146. package/build-module/navigation/constants.js +1 -0
  147. package/build-module/navigation/constants.js.map +1 -1
  148. package/build-module/navigation/edit/inner-blocks.js +2 -1
  149. package/build-module/navigation/edit/inner-blocks.js.map +1 -1
  150. package/build-module/navigation/edit/leaf-more-menu.js +132 -0
  151. package/build-module/navigation/edit/leaf-more-menu.js.map +1 -0
  152. package/build-module/navigation/edit/menu-inspector-controls.js +52 -9
  153. package/build-module/navigation/edit/menu-inspector-controls.js.map +1 -1
  154. package/build-module/navigation/edit/navigation-menu-delete-control.js +7 -7
  155. package/build-module/navigation/edit/navigation-menu-delete-control.js.map +1 -1
  156. package/build-module/navigation/edit/unsaved-inner-blocks.js +8 -16
  157. package/build-module/navigation/edit/unsaved-inner-blocks.js.map +1 -1
  158. package/build-module/navigation/interactivity.js +24 -6
  159. package/build-module/navigation/interactivity.js.map +1 -1
  160. package/build-module/navigation-link/edit.js +6 -4
  161. package/build-module/navigation-link/edit.js.map +1 -1
  162. package/build-module/navigation-link/update-attributes.js +4 -4
  163. package/build-module/navigation-link/update-attributes.js.map +1 -1
  164. package/build-module/navigation-submenu/edit.js +6 -4
  165. package/build-module/navigation-submenu/edit.js.map +1 -1
  166. package/build-module/pattern/edit.js +42 -9
  167. package/build-module/pattern/edit.js.map +1 -1
  168. package/build-module/pattern/index.js +12 -3
  169. package/build-module/pattern/index.js.map +1 -1
  170. package/build-module/pattern/v1/edit.js +48 -0
  171. package/build-module/pattern/v1/edit.js.map +1 -0
  172. package/build-module/post-title/edit.js +10 -3
  173. package/build-module/post-title/edit.js.map +1 -1
  174. package/build-module/quote/transforms.js +9 -12
  175. package/build-module/quote/transforms.js.map +1 -1
  176. package/build-module/social-link/edit.js +20 -5
  177. package/build-module/social-link/edit.js.map +1 -1
  178. package/build-module/template-part/edit/index.js +1 -6
  179. package/build-module/template-part/edit/index.js.map +1 -1
  180. package/build-module/template-part/edit/utils/hooks.js +1 -1
  181. package/build-module/template-part/edit/utils/hooks.js.map +1 -1
  182. package/build-module/utils/interactivity/directives.js +49 -22
  183. package/build-module/utils/interactivity/directives.js.map +1 -1
  184. package/build-module/utils/interactivity/hooks.js +77 -13
  185. package/build-module/utils/interactivity/hooks.js.map +1 -1
  186. package/build-module/utils/interactivity/portals.js +100 -0
  187. package/build-module/utils/interactivity/portals.js.map +1 -0
  188. package/build-style/common-rtl.css +1 -1
  189. package/build-style/common.css +1 -1
  190. package/build-style/cover/style-rtl.css +1 -2
  191. package/build-style/cover/style.css +1 -2
  192. package/build-style/editor-rtl.css +68 -0
  193. package/build-style/editor.css +68 -0
  194. package/build-style/file/editor-rtl.css +3 -0
  195. package/build-style/file/editor.css +3 -0
  196. package/build-style/freeform/editor-rtl.css +29 -0
  197. package/build-style/freeform/editor.css +29 -0
  198. package/build-style/gallery/style-rtl.css +2 -4
  199. package/build-style/gallery/style.css +2 -4
  200. package/build-style/image/style-rtl.css +98 -0
  201. package/build-style/image/style.css +98 -0
  202. package/build-style/navigation/editor-rtl.css +36 -0
  203. package/build-style/navigation/editor.css +36 -0
  204. package/build-style/post-comments-form/style-rtl.css +1 -1
  205. package/build-style/post-comments-form/style.css +1 -1
  206. package/build-style/style-rtl.css +103 -9
  207. package/build-style/style.css +103 -9
  208. package/build-style/video/style-rtl.css +1 -2
  209. package/build-style/video/style.css +1 -2
  210. package/package.json +32 -32
  211. package/src/block/edit.native.js +18 -4
  212. package/src/buttons/test/edit.native.js +0 -9
  213. package/src/code/block.json +1 -0
  214. package/src/column/block.json +1 -1
  215. package/src/columns/test/__snapshots__/transforms.native.js.snap +1 -1
  216. package/src/columns/test/transforms.native.js +3 -5
  217. package/src/columns/transforms.js +2 -8
  218. package/src/comments/index.php +1 -6
  219. package/src/cover/edit/resizable-cover-popover.js +2 -1
  220. package/src/file/editor.scss +4 -0
  221. package/src/file/interactivity.js +15 -0
  222. package/src/freeform/editor.scss +45 -0
  223. package/src/freeform/modal.js +22 -19
  224. package/src/gallery/v1/edit.js +1 -6
  225. package/src/gallery/v1/gallery-image.native.js +1 -2
  226. package/src/group/test/__snapshots__/transforms.native.js.snap +1 -1
  227. package/src/group/test/transforms.native.js +3 -5
  228. package/src/group/transforms.js +0 -7
  229. package/src/image/block.json +3 -0
  230. package/src/image/deprecated.js +2 -3
  231. package/src/image/edit.js +18 -18
  232. package/src/image/image.js +8 -11
  233. package/src/image/index.php +75 -2
  234. package/src/image/interactivity.js +113 -0
  235. package/src/image/save.js +4 -3
  236. package/src/image/style.scss +113 -0
  237. package/src/image/utils.js +11 -18
  238. package/src/latest-posts/edit.native.js +1 -4
  239. package/src/list/edit.js +1 -1
  240. package/src/list/test/edit.native.js +80 -1
  241. package/src/list-item/edit.native.js +1 -1
  242. package/src/list-item/transforms.js +4 -2
  243. package/src/media-text/deprecated.js +4 -5
  244. package/src/media-text/edit.js +12 -10
  245. package/src/media-text/media-container.js +3 -3
  246. package/src/media-text/save.js +1 -2
  247. package/src/navigation/constants.js +5 -0
  248. package/src/navigation/edit/inner-blocks.js +6 -1
  249. package/src/navigation/edit/leaf-more-menu.js +170 -0
  250. package/src/navigation/edit/menu-inspector-controls.js +78 -10
  251. package/src/navigation/edit/navigation-menu-delete-control.js +29 -29
  252. package/src/navigation/edit/unsaved-inner-blocks.js +11 -24
  253. package/src/navigation/editor.scss +10 -0
  254. package/src/navigation/index.php +4 -1
  255. package/src/navigation/interactivity.js +9 -2
  256. package/src/navigation-link/edit.js +8 -2
  257. package/src/navigation-link/update-attributes.js +2 -2
  258. package/src/navigation-submenu/edit.js +8 -2
  259. package/src/pattern/block.json +4 -0
  260. package/src/pattern/edit.js +53 -16
  261. package/src/pattern/index.js +5 -4
  262. package/src/pattern/index.php +14 -1
  263. package/src/pattern/v1/edit.js +57 -0
  264. package/src/post-comments-form/style.scss +3 -1
  265. package/src/post-title/edit.js +50 -44
  266. package/src/quote/test/__snapshots__/transforms.native.js.snap +1 -1
  267. package/src/quote/test/transforms.native.js +3 -5
  268. package/src/quote/transforms.js +9 -13
  269. package/src/social-link/edit.js +51 -26
  270. package/src/template-part/edit/index.js +4 -6
  271. package/src/template-part/edit/utils/hooks.js +1 -1
  272. package/src/template-part/index.php +2 -2
  273. package/src/utils/interactivity/directives.js +27 -6
  274. package/src/utils/interactivity/hooks.js +83 -14
  275. package/src/utils/interactivity/portals.js +98 -0
  276. package/build/file/utils.js.map +0 -1
  277. package/build-module/file/utils.js.map +0 -1
  278. /package/src/file/{utils.js → utils/index.js} +0 -0
@@ -1,46 +1,83 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
+ import { cloneBlock } from '@wordpress/blocks';
4
5
  import { useSelect, useDispatch } from '@wordpress/data';
5
6
  import { useEffect } from '@wordpress/element';
6
7
  import {
7
8
  store as blockEditorStore,
8
9
  useBlockProps,
10
+ useInnerBlocksProps,
9
11
  } from '@wordpress/block-editor';
10
12
 
11
13
  const PatternEdit = ( { attributes, clientId } ) => {
12
- const selectedPattern = useSelect(
13
- ( select ) =>
14
- select( blockEditorStore ).__experimentalGetParsedPattern(
15
- attributes.slug
16
- ),
17
- [ attributes.slug ]
14
+ const { slug, syncStatus } = attributes;
15
+ const { selectedPattern, innerBlocks } = useSelect(
16
+ ( select ) => {
17
+ return {
18
+ selectedPattern:
19
+ select( blockEditorStore ).__experimentalGetParsedPattern(
20
+ slug
21
+ ),
22
+ innerBlocks:
23
+ select( blockEditorStore ).getBlock( clientId )
24
+ ?.innerBlocks,
25
+ };
26
+ },
27
+ [ slug, clientId ]
18
28
  );
19
-
20
- const { replaceBlocks, __unstableMarkNextChangeAsNotPersistent } =
21
- useDispatch( blockEditorStore );
29
+ const {
30
+ replaceBlocks,
31
+ replaceInnerBlocks,
32
+ __unstableMarkNextChangeAsNotPersistent,
33
+ } = useDispatch( blockEditorStore );
22
34
 
23
35
  // Run this effect when the component loads.
24
36
  // This adds the Pattern's contents to the post.
25
- // This change won't be saved.
26
- // It will continue to pull from the pattern file unless changes are made to its respective template part.
27
37
  useEffect( () => {
28
- if ( selectedPattern?.blocks ) {
38
+ if ( selectedPattern?.blocks && ! innerBlocks?.length ) {
29
39
  // We batch updates to block list settings to avoid triggering cascading renders
30
40
  // for each container block included in a tree and optimize initial render.
31
41
  // Since the above uses microtasks, we need to use a microtask here as well,
32
42
  // because nested pattern blocks cannot be inserted if the parent block supports
33
43
  // inner blocks but doesn't have blockSettings in the state.
34
44
  window.queueMicrotask( () => {
45
+ // Clone blocks from the pattern before insertion to ensure they receive
46
+ // distinct client ids. See https://github.com/WordPress/gutenberg/issues/50628.
47
+ const clonedBlocks = selectedPattern.blocks.map( ( block ) =>
48
+ cloneBlock( block )
49
+ );
35
50
  __unstableMarkNextChangeAsNotPersistent();
36
- replaceBlocks( clientId, selectedPattern.blocks );
51
+ if ( syncStatus === 'partial' ) {
52
+ replaceInnerBlocks( clientId, clonedBlocks );
53
+ return;
54
+ }
55
+ replaceBlocks( clientId, clonedBlocks );
37
56
  } );
38
57
  }
39
- }, [ clientId, selectedPattern?.blocks ] );
58
+ }, [
59
+ clientId,
60
+ selectedPattern?.blocks,
61
+ replaceInnerBlocks,
62
+ __unstableMarkNextChangeAsNotPersistent,
63
+ innerBlocks,
64
+ syncStatus,
65
+ replaceBlocks,
66
+ ] );
67
+
68
+ const blockProps = useBlockProps( {
69
+ className: slug?.replace( '/', '-' ),
70
+ } );
71
+
72
+ const innerBlocksProps = useInnerBlocksProps( blockProps, {
73
+ templateLock: syncStatus === 'partial' ? 'contentOnly' : false,
74
+ } );
40
75
 
41
- const props = useBlockProps();
76
+ if ( syncStatus !== 'partial' ) {
77
+ return <div { ...blockProps } />;
78
+ }
42
79
 
43
- return <div { ...props } />;
80
+ return <div { ...innerBlocksProps } />;
44
81
  };
45
82
 
46
83
  export default PatternEdit;
@@ -3,13 +3,14 @@
3
3
  */
4
4
  import initBlock from '../utils/init-block';
5
5
  import metadata from './block.json';
6
- import PatternEdit from './edit';
6
+ import PatternEditV1 from './v1/edit';
7
+ import PatternEditV2 from './edit';
7
8
 
8
9
  const { name } = metadata;
9
10
  export { metadata, name };
10
11
 
11
- export const settings = {
12
- edit: PatternEdit,
13
- };
12
+ export const settings = window?.__experimentalEnablePatternEnhancements
13
+ ? { edit: PatternEditV2 }
14
+ : { edit: PatternEditV1 };
14
15
 
15
16
  export const init = () => initBlock( { name, metadata, settings } );
@@ -33,12 +33,25 @@ function render_block_core_pattern( $attributes ) {
33
33
 
34
34
  $slug = $attributes['slug'];
35
35
  $registry = WP_Block_Patterns_Registry::get_instance();
36
+
36
37
  if ( ! $registry->is_registered( $slug ) ) {
37
38
  return '';
38
39
  }
39
40
 
40
41
  $pattern = $registry->get_registered( $slug );
41
- return do_blocks( $pattern['content'] );
42
+
43
+ // Currently all existing blocks should be returned here without a wp-block-pattern wrapper
44
+ // as the syncStatus attribute is only used if the gutenberg-pattern-enhancements experiment
45
+ // is enabled.
46
+ if ( ! isset( $attributes['syncStatus'] ) ) {
47
+ return do_blocks( $pattern['content'] );
48
+ }
49
+
50
+ $block_classnames = 'wp-block-pattern ' . str_replace( '/', '-', $attributes['slug'] );
51
+ $classnames = isset( $attributes['className'] ) ? $attributes['className'] . ' ' . $block_classnames : $block_classnames;
52
+ $wrapper = '<div class="' . esc_attr( $classnames ) . '">%s</div>';
53
+
54
+ return sprintf( $wrapper, do_blocks( $pattern['content'] ) );
42
55
  }
43
56
 
44
57
  add_action( 'init', 'register_block_core_pattern' );
@@ -0,0 +1,57 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { cloneBlock } from '@wordpress/blocks';
5
+ import { useSelect, useDispatch } from '@wordpress/data';
6
+ import { useEffect } from '@wordpress/element';
7
+ import {
8
+ store as blockEditorStore,
9
+ useBlockProps,
10
+ } from '@wordpress/block-editor';
11
+
12
+ const PatternEdit = ( { attributes, clientId } ) => {
13
+ const selectedPattern = useSelect(
14
+ ( select ) =>
15
+ select( blockEditorStore ).__experimentalGetParsedPattern(
16
+ attributes.slug
17
+ ),
18
+ [ attributes.slug ]
19
+ );
20
+
21
+ const { replaceBlocks, __unstableMarkNextChangeAsNotPersistent } =
22
+ useDispatch( blockEditorStore );
23
+
24
+ // Run this effect when the component loads.
25
+ // This adds the Pattern's contents to the post.
26
+ // This change won't be saved.
27
+ // It will continue to pull from the pattern file unless changes are made to its respective template part.
28
+ useEffect( () => {
29
+ if ( selectedPattern?.blocks ) {
30
+ // We batch updates to block list settings to avoid triggering cascading renders
31
+ // for each container block included in a tree and optimize initial render.
32
+ // Since the above uses microtasks, we need to use a microtask here as well,
33
+ // because nested pattern blocks cannot be inserted if the parent block supports
34
+ // inner blocks but doesn't have blockSettings in the state.
35
+ window.queueMicrotask( () => {
36
+ // Clone blocks from the pattern before insertion to ensure they receive
37
+ // distinct client ids. See https://github.com/WordPress/gutenberg/issues/50628.
38
+ const clonedBlocks = selectedPattern.blocks.map( ( block ) =>
39
+ cloneBlock( block )
40
+ );
41
+ __unstableMarkNextChangeAsNotPersistent();
42
+ replaceBlocks( clientId, clonedBlocks );
43
+ } );
44
+ }
45
+ }, [
46
+ clientId,
47
+ selectedPattern?.blocks,
48
+ __unstableMarkNextChangeAsNotPersistent,
49
+ replaceBlocks,
50
+ ] );
51
+
52
+ const props = useBlockProps();
53
+
54
+ return <div { ...props } />;
55
+ };
56
+
57
+ export default PatternEdit;
@@ -45,7 +45,9 @@
45
45
 
46
46
  .comment-form {
47
47
  textarea,
48
- input:not([type="submit"]):not([type="checkbox"]) {
48
+ // Make sure to not set display block on hidden input fields, to prevent
49
+ // the Safari bug experienced in https://github.com/WordPress/gutenberg/issues/50830
50
+ input:not([type="submit"]):not([type="checkbox"]):not([type="hidden"]) {
49
51
  display: block;
50
52
  box-sizing: border-box;
51
53
  width: 100%;
@@ -32,7 +32,17 @@ export default function PostTitleEdit( {
32
32
  } ) {
33
33
  const TagName = 0 === level ? 'p' : 'h' + level;
34
34
  const isDescendentOfQueryLoop = Number.isFinite( queryId );
35
- const userCanEdit = useCanEditEntity( 'postType', postType, postId );
35
+ /**
36
+ * Hack: useCanEditEntity may trigger an OPTIONS request to the REST API via the canUser resolver.
37
+ * However, when the Post Title is a descendant of a Query Loop block, the title cannot be edited.
38
+ * In order to avoid these unnecessary requests, we call the hook without
39
+ * the proper data, resulting in returning early without making them.
40
+ */
41
+ const userCanEdit = useCanEditEntity(
42
+ 'postType',
43
+ ! isDescendentOfQueryLoop && postType,
44
+ postId
45
+ );
36
46
  const [ rawTitle = '', setTitle, fullTitle ] = useEntityProp(
37
47
  'postType',
38
48
  postType,
@@ -54,56 +64,52 @@ export default function PostTitleEdit( {
54
64
  );
55
65
 
56
66
  if ( postType && postId ) {
57
- titleElement =
58
- userCanEdit && ! isDescendentOfQueryLoop ? (
67
+ titleElement = userCanEdit ? (
68
+ <PlainText
69
+ tagName={ TagName }
70
+ placeholder={ __( 'No Title' ) }
71
+ value={ rawTitle }
72
+ onChange={ setTitle }
73
+ __experimentalVersion={ 2 }
74
+ __unstableOnSplitAtEnd={ onSplitAtEnd }
75
+ { ...blockProps }
76
+ />
77
+ ) : (
78
+ <TagName
79
+ { ...blockProps }
80
+ dangerouslySetInnerHTML={ { __html: fullTitle?.rendered } }
81
+ />
82
+ );
83
+ }
84
+
85
+ if ( isLink && postType && postId ) {
86
+ titleElement = userCanEdit ? (
87
+ <TagName { ...blockProps }>
59
88
  <PlainText
60
- tagName={ TagName }
61
- placeholder={ __( 'No Title' ) }
89
+ tagName="a"
90
+ href={ link }
91
+ target={ linkTarget }
92
+ rel={ rel }
93
+ placeholder={ ! rawTitle.length ? __( 'No Title' ) : null }
62
94
  value={ rawTitle }
63
95
  onChange={ setTitle }
64
96
  __experimentalVersion={ 2 }
65
97
  __unstableOnSplitAtEnd={ onSplitAtEnd }
66
- { ...blockProps }
67
98
  />
68
- ) : (
69
- <TagName
70
- { ...blockProps }
71
- dangerouslySetInnerHTML={ { __html: fullTitle?.rendered } }
99
+ </TagName>
100
+ ) : (
101
+ <TagName { ...blockProps }>
102
+ <a
103
+ href={ link }
104
+ target={ linkTarget }
105
+ rel={ rel }
106
+ onClick={ ( event ) => event.preventDefault() }
107
+ dangerouslySetInnerHTML={ {
108
+ __html: fullTitle?.rendered,
109
+ } }
72
110
  />
73
- );
74
- }
75
-
76
- if ( isLink && postType && postId ) {
77
- titleElement =
78
- userCanEdit && ! isDescendentOfQueryLoop ? (
79
- <TagName { ...blockProps }>
80
- <PlainText
81
- tagName="a"
82
- href={ link }
83
- target={ linkTarget }
84
- rel={ rel }
85
- placeholder={
86
- ! rawTitle.length ? __( 'No Title' ) : null
87
- }
88
- value={ rawTitle }
89
- onChange={ setTitle }
90
- __experimentalVersion={ 2 }
91
- __unstableOnSplitAtEnd={ onSplitAtEnd }
92
- />
93
- </TagName>
94
- ) : (
95
- <TagName { ...blockProps }>
96
- <a
97
- href={ link }
98
- target={ linkTarget }
99
- rel={ rel }
100
- onClick={ ( event ) => event.preventDefault() }
101
- dangerouslySetInnerHTML={ {
102
- __html: fullTitle?.rendered,
103
- } }
104
- />
105
- </TagName>
106
- );
111
+ </TagName>
112
+ );
107
113
  }
108
114
 
109
115
  return (
@@ -28,7 +28,7 @@ exports[`Quote block transforms to Pullquote block 1`] = `
28
28
  <!-- /wp:pullquote -->"
29
29
  `;
30
30
 
31
- exports[`Quote block transforms unwraps content 1`] = `
31
+ exports[`Quote block transforms ungroups block 1`] = `
32
32
  "<!-- wp:paragraph -->
33
33
  <p>"This will make running your own blog a viable alternative again."</p>
34
34
  <!-- /wp:paragraph -->
@@ -36,14 +36,13 @@ describe( `${ block } block transforms`, () => {
36
36
  expect( getEditorHtml() ).toMatchSnapshot();
37
37
  } );
38
38
 
39
- it( 'unwraps content', async () => {
39
+ it( 'ungroups block', async () => {
40
40
  const screen = await initializeEditor( { initialHtml } );
41
41
  const { getByText } = screen;
42
42
  fireEvent.press( getBlock( screen, block ) );
43
43
 
44
44
  await openBlockActionsMenu( screen );
45
- fireEvent.press( getByText( 'Transform block…' ) );
46
- fireEvent.press( getByText( 'Unwrap' ) );
45
+ fireEvent.press( getByText( 'Ungroup' ) );
47
46
 
48
47
  // The first block created is the content of the Paragraph block.
49
48
  const paragraph = getBlock( screen, 'Paragraph', 0 );
@@ -59,8 +58,7 @@ describe( `${ block } block transforms`, () => {
59
58
  const screen = await initializeEditor( { initialHtml } );
60
59
  const transformOptions = await getBlockTransformOptions(
61
60
  screen,
62
- block,
63
- { canUnwrap: true }
61
+ block
64
62
  );
65
63
  expect( transformOptions ).toHaveLength( blockTransforms.length );
66
64
  } );
@@ -126,20 +126,16 @@ const transforms = {
126
126
  : innerBlocks
127
127
  ),
128
128
  },
129
- {
130
- type: 'block',
131
- blocks: [ '*' ],
132
- transform: ( { citation }, innerBlocks ) =>
133
- citation
134
- ? [
135
- ...innerBlocks,
136
- createBlock( 'core/paragraph', {
137
- content: citation,
138
- } ),
139
- ]
140
- : innerBlocks,
141
- },
142
129
  ],
130
+ ungroup: ( { citation }, innerBlocks ) =>
131
+ citation
132
+ ? [
133
+ ...innerBlocks,
134
+ createBlock( 'core/paragraph', {
135
+ content: citation,
136
+ } ),
137
+ ]
138
+ : innerBlocks,
143
139
  };
144
140
 
145
141
  export default transforms;
@@ -6,11 +6,15 @@ import classNames from 'classnames';
6
6
  /**
7
7
  * WordPress dependencies
8
8
  */
9
+ import { DELETE, BACKSPACE } from '@wordpress/keycodes';
10
+ import { useDispatch } from '@wordpress/data';
11
+
9
12
  import {
10
13
  InspectorControls,
11
14
  URLPopover,
12
15
  URLInput,
13
16
  useBlockProps,
17
+ store as blockEditorStore,
14
18
  } from '@wordpress/block-editor';
15
19
  import { useState } from '@wordpress/element';
16
20
  import {
@@ -32,40 +36,60 @@ const SocialLinkURLPopover = ( {
32
36
  setAttributes,
33
37
  setPopover,
34
38
  popoverAnchor,
35
- } ) => (
36
- <URLPopover anchor={ popoverAnchor } onClose={ () => setPopover( false ) }>
37
- <form
38
- className="block-editor-url-popover__link-editor"
39
- onSubmit={ ( event ) => {
40
- event.preventDefault();
41
- setPopover( false );
42
- } }
39
+ clientId,
40
+ } ) => {
41
+ const { removeBlock } = useDispatch( blockEditorStore );
42
+ return (
43
+ <URLPopover
44
+ anchor={ popoverAnchor }
45
+ onClose={ () => setPopover( false ) }
43
46
  >
44
- <div className="block-editor-url-input">
45
- <URLInput
46
- __nextHasNoMarginBottom
47
- value={ url }
48
- onChange={ ( nextURL ) =>
49
- setAttributes( { url: nextURL } )
50
- }
51
- placeholder={ __( 'Enter address' ) }
52
- disableSuggestions={ true }
47
+ <form
48
+ className="block-editor-url-popover__link-editor"
49
+ onSubmit={ ( event ) => {
50
+ event.preventDefault();
51
+ setPopover( false );
52
+ } }
53
+ >
54
+ <div className="block-editor-url-input">
55
+ <URLInput
56
+ __nextHasNoMarginBottom
57
+ value={ url }
58
+ onChange={ ( nextURL ) =>
59
+ setAttributes( { url: nextURL } )
60
+ }
61
+ placeholder={ __( 'Enter address' ) }
62
+ disableSuggestions={ true }
63
+ onKeyDown={ ( event ) => {
64
+ if (
65
+ !! url ||
66
+ event.defaultPrevented ||
67
+ ! [ BACKSPACE, DELETE ].includes(
68
+ event.keyCode
69
+ )
70
+ ) {
71
+ return;
72
+ }
73
+ removeBlock( clientId );
74
+ } }
75
+ />
76
+ </div>
77
+ <Button
78
+ icon={ keyboardReturn }
79
+ label={ __( 'Apply' ) }
80
+ type="submit"
53
81
  />
54
- </div>
55
- <Button
56
- icon={ keyboardReturn }
57
- label={ __( 'Apply' ) }
58
- type="submit"
59
- />
60
- </form>
61
- </URLPopover>
62
- );
82
+ </form>
83
+ </URLPopover>
84
+ );
85
+ };
63
86
 
64
87
  const SocialLinkEdit = ( {
65
88
  attributes,
66
89
  context,
67
90
  isSelected,
68
91
  setAttributes,
92
+ clientId,
69
93
  } ) => {
70
94
  const { url, service, label, rel } = attributes;
71
95
  const { showLabels, iconColorValue, iconBackgroundColorValue } = context;
@@ -143,6 +167,7 @@ const SocialLinkEdit = ( {
143
167
  setAttributes={ setAttributes }
144
168
  setPopover={ setPopover }
145
169
  popoverAnchor={ popoverAnchor }
170
+ clientId={ clientId }
146
171
  />
147
172
  ) }
148
173
  </Button>
@@ -1,8 +1,3 @@
1
- /**
2
- * External dependencies
3
- */
4
- import { isEmpty } from 'lodash';
5
-
6
1
  /**
7
2
  * WordPress dependencies
8
3
  */
@@ -75,7 +70,10 @@ export default function TemplatePartEdit( {
75
70
  return {
76
71
  innerBlocks: getBlocks( clientId ),
77
72
  isResolved: hasResolvedEntity,
78
- isMissing: hasResolvedEntity && isEmpty( entityRecord ),
73
+ isMissing:
74
+ hasResolvedEntity &&
75
+ ( ! entityRecord ||
76
+ Object.keys( entityRecord ).length === 0 ),
79
77
  area: _area,
80
78
  };
81
79
  },
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
- import { kebabCase } from 'lodash';
4
+ import { paramCase as kebabCase } from 'change-case';
5
5
 
6
6
  /**
7
7
  * WordPress dependencies
@@ -143,14 +143,14 @@ function render_block_core_template_part( $attributes ) {
143
143
  }
144
144
 
145
145
  // Run through the actions that are typically taken on the_content.
146
+ $content = shortcode_unautop( $content );
147
+ $content = do_shortcode( $content );
146
148
  $seen_ids[ $template_part_id ] = true;
147
149
  $content = do_blocks( $content );
148
150
  unset( $seen_ids[ $template_part_id ] );
149
151
  $content = wptexturize( $content );
150
152
  $content = convert_smilies( $content );
151
- $content = shortcode_unautop( $content );
152
153
  $content = wp_filter_content_tags( $content, "template_part_{$area}" );
153
- $content = do_shortcode( $content );
154
154
 
155
155
  // Handle embeds for block template parts.
156
156
  global $wp_embed;
@@ -3,6 +3,10 @@
3
3
  */
4
4
  import { useContext, useMemo, useEffect } from 'preact/hooks';
5
5
  import { deepSignal, peek } from 'deepsignal';
6
+ /**
7
+ * Internal dependencies
8
+ */
9
+ import { createPortal } from './portals.js';
6
10
 
7
11
  /**
8
12
  * Internal dependencies
@@ -49,9 +53,20 @@ export default () => {
49
53
  }, [ context, inheritedValue ] );
50
54
 
51
55
  return <Provider value={ value }>{ children }</Provider>;
52
- }
56
+ },
57
+ { priority: 5 }
53
58
  );
54
59
 
60
+ // data-wp-body
61
+ directive( 'body', ( { props: { children }, context: inherited } ) => {
62
+ const { Provider } = inherited;
63
+ const inheritedValue = useContext( inherited );
64
+ return createPortal(
65
+ <Provider value={ inheritedValue }>{ children }</Provider>,
66
+ document.body
67
+ );
68
+ } );
69
+
55
70
  // data-wp-effect.[name]
56
71
  directive( 'effect', ( { directives: { effect }, context, evaluate } ) => {
57
72
  const contextValue = useContext( context );
@@ -140,16 +155,22 @@ export default () => {
140
155
  } );
141
156
  element.props[ attribute ] = result;
142
157
 
158
+ // This seems necessary because Preact doesn't change the attributes
159
+ // on the hydration, so we have to do it manually. It doesn't need
160
+ // deps because it only needs to do it the first time.
143
161
  useEffect( () => {
144
- // This seems necessary because Preact doesn't change the attributes
145
- // on the hydration, so we have to do it manually. It doesn't need
146
- // deps because it only needs to do it the first time.
147
- if ( result === false ) {
162
+ // aria- and data- attributes have no boolean representation.
163
+ // A `false` value is different from the attribute not being
164
+ // present, so we can't remove it.
165
+ // We follow Preact's logic: https://github.com/preactjs/preact/blob/ea49f7a0f9d1ff2c98c0bdd66aa0cbc583055246/src/diff/props.js#L131C24-L136
166
+ if ( result === false && attribute[ 4 ] !== '-' ) {
148
167
  element.ref.current.removeAttribute( attribute );
149
168
  } else {
150
169
  element.ref.current.setAttribute(
151
170
  attribute,
152
- result === true ? '' : result
171
+ result === true && attribute[ 4 ] !== '-'
172
+ ? ''
173
+ : result
153
174
  );
154
175
  }
155
176
  }, [] );