@triptease/tt-date-picker 6.3.4 → 6.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -39,6 +39,7 @@ class TtDatePicker extends lit_1.LitElement {
39
39
  };
40
40
  this._onDialogClose = () => {
41
41
  this._open = false;
42
+ this.internals.states.delete('open-above');
42
43
  };
43
44
  this.onFocusOut = (event) => {
44
45
  if (!this._open)
@@ -131,6 +132,13 @@ class TtDatePicker extends lit_1.LitElement {
131
132
  }
132
133
  showCalendar() {
133
134
  if (!this._open) {
135
+ const rect = this.getBoundingClientRect();
136
+ if (!this.openLeft && rect.top > window.innerHeight - rect.bottom) {
137
+ this.internals.states.add('open-above');
138
+ }
139
+ else {
140
+ this.internals.states.delete('open-above');
141
+ }
134
142
  this.dialog.show();
135
143
  if (this.openLeft) {
136
144
  this.style.setProperty('--calendar-left-distance', '-192px');
@@ -1 +1 @@
1
- {"version":3,"file":"TtDatePicker.js","sourceRoot":"","sources":["../../../src/TtDatePicker.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, nothing, PropertyValues } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\nimport { unsafeSVG } from 'lit/directives/unsafe-svg.js';\nimport { DateTime } from 'luxon';\nimport { Calendar } from '@triptease/tt-calendar';\nimport { calendarIcon } from '@triptease/icons';\nimport { TtDialog } from '@triptease/tt-dialog';\nimport { DateInput } from '@triptease/tt-date-input';\nimport { DateSelectionEvent } from '@triptease/tt-calendar/date-selection-context.js';\nimport { dateConverter } from './helpers.js';\nimport { styles } from './styles.js';\n\nexport class TtDatePicker extends LitElement {\n static styles = [\n styles,\n css`\n [part='controls'] {\n min-width: 19.1ch;\n }\n `,\n ];\n\n static formAssociated = true;\n\n static shadowRootOptions = {\n ...LitElement.shadowRootOptions,\n delegatesFocus: true,\n };\n\n @query('tt-calendar')\n calendar!: Calendar;\n\n @query('tt-dialog')\n dialog!: TtDialog;\n\n @property({ type: String })\n public value?: string;\n\n @property({\n type: Date,\n converter: dateConverter,\n })\n public minDate?: Date;\n\n @property({\n type: Date,\n converter: dateConverter,\n })\n public maxDate?: Date;\n\n @property({ type: Boolean, attribute: 'open-left' })\n public openLeft = false;\n\n @property({ type: Boolean })\n public disabled = false;\n\n // Internal DateTime properties for calculations\n private get _valueDateTime(): DateTime | undefined {\n return this.value ? DateTime.fromISO(this.value) : undefined;\n }\n\n private get _minDateTime(): DateTime | undefined {\n return this.minDate ? DateTime.fromJSDate(this.minDate) : undefined;\n }\n\n private get _maxDateTime(): DateTime | undefined {\n return this.maxDate ? DateTime.fromJSDate(this.maxDate) : undefined;\n }\n\n @state()\n private _open: boolean = false;\n\n @query('tt-date-input')\n private dateInput!: DateInput;\n\n public internals: ReturnType<typeof this.attachInternals>;\n\n private get _formValue(): string {\n return this.value ?? '';\n }\n\n constructor() {\n super();\n this.internals = this.attachInternals();\n }\n\n onDateChange(e: Event) {\n if (DateSelectionEvent.is(e)) {\n this.value = e.detail;\n } else if (e.type === 'change') {\n this.value = (e.target as HTMLInputElement).value;\n }\n\n this.dispatchEvent(new InputEvent('change'));\n this.dialog.hide();\n }\n\n get form(): HTMLFormElement | null {\n return this.internals.form;\n }\n\n public updated(changedProperties: PropertyValues) {\n super.updated(changedProperties);\n\n if (changedProperties.has('value')) {\n this.internals.setFormValue(this._formValue);\n this.validate();\n }\n\n if (changedProperties.has('disabled')) {\n if (this.disabled) {\n this.internals.setFormValue(null);\n this.internals.states.add('disabled');\n this.inert = true;\n } else {\n this.internals.states.delete('disabled');\n this.internals.setFormValue(this._formValue);\n this.inert = false;\n }\n }\n }\n\n private validate() {\n const wasValid = this.internals.validity.valid;\n const oldMessage = this.internals.validationMessage;\n this.internals.setValidity({});\n\n if (this._valueDateTime) {\n const minDateIsValid =\n !this._minDateTime || this._valueDateTime > this._minDateTime || this._valueDateTime.equals(this._minDateTime);\n if (!minDateIsValid) {\n this.internals.setValidity(\n { rangeUnderflow: true },\n `Date should be equal or after ${this._minDateTime?.toLocaleString({\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n })}`\n );\n return;\n }\n const maxDateIsValid =\n !this._maxDateTime || this._valueDateTime.equals(this._maxDateTime) || this._valueDateTime < this._maxDateTime;\n if (!maxDateIsValid) {\n this.internals.setValidity(\n { rangeOverflow: true },\n `Date should be before or equal to ${this._maxDateTime?.toLocaleString({\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n })}`\n );\n return;\n }\n }\n if (wasValid !== this.internals.validity.valid || oldMessage !== this.internals.validationMessage) {\n this.requestUpdate();\n }\n }\n\n public connectedCallback() {\n super.connectedCallback();\n\n this.addEventListener('date-selection', this.onDateChange);\n this.addEventListener('dialog-open', this._onDialogOpen);\n this.addEventListener('dialog-close', this._onDialogClose);\n this.addEventListener('focusout', this.onFocusOut);\n this.addEventListener('focus', this._onFocus);\n }\n\n private _onDialogOpen = () => {\n this._open = true;\n };\n\n private _onDialogClose = () => {\n this._open = false;\n };\n\n public onFocusOut = (event: FocusEvent) => {\n if (!this._open) return;\n\n const target = (event.relatedTarget ?? event.explicitOriginalTarget) as HTMLElement | null;\n\n if (!this.contains(target)) {\n this.dialog.hide();\n }\n };\n\n private _onFocus = () => {\n this.dateInput.focus();\n };\n\n public disconnectedCallback() {\n super.disconnectedCallback();\n this.removeEventListener('date-selection', this.onDateChange);\n this.removeEventListener('dialog-open', this._onDialogOpen);\n this.removeEventListener('dialog-close', this._onDialogClose);\n this.removeEventListener('focusout', this.onFocusOut);\n this.removeEventListener('focus', this._onFocus);\n }\n\n showCalendar() {\n if (!this._open) {\n this.dialog.show();\n\n if (this.openLeft) {\n this.style.setProperty('--calendar-left-distance', '-192px');\n }\n } else {\n this.dialog.hide();\n }\n }\n\n render() {\n return html`\n <div part=\"controls\" aria-invalid=${!this.internals.validity.valid} aria-disabled=\"${this.disabled}\">\n <div name=\"container\" part=\"container\">\n <tt-date-input @change=${this.onDateChange} .value=${this.value} .disabled=${this.disabled}></tt-date-input>\n </div>\n <button\n name=\"Show calendar\"\n @click=${this.showCalendar}\n class=\"show-calendar\"\n aria-label=\"Choose date, ${this}\"\n ?disabled=${this.disabled}\n >\n ${unsafeSVG(calendarIcon)}\n </button>\n </div>\n <tt-dialog name=\"calendar\" aria-label=\"Choose date\" part=\"dialog\">\n <tt-calendar\n .value=\"${this.value}\"\n .minDate=${this.minDate}\n .maxDate=${this.maxDate}\n part=\"calendar\"\n ></tt-calendar>\n </tt-dialog>\n <div class=\"errormessage\" id=\"error-msg-${this.id}\" role=\"alert\" aria-atomic=\"true\" part=\"error\">\n ${this.internals.validity.valid ? nothing : this.internals.validationMessage}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'tt-date-picker': TtDatePicker;\n }\n}\n"]}
1
+ {"version":3,"file":"TtDatePicker.js","sourceRoot":"","sources":["../../../src/TtDatePicker.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, nothing, PropertyValues } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\nimport { unsafeSVG } from 'lit/directives/unsafe-svg.js';\nimport { DateTime } from 'luxon';\nimport { Calendar } from '@triptease/tt-calendar';\nimport { calendarIcon } from '@triptease/icons';\nimport { TtDialog } from '@triptease/tt-dialog';\nimport { DateInput } from '@triptease/tt-date-input';\nimport { DateSelectionEvent } from '@triptease/tt-calendar/date-selection-context.js';\nimport { dateConverter } from './helpers.js';\nimport { styles } from './styles.js';\n\nexport class TtDatePicker extends LitElement {\n static styles = [\n styles,\n css`\n [part='controls'] {\n min-width: 19.1ch;\n }\n `,\n ];\n\n static formAssociated = true;\n\n static shadowRootOptions = {\n ...LitElement.shadowRootOptions,\n delegatesFocus: true,\n };\n\n @query('tt-calendar')\n calendar!: Calendar;\n\n @query('tt-dialog')\n dialog!: TtDialog;\n\n @property({ type: String })\n public value?: string;\n\n @property({\n type: Date,\n converter: dateConverter,\n })\n public minDate?: Date;\n\n @property({\n type: Date,\n converter: dateConverter,\n })\n public maxDate?: Date;\n\n @property({ type: Boolean, attribute: 'open-left' })\n public openLeft = false;\n\n @property({ type: Boolean })\n public disabled = false;\n\n // Internal DateTime properties for calculations\n private get _valueDateTime(): DateTime | undefined {\n return this.value ? DateTime.fromISO(this.value) : undefined;\n }\n\n private get _minDateTime(): DateTime | undefined {\n return this.minDate ? DateTime.fromJSDate(this.minDate) : undefined;\n }\n\n private get _maxDateTime(): DateTime | undefined {\n return this.maxDate ? DateTime.fromJSDate(this.maxDate) : undefined;\n }\n\n @state()\n private _open: boolean = false;\n\n @query('tt-date-input')\n private dateInput!: DateInput;\n\n public internals: ReturnType<typeof this.attachInternals>;\n\n private get _formValue(): string {\n return this.value ?? '';\n }\n\n constructor() {\n super();\n this.internals = this.attachInternals();\n }\n\n onDateChange(e: Event) {\n if (DateSelectionEvent.is(e)) {\n this.value = e.detail;\n } else if (e.type === 'change') {\n this.value = (e.target as HTMLInputElement).value;\n }\n\n this.dispatchEvent(new InputEvent('change'));\n this.dialog.hide();\n }\n\n get form(): HTMLFormElement | null {\n return this.internals.form;\n }\n\n public updated(changedProperties: PropertyValues) {\n super.updated(changedProperties);\n\n if (changedProperties.has('value')) {\n this.internals.setFormValue(this._formValue);\n this.validate();\n }\n\n if (changedProperties.has('disabled')) {\n if (this.disabled) {\n this.internals.setFormValue(null);\n this.internals.states.add('disabled');\n this.inert = true;\n } else {\n this.internals.states.delete('disabled');\n this.internals.setFormValue(this._formValue);\n this.inert = false;\n }\n }\n }\n\n private validate() {\n const wasValid = this.internals.validity.valid;\n const oldMessage = this.internals.validationMessage;\n this.internals.setValidity({});\n\n if (this._valueDateTime) {\n const minDateIsValid =\n !this._minDateTime || this._valueDateTime > this._minDateTime || this._valueDateTime.equals(this._minDateTime);\n if (!minDateIsValid) {\n this.internals.setValidity(\n { rangeUnderflow: true },\n `Date should be equal or after ${this._minDateTime?.toLocaleString({\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n })}`\n );\n return;\n }\n const maxDateIsValid =\n !this._maxDateTime || this._valueDateTime.equals(this._maxDateTime) || this._valueDateTime < this._maxDateTime;\n if (!maxDateIsValid) {\n this.internals.setValidity(\n { rangeOverflow: true },\n `Date should be before or equal to ${this._maxDateTime?.toLocaleString({\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n })}`\n );\n return;\n }\n }\n if (wasValid !== this.internals.validity.valid || oldMessage !== this.internals.validationMessage) {\n this.requestUpdate();\n }\n }\n\n public connectedCallback() {\n super.connectedCallback();\n\n this.addEventListener('date-selection', this.onDateChange);\n this.addEventListener('dialog-open', this._onDialogOpen);\n this.addEventListener('dialog-close', this._onDialogClose);\n this.addEventListener('focusout', this.onFocusOut);\n this.addEventListener('focus', this._onFocus);\n }\n\n private _onDialogOpen = () => {\n this._open = true;\n };\n\n private _onDialogClose = () => {\n this._open = false;\n this.internals.states.delete('open-above');\n };\n\n public onFocusOut = (event: FocusEvent) => {\n if (!this._open) return;\n\n const target = (event.relatedTarget ?? event.explicitOriginalTarget) as HTMLElement | null;\n\n if (!this.contains(target)) {\n this.dialog.hide();\n }\n };\n\n private _onFocus = () => {\n this.dateInput.focus();\n };\n\n public disconnectedCallback() {\n super.disconnectedCallback();\n this.removeEventListener('date-selection', this.onDateChange);\n this.removeEventListener('dialog-open', this._onDialogOpen);\n this.removeEventListener('dialog-close', this._onDialogClose);\n this.removeEventListener('focusout', this.onFocusOut);\n this.removeEventListener('focus', this._onFocus);\n }\n\n showCalendar() {\n if (!this._open) {\n const rect = this.getBoundingClientRect();\n if (!this.openLeft && rect.top > window.innerHeight - rect.bottom) {\n this.internals.states.add('open-above');\n } else {\n this.internals.states.delete('open-above');\n }\n\n this.dialog.show();\n\n if (this.openLeft) {\n this.style.setProperty('--calendar-left-distance', '-192px');\n }\n } else {\n this.dialog.hide();\n }\n }\n\n render() {\n return html`\n <div part=\"controls\" aria-invalid=${!this.internals.validity.valid} aria-disabled=\"${this.disabled}\">\n <div name=\"container\" part=\"container\">\n <tt-date-input @change=${this.onDateChange} .value=${this.value} .disabled=${this.disabled}></tt-date-input>\n </div>\n <button\n name=\"Show calendar\"\n @click=${this.showCalendar}\n class=\"show-calendar\"\n aria-label=\"Choose date, ${this}\"\n ?disabled=${this.disabled}\n >\n ${unsafeSVG(calendarIcon)}\n </button>\n </div>\n <tt-dialog name=\"calendar\" aria-label=\"Choose date\" part=\"dialog\">\n <tt-calendar\n .value=\"${this.value}\"\n .minDate=${this.minDate}\n .maxDate=${this.maxDate}\n part=\"calendar\"\n ></tt-calendar>\n </tt-dialog>\n <div class=\"errormessage\" id=\"error-msg-${this.id}\" role=\"alert\" aria-atomic=\"true\" part=\"error\">\n ${this.internals.validity.valid ? nothing : this.internals.validationMessage}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'tt-date-picker': TtDatePicker;\n }\n}\n"]}
@@ -75,6 +75,26 @@ exports.styles = (0, lit_1.css) `
75
75
  position-anchor: --date-picker;
76
76
  position: fixed;
77
77
  z-index: 1;
78
+ inset-block-start: anchor(bottom);
79
+ margin-block-start: var(--space-scale-1);
80
+ }
81
+
82
+ [part='dialog']::part(dialog) {
83
+ margin-top: 0;
84
+ }
85
+
86
+ :host(:state(open-above)) [part='dialog'] {
87
+ inset-block-start: auto;
88
+ margin-block-start: 0;
89
+ }
90
+
91
+ :host(:state(open-above)) [part='dialog']::part(dialog) {
92
+ position: fixed;
93
+ position-anchor: --date-picker;
94
+ bottom: anchor(top);
95
+ top: auto;
96
+ left: anchor(left);
97
+ margin-bottom: var(--space-scale-1);
78
98
  }
79
99
  }
80
100
  `;
@@ -1 +1 @@
1
- {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../../src/styles.ts"],"names":[],"mappings":";;;AAAA,6BAA0B;AAEb,QAAA,MAAM,GAAG,IAAA,SAAG,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2ExB,CAAC","sourcesContent":["import { css } from 'lit';\n\nexport const styles = css`\n :host {\n position: relative;\n anchor-name: --date-picker;\n anchor-scope: --date-picker;\n }\n\n :host(:state(disabled)) {\n pointer-events: none;\n opacity: 0.5;\n }\n\n tt-side-panel::part(side-panel) {\n border-right: 1px solid var(--color-border-200);\n }\n\n tt-side-panel:empty {\n display: none;\n }\n\n [part='container'] {\n padding: var(--space-scale-1) var(--space-scale-1-5);\n gap: var(--space-scale-1);\n }\n\n [part='controls'] {\n display: flex;\n border: 1px solid var(--color-border-200);\n border-radius: var(--border-radius);\n width: fit-content;\n height: var(--date-picker-height, fit-content);\n background-color: var(--color-surface-100);\n font-size: var(--font-size-200);\n color: var(--color-text-400);\n align-items: stretch;\n justify-content: space-around;\n padding: 0;\n\n &[aria-invalid='true'] {\n outline: 2px solid var(--color-alert-strong);\n }\n\n button {\n border: 0;\n padding-inline: var(--space-scale-1);\n background-color: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n align-self: stretch;\n border-left: 1px solid var(--color-border-200);\n box-sizing: border-box;\n color: var(--color-text-400);\n }\n\n &:has(+ tt-dialog[open]) .show-calendar svg,\n .show-calendar:hover svg {\n color: var(--color-primary-400);\n }\n }\n\n [part='dialog']::part(dialog) {\n margin-top: var(--space-scale-1);\n flex-direction: row-reverse;\n }\n\n /** If supported, use CSS anchor positioning, which allows the dialog to escape overflow containers */\n @supports (position-anchor: --date-picker) {\n [part='dialog'] {\n position-anchor: --date-picker;\n position: fixed;\n z-index: 1;\n }\n }\n`;\n"]}
1
+ {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../../src/styles.ts"],"names":[],"mappings":";;;AAAA,6BAA0B;AAEb,QAAA,MAAM,GAAG,IAAA,SAAG,EAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+FxB,CAAC","sourcesContent":["import { css } from 'lit';\n\nexport const styles = css`\n :host {\n position: relative;\n anchor-name: --date-picker;\n anchor-scope: --date-picker;\n }\n\n :host(:state(disabled)) {\n pointer-events: none;\n opacity: 0.5;\n }\n\n tt-side-panel::part(side-panel) {\n border-right: 1px solid var(--color-border-200);\n }\n\n tt-side-panel:empty {\n display: none;\n }\n\n [part='container'] {\n padding: var(--space-scale-1) var(--space-scale-1-5);\n gap: var(--space-scale-1);\n }\n\n [part='controls'] {\n display: flex;\n border: 1px solid var(--color-border-200);\n border-radius: var(--border-radius);\n width: fit-content;\n height: var(--date-picker-height, fit-content);\n background-color: var(--color-surface-100);\n font-size: var(--font-size-200);\n color: var(--color-text-400);\n align-items: stretch;\n justify-content: space-around;\n padding: 0;\n\n &[aria-invalid='true'] {\n outline: 2px solid var(--color-alert-strong);\n }\n\n button {\n border: 0;\n padding-inline: var(--space-scale-1);\n background-color: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n align-self: stretch;\n border-left: 1px solid var(--color-border-200);\n box-sizing: border-box;\n color: var(--color-text-400);\n }\n\n &:has(+ tt-dialog[open]) .show-calendar svg,\n .show-calendar:hover svg {\n color: var(--color-primary-400);\n }\n }\n\n [part='dialog']::part(dialog) {\n margin-top: var(--space-scale-1);\n flex-direction: row-reverse;\n }\n\n /** If supported, use CSS anchor positioning, which allows the dialog to escape overflow containers */\n @supports (position-anchor: --date-picker) {\n [part='dialog'] {\n position-anchor: --date-picker;\n position: fixed;\n z-index: 1;\n inset-block-start: anchor(bottom);\n margin-block-start: var(--space-scale-1);\n }\n\n [part='dialog']::part(dialog) {\n margin-top: 0;\n }\n\n :host(:state(open-above)) [part='dialog'] {\n inset-block-start: auto;\n margin-block-start: 0;\n }\n\n :host(:state(open-above)) [part='dialog']::part(dialog) {\n position: fixed;\n position-anchor: --date-picker;\n bottom: anchor(top);\n top: auto;\n left: anchor(left);\n margin-bottom: var(--space-scale-1);\n }\n }\n`;\n"]}
@@ -36,6 +36,7 @@ export class TtDatePicker extends LitElement {
36
36
  };
37
37
  this._onDialogClose = () => {
38
38
  this._open = false;
39
+ this.internals.states.delete('open-above');
39
40
  };
40
41
  this.onFocusOut = (event) => {
41
42
  if (!this._open)
@@ -128,6 +129,13 @@ export class TtDatePicker extends LitElement {
128
129
  }
129
130
  showCalendar() {
130
131
  if (!this._open) {
132
+ const rect = this.getBoundingClientRect();
133
+ if (!this.openLeft && rect.top > window.innerHeight - rect.bottom) {
134
+ this.internals.states.add('open-above');
135
+ }
136
+ else {
137
+ this.internals.states.delete('open-above');
138
+ }
131
139
  this.dialog.show();
132
140
  if (this.openLeft) {
133
141
  this.style.setProperty('--calendar-left-distance', '-192px');
@@ -1 +1 @@
1
- {"version":3,"file":"TtDatePicker.js","sourceRoot":"","sources":["../../../src/TtDatePicker.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, nothing, PropertyValues } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\nimport { unsafeSVG } from 'lit/directives/unsafe-svg.js';\nimport { DateTime } from 'luxon';\nimport { Calendar } from '@triptease/tt-calendar';\nimport { calendarIcon } from '@triptease/icons';\nimport { TtDialog } from '@triptease/tt-dialog';\nimport { DateInput } from '@triptease/tt-date-input';\nimport { DateSelectionEvent } from '@triptease/tt-calendar/date-selection-context.js';\nimport { dateConverter } from './helpers.js';\nimport { styles } from './styles.js';\n\nexport class TtDatePicker extends LitElement {\n static styles = [\n styles,\n css`\n [part='controls'] {\n min-width: 19.1ch;\n }\n `,\n ];\n\n static formAssociated = true;\n\n static shadowRootOptions = {\n ...LitElement.shadowRootOptions,\n delegatesFocus: true,\n };\n\n @query('tt-calendar')\n calendar!: Calendar;\n\n @query('tt-dialog')\n dialog!: TtDialog;\n\n @property({ type: String })\n public value?: string;\n\n @property({\n type: Date,\n converter: dateConverter,\n })\n public minDate?: Date;\n\n @property({\n type: Date,\n converter: dateConverter,\n })\n public maxDate?: Date;\n\n @property({ type: Boolean, attribute: 'open-left' })\n public openLeft = false;\n\n @property({ type: Boolean })\n public disabled = false;\n\n // Internal DateTime properties for calculations\n private get _valueDateTime(): DateTime | undefined {\n return this.value ? DateTime.fromISO(this.value) : undefined;\n }\n\n private get _minDateTime(): DateTime | undefined {\n return this.minDate ? DateTime.fromJSDate(this.minDate) : undefined;\n }\n\n private get _maxDateTime(): DateTime | undefined {\n return this.maxDate ? DateTime.fromJSDate(this.maxDate) : undefined;\n }\n\n @state()\n private _open: boolean = false;\n\n @query('tt-date-input')\n private dateInput!: DateInput;\n\n public internals: ReturnType<typeof this.attachInternals>;\n\n private get _formValue(): string {\n return this.value ?? '';\n }\n\n constructor() {\n super();\n this.internals = this.attachInternals();\n }\n\n onDateChange(e: Event) {\n if (DateSelectionEvent.is(e)) {\n this.value = e.detail;\n } else if (e.type === 'change') {\n this.value = (e.target as HTMLInputElement).value;\n }\n\n this.dispatchEvent(new InputEvent('change'));\n this.dialog.hide();\n }\n\n get form(): HTMLFormElement | null {\n return this.internals.form;\n }\n\n public updated(changedProperties: PropertyValues) {\n super.updated(changedProperties);\n\n if (changedProperties.has('value')) {\n this.internals.setFormValue(this._formValue);\n this.validate();\n }\n\n if (changedProperties.has('disabled')) {\n if (this.disabled) {\n this.internals.setFormValue(null);\n this.internals.states.add('disabled');\n this.inert = true;\n } else {\n this.internals.states.delete('disabled');\n this.internals.setFormValue(this._formValue);\n this.inert = false;\n }\n }\n }\n\n private validate() {\n const wasValid = this.internals.validity.valid;\n const oldMessage = this.internals.validationMessage;\n this.internals.setValidity({});\n\n if (this._valueDateTime) {\n const minDateIsValid =\n !this._minDateTime || this._valueDateTime > this._minDateTime || this._valueDateTime.equals(this._minDateTime);\n if (!minDateIsValid) {\n this.internals.setValidity(\n { rangeUnderflow: true },\n `Date should be equal or after ${this._minDateTime?.toLocaleString({\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n })}`\n );\n return;\n }\n const maxDateIsValid =\n !this._maxDateTime || this._valueDateTime.equals(this._maxDateTime) || this._valueDateTime < this._maxDateTime;\n if (!maxDateIsValid) {\n this.internals.setValidity(\n { rangeOverflow: true },\n `Date should be before or equal to ${this._maxDateTime?.toLocaleString({\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n })}`\n );\n return;\n }\n }\n if (wasValid !== this.internals.validity.valid || oldMessage !== this.internals.validationMessage) {\n this.requestUpdate();\n }\n }\n\n public connectedCallback() {\n super.connectedCallback();\n\n this.addEventListener('date-selection', this.onDateChange);\n this.addEventListener('dialog-open', this._onDialogOpen);\n this.addEventListener('dialog-close', this._onDialogClose);\n this.addEventListener('focusout', this.onFocusOut);\n this.addEventListener('focus', this._onFocus);\n }\n\n private _onDialogOpen = () => {\n this._open = true;\n };\n\n private _onDialogClose = () => {\n this._open = false;\n };\n\n public onFocusOut = (event: FocusEvent) => {\n if (!this._open) return;\n\n const target = (event.relatedTarget ?? event.explicitOriginalTarget) as HTMLElement | null;\n\n if (!this.contains(target)) {\n this.dialog.hide();\n }\n };\n\n private _onFocus = () => {\n this.dateInput.focus();\n };\n\n public disconnectedCallback() {\n super.disconnectedCallback();\n this.removeEventListener('date-selection', this.onDateChange);\n this.removeEventListener('dialog-open', this._onDialogOpen);\n this.removeEventListener('dialog-close', this._onDialogClose);\n this.removeEventListener('focusout', this.onFocusOut);\n this.removeEventListener('focus', this._onFocus);\n }\n\n showCalendar() {\n if (!this._open) {\n this.dialog.show();\n\n if (this.openLeft) {\n this.style.setProperty('--calendar-left-distance', '-192px');\n }\n } else {\n this.dialog.hide();\n }\n }\n\n render() {\n return html`\n <div part=\"controls\" aria-invalid=${!this.internals.validity.valid} aria-disabled=\"${this.disabled}\">\n <div name=\"container\" part=\"container\">\n <tt-date-input @change=${this.onDateChange} .value=${this.value} .disabled=${this.disabled}></tt-date-input>\n </div>\n <button\n name=\"Show calendar\"\n @click=${this.showCalendar}\n class=\"show-calendar\"\n aria-label=\"Choose date, ${this}\"\n ?disabled=${this.disabled}\n >\n ${unsafeSVG(calendarIcon)}\n </button>\n </div>\n <tt-dialog name=\"calendar\" aria-label=\"Choose date\" part=\"dialog\">\n <tt-calendar\n .value=\"${this.value}\"\n .minDate=${this.minDate}\n .maxDate=${this.maxDate}\n part=\"calendar\"\n ></tt-calendar>\n </tt-dialog>\n <div class=\"errormessage\" id=\"error-msg-${this.id}\" role=\"alert\" aria-atomic=\"true\" part=\"error\">\n ${this.internals.validity.valid ? nothing : this.internals.validationMessage}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'tt-date-picker': TtDatePicker;\n }\n}\n"]}
1
+ {"version":3,"file":"TtDatePicker.js","sourceRoot":"","sources":["../../../src/TtDatePicker.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, nothing, PropertyValues } from 'lit';\nimport { property, query, state } from 'lit/decorators.js';\nimport { unsafeSVG } from 'lit/directives/unsafe-svg.js';\nimport { DateTime } from 'luxon';\nimport { Calendar } from '@triptease/tt-calendar';\nimport { calendarIcon } from '@triptease/icons';\nimport { TtDialog } from '@triptease/tt-dialog';\nimport { DateInput } from '@triptease/tt-date-input';\nimport { DateSelectionEvent } from '@triptease/tt-calendar/date-selection-context.js';\nimport { dateConverter } from './helpers.js';\nimport { styles } from './styles.js';\n\nexport class TtDatePicker extends LitElement {\n static styles = [\n styles,\n css`\n [part='controls'] {\n min-width: 19.1ch;\n }\n `,\n ];\n\n static formAssociated = true;\n\n static shadowRootOptions = {\n ...LitElement.shadowRootOptions,\n delegatesFocus: true,\n };\n\n @query('tt-calendar')\n calendar!: Calendar;\n\n @query('tt-dialog')\n dialog!: TtDialog;\n\n @property({ type: String })\n public value?: string;\n\n @property({\n type: Date,\n converter: dateConverter,\n })\n public minDate?: Date;\n\n @property({\n type: Date,\n converter: dateConverter,\n })\n public maxDate?: Date;\n\n @property({ type: Boolean, attribute: 'open-left' })\n public openLeft = false;\n\n @property({ type: Boolean })\n public disabled = false;\n\n // Internal DateTime properties for calculations\n private get _valueDateTime(): DateTime | undefined {\n return this.value ? DateTime.fromISO(this.value) : undefined;\n }\n\n private get _minDateTime(): DateTime | undefined {\n return this.minDate ? DateTime.fromJSDate(this.minDate) : undefined;\n }\n\n private get _maxDateTime(): DateTime | undefined {\n return this.maxDate ? DateTime.fromJSDate(this.maxDate) : undefined;\n }\n\n @state()\n private _open: boolean = false;\n\n @query('tt-date-input')\n private dateInput!: DateInput;\n\n public internals: ReturnType<typeof this.attachInternals>;\n\n private get _formValue(): string {\n return this.value ?? '';\n }\n\n constructor() {\n super();\n this.internals = this.attachInternals();\n }\n\n onDateChange(e: Event) {\n if (DateSelectionEvent.is(e)) {\n this.value = e.detail;\n } else if (e.type === 'change') {\n this.value = (e.target as HTMLInputElement).value;\n }\n\n this.dispatchEvent(new InputEvent('change'));\n this.dialog.hide();\n }\n\n get form(): HTMLFormElement | null {\n return this.internals.form;\n }\n\n public updated(changedProperties: PropertyValues) {\n super.updated(changedProperties);\n\n if (changedProperties.has('value')) {\n this.internals.setFormValue(this._formValue);\n this.validate();\n }\n\n if (changedProperties.has('disabled')) {\n if (this.disabled) {\n this.internals.setFormValue(null);\n this.internals.states.add('disabled');\n this.inert = true;\n } else {\n this.internals.states.delete('disabled');\n this.internals.setFormValue(this._formValue);\n this.inert = false;\n }\n }\n }\n\n private validate() {\n const wasValid = this.internals.validity.valid;\n const oldMessage = this.internals.validationMessage;\n this.internals.setValidity({});\n\n if (this._valueDateTime) {\n const minDateIsValid =\n !this._minDateTime || this._valueDateTime > this._minDateTime || this._valueDateTime.equals(this._minDateTime);\n if (!minDateIsValid) {\n this.internals.setValidity(\n { rangeUnderflow: true },\n `Date should be equal or after ${this._minDateTime?.toLocaleString({\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n })}`\n );\n return;\n }\n const maxDateIsValid =\n !this._maxDateTime || this._valueDateTime.equals(this._maxDateTime) || this._valueDateTime < this._maxDateTime;\n if (!maxDateIsValid) {\n this.internals.setValidity(\n { rangeOverflow: true },\n `Date should be before or equal to ${this._maxDateTime?.toLocaleString({\n month: 'short',\n day: 'numeric',\n year: 'numeric',\n })}`\n );\n return;\n }\n }\n if (wasValid !== this.internals.validity.valid || oldMessage !== this.internals.validationMessage) {\n this.requestUpdate();\n }\n }\n\n public connectedCallback() {\n super.connectedCallback();\n\n this.addEventListener('date-selection', this.onDateChange);\n this.addEventListener('dialog-open', this._onDialogOpen);\n this.addEventListener('dialog-close', this._onDialogClose);\n this.addEventListener('focusout', this.onFocusOut);\n this.addEventListener('focus', this._onFocus);\n }\n\n private _onDialogOpen = () => {\n this._open = true;\n };\n\n private _onDialogClose = () => {\n this._open = false;\n this.internals.states.delete('open-above');\n };\n\n public onFocusOut = (event: FocusEvent) => {\n if (!this._open) return;\n\n const target = (event.relatedTarget ?? event.explicitOriginalTarget) as HTMLElement | null;\n\n if (!this.contains(target)) {\n this.dialog.hide();\n }\n };\n\n private _onFocus = () => {\n this.dateInput.focus();\n };\n\n public disconnectedCallback() {\n super.disconnectedCallback();\n this.removeEventListener('date-selection', this.onDateChange);\n this.removeEventListener('dialog-open', this._onDialogOpen);\n this.removeEventListener('dialog-close', this._onDialogClose);\n this.removeEventListener('focusout', this.onFocusOut);\n this.removeEventListener('focus', this._onFocus);\n }\n\n showCalendar() {\n if (!this._open) {\n const rect = this.getBoundingClientRect();\n if (!this.openLeft && rect.top > window.innerHeight - rect.bottom) {\n this.internals.states.add('open-above');\n } else {\n this.internals.states.delete('open-above');\n }\n\n this.dialog.show();\n\n if (this.openLeft) {\n this.style.setProperty('--calendar-left-distance', '-192px');\n }\n } else {\n this.dialog.hide();\n }\n }\n\n render() {\n return html`\n <div part=\"controls\" aria-invalid=${!this.internals.validity.valid} aria-disabled=\"${this.disabled}\">\n <div name=\"container\" part=\"container\">\n <tt-date-input @change=${this.onDateChange} .value=${this.value} .disabled=${this.disabled}></tt-date-input>\n </div>\n <button\n name=\"Show calendar\"\n @click=${this.showCalendar}\n class=\"show-calendar\"\n aria-label=\"Choose date, ${this}\"\n ?disabled=${this.disabled}\n >\n ${unsafeSVG(calendarIcon)}\n </button>\n </div>\n <tt-dialog name=\"calendar\" aria-label=\"Choose date\" part=\"dialog\">\n <tt-calendar\n .value=\"${this.value}\"\n .minDate=${this.minDate}\n .maxDate=${this.maxDate}\n part=\"calendar\"\n ></tt-calendar>\n </tt-dialog>\n <div class=\"errormessage\" id=\"error-msg-${this.id}\" role=\"alert\" aria-atomic=\"true\" part=\"error\">\n ${this.internals.validity.valid ? nothing : this.internals.validationMessage}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'tt-date-picker': TtDatePicker;\n }\n}\n"]}
@@ -72,6 +72,26 @@ export const styles = css `
72
72
  position-anchor: --date-picker;
73
73
  position: fixed;
74
74
  z-index: 1;
75
+ inset-block-start: anchor(bottom);
76
+ margin-block-start: var(--space-scale-1);
77
+ }
78
+
79
+ [part='dialog']::part(dialog) {
80
+ margin-top: 0;
81
+ }
82
+
83
+ :host(:state(open-above)) [part='dialog'] {
84
+ inset-block-start: auto;
85
+ margin-block-start: 0;
86
+ }
87
+
88
+ :host(:state(open-above)) [part='dialog']::part(dialog) {
89
+ position: fixed;
90
+ position-anchor: --date-picker;
91
+ bottom: anchor(top);
92
+ top: auto;
93
+ left: anchor(left);
94
+ margin-bottom: var(--space-scale-1);
75
95
  }
76
96
  }
77
97
  `;
@@ -1 +1 @@
1
- {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../../src/styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2ExB,CAAC","sourcesContent":["import { css } from 'lit';\n\nexport const styles = css`\n :host {\n position: relative;\n anchor-name: --date-picker;\n anchor-scope: --date-picker;\n }\n\n :host(:state(disabled)) {\n pointer-events: none;\n opacity: 0.5;\n }\n\n tt-side-panel::part(side-panel) {\n border-right: 1px solid var(--color-border-200);\n }\n\n tt-side-panel:empty {\n display: none;\n }\n\n [part='container'] {\n padding: var(--space-scale-1) var(--space-scale-1-5);\n gap: var(--space-scale-1);\n }\n\n [part='controls'] {\n display: flex;\n border: 1px solid var(--color-border-200);\n border-radius: var(--border-radius);\n width: fit-content;\n height: var(--date-picker-height, fit-content);\n background-color: var(--color-surface-100);\n font-size: var(--font-size-200);\n color: var(--color-text-400);\n align-items: stretch;\n justify-content: space-around;\n padding: 0;\n\n &[aria-invalid='true'] {\n outline: 2px solid var(--color-alert-strong);\n }\n\n button {\n border: 0;\n padding-inline: var(--space-scale-1);\n background-color: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n align-self: stretch;\n border-left: 1px solid var(--color-border-200);\n box-sizing: border-box;\n color: var(--color-text-400);\n }\n\n &:has(+ tt-dialog[open]) .show-calendar svg,\n .show-calendar:hover svg {\n color: var(--color-primary-400);\n }\n }\n\n [part='dialog']::part(dialog) {\n margin-top: var(--space-scale-1);\n flex-direction: row-reverse;\n }\n\n /** If supported, use CSS anchor positioning, which allows the dialog to escape overflow containers */\n @supports (position-anchor: --date-picker) {\n [part='dialog'] {\n position-anchor: --date-picker;\n position: fixed;\n z-index: 1;\n }\n }\n`;\n"]}
1
+ {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../../src/styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,CAAC,MAAM,MAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+FxB,CAAC","sourcesContent":["import { css } from 'lit';\n\nexport const styles = css`\n :host {\n position: relative;\n anchor-name: --date-picker;\n anchor-scope: --date-picker;\n }\n\n :host(:state(disabled)) {\n pointer-events: none;\n opacity: 0.5;\n }\n\n tt-side-panel::part(side-panel) {\n border-right: 1px solid var(--color-border-200);\n }\n\n tt-side-panel:empty {\n display: none;\n }\n\n [part='container'] {\n padding: var(--space-scale-1) var(--space-scale-1-5);\n gap: var(--space-scale-1);\n }\n\n [part='controls'] {\n display: flex;\n border: 1px solid var(--color-border-200);\n border-radius: var(--border-radius);\n width: fit-content;\n height: var(--date-picker-height, fit-content);\n background-color: var(--color-surface-100);\n font-size: var(--font-size-200);\n color: var(--color-text-400);\n align-items: stretch;\n justify-content: space-around;\n padding: 0;\n\n &[aria-invalid='true'] {\n outline: 2px solid var(--color-alert-strong);\n }\n\n button {\n border: 0;\n padding-inline: var(--space-scale-1);\n background-color: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n align-self: stretch;\n border-left: 1px solid var(--color-border-200);\n box-sizing: border-box;\n color: var(--color-text-400);\n }\n\n &:has(+ tt-dialog[open]) .show-calendar svg,\n .show-calendar:hover svg {\n color: var(--color-primary-400);\n }\n }\n\n [part='dialog']::part(dialog) {\n margin-top: var(--space-scale-1);\n flex-direction: row-reverse;\n }\n\n /** If supported, use CSS anchor positioning, which allows the dialog to escape overflow containers */\n @supports (position-anchor: --date-picker) {\n [part='dialog'] {\n position-anchor: --date-picker;\n position: fixed;\n z-index: 1;\n inset-block-start: anchor(bottom);\n margin-block-start: var(--space-scale-1);\n }\n\n [part='dialog']::part(dialog) {\n margin-top: 0;\n }\n\n :host(:state(open-above)) [part='dialog'] {\n inset-block-start: auto;\n margin-block-start: 0;\n }\n\n :host(:state(open-above)) [part='dialog']::part(dialog) {\n position: fixed;\n position-anchor: --date-picker;\n bottom: anchor(top);\n top: auto;\n left: anchor(left);\n margin-bottom: var(--space-scale-1);\n }\n }\n`;\n"]}
@@ -43,6 +43,42 @@ describe('TtDatePicker', () => {
43
43
  expect(eventValue).to.equal(expectedEndDate);
44
44
  });
45
45
  });
46
+ it('should add open-above state when there is more space above than below', async () => {
47
+ const datePicker = await fixture(html ` <tt-date-picker></tt-date-picker> `);
48
+ datePicker.getBoundingClientRect = () => ({ top: 9999, bottom: 10000, left: 0, right: 200, width: 200, height: 1, x: 0, y: 9999, toJSON: () => { } });
49
+ const button = datePicker.shadowRoot.querySelector('[name="Show calendar"]');
50
+ button.click();
51
+ await elementUpdated(datePicker);
52
+ expect(datePicker.internals.states.has('open-above')).to.be.true;
53
+ });
54
+ it('should not add open-above state when there is more space below', async () => {
55
+ const datePicker = await fixture(html ` <tt-date-picker></tt-date-picker> `);
56
+ datePicker.getBoundingClientRect = () => ({ top: 0, bottom: 40, left: 0, right: 200, width: 200, height: 40, x: 0, y: 0, toJSON: () => { } });
57
+ const button = datePicker.shadowRoot.querySelector('[name="Show calendar"]');
58
+ button.click();
59
+ await elementUpdated(datePicker);
60
+ expect(datePicker.internals.states.has('open-above')).to.be.false;
61
+ });
62
+ it('should clear open-above state when dialog is closed', async () => {
63
+ const datePicker = await fixture(html ` <tt-date-picker></tt-date-picker> `);
64
+ datePicker.getBoundingClientRect = () => ({ top: 9999, bottom: 10000, left: 0, right: 200, width: 200, height: 1, x: 0, y: 9999, toJSON: () => { } });
65
+ const button = datePicker.shadowRoot.querySelector('[name="Show calendar"]');
66
+ button.click();
67
+ await elementUpdated(datePicker);
68
+ expect(datePicker.internals.states.has('open-above')).to.be.true;
69
+ const dialog = datePicker.shadowRoot.querySelector('tt-dialog');
70
+ dialog.hide();
71
+ await elementUpdated(datePicker);
72
+ expect(datePicker.internals.states.has('open-above')).to.be.false;
73
+ });
74
+ it('should not add open-above state when open-left is set', async () => {
75
+ const datePicker = await fixture(html ` <tt-date-picker open-left></tt-date-picker> `);
76
+ datePicker.getBoundingClientRect = () => ({ top: 9999, bottom: 10000, left: 0, right: 200, width: 200, height: 1, x: 0, y: 9999, toJSON: () => { } });
77
+ const button = datePicker.shadowRoot.querySelector('[name="Show calendar"]');
78
+ button.click();
79
+ await elementUpdated(datePicker);
80
+ expect(datePicker.internals.states.has('open-above')).to.be.false;
81
+ });
46
82
  it('should disable the date picker when disabled attribute is set', async () => {
47
83
  const datePicker = await fixture(html `
48
84
  <tt-date-picker value="2025-05-01" disabled></tt-date-picker>
@@ -1 +1 @@
1
- {"version":3,"file":"date-picker.test.js","sourceRoot":"","sources":["../../../test/date-picker.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { elementUpdated, expect, fixture, oneDefaultPreventedEvent, oneEvent } from '@open-wc/testing';\nimport { html } from 'lit';\nimport { Settings } from 'luxon';\nimport { TtDialog } from '@triptease/tt-dialog';\nimport '../src/index.js'; // This handles the registration\nimport { TtDatePicker } from '../src/index.js';\n\ndescribe('TtDatePicker', () => {\n afterEach(() => {\n Settings.defaultZone = 'system';\n });\n\n ['Australia/Brisbane', 'America/New_York', 'Europe/London', 'Asia/Tokyo', 'Etc/UTC'].forEach((timezone) => {\n it('should include date value in form submission data', async () => {\n Settings.defaultZone = timezone;\n const form = await fixture<HTMLFormElement>(html`\n <form method=\"post\" action=\"#\">\n <input type=\"text\" name=\"other_field\" value=\"test_value\" />\n <tt-date-picker name=\"booking_date\" value=\"2025-04-16\"></tt-date-picker>\n <button type=\"submit\">Submit</button>\n </form>\n `);\n\n const datePicker = form.querySelector('tt-date-picker') as TtDatePicker;\n expect(datePicker).to.exist;\n\n await elementUpdated(datePicker);\n\n setTimeout(() => form.querySelector('button')!.click());\n await oneDefaultPreventedEvent(form, 'submit');\n\n const formData = new FormData(form);\n const dateValue = formData.get('booking_date');\n const expectedDate = `2025-04-16`;\n\n expect(dateValue).to.equal(expectedDate);\n });\n\n it(`should emit change event on date selection for ${timezone}`, async () => {\n Settings.defaultZone = timezone;\n const datePicker = await fixture<TtDatePicker>(html` <tt-date-picker value=\"2025-05-01\"></tt-date-picker> `);\n\n const showCalendarButton = datePicker.shadowRoot!.querySelector('[name=\"Show calendar\"]') as HTMLButtonElement;\n showCalendarButton.click();\n await elementUpdated(datePicker);\n\n const changeEventPromise = oneEvent(datePicker, 'change');\n\n const calendar = datePicker.shadowRoot!.querySelector('tt-calendar')!;\n const desiredDate = calendar.shadowRoot!.querySelector(\n '[role=\"gridcell\"][data-date=\"2025-05-02\"]'\n ) as HTMLLIElement;\n desiredDate.click();\n await elementUpdated(datePicker);\n\n const event = await changeEventPromise;\n const eventValue = (event.target as TtDatePicker).value;\n\n const expectedEndDate = '2025-05-02';\n\n expect(eventValue).to.equal(expectedEndDate);\n });\n });\n\n it('should disable the date picker when disabled attribute is set', async () => {\n const datePicker = await fixture<TtDatePicker>(html`\n <tt-date-picker value=\"2025-05-01\" disabled></tt-date-picker>\n `);\n\n expect(datePicker.inert).to.be.true;\n\n const showCalendarButton = datePicker.shadowRoot!.querySelector('button.show-calendar') as HTMLButtonElement;\n showCalendarButton.click();\n\n const dialog = datePicker.shadowRoot!.querySelector('tt-dialog') as TtDialog;\n expect(dialog.open).to.be.false;\n });\n});\n"]}
1
+ {"version":3,"file":"date-picker.test.js","sourceRoot":"","sources":["../../../test/date-picker.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { elementUpdated, expect, fixture, oneDefaultPreventedEvent, oneEvent } from '@open-wc/testing';\nimport { html } from 'lit';\nimport { Settings } from 'luxon';\nimport { TtDialog } from '@triptease/tt-dialog';\nimport '../src/index.js'; // This handles the registration\nimport { TtDatePicker } from '../src/index.js';\n\ndescribe('TtDatePicker', () => {\n afterEach(() => {\n Settings.defaultZone = 'system';\n });\n\n ['Australia/Brisbane', 'America/New_York', 'Europe/London', 'Asia/Tokyo', 'Etc/UTC'].forEach((timezone) => {\n it('should include date value in form submission data', async () => {\n Settings.defaultZone = timezone;\n const form = await fixture<HTMLFormElement>(html`\n <form method=\"post\" action=\"#\">\n <input type=\"text\" name=\"other_field\" value=\"test_value\" />\n <tt-date-picker name=\"booking_date\" value=\"2025-04-16\"></tt-date-picker>\n <button type=\"submit\">Submit</button>\n </form>\n `);\n\n const datePicker = form.querySelector('tt-date-picker') as TtDatePicker;\n expect(datePicker).to.exist;\n\n await elementUpdated(datePicker);\n\n setTimeout(() => form.querySelector('button')!.click());\n await oneDefaultPreventedEvent(form, 'submit');\n\n const formData = new FormData(form);\n const dateValue = formData.get('booking_date');\n const expectedDate = `2025-04-16`;\n\n expect(dateValue).to.equal(expectedDate);\n });\n\n it(`should emit change event on date selection for ${timezone}`, async () => {\n Settings.defaultZone = timezone;\n const datePicker = await fixture<TtDatePicker>(html` <tt-date-picker value=\"2025-05-01\"></tt-date-picker> `);\n\n const showCalendarButton = datePicker.shadowRoot!.querySelector('[name=\"Show calendar\"]') as HTMLButtonElement;\n showCalendarButton.click();\n await elementUpdated(datePicker);\n\n const changeEventPromise = oneEvent(datePicker, 'change');\n\n const calendar = datePicker.shadowRoot!.querySelector('tt-calendar')!;\n const desiredDate = calendar.shadowRoot!.querySelector(\n '[role=\"gridcell\"][data-date=\"2025-05-02\"]'\n ) as HTMLLIElement;\n desiredDate.click();\n await elementUpdated(datePicker);\n\n const event = await changeEventPromise;\n const eventValue = (event.target as TtDatePicker).value;\n\n const expectedEndDate = '2025-05-02';\n\n expect(eventValue).to.equal(expectedEndDate);\n });\n });\n\n it('should add open-above state when there is more space above than below', async () => {\n const datePicker = await fixture<TtDatePicker>(html` <tt-date-picker></tt-date-picker> `);\n\n datePicker.getBoundingClientRect = () =>\n ({ top: 9999, bottom: 10000, left: 0, right: 200, width: 200, height: 1, x: 0, y: 9999, toJSON: () => {} } as DOMRect);\n\n const button = datePicker.shadowRoot!.querySelector('[name=\"Show calendar\"]') as HTMLButtonElement;\n button.click();\n await elementUpdated(datePicker);\n\n expect(datePicker.internals.states.has('open-above')).to.be.true;\n });\n\n it('should not add open-above state when there is more space below', async () => {\n const datePicker = await fixture<TtDatePicker>(html` <tt-date-picker></tt-date-picker> `);\n\n datePicker.getBoundingClientRect = () =>\n ({ top: 0, bottom: 40, left: 0, right: 200, width: 200, height: 40, x: 0, y: 0, toJSON: () => {} } as DOMRect);\n\n const button = datePicker.shadowRoot!.querySelector('[name=\"Show calendar\"]') as HTMLButtonElement;\n button.click();\n await elementUpdated(datePicker);\n\n expect(datePicker.internals.states.has('open-above')).to.be.false;\n });\n\n it('should clear open-above state when dialog is closed', async () => {\n const datePicker = await fixture<TtDatePicker>(html` <tt-date-picker></tt-date-picker> `);\n\n datePicker.getBoundingClientRect = () =>\n ({ top: 9999, bottom: 10000, left: 0, right: 200, width: 200, height: 1, x: 0, y: 9999, toJSON: () => {} } as DOMRect);\n\n const button = datePicker.shadowRoot!.querySelector('[name=\"Show calendar\"]') as HTMLButtonElement;\n button.click();\n await elementUpdated(datePicker);\n expect(datePicker.internals.states.has('open-above')).to.be.true;\n\n const dialog = datePicker.shadowRoot!.querySelector('tt-dialog') as TtDialog;\n dialog.hide();\n await elementUpdated(datePicker);\n\n expect(datePicker.internals.states.has('open-above')).to.be.false;\n });\n\n it('should not add open-above state when open-left is set', async () => {\n const datePicker = await fixture<TtDatePicker>(html` <tt-date-picker open-left></tt-date-picker> `);\n\n datePicker.getBoundingClientRect = () =>\n ({ top: 9999, bottom: 10000, left: 0, right: 200, width: 200, height: 1, x: 0, y: 9999, toJSON: () => {} } as DOMRect);\n\n const button = datePicker.shadowRoot!.querySelector('[name=\"Show calendar\"]') as HTMLButtonElement;\n button.click();\n await elementUpdated(datePicker);\n\n expect(datePicker.internals.states.has('open-above')).to.be.false;\n });\n\n it('should disable the date picker when disabled attribute is set', async () => {\n const datePicker = await fixture<TtDatePicker>(html`\n <tt-date-picker value=\"2025-05-01\" disabled></tt-date-picker>\n `);\n\n expect(datePicker.inert).to.be.true;\n\n const showCalendarButton = datePicker.shadowRoot!.querySelector('button.show-calendar') as HTMLButtonElement;\n showCalendarButton.click();\n\n const dialog = datePicker.shadowRoot!.querySelector('tt-dialog') as TtDialog;\n expect(dialog.open).to.be.false;\n });\n});\n"]}
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Webcomponent tt-date-picker following open-wc recommendations",
4
4
  "license": "MIT",
5
5
  "author": "@triptease",
6
- "version": "6.3.4",
6
+ "version": "6.3.6",
7
7
  "type": "module",
8
8
  "main": "dist/esm/src/index.js",
9
9
  "module": "dist/esm/src/index.js",
@@ -38,7 +38,7 @@
38
38
  },
39
39
  "dependencies": {
40
40
  "@triptease/icons": "1.4.1",
41
- "@triptease/tt-calendar": "6.3.0",
41
+ "@triptease/tt-calendar": "6.4.0",
42
42
  "@triptease/tt-date-input": "6.1.2",
43
43
  "@triptease/tt-dialog": "5.2.2",
44
44
  "@types/luxon": "^3.6.2",