first commit
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
import { register } from '@elementor/frontend-handlers';
|
||||
import { Alpine } from '@elementor/alpinejs';
|
||||
import { TAB_ELEMENT_TYPE, TAB_CONTENT_ELEMENT_TYPE, getTabId, getTabContentId, getIndex, getNextTab } from './utils';
|
||||
|
||||
const SELECTED_CLASS = 'e--selected';
|
||||
|
||||
register( {
|
||||
elementType: 'e-tabs',
|
||||
id: 'e-tabs-handler',
|
||||
callback: ( { element, settings } ) => {
|
||||
const tabsId = element.dataset.id;
|
||||
|
||||
Alpine.data( `eTabs${ tabsId }`, () => ( {
|
||||
activeTab: settings[ 'default-active-tab' ],
|
||||
|
||||
navigateTabs( { key, target: tab } ) {
|
||||
const nextTab = getNextTab( key, tab );
|
||||
|
||||
nextTab.focus();
|
||||
},
|
||||
tab: {
|
||||
':id'() {
|
||||
const index = getIndex( this.$el, TAB_ELEMENT_TYPE );
|
||||
|
||||
return getTabId( tabsId, index );
|
||||
},
|
||||
'@click'() {
|
||||
const id = this.$el.id;
|
||||
|
||||
this.activeTab = id;
|
||||
},
|
||||
'@keydown.arrow-right.prevent'( event ) {
|
||||
this.navigateTabs( event );
|
||||
},
|
||||
'@keydown.arrow-left.prevent'( event ) {
|
||||
this.navigateTabs( event );
|
||||
},
|
||||
':class'() {
|
||||
const id = this.$el.id;
|
||||
|
||||
return this.activeTab === id ? SELECTED_CLASS : '';
|
||||
},
|
||||
':aria-selected'() {
|
||||
const id = this.$el.id;
|
||||
|
||||
return this.activeTab === id ? 'true' : 'false';
|
||||
},
|
||||
':tabindex'() {
|
||||
const id = this.$el.id;
|
||||
|
||||
return this.activeTab === id ? '0' : '-1';
|
||||
},
|
||||
':aria-controls'() {
|
||||
const index = getIndex( this.$el, TAB_ELEMENT_TYPE );
|
||||
|
||||
return getTabContentId( tabsId, index );
|
||||
},
|
||||
},
|
||||
|
||||
tabContent: {
|
||||
':aria-labelledby'() {
|
||||
const index = getIndex( this.$el, TAB_CONTENT_ELEMENT_TYPE );
|
||||
|
||||
return getTabId( tabsId, index );
|
||||
},
|
||||
'x-show'() {
|
||||
const index = getIndex( this.$el, TAB_CONTENT_ELEMENT_TYPE );
|
||||
const tabId = getTabId( tabsId, index );
|
||||
|
||||
const isActive = this.activeTab === tabId;
|
||||
|
||||
this.$nextTick( () => {
|
||||
this.$el.classList.toggle( SELECTED_CLASS, isActive );
|
||||
} );
|
||||
|
||||
return isActive;
|
||||
},
|
||||
':id'() {
|
||||
const index = getIndex( this.$el, TAB_CONTENT_ELEMENT_TYPE );
|
||||
|
||||
return getTabContentId( tabsId, index );
|
||||
},
|
||||
},
|
||||
} ) );
|
||||
},
|
||||
} );
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import { register } from '@elementor/frontend-handlers';
|
||||
import { Alpine, refreshTree } from '@elementor/alpinejs';
|
||||
import { TAB_ELEMENT_TYPE, TAB_CONTENT_ELEMENT_TYPE, getTabId, getIndex } from './utils';
|
||||
|
||||
register( {
|
||||
elementType: 'e-tabs',
|
||||
id: 'e-tabs-preview-handler',
|
||||
callback: ( { element, signal, listenToChildren } ) => {
|
||||
window?.parent.addEventListener( 'elementor/navigator/item/click', ( event ) => {
|
||||
const { id, type } = event.detail;
|
||||
|
||||
if ( type !== TAB_ELEMENT_TYPE && type !== TAB_CONTENT_ELEMENT_TYPE ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const targetElement = Alpine.$data( element ).$refs[ id ];
|
||||
|
||||
if ( ! targetElement ) {
|
||||
return;
|
||||
}
|
||||
|
||||
const targetIndex = getIndex( targetElement, type );
|
||||
Alpine.$data( element ).activeTab = getTabId( element.dataset.id, targetIndex );
|
||||
}, { signal } );
|
||||
|
||||
// Re-initialize Alpine to sync with editor DOM manipulations that bypass Alpine's reactivity.
|
||||
listenToChildren( [ TAB_ELEMENT_TYPE, TAB_CONTENT_ELEMENT_TYPE ] )
|
||||
.render( () => refreshTree( element ) );
|
||||
},
|
||||
} );
|
||||
@@ -0,0 +1,44 @@
|
||||
export const TAB_ELEMENT_TYPE = 'e-tab';
|
||||
export const TAB_CONTENT_ELEMENT_TYPE = 'e-tab-content';
|
||||
export const TABS_CONTENT_AREA_ELEMENT_TYPE = 'e-tabs-content-area';
|
||||
export const TABS_MENU_ELEMENT_TYPE = 'e-tabs-menu';
|
||||
|
||||
const NAVIGATE_UP_KEYS = [ 'ArrowUp', 'ArrowLeft' ];
|
||||
const NAVIGATE_DOWN_KEYS = [ 'ArrowDown', 'ArrowRight' ];
|
||||
|
||||
export const getTabId = ( tabsId, tabIndex ) => {
|
||||
return `${ tabsId }-tab-${ tabIndex }`;
|
||||
};
|
||||
|
||||
export const getTabContentId = ( tabsId, tabIndex ) => {
|
||||
return `${ tabsId }-tab-content-${ tabIndex }`;
|
||||
};
|
||||
|
||||
export const getChildren = ( el, elementType ) => {
|
||||
const parent = el.parentElement;
|
||||
|
||||
return Array.from( parent.children ).filter( ( child ) => {
|
||||
return child.dataset.element_type === elementType;
|
||||
} );
|
||||
};
|
||||
|
||||
export const getIndex = ( el, elementType ) => {
|
||||
const children = getChildren( el, elementType );
|
||||
|
||||
return children.indexOf( el );
|
||||
};
|
||||
|
||||
export const getNextTab = ( key, tab ) => {
|
||||
const tabs = getChildren( tab, TAB_ELEMENT_TYPE );
|
||||
const tabsLength = tabs.length;
|
||||
|
||||
const currentIndex = getIndex( tab, TAB_ELEMENT_TYPE );
|
||||
|
||||
if ( NAVIGATE_DOWN_KEYS.includes( key ) ) {
|
||||
return tabs[ ( currentIndex + 1 ) % tabsLength ];
|
||||
}
|
||||
|
||||
if ( NAVIGATE_UP_KEYS.includes( key ) ) {
|
||||
return tabs[ ( currentIndex - 1 + tabsLength ) % tabsLength ];
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user