import { html, nothing, PropertyValues } from 'lit'
import { PktElement } from '@/base-elements/element'
import { customElement, property, state } from 'lit/decorators.js'
import { classMap } from 'lit/directives/class-map.js'
import { ref, createRef, Ref } from 'lit/directives/ref.js'
import { formatISODate, newDate } from 'shared-utils/date-utils'
import { PktCalendar } from '../calendar/calendar'
import { calendarUtils } from './datepicker-utils'
export class PktDatepickerPopup extends PktElement {
@property({ type: Boolean, reflect: true }) open = false
@property({ type: Boolean }) multiple = false
@property({ type: Boolean }) range = false
@property({ type: Boolean }) weeknumbers = false
@property({ type: Boolean }) withcontrols = false
@property({ type: Number }) maxMultiple: number | null = null
@property({ type: Array }) selected: string[] = []
@property({ type: String }) earliest: string | null = null
@property({ type: String }) latest: string | null = null
@property({ type: Array }) excludedates: string[] = []
@property({ type: Array }) excludeweekdays: string[] = []
@property({ type: String }) currentmonth: string | null = null
@property({ type: String }) today: string | null = null
@state() private _hasBeenOpened = false
popupRef: Ref = createRef()
calendarRef: Ref = createRef()
firstUpdated() {
// expose calendarRef for external use
this.calRef = this.calendarRef
}
updated(changedProperties: PropertyValues) {
super.updated(changedProperties)
if (changedProperties.has('open')) {
if (this.open) {
this._hasBeenOpened = true
document.addEventListener('keydown', this.handleDocumentKeydown)
document.addEventListener('click', this.handleDocumentClick)
} else {
document.removeEventListener('click', this.handleDocumentClick)
document.removeEventListener('keydown', this.handleDocumentKeydown)
}
}
}
disconnectedCallback() {
super.disconnectedCallback()
document.removeEventListener('click', this.handleDocumentClick)
document.removeEventListener('keydown', this.handleDocumentKeydown)
}
handleDocumentClick = (e: MouseEvent) => {
if (!this.open) return
const path = e.composedPath() as EventTarget[]
const host = this.parentElement as EventTarget | null
const popupNode = this.popupRef.value as EventTarget | null
if (
!path.includes(this) &&
!path.includes(popupNode as EventTarget) &&
!(host && path.includes(host))
) {
this.hide()
this.dispatchEvent(new CustomEvent('close', { bubbles: true, composed: true }))
}
}
handleDocumentKeydown = (e: KeyboardEvent) => {
if (!this.open) return
if (e.key === 'Escape') {
this.hide()
this.dispatchEvent(new CustomEvent('close', { bubbles: true, composed: true }))
}
}
show() {
this.open = true
;(this.calendarRef.value as HTMLElement | null)?.focus()
}
hide() {
this.open = false
}
toggle() {
this.open ? this.hide() : this.show()
}
contains(node: Node | null) {
return !!node && !!(this.popupRef.value as HTMLElement | null)?.contains(node as Node)
}
focusOnCurrentDate() {
const cal = this.calendarRef.value as PktCalendar
if (cal && typeof cal.focusOnCurrentDate === 'function') cal.focusOnCurrentDate()
}
addToSelected(e: Event, min?: string | null, max?: string | null) {
const cal = this.calendarRef.value as PktCalendar
if (cal && typeof calendarUtils.addToSelected === 'function') {
return calendarUtils.addToSelected(e, this.calendarRef as any, min, max)
}
// Calendar not rendered yet — handle add directly
const target = e.target as HTMLInputElement
if (!target.value) return
const minAsDate = min ? newDate(min) : null
const maxAsDate = max ? newDate(max) : null
const date = newDate(target.value.split(',')[0])
if (date && !isNaN(date.getTime()) && (!minAsDate || date >= minAsDate) && (!maxAsDate || date <= maxAsDate)) {
this.handleDateSelect(date)
}
target.value = ''
}
handleDateSelect(date: Date) {
const cal = this.calendarRef.value as PktCalendar
if (cal && typeof cal.handleDateSelect === 'function') return cal.handleDateSelect(date)
// Calendar not rendered yet — handle selection toggle directly
const dateStr = formatISODate(date)
const index = this.selected.indexOf(dateStr)
const newSelected = index >= 0
? this.selected.filter((d) => d !== dateStr)
: [...this.selected, dateStr]
this.selected = newSelected
this.dispatchEvent(
new CustomEvent('date-selected', { detail: newSelected, bubbles: true, composed: true }),
)
return undefined
}
render() {
const classes = { 'pkt-calendar-popup': true, show: this.open, hide: !this.open }
return html`
`
}
}
try {
customElement('pkt-datepicker-popup')(PktDatepickerPopup)
} catch (e) {
console.warn('Forsøker å definere , men den er allerede definert')
}