From 74059b5f555ad93cdd31320fea6907e101beb05d Mon Sep 17 00:00:00 2001 From: Sean Doyle Date: Wed, 8 May 2024 10:32:15 -0400 Subject: [PATCH 1/5] Fix README backtick formatted A fenced HTML code block wasn't closed properly, which affected subsequent markdown formatting syntax. This commit closes that block, and adds newlines between headings and other fenced code blocks. --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 09354f6..62103ab 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,7 @@ If none of the tabs have `aria-selected=true`, then the first tab will be select +``` ### Events @@ -109,6 +110,7 @@ In those cases, apply `data-tab-container-no-tabstop` to the `tabpanel` element. ### Unmanaged slots `` aims to simplify complex markup away in the ShadowDOM, so that the HTML you end up writing is overall less. However sometimes it can be useful to have _full_ control over the markup. Each of the `::part` selectors are also ``s, this means you can take any part and slot it, overriding the built-in ShadowDOM. + #### Unmanaged `tablist` You are able to provide your own `role=tablist` and `` will accommodate. This can be useful if you need extra presentational markup in the tablist. But remember: @@ -148,6 +150,7 @@ You are able to slot the `tablist-tab-wrapper` part. This slot manages the tabs
``` + #### Unmanaged `tablist-wrapper` If you want to take full control over the entire tab region, including managing the content before and after the tabs, then you can slot the `tablist-wrapper` element. Bear in mind if you're supplying this element that: From f6a218f24fe22449ff2a0dbbbe23e14216b55a29 Mon Sep 17 00:00:00 2001 From: Keith Cirkel Date: Wed, 8 May 2024 18:09:46 +0100 Subject: [PATCH 2/5] drop redundant role=presentation from slot element --- src/tab-container-element.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tab-container-element.ts b/src/tab-container-element.ts index 93e625a..14de5ef 100644 --- a/src/tab-container-element.ts +++ b/src/tab-container-element.ts @@ -184,7 +184,6 @@ export class TabContainerElement extends HTMLElement { const panelSlot = document.createElement('slot') panelSlot.setAttribute('part', 'panel') panelSlot.setAttribute('name', 'panel') - panelSlot.setAttribute('role', 'presentation') const beforeTabSlot = document.createElement('slot') beforeTabSlot.setAttribute('part', 'before-tabs') beforeTabSlot.setAttribute('name', 'before-tabs') From 2d6c046721a0e8170d379c56a0ed07f5c473aaa2 Mon Sep 17 00:00:00 2001 From: Owen Niblock Date: Thu, 9 May 2024 11:58:47 +0100 Subject: [PATCH 3/5] Tidy up manual slot assignment code --- src/tab-container-element.ts | 64 ++++++++++++++---------------------- 1 file changed, 24 insertions(+), 40 deletions(-) diff --git a/src/tab-container-element.ts b/src/tab-container-element.ts index 14de5ef..2374f00 100644 --- a/src/tab-container-element.ts +++ b/src/tab-container-element.ts @@ -1,5 +1,20 @@ const HTMLElement = globalThis.HTMLElement || (null as unknown as (typeof window)['HTMLElement']) -const manualSlotsSupported = 'assign' in (globalThis.HTMLSlotElement?.prototype || {}) + +// Function to see if manual slots are supported and if not, manual assign the slot attribute +const assignSlotWithFallback = + 'assign' in (globalThis.HTMLSlotElement?.prototype || {}) + ? (slot: HTMLSlotElement, ...elements: Element[]) => { + slot.assign(...elements) + } + : (slot: HTMLSlotElement, ...elements: Element[]) => { + const host = (slot.getRootNode() as ShadowRoot).host + for (const element of host.querySelectorAll(`[slot="${slot.name}"]`)) { + element.removeAttribute('slot') + } + for (const element of elements) { + element.setAttribute('slot', slot.name) + } + } export class TabContainerChangeEvent extends Event { constructor( @@ -289,32 +304,14 @@ export class TabContainerElement extends HTMLElement { const customTabListWrapper = this.querySelector('[slot=tablist-wrapper]') const customTabListTabWrapper = this.querySelector('[slot=tablist-tab-wrapper]') if (customTabListWrapper && customTabListWrapper.closest(this.tagName) === this) { - if (manualSlotsSupported) { - tabListWrapper.assign(customTabListWrapper) - } else { - customTabListWrapper.setAttribute('slot', 'tablist-wrapper') - } + assignSlotWithFallback(tabListWrapper, customTabListWrapper) } else if (customTabListTabWrapper && customTabListTabWrapper.closest(this.tagName) === this) { - if (manualSlotsSupported) { - tabListTabWrapper.assign(customTabListTabWrapper) - } else { - customTabListTabWrapper.setAttribute('slot', 'tablist-tab-wrapper') - } + assignSlotWithFallback(tabListTabWrapper, customTabListTabWrapper) } else if (customTabList && customTabList.closest(this.tagName) === this) { - if (manualSlotsSupported) { - tabListSlot.assign(customTabList) - } else { - customTabList.setAttribute('slot', 'tablist') - } + assignSlotWithFallback(tabListSlot, customTabList) } else { this.#tabListTabWrapper.role = 'tablist' - if (manualSlotsSupported) { - tabListSlot.assign(...[...this.children].filter(e => e.matches('[role=tab]'))) - } else { - for (const e of this.children) { - if (e.matches('[role=tab]')) e.setAttribute('slot', 'tablist') - } - } + assignSlotWithFallback(tabListSlot, ...[...this.children].filter(e => e.matches('[role=tab]'))) } const tabList = this.#tabList this.#reflectAttributeToShadow('aria-description', tabList) @@ -349,15 +346,9 @@ export class TabContainerElement extends HTMLElement { autoSlotted.push(child) } } - if (manualSlotsSupported) { - this.#beforeTabsSlot.assign(...beforeSlotted) - this.#afterTabsSlot.assign(...afterTabSlotted) - this.#afterPanelsSlot.assign(...afterSlotted) - } else { - for (const el of beforeSlotted) el.setAttribute('slot', 'before-tabs') - for (const el of afterTabSlotted) el.setAttribute('slot', 'after-tabs') - for (const el of afterSlotted) el.setAttribute('slot', 'after-panels') - } + assignSlotWithFallback(this.#beforeTabsSlot, ...beforeSlotted) + assignSlotWithFallback(this.#afterTabsSlot, ...afterTabSlotted) + assignSlotWithFallback(this.#afterPanelsSlot, ...afterSlotted) } const defaultTab = this.defaultTabIndex const defaultIndex = defaultTab >= 0 ? defaultTab : this.selectedTabIndex @@ -400,18 +391,11 @@ export class TabContainerElement extends HTMLElement { if (!panel.hasAttribute('tabindex') && !panel.hasAttribute('data-tab-container-no-tabstop')) { panel.setAttribute('tabindex', '0') } - if (!manualSlotsSupported && panel.hasAttribute('slot')) { - panel.removeAttribute('slot') - } } selectedTab.setAttribute('aria-selected', 'true') selectedTab.setAttribute('tabindex', '0') - if (manualSlotsSupported) { - this.#panelSlot.assign(selectedPanel) - } else { - selectedPanel.setAttribute('slot', 'panel') - } + assignSlotWithFallback(this.#panelSlot, selectedPanel) selectedPanel.hidden = false if (this.#setupComplete) { From e6a75c9b4b8d58b7bdc0fe5af0f04af7d2ae6d58 Mon Sep 17 00:00:00 2001 From: Owen Niblock Date: Thu, 9 May 2024 12:32:57 +0100 Subject: [PATCH 4/5] Fixes tablist-tab-wrapper accessibility violation by reverting div->slot change --- src/tab-container-element.ts | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/tab-container-element.ts b/src/tab-container-element.ts index 2374f00..ebccbd9 100644 --- a/src/tab-container-element.ts +++ b/src/tab-container-element.ts @@ -110,7 +110,7 @@ export class TabContainerElement extends HTMLElement { static observedAttributes = ['vertical'] get #tabList() { - const wrapper = this.querySelector('[slot=tablist-wrapper],[slot=tablist-tab-wrapper]') + const wrapper = this.querySelector('[slot=tablist-wrapper]') if (wrapper?.closest(this.tagName) === this) { return wrapper.querySelector('[role=tablist]') as HTMLElement } @@ -127,7 +127,7 @@ export class TabContainerElement extends HTMLElement { } get #tabListTabWrapper() { - return this.shadowRoot!.querySelector('slot[part="tablist-tab-wrapper"]')! + return this.shadowRoot!.querySelector('div[part="tablist-tab-wrapper"]')! } get #beforeTabsSlot() { @@ -189,7 +189,7 @@ export class TabContainerElement extends HTMLElement { tabListContainer.style.display = 'flex' tabListContainer.setAttribute('part', 'tablist-wrapper') tabListContainer.setAttribute('name', 'tablist-wrapper') - const tabListTabWrapper = document.createElement('slot') + const tabListTabWrapper = document.createElement('div') tabListTabWrapper.setAttribute('part', 'tablist-tab-wrapper') tabListTabWrapper.setAttribute('name', 'tablist-tab-wrapper') const tabListSlot = document.createElement('slot') @@ -299,14 +299,10 @@ export class TabContainerElement extends HTMLElement { if (!this.#setupComplete) { const tabListSlot = this.#tabListSlot const tabListWrapper = this.#tabListWrapper - const tabListTabWrapper = this.#tabListTabWrapper const customTabList = this.querySelector('[role=tablist]') const customTabListWrapper = this.querySelector('[slot=tablist-wrapper]') - const customTabListTabWrapper = this.querySelector('[slot=tablist-tab-wrapper]') if (customTabListWrapper && customTabListWrapper.closest(this.tagName) === this) { assignSlotWithFallback(tabListWrapper, customTabListWrapper) - } else if (customTabListTabWrapper && customTabListTabWrapper.closest(this.tagName) === this) { - assignSlotWithFallback(tabListTabWrapper, customTabListTabWrapper) } else if (customTabList && customTabList.closest(this.tagName) === this) { assignSlotWithFallback(tabListSlot, customTabList) } else { @@ -326,11 +322,7 @@ export class TabContainerElement extends HTMLElement { const afterSlotted: Element[] = [] let autoSlotted = beforeSlotted for (const child of this.children) { - if ( - child.getAttribute('role') === 'tab' || - child.getAttribute('role') === 'tablist' || - child.getAttribute('slot') === 'tablist-tab-wrapper' - ) { + if (child.getAttribute('role') === 'tab' || child.getAttribute('role') === 'tablist') { autoSlotted = afterTabSlotted continue } From 4b09f51d1b81b97f2d9671a51bf3018ac9008854 Mon Sep 17 00:00:00 2001 From: Owen Niblock Date: Thu, 9 May 2024 12:35:37 +0100 Subject: [PATCH 5/5] Fix the test and examples page --- examples/index.html | 23 +-------------------- test/test.js | 50 --------------------------------------------- 2 files changed, 1 insertion(+), 72 deletions(-) diff --git a/examples/index.html b/examples/index.html index 12fc8e7..238e319 100644 --- a/examples/index.html +++ b/examples/index.html @@ -67,27 +67,6 @@

Horizontal (custom tablist and tablist-wrapper)

-

Horizontal (custom tablist and tablist-tab-wrapper)

- - -
-
- - - -
-
-
- Panel 1 -
- - -
-

Vertical (shadow tablist)

@@ -144,7 +123,7 @@

Set initially selected tab

Set default tab

- + diff --git a/test/test.js b/test/test.js index f5dce71..a65a03d 100644 --- a/test/test.js +++ b/test/test.js @@ -719,54 +719,4 @@ describe('tab-container', function () { assert.deepStrictEqual(panels.map(isHidden), [false, true, true], 'First panel is visible') }) }) - - describe('with custom tablist-tab-wrapper', function () { - beforeEach(function () { - document.body.innerHTML = ` - -
-
- - - -
-
- -
- Panel 2 -
- -
- ` - tabs = Array.from(document.querySelectorAll('button')) - panels = Array.from(document.querySelectorAll('[role="tabpanel"]')) - }) - - afterEach(function () { - // Check to make sure we still have accessible markup after the test finishes running. - expect(document.body).to.be.accessible() - - document.body.innerHTML = '' - }) - - it('has accessible markup', function () { - expect(document.body).to.be.accessible() - }) - - it('the second tab is still selected', function () { - assert.deepStrictEqual(tabs.map(isSelected), [false, true, false], 'Second tab is selected') - assert.deepStrictEqual(panels.map(isHidden), [true, false, true], 'Second panel is visible') - }) - - it('selects the clicked tab', function () { - tabs[0].click() - - assert.deepStrictEqual(tabs.map(isSelected), [true, false, false], 'First tab is selected') - assert.deepStrictEqual(panels.map(isHidden), [false, true, true], 'First panel is visible') - }) - }) }) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy