diff --git a/.plugin-data b/.plugin-data index 1b94983..ff53658 100644 --- a/.plugin-data +++ b/.plugin-data @@ -1,4 +1,4 @@ { - "version": "1.1.2", + "version": "1.1.3", "slug": "blockparty-tabs" } diff --git a/.wordpress-org/blueprints/blueprint.json b/.wordpress-org/blueprints/blueprint.json index 9e4b1c8..c3b6a21 100644 --- a/.wordpress-org/blueprints/blueprint.json +++ b/.wordpress-org/blueprints/blueprint.json @@ -11,7 +11,7 @@ "pluginData": { "resource": "git:directory", "url": "https://github.com/BeAPI/blockparty-tabs", - "ref": "1.1.2", + "ref": "1.1.3", "refType": "tag" }, "options": { diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bbebbe..ec6f75a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 1.1.3 - 2026-04-27 + +- Performance improvements + ## 1.1.2 - 2026-04-24 - Fix css for nested tabs block diff --git a/blockparty-tabs.php b/blockparty-tabs.php index d7d5296..a9bbbab 100644 --- a/blockparty-tabs.php +++ b/blockparty-tabs.php @@ -4,7 +4,7 @@ * Description: Accessible Tabs block for WordPress gutenberg. * Requires at least: 6.2 * Requires PHP: 8.1 - * Version: 1.1.2 + * Version: 1.1.3 * Author: Be API Technical team * Author URI: https://beapi.fr * License: GPL-2.0-or-later @@ -14,7 +14,7 @@ namespace Blockparty\Tabs; -define( 'BLOCKPARTY_TABS_VERSION', '1.1.2' ); +define( 'BLOCKPARTY_TABS_VERSION', '1.1.3' ); define( 'BLOCKPARTY_TABS_URL', plugin_dir_url( __FILE__ ) ); define( 'BLOCKPARTY_TABS_DIR', plugin_dir_path( __FILE__ ) ); define( 'BLOCKPARTY_TABS_PLUGIN_BASENAME', plugin_basename( __FILE__ ) ); diff --git a/readme.txt b/readme.txt index 28f8f03..8fb5c20 100644 --- a/readme.txt +++ b/readme.txt @@ -31,6 +31,10 @@ directory take precedence. For example, `/assets/screenshot-1.png` would win ove == Changelog == += 1.1.3 = + +* Performance improvements + = 1.1.2 = * Fix css for nested tabs block diff --git a/src/blockparty-tabs-nav-item/block.json b/src/blockparty-tabs-nav-item/block.json index d49076e..40d356e 100644 --- a/src/blockparty-tabs-nav-item/block.json +++ b/src/blockparty-tabs-nav-item/block.json @@ -2,7 +2,7 @@ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 2, "name": "blockparty/tabs-nav-item", - "version": "1.1.2", + "version": "1.1.3", "title": "Tab", "category": "widgets", "description": "Accessible tabs block item", 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/block.json b/src/blockparty-tabs/block.json index 151b963..d4e8aa2 100644 --- a/src/blockparty-tabs/block.json +++ b/src/blockparty-tabs/block.json @@ -2,7 +2,7 @@ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 2, "name": "blockparty/tabs", - "version": "1.1.2", + "version": "1.1.3", "title": "Tabs", "category": "widgets", "description": "Accessible tabs block", 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( {