@oslokommune/punkt-elements
Version:
Komponentbiblioteket til Punkt, et designsystem laget av Oslo Origo
147 lines (128 loc) • 4.77 kB
text/typescript
import { PktElementWithSlot } from '@/base-elements/element-with-slot'
import { slotContent } from '@/directives/slot-content'
import { html } from 'lit'
import { customElement, property } from 'lit/decorators.js'
import { consume } from '@lit/context'
import { createRef, Ref, ref } from 'lit/directives/ref.js'
import { ifDefined } from 'lit/directives/if-defined.js'
import { tabsContext, type TabsContext } from './tabs-context'
export type TSkin = 'blue' | 'green' | 'red' | 'beige' | 'yellow' | 'grey' | 'gray' | 'blue-light'
export interface IPktTabItem {
active?: boolean
disabled?: boolean
href?: string
icon?: string
controls?: string
tag?: string
tagSkin?: TSkin
index?: number
}
export class PktTabItem extends PktElementWithSlot<IPktTabItem> implements IPktTabItem {
active: boolean = false
disabled: boolean = false
href: string = ''
icon: string = ''
controls: string = ''
tag: string = ''
tagSkin: TSkin = 'blue'
index: number = 0
// Consume context from parent pkt-tabs
context?: TabsContext
elementRef: Ref<HTMLAnchorElement | HTMLButtonElement> = createRef()
constructor() {
super()
}
connectedCallback() {
super.connectedCallback()
// Wait for element to be fully initialized
this.updateComplete.then(() => {
if (this.elementRef.value && this.context) {
this.context.registerTab(this.elementRef.value, this.index, this.disabled)
}
})
}
updated() {
if (this.elementRef.value && this.context) {
this.context.registerTab(this.elementRef.value, this.index, this.disabled)
}
}
private handleClick(event: Event) {
if (this.disabled) {
event.preventDefault()
event.stopPropagation()
return
}
if (this.context) {
this.context.handleClick(this.index)
}
}
private handleKeyDown(event: KeyboardEvent) {
if (this.disabled && (event.key === 'Enter' || event.key === ' ' || event.key === 'Spacebar')) {
event.preventDefault()
event.stopPropagation()
return
}
if (this.context) {
this.context.handleKeyUp(event, this.index)
}
}
render() {
const useArrowNav = this.context?.useArrowNav ?? true
const isActive = this.active && !this.disabled
const commonClasses = [isActive ? 'active' : '', this.disabled ? 'pkt-tabs__item--disabled' : '']
.filter(Boolean)
.join(' ')
const role = useArrowNav ? 'tab' : undefined
const ariaSelected = useArrowNav ? isActive : undefined
const tabIndex = this.disabled ? -1 : isActive || !useArrowNav ? undefined : -1
const iconClasses = `pkt-icon--small ${this.icon === 'check' ? 'pkt-tabs__status-icon' : ''}`
const content = html`
${this.icon ? html`<pkt-icon name=${this.icon} class=${iconClasses}></pkt-icon>` : ''}
<span>${slotContent(this)}</span>
${this.tag ? html`<pkt-tag skin=${this.tagSkin} size="small">${this.tag}</pkt-tag>` : ''}
`
if (this.href) {
return html`
<a
${ref(this.elementRef)}
href=${ifDefined(this.disabled ? undefined : this.href)}
class="pkt-tabs__link ${commonClasses}"
role=${ifDefined(role)}
aria-selected=${ifDefined(ariaSelected)}
aria-disabled=${ifDefined(this.disabled ? 'true' : undefined)}
aria-controls=${ifDefined(this.controls || undefined)}
tabindex=${ifDefined(tabIndex)}
=${this.handleClick}
=${this.handleKeyDown}
>
${content}
</a>
`
}
return html`
<button
${ref(this.elementRef)}
type="button"
class="pkt-tabs__button pkt-link-button ${commonClasses}"
?disabled=${this.disabled}
aria-disabled=${ifDefined(this.disabled ? 'true' : undefined)}
role=${ifDefined(role)}
aria-selected=${ifDefined(ariaSelected)}
aria-controls=${ifDefined(this.controls || undefined)}
tabindex=${ifDefined(tabIndex)}
=${this.handleClick}
=${this.handleKeyDown}
>
${content}
</button>
`
}
}
export default PktTabItem
try {
customElement('pkt-tab-item')(PktTabItem)
} catch (e) {
console.warn('Forsøker å definere <pkt-tab-item>, men den er allerede definert')
}