diff --git a/.plugin-data b/.plugin-data index dca7deb..c4ee859 100644 --- a/.plugin-data +++ b/.plugin-data @@ -1,4 +1,4 @@ { - "version": "1.0.5", + "version": "1.0.6", "slug": "blockparty-tabs" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 0eeec90..fe7011a 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.0.6 - 2026-02-11 + +- Update view and edit script to allow to use nested tabs block (tabs inside tab panel). + ## 1.0.5 - 2025-11-10 - Update block icons diff --git a/blockparty-tabs.php b/blockparty-tabs.php index 0b48737..fbcefff 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.0.5 + * Version: 1.0.6 * 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.0.5' ); +define( 'BLOCKPARTY_TABS_VERSION', '1.0.6' ); 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/package.json b/package.json index e1dfa1f..82bdcf0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blockparty-tabs", - "version": "1.0.5", + "version": "1.0.6", "description": "Accessible tabs block for WordPress", "author": "Be API Technical team", "license": "GPL-2.0-or-later", diff --git a/readme.txt b/readme.txt index 843065a..c6148a1 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.0.6 = + +* Update view and edit script to allow to use nested tabs block (tabs inside tab panel). + = 1.0.5 = * Update block icons diff --git a/src/blockparty-tabs-nav-item/block.json b/src/blockparty-tabs-nav-item/block.json index 4e32968..dc0bbb8 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.0.5", + "version": "1.0.6", "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 2dc11e9..e044d51 100644 --- a/src/blockparty-tabs-nav-item/edit.js +++ b/src/blockparty-tabs-nav-item/edit.js @@ -5,6 +5,7 @@ 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, @@ -47,6 +48,7 @@ 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 ] + ); + + const { updateBlockAttributes } = useDispatch( 'core/block-editor' ); + + // When this block is the active tab (closest to selection or selected), sync tabsActive. + useEffect( () => { + if ( ! selectedBlockClientId || ! tabsBlockId ) { + return; + } + const isActiveTab = + closestTabItemId === clientId || selectedBlockClientId === clientId; + if ( ! isActiveTab ) { + return; + } + updateBlockAttributes( tabsBlockId, { tabsActive: myIndex } ); + }, [ + selectedBlockClientId, + closestTabItemId, + clientId, + tabsBlockId, + myIndex, + updateBlockAttributes, + ] ); + + return null; +} diff --git a/src/blockparty-tabs/TabsFocus.js b/src/blockparty-tabs/TabsFocus.js deleted file mode 100644 index ddd229d..0000000 --- a/src/blockparty-tabs/TabsFocus.js +++ /dev/null @@ -1,44 +0,0 @@ -import { withSelect } from '@wordpress/data'; -import { compose } from '@wordpress/compose'; - -const TabsFocus = ( { activeTab, setAttributes } ) => { - if ( activeTab >= 0 ) { - setAttributes( { tabsActive: activeTab } ); - } - return null; -}; - -export default compose( [ - withSelect( ( select, ownProps ) => { - const { - getBlockName, - getBlockIndex, - getSelectedBlockClientId, - getBlockParentsByBlockName, - hasSelectedInnerBlock, - } = select( 'core/block-editor' ); - if ( ! hasSelectedInnerBlock( ownProps.clientId, true ) ) { - return { - activeTab: -1, - setAttributes: ownProps.setAttributes, - }; - } - const selected = getSelectedBlockClientId(); - const name = getBlockName( selected ); - let currentIndex = getBlockIndex( selected ); - if ( - 'blockparty/tabs-panel-item' !== name && - 'blockparty/tabs-nav-item' !== name - ) { - const parents = getBlockParentsByBlockName( selected, [ - 'blockparty/tabs-nav-item', - 'blockparty/tabs-panel-item', - ] ); - currentIndex = getBlockIndex( parents[ 0 ] ); - } - return { - activeTab: currentIndex, - setAttributes: ownProps.setAttributes, - }; - } ), -] )( TabsFocus ); diff --git a/src/blockparty-tabs/block.json b/src/blockparty-tabs/block.json index b6e6f31..c5830d4 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.0.5", + "version": "1.0.6", "title": "Tabs", "category": "widgets", "description": "Accessible tabs block", diff --git a/src/blockparty-tabs/edit.js b/src/blockparty-tabs/edit.js index fd56104..edea034 100644 --- a/src/blockparty-tabs/edit.js +++ b/src/blockparty-tabs/edit.js @@ -9,7 +9,6 @@ import { } from '@wordpress/block-editor'; import { PanelBody, PanelRow, TextControl } from '@wordpress/components'; import { select } from '@wordpress/data'; -import TabsFocus from './TabsFocus'; import { heading, justifyRight, @@ -119,7 +118,6 @@ export default function Edit( { attributes, setAttributes, clientId } ) { -
); diff --git a/src/blockparty-tabs/script.js b/src/blockparty-tabs/script.js index 38f8623..8d02185 100644 --- a/src/blockparty-tabs/script.js +++ b/src/blockparty-tabs/script.js @@ -18,18 +18,17 @@ class TabsAutomatic { this.firstTab = null; this.lastTab = null; - this.tabs = Array.from( - this.tablistNode.querySelectorAll( '[role=tab]' ) + this.tabnav = this.tablistNode.querySelector( + '.wp-block-blockparty-tabs-nav' ); + this.tabs = Array.from( this.tabnav.querySelectorAll( 'a[role=tab]' ) ); + this.tabpanelsNode = this.tabnav.nextElementSibling; + this.tabpanels = []; for ( let i = 0; i < this.tabs.length; i += 1 ) { const tab = this.tabs[ i ]; - const tabpanel = this.tablistNode - .closest( '.wp-block-blockparty-tabs' ) - .querySelectorAll( '.wp-block-blockparty-tabs-panels > *' )[ - i - ]; + const tabpanel = this.tabpanelsNode.children[ i ]; tab.tabIndex = -1; tab.setAttribute( 'aria-selected', 'false' );