@oslokommune/punkt-elements
Version:
Komponentbiblioteket til Punkt, et designsystem laget av Oslo Origo
159 lines (143 loc) • 4.57 kB
text/typescript
import { PktShadowElement } from '@/base-elements/element'
import { html, PropertyValues } from 'lit'
import { customElement, property } from 'lit/decorators.js'
import type { THeadingLevel, THeadingSize, THeadingWeight } from 'shared-types'
export type TPktHeadingLevel = THeadingLevel
export type TPktHeadingSize = THeadingSize
export type TPktHeadingWeight = THeadingWeight
export interface IPktHeading {
size?: TPktHeadingSize
level?: TPktHeadingLevel
weight?: TPktHeadingWeight
visuallyHidden?: boolean
align?: 'start' | 'center' | 'end'
}
export class PktHeading extends PktShadowElement<IPktHeading> implements IPktHeading {
size: TPktHeadingSize | undefined = undefined
level: TPktHeadingLevel = 2
weight: TPktHeadingWeight | undefined = undefined
visuallyHidden: boolean = false
align: 'start' | 'center' | 'end' | undefined =
undefined
connectedCallback(): void {
super.connectedCallback()
this.setAttribute('role', 'heading')
this.setAttribute('aria-level', String(this.level))
this.updateHostClasses()
}
attributeChangedCallback(name: string, _old: string | null, value: string | null): void {
super.attributeChangedCallback(name, _old, value)
if (name === 'level' && value) {
this.setLevel(Number(value) as TPktHeadingLevel)
}
if (name === 'visuallyHidden') {
this.visuallyHidden = value !== null && value !== 'false'
}
if (name === 'size' || name === 'visuallyHidden' || name === 'align' || name === 'weight') {
this.updateHostClasses()
}
}
protected updated(_changedProperties: PropertyValues): void {
super.updated(_changedProperties)
if (_changedProperties.has('level')) {
this.setLevel(this.level)
if (!this.hasAttribute('size')) {
this.size = this.defaultSizeForLevel
}
if (!this.hasAttribute('weight')) {
this.weight = this.defaultWeightForLevel
}
}
if (
!this.hasAttribute('size') &&
(_changedProperties.has('level') || this.size === undefined)
) {
this.size = this.defaultSizeForLevel
}
if (
_changedProperties.has('size') ||
_changedProperties.has('visuallyHidden') ||
_changedProperties.has('align') ||
_changedProperties.has('weight')
) {
this.updateHostClasses()
}
}
private setLevel(level: TPktHeadingLevel): void {
if (level >= 1 && level <= 6) {
this.level = level
this.setAttribute('aria-level', String(level))
} else {
console.warn(`Invalid heading level: ${level}. Must be between 1 and 6.`)
}
}
private get defaultSizeForLevel(): TPktHeadingSize {
switch (this.level) {
case 1:
return 'xlarge'
case 2:
return 'large'
case 3:
return 'medium'
case 4:
return 'small'
case 5:
return 'xsmall'
case 6:
return 'xsmall'
default:
return 'medium'
}
}
private get defaultWeightForLevel(): TPktHeadingWeight {
switch (this.level) {
case 1:
return 'regular'
case 2:
return 'regular'
case 3:
return 'medium'
case 4:
return 'medium'
case 5:
return 'medium'
case 6:
return 'medium'
default:
return 'medium'
}
}
private updateHostClasses() {
// Remove all possible classes first
this.classList.remove(
'pkt-heading',
'pkt-heading--xsmall',
'pkt-heading--small',
'pkt-heading--medium',
'pkt-heading--large',
'pkt-heading--xlarge',
'pkt-sr-only',
'pkt-heading--start',
'pkt-heading--center',
'pkt-heading--end',
'pkt-heading--light',
'pkt-heading--regular',
'pkt-heading--medium',
'pkt-heading--bold',
)
// Add current classes
this.classList.add('pkt-heading')
if (this.size) this.classList.add(`pkt-heading--${this.size}`)
if (this.weight) this.classList.add(`pkt-heading--fw-${this.weight}`)
if (this.visuallyHidden) this.classList.add('pkt-sr-only')
if (this.align) this.classList.add(`pkt-heading--${this.align}`)
}
render() {
return html`<slot></slot>`
}
}
try {
customElement('pkt-heading')(PktHeading)
} catch (e) {
console.warn('Forsøker å definere <pkt-heading>, men den er allerede definert')
}