UNPKG

@oslokommune/punkt-elements

Version:

Komponentbiblioteket til Punkt, et designsystem laget av Oslo Origo

152 lines (128 loc) 3.86 kB
import { html, TemplateResult } from 'lit' import { property } from 'lit/decorators.js' import { Ref, createRef } from 'lit/directives/ref.js' import { classMap } from 'lit/directives/class-map.js' import { PktElement } from '@/base-elements/element' import { cssUtils } from './datepicker-utils' import { IDatepickerStrings } from './datepicker-types' import '@/components/icon' /** * Abstract base class for datepicker input components * * Consolidates shared properties, methods, and event dispatchers * used by all three datepicker input types (single, multiple, range). * * Subclasses must implement: * - `strings` property with component-specific defaults * - `render()` method with component-specific template */ export abstract class PktDatepickerBase extends PktElement { // Shared properties (9 identical across all sub-components) @property({ type: String }) inputType: string = 'date' @property({ type: String }) id: string = '' @property({ type: String }) min?: string @property({ type: String }) max?: string @property({ type: String }) placeholder?: string @property({ type: Boolean }) readonly: boolean = false @property({ type: Boolean }) disabled: boolean = false @property({ type: Object }) inputClasses: Record<string, boolean> = {} @property({ type: Object }) internals?: ElementInternals // Abstract property - must be implemented by subclasses abstract strings: IDatepickerStrings // Shared refs inputRef: Ref<HTMLInputElement> = createRef() btnRef: Ref<HTMLButtonElement> = createRef() // Shared getters get inputElement(): HTMLInputElement | undefined { return this.inputRef.value } get buttonElement(): HTMLButtonElement | undefined { return this.btnRef.value } get isInputReadonly(): boolean { return this.readonly || this.inputType === 'text' } // Shared event dispatchers (protected so subclasses can use them) protected dispatchToggleCalendar(e: Event): void { if (this.readonly) return this.dispatchEvent( new CustomEvent('toggle-calendar', { detail: e, bubbles: true, composed: true, }), ) } protected dispatchInput(e: Event): void { this.dispatchEvent( new CustomEvent('input-change', { detail: e, bubbles: true, composed: true, }), ) } protected dispatchFocus(): void { this.dispatchEvent( new CustomEvent('input-focus', { bubbles: true, composed: true, }), ) } protected dispatchBlur(e: FocusEvent): void { this.dispatchEvent( new CustomEvent('input-blur', { detail: e, bubbles: true, composed: true, }), ) } protected dispatchChange(e: Event): void { this.dispatchEvent( new CustomEvent('input-changed', { detail: e, bubbles: true, composed: true, }), ) } // Shared render helper for calendar button protected renderCalendarButton(): TemplateResult { return html` <button class="${classMap(cssUtils.getButtonClasses())}" type="button" @click=${(e: Event) => this.dispatchToggleCalendar(e)} @keydown=${(e: KeyboardEvent) => { const { key } = e if (key === 'Enter' || key === ' ' || key === 'Space') { e.preventDefault() this.dispatchToggleCalendar(e) } }} ?disabled=${this.disabled} ${this.btnRef} > <pkt-icon name="calendar"></pkt-icon> <span class="pkt-btn__text">${this.strings.calendar?.buttonAltText || 'Åpne kalender'}</span> </button> ` } // Shared method - no shadow DOM createRenderRoot() { return this } // Abstract render method - must be implemented by subclasses abstract render(): TemplateResult }