@wordpress/block-library 9.46.0 → 9.48.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 (176) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/build/button/edit.cjs +7 -4
  3. package/build/button/edit.cjs.map +3 -3
  4. package/build/columns/edit.cjs +4 -10
  5. package/build/columns/edit.cjs.map +2 -2
  6. package/build/cover/edit/inspector-controls.cjs +20 -6
  7. package/build/cover/edit/inspector-controls.cjs.map +2 -2
  8. package/build/freeform/migration-notice.cjs +1 -1
  9. package/build/freeform/migration-notice.cjs.map +1 -1
  10. package/build/home-link/block.json +7 -0
  11. package/build/home-link/edit.cjs +167 -24
  12. package/build/home-link/edit.cjs.map +3 -3
  13. package/build/html/edit.cjs +2 -4
  14. package/build/html/edit.cjs.map +2 -2
  15. package/build/html/modal.cjs +0 -4
  16. package/build/html/modal.cjs.map +2 -2
  17. package/build/image/block.json +4 -0
  18. package/build/image/deprecated.cjs +202 -4
  19. package/build/image/deprecated.cjs.map +3 -3
  20. package/build/image/image.cjs +94 -30
  21. package/build/image/image.cjs.map +2 -2
  22. package/build/image/index.cjs +23 -4
  23. package/build/image/index.cjs.map +2 -2
  24. package/build/image/save.cjs +25 -10
  25. package/build/image/save.cjs.map +2 -2
  26. package/build/image/transforms.cjs +15 -3
  27. package/build/image/transforms.cjs.map +2 -2
  28. package/build/image/use-open-image-media-editor-modal.cjs +37 -14
  29. package/build/image/use-open-image-media-editor-modal.cjs.map +2 -2
  30. package/build/list-item/hooks/use-enter.cjs +8 -4
  31. package/build/list-item/hooks/use-enter.cjs.map +3 -3
  32. package/build/list-item/hooks/use-space.cjs +8 -4
  33. package/build/list-item/hooks/use-space.cjs.map +3 -3
  34. package/build/navigation-link/edit.cjs +2 -1
  35. package/build/navigation-link/edit.cjs.map +2 -2
  36. package/build/navigation-link/shared/use-handle-link-change.cjs +19 -3
  37. package/build/navigation-link/shared/use-handle-link-change.cjs.map +3 -3
  38. package/build/navigation-submenu/edit.cjs +8 -22
  39. package/build/navigation-submenu/edit.cjs.map +2 -2
  40. package/build/paragraph/use-enter.cjs +8 -4
  41. package/build/paragraph/use-enter.cjs.map +3 -3
  42. package/build/post-date/edit.cjs +9 -1
  43. package/build/post-date/edit.cjs.map +2 -2
  44. package/build/post-featured-image/edit.cjs +6 -5
  45. package/build/post-featured-image/edit.cjs.map +2 -2
  46. package/build/site-logo/edit.cjs +5 -2
  47. package/build/site-logo/edit.cjs.map +2 -2
  48. package/build/social-link/edit.cjs.map +3 -3
  49. package/build/tab-list/edit.cjs +2 -0
  50. package/build/tab-list/edit.cjs.map +2 -2
  51. package/build/tab-panels/edit.cjs +5 -1
  52. package/build/tab-panels/edit.cjs.map +2 -2
  53. package/build/table/edit.cjs +1 -0
  54. package/build/table/edit.cjs.map +2 -2
  55. package/build/tabs/edit.cjs +1 -36
  56. package/build/tabs/edit.cjs.map +2 -2
  57. package/build-module/button/edit.mjs +12 -5
  58. package/build-module/button/edit.mjs.map +2 -2
  59. package/build-module/columns/edit.mjs +4 -10
  60. package/build-module/columns/edit.mjs.map +2 -2
  61. package/build-module/cover/edit/inspector-controls.mjs +20 -7
  62. package/build-module/cover/edit/inspector-controls.mjs.map +2 -2
  63. package/build-module/freeform/migration-notice.mjs +1 -1
  64. package/build-module/freeform/migration-notice.mjs.map +1 -1
  65. package/build-module/home-link/block.json +7 -0
  66. package/build-module/home-link/edit.mjs +181 -26
  67. package/build-module/home-link/edit.mjs.map +2 -2
  68. package/build-module/html/edit.mjs +2 -4
  69. package/build-module/html/edit.mjs.map +2 -2
  70. package/build-module/html/modal.mjs +0 -4
  71. package/build-module/html/modal.mjs.map +2 -2
  72. package/build-module/image/block.json +4 -0
  73. package/build-module/image/deprecated.mjs +204 -5
  74. package/build-module/image/deprecated.mjs.map +2 -2
  75. package/build-module/image/image.mjs +96 -30
  76. package/build-module/image/image.mjs.map +2 -2
  77. package/build-module/image/index.mjs +23 -4
  78. package/build-module/image/index.mjs.map +2 -2
  79. package/build-module/image/save.mjs +25 -10
  80. package/build-module/image/save.mjs.map +2 -2
  81. package/build-module/image/transforms.mjs +15 -3
  82. package/build-module/image/transforms.mjs.map +2 -2
  83. package/build-module/image/use-open-image-media-editor-modal.mjs +37 -14
  84. package/build-module/image/use-open-image-media-editor-modal.mjs.map +2 -2
  85. package/build-module/list-item/hooks/use-enter.mjs +12 -5
  86. package/build-module/list-item/hooks/use-enter.mjs.map +2 -2
  87. package/build-module/list-item/hooks/use-space.mjs +12 -5
  88. package/build-module/list-item/hooks/use-space.mjs.map +2 -2
  89. package/build-module/navigation-link/edit.mjs +2 -1
  90. package/build-module/navigation-link/edit.mjs.map +2 -2
  91. package/build-module/navigation-link/shared/use-handle-link-change.mjs +19 -3
  92. package/build-module/navigation-link/shared/use-handle-link-change.mjs.map +2 -2
  93. package/build-module/navigation-submenu/edit.mjs +9 -23
  94. package/build-module/navigation-submenu/edit.mjs.map +2 -2
  95. package/build-module/paragraph/use-enter.mjs +12 -5
  96. package/build-module/paragraph/use-enter.mjs.map +2 -2
  97. package/build-module/post-date/edit.mjs +9 -1
  98. package/build-module/post-date/edit.mjs.map +2 -2
  99. package/build-module/post-featured-image/edit.mjs +6 -5
  100. package/build-module/post-featured-image/edit.mjs.map +2 -2
  101. package/build-module/site-logo/edit.mjs +6 -2
  102. package/build-module/site-logo/edit.mjs.map +2 -2
  103. package/build-module/social-link/edit.mjs +2 -2
  104. package/build-module/social-link/edit.mjs.map +2 -2
  105. package/build-module/tab-list/edit.mjs +2 -0
  106. package/build-module/tab-list/edit.mjs.map +2 -2
  107. package/build-module/tab-panels/edit.mjs +5 -1
  108. package/build-module/tab-panels/edit.mjs.map +2 -2
  109. package/build-module/table/edit.mjs +1 -0
  110. package/build-module/table/edit.mjs.map +2 -2
  111. package/build-module/tabs/edit.mjs +2 -37
  112. package/build-module/tabs/edit.mjs.map +2 -2
  113. package/build-style/breadcrumbs/style-rtl.css +1 -1
  114. package/build-style/breadcrumbs/style.css +1 -1
  115. package/build-style/editor-rtl.css +0 -11
  116. package/build-style/editor.css +0 -11
  117. package/build-style/gallery/editor-rtl.css +0 -11
  118. package/build-style/gallery/editor.css +0 -11
  119. package/build-style/style-rtl.css +1 -1
  120. package/build-style/style.css +1 -1
  121. package/package.json +40 -40
  122. package/src/block/edit-title.native.js +3 -3
  123. package/src/block/edit.native.js +2 -2
  124. package/src/breadcrumbs/style.scss +1 -1
  125. package/src/button/edit.js +14 -5
  126. package/src/columns/edit.js +3 -9
  127. package/src/cover/controls.native.js +2 -2
  128. package/src/cover/edit/inspector-controls.js +69 -52
  129. package/src/cover/edit.native.js +6 -4
  130. package/src/cover/focal-point-settings-button.native.js +2 -2
  131. package/src/cover/test/edit.js +70 -31
  132. package/src/embed/embed-no-preview.native.js +7 -3
  133. package/src/embed/embed-placeholder.native.js +2 -2
  134. package/src/file/edit.native.js +2 -2
  135. package/src/freeform/migration-notice.js +1 -1
  136. package/src/gallery/editor.scss +0 -14
  137. package/src/home-link/block.json +7 -0
  138. package/src/home-link/edit.js +185 -22
  139. package/src/home-link/index.php +14 -2
  140. package/src/html/edit.js +14 -12
  141. package/src/html/modal.js +0 -5
  142. package/src/image/block.json +4 -0
  143. package/src/image/deprecated.js +236 -4
  144. package/src/image/edit.native.js +2 -2
  145. package/src/image/image.js +166 -76
  146. package/src/image/index.js +20 -1
  147. package/src/image/index.php +1 -1
  148. package/src/image/save.js +39 -12
  149. package/src/image/test/use-open-image-media-editor-modal.js +101 -0
  150. package/src/image/transforms.js +21 -5
  151. package/src/image/use-open-image-media-editor-modal.js +41 -17
  152. package/src/latest-posts/edit.native.js +2 -2
  153. package/src/list-item/hooks/use-enter.js +15 -5
  154. package/src/list-item/hooks/use-space.js +15 -5
  155. package/src/list-item/list-style-type.native.js +2 -2
  156. package/src/media-text/media-container.native.js +7 -3
  157. package/src/missing/edit.native.js +4 -4
  158. package/src/missing/test/edit.native.js +3 -3
  159. package/src/navigation/test/use-navigation-menu.js +8 -2
  160. package/src/navigation-link/edit.js +1 -0
  161. package/src/navigation-link/shared/test/use-handle-link-change.test.js +212 -0
  162. package/src/navigation-link/shared/use-handle-link-change.js +36 -9
  163. package/src/navigation-submenu/edit.js +11 -28
  164. package/src/navigation-submenu/index.php +13 -0
  165. package/src/paragraph/use-enter.js +19 -5
  166. package/src/post-date/edit.js +7 -3
  167. package/src/post-featured-image/edit.js +15 -11
  168. package/src/search/edit.native.js +2 -2
  169. package/src/search/test/edit.native.js +2 -2
  170. package/src/site-logo/edit.js +7 -1
  171. package/src/social-link/edit.js +2 -2
  172. package/src/tab-list/edit.js +3 -0
  173. package/src/tab-panels/edit.js +10 -1
  174. package/src/table/edit.js +1 -0
  175. package/src/tabs/edit.js +14 -42
  176. package/src/video/edit.native.js +3 -3
@@ -54,6 +54,29 @@ async function createAndSelectBlock() {
54
54
  await selectBlock( 'Block: Cover' );
55
55
  }
56
56
 
57
+ async function openStylesTabIfAvailable() {
58
+ const stylesTab = screen.queryByRole( 'tab', {
59
+ name: 'Styles',
60
+ } );
61
+
62
+ if ( stylesTab ) {
63
+ await userEvent.click( stylesTab );
64
+ }
65
+ }
66
+
67
+ async function selectViewportState( name ) {
68
+ await userEvent.click(
69
+ screen.getByRole( 'button', {
70
+ name: 'State: Default',
71
+ } )
72
+ );
73
+ await userEvent.click(
74
+ screen.getByRole( 'menuitem', {
75
+ name,
76
+ } )
77
+ );
78
+ }
79
+
57
80
  describe( 'Cover block', () => {
58
81
  describe( 'Editor canvas', () => {
59
82
  test( 'shows placeholder if background image and color not set', async () => {
@@ -189,6 +212,21 @@ describe( 'Cover block', () => {
189
212
  } )
190
213
  ).not.toBeInTheDocument();
191
214
  } );
215
+ test( 'does not display settings tab when media settings are empty', async () => {
216
+ await setup();
217
+ await createAndSelectBlock();
218
+
219
+ expect(
220
+ screen.queryByRole( 'tab', {
221
+ name: 'Settings',
222
+ } )
223
+ ).not.toBeInTheDocument();
224
+ expect(
225
+ screen.getByRole( 'button', {
226
+ name: 'Advanced',
227
+ } )
228
+ ).toBeInTheDocument();
229
+ } );
192
230
  test( 'displays media settings panel if url is set', async () => {
193
231
  await setup( {
194
232
  url: 'http://localhost/my-image.jpg',
@@ -275,11 +313,7 @@ describe( 'Cover block', () => {
275
313
 
276
314
  expect( overlay[ 0 ] ).toHaveClass( 'has-background-dim-100' );
277
315
 
278
- await userEvent.click(
279
- screen.getByRole( 'tab', {
280
- name: 'Styles',
281
- } )
282
- );
316
+ await openStylesTabIfAvailable();
283
317
  // Need act here as the isDark method is async.
284
318
  // eslint-disable-next-line testing-library/no-unnecessary-act
285
319
  await act( async () => {
@@ -308,11 +342,7 @@ describe( 'Cover block', () => {
308
342
 
309
343
  expect( overlay[ 0 ] ).toHaveClass( 'has-background-dim-100' );
310
344
 
311
- await userEvent.click(
312
- screen.getByRole( 'tab', {
313
- name: 'Styles',
314
- } )
315
- );
345
+ await openStylesTabIfAvailable();
316
346
 
317
347
  // Need act here as the isDark method is async.
318
348
  // eslint-disable-next-line testing-library/no-unnecessary-act
@@ -332,9 +362,7 @@ describe( 'Cover block', () => {
332
362
  test( 'does not render overlay control', async () => {
333
363
  await setup( undefined, true, disabledColorSettings );
334
364
  await selectBlock( 'Block: Cover' );
335
- await userEvent.click(
336
- screen.getByRole( 'tab', { name: 'Styles' } )
337
- );
365
+ await openStylesTabIfAvailable();
338
366
 
339
367
  const overlayControl = screen.queryByRole( 'button', {
340
368
  name: 'Overlay',
@@ -345,9 +373,7 @@ describe( 'Cover block', () => {
345
373
  test( 'does not render opacity control', async () => {
346
374
  await setup( undefined, true, disabledColorSettings );
347
375
  await selectBlock( 'Block: Cover' );
348
- await userEvent.click(
349
- screen.getByRole( 'tab', { name: 'Styles' } )
350
- );
376
+ await openStylesTabIfAvailable();
351
377
 
352
378
  const opacityControl = screen.queryByRole( 'slider', {
353
379
  name: 'Overlay opacity',
@@ -356,17 +382,38 @@ describe( 'Cover block', () => {
356
382
  expect( opacityControl ).not.toBeInTheDocument();
357
383
  } );
358
384
  } );
385
+
386
+ test( 'does not render overlay controls when a viewport state is selected', async () => {
387
+ await setup();
388
+ await createAndSelectBlock();
389
+ await openStylesTabIfAvailable();
390
+
391
+ expect(
392
+ screen.getByRole( 'button', {
393
+ name: 'Overlay',
394
+ } )
395
+ ).toBeInTheDocument();
396
+
397
+ await selectViewportState( 'Tablet' );
398
+
399
+ expect(
400
+ screen.queryByRole( 'button', {
401
+ name: 'Overlay',
402
+ } )
403
+ ).not.toBeInTheDocument();
404
+ expect(
405
+ screen.queryByRole( 'slider', {
406
+ name: 'Overlay opacity',
407
+ } )
408
+ ).not.toBeInTheDocument();
409
+ } );
359
410
  } );
360
411
 
361
412
  describe( 'Dimensions panel', () => {
362
413
  test( 'sets minHeight attribute when number control value changed', async () => {
363
414
  await setup();
364
415
  await createAndSelectBlock();
365
- await userEvent.click(
366
- screen.getByRole( 'tab', {
367
- name: 'Styles',
368
- } )
369
- );
416
+ await openStylesTabIfAvailable();
370
417
  await userEvent.clear(
371
418
  screen.getByLabelText( 'Minimum height' )
372
419
  );
@@ -395,11 +442,7 @@ describe( 'Cover block', () => {
395
442
  expect( coverBlock ).toHaveClass( 'is-light' );
396
443
 
397
444
  await selectBlock( 'Block: Cover' );
398
- await userEvent.click(
399
- screen.getByRole( 'tab', {
400
- name: 'Styles',
401
- } )
402
- );
445
+ await openStylesTabIfAvailable();
403
446
  await userEvent.click( screen.getByText( 'Overlay' ) );
404
447
  const popupColorPicker = screen.getByRole( 'option', {
405
448
  name: 'Black',
@@ -416,11 +459,7 @@ describe( 'Cover block', () => {
416
459
  const coverBlock = screen.getByLabelText( 'Block: Cover' );
417
460
  expect( coverBlock ).toHaveClass( 'is-light' );
418
461
  await selectBlock( 'Block: Cover' );
419
- await userEvent.click(
420
- screen.getByRole( 'tab', {
421
- name: 'Styles',
422
- } )
423
- );
462
+ await openStylesTabIfAvailable();
424
463
  await userEvent.click( screen.getByText( 'Overlay' ) );
425
464
  // The default color is black, so clicking the black color button will remove the background color,
426
465
  // which should remove the isDark setting and assign the is-light class.
@@ -14,7 +14,11 @@ import { usePreferredColorSchemeStyle } from '@wordpress/compose';
14
14
  import { requestPreview } from '@wordpress/react-native-bridge';
15
15
  import { useSelect } from '@wordpress/data';
16
16
  import { store as editorStore } from '@wordpress/editor';
17
- import { BottomSheet, Icon, TextControl } from '@wordpress/components';
17
+ import {
18
+ BottomSheet,
19
+ Icon as WCIcon,
20
+ TextControl,
21
+ } from '@wordpress/components';
18
22
  import { help } from '@wordpress/icons';
19
23
  import { BlockIcon } from '@wordpress/block-editor';
20
24
 
@@ -150,7 +154,7 @@ const EmbedNoPreview = ( {
150
154
  onPress={ onPressHelp }
151
155
  style={ helpIconStyle }
152
156
  >
153
- <Icon
157
+ <WCIcon
154
158
  icon={ help }
155
159
  fill={ helpIconStyle.fill }
156
160
  size={ helpIconStyle.width }
@@ -167,7 +171,7 @@ const EmbedNoPreview = ( {
167
171
  >
168
172
  <View style={ styles[ 'embed-no-preview__container' ] }>
169
173
  <View style={ sheetIconStyle }>
170
- <Icon
174
+ <WCIcon
171
175
  icon={ help }
172
176
  fill={ sheetIconStyle.fill }
173
177
  size={ sheetIconStyle.width }
@@ -8,7 +8,7 @@ import { View, Text, TouchableOpacity } from 'react-native';
8
8
  */
9
9
  import { __ } from '@wordpress/i18n';
10
10
  import { usePreferredColorSchemeStyle } from '@wordpress/compose';
11
- import { Icon, Picker } from '@wordpress/components';
11
+ import { Icon as WCIcon, Picker } from '@wordpress/components';
12
12
  import { BlockIcon } from '@wordpress/block-editor';
13
13
  import { useRef } from '@wordpress/element';
14
14
 
@@ -110,7 +110,7 @@ const EmbedPlaceholder = ( {
110
110
  <View style={ containerStyle }>
111
111
  { cannotEmbed ? (
112
112
  <>
113
- <Icon
113
+ <WCIcon
114
114
  icon={ noticeOutline }
115
115
  fill={ embedIconErrorStyle.fill }
116
116
  style={ embedIconErrorStyle }
@@ -31,7 +31,7 @@ import {
31
31
  ToggleControl,
32
32
  TextControl,
33
33
  SelectControl,
34
- Icon,
34
+ Icon as WCIcon,
35
35
  } from '@wordpress/components';
36
36
  import {
37
37
  file as icon,
@@ -476,7 +476,7 @@ export class FileEdit extends Component {
476
476
  />
477
477
  { isUploadFailed && (
478
478
  <View style={ styles.errorContainer }>
479
- <Icon
479
+ <WCIcon
480
480
  icon={ cautionFilled }
481
481
  style={ errorIconStyle }
482
482
  />
@@ -44,7 +44,7 @@ export default function MigrationNotice( { content, onReplace } ) {
44
44
  return (
45
45
  <Warning actions={ actions }>
46
46
  { __(
47
- 'The Classic block is being phased out. Convert this content to blocks for the best editing experience, or move it to a Custom HTML block to preserve the markup as-is.'
47
+ 'The Classic block is being phased out. Convert this content to blocks for the best editing experience, or move it to a Custom HTML block to preserve the original markup.'
48
48
  ) }
49
49
  </Warning>
50
50
  );
@@ -21,20 +21,6 @@
21
21
  flex-basis: 100%;
22
22
  }
23
23
 
24
- .wp-block-image {
25
- .components-notice.is-error {
26
- display: block;
27
- }
28
- .components-notice__content {
29
- margin: 4px 0;
30
- }
31
- .components-notice__dismiss {
32
- position: absolute;
33
- top: 0;
34
- right: 5px;
35
- }
36
- }
37
-
38
24
  // @todo this deserves a refactor, by being moved to the toolbar.
39
25
  .block-editor-media-placeholder.is-appender {
40
26
  .components-placeholder__label {
@@ -11,6 +11,13 @@
11
11
  "label": {
12
12
  "type": "string",
13
13
  "role": "content"
14
+ },
15
+ "opensInNewTab": {
16
+ "type": "boolean",
17
+ "default": false
18
+ },
19
+ "description": {
20
+ "type": "string"
14
21
  }
15
22
  },
16
23
  "usesContext": [
@@ -6,21 +6,74 @@ import clsx from 'clsx';
6
6
  /**
7
7
  * WordPress dependencies
8
8
  */
9
- import { RichText, useBlockProps } from '@wordpress/block-editor';
9
+ import {
10
+ InspectorControls,
11
+ RichText,
12
+ useBlockProps,
13
+ store as blockEditorStore,
14
+ } from '@wordpress/block-editor';
15
+ import {
16
+ Button,
17
+ CheckboxControl,
18
+ TextControl,
19
+ TextareaControl,
20
+ __experimentalToolsPanel as ToolsPanel,
21
+ __experimentalToolsPanelItem as ToolsPanelItem,
22
+ } from '@wordpress/components';
10
23
  import { __ } from '@wordpress/i18n';
11
24
  import { useSelect } from '@wordpress/data';
12
25
  import { store as coreStore } from '@wordpress/core-data';
26
+ import { external } from '@wordpress/icons';
27
+ import { __unstableStripHTML as stripHTML } from '@wordpress/dom';
28
+
29
+ /**
30
+ * Internal dependencies
31
+ */
32
+ import { useToolsPanelDropdownMenuProps } from '../utils/hooks';
13
33
 
14
34
  const preventDefault = ( event ) => event.preventDefault();
15
35
 
16
36
  export default function HomeEdit( { attributes, setAttributes, context } ) {
17
- const homeUrl = useSelect( ( select ) => {
37
+ const {
38
+ homeUrl,
39
+ onNavigateToEntityRecord,
40
+ frontPageId,
41
+ frontPageTemplateId,
42
+ } = useSelect( ( select ) => {
43
+ const { getEntityRecord, getDefaultTemplateId, canUser } =
44
+ select( coreStore );
45
+
18
46
  // Site index.
19
- return select( coreStore ).getEntityRecord( 'root', '__unstableBase' )
20
- ?.home;
47
+ const baseUrl = getEntityRecord( 'root', '__unstableBase' )?.home;
48
+
49
+ // Front-page data (only available if the user can read site settings).
50
+ const canReadSettings = canUser( 'read', {
51
+ kind: 'root',
52
+ name: 'site',
53
+ } );
54
+ const site = canReadSettings ? getEntityRecord( 'root', 'site' ) : null;
55
+ const resolvedFrontPageId =
56
+ site?.show_on_front === 'page' ? site?.page_on_front : null;
57
+
58
+ // When no specific front page is set, fall back to the front-page template.
59
+ const resolvedFrontPageTemplateId = ! resolvedFrontPageId
60
+ ? getDefaultTemplateId( { slug: 'front-page' } )
61
+ : null;
62
+
63
+ return {
64
+ homeUrl: baseUrl,
65
+ onNavigateToEntityRecord:
66
+ select( blockEditorStore ).getSettings()
67
+ .onNavigateToEntityRecord,
68
+ frontPageId: resolvedFrontPageId,
69
+ frontPageTemplateId: resolvedFrontPageTemplateId,
70
+ };
21
71
  }, [] );
22
72
 
23
73
  const { textColor, backgroundColor, style } = context;
74
+ const { label, opensInNewTab, description } = attributes;
75
+ const dropdownMenuProps = useToolsPanelDropdownMenuProps();
76
+
24
77
  const blockProps = useBlockProps( {
25
78
  className: clsx( 'wp-block-navigation-item', {
26
79
  'has-text-color': !! textColor || !! style?.color?.text,
@@ -35,24 +88,134 @@ export default function HomeEdit( { attributes, setAttributes, context } ) {
35
88
  } );
36
89
 
37
90
  return (
38
- <div { ...blockProps }>
39
- <a
40
- className="wp-block-home-link__content wp-block-navigation-item__content"
41
- href={ homeUrl }
42
- onClick={ preventDefault }
43
- >
44
- <RichText
45
- identifier="label"
46
- className="wp-block-home-link__label"
47
- value={ attributes.label ?? __( 'Home' ) }
48
- onChange={ ( labelValue ) => {
49
- setAttributes( { label: labelValue } );
91
+ <>
92
+ <InspectorControls group="content">
93
+ <ToolsPanel
94
+ label={ __( 'Settings' ) }
95
+ resetAll={ () => {
96
+ setAttributes( {
97
+ label: '',
98
+ opensInNewTab: false,
99
+ description: '',
100
+ } );
50
101
  } }
51
- aria-label={ __( 'Home link text' ) }
52
- placeholder={ __( 'Add home link' ) }
53
- withoutInteractiveFormatting
54
- />
55
- </a>
56
- </div>
102
+ dropdownMenuProps={ dropdownMenuProps }
103
+ >
104
+ <ToolsPanelItem
105
+ hasValue={ () => !! label }
106
+ label={ __( 'Text' ) }
107
+ onDeselect={ () => setAttributes( { label: '' } ) }
108
+ isShownByDefault
109
+ >
110
+ <TextControl
111
+ __next40pxDefaultSize
112
+ label={ __( 'Text' ) }
113
+ value={ label ? stripHTML( label ) : '' }
114
+ onChange={ ( labelValue ) => {
115
+ setAttributes( { label: labelValue } );
116
+ } }
117
+ autoComplete="off"
118
+ />
119
+ </ToolsPanelItem>
120
+ <ToolsPanelItem
121
+ hasValue={ () => !! opensInNewTab }
122
+ label={ __( 'Open in new tab' ) }
123
+ onDeselect={ () =>
124
+ setAttributes( { opensInNewTab: false } )
125
+ }
126
+ isShownByDefault
127
+ >
128
+ <CheckboxControl
129
+ label={ __( 'Open in new tab' ) }
130
+ checked={ opensInNewTab }
131
+ onChange={ ( value ) =>
132
+ setAttributes( { opensInNewTab: value } )
133
+ }
134
+ />
135
+ </ToolsPanelItem>
136
+ { onNavigateToEntityRecord &&
137
+ ( frontPageId || frontPageTemplateId ) && (
138
+ <Button
139
+ variant="secondary"
140
+ onClick={ () => {
141
+ if ( frontPageId ) {
142
+ onNavigateToEntityRecord( {
143
+ postId: frontPageId,
144
+ postType: 'page',
145
+ } );
146
+ } else {
147
+ onNavigateToEntityRecord( {
148
+ postId: frontPageTemplateId,
149
+ postType: 'wp_template',
150
+ } );
151
+ }
152
+ } }
153
+ __next40pxDefaultSize
154
+ className="navigation-link-to__action-button"
155
+ >
156
+ { __( 'Edit' ) }
157
+ </Button>
158
+ ) }
159
+ { homeUrl && (
160
+ <Button
161
+ variant="secondary"
162
+ href={ homeUrl }
163
+ target="_blank"
164
+ icon={ external }
165
+ iconPosition="right"
166
+ __next40pxDefaultSize
167
+ className="navigation-link-to__action-button"
168
+ >
169
+ { __( 'View' ) }
170
+ </Button>
171
+ ) }
172
+ <ToolsPanelItem
173
+ hasValue={ () => !! description }
174
+ label={ __( 'Description' ) }
175
+ onDeselect={ () =>
176
+ setAttributes( { description: '' } )
177
+ }
178
+ isShownByDefault
179
+ >
180
+ <TextareaControl
181
+ label={ __( 'Description' ) }
182
+ value={ description || '' }
183
+ onChange={ ( descriptionValue ) => {
184
+ setAttributes( {
185
+ description: descriptionValue,
186
+ } );
187
+ } }
188
+ help={ __(
189
+ 'The description will be displayed in the menu if the current theme supports it.'
190
+ ) }
191
+ />
192
+ </ToolsPanelItem>
193
+ </ToolsPanel>
194
+ </InspectorControls>
195
+ <div { ...blockProps }>
196
+ <a
197
+ className="wp-block-home-link__content wp-block-navigation-item__content"
198
+ href={ homeUrl }
199
+ onClick={ preventDefault }
200
+ >
201
+ <RichText
202
+ identifier="label"
203
+ className="wp-block-home-link__label"
204
+ value={ label ?? __( 'Home' ) }
205
+ onChange={ ( labelValue ) => {
206
+ setAttributes( { label: labelValue } );
207
+ } }
208
+ aria-label={ __( 'Home link text' ) }
209
+ placeholder={ __( 'Add label…' ) }
210
+ withoutInteractiveFormatting
211
+ />
212
+ { description && (
213
+ <span className="wp-block-navigation-item__description">
214
+ { description }
215
+ </span>
216
+ ) }
217
+ </a>
218
+ </div>
219
+ </>
57
220
  );
58
221
  }
@@ -129,12 +129,24 @@ function render_block_core_home_link( $attributes, $content, $block ) {
129
129
  $aria_current = ' aria-current="page"';
130
130
  }
131
131
 
132
+ $target = '';
133
+ if ( isset( $attributes['opensInNewTab'] ) && true === $attributes['opensInNewTab'] ) {
134
+ $target = ' target="_blank"';
135
+ }
136
+
137
+ $description = '';
138
+ if ( ! empty( $attributes['description'] ) ) {
139
+ $description = '<span class="wp-block-navigation-item__description">' . wp_kses_post( $attributes['description'] ) . '</span>';
140
+ }
141
+
132
142
  return sprintf(
133
- '<li %1$s><a class="wp-block-home-link__content wp-block-navigation-item__content" href="%2$s" rel="home"%3$s>%4$s</a></li>',
143
+ '<li %1$s><a class="wp-block-home-link__content wp-block-navigation-item__content" href="%2$s" rel="home" %3$s%4$s>%5$s%6$s</a></li>',
134
144
  block_core_home_link_build_li_wrapper_attributes( $block->context ),
135
145
  esc_url( home_url() ),
146
+ $target,
136
147
  $aria_current,
137
- wp_kses_post( $attributes['label'] )
148
+ wp_kses_post( $attributes['label'] ),
149
+ $description
138
150
  );
139
151
  }
140
152
 
package/src/html/edit.js CHANGED
@@ -49,12 +49,13 @@ export default function HTMLEdit( { attributes, setAttributes, isSelected } ) {
49
49
  { __( 'Edit HTML' ) }
50
50
  </Button>
51
51
  </Placeholder>
52
- <HTMLEditModal
53
- isOpen={ isModalOpen }
54
- onRequestClose={ () => setIsModalOpen( false ) }
55
- content={ attributes.content }
56
- setAttributes={ setAttributes }
57
- />
52
+ { isModalOpen && (
53
+ <HTMLEditModal
54
+ onRequestClose={ () => setIsModalOpen( false ) }
55
+ content={ attributes.content }
56
+ setAttributes={ setAttributes }
57
+ />
58
+ ) }
58
59
  </div>
59
60
  );
60
61
  }
@@ -84,12 +85,13 @@ export default function HTMLEdit( { attributes, setAttributes, isSelected } ) {
84
85
  </VStack>
85
86
  </InspectorControls>
86
87
  <Preview content={ attributes.content } isSelected={ isSelected } />
87
- <HTMLEditModal
88
- isOpen={ isModalOpen }
89
- onRequestClose={ () => setIsModalOpen( false ) }
90
- content={ attributes.content }
91
- setAttributes={ setAttributes }
92
- />
88
+ { isModalOpen && (
89
+ <HTMLEditModal
90
+ onRequestClose={ () => setIsModalOpen( false ) }
91
+ content={ attributes.content }
92
+ setAttributes={ setAttributes }
93
+ />
94
+ ) }
93
95
  </div>
94
96
  );
95
97
  }
package/src/html/modal.js CHANGED
@@ -27,7 +27,6 @@ import { parseContent, serializeContent } from './utils';
27
27
  const { Tabs } = unlock( componentsPrivateApis );
28
28
 
29
29
  export default function HTMLEditModal( {
30
- isOpen,
31
30
  onRequestClose,
32
31
  content,
33
32
  setAttributes,
@@ -54,10 +53,6 @@ export default function HTMLEditModal( {
54
53
  const hasRestrictedContent =
55
54
  ! canUserUseUnfilteredHTML && ( css.trim() || js.trim() );
56
55
 
57
- if ( ! isOpen ) {
58
- return null;
59
- }
60
-
61
56
  const handleUpdate = () => {
62
57
  // For users without unfiltered_html capability, strip CSS and JS content
63
58
  // to prevent kses from leaving broken content
@@ -105,6 +105,10 @@
105
105
  "source": "attribute",
106
106
  "selector": "figure > a",
107
107
  "attribute": "target"
108
+ },
109
+ "isDecorative": {
110
+ "type": "boolean",
111
+ "default": false
108
112
  }
109
113
  },
110
114
  "supports": {