@api-client/ui 0.5.5 → 0.5.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.
Files changed (82) hide show
  1. package/build/src/elements/highlight/MarkdownStyles.d.ts.map +1 -1
  2. package/build/src/elements/highlight/MarkdownStyles.js +0 -13
  3. package/build/src/elements/highlight/MarkdownStyles.js.map +1 -1
  4. package/build/src/elements/http/BodyEditor.d.ts +0 -13
  5. package/build/src/elements/http/BodyEditor.d.ts.map +1 -1
  6. package/build/src/elements/http/BodyEditor.js +0 -13
  7. package/build/src/elements/http/BodyEditor.js.map +1 -1
  8. package/build/src/elements/http/BodyTextEditor.d.ts +0 -13
  9. package/build/src/elements/http/BodyTextEditor.d.ts.map +1 -1
  10. package/build/src/elements/http/BodyTextEditor.js +0 -13
  11. package/build/src/elements/http/BodyTextEditor.js.map +1 -1
  12. package/build/src/elements/http/BodyUrlEncodedEditor.d.ts +0 -13
  13. package/build/src/elements/http/BodyUrlEncodedEditor.d.ts.map +1 -1
  14. package/build/src/elements/http/BodyUrlEncodedEditor.js +0 -13
  15. package/build/src/elements/http/BodyUrlEncodedEditor.js.map +1 -1
  16. package/build/src/elements/http/UrlInput.d.ts +0 -13
  17. package/build/src/elements/http/UrlInput.d.ts.map +1 -1
  18. package/build/src/elements/http/UrlInput.js +0 -13
  19. package/build/src/elements/http/UrlInput.js.map +1 -1
  20. package/build/src/index.d.ts +2 -0
  21. package/build/src/index.d.ts.map +1 -1
  22. package/build/src/index.js +2 -0
  23. package/build/src/index.js.map +1 -1
  24. package/build/src/md/button/internals/button.styles.js +1 -1
  25. package/build/src/md/button/internals/button.styles.js.map +1 -1
  26. package/build/src/md/date/internals/DateTime.d.ts +0 -13
  27. package/build/src/md/date/internals/DateTime.d.ts.map +1 -1
  28. package/build/src/md/date/internals/DateTime.js +0 -13
  29. package/build/src/md/date/internals/DateTime.js.map +1 -1
  30. package/build/src/md/date-picker/index.d.ts +13 -0
  31. package/build/src/md/date-picker/index.d.ts.map +1 -0
  32. package/build/src/md/date-picker/index.js +13 -0
  33. package/build/src/md/date-picker/index.js.map +1 -0
  34. package/build/src/md/date-picker/internals/DatePicker.styles.d.ts +4 -0
  35. package/build/src/md/date-picker/internals/DatePicker.styles.d.ts.map +1 -0
  36. package/build/src/md/date-picker/internals/DatePicker.styles.js +336 -0
  37. package/build/src/md/date-picker/internals/DatePicker.styles.js.map +1 -0
  38. package/build/src/md/date-picker/internals/DatePickerCalendar.d.ts +159 -0
  39. package/build/src/md/date-picker/internals/DatePickerCalendar.d.ts.map +1 -0
  40. package/build/src/md/date-picker/internals/DatePickerCalendar.js +770 -0
  41. package/build/src/md/date-picker/internals/DatePickerCalendar.js.map +1 -0
  42. package/build/src/md/date-picker/internals/DatePickerUtils.d.ts +93 -0
  43. package/build/src/md/date-picker/internals/DatePickerUtils.d.ts.map +1 -0
  44. package/build/src/md/date-picker/internals/DatePickerUtils.js +221 -0
  45. package/build/src/md/date-picker/internals/DatePickerUtils.js.map +1 -0
  46. package/build/src/md/date-picker/ui-date-picker-input.d.ts +108 -0
  47. package/build/src/md/date-picker/ui-date-picker-input.d.ts.map +1 -0
  48. package/build/src/md/date-picker/ui-date-picker-input.js +397 -0
  49. package/build/src/md/date-picker/ui-date-picker-input.js.map +1 -0
  50. package/build/src/md/date-picker/ui-date-picker-modal-input.d.ts +119 -0
  51. package/build/src/md/date-picker/ui-date-picker-modal-input.d.ts.map +1 -0
  52. package/build/src/md/date-picker/ui-date-picker-modal-input.js +473 -0
  53. package/build/src/md/date-picker/ui-date-picker-modal-input.js.map +1 -0
  54. package/build/src/md/date-picker/ui-date-picker-modal.d.ts +108 -0
  55. package/build/src/md/date-picker/ui-date-picker-modal.d.ts.map +1 -0
  56. package/build/src/md/date-picker/ui-date-picker-modal.js +344 -0
  57. package/build/src/md/date-picker/ui-date-picker-modal.js.map +1 -0
  58. package/build/src/md/dialog/internals/Dialog.styles.d.ts.map +1 -1
  59. package/build/src/md/dialog/internals/Dialog.styles.js +1 -0
  60. package/build/src/md/dialog/internals/Dialog.styles.js.map +1 -1
  61. package/demo/elements/har/har2.json +1 -1
  62. package/demo/md/date-picker/date-picker.ts +301 -0
  63. package/demo/md/date-picker/index.html +171 -0
  64. package/demo/md/index.html +2 -0
  65. package/package.json +1 -1
  66. package/src/elements/highlight/MarkdownStyles.ts +0 -13
  67. package/src/elements/http/BodyEditor.ts +0 -13
  68. package/src/elements/http/BodyTextEditor.ts +0 -13
  69. package/src/elements/http/BodyUrlEncodedEditor.ts +0 -13
  70. package/src/elements/http/UrlInput.ts +0 -13
  71. package/src/index.ts +17 -0
  72. package/src/md/button/internals/button.styles.ts +1 -1
  73. package/src/md/date/internals/DateTime.ts +0 -14
  74. package/src/md/date-picker/README.md +184 -0
  75. package/src/md/date-picker/index.ts +17 -0
  76. package/src/md/date-picker/internals/DatePicker.styles.ts +338 -0
  77. package/src/md/date-picker/internals/DatePickerCalendar.ts +697 -0
  78. package/src/md/date-picker/internals/DatePickerUtils.ts +288 -0
  79. package/src/md/date-picker/ui-date-picker-input.ts +272 -0
  80. package/src/md/date-picker/ui-date-picker-modal-input.ts +371 -0
  81. package/src/md/date-picker/ui-date-picker-modal.ts +263 -0
  82. package/src/md/dialog/internals/Dialog.styles.ts +1 -0
@@ -0,0 +1,371 @@
1
+ import { LitElement, html, TemplateResult } from 'lit'
2
+ import { customElement, property, state } from 'lit/decorators.js'
3
+ import { modalStyles } from './internals/DatePicker.styles.js'
4
+ import { DateRange, formatDate, parseDate } from './internals/DatePickerUtils.js'
5
+ import '../../md/dialog/ui-dialog.js'
6
+ import '../../md/button/ui-button.js'
7
+ import '../../md/icon-button/ui-icon-button.js'
8
+ import '../../md/text-field/ui-outlined-text-field.js'
9
+ import '../../md/icons/ui-icon.js'
10
+
11
+ export interface ModalInputDatePickerChangeEvent {
12
+ range: DateRange
13
+ formattedRange: {
14
+ start: string | null
15
+ end: string | null
16
+ }
17
+ }
18
+
19
+ /**
20
+ * A modal date input picker for manual date entry using keyboard.
21
+ * Ideal for compact layouts and precise date entry.
22
+ *
23
+ * ## Usage
24
+ *
25
+ * ```html
26
+ * <ui-date-picker-modal-input
27
+ * .open=${true}
28
+ * .selectedRange=${{ start: new Date(), end: null }}
29
+ * @date-input-change=${this.handleRangeChange}
30
+ * @close=${this.handleClose}
31
+ * ></ui-date-picker-modal-input>
32
+ * ```
33
+ *
34
+ * ### Single date mode
35
+ * ```html
36
+ * <ui-date-picker-modal-input
37
+ * .rangeMode=${false}
38
+ * .selectedDate=${new Date()}
39
+ * ></ui-date-picker-modal-input>
40
+ * ```
41
+ */
42
+ @customElement('ui-date-picker-modal-input')
43
+ export class UiDatePickerModalInput extends LitElement {
44
+ static override styles = modalStyles
45
+
46
+ /**
47
+ * Whether the modal is open
48
+ */
49
+ @property({ type: Boolean }) accessor open = false
50
+
51
+ /**
52
+ * The modal title
53
+ */
54
+ @property({ type: String }) override accessor title = 'Enter dates'
55
+
56
+ /**
57
+ * Whether to use range mode (two date inputs) or single date mode
58
+ */
59
+ @property({ type: Boolean }) accessor rangeMode = true
60
+
61
+ /**
62
+ * Label for the start date (or single date)
63
+ */
64
+ @property({ type: String }) accessor startLabel = 'Start date'
65
+
66
+ /**
67
+ * Label for the end date (only used in range mode)
68
+ */
69
+ @property({ type: String }) accessor endLabel = 'End date'
70
+
71
+ /**
72
+ * Placeholder for date inputs
73
+ */
74
+ @property({ type: String }) accessor placeholder = 'MM/DD/YYYY'
75
+
76
+ /**
77
+ * The selected date (single mode)
78
+ */
79
+ @property({ type: Object }) accessor selectedDate: Date | null = null
80
+
81
+ /**
82
+ * The selected date range (range mode)
83
+ */
84
+ @property({ type: Object }) accessor selectedRange: DateRange | null = null
85
+
86
+ /**
87
+ * Minimum selectable date
88
+ */
89
+ @property({ type: Object }) accessor minDate: Date | undefined = undefined
90
+
91
+ /**
92
+ * Maximum selectable date
93
+ */
94
+ @property({ type: Object }) accessor maxDate: Date | undefined = undefined
95
+
96
+ /**
97
+ * Locale for date formatting
98
+ */
99
+ @property({ type: String }) accessor locale: string | undefined = undefined
100
+
101
+ @state() private accessor _startInput = ''
102
+
103
+ @state() private accessor _endInput = ''
104
+
105
+ @state() private accessor _startError = ''
106
+
107
+ @state() private accessor _endError = ''
108
+
109
+ override connectedCallback(): void {
110
+ super.connectedCallback()
111
+ this._updateInputValues()
112
+ }
113
+
114
+ override willUpdate(changedProperties: Map<string | number | symbol, unknown>): void {
115
+ if (changedProperties.has('selectedDate') || changedProperties.has('selectedRange')) {
116
+ this._updateInputValues()
117
+ }
118
+ }
119
+
120
+ private _updateInputValues(): void {
121
+ if (this.rangeMode && this.selectedRange) {
122
+ this._startInput = this.selectedRange.start ? formatDate(this.selectedRange.start, this.locale) : ''
123
+ this._endInput = this.selectedRange.end ? formatDate(this.selectedRange.end, this.locale) : ''
124
+ } else if (!this.rangeMode && this.selectedDate) {
125
+ this._startInput = formatDate(this.selectedDate, this.locale)
126
+ }
127
+ }
128
+
129
+ private _validateDate(dateString: string, isEndDate = false): Date | null {
130
+ if (!dateString.trim()) return null
131
+
132
+ const parsedDate = parseDate(dateString)
133
+ if (!parsedDate) return null
134
+
135
+ // Check min/max constraints
136
+ if (this.minDate && parsedDate < this.minDate) return null
137
+ if (this.maxDate && parsedDate > this.maxDate) return null
138
+
139
+ // For range mode, validate end date is after start date
140
+ if (this.rangeMode && isEndDate) {
141
+ const startDate = parseDate(this._startInput)
142
+ if (startDate && parsedDate < startDate) return null
143
+ }
144
+
145
+ return parsedDate
146
+ }
147
+
148
+ private _handleStartInput(event: Event): void {
149
+ const target = event.target as HTMLInputElement
150
+ this._startInput = target.value
151
+ this._startError = ''
152
+
153
+ if (this._startInput.trim()) {
154
+ const date = this._validateDate(this._startInput)
155
+ if (!date) {
156
+ this._startError = 'Invalid date format or out of range'
157
+ return
158
+ }
159
+
160
+ if (this.rangeMode) {
161
+ const currentRange = this.selectedRange || { start: null, end: null }
162
+ this.selectedRange = { ...currentRange, start: date }
163
+ } else {
164
+ this.selectedDate = date
165
+ }
166
+
167
+ this._dispatchChangeEvent()
168
+ }
169
+ }
170
+
171
+ private _handleEndInput(event: Event): void {
172
+ const target = event.target as HTMLInputElement
173
+ this._endInput = target.value
174
+ this._endError = ''
175
+
176
+ if (this._endInput.trim()) {
177
+ const date = this._validateDate(this._endInput, true)
178
+ if (!date) {
179
+ this._endError = 'Invalid date format, out of range, or before start date'
180
+ return
181
+ }
182
+
183
+ const currentRange = this.selectedRange || { start: null, end: null }
184
+ this.selectedRange = { ...currentRange, end: date }
185
+ this._dispatchChangeEvent()
186
+ }
187
+ }
188
+
189
+ private _handleCancel(): void {
190
+ this._dispatchCloseEvent(false)
191
+ }
192
+
193
+ private _handleConfirm(): void {
194
+ // Validate all inputs before confirming
195
+ let hasErrors = false
196
+
197
+ if (this.rangeMode) {
198
+ if (!this._startInput.trim()) {
199
+ this._startError = 'Start date is required'
200
+ hasErrors = true
201
+ } else if (!this._validateDate(this._startInput)) {
202
+ this._startError = 'Invalid start date'
203
+ hasErrors = true
204
+ }
205
+
206
+ if (!this._endInput.trim()) {
207
+ this._endError = 'End date is required'
208
+ hasErrors = true
209
+ } else if (!this._validateDate(this._endInput, true)) {
210
+ this._endError = 'Invalid end date'
211
+ hasErrors = true
212
+ }
213
+ } else {
214
+ if (!this._startInput.trim()) {
215
+ this._startError = 'Date is required'
216
+ hasErrors = true
217
+ } else if (!this._validateDate(this._startInput)) {
218
+ this._startError = 'Invalid date'
219
+ hasErrors = true
220
+ }
221
+ }
222
+
223
+ if (!hasErrors) {
224
+ this._dispatchCloseEvent(true)
225
+ }
226
+ }
227
+
228
+ private _dispatchChangeEvent(): void {
229
+ if (this.rangeMode && this.selectedRange) {
230
+ const event: ModalInputDatePickerChangeEvent = {
231
+ range: this.selectedRange,
232
+ formattedRange: {
233
+ start: this.selectedRange.start ? formatDate(this.selectedRange.start, this.locale) : null,
234
+ end: this.selectedRange.end ? formatDate(this.selectedRange.end, this.locale) : null,
235
+ },
236
+ }
237
+
238
+ this.dispatchEvent(
239
+ new CustomEvent('date-input-change', {
240
+ detail: event,
241
+ bubbles: true,
242
+ composed: true,
243
+ })
244
+ )
245
+ } else if (!this.rangeMode && this.selectedDate) {
246
+ this.dispatchEvent(
247
+ new CustomEvent('date-input-change', {
248
+ detail: {
249
+ date: this.selectedDate,
250
+ formattedDate: formatDate(this.selectedDate, this.locale),
251
+ },
252
+ bubbles: true,
253
+ composed: true,
254
+ })
255
+ )
256
+ }
257
+ }
258
+
259
+ private _dispatchCloseEvent(confirmed: boolean): void {
260
+ this.dispatchEvent(
261
+ new CustomEvent('modal-input-close', {
262
+ detail: {
263
+ confirmed,
264
+ date: confirmed && !this.rangeMode ? this.selectedDate : null,
265
+ range: confirmed && this.rangeMode ? this.selectedRange : null,
266
+ },
267
+ bubbles: true,
268
+ composed: true,
269
+ })
270
+ )
271
+ }
272
+
273
+ private _renderHeader(): TemplateResult {
274
+ return html`
275
+ <div class="modal-header">
276
+ <h2 class="modal-title">${this.title}</h2>
277
+ <ui-icon-button @click=${this._handleCancel} aria-label="Close" title="Close">
278
+ <ui-icon icon="close"></ui-icon>
279
+ </ui-icon-button>
280
+ </div>
281
+ `
282
+ }
283
+
284
+ private _renderInputs(): TemplateResult {
285
+ return html`
286
+ <div class="modal-content">
287
+ <div style="display: flex; flex-direction: column; gap: 16px; width: 100%; max-width: 400px;">
288
+ <ui-outlined-text-field
289
+ .label=${this.rangeMode ? this.startLabel : 'Date'}
290
+ .placeholder=${this.placeholder}
291
+ .value=${this._startInput}
292
+ .errorMessage=${this._startError}
293
+ .error=${!!this._startError}
294
+ @input=${this._handleStartInput}
295
+ >
296
+ <ui-icon slot="trailing-icon" icon="calendarToday"></ui-icon>
297
+ </ui-outlined-text-field>
298
+
299
+ ${this.rangeMode
300
+ ? html`
301
+ <ui-outlined-text-field
302
+ .label=${this.endLabel}
303
+ .placeholder=${this.placeholder}
304
+ .value=${this._endInput}
305
+ .errorMessage=${this._endError}
306
+ .error=${!!this._endError}
307
+ @input=${this._handleEndInput}
308
+ >
309
+ <ui-icon slot="trailing-icon" icon="calendarToday"></ui-icon>
310
+ </ui-outlined-text-field>
311
+ `
312
+ : ''}
313
+
314
+ <div
315
+ style="margin-top: 16px; padding: 16px; background: var(--ui-color-surface-variant, #e7e0ec); border-radius: 12px;"
316
+ >
317
+ <p style="margin: 0; font-size: 14px; color: var(--ui-color-on-surface-variant, #49454f);">
318
+ <strong>Supported formats:</strong><br />
319
+ MM/DD/YYYY, MM-DD-YYYY, YYYY-MM-DD
320
+ </p>
321
+ <p style="margin: 8px 0 0; font-size: 14px; color: var(--ui-color-on-surface-variant, #49454f);">
322
+ <strong>Examples:</strong> 12/25/2024, 12-25-2024, 2024-12-25
323
+ </p>
324
+ </div>
325
+ </div>
326
+ </div>
327
+ `
328
+ }
329
+
330
+ private _renderActions(): TemplateResult {
331
+ const hasValidInput = this.rangeMode
332
+ ? this._startInput.trim() && this._endInput.trim() && !this._startError && !this._endError
333
+ : this._startInput.trim() && !this._startError
334
+
335
+ return html`
336
+ <div class="modal-actions">
337
+ <ui-button color="text" @click=${this._handleCancel}>Cancel</ui-button>
338
+ <ui-button color="filled" @click=${this._handleConfirm} .disabled=${!hasValidInput}> Confirm </ui-button>
339
+ </div>
340
+ `
341
+ }
342
+
343
+ override render(): TemplateResult {
344
+ return html`
345
+ <ui-dialog .open=${this.open} @close=${this._handleCancel}>
346
+ ${this._renderHeader()} ${this._renderInputs()} ${this._renderActions()}
347
+ </ui-dialog>
348
+ `
349
+ }
350
+ }
351
+
352
+ declare global {
353
+ interface HTMLElementTagNameMap {
354
+ 'ui-date-picker-modal-input': UiDatePickerModalInput
355
+ }
356
+
357
+ interface HTMLElementEventMap {
358
+ 'date-input-change': CustomEvent<
359
+ | ModalInputDatePickerChangeEvent
360
+ | {
361
+ date: Date
362
+ formattedDate: string
363
+ }
364
+ >
365
+ 'modal-input-close': CustomEvent<{
366
+ confirmed: boolean
367
+ date?: Date | null
368
+ range?: DateRange | null
369
+ }>
370
+ }
371
+ }
@@ -0,0 +1,263 @@
1
+ import { LitElement, html, TemplateResult } from 'lit'
2
+ import { customElement, property, state } from 'lit/decorators.js'
3
+ import { modalStyles } from './internals/DatePicker.styles.js'
4
+ import { DateRange, formatDate } from './internals/DatePickerUtils.js'
5
+ import type { DateRangeSelectEvent } from './internals/DatePickerCalendar.js'
6
+ import './internals/DatePickerCalendar.js'
7
+ import '../../md/dialog/ui-dialog.js'
8
+ import '../../md/button/ui-button.js'
9
+ import '../../md/icon-button/ui-icon-button.js'
10
+ import '../../md/icons/ui-icon.js'
11
+
12
+ export interface ModalDatePickerChangeEvent {
13
+ range: DateRange
14
+ formattedRange: {
15
+ start: string | null
16
+ end: string | null
17
+ }
18
+ }
19
+
20
+ /**
21
+ * A modal date picker for selecting date ranges.
22
+ * Extends full-screen and is ideal for date range selection like flight bookings.
23
+ *
24
+ * ## Usage
25
+ *
26
+ * ```html
27
+ * <ui-date-picker-modal
28
+ * .open=${true}
29
+ * .selectedRange=${{ start: new Date(), end: null }}
30
+ * @change=${this.handleRangeChange}
31
+ * @close=${this.handleClose}
32
+ * ></ui-date-picker-modal>
33
+ * ```
34
+ *
35
+ * ### Custom labels
36
+ * ```html
37
+ * <ui-date-picker-modal
38
+ * title="Select travel dates"
39
+ * startLabel="Check-in"
40
+ * endLabel="Check-out"
41
+ * ></ui-date-picker-modal>
42
+ * ```
43
+ */
44
+ @customElement('ui-date-picker-modal')
45
+ export class UiDatePickerModal extends LitElement {
46
+ static override styles = modalStyles
47
+
48
+ /**
49
+ * Whether the modal is open
50
+ */
51
+ @property({ type: Boolean }) accessor open = false
52
+
53
+ /**
54
+ * The modal title
55
+ */
56
+ @property({ type: String }) override accessor title = 'Select dates'
57
+
58
+ /**
59
+ * Label for the start date
60
+ */
61
+ @property({ type: String }) accessor startLabel = 'Start date'
62
+
63
+ /**
64
+ * Label for the end date
65
+ */
66
+ @property({ type: String }) accessor endLabel = 'End date'
67
+
68
+ /**
69
+ * The selected date range
70
+ */
71
+ @property({ type: Object }) accessor selectedRange: DateRange | null = null
72
+
73
+ /**
74
+ * Minimum selectable date
75
+ */
76
+ @property({ type: Object }) accessor minDate: Date | undefined = undefined
77
+
78
+ /**
79
+ * Maximum selectable date
80
+ */
81
+ @property({ type: Object }) accessor maxDate: Date | undefined = undefined
82
+
83
+ /**
84
+ * Array of disabled dates
85
+ */
86
+ @property({ type: Array }) accessor disabledDates: Date[] | undefined = undefined
87
+
88
+ /**
89
+ * Locale for date formatting
90
+ */
91
+ @property({ type: String }) accessor locale: string | undefined = undefined
92
+
93
+ /**
94
+ * Whether to show edit/calendar toggle button
95
+ */
96
+ @property({ type: Boolean }) accessor showModeToggle = true
97
+
98
+ @state() private accessor _isInputMode = false
99
+
100
+ private _handleRangeSelect(event: CustomEvent<DateRangeSelectEvent>): void {
101
+ this.selectedRange = event.detail.range
102
+ this._dispatchChangeEvent()
103
+ }
104
+
105
+ private _handleCancel(): void {
106
+ this._dispatchCloseEvent(false)
107
+ }
108
+
109
+ private _handleConfirm(): void {
110
+ this._dispatchCloseEvent(true)
111
+ }
112
+
113
+ private _handleModeToggle(): void {
114
+ this._isInputMode = !this._isInputMode
115
+ }
116
+
117
+ private _dispatchChangeEvent(): void {
118
+ if (!this.selectedRange) return
119
+
120
+ const event: ModalDatePickerChangeEvent = {
121
+ range: this.selectedRange,
122
+ formattedRange: {
123
+ start: this.selectedRange.start ? formatDate(this.selectedRange.start, this.locale) : null,
124
+ end: this.selectedRange.end ? formatDate(this.selectedRange.end, this.locale) : null,
125
+ },
126
+ }
127
+
128
+ this.dispatchEvent(
129
+ new CustomEvent('date-range-change', {
130
+ detail: event,
131
+ bubbles: true,
132
+ composed: true,
133
+ })
134
+ )
135
+ }
136
+
137
+ private _dispatchCloseEvent(confirmed: boolean): void {
138
+ this.dispatchEvent(
139
+ new CustomEvent('close', {
140
+ detail: {
141
+ confirmed,
142
+ range: confirmed ? this.selectedRange : null,
143
+ },
144
+ bubbles: true,
145
+ composed: true,
146
+ })
147
+ )
148
+ }
149
+
150
+ private _renderHeader(): TemplateResult {
151
+ return html`
152
+ <div class="modal-header">
153
+ <h2 class="modal-title">${this.title}</h2>
154
+ <div style="display: flex; gap: 8px;">
155
+ ${this.showModeToggle
156
+ ? html`
157
+ <ui-icon-button
158
+ @click=${this._handleModeToggle}
159
+ aria-label=${this._isInputMode ? 'Show calendar' : 'Show date input'}
160
+ title=${this._isInputMode ? 'Show calendar' : 'Show date input'}
161
+ >
162
+ <ui-icon icon=${this._isInputMode ? 'calendarToday' : 'edit'}></ui-icon>
163
+ </ui-icon-button>
164
+ `
165
+ : ''}
166
+ <ui-icon-button @click=${this._handleCancel} aria-label="Close" title="Close">
167
+ <ui-icon icon="close"></ui-icon>
168
+ </ui-icon-button>
169
+ </div>
170
+ </div>
171
+ `
172
+ }
173
+
174
+ private _renderDateDisplay(): TemplateResult {
175
+ const startDate = this.selectedRange?.start
176
+ const endDate = this.selectedRange?.end
177
+
178
+ return html`
179
+ <div class="date-range-display">
180
+ <div class="date-display">
181
+ <div class="date-label">${this.startLabel}</div>
182
+ <div class="date-value">${startDate ? formatDate(startDate, this.locale) : 'Select date'}</div>
183
+ </div>
184
+ <div class="date-separator">—</div>
185
+ <div class="date-display">
186
+ <div class="date-label">${this.endLabel}</div>
187
+ <div class="date-value">${endDate ? formatDate(endDate, this.locale) : 'Select date'}</div>
188
+ </div>
189
+ </div>
190
+ `
191
+ }
192
+
193
+ private _renderCalendar(): TemplateResult {
194
+ const currentDate = this.selectedRange?.start || new Date()
195
+
196
+ return html`
197
+ <ui-date-picker-calendar
198
+ .year=${currentDate.getFullYear()}
199
+ .month=${currentDate.getMonth()}
200
+ .selectedRange=${this.selectedRange}
201
+ .rangeSelection=${true}
202
+ .minDate=${this.minDate}
203
+ .maxDate=${this.maxDate}
204
+ .disabledDates=${this.disabledDates}
205
+ .locale=${this.locale}
206
+ @date-range-select=${this._handleRangeSelect}
207
+ ></ui-date-picker-calendar>
208
+ `
209
+ }
210
+
211
+ private _renderInputMode(): TemplateResult {
212
+ // For now, we'll show a placeholder for input mode
213
+ // This could be enhanced with actual date input fields
214
+ return html`
215
+ <div style="padding: 24px; text-align: center; color: var(--ui-color-on-surface-variant);">
216
+ <ui-icon icon="edit" style="font-size: 48px; margin-bottom: 16px;"></ui-icon>
217
+ <p>Manual date input mode</p>
218
+ <p>This feature can be enhanced with date input fields</p>
219
+ </div>
220
+ `
221
+ }
222
+
223
+ private _renderContent(): TemplateResult {
224
+ return html`
225
+ <div class="modal-content">
226
+ ${this._renderDateDisplay()} ${this._isInputMode ? this._renderInputMode() : this._renderCalendar()}
227
+ </div>
228
+ `
229
+ }
230
+
231
+ private _renderActions(): TemplateResult {
232
+ const hasValidRange = this.selectedRange?.start && this.selectedRange?.end
233
+
234
+ return html`
235
+ <div class="modal-actions">
236
+ <ui-button color="text" @click=${this._handleCancel}>Cancel</ui-button>
237
+ <ui-button color="filled" @click=${this._handleConfirm} .disabled=${!hasValidRange}> Confirm </ui-button>
238
+ </div>
239
+ `
240
+ }
241
+
242
+ override render(): TemplateResult {
243
+ return html`
244
+ <ui-dialog .open=${this.open} @close=${this._handleCancel}>
245
+ ${this._renderHeader()} ${this._renderContent()} ${this._renderActions()}
246
+ </ui-dialog>
247
+ `
248
+ }
249
+ }
250
+
251
+ declare global {
252
+ interface HTMLElementTagNameMap {
253
+ 'ui-date-picker-modal': UiDatePickerModal
254
+ }
255
+
256
+ interface HTMLElementEventMap {
257
+ 'date-range-change': CustomEvent<ModalDatePickerChangeEvent>
258
+ 'close': CustomEvent<{
259
+ confirmed: boolean
260
+ range: DateRange | null
261
+ }>
262
+ }
263
+ }
@@ -35,6 +35,7 @@ export default css`
35
35
  left: 50%;
36
36
  transform: translate(-50%, -50%);
37
37
  margin: 0;
38
+ z-index: 1000;
38
39
  }
39
40
 
40
41
  dialog.non-modal:open {