Skip to content

Commit 9993b1d

Browse files
authored
Merge pull request #73 from github/simplify-events
Simplify events
2 parents 0b7d552 + 5334a82 commit 9993b1d

1 file changed

Lines changed: 43 additions & 57 deletions

File tree

src/tab-container-element.ts

Lines changed: 43 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
const HTMLElement = globalThis.HTMLElement || (null as unknown as (typeof window)['HTMLElement'])
22

3-
type IncrementKeyCode = 'ArrowRight' | 'ArrowDown'
4-
type DecrementKeyCode = 'ArrowUp' | 'ArrowLeft'
5-
63
function getTabs(el: TabContainerElement): HTMLElement[] {
74
return Array.from(el.querySelectorAll<HTMLElement>('[role="tablist"] [role="tab"]')).filter(
85
tab => tab instanceof HTMLElement && tab.closest(el.tagName) === el,
@@ -33,17 +30,6 @@ export class TabContainerChangeEvent extends Event {
3330
}
3431
}
3532

36-
function getNavigationKeyCodes(vertical: boolean): [IncrementKeyCode[], DecrementKeyCode[]] {
37-
if (vertical) {
38-
return [
39-
['ArrowDown', 'ArrowRight'],
40-
['ArrowUp', 'ArrowLeft'],
41-
]
42-
} else {
43-
return [['ArrowRight'], ['ArrowLeft']]
44-
}
45-
}
46-
4733
export class TabContainerElement extends HTMLElement {
4834
static define(tag = 'tab-container', registry = customElements) {
4935
registry.define(tag, this)
@@ -87,49 +73,8 @@ export class TabContainerElement extends HTMLElement {
8773
}
8874

8975
connectedCallback(): void {
90-
this.addEventListener('keydown', (event: KeyboardEvent) => {
91-
const target = event.target
92-
if (!(target instanceof HTMLElement)) return
93-
if (target.closest(this.tagName) !== this) return
94-
if (target.getAttribute('role') !== 'tab' && !target.closest('[role="tablist"]')) return
95-
const tabs = getTabs(this)
96-
const currentIndex = tabs.indexOf(tabs.find(tab => tab.matches('[aria-selected="true"]'))!)
97-
const [incrementKeys, decrementKeys] = getNavigationKeyCodes(
98-
target.closest('[role="tablist"]')?.getAttribute('aria-orientation') === 'vertical',
99-
)
100-
101-
if (incrementKeys.some(code => event.code === code)) {
102-
let index = currentIndex + 1
103-
if (index >= tabs.length) index = 0
104-
this.selectTab(index)
105-
} else if (decrementKeys.some(code => event.code === code)) {
106-
let index = currentIndex - 1
107-
if (index < 0) index = tabs.length - 1
108-
this.selectTab(index)
109-
} else if (event.code === 'Home') {
110-
this.selectTab(0)
111-
event.preventDefault()
112-
} else if (event.code === 'End') {
113-
this.selectTab(tabs.length - 1)
114-
event.preventDefault()
115-
}
116-
})
117-
118-
this.addEventListener('click', (event: MouseEvent) => {
119-
const tabs = getTabs(this)
120-
121-
if (!(event.target instanceof Element)) return
122-
if (event.target.closest(this.tagName) !== this) return
123-
124-
const tab = event.target.closest('[role="tab"]')
125-
if (!(tab instanceof HTMLElement) || !tab.closest('[role="tablist"]')) {
126-
return
127-
}
128-
129-
const index = tabs.indexOf(tab)
130-
this.selectTab(index)
131-
})
132-
76+
this.addEventListener('keydown', this)
77+
this.addEventListener('click', this)
13378
for (const tab of getTabs(this)) {
13479
if (!tab.hasAttribute('aria-selected')) {
13580
tab.setAttribute('aria-selected', 'false')
@@ -144,6 +89,47 @@ export class TabContainerElement extends HTMLElement {
14489
}
14590
}
14691

92+
handleEvent(event: Event) {
93+
if (event.type === 'click') return this.#handleClick(event as MouseEvent)
94+
if (event.type === 'keydown') return this.#handleKeydown(event as KeyboardEvent)
95+
}
96+
97+
#handleKeydown(event: KeyboardEvent) {
98+
const tab = (event.target as HTMLElement)?.closest?.('[role="tab"]')
99+
if (!tab) return
100+
const tabs = getTabs(this)
101+
if (!tabs.includes(tab as HTMLElement)) return
102+
103+
const currentIndex = tabs.indexOf(tabs.find(e => e.matches('[aria-selected="true"]'))!)
104+
const vertical = tab.closest('[role="tablist"]')?.getAttribute('aria-orientation') === 'vertical'
105+
const prevTab = event.code === 'ArrowLeft' || (vertical && event.code === 'ArrowUp')
106+
const nextTab = event.code === 'ArrowRight' || (vertical && event.code === 'ArrowDown')
107+
108+
if (nextTab) {
109+
let index = currentIndex + 1
110+
if (index >= tabs.length) index = 0
111+
this.selectTab(index)
112+
} else if (prevTab) {
113+
let index = currentIndex - 1
114+
if (index < 0) index = tabs.length - 1
115+
this.selectTab(index)
116+
} else if (event.code === 'Home') {
117+
this.selectTab(0)
118+
event.preventDefault()
119+
} else if (event.code === 'End') {
120+
this.selectTab(tabs.length - 1)
121+
event.preventDefault()
122+
}
123+
}
124+
125+
#handleClick(event: MouseEvent) {
126+
const tab = (event.target as HTMLElement)?.closest?.('[role=tab]')
127+
if (!tab) return
128+
const tabs = getTabs(this)
129+
const index = tabs.indexOf(tab as HTMLElement)
130+
if (index >= 0) this.selectTab(index)
131+
}
132+
147133
selectTab(index: number): void {
148134
const tabs = getTabs(this)
149135
const panels = Array.from(this.querySelectorAll<HTMLElement>('[role="tabpanel"]')).filter(

0 commit comments

Comments
 (0)