diff --git a/src/blockparty-tabs-nav-item/edit.js b/src/blockparty-tabs-nav-item/edit.js
index 7d68c46..762e5aa 100644
--- a/src/blockparty-tabs-nav-item/edit.js
+++ b/src/blockparty-tabs-nav-item/edit.js
@@ -5,8 +5,6 @@ import { getBlockType } from '@wordpress/blocks';
import { select } from '@wordpress/data';
import ComposeBlockControls from './ComposeBlockControls';
import getSynchedID from '../blockparty-tabs/GetSynchedID';
-import SyncTabsActive from '../blockparty-tabs/SyncTabsActive';
-
export default function Edit( {
attributes,
setAttributes,
@@ -53,7 +51,6 @@ export default function Edit( {
return (
<>
-
-
{
- const {
- getBlockName,
- getBlockIndex,
- getSelectedBlockClientId,
- getBlockParents,
- getBlockRootClientId,
- } = select( 'core/block-editor' );
- const selected = getSelectedBlockClientId();
- if ( ! selected ) {
- return {
- selectedBlockClientId: null,
- closestTabItemId: null,
- tabsBlockId: null,
- myIndex: 0,
- };
- }
- // Find the tab item closest to the selection: the selected block if it
- // is a tab item, otherwise the first tab item in the ancestor chain.
- let closest = null;
- if (
- TAB_ITEM_NAMES.indexOf( getBlockName( selected ) ) !== -1
- ) {
- closest = selected;
- } else {
- const parents = getBlockParents( selected );
- for ( let i = 0; i < parents.length; i += 1 ) {
- if (
- TAB_ITEM_NAMES.indexOf(
- getBlockName( parents[ i ] )
- ) !== -1
- ) {
- closest = parents[ i ];
- break;
- }
- }
- }
- // Parent chain: this block → tabs-nav or tabs-panels → blockparty/tabs.
- const directParent = getBlockRootClientId( clientId );
- const tabsId = directParent
- ? getBlockRootClientId( directParent )
- : null;
- return {
- selectedBlockClientId: selected,
- closestTabItemId: closest,
- tabsBlockId: tabsId,
- myIndex: getBlockIndex( clientId ),
- };
- },
- [ clientId ]
- );
+/**
+ * Finds the tab item (nav or panel) closest to the current selection.
+ *
+ * @param {Function} selectStore Bound select from useSelect.
+ * @return {string|null} Closest tab item clientId, or null.
+ */
+function getClosestTabItemClientId( selectStore ) {
+ const { getBlockName, getSelectedBlockClientId, getBlockParents } =
+ selectStore( 'core/block-editor' );
+ const selected = getSelectedBlockClientId();
+ if ( ! selected ) {
+ return null;
+ }
+ if ( TAB_ITEM_NAMES.indexOf( getBlockName( selected ) ) !== -1 ) {
+ return selected;
+ }
+ const parents = getBlockParents( selected );
+ for ( let i = 0; i < parents.length; i += 1 ) {
+ if ( TAB_ITEM_NAMES.indexOf( getBlockName( parents[ i ] ) ) !== -1 ) {
+ return parents[ i ];
+ }
+ }
+ return null;
+}
+
+/**
+ * Resolves the blockparty/tabs clientId that owns a tab item (same chain as legacy per-item sync).
+ *
+ * @param {Function} selectStore Bound select from useSelect.
+ * @param {string} tabItemId tabs-nav-item or tabs-panel-item clientId.
+ * @return {string|null} Owning blockparty/tabs clientId.
+ */
+function getOwningTabsBlockClientId( selectStore, tabItemId ) {
+ const { getBlockRootClientId } = selectStore( 'core/block-editor' );
+ const directParent = getBlockRootClientId( tabItemId );
+ return directParent ? getBlockRootClientId( directParent ) : null;
+}
+
+/**
+ * Subscribes to selection and syncs this tabs block's tabsActive when appropriate.
+ *
+ * @param {string} tabsBlockClientId This blockparty/tabs block clientId.
+ * @return {void}
+ */
+export function useSyncTabsActiveForTabsBlock( tabsBlockClientId ) {
+ const { shouldSync, targetTabsActive } = useSelect(
+ ( selectStore ) => {
+ const closest = getClosestTabItemClientId( selectStore );
+ if ( ! closest ) {
+ return { shouldSync: false, targetTabsActive: 0 };
+ }
+ const owningTabsId = getOwningTabsBlockClientId(
+ selectStore,
+ closest
+ );
+ if ( owningTabsId !== tabsBlockClientId ) {
+ return { shouldSync: false, targetTabsActive: 0 };
+ }
+ const { getBlockIndex } = selectStore( 'core/block-editor' );
+ return {
+ shouldSync: true,
+ targetTabsActive: getBlockIndex( closest ),
+ };
+ },
+ [ tabsBlockClientId ]
+ );
const { updateBlockAttributes } = useDispatch( 'core/block-editor' );
- // When this block is the active tab (closest to selection or selected), sync tabsActive.
useEffect( () => {
- if ( ! selectedBlockClientId || ! tabsBlockId ) {
+ if ( ! shouldSync ) {
return;
}
- const isActiveTab =
- closestTabItemId === clientId || selectedBlockClientId === clientId;
- if ( ! isActiveTab ) {
+ const current =
+ select( 'core/block-editor' ).getBlockAttributes(
+ tabsBlockClientId
+ )?.tabsActive;
+ if ( current === targetTabsActive ) {
return;
}
- updateBlockAttributes( tabsBlockId, { tabsActive: myIndex } );
+ updateBlockAttributes( tabsBlockClientId, {
+ tabsActive: targetTabsActive,
+ } );
}, [
- selectedBlockClientId,
- closestTabItemId,
- clientId,
- tabsBlockId,
- myIndex,
+ shouldSync,
+ targetTabsActive,
+ tabsBlockClientId,
updateBlockAttributes,
] );
-
- return null;
}
diff --git a/src/blockparty-tabs/edit.js b/src/blockparty-tabs/edit.js
index edea034..0da9a0e 100644
--- a/src/blockparty-tabs/edit.js
+++ b/src/blockparty-tabs/edit.js
@@ -19,6 +19,7 @@ import {
justifySpaceBetween,
} from '@wordpress/icons';
import './editor.scss';
+import { useSyncTabsActiveForTabsBlock } from './SyncTabsActive';
const DEFAULT_TABS_POSITIONS = [
{
@@ -60,6 +61,7 @@ const setTabsIndex = ( setAttributes, clientId ) => {
};
export default function Edit( { attributes, setAttributes, clientId } ) {
+ useSyncTabsActiveForTabsBlock( clientId );
setTabsIndex( setAttributes, clientId );
const { title, mode } = attributes;
const blockProps = useBlockProps( {