@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
@@ -8,38 +8,24 @@ import {
8
8
  VisuallyHidden,
9
9
  __experimentalVStack as VStack,
10
10
  } from '@wordpress/components';
11
- import { __, sprintf, isRTL } from '@wordpress/i18n';
11
+ import { __ } from '@wordpress/i18n';
12
+ import { LinkControl, useBlockEditingMode } from '@wordpress/block-editor';
12
13
  import {
13
- LinkControl,
14
- store as blockEditorStore,
15
- privateApis as blockEditorPrivateApis,
16
- useBlockEditingMode,
17
- } from '@wordpress/block-editor';
18
- import {
19
- createInterpolateElement,
20
14
  useMemo,
21
15
  useState,
22
16
  useRef,
23
17
  useEffect,
24
18
  forwardRef,
25
19
  } from '@wordpress/element';
26
- import {
27
- store as coreStore,
28
- useResourcePermissions,
29
- } from '@wordpress/core-data';
30
- import { decodeEntities } from '@wordpress/html-entities';
31
- import { useSelect, useDispatch } from '@wordpress/data';
32
- import { chevronLeftSmall, chevronRightSmall, plus } from '@wordpress/icons';
33
- import { useInstanceId, useFocusOnMount } from '@wordpress/compose';
20
+ import { useResourcePermissions } from '@wordpress/core-data';
21
+ import { plus } from '@wordpress/icons';
22
+ import { useInstanceId } from '@wordpress/compose';
34
23
 
35
24
  /**
36
25
  * Internal dependencies
37
26
  */
38
- import { unlock } from '../lock-unlock';
39
-
40
- const { PrivateQuickInserter: QuickInserter } = unlock(
41
- blockEditorPrivateApis
42
- );
27
+ import { LinkUIPageCreator } from './page-creator';
28
+ import LinkUIBlockInserter from './block-inserter';
43
29
 
44
30
  /**
45
31
  * Given the Link block's type attribute, return the query params to give to
@@ -79,114 +65,19 @@ export function getSuggestionsQuery( type, kind ) {
79
65
  }
80
66
  }
81
67
 
82
- function LinkUIBlockInserter( { clientId, onBack } ) {
83
- const { rootBlockClientId } = useSelect(
84
- ( select ) => {
85
- const { getBlockRootClientId } = select( blockEditorStore );
86
-
87
- return {
88
- rootBlockClientId: getBlockRootClientId( clientId ),
89
- };
90
- },
91
- [ clientId ]
92
- );
93
-
94
- const focusOnMountRef = useFocusOnMount( 'firstElement' );
95
-
96
- const dialogTitleId = useInstanceId(
97
- LinkControl,
98
- `link-ui-block-inserter__title`
99
- );
100
- const dialogDescriptionId = useInstanceId(
101
- LinkControl,
102
- `link-ui-block-inserter__description`
103
- );
104
-
105
- if ( ! clientId ) {
106
- return null;
107
- }
108
-
109
- return (
110
- <div
111
- className="link-ui-block-inserter"
112
- role="dialog"
113
- aria-labelledby={ dialogTitleId }
114
- aria-describedby={ dialogDescriptionId }
115
- ref={ focusOnMountRef }
116
- >
117
- <VisuallyHidden>
118
- <h2 id={ dialogTitleId }>{ __( 'Add block' ) }</h2>
119
-
120
- <p id={ dialogDescriptionId }>
121
- { __( 'Choose a block to add to your Navigation.' ) }
122
- </p>
123
- </VisuallyHidden>
124
-
125
- <Button
126
- className="link-ui-block-inserter__back"
127
- icon={ isRTL() ? chevronRightSmall : chevronLeftSmall }
128
- onClick={ ( e ) => {
129
- e.preventDefault();
130
- onBack();
131
- } }
132
- size="small"
133
- >
134
- { __( 'Back' ) }
135
- </Button>
136
-
137
- <QuickInserter
138
- rootClientId={ rootBlockClientId }
139
- clientId={ clientId }
140
- isAppender={ false }
141
- prioritizePatterns={ false }
142
- selectBlockOnInsert
143
- hasSearch={ false }
144
- />
145
- </div>
146
- );
147
- }
148
-
149
68
  function UnforwardedLinkUI( props, ref ) {
150
69
  const { label, url, opensInNewTab, type, kind } = props.link;
151
70
  const postType = type || 'page';
152
71
 
153
72
  const [ addingBlock, setAddingBlock ] = useState( false );
73
+ const [ addingPage, setAddingPage ] = useState( false );
154
74
  const [ focusAddBlockButton, setFocusAddBlockButton ] = useState( false );
155
- const { saveEntityRecord } = useDispatch( coreStore );
75
+ const [ focusAddPageButton, setFocusAddPageButton ] = useState( false );
156
76
  const permissions = useResourcePermissions( {
157
77
  kind: 'postType',
158
78
  name: postType,
159
79
  } );
160
80
 
161
- // Check if we're in contentOnly mode
162
- const blockEditingMode = useBlockEditingMode();
163
- const isDefaultBlockEditingMode = blockEditingMode === 'default';
164
-
165
- async function handleCreate( pageTitle ) {
166
- const page = await saveEntityRecord( 'postType', postType, {
167
- title: pageTitle,
168
- status: 'draft',
169
- } );
170
-
171
- return {
172
- id: page.id,
173
- type: postType,
174
- // Make `title` property consistent with that in `fetchLinkSuggestions` where the `rendered` title (containing HTML entities)
175
- // is also being decoded. By being consistent in both locations we avoid having to branch in the rendering output code.
176
- // Ideally in the future we will update both APIs to utilise the "raw" form of the title which is better suited to edit contexts.
177
- // e.g.
178
- // - title.raw = "Yes & No"
179
- // - title.rendered = "Yes &#038; No"
180
- // - decodeEntities( title.rendered ) = "Yes & No"
181
- // See:
182
- // - https://github.com/WordPress/gutenberg/pull/41063
183
- // - https://github.com/WordPress/gutenberg/blob/a1e1fdc0e6278457e9f4fc0b31ac6d2095f5450b/packages/core-data/src/fetch/__experimental-fetch-link-suggestions.js#L212-L218
184
- title: decodeEntities( page.title.rendered ),
185
- url: page.link,
186
- kind: 'post-type',
187
- };
188
- }
189
-
190
81
  // Memoize link value to avoid overriding the LinkControl's internal state.
191
82
  // This is a temporary fix. See https://github.com/WordPress/gutenberg/issues/50976#issuecomment-1568226407.
192
83
  const link = useMemo(
@@ -198,15 +89,24 @@ function UnforwardedLinkUI( props, ref ) {
198
89
  [ label, opensInNewTab, url ]
199
90
  );
200
91
 
92
+ const handlePageCreated = ( pageLink ) => {
93
+ // Set the new page as the current link
94
+ props.onChange( pageLink );
95
+ // Return to main Link UI
96
+ setAddingPage( false );
97
+ };
98
+
201
99
  const dialogTitleId = useInstanceId(
202
100
  LinkUI,
203
- `link-ui-link-control__title`
101
+ 'link-ui-link-control__title'
204
102
  );
205
103
  const dialogDescriptionId = useInstanceId(
206
104
  LinkUI,
207
- `link-ui-link-control__description`
105
+ 'link-ui-link-control__description'
208
106
  );
209
107
 
108
+ const blockEditingMode = useBlockEditingMode();
109
+
210
110
  return (
211
111
  <Popover
212
112
  ref={ ref }
@@ -215,7 +115,7 @@ function UnforwardedLinkUI( props, ref ) {
215
115
  anchor={ props.anchor }
216
116
  shift
217
117
  >
218
- { ! addingBlock && (
118
+ { ! addingBlock && ! addingPage && (
219
119
  <div
220
120
  role="dialog"
221
121
  aria-labelledby={ dialogTitleId }
@@ -235,48 +135,41 @@ function UnforwardedLinkUI( props, ref ) {
235
135
  hasRichPreviews
236
136
  value={ link }
237
137
  showInitialSuggestions
238
- withCreateSuggestion={ permissions.canCreate }
239
- createSuggestion={ handleCreate }
240
- createSuggestionButtonText={ ( searchTerm ) => {
241
- let format;
242
-
243
- if ( type === 'post' ) {
244
- /* translators: %s: search term. */
245
- format = __(
246
- 'Create draft post: <mark>%s</mark>'
247
- );
248
- } else {
249
- /* translators: %s: search term. */
250
- format = __(
251
- 'Create draft page: <mark>%s</mark>'
252
- );
253
- }
254
-
255
- return createInterpolateElement(
256
- sprintf( format, searchTerm ),
257
- {
258
- mark: <mark />,
259
- }
260
- );
261
- } }
138
+ withCreateSuggestion={ false }
262
139
  noDirectEntry={ !! type }
263
140
  noURLSuggestion={ !! type }
264
141
  suggestionsQuery={ getSuggestionsQuery( type, kind ) }
265
142
  onChange={ props.onChange }
266
143
  onRemove={ props.onRemove }
267
144
  onCancel={ props.onCancel }
268
- renderControlBottom={ () =>
269
- ! link?.url?.length &&
270
- isDefaultBlockEditingMode && (
145
+ renderControlBottom={ () => {
146
+ // Don't show the tools when there is submitted link (preview state).
147
+ if ( link?.url?.length ) {
148
+ return null;
149
+ }
150
+
151
+ return (
271
152
  <LinkUITools
272
153
  focusAddBlockButton={ focusAddBlockButton }
154
+ focusAddPageButton={ focusAddPageButton }
273
155
  setAddingBlock={ () => {
274
156
  setAddingBlock( true );
275
157
  setFocusAddBlockButton( false );
276
158
  } }
159
+ setAddingPage={ () => {
160
+ setAddingPage( true );
161
+ setFocusAddPageButton( false );
162
+ } }
163
+ canAddPage={
164
+ permissions?.canCreate &&
165
+ type === 'page'
166
+ }
167
+ canAddBlock={
168
+ blockEditingMode === 'default'
169
+ }
277
170
  />
278
- )
279
- }
171
+ );
172
+ } }
280
173
  />
281
174
  </div>
282
175
  ) }
@@ -287,7 +180,22 @@ function UnforwardedLinkUI( props, ref ) {
287
180
  onBack={ () => {
288
181
  setAddingBlock( false );
289
182
  setFocusAddBlockButton( true );
183
+ setFocusAddPageButton( false );
184
+ } }
185
+ onBlockInsert={ props?.onBlockInsert }
186
+ />
187
+ ) }
188
+
189
+ { addingPage && (
190
+ <LinkUIPageCreator
191
+ postType={ postType }
192
+ onBack={ () => {
193
+ setAddingPage( false );
194
+ setFocusAddPageButton( true );
195
+ setFocusAddBlockButton( false );
290
196
  } }
197
+ onPageCreated={ handlePageCreated }
198
+ initialTitle={ link?.url || '' }
291
199
  />
292
200
  ) }
293
201
  </Popover>
@@ -296,9 +204,17 @@ function UnforwardedLinkUI( props, ref ) {
296
204
 
297
205
  export const LinkUI = forwardRef( UnforwardedLinkUI );
298
206
 
299
- const LinkUITools = ( { setAddingBlock, focusAddBlockButton } ) => {
207
+ const LinkUITools = ( {
208
+ setAddingBlock,
209
+ setAddingPage,
210
+ focusAddBlockButton,
211
+ focusAddPageButton,
212
+ canAddPage,
213
+ canAddBlock,
214
+ } ) => {
300
215
  const blockInserterAriaRole = 'listbox';
301
216
  const addBlockButtonRef = useRef();
217
+ const addPageButtonRef = useRef();
302
218
 
303
219
  // Focus the add block button when the popover is opened.
304
220
  useEffect( () => {
@@ -307,20 +223,48 @@ const LinkUITools = ( { setAddingBlock, focusAddBlockButton } ) => {
307
223
  }
308
224
  }, [ focusAddBlockButton ] );
309
225
 
226
+ // Focus the add page button when the popover is opened.
227
+ useEffect( () => {
228
+ if ( focusAddPageButton ) {
229
+ addPageButtonRef.current?.focus();
230
+ }
231
+ }, [ focusAddPageButton ] );
232
+
233
+ // Don't render anything if neither button should be shown
234
+ if ( ! canAddPage && ! canAddBlock ) {
235
+ return null;
236
+ }
237
+
310
238
  return (
311
- <VStack className="link-ui-tools">
312
- <Button
313
- __next40pxDefaultSize
314
- ref={ addBlockButtonRef }
315
- icon={ plus }
316
- onClick={ ( e ) => {
317
- e.preventDefault();
318
- setAddingBlock( true );
319
- } }
320
- aria-haspopup={ blockInserterAriaRole }
321
- >
322
- { __( 'Add block' ) }
323
- </Button>
239
+ <VStack spacing={ 0 } className="link-ui-tools">
240
+ { canAddPage && (
241
+ <Button
242
+ __next40pxDefaultSize
243
+ ref={ addPageButtonRef }
244
+ icon={ plus }
245
+ onClick={ ( e ) => {
246
+ e.preventDefault();
247
+ setAddingPage( true );
248
+ } }
249
+ aria-haspopup={ blockInserterAriaRole }
250
+ >
251
+ { __( 'Create page' ) }
252
+ </Button>
253
+ ) }
254
+ { canAddBlock && (
255
+ <Button
256
+ __next40pxDefaultSize
257
+ ref={ addBlockButtonRef }
258
+ icon={ plus }
259
+ onClick={ ( e ) => {
260
+ e.preventDefault();
261
+ setAddingBlock( true );
262
+ } }
263
+ aria-haspopup={ blockInserterAriaRole }
264
+ >
265
+ { __( 'Add block' ) }
266
+ </Button>
267
+ ) }
324
268
  </VStack>
325
269
  );
326
270
  };
@@ -0,0 +1,157 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import {
5
+ Button,
6
+ TextControl,
7
+ Notice,
8
+ CheckboxControl,
9
+ __experimentalVStack as VStack,
10
+ __experimentalHStack as HStack,
11
+ } from '@wordpress/components';
12
+ import { __ } from '@wordpress/i18n';
13
+ import { useSelect, useDispatch } from '@wordpress/data';
14
+ import { store as coreStore } from '@wordpress/core-data';
15
+ import { decodeEntities } from '@wordpress/html-entities';
16
+ import { useState } from '@wordpress/element';
17
+
18
+ /**
19
+ * Internal dependencies
20
+ */
21
+ import DialogWrapper from './dialog-wrapper';
22
+
23
+ /**
24
+ * Component for creating new pages within the Navigation Link UI.
25
+ *
26
+ * @param {Object} props Component props.
27
+ * @param {string} props.postType The post type to create.
28
+ * @param {Function} props.onBack Callback when user wants to go back.
29
+ * @param {Function} props.onPageCreated Callback when page is successfully created.
30
+ * @param {string} [props.initialTitle] Initial title to pre-fill the form.
31
+ */
32
+ export function LinkUIPageCreator( {
33
+ postType,
34
+ onBack,
35
+ onPageCreated,
36
+ initialTitle = '',
37
+ } ) {
38
+ const [ title, setTitle ] = useState( initialTitle );
39
+ const [ shouldPublish, setShouldPublish ] = useState( false );
40
+
41
+ // Check if the title is valid for submission
42
+ const isTitleValid = title.trim().length > 0;
43
+
44
+ // Get the last created entity record (without ID) to track creation state
45
+ const { lastError, isSaving } = useSelect(
46
+ ( select ) => ( {
47
+ lastError: select( coreStore ).getLastEntitySaveError(
48
+ 'postType',
49
+ postType
50
+ ),
51
+ isSaving: select( coreStore ).isSavingEntityRecord(
52
+ 'postType',
53
+ postType
54
+ ),
55
+ } ),
56
+ [ postType ]
57
+ );
58
+
59
+ const { saveEntityRecord } = useDispatch( coreStore );
60
+
61
+ async function createPage( event ) {
62
+ event.preventDefault();
63
+ if ( isSaving || ! isTitleValid ) {
64
+ return;
65
+ }
66
+
67
+ try {
68
+ const savedRecord = await saveEntityRecord(
69
+ 'postType',
70
+ postType,
71
+ {
72
+ title,
73
+ status: shouldPublish ? 'publish' : 'draft',
74
+ },
75
+ { throwOnError: true }
76
+ );
77
+
78
+ if ( savedRecord ) {
79
+ // Create the page link object from the saved record
80
+ const pageLink = {
81
+ id: savedRecord.id,
82
+ type: postType,
83
+ title: decodeEntities( savedRecord.title.rendered ),
84
+ url: savedRecord.link,
85
+ kind: 'post-type',
86
+ };
87
+
88
+ onPageCreated( pageLink );
89
+ }
90
+ } catch ( error ) {
91
+ // Error handling is done via the data store selectors
92
+ }
93
+ }
94
+
95
+ const isSubmitDisabled = isSaving || ! isTitleValid;
96
+
97
+ return (
98
+ <DialogWrapper
99
+ className="link-ui-page-creator"
100
+ title={ __( 'Create page' ) }
101
+ description={ __( 'Create a new page to add to your Navigation.' ) }
102
+ onBack={ onBack }
103
+ >
104
+ <VStack className="link-ui-page-creator__inner" spacing={ 4 }>
105
+ <form onSubmit={ createPage }>
106
+ <VStack spacing={ 4 }>
107
+ <TextControl
108
+ __next40pxDefaultSize
109
+ __nextHasNoMarginBottom
110
+ label={ __( 'Title' ) }
111
+ onChange={ setTitle }
112
+ placeholder={ __( 'No title' ) }
113
+ value={ title }
114
+ />
115
+
116
+ <CheckboxControl
117
+ __nextHasNoMarginBottom
118
+ label={ __( 'Publish immediately' ) }
119
+ help={ __(
120
+ 'If unchecked, the page will be created as a draft.'
121
+ ) }
122
+ checked={ shouldPublish }
123
+ onChange={ setShouldPublish }
124
+ />
125
+
126
+ { lastError && (
127
+ <Notice status="error" isDismissible={ false }>
128
+ { lastError.message }
129
+ </Notice>
130
+ ) }
131
+
132
+ <HStack spacing={ 2 } justify="flex-end">
133
+ <Button
134
+ __next40pxDefaultSize
135
+ variant="tertiary"
136
+ onClick={ onBack }
137
+ disabled={ isSaving }
138
+ accessibleWhenDisabled
139
+ >
140
+ { __( 'Cancel' ) }
141
+ </Button>
142
+ <Button
143
+ __next40pxDefaultSize
144
+ variant="primary"
145
+ type="submit"
146
+ isBusy={ isSaving }
147
+ aria-disabled={ isSubmitDisabled }
148
+ >
149
+ { __( 'Create page' ) }
150
+ </Button>
151
+ </HStack>
152
+ </VStack>
153
+ </form>
154
+ </VStack>
155
+ </DialogWrapper>
156
+ );
157
+ }
@@ -16,7 +16,7 @@
16
16
  }
17
17
 
18
18
  .link-ui-tools {
19
- border-top: 1px solid $gray-100;
19
+ outline: 1px solid $gray-100;
20
20
  padding: $grid-unit-10;
21
21
  }
22
22
 
@@ -1,16 +1,16 @@
1
1
  // Allow these default styles to be overridden by global styles.
2
- :where(.wp-block-post-comments-form) {
3
- textarea,
4
- input:not([type="submit"]) {
5
- border: 1px solid $gray-600;
6
- font-size: 1em;
7
- font-family: inherit;
8
- }
2
+ :where(.wp-block-post-comments-form textarea),
3
+ :where(.wp-block-post-comments-form input:not([type="submit"])) {
4
+ border-width: 1px;
5
+ border-style: solid;
6
+ border-color: $gray-600;
7
+ font-size: 1em;
8
+ font-family: inherit;
9
+ }
9
10
 
10
- textarea,
11
- input:where(:not([type="submit"]):not([type="checkbox"])) {
12
- padding: calc(0.667em + 2px); // The extra 2px is added to match outline buttons.
13
- }
11
+ :where(.wp-block-post-comments-form textarea),
12
+ :where(.wp-block-post-comments-form input:where(:not([type="submit"]):not([type="checkbox"]))) {
13
+ padding: calc(0.667em + 2px); // The extra 2px is added to match outline buttons.
14
14
  }
15
15
 
16
16
  .wp-block-post-comments-form {
@@ -20,19 +20,11 @@ function render_block_core_post_date( $attributes, $content, $block ) {
20
20
  $classes = array();
21
21
 
22
22
  if (
23
- isset( $attributes['metadata']['bindings']['datetime']['source'] ) &&
24
- isset( $attributes['metadata']['bindings']['datetime']['args'] )
23
+ ! isset( $attributes['datetime'] ) && ! (
24
+ isset( $attributes['metadata']['bindings']['datetime']['source'] ) &&
25
+ isset( $attributes['metadata']['bindings']['datetime']['args'] )
26
+ )
25
27
  ) {
26
- /*
27
- * We might be running on a version of WordPress that doesn't support binding the block's `datetime` attribute
28
- * to a Block Bindings source. In this case, we need to manually set the `datetime` attribute to its correct value.
29
- * This branch can be removed once the minimum required WordPress version is 6.9 or newer.
30
- */
31
- $source = get_block_bindings_source( $attributes['metadata']['bindings']['datetime']['source'] );
32
- $source_args = $attributes['metadata']['bindings']['datetime']['args'];
33
-
34
- $attributes['datetime'] = $source->get_value( $source_args, $block, 'datetime' );
35
- } elseif ( ! isset( $attributes['datetime'] ) ) {
36
28
  /*
37
29
  * This is the legacy version of the block that didn't have the `datetime` attribute.
38
30
  * This branch needs to be kept for backward compatibility.
@@ -61,7 +53,7 @@ function render_block_core_post_date( $attributes, $content, $block ) {
61
53
  // (See https://github.com/WordPress/gutenberg/pull/46839 where this logic was originally
62
54
  // implemented.)
63
55
  // In this case, we have to respect and return the empty value.
64
- return $attributes['datetime'];
56
+ return '';
65
57
  }
66
58
 
67
59
  $unformatted_date = $attributes['datetime'];
@@ -113,5 +105,18 @@ function register_block_core_post_date() {
113
105
  'render_callback' => 'render_block_core_post_date',
114
106
  )
115
107
  );
108
+
109
+ // The following filter can be removed once the minimum required WordPress version is 6.9 or newer.
110
+ add_filter(
111
+ 'block_bindings_supported_attributes_core/post-date',
112
+ function ( $attributes ) {
113
+ if ( ! in_array( 'datetime', $attributes, true ) ) {
114
+ $attributes[] = 'datetime';
115
+ }
116
+ return $attributes;
117
+ },
118
+ 10,
119
+ 3
120
+ );
116
121
  }
117
122
  add_action( 'init', 'register_block_core_post_date' );