UNPKG

@oslokommune/punkt-elements

Version:

Komponentbiblioteket til Punkt, et designsystem laget av Oslo Origo

140 lines (119 loc) • 4.48 kB
import { classMap } from 'lit/directives/class-map.js' import { customElement, property, state } from 'lit/decorators.js' import { html, nothing, PropertyValues } from 'lit' import { PktElement } from '@/base-elements/element' import { PktSlotController } from '@/controllers/pkt-slot-controller' import { ref, createRef, Ref } from 'lit/directives/ref.js' import { TAriaLive } from '@/types/aria' import { updateClassAttribute } from '@/utils/classutils' import specs from 'componentSpecs/alert.json' import '@/components/icon' export type TAlertSkin = 'error' | 'success' | 'warning' | 'info' export interface IPktAlert { skin?: TAlertSkin closeAlert?: boolean title?: string date?: string | null ariaLive?: TAriaLive | null 'aria-live'?: TAriaLive | null compact?: boolean role?: string } @customElement('pkt-alert') export class PktAlert extends PktElement implements IPktAlert { defaultSlot: Ref<HTMLElement> = createRef() constructor() { super() this.slotController = new PktSlotController(this, this.defaultSlot) this._isClosed = false } // Properties @property({ type: Boolean, reflect: false }) compact = specs.props.compact.default @property({ type: String, reflect: true }) title: string = '' @property({ type: String, reflect: true }) skin: TAlertSkin = specs.props.skin .default as TAlertSkin @property({ type: String }) ariaLive: TAriaLive = specs.props.ariaLive.default as TAriaLive @property({ type: String, reflect: true }) 'aria-live': TAriaLive | null = null @property({ type: Boolean, reflect: true }) closeAlert = specs.props.closeAlert.default @property({ type: String, reflect: true }) date: string | null = null @property({ type: String, reflect: true }) role: string = 'status' @state() _isClosed: boolean = false // Lifecycle connectedCallback(): void { super.connectedCallback() this['aria-live'] = (this.getAttribute('aria-live') as TAriaLive) || this.ariaLive } attributeChangedCallback(name: string, _old: string | null, value: string | null): void { if (name === 'ariaLive') { this['aria-live'] = value as TAriaLive } super.attributeChangedCallback(name, _old, value) } protected updated(_changedProperties: PropertyValues): void { super.updated(_changedProperties) if (_changedProperties.has('ariaLive')) { this['aria-live'] = this.ariaLive } if (_changedProperties.has('_isClosed')) { updateClassAttribute(this, 'pkt-hide', this._isClosed) } } // Render render() { const classes = { 'pkt-alert': true, 'pkt-alert--compact': this.compact, [`pkt-alert--${this.skin}`]: this.skin, 'pkt-hide': this._isClosed, } const gridClasses = { 'pkt-alert__grid': true, 'pkt-alert__noTitle': !this.title, 'pkt-alert__noDate': !this.date, } return html` <div class=${classMap(classes)} aria-live=${this['aria-live']}> <div class=${classMap(gridClasses)}> <pkt-icon class="pkt-alert__icon" aria-hidden="true" name=${this.skin === 'info' ? 'alert-information' : `alert-${this.skin}`} ></pkt-icon> ${this.closeAlert ? html` <div class="pkt-alert__close"> <pkt-button tabindex="0" aria-label="close" size=${this.compact ? 'small' : 'medium'} type="button" skin="tertiary" iconName="close" variant="icon-only" @click=${this.close} > </pkt-button> </div> ` : nothing} ${this.title ? html`<div class="pkt-alert__title">${this.title}</div>` : nothing} <div class="pkt-alert__text" ${ref(this.defaultSlot)}></div> ${this.date ? html`<div class="pkt-alert__date">Sist oppdatert: ${this.date}</div>` : nothing} </div> </div> ` } // Methods private close = (event: MouseEvent) => { this._isClosed = true this.dispatchEvent( new CustomEvent('close', { detail: { origin: event }, bubbles: true, composed: true }), ) // Historical support of old Vue implementations… this.dispatchEvent( new CustomEvent('on-close', { detail: { origin: event }, bubbles: true, composed: true }), ) } }