@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
@@ -164,11 +164,420 @@ let AuroLibraryRuntimeUtils$4 = class AuroLibraryRuntimeUtils {
164
164
  }
165
165
  };
166
166
 
167
+ let DateFormatter$1 = class DateFormatter {
168
+
169
+ constructor() {
170
+
171
+ /**
172
+ * @description Parses a date string into its components.
173
+ * @param {string} dateStr - Date string to parse.
174
+ * @param {string} format - Date format to parse.
175
+ * @returns {Object<key["month" | "day" | "year"]: number>|undefined}
176
+ */
177
+ this.parseDate = (dateStr, format = 'mm/dd/yyyy') => {
178
+
179
+ // Guard Clause: Date string is defined
180
+ if (!dateStr) {
181
+ return undefined;
182
+ }
183
+
184
+ // Assume the separator is a "/" a defined in our code base
185
+ const separator = '/';
186
+
187
+ // Get the parts of the date and format
188
+ const valueParts = dateStr.split(separator);
189
+ const formatParts = format.split(separator);
190
+
191
+ // Check if the value and format have the correct number of parts
192
+ if (valueParts.length !== formatParts.length) {
193
+ throw new Error('AuroDatepickerUtilities | parseDate: Date string and format length do not match');
194
+ }
195
+
196
+ // Holds the result to be returned
197
+ const result = formatParts.reduce((acc, part, index) => {
198
+ const value = valueParts[index];
199
+
200
+ if ((/m/iu).test(part)) {
201
+ acc.month = value;
202
+ } else if ((/d/iu).test(part)) {
203
+ acc.day = value;
204
+ } else if ((/y/iu).test(part)) {
205
+ acc.year = value;
206
+ }
207
+
208
+ return acc;
209
+ }, {});
210
+
211
+ // If we found all the parts, return the result
212
+ if (result.month && result.year) {
213
+ return result;
214
+ }
215
+
216
+ // Throw an error to let the dev know we were unable to parse the date string
217
+ throw new Error('AuroDatepickerUtilities | parseDate: Unable to parse date string');
218
+ };
219
+
220
+ /**
221
+ * Convert a date object to string format.
222
+ * @param {Object} date - Date to convert to string.
223
+ * @returns {Object} Returns the date as a string.
224
+ */
225
+ this.getDateAsString = (date) => date.toLocaleDateString(undefined, {
226
+ year: "numeric",
227
+ month: "2-digit",
228
+ day: "2-digit",
229
+ });
230
+
231
+ /**
232
+ * Converts a date string to a North American date format.
233
+ * @param {String} dateStr - Date to validate.
234
+ * @param {String} format - Date format to validate against.
235
+ * @returns {Boolean}
236
+ */
237
+ this.toNorthAmericanFormat = (dateStr, format) => {
238
+
239
+ if (format === 'mm/dd/yyyy') {
240
+ return dateStr;
241
+ }
242
+
243
+ const parsedDate = this.parseDate(dateStr, format);
244
+
245
+ if (!parsedDate) {
246
+ throw new Error('AuroDatepickerUtilities | toNorthAmericanFormat: Unable to parse date string');
247
+ }
248
+
249
+ const { month, day, year } = parsedDate;
250
+
251
+ const dateParts = [];
252
+ if (month) {
253
+ dateParts.push(month);
254
+ }
255
+
256
+ if (day) {
257
+ dateParts.push(day);
258
+ }
259
+
260
+ if (year) {
261
+ dateParts.push(year);
262
+ }
263
+
264
+ return dateParts.join('/');
265
+ };
266
+ }
267
+ };
268
+ const dateFormatter$1 = new DateFormatter$1();
269
+
270
+ // filepath: dateConstraints.mjs
271
+ const DATE_UTIL_CONSTRAINTS$1 = {
272
+ maxDay: 31,
273
+ maxMonth: 12,
274
+ maxYear: 2400,
275
+ minDay: 1,
276
+ minMonth: 1,
277
+ minYear: 1900,
278
+ };
279
+
280
+ let AuroDateUtilitiesBase$1 = class AuroDateUtilitiesBase {
281
+
282
+ /**
283
+ * @description The maximum day value allowed by the various utilities in this class.
284
+ * @readonly
285
+ * @type {Number}
286
+ */
287
+ get maxDay() {
288
+ return DATE_UTIL_CONSTRAINTS$1.maxDay;
289
+ }
290
+
291
+ /**
292
+ * @description The maximum month value allowed by the various utilities in this class.
293
+ * @readonly
294
+ * @type {Number}
295
+ */
296
+ get maxMonth() {
297
+ return DATE_UTIL_CONSTRAINTS$1.maxMonth;
298
+ }
299
+
300
+ /**
301
+ * @description The maximum year value allowed by the various utilities in this class.
302
+ * @readonly
303
+ * @type {Number}
304
+ */
305
+ get maxYear() {
306
+ return DATE_UTIL_CONSTRAINTS$1.maxYear;
307
+ }
308
+
309
+ /**
310
+ * @description The minimum day value allowed by the various utilities in this class.
311
+ * @readonly
312
+ * @type {Number}
313
+ */
314
+ get minDay() {
315
+ return DATE_UTIL_CONSTRAINTS$1.minDay;
316
+ }
317
+
318
+ /**
319
+ * @description The minimum month value allowed by the various utilities in this class.
320
+ * @readonly
321
+ * @type {Number}
322
+ */
323
+ get minMonth() {
324
+ return DATE_UTIL_CONSTRAINTS$1.minMonth;
325
+ }
326
+
327
+ /**
328
+ * @description The minimum year value allowed by the various utilities in this class.
329
+ * @readonly
330
+ * @type {Number}
331
+ */
332
+ get minYear() {
333
+ return DATE_UTIL_CONSTRAINTS$1.minYear;
334
+ }
335
+ };
336
+
337
+ /* eslint-disable no-magic-numbers */
338
+
339
+ let AuroDateUtilities$1 = class AuroDateUtilities extends AuroDateUtilitiesBase$1 {
340
+
341
+ /**
342
+ * Returns the current century.
343
+ * @returns {String} The current century.
344
+ */
345
+ getCentury () {
346
+ return String(new Date().getFullYear()).slice(0, 2);
347
+ }
348
+
349
+ /**
350
+ * Returns a four digit year.
351
+ * @param {String} year - The year to convert to four digits.
352
+ * @returns {String} The four digit year.
353
+ */
354
+ getFourDigitYear (year) {
355
+
356
+ const strYear = String(year).trim();
357
+ return strYear.length <= 2 ? this.getCentury() + strYear : strYear;
358
+ }
359
+
360
+ constructor() {
361
+
362
+ super();
363
+
364
+ /**
365
+ * Compares two dates to see if they match.
366
+ * @param {Object} date1 - First date to compare.
367
+ * @param {Object} date2 - Second date to compare.
368
+ * @returns {Boolean} Returns true if the dates match.
369
+ */
370
+ this.datesMatch = (date1, date2) => new Date(date1).getTime() === new Date(date2).getTime();
371
+
372
+ /**
373
+ * Returns true if value passed in is a valid date.
374
+ * @param {String} date - Date to validate.
375
+ * @param {String} format - Date format to validate against.
376
+ * @returns {Boolean}
377
+ */
378
+ this.validDateStr = (date, format) => {
379
+
380
+ // The length we expect the date string to be
381
+ const dateStrLength = format.length;
382
+
383
+ // Guard Clause: Date and format are defined
384
+ if (typeof date === "undefined" || typeof format === "undefined") {
385
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date and format are required');
386
+ }
387
+
388
+ // Guard Clause: Date should be of type string
389
+ if (typeof date !== "string") {
390
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date must be a string');
391
+ }
392
+
393
+ // Guard Clause: Format should be of type string
394
+ if (typeof format !== "string") {
395
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Format must be a string');
396
+ }
397
+
398
+ // Guard Clause: Length is what we expect it to be
399
+ if (date.length !== dateStrLength) {
400
+ return false;
401
+ }
402
+ // Get a formatted date string and parse it
403
+ const dateParts = dateFormatter$1.parseDate(date, format);
404
+
405
+ // Guard Clause: Date parse succeeded
406
+ if (!dateParts) {
407
+ return false;
408
+ }
409
+
410
+ // Create the expected date string based on the date parts
411
+ const expectedDateStr = `${dateParts.month}/${dateParts.day || "01"}/${this.getFourDigitYear(dateParts.year)}`;
412
+
413
+ // Generate a date object that we will extract a string date from to compare to the passed in date string
414
+ const dateObj = new Date(this.getFourDigitYear(dateParts.year), dateParts.month - 1, dateParts.day || 1);
415
+
416
+ // Get the date string of the date object we created from the string date
417
+ const actualDateStr = dateFormatter$1.getDateAsString(dateObj);
418
+
419
+ // Guard Clause: Generated date matches date string input
420
+ if (expectedDateStr !== actualDateStr) {
421
+ return false;
422
+ }
423
+
424
+ // If we passed all other checks, we can assume the date is valid
425
+ return true;
426
+ };
427
+
428
+ /**
429
+ * Determines if a string date value matches the format provided.
430
+ * @param {string} value = The date string value.
431
+ * @param { string} format = The date format to match against.
432
+ * @returns {boolean}
433
+ */
434
+ this.dateAndFormatMatch = (value, format) => {
435
+
436
+ // Ensure we have both values we need to do the comparison
437
+ if (!value || !format) {
438
+ throw new Error('AuroFormValidation | dateFormatMatch: value and format are required');
439
+ }
440
+
441
+ // If the lengths are different, they cannot match
442
+ if (value.length !== format.length) {
443
+ return false;
444
+ }
445
+
446
+ // Get the parts of the date
447
+ const dateParts = dateFormatter$1.parseDate(value, format);
448
+
449
+ // Validator for day
450
+ const dayValueIsValid = (day) => {
451
+
452
+ // Guard clause: if there is no day in the dateParts, we can ignore this check.
453
+ if (!dateParts.day) {
454
+ return true;
455
+ }
456
+
457
+ // Guard clause: ensure day exists.
458
+ if (!day) {
459
+ return false;
460
+ }
461
+
462
+ // Convert day to number
463
+ const numDay = Number.parseInt(day, 10);
464
+
465
+ // Guard clause: ensure day is a valid integer
466
+ if (Number.isNaN(numDay)) {
467
+ throw new Error('AuroDatepickerUtilities | dayValueIsValid: Unable to parse day value integer');
468
+ }
469
+
470
+ // Guard clause: ensure day is within the valid range
471
+ if (numDay < this.minDay || numDay > this.maxDay) {
472
+ return false;
473
+ }
474
+
475
+ // Default return
476
+ return true;
477
+ };
478
+
479
+ // Validator for month
480
+ const monthValueIsValid = (month) => {
481
+
482
+ // Guard clause: ensure month exists.
483
+ if (!month) {
484
+ return false;
485
+ }
486
+
487
+ // Convert month to number
488
+ const numMonth = Number.parseInt(month, 10);
489
+
490
+ // Guard clause: ensure month is a valid integer
491
+ if (Number.isNaN(numMonth)) {
492
+ throw new Error('AuroDatepickerUtilities | monthValueIsValid: Unable to parse month value integer');
493
+ }
494
+
495
+ // Guard clause: ensure month is within the valid range
496
+ if (numMonth < this.minMonth || numMonth > this.maxMonth) {
497
+ return false;
498
+ }
499
+
500
+ // Default return
501
+ return true;
502
+ };
503
+
504
+ // Validator for year
505
+ const yearIsValid = (_year) => {
506
+
507
+ // Guard clause: ensure year exists.
508
+ if (!_year) {
509
+ return false;
510
+ }
511
+
512
+ // Get the full year
513
+ const year = this.getFourDigitYear(_year);
514
+
515
+ // Convert year to number
516
+ const numYear = Number.parseInt(year, 10);
517
+
518
+ // Guard clause: ensure year is a valid integer
519
+ if (Number.isNaN(numYear)) {
520
+ throw new Error('AuroDatepickerUtilities | yearValueIsValid: Unable to parse year value integer');
521
+ }
522
+
523
+ // Guard clause: ensure year is within the valid range
524
+ if (numYear < this.minYear || numYear > this.maxYear) {
525
+ return false;
526
+ }
527
+
528
+ // Default return
529
+ return true;
530
+ };
531
+
532
+ // Self-contained checks for month, day, and year
533
+ const checks = [
534
+ monthValueIsValid(dateParts.month),
535
+ dayValueIsValid(dateParts.day),
536
+ yearIsValid(dateParts.year)
537
+ ];
538
+
539
+ // If any of the checks failed, the date format does not match and the result is invalid
540
+ const isValid = checks.every((check) => check === true);
541
+
542
+ // If the check is invalid, return false
543
+ if (!isValid) {
544
+ return false;
545
+ }
546
+
547
+ // Default case
548
+ return true;
549
+ };
550
+ }
551
+ };
552
+
553
+ // Export a class instance
554
+ const dateUtilities$1 = new AuroDateUtilities$1();
555
+
556
+ // Export the class instance methods individually
557
+ const {
558
+ datesMatch: datesMatch$1,
559
+ validDateStr: validDateStr$1,
560
+ dateAndFormatMatch: dateAndFormatMatch$1,
561
+ minDay: minDay$1,
562
+ minMonth: minMonth$1,
563
+ minYear: minYear$1,
564
+ maxDay: maxDay$1,
565
+ maxMonth: maxMonth$1,
566
+ maxYear: maxYear$1
567
+ } = dateUtilities$1;
568
+
569
+ const {
570
+ toNorthAmericanFormat: toNorthAmericanFormat$1,
571
+ parseDate: parseDate$1,
572
+ getDateAsString: getDateAsString$1
573
+ } = dateFormatter$1;
574
+
167
575
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
168
576
  // See LICENSE in the project root for license information.
169
577
 
170
578
 
171
579
  let AuroFormValidation$1 = class AuroFormValidation {
580
+
172
581
  constructor() {
173
582
  this.runtimeUtils = new AuroLibraryRuntimeUtils$4();
174
583
  }
@@ -260,17 +669,17 @@ let AuroFormValidation$1 = class AuroFormValidation {
260
669
  ]
261
670
  }
262
671
  };
263
-
672
+
264
673
  let elementType;
265
674
  if (this.runtimeUtils.elementMatch(elem, 'auro-input')) {
266
675
  elementType = 'input';
267
676
  } else if (this.runtimeUtils.elementMatch(elem, 'auro-counter') || this.runtimeUtils.elementMatch(elem, 'auro-counter-group')) {
268
677
  elementType = 'counter';
269
678
  }
270
-
679
+
271
680
  if (elementType) {
272
681
  const rules = validationRules[elementType];
273
-
682
+
274
683
  if (rules) {
275
684
  Object.values(rules).flat().forEach(rule => {
276
685
  if (rule.check(elem)) {
@@ -296,48 +705,82 @@ let AuroFormValidation$1 = class AuroFormValidation {
296
705
  if (!elem.value.match(emailRegex)) {
297
706
  elem.validity = 'patternMismatch';
298
707
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
708
+ return;
299
709
  }
300
710
  } else if (elem.type === 'credit-card') {
301
711
  if (elem.value.length > 0 && elem.value.length < elem.validationCCLength) {
302
712
  elem.validity = 'tooShort';
303
713
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
714
+ return;
304
715
  }
305
716
  } else if (elem.type === 'number') {
306
717
  if (elem.max !== undefined && Number(elem.max) < Number(elem.value)) {
307
718
  elem.validity = 'rangeOverflow';
308
719
  elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
720
+ return;
309
721
  }
310
722
 
311
723
  if (elem.min !== undefined && elem.value?.length > 0 && Number(elem.min) > Number(elem.value)) {
312
724
  elem.validity = 'rangeUnderflow';
313
725
  elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
726
+ return;
314
727
  }
315
- } else if (elem.type === 'date') {
316
- if (elem.value?.length > 0 && elem.value?.length < elem.lengthForType) {
728
+ } else if (elem.type === 'date' && elem.value?.length > 0) {
729
+
730
+ // Guard Clause: if the value is too short
731
+ if (elem.value.length < elem.lengthForType) {
732
+
317
733
  elem.validity = 'tooShort';
318
734
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
319
- } else if (elem.value?.length === elem.lengthForType && elem.util.toNorthAmericanFormat(elem.value, elem.format)) {
320
- const formattedValue = elem.util.toNorthAmericanFormat(elem.value, elem.format);
321
- const valueDate = new Date(formattedValue.dateForComparison);
735
+ return;
736
+ }
737
+
738
+ // Guard Clause: If the value is too long for the type
739
+ if (elem.value?.length > elem.lengthForType) {
740
+
741
+ elem.validity = 'tooLong';
742
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
743
+ return;
744
+ }
745
+
746
+ // Validate that the date passed was the correct format
747
+ if (!dateAndFormatMatch$1(elem.value, elem.format)) {
748
+ elem.validity = 'patternMismatch';
749
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || 'Invalid Date Format Entered';
750
+ return;
751
+ }
752
+
753
+ // Validate that the date passed was a valid date
754
+ if (!validDateStr$1(elem.value, elem.format)) {
755
+ elem.validity = 'invalidDate';
756
+ elem.errorMessage = elem.setCustomValidityInvalidDate || elem.setCustomValidity || 'Invalid Date Entered';
757
+ return;
758
+ }
322
759
 
323
- // validate max
324
- if (elem.max?.length === elem.lengthForType) {
325
- const maxDate = new Date(elem.util.toNorthAmericanFormat(elem.max, elem.format).dateForComparison);
760
+ // Perform the rest of the validation
761
+ const formattedValue = toNorthAmericanFormat$1(elem.value, elem.format);
762
+ const valueDate = new Date(formattedValue);
326
763
 
327
- if (valueDate > maxDate) {
328
- elem.validity = 'rangeOverflow';
329
- elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
330
- }
764
+ // // Validate max date
765
+ if (elem.max?.length === elem.lengthForType) {
766
+
767
+ const maxDate = new Date(toNorthAmericanFormat$1(elem.max, elem.format));
768
+
769
+ if (valueDate > maxDate) {
770
+ elem.validity = 'rangeOverflow';
771
+ elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
772
+ return;
331
773
  }
774
+ }
332
775
 
333
- // validate min
334
- if (elem.min?.length === elem.lengthForType) {
335
- const minDate = new Date(elem.util.toNorthAmericanFormat(elem.min, elem.format).dateForComparison);
776
+ // Validate min date
777
+ if (elem.min?.length === elem.lengthForType) {
778
+ const minDate = new Date(toNorthAmericanFormat$1(elem.min, elem.format));
336
779
 
337
- if (valueDate < minDate) {
338
- elem.validity = 'rangeUnderflow';
339
- elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
340
- }
780
+ if (valueDate < minDate) {
781
+ elem.validity = 'rangeUnderflow';
782
+ elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
783
+ return;
341
784
  }
342
785
  }
343
786
  }
@@ -456,7 +899,7 @@ let AuroFormValidation$1 = class AuroFormValidation {
456
899
  if (input.validationMessage.length > 0) {
457
900
  elem.errorMessage = input.validationMessage;
458
901
  }
459
- } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
902
+ } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
460
903
  const firstInput = this.inputElements[0];
461
904
 
462
905
  if (firstInput.validationMessage.length > 0) {
@@ -2337,7 +2780,7 @@ class AuroFloatingUI {
2337
2780
  /**
2338
2781
  * @private
2339
2782
  * getting called on 'blur' in trigger or `focusin` in document
2340
- *
2783
+ *
2341
2784
  * Hides the bib if focus moves outside of the trigger or bib, unless a 'noHideOnThisFocusLoss' flag is set.
2342
2785
  * This method checks if the currently active element is still within the trigger or bib.
2343
2786
  * If not, and if the bib isn't in fullscreen mode with focus lost, it hides the bib.
@@ -2453,7 +2896,7 @@ class AuroFloatingUI {
2453
2896
  // Close any other dropdown that is already open
2454
2897
  const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
2455
2898
  if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this &&
2456
- existedVisibleFloatingUI.isPopoverVisible &&
2899
+ existedVisibleFloatingUI.element.isPopoverVisible &&
2457
2900
  document.expandedAuroFloater.eventPrefix === this.eventPrefix) {
2458
2901
  document.expandedAuroFloater.hideBib();
2459
2902
  }
@@ -2629,7 +3072,7 @@ class AuroFloatingUI {
2629
3072
  this.id = window.crypto.randomUUID();
2630
3073
  this.element.setAttribute('id', this.id);
2631
3074
  }
2632
-
3075
+
2633
3076
  this.element.bib.setAttribute("id", `${this.id}-floater-bib`);
2634
3077
  }
2635
3078
 
@@ -2682,7 +3125,7 @@ class AuroFloatingUI {
2682
3125
  if (this.element.bib) {
2683
3126
  this.element.shadowRoot.append(this.element.bib);
2684
3127
  }
2685
-
3128
+
2686
3129
  // Remove event & keyboard listeners
2687
3130
  if (this.element?.trigger) {
2688
3131
  this.element.trigger.removeEventListener('keydown', this.handleEvent);
@@ -3413,6 +3856,7 @@ var helpTextVersion$1 = '1.0.0';
3413
3856
  * @csspart helpText - The helpText content container.
3414
3857
  * @event auroDropdown-triggerClick - Notifies that the trigger has been clicked.
3415
3858
  * @event auroDropdown-toggled - Notifies that the visibility of the dropdown bib has changed.
3859
+ * @event auroDropdown-idAdded - Notifies consumers that the unique ID for the dropdown bib has been generated.
3416
3860
  */
3417
3861
  class AuroDropdown extends r$1 {
3418
3862
  constructor() {
@@ -3458,7 +3902,9 @@ class AuroDropdown extends r$1 {
3458
3902
  this.rounded = false;
3459
3903
  this.tabIndex = 0;
3460
3904
  this.noToggle = false;
3905
+ this.a11yAutocomplete = 'none';
3461
3906
  this.labeled = true;
3907
+ this.a11yRole = 'combobox';
3462
3908
  this.onDark = false;
3463
3909
 
3464
3910
  // floaterConfig
@@ -3594,6 +4040,16 @@ class AuroDropdown extends r$1 {
3594
4040
  type: Number
3595
4041
  },
3596
4042
 
4043
+ /**
4044
+ * The unique ID for the dropdown bib element.
4045
+ * @private
4046
+ */
4047
+ dropdownId: {
4048
+ type: String,
4049
+ reflect: false,
4050
+ attribute: false
4051
+ },
4052
+
3597
4053
  /**
3598
4054
  * If declared in combination with `bordered` property or `helpText` slot content, will apply red color to both.
3599
4055
  */
@@ -3761,6 +4217,23 @@ class AuroDropdown extends r$1 {
3761
4217
  */
3762
4218
  tabIndex: {
3763
4219
  type: Number
4220
+ },
4221
+
4222
+ /**
4223
+ * The value for the role attribute of the trigger element.
4224
+ */
4225
+ a11yRole: {
4226
+ type: String || undefined,
4227
+ attribute: false,
4228
+ reflect: false
4229
+ },
4230
+
4231
+ /**
4232
+ * The value for the aria-autocomplete attribute of the trigger element.
4233
+ */
4234
+ a11yAutocomplete: {
4235
+ type: String,
4236
+ attribute: false,
3764
4237
  }
3765
4238
  };
3766
4239
  }
@@ -3822,7 +4295,22 @@ class AuroDropdown extends r$1 {
3822
4295
  }
3823
4296
 
3824
4297
  firstUpdated() {
4298
+
4299
+ // Configure the floater to, this will generate the ID for the bib
3825
4300
  this.floater.configure(this, 'auroDropdown');
4301
+
4302
+ /**
4303
+ * @description Let subscribers know that the dropdown ID ha been generated and added.
4304
+ * @event auroDropdown-idAdded
4305
+ * @type {Object<key: 'id', value: string>} - The ID of the dropdown bib element.
4306
+ */
4307
+ this.dispatchEvent(new CustomEvent('auroDropdown-idAdded', {detail: {id: this.floater.element.id}}));
4308
+
4309
+ // Set the bib ID locally if the user hasn't provided a focusable trigger
4310
+ if (!this.triggerContentFocusable) {
4311
+ this.dropdownId = this.floater.element.id;
4312
+ }
4313
+
3826
4314
  this.bibContent = this.floater.element.bib;
3827
4315
 
3828
4316
  // Add the tag name as an attribute if it is different than the component name
@@ -3974,6 +4462,30 @@ class AuroDropdown extends r$1 {
3974
4462
  });
3975
4463
  }
3976
4464
 
4465
+ /*
4466
+ * Sets aria attributes for the trigger element if a custom one is passed in.
4467
+ * @private
4468
+ * @method setTriggerAriaAttributes
4469
+ * @param { HTMLElement } triggerElement - The custom trigger element.
4470
+ */
4471
+ clearTriggerA11yAttributes(triggerElement) {
4472
+
4473
+ if (!triggerElement || !triggerElement.removeAttribute) {
4474
+ return;
4475
+ }
4476
+
4477
+ // Reset appropriate attributes for a11y
4478
+ triggerElement.removeAttribute('aria-labelledby');
4479
+ if (triggerElement.getAttribute('id') === `${this.id}-trigger-element`) {
4480
+ triggerElement.removeAttribute('id');
4481
+ }
4482
+ triggerElement.removeAttribute('role');
4483
+ triggerElement.removeAttribute('aria-expanded');
4484
+
4485
+ triggerElement.removeAttribute('aria-controls');
4486
+ triggerElement.removeAttribute('aria-autocomplete');
4487
+ }
4488
+
3977
4489
  /**
3978
4490
  * Handles changes to the trigger content slot and updates related properties.
3979
4491
  *
@@ -3987,32 +4499,41 @@ class AuroDropdown extends r$1 {
3987
4499
  * @returns {void}
3988
4500
  */
3989
4501
  handleTriggerContentSlotChange(event) {
4502
+
3990
4503
  this.floater.handleTriggerTabIndex();
3991
4504
 
4505
+ // Get the trigger
4506
+ const trigger = this.shadowRoot.querySelector('#trigger');
4507
+
4508
+ // Get the trigger slot
3992
4509
  const triggerSlot = this.shadowRoot.querySelector('.triggerContent slot');
3993
4510
 
4511
+ // If there's a trigger slot
3994
4512
  if (triggerSlot) {
3995
4513
 
4514
+ // Get the content nodes to see if there are any children
3996
4515
  const triggerContentNodes = triggerSlot.assignedNodes();
3997
4516
 
4517
+ // If there are children
3998
4518
  if (triggerContentNodes) {
3999
4519
 
4000
- triggerContentNodes.forEach((node) => {
4001
- if (!this.triggerContentFocusable) {
4002
- this.triggerContentFocusable = this.containsFocusableElement(node);
4003
- }
4004
- });
4005
- }
4006
- }
4520
+ // See if any of them are focusable elemeents
4521
+ this.triggerContentFocusable = triggerContentNodes.some((node) => this.containsFocusableElement(node));
4007
4522
 
4008
- const trigger = this.shadowRoot.querySelector('#trigger');
4523
+ // If any of them are focusable elements
4524
+ if (this.triggerContentFocusable) {
4009
4525
 
4010
- if (!this.triggerContentFocusable) {
4011
- trigger.setAttribute('tabindex', '0');
4012
- trigger.setAttribute('role', 'button');
4013
- } else {
4014
- trigger.removeAttribute('tabindex');
4015
- trigger.removeAttribute('role');
4526
+ // Assume the consumer will be providing their own a11y in whatever they passed in
4527
+ this.clearTriggerA11yAttributes(trigger);
4528
+
4529
+ // Remove the tabindex from the trigger so it doesn't interrupt focus flow
4530
+ trigger.removeAttribute('tabindex');
4531
+ } else {
4532
+
4533
+ // Add the tabindex to the trigger so that it's in the focus flow
4534
+ trigger.setAttribute('tabindex', '0');
4535
+ }
4536
+ }
4016
4537
  }
4017
4538
 
4018
4539
  if (event) {
@@ -4022,6 +4543,7 @@ class AuroDropdown extends r$1 {
4022
4543
 
4023
4544
  if (this.triggerContentSlot) {
4024
4545
  this.setupTriggerFocusEventBinding();
4546
+
4025
4547
  this.hasTriggerContent = this.triggerContentSlot.some((slot) => {
4026
4548
  if (slot.textContent.trim()) {
4027
4549
  return true;
@@ -4089,10 +4611,13 @@ class AuroDropdown extends r$1 {
4089
4611
  id="trigger"
4090
4612
  class="trigger"
4091
4613
  part="trigger"
4092
- aria-labelledby="triggerLabel"
4093
4614
  tabindex="${this.tabIndex}"
4094
4615
  ?showBorder="${this.showTriggerBorders}"
4095
- >
4616
+ role="${o(this.triggerContentFocusable ? undefined : this.a11yRole)}"
4617
+ aria-expanded="${o(this.triggerContentFocusable ? undefined : this.isPopoverVisible)}"
4618
+ aria-controls="${o(this.triggerContentFocusable ? undefined : this.dropdownId)}"
4619
+ aria-labelledby="${o(this.triggerContentFocusable ? undefined : 'triggerLabel')}"
4620
+ >
4096
4621
  <div class="triggerContentWrapper">
4097
4622
  <label class="label" id="triggerLabel" hasTrigger=${this.hasTriggerContent}>
4098
4623
  <slot name="label" @slotchange="${this.handleLabelSlotChange}"></slot>
@@ -4126,12 +4651,12 @@ class AuroDropdown extends r$1 {
4126
4651
  <div id="bibSizer" part="size"></div>
4127
4652
  <${this.dropdownBibTag}
4128
4653
  id="bib"
4129
- role="tooltip"
4130
4654
  ?data-show="${this.isPopoverVisible}"
4131
4655
  ?isfullscreen="${this.isBibFullscreen}"
4132
4656
  ?common="${this.common}"
4133
4657
  ?rounded="${this.common || this.rounded}"
4134
- ?inset="${this.common || this.inset}">
4658
+ ?inset="${this.common || this.inset}"
4659
+ >
4135
4660
  </${this.dropdownBibTag}>
4136
4661
  </div>
4137
4662
  `;
@@ -8122,6 +8647,414 @@ class AuroInputUtilities {
8122
8647
  }
8123
8648
  }
8124
8649
 
8650
+ class DateFormatter {
8651
+
8652
+ constructor() {
8653
+
8654
+ /**
8655
+ * @description Parses a date string into its components.
8656
+ * @param {string} dateStr - Date string to parse.
8657
+ * @param {string} format - Date format to parse.
8658
+ * @returns {Object<key["month" | "day" | "year"]: number>|undefined}
8659
+ */
8660
+ this.parseDate = (dateStr, format = 'mm/dd/yyyy') => {
8661
+
8662
+ // Guard Clause: Date string is defined
8663
+ if (!dateStr) {
8664
+ return undefined;
8665
+ }
8666
+
8667
+ // Assume the separator is a "/" a defined in our code base
8668
+ const separator = '/';
8669
+
8670
+ // Get the parts of the date and format
8671
+ const valueParts = dateStr.split(separator);
8672
+ const formatParts = format.split(separator);
8673
+
8674
+ // Check if the value and format have the correct number of parts
8675
+ if (valueParts.length !== formatParts.length) {
8676
+ throw new Error('AuroDatepickerUtilities | parseDate: Date string and format length do not match');
8677
+ }
8678
+
8679
+ // Holds the result to be returned
8680
+ const result = formatParts.reduce((acc, part, index) => {
8681
+ const value = valueParts[index];
8682
+
8683
+ if ((/m/iu).test(part)) {
8684
+ acc.month = value;
8685
+ } else if ((/d/iu).test(part)) {
8686
+ acc.day = value;
8687
+ } else if ((/y/iu).test(part)) {
8688
+ acc.year = value;
8689
+ }
8690
+
8691
+ return acc;
8692
+ }, {});
8693
+
8694
+ // If we found all the parts, return the result
8695
+ if (result.month && result.year) {
8696
+ return result;
8697
+ }
8698
+
8699
+ // Throw an error to let the dev know we were unable to parse the date string
8700
+ throw new Error('AuroDatepickerUtilities | parseDate: Unable to parse date string');
8701
+ };
8702
+
8703
+ /**
8704
+ * Convert a date object to string format.
8705
+ * @param {Object} date - Date to convert to string.
8706
+ * @returns {Object} Returns the date as a string.
8707
+ */
8708
+ this.getDateAsString = (date) => date.toLocaleDateString(undefined, {
8709
+ year: "numeric",
8710
+ month: "2-digit",
8711
+ day: "2-digit",
8712
+ });
8713
+
8714
+ /**
8715
+ * Converts a date string to a North American date format.
8716
+ * @param {String} dateStr - Date to validate.
8717
+ * @param {String} format - Date format to validate against.
8718
+ * @returns {Boolean}
8719
+ */
8720
+ this.toNorthAmericanFormat = (dateStr, format) => {
8721
+
8722
+ if (format === 'mm/dd/yyyy') {
8723
+ return dateStr;
8724
+ }
8725
+
8726
+ const parsedDate = this.parseDate(dateStr, format);
8727
+
8728
+ if (!parsedDate) {
8729
+ throw new Error('AuroDatepickerUtilities | toNorthAmericanFormat: Unable to parse date string');
8730
+ }
8731
+
8732
+ const { month, day, year } = parsedDate;
8733
+
8734
+ const dateParts = [];
8735
+ if (month) {
8736
+ dateParts.push(month);
8737
+ }
8738
+
8739
+ if (day) {
8740
+ dateParts.push(day);
8741
+ }
8742
+
8743
+ if (year) {
8744
+ dateParts.push(year);
8745
+ }
8746
+
8747
+ return dateParts.join('/');
8748
+ };
8749
+ }
8750
+ }
8751
+ const dateFormatter = new DateFormatter();
8752
+
8753
+ // filepath: dateConstraints.mjs
8754
+ const DATE_UTIL_CONSTRAINTS = {
8755
+ maxDay: 31,
8756
+ maxMonth: 12,
8757
+ maxYear: 2400,
8758
+ minDay: 1,
8759
+ minMonth: 1,
8760
+ minYear: 1900,
8761
+ };
8762
+
8763
+ class AuroDateUtilitiesBase {
8764
+
8765
+ /**
8766
+ * @description The maximum day value allowed by the various utilities in this class.
8767
+ * @readonly
8768
+ * @type {Number}
8769
+ */
8770
+ get maxDay() {
8771
+ return DATE_UTIL_CONSTRAINTS.maxDay;
8772
+ }
8773
+
8774
+ /**
8775
+ * @description The maximum month value allowed by the various utilities in this class.
8776
+ * @readonly
8777
+ * @type {Number}
8778
+ */
8779
+ get maxMonth() {
8780
+ return DATE_UTIL_CONSTRAINTS.maxMonth;
8781
+ }
8782
+
8783
+ /**
8784
+ * @description The maximum year value allowed by the various utilities in this class.
8785
+ * @readonly
8786
+ * @type {Number}
8787
+ */
8788
+ get maxYear() {
8789
+ return DATE_UTIL_CONSTRAINTS.maxYear;
8790
+ }
8791
+
8792
+ /**
8793
+ * @description The minimum day value allowed by the various utilities in this class.
8794
+ * @readonly
8795
+ * @type {Number}
8796
+ */
8797
+ get minDay() {
8798
+ return DATE_UTIL_CONSTRAINTS.minDay;
8799
+ }
8800
+
8801
+ /**
8802
+ * @description The minimum month value allowed by the various utilities in this class.
8803
+ * @readonly
8804
+ * @type {Number}
8805
+ */
8806
+ get minMonth() {
8807
+ return DATE_UTIL_CONSTRAINTS.minMonth;
8808
+ }
8809
+
8810
+ /**
8811
+ * @description The minimum year value allowed by the various utilities in this class.
8812
+ * @readonly
8813
+ * @type {Number}
8814
+ */
8815
+ get minYear() {
8816
+ return DATE_UTIL_CONSTRAINTS.minYear;
8817
+ }
8818
+ }
8819
+
8820
+ /* eslint-disable no-magic-numbers */
8821
+
8822
+ class AuroDateUtilities extends AuroDateUtilitiesBase {
8823
+
8824
+ /**
8825
+ * Returns the current century.
8826
+ * @returns {String} The current century.
8827
+ */
8828
+ getCentury () {
8829
+ return String(new Date().getFullYear()).slice(0, 2);
8830
+ }
8831
+
8832
+ /**
8833
+ * Returns a four digit year.
8834
+ * @param {String} year - The year to convert to four digits.
8835
+ * @returns {String} The four digit year.
8836
+ */
8837
+ getFourDigitYear (year) {
8838
+
8839
+ const strYear = String(year).trim();
8840
+ return strYear.length <= 2 ? this.getCentury() + strYear : strYear;
8841
+ }
8842
+
8843
+ constructor() {
8844
+
8845
+ super();
8846
+
8847
+ /**
8848
+ * Compares two dates to see if they match.
8849
+ * @param {Object} date1 - First date to compare.
8850
+ * @param {Object} date2 - Second date to compare.
8851
+ * @returns {Boolean} Returns true if the dates match.
8852
+ */
8853
+ this.datesMatch = (date1, date2) => new Date(date1).getTime() === new Date(date2).getTime();
8854
+
8855
+ /**
8856
+ * Returns true if value passed in is a valid date.
8857
+ * @param {String} date - Date to validate.
8858
+ * @param {String} format - Date format to validate against.
8859
+ * @returns {Boolean}
8860
+ */
8861
+ this.validDateStr = (date, format) => {
8862
+
8863
+ // The length we expect the date string to be
8864
+ const dateStrLength = format.length;
8865
+
8866
+ // Guard Clause: Date and format are defined
8867
+ if (typeof date === "undefined" || typeof format === "undefined") {
8868
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date and format are required');
8869
+ }
8870
+
8871
+ // Guard Clause: Date should be of type string
8872
+ if (typeof date !== "string") {
8873
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date must be a string');
8874
+ }
8875
+
8876
+ // Guard Clause: Format should be of type string
8877
+ if (typeof format !== "string") {
8878
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Format must be a string');
8879
+ }
8880
+
8881
+ // Guard Clause: Length is what we expect it to be
8882
+ if (date.length !== dateStrLength) {
8883
+ return false;
8884
+ }
8885
+ // Get a formatted date string and parse it
8886
+ const dateParts = dateFormatter.parseDate(date, format);
8887
+
8888
+ // Guard Clause: Date parse succeeded
8889
+ if (!dateParts) {
8890
+ return false;
8891
+ }
8892
+
8893
+ // Create the expected date string based on the date parts
8894
+ const expectedDateStr = `${dateParts.month}/${dateParts.day || "01"}/${this.getFourDigitYear(dateParts.year)}`;
8895
+
8896
+ // Generate a date object that we will extract a string date from to compare to the passed in date string
8897
+ const dateObj = new Date(this.getFourDigitYear(dateParts.year), dateParts.month - 1, dateParts.day || 1);
8898
+
8899
+ // Get the date string of the date object we created from the string date
8900
+ const actualDateStr = dateFormatter.getDateAsString(dateObj);
8901
+
8902
+ // Guard Clause: Generated date matches date string input
8903
+ if (expectedDateStr !== actualDateStr) {
8904
+ return false;
8905
+ }
8906
+
8907
+ // If we passed all other checks, we can assume the date is valid
8908
+ return true;
8909
+ };
8910
+
8911
+ /**
8912
+ * Determines if a string date value matches the format provided.
8913
+ * @param {string} value = The date string value.
8914
+ * @param { string} format = The date format to match against.
8915
+ * @returns {boolean}
8916
+ */
8917
+ this.dateAndFormatMatch = (value, format) => {
8918
+
8919
+ // Ensure we have both values we need to do the comparison
8920
+ if (!value || !format) {
8921
+ throw new Error('AuroFormValidation | dateFormatMatch: value and format are required');
8922
+ }
8923
+
8924
+ // If the lengths are different, they cannot match
8925
+ if (value.length !== format.length) {
8926
+ return false;
8927
+ }
8928
+
8929
+ // Get the parts of the date
8930
+ const dateParts = dateFormatter.parseDate(value, format);
8931
+
8932
+ // Validator for day
8933
+ const dayValueIsValid = (day) => {
8934
+
8935
+ // Guard clause: if there is no day in the dateParts, we can ignore this check.
8936
+ if (!dateParts.day) {
8937
+ return true;
8938
+ }
8939
+
8940
+ // Guard clause: ensure day exists.
8941
+ if (!day) {
8942
+ return false;
8943
+ }
8944
+
8945
+ // Convert day to number
8946
+ const numDay = Number.parseInt(day, 10);
8947
+
8948
+ // Guard clause: ensure day is a valid integer
8949
+ if (Number.isNaN(numDay)) {
8950
+ throw new Error('AuroDatepickerUtilities | dayValueIsValid: Unable to parse day value integer');
8951
+ }
8952
+
8953
+ // Guard clause: ensure day is within the valid range
8954
+ if (numDay < this.minDay || numDay > this.maxDay) {
8955
+ return false;
8956
+ }
8957
+
8958
+ // Default return
8959
+ return true;
8960
+ };
8961
+
8962
+ // Validator for month
8963
+ const monthValueIsValid = (month) => {
8964
+
8965
+ // Guard clause: ensure month exists.
8966
+ if (!month) {
8967
+ return false;
8968
+ }
8969
+
8970
+ // Convert month to number
8971
+ const numMonth = Number.parseInt(month, 10);
8972
+
8973
+ // Guard clause: ensure month is a valid integer
8974
+ if (Number.isNaN(numMonth)) {
8975
+ throw new Error('AuroDatepickerUtilities | monthValueIsValid: Unable to parse month value integer');
8976
+ }
8977
+
8978
+ // Guard clause: ensure month is within the valid range
8979
+ if (numMonth < this.minMonth || numMonth > this.maxMonth) {
8980
+ return false;
8981
+ }
8982
+
8983
+ // Default return
8984
+ return true;
8985
+ };
8986
+
8987
+ // Validator for year
8988
+ const yearIsValid = (_year) => {
8989
+
8990
+ // Guard clause: ensure year exists.
8991
+ if (!_year) {
8992
+ return false;
8993
+ }
8994
+
8995
+ // Get the full year
8996
+ const year = this.getFourDigitYear(_year);
8997
+
8998
+ // Convert year to number
8999
+ const numYear = Number.parseInt(year, 10);
9000
+
9001
+ // Guard clause: ensure year is a valid integer
9002
+ if (Number.isNaN(numYear)) {
9003
+ throw new Error('AuroDatepickerUtilities | yearValueIsValid: Unable to parse year value integer');
9004
+ }
9005
+
9006
+ // Guard clause: ensure year is within the valid range
9007
+ if (numYear < this.minYear || numYear > this.maxYear) {
9008
+ return false;
9009
+ }
9010
+
9011
+ // Default return
9012
+ return true;
9013
+ };
9014
+
9015
+ // Self-contained checks for month, day, and year
9016
+ const checks = [
9017
+ monthValueIsValid(dateParts.month),
9018
+ dayValueIsValid(dateParts.day),
9019
+ yearIsValid(dateParts.year)
9020
+ ];
9021
+
9022
+ // If any of the checks failed, the date format does not match and the result is invalid
9023
+ const isValid = checks.every((check) => check === true);
9024
+
9025
+ // If the check is invalid, return false
9026
+ if (!isValid) {
9027
+ return false;
9028
+ }
9029
+
9030
+ // Default case
9031
+ return true;
9032
+ };
9033
+ }
9034
+ }
9035
+
9036
+ // Export a class instance
9037
+ const dateUtilities = new AuroDateUtilities();
9038
+
9039
+ // Export the class instance methods individually
9040
+ const {
9041
+ datesMatch,
9042
+ validDateStr,
9043
+ dateAndFormatMatch,
9044
+ minDay,
9045
+ minMonth,
9046
+ minYear,
9047
+ maxDay,
9048
+ maxMonth,
9049
+ maxYear
9050
+ } = dateUtilities;
9051
+
9052
+ const {
9053
+ toNorthAmericanFormat,
9054
+ parseDate,
9055
+ getDateAsString
9056
+ } = dateFormatter;
9057
+
8125
9058
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
8126
9059
  // See LICENSE in the project root for license information.
8127
9060
 
@@ -8197,6 +9130,7 @@ let AuroLibraryRuntimeUtils$1$1 = class AuroLibraryRuntimeUtils {
8197
9130
 
8198
9131
 
8199
9132
  class AuroFormValidation {
9133
+
8200
9134
  constructor() {
8201
9135
  this.runtimeUtils = new AuroLibraryRuntimeUtils$1$1();
8202
9136
  }
@@ -8288,17 +9222,17 @@ class AuroFormValidation {
8288
9222
  ]
8289
9223
  }
8290
9224
  };
8291
-
9225
+
8292
9226
  let elementType;
8293
9227
  if (this.runtimeUtils.elementMatch(elem, 'auro-input')) {
8294
9228
  elementType = 'input';
8295
9229
  } else if (this.runtimeUtils.elementMatch(elem, 'auro-counter') || this.runtimeUtils.elementMatch(elem, 'auro-counter-group')) {
8296
9230
  elementType = 'counter';
8297
9231
  }
8298
-
9232
+
8299
9233
  if (elementType) {
8300
9234
  const rules = validationRules[elementType];
8301
-
9235
+
8302
9236
  if (rules) {
8303
9237
  Object.values(rules).flat().forEach(rule => {
8304
9238
  if (rule.check(elem)) {
@@ -8324,48 +9258,82 @@ class AuroFormValidation {
8324
9258
  if (!elem.value.match(emailRegex)) {
8325
9259
  elem.validity = 'patternMismatch';
8326
9260
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
9261
+ return;
8327
9262
  }
8328
9263
  } else if (elem.type === 'credit-card') {
8329
9264
  if (elem.value.length > 0 && elem.value.length < elem.validationCCLength) {
8330
9265
  elem.validity = 'tooShort';
8331
9266
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
9267
+ return;
8332
9268
  }
8333
9269
  } else if (elem.type === 'number') {
8334
9270
  if (elem.max !== undefined && Number(elem.max) < Number(elem.value)) {
8335
9271
  elem.validity = 'rangeOverflow';
8336
9272
  elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
9273
+ return;
8337
9274
  }
8338
9275
 
8339
9276
  if (elem.min !== undefined && elem.value?.length > 0 && Number(elem.min) > Number(elem.value)) {
8340
9277
  elem.validity = 'rangeUnderflow';
8341
9278
  elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
9279
+ return;
8342
9280
  }
8343
- } else if (elem.type === 'date') {
8344
- if (elem.value?.length > 0 && elem.value?.length < elem.lengthForType) {
9281
+ } else if (elem.type === 'date' && elem.value?.length > 0) {
9282
+
9283
+ // Guard Clause: if the value is too short
9284
+ if (elem.value.length < elem.lengthForType) {
9285
+
8345
9286
  elem.validity = 'tooShort';
8346
9287
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
8347
- } else if (elem.value?.length === elem.lengthForType && elem.util.toNorthAmericanFormat(elem.value, elem.format)) {
8348
- const formattedValue = elem.util.toNorthAmericanFormat(elem.value, elem.format);
8349
- const valueDate = new Date(formattedValue.dateForComparison);
9288
+ return;
9289
+ }
9290
+
9291
+ // Guard Clause: If the value is too long for the type
9292
+ if (elem.value?.length > elem.lengthForType) {
9293
+
9294
+ elem.validity = 'tooLong';
9295
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
9296
+ return;
9297
+ }
9298
+
9299
+ // Validate that the date passed was the correct format
9300
+ if (!dateAndFormatMatch(elem.value, elem.format)) {
9301
+ elem.validity = 'patternMismatch';
9302
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || 'Invalid Date Format Entered';
9303
+ return;
9304
+ }
9305
+
9306
+ // Validate that the date passed was a valid date
9307
+ if (!validDateStr(elem.value, elem.format)) {
9308
+ elem.validity = 'invalidDate';
9309
+ elem.errorMessage = elem.setCustomValidityInvalidDate || elem.setCustomValidity || 'Invalid Date Entered';
9310
+ return;
9311
+ }
8350
9312
 
8351
- // validate max
8352
- if (elem.max?.length === elem.lengthForType) {
8353
- const maxDate = new Date(elem.util.toNorthAmericanFormat(elem.max, elem.format).dateForComparison);
9313
+ // Perform the rest of the validation
9314
+ const formattedValue = toNorthAmericanFormat(elem.value, elem.format);
9315
+ const valueDate = new Date(formattedValue);
8354
9316
 
8355
- if (valueDate > maxDate) {
8356
- elem.validity = 'rangeOverflow';
8357
- elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
8358
- }
9317
+ // // Validate max date
9318
+ if (elem.max?.length === elem.lengthForType) {
9319
+
9320
+ const maxDate = new Date(toNorthAmericanFormat(elem.max, elem.format));
9321
+
9322
+ if (valueDate > maxDate) {
9323
+ elem.validity = 'rangeOverflow';
9324
+ elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
9325
+ return;
8359
9326
  }
9327
+ }
8360
9328
 
8361
- // validate min
8362
- if (elem.min?.length === elem.lengthForType) {
8363
- const minDate = new Date(elem.util.toNorthAmericanFormat(elem.min, elem.format).dateForComparison);
9329
+ // Validate min date
9330
+ if (elem.min?.length === elem.lengthForType) {
9331
+ const minDate = new Date(toNorthAmericanFormat(elem.min, elem.format));
8364
9332
 
8365
- if (valueDate < minDate) {
8366
- elem.validity = 'rangeUnderflow';
8367
- elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
8368
- }
9333
+ if (valueDate < minDate) {
9334
+ elem.validity = 'rangeUnderflow';
9335
+ elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
9336
+ return;
8369
9337
  }
8370
9338
  }
8371
9339
  }
@@ -8484,7 +9452,7 @@ class AuroFormValidation {
8484
9452
  if (input.validationMessage.length > 0) {
8485
9453
  elem.errorMessage = input.validationMessage;
8486
9454
  }
8487
- } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
9455
+ } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
8488
9456
  const firstInput = this.inputElements[0];
8489
9457
 
8490
9458
  if (firstInput.validationMessage.length > 0) {
@@ -8606,6 +9574,33 @@ class BaseInput extends r$1 {
8606
9574
  static get properties() {
8607
9575
  return {
8608
9576
 
9577
+ /**
9578
+ * The value for the role attribute.
9579
+ */
9580
+ a11yRole: {
9581
+ type: String,
9582
+ attribute: true,
9583
+ reflect: true
9584
+ },
9585
+
9586
+ /**
9587
+ * The value for the aria-expanded attribute.
9588
+ */
9589
+ a11yExpanded: {
9590
+ type: Boolean,
9591
+ attribute: true,
9592
+ reflect: true
9593
+ },
9594
+
9595
+ /**
9596
+ * The value for the aria-controls attribute.
9597
+ */
9598
+ a11yControls: {
9599
+ type: String,
9600
+ attribute: true,
9601
+ reflect: true
9602
+ },
9603
+
8609
9604
  /**
8610
9605
  * If set, the label will remain fixed in the active position.
8611
9606
  */
@@ -9247,6 +10242,10 @@ class BaseInput extends r$1 {
9247
10242
  } else if (this.type === 'number') {
9248
10243
  this.inputMode = 'numeric';
9249
10244
  }
10245
+
10246
+ if (this.type === "date" && !this.format) {
10247
+ this.format = 'mm/dd/yyyy';
10248
+ }
9250
10249
  }
9251
10250
 
9252
10251
  /**
@@ -10490,6 +11489,7 @@ var helpTextVersion = '1.0.0';
10490
11489
 
10491
11490
  // build the component class
10492
11491
  class AuroInput extends BaseInput {
11492
+
10493
11493
  constructor() {
10494
11494
  super();
10495
11495
 
@@ -10602,7 +11602,7 @@ class AuroInput extends BaseInput {
10602
11602
  ?required="${this.required}"
10603
11603
  ?disabled="${this.disabled}"
10604
11604
  aria-describedby="${this.uniqueId}"
10605
- aria-invalid="${this.validity !== 'valid'}"
11605
+ ?aria-invalid="${this.validity !== 'valid'}"
10606
11606
  placeholder=${this.getPlaceholder()}
10607
11607
  lang="${o(this.lang)}"
10608
11608
  ?activeLabel="${this.activeLabel}"
@@ -10611,7 +11611,10 @@ class AuroInput extends BaseInput {
10611
11611
  autocapitalize="${o(this.autocapitalize ? this.autocapitalize : undefined)}"
10612
11612
  autocomplete="${o(this.autocomplete ? this.autocomplete : undefined)}"
10613
11613
  part="input"
10614
- />
11614
+ role="${o(this.a11yRole)}"
11615
+ aria-expanded="${o(this.a11yExpanded)}"
11616
+ aria-controls="${o(this.a11yControls)}"
11617
+ />
10615
11618
  </div>
10616
11619
  <div
10617
11620
  class="notificationIcons"
@@ -11603,6 +12606,7 @@ var styleCss$3 = i$5`.util_displayInline{display:inline}.util_displayInlineBlock
11603
12606
 
11604
12607
  // build the component class
11605
12608
  class AuroCombobox extends r$1 {
12609
+
11606
12610
  constructor() {
11607
12611
  super();
11608
12612
 
@@ -11614,6 +12618,8 @@ class AuroCombobox extends r$1 {
11614
12618
  * @returns {void} Internal defaults.
11615
12619
  */
11616
12620
  privateDefaults() {
12621
+ this.dropdownOpen = false;
12622
+ this.dropdownId = undefined;
11617
12623
  this.onDark = false;
11618
12624
 
11619
12625
  this.noFilter = false;
@@ -11693,6 +12699,26 @@ class AuroCombobox extends r$1 {
11693
12699
  reflect: true
11694
12700
  },
11695
12701
 
12702
+ /**
12703
+ * ID for the dropdown
12704
+ * @private
12705
+ */
12706
+ dropdownId: {
12707
+ type: String,
12708
+ reflect: false,
12709
+ attribute: false
12710
+ },
12711
+
12712
+ /**
12713
+ * Whether or not the dropdown is open
12714
+ * @private
12715
+ */
12716
+ dropdownOpen: {
12717
+ type: Boolean,
12718
+ reflect: false,
12719
+ attribute: false
12720
+ },
12721
+
11696
12722
  /**
11697
12723
  * When defined, sets persistent validity to `customError` and sets the validation message to the attribute value.
11698
12724
  */
@@ -11854,8 +12880,19 @@ class AuroCombobox extends r$1 {
11854
12880
  * @private
11855
12881
  */
11856
12882
  isDropdownFullscreen: {
11857
- type: Boolean
11858
- }
12883
+ type: Boolean,
12884
+ reflect: false
12885
+ },
12886
+
12887
+ /**
12888
+ * @private
12889
+ * specifies the currently active option
12890
+ */
12891
+ optionActive: {
12892
+ type: Object,
12893
+ reflect: false,
12894
+ attribute: false
12895
+ },
11859
12896
  };
11860
12897
  }
11861
12898
 
@@ -12007,6 +13044,18 @@ class AuroCombobox extends r$1 {
12007
13044
  * @returns {void}
12008
13045
  */
12009
13046
  configureDropdown() {
13047
+
13048
+ // Listen for the ID to be added to the dropdown so we can capture it and use it for accessibility.
13049
+ this.dropdown.addEventListener('auroDropdown-idAdded', (event) => {
13050
+ this.dropdownId = event.detail.id;
13051
+ });
13052
+
13053
+ // Listen for the dropdown to be shown or hidden
13054
+ this.dropdown.addEventListener("auroDropdown-toggled", (ev) => {
13055
+ this.dropdownOpen = ev.detail.expanded;
13056
+ });
13057
+
13058
+ // this.dropdown.addEventListener('auroDropdown-show', () => {
12010
13059
  this.menuWrapper = this.dropdown.querySelector('.menuWrapper');
12011
13060
  this.menuWrapper.append(this.menu);
12012
13061
 
@@ -12020,7 +13069,6 @@ class AuroCombobox extends r$1 {
12020
13069
  this.hideBib = this.hideBib.bind(this);
12021
13070
  this.bibtemplate.addEventListener('close-click', this.hideBib);
12022
13071
 
12023
- this.dropdown.setAttribute('role', 'combobox');
12024
13072
  this.dropdown.addEventListener('auroDropdown-triggerClick', () => {
12025
13073
  this.showBib();
12026
13074
  });
@@ -12036,7 +13084,6 @@ class AuroCombobox extends r$1 {
12036
13084
  this.isDropdownFullscreen = event.detail.strategy === 'fullscreen';
12037
13085
  setTimeout(this.transportInput);
12038
13086
  });
12039
-
12040
13087
  }
12041
13088
 
12042
13089
  /**
@@ -12530,6 +13577,10 @@ class AuroCombobox extends r$1 {
12530
13577
  ?noFlip="${this.noFlip}"
12531
13578
  disableEventShow>
12532
13579
  <${this.inputTag}
13580
+ .a11yRole="${"combobox"}"
13581
+ .a11yExpanded="${this.dropdownOpen}"
13582
+ .a11yControls="${this.dropdownId}"
13583
+ id="${this.id || 'auro-combobox-input'}"
12533
13584
  slot="trigger"
12534
13585
  bordered
12535
13586
  ?onDark="${this.onDark}"