@wordpress/block-library 9.43.0 → 9.44.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.
- package/CHANGELOG.md +2 -0
- package/build/code/edit.cjs +2 -1
- package/build/code/edit.cjs.map +2 -2
- package/build/cover/edit/color-utils.cjs +1 -1
- package/build/cover/edit/color-utils.cjs.map +2 -2
- package/build/cover/edit/index.cjs +39 -26
- package/build/cover/edit/index.cjs.map +2 -2
- package/build/cover/embed-video-utils.cjs +9 -7
- package/build/cover/embed-video-utils.cjs.map +2 -2
- package/build/embed/embed-preview.cjs +2 -1
- package/build/embed/embed-preview.cjs.map +2 -2
- package/build/file/utils/index.cjs +1 -1
- package/build/file/utils/index.cjs.map +2 -2
- package/build/form/view.cjs +1 -1
- package/build/form/view.cjs.map +2 -2
- package/build/icon/edit.cjs +1 -3
- package/build/icon/edit.cjs.map +2 -2
- package/build/image/image.cjs +32 -9
- package/build/image/image.cjs.map +2 -2
- package/build/navigation-link/link-ui/index.cjs +12 -1
- package/build/navigation-link/link-ui/index.cjs.map +2 -2
- package/build/navigation-link/link-ui/page-creator.cjs +1 -1
- package/build/navigation-link/link-ui/page-creator.cjs.map +2 -2
- package/build/navigation-link/shared/update-attributes.cjs +1 -1
- package/build/navigation-link/shared/update-attributes.cjs.map +2 -2
- package/build/navigation-link/shared/use-link-preview.cjs +1 -1
- package/build/navigation-link/shared/use-link-preview.cjs.map +2 -2
- package/build/paragraph/use-enter.cjs +4 -5
- package/build/paragraph/use-enter.cjs.map +2 -2
- package/build/pattern/edit.cjs +1 -1
- package/build/pattern/edit.cjs.map +2 -2
- package/build/search/block.json +5 -5
- package/build/search/edit.cjs +8 -33
- package/build/search/edit.cjs.map +2 -2
- package/build/separator/transforms.cjs +12 -4
- package/build/separator/transforms.cjs.map +2 -2
- package/build/tab/add-tab-toolbar-control.cjs +5 -17
- package/build/tab/add-tab-toolbar-control.cjs.map +2 -2
- package/build/tab/block.json +2 -1
- package/build/tab/remove-tab-toolbar-control.cjs +1 -4
- package/build/tab/remove-tab-toolbar-control.cjs.map +2 -2
- package/build/tabs/edit.cjs +45 -45
- package/build/tabs/edit.cjs.map +2 -2
- package/build/tabs-menu/block.json +1 -2
- package/build/tabs-menu-item/block.json +0 -6
- package/build/tabs-menu-item/edit.cjs +2 -8
- package/build/tabs-menu-item/edit.cjs.map +2 -2
- package/build-module/code/edit.mjs +2 -1
- package/build-module/code/edit.mjs.map +2 -2
- package/build-module/cover/edit/color-utils.mjs +1 -1
- package/build-module/cover/edit/color-utils.mjs.map +2 -2
- package/build-module/cover/edit/index.mjs +47 -29
- package/build-module/cover/edit/index.mjs.map +2 -2
- package/build-module/cover/embed-video-utils.mjs +8 -6
- package/build-module/cover/embed-video-utils.mjs.map +2 -2
- package/build-module/embed/embed-preview.mjs +2 -1
- package/build-module/embed/embed-preview.mjs.map +2 -2
- package/build-module/file/utils/index.mjs +1 -1
- package/build-module/file/utils/index.mjs.map +2 -2
- package/build-module/form/view.mjs +1 -1
- package/build-module/form/view.mjs.map +2 -2
- package/build-module/icon/edit.mjs +1 -3
- package/build-module/icon/edit.mjs.map +2 -2
- package/build-module/image/image.mjs +32 -9
- package/build-module/image/image.mjs.map +2 -2
- package/build-module/navigation-link/link-ui/index.mjs +12 -1
- package/build-module/navigation-link/link-ui/index.mjs.map +2 -2
- package/build-module/navigation-link/link-ui/page-creator.mjs +1 -1
- package/build-module/navigation-link/link-ui/page-creator.mjs.map +2 -2
- package/build-module/navigation-link/shared/update-attributes.mjs +1 -1
- package/build-module/navigation-link/shared/update-attributes.mjs.map +2 -2
- package/build-module/navigation-link/shared/use-link-preview.mjs +1 -1
- package/build-module/navigation-link/shared/use-link-preview.mjs.map +2 -2
- package/build-module/paragraph/use-enter.mjs +4 -5
- package/build-module/paragraph/use-enter.mjs.map +2 -2
- package/build-module/pattern/edit.mjs +1 -1
- package/build-module/pattern/edit.mjs.map +2 -2
- package/build-module/search/block.json +5 -5
- package/build-module/search/edit.mjs +8 -33
- package/build-module/search/edit.mjs.map +2 -2
- package/build-module/separator/transforms.mjs +17 -5
- package/build-module/separator/transforms.mjs.map +2 -2
- package/build-module/tab/add-tab-toolbar-control.mjs +6 -18
- package/build-module/tab/add-tab-toolbar-control.mjs.map +2 -2
- package/build-module/tab/block.json +2 -1
- package/build-module/tab/remove-tab-toolbar-control.mjs +1 -4
- package/build-module/tab/remove-tab-toolbar-control.mjs.map +2 -2
- package/build-module/tabs/edit.mjs +45 -45
- package/build-module/tabs/edit.mjs.map +2 -2
- package/build-module/tabs-menu/block.json +1 -2
- package/build-module/tabs-menu-item/block.json +0 -6
- package/build-module/tabs-menu-item/edit.mjs +3 -9
- package/build-module/tabs-menu-item/edit.mjs.map +2 -2
- package/build-style/code/style-rtl.css +1 -1
- package/build-style/code/style.css +1 -1
- package/build-style/post-author-biography/style-rtl.css +1 -0
- package/build-style/post-author-biography/style.css +1 -0
- package/build-style/style-rtl.css +11 -16
- package/build-style/style.css +11 -16
- package/build-style/tabs-menu-item/style-rtl.css +9 -6
- package/build-style/tabs-menu-item/style.css +9 -6
- package/package.json +38 -38
- package/src/code/edit.js +1 -0
- package/src/code/style.scss +1 -1
- package/src/cover/edit/color-utils.js +1 -1
- package/src/cover/edit/index.js +72 -35
- package/src/cover/embed-video-utils.js +10 -8
- package/src/embed/embed-preview.js +6 -5
- package/src/embed/test/index.native.js +3 -2
- package/src/file/utils/index.js +1 -1
- package/src/form/view.js +1 -1
- package/src/icon/edit.js +1 -3
- package/src/image/image.js +56 -9
- package/src/image/index.php +4 -4
- package/src/navigation-link/link-ui/index.js +12 -1
- package/src/navigation-link/link-ui/page-creator.js +1 -1
- package/src/navigation-link/shared/update-attributes.js +1 -1
- package/src/navigation-link/shared/use-link-preview.js +1 -1
- package/src/paragraph/use-enter.js +5 -5
- package/src/pattern/edit.js +1 -1
- package/src/post-author-biography/style.scss +1 -0
- package/src/search/block.json +5 -5
- package/src/search/edit.js +4 -35
- package/src/search/index.php +23 -3
- package/src/separator/transforms.js +19 -5
- package/src/style.scss +0 -1
- package/src/tab/add-tab-toolbar-control.js +24 -42
- package/src/tab/block.json +2 -1
- package/src/tab/index.php +21 -4
- package/src/tab/remove-tab-toolbar-control.js +1 -9
- package/src/tabs/edit.js +59 -66
- package/src/tabs/index.php +14 -15
- package/src/tabs-menu/block.json +1 -2
- package/src/tabs-menu/index.php +6 -17
- package/src/tabs-menu-item/block.json +0 -6
- package/src/tabs-menu-item/edit.js +3 -15
- package/src/tabs-menu-item/style.scss +10 -8
- package/build-style/tabs-menu/style-rtl.css +0 -8
- package/build-style/tabs-menu/style.css +0 -8
- package/src/tabs-menu/style.scss +0 -8
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* WordPress dependencies
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import { __ } from '@wordpress/i18n';
|
|
5
5
|
import { createBlock } from '@wordpress/blocks';
|
|
6
6
|
import {
|
|
7
7
|
BlockControls,
|
|
@@ -22,61 +22,43 @@ import { useDispatch, useSelect } from '@wordpress/data';
|
|
|
22
22
|
export default function AddTabToolbarControl( { tabsClientId } ) {
|
|
23
23
|
const { insertBlock } = useDispatch( blockEditorStore );
|
|
24
24
|
|
|
25
|
-
const { tabPanelClientId, tabsMenuClientId
|
|
26
|
-
|
|
27
|
-
(
|
|
28
|
-
if ( ! tabsClientId ) {
|
|
29
|
-
return {
|
|
30
|
-
tabPanelClientId: null,
|
|
31
|
-
tabsMenuClientId: null,
|
|
32
|
-
existingAnchors: [],
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
const { getBlocks } = select( blockEditorStore );
|
|
36
|
-
const innerBlocks = getBlocks( tabsClientId );
|
|
37
|
-
const tabPanel = innerBlocks.find(
|
|
38
|
-
( block ) => block.name === 'core/tab-panel'
|
|
39
|
-
);
|
|
40
|
-
const tabsMenu = innerBlocks.find(
|
|
41
|
-
( block ) => block.name === 'core/tabs-menu'
|
|
42
|
-
);
|
|
25
|
+
const { tabPanelClientId, tabsMenuClientId } = useSelect(
|
|
26
|
+
( select ) => {
|
|
27
|
+
if ( ! tabsClientId ) {
|
|
43
28
|
return {
|
|
44
|
-
tabPanelClientId:
|
|
45
|
-
tabsMenuClientId:
|
|
46
|
-
tabCount: tabPanel?.innerBlocks?.length || 0,
|
|
47
|
-
existingAnchors: ( tabPanel?.innerBlocks || [] )
|
|
48
|
-
.map( ( block ) => block.attributes.anchor )
|
|
49
|
-
.filter( Boolean ),
|
|
29
|
+
tabPanelClientId: null,
|
|
30
|
+
tabsMenuClientId: null,
|
|
50
31
|
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
32
|
+
}
|
|
33
|
+
const { getBlocks } = select( blockEditorStore );
|
|
34
|
+
const innerBlocks = getBlocks( tabsClientId );
|
|
35
|
+
const tabPanel = innerBlocks.find(
|
|
36
|
+
( block ) => block.name === 'core/tab-panel'
|
|
37
|
+
);
|
|
38
|
+
const tabsMenu = innerBlocks.find(
|
|
39
|
+
( block ) => block.name === 'core/tabs-menu'
|
|
40
|
+
);
|
|
41
|
+
return {
|
|
42
|
+
tabPanelClientId: tabPanel?.clientId || null,
|
|
43
|
+
tabsMenuClientId: tabsMenu?.clientId || null,
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
[ tabsClientId ]
|
|
47
|
+
);
|
|
54
48
|
|
|
55
49
|
const addTab = () => {
|
|
56
50
|
if ( ! tabPanelClientId ) {
|
|
57
51
|
return;
|
|
58
52
|
}
|
|
59
53
|
|
|
60
|
-
// Start from count + 1 so the label stays sequential, then increment
|
|
61
|
-
// until the anchor slot is free.
|
|
62
|
-
const existingAnchorSet = new Set( existingAnchors );
|
|
63
|
-
let tabNumber = tabCount + 1;
|
|
64
|
-
while ( existingAnchorSet.has( `tab-${ tabNumber }` ) ) {
|
|
65
|
-
tabNumber++;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
54
|
const newTabBlock = createBlock( 'core/tab', {
|
|
69
|
-
|
|
70
|
-
/* translators: %d: tab number */
|
|
71
|
-
label: sprintf( __( 'Tab %d' ), tabNumber ),
|
|
55
|
+
label: __( 'Tab' ),
|
|
72
56
|
} );
|
|
73
57
|
insertBlock( newTabBlock, undefined, tabPanelClientId );
|
|
74
58
|
|
|
75
59
|
// Insert a corresponding menu item into the tabs-menu.
|
|
76
60
|
if ( tabsMenuClientId ) {
|
|
77
|
-
const newMenuItemBlock = createBlock( 'core/tabs-menu-item', {
|
|
78
|
-
anchor: `tab-${ tabNumber }-button`,
|
|
79
|
-
} );
|
|
61
|
+
const newMenuItemBlock = createBlock( 'core/tabs-menu-item', {} );
|
|
80
62
|
insertBlock( newMenuItemBlock, undefined, tabsMenuClientId );
|
|
81
63
|
}
|
|
82
64
|
};
|
package/src/tab/block.json
CHANGED
package/src/tab/index.php
CHANGED
|
@@ -11,17 +11,34 @@
|
|
|
11
11
|
* @since 7.0.0
|
|
12
12
|
*
|
|
13
13
|
* @param array $attributes Block attributes.
|
|
14
|
-
|
|
14
|
+
* @param array $attributes Block attributes.
|
|
15
|
+
* @param string $content Block content.
|
|
16
|
+
* @param \WP_Block $block Block instance.
|
|
15
17
|
*
|
|
16
18
|
* @return string Updated HTML.
|
|
17
19
|
*/
|
|
18
|
-
function block_core_tab_render( array $attributes, string $content ): string {
|
|
20
|
+
function block_core_tab_render( array $attributes, string $content, \WP_Block $block ): string {
|
|
21
|
+
$tabs_id = $block->context['core/tabs-id'] ?? '';
|
|
22
|
+
|
|
23
|
+
static $tab_counters = array();
|
|
24
|
+
|
|
25
|
+
if ( ! isset( $tab_counters[ $tabs_id ] ) ) {
|
|
26
|
+
$tab_counters[ $tabs_id ] = 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
$tab_index = $tab_counters[ $tabs_id ];
|
|
30
|
+
++$tab_counters[ $tabs_id ];
|
|
31
|
+
|
|
19
32
|
$tag_processor = new WP_HTML_Tag_Processor( $content );
|
|
20
33
|
$tag_processor->next_tag( array( 'class_name' => 'wp-block-tab' ) );
|
|
34
|
+
|
|
35
|
+
// Use the user's custom anchor if present, otherwise fall back to
|
|
36
|
+
// the generated position-based ID.
|
|
21
37
|
$tab_id = (string) $tag_processor->get_attribute( 'id' );
|
|
22
|
-
// If no id, generate a unique one
|
|
23
38
|
if ( empty( $tab_id ) ) {
|
|
24
|
-
$tab_id =
|
|
39
|
+
$tab_id = ! empty( $tabs_id )
|
|
40
|
+
? $tabs_id . '-tab-' . $tab_index
|
|
41
|
+
: 'tab-' . $tab_index;
|
|
25
42
|
$tag_processor->set_attribute( 'id', $tab_id );
|
|
26
43
|
}
|
|
27
44
|
|
|
@@ -58,15 +58,7 @@ export default function RemoveTabToolbarControl( { tabsClientId } ) {
|
|
|
58
58
|
const tabs = tabPanel?.innerBlocks || [];
|
|
59
59
|
const menuItems = tabsMenu?.innerBlocks || [];
|
|
60
60
|
const activeTab = tabs[ activeIndex ];
|
|
61
|
-
|
|
62
|
-
const expectedMenuAnchor = activeTab?.attributes?.anchor
|
|
63
|
-
? `${ activeTab.attributes.anchor }-button`
|
|
64
|
-
: null;
|
|
65
|
-
const activeMenuItem = expectedMenuAnchor
|
|
66
|
-
? menuItems.find(
|
|
67
|
-
( m ) => m.attributes?.anchor === expectedMenuAnchor
|
|
68
|
-
)
|
|
69
|
-
: menuItems[ activeIndex ];
|
|
61
|
+
const activeMenuItem = menuItems[ activeIndex ];
|
|
70
62
|
return {
|
|
71
63
|
activeTabClientId: activeTab?.clientId || null,
|
|
72
64
|
activeMenuItemClientId: activeMenuItem?.clientId || null,
|
package/src/tabs/edit.js
CHANGED
|
@@ -9,12 +9,15 @@ import {
|
|
|
9
9
|
} from '@wordpress/block-editor';
|
|
10
10
|
import { useSelect, useDispatch } from '@wordpress/data';
|
|
11
11
|
import { useMemo, useEffect, useRef } from '@wordpress/element';
|
|
12
|
+
import { __ } from '@wordpress/i18n';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Internal dependencies
|
|
15
16
|
*/
|
|
16
17
|
import Controls from './controls';
|
|
17
18
|
|
|
19
|
+
const EMPTY_ARRAY = [];
|
|
20
|
+
|
|
18
21
|
const TABS_TEMPLATE = [
|
|
19
22
|
[
|
|
20
23
|
'core/tabs-menu',
|
|
@@ -24,8 +27,8 @@ const TABS_TEMPLATE = [
|
|
|
24
27
|
},
|
|
25
28
|
},
|
|
26
29
|
[
|
|
27
|
-
[ 'core/tabs-menu-item', {
|
|
28
|
-
[ 'core/tabs-menu-item', {
|
|
30
|
+
[ 'core/tabs-menu-item', {} ],
|
|
31
|
+
[ 'core/tabs-menu-item', {} ],
|
|
29
32
|
],
|
|
30
33
|
],
|
|
31
34
|
[
|
|
@@ -39,16 +42,14 @@ const TABS_TEMPLATE = [
|
|
|
39
42
|
[
|
|
40
43
|
'core/tab',
|
|
41
44
|
{
|
|
42
|
-
|
|
43
|
-
label: 'Tab 1',
|
|
45
|
+
label: __( 'Tab' ),
|
|
44
46
|
},
|
|
45
47
|
[ [ 'core/paragraph' ] ],
|
|
46
48
|
],
|
|
47
49
|
[
|
|
48
50
|
'core/tab',
|
|
49
51
|
{
|
|
50
|
-
|
|
51
|
-
label: 'Tab 2',
|
|
52
|
+
label: __( 'Tab' ),
|
|
52
53
|
},
|
|
53
54
|
[ [ 'core/paragraph' ] ],
|
|
54
55
|
],
|
|
@@ -74,41 +75,24 @@ function Edit( {
|
|
|
74
75
|
}
|
|
75
76
|
}, [] ); // eslint-disable-line react-hooks/exhaustive-deps
|
|
76
77
|
|
|
77
|
-
const { removeBlock } = useDispatch( blockEditorStore );
|
|
78
|
+
const { removeBlock, replaceInnerBlocks } = useDispatch( blockEditorStore );
|
|
78
79
|
|
|
79
|
-
|
|
80
|
-
* Construct a list of core/tab blocks, used to create tabs-list context.
|
|
81
|
-
* Also select menu items with their anchors for anchor-based deletion sync.
|
|
82
|
-
*/
|
|
83
|
-
const { tabs, menuItems } = useSelect(
|
|
80
|
+
const { tabs, tabPanelClientId, menuItems } = useSelect(
|
|
84
81
|
( select ) => {
|
|
85
82
|
const { getBlocks } = select( blockEditorStore );
|
|
86
83
|
const innerBlocks = getBlocks( clientId );
|
|
87
84
|
|
|
88
|
-
// Find tab-panel block and extract tab data.
|
|
89
85
|
const tabPanel = innerBlocks.find(
|
|
90
86
|
( block ) => block.name === 'core/tab-panel'
|
|
91
87
|
);
|
|
92
|
-
|
|
93
|
-
// Find tabs-menu block and get its children with their anchors.
|
|
94
88
|
const tabsMenu = innerBlocks.find(
|
|
95
89
|
( block ) => block.name === 'core/tabs-menu'
|
|
96
90
|
);
|
|
97
91
|
|
|
98
92
|
return {
|
|
99
|
-
tabs: tabPanel
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
)
|
|
103
|
-
: [],
|
|
104
|
-
menuItems: tabsMenu
|
|
105
|
-
? getBlocks( tabsMenu.clientId )
|
|
106
|
-
.filter( ( b ) => b.name === 'core/tabs-menu-item' )
|
|
107
|
-
.map( ( b ) => ( {
|
|
108
|
-
clientId: b.clientId,
|
|
109
|
-
anchor: b.attributes.anchor ?? '',
|
|
110
|
-
} ) )
|
|
111
|
-
: [],
|
|
93
|
+
tabs: tabPanel?.innerBlocks ?? EMPTY_ARRAY,
|
|
94
|
+
tabPanelClientId: tabPanel?.clientId ?? null,
|
|
95
|
+
menuItems: tabsMenu?.innerBlocks ?? EMPTY_ARRAY,
|
|
112
96
|
};
|
|
113
97
|
},
|
|
114
98
|
[ clientId ]
|
|
@@ -130,7 +114,6 @@ function Edit( {
|
|
|
130
114
|
useEffect( () => {
|
|
131
115
|
const currentTabs = tabs.map( ( tab ) => ( {
|
|
132
116
|
clientId: tab.clientId,
|
|
133
|
-
anchor: tab.attributes.anchor ?? '',
|
|
134
117
|
} ) );
|
|
135
118
|
|
|
136
119
|
if ( prevSyncStateRef.current === null ) {
|
|
@@ -146,6 +129,13 @@ function Edit( {
|
|
|
146
129
|
|
|
147
130
|
const tabsRemoved = currentTabs.length < prevTabs.length;
|
|
148
131
|
const menuItemsRemoved = menuItems.length < prevMenuItems.length;
|
|
132
|
+
const menuItemsReordered =
|
|
133
|
+
! tabsRemoved &&
|
|
134
|
+
! menuItemsRemoved &&
|
|
135
|
+
menuItems.length === prevMenuItems.length &&
|
|
136
|
+
menuItems.some(
|
|
137
|
+
( m, i ) => m.clientId !== prevMenuItems[ i ]?.clientId
|
|
138
|
+
);
|
|
149
139
|
|
|
150
140
|
// Update snapshot to the current state.
|
|
151
141
|
// Snapshot is updated eagerly; post-removal mutations keep it consistent
|
|
@@ -155,6 +145,23 @@ function Edit( {
|
|
|
155
145
|
menuItems: [ ...menuItems ],
|
|
156
146
|
};
|
|
157
147
|
|
|
148
|
+
// When menu items are reordered, move the corresponding tab content
|
|
149
|
+
// blocks to match the new order.
|
|
150
|
+
if ( menuItemsReordered && tabPanelClientId ) {
|
|
151
|
+
const reorderedTabs = menuItems
|
|
152
|
+
.map( ( menuItem ) => {
|
|
153
|
+
const oldIndex = prevMenuItems.findIndex(
|
|
154
|
+
( pm ) => pm.clientId === menuItem.clientId
|
|
155
|
+
);
|
|
156
|
+
return oldIndex !== -1 ? tabs[ oldIndex ] : null;
|
|
157
|
+
} )
|
|
158
|
+
.filter( Boolean );
|
|
159
|
+
if ( reorderedTabs.length === tabs.length ) {
|
|
160
|
+
replaceInnerBlocks( tabPanelClientId, reorderedTabs, false );
|
|
161
|
+
}
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
158
165
|
// Lists are in sync, nothing changed, or toolbar already removed both.
|
|
159
166
|
if (
|
|
160
167
|
( ! tabsRemoved && ! menuItemsRemoved ) ||
|
|
@@ -169,45 +176,31 @@ function Edit( {
|
|
|
169
176
|
);
|
|
170
177
|
|
|
171
178
|
if ( tabsRemoved ) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
removeBlock( menuItemToRemove.clientId, false );
|
|
184
|
-
prevSyncStateRef.current.menuItems =
|
|
185
|
-
prevSyncStateRef.current.menuItems.filter(
|
|
186
|
-
( m ) => m.clientId !== menuItemToRemove.clientId
|
|
187
|
-
);
|
|
188
|
-
}
|
|
189
|
-
} );
|
|
179
|
+
// Remove the menu item at the same position.
|
|
180
|
+
const removedIndex = prevTabs.findIndex(
|
|
181
|
+
( t ) => ! currentTabIds.has( t.clientId )
|
|
182
|
+
);
|
|
183
|
+
if ( removedIndex >= 0 && menuItems[ removedIndex ] ) {
|
|
184
|
+
removeBlock( menuItems[ removedIndex ].clientId, false );
|
|
185
|
+
prevSyncStateRef.current.menuItems =
|
|
186
|
+
prevSyncStateRef.current.menuItems.filter(
|
|
187
|
+
( _, i ) => i !== removedIndex
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
190
|
} else {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
(
|
|
199
|
-
(
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
removeBlock( tabToRemove.clientId, false );
|
|
203
|
-
prevSyncStateRef.current.tabs =
|
|
204
|
-
prevSyncStateRef.current.tabs.filter(
|
|
205
|
-
( t ) => t.clientId !== tabToRemove.clientId
|
|
206
|
-
);
|
|
207
|
-
}
|
|
208
|
-
} );
|
|
191
|
+
// Remove the tab at the same position.
|
|
192
|
+
const removedIndex = prevMenuItems.findIndex(
|
|
193
|
+
( m ) => ! currentMenuItemIds.has( m.clientId )
|
|
194
|
+
);
|
|
195
|
+
if ( removedIndex >= 0 && tabs[ removedIndex ] ) {
|
|
196
|
+
removeBlock( tabs[ removedIndex ].clientId, false );
|
|
197
|
+
prevSyncStateRef.current.tabs =
|
|
198
|
+
prevSyncStateRef.current.tabs.filter(
|
|
199
|
+
( _, i ) => i !== removedIndex
|
|
200
|
+
);
|
|
201
|
+
}
|
|
209
202
|
}
|
|
210
|
-
}, [ tabs, menuItems, removeBlock ] );
|
|
203
|
+
}, [ tabs, tabPanelClientId, menuItems, removeBlock, replaceInnerBlocks ] );
|
|
211
204
|
|
|
212
205
|
/**
|
|
213
206
|
* Memoize context value to prevent unnecessary re-renders.
|
package/src/tabs/index.php
CHANGED
|
@@ -10,11 +10,12 @@
|
|
|
10
10
|
*
|
|
11
11
|
* @since 7.0.0
|
|
12
12
|
*
|
|
13
|
-
* @param array
|
|
13
|
+
* @param array $innerblocks Parsed inner blocks of tabs block.
|
|
14
|
+
* @param string $tabs_id Unique ID for the tabs instance, used to generate tab IDs.
|
|
14
15
|
*
|
|
15
16
|
* @return array List of tabs with id, label, index.
|
|
16
17
|
*/
|
|
17
|
-
function block_core_tabs_generate_tabs_list( array $innerblocks = array() ): array {
|
|
18
|
+
function block_core_tabs_generate_tabs_list( array $innerblocks = array(), string $tabs_id = '' ): array {
|
|
18
19
|
$tabs_list = array();
|
|
19
20
|
|
|
20
21
|
// Find tab-panel block
|
|
@@ -26,17 +27,11 @@ function block_core_tabs_generate_tabs_list( array $innerblocks = array() ): arr
|
|
|
26
27
|
$attrs = $tab_block['attrs'] ?? array();
|
|
27
28
|
$tab_label = $attrs['label'] ?? '';
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
$tab_id = $tag_processor->get_attribute( 'id' ) ?? '';
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
if ( empty( $tab_id ) ) {
|
|
38
|
-
$tab_id = 'tab-' . $tab_index;
|
|
39
|
-
}
|
|
30
|
+
$tab_id = ! empty( $attrs['anchor'] )
|
|
31
|
+
? $attrs['anchor']
|
|
32
|
+
: ( ! empty( $tabs_id )
|
|
33
|
+
? $tabs_id . '-tab-' . $tab_index
|
|
34
|
+
: 'tab-' . $tab_index );
|
|
40
35
|
|
|
41
36
|
$tabs_list[] = array(
|
|
42
37
|
'id' => esc_attr( $tab_id ),
|
|
@@ -67,9 +62,13 @@ function block_core_tabs_generate_tabs_list( array $innerblocks = array() ): arr
|
|
|
67
62
|
*/
|
|
68
63
|
function block_core_tabs_provide_context( array $context, array $parsed_block ): array {
|
|
69
64
|
if ( 'core/tabs' === $parsed_block['blockName'] ) {
|
|
70
|
-
|
|
65
|
+
// Generate a unique ID for the tabs instance first, so it can be used
|
|
66
|
+
// to derive stable tab IDs. Used for 3rd party extensibility to identify
|
|
67
|
+
// the tabs instance.
|
|
68
|
+
$tabs_id = $parsed_block['attrs']['anchor'] ?? wp_unique_id( 'tabs_' );
|
|
69
|
+
$tabs_list = block_core_tabs_generate_tabs_list( $parsed_block['innerBlocks'] ?? array(), $tabs_id );
|
|
71
70
|
$context['core/tabs-list'] = $tabs_list;
|
|
72
|
-
$context['core/tabs-id'] = $
|
|
71
|
+
$context['core/tabs-id'] = $tabs_id;
|
|
73
72
|
}
|
|
74
73
|
|
|
75
74
|
return $context;
|
package/src/tabs-menu/block.json
CHANGED
package/src/tabs-menu/index.php
CHANGED
|
@@ -28,29 +28,18 @@ function block_core_tabs_menu_render_callback( array $attributes, string $conten
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
// Re-render each tabs-menu-item with per-item context (index, id, label).
|
|
31
|
-
// Match by
|
|
32
|
-
|
|
33
|
-
$
|
|
31
|
+
// Match by position so items align with their corresponding tabs.
|
|
32
|
+
$buttons_html = '';
|
|
33
|
+
$menu_item_position = 0;
|
|
34
34
|
|
|
35
35
|
foreach ( $block->parsed_block['innerBlocks'] ?? array() as $parsed_menu_item ) {
|
|
36
36
|
if ( 'core/tabs-menu-item' !== ( $parsed_menu_item['blockName'] ?? '' ) ) {
|
|
37
37
|
continue;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
$
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
// Find the matching tab in $tabs_list by id.
|
|
45
|
-
$tab = null;
|
|
46
|
-
$tab_index = 0;
|
|
47
|
-
foreach ( $tabs_list as $index => $candidate ) {
|
|
48
|
-
if ( ( $candidate['id'] ?? '' ) === $tab_anchor ) {
|
|
49
|
-
$tab = $candidate;
|
|
50
|
-
$tab_index = $index;
|
|
51
|
-
break;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
40
|
+
$tab = $tabs_list[ $menu_item_position ] ?? null;
|
|
41
|
+
$tab_index = $menu_item_position;
|
|
42
|
+
++$menu_item_position;
|
|
54
43
|
|
|
55
44
|
// Skip menu items with no matching tab.
|
|
56
45
|
if ( null === $tab ) {
|
|
@@ -6,7 +6,7 @@ import clsx from 'clsx';
|
|
|
6
6
|
/**
|
|
7
7
|
* WordPress dependencies
|
|
8
8
|
*/
|
|
9
|
-
import { __
|
|
9
|
+
import { __ } from '@wordpress/i18n';
|
|
10
10
|
import {
|
|
11
11
|
useBlockProps,
|
|
12
12
|
store as blockEditorStore,
|
|
@@ -23,7 +23,6 @@ import Controls from './controls';
|
|
|
23
23
|
const EMPTY_ARRAY = [];
|
|
24
24
|
|
|
25
25
|
function Edit( {
|
|
26
|
-
attributes,
|
|
27
26
|
context,
|
|
28
27
|
clientId,
|
|
29
28
|
__unstableLayoutClassNames: layoutClassNames,
|
|
@@ -75,14 +74,7 @@ function Edit( {
|
|
|
75
74
|
[ clientId, tabsList ]
|
|
76
75
|
);
|
|
77
76
|
|
|
78
|
-
|
|
79
|
-
// attribute (e.g., "tab-1-button" → "tab-1"), then look it up in tabsList.
|
|
80
|
-
// Falls back to positional lookup when no anchor is set.
|
|
81
|
-
const tabAnchor = attributes.anchor?.replace( /-button$/, '' ) ?? '';
|
|
82
|
-
const tab =
|
|
83
|
-
( tabAnchor && tabsList.find( ( t ) => t.id === tabAnchor ) ) ||
|
|
84
|
-
tabsList[ menuItemIndex ] ||
|
|
85
|
-
{};
|
|
77
|
+
const tab = tabsList[ menuItemIndex ] || {};
|
|
86
78
|
|
|
87
79
|
// tabListIndex is the tab's position in tabsList, used for active-state
|
|
88
80
|
// checks and click handling.
|
|
@@ -146,11 +138,7 @@ function Edit( {
|
|
|
146
138
|
<RichText
|
|
147
139
|
tagName="span"
|
|
148
140
|
withoutInteractiveFormatting
|
|
149
|
-
placeholder={
|
|
150
|
-
/* translators: %d is the tab index + 1 */
|
|
151
|
-
__( 'Tab title %d' ),
|
|
152
|
-
menuItemIndex + 1
|
|
153
|
-
) }
|
|
141
|
+
placeholder={ __( 'Tab title' ) }
|
|
154
142
|
value={ label }
|
|
155
143
|
onChange={ handleLabelChange }
|
|
156
144
|
/>
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
cursor: pointer;
|
|
8
8
|
flex-basis: inherit !important;
|
|
9
9
|
flex-grow: inherit !important;
|
|
10
|
+
position: relative;
|
|
10
11
|
|
|
11
12
|
// Button reset
|
|
12
13
|
border: none;
|
|
@@ -26,13 +27,14 @@
|
|
|
26
27
|
text-transform: inherit;
|
|
27
28
|
text-align: inherit;
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
&[aria-selected="true"]::before,
|
|
31
|
+
&.is-active::before {
|
|
32
|
+
content: "";
|
|
33
|
+
position: absolute;
|
|
34
|
+
border-bottom: 2px solid currentColor;
|
|
35
|
+
pointer-events: none;
|
|
36
|
+
left: 0;
|
|
37
|
+
width: 100%;
|
|
38
|
+
bottom: 0;
|
|
37
39
|
}
|
|
38
40
|
}
|
package/src/tabs-menu/style.scss
DELETED