@aurodesignsystem/auro-formkit 3.1.0-beta.1 → 3.2.0-beta.1

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 (59) hide show
  1. package/CHANGELOG.md +19 -1
  2. package/components/checkbox/README.md +1 -1
  3. package/components/checkbox/demo/api.min.js +468 -25
  4. package/components/checkbox/demo/index.min.js +468 -25
  5. package/components/checkbox/demo/readme.md +1 -1
  6. package/components/checkbox/dist/index.js +468 -25
  7. package/components/checkbox/dist/registered.js +468 -25
  8. package/components/combobox/README.md +1 -1
  9. package/components/combobox/demo/api.min.js +1125 -74
  10. package/components/combobox/demo/index.min.js +1125 -74
  11. package/components/combobox/demo/readme.md +1 -1
  12. package/components/combobox/dist/auro-combobox.d.ts +30 -0
  13. package/components/combobox/dist/index.js +1125 -74
  14. package/components/combobox/dist/registered.js +1125 -74
  15. package/components/counter/README.md +1 -1
  16. package/components/counter/demo/api.min.js +570 -45
  17. package/components/counter/demo/index.min.js +570 -45
  18. package/components/counter/demo/readme.md +1 -1
  19. package/components/counter/dist/index.js +570 -45
  20. package/components/counter/dist/registered.js +570 -45
  21. package/components/datepicker/README.md +1 -1
  22. package/components/datepicker/demo/api.min.js +1073 -70
  23. package/components/datepicker/demo/index.min.js +1073 -70
  24. package/components/datepicker/demo/readme.md +1 -1
  25. package/components/datepicker/dist/index.js +1073 -70
  26. package/components/datepicker/dist/registered.js +1073 -70
  27. package/components/dropdown/README.md +1 -1
  28. package/components/dropdown/demo/api.md +8 -5
  29. package/components/dropdown/demo/api.min.js +104 -22
  30. package/components/dropdown/demo/index.min.js +104 -22
  31. package/components/dropdown/demo/readme.md +1 -1
  32. package/components/dropdown/dist/auro-dropdown.d.ts +29 -0
  33. package/components/dropdown/dist/index.js +104 -22
  34. package/components/dropdown/dist/registered.js +104 -22
  35. package/components/form/README.md +1 -1
  36. package/components/form/demo/readme.md +1 -1
  37. package/components/input/README.md +1 -1
  38. package/components/input/demo/api.md +4 -1
  39. package/components/input/demo/api.min.js +503 -25
  40. package/components/input/demo/index.min.js +503 -25
  41. package/components/input/demo/readme.md +1 -1
  42. package/components/input/dist/base-input.d.ts +24 -0
  43. package/components/input/dist/index.js +503 -25
  44. package/components/input/dist/registered.js +503 -25
  45. package/components/menu/README.md +1 -1
  46. package/components/menu/demo/readme.md +1 -1
  47. package/components/radio/README.md +1 -1
  48. package/components/radio/demo/api.min.js +468 -25
  49. package/components/radio/demo/index.min.js +468 -25
  50. package/components/radio/demo/readme.md +1 -1
  51. package/components/radio/dist/index.js +468 -25
  52. package/components/radio/dist/registered.js +468 -25
  53. package/components/select/README.md +1 -1
  54. package/components/select/demo/api.min.js +570 -45
  55. package/components/select/demo/index.min.js +570 -45
  56. package/components/select/demo/readme.md +1 -1
  57. package/components/select/dist/index.js +570 -45
  58. package/components/select/dist/registered.js +570 -45
  59. package/package.json +2 -2
@@ -5,6 +5,414 @@ import { classMap } from 'lit/directives/class-map.js';
5
5
  import { ifDefined } from 'lit/directives/if-defined.js';
6
6
  import { repeat } from 'lit/directives/repeat.js';
7
7
 
8
+ let DateFormatter$1 = class DateFormatter {
9
+
10
+ constructor() {
11
+
12
+ /**
13
+ * @description Parses a date string into its components.
14
+ * @param {string} dateStr - Date string to parse.
15
+ * @param {string} format - Date format to parse.
16
+ * @returns {Object<key["month" | "day" | "year"]: number>|undefined}
17
+ */
18
+ this.parseDate = (dateStr, format = 'mm/dd/yyyy') => {
19
+
20
+ // Guard Clause: Date string is defined
21
+ if (!dateStr) {
22
+ return undefined;
23
+ }
24
+
25
+ // Assume the separator is a "/" a defined in our code base
26
+ const separator = '/';
27
+
28
+ // Get the parts of the date and format
29
+ const valueParts = dateStr.split(separator);
30
+ const formatParts = format.split(separator);
31
+
32
+ // Check if the value and format have the correct number of parts
33
+ if (valueParts.length !== formatParts.length) {
34
+ throw new Error('AuroDatepickerUtilities | parseDate: Date string and format length do not match');
35
+ }
36
+
37
+ // Holds the result to be returned
38
+ const result = formatParts.reduce((acc, part, index) => {
39
+ const value = valueParts[index];
40
+
41
+ if ((/m/iu).test(part)) {
42
+ acc.month = value;
43
+ } else if ((/d/iu).test(part)) {
44
+ acc.day = value;
45
+ } else if ((/y/iu).test(part)) {
46
+ acc.year = value;
47
+ }
48
+
49
+ return acc;
50
+ }, {});
51
+
52
+ // If we found all the parts, return the result
53
+ if (result.month && result.year) {
54
+ return result;
55
+ }
56
+
57
+ // Throw an error to let the dev know we were unable to parse the date string
58
+ throw new Error('AuroDatepickerUtilities | parseDate: Unable to parse date string');
59
+ };
60
+
61
+ /**
62
+ * Convert a date object to string format.
63
+ * @param {Object} date - Date to convert to string.
64
+ * @returns {Object} Returns the date as a string.
65
+ */
66
+ this.getDateAsString = (date) => date.toLocaleDateString(undefined, {
67
+ year: "numeric",
68
+ month: "2-digit",
69
+ day: "2-digit",
70
+ });
71
+
72
+ /**
73
+ * Converts a date string to a North American date format.
74
+ * @param {String} dateStr - Date to validate.
75
+ * @param {String} format - Date format to validate against.
76
+ * @returns {Boolean}
77
+ */
78
+ this.toNorthAmericanFormat = (dateStr, format) => {
79
+
80
+ if (format === 'mm/dd/yyyy') {
81
+ return dateStr;
82
+ }
83
+
84
+ const parsedDate = this.parseDate(dateStr, format);
85
+
86
+ if (!parsedDate) {
87
+ throw new Error('AuroDatepickerUtilities | toNorthAmericanFormat: Unable to parse date string');
88
+ }
89
+
90
+ const { month, day, year } = parsedDate;
91
+
92
+ const dateParts = [];
93
+ if (month) {
94
+ dateParts.push(month);
95
+ }
96
+
97
+ if (day) {
98
+ dateParts.push(day);
99
+ }
100
+
101
+ if (year) {
102
+ dateParts.push(year);
103
+ }
104
+
105
+ return dateParts.join('/');
106
+ };
107
+ }
108
+ };
109
+ const dateFormatter$1 = new DateFormatter$1();
110
+
111
+ // filepath: dateConstraints.mjs
112
+ const DATE_UTIL_CONSTRAINTS$1 = {
113
+ maxDay: 31,
114
+ maxMonth: 12,
115
+ maxYear: 2400,
116
+ minDay: 1,
117
+ minMonth: 1,
118
+ minYear: 1900,
119
+ };
120
+
121
+ let AuroDateUtilitiesBase$1 = class AuroDateUtilitiesBase {
122
+
123
+ /**
124
+ * @description The maximum day value allowed by the various utilities in this class.
125
+ * @readonly
126
+ * @type {Number}
127
+ */
128
+ get maxDay() {
129
+ return DATE_UTIL_CONSTRAINTS$1.maxDay;
130
+ }
131
+
132
+ /**
133
+ * @description The maximum month value allowed by the various utilities in this class.
134
+ * @readonly
135
+ * @type {Number}
136
+ */
137
+ get maxMonth() {
138
+ return DATE_UTIL_CONSTRAINTS$1.maxMonth;
139
+ }
140
+
141
+ /**
142
+ * @description The maximum year value allowed by the various utilities in this class.
143
+ * @readonly
144
+ * @type {Number}
145
+ */
146
+ get maxYear() {
147
+ return DATE_UTIL_CONSTRAINTS$1.maxYear;
148
+ }
149
+
150
+ /**
151
+ * @description The minimum day value allowed by the various utilities in this class.
152
+ * @readonly
153
+ * @type {Number}
154
+ */
155
+ get minDay() {
156
+ return DATE_UTIL_CONSTRAINTS$1.minDay;
157
+ }
158
+
159
+ /**
160
+ * @description The minimum month value allowed by the various utilities in this class.
161
+ * @readonly
162
+ * @type {Number}
163
+ */
164
+ get minMonth() {
165
+ return DATE_UTIL_CONSTRAINTS$1.minMonth;
166
+ }
167
+
168
+ /**
169
+ * @description The minimum year value allowed by the various utilities in this class.
170
+ * @readonly
171
+ * @type {Number}
172
+ */
173
+ get minYear() {
174
+ return DATE_UTIL_CONSTRAINTS$1.minYear;
175
+ }
176
+ };
177
+
178
+ /* eslint-disable no-magic-numbers */
179
+
180
+ let AuroDateUtilities$1 = class AuroDateUtilities extends AuroDateUtilitiesBase$1 {
181
+
182
+ /**
183
+ * Returns the current century.
184
+ * @returns {String} The current century.
185
+ */
186
+ getCentury () {
187
+ return String(new Date().getFullYear()).slice(0, 2);
188
+ }
189
+
190
+ /**
191
+ * Returns a four digit year.
192
+ * @param {String} year - The year to convert to four digits.
193
+ * @returns {String} The four digit year.
194
+ */
195
+ getFourDigitYear (year) {
196
+
197
+ const strYear = String(year).trim();
198
+ return strYear.length <= 2 ? this.getCentury() + strYear : strYear;
199
+ }
200
+
201
+ constructor() {
202
+
203
+ super();
204
+
205
+ /**
206
+ * Compares two dates to see if they match.
207
+ * @param {Object} date1 - First date to compare.
208
+ * @param {Object} date2 - Second date to compare.
209
+ * @returns {Boolean} Returns true if the dates match.
210
+ */
211
+ this.datesMatch = (date1, date2) => new Date(date1).getTime() === new Date(date2).getTime();
212
+
213
+ /**
214
+ * Returns true if value passed in is a valid date.
215
+ * @param {String} date - Date to validate.
216
+ * @param {String} format - Date format to validate against.
217
+ * @returns {Boolean}
218
+ */
219
+ this.validDateStr = (date, format) => {
220
+
221
+ // The length we expect the date string to be
222
+ const dateStrLength = format.length;
223
+
224
+ // Guard Clause: Date and format are defined
225
+ if (typeof date === "undefined" || typeof format === "undefined") {
226
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date and format are required');
227
+ }
228
+
229
+ // Guard Clause: Date should be of type string
230
+ if (typeof date !== "string") {
231
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date must be a string');
232
+ }
233
+
234
+ // Guard Clause: Format should be of type string
235
+ if (typeof format !== "string") {
236
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Format must be a string');
237
+ }
238
+
239
+ // Guard Clause: Length is what we expect it to be
240
+ if (date.length !== dateStrLength) {
241
+ return false;
242
+ }
243
+ // Get a formatted date string and parse it
244
+ const dateParts = dateFormatter$1.parseDate(date, format);
245
+
246
+ // Guard Clause: Date parse succeeded
247
+ if (!dateParts) {
248
+ return false;
249
+ }
250
+
251
+ // Create the expected date string based on the date parts
252
+ const expectedDateStr = `${dateParts.month}/${dateParts.day || "01"}/${this.getFourDigitYear(dateParts.year)}`;
253
+
254
+ // Generate a date object that we will extract a string date from to compare to the passed in date string
255
+ const dateObj = new Date(this.getFourDigitYear(dateParts.year), dateParts.month - 1, dateParts.day || 1);
256
+
257
+ // Get the date string of the date object we created from the string date
258
+ const actualDateStr = dateFormatter$1.getDateAsString(dateObj);
259
+
260
+ // Guard Clause: Generated date matches date string input
261
+ if (expectedDateStr !== actualDateStr) {
262
+ return false;
263
+ }
264
+
265
+ // If we passed all other checks, we can assume the date is valid
266
+ return true;
267
+ };
268
+
269
+ /**
270
+ * Determines if a string date value matches the format provided.
271
+ * @param {string} value = The date string value.
272
+ * @param { string} format = The date format to match against.
273
+ * @returns {boolean}
274
+ */
275
+ this.dateAndFormatMatch = (value, format) => {
276
+
277
+ // Ensure we have both values we need to do the comparison
278
+ if (!value || !format) {
279
+ throw new Error('AuroFormValidation | dateFormatMatch: value and format are required');
280
+ }
281
+
282
+ // If the lengths are different, they cannot match
283
+ if (value.length !== format.length) {
284
+ return false;
285
+ }
286
+
287
+ // Get the parts of the date
288
+ const dateParts = dateFormatter$1.parseDate(value, format);
289
+
290
+ // Validator for day
291
+ const dayValueIsValid = (day) => {
292
+
293
+ // Guard clause: if there is no day in the dateParts, we can ignore this check.
294
+ if (!dateParts.day) {
295
+ return true;
296
+ }
297
+
298
+ // Guard clause: ensure day exists.
299
+ if (!day) {
300
+ return false;
301
+ }
302
+
303
+ // Convert day to number
304
+ const numDay = Number.parseInt(day, 10);
305
+
306
+ // Guard clause: ensure day is a valid integer
307
+ if (Number.isNaN(numDay)) {
308
+ throw new Error('AuroDatepickerUtilities | dayValueIsValid: Unable to parse day value integer');
309
+ }
310
+
311
+ // Guard clause: ensure day is within the valid range
312
+ if (numDay < this.minDay || numDay > this.maxDay) {
313
+ return false;
314
+ }
315
+
316
+ // Default return
317
+ return true;
318
+ };
319
+
320
+ // Validator for month
321
+ const monthValueIsValid = (month) => {
322
+
323
+ // Guard clause: ensure month exists.
324
+ if (!month) {
325
+ return false;
326
+ }
327
+
328
+ // Convert month to number
329
+ const numMonth = Number.parseInt(month, 10);
330
+
331
+ // Guard clause: ensure month is a valid integer
332
+ if (Number.isNaN(numMonth)) {
333
+ throw new Error('AuroDatepickerUtilities | monthValueIsValid: Unable to parse month value integer');
334
+ }
335
+
336
+ // Guard clause: ensure month is within the valid range
337
+ if (numMonth < this.minMonth || numMonth > this.maxMonth) {
338
+ return false;
339
+ }
340
+
341
+ // Default return
342
+ return true;
343
+ };
344
+
345
+ // Validator for year
346
+ const yearIsValid = (_year) => {
347
+
348
+ // Guard clause: ensure year exists.
349
+ if (!_year) {
350
+ return false;
351
+ }
352
+
353
+ // Get the full year
354
+ const year = this.getFourDigitYear(_year);
355
+
356
+ // Convert year to number
357
+ const numYear = Number.parseInt(year, 10);
358
+
359
+ // Guard clause: ensure year is a valid integer
360
+ if (Number.isNaN(numYear)) {
361
+ throw new Error('AuroDatepickerUtilities | yearValueIsValid: Unable to parse year value integer');
362
+ }
363
+
364
+ // Guard clause: ensure year is within the valid range
365
+ if (numYear < this.minYear || numYear > this.maxYear) {
366
+ return false;
367
+ }
368
+
369
+ // Default return
370
+ return true;
371
+ };
372
+
373
+ // Self-contained checks for month, day, and year
374
+ const checks = [
375
+ monthValueIsValid(dateParts.month),
376
+ dayValueIsValid(dateParts.day),
377
+ yearIsValid(dateParts.year)
378
+ ];
379
+
380
+ // If any of the checks failed, the date format does not match and the result is invalid
381
+ const isValid = checks.every((check) => check === true);
382
+
383
+ // If the check is invalid, return false
384
+ if (!isValid) {
385
+ return false;
386
+ }
387
+
388
+ // Default case
389
+ return true;
390
+ };
391
+ }
392
+ };
393
+
394
+ // Export a class instance
395
+ const dateUtilities$1 = new AuroDateUtilities$1();
396
+
397
+ // Export the class instance methods individually
398
+ const {
399
+ datesMatch: datesMatch$1,
400
+ validDateStr: validDateStr$1,
401
+ dateAndFormatMatch: dateAndFormatMatch$1,
402
+ minDay: minDay$1,
403
+ minMonth: minMonth$1,
404
+ minYear: minYear$1,
405
+ maxDay: maxDay$1,
406
+ maxMonth: maxMonth$1,
407
+ maxYear: maxYear$1
408
+ } = dateUtilities$1;
409
+
410
+ const {
411
+ toNorthAmericanFormat: toNorthAmericanFormat$1,
412
+ parseDate: parseDate$1,
413
+ getDateAsString: getDateAsString$1
414
+ } = dateFormatter$1;
415
+
8
416
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
9
417
  // See LICENSE in the project root for license information.
10
418
 
@@ -80,6 +488,7 @@ let AuroLibraryRuntimeUtils$4 = class AuroLibraryRuntimeUtils {
80
488
 
81
489
 
82
490
  let AuroFormValidation$1 = class AuroFormValidation {
491
+
83
492
  constructor() {
84
493
  this.runtimeUtils = new AuroLibraryRuntimeUtils$4();
85
494
  }
@@ -171,17 +580,17 @@ let AuroFormValidation$1 = class AuroFormValidation {
171
580
  ]
172
581
  }
173
582
  };
174
-
583
+
175
584
  let elementType;
176
585
  if (this.runtimeUtils.elementMatch(elem, 'auro-input')) {
177
586
  elementType = 'input';
178
587
  } else if (this.runtimeUtils.elementMatch(elem, 'auro-counter') || this.runtimeUtils.elementMatch(elem, 'auro-counter-group')) {
179
588
  elementType = 'counter';
180
589
  }
181
-
590
+
182
591
  if (elementType) {
183
592
  const rules = validationRules[elementType];
184
-
593
+
185
594
  if (rules) {
186
595
  Object.values(rules).flat().forEach(rule => {
187
596
  if (rule.check(elem)) {
@@ -207,48 +616,82 @@ let AuroFormValidation$1 = class AuroFormValidation {
207
616
  if (!elem.value.match(emailRegex)) {
208
617
  elem.validity = 'patternMismatch';
209
618
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
619
+ return;
210
620
  }
211
621
  } else if (elem.type === 'credit-card') {
212
622
  if (elem.value.length > 0 && elem.value.length < elem.validationCCLength) {
213
623
  elem.validity = 'tooShort';
214
624
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
625
+ return;
215
626
  }
216
627
  } else if (elem.type === 'number') {
217
628
  if (elem.max !== undefined && Number(elem.max) < Number(elem.value)) {
218
629
  elem.validity = 'rangeOverflow';
219
630
  elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
631
+ return;
220
632
  }
221
633
 
222
634
  if (elem.min !== undefined && elem.value?.length > 0 && Number(elem.min) > Number(elem.value)) {
223
635
  elem.validity = 'rangeUnderflow';
224
636
  elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
637
+ return;
225
638
  }
226
- } else if (elem.type === 'date') {
227
- if (elem.value?.length > 0 && elem.value?.length < elem.lengthForType) {
639
+ } else if (elem.type === 'date' && elem.value?.length > 0) {
640
+
641
+ // Guard Clause: if the value is too short
642
+ if (elem.value.length < elem.lengthForType) {
643
+
228
644
  elem.validity = 'tooShort';
229
645
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
230
- } else if (elem.value?.length === elem.lengthForType && elem.util.toNorthAmericanFormat(elem.value, elem.format)) {
231
- const formattedValue = elem.util.toNorthAmericanFormat(elem.value, elem.format);
232
- const valueDate = new Date(formattedValue.dateForComparison);
646
+ return;
647
+ }
648
+
649
+ // Guard Clause: If the value is too long for the type
650
+ if (elem.value?.length > elem.lengthForType) {
233
651
 
234
- // validate max
235
- if (elem.max?.length === elem.lengthForType) {
236
- const maxDate = new Date(elem.util.toNorthAmericanFormat(elem.max, elem.format).dateForComparison);
652
+ elem.validity = 'tooLong';
653
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
654
+ return;
655
+ }
656
+
657
+ // Validate that the date passed was the correct format
658
+ if (!dateAndFormatMatch$1(elem.value, elem.format)) {
659
+ elem.validity = 'patternMismatch';
660
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || 'Invalid Date Format Entered';
661
+ return;
662
+ }
663
+
664
+ // Validate that the date passed was a valid date
665
+ if (!validDateStr$1(elem.value, elem.format)) {
666
+ elem.validity = 'invalidDate';
667
+ elem.errorMessage = elem.setCustomValidityInvalidDate || elem.setCustomValidity || 'Invalid Date Entered';
668
+ return;
669
+ }
237
670
 
238
- if (valueDate > maxDate) {
239
- elem.validity = 'rangeOverflow';
240
- elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
241
- }
671
+ // Perform the rest of the validation
672
+ const formattedValue = toNorthAmericanFormat$1(elem.value, elem.format);
673
+ const valueDate = new Date(formattedValue);
674
+
675
+ // // Validate max date
676
+ if (elem.max?.length === elem.lengthForType) {
677
+
678
+ const maxDate = new Date(toNorthAmericanFormat$1(elem.max, elem.format));
679
+
680
+ if (valueDate > maxDate) {
681
+ elem.validity = 'rangeOverflow';
682
+ elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
683
+ return;
242
684
  }
685
+ }
243
686
 
244
- // validate min
245
- if (elem.min?.length === elem.lengthForType) {
246
- const minDate = new Date(elem.util.toNorthAmericanFormat(elem.min, elem.format).dateForComparison);
687
+ // Validate min date
688
+ if (elem.min?.length === elem.lengthForType) {
689
+ const minDate = new Date(toNorthAmericanFormat$1(elem.min, elem.format));
247
690
 
248
- if (valueDate < minDate) {
249
- elem.validity = 'rangeUnderflow';
250
- elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
251
- }
691
+ if (valueDate < minDate) {
692
+ elem.validity = 'rangeUnderflow';
693
+ elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
694
+ return;
252
695
  }
253
696
  }
254
697
  }
@@ -367,7 +810,7 @@ let AuroFormValidation$1 = class AuroFormValidation {
367
810
  if (input.validationMessage.length > 0) {
368
811
  elem.errorMessage = input.validationMessage;
369
812
  }
370
- } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
813
+ } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
371
814
  const firstInput = this.inputElements[0];
372
815
 
373
816
  if (firstInput.validationMessage.length > 0) {
@@ -13709,7 +14152,7 @@ class AuroFloatingUI {
13709
14152
  /**
13710
14153
  * @private
13711
14154
  * getting called on 'blur' in trigger or `focusin` in document
13712
- *
14155
+ *
13713
14156
  * Hides the bib if focus moves outside of the trigger or bib, unless a 'noHideOnThisFocusLoss' flag is set.
13714
14157
  * This method checks if the currently active element is still within the trigger or bib.
13715
14158
  * If not, and if the bib isn't in fullscreen mode with focus lost, it hides the bib.
@@ -13825,7 +14268,7 @@ class AuroFloatingUI {
13825
14268
  // Close any other dropdown that is already open
13826
14269
  const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
13827
14270
  if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this &&
13828
- existedVisibleFloatingUI.isPopoverVisible &&
14271
+ existedVisibleFloatingUI.element.isPopoverVisible &&
13829
14272
  document.expandedAuroFloater.eventPrefix === this.eventPrefix) {
13830
14273
  document.expandedAuroFloater.hideBib();
13831
14274
  }
@@ -14001,7 +14444,7 @@ class AuroFloatingUI {
14001
14444
  this.id = window.crypto.randomUUID();
14002
14445
  this.element.setAttribute('id', this.id);
14003
14446
  }
14004
-
14447
+
14005
14448
  this.element.bib.setAttribute("id", `${this.id}-floater-bib`);
14006
14449
  }
14007
14450
 
@@ -14054,7 +14497,7 @@ class AuroFloatingUI {
14054
14497
  if (this.element.bib) {
14055
14498
  this.element.shadowRoot.append(this.element.bib);
14056
14499
  }
14057
-
14500
+
14058
14501
  // Remove event & keyboard listeners
14059
14502
  if (this.element?.trigger) {
14060
14503
  this.element.trigger.removeEventListener('keydown', this.handleEvent);
@@ -14785,6 +15228,7 @@ var helpTextVersion$1 = '1.0.0';
14785
15228
  * @csspart helpText - The helpText content container.
14786
15229
  * @event auroDropdown-triggerClick - Notifies that the trigger has been clicked.
14787
15230
  * @event auroDropdown-toggled - Notifies that the visibility of the dropdown bib has changed.
15231
+ * @event auroDropdown-idAdded - Notifies consumers that the unique ID for the dropdown bib has been generated.
14788
15232
  */
14789
15233
  class AuroDropdown extends LitElement {
14790
15234
  constructor() {
@@ -14830,7 +15274,9 @@ class AuroDropdown extends LitElement {
14830
15274
  this.rounded = false;
14831
15275
  this.tabIndex = 0;
14832
15276
  this.noToggle = false;
15277
+ this.a11yAutocomplete = 'none';
14833
15278
  this.labeled = true;
15279
+ this.a11yRole = 'combobox';
14834
15280
  this.onDark = false;
14835
15281
 
14836
15282
  // floaterConfig
@@ -14966,6 +15412,16 @@ class AuroDropdown extends LitElement {
14966
15412
  type: Number
14967
15413
  },
14968
15414
 
15415
+ /**
15416
+ * The unique ID for the dropdown bib element.
15417
+ * @private
15418
+ */
15419
+ dropdownId: {
15420
+ type: String,
15421
+ reflect: false,
15422
+ attribute: false
15423
+ },
15424
+
14969
15425
  /**
14970
15426
  * If declared in combination with `bordered` property or `helpText` slot content, will apply red color to both.
14971
15427
  */
@@ -15133,6 +15589,23 @@ class AuroDropdown extends LitElement {
15133
15589
  */
15134
15590
  tabIndex: {
15135
15591
  type: Number
15592
+ },
15593
+
15594
+ /**
15595
+ * The value for the role attribute of the trigger element.
15596
+ */
15597
+ a11yRole: {
15598
+ type: String || undefined,
15599
+ attribute: false,
15600
+ reflect: false
15601
+ },
15602
+
15603
+ /**
15604
+ * The value for the aria-autocomplete attribute of the trigger element.
15605
+ */
15606
+ a11yAutocomplete: {
15607
+ type: String,
15608
+ attribute: false,
15136
15609
  }
15137
15610
  };
15138
15611
  }
@@ -15194,7 +15667,22 @@ class AuroDropdown extends LitElement {
15194
15667
  }
15195
15668
 
15196
15669
  firstUpdated() {
15670
+
15671
+ // Configure the floater to, this will generate the ID for the bib
15197
15672
  this.floater.configure(this, 'auroDropdown');
15673
+
15674
+ /**
15675
+ * @description Let subscribers know that the dropdown ID ha been generated and added.
15676
+ * @event auroDropdown-idAdded
15677
+ * @type {Object<key: 'id', value: string>} - The ID of the dropdown bib element.
15678
+ */
15679
+ this.dispatchEvent(new CustomEvent('auroDropdown-idAdded', {detail: {id: this.floater.element.id}}));
15680
+
15681
+ // Set the bib ID locally if the user hasn't provided a focusable trigger
15682
+ if (!this.triggerContentFocusable) {
15683
+ this.dropdownId = this.floater.element.id;
15684
+ }
15685
+
15198
15686
  this.bibContent = this.floater.element.bib;
15199
15687
 
15200
15688
  // Add the tag name as an attribute if it is different than the component name
@@ -15346,6 +15834,30 @@ class AuroDropdown extends LitElement {
15346
15834
  });
15347
15835
  }
15348
15836
 
15837
+ /*
15838
+ * Sets aria attributes for the trigger element if a custom one is passed in.
15839
+ * @private
15840
+ * @method setTriggerAriaAttributes
15841
+ * @param { HTMLElement } triggerElement - The custom trigger element.
15842
+ */
15843
+ clearTriggerA11yAttributes(triggerElement) {
15844
+
15845
+ if (!triggerElement || !triggerElement.removeAttribute) {
15846
+ return;
15847
+ }
15848
+
15849
+ // Reset appropriate attributes for a11y
15850
+ triggerElement.removeAttribute('aria-labelledby');
15851
+ if (triggerElement.getAttribute('id') === `${this.id}-trigger-element`) {
15852
+ triggerElement.removeAttribute('id');
15853
+ }
15854
+ triggerElement.removeAttribute('role');
15855
+ triggerElement.removeAttribute('aria-expanded');
15856
+
15857
+ triggerElement.removeAttribute('aria-controls');
15858
+ triggerElement.removeAttribute('aria-autocomplete');
15859
+ }
15860
+
15349
15861
  /**
15350
15862
  * Handles changes to the trigger content slot and updates related properties.
15351
15863
  *
@@ -15359,32 +15871,41 @@ class AuroDropdown extends LitElement {
15359
15871
  * @returns {void}
15360
15872
  */
15361
15873
  handleTriggerContentSlotChange(event) {
15874
+
15362
15875
  this.floater.handleTriggerTabIndex();
15363
15876
 
15877
+ // Get the trigger
15878
+ const trigger = this.shadowRoot.querySelector('#trigger');
15879
+
15880
+ // Get the trigger slot
15364
15881
  const triggerSlot = this.shadowRoot.querySelector('.triggerContent slot');
15365
15882
 
15883
+ // If there's a trigger slot
15366
15884
  if (triggerSlot) {
15367
15885
 
15886
+ // Get the content nodes to see if there are any children
15368
15887
  const triggerContentNodes = triggerSlot.assignedNodes();
15369
15888
 
15889
+ // If there are children
15370
15890
  if (triggerContentNodes) {
15371
15891
 
15372
- triggerContentNodes.forEach((node) => {
15373
- if (!this.triggerContentFocusable) {
15374
- this.triggerContentFocusable = this.containsFocusableElement(node);
15375
- }
15376
- });
15377
- }
15378
- }
15892
+ // See if any of them are focusable elemeents
15893
+ this.triggerContentFocusable = triggerContentNodes.some((node) => this.containsFocusableElement(node));
15379
15894
 
15380
- const trigger = this.shadowRoot.querySelector('#trigger');
15895
+ // If any of them are focusable elements
15896
+ if (this.triggerContentFocusable) {
15381
15897
 
15382
- if (!this.triggerContentFocusable) {
15383
- trigger.setAttribute('tabindex', '0');
15384
- trigger.setAttribute('role', 'button');
15385
- } else {
15386
- trigger.removeAttribute('tabindex');
15387
- trigger.removeAttribute('role');
15898
+ // Assume the consumer will be providing their own a11y in whatever they passed in
15899
+ this.clearTriggerA11yAttributes(trigger);
15900
+
15901
+ // Remove the tabindex from the trigger so it doesn't interrupt focus flow
15902
+ trigger.removeAttribute('tabindex');
15903
+ } else {
15904
+
15905
+ // Add the tabindex to the trigger so that it's in the focus flow
15906
+ trigger.setAttribute('tabindex', '0');
15907
+ }
15908
+ }
15388
15909
  }
15389
15910
 
15390
15911
  if (event) {
@@ -15394,6 +15915,7 @@ class AuroDropdown extends LitElement {
15394
15915
 
15395
15916
  if (this.triggerContentSlot) {
15396
15917
  this.setupTriggerFocusEventBinding();
15918
+
15397
15919
  this.hasTriggerContent = this.triggerContentSlot.some((slot) => {
15398
15920
  if (slot.textContent.trim()) {
15399
15921
  return true;
@@ -15461,10 +15983,13 @@ class AuroDropdown extends LitElement {
15461
15983
  id="trigger"
15462
15984
  class="trigger"
15463
15985
  part="trigger"
15464
- aria-labelledby="triggerLabel"
15465
15986
  tabindex="${this.tabIndex}"
15466
15987
  ?showBorder="${this.showTriggerBorders}"
15467
- >
15988
+ role="${ifDefined(this.triggerContentFocusable ? undefined : this.a11yRole)}"
15989
+ aria-expanded="${ifDefined(this.triggerContentFocusable ? undefined : this.isPopoverVisible)}"
15990
+ aria-controls="${ifDefined(this.triggerContentFocusable ? undefined : this.dropdownId)}"
15991
+ aria-labelledby="${ifDefined(this.triggerContentFocusable ? undefined : 'triggerLabel')}"
15992
+ >
15468
15993
  <div class="triggerContentWrapper">
15469
15994
  <label class="label" id="triggerLabel" hasTrigger=${this.hasTriggerContent}>
15470
15995
  <slot name="label" @slotchange="${this.handleLabelSlotChange}"></slot>
@@ -15498,12 +16023,12 @@ class AuroDropdown extends LitElement {
15498
16023
  <div id="bibSizer" part="size"></div>
15499
16024
  <${this.dropdownBibTag}
15500
16025
  id="bib"
15501
- role="tooltip"
15502
16026
  ?data-show="${this.isPopoverVisible}"
15503
16027
  ?isfullscreen="${this.isBibFullscreen}"
15504
16028
  ?common="${this.common}"
15505
16029
  ?rounded="${this.common || this.rounded}"
15506
- ?inset="${this.common || this.inset}">
16030
+ ?inset="${this.common || this.inset}"
16031
+ >
15507
16032
  </${this.dropdownBibTag}>
15508
16033
  </div>
15509
16034
  `;
@@ -19481,6 +20006,414 @@ class AuroInputUtilities {
19481
20006
  }
19482
20007
  }
19483
20008
 
20009
+ class DateFormatter {
20010
+
20011
+ constructor() {
20012
+
20013
+ /**
20014
+ * @description Parses a date string into its components.
20015
+ * @param {string} dateStr - Date string to parse.
20016
+ * @param {string} format - Date format to parse.
20017
+ * @returns {Object<key["month" | "day" | "year"]: number>|undefined}
20018
+ */
20019
+ this.parseDate = (dateStr, format = 'mm/dd/yyyy') => {
20020
+
20021
+ // Guard Clause: Date string is defined
20022
+ if (!dateStr) {
20023
+ return undefined;
20024
+ }
20025
+
20026
+ // Assume the separator is a "/" a defined in our code base
20027
+ const separator = '/';
20028
+
20029
+ // Get the parts of the date and format
20030
+ const valueParts = dateStr.split(separator);
20031
+ const formatParts = format.split(separator);
20032
+
20033
+ // Check if the value and format have the correct number of parts
20034
+ if (valueParts.length !== formatParts.length) {
20035
+ throw new Error('AuroDatepickerUtilities | parseDate: Date string and format length do not match');
20036
+ }
20037
+
20038
+ // Holds the result to be returned
20039
+ const result = formatParts.reduce((acc, part, index) => {
20040
+ const value = valueParts[index];
20041
+
20042
+ if ((/m/iu).test(part)) {
20043
+ acc.month = value;
20044
+ } else if ((/d/iu).test(part)) {
20045
+ acc.day = value;
20046
+ } else if ((/y/iu).test(part)) {
20047
+ acc.year = value;
20048
+ }
20049
+
20050
+ return acc;
20051
+ }, {});
20052
+
20053
+ // If we found all the parts, return the result
20054
+ if (result.month && result.year) {
20055
+ return result;
20056
+ }
20057
+
20058
+ // Throw an error to let the dev know we were unable to parse the date string
20059
+ throw new Error('AuroDatepickerUtilities | parseDate: Unable to parse date string');
20060
+ };
20061
+
20062
+ /**
20063
+ * Convert a date object to string format.
20064
+ * @param {Object} date - Date to convert to string.
20065
+ * @returns {Object} Returns the date as a string.
20066
+ */
20067
+ this.getDateAsString = (date) => date.toLocaleDateString(undefined, {
20068
+ year: "numeric",
20069
+ month: "2-digit",
20070
+ day: "2-digit",
20071
+ });
20072
+
20073
+ /**
20074
+ * Converts a date string to a North American date format.
20075
+ * @param {String} dateStr - Date to validate.
20076
+ * @param {String} format - Date format to validate against.
20077
+ * @returns {Boolean}
20078
+ */
20079
+ this.toNorthAmericanFormat = (dateStr, format) => {
20080
+
20081
+ if (format === 'mm/dd/yyyy') {
20082
+ return dateStr;
20083
+ }
20084
+
20085
+ const parsedDate = this.parseDate(dateStr, format);
20086
+
20087
+ if (!parsedDate) {
20088
+ throw new Error('AuroDatepickerUtilities | toNorthAmericanFormat: Unable to parse date string');
20089
+ }
20090
+
20091
+ const { month, day, year } = parsedDate;
20092
+
20093
+ const dateParts = [];
20094
+ if (month) {
20095
+ dateParts.push(month);
20096
+ }
20097
+
20098
+ if (day) {
20099
+ dateParts.push(day);
20100
+ }
20101
+
20102
+ if (year) {
20103
+ dateParts.push(year);
20104
+ }
20105
+
20106
+ return dateParts.join('/');
20107
+ };
20108
+ }
20109
+ }
20110
+ const dateFormatter = new DateFormatter();
20111
+
20112
+ // filepath: dateConstraints.mjs
20113
+ const DATE_UTIL_CONSTRAINTS = {
20114
+ maxDay: 31,
20115
+ maxMonth: 12,
20116
+ maxYear: 2400,
20117
+ minDay: 1,
20118
+ minMonth: 1,
20119
+ minYear: 1900,
20120
+ };
20121
+
20122
+ class AuroDateUtilitiesBase {
20123
+
20124
+ /**
20125
+ * @description The maximum day value allowed by the various utilities in this class.
20126
+ * @readonly
20127
+ * @type {Number}
20128
+ */
20129
+ get maxDay() {
20130
+ return DATE_UTIL_CONSTRAINTS.maxDay;
20131
+ }
20132
+
20133
+ /**
20134
+ * @description The maximum month value allowed by the various utilities in this class.
20135
+ * @readonly
20136
+ * @type {Number}
20137
+ */
20138
+ get maxMonth() {
20139
+ return DATE_UTIL_CONSTRAINTS.maxMonth;
20140
+ }
20141
+
20142
+ /**
20143
+ * @description The maximum year value allowed by the various utilities in this class.
20144
+ * @readonly
20145
+ * @type {Number}
20146
+ */
20147
+ get maxYear() {
20148
+ return DATE_UTIL_CONSTRAINTS.maxYear;
20149
+ }
20150
+
20151
+ /**
20152
+ * @description The minimum day value allowed by the various utilities in this class.
20153
+ * @readonly
20154
+ * @type {Number}
20155
+ */
20156
+ get minDay() {
20157
+ return DATE_UTIL_CONSTRAINTS.minDay;
20158
+ }
20159
+
20160
+ /**
20161
+ * @description The minimum month value allowed by the various utilities in this class.
20162
+ * @readonly
20163
+ * @type {Number}
20164
+ */
20165
+ get minMonth() {
20166
+ return DATE_UTIL_CONSTRAINTS.minMonth;
20167
+ }
20168
+
20169
+ /**
20170
+ * @description The minimum year value allowed by the various utilities in this class.
20171
+ * @readonly
20172
+ * @type {Number}
20173
+ */
20174
+ get minYear() {
20175
+ return DATE_UTIL_CONSTRAINTS.minYear;
20176
+ }
20177
+ }
20178
+
20179
+ /* eslint-disable no-magic-numbers */
20180
+
20181
+ class AuroDateUtilities extends AuroDateUtilitiesBase {
20182
+
20183
+ /**
20184
+ * Returns the current century.
20185
+ * @returns {String} The current century.
20186
+ */
20187
+ getCentury () {
20188
+ return String(new Date().getFullYear()).slice(0, 2);
20189
+ }
20190
+
20191
+ /**
20192
+ * Returns a four digit year.
20193
+ * @param {String} year - The year to convert to four digits.
20194
+ * @returns {String} The four digit year.
20195
+ */
20196
+ getFourDigitYear (year) {
20197
+
20198
+ const strYear = String(year).trim();
20199
+ return strYear.length <= 2 ? this.getCentury() + strYear : strYear;
20200
+ }
20201
+
20202
+ constructor() {
20203
+
20204
+ super();
20205
+
20206
+ /**
20207
+ * Compares two dates to see if they match.
20208
+ * @param {Object} date1 - First date to compare.
20209
+ * @param {Object} date2 - Second date to compare.
20210
+ * @returns {Boolean} Returns true if the dates match.
20211
+ */
20212
+ this.datesMatch = (date1, date2) => new Date(date1).getTime() === new Date(date2).getTime();
20213
+
20214
+ /**
20215
+ * Returns true if value passed in is a valid date.
20216
+ * @param {String} date - Date to validate.
20217
+ * @param {String} format - Date format to validate against.
20218
+ * @returns {Boolean}
20219
+ */
20220
+ this.validDateStr = (date, format) => {
20221
+
20222
+ // The length we expect the date string to be
20223
+ const dateStrLength = format.length;
20224
+
20225
+ // Guard Clause: Date and format are defined
20226
+ if (typeof date === "undefined" || typeof format === "undefined") {
20227
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date and format are required');
20228
+ }
20229
+
20230
+ // Guard Clause: Date should be of type string
20231
+ if (typeof date !== "string") {
20232
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date must be a string');
20233
+ }
20234
+
20235
+ // Guard Clause: Format should be of type string
20236
+ if (typeof format !== "string") {
20237
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Format must be a string');
20238
+ }
20239
+
20240
+ // Guard Clause: Length is what we expect it to be
20241
+ if (date.length !== dateStrLength) {
20242
+ return false;
20243
+ }
20244
+ // Get a formatted date string and parse it
20245
+ const dateParts = dateFormatter.parseDate(date, format);
20246
+
20247
+ // Guard Clause: Date parse succeeded
20248
+ if (!dateParts) {
20249
+ return false;
20250
+ }
20251
+
20252
+ // Create the expected date string based on the date parts
20253
+ const expectedDateStr = `${dateParts.month}/${dateParts.day || "01"}/${this.getFourDigitYear(dateParts.year)}`;
20254
+
20255
+ // Generate a date object that we will extract a string date from to compare to the passed in date string
20256
+ const dateObj = new Date(this.getFourDigitYear(dateParts.year), dateParts.month - 1, dateParts.day || 1);
20257
+
20258
+ // Get the date string of the date object we created from the string date
20259
+ const actualDateStr = dateFormatter.getDateAsString(dateObj);
20260
+
20261
+ // Guard Clause: Generated date matches date string input
20262
+ if (expectedDateStr !== actualDateStr) {
20263
+ return false;
20264
+ }
20265
+
20266
+ // If we passed all other checks, we can assume the date is valid
20267
+ return true;
20268
+ };
20269
+
20270
+ /**
20271
+ * Determines if a string date value matches the format provided.
20272
+ * @param {string} value = The date string value.
20273
+ * @param { string} format = The date format to match against.
20274
+ * @returns {boolean}
20275
+ */
20276
+ this.dateAndFormatMatch = (value, format) => {
20277
+
20278
+ // Ensure we have both values we need to do the comparison
20279
+ if (!value || !format) {
20280
+ throw new Error('AuroFormValidation | dateFormatMatch: value and format are required');
20281
+ }
20282
+
20283
+ // If the lengths are different, they cannot match
20284
+ if (value.length !== format.length) {
20285
+ return false;
20286
+ }
20287
+
20288
+ // Get the parts of the date
20289
+ const dateParts = dateFormatter.parseDate(value, format);
20290
+
20291
+ // Validator for day
20292
+ const dayValueIsValid = (day) => {
20293
+
20294
+ // Guard clause: if there is no day in the dateParts, we can ignore this check.
20295
+ if (!dateParts.day) {
20296
+ return true;
20297
+ }
20298
+
20299
+ // Guard clause: ensure day exists.
20300
+ if (!day) {
20301
+ return false;
20302
+ }
20303
+
20304
+ // Convert day to number
20305
+ const numDay = Number.parseInt(day, 10);
20306
+
20307
+ // Guard clause: ensure day is a valid integer
20308
+ if (Number.isNaN(numDay)) {
20309
+ throw new Error('AuroDatepickerUtilities | dayValueIsValid: Unable to parse day value integer');
20310
+ }
20311
+
20312
+ // Guard clause: ensure day is within the valid range
20313
+ if (numDay < this.minDay || numDay > this.maxDay) {
20314
+ return false;
20315
+ }
20316
+
20317
+ // Default return
20318
+ return true;
20319
+ };
20320
+
20321
+ // Validator for month
20322
+ const monthValueIsValid = (month) => {
20323
+
20324
+ // Guard clause: ensure month exists.
20325
+ if (!month) {
20326
+ return false;
20327
+ }
20328
+
20329
+ // Convert month to number
20330
+ const numMonth = Number.parseInt(month, 10);
20331
+
20332
+ // Guard clause: ensure month is a valid integer
20333
+ if (Number.isNaN(numMonth)) {
20334
+ throw new Error('AuroDatepickerUtilities | monthValueIsValid: Unable to parse month value integer');
20335
+ }
20336
+
20337
+ // Guard clause: ensure month is within the valid range
20338
+ if (numMonth < this.minMonth || numMonth > this.maxMonth) {
20339
+ return false;
20340
+ }
20341
+
20342
+ // Default return
20343
+ return true;
20344
+ };
20345
+
20346
+ // Validator for year
20347
+ const yearIsValid = (_year) => {
20348
+
20349
+ // Guard clause: ensure year exists.
20350
+ if (!_year) {
20351
+ return false;
20352
+ }
20353
+
20354
+ // Get the full year
20355
+ const year = this.getFourDigitYear(_year);
20356
+
20357
+ // Convert year to number
20358
+ const numYear = Number.parseInt(year, 10);
20359
+
20360
+ // Guard clause: ensure year is a valid integer
20361
+ if (Number.isNaN(numYear)) {
20362
+ throw new Error('AuroDatepickerUtilities | yearValueIsValid: Unable to parse year value integer');
20363
+ }
20364
+
20365
+ // Guard clause: ensure year is within the valid range
20366
+ if (numYear < this.minYear || numYear > this.maxYear) {
20367
+ return false;
20368
+ }
20369
+
20370
+ // Default return
20371
+ return true;
20372
+ };
20373
+
20374
+ // Self-contained checks for month, day, and year
20375
+ const checks = [
20376
+ monthValueIsValid(dateParts.month),
20377
+ dayValueIsValid(dateParts.day),
20378
+ yearIsValid(dateParts.year)
20379
+ ];
20380
+
20381
+ // If any of the checks failed, the date format does not match and the result is invalid
20382
+ const isValid = checks.every((check) => check === true);
20383
+
20384
+ // If the check is invalid, return false
20385
+ if (!isValid) {
20386
+ return false;
20387
+ }
20388
+
20389
+ // Default case
20390
+ return true;
20391
+ };
20392
+ }
20393
+ }
20394
+
20395
+ // Export a class instance
20396
+ const dateUtilities = new AuroDateUtilities();
20397
+
20398
+ // Export the class instance methods individually
20399
+ const {
20400
+ datesMatch,
20401
+ validDateStr,
20402
+ dateAndFormatMatch,
20403
+ minDay,
20404
+ minMonth,
20405
+ minYear,
20406
+ maxDay,
20407
+ maxMonth,
20408
+ maxYear
20409
+ } = dateUtilities;
20410
+
20411
+ const {
20412
+ toNorthAmericanFormat,
20413
+ parseDate,
20414
+ getDateAsString
20415
+ } = dateFormatter;
20416
+
19484
20417
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
19485
20418
  // See LICENSE in the project root for license information.
19486
20419
 
@@ -19556,6 +20489,7 @@ let AuroLibraryRuntimeUtils$1 = class AuroLibraryRuntimeUtils {
19556
20489
 
19557
20490
 
19558
20491
  class AuroFormValidation {
20492
+
19559
20493
  constructor() {
19560
20494
  this.runtimeUtils = new AuroLibraryRuntimeUtils$1();
19561
20495
  }
@@ -19647,17 +20581,17 @@ class AuroFormValidation {
19647
20581
  ]
19648
20582
  }
19649
20583
  };
19650
-
20584
+
19651
20585
  let elementType;
19652
20586
  if (this.runtimeUtils.elementMatch(elem, 'auro-input')) {
19653
20587
  elementType = 'input';
19654
20588
  } else if (this.runtimeUtils.elementMatch(elem, 'auro-counter') || this.runtimeUtils.elementMatch(elem, 'auro-counter-group')) {
19655
20589
  elementType = 'counter';
19656
20590
  }
19657
-
20591
+
19658
20592
  if (elementType) {
19659
20593
  const rules = validationRules[elementType];
19660
-
20594
+
19661
20595
  if (rules) {
19662
20596
  Object.values(rules).flat().forEach(rule => {
19663
20597
  if (rule.check(elem)) {
@@ -19683,48 +20617,82 @@ class AuroFormValidation {
19683
20617
  if (!elem.value.match(emailRegex)) {
19684
20618
  elem.validity = 'patternMismatch';
19685
20619
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
20620
+ return;
19686
20621
  }
19687
20622
  } else if (elem.type === 'credit-card') {
19688
20623
  if (elem.value.length > 0 && elem.value.length < elem.validationCCLength) {
19689
20624
  elem.validity = 'tooShort';
19690
20625
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
20626
+ return;
19691
20627
  }
19692
20628
  } else if (elem.type === 'number') {
19693
20629
  if (elem.max !== undefined && Number(elem.max) < Number(elem.value)) {
19694
20630
  elem.validity = 'rangeOverflow';
19695
20631
  elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
20632
+ return;
19696
20633
  }
19697
20634
 
19698
20635
  if (elem.min !== undefined && elem.value?.length > 0 && Number(elem.min) > Number(elem.value)) {
19699
20636
  elem.validity = 'rangeUnderflow';
19700
20637
  elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
20638
+ return;
19701
20639
  }
19702
- } else if (elem.type === 'date') {
19703
- if (elem.value?.length > 0 && elem.value?.length < elem.lengthForType) {
20640
+ } else if (elem.type === 'date' && elem.value?.length > 0) {
20641
+
20642
+ // Guard Clause: if the value is too short
20643
+ if (elem.value.length < elem.lengthForType) {
20644
+
19704
20645
  elem.validity = 'tooShort';
19705
20646
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
19706
- } else if (elem.value?.length === elem.lengthForType && elem.util.toNorthAmericanFormat(elem.value, elem.format)) {
19707
- const formattedValue = elem.util.toNorthAmericanFormat(elem.value, elem.format);
19708
- const valueDate = new Date(formattedValue.dateForComparison);
20647
+ return;
20648
+ }
20649
+
20650
+ // Guard Clause: If the value is too long for the type
20651
+ if (elem.value?.length > elem.lengthForType) {
20652
+
20653
+ elem.validity = 'tooLong';
20654
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
20655
+ return;
20656
+ }
20657
+
20658
+ // Validate that the date passed was the correct format
20659
+ if (!dateAndFormatMatch(elem.value, elem.format)) {
20660
+ elem.validity = 'patternMismatch';
20661
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || 'Invalid Date Format Entered';
20662
+ return;
20663
+ }
20664
+
20665
+ // Validate that the date passed was a valid date
20666
+ if (!validDateStr(elem.value, elem.format)) {
20667
+ elem.validity = 'invalidDate';
20668
+ elem.errorMessage = elem.setCustomValidityInvalidDate || elem.setCustomValidity || 'Invalid Date Entered';
20669
+ return;
20670
+ }
19709
20671
 
19710
- // validate max
19711
- if (elem.max?.length === elem.lengthForType) {
19712
- const maxDate = new Date(elem.util.toNorthAmericanFormat(elem.max, elem.format).dateForComparison);
20672
+ // Perform the rest of the validation
20673
+ const formattedValue = toNorthAmericanFormat(elem.value, elem.format);
20674
+ const valueDate = new Date(formattedValue);
19713
20675
 
19714
- if (valueDate > maxDate) {
19715
- elem.validity = 'rangeOverflow';
19716
- elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
19717
- }
20676
+ // // Validate max date
20677
+ if (elem.max?.length === elem.lengthForType) {
20678
+
20679
+ const maxDate = new Date(toNorthAmericanFormat(elem.max, elem.format));
20680
+
20681
+ if (valueDate > maxDate) {
20682
+ elem.validity = 'rangeOverflow';
20683
+ elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
20684
+ return;
19718
20685
  }
20686
+ }
19719
20687
 
19720
- // validate min
19721
- if (elem.min?.length === elem.lengthForType) {
19722
- const minDate = new Date(elem.util.toNorthAmericanFormat(elem.min, elem.format).dateForComparison);
20688
+ // Validate min date
20689
+ if (elem.min?.length === elem.lengthForType) {
20690
+ const minDate = new Date(toNorthAmericanFormat(elem.min, elem.format));
19723
20691
 
19724
- if (valueDate < minDate) {
19725
- elem.validity = 'rangeUnderflow';
19726
- elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
19727
- }
20692
+ if (valueDate < minDate) {
20693
+ elem.validity = 'rangeUnderflow';
20694
+ elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
20695
+ return;
19728
20696
  }
19729
20697
  }
19730
20698
  }
@@ -19843,7 +20811,7 @@ class AuroFormValidation {
19843
20811
  if (input.validationMessage.length > 0) {
19844
20812
  elem.errorMessage = input.validationMessage;
19845
20813
  }
19846
- } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
20814
+ } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
19847
20815
  const firstInput = this.inputElements[0];
19848
20816
 
19849
20817
  if (firstInput.validationMessage.length > 0) {
@@ -19965,6 +20933,33 @@ class BaseInput extends LitElement {
19965
20933
  static get properties() {
19966
20934
  return {
19967
20935
 
20936
+ /**
20937
+ * The value for the role attribute.
20938
+ */
20939
+ a11yRole: {
20940
+ type: String,
20941
+ attribute: true,
20942
+ reflect: true
20943
+ },
20944
+
20945
+ /**
20946
+ * The value for the aria-expanded attribute.
20947
+ */
20948
+ a11yExpanded: {
20949
+ type: Boolean,
20950
+ attribute: true,
20951
+ reflect: true
20952
+ },
20953
+
20954
+ /**
20955
+ * The value for the aria-controls attribute.
20956
+ */
20957
+ a11yControls: {
20958
+ type: String,
20959
+ attribute: true,
20960
+ reflect: true
20961
+ },
20962
+
19968
20963
  /**
19969
20964
  * If set, the label will remain fixed in the active position.
19970
20965
  */
@@ -20606,6 +21601,10 @@ class BaseInput extends LitElement {
20606
21601
  } else if (this.type === 'number') {
20607
21602
  this.inputMode = 'numeric';
20608
21603
  }
21604
+
21605
+ if (this.type === "date" && !this.format) {
21606
+ this.format = 'mm/dd/yyyy';
21607
+ }
20609
21608
  }
20610
21609
 
20611
21610
  /**
@@ -21849,6 +22848,7 @@ var helpTextVersion = '1.0.0';
21849
22848
 
21850
22849
  // build the component class
21851
22850
  class AuroInput extends BaseInput {
22851
+
21852
22852
  constructor() {
21853
22853
  super();
21854
22854
 
@@ -21961,7 +22961,7 @@ class AuroInput extends BaseInput {
21961
22961
  ?required="${this.required}"
21962
22962
  ?disabled="${this.disabled}"
21963
22963
  aria-describedby="${this.uniqueId}"
21964
- aria-invalid="${this.validity !== 'valid'}"
22964
+ ?aria-invalid="${this.validity !== 'valid'}"
21965
22965
  placeholder=${this.getPlaceholder()}
21966
22966
  lang="${ifDefined(this.lang)}"
21967
22967
  ?activeLabel="${this.activeLabel}"
@@ -21970,7 +22970,10 @@ class AuroInput extends BaseInput {
21970
22970
  autocapitalize="${ifDefined(this.autocapitalize ? this.autocapitalize : undefined)}"
21971
22971
  autocomplete="${ifDefined(this.autocomplete ? this.autocomplete : undefined)}"
21972
22972
  part="input"
21973
- />
22973
+ role="${ifDefined(this.a11yRole)}"
22974
+ aria-expanded="${ifDefined(this.a11yExpanded)}"
22975
+ aria-controls="${ifDefined(this.a11yControls)}"
22976
+ />
21974
22977
  </div>
21975
22978
  <div
21976
22979
  class="notificationIcons"