/** * Copyright Aquera Inc 2023 * * This source code is licensed under the BSD-3-Clause license found in the * LICENSE file in the root directory of this source tree. */ import { LitElement, html, CSSResultArray, TemplateResult, } from 'lit'; import { customElement, query, property } from 'lit/decorators.js'; import { styles } from './nile-date-picker.css'; import NileElement from '../internal/nile-element'; import { NileDropdown } from '../nile-dropdown'; /** * Nile icon component. * * @tag nile-date-picker * */ import { parseDateFromFormat, formatDateToFormat, parseRangeFromFormat, normalizeDateRange } from './nile-date-picker-utils'; @customElement('nile-date-picker') export class NileDatePicker extends NileElement { /** * The styles for DatePicker * @remarks If you are extending this class you can extend the base styles with super. Eg `return [super(), myCustomStyles]` */ public static get styles(): CSSResultArray { return [styles]; } @property({ type: Boolean }) range = false; @property({ type: Boolean }) hideTypes = false; @property({ type: Boolean, reflect: true }) doubleClickUnselect = false; @property({ type: Boolean, reflect: true }) allowClear = false; @property({ type: Boolean }) open = false; @property({ type: Boolean, attribute: 'hide-time-zone' }) hideTimeZone = false; @property({ type: String, reflect: true }) type: 'absolute' | 'relative' = 'absolute'; @property({ type: Boolean, attribute: 'showManualInputs' }) showManualInputs = false; @property() value: any; @property({ type: Array, attribute: 'hide-duration-fields' }) hideDurationFields: any = []; @property({ attribute: 'allowedDates' }) allowedDates: any = '{}'; @property({ type: Boolean, attribute: true, reflect: true }) syncDatePicker = false; @property({ type: String, attribute: true, reflect: true }) dateFormat = "DD/MM/YYYY"; @property({ type: String, attribute: true, reflect: true }) rangeSeparator = " - "; @property({ type: Number, attribute: true, reflect: true }) startYear: number; @property({ type: Number, attribute: true, reflect: true }) endYear: number; @property({ type: Boolean, attribute: true, reflect: true }) showYearDropdown = false; @property({ type: Boolean, attribute: true, reflect: true }) showMonthDropdown = false; @property({ type: Boolean, attribute: true, reflect: true }) portal = false; @property({ type: Boolean, attribute: true, reflect: true }) disabled = false; @query('nile-dropdown') dropdown: NileDropdown; /** * Render method * @slot This is a slot test */ firstUpdated() { super.firstUpdated?.(new Map()); if (!this.syncDatePicker) return; const input = this.querySelector("nile-input"); if (!input) return; input.addEventListener("nile-input", (e: any) => { const text = e.detail.value; const { first, second } = parseRangeFromFormat(text, this.dateFormat, this.range, this.rangeSeparator); if (!this.range) { if (first) this.jumpTo(first); return; } if (first && !second) { this.jumpTo(first); this.syncRangeCalendar(first, null); } if (first && second) { const [start, end] = normalizeDateRange(first, second); if (end) this.jumpTo(end); this.syncRangeCalendar(start, end); } }); } updated(changedProperties: Map) { super.updated(changedProperties); if (changedProperties.has('disabled')) { this.updateTriggerDisabledState(); } } private updateTriggerDisabledState() { const trigger = this.querySelector('[slot="trigger"]') as HTMLElement | null; if (!trigger) return; if ('disabled' in trigger) { (trigger as any).disabled = this.disabled; } } private jumpTo(date: Date) { this.open = true; const cal = this.shadowRoot!.querySelector("nile-calendar") as any; if (!cal) return; cal.currentYear = date.getFullYear(); cal.currentMonth = date.getMonth(); cal.value = date; cal.valueAttribute = date.toISOString(); } private syncRangeCalendar(first: Date | null, second: Date | null) { const cal = this.shadowRoot!.querySelector("nile-calendar") as any; if (!cal) return; if (!this.range) return; if (first) cal.startDate = first; if (second) cal.endDate = second; } render(): TemplateResult { return html` `; } handleChanged(event: CustomEvent) { event.stopPropagation(); const detail = event.detail; const triggerInput = this.querySelector("nile-input"); if (this.disabled) return; if (!this.range) { const picked = detail.value; if (picked && triggerInput) { triggerInput.value = formatDateToFormat(new Date(picked), this.dateFormat); triggerInput.emit("nile-input", { value: triggerInput.value }); } this.emit('nile-changed', event.detail); this.emit('nile-change', event.detail); this.dropdown?.hide(); return; } const start = detail.startDate; const end = detail.endDate; if (triggerInput) { let text = ""; if (start) text += formatDateToFormat(new Date(start), this.dateFormat); if (start && end) text += " - " + formatDateToFormat(new Date(end), this.dateFormat); triggerInput.value = text; triggerInput.emit("nile-input", { value: text }); } this.emit('nile-changed', event.detail); this.emit('nile-change', event.detail); if (this.dropdown) { this.dropdown.hide(); } } connectedCallback() { super.connectedCallback(); this.emit('nile-init'); } disconnectedCallback() { super.disconnectedCallback(); this.emit('nile-destroy'); } } export default NileDatePicker; declare global { interface HTMLElementTagNameMap { 'nile-date-picker': NileDatePicker; } }