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 type { TPktInputSize } from 'shared-types/size'
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 = {}
@property({ type: String })
inputSize: TPktInputSize = 'medium'
@property({ type: Object })
internals?: ElementInternals
// Abstract property - must be implemented by subclasses
abstract strings: IDatepickerStrings
// Shared refs
inputRef: Ref = createRef()
btnRef: Ref = 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`
`
}
// Shared method - no shadow DOM
createRenderRoot() {
return this
}
// Abstract render method - must be implemented by subclasses
abstract render(): TemplateResult
}