@wordpress/block-library 8.15.0 → 8.16.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 (156) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/avatar/index.js +3 -0
  3. package/build/avatar/index.js.map +1 -1
  4. package/build/block/edit.js +2 -30
  5. package/build/block/edit.js.map +1 -1
  6. package/build/cover/index.js +2 -1
  7. package/build/cover/index.js.map +1 -1
  8. package/build/footnotes/edit.js +11 -0
  9. package/build/footnotes/edit.js.map +1 -1
  10. package/build/footnotes/format.js +101 -8
  11. package/build/footnotes/format.js.map +1 -1
  12. package/build/footnotes/index.js +45 -3
  13. package/build/footnotes/index.js.map +1 -1
  14. package/build/gallery/edit.js +7 -5
  15. package/build/gallery/edit.js.map +1 -1
  16. package/build/image/deprecated.js +106 -2
  17. package/build/image/deprecated.js.map +1 -1
  18. package/build/image/image.js +2 -2
  19. package/build/image/image.js.map +1 -1
  20. package/build/image/index.js +2 -1
  21. package/build/image/index.js.map +1 -1
  22. package/build/index.js +3 -1
  23. package/build/index.js.map +1 -1
  24. package/build/list-item/hooks/use-merge.js +10 -1
  25. package/build/list-item/hooks/use-merge.js.map +1 -1
  26. package/build/navigation/edit/menu-inspector-controls.js +1 -1
  27. package/build/navigation/edit/menu-inspector-controls.js.map +1 -1
  28. package/build/navigation/edit/navigation-menu-selector.js +4 -4
  29. package/build/navigation/edit/navigation-menu-selector.js.map +1 -1
  30. package/build/navigation/view-modal.js +93 -32
  31. package/build/navigation/view-modal.js.map +1 -1
  32. package/build/navigation/view.js +63 -31
  33. package/build/navigation/view.js.map +1 -1
  34. package/build/pattern/edit.js +28 -4
  35. package/build/pattern/edit.js.map +1 -1
  36. package/build/preformatted/index.js +4 -0
  37. package/build/preformatted/index.js.map +1 -1
  38. package/build/search/view.js +166 -62
  39. package/build/search/view.js.map +1 -1
  40. package/build/social-link/icons/index.js +13 -0
  41. package/build/social-link/icons/index.js.map +1 -1
  42. package/build/social-link/icons/threads.js +25 -0
  43. package/build/social-link/icons/threads.js.map +1 -0
  44. package/build/social-link/variations.js +7 -0
  45. package/build/social-link/variations.js.map +1 -1
  46. package/build/template-part/edit/import-controls.js +1 -1
  47. package/build/template-part/edit/import-controls.js.map +1 -1
  48. package/build-module/avatar/index.js +3 -0
  49. package/build-module/avatar/index.js.map +1 -1
  50. package/build-module/block/edit.js +4 -29
  51. package/build-module/block/edit.js.map +1 -1
  52. package/build-module/cover/index.js +2 -1
  53. package/build-module/cover/index.js.map +1 -1
  54. package/build-module/footnotes/edit.js +11 -0
  55. package/build-module/footnotes/edit.js.map +1 -1
  56. package/build-module/footnotes/format.js +102 -10
  57. package/build-module/footnotes/format.js.map +1 -1
  58. package/build-module/footnotes/index.js +45 -3
  59. package/build-module/footnotes/index.js.map +1 -1
  60. package/build-module/gallery/edit.js +7 -5
  61. package/build-module/gallery/edit.js.map +1 -1
  62. package/build-module/image/deprecated.js +107 -3
  63. package/build-module/image/deprecated.js.map +1 -1
  64. package/build-module/image/image.js +2 -2
  65. package/build-module/image/image.js.map +1 -1
  66. package/build-module/image/index.js +2 -1
  67. package/build-module/image/index.js.map +1 -1
  68. package/build-module/index.js +3 -1
  69. package/build-module/index.js.map +1 -1
  70. package/build-module/list-item/hooks/use-merge.js +10 -1
  71. package/build-module/list-item/hooks/use-merge.js.map +1 -1
  72. package/build-module/navigation/edit/menu-inspector-controls.js +1 -1
  73. package/build-module/navigation/edit/menu-inspector-controls.js.map +1 -1
  74. package/build-module/navigation/edit/navigation-menu-selector.js +4 -4
  75. package/build-module/navigation/edit/navigation-menu-selector.js.map +1 -1
  76. package/build-module/navigation/view-modal.js +93 -31
  77. package/build-module/navigation/view-modal.js.map +1 -1
  78. package/build-module/navigation/view.js +63 -31
  79. package/build-module/navigation/view.js.map +1 -1
  80. package/build-module/pattern/edit.js +27 -4
  81. package/build-module/pattern/edit.js.map +1 -1
  82. package/build-module/preformatted/index.js +4 -0
  83. package/build-module/preformatted/index.js.map +1 -1
  84. package/build-module/search/view.js +166 -62
  85. package/build-module/search/view.js.map +1 -1
  86. package/build-module/social-link/icons/index.js +1 -0
  87. package/build-module/social-link/icons/index.js.map +1 -1
  88. package/build-module/social-link/icons/threads.js +15 -0
  89. package/build-module/social-link/icons/threads.js.map +1 -0
  90. package/build-module/social-link/variations.js +8 -1
  91. package/build-module/social-link/variations.js.map +1 -1
  92. package/build-module/template-part/edit/import-controls.js +2 -2
  93. package/build-module/template-part/edit/import-controls.js.map +1 -1
  94. package/build-style/preformatted/style-rtl.css +2 -1
  95. package/build-style/preformatted/style.css +2 -1
  96. package/build-style/social-links/style-rtl.css +7 -0
  97. package/build-style/social-links/style.css +7 -0
  98. package/build-style/style-rtl.css +10 -1
  99. package/build-style/style.css +10 -1
  100. package/build-style/video/style-rtl.css +1 -0
  101. package/build-style/video/style.css +1 -0
  102. package/package.json +32 -32
  103. package/src/audio/test/__snapshots__/edit.native.js.snap +60 -0
  104. package/src/avatar/block.json +3 -0
  105. package/src/block/edit.js +1 -39
  106. package/src/buttons/test/edit.native.js +4 -0
  107. package/src/columns/test/edit.native.js +5 -0
  108. package/src/comment-template/index.php +2 -0
  109. package/src/cover/block.json +2 -1
  110. package/src/cover/test/edit.native.js +8 -0
  111. package/src/embed/test/index.native.js +8 -0
  112. package/src/file/index.php +1 -1
  113. package/src/file/test/__snapshots__/edit.native.js.snap +61 -0
  114. package/src/footnotes/block.json +44 -1
  115. package/src/footnotes/edit.js +12 -0
  116. package/src/footnotes/format.js +70 -7
  117. package/src/footnotes/index.js +0 -1
  118. package/src/footnotes/index.php +207 -0
  119. package/src/gallery/edit.js +41 -37
  120. package/src/gallery/test/index.native.js +15 -3
  121. package/src/heading/test/index.native.js +4 -0
  122. package/src/image/block.json +2 -1
  123. package/src/image/deprecated.js +109 -3
  124. package/src/image/image.js +2 -2
  125. package/src/image/index.php +1 -3
  126. package/src/image/test/edit.native.js +0 -1
  127. package/src/index.js +5 -1
  128. package/src/list/test/edit.native.js +5 -0
  129. package/src/list-item/hooks/use-merge.js +12 -5
  130. package/src/missing/test/__snapshots__/edit.native.js.snap +21 -0
  131. package/src/navigation/edit/menu-inspector-controls.js +1 -1
  132. package/src/navigation/edit/navigation-menu-selector.js +8 -4
  133. package/src/navigation/index.php +27 -13
  134. package/src/navigation/view-modal.js +88 -39
  135. package/src/navigation/view.js +69 -36
  136. package/src/paragraph/test/edit.native.js +55 -35
  137. package/src/pattern/edit.js +21 -0
  138. package/src/pattern/index.php +13 -1
  139. package/src/post-template/index.php +2 -0
  140. package/src/post-title/index.php +2 -0
  141. package/src/preformatted/block.json +4 -0
  142. package/src/preformatted/style.scss +4 -1
  143. package/src/pullquote/test/edit.native.js +12 -4
  144. package/src/quote/test/edit.native.js +12 -4
  145. package/src/search/index.php +4 -0
  146. package/src/search/test/__snapshots__/edit.native.js.snap +63 -0
  147. package/src/search/view.js +171 -67
  148. package/src/social-link/icons/index.js +1 -0
  149. package/src/social-link/icons/threads.js +10 -0
  150. package/src/social-link/index.php +4 -0
  151. package/src/social-link/socials-with-bg.scss +5 -0
  152. package/src/social-link/socials-without-bg.scss +4 -0
  153. package/src/social-link/variations.js +7 -0
  154. package/src/template-part/edit/import-controls.js +2 -2
  155. package/src/template-part/index.php +6 -9
  156. package/src/video/style.scss +1 -0
@@ -9,6 +9,11 @@ import {
9
9
  useBlockProps,
10
10
  } from '@wordpress/block-editor';
11
11
 
12
+ /**
13
+ * Internal dependencies
14
+ */
15
+ import { unlock } from '../lock-unlock';
16
+
12
17
  const PatternEdit = ( { attributes, clientId } ) => {
13
18
  const selectedPattern = useSelect(
14
19
  ( select ) =>
@@ -20,6 +25,10 @@ const PatternEdit = ( { attributes, clientId } ) => {
20
25
 
21
26
  const { replaceBlocks, __unstableMarkNextChangeAsNotPersistent } =
22
27
  useDispatch( blockEditorStore );
28
+ const { setBlockEditingMode } = unlock( useDispatch( blockEditorStore ) );
29
+ const { getBlockRootClientId, getBlockEditingMode } = unlock(
30
+ useSelect( blockEditorStore )
31
+ );
23
32
 
24
33
  // Run this effect when the component loads.
25
34
  // This adds the Pattern's contents to the post.
@@ -33,13 +42,22 @@ const PatternEdit = ( { attributes, clientId } ) => {
33
42
  // because nested pattern blocks cannot be inserted if the parent block supports
34
43
  // inner blocks but doesn't have blockSettings in the state.
35
44
  window.queueMicrotask( () => {
45
+ const rootClientId = getBlockRootClientId( clientId );
36
46
  // Clone blocks from the pattern before insertion to ensure they receive
37
47
  // distinct client ids. See https://github.com/WordPress/gutenberg/issues/50628.
38
48
  const clonedBlocks = selectedPattern.blocks.map( ( block ) =>
39
49
  cloneBlock( block )
40
50
  );
51
+ const rootEditingMode = getBlockEditingMode( rootClientId );
52
+ // Temporarily set the root block to default mode to allow replacing the pattern.
53
+ // This could happen when the page is disabling edits of non-content blocks.
54
+ __unstableMarkNextChangeAsNotPersistent();
55
+ setBlockEditingMode( rootClientId, 'default' );
41
56
  __unstableMarkNextChangeAsNotPersistent();
42
57
  replaceBlocks( clientId, clonedBlocks );
58
+ // Restore the root block's original mode.
59
+ __unstableMarkNextChangeAsNotPersistent();
60
+ setBlockEditingMode( rootClientId, rootEditingMode );
43
61
  } );
44
62
  }
45
63
  }, [
@@ -47,6 +65,9 @@ const PatternEdit = ( { attributes, clientId } ) => {
47
65
  selectedPattern?.blocks,
48
66
  __unstableMarkNextChangeAsNotPersistent,
49
67
  replaceBlocks,
68
+ getBlockEditingMode,
69
+ setBlockEditingMode,
70
+ getBlockRootClientId,
50
71
  ] );
51
72
 
52
73
  const props = useBlockProps();
@@ -22,6 +22,8 @@ function register_block_core_pattern() {
22
22
  /**
23
23
  * Renders the `core/pattern` block on the server.
24
24
  *
25
+ * @since 6.3.0 Backwards compatibility: blocks with no `syncStatus` attribute do not receive block wrapper.
26
+ *
25
27
  * @param array $attributes Block attributes.
26
28
  *
27
29
  * @return string Returns the output of the pattern.
@@ -39,7 +41,17 @@ function render_block_core_pattern( $attributes ) {
39
41
  }
40
42
 
41
43
  $pattern = $registry->get_registered( $slug );
42
- return do_blocks( $pattern['content'] );
44
+ $content = $pattern['content'];
45
+
46
+ $gutenberg_experiments = get_option( 'gutenberg-experiments' );
47
+ if ( $gutenberg_experiments && ! empty( $gutenberg_experiments['gutenberg-auto-inserting-blocks'] ) ) {
48
+ // TODO: In the long run, we'd likely want to have a filter in the `WP_Block_Patterns_Registry` class
49
+ // instead to allow us plugging in code like this.
50
+ $blocks = parse_blocks( $content );
51
+ $content = gutenberg_serialize_blocks( $blocks );
52
+ }
53
+
54
+ return do_blocks( $content );
43
55
  }
44
56
 
45
57
  add_action( 'init', 'register_block_core_pattern' );
@@ -34,6 +34,8 @@ function block_core_post_template_uses_featured_image( $inner_blocks ) {
34
34
  /**
35
35
  * Renders the `core/post-template` block on the server.
36
36
  *
37
+ * @since 6.3.0 Changed render_block_context priority to `1`.
38
+ *
37
39
  * @param array $attributes Block attributes.
38
40
  * @param string $content Block default content.
39
41
  * @param WP_Block $block Block instance.
@@ -8,6 +8,8 @@
8
8
  /**
9
9
  * Renders the `core/post-title` block on the server.
10
10
  *
11
+ * @since 6.3.0 Omitting the $post argument from the `get_the_title`.
12
+ *
11
13
  * @param array $attributes Block attributes.
12
14
  * @param string $content Block default content.
13
15
  * @param WP_Block $block Block instance.
@@ -25,6 +25,10 @@
25
25
  "text": true
26
26
  }
27
27
  },
28
+ "spacing": {
29
+ "padding": true,
30
+ "margin": true
31
+ },
28
32
  "typography": {
29
33
  "fontSize": true,
30
34
  "lineHeight": true,
@@ -1,7 +1,10 @@
1
1
  .wp-block-preformatted {
2
+ // This block has customizable padding, border-box makes that more predictable.
3
+ box-sizing: border-box;
2
4
  white-space: pre-wrap;
3
5
  }
4
6
 
5
- .wp-block-preformatted.has-background {
7
+ // Add low specificity default padding when a background is used.
8
+ :where(.wp-block-preformatted.has-background) {
6
9
  padding: $block-bg-padding--v $block-bg-padding--h;
7
10
  }
@@ -5,6 +5,7 @@ import {
5
5
  addBlock,
6
6
  getBlock,
7
7
  initializeEditor,
8
+ selectRangeInRichText,
8
9
  setupCoreBlocks,
9
10
  getEditorHtml,
10
11
  fireEvent,
@@ -45,10 +46,13 @@ describe( 'Pullquote', () => {
45
46
 
46
47
  const citationTextInput =
47
48
  within( citationBlock ).getByPlaceholderText( 'Add citation' );
48
- typeInRichText( citationTextInput, 'A person', {
49
- finalSelectionStart: 2,
50
- finalSelectionEnd: 2,
49
+ typeInRichText( citationTextInput, 'A person' );
50
+ fireEvent( citationTextInput, 'onKeyDown', {
51
+ nativeEvent: {},
52
+ preventDefault() {},
53
+ keyCode: ENTER,
51
54
  } );
55
+ selectRangeInRichText( citationTextInput, 2 );
52
56
  fireEvent( citationTextInput, 'onKeyDown', {
53
57
  nativeEvent: {},
54
58
  preventDefault() {},
@@ -59,7 +63,11 @@ describe( 'Pullquote', () => {
59
63
  expect( getEditorHtml() ).toMatchInlineSnapshot( `
60
64
  "<!-- wp:pullquote -->
61
65
  <figure class="wp-block-pullquote"><blockquote><p>A great statement.<br>Again</p><cite>A <br>person</cite></blockquote></figure>
62
- <!-- /wp:pullquote -->"
66
+ <!-- /wp:pullquote -->
67
+
68
+ <!-- wp:paragraph -->
69
+ <p></p>
70
+ <!-- /wp:paragraph -->"
63
71
  ` );
64
72
  } );
65
73
  } );
@@ -5,6 +5,7 @@ import {
5
5
  addBlock,
6
6
  getBlock,
7
7
  initializeEditor,
8
+ selectRangeInRichText,
8
9
  setupCoreBlocks,
9
10
  getEditorHtml,
10
11
  fireEvent,
@@ -62,10 +63,13 @@ describe( 'Quote', () => {
62
63
  typeInRichText( quoteTextInput, 'Again.' );
63
64
  const citationTextInput =
64
65
  within( citationBlock ).getByPlaceholderText( 'Add citation' );
65
- typeInRichText( citationTextInput, 'A person', {
66
- finalSelectionStart: 2,
67
- finalSelectionEnd: 2,
66
+ typeInRichText( citationTextInput, 'A person' );
67
+ fireEvent( citationTextInput, 'onKeyDown', {
68
+ nativeEvent: {},
69
+ preventDefault() {},
70
+ keyCode: ENTER,
68
71
  } );
72
+ selectRangeInRichText( citationTextInput, 2 );
69
73
  fireEvent( citationTextInput, 'onKeyDown', {
70
74
  nativeEvent: {},
71
75
  preventDefault() {},
@@ -82,7 +86,11 @@ describe( 'Quote', () => {
82
86
  <!-- wp:paragraph -->
83
87
  <p>Again.</p>
84
88
  <!-- /wp:paragraph --><cite>A <br>person</cite></blockquote>
85
- <!-- /wp:quote -->"
89
+ <!-- /wp:quote -->
90
+
91
+ <!-- wp:paragraph -->
92
+ <p></p>
93
+ <!-- /wp:paragraph -->"
86
94
  ` );
87
95
  } );
88
96
  } );
@@ -8,6 +8,8 @@
8
8
  /**
9
9
  * Dynamically renders the `core/search` block.
10
10
  *
11
+ * @since 6.3.0 Using block.json `viewScript` to register script, and update `view_script_handles()` only when needed.
12
+ *
11
13
  * @param array $attributes The block attributes.
12
14
  * @param string $content The saved content.
13
15
  * @param WP_Block $block The parsed block.
@@ -138,8 +140,10 @@ function render_block_core_search( $attributes, $content, $block ) {
138
140
  $button->add_class( implode( ' ', $button_classes ) );
139
141
  if ( 'expand-searchfield' === $attributes['buttonBehavior'] && 'button-only' === $attributes['buttonPosition'] ) {
140
142
  $button->set_attribute( 'aria-label', __( 'Expand search field' ) );
143
+ $button->set_attribute( 'data-toggled-aria-label', __( 'Submit Search' ) );
141
144
  $button->set_attribute( 'aria-controls', 'wp-block-search__input-' . $input_id );
142
145
  $button->set_attribute( 'aria-expanded', 'false' );
146
+ $button->set_attribute( 'type', 'button' ); // Will be set to submit after clicking.
143
147
  } else {
144
148
  $button->set_attribute( 'aria-label', wp_strip_all_tags( $attributes['buttonText'] ) );
145
149
  }
@@ -20,6 +20,15 @@ exports[`Search Block renders block with button inside option 1`] = `
20
20
  }
21
21
  >
22
22
  <RCTAztecView
23
+ accessibilityState={
24
+ {
25
+ "busy": undefined,
26
+ "checked": undefined,
27
+ "disabled": undefined,
28
+ "expanded": undefined,
29
+ "selected": undefined,
30
+ }
31
+ }
23
32
  accessible={true}
24
33
  activeFormats={[]}
25
34
  blockType={
@@ -136,6 +145,15 @@ exports[`Search Block renders block with button inside option 1`] = `
136
145
  }
137
146
  >
138
147
  <RCTAztecView
148
+ accessibilityState={
149
+ {
150
+ "busy": undefined,
151
+ "checked": undefined,
152
+ "disabled": undefined,
153
+ "expanded": undefined,
154
+ "selected": undefined,
155
+ }
156
+ }
139
157
  accessible={true}
140
158
  activeFormats={[]}
141
159
  blockType={
@@ -216,6 +234,15 @@ exports[`Search Block renders block with icon button option matches snapshot 1`]
216
234
  }
217
235
  >
218
236
  <RCTAztecView
237
+ accessibilityState={
238
+ {
239
+ "busy": undefined,
240
+ "checked": undefined,
241
+ "disabled": undefined,
242
+ "expanded": undefined,
243
+ "selected": undefined,
244
+ }
245
+ }
219
246
  accessible={true}
220
247
  activeFormats={[]}
221
248
  blockType={
@@ -402,6 +429,15 @@ exports[`Search Block renders block with label hidden matches snapshot 1`] = `
402
429
  }
403
430
  >
404
431
  <RCTAztecView
432
+ accessibilityState={
433
+ {
434
+ "busy": undefined,
435
+ "checked": undefined,
436
+ "disabled": undefined,
437
+ "expanded": undefined,
438
+ "selected": undefined,
439
+ }
440
+ }
405
441
  accessible={true}
406
442
  activeFormats={[]}
407
443
  blockType={
@@ -482,6 +518,15 @@ exports[`Search Block renders with default configuration matches snapshot 1`] =
482
518
  }
483
519
  >
484
520
  <RCTAztecView
521
+ accessibilityState={
522
+ {
523
+ "busy": undefined,
524
+ "checked": undefined,
525
+ "disabled": undefined,
526
+ "expanded": undefined,
527
+ "selected": undefined,
528
+ }
529
+ }
485
530
  accessible={true}
486
531
  activeFormats={[]}
487
532
  blockType={
@@ -598,6 +643,15 @@ exports[`Search Block renders with default configuration matches snapshot 1`] =
598
643
  }
599
644
  >
600
645
  <RCTAztecView
646
+ accessibilityState={
647
+ {
648
+ "busy": undefined,
649
+ "checked": undefined,
650
+ "disabled": undefined,
651
+ "expanded": undefined,
652
+ "selected": undefined,
653
+ }
654
+ }
601
655
  accessible={true}
602
656
  activeFormats={[]}
603
657
  blockType={
@@ -678,6 +732,15 @@ exports[`Search Block renders with no-button option matches snapshot 1`] = `
678
732
  }
679
733
  >
680
734
  <RCTAztecView
735
+ accessibilityState={
736
+ {
737
+ "busy": undefined,
738
+ "checked": undefined,
739
+ "disabled": undefined,
740
+ "expanded": undefined,
741
+ "selected": undefined,
742
+ }
743
+ }
681
744
  accessible={true}
682
745
  activeFormats={[]}
683
746
  blockType={
@@ -1,68 +1,172 @@
1
- window.addEventListener( 'DOMContentLoaded', () => {
2
- const hiddenClass = 'wp-block-search__searchfield-hidden';
3
-
4
- Array.from(
5
- document.getElementsByClassName(
6
- 'wp-block-search__button-behavior-expand'
7
- )
8
- ).forEach( ( block ) => {
9
- const searchField = block.querySelector( '.wp-block-search__input' );
10
- const searchButton = block.querySelector( '.wp-block-search__button' );
11
- const searchLabel = block.querySelector( '.wp-block-search__label' );
12
- const ariaLabel = searchButton.getAttribute( 'aria-label' );
13
- const id = searchField.getAttribute( 'id' );
14
-
15
- const toggleSearchField = ( showSearchField ) => {
16
- if ( showSearchField ) {
17
- searchField.removeAttribute( 'aria-hidden' );
18
- searchField.removeAttribute( 'tabindex' );
19
- searchButton.removeAttribute( 'aria-expanded' );
20
- searchButton.removeAttribute( 'aria-controls' );
21
- searchButton.setAttribute( 'type', 'submit' );
22
- searchButton.setAttribute( 'aria-label', 'Submit Search' );
23
-
24
- return block.classList.remove( hiddenClass );
25
- }
26
-
27
- searchButton.removeAttribute( 'type' );
28
- searchField.setAttribute( 'aria-hidden', 'true' );
29
- searchField.setAttribute( 'tabindex', '-1' );
30
- searchButton.setAttribute( 'aria-expanded', 'false' );
31
- searchButton.setAttribute( 'aria-controls', id );
32
- searchButton.setAttribute( 'aria-label', ariaLabel );
33
- return block.classList.add( hiddenClass );
34
- };
35
-
36
- const hideSearchField = ( e ) => {
37
- if ( ! e.target.closest( '.wp-block-search' ) ) {
38
- return toggleSearchField( false );
39
- }
40
-
41
- if ( e.key === 'Escape' ) {
42
- searchButton.focus();
43
- return toggleSearchField( false );
44
- }
45
- };
46
-
47
- const handleButtonClick = ( e ) => {
48
- if ( block.classList.contains( hiddenClass ) ) {
49
- e.preventDefault();
50
- searchField.focus();
51
- toggleSearchField( true );
52
- }
53
- };
54
-
55
- searchButton.removeAttribute( 'type' );
56
- searchField.addEventListener( 'keydown', ( e ) => {
57
- hideSearchField( e );
58
- } );
59
- searchButton.addEventListener( 'click', handleButtonClick );
60
- searchButton.addEventListener( 'keydown', ( e ) => {
61
- hideSearchField( e );
62
- } );
63
- if ( searchLabel ) {
64
- searchLabel.addEventListener( 'click', handleButtonClick );
65
- }
66
- document.body.addEventListener( 'click', hideSearchField );
1
+ /*eslint-env browser*/
2
+
3
+ /** @type {?HTMLFormElement} */
4
+ let expandedSearchBlock = null;
5
+
6
+ const hiddenClass = 'wp-block-search__searchfield-hidden';
7
+
8
+ /**
9
+ * Toggles aria-label with data-toggled-aria-label.
10
+ *
11
+ * @param {HTMLElement} element
12
+ */
13
+ function toggleAriaLabel( element ) {
14
+ if ( ! ( 'toggledAriaLabel' in element.dataset ) ) {
15
+ throw new Error( 'Element lacks toggledAriaLabel in dataset.' );
16
+ }
17
+
18
+ const ariaLabel = element.dataset.toggledAriaLabel;
19
+ element.dataset.toggledAriaLabel = element.ariaLabel;
20
+ element.ariaLabel = ariaLabel;
21
+ }
22
+
23
+ /**
24
+ * Gets search input.
25
+ *
26
+ * @param {HTMLFormElement} block Search block.
27
+ * @return {HTMLInputElement} Search input.
28
+ */
29
+ function getSearchInput( block ) {
30
+ return block.querySelector( '.wp-block-search__input' );
31
+ }
32
+
33
+ /**
34
+ * Gets search button.
35
+ *
36
+ * @param {HTMLFormElement} block Search block.
37
+ * @return {HTMLButtonElement} Search button.
38
+ */
39
+ function getSearchButton( block ) {
40
+ return block.querySelector( '.wp-block-search__button' );
41
+ }
42
+
43
+ /**
44
+ * Handles keydown event to collapse an expanded Search block (when pressing Escape key).
45
+ *
46
+ * @param {KeyboardEvent} event
47
+ */
48
+ function handleKeydownEvent( event ) {
49
+ if ( ! expandedSearchBlock ) {
50
+ // In case the event listener wasn't removed in time.
51
+ return;
52
+ }
53
+
54
+ if ( event.key === 'Escape' ) {
55
+ const block = expandedSearchBlock; // This is nullified by collapseExpandedSearchBlock().
56
+ collapseExpandedSearchBlock();
57
+ getSearchButton( block ).focus();
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Handles keyup event to collapse an expanded Search block (e.g. when tabbing out of expanded Search block).
63
+ *
64
+ * @param {KeyboardEvent} event
65
+ */
66
+ function handleKeyupEvent( event ) {
67
+ if ( ! expandedSearchBlock ) {
68
+ // In case the event listener wasn't removed in time.
69
+ return;
70
+ }
71
+
72
+ if ( event.target.closest( '.wp-block-search' ) !== expandedSearchBlock ) {
73
+ collapseExpandedSearchBlock();
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Expands search block.
79
+ *
80
+ * Inverse of what is done in collapseExpandedSearchBlock().
81
+ *
82
+ * @param {HTMLFormElement} block Search block.
83
+ */
84
+ function expandSearchBlock( block ) {
85
+ // Make sure only one is open at a time.
86
+ if ( expandedSearchBlock ) {
87
+ collapseExpandedSearchBlock();
88
+ }
89
+
90
+ const searchField = getSearchInput( block );
91
+ const searchButton = getSearchButton( block );
92
+
93
+ searchButton.type = 'submit';
94
+ searchField.ariaHidden = 'false';
95
+ searchField.tabIndex = 0;
96
+ searchButton.ariaExpanded = 'true';
97
+ searchButton.removeAttribute( 'aria-controls' ); // Note: Seemingly not reflected with searchButton.ariaControls.
98
+ toggleAriaLabel( searchButton );
99
+ block.classList.remove( hiddenClass );
100
+
101
+ searchField.focus(); // Note that Chrome seems to do this automatically.
102
+
103
+ // The following two must be inverse of what is done in collapseExpandedSearchBlock().
104
+ document.addEventListener( 'keydown', handleKeydownEvent, {
105
+ passive: true,
106
+ } );
107
+ document.addEventListener( 'keyup', handleKeyupEvent, {
108
+ passive: true,
109
+ } );
110
+
111
+ expandedSearchBlock = block;
112
+ }
113
+
114
+ /**
115
+ * Collapses the expanded search block.
116
+ *
117
+ * Inverse of what is done in expandSearchBlock().
118
+ */
119
+ function collapseExpandedSearchBlock() {
120
+ if ( ! expandedSearchBlock ) {
121
+ throw new Error( 'Expected expandedSearchBlock to be defined.' );
122
+ }
123
+ const block = expandedSearchBlock;
124
+ const searchField = getSearchInput( block );
125
+ const searchButton = getSearchButton( block );
126
+
127
+ searchButton.type = 'button';
128
+ searchField.ariaHidden = 'true';
129
+ searchField.tabIndex = -1;
130
+ searchButton.ariaExpanded = 'false';
131
+ searchButton.setAttribute( 'aria-controls', searchField.id ); // Note: Seemingly not reflected with searchButton.ariaControls.
132
+ toggleAriaLabel( searchButton );
133
+ block.classList.add( hiddenClass );
134
+
135
+ // The following two must be inverse of what is done in expandSearchBlock().
136
+ document.removeEventListener( 'keydown', handleKeydownEvent, {
137
+ passive: true,
67
138
  } );
68
- } );
139
+ document.removeEventListener( 'keyup', handleKeyupEvent, {
140
+ passive: true,
141
+ } );
142
+
143
+ expandedSearchBlock = null;
144
+ }
145
+
146
+ // Listen for click events anywhere on the document so this script can be loaded asynchronously in the head.
147
+ document.addEventListener(
148
+ 'click',
149
+ ( event ) => {
150
+ // Get the ancestor expandable Search block of the clicked element.
151
+ const block = event.target.closest(
152
+ '.wp-block-search__button-behavior-expand'
153
+ );
154
+
155
+ /*
156
+ * If there is already an expanded search block and either the current click was not for a Search block or it was
157
+ * for another block, then collapse the currently-expanded block.
158
+ */
159
+ if ( expandedSearchBlock && block !== expandedSearchBlock ) {
160
+ collapseExpandedSearchBlock();
161
+ }
162
+
163
+ // If the click was on or inside a collapsed Search block, expand it.
164
+ if (
165
+ block instanceof HTMLFormElement &&
166
+ block.classList.contains( hiddenClass )
167
+ ) {
168
+ expandSearchBlock( block );
169
+ }
170
+ },
171
+ { passive: true }
172
+ );
@@ -31,6 +31,7 @@ export * from './snapchat';
31
31
  export * from './soundcloud';
32
32
  export * from './spotify';
33
33
  export * from './telegram';
34
+ export * from './threads';
34
35
  export * from './tiktok';
35
36
  export * from './tumblr';
36
37
  export * from './twitch';
@@ -0,0 +1,10 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { Path, SVG } from '@wordpress/primitives';
5
+
6
+ export const ThreadsIcon = () => (
7
+ <SVG width="24" height="24" viewBox="0 0 24 24" version="1.1">
8
+ <Path d="M16.3 11.3c-.1 0-.2-.1-.2-.1-.1-2.6-1.5-4-3.9-4-1.4 0-2.6.6-3.3 1.7l1.3.9c.5-.8 1.4-1 2-1 .8 0 1.4.2 1.7.7.3.3.5.8.5 1.3-.7-.1-1.4-.2-2.2-.1-2.2.1-3.7 1.4-3.6 3.2 0 .9.5 1.7 1.3 2.2.7.4 1.5.6 2.4.6 1.2-.1 2.1-.5 2.7-1.3.5-.6.8-1.4.9-2.4.6.3 1 .8 1.2 1.3.4.9.4 2.4-.8 3.6-1.1 1.1-2.3 1.5-4.3 1.5-2.1 0-3.8-.7-4.8-2S5.7 14.3 5.7 12c0-2.3.5-4.1 1.5-5.4 1.1-1.3 2.7-2 4.8-2 2.2 0 3.8.7 4.9 2 .5.7.9 1.5 1.2 2.5l1.5-.4c-.3-1.2-.8-2.2-1.5-3.1-1.3-1.7-3.3-2.6-6-2.6-2.6 0-4.7.9-6 2.6C4.9 7.2 4.3 9.3 4.3 12s.6 4.8 1.9 6.4c1.4 1.7 3.4 2.6 6 2.6 2.3 0 4-.6 5.3-2 1.8-1.8 1.7-4 1.1-5.4-.4-.9-1.2-1.7-2.3-2.3zm-4 3.8c-1 .1-2-.4-2-1.3 0-.7.5-1.5 2.1-1.6h.5c.6 0 1.1.1 1.6.2-.2 2.3-1.3 2.7-2.2 2.7z" />
9
+ </SVG>
10
+ );
@@ -258,6 +258,10 @@ function block_core_social_link_services( $service = '', $field = '' ) {
258
258
  'name' => 'Telegram',
259
259
  'icon' => '<svg width="24" height="24" viewBox="0 0 128 128" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M28.9700376,63.3244248 C47.6273373,55.1957357 60.0684594,49.8368063 66.2934036,47.2476366 C84.0668845,39.855031 87.7600616,38.5708563 90.1672227,38.528 C90.6966555,38.5191258 91.8804274,38.6503351 92.6472251,39.2725385 C93.294694,39.7979149 93.4728387,40.5076237 93.5580865,41.0057381 C93.6433345,41.5038525 93.7494885,42.63857 93.6651041,43.5252052 C92.7019529,53.6451182 88.5344133,78.2034783 86.4142057,89.5379542 C85.5170662,94.3339958 83.750571,95.9420841 82.0403991,96.0994568 C78.3237996,96.4414641 75.5015827,93.6432685 71.9018743,91.2836143 C66.2690414,87.5912212 63.0868492,85.2926952 57.6192095,81.6896017 C51.3004058,77.5256038 55.3966232,75.2369981 58.9976911,71.4967761 C59.9401076,70.5179421 76.3155302,55.6232293 76.6324771,54.2720454 C76.6721165,54.1030573 76.7089039,53.4731496 76.3346867,53.1405352 C75.9604695,52.8079208 75.4081573,52.921662 75.0095933,53.0121213 C74.444641,53.1403447 65.4461175,59.0880351 48.0140228,70.8551922 C45.4598218,72.6091037 43.1463059,73.4636682 41.0734751,73.4188859 C38.7883453,73.3695169 34.3926725,72.1268388 31.1249416,71.0646282 C27.1169366,69.7617838 23.931454,69.0729605 24.208838,66.8603276 C24.3533167,65.7078514 25.9403832,64.5292172 28.9700376,63.3244248 Z" /></svg>',
260
260
  ),
261
+ 'threads' => array(
262
+ 'name' => 'Threads',
263
+ 'icon' => '<svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M16.3 11.3c-.1 0-.2-.1-.2-.1-.1-2.6-1.5-4-3.9-4-1.4 0-2.6.6-3.3 1.7l1.3.9c.5-.8 1.4-1 2-1 .8 0 1.4.2 1.7.7.3.3.5.8.5 1.3-.7-.1-1.4-.2-2.2-.1-2.2.1-3.7 1.4-3.6 3.2 0 .9.5 1.7 1.3 2.2.7.4 1.5.6 2.4.6 1.2-.1 2.1-.5 2.7-1.3.5-.6.8-1.4.9-2.4.6.3 1 .8 1.2 1.3.4.9.4 2.4-.8 3.6-1.1 1.1-2.3 1.5-4.3 1.5-2.1 0-3.8-.7-4.8-2S5.7 14.3 5.7 12c0-2.3.5-4.1 1.5-5.4 1.1-1.3 2.7-2 4.8-2 2.2 0 3.8.7 4.9 2 .5.7.9 1.5 1.2 2.5l1.5-.4c-.3-1.2-.8-2.2-1.5-3.1-1.3-1.7-3.3-2.6-6-2.6-2.6 0-4.7.9-6 2.6C4.9 7.2 4.3 9.3 4.3 12s.6 4.8 1.9 6.4c1.4 1.7 3.4 2.6 6 2.6 2.3 0 4-.6 5.3-2 1.8-1.8 1.7-4 1.1-5.4-.4-.9-1.2-1.7-2.3-2.3zm-4 3.8c-1 .1-2-.4-2-1.3 0-.7.5-1.5 2.1-1.6h.5c.6 0 1.1.1 1.6.2-.2 2.3-1.3 2.7-2.2 2.7z"/></svg>',
264
+ ),
261
265
  'tiktok' => array(
262
266
  'name' => 'TikTok',
263
267
  'icon' => '<svg width="24" height="24" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M16.708 0.027c1.745-0.027 3.48-0.011 5.213-0.027 0.105 2.041 0.839 4.12 2.333 5.563 1.491 1.479 3.6 2.156 5.652 2.385v5.369c-1.923-0.063-3.855-0.463-5.6-1.291-0.76-0.344-1.468-0.787-2.161-1.24-0.009 3.896 0.016 7.787-0.025 11.667-0.104 1.864-0.719 3.719-1.803 5.255-1.744 2.557-4.771 4.224-7.88 4.276-1.907 0.109-3.812-0.411-5.437-1.369-2.693-1.588-4.588-4.495-4.864-7.615-0.032-0.667-0.043-1.333-0.016-1.984 0.24-2.537 1.495-4.964 3.443-6.615 2.208-1.923 5.301-2.839 8.197-2.297 0.027 1.975-0.052 3.948-0.052 5.923-1.323-0.428-2.869-0.308-4.025 0.495-0.844 0.547-1.485 1.385-1.819 2.333-0.276 0.676-0.197 1.427-0.181 2.145 0.317 2.188 2.421 4.027 4.667 3.828 1.489-0.016 2.916-0.88 3.692-2.145 0.251-0.443 0.532-0.896 0.547-1.417 0.131-2.385 0.079-4.76 0.095-7.145 0.011-5.375-0.016-10.735 0.025-16.093z" /></svg>',
@@ -154,6 +154,11 @@
154
154
  color: #fff;
155
155
  }
156
156
 
157
+ .wp-social-link-threads {
158
+ background-color: #000;
159
+ color: #fff;
160
+ }
161
+
157
162
  .wp-social-link-tiktok {
158
163
  background-color: #000;
159
164
  color: #fff;
@@ -119,6 +119,10 @@
119
119
  color: #2aabee;
120
120
  }
121
121
 
122
+ .wp-social-link-threads {
123
+ color: #000;
124
+ }
125
+
122
126
  .wp-social-link-tiktok {
123
127
  color: #000;
124
128
  }
@@ -35,6 +35,7 @@ import {
35
35
  SoundCloudIcon,
36
36
  SpotifyIcon,
37
37
  TelegramIcon,
38
+ ThreadsIcon,
38
39
  TiktokIcon,
39
40
  TumblrIcon,
40
41
  TwitchIcon,
@@ -255,6 +256,12 @@ const variations = [
255
256
  title: 'Telegram',
256
257
  icon: TelegramIcon,
257
258
  },
259
+ {
260
+ name: 'threads',
261
+ attributes: { service: 'threads' },
262
+ title: 'Threads',
263
+ icon: ThreadsIcon,
264
+ },
258
265
  {
259
266
  name: 'tiktok',
260
267
  attributes: { service: 'tiktok' },