diff --git a/examples/index.html b/examples/index.html index 26f55e8..94e6620 100644 --- a/examples/index.html +++ b/examples/index.html @@ -86,16 +86,12 @@

Vertical (custom tablist)

Panel with extra buttons

-
- - -
- - - -
- -
+ + + + + +
Panel 1
diff --git a/src/tab-container-element.ts b/src/tab-container-element.ts index 28e37ae..6693532 100644 --- a/src/tab-container-element.ts +++ b/src/tab-container-element.ts @@ -77,6 +77,18 @@ export class TabContainerElement extends HTMLElement { } } + get #beforeTabsSlot() { + return this.shadowRoot!.querySelector('slot[part="before-tabs"]')! + } + + get #afterTabsSlot() { + return this.shadowRoot!.querySelector('slot[part="after-tabs"]')! + } + + get #afterPanelsSlot() { + return this.shadowRoot!.querySelector('slot[part="after-panels"]')! + } + get #tabListSlot() { return this.shadowRoot!.querySelector('slot[part="tablist"]')! } @@ -94,8 +106,12 @@ export class TabContainerElement extends HTMLElement { ) } + get activePanel() { + return this.#panelSlot.assignedNodes()[0] as HTMLElement + } + get vertical(): boolean { - return this.#tabList.getAttribute('aria-orientation') === 'vertical' + return this.#tabList?.getAttribute('aria-orientation') === 'vertical' } set vertical(isVertical: boolean) { @@ -112,12 +128,21 @@ export class TabContainerElement extends HTMLElement { connectedCallback(): void { this.#internals ||= this.attachInternals ? this.attachInternals() : null const shadowRoot = this.shadowRoot || this.attachShadow({mode: 'open', slotAssignment: 'manual'}) + const tabListContainer = document.createElement('div') + tabListContainer.style.display = 'flex' const tabListSlot = document.createElement('slot') tabListSlot.setAttribute('part', 'tablist') const panelSlot = document.createElement('slot') panelSlot.setAttribute('part', 'panel') panelSlot.setAttribute('role', 'presentation') - shadowRoot.replaceChildren(tabListSlot, panelSlot) + const beforeTabSlot = document.createElement('slot') + beforeTabSlot.setAttribute('part', 'before-tabs') + const afterTabSlot = document.createElement('slot') + afterTabSlot.setAttribute('part', 'after-tabs') + tabListContainer.append(beforeTabSlot, tabListSlot, afterTabSlot) + const afterSlot = document.createElement('slot') + afterSlot.setAttribute('part', 'after-panels') + shadowRoot.replaceChildren(tabListContainer, panelSlot, afterSlot) if (this.#internals && 'role' in this.#internals) { this.#internals.role = 'presentation' @@ -186,7 +211,7 @@ export class TabContainerElement extends HTMLElement { selectTab(index: number): void { if (!this.#setup) { - const tabListSlot = this.#tabListSlot; + const tabListSlot = this.#tabListSlot const customTabList = this.querySelector('[role=tablist]') if (customTabList && customTabList.closest(this.tagName) === this) { tabListSlot.assign(customTabList) @@ -207,6 +232,30 @@ export class TabContainerElement extends HTMLElement { if (this.vertical) { this.#tabList.setAttribute('aria-orientation', 'vertical') } + const beforeSlotted: Element[] = [] + const afterTabSlotted: Element[] = [] + const afterSlotted: Element[] = [] + let autoSlotted = beforeSlotted + for (const child of this.children) { + if (child.getAttribute('role') === 'tab' || child.getAttribute('role') === 'tablist') { + autoSlotted = afterTabSlotted + continue + } + if (child.getAttribute('role') === 'tabpanel') { + autoSlotted = afterSlotted + continue + } + if (child.getAttribute('slot') === 'before-tabs') { + beforeSlotted.push(child) + } else if (child.getAttribute('slot') === 'after-tabs') { + afterTabSlotted.push(child) + } else { + autoSlotted.push(child) + } + } + this.#beforeTabsSlot.assign(...beforeSlotted) + this.#afterTabsSlot.assign(...afterTabSlotted) + this.#afterPanelsSlot.assign(...afterSlotted) } const tabs = this.#tabs