@api-client/ui 0.5.5 → 0.5.7
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.
- package/.cursor/rules/html-and-css-best-practices.mdc +63 -0
- package/.cursor/rules/lit-best-practices.mdc +78 -0
- package/.github/instructions/html-and-css-best-practices.instructions.md +70 -0
- package/.github/instructions/lit-best-practices.instructions.md +86 -0
- package/build/src/elements/currency/currency-picker.d.ts +10 -0
- package/build/src/elements/currency/currency-picker.d.ts.map +1 -0
- package/build/src/elements/currency/currency-picker.js +27 -0
- package/build/src/elements/currency/currency-picker.js.map +1 -0
- package/build/src/elements/currency/internals/Picker.d.ts +311 -0
- package/build/src/elements/currency/internals/Picker.d.ts.map +1 -0
- package/build/src/elements/currency/internals/Picker.js +857 -0
- package/build/src/elements/currency/internals/Picker.js.map +1 -0
- package/build/src/elements/currency/internals/Picker.styles.d.ts +3 -0
- package/build/src/elements/currency/internals/Picker.styles.d.ts.map +1 -0
- package/build/src/elements/currency/internals/Picker.styles.js +58 -0
- package/build/src/elements/currency/internals/Picker.styles.js.map +1 -0
- package/build/src/elements/highlight/MarkdownStyles.d.ts.map +1 -1
- package/build/src/elements/highlight/MarkdownStyles.js +0 -13
- package/build/src/elements/highlight/MarkdownStyles.js.map +1 -1
- package/build/src/elements/http/BodyEditor.d.ts +0 -13
- package/build/src/elements/http/BodyEditor.d.ts.map +1 -1
- package/build/src/elements/http/BodyEditor.js +0 -13
- package/build/src/elements/http/BodyEditor.js.map +1 -1
- package/build/src/elements/http/BodyTextEditor.d.ts +0 -13
- package/build/src/elements/http/BodyTextEditor.d.ts.map +1 -1
- package/build/src/elements/http/BodyTextEditor.js +0 -13
- package/build/src/elements/http/BodyTextEditor.js.map +1 -1
- package/build/src/elements/http/BodyUrlEncodedEditor.d.ts +0 -13
- package/build/src/elements/http/BodyUrlEncodedEditor.d.ts.map +1 -1
- package/build/src/elements/http/BodyUrlEncodedEditor.js +0 -13
- package/build/src/elements/http/BodyUrlEncodedEditor.js.map +1 -1
- package/build/src/elements/http/UrlInput.d.ts +0 -13
- package/build/src/elements/http/UrlInput.d.ts.map +1 -1
- package/build/src/elements/http/UrlInput.js +0 -13
- package/build/src/elements/http/UrlInput.js.map +1 -1
- package/build/src/index.d.ts +2 -0
- package/build/src/index.d.ts.map +1 -1
- package/build/src/index.js +2 -0
- package/build/src/index.js.map +1 -1
- package/build/src/md/button/internals/base.d.ts +1 -0
- package/build/src/md/button/internals/base.d.ts.map +1 -1
- package/build/src/md/button/internals/base.js +7 -0
- package/build/src/md/button/internals/base.js.map +1 -1
- package/build/src/md/button/internals/button.styles.js +1 -1
- package/build/src/md/button/internals/button.styles.js.map +1 -1
- package/build/src/md/date/internals/DateTime.d.ts +0 -13
- package/build/src/md/date/internals/DateTime.d.ts.map +1 -1
- package/build/src/md/date/internals/DateTime.js +0 -13
- package/build/src/md/date/internals/DateTime.js.map +1 -1
- package/build/src/md/date-picker/index.d.ts +13 -0
- package/build/src/md/date-picker/index.d.ts.map +1 -0
- package/build/src/md/date-picker/index.js +13 -0
- package/build/src/md/date-picker/index.js.map +1 -0
- package/build/src/md/date-picker/internals/DatePicker.styles.d.ts +4 -0
- package/build/src/md/date-picker/internals/DatePicker.styles.d.ts.map +1 -0
- package/build/src/md/date-picker/internals/DatePicker.styles.js +409 -0
- package/build/src/md/date-picker/internals/DatePicker.styles.js.map +1 -0
- package/build/src/md/date-picker/internals/DatePickerCalendar.d.ts +272 -0
- package/build/src/md/date-picker/internals/DatePickerCalendar.d.ts.map +1 -0
- package/build/src/md/date-picker/internals/DatePickerCalendar.js +1062 -0
- package/build/src/md/date-picker/internals/DatePickerCalendar.js.map +1 -0
- package/build/src/md/date-picker/internals/DatePickerUtils.d.ts +93 -0
- package/build/src/md/date-picker/internals/DatePickerUtils.d.ts.map +1 -0
- package/build/src/md/date-picker/internals/DatePickerUtils.js +221 -0
- package/build/src/md/date-picker/internals/DatePickerUtils.js.map +1 -0
- package/build/src/md/date-picker/ui-date-picker-input.d.ts +160 -0
- package/build/src/md/date-picker/ui-date-picker-input.d.ts.map +1 -0
- package/build/src/md/date-picker/ui-date-picker-input.js +464 -0
- package/build/src/md/date-picker/ui-date-picker-input.js.map +1 -0
- package/build/src/md/date-picker/ui-date-picker-modal-input.d.ts +178 -0
- package/build/src/md/date-picker/ui-date-picker-modal-input.d.ts.map +1 -0
- package/build/src/md/date-picker/ui-date-picker-modal-input.js +538 -0
- package/build/src/md/date-picker/ui-date-picker-modal-input.js.map +1 -0
- package/build/src/md/date-picker/ui-date-picker-modal.d.ts +156 -0
- package/build/src/md/date-picker/ui-date-picker-modal.d.ts.map +1 -0
- package/build/src/md/date-picker/ui-date-picker-modal.js +423 -0
- package/build/src/md/date-picker/ui-date-picker-modal.js.map +1 -0
- package/build/src/md/dialog/internals/Dialog.styles.d.ts.map +1 -1
- package/build/src/md/dialog/internals/Dialog.styles.js +1 -0
- package/build/src/md/dialog/internals/Dialog.styles.js.map +1 -1
- package/demo/elements/currency/index.html +91 -0
- package/demo/elements/currency/index.ts +272 -0
- package/demo/elements/har/har2.json +1 -1
- package/demo/elements/index.html +3 -0
- package/demo/md/date-picker/date-picker.ts +336 -0
- package/demo/md/date-picker/index.html +171 -0
- package/demo/md/index.html +2 -0
- package/package.json +1 -1
- package/src/elements/currency/currency-picker.ts +14 -0
- package/src/elements/currency/internals/Picker.styles.ts +58 -0
- package/src/elements/currency/internals/Picker.ts +846 -0
- package/src/elements/highlight/MarkdownStyles.ts +0 -13
- package/src/elements/http/BodyEditor.ts +0 -13
- package/src/elements/http/BodyTextEditor.ts +0 -13
- package/src/elements/http/BodyUrlEncodedEditor.ts +0 -13
- package/src/elements/http/UrlInput.ts +0 -13
- package/src/index.ts +17 -0
- package/src/md/button/internals/base.ts +7 -0
- package/src/md/button/internals/button.styles.ts +1 -1
- package/src/md/date/internals/DateTime.ts +0 -14
- package/src/md/date-picker/README.md +184 -0
- package/src/md/date-picker/index.ts +17 -0
- package/src/md/date-picker/internals/DatePicker.styles.ts +411 -0
- package/src/md/date-picker/internals/DatePickerCalendar.ts +1031 -0
- package/src/md/date-picker/internals/DatePickerUtils.ts +288 -0
- package/src/md/date-picker/ui-date-picker-input.ts +333 -0
- package/src/md/date-picker/ui-date-picker-modal-input.ts +440 -0
- package/src/md/date-picker/ui-date-picker-modal.ts +346 -0
- package/src/md/dialog/internals/Dialog.styles.ts +1 -0
- package/test/README.md +3 -2
- package/test/elements/currency/CurrencyPicker.accessibility.test.ts +328 -0
- package/test/elements/currency/CurrencyPicker.core.test.ts +318 -0
- package/test/elements/currency/CurrencyPicker.integration.test.ts +482 -0
- package/test/elements/currency/CurrencyPicker.test.ts +486 -0
|
@@ -0,0 +1,440 @@
|
|
|
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. Supports both single
|
|
22
|
+
* date selection and date range selection modes.
|
|
23
|
+
*
|
|
24
|
+
* ## Features
|
|
25
|
+
* - Manual date entry with keyboard input
|
|
26
|
+
* - Single date and date range modes
|
|
27
|
+
* - Input validation with error messages
|
|
28
|
+
* - Min/max date constraints
|
|
29
|
+
* - Multiple date format support (MM/DD/YYYY, MM-DD-YYYY, YYYY-MM-DD)
|
|
30
|
+
* - Accessible design with proper ARIA labels and semantic HTML
|
|
31
|
+
* - Real-time validation feedback
|
|
32
|
+
*
|
|
33
|
+
* ## Events
|
|
34
|
+
*
|
|
35
|
+
* ### `date-input-change`
|
|
36
|
+
* Fired when a valid date is entered in the input fields.
|
|
37
|
+
*
|
|
38
|
+
* **Detail for range mode:**
|
|
39
|
+
* ```typescript
|
|
40
|
+
* {
|
|
41
|
+
* range: DateRange,
|
|
42
|
+
* formattedRange: {
|
|
43
|
+
* start: string | null,
|
|
44
|
+
* end: string | null
|
|
45
|
+
* }
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* **Detail for single date mode:**
|
|
50
|
+
* ```typescript
|
|
51
|
+
* {
|
|
52
|
+
* date: Date,
|
|
53
|
+
* formattedDate: string
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* ### `modal-input-close`
|
|
58
|
+
* Fired when the modal is closed, either by confirmation or cancellation.
|
|
59
|
+
*
|
|
60
|
+
* **Detail:**
|
|
61
|
+
* ```typescript
|
|
62
|
+
* {
|
|
63
|
+
* confirmed: boolean,
|
|
64
|
+
* date?: Date | null, // Available in single date mode
|
|
65
|
+
* range?: DateRange | null // Available in range mode
|
|
66
|
+
* }
|
|
67
|
+
* ```
|
|
68
|
+
*
|
|
69
|
+
* ## Usage
|
|
70
|
+
*
|
|
71
|
+
* ### Range mode (default)
|
|
72
|
+
* ```html
|
|
73
|
+
* <ui-date-picker-modal-input
|
|
74
|
+
* .open=${true}
|
|
75
|
+
* .selectedRange=${{ start: new Date(), end: null }}
|
|
76
|
+
* @date-input-change=${this.handleRangeChange}
|
|
77
|
+
* @modal-input-close=${this.handleClose}
|
|
78
|
+
* ></ui-date-picker-modal-input>
|
|
79
|
+
* ```
|
|
80
|
+
*
|
|
81
|
+
* ### Single date mode
|
|
82
|
+
* ```html
|
|
83
|
+
* <ui-date-picker-modal-input
|
|
84
|
+
* .rangeMode=${false}
|
|
85
|
+
* .selectedDate=${new Date()}
|
|
86
|
+
* @date-input-change=${this.handleDateChange}
|
|
87
|
+
* @modal-input-close=${this.handleClose}
|
|
88
|
+
* ></ui-date-picker-modal-input>
|
|
89
|
+
* ```
|
|
90
|
+
*
|
|
91
|
+
* ### With constraints
|
|
92
|
+
* ```html
|
|
93
|
+
* <ui-date-picker-modal-input
|
|
94
|
+
* .minDate=${new Date('2024-01-01')}
|
|
95
|
+
* .maxDate=${new Date('2024-12-31')}
|
|
96
|
+
* .locale=${'en-US'}
|
|
97
|
+
* ></ui-date-picker-modal-input>
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
@customElement('ui-date-picker-modal-input')
|
|
101
|
+
export class UiDatePickerModalInput extends LitElement {
|
|
102
|
+
static override styles = modalStyles
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Whether the modal is open
|
|
106
|
+
*/
|
|
107
|
+
@property({ type: Boolean }) accessor open = false
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The modal title
|
|
111
|
+
*/
|
|
112
|
+
@property({ type: String }) override accessor title = 'Enter dates'
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Whether to use range mode (two date inputs) or single date mode
|
|
116
|
+
*/
|
|
117
|
+
@property({ type: Boolean }) accessor rangeMode = false
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Label for the start date (or single date)
|
|
121
|
+
*/
|
|
122
|
+
@property({ type: String }) accessor startLabel = 'Start date'
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Label for the end date (only used in range mode)
|
|
126
|
+
*/
|
|
127
|
+
@property({ type: String }) accessor endLabel = 'End date'
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Placeholder for date inputs
|
|
131
|
+
*/
|
|
132
|
+
@property({ type: String }) accessor placeholder = 'MM/DD/YYYY'
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* The selected date (single mode)
|
|
136
|
+
*/
|
|
137
|
+
@property({ type: Object }) accessor selectedDate: Date | null = null
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* The selected date range (range mode)
|
|
141
|
+
*/
|
|
142
|
+
@property({ type: Object }) accessor selectedRange: DateRange | null = null
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Minimum selectable date
|
|
146
|
+
*/
|
|
147
|
+
@property({ type: Object }) accessor minDate: Date | undefined = undefined
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Maximum selectable date
|
|
151
|
+
*/
|
|
152
|
+
@property({ type: Object }) accessor maxDate: Date | undefined = undefined
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Locale for date formatting
|
|
156
|
+
*/
|
|
157
|
+
@property({ type: String }) accessor locale: string | undefined = undefined
|
|
158
|
+
|
|
159
|
+
@state() private accessor startInput = ''
|
|
160
|
+
|
|
161
|
+
@state() private accessor endInput = ''
|
|
162
|
+
|
|
163
|
+
@state() private accessor startError = ''
|
|
164
|
+
|
|
165
|
+
@state() private accessor endError = ''
|
|
166
|
+
|
|
167
|
+
constructor() {
|
|
168
|
+
super()
|
|
169
|
+
// Initialize boolean properties to false first, then set intended defaults
|
|
170
|
+
this.open = false
|
|
171
|
+
this.rangeMode = true // Default to range mode as documented
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
override connectedCallback(): void {
|
|
175
|
+
super.connectedCallback()
|
|
176
|
+
this.updateInputValues()
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
override willUpdate(changedProperties: Map<string | number | symbol, unknown>): void {
|
|
180
|
+
if (changedProperties.has('selectedDate') || changedProperties.has('selectedRange')) {
|
|
181
|
+
this.updateInputValues()
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
private updateInputValues(): void {
|
|
186
|
+
if (this.rangeMode && this.selectedRange) {
|
|
187
|
+
this.startInput = this.selectedRange.start ? formatDate(this.selectedRange.start, this.locale) : ''
|
|
188
|
+
this.endInput = this.selectedRange.end ? formatDate(this.selectedRange.end, this.locale) : ''
|
|
189
|
+
} else if (!this.rangeMode && this.selectedDate) {
|
|
190
|
+
this.startInput = formatDate(this.selectedDate, this.locale)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
private validateDate(dateString: string, isEndDate = false): Date | null {
|
|
195
|
+
if (!dateString.trim()) return null
|
|
196
|
+
|
|
197
|
+
const parsedDate = parseDate(dateString)
|
|
198
|
+
if (!parsedDate) return null
|
|
199
|
+
|
|
200
|
+
// Check min/max constraints
|
|
201
|
+
if (this.minDate && parsedDate < this.minDate) return null
|
|
202
|
+
if (this.maxDate && parsedDate > this.maxDate) return null
|
|
203
|
+
|
|
204
|
+
// For range mode, validate end date is after start date
|
|
205
|
+
if (this.rangeMode && isEndDate) {
|
|
206
|
+
const startDate = parseDate(this.startInput)
|
|
207
|
+
if (startDate && parsedDate < startDate) return null
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return parsedDate
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
private handleStartInput(event: Event): void {
|
|
214
|
+
const target = event.target as HTMLInputElement
|
|
215
|
+
this.startInput = target.value
|
|
216
|
+
this.startError = ''
|
|
217
|
+
|
|
218
|
+
if (this.startInput.trim()) {
|
|
219
|
+
const date = this.validateDate(this.startInput)
|
|
220
|
+
if (!date) {
|
|
221
|
+
this.startError = 'Invalid date format or out of range'
|
|
222
|
+
return
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (this.rangeMode) {
|
|
226
|
+
const currentRange = this.selectedRange || { start: null, end: null }
|
|
227
|
+
this.selectedRange = { ...currentRange, start: date }
|
|
228
|
+
} else {
|
|
229
|
+
this.selectedDate = date
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
this.dispatchChangeEvent()
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
private handleEndInput(event: Event): void {
|
|
237
|
+
const target = event.target as HTMLInputElement
|
|
238
|
+
this.endInput = target.value
|
|
239
|
+
this.endError = ''
|
|
240
|
+
|
|
241
|
+
if (this.endInput.trim()) {
|
|
242
|
+
const date = this.validateDate(this.endInput, true)
|
|
243
|
+
if (!date) {
|
|
244
|
+
this.endError = 'Invalid date format, out of range, or before start date'
|
|
245
|
+
return
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const currentRange = this.selectedRange || { start: null, end: null }
|
|
249
|
+
this.selectedRange = { ...currentRange, end: date }
|
|
250
|
+
this.dispatchChangeEvent()
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
private handleCancel(): void {
|
|
255
|
+
this.dispatchCloseEvent(false)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
private handleConfirm(): void {
|
|
259
|
+
// Validate all inputs before confirming
|
|
260
|
+
let hasErrors = false
|
|
261
|
+
|
|
262
|
+
if (this.rangeMode) {
|
|
263
|
+
if (!this.startInput.trim()) {
|
|
264
|
+
this.startError = 'Start date is required'
|
|
265
|
+
hasErrors = true
|
|
266
|
+
} else if (!this.validateDate(this.startInput)) {
|
|
267
|
+
this.startError = 'Invalid start date'
|
|
268
|
+
hasErrors = true
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (!this.endInput.trim()) {
|
|
272
|
+
this.endError = 'End date is required'
|
|
273
|
+
hasErrors = true
|
|
274
|
+
} else if (!this.validateDate(this.endInput, true)) {
|
|
275
|
+
this.endError = 'Invalid end date'
|
|
276
|
+
hasErrors = true
|
|
277
|
+
}
|
|
278
|
+
} else {
|
|
279
|
+
if (!this.startInput.trim()) {
|
|
280
|
+
this.startError = 'Date is required'
|
|
281
|
+
hasErrors = true
|
|
282
|
+
} else if (!this.validateDate(this.startInput)) {
|
|
283
|
+
this.startError = 'Invalid date'
|
|
284
|
+
hasErrors = true
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (!hasErrors) {
|
|
289
|
+
this.dispatchCloseEvent(true)
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
private dispatchChangeEvent(): void {
|
|
294
|
+
if (this.rangeMode && this.selectedRange) {
|
|
295
|
+
const event: ModalInputDatePickerChangeEvent = {
|
|
296
|
+
range: this.selectedRange,
|
|
297
|
+
formattedRange: {
|
|
298
|
+
start: this.selectedRange.start ? formatDate(this.selectedRange.start, this.locale) : null,
|
|
299
|
+
end: this.selectedRange.end ? formatDate(this.selectedRange.end, this.locale) : null,
|
|
300
|
+
},
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
this.dispatchEvent(
|
|
304
|
+
new CustomEvent('date-input-change', {
|
|
305
|
+
detail: event,
|
|
306
|
+
bubbles: true,
|
|
307
|
+
composed: true,
|
|
308
|
+
})
|
|
309
|
+
)
|
|
310
|
+
} else if (!this.rangeMode && this.selectedDate) {
|
|
311
|
+
this.dispatchEvent(
|
|
312
|
+
new CustomEvent('date-input-change', {
|
|
313
|
+
detail: {
|
|
314
|
+
date: this.selectedDate,
|
|
315
|
+
formattedDate: formatDate(this.selectedDate, this.locale),
|
|
316
|
+
},
|
|
317
|
+
bubbles: true,
|
|
318
|
+
composed: true,
|
|
319
|
+
})
|
|
320
|
+
)
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
private dispatchCloseEvent(confirmed: boolean): void {
|
|
325
|
+
this.dispatchEvent(
|
|
326
|
+
new CustomEvent('modal-input-close', {
|
|
327
|
+
detail: {
|
|
328
|
+
confirmed,
|
|
329
|
+
date: confirmed && !this.rangeMode ? this.selectedDate : null,
|
|
330
|
+
range: confirmed && this.rangeMode ? this.selectedRange : null,
|
|
331
|
+
},
|
|
332
|
+
bubbles: true,
|
|
333
|
+
composed: true,
|
|
334
|
+
})
|
|
335
|
+
)
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
private renderHeader(): TemplateResult {
|
|
339
|
+
return html`
|
|
340
|
+
<header class="modal-header">
|
|
341
|
+
<h2 id="modal-title" class="modal-title">${this.title}</h2>
|
|
342
|
+
<ui-icon-button @click=${this.handleCancel} aria-label="Close" title="Close">
|
|
343
|
+
<ui-icon icon="close"></ui-icon>
|
|
344
|
+
</ui-icon-button>
|
|
345
|
+
</header>
|
|
346
|
+
`
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
private renderInputs(): TemplateResult {
|
|
350
|
+
return html`
|
|
351
|
+
<main class="modal-content">
|
|
352
|
+
<div class="input-container" role="form" aria-labelledby="modal-title">
|
|
353
|
+
<fieldset>
|
|
354
|
+
<legend class="visually-hidden">${this.rangeMode ? 'Enter date range' : 'Enter date'}</legend>
|
|
355
|
+
|
|
356
|
+
<ui-outlined-text-field
|
|
357
|
+
.label=${this.rangeMode ? this.startLabel : 'Date'}
|
|
358
|
+
.placeholder=${this.placeholder}
|
|
359
|
+
.value=${this.startInput}
|
|
360
|
+
.invalidText=${this.startError}
|
|
361
|
+
?invalid=${!!this.startError}
|
|
362
|
+
@input=${this.handleStartInput}
|
|
363
|
+
required
|
|
364
|
+
aria-describedby="format-help"
|
|
365
|
+
>
|
|
366
|
+
<ui-icon slot="suffix" icon="calendarToday"></ui-icon>
|
|
367
|
+
</ui-outlined-text-field>
|
|
368
|
+
|
|
369
|
+
${this.rangeMode
|
|
370
|
+
? html`
|
|
371
|
+
<ui-outlined-text-field
|
|
372
|
+
.label=${this.endLabel}
|
|
373
|
+
.placeholder=${this.placeholder}
|
|
374
|
+
.value=${this.endInput}
|
|
375
|
+
.invalidText=${this.endError}
|
|
376
|
+
?invalid=${!!this.endError}
|
|
377
|
+
@input=${this.handleEndInput}
|
|
378
|
+
required
|
|
379
|
+
aria-describedby="format-help"
|
|
380
|
+
>
|
|
381
|
+
<ui-icon slot="suffix" icon="calendarToday"></ui-icon>
|
|
382
|
+
</ui-outlined-text-field>
|
|
383
|
+
`
|
|
384
|
+
: ''}
|
|
385
|
+
</fieldset>
|
|
386
|
+
|
|
387
|
+
<aside id="format-help" class="format-help" role="note" aria-label="Date format information">
|
|
388
|
+
<p class="help-title">
|
|
389
|
+
<strong>Supported formats:</strong><br />
|
|
390
|
+
MM/DD/YYYY, MM-DD-YYYY, YYYY-MM-DD
|
|
391
|
+
</p>
|
|
392
|
+
<p class="help-examples"><strong>Examples:</strong> 12/25/2024, 12-25-2024, 2024-12-25</p>
|
|
393
|
+
</aside>
|
|
394
|
+
</div>
|
|
395
|
+
</main>
|
|
396
|
+
`
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
private renderActions(): TemplateResult {
|
|
400
|
+
const hasValidInput = this.rangeMode
|
|
401
|
+
? this.startInput.trim() && this.endInput.trim() && !this.startError && !this.endError
|
|
402
|
+
: this.startInput.trim() && !this.startError
|
|
403
|
+
|
|
404
|
+
return html`
|
|
405
|
+
<footer class="modal-actions">
|
|
406
|
+
<ui-button color="text" @click=${this.handleCancel}>Cancel</ui-button>
|
|
407
|
+
<ui-button color="filled" @click=${this.handleConfirm} .disabled=${!hasValidInput}> Confirm </ui-button>
|
|
408
|
+
</footer>
|
|
409
|
+
`
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
override render(): TemplateResult {
|
|
413
|
+
return html`
|
|
414
|
+
<ui-dialog .open=${this.open} @close=${this.handleCancel}>
|
|
415
|
+
${this.renderHeader()} ${this.renderInputs()} ${this.renderActions()}
|
|
416
|
+
</ui-dialog>
|
|
417
|
+
`
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
declare global {
|
|
422
|
+
interface HTMLElementTagNameMap {
|
|
423
|
+
'ui-date-picker-modal-input': UiDatePickerModalInput
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
interface HTMLElementEventMap {
|
|
427
|
+
'date-input-change': CustomEvent<
|
|
428
|
+
| ModalInputDatePickerChangeEvent
|
|
429
|
+
| {
|
|
430
|
+
date: Date
|
|
431
|
+
formattedDate: string
|
|
432
|
+
}
|
|
433
|
+
>
|
|
434
|
+
'modal-input-close': CustomEvent<{
|
|
435
|
+
confirmed: boolean
|
|
436
|
+
date?: Date | null
|
|
437
|
+
range?: DateRange | null
|
|
438
|
+
}>
|
|
439
|
+
}
|
|
440
|
+
}
|