@wordpress/block-library 9.44.1-next.v.202604201441.0 → 9.45.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 (315) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/build/accordion/edit.cjs +0 -2
  3. package/build/accordion/edit.cjs.map +2 -2
  4. package/build/accordion-item/block.json +1 -0
  5. package/build/categories/edit.cjs +5 -1
  6. package/build/categories/edit.cjs.map +2 -2
  7. package/build/embed/edit.cjs +38 -34
  8. package/build/embed/edit.cjs.map +3 -3
  9. package/build/embed/transforms.cjs +3 -1
  10. package/build/embed/transforms.cjs.map +2 -2
  11. package/build/embed/util.cjs +13 -2
  12. package/build/embed/util.cjs.map +2 -2
  13. package/build/form/block.json +1 -1
  14. package/build/form-input/block.json +1 -1
  15. package/build/form-submission-notification/block.json +1 -1
  16. package/build/form-submit-button/block.json +1 -1
  17. package/build/image/edit.cjs +1 -1
  18. package/build/image/edit.cjs.map +2 -2
  19. package/build/image/image.cjs +29 -10
  20. package/build/image/image.cjs.map +3 -3
  21. package/build/index.cjs +4 -4
  22. package/build/index.cjs.map +2 -2
  23. package/build/math/edit.cjs +2 -2
  24. package/build/math/edit.cjs.map +2 -2
  25. package/build/navigation/edit/accessible-description.cjs +2 -2
  26. package/build/navigation/edit/accessible-description.cjs.map +2 -2
  27. package/build/navigation/edit/overlay-template-part-selector.cjs.map +2 -2
  28. package/build/navigation-link/edit.cjs +2 -1
  29. package/build/navigation-link/edit.cjs.map +2 -2
  30. package/build/navigation-link/link-ui/dialog-wrapper.cjs +2 -1
  31. package/build/navigation-link/link-ui/dialog-wrapper.cjs.map +2 -2
  32. package/build/navigation-link/link-ui/index.cjs +2 -1
  33. package/build/navigation-link/link-ui/index.cjs.map +2 -2
  34. package/build/post-author/edit.cjs.map +3 -3
  35. package/build/post-comments-form/edit.cjs +2 -2
  36. package/build/post-comments-form/edit.cjs.map +2 -2
  37. package/build/query/edit/inspector-controls/author-control.cjs +1 -1
  38. package/build/query/edit/inspector-controls/author-control.cjs.map +2 -2
  39. package/build/query/edit/inspector-controls/format-controls.cjs +1 -1
  40. package/build/query/edit/inspector-controls/format-controls.cjs.map +2 -2
  41. package/build/query/edit/inspector-controls/parent-control.cjs +1 -1
  42. package/build/query/edit/inspector-controls/parent-control.cjs.map +2 -2
  43. package/build/query/edit/inspector-controls/taxonomy-controls.cjs +1 -1
  44. package/build/query/edit/inspector-controls/taxonomy-controls.cjs.map +2 -2
  45. package/build/site-logo/edit.cjs +32 -18
  46. package/build/site-logo/edit.cjs.map +2 -2
  47. package/build/tab/block.json +23 -23
  48. package/build/tab/controls.cjs +5 -48
  49. package/build/tab/controls.cjs.map +3 -3
  50. package/build/tab/edit.cjs +77 -75
  51. package/build/tab/edit.cjs.map +3 -3
  52. package/build/tab/save.cjs +3 -3
  53. package/build/tab/save.cjs.map +2 -2
  54. package/{src/tabs-menu → build/tab-list}/block.json +3 -3
  55. package/build/{tabs-menu → tab-list}/edit.cjs +4 -4
  56. package/build/tab-list/edit.cjs.map +7 -0
  57. package/build/{tabs-menu → tab-list}/index.cjs +5 -5
  58. package/build/tab-list/index.cjs.map +7 -0
  59. package/build/{tabs-menu → tab-list}/save.cjs +1 -1
  60. package/build/{tabs-menu → tab-list}/save.cjs.map +1 -1
  61. package/build/{tab → tab-panel}/add-tab-toolbar-control.cjs +16 -16
  62. package/build/tab-panel/add-tab-toolbar-control.cjs.map +7 -0
  63. package/build/tab-panel/block.json +27 -37
  64. package/build/tab-panel/controls.cjs +89 -0
  65. package/build/tab-panel/controls.cjs.map +7 -0
  66. package/build/tab-panel/edit.cjs +90 -17
  67. package/build/tab-panel/edit.cjs.map +3 -3
  68. package/build/tab-panel/index.cjs +1 -1
  69. package/build/tab-panel/index.cjs.map +1 -1
  70. package/build/{tab → tab-panel}/init.cjs +1 -1
  71. package/build/{tab → tab-panel}/init.cjs.map +1 -1
  72. package/build/{tab → tab-panel}/remove-tab-toolbar-control.cjs +16 -16
  73. package/build/tab-panel/remove-tab-toolbar-control.cjs.map +7 -0
  74. package/build/tab-panel/save.cjs +4 -2
  75. package/build/tab-panel/save.cjs.map +2 -2
  76. package/build/tab-panels/block.json +66 -0
  77. package/build/{tabs-menu-item/controls.cjs → tab-panels/edit.cjs} +25 -11
  78. package/build/tab-panels/edit.cjs.map +7 -0
  79. package/build/{tabs-menu-item → tab-panels}/index.cjs +5 -5
  80. package/build/{tabs-menu → tab-panels}/index.cjs.map +2 -2
  81. package/build/{tabs-menu-item → tab-panels}/save.cjs +4 -6
  82. package/build/tab-panels/save.cjs.map +7 -0
  83. package/build/tabs/block.json +1 -1
  84. package/build/tabs/controls.cjs +2 -2
  85. package/build/tabs/controls.cjs.map +1 -1
  86. package/build/tabs/edit.cjs +24 -19
  87. package/build/tabs/edit.cjs.map +3 -3
  88. package/build/tabs/index.cjs +5 -5
  89. package/build/tabs/index.cjs.map +1 -1
  90. package/build/tabs/{use-tab-menu-sync.cjs → use-tab-list-sync.cjs} +78 -80
  91. package/build/tabs/use-tab-list-sync.cjs.map +7 -0
  92. package/build/terms-query/edit/inspector-controls/include-control.cjs +1 -1
  93. package/build/terms-query/edit/inspector-controls/include-control.cjs.map +2 -2
  94. package/build/video/tracks-editor.cjs +2 -2
  95. package/build/video/tracks-editor.cjs.map +2 -2
  96. package/build-module/accordion/edit.mjs +0 -2
  97. package/build-module/accordion/edit.mjs.map +2 -2
  98. package/build-module/accordion-item/block.json +1 -0
  99. package/build-module/categories/edit.mjs +5 -2
  100. package/build-module/categories/edit.mjs.map +2 -2
  101. package/build-module/embed/edit.mjs +45 -36
  102. package/build-module/embed/edit.mjs.map +2 -2
  103. package/build-module/embed/transforms.mjs +8 -2
  104. package/build-module/embed/transforms.mjs.map +2 -2
  105. package/build-module/embed/util.mjs +11 -1
  106. package/build-module/embed/util.mjs.map +2 -2
  107. package/build-module/form/block.json +1 -1
  108. package/build-module/form-input/block.json +1 -1
  109. package/build-module/form-submission-notification/block.json +1 -1
  110. package/build-module/form-submit-button/block.json +1 -1
  111. package/build-module/image/edit.mjs +1 -1
  112. package/build-module/image/edit.mjs.map +2 -2
  113. package/build-module/image/image.mjs +29 -10
  114. package/build-module/image/image.mjs.map +3 -3
  115. package/build-module/index.mjs +4 -4
  116. package/build-module/index.mjs.map +2 -2
  117. package/build-module/math/edit.mjs +2 -2
  118. package/build-module/math/edit.mjs.map +2 -2
  119. package/build-module/navigation/edit/accessible-description.mjs +1 -1
  120. package/build-module/navigation/edit/accessible-description.mjs.map +1 -1
  121. package/build-module/navigation/edit/overlay-template-part-selector.mjs +2 -2
  122. package/build-module/navigation/edit/overlay-template-part-selector.mjs.map +1 -1
  123. package/build-module/navigation-link/edit.mjs +2 -5
  124. package/build-module/navigation-link/edit.mjs.map +2 -2
  125. package/build-module/navigation-link/link-ui/dialog-wrapper.mjs +2 -1
  126. package/build-module/navigation-link/link-ui/dialog-wrapper.mjs.map +2 -2
  127. package/build-module/navigation-link/link-ui/index.mjs +1 -1
  128. package/build-module/navigation-link/link-ui/index.mjs.map +2 -2
  129. package/build-module/post-author/edit.mjs +2 -2
  130. package/build-module/post-author/edit.mjs.map +2 -2
  131. package/build-module/post-comments-form/edit.mjs +1 -1
  132. package/build-module/post-comments-form/edit.mjs.map +2 -2
  133. package/build-module/query/edit/inspector-controls/author-control.mjs +1 -1
  134. package/build-module/query/edit/inspector-controls/author-control.mjs.map +2 -2
  135. package/build-module/query/edit/inspector-controls/format-controls.mjs +1 -1
  136. package/build-module/query/edit/inspector-controls/format-controls.mjs.map +2 -2
  137. package/build-module/query/edit/inspector-controls/parent-control.mjs +1 -1
  138. package/build-module/query/edit/inspector-controls/parent-control.mjs.map +2 -2
  139. package/build-module/query/edit/inspector-controls/taxonomy-controls.mjs +1 -1
  140. package/build-module/query/edit/inspector-controls/taxonomy-controls.mjs.map +2 -2
  141. package/build-module/site-logo/edit.mjs +32 -18
  142. package/build-module/site-logo/edit.mjs.map +2 -2
  143. package/build-module/tab/block.json +23 -23
  144. package/build-module/tab/controls.mjs +7 -57
  145. package/build-module/tab/controls.mjs.map +2 -2
  146. package/build-module/tab/edit.mjs +81 -79
  147. package/build-module/tab/edit.mjs.map +3 -3
  148. package/build-module/tab/save.mjs +4 -4
  149. package/build-module/tab/save.mjs.map +2 -2
  150. package/build-module/{tabs-menu → tab-list}/block.json +3 -3
  151. package/build-module/{tabs-menu → tab-list}/edit.mjs +4 -4
  152. package/build-module/tab-list/edit.mjs.map +7 -0
  153. package/build-module/{tabs-menu → tab-list}/index.mjs +2 -2
  154. package/build-module/tab-list/index.mjs.map +7 -0
  155. package/build-module/{tabs-menu → tab-list}/save.mjs +1 -1
  156. package/build-module/{tabs-menu → tab-list}/save.mjs.map +1 -1
  157. package/build-module/{tab → tab-panel}/add-tab-toolbar-control.mjs +16 -16
  158. package/build-module/tab-panel/add-tab-toolbar-control.mjs.map +7 -0
  159. package/build-module/tab-panel/block.json +27 -37
  160. package/build-module/tab-panel/controls.mjs +65 -0
  161. package/build-module/tab-panel/controls.mjs.map +7 -0
  162. package/build-module/tab-panel/edit.mjs +92 -19
  163. package/build-module/tab-panel/edit.mjs.map +2 -2
  164. package/build-module/tab-panel/index.mjs +1 -1
  165. package/build-module/tab-panel/index.mjs.map +1 -1
  166. package/build-module/{tab → tab-panel}/init.mjs +1 -1
  167. package/build-module/{tab → tab-panel}/init.mjs.map +1 -1
  168. package/build-module/{tab → tab-panel}/remove-tab-toolbar-control.mjs +16 -16
  169. package/build-module/tab-panel/remove-tab-toolbar-control.mjs.map +7 -0
  170. package/build-module/tab-panel/save.mjs +4 -2
  171. package/build-module/tab-panel/save.mjs.map +2 -2
  172. package/build-module/tab-panels/block.json +66 -0
  173. package/build-module/tab-panels/edit.mjs +33 -0
  174. package/build-module/tab-panels/edit.mjs.map +7 -0
  175. package/build-module/{tabs-menu-item → tab-panels}/index.mjs +2 -2
  176. package/build-module/{tabs-menu → tab-panels}/index.mjs.map +2 -2
  177. package/build-module/tab-panels/save.mjs +12 -0
  178. package/build-module/tab-panels/save.mjs.map +7 -0
  179. package/build-module/tabs/block.json +1 -1
  180. package/build-module/tabs/controls.mjs +2 -2
  181. package/build-module/tabs/controls.mjs.map +1 -1
  182. package/build-module/tabs/edit.mjs +24 -19
  183. package/build-module/tabs/edit.mjs.map +2 -2
  184. package/build-module/tabs/index.mjs +5 -5
  185. package/build-module/tabs/index.mjs.map +1 -1
  186. package/build-module/tabs/use-tab-list-sync.mjs +169 -0
  187. package/build-module/tabs/use-tab-list-sync.mjs.map +7 -0
  188. package/build-module/terms-query/edit/inspector-controls/include-control.mjs +1 -1
  189. package/build-module/terms-query/edit/inspector-controls/include-control.mjs.map +2 -2
  190. package/build-module/video/tracks-editor.mjs +2 -2
  191. package/build-module/video/tracks-editor.mjs.map +2 -2
  192. package/build-style/classic-rtl.css +14 -0
  193. package/build-style/classic.css +14 -0
  194. package/build-style/editor-rtl.css +9 -5
  195. package/build-style/editor.css +9 -5
  196. package/build-style/style-rtl.css +40 -40
  197. package/build-style/style.css +40 -40
  198. package/build-style/tab/editor-rtl.css +11 -0
  199. package/build-style/tab/editor.css +11 -0
  200. package/build-style/tab/style-rtl.css +29 -16
  201. package/build-style/tab/style.css +29 -16
  202. package/build-style/tab-list/editor-rtl.css +6 -0
  203. package/build-style/tab-list/editor.css +6 -0
  204. package/build-style/tab-panel/style-rtl.css +17 -1
  205. package/build-style/tab-panel/style.css +17 -1
  206. package/build-style/tab-panels/style-rtl.css +4 -0
  207. package/build-style/tab-panels/style.css +4 -0
  208. package/build-style/video/editor-rtl.css +4 -0
  209. package/build-style/video/editor.css +4 -0
  210. package/package.json +39 -38
  211. package/src/accordion/edit.js +0 -2
  212. package/src/accordion-item/block.json +1 -0
  213. package/src/categories/edit.js +3 -2
  214. package/src/classic.scss +25 -0
  215. package/src/editor.scss +2 -2
  216. package/src/embed/edit.js +61 -52
  217. package/src/embed/edit.native.js +71 -57
  218. package/src/embed/transforms.js +8 -2
  219. package/src/embed/util.js +17 -0
  220. package/src/form/block.json +1 -1
  221. package/src/form-input/block.json +1 -1
  222. package/src/form-submission-notification/block.json +1 -1
  223. package/src/form-submit-button/block.json +1 -1
  224. package/src/image/edit.js +5 -1
  225. package/src/image/edit.native.js +3 -3
  226. package/src/image/image.js +30 -5
  227. package/src/index.js +4 -4
  228. package/src/math/edit.js +3 -3
  229. package/src/navigation/edit/accessible-description.js +1 -1
  230. package/src/navigation/edit/overlay-template-part-selector.js +3 -3
  231. package/src/navigation-link/edit.js +2 -5
  232. package/src/navigation-link/link-ui/dialog-wrapper.js +2 -1
  233. package/src/navigation-link/link-ui/index.js +1 -1
  234. package/src/post-author/edit.js +3 -5
  235. package/src/post-comments-form/edit.js +1 -1
  236. package/src/query/edit/inspector-controls/author-control.js +1 -1
  237. package/src/query/edit/inspector-controls/format-controls.js +1 -1
  238. package/src/query/edit/inspector-controls/parent-control.js +1 -1
  239. package/src/query/edit/inspector-controls/taxonomy-controls.js +1 -1
  240. package/src/site-logo/edit.js +38 -18
  241. package/src/style.scss +1 -1
  242. package/src/tab/block.json +23 -23
  243. package/src/tab/controls.js +6 -52
  244. package/src/tab/edit.js +99 -103
  245. package/src/{tabs-menu-item → tab}/editor.scss +3 -3
  246. package/src/tab/index.php +32 -51
  247. package/src/tab/save.js +4 -4
  248. package/src/tab/style.scss +34 -17
  249. package/{build/tabs-menu → src/tab-list}/block.json +3 -3
  250. package/src/{tabs-menu → tab-list}/edit.js +3 -3
  251. package/src/{tabs-menu → tab-list}/editor.scss +2 -2
  252. package/src/{tabs-menu → tab-list}/index.js +1 -1
  253. package/src/tab-list/index.php +80 -0
  254. package/src/{tab → tab-panel}/add-tab-toolbar-control.js +19 -19
  255. package/src/tab-panel/block.json +27 -37
  256. package/src/tab-panel/controls.js +65 -0
  257. package/src/tab-panel/edit.js +123 -20
  258. package/src/tab-panel/index.js +1 -1
  259. package/src/tab-panel/index.php +88 -0
  260. package/src/{tab → tab-panel}/remove-tab-toolbar-control.js +20 -19
  261. package/src/tab-panel/save.js +4 -2
  262. package/src/tab-panel/style.scss +20 -1
  263. package/src/tab-panels/block.json +66 -0
  264. package/src/tab-panels/edit.js +42 -0
  265. package/src/{tabs-menu-item → tab-panels}/index.js +1 -1
  266. package/src/tab-panels/save.js +11 -0
  267. package/src/tab-panels/style.scss +4 -0
  268. package/src/tabs/block.json +1 -1
  269. package/src/tabs/controls.js +2 -2
  270. package/src/tabs/edit.js +25 -20
  271. package/src/tabs/index.js +5 -5
  272. package/src/tabs/index.php +5 -5
  273. package/src/tabs/use-tab-list-sync.js +237 -0
  274. package/src/terms-query/edit/inspector-controls/include-control.js +1 -1
  275. package/src/video/editor.scss +5 -0
  276. package/src/video/tracks-editor.js +2 -2
  277. package/build/tab/add-tab-toolbar-control.cjs.map +0 -7
  278. package/build/tab/remove-tab-toolbar-control.cjs.map +0 -7
  279. package/build/tabs/use-tab-menu-sync.cjs.map +0 -7
  280. package/build/tabs-menu/edit.cjs.map +0 -7
  281. package/build/tabs-menu-item/block.json +0 -56
  282. package/build/tabs-menu-item/controls.cjs.map +0 -7
  283. package/build/tabs-menu-item/edit.cjs +0 -135
  284. package/build/tabs-menu-item/edit.cjs.map +0 -7
  285. package/build/tabs-menu-item/index.cjs.map +0 -7
  286. package/build/tabs-menu-item/save.cjs.map +0 -7
  287. package/build-module/tab/add-tab-toolbar-control.mjs.map +0 -7
  288. package/build-module/tab/remove-tab-toolbar-control.mjs.map +0 -7
  289. package/build-module/tabs/use-tab-menu-sync.mjs +0 -171
  290. package/build-module/tabs/use-tab-menu-sync.mjs.map +0 -7
  291. package/build-module/tabs-menu/edit.mjs.map +0 -7
  292. package/build-module/tabs-menu-item/block.json +0 -56
  293. package/build-module/tabs-menu-item/controls.mjs +0 -15
  294. package/build-module/tabs-menu-item/controls.mjs.map +0 -7
  295. package/build-module/tabs-menu-item/edit.mjs +0 -108
  296. package/build-module/tabs-menu-item/edit.mjs.map +0 -7
  297. package/build-module/tabs-menu-item/index.mjs.map +0 -7
  298. package/build-module/tabs-menu-item/save.mjs +0 -14
  299. package/build-module/tabs-menu-item/save.mjs.map +0 -7
  300. package/build-style/tabs-menu/editor-rtl.css +0 -6
  301. package/build-style/tabs-menu/editor.css +0 -6
  302. package/build-style/tabs-menu-item/editor-rtl.css +0 -11
  303. package/build-style/tabs-menu-item/editor.css +0 -11
  304. package/build-style/tabs-menu-item/style-rtl.css +0 -33
  305. package/build-style/tabs-menu-item/style.css +0 -33
  306. package/src/tabs/use-tab-menu-sync.js +0 -239
  307. package/src/tabs-menu/index.php +0 -80
  308. package/src/tabs-menu-item/block.json +0 -56
  309. package/src/tabs-menu-item/controls.js +0 -19
  310. package/src/tabs-menu-item/edit.js +0 -141
  311. package/src/tabs-menu-item/index.php +0 -70
  312. package/src/tabs-menu-item/save.js +0 -13
  313. package/src/tabs-menu-item/style.scss +0 -40
  314. /package/src/{tabs-menu → tab-list}/save.js +0 -0
  315. /package/src/{tab → tab-panel}/init.js +0 -0
@@ -1,42 +1,145 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
+ import { __ } from '@wordpress/i18n';
4
5
  import {
5
6
  useBlockProps,
6
7
  useInnerBlocksProps,
7
8
  store as blockEditorStore,
8
9
  } from '@wordpress/block-editor';
9
- import { useSelect } from '@wordpress/data';
10
+ import { useSelect, useDispatch } from '@wordpress/data';
11
+ import { useMemo, useRef, useEffect } from '@wordpress/element';
10
12
 
11
13
  /**
12
14
  * Internal dependencies
13
15
  */
14
- import AddTabToolbarControl from '../tab/add-tab-toolbar-control';
15
- import RemoveTabToolbarControl from '../tab/remove-tab-toolbar-control';
16
+ import Controls from './controls';
16
17
 
17
- const TAB_PANELS_TEMPLATE = [ [ 'core/tab', {} ] ];
18
+ const TEMPLATE = [
19
+ [
20
+ 'core/paragraph',
21
+ {
22
+ placeholder: __( 'Type / to choose a block' ),
23
+ },
24
+ ],
25
+ ];
18
26
 
19
- export default function Edit( { clientId } ) {
20
- const blockProps = useBlockProps();
27
+ const { cancelAnimationFrame } = window;
21
28
 
22
- const innerBlocksProps = useInnerBlocksProps( blockProps, {
23
- template: TAB_PANELS_TEMPLATE,
24
- templateLock: false,
25
- renderAppender: false, // Appender handled by individual tab blocks
26
- } );
29
+ export default function Edit( { clientId, context, isSelected } ) {
30
+ const focusRef = useRef();
31
+
32
+ // Consume tab indices from context
33
+ const activeTabIndex = context[ 'core/tabs-activeTabIndex' ];
34
+ const editorActiveTabIndex = context[ 'core/tabs-editorActiveTabIndex' ];
35
+ const effectiveActiveIndex = editorActiveTabIndex ?? activeTabIndex;
36
+
37
+ // Clean up animation frames on unmount.
38
+ useEffect( () => {
39
+ return () => {
40
+ if ( focusRef.current ) {
41
+ cancelAnimationFrame( focusRef.current );
42
+ }
43
+ };
44
+ }, [] );
45
+
46
+ const { blockIndex, hasInnerBlocksSelected, tabsClientId } = useSelect(
47
+ ( select ) => {
48
+ const {
49
+ getBlockRootClientId,
50
+ getBlockIndex,
51
+ hasSelectedInnerBlock,
52
+ } = select( blockEditorStore );
27
53
 
28
- // Get the parent tabs block clientId
29
- const tabsClientId = useSelect(
30
- ( select ) =>
31
- select( blockEditorStore ).getBlockRootClientId( clientId ),
54
+ // Get the tab-panel parent first
55
+ const tabPanelsClientId = getBlockRootClientId( clientId );
56
+ // Then get the tabs parent
57
+ const _tabsClientId = getBlockRootClientId( tabPanelsClientId );
58
+
59
+ // Get data about this instance of core/tab.
60
+ const _blockIndex = getBlockIndex( clientId );
61
+ const _hasInnerBlocksSelected = hasSelectedInnerBlock(
62
+ clientId,
63
+ true
64
+ );
65
+
66
+ return {
67
+ blockIndex: _blockIndex,
68
+ hasInnerBlocksSelected: _hasInnerBlocksSelected,
69
+ tabsClientId: _tabsClientId,
70
+ };
71
+ },
32
72
  [ clientId ]
33
73
  );
34
74
 
75
+ const { updateBlockAttributes, __unstableMarkNextChangeAsNotPersistent } =
76
+ useDispatch( blockEditorStore );
77
+
78
+ // Sync editorActiveTabIndex when this tab is selected directly
79
+ useEffect( () => {
80
+ // Only update if this tab is selected and not already the active index
81
+ const isTabSelected = isSelected || hasInnerBlocksSelected;
82
+ if (
83
+ isTabSelected &&
84
+ tabsClientId &&
85
+ effectiveActiveIndex !== blockIndex
86
+ ) {
87
+ // Mark as non-persistent so it doesn't add to undo history
88
+ __unstableMarkNextChangeAsNotPersistent();
89
+ updateBlockAttributes( tabsClientId, {
90
+ editorActiveTabIndex: blockIndex,
91
+ } );
92
+ }
93
+ }, [
94
+ isSelected,
95
+ hasInnerBlocksSelected,
96
+ tabsClientId,
97
+ effectiveActiveIndex,
98
+ blockIndex,
99
+ updateBlockAttributes,
100
+ __unstableMarkNextChangeAsNotPersistent,
101
+ ] );
102
+
103
+ // Determine if this is the currently active tab (for editor visibility)
104
+ const isActiveTab = effectiveActiveIndex === blockIndex;
105
+
106
+ // Determine if this is the default tab (for the "Default Tab" toggle in controls)
107
+ const isDefaultTab = activeTabIndex === blockIndex;
108
+
109
+ /**
110
+ * This hook determines if the current tab panel should be visible.
111
+ * This is true if it is the editor active tab, or if it is selected directly.
112
+ */
113
+ const isSelectedTab = useMemo( () => {
114
+ // Show if this tab is directly selected or has selected inner blocks
115
+ if ( isSelected || hasInnerBlocksSelected ) {
116
+ return true;
117
+ }
118
+ // Always show the active tab (at effectiveActiveIndex) regardless of other selection state.
119
+ // This ensures the tab panel remains visible when editing labels in tab-list.
120
+ if ( isActiveTab ) {
121
+ return true;
122
+ }
123
+ return false;
124
+ }, [ isSelected, hasInnerBlocksSelected, isActiveTab ] );
125
+
126
+ const blockProps = useBlockProps( {
127
+ hidden: ! isSelectedTab,
128
+ tabIndex: isSelectedTab ? 0 : -1,
129
+ } );
130
+
131
+ const innerBlocksProps = useInnerBlocksProps( blockProps, {
132
+ template: TEMPLATE,
133
+ } );
134
+
35
135
  return (
36
- <>
37
- <AddTabToolbarControl tabsClientId={ tabsClientId } />
38
- <RemoveTabToolbarControl tabsClientId={ tabsClientId } />
39
- <div { ...innerBlocksProps } />
40
- </>
136
+ <section { ...innerBlocksProps }>
137
+ <Controls
138
+ tabsClientId={ tabsClientId }
139
+ blockIndex={ blockIndex }
140
+ isDefaultTab={ isDefaultTab }
141
+ />
142
+ { isSelectedTab && innerBlocksProps.children }
143
+ </section>
41
144
  );
42
145
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { contents as icon } from '@wordpress/icons';
4
+ import { tabPanel as icon } from '@wordpress/icons';
5
5
 
6
6
  /**
7
7
  * Internal dependencies
@@ -0,0 +1,88 @@
1
+ <?php
2
+ /**
3
+ * Tab Panel Block
4
+ *
5
+ * @package WordPress
6
+ */
7
+
8
+ /**
9
+ * Render callback for core/tab-panel.
10
+ *
11
+ * @since 7.0.0
12
+ *
13
+ * @param array $attributes Block attributes.
14
+ * @param string $content Block content.
15
+ * @param \WP_Block $block Block instance.
16
+ *
17
+ * @return string Updated HTML.
18
+ */
19
+ function block_core_tab_panel_render( array $attributes, string $content, \WP_Block $block ): string {
20
+ $tabs_id = $block->context['core/tabs-id'] ?? '';
21
+
22
+ static $tab_counters = array();
23
+
24
+ if ( ! isset( $tab_counters[ $tabs_id ] ) ) {
25
+ $tab_counters[ $tabs_id ] = 0;
26
+ }
27
+
28
+ $tab_index = $tab_counters[ $tabs_id ];
29
+ ++$tab_counters[ $tabs_id ];
30
+
31
+ $tag_processor = new WP_HTML_Tag_Processor( $content );
32
+ $tag_processor->next_tag( array( 'class_name' => 'wp-block-tab-panel' ) );
33
+
34
+ // Use the user's custom anchor if present, otherwise fall back to
35
+ // the generated position-based ID.
36
+ $tab_id = (string) $tag_processor->get_attribute( 'id' );
37
+ if ( empty( $tab_id ) ) {
38
+ $tab_id = ! empty( $tabs_id )
39
+ ? $tabs_id . '-tab-' . $tab_index
40
+ : 'tab-' . $tab_index;
41
+ $tag_processor->set_attribute( 'id', $tab_id );
42
+ }
43
+
44
+ /**
45
+ * Add interactivity to the tab element.
46
+ */
47
+ $tag_processor->set_attribute(
48
+ 'data-wp-interactive',
49
+ 'core/tabs/private'
50
+ );
51
+ $tag_processor->set_attribute(
52
+ 'data-wp-context',
53
+ wp_json_encode(
54
+ array(
55
+ 'tab' => array(
56
+ 'id' => $tab_id,
57
+ ),
58
+ )
59
+ )
60
+ );
61
+
62
+ /**
63
+ * Process accessibility and interactivity attributes.
64
+ */
65
+ $tag_processor->set_attribute( 'role', 'tabpanel' );
66
+ $tag_processor->set_attribute( 'aria-labelledby', 'tab__' . $tab_id );
67
+ $tag_processor->set_attribute( 'data-wp-bind--hidden', '!state.isActiveTab' );
68
+ $tag_processor->set_attribute( 'tabindex', 0 );
69
+
70
+ return (string) $tag_processor->get_updated_html();
71
+ }
72
+
73
+ /**
74
+ * Registers the `core/tab-panel` block on the server.
75
+ *
76
+ * @hook init
77
+ *
78
+ * @since 7.0.0
79
+ */
80
+ function register_block_core_tab_panel() {
81
+ register_block_type_from_metadata(
82
+ __DIR__ . '/tab-panel',
83
+ array(
84
+ 'render_callback' => 'block_core_tab_panel_render',
85
+ )
86
+ );
87
+ }
88
+ add_action( 'init', 'register_block_core_tab_panel' );
@@ -10,9 +10,9 @@ import { __ } from '@wordpress/i18n';
10
10
  import { useDispatch, useSelect } from '@wordpress/data';
11
11
 
12
12
  /**
13
- * "Remove Tab" button in the block toolbar for the tab block.
14
- * Removes the currently active core/tab and its corresponding
15
- * core/tabs-menu-item, keeping both in sync.
13
+ * "Remove Tab" button in the block toolbar for the tabs block.
14
+ * Removes the currently active core/tab-panel and its corresponding
15
+ * core/tab, keeping both in sync.
16
16
  *
17
17
  * @param {Object} props
18
18
  * @param {string} props.tabsClientId The client ID of the parent tabs block.
@@ -27,16 +27,16 @@ export default function RemoveTabToolbarControl( { tabsClientId } ) {
27
27
  } = useDispatch( blockEditorStore );
28
28
 
29
29
  const {
30
+ activeTabPanelClientId,
30
31
  activeTabClientId,
31
- activeMenuItemClientId,
32
32
  tabCount,
33
33
  editorActiveTabIndex,
34
34
  } = useSelect(
35
35
  ( select ) => {
36
36
  if ( ! tabsClientId ) {
37
37
  return {
38
+ activeTabPanelClientId: null,
38
39
  activeTabClientId: null,
39
- activeMenuItemClientId: null,
40
40
  tabCount: 0,
41
41
  editorActiveTabIndex: 0,
42
42
  };
@@ -49,19 +49,20 @@ export default function RemoveTabToolbarControl( { tabsClientId } ) {
49
49
  tabsAttributes?.activeTabIndex ??
50
50
  0;
51
51
  const innerBlocks = getBlocks( tabsClientId );
52
- const tabPanel = innerBlocks.find(
53
- ( block ) => block.name === 'core/tab-panel'
52
+ const tabPanels = innerBlocks.find(
53
+ ( block ) => block.name === 'core/tab-panels'
54
54
  );
55
- const tabsMenu = innerBlocks.find(
56
- ( block ) => block.name === 'core/tabs-menu'
55
+ const tabList = innerBlocks.find(
56
+ ( block ) => block.name === 'core/tab-list'
57
57
  );
58
- const tabs = tabPanel?.innerBlocks || [];
59
- const menuItems = tabsMenu?.innerBlocks || [];
58
+ const tabPanelBlocks = tabPanels?.innerBlocks || [];
59
+ const tabs = tabList?.innerBlocks || [];
60
+ const activeTabPanel = tabPanelBlocks[ activeIndex ];
60
61
  const activeTab = tabs[ activeIndex ];
61
- const activeMenuItem = menuItems[ activeIndex ];
62
+
62
63
  return {
64
+ activeTabPanelClientId: activeTabPanel?.clientId || null,
63
65
  activeTabClientId: activeTab?.clientId || null,
64
- activeMenuItemClientId: activeMenuItem?.clientId || null,
65
66
  tabCount: tabs.length,
66
67
  editorActiveTabIndex: activeIndex,
67
68
  };
@@ -70,7 +71,7 @@ export default function RemoveTabToolbarControl( { tabsClientId } ) {
70
71
  );
71
72
 
72
73
  const removeTab = () => {
73
- if ( ! activeTabClientId || tabCount <= 1 ) {
74
+ if ( ! activeTabPanelClientId || tabCount <= 1 ) {
74
75
  return;
75
76
  }
76
77
 
@@ -85,10 +86,10 @@ export default function RemoveTabToolbarControl( { tabsClientId } ) {
85
86
  editorActiveTabIndex: newActiveIndex,
86
87
  } );
87
88
 
88
- // Remove the tab content block and the corresponding menu item.
89
- removeBlock( activeTabClientId, false );
90
- if ( activeMenuItemClientId ) {
91
- removeBlock( activeMenuItemClientId, false );
89
+ // Remove the tab panel and corresponding tab
90
+ removeBlock( activeTabPanelClientId, false );
91
+ if ( activeTabClientId ) {
92
+ removeBlock( activeTabClientId, false );
92
93
  }
93
94
 
94
95
  if ( tabsClientId ) {
@@ -96,7 +97,7 @@ export default function RemoveTabToolbarControl( { tabsClientId } ) {
96
97
  }
97
98
  };
98
99
 
99
- const isDisabled = tabCount <= 1 || ! activeTabClientId;
100
+ const isDisabled = tabCount <= 1 || ! activeTabPanelClientId;
100
101
 
101
102
  return (
102
103
  <BlockControls group="other">
@@ -4,8 +4,10 @@
4
4
  import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';
5
5
 
6
6
  export default function save() {
7
- const blockProps = useBlockProps.save();
7
+ const blockProps = useBlockProps.save( {
8
+ role: 'tabpanel',
9
+ } );
8
10
  const innerBlocksProps = useInnerBlocksProps.save( blockProps );
9
11
 
10
- return <div { ...innerBlocksProps } />;
12
+ return <section { ...innerBlocksProps } />;
11
13
  }
@@ -1,4 +1,23 @@
1
1
  .wp-block-tab-panel {
2
+ max-width: 100%;
3
+ flex-basis: 100%;
2
4
  flex-grow: 1;
3
- min-width: 0;
5
+ box-sizing: border-box;
6
+
7
+ & > *:first-child {
8
+ margin-top: 0;
9
+ }
10
+ & > *:last-child {
11
+ margin-bottom: 0;
12
+ }
13
+
14
+ &[hidden],
15
+ &:empty {
16
+ display: none !important;
17
+ }
18
+ }
19
+
20
+ .wp-block-tab-panel.wp-block.has-background,
21
+ .wp-block-tab-panel:not(.wp-block).has-background {
22
+ padding: var(--wp--preset--spacing--30);
4
23
  }
@@ -0,0 +1,66 @@
1
+ {
2
+ "$schema": "https://schemas.wp.org/trunk/block.json",
3
+ "__experimental": true,
4
+ "apiVersion": 3,
5
+ "name": "core/tab-panels",
6
+ "title": "Tab Panels",
7
+ "description": "Container for tab panel content in a tabbed interface.",
8
+ "category": "design",
9
+ "textdomain": "default",
10
+ "parent": [ "core/tabs" ],
11
+ "allowedBlocks": [ "core/tab-panel" ],
12
+ "attributes": {},
13
+ "supports": {
14
+ "anchor": false,
15
+ "html": false,
16
+ "reusable": false,
17
+ "visibility": false,
18
+ "lock": false,
19
+ "dimensions": {
20
+ "aspectRatio": false,
21
+ "height": false,
22
+ "minHeight": false,
23
+ "width": false
24
+ },
25
+ "color": {
26
+ "background": true,
27
+ "text": true,
28
+ "heading": true,
29
+ "link": true,
30
+ "__experimentalDefaultControls": {
31
+ "background": true,
32
+ "text": true
33
+ }
34
+ },
35
+ "spacing": {
36
+ "blockGap": false,
37
+ "padding": true,
38
+ "margin": true
39
+ },
40
+ "typography": {
41
+ "fontSize": true,
42
+ "__experimentalFontFamily": true
43
+ },
44
+ "layout": {
45
+ "default": {
46
+ "type": "flex",
47
+ "flexWrap": "nowrap",
48
+ "justifyContent": "stretch",
49
+ "orientation": "vertical"
50
+ },
51
+ "allowSwitching": false,
52
+ "allowVerticalAlignment": false,
53
+ "allowOrientation": false,
54
+ "allowJustification": true,
55
+ "allowSizingOnChildren": false
56
+ },
57
+ "__experimentalBorder": {
58
+ "radius": true,
59
+ "color": true,
60
+ "width": true,
61
+ "style": true
62
+ }
63
+ },
64
+ "editorScript": "file:./index.js",
65
+ "style": "file:./style-index.css"
66
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import {
5
+ useBlockProps,
6
+ useInnerBlocksProps,
7
+ store as blockEditorStore,
8
+ } from '@wordpress/block-editor';
9
+ import { useSelect } from '@wordpress/data';
10
+
11
+ /**
12
+ * Internal dependencies
13
+ */
14
+ import AddTabToolbarControl from '../tab-panel/add-tab-toolbar-control';
15
+ import RemoveTabToolbarControl from '../tab-panel/remove-tab-toolbar-control';
16
+
17
+ const TAB_PANELS_TEMPLATE = [ [ 'core/tab-panel', {} ] ];
18
+
19
+ export default function Edit( { clientId } ) {
20
+ const blockProps = useBlockProps();
21
+
22
+ const innerBlocksProps = useInnerBlocksProps( blockProps, {
23
+ template: TAB_PANELS_TEMPLATE,
24
+ templateLock: false,
25
+ renderAppender: false, // Appender handled by individual tab blocks
26
+ } );
27
+
28
+ // Get the parent tabs block clientId
29
+ const tabsClientId = useSelect(
30
+ ( select ) =>
31
+ select( blockEditorStore ).getBlockRootClientId( clientId ),
32
+ [ clientId ]
33
+ );
34
+
35
+ return (
36
+ <>
37
+ <AddTabToolbarControl tabsClientId={ tabsClientId } />
38
+ <RemoveTabToolbarControl tabsClientId={ tabsClientId } />
39
+ <div { ...innerBlocksProps } />
40
+ </>
41
+ );
42
+ }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * WordPress dependencies
3
3
  */
4
- import { tabsMenuItem as icon } from '@wordpress/icons';
4
+ import { contents as icon } from '@wordpress/icons';
5
5
 
6
6
  /**
7
7
  * Internal dependencies
@@ -0,0 +1,11 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';
5
+
6
+ export default function save() {
7
+ const blockProps = useBlockProps.save();
8
+ const innerBlocksProps = useInnerBlocksProps.save( blockProps );
9
+
10
+ return <div { ...innerBlocksProps } />;
11
+ }
@@ -0,0 +1,4 @@
1
+ .wp-block-tab-panels {
2
+ flex-grow: 1;
3
+ min-width: 0;
4
+ }
@@ -7,7 +7,7 @@
7
7
  "description": "Display content in a tabbed interface to help users navigate detailed content with ease.",
8
8
  "category": "design",
9
9
  "textdomain": "default",
10
- "allowedBlocks": [ "core/tabs-menu", "core/tab-panel" ],
10
+ "allowedBlocks": [ "core/tab-list", "core/tab-panels" ],
11
11
  "attributes": {
12
12
  "activeTabIndex": {
13
13
  "type": "number",
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Internal dependencies
3
3
  */
4
- import AddTabToolbarControl from '../tab/add-tab-toolbar-control';
5
- import RemoveTabToolbarControl from '../tab/remove-tab-toolbar-control';
4
+ import AddTabToolbarControl from '../tab-panel/add-tab-toolbar-control';
5
+ import RemoveTabToolbarControl from '../tab-panel/remove-tab-toolbar-control';
6
6
 
7
7
  export default function Controls( { clientId } ) {
8
8
  return (
package/src/tabs/edit.js CHANGED
@@ -15,32 +15,32 @@ import { __ } from '@wordpress/i18n';
15
15
  * Internal dependencies
16
16
  */
17
17
  import Controls from './controls';
18
- import useTabMenuSync from './use-tab-menu-sync';
18
+ import useTabListSync from './use-tab-list-sync';
19
19
 
20
20
  const EMPTY_ARRAY = [];
21
21
 
22
22
  const TABS_TEMPLATE = [
23
23
  [
24
- 'core/tabs-menu',
24
+ 'core/tab-list',
25
25
  {},
26
26
  [
27
- [ 'core/tabs-menu-item', {} ],
28
- [ 'core/tabs-menu-item', {} ],
27
+ [ 'core/tab', {} ],
28
+ [ 'core/tab', {} ],
29
29
  ],
30
30
  ],
31
31
  [
32
- 'core/tab-panel',
32
+ 'core/tab-panels',
33
33
  {},
34
34
  [
35
35
  [
36
- 'core/tab',
36
+ 'core/tab-panel',
37
37
  {
38
38
  label: __( 'Tab' ),
39
39
  },
40
40
  [ [ 'core/paragraph' ] ],
41
41
  ],
42
42
  [
43
- 'core/tab',
43
+ 'core/tab-panel',
44
44
  {
45
45
  label: __( 'Tab' ),
46
46
  },
@@ -63,29 +63,34 @@ function Edit( { clientId, attributes, setAttributes } ) {
63
63
  }
64
64
  }, [] ); // eslint-disable-line react-hooks/exhaustive-deps
65
65
 
66
- const { tabs, tabPanelClientId, menuItems, tabsMenuClientId } = useSelect(
66
+ const { tabPanels, tabPanelsClientId, tabs, tabListClientId } = useSelect(
67
67
  ( select ) => {
68
68
  const { getBlocks } = select( blockEditorStore );
69
69
  const innerBlocks = getBlocks( clientId );
70
70
 
71
- const tabPanel = innerBlocks.find(
72
- ( block ) => block.name === 'core/tab-panel'
71
+ const tabPanelBlocks = innerBlocks.find(
72
+ ( block ) => block.name === 'core/tab-panels'
73
73
  );
74
- const tabsMenu = innerBlocks.find(
75
- ( block ) => block.name === 'core/tabs-menu'
74
+ const tabList = innerBlocks.find(
75
+ ( block ) => block.name === 'core/tab-list'
76
76
  );
77
77
 
78
78
  return {
79
- tabs: tabPanel?.innerBlocks ?? EMPTY_ARRAY,
80
- tabPanelClientId: tabPanel?.clientId ?? null,
81
- menuItems: tabsMenu?.innerBlocks ?? EMPTY_ARRAY,
82
- tabsMenuClientId: tabsMenu?.clientId ?? null,
79
+ tabPanels: tabPanelBlocks?.innerBlocks ?? EMPTY_ARRAY,
80
+ tabPanelsClientId: tabPanelBlocks?.clientId ?? null,
81
+ tabs: tabList?.innerBlocks ?? EMPTY_ARRAY,
82
+ tabListClientId: tabList?.clientId ?? null,
83
83
  };
84
84
  },
85
85
  [ clientId ]
86
86
  );
87
87
 
88
- useTabMenuSync( { tabs, menuItems, tabPanelClientId, tabsMenuClientId } );
88
+ useTabListSync( {
89
+ tabPanels,
90
+ tabs,
91
+ tabPanelsClientId,
92
+ tabListClientId,
93
+ } );
89
94
 
90
95
  /**
91
96
  * Memoize context value to prevent unnecessary re-renders.
@@ -94,9 +99,9 @@ function Edit( { clientId, attributes, setAttributes } ) {
94
99
  /**
95
100
  * Compute tabs list from innerblocks to provide via context.
96
101
  * This traverses the tab-panel block to find all tab blocks
97
- * and extracts their label and anchor for the tabs-menu to consume.
102
+ * and extracts their label and anchor for the tab-list to consume.
98
103
  */
99
- const tabList = tabs.map( ( tab, index ) => ( {
104
+ const tabList = tabPanels.map( ( tab, index ) => ( {
100
105
  id: tab.attributes.anchor || `tab-${ index }`,
101
106
  label: tab.attributes.label || '',
102
107
  clientId: tab.clientId,
@@ -109,7 +114,7 @@ function Edit( { clientId, attributes, setAttributes } ) {
109
114
  'core/tabs-activeTabIndex': activeTabIndex,
110
115
  'core/tabs-editorActiveTabIndex': editorActiveTabIndex,
111
116
  };
112
- }, [ tabs, anchor, activeTabIndex, editorActiveTabIndex ] );
117
+ }, [ tabPanels, anchor, activeTabIndex, editorActiveTabIndex ] );
113
118
 
114
119
  const blockProps = useBlockProps();
115
120