@wordpress/block-library 9.38.1-next.v.0 → 9.39.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 (273) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/button/index.cjs +3 -0
  3. package/build/button/index.cjs.map +2 -2
  4. package/build/comments-title/block.json +1 -3
  5. package/build/comments-title/deprecated.cjs +148 -24
  6. package/build/comments-title/deprecated.cjs.map +3 -3
  7. package/build/comments-title/edit.cjs +17 -31
  8. package/build/comments-title/edit.cjs.map +3 -3
  9. package/build/cover/edit/block-controls.cjs +10 -2
  10. package/build/cover/edit/block-controls.cjs.map +2 -2
  11. package/build/cover/edit/embed-video-url-input.cjs +6 -2
  12. package/build/cover/edit/embed-video-url-input.cjs.map +2 -2
  13. package/build/details/index.cjs +3 -0
  14. package/build/details/index.cjs.map +2 -2
  15. package/build/heading/index.cjs +3 -0
  16. package/build/heading/index.cjs.map +2 -2
  17. package/build/image/index.cjs +1 -1
  18. package/build/image/index.cjs.map +2 -2
  19. package/build/index.cjs +6 -0
  20. package/build/index.cjs.map +2 -2
  21. package/build/list-item/index.cjs +3 -0
  22. package/build/list-item/index.cjs.map +2 -2
  23. package/build/more/index.cjs +1 -1
  24. package/build/more/index.cjs.map +2 -2
  25. package/build/navigation/edit/index.cjs +23 -2
  26. package/build/navigation/edit/index.cjs.map +2 -2
  27. package/build/navigation-submenu/index.cjs +2 -2
  28. package/build/navigation-submenu/index.cjs.map +2 -2
  29. package/build/paragraph/index.cjs +1 -1
  30. package/build/paragraph/index.cjs.map +2 -2
  31. package/build/post-excerpt/edit.cjs +1 -1
  32. package/build/post-excerpt/edit.cjs.map +2 -2
  33. package/build/tab/add-tab-toolbar-control.cjs +31 -9
  34. package/build/tab/add-tab-toolbar-control.cjs.map +2 -2
  35. package/build/tab/block.json +18 -4
  36. package/build/tab/controls.cjs +4 -8
  37. package/build/tab/controls.cjs.map +3 -3
  38. package/build/tab/edit.cjs +46 -118
  39. package/build/tab/edit.cjs.map +3 -3
  40. package/build/tab/remove-tab-toolbar-control.cjs +91 -0
  41. package/build/tab/remove-tab-toolbar-control.cjs.map +7 -0
  42. package/build/tab/save.cjs +2 -2
  43. package/build/tab/save.cjs.map +2 -2
  44. package/build/tab-panels/block.json +70 -0
  45. package/build/tab-panels/edit.cjs +63 -0
  46. package/build/tab-panels/edit.cjs.map +7 -0
  47. package/build/tab-panels/icon.cjs +29 -0
  48. package/build/tab-panels/icon.cjs.map +7 -0
  49. package/build/tab-panels/index.cjs +58 -0
  50. package/build/tab-panels/index.cjs.map +7 -0
  51. package/build/tab-panels/save.cjs +33 -0
  52. package/build/tab-panels/save.cjs.map +7 -0
  53. package/build/tabs/block.json +61 -90
  54. package/build/tabs/controls.cjs +19 -221
  55. package/build/tabs/controls.cjs.map +3 -3
  56. package/build/tabs/deprecated.cjs +179 -0
  57. package/build/tabs/deprecated.cjs.map +7 -0
  58. package/build/tabs/edit.cjs +84 -62
  59. package/build/tabs/edit.cjs.map +3 -3
  60. package/build/tabs/index.cjs +3 -1
  61. package/build/tabs/index.cjs.map +3 -3
  62. package/build/tabs/save.cjs +6 -9
  63. package/build/tabs/save.cjs.map +2 -2
  64. package/build/tabs-menu/block.json +77 -0
  65. package/build/tabs-menu/edit.cjs +204 -0
  66. package/build/tabs-menu/edit.cjs.map +7 -0
  67. package/build/tabs-menu/icon.cjs +29 -0
  68. package/build/tabs-menu/icon.cjs.map +7 -0
  69. package/build/tabs-menu/index.cjs +58 -0
  70. package/build/tabs-menu/index.cjs.map +7 -0
  71. package/build/tabs-menu/save.cjs +35 -0
  72. package/build/tabs-menu/save.cjs.map +7 -0
  73. package/build/tabs-menu-item/block.json +98 -0
  74. package/build/tabs-menu-item/controls.cjs +247 -0
  75. package/build/tabs-menu-item/controls.cjs.map +7 -0
  76. package/build/tabs-menu-item/edit.cjs +272 -0
  77. package/build/tabs-menu-item/edit.cjs.map +7 -0
  78. package/build/tabs-menu-item/icon.cjs +29 -0
  79. package/build/tabs-menu-item/icon.cjs.map +7 -0
  80. package/build/tabs-menu-item/index.cjs +58 -0
  81. package/build/tabs-menu-item/index.cjs.map +7 -0
  82. package/build/tabs-menu-item/save.cjs +50 -0
  83. package/build/tabs-menu-item/save.cjs.map +7 -0
  84. package/build/template-part/edit/index.cjs +1 -1
  85. package/build/template-part/edit/index.cjs.map +2 -2
  86. package/build/utils/caption.cjs +4 -6
  87. package/build/utils/caption.cjs.map +3 -3
  88. package/build/video/edit.cjs +4 -2
  89. package/build/video/edit.cjs.map +2 -2
  90. package/build-module/button/index.mjs +3 -0
  91. package/build-module/button/index.mjs.map +2 -2
  92. package/build-module/comments-title/block.json +1 -3
  93. package/build-module/comments-title/deprecated.mjs +148 -24
  94. package/build-module/comments-title/deprecated.mjs.map +2 -2
  95. package/build-module/comments-title/edit.mjs +17 -32
  96. package/build-module/comments-title/edit.mjs.map +2 -2
  97. package/build-module/cover/edit/block-controls.mjs +11 -3
  98. package/build-module/cover/edit/block-controls.mjs.map +2 -2
  99. package/build-module/cover/edit/embed-video-url-input.mjs +6 -2
  100. package/build-module/cover/edit/embed-video-url-input.mjs.map +2 -2
  101. package/build-module/details/index.mjs +3 -0
  102. package/build-module/details/index.mjs.map +2 -2
  103. package/build-module/heading/index.mjs +3 -0
  104. package/build-module/heading/index.mjs.map +2 -2
  105. package/build-module/image/index.mjs +1 -1
  106. package/build-module/image/index.mjs.map +2 -2
  107. package/build-module/index.mjs +6 -0
  108. package/build-module/index.mjs.map +2 -2
  109. package/build-module/list-item/index.mjs +3 -0
  110. package/build-module/list-item/index.mjs.map +2 -2
  111. package/build-module/more/index.mjs +1 -1
  112. package/build-module/more/index.mjs.map +2 -2
  113. package/build-module/navigation/edit/index.mjs +23 -2
  114. package/build-module/navigation/edit/index.mjs.map +2 -2
  115. package/build-module/navigation-submenu/index.mjs +2 -2
  116. package/build-module/navigation-submenu/index.mjs.map +2 -2
  117. package/build-module/paragraph/index.mjs +1 -1
  118. package/build-module/paragraph/index.mjs.map +2 -2
  119. package/build-module/post-excerpt/edit.mjs +1 -1
  120. package/build-module/post-excerpt/edit.mjs.map +2 -2
  121. package/build-module/tab/add-tab-toolbar-control.mjs +32 -10
  122. package/build-module/tab/add-tab-toolbar-control.mjs.map +2 -2
  123. package/build-module/tab/block.json +18 -4
  124. package/build-module/tab/controls.mjs +4 -8
  125. package/build-module/tab/controls.mjs.map +2 -2
  126. package/build-module/tab/edit.mjs +48 -128
  127. package/build-module/tab/edit.mjs.map +2 -2
  128. package/build-module/tab/remove-tab-toolbar-control.mjs +73 -0
  129. package/build-module/tab/remove-tab-toolbar-control.mjs.map +7 -0
  130. package/build-module/tab/save.mjs +2 -2
  131. package/build-module/tab/save.mjs.map +2 -2
  132. package/build-module/tab-panels/block.json +70 -0
  133. package/build-module/tab-panels/edit.mjs +36 -0
  134. package/build-module/tab-panels/edit.mjs.map +7 -0
  135. package/build-module/tab-panels/icon.mjs +8 -0
  136. package/build-module/tab-panels/icon.mjs.map +7 -0
  137. package/build-module/tab-panels/index.mjs +20 -0
  138. package/build-module/tab-panels/index.mjs.map +7 -0
  139. package/build-module/tab-panels/save.mjs +12 -0
  140. package/build-module/tab-panels/save.mjs.map +7 -0
  141. package/build-module/tabs/block.json +61 -90
  142. package/build-module/tabs/controls.mjs +21 -228
  143. package/build-module/tabs/controls.mjs.map +2 -2
  144. package/build-module/tabs/deprecated.mjs +158 -0
  145. package/build-module/tabs/deprecated.mjs.map +7 -0
  146. package/build-module/tabs/edit.mjs +87 -64
  147. package/build-module/tabs/edit.mjs.map +2 -2
  148. package/build-module/tabs/index.mjs +3 -1
  149. package/build-module/tabs/index.mjs.map +2 -2
  150. package/build-module/tabs/save.mjs +7 -10
  151. package/build-module/tabs/save.mjs.map +2 -2
  152. package/build-module/tabs-menu/block.json +77 -0
  153. package/build-module/tabs-menu/edit.mjs +186 -0
  154. package/build-module/tabs-menu/edit.mjs.map +7 -0
  155. package/build-module/tabs-menu/icon.mjs +8 -0
  156. package/build-module/tabs-menu/icon.mjs.map +7 -0
  157. package/build-module/tabs-menu/index.mjs +20 -0
  158. package/build-module/tabs-menu/index.mjs.map +7 -0
  159. package/build-module/tabs-menu/save.mjs +14 -0
  160. package/build-module/tabs-menu/save.mjs.map +7 -0
  161. package/build-module/tabs-menu-item/block.json +98 -0
  162. package/build-module/tabs-menu-item/controls.mjs +227 -0
  163. package/build-module/tabs-menu-item/controls.mjs.map +7 -0
  164. package/build-module/tabs-menu-item/edit.mjs +253 -0
  165. package/build-module/tabs-menu-item/edit.mjs.map +7 -0
  166. package/build-module/tabs-menu-item/icon.mjs +8 -0
  167. package/build-module/tabs-menu-item/icon.mjs.map +7 -0
  168. package/build-module/tabs-menu-item/index.mjs +20 -0
  169. package/build-module/tabs-menu-item/index.mjs.map +7 -0
  170. package/build-module/tabs-menu-item/save.mjs +29 -0
  171. package/build-module/tabs-menu-item/save.mjs.map +7 -0
  172. package/build-module/template-part/edit/index.mjs +1 -1
  173. package/build-module/template-part/edit/index.mjs.map +2 -2
  174. package/build-module/utils/caption.mjs +1 -3
  175. package/build-module/utils/caption.mjs.map +2 -2
  176. package/build-module/video/edit.mjs +4 -2
  177. package/build-module/video/edit.mjs.map +2 -2
  178. package/build-style/editor-rtl.css +16 -21
  179. package/build-style/editor.css +16 -21
  180. package/build-style/gallery/style-rtl.css +1 -1
  181. package/build-style/gallery/style.css +1 -1
  182. package/build-style/style-rtl.css +42 -153
  183. package/build-style/style.css +42 -153
  184. package/build-style/tab/style-rtl.css +7 -1
  185. package/build-style/tab/style.css +7 -1
  186. package/build-style/tab-panels/style-rtl.css +4 -0
  187. package/build-style/tab-panels/style.css +4 -0
  188. package/build-style/tabs/style-rtl.css +1 -167
  189. package/build-style/tabs/style.css +1 -167
  190. package/build-style/tabs-menu/editor-rtl.css +4 -0
  191. package/build-style/tabs-menu/editor.css +4 -0
  192. package/build-style/tabs-menu/style-rtl.css +8 -0
  193. package/build-style/tabs-menu/style.css +8 -0
  194. package/build-style/tabs-menu-item/editor-rtl.css +16 -0
  195. package/build-style/tabs-menu-item/editor.css +16 -0
  196. package/build-style/tabs-menu-item/style-rtl.css +34 -0
  197. package/build-style/tabs-menu-item/style.css +34 -0
  198. package/package.json +37 -37
  199. package/src/button/index.js +4 -0
  200. package/src/comments-title/block.json +1 -3
  201. package/src/comments-title/deprecated.js +153 -23
  202. package/src/comments-title/edit.js +9 -25
  203. package/src/cover/edit/block-controls.js +14 -3
  204. package/src/cover/edit/embed-video-url-input.js +6 -2
  205. package/src/details/index.js +4 -0
  206. package/src/editor.scss +2 -1
  207. package/src/gallery/style.scss +1 -1
  208. package/src/heading/index.js +4 -0
  209. package/src/image/index.js +4 -1
  210. package/src/index.js +6 -0
  211. package/src/list-item/index.js +4 -0
  212. package/src/more/index.js +4 -1
  213. package/src/navigation/edit/index.js +28 -4
  214. package/src/navigation-submenu/index.js +6 -3
  215. package/src/paragraph/index.js +4 -1
  216. package/src/post-excerpt/edit.js +1 -1
  217. package/src/post-excerpt/index.php +39 -16
  218. package/src/style.scss +3 -0
  219. package/src/tab/add-tab-toolbar-control.js +36 -11
  220. package/src/tab/block.json +18 -4
  221. package/src/tab/controls.js +4 -5
  222. package/src/tab/edit.js +75 -150
  223. package/src/tab/index.php +5 -63
  224. package/src/tab/remove-tab-toolbar-control.js +103 -0
  225. package/src/tab/save.js +1 -3
  226. package/src/tab/style.scss +8 -1
  227. package/src/tab-panels/block.json +70 -0
  228. package/src/tab-panels/edit.js +44 -0
  229. package/src/tab-panels/icon.js +10 -0
  230. package/src/tab-panels/index.js +21 -0
  231. package/src/tab-panels/save.js +11 -0
  232. package/src/tab-panels/style.scss +4 -0
  233. package/src/tabs/block.json +61 -90
  234. package/src/tabs/controls.js +7 -221
  235. package/src/tabs/deprecated.js +214 -0
  236. package/src/tabs/edit.js +108 -68
  237. package/src/tabs/index.js +2 -0
  238. package/src/tabs/index.php +86 -191
  239. package/src/tabs/save.js +6 -13
  240. package/src/tabs/style.scss +1 -187
  241. package/src/tabs-menu/block.json +77 -0
  242. package/src/tabs-menu/edit.js +251 -0
  243. package/src/tabs-menu/editor.scss +6 -0
  244. package/src/tabs-menu/icon.js +10 -0
  245. package/src/tabs-menu/index.js +21 -0
  246. package/src/tabs-menu/index.php +74 -0
  247. package/src/tabs-menu/save.js +18 -0
  248. package/src/tabs-menu/style.scss +8 -0
  249. package/src/tabs-menu-item/block.json +98 -0
  250. package/src/tabs-menu-item/controls.js +262 -0
  251. package/src/tabs-menu-item/edit.js +322 -0
  252. package/src/tabs-menu-item/editor.scss +20 -0
  253. package/src/tabs-menu-item/icon.js +10 -0
  254. package/src/tabs-menu-item/index.js +21 -0
  255. package/src/tabs-menu-item/index.php +82 -0
  256. package/src/tabs-menu-item/save.js +44 -0
  257. package/src/tabs-menu-item/style.scss +42 -0
  258. package/src/template-part/edit/index.js +1 -3
  259. package/src/utils/caption.js +1 -7
  260. package/src/video/edit.js +4 -2
  261. package/build/tab/tabs-list.cjs +0 -132
  262. package/build/tab/tabs-list.cjs.map +0 -7
  263. package/build/tabs/style-engine.cjs +0 -119
  264. package/build/tabs/style-engine.cjs.map +0 -7
  265. package/build-module/tab/tabs-list.mjs +0 -101
  266. package/build-module/tab/tabs-list.mjs.map +0 -7
  267. package/build-module/tabs/style-engine.mjs +0 -101
  268. package/build-module/tabs/style-engine.mjs.map +0 -7
  269. package/build-style/tabs/editor-rtl.css +0 -26
  270. package/build-style/tabs/editor.css +0 -26
  271. package/src/tab/tabs-list.js +0 -122
  272. package/src/tabs/editor.scss +0 -30
  273. package/src/tabs/style-engine.js +0 -164
@@ -33,10 +33,13 @@ export const settings = {
33
33
 
34
34
  const customName = attributes?.metadata?.name;
35
35
 
36
- // In the list view, use the block's menu label as the label.
36
+ // In the list view and breadcrumb, use the block's menu label as the label.
37
37
  // If the menu label is empty, fall back to the default label.
38
- if ( context === 'list-view' && ( customName || label ) ) {
39
- return attributes?.metadata?.name || label;
38
+ if (
39
+ ( context === 'list-view' || context === 'breadcrumb' ) &&
40
+ customName
41
+ ) {
42
+ return customName;
40
43
  }
41
44
 
42
45
  return label;
@@ -34,7 +34,10 @@ export const settings = {
34
34
  __experimentalLabel( attributes, { context } ) {
35
35
  const customName = attributes?.metadata?.name;
36
36
 
37
- if ( context === 'list-view' && customName ) {
37
+ if (
38
+ ( context === 'list-view' || context === 'breadcrumb' ) &&
39
+ customName
40
+ ) {
38
41
  return customName;
39
42
  }
40
43
 
@@ -169,7 +169,7 @@ export default function PostExcerptEditor( {
169
169
  let trimmedExcerpt = '';
170
170
  if ( wordCountType === 'words' ) {
171
171
  trimmedExcerpt = rawOrRenderedExcerpt
172
- .split( ' ', excerptLength )
172
+ .split( /\s+/, excerptLength )
173
173
  .join( ' ' );
174
174
  } else if ( wordCountType === 'characters_excluding_spaces' ) {
175
175
  /*
@@ -39,13 +39,23 @@ function render_block_core_post_excerpt( $attributes, $content, $block ) {
39
39
  add_filter( 'excerpt_more', $filter_excerpt_more );
40
40
 
41
41
  /*
42
- * The purpose of the excerpt length setting is to limit the length of both
43
- * automatically generated and user-created excerpts.
44
- * Because the excerpt_length filter only applies to auto generated excerpts,
45
- * wp_trim_words is used instead.
46
- */
42
+ * The purpose of the excerpt length setting is to limit the length of both
43
+ * automatically generated and user-created excerpts.
44
+ * Because the excerpt_length filter only applies to auto generated excerpts,
45
+ * wp_trim_words is used instead.
46
+ *
47
+ * To ensure the block's excerptLength setting works correctly for auto-generated
48
+ * excerpts, we temporarily override excerpt_length to 101 (the max block setting)
49
+ * so that wp_trim_excerpt doesn't pre-trim the content before wp_trim_words can
50
+ * apply the user's desired length.
51
+ */
47
52
  $excerpt_length = $attributes['excerptLength'];
48
- $excerpt = get_the_excerpt( $block->context['postId'] );
53
+ add_filter( 'excerpt_length', 'block_core_post_excerpt_excerpt_length', PHP_INT_MAX );
54
+
55
+ $excerpt = get_the_excerpt( $block->context['postId'] );
56
+
57
+ remove_filter( 'excerpt_length', 'block_core_post_excerpt_excerpt_length', PHP_INT_MAX );
58
+
49
59
  if ( isset( $excerpt_length ) ) {
50
60
  $excerpt = wp_trim_words( $excerpt, $excerpt_length );
51
61
  }
@@ -86,18 +96,31 @@ function register_block_core_post_excerpt() {
86
96
  add_action( 'init', 'register_block_core_post_excerpt' );
87
97
 
88
98
  /**
99
+ * Callback for the excerpt_length filter to override the excerpt length.
100
+ *
89
101
  * If themes or plugins filter the excerpt_length, we need to
90
102
  * override the filter in the editor, otherwise
91
103
  * the excerpt length block setting has no effect.
92
- * Returns 100 because 100 is the max length in the setting.
104
+ * Returns 101 (one more than the max block setting of 100) to ensure
105
+ * wp_trim_words can detect when trimming is needed and add the ellipsis.
106
+ *
107
+ * For REST API requests, the filter is added on 'rest_api_init'
108
+ * because REST_REQUEST is not defined until 'parse_request'.
109
+ *
110
+ * @since 7.0.0
111
+ *
112
+ * @return int The excerpt length.
93
113
  */
94
- if ( is_admin() ||
95
- defined( 'REST_REQUEST' ) && REST_REQUEST ) {
96
- add_filter(
97
- 'excerpt_length',
98
- static function () {
99
- return 100;
100
- },
101
- PHP_INT_MAX
102
- );
114
+ function block_core_post_excerpt_excerpt_length() {
115
+ return 101;
103
116
  }
117
+
118
+ if ( is_admin() ) {
119
+ add_filter( 'excerpt_length', 'block_core_post_excerpt_excerpt_length', PHP_INT_MAX );
120
+ }
121
+ add_action(
122
+ 'rest_api_init',
123
+ static function () {
124
+ add_filter( 'excerpt_length', 'block_core_post_excerpt_excerpt_length', PHP_INT_MAX );
125
+ }
126
+ );
package/src/style.scss CHANGED
@@ -72,9 +72,12 @@
72
72
  @use "./spacer/style.scss" as *;
73
73
  @use "./tag-cloud/style.scss" as *;
74
74
  @use "./tab/style.scss" as *;
75
+ @use "./tab-panels/style.scss" as *;
75
76
  @use "./table/style.scss" as *;
76
77
  @use "./table-of-contents/style.scss" as *;
77
78
  @use "./tabs/style.scss" as *;
79
+ @use "./tabs-menu/style.scss" as *;
80
+ @use "./tabs-menu-item/style.scss" as *;
78
81
  @use "./term-count/style.scss" as *;
79
82
  @use "./term-description/style.scss" as *;
80
83
  @use "./term-name/style.scss" as *;
@@ -1,42 +1,67 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
+ import { sprintf, __ } from '@wordpress/i18n';
4
5
  import { createBlock } from '@wordpress/blocks';
5
6
  import {
6
7
  BlockControls,
7
8
  store as blockEditorStore,
8
9
  } from '@wordpress/block-editor';
9
10
  import { ToolbarGroup, ToolbarButton } from '@wordpress/components';
10
- import { __ } from '@wordpress/i18n';
11
- import { useDispatch } from '@wordpress/data';
11
+ import { useDispatch, useSelect } from '@wordpress/data';
12
12
 
13
13
  /**
14
14
  * "Add Tab" button in the block toolbar for the tab block.
15
+ * Inserts new tabs into the tab-panels block.
16
+ *
15
17
  * @param {Object} props
16
- * @param {Object} props.attributes The block attributes.
17
18
  * @param {string} props.tabsClientId The client ID of the parent tabs block.
18
19
  * @return {JSX.Element} The toolbar control element.
19
20
  */
20
- export default function AddTabToolbarControl( { attributes, tabsClientId } ) {
21
+ export default function AddTabToolbarControl( { tabsClientId } ) {
21
22
  const { insertBlock } = useDispatch( blockEditorStore );
22
23
 
23
- const { className, fontFamily, fontSize } = attributes;
24
+ // Find the tab-panels block within the tabs block
25
+ const { tabPanelsClientId, nextTabIndex } = useSelect(
26
+ ( select ) => {
27
+ if ( ! tabsClientId ) {
28
+ return {
29
+ tabPanelsClientId: null,
30
+ nextTabIndex: 0,
31
+ };
32
+ }
33
+ const { getBlocks } = select( blockEditorStore );
34
+ const innerBlocks = getBlocks( tabsClientId );
35
+ const tabPanels = innerBlocks.find(
36
+ ( block ) => block.name === 'core/tab-panels'
37
+ );
38
+ return {
39
+ tabPanelsClientId: tabPanels?.clientId || null,
40
+ nextTabIndex: ( tabPanels?.innerBlocks.length || 0 ) + 1,
41
+ };
42
+ },
43
+ [ tabsClientId ]
44
+ );
24
45
 
25
46
  const addTab = () => {
47
+ if ( ! tabPanelsClientId ) {
48
+ return;
49
+ }
26
50
  const newTabBlock = createBlock( 'core/tab', {
27
- className,
28
- fontFamily,
29
- fontSize,
51
+ anchor: 'tab-' + nextTabIndex,
52
+ /* translators: %d: tab number */
53
+ label: sprintf( __( 'Tab %d' ), nextTabIndex ),
30
54
  } );
31
- insertBlock( newTabBlock, undefined, tabsClientId );
55
+ insertBlock( newTabBlock, undefined, tabPanelsClientId );
56
+ // @TODO: Possible select and focus the tabs-menu-item active tab RichText editor?
32
57
  };
33
58
 
34
59
  return (
35
- <BlockControls group="block">
60
+ <BlockControls group="other">
36
61
  <ToolbarGroup>
37
62
  <ToolbarButton
38
63
  className="components-toolbar__control"
39
- label={ __( 'Add Tab' ) }
64
+ label={ __( 'Add a new tab' ) }
40
65
  onClick={ addTab }
41
66
  showTooltip
42
67
  text={ __( 'Add Tab' ) }
@@ -14,11 +14,25 @@
14
14
  "default": ""
15
15
  }
16
16
  },
17
- "parent": [ "core/tabs" ],
17
+ "parent": [
18
+ "core/tab-panels"
19
+ ],
20
+ "usesContext": [
21
+ "core/tabs-activeTabIndex",
22
+ "core/tabs-editorActiveTabIndex"
23
+ ],
18
24
  "supports": {
19
25
  "anchor": true,
20
26
  "html": false,
21
27
  "reusable": false,
28
+ "color": {
29
+ "background": true,
30
+ "text": true,
31
+ "__experimentalDefaultControls": {
32
+ "background": true,
33
+ "text": true
34
+ }
35
+ },
22
36
  "layout": {
23
37
  "allowSwitching": true,
24
38
  "allowInheriting": false,
@@ -38,9 +52,9 @@
38
52
  "__experimentalDefaultControls": {
39
53
  "fontSize": true,
40
54
  "__experimentalFontFamily": true
41
- },
42
- "__experimentalSkipSerialization": true
43
- }
55
+ }
56
+ },
57
+ "renaming": true
44
58
  },
45
59
  "providesContext": {
46
60
  "core/tab-label": "label"
@@ -14,6 +14,7 @@ import { decodeEntities } from '@wordpress/html-entities';
14
14
  * Internal dependencies
15
15
  */
16
16
  import AddTabToolbarControl from './add-tab-toolbar-control';
17
+ import RemoveTabToolbarControl from './remove-tab-toolbar-control';
17
18
  import slugFromLabel from './slug-from-label';
18
19
 
19
20
  export default function Controls( {
@@ -29,12 +30,10 @@ export default function Controls( {
29
30
 
30
31
  return (
31
32
  <>
32
- <AddTabToolbarControl
33
- tabsClientId={ tabsClientId }
34
- attributes={ attributes }
35
- />
33
+ <AddTabToolbarControl tabsClientId={ tabsClientId } />
34
+ <RemoveTabToolbarControl tabsClientId={ tabsClientId } />
36
35
  <InspectorControls>
37
- <PanelBody title={ __( 'Tab Settings' ) }>
36
+ <PanelBody title={ __( 'Settings' ) }>
38
37
  <TextControl
39
38
  label={ __( 'Tab Label' ) }
40
39
  value={ decodeEntities( label ) }
package/src/tab/edit.js CHANGED
@@ -10,82 +10,44 @@ import { __ } from '@wordpress/i18n';
10
10
  import {
11
11
  useBlockProps,
12
12
  useInnerBlocksProps,
13
- getTypographyClassesAndStyles as useTypographyProps,
14
- __experimentalUseColorProps as useColorProps,
15
13
  store as blockEditorStore,
16
14
  } from '@wordpress/block-editor';
17
15
  import { useSelect, useDispatch } from '@wordpress/data';
18
- import {
19
- useMemo,
20
- useRef,
21
- useEffect,
22
- useCallback,
23
- useState,
24
- } from '@wordpress/element';
16
+ import { useMemo, useRef, useEffect } from '@wordpress/element';
17
+
25
18
  /**
26
19
  * Internal dependencies
27
20
  */
28
21
  import Controls from './controls';
29
22
  import slugFromLabel from './slug-from-label';
30
- import TabsList from './tabs-list';
31
23
 
32
24
  const TEMPLATE = [
33
25
  [
34
26
  'core/paragraph',
35
27
  {
36
- placeholder: __( 'Type / to add a block to tab' ),
28
+ placeholder: __( 'Type / to choose a block' ),
37
29
  },
38
30
  ],
39
31
  ];
40
32
 
41
- const { requestAnimationFrame, cancelAnimationFrame } = window;
33
+ const { cancelAnimationFrame } = window;
42
34
 
43
35
  export default function Edit( {
44
36
  attributes,
45
37
  clientId,
38
+ context,
46
39
  isSelected,
47
40
  setAttributes,
48
41
  __unstableLayoutClassNames: layoutClassNames,
49
42
  } ) {
50
- const { selectBlock } = useDispatch( blockEditorStore );
51
-
52
- const innerBlocksRef = useRef( null );
53
43
  const focusRef = useRef();
54
- const [ isInitialMount, setIsInitialMount ] = useState( true );
55
- const labelElementRef = useRef( null );
56
44
 
57
45
  const { anchor, label } = attributes;
58
46
 
59
- // Callback ref that stores the element and focuses on initial mount.
60
- const labelRef = useCallback(
61
- ( node ) => {
62
- labelElementRef.current = node;
63
- if ( node && isInitialMount ) {
64
- // Focus immediately when ref is set on initial mount.
65
- const animationId = requestAnimationFrame( () => {
66
- if ( node ) {
67
- node.focus();
68
- }
69
- } );
70
- focusRef.current = animationId;
71
- setIsInitialMount( false );
72
- }
73
- },
74
- [ isInitialMount ]
75
- );
76
-
77
- // Focus the label RichText component when no label exists (after initial mount).
78
- useEffect( () => {
79
- if ( ! label && ! isInitialMount && labelElementRef.current ) {
80
- const animationId = requestAnimationFrame( () => {
81
- if ( labelElementRef.current ) {
82
- labelElementRef.current.focus();
83
- }
84
- } );
85
- focusRef.current = animationId;
86
- return () => cancelAnimationFrame( focusRef.current );
87
- }
88
- }, [ label, isInitialMount ] );
47
+ // Consume tab indices from context
48
+ const activeTabIndex = context[ 'core/tabs-activeTabIndex' ] ?? 0;
49
+ const editorActiveTabIndex = context[ 'core/tabs-editorActiveTabIndex' ];
50
+ const effectiveActiveIndex = editorActiveTabIndex ?? activeTabIndex;
89
51
 
90
52
  // Clean up animation frames on unmount.
91
53
  useEffect( () => {
@@ -96,84 +58,85 @@ export default function Edit( {
96
58
  };
97
59
  }, [] );
98
60
 
99
- const {
100
- blockIndex,
101
- hasInnerBlocksSelected,
102
- tabsHasSelectedBlock,
103
- tabsClientId,
104
- tabsAttributes,
105
- forceDisplay,
106
- isTabsClientSelected,
107
- isDefaultTab,
108
- siblingTabs,
109
- } = useSelect(
61
+ const { blockIndex, hasInnerBlocksSelected, tabsClientId } = useSelect(
110
62
  ( select ) => {
111
63
  const {
112
64
  getBlockRootClientId,
113
65
  getBlockIndex,
114
- isBlockSelected,
115
66
  hasSelectedInnerBlock,
116
- getBlockAttributes,
117
- getBlocks,
118
67
  } = select( blockEditorStore );
119
68
 
120
- // Get data from core/tabs.
121
- const rootClientId = getBlockRootClientId( clientId );
122
- const hasTabSelected = hasSelectedInnerBlock( rootClientId, true );
123
- const rootAttributes = getBlockAttributes( rootClientId );
124
- const { activeTabIndex } = rootAttributes;
125
- const _isTabsClientSelected = isBlockSelected( rootClientId );
69
+ // Get the tab-panels parent first
70
+ const tabPanelsClientId = getBlockRootClientId( clientId );
71
+ // Then get the tabs parent
72
+ const _tabsClientId = getBlockRootClientId( tabPanelsClientId );
126
73
 
127
74
  // Get data about this instance of core/tab.
128
75
  const _blockIndex = getBlockIndex( clientId );
129
- const _isDefaultTab = activeTabIndex === _blockIndex;
130
76
  const _hasInnerBlocksSelected = hasSelectedInnerBlock(
131
77
  clientId,
132
78
  true
133
79
  );
134
80
 
135
- // Get all sibling tabs from parent.
136
- const _siblingTabs = getBlocks( rootClientId );
137
-
138
81
  return {
139
82
  blockIndex: _blockIndex,
140
83
  hasInnerBlocksSelected: _hasInnerBlocksSelected,
141
- tabsClientId: rootClientId,
142
- forceDisplay: _isDefaultTab && _isTabsClientSelected,
143
- tabsHasSelectedBlock: hasTabSelected,
144
- isTabsClientSelected: _isTabsClientSelected,
145
- isDefaultTab: _isDefaultTab,
146
- tabsAttributes: rootAttributes,
147
- siblingTabs: _siblingTabs,
84
+ tabsClientId: _tabsClientId,
148
85
  };
149
86
  },
150
87
  [ clientId ]
151
88
  );
152
89
 
90
+ const { updateBlockAttributes, __unstableMarkNextChangeAsNotPersistent } =
91
+ useDispatch( blockEditorStore );
92
+
93
+ // Sync editorActiveTabIndex when this tab is selected directly
94
+ useEffect( () => {
95
+ // Only update if this tab is selected and not already the active index
96
+ const isTabSelected = isSelected || hasInnerBlocksSelected;
97
+ if (
98
+ isTabSelected &&
99
+ tabsClientId &&
100
+ effectiveActiveIndex !== blockIndex
101
+ ) {
102
+ // Mark as non-persistent so it doesn't add to undo history
103
+ __unstableMarkNextChangeAsNotPersistent();
104
+ updateBlockAttributes( tabsClientId, {
105
+ editorActiveTabIndex: blockIndex,
106
+ } );
107
+ }
108
+ }, [
109
+ isSelected,
110
+ hasInnerBlocksSelected,
111
+ tabsClientId,
112
+ effectiveActiveIndex,
113
+ blockIndex,
114
+ updateBlockAttributes,
115
+ __unstableMarkNextChangeAsNotPersistent,
116
+ ] );
117
+
118
+ // Determine if this is the currently active tab (for editor visibility)
119
+ const isActiveTab = effectiveActiveIndex === blockIndex;
120
+
121
+ // Determine if this is the default tab (for the "Default Tab" toggle in controls)
122
+ const isDefaultTab = activeTabIndex === blockIndex;
123
+
153
124
  /**
154
- * This hook determines if the current tab is selected. This is true if it is the active tab, or if it is selected directly.
125
+ * This hook determines if the current tab panel should be visible.
126
+ * This is true if it is the editor active tab, or if it is selected directly.
155
127
  */
156
128
  const isSelectedTab = useMemo( () => {
157
- if ( isSelected || hasInnerBlocksSelected || forceDisplay ) {
129
+ // Show if this tab is directly selected or has selected inner blocks
130
+ if ( isSelected || hasInnerBlocksSelected ) {
158
131
  return true;
159
132
  }
160
- if (
161
- isDefaultTab &&
162
- ! isTabsClientSelected &&
163
- ! isSelected &&
164
- ! tabsHasSelectedBlock
165
- ) {
133
+ // Always show the active tab (at effectiveActiveIndex) regardless of other selection state.
134
+ // This ensures the tab panel remains visible when editing labels in tabs-menu.
135
+ if ( isActiveTab ) {
166
136
  return true;
167
137
  }
168
138
  return false;
169
- }, [
170
- isSelected,
171
- hasInnerBlocksSelected,
172
- forceDisplay,
173
- isDefaultTab,
174
- isTabsClientSelected,
175
- tabsHasSelectedBlock,
176
- ] );
139
+ }, [ isSelected, hasInnerBlocksSelected, isActiveTab ] );
177
140
 
178
141
  // Use a custom anchor, if set. Otherwise fall back to the slug generated from the label text.
179
142
  const tabPanelId = useMemo(
@@ -182,67 +145,29 @@ export default function Edit( {
182
145
  );
183
146
  const tabLabelId = useMemo( () => `${ tabPanelId }--tab`, [ tabPanelId ] );
184
147
 
185
- const tabItemColorProps = useColorProps( tabsAttributes );
186
- const tabContentTypographyProps = useTypographyProps( attributes );
187
-
188
148
  const blockProps = useBlockProps( {
189
149
  hidden: ! isSelectedTab,
150
+ 'aria-labelledby': tabLabelId,
151
+ id: tabPanelId,
152
+ role: 'tabpanel',
153
+ tabIndex: isSelectedTab ? 0 : -1,
154
+ className: clsx( 'wp-block-tab__editor-content', layoutClassNames ),
190
155
  } );
191
156
 
192
- const innerBlocksProps = useInnerBlocksProps(
193
- {
194
- 'aria-labelledby': tabLabelId,
195
- id: tabPanelId,
196
- role: 'tabpanel',
197
- ref: innerBlocksRef,
198
- tabIndex: isSelectedTab ? 0 : -1,
199
- className: clsx(
200
- tabContentTypographyProps.className,
201
- 'tabs__tab-editor-content',
202
- layoutClassNames
203
- ),
204
- style: {
205
- ...tabContentTypographyProps.style,
206
- },
207
- },
208
- {
209
- template: TEMPLATE,
210
- }
211
- );
157
+ const innerBlocksProps = useInnerBlocksProps( blockProps, {
158
+ template: TEMPLATE,
159
+ } );
212
160
 
213
161
  return (
214
- <>
215
- <div { ...blockProps }>
216
- <Controls
217
- attributes={ attributes }
218
- setAttributes={ setAttributes }
219
- tabsClientId={ tabsClientId }
220
- blockIndex={ blockIndex }
221
- isDefaultTab={ isDefaultTab }
222
- />
223
- { isSelectedTab && (
224
- <>
225
- <TabsList
226
- siblingTabs={ siblingTabs }
227
- currentClientId={ clientId }
228
- currentBlockIndex={ blockIndex }
229
- currentLabel={ label }
230
- tabItemColorProps={ tabItemColorProps }
231
- onSelectTab={ selectBlock }
232
- onLabelChange={ ( value ) =>
233
- setAttributes( {
234
- label: value,
235
- anchor: slugFromLabel( value, blockIndex ),
236
- } )
237
- }
238
- labelRef={ labelRef }
239
- focusRef={ focusRef }
240
- labelElementRef={ labelElementRef }
241
- />
242
- <section { ...innerBlocksProps } />
243
- </>
244
- ) }
245
- </div>
246
- </>
162
+ <section { ...innerBlocksProps }>
163
+ <Controls
164
+ attributes={ attributes }
165
+ setAttributes={ setAttributes }
166
+ tabsClientId={ tabsClientId }
167
+ blockIndex={ blockIndex }
168
+ isDefaultTab={ isDefaultTab }
169
+ />
170
+ { isSelectedTab && innerBlocksProps.children }
171
+ </section>
247
172
  );
248
173
  }
package/src/tab/index.php CHANGED
@@ -5,55 +5,6 @@
5
5
  * @package WordPress
6
6
  */
7
7
 
8
- /**
9
- * Build typography classnames from named size/family.
10
- *
11
- * @param array $attributes Block attributes.
12
- * @return string Classnames.
13
- */
14
- function block_core_tab_get_typography_classes( array $attributes ): string {
15
- $typography_classes = array();
16
- $has_named_font_family = ! empty( $attributes['fontFamily'] );
17
- $has_named_font_size = ! empty( $attributes['fontSize'] );
18
-
19
- if ( $has_named_font_size ) {
20
- $typography_classes[] = sprintf( 'has-%s-font-size', esc_attr( (string) $attributes['fontSize'] ) );
21
- }
22
-
23
- if ( $has_named_font_family ) {
24
- $typography_classes[] = sprintf( 'has-%s-font-family', esc_attr( (string) $attributes['fontFamily'] ) );
25
- }
26
-
27
- return implode( ' ', $typography_classes );
28
- }
29
-
30
- /**
31
- * Build inline typography styles.
32
- *
33
- * @param array $attributes Block attributes.
34
- * @return string Inline CSS.
35
- */
36
- function block_core_tab_get_typography_styles( array $attributes ): string {
37
- $typography_styles = array();
38
-
39
- if ( ! empty( $attributes['style']['typography']['fontSize'] ) ) {
40
- $typography_styles[] = sprintf(
41
- 'font-size: %s;',
42
- wp_get_typography_font_size_value(
43
- array(
44
- 'size' => $attributes['style']['typography']['fontSize'],
45
- )
46
- )
47
- );
48
- }
49
-
50
- if ( ! empty( $attributes['style']['typography']['fontFamily'] ) ) {
51
- $typography_styles[] = sprintf( 'font-family: %s;', $attributes['style']['typography']['fontFamily'] );
52
- }
53
-
54
- return implode( '', $typography_styles );
55
- }
56
-
57
8
  /**
58
9
  * Render callback for core/tab.
59
10
  *
@@ -66,6 +17,11 @@ function block_core_tab_render( array $attributes, string $content ): string {
66
17
  $tag_processor = new WP_HTML_Tag_Processor( $content );
67
18
  $tag_processor->next_tag( array( 'class_name' => 'wp-block-tab' ) );
68
19
  $tab_id = (string) $tag_processor->get_attribute( 'id' );
20
+ // If no id, generate a unique one
21
+ if ( empty( $tab_id ) ) {
22
+ $tab_id = sanitize_title( $attributes['label'] );
23
+ $tag_processor->set_attribute( 'id', $tab_id );
24
+ }
69
25
 
70
26
  /**
71
27
  * Add interactivity to the tab element.
@@ -85,13 +41,6 @@ function block_core_tab_render( array $attributes, string $content ): string {
85
41
  )
86
42
  );
87
43
 
88
- /**
89
- * Process style classnames.
90
- */
91
- $classname = (string) $tag_processor->get_attribute( 'class' );
92
- $classname .= ' ' . block_core_tab_get_typography_classes( $attributes );
93
- $tag_processor->set_attribute( 'class', $classname );
94
-
95
44
  /**
96
45
  * Process accessibility and interactivity attributes.
97
46
  */
@@ -100,13 +49,6 @@ function block_core_tab_render( array $attributes, string $content ): string {
100
49
  $tag_processor->set_attribute( 'data-wp-bind--hidden', '!state.isActiveTab' );
101
50
  $tag_processor->set_attribute( 'data-wp-bind--tabindex', 'state.tabIndexAttribute' );
102
51
 
103
- /**
104
- * Process style attribute.
105
- */
106
- $style = (string) $tag_processor->get_attribute( 'style' );
107
- $style .= block_core_tab_get_typography_styles( $attributes );
108
- $tag_processor->set_attribute( 'style', $style );
109
-
110
52
  return (string) $tag_processor->get_updated_html();
111
53
  }
112
54