@wordpress/block-library 9.30.0 → 9.30.1-next.6f42e1382.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 (189) hide show
  1. package/build/accordion-content/edit.js +8 -8
  2. package/build/accordion-content/edit.js.map +1 -1
  3. package/build/accordion-content/index.js +2 -1
  4. package/build/accordion-content/index.js.map +1 -1
  5. package/build/accordion-panel/index.js +2 -1
  6. package/build/accordion-panel/index.js.map +1 -1
  7. package/build/buttons/index.js +2 -1
  8. package/build/buttons/index.js.map +1 -1
  9. package/build/categories/edit.js +3 -1
  10. package/build/categories/edit.js.map +1 -1
  11. package/build/index.js +4 -0
  12. package/build/index.js.map +1 -1
  13. package/build/navigation/constants.js +5 -1
  14. package/build/navigation/constants.js.map +1 -1
  15. package/build/navigation/edit/index.js +45 -1
  16. package/build/navigation/edit/index.js.map +1 -1
  17. package/build/navigation/edit/leaf-more-menu.js +0 -1
  18. package/build/navigation/edit/leaf-more-menu.js.map +1 -1
  19. package/build/navigation/edit/menu-inspector-controls.js +40 -5
  20. package/build/navigation/edit/menu-inspector-controls.js.map +1 -1
  21. package/build/navigation-link/block-inserter.js +69 -0
  22. package/build/navigation-link/block-inserter.js.map +1 -0
  23. package/build/navigation-link/dialog-wrapper.js +80 -0
  24. package/build/navigation-link/dialog-wrapper.js.map +1 -0
  25. package/build/navigation-link/link-ui.js +80 -120
  26. package/build/navigation-link/link-ui.js.map +1 -1
  27. package/build/navigation-link/page-creator.js +137 -0
  28. package/build/navigation-link/page-creator.js.map +1 -0
  29. package/build/search/edit.js +22 -14
  30. package/build/search/edit.js.map +1 -1
  31. package/build/social-links/index.js +2 -1
  32. package/build/social-links/index.js.map +1 -1
  33. package/build/table-of-contents/edit.js +33 -9
  34. package/build/table-of-contents/edit.js.map +1 -1
  35. package/build/table-of-contents/index.js +4 -0
  36. package/build/table-of-contents/index.js.map +1 -1
  37. package/build/table-of-contents/list.js +6 -3
  38. package/build/table-of-contents/list.js.map +1 -1
  39. package/build/table-of-contents/save.js +6 -3
  40. package/build/table-of-contents/save.js.map +1 -1
  41. package/build/term-template/edit.js +318 -0
  42. package/build/term-template/edit.js.map +1 -0
  43. package/build/term-template/index.js +109 -0
  44. package/build/term-template/index.js.map +1 -0
  45. package/build/term-template/save.js +16 -0
  46. package/build/term-template/save.js.map +1 -0
  47. package/build/term-template/variations.js +83 -0
  48. package/build/term-template/variations.js.map +1 -0
  49. package/build/terms-query/edit.js +20 -0
  50. package/build/terms-query/edit.js.map +1 -0
  51. package/build/terms-query/index.js +83 -0
  52. package/build/terms-query/index.js.map +1 -0
  53. package/build/terms-query/inspector-controls.js +246 -0
  54. package/build/terms-query/inspector-controls.js.map +1 -0
  55. package/build/terms-query/save.js +24 -0
  56. package/build/terms-query/save.js.map +1 -0
  57. package/build/terms-query/terms-query-content.js +71 -0
  58. package/build/terms-query/terms-query-content.js.map +1 -0
  59. package/build-module/accordion-content/edit.js +8 -8
  60. package/build-module/accordion-content/edit.js.map +1 -1
  61. package/build-module/accordion-content/index.js +2 -1
  62. package/build-module/accordion-content/index.js.map +1 -1
  63. package/build-module/accordion-panel/index.js +2 -1
  64. package/build-module/accordion-panel/index.js.map +1 -1
  65. package/build-module/buttons/index.js +2 -1
  66. package/build-module/buttons/index.js.map +1 -1
  67. package/build-module/categories/edit.js +3 -1
  68. package/build-module/categories/edit.js.map +1 -1
  69. package/build-module/index.js +4 -0
  70. package/build-module/index.js.map +1 -1
  71. package/build-module/navigation/constants.js +5 -1
  72. package/build-module/navigation/constants.js.map +1 -1
  73. package/build-module/navigation/edit/index.js +50 -4
  74. package/build-module/navigation/edit/index.js.map +1 -1
  75. package/build-module/navigation/edit/leaf-more-menu.js +0 -1
  76. package/build-module/navigation/edit/leaf-more-menu.js.map +1 -1
  77. package/build-module/navigation/edit/menu-inspector-controls.js +40 -5
  78. package/build-module/navigation/edit/menu-inspector-controls.js.map +1 -1
  79. package/build-module/navigation-link/block-inserter.js +61 -0
  80. package/build-module/navigation-link/block-inserter.js.map +1 -0
  81. package/build-module/navigation-link/dialog-wrapper.js +75 -0
  82. package/build-module/navigation-link/dialog-wrapper.js.map +1 -0
  83. package/build-module/navigation-link/link-ui.js +85 -125
  84. package/build-module/navigation-link/link-ui.js.map +1 -1
  85. package/build-module/navigation-link/page-creator.js +130 -0
  86. package/build-module/navigation-link/page-creator.js.map +1 -0
  87. package/build-module/search/edit.js +22 -14
  88. package/build-module/search/edit.js.map +1 -1
  89. package/build-module/social-links/index.js +2 -1
  90. package/build-module/social-links/index.js.map +1 -1
  91. package/build-module/table-of-contents/edit.js +35 -11
  92. package/build-module/table-of-contents/edit.js.map +1 -1
  93. package/build-module/table-of-contents/index.js +4 -0
  94. package/build-module/table-of-contents/index.js.map +1 -1
  95. package/build-module/table-of-contents/list.js +6 -3
  96. package/build-module/table-of-contents/list.js.map +1 -1
  97. package/build-module/table-of-contents/save.js +6 -3
  98. package/build-module/table-of-contents/save.js.map +1 -1
  99. package/build-module/term-template/edit.js +310 -0
  100. package/build-module/term-template/edit.js.map +1 -0
  101. package/build-module/term-template/index.js +102 -0
  102. package/build-module/term-template/index.js.map +1 -0
  103. package/build-module/term-template/save.js +9 -0
  104. package/build-module/term-template/save.js.map +1 -0
  105. package/build-module/term-template/variations.js +76 -0
  106. package/build-module/term-template/variations.js.map +1 -0
  107. package/build-module/terms-query/edit.js +12 -0
  108. package/build-module/terms-query/edit.js.map +1 -0
  109. package/build-module/terms-query/index.js +76 -0
  110. package/build-module/terms-query/index.js.map +1 -0
  111. package/build-module/terms-query/inspector-controls.js +239 -0
  112. package/build-module/terms-query/inspector-controls.js.map +1 -0
  113. package/build-module/terms-query/save.js +17 -0
  114. package/build-module/terms-query/save.js.map +1 -0
  115. package/build-module/terms-query/terms-query-content.js +63 -0
  116. package/build-module/terms-query/terms-query-content.js.map +1 -0
  117. package/build-style/accordion/style-rtl.css +5 -6
  118. package/build-style/accordion/style.css +5 -6
  119. package/build-style/editor-rtl.css +38 -0
  120. package/build-style/editor.css +38 -0
  121. package/build-style/form-input/style-rtl.css +4 -3
  122. package/build-style/form-input/style.css +4 -3
  123. package/build-style/navigation-link/editor-rtl.css +14 -0
  124. package/build-style/navigation-link/editor.css +14 -0
  125. package/build-style/navigation-link/style-rtl.css +1 -1
  126. package/build-style/navigation-link/style.css +1 -1
  127. package/build-style/post-comments-form/style-rtl.css +8 -5
  128. package/build-style/post-comments-form/style.css +8 -5
  129. package/build-style/search/style-rtl.css +11 -12
  130. package/build-style/search/style.css +11 -12
  131. package/build-style/style-rtl.css +45 -27
  132. package/build-style/style.css +45 -27
  133. package/build-style/term-template/editor-rtl.css +160 -0
  134. package/build-style/term-template/editor.css +160 -0
  135. package/build-style/term-template/style-rtl.css +146 -0
  136. package/build-style/term-template/style.css +146 -0
  137. package/build-style/terms-query/style-rtl.css +140 -0
  138. package/build-style/terms-query/style.css +140 -0
  139. package/build-types/table-of-contents/list.d.ts +2 -1
  140. package/build-types/table-of-contents/list.d.ts.map +1 -1
  141. package/package.json +35 -35
  142. package/src/accordion/style.scss +6 -6
  143. package/src/accordion-content/block.json +2 -1
  144. package/src/accordion-content/edit.js +21 -27
  145. package/src/accordion-panel/block.json +2 -1
  146. package/src/buttons/block.json +2 -1
  147. package/src/categories/edit.js +2 -1
  148. package/src/cover/test/edit.js +1 -5
  149. package/src/editor.scss +1 -0
  150. package/src/form-input/style.scss +3 -2
  151. package/src/index.js +4 -0
  152. package/src/navigation/constants.js +4 -0
  153. package/src/navigation/edit/index.js +50 -1
  154. package/src/navigation/edit/leaf-more-menu.js +0 -1
  155. package/src/navigation/edit/menu-inspector-controls.js +40 -5
  156. package/src/navigation-link/block-inserter.js +65 -0
  157. package/src/navigation-link/dialog-wrapper.js +74 -0
  158. package/src/navigation-link/editor.scss +17 -0
  159. package/src/navigation-link/link-ui.js +108 -164
  160. package/src/navigation-link/page-creator.js +157 -0
  161. package/src/navigation-link/style.scss +1 -1
  162. package/src/post-comments-form/style.scss +11 -11
  163. package/src/post-date/index.php +18 -13
  164. package/src/search/edit.js +44 -13
  165. package/src/search/index.php +16 -2
  166. package/src/search/style.scss +15 -16
  167. package/src/social-links/block.json +2 -1
  168. package/src/style.scss +2 -0
  169. package/src/table-of-contents/block.json +4 -0
  170. package/src/table-of-contents/edit.js +58 -21
  171. package/src/table-of-contents/list.tsx +7 -2
  172. package/src/table-of-contents/save.js +7 -3
  173. package/src/term-template/block.json +73 -0
  174. package/src/term-template/edit.js +391 -0
  175. package/src/term-template/editor.scss +26 -0
  176. package/src/term-template/index.js +26 -0
  177. package/src/term-template/index.php +224 -0
  178. package/src/term-template/save.js +8 -0
  179. package/src/term-template/style.scss +12 -0
  180. package/src/term-template/variations.js +87 -0
  181. package/src/terms-query/block.json +49 -0
  182. package/src/terms-query/edit.js +10 -0
  183. package/src/terms-query/index.js +24 -0
  184. package/src/terms-query/index.php +44 -0
  185. package/src/terms-query/inspector-controls.js +233 -0
  186. package/src/terms-query/save.js +10 -0
  187. package/src/terms-query/style.scss +6 -0
  188. package/src/terms-query/terms-query-content.js +74 -0
  189. package/tsconfig.tsbuildinfo +1 -1
@@ -30,7 +30,8 @@
30
30
  "width": true
31
31
  }
32
32
  },
33
- "shadow": true
33
+ "shadow": true,
34
+ "layout": true
34
35
  },
35
36
  "attributes": {
36
37
  "openByDefault": {
@@ -25,11 +25,8 @@ import clsx from 'clsx';
25
25
  */
26
26
  import { useToolsPanelDropdownMenuProps } from '../utils/hooks';
27
27
 
28
- export default function Edit( {
29
- attributes: { openByDefault },
30
- clientId,
31
- setAttributes,
32
- } ) {
28
+ export default function Edit( { attributes, clientId, setAttributes } ) {
29
+ const { openByDefault } = attributes;
33
30
  const dropdownMenuProps = useToolsPanelDropdownMenuProps();
34
31
 
35
32
  const { isSelected, getBlockOrder } = useSelect(
@@ -67,29 +64,26 @@ export default function Edit( {
67
64
  updateBlockAttributes,
68
65
  ] );
69
66
 
70
- const blockProps = useBlockProps();
71
- const innerBlocksProps = useInnerBlocksProps(
72
- {
73
- ...blockProps,
74
- className: clsx( blockProps.className, {
75
- 'is-open': openByDefault || isSelected,
76
- } ),
77
- },
78
- {
79
- template: [
80
- [ 'core/accordion-header', {} ],
81
- [
82
- 'core/accordion-panel',
83
- {
84
- openByDefault,
85
- },
86
- ],
67
+ const blockProps = useBlockProps( {
68
+ className: clsx( {
69
+ 'is-open': openByDefault || isSelected,
70
+ } ),
71
+ } );
72
+
73
+ const innerBlocksProps = useInnerBlocksProps( blockProps, {
74
+ template: [
75
+ [ 'core/accordion-header', {} ],
76
+ [
77
+ 'core/accordion-panel',
78
+ {
79
+ openByDefault,
80
+ },
87
81
  ],
88
- templateLock: 'all',
89
- directInsert: true,
90
- templateInsertUpdatesSelection: true,
91
- }
92
- );
82
+ ],
83
+ templateLock: 'all',
84
+ directInsert: true,
85
+ templateInsertUpdatesSelection: true,
86
+ } );
93
87
 
94
88
  return (
95
89
  <>
@@ -47,7 +47,8 @@
47
47
  "fontSize": true
48
48
  }
49
49
  },
50
- "shadow": true
50
+ "shadow": true,
51
+ "layout": true
51
52
  },
52
53
  "attributes": {
53
54
  "allowedBlocks": {
@@ -62,7 +62,8 @@
62
62
  },
63
63
  "interactivity": {
64
64
  "clientNavigation": true
65
- }
65
+ },
66
+ "contentRole": true
66
67
  },
67
68
  "editorStyle": "wp-block-buttons-editor",
68
69
  "style": "wp-block-buttons"
@@ -52,7 +52,8 @@ export default function CategoriesEdit( {
52
52
 
53
53
  const { records: allTaxonomies, isResolvingTaxonomies } = useEntityRecords(
54
54
  'root',
55
- 'taxonomy'
55
+ 'taxonomy',
56
+ { per_page: -1 }
56
57
  );
57
58
 
58
59
  const taxonomies = allTaxonomies?.filter( ( t ) => t.visibility.public );
@@ -51,11 +51,7 @@ async function createAndSelectBlock() {
51
51
  name: 'Black',
52
52
  } )
53
53
  );
54
- await userEvent.click(
55
- screen.getByRole( 'button', {
56
- name: 'Select parent block: Cover',
57
- } )
58
- );
54
+ await selectBlock( 'Block: Cover' );
59
55
  }
60
56
 
61
57
  describe( 'Cover block', () => {
package/src/editor.scss CHANGED
@@ -46,6 +46,7 @@
46
46
  @import "./table/editor.scss";
47
47
  @import "./tag-cloud/editor.scss";
48
48
  @import "./template-part/editor.scss";
49
+ @import "./term-template/editor.scss";
49
50
  @import "./text-columns/editor.scss";
50
51
  @import "./video/editor.scss";
51
52
  @import "./query/editor.scss";
@@ -34,7 +34,7 @@
34
34
  width: fit-content;
35
35
  }
36
36
 
37
- .wp-block-form-input__input {
37
+ :where(.wp-block-form-input__input) {
38
38
  padding: 0 0.5em;
39
39
  font-size: 1em;
40
40
  margin-bottom: 0.5em;
@@ -54,7 +54,8 @@
54
54
  &[type="week"] {
55
55
  min-height: 2em;
56
56
  line-height: 2;
57
- border: 1px solid;
57
+ border-width: 1px;
58
+ border-style: solid;
58
59
  }
59
60
  }
60
61
 
package/src/index.js CHANGED
@@ -122,6 +122,8 @@ import * as tableOfContents from './table-of-contents';
122
122
  import * as tagCloud from './tag-cloud';
123
123
  import * as templatePart from './template-part';
124
124
  import * as termDescription from './term-description';
125
+ import * as termsQuery from './terms-query';
126
+ import * as termTemplate from './term-template';
125
127
  import * as textColumns from './text-columns';
126
128
  import * as verse from './verse';
127
129
  import * as video from './video';
@@ -244,6 +246,8 @@ const getAllBlocks = () => {
244
246
  blocks.push( accordionContent );
245
247
  blocks.push( accordionHeader );
246
248
  blocks.push( accordionPanel );
249
+ blocks.push( termsQuery );
250
+ blocks.push( termTemplate );
247
251
  }
248
252
 
249
253
  if ( window?.__experimentalEnableFormBlocks ) {
@@ -1,5 +1,9 @@
1
1
  export const DEFAULT_BLOCK = {
2
2
  name: 'core/navigation-link',
3
+ attributes: {
4
+ kind: 'post-type',
5
+ type: 'page',
6
+ },
3
7
  };
4
8
 
5
9
  export const PRIORITIZED_INSERTER_BLOCKS = [
@@ -26,6 +26,7 @@ import {
26
26
  __experimentalColorGradientSettingsDropdown as ColorGradientSettingsDropdown,
27
27
  __experimentalUseMultipleOriginColorsAndGradients as useMultipleOriginColorsAndGradients,
28
28
  useBlockEditingMode,
29
+ BlockControls,
29
30
  } from '@wordpress/block-editor';
30
31
  import { EntityProvider, store as coreStore } from '@wordpress/core-data';
31
32
 
@@ -40,10 +41,13 @@ import {
40
41
  Button,
41
42
  Spinner,
42
43
  Notice,
44
+ ToolbarButton,
45
+ ToolbarGroup,
43
46
  } from '@wordpress/components';
44
47
  import { __ } from '@wordpress/i18n';
45
48
  import { speak } from '@wordpress/a11y';
46
- import { close, Icon } from '@wordpress/icons';
49
+ import { close, Icon, page } from '@wordpress/icons';
50
+ import { createBlock } from '@wordpress/blocks';
47
51
  import { useInstanceId } from '@wordpress/compose';
48
52
 
49
53
  /**
@@ -75,6 +79,48 @@ import AccessibleDescription from './accessible-description';
75
79
  import AccessibleMenuDescription from './accessible-menu-description';
76
80
  import { unlock } from '../../lock-unlock';
77
81
  import { useToolsPanelDropdownMenuProps } from '../../utils/hooks';
82
+ import { DEFAULT_BLOCK } from '../constants';
83
+
84
+ /**
85
+ * Component that renders the Add page button for the Navigation block.
86
+ *
87
+ * @param {Object} props Component props.
88
+ * @param {string} props.clientId Block client ID.
89
+ * @return {JSX.Element|null} The Add page button component or null if not applicable.
90
+ */
91
+ function NavigationAddPageButton( { clientId } ) {
92
+ const { insertBlock } = useDispatch( blockEditorStore );
93
+ const { getBlockCount } = useSelect( blockEditorStore );
94
+
95
+ const onAddPage = useCallback( () => {
96
+ // Get the current number of blocks to insert at the end
97
+ const blockCount = getBlockCount( clientId );
98
+
99
+ // Create a new navigation link block (default block)
100
+ const newBlock = createBlock( DEFAULT_BLOCK.name, {
101
+ kind: DEFAULT_BLOCK.attributes.kind,
102
+ type: DEFAULT_BLOCK.attributes.type,
103
+ } );
104
+
105
+ // Insert the block at the end of the navigation
106
+ insertBlock( newBlock, blockCount, clientId );
107
+ }, [ clientId, insertBlock, getBlockCount ] );
108
+
109
+ return (
110
+ <BlockControls>
111
+ <ToolbarGroup>
112
+ <ToolbarButton
113
+ name="add-page"
114
+ icon={ page }
115
+ title={ __( 'Add page' ) }
116
+ onClick={ onAddPage }
117
+ >
118
+ { __( 'Add page' ) }
119
+ </ToolbarButton>
120
+ </ToolbarGroup>
121
+ </BlockControls>
122
+ );
123
+ }
78
124
 
79
125
  function ColorTools( {
80
126
  textColor,
@@ -937,6 +983,9 @@ function Navigation( {
937
983
  blockEditingMode={ blockEditingMode }
938
984
  />
939
985
  { blockEditingMode === 'default' && stylingInspectorControls }
986
+ { blockEditingMode === 'contentOnly' && isEntityAvailable && (
987
+ <NavigationAddPageButton clientId={ clientId } />
988
+ ) }
940
989
  { blockEditingMode === 'default' && isEntityAvailable && (
941
990
  <InspectorControls group="advanced">
942
991
  { hasResolvedCanUserUpdateNavigationMenu &&
@@ -146,7 +146,6 @@ export default function LeafMoreMenu( props ) {
146
146
  <AddSubmenuItem
147
147
  block={ block }
148
148
  onClose={ onClose }
149
- expanded
150
149
  expandedState={ props.expandedState }
151
150
  expand={ props.expand }
152
151
  setInsertedBlock={ props.setInsertedBlock }
@@ -35,7 +35,8 @@ const BLOCKS_WITH_LINK_UI_SUPPORT = [
35
35
  const { PrivateListView } = unlock( blockEditorPrivateApis );
36
36
 
37
37
  function AdditionalBlockContent( { block, insertedBlock, setInsertedBlock } ) {
38
- const { updateBlockAttributes } = useDispatch( blockEditorStore );
38
+ const { updateBlockAttributes, removeBlock } =
39
+ useDispatch( blockEditorStore );
39
40
 
40
41
  const supportsLinkControls = BLOCKS_WITH_LINK_UI_SUPPORT?.includes(
41
42
  insertedBlock?.name
@@ -47,6 +48,27 @@ function AdditionalBlockContent( { block, insertedBlock, setInsertedBlock } ) {
47
48
  return null;
48
49
  }
49
50
 
51
+ /**
52
+ * Cleanup function for auto-inserted Navigation Link blocks.
53
+ *
54
+ * Removes the block if it has no URL and clears the inserted block state.
55
+ * This ensures consistent cleanup behavior across different contexts.
56
+ */
57
+ const cleanupInsertedBlock = () => {
58
+ // Prevent automatic block selection when removing blocks in list view context
59
+ // This avoids focus stealing that would close the list view and switch to canvas
60
+ const shouldAutoSelectBlock = false;
61
+
62
+ // Follows the exact same pattern as Navigation Link block's onClose handler
63
+ // If there is no URL then remove the auto-inserted block to avoid empty blocks
64
+ if ( ! insertedBlock?.attributes?.url && insertedBlock?.clientId ) {
65
+ // Remove the block entirely to avoid poor UX
66
+ // This matches the Navigation Link block's behavior
67
+ removeBlock( insertedBlock.clientId, shouldAutoSelectBlock );
68
+ }
69
+ setInsertedBlock( null );
70
+ };
71
+
50
72
  const setInsertedBlockAttributes =
51
73
  ( _insertedBlockClientId ) => ( _updatedAttributes ) => {
52
74
  if ( ! _insertedBlockClientId ) {
@@ -55,12 +77,28 @@ function AdditionalBlockContent( { block, insertedBlock, setInsertedBlock } ) {
55
77
  updateBlockAttributes( _insertedBlockClientId, _updatedAttributes );
56
78
  };
57
79
 
80
+ // Wrapper function to clean up original block when a new block is selected
81
+ const handleSetInsertedBlock = ( newBlock ) => {
82
+ // Prevent automatic block selection when removing blocks in list view context
83
+ // This avoids focus stealing that would close the list view and switch to canvas
84
+ const shouldAutoSelectBlock = false;
85
+
86
+ // If we have an existing inserted block and a new block is being set,
87
+ // remove the original block to avoid duplicates
88
+ if ( insertedBlock?.clientId && newBlock ) {
89
+ removeBlock( insertedBlock.clientId, shouldAutoSelectBlock );
90
+ }
91
+ setInsertedBlock( newBlock );
92
+ };
93
+
58
94
  return (
59
95
  <LinkUI
60
96
  clientId={ insertedBlock?.clientId }
61
97
  link={ insertedBlock?.attributes }
98
+ onBlockInsert={ handleSetInsertedBlock }
62
99
  onClose={ () => {
63
- setInsertedBlock( null );
100
+ // Use cleanup function
101
+ cleanupInsertedBlock();
64
102
  } }
65
103
  onChange={ ( updatedValue ) => {
66
104
  updateAttributes(
@@ -70,9 +108,6 @@ function AdditionalBlockContent( { block, insertedBlock, setInsertedBlock } ) {
70
108
  );
71
109
  setInsertedBlock( null );
72
110
  } }
73
- onCancel={ () => {
74
- setInsertedBlock( null );
75
- } }
76
111
  />
77
112
  );
78
113
  }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { __ } from '@wordpress/i18n';
5
+ import { useSelect } from '@wordpress/data';
6
+ import {
7
+ store as blockEditorStore,
8
+ privateApis as blockEditorPrivateApis,
9
+ } from '@wordpress/block-editor';
10
+
11
+ /**
12
+ * Internal dependencies
13
+ */
14
+ import DialogWrapper from './dialog-wrapper';
15
+ import { unlock } from '../lock-unlock';
16
+
17
+ const { PrivateQuickInserter: QuickInserter } = unlock(
18
+ blockEditorPrivateApis
19
+ );
20
+
21
+ /**
22
+ * Component for inserting blocks within the Navigation Link UI.
23
+ *
24
+ * @param {Object} props Component props.
25
+ * @param {string} props.clientId Client ID of the navigation link block.
26
+ * @param {Function} props.onBack Callback when user wants to go back.
27
+ * @param {Function} props.onBlockInsert Callback when a block is inserted.
28
+ */
29
+ function LinkUIBlockInserter( { clientId, onBack, onBlockInsert } ) {
30
+ const { rootBlockClientId } = useSelect(
31
+ ( select ) => {
32
+ const { getBlockRootClientId } = select( blockEditorStore );
33
+
34
+ return {
35
+ rootBlockClientId: getBlockRootClientId( clientId ),
36
+ };
37
+ },
38
+ [ clientId ]
39
+ );
40
+
41
+ if ( ! clientId ) {
42
+ return null;
43
+ }
44
+
45
+ return (
46
+ <DialogWrapper
47
+ className="link-ui-block-inserter"
48
+ title={ __( 'Add block' ) }
49
+ description={ __( 'Choose a block to add to your Navigation.' ) }
50
+ onBack={ onBack }
51
+ >
52
+ <QuickInserter
53
+ rootClientId={ rootBlockClientId }
54
+ clientId={ clientId }
55
+ isAppender={ false }
56
+ prioritizePatterns={ false }
57
+ selectBlockOnInsert={ ! onBlockInsert }
58
+ onSelect={ onBlockInsert ? onBlockInsert : undefined }
59
+ hasSearch={ false }
60
+ />
61
+ </DialogWrapper>
62
+ );
63
+ }
64
+
65
+ export default LinkUIBlockInserter;
@@ -0,0 +1,74 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { Button, VisuallyHidden } from '@wordpress/components';
5
+ import { __, isRTL } from '@wordpress/i18n';
6
+ import { chevronLeftSmall, chevronRightSmall } from '@wordpress/icons';
7
+ import { useInstanceId, useFocusOnMount } from '@wordpress/compose';
8
+
9
+ /**
10
+ * Shared BackButton component for consistent navigation across LinkUI sub-components.
11
+ *
12
+ * @param {Object} props Component props.
13
+ * @param {string} props.className CSS class name for the button.
14
+ * @param {Function} props.onBack Callback when user wants to go back.
15
+ */
16
+ function BackButton( { className, onBack } ) {
17
+ return (
18
+ <Button
19
+ className={ className }
20
+ icon={ isRTL() ? chevronRightSmall : chevronLeftSmall }
21
+ onClick={ ( e ) => {
22
+ e.preventDefault();
23
+ onBack();
24
+ } }
25
+ size="small"
26
+ >
27
+ { __( 'Back' ) }
28
+ </Button>
29
+ );
30
+ }
31
+
32
+ /**
33
+ * Shared DialogWrapper component for consistent dialog structure across LinkUI sub-components.
34
+ *
35
+ * @param {Object} props Component props.
36
+ * @param {string} props.className CSS class name for the dialog container.
37
+ * @param {string} props.title Dialog title for accessibility.
38
+ * @param {string} props.description Dialog description for accessibility.
39
+ * @param {Function} props.onBack Callback when user wants to go back.
40
+ * @param {Object} props.children Child components to render inside the dialog.
41
+ */
42
+ function DialogWrapper( { className, title, description, onBack, children } ) {
43
+ const dialogTitleId = useInstanceId(
44
+ DialogWrapper,
45
+ 'link-ui-dialog-title'
46
+ );
47
+ const dialogDescriptionId = useInstanceId(
48
+ DialogWrapper,
49
+ 'link-ui-dialog-description'
50
+ );
51
+ const focusOnMountRef = useFocusOnMount( 'firstElement' );
52
+ const backButtonClassName = `${ className }__back`;
53
+
54
+ return (
55
+ <div
56
+ className={ className }
57
+ role="dialog"
58
+ aria-labelledby={ dialogTitleId }
59
+ aria-describedby={ dialogDescriptionId }
60
+ ref={ focusOnMountRef }
61
+ >
62
+ <VisuallyHidden>
63
+ <h2 id={ dialogTitleId }>{ title }</h2>
64
+ <p id={ dialogDescriptionId }>{ description }</p>
65
+ </VisuallyHidden>
66
+
67
+ <BackButton className={ backButtonClassName } onBack={ onBack } />
68
+
69
+ { children }
70
+ </div>
71
+ );
72
+ }
73
+
74
+ export default DialogWrapper;
@@ -122,3 +122,20 @@
122
122
  gap: $grid-unit-10;
123
123
  height: auto;
124
124
  }
125
+
126
+ .link-ui-page-creator {
127
+ // Match LinkControl width constraints for consistent UI sizing
128
+ max-width: 350px;
129
+ min-width: auto;
130
+ width: 90vw;
131
+ padding-top: $grid-unit-10;
132
+
133
+ &__inner {
134
+ padding: $grid-unit-20;
135
+ }
136
+
137
+ &__back {
138
+ margin-left: $grid-unit-10;
139
+ text-transform: uppercase;
140
+ }
141
+ }