@wordpress/block-library 7.14.2 → 7.15.1-next.4d3b314fd5.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 (235) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/build/avatar/index.js +1 -1
  3. package/build/block/edit.native.js +1 -1
  4. package/build/block/edit.native.js.map +1 -1
  5. package/build/buttons/edit.native.js +1 -3
  6. package/build/buttons/edit.native.js.map +1 -1
  7. package/build/calendar/index.js +9 -0
  8. package/build/calendar/index.js.map +1 -1
  9. package/build/code/index.js +1 -1
  10. package/build/code/index.js.map +1 -1
  11. package/build/comments/edit/comments-legacy.js +1 -1
  12. package/build/comments/edit/comments-legacy.js.map +1 -1
  13. package/build/comments-pagination-next/index.js +1 -1
  14. package/build/comments-pagination-numbers/index.js +8 -1
  15. package/build/comments-pagination-numbers/index.js.map +1 -1
  16. package/build/comments-pagination-previous/index.js +1 -1
  17. package/build/comments-title/edit.js +1 -1
  18. package/build/comments-title/edit.js.map +1 -1
  19. package/build/cover/edit/use-cover-is-dark.js +10 -7
  20. package/build/cover/edit/use-cover-is-dark.js.map +1 -1
  21. package/build/cover/index.js +9 -2
  22. package/build/cover/index.js.map +1 -1
  23. package/build/embed/deprecated.js +12 -6
  24. package/build/embed/deprecated.js.map +1 -1
  25. package/build/embed/index.js +12 -6
  26. package/build/embed/index.js.map +1 -1
  27. package/build/embed/transforms.js +12 -6
  28. package/build/embed/transforms.js.map +1 -1
  29. package/build/embed/util.js +12 -6
  30. package/build/embed/util.js.map +1 -1
  31. package/build/embed/variations.js +1 -1
  32. package/build/embed/variations.js.map +1 -1
  33. package/build/freeform/edit.js +5 -8
  34. package/build/freeform/edit.js.map +1 -1
  35. package/build/gallery/deprecated.js +4 -4
  36. package/build/gallery/deprecated.js.map +1 -1
  37. package/build/gallery/gallery.js +2 -28
  38. package/build/gallery/gallery.js.map +1 -1
  39. package/build/list-item/edit.js +2 -1
  40. package/build/list-item/edit.js.map +1 -1
  41. package/build/missing/edit.js +9 -2
  42. package/build/missing/edit.js.map +1 -1
  43. package/build/more/edit.js +1 -1
  44. package/build/more/edit.js.map +1 -1
  45. package/build/navigation/menu-items-to-blocks.js +16 -6
  46. package/build/navigation/menu-items-to-blocks.js.map +1 -1
  47. package/build/paragraph/drop-zone.js +99 -0
  48. package/build/paragraph/drop-zone.js.map +1 -0
  49. package/build/paragraph/edit.js +11 -3
  50. package/build/paragraph/edit.js.map +1 -1
  51. package/build/post-content/edit.js +6 -1
  52. package/build/post-content/edit.js.map +1 -1
  53. package/build/post-excerpt/edit.js +1 -1
  54. package/build/post-excerpt/edit.js.map +1 -1
  55. package/build/post-navigation-link/edit.js +35 -4
  56. package/build/post-navigation-link/edit.js.map +1 -1
  57. package/build/post-navigation-link/index.js +6 -1
  58. package/build/post-navigation-link/index.js.map +1 -1
  59. package/build/post-template/edit.js +13 -28
  60. package/build/post-template/edit.js.map +1 -1
  61. package/build/query/edit/inspector-controls/index.js +4 -8
  62. package/build/query/edit/inspector-controls/index.js.map +1 -1
  63. package/build/query/edit/inspector-controls/sticky-control.js +1 -1
  64. package/build/query/edit/inspector-controls/sticky-control.js.map +1 -1
  65. package/build/query/edit/query-placeholder.js +2 -2
  66. package/build/query/edit/query-placeholder.js.map +1 -1
  67. package/build/query-title/edit.js +1 -1
  68. package/build/query-title/edit.js.map +1 -1
  69. package/build/quote/transforms.js +2 -2
  70. package/build/quote/transforms.js.map +1 -1
  71. package/build/read-more/edit.js +1 -1
  72. package/build/read-more/edit.js.map +1 -1
  73. package/build/site-tagline/index.js +1 -1
  74. package/build/social-links/edit.native.js +1 -0
  75. package/build/social-links/edit.native.js.map +1 -1
  76. package/build/template-part/edit/index.js +2 -2
  77. package/build/template-part/edit/index.js.map +1 -1
  78. package/build-module/avatar/index.js +1 -1
  79. package/build-module/block/edit.native.js +1 -1
  80. package/build-module/block/edit.native.js.map +1 -1
  81. package/build-module/buttons/edit.native.js +1 -2
  82. package/build-module/buttons/edit.native.js.map +1 -1
  83. package/build-module/calendar/index.js +9 -0
  84. package/build-module/calendar/index.js.map +1 -1
  85. package/build-module/code/index.js +1 -1
  86. package/build-module/code/index.js.map +1 -1
  87. package/build-module/comments/edit/comments-legacy.js +1 -1
  88. package/build-module/comments/edit/comments-legacy.js.map +1 -1
  89. package/build-module/comments-pagination-next/index.js +1 -1
  90. package/build-module/comments-pagination-numbers/index.js +8 -1
  91. package/build-module/comments-pagination-numbers/index.js.map +1 -1
  92. package/build-module/comments-pagination-previous/index.js +1 -1
  93. package/build-module/comments-title/edit.js +1 -1
  94. package/build-module/comments-title/edit.js.map +1 -1
  95. package/build-module/cover/edit/use-cover-is-dark.js +9 -4
  96. package/build-module/cover/edit/use-cover-is-dark.js.map +1 -1
  97. package/build-module/cover/index.js +9 -2
  98. package/build-module/cover/index.js.map +1 -1
  99. package/build-module/embed/deprecated.js +12 -6
  100. package/build-module/embed/deprecated.js.map +1 -1
  101. package/build-module/embed/index.js +12 -6
  102. package/build-module/embed/index.js.map +1 -1
  103. package/build-module/embed/transforms.js +12 -6
  104. package/build-module/embed/transforms.js.map +1 -1
  105. package/build-module/embed/util.js +12 -6
  106. package/build-module/embed/util.js.map +1 -1
  107. package/build-module/embed/variations.js +1 -1
  108. package/build-module/embed/variations.js.map +1 -1
  109. package/build-module/freeform/edit.js +3 -6
  110. package/build-module/freeform/edit.js.map +1 -1
  111. package/build-module/gallery/deprecated.js +4 -4
  112. package/build-module/gallery/deprecated.js.map +1 -1
  113. package/build-module/gallery/gallery.js +2 -29
  114. package/build-module/gallery/gallery.js.map +1 -1
  115. package/build-module/list-item/edit.js +2 -1
  116. package/build-module/list-item/edit.js.map +1 -1
  117. package/build-module/missing/edit.js +11 -4
  118. package/build-module/missing/edit.js.map +1 -1
  119. package/build-module/more/edit.js +1 -1
  120. package/build-module/more/edit.js.map +1 -1
  121. package/build-module/navigation/menu-items-to-blocks.js +16 -6
  122. package/build-module/navigation/menu-items-to-blocks.js.map +1 -1
  123. package/build-module/paragraph/drop-zone.js +88 -0
  124. package/build-module/paragraph/drop-zone.js.map +1 -0
  125. package/build-module/paragraph/edit.js +10 -3
  126. package/build-module/paragraph/edit.js.map +1 -1
  127. package/build-module/post-content/edit.js +6 -1
  128. package/build-module/post-content/edit.js.map +1 -1
  129. package/build-module/post-excerpt/edit.js +1 -1
  130. package/build-module/post-excerpt/edit.js.map +1 -1
  131. package/build-module/post-navigation-link/edit.js +37 -6
  132. package/build-module/post-navigation-link/edit.js.map +1 -1
  133. package/build-module/post-navigation-link/index.js +6 -1
  134. package/build-module/post-navigation-link/index.js.map +1 -1
  135. package/build-module/post-template/edit.js +14 -29
  136. package/build-module/post-template/edit.js.map +1 -1
  137. package/build-module/query/edit/inspector-controls/index.js +2 -6
  138. package/build-module/query/edit/inspector-controls/index.js.map +1 -1
  139. package/build-module/query/edit/inspector-controls/sticky-control.js +1 -1
  140. package/build-module/query/edit/inspector-controls/sticky-control.js.map +1 -1
  141. package/build-module/query/edit/query-placeholder.js +2 -2
  142. package/build-module/query/edit/query-placeholder.js.map +1 -1
  143. package/build-module/query-title/edit.js +1 -1
  144. package/build-module/query-title/edit.js.map +1 -1
  145. package/build-module/quote/transforms.js +2 -2
  146. package/build-module/quote/transforms.js.map +1 -1
  147. package/build-module/read-more/edit.js +1 -1
  148. package/build-module/read-more/edit.js.map +1 -1
  149. package/build-module/site-tagline/index.js +1 -1
  150. package/build-module/social-links/edit.native.js +1 -0
  151. package/build-module/social-links/edit.native.js.map +1 -1
  152. package/build-module/template-part/edit/index.js +3 -3
  153. package/build-module/template-part/edit/index.js.map +1 -1
  154. package/build-style/calendar/style-rtl.css +21 -12
  155. package/build-style/calendar/style.css +21 -12
  156. package/build-style/classic-rtl.css +85 -0
  157. package/build-style/classic.css +85 -0
  158. package/build-style/editor-rtl.css +41 -2
  159. package/build-style/editor.css +41 -2
  160. package/build-style/group/editor-rtl.css +11 -1
  161. package/build-style/group/editor.css +11 -1
  162. package/build-style/image/editor-rtl.css +3 -0
  163. package/build-style/image/editor.css +3 -0
  164. package/build-style/navigation/editor-rtl.css +11 -1
  165. package/build-style/navigation/editor.css +11 -1
  166. package/build-style/paragraph/editor-rtl.css +16 -0
  167. package/build-style/paragraph/editor.css +16 -0
  168. package/build-style/post-navigation-link/style-rtl.css +90 -0
  169. package/build-style/post-navigation-link/style.css +90 -0
  170. package/build-style/style-rtl.css +36 -12
  171. package/build-style/style.css +36 -12
  172. package/package.json +29 -29
  173. package/src/archives/index.php +4 -7
  174. package/src/avatar/block.json +1 -1
  175. package/src/block/edit.native.js +1 -1
  176. package/src/buttons/edit.native.js +1 -2
  177. package/src/buttons/test/__snapshots__/edit.native.js.snap +28 -0
  178. package/src/buttons/test/edit.native.js +170 -0
  179. package/src/calendar/block.json +9 -0
  180. package/src/calendar/index.php +22 -1
  181. package/src/calendar/style.scss +28 -15
  182. package/src/classic.scss +15 -0
  183. package/src/code/index.js +1 -1
  184. package/src/columns/test/__snapshots__/edit.native.js.snap +219 -0
  185. package/src/columns/test/edit.native.js +432 -0
  186. package/src/comment-template/index.php +18 -8
  187. package/src/comments/edit/comments-legacy.js +1 -1
  188. package/src/comments-pagination-next/block.json +1 -1
  189. package/src/comments-pagination-numbers/block.json +8 -1
  190. package/src/comments-pagination-previous/block.json +1 -1
  191. package/src/comments-title/edit.js +1 -1
  192. package/src/cover/edit/use-cover-is-dark.js +11 -7
  193. package/src/cover/index.js +8 -1
  194. package/src/cover/test/__snapshots__/edit.native.js.snap +64 -0
  195. package/src/cover/test/edit.native.js +136 -4
  196. package/src/embed/block.json +12 -6
  197. package/src/embed/test/index.native.js +1 -2
  198. package/src/embed/variations.js +1 -1
  199. package/src/freeform/edit.js +12 -10
  200. package/src/gallery/deprecated.js +4 -4
  201. package/src/gallery/gallery.js +1 -31
  202. package/src/group/test/__snapshots__/edit.native.js.snap +19 -0
  203. package/src/group/test/edit.native.js +102 -0
  204. package/src/image/editor.scss +4 -0
  205. package/src/list-item/edit.js +1 -0
  206. package/src/missing/edit.js +15 -4
  207. package/src/more/edit.js +1 -1
  208. package/src/navigation/menu-items-to-blocks.js +39 -22
  209. package/src/navigation/test/menu-items-to-blocks.js +6 -0
  210. package/src/navigation-submenu/index.php +11 -2
  211. package/src/page-list/index.php +1 -1
  212. package/src/paragraph/drop-zone.js +105 -0
  213. package/src/paragraph/edit.js +14 -1
  214. package/src/paragraph/editor.scss +20 -0
  215. package/src/post-content/edit.js +3 -1
  216. package/src/post-excerpt/edit.js +1 -1
  217. package/src/post-featured-image/index.php +11 -18
  218. package/src/post-navigation-link/block.json +6 -1
  219. package/src/post-navigation-link/edit.js +64 -3
  220. package/src/post-navigation-link/index.php +23 -0
  221. package/src/post-navigation-link/style.scss +23 -0
  222. package/src/post-template/edit.js +14 -23
  223. package/src/query/edit/inspector-controls/index.js +2 -6
  224. package/src/query/edit/inspector-controls/sticky-control.js +1 -1
  225. package/src/query/edit/query-placeholder.js +4 -1
  226. package/src/query-title/edit.js +1 -1
  227. package/src/quote/transforms.js +1 -1
  228. package/src/read-more/edit.js +1 -1
  229. package/src/site-tagline/block.json +1 -1
  230. package/src/social-links/edit.native.js +7 -1
  231. package/src/social-links/test/__snapshots__/edit.native.js.snap +57 -0
  232. package/src/social-links/test/edit.native.js +199 -0
  233. package/src/style.scss +1 -0
  234. package/src/tag-cloud/index.php +1 -8
  235. package/src/template-part/edit/index.js +60 -58
@@ -0,0 +1,102 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import {
5
+ addBlock,
6
+ fireEvent,
7
+ getEditorHtml,
8
+ initializeEditor,
9
+ within,
10
+ getBlock,
11
+ waitFor,
12
+ } from 'test/helpers';
13
+
14
+ /**
15
+ * WordPress dependencies
16
+ */
17
+ import { getBlockTypes, unregisterBlockType } from '@wordpress/blocks';
18
+ import { registerCoreBlocks } from '@wordpress/block-library';
19
+
20
+ const NESTED_GROUP_BLOCK = `<!-- wp:group {"layout":{"type":"constrained"}} -->
21
+ <div class="wp-block-group"><!-- wp:image -->
22
+ <figure class="wp-block-image"><img alt=""/></figure>
23
+ <!-- /wp:image -->
24
+ <!-- wp:group {"layout":{"type":"constrained"}} -->
25
+ <div class="wp-block-group"><!-- wp:spacer -->
26
+ <div style="height:100px" aria-hidden="true" class="wp-block-spacer"></div>
27
+ <!-- /wp:spacer --></div>
28
+ <!-- /wp:group --></div>
29
+ <!-- /wp:group -->`;
30
+
31
+ beforeAll( () => {
32
+ // Register all core blocks
33
+ registerCoreBlocks();
34
+ } );
35
+
36
+ afterAll( () => {
37
+ // Clean up registered blocks
38
+ getBlockTypes().forEach( ( block ) => {
39
+ unregisterBlockType( block.name );
40
+ } );
41
+ } );
42
+
43
+ describe( 'Group block', () => {
44
+ it( 'inserts block and adds a Heading block as an inner block', async () => {
45
+ const screen = await initializeEditor();
46
+ const { getByTestId, getByText } = screen;
47
+
48
+ // Add block
49
+ await addBlock( screen, 'Group' );
50
+
51
+ // Get block
52
+ const groupBlock = await getBlock( screen, 'Group' );
53
+ fireEvent.press( groupBlock );
54
+
55
+ // Append a block in the Group block
56
+ const appenderButton =
57
+ within( groupBlock ).getByTestId( 'appender-button' );
58
+ fireEvent.press( appenderButton );
59
+
60
+ // Look for a block in the inserter
61
+ const blockList = getByTestId( 'InserterUI-Blocks' );
62
+
63
+ // onScroll event used to force the FlatList to render all items
64
+ fireEvent.scroll( blockList, {
65
+ nativeEvent: {
66
+ contentOffset: { y: 0, x: 0 },
67
+ contentSize: { width: 100, height: 100 },
68
+ layoutMeasurement: { width: 100, height: 100 },
69
+ },
70
+ } );
71
+
72
+ // Add a block
73
+ fireEvent.press( await waitFor( () => getByText( 'Heading' ) ) );
74
+
75
+ expect( getEditorHtml() ).toMatchSnapshot();
76
+ } );
77
+
78
+ it( 'ungroups inner blocks', async () => {
79
+ const screen = await initializeEditor( {
80
+ initialHtml: NESTED_GROUP_BLOCK,
81
+ } );
82
+ const { getByA11yLabel } = screen;
83
+
84
+ // Get block
85
+ let groupBlock = await getBlock( screen, 'Group' );
86
+ fireEvent.press( groupBlock );
87
+
88
+ // Get Ungroup button
89
+ let ungroupButton = getByA11yLabel( /Ungroup/ );
90
+ fireEvent.press( ungroupButton );
91
+
92
+ // Press Group block again
93
+ groupBlock = await getBlock( screen, 'Group', { rowIndex: 2 } );
94
+ fireEvent.press( groupBlock );
95
+
96
+ // Ungroup last block
97
+ ungroupButton = getByA11yLabel( /Ungroup/ );
98
+ fireEvent.press( ungroupButton );
99
+
100
+ expect( getEditorHtml() ).toMatchSnapshot();
101
+ } );
102
+ } );
@@ -22,6 +22,10 @@
22
22
  .components-placeholder__illustration {
23
23
  display: none;
24
24
  }
25
+
26
+ &::before {
27
+ opacity: 0;
28
+ }
25
29
  }
26
30
 
27
31
  // Remove the transition while we still have a legacy placeholder style.
@@ -65,6 +65,7 @@ export default function ListItemEdit( {
65
65
  const blockProps = useBlockProps( { ref: useCopy( clientId ) } );
66
66
  const innerBlocksProps = useInnerBlocksProps( blockProps, {
67
67
  allowedBlocks: [ 'core/list' ],
68
+ renderAppender: false,
68
69
  } );
69
70
  const useEnterRef = useEnter( { content, clientId } );
70
71
  const useSpaceRef = useSpace( clientId );
@@ -4,8 +4,8 @@
4
4
  import { __, sprintf } from '@wordpress/i18n';
5
5
  import { RawHTML } from '@wordpress/element';
6
6
  import { Button } from '@wordpress/components';
7
- import { getBlockType, createBlock } from '@wordpress/blocks';
8
- import { withDispatch } from '@wordpress/data';
7
+ import { createBlock } from '@wordpress/blocks';
8
+ import { withDispatch, useSelect } from '@wordpress/data';
9
9
  import {
10
10
  Warning,
11
11
  useBlockProps,
@@ -13,10 +13,21 @@ import {
13
13
  } from '@wordpress/block-editor';
14
14
  import { safeHTML } from '@wordpress/dom';
15
15
 
16
- function MissingBlockWarning( { attributes, convertToHTML } ) {
16
+ function MissingBlockWarning( { attributes, convertToHTML, clientId } ) {
17
17
  const { originalName, originalUndelimitedContent } = attributes;
18
18
  const hasContent = !! originalUndelimitedContent;
19
- const hasHTMLBlock = getBlockType( 'core/html' );
19
+ const hasHTMLBlock = useSelect(
20
+ ( select ) => {
21
+ const { canInsertBlockType, getBlockRootClientId } =
22
+ select( blockEditorStore );
23
+
24
+ return canInsertBlockType(
25
+ 'core/html',
26
+ getBlockRootClientId( clientId )
27
+ );
28
+ },
29
+ [ clientId ]
30
+ );
20
31
 
21
32
  const actions = [];
22
33
  let messageHTML;
package/src/more/edit.js CHANGED
@@ -54,7 +54,7 @@ export default function MoreEdit( {
54
54
  </InspectorControls>
55
55
  <div { ...useBlockProps() }>
56
56
  <input
57
- aria-label={ __( 'Read more link text' ) }
57
+ aria-label={ __( 'Read more link text' ) }
58
58
  type="text"
59
59
  value={ customText }
60
60
  placeholder={ DEFAULT_TEXT }
@@ -29,9 +29,10 @@ export default function menuItemsToBlocks( menuItems ) {
29
29
  * A recursive function that maps menu item nodes to blocks.
30
30
  *
31
31
  * @param {WPNavMenuItem[]} menuItems An array of WPNavMenuItem items.
32
+ * @param {number} level An integer representing the nesting level.
32
33
  * @return {Object} Object containing innerBlocks and mapping.
33
34
  */
34
- function mapMenuItemsToBlocks( menuItems ) {
35
+ function mapMenuItemsToBlocks( menuItems, level = 0 ) {
35
36
  let mapping = {};
36
37
 
37
38
  // The menuItem should be in menu_order sort order.
@@ -52,14 +53,22 @@ function mapMenuItemsToBlocks( menuItems ) {
52
53
  return block;
53
54
  }
54
55
 
55
- const attributes = menuItemToBlockAttributes( menuItem );
56
+ const blockType = menuItem.children?.length
57
+ ? 'core/navigation-submenu'
58
+ : 'core/navigation-link';
59
+
60
+ const attributes = menuItemToBlockAttributes(
61
+ menuItem,
62
+ blockType,
63
+ level
64
+ );
56
65
 
57
66
  // If there are children recurse to build those nested blocks.
58
67
  const {
59
68
  innerBlocks: nestedBlocks = [], // alias to avoid shadowing
60
69
  mapping: nestedMapping = {}, // alias to avoid shadowing
61
70
  } = menuItem.children?.length
62
- ? mapMenuItemsToBlocks( menuItem.children )
71
+ ? mapMenuItemsToBlocks( menuItem.children, level + 1 )
63
72
  : {};
64
73
 
65
74
  // Update parent mapping with nested mapping.
@@ -68,10 +77,6 @@ function mapMenuItemsToBlocks( menuItems ) {
68
77
  ...nestedMapping,
69
78
  };
70
79
 
71
- const blockType = menuItem.children?.length
72
- ? 'core/navigation-submenu'
73
- : 'core/navigation-link';
74
-
75
80
  // Create block with nested "innerBlocks".
76
81
  const block = createBlock( blockType, attributes, nestedBlocks );
77
82
 
@@ -111,23 +116,29 @@ function mapMenuItemsToBlocks( menuItems ) {
111
116
  /**
112
117
  * Convert block attributes to menu item.
113
118
  *
114
- * @param {WPNavMenuItem} menuItem the menu item to be converted to block attributes.
119
+ * @param {WPNavMenuItem} menuItem the menu item to be converted to block attributes.
120
+ * @param {string} blockType The block type.
121
+ * @param {number} level An integer representing the nesting level.
115
122
  * @return {Object} the block attributes converted from the WPNavMenuItem item.
116
123
  */
117
- function menuItemToBlockAttributes( {
118
- title: menuItemTitleField,
119
- xfn,
120
- classes,
121
- // eslint-disable-next-line camelcase
122
- attr_title,
123
- object,
124
- // eslint-disable-next-line camelcase
125
- object_id,
126
- description,
127
- url,
128
- type: menuItemTypeField,
129
- target,
130
- } ) {
124
+ function menuItemToBlockAttributes(
125
+ {
126
+ title: menuItemTitleField,
127
+ xfn,
128
+ classes,
129
+ // eslint-disable-next-line camelcase
130
+ attr_title,
131
+ object,
132
+ // eslint-disable-next-line camelcase
133
+ object_id,
134
+ description,
135
+ url,
136
+ type: menuItemTypeField,
137
+ target,
138
+ },
139
+ blockType,
140
+ level
141
+ ) {
131
142
  // For historical reasons, the `core/navigation-link` variation type is `tag`
132
143
  // whereas WP Core expects `post_tag` as the `object` type.
133
144
  // To avoid writing a block migration we perform a conversion here.
@@ -166,6 +177,12 @@ function menuItemToBlockAttributes( {
166
177
  ...( target === '_blank' && {
167
178
  opensInNewTab: true,
168
179
  } ),
180
+ ...( blockType === 'core/navigation-submenu' && {
181
+ isTopLevelItem: level === 0,
182
+ } ),
183
+ ...( blockType === 'core/navigation-link' && {
184
+ isTopLevelLink: level === 0,
185
+ } ),
169
186
  };
170
187
  }
171
188
 
@@ -189,12 +189,14 @@ describe( 'converting menu items to blocks', () => {
189
189
  name: 'core/navigation-submenu',
190
190
  attributes: expect.objectContaining( {
191
191
  label: 'Top Level',
192
+ isTopLevelItem: true,
192
193
  } ),
193
194
  innerBlocks: [
194
195
  expect.objectContaining( {
195
196
  name: 'core/navigation-link',
196
197
  attributes: expect.objectContaining( {
197
198
  label: 'Child 1',
199
+ isTopLevelLink: false,
198
200
  } ),
199
201
  innerBlocks: [],
200
202
  } ),
@@ -202,18 +204,21 @@ describe( 'converting menu items to blocks', () => {
202
204
  name: 'core/navigation-submenu',
203
205
  attributes: expect.objectContaining( {
204
206
  label: 'Child 2',
207
+ isTopLevelItem: false,
205
208
  } ),
206
209
  innerBlocks: [
207
210
  expect.objectContaining( {
208
211
  name: 'core/navigation-submenu',
209
212
  attributes: expect.objectContaining( {
210
213
  label: 'Sub Child',
214
+ isTopLevelItem: false,
211
215
  } ),
212
216
  innerBlocks: [
213
217
  expect.objectContaining( {
214
218
  name: 'core/navigation-link',
215
219
  attributes: expect.objectContaining( {
216
220
  label: 'Sub Sub Child',
221
+ isTopLevelLink: false,
217
222
  } ),
218
223
  innerBlocks: [],
219
224
  } ),
@@ -227,6 +232,7 @@ describe( 'converting menu items to blocks', () => {
227
232
  name: 'core/navigation-link',
228
233
  attributes: expect.objectContaining( {
229
234
  label: 'Top Level 2',
235
+ isTopLevelLink: true,
230
236
  } ),
231
237
  innerBlocks: [],
232
238
  } ),
@@ -148,7 +148,7 @@ function render_block_core_navigation_submenu( $attributes, $content, $block ) {
148
148
 
149
149
  $css_classes = trim( implode( ' ', $classes ) );
150
150
  $has_submenu = count( $block->inner_blocks ) > 0;
151
- $is_active = ! empty( $attributes['id'] ) && ( get_the_ID() === (int) $attributes['id'] );
151
+ $is_active = ! empty( $attributes['id'] ) && ( get_queried_object_id() === (int) $attributes['id'] );
152
152
 
153
153
  $show_submenu_indicators = isset( $block->context['showSubmenuIcon'] ) && $block->context['showSubmenuIcon'];
154
154
  $open_on_click = isset( $block->context['openSubmenusOnClick'] ) && $block->context['openSubmenusOnClick'];
@@ -183,7 +183,16 @@ function render_block_core_navigation_submenu( $attributes, $content, $block ) {
183
183
  if ( ! $open_on_click ) {
184
184
  $item_url = isset( $attributes['url'] ) ? $attributes['url'] : '';
185
185
  // Start appending HTML attributes to anchor tag.
186
- $html .= '<a class="wp-block-navigation-item__content" href="' . esc_url( $item_url ) . '"';
186
+ $html .= '<a class="wp-block-navigation-item__content"';
187
+
188
+ // The href attribute on a and area elements is not required;
189
+ // when those elements do not have href attributes they do not create hyperlinks.
190
+ // But also The href attribute must have a value that is a valid URL potentially
191
+ // surrounded by spaces.
192
+ // see: https://html.spec.whatwg.org/multipage/links.html#links-created-by-a-and-area-elements.
193
+ if ( ! empty( $item_url ) ) {
194
+ $html .= ' href="' . esc_url( $item_url ) . '"';
195
+ }
187
196
 
188
197
  if ( $is_active ) {
189
198
  $html .= ' aria-current="page"';
@@ -264,7 +264,7 @@ function render_block_core_page_list( $attributes, $content, $block ) {
264
264
  $active_page_ancestor_ids = array();
265
265
 
266
266
  foreach ( (array) $all_pages as $page ) {
267
- $is_active = ! empty( $page->ID ) && ( get_the_ID() === $page->ID );
267
+ $is_active = ! empty( $page->ID ) && ( get_queried_object_id() === $page->ID );
268
268
 
269
269
  if ( $is_active ) {
270
270
  $active_page_ancestor_ids = get_post_ancestors( $page->ID );
@@ -0,0 +1,105 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useState } from '@wordpress/element';
5
+ import { useSelect } from '@wordpress/data';
6
+ import {
7
+ __experimentalUseOnBlockDrop as useOnBlockDrop,
8
+ store as blockEditorStore,
9
+ } from '@wordpress/block-editor';
10
+ import {
11
+ __experimentalUseDropZone as useDropZone,
12
+ useReducedMotion,
13
+ } from '@wordpress/compose';
14
+ import {
15
+ Popover,
16
+ __unstableMotion as motion,
17
+ __unstableAnimatePresence as AnimatePresence,
18
+ } from '@wordpress/components';
19
+
20
+ const animateVariants = {
21
+ hide: { opacity: 0, scaleY: 0.75 },
22
+ show: { opacity: 1, scaleY: 1 },
23
+ exit: { opacity: 0, scaleY: 0.9 },
24
+ };
25
+
26
+ export default function DropZone( { paragraphElement, clientId } ) {
27
+ const { rootClientId, blockIndex } = useSelect(
28
+ ( select ) => {
29
+ const selectors = select( blockEditorStore );
30
+ return {
31
+ rootClientId: selectors.getBlockRootClientId( clientId ),
32
+ blockIndex: selectors.getBlockIndex( clientId ),
33
+ };
34
+ },
35
+ [ clientId ]
36
+ );
37
+ const onBlockDrop = useOnBlockDrop( rootClientId, blockIndex, {
38
+ action: 'replace',
39
+ } );
40
+ const [ isDragging, setIsDragging ] = useState( false );
41
+ const [ isVisible, setIsVisible ] = useState( false );
42
+ const popoverRef = useDropZone( {
43
+ onDragStart: () => {
44
+ setIsDragging( true );
45
+ },
46
+ onDragEnd: () => {
47
+ setIsDragging( false );
48
+ },
49
+ } );
50
+ const dropZoneRef = useDropZone( {
51
+ onDrop: onBlockDrop,
52
+ onDragEnter: () => {
53
+ setIsVisible( true );
54
+ },
55
+ onDragLeave: () => {
56
+ setIsVisible( false );
57
+ },
58
+ } );
59
+ const reducedMotion = useReducedMotion();
60
+
61
+ return (
62
+ <Popover
63
+ anchor={ paragraphElement }
64
+ animate={ false }
65
+ placement="top-start"
66
+ focusOnMount={ false }
67
+ flip={ false }
68
+ resize={ false }
69
+ className="wp-block-paragraph__drop-zone"
70
+ ref={ popoverRef }
71
+ >
72
+ { isDragging ? (
73
+ <div
74
+ className="wp-block-paragraph__drop-zone-backdrop"
75
+ ref={ dropZoneRef }
76
+ style={ {
77
+ width: paragraphElement?.offsetWidth,
78
+ height: paragraphElement?.offsetHeight,
79
+ } }
80
+ >
81
+ <AnimatePresence>
82
+ { isVisible ? (
83
+ <motion.div
84
+ key="drop-zone-foreground"
85
+ data-testid="empty-paragraph-drop-zone"
86
+ initial={
87
+ reducedMotion
88
+ ? animateVariants.show
89
+ : animateVariants.hide
90
+ }
91
+ animate={ animateVariants.show }
92
+ exit={
93
+ reducedMotion
94
+ ? animateVariants.show
95
+ : animateVariants.exit
96
+ }
97
+ className="wp-block-paragraph__drop-zone-foreground"
98
+ />
99
+ ) : null }
100
+ </AnimatePresence>
101
+ </div>
102
+ ) : null }
103
+ </Popover>
104
+ );
105
+ }
@@ -6,6 +6,7 @@ import classnames from 'classnames';
6
6
  /**
7
7
  * WordPress dependencies
8
8
  */
9
+ import { useState } from '@wordpress/element';
9
10
  import { __, _x, isRTL } from '@wordpress/i18n';
10
11
  import {
11
12
  ToolbarButton,
@@ -20,6 +21,7 @@ import {
20
21
  useBlockProps,
21
22
  useSetting,
22
23
  } from '@wordpress/block-editor';
24
+ import { useMergeRefs } from '@wordpress/compose';
23
25
  import { createBlock } from '@wordpress/blocks';
24
26
  import { formatLtr } from '@wordpress/icons';
25
27
 
@@ -27,6 +29,7 @@ import { formatLtr } from '@wordpress/icons';
27
29
  * Internal dependencies
28
30
  */
29
31
  import { useOnEnter } from './use-enter';
32
+ import DropZone from './drop-zone';
30
33
 
31
34
  const name = 'core/paragraph';
32
35
 
@@ -55,8 +58,12 @@ function ParagraphBlock( {
55
58
  } ) {
56
59
  const { align, content, direction, dropCap, placeholder } = attributes;
57
60
  const isDropCapFeatureEnabled = useSetting( 'typography.dropCap' );
61
+ const [ paragraphElement, setParagraphElement ] = useState( null );
58
62
  const blockProps = useBlockProps( {
59
- ref: useOnEnter( { clientId, content } ),
63
+ ref: useMergeRefs( [
64
+ useOnEnter( { clientId, content } ),
65
+ setParagraphElement,
66
+ ] ),
60
67
  className: classnames( {
61
68
  'has-drop-cap': dropCap,
62
69
  [ `has-text-align-${ align }` ]: align,
@@ -108,6 +115,12 @@ function ParagraphBlock( {
108
115
  </ToolsPanelItem>
109
116
  </InspectorControls>
110
117
  ) }
118
+ { ! content && (
119
+ <DropZone
120
+ clientId={ clientId }
121
+ paragraphElement={ paragraphElement }
122
+ />
123
+ ) }
111
124
  <RichText
112
125
  identifier="content"
113
126
  tagName="p"
@@ -17,3 +17,23 @@
17
17
  }
18
18
  }
19
19
  }
20
+
21
+ .components-popover.wp-block-paragraph__drop-zone {
22
+ .components-popover__content {
23
+ border: none;
24
+ outline: none;
25
+ box-shadow: none;
26
+ }
27
+
28
+ .wp-block-paragraph__drop-zone-backdrop {
29
+ position: absolute;
30
+ }
31
+
32
+ .wp-block-paragraph__drop-zone-foreground {
33
+ position: absolute;
34
+ inset: 0;
35
+ pointer-events: none;
36
+ background-color: var(--wp-admin-theme-color);
37
+ border-radius: 2px;
38
+ }
39
+ }
@@ -46,7 +46,9 @@ function EditableContent( { layout, context = {} } ) {
46
46
  return getSettings()?.supportsLayout;
47
47
  }, [] );
48
48
  const defaultLayout = useSetting( 'layout' ) || {};
49
- const usedLayout = !! layout && layout.inherit ? defaultLayout : layout;
49
+ const usedLayout = ! layout?.type
50
+ ? { ...defaultLayout, ...layout, type: 'default' }
51
+ : { ...defaultLayout, ...layout };
50
52
  const [ blocks, onInput, onChange ] = useEntityBlockEditor(
51
53
  'postType',
52
54
  postType,
@@ -87,7 +87,7 @@ export default function PostExcerptEditor( {
87
87
  <RichText
88
88
  className="wp-block-post-excerpt__more-link"
89
89
  tagName="a"
90
- aria-label={ __( '"Read more" link text' ) }
90
+ aria-label={ __( 'Read more link text' ) }
91
91
  placeholder={ __( 'Add "read more" link text' ) }
92
92
  value={ moreText }
93
93
  onChange={ ( newMoreText ) =>
@@ -29,11 +29,18 @@ function render_block_core_post_featured_image( $attributes, $content, $block )
29
29
  $attr['alt'] = $post_title;
30
30
  }
31
31
 
32
+ if ( ! empty( $attributes['height'] ) ) {
33
+ $extra_styles = "height:{$attributes['height']};";
34
+ if ( ! empty( $attributes['scale'] ) ) {
35
+ $extra_styles .= "object-fit:{$attributes['scale']};";
36
+ }
37
+ $attr['style'] = empty( $attr['style'] ) ? $extra_styles : $attr['style'] . $extra_styles;
38
+ }
39
+
32
40
  $featured_image = get_the_post_thumbnail( $post_ID, $size_slug, $attr );
33
41
  if ( ! $featured_image ) {
34
42
  return '';
35
43
  }
36
- $wrapper_attributes = get_block_wrapper_attributes();
37
44
  if ( $is_link ) {
38
45
  $link_target = $attributes['linkTarget'];
39
46
  $rel = ! empty( $attributes['rel'] ) ? 'rel="' . esc_attr( $attributes['rel'] ) . '"' : '';
@@ -49,23 +56,9 @@ function render_block_core_post_featured_image( $attributes, $content, $block )
49
56
  $featured_image = $featured_image . $overlay_markup;
50
57
  }
51
58
 
52
- $has_width = ! empty( $attributes['width'] );
53
- $has_height = ! empty( $attributes['height'] );
54
- if ( ! $has_height && ! $has_width ) {
55
- return "<figure {$wrapper_attributes}>{$featured_image}</figure>";
56
- }
57
-
58
- if ( $has_width ) {
59
- $wrapper_attributes = get_block_wrapper_attributes( array( 'style' => "width:{$attributes['width']};" ) );
60
- }
61
-
62
- if ( $has_height ) {
63
- $image_styles = "height:{$attributes['height']};";
64
- if ( ! empty( $attributes['scale'] ) ) {
65
- $image_styles .= "object-fit:{$attributes['scale']};";
66
- }
67
- $featured_image = str_replace( 'src=', 'style="' . esc_attr( $image_styles ) . '" src=', $featured_image );
68
- }
59
+ $wrapper_attributes = empty( $attributes['width'] )
60
+ ? get_block_wrapper_attributes()
61
+ : get_block_wrapper_attributes( array( 'style' => "width:{$attributes['width']};" ) );
69
62
 
70
63
  return "<figure {$wrapper_attributes}>{$featured_image}</figure>";
71
64
  }
@@ -24,6 +24,10 @@
24
24
  "linkLabel": {
25
25
  "type": "boolean",
26
26
  "default": false
27
+ },
28
+ "arrow": {
29
+ "type": "string",
30
+ "default": "none"
27
31
  }
28
32
  },
29
33
  "supports": {
@@ -45,5 +49,6 @@
45
49
  "fontSize": true
46
50
  }
47
51
  }
48
- }
52
+ },
53
+ "style": "wp-block-post-navigation-link"
49
54
  }