@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
@@ -306,11 +306,420 @@ let AuroLibraryRuntimeUtils$4 = class AuroLibraryRuntimeUtils {
306
306
  }
307
307
  };
308
308
 
309
+ let DateFormatter$1 = class DateFormatter {
310
+
311
+ constructor() {
312
+
313
+ /**
314
+ * @description Parses a date string into its components.
315
+ * @param {string} dateStr - Date string to parse.
316
+ * @param {string} format - Date format to parse.
317
+ * @returns {Object<key["month" | "day" | "year"]: number>|undefined}
318
+ */
319
+ this.parseDate = (dateStr, format = 'mm/dd/yyyy') => {
320
+
321
+ // Guard Clause: Date string is defined
322
+ if (!dateStr) {
323
+ return undefined;
324
+ }
325
+
326
+ // Assume the separator is a "/" a defined in our code base
327
+ const separator = '/';
328
+
329
+ // Get the parts of the date and format
330
+ const valueParts = dateStr.split(separator);
331
+ const formatParts = format.split(separator);
332
+
333
+ // Check if the value and format have the correct number of parts
334
+ if (valueParts.length !== formatParts.length) {
335
+ throw new Error('AuroDatepickerUtilities | parseDate: Date string and format length do not match');
336
+ }
337
+
338
+ // Holds the result to be returned
339
+ const result = formatParts.reduce((acc, part, index) => {
340
+ const value = valueParts[index];
341
+
342
+ if ((/m/iu).test(part)) {
343
+ acc.month = value;
344
+ } else if ((/d/iu).test(part)) {
345
+ acc.day = value;
346
+ } else if ((/y/iu).test(part)) {
347
+ acc.year = value;
348
+ }
349
+
350
+ return acc;
351
+ }, {});
352
+
353
+ // If we found all the parts, return the result
354
+ if (result.month && result.year) {
355
+ return result;
356
+ }
357
+
358
+ // Throw an error to let the dev know we were unable to parse the date string
359
+ throw new Error('AuroDatepickerUtilities | parseDate: Unable to parse date string');
360
+ };
361
+
362
+ /**
363
+ * Convert a date object to string format.
364
+ * @param {Object} date - Date to convert to string.
365
+ * @returns {Object} Returns the date as a string.
366
+ */
367
+ this.getDateAsString = (date) => date.toLocaleDateString(undefined, {
368
+ year: "numeric",
369
+ month: "2-digit",
370
+ day: "2-digit",
371
+ });
372
+
373
+ /**
374
+ * Converts a date string to a North American date format.
375
+ * @param {String} dateStr - Date to validate.
376
+ * @param {String} format - Date format to validate against.
377
+ * @returns {Boolean}
378
+ */
379
+ this.toNorthAmericanFormat = (dateStr, format) => {
380
+
381
+ if (format === 'mm/dd/yyyy') {
382
+ return dateStr;
383
+ }
384
+
385
+ const parsedDate = this.parseDate(dateStr, format);
386
+
387
+ if (!parsedDate) {
388
+ throw new Error('AuroDatepickerUtilities | toNorthAmericanFormat: Unable to parse date string');
389
+ }
390
+
391
+ const { month, day, year } = parsedDate;
392
+
393
+ const dateParts = [];
394
+ if (month) {
395
+ dateParts.push(month);
396
+ }
397
+
398
+ if (day) {
399
+ dateParts.push(day);
400
+ }
401
+
402
+ if (year) {
403
+ dateParts.push(year);
404
+ }
405
+
406
+ return dateParts.join('/');
407
+ };
408
+ }
409
+ };
410
+ const dateFormatter$1 = new DateFormatter$1();
411
+
412
+ // filepath: dateConstraints.mjs
413
+ const DATE_UTIL_CONSTRAINTS$1 = {
414
+ maxDay: 31,
415
+ maxMonth: 12,
416
+ maxYear: 2400,
417
+ minDay: 1,
418
+ minMonth: 1,
419
+ minYear: 1900,
420
+ };
421
+
422
+ let AuroDateUtilitiesBase$1 = class AuroDateUtilitiesBase {
423
+
424
+ /**
425
+ * @description The maximum day value allowed by the various utilities in this class.
426
+ * @readonly
427
+ * @type {Number}
428
+ */
429
+ get maxDay() {
430
+ return DATE_UTIL_CONSTRAINTS$1.maxDay;
431
+ }
432
+
433
+ /**
434
+ * @description The maximum month value allowed by the various utilities in this class.
435
+ * @readonly
436
+ * @type {Number}
437
+ */
438
+ get maxMonth() {
439
+ return DATE_UTIL_CONSTRAINTS$1.maxMonth;
440
+ }
441
+
442
+ /**
443
+ * @description The maximum year value allowed by the various utilities in this class.
444
+ * @readonly
445
+ * @type {Number}
446
+ */
447
+ get maxYear() {
448
+ return DATE_UTIL_CONSTRAINTS$1.maxYear;
449
+ }
450
+
451
+ /**
452
+ * @description The minimum day value allowed by the various utilities in this class.
453
+ * @readonly
454
+ * @type {Number}
455
+ */
456
+ get minDay() {
457
+ return DATE_UTIL_CONSTRAINTS$1.minDay;
458
+ }
459
+
460
+ /**
461
+ * @description The minimum month value allowed by the various utilities in this class.
462
+ * @readonly
463
+ * @type {Number}
464
+ */
465
+ get minMonth() {
466
+ return DATE_UTIL_CONSTRAINTS$1.minMonth;
467
+ }
468
+
469
+ /**
470
+ * @description The minimum year value allowed by the various utilities in this class.
471
+ * @readonly
472
+ * @type {Number}
473
+ */
474
+ get minYear() {
475
+ return DATE_UTIL_CONSTRAINTS$1.minYear;
476
+ }
477
+ };
478
+
479
+ /* eslint-disable no-magic-numbers */
480
+
481
+ let AuroDateUtilities$1 = class AuroDateUtilities extends AuroDateUtilitiesBase$1 {
482
+
483
+ /**
484
+ * Returns the current century.
485
+ * @returns {String} The current century.
486
+ */
487
+ getCentury () {
488
+ return String(new Date().getFullYear()).slice(0, 2);
489
+ }
490
+
491
+ /**
492
+ * Returns a four digit year.
493
+ * @param {String} year - The year to convert to four digits.
494
+ * @returns {String} The four digit year.
495
+ */
496
+ getFourDigitYear (year) {
497
+
498
+ const strYear = String(year).trim();
499
+ return strYear.length <= 2 ? this.getCentury() + strYear : strYear;
500
+ }
501
+
502
+ constructor() {
503
+
504
+ super();
505
+
506
+ /**
507
+ * Compares two dates to see if they match.
508
+ * @param {Object} date1 - First date to compare.
509
+ * @param {Object} date2 - Second date to compare.
510
+ * @returns {Boolean} Returns true if the dates match.
511
+ */
512
+ this.datesMatch = (date1, date2) => new Date(date1).getTime() === new Date(date2).getTime();
513
+
514
+ /**
515
+ * Returns true if value passed in is a valid date.
516
+ * @param {String} date - Date to validate.
517
+ * @param {String} format - Date format to validate against.
518
+ * @returns {Boolean}
519
+ */
520
+ this.validDateStr = (date, format) => {
521
+
522
+ // The length we expect the date string to be
523
+ const dateStrLength = format.length;
524
+
525
+ // Guard Clause: Date and format are defined
526
+ if (typeof date === "undefined" || typeof format === "undefined") {
527
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date and format are required');
528
+ }
529
+
530
+ // Guard Clause: Date should be of type string
531
+ if (typeof date !== "string") {
532
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date must be a string');
533
+ }
534
+
535
+ // Guard Clause: Format should be of type string
536
+ if (typeof format !== "string") {
537
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Format must be a string');
538
+ }
539
+
540
+ // Guard Clause: Length is what we expect it to be
541
+ if (date.length !== dateStrLength) {
542
+ return false;
543
+ }
544
+ // Get a formatted date string and parse it
545
+ const dateParts = dateFormatter$1.parseDate(date, format);
546
+
547
+ // Guard Clause: Date parse succeeded
548
+ if (!dateParts) {
549
+ return false;
550
+ }
551
+
552
+ // Create the expected date string based on the date parts
553
+ const expectedDateStr = `${dateParts.month}/${dateParts.day || "01"}/${this.getFourDigitYear(dateParts.year)}`;
554
+
555
+ // Generate a date object that we will extract a string date from to compare to the passed in date string
556
+ const dateObj = new Date(this.getFourDigitYear(dateParts.year), dateParts.month - 1, dateParts.day || 1);
557
+
558
+ // Get the date string of the date object we created from the string date
559
+ const actualDateStr = dateFormatter$1.getDateAsString(dateObj);
560
+
561
+ // Guard Clause: Generated date matches date string input
562
+ if (expectedDateStr !== actualDateStr) {
563
+ return false;
564
+ }
565
+
566
+ // If we passed all other checks, we can assume the date is valid
567
+ return true;
568
+ };
569
+
570
+ /**
571
+ * Determines if a string date value matches the format provided.
572
+ * @param {string} value = The date string value.
573
+ * @param { string} format = The date format to match against.
574
+ * @returns {boolean}
575
+ */
576
+ this.dateAndFormatMatch = (value, format) => {
577
+
578
+ // Ensure we have both values we need to do the comparison
579
+ if (!value || !format) {
580
+ throw new Error('AuroFormValidation | dateFormatMatch: value and format are required');
581
+ }
582
+
583
+ // If the lengths are different, they cannot match
584
+ if (value.length !== format.length) {
585
+ return false;
586
+ }
587
+
588
+ // Get the parts of the date
589
+ const dateParts = dateFormatter$1.parseDate(value, format);
590
+
591
+ // Validator for day
592
+ const dayValueIsValid = (day) => {
593
+
594
+ // Guard clause: if there is no day in the dateParts, we can ignore this check.
595
+ if (!dateParts.day) {
596
+ return true;
597
+ }
598
+
599
+ // Guard clause: ensure day exists.
600
+ if (!day) {
601
+ return false;
602
+ }
603
+
604
+ // Convert day to number
605
+ const numDay = Number.parseInt(day, 10);
606
+
607
+ // Guard clause: ensure day is a valid integer
608
+ if (Number.isNaN(numDay)) {
609
+ throw new Error('AuroDatepickerUtilities | dayValueIsValid: Unable to parse day value integer');
610
+ }
611
+
612
+ // Guard clause: ensure day is within the valid range
613
+ if (numDay < this.minDay || numDay > this.maxDay) {
614
+ return false;
615
+ }
616
+
617
+ // Default return
618
+ return true;
619
+ };
620
+
621
+ // Validator for month
622
+ const monthValueIsValid = (month) => {
623
+
624
+ // Guard clause: ensure month exists.
625
+ if (!month) {
626
+ return false;
627
+ }
628
+
629
+ // Convert month to number
630
+ const numMonth = Number.parseInt(month, 10);
631
+
632
+ // Guard clause: ensure month is a valid integer
633
+ if (Number.isNaN(numMonth)) {
634
+ throw new Error('AuroDatepickerUtilities | monthValueIsValid: Unable to parse month value integer');
635
+ }
636
+
637
+ // Guard clause: ensure month is within the valid range
638
+ if (numMonth < this.minMonth || numMonth > this.maxMonth) {
639
+ return false;
640
+ }
641
+
642
+ // Default return
643
+ return true;
644
+ };
645
+
646
+ // Validator for year
647
+ const yearIsValid = (_year) => {
648
+
649
+ // Guard clause: ensure year exists.
650
+ if (!_year) {
651
+ return false;
652
+ }
653
+
654
+ // Get the full year
655
+ const year = this.getFourDigitYear(_year);
656
+
657
+ // Convert year to number
658
+ const numYear = Number.parseInt(year, 10);
659
+
660
+ // Guard clause: ensure year is a valid integer
661
+ if (Number.isNaN(numYear)) {
662
+ throw new Error('AuroDatepickerUtilities | yearValueIsValid: Unable to parse year value integer');
663
+ }
664
+
665
+ // Guard clause: ensure year is within the valid range
666
+ if (numYear < this.minYear || numYear > this.maxYear) {
667
+ return false;
668
+ }
669
+
670
+ // Default return
671
+ return true;
672
+ };
673
+
674
+ // Self-contained checks for month, day, and year
675
+ const checks = [
676
+ monthValueIsValid(dateParts.month),
677
+ dayValueIsValid(dateParts.day),
678
+ yearIsValid(dateParts.year)
679
+ ];
680
+
681
+ // If any of the checks failed, the date format does not match and the result is invalid
682
+ const isValid = checks.every((check) => check === true);
683
+
684
+ // If the check is invalid, return false
685
+ if (!isValid) {
686
+ return false;
687
+ }
688
+
689
+ // Default case
690
+ return true;
691
+ };
692
+ }
693
+ };
694
+
695
+ // Export a class instance
696
+ const dateUtilities$1 = new AuroDateUtilities$1();
697
+
698
+ // Export the class instance methods individually
699
+ const {
700
+ datesMatch: datesMatch$1,
701
+ validDateStr: validDateStr$1,
702
+ dateAndFormatMatch: dateAndFormatMatch$1,
703
+ minDay: minDay$1,
704
+ minMonth: minMonth$1,
705
+ minYear: minYear$1,
706
+ maxDay: maxDay$1,
707
+ maxMonth: maxMonth$1,
708
+ maxYear: maxYear$1
709
+ } = dateUtilities$1;
710
+
711
+ const {
712
+ toNorthAmericanFormat: toNorthAmericanFormat$1,
713
+ parseDate: parseDate$1,
714
+ getDateAsString: getDateAsString$1
715
+ } = dateFormatter$1;
716
+
309
717
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
310
718
  // See LICENSE in the project root for license information.
311
719
 
312
720
 
313
721
  let AuroFormValidation$1 = class AuroFormValidation {
722
+
314
723
  constructor() {
315
724
  this.runtimeUtils = new AuroLibraryRuntimeUtils$4();
316
725
  }
@@ -402,17 +811,17 @@ let AuroFormValidation$1 = class AuroFormValidation {
402
811
  ]
403
812
  }
404
813
  };
405
-
814
+
406
815
  let elementType;
407
816
  if (this.runtimeUtils.elementMatch(elem, 'auro-input')) {
408
817
  elementType = 'input';
409
818
  } else if (this.runtimeUtils.elementMatch(elem, 'auro-counter') || this.runtimeUtils.elementMatch(elem, 'auro-counter-group')) {
410
819
  elementType = 'counter';
411
820
  }
412
-
821
+
413
822
  if (elementType) {
414
823
  const rules = validationRules[elementType];
415
-
824
+
416
825
  if (rules) {
417
826
  Object.values(rules).flat().forEach(rule => {
418
827
  if (rule.check(elem)) {
@@ -438,48 +847,82 @@ let AuroFormValidation$1 = class AuroFormValidation {
438
847
  if (!elem.value.match(emailRegex)) {
439
848
  elem.validity = 'patternMismatch';
440
849
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
850
+ return;
441
851
  }
442
852
  } else if (elem.type === 'credit-card') {
443
853
  if (elem.value.length > 0 && elem.value.length < elem.validationCCLength) {
444
854
  elem.validity = 'tooShort';
445
855
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
856
+ return;
446
857
  }
447
858
  } else if (elem.type === 'number') {
448
859
  if (elem.max !== undefined && Number(elem.max) < Number(elem.value)) {
449
860
  elem.validity = 'rangeOverflow';
450
861
  elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
862
+ return;
451
863
  }
452
864
 
453
865
  if (elem.min !== undefined && elem.value?.length > 0 && Number(elem.min) > Number(elem.value)) {
454
866
  elem.validity = 'rangeUnderflow';
455
867
  elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
868
+ return;
456
869
  }
457
- } else if (elem.type === 'date') {
458
- if (elem.value?.length > 0 && elem.value?.length < elem.lengthForType) {
870
+ } else if (elem.type === 'date' && elem.value?.length > 0) {
871
+
872
+ // Guard Clause: if the value is too short
873
+ if (elem.value.length < elem.lengthForType) {
874
+
459
875
  elem.validity = 'tooShort';
460
876
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
461
- } else if (elem.value?.length === elem.lengthForType && elem.util.toNorthAmericanFormat(elem.value, elem.format)) {
462
- const formattedValue = elem.util.toNorthAmericanFormat(elem.value, elem.format);
463
- const valueDate = new Date(formattedValue.dateForComparison);
877
+ return;
878
+ }
879
+
880
+ // Guard Clause: If the value is too long for the type
881
+ if (elem.value?.length > elem.lengthForType) {
882
+
883
+ elem.validity = 'tooLong';
884
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
885
+ return;
886
+ }
887
+
888
+ // Validate that the date passed was the correct format
889
+ if (!dateAndFormatMatch$1(elem.value, elem.format)) {
890
+ elem.validity = 'patternMismatch';
891
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || 'Invalid Date Format Entered';
892
+ return;
893
+ }
894
+
895
+ // Validate that the date passed was a valid date
896
+ if (!validDateStr$1(elem.value, elem.format)) {
897
+ elem.validity = 'invalidDate';
898
+ elem.errorMessage = elem.setCustomValidityInvalidDate || elem.setCustomValidity || 'Invalid Date Entered';
899
+ return;
900
+ }
464
901
 
465
- // validate max
466
- if (elem.max?.length === elem.lengthForType) {
467
- const maxDate = new Date(elem.util.toNorthAmericanFormat(elem.max, elem.format).dateForComparison);
902
+ // Perform the rest of the validation
903
+ const formattedValue = toNorthAmericanFormat$1(elem.value, elem.format);
904
+ const valueDate = new Date(formattedValue);
468
905
 
469
- if (valueDate > maxDate) {
470
- elem.validity = 'rangeOverflow';
471
- elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
472
- }
906
+ // // Validate max date
907
+ if (elem.max?.length === elem.lengthForType) {
908
+
909
+ const maxDate = new Date(toNorthAmericanFormat$1(elem.max, elem.format));
910
+
911
+ if (valueDate > maxDate) {
912
+ elem.validity = 'rangeOverflow';
913
+ elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
914
+ return;
473
915
  }
916
+ }
474
917
 
475
- // validate min
476
- if (elem.min?.length === elem.lengthForType) {
477
- const minDate = new Date(elem.util.toNorthAmericanFormat(elem.min, elem.format).dateForComparison);
918
+ // Validate min date
919
+ if (elem.min?.length === elem.lengthForType) {
920
+ const minDate = new Date(toNorthAmericanFormat$1(elem.min, elem.format));
478
921
 
479
- if (valueDate < minDate) {
480
- elem.validity = 'rangeUnderflow';
481
- elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
482
- }
922
+ if (valueDate < minDate) {
923
+ elem.validity = 'rangeUnderflow';
924
+ elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
925
+ return;
483
926
  }
484
927
  }
485
928
  }
@@ -598,7 +1041,7 @@ let AuroFormValidation$1 = class AuroFormValidation {
598
1041
  if (input.validationMessage.length > 0) {
599
1042
  elem.errorMessage = input.validationMessage;
600
1043
  }
601
- } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
1044
+ } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
602
1045
  const firstInput = this.inputElements[0];
603
1046
 
604
1047
  if (firstInput.validationMessage.length > 0) {
@@ -2479,7 +2922,7 @@ class AuroFloatingUI {
2479
2922
  /**
2480
2923
  * @private
2481
2924
  * getting called on 'blur' in trigger or `focusin` in document
2482
- *
2925
+ *
2483
2926
  * Hides the bib if focus moves outside of the trigger or bib, unless a 'noHideOnThisFocusLoss' flag is set.
2484
2927
  * This method checks if the currently active element is still within the trigger or bib.
2485
2928
  * If not, and if the bib isn't in fullscreen mode with focus lost, it hides the bib.
@@ -2595,7 +3038,7 @@ class AuroFloatingUI {
2595
3038
  // Close any other dropdown that is already open
2596
3039
  const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
2597
3040
  if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this &&
2598
- existedVisibleFloatingUI.isPopoverVisible &&
3041
+ existedVisibleFloatingUI.element.isPopoverVisible &&
2599
3042
  document.expandedAuroFloater.eventPrefix === this.eventPrefix) {
2600
3043
  document.expandedAuroFloater.hideBib();
2601
3044
  }
@@ -2771,7 +3214,7 @@ class AuroFloatingUI {
2771
3214
  this.id = window.crypto.randomUUID();
2772
3215
  this.element.setAttribute('id', this.id);
2773
3216
  }
2774
-
3217
+
2775
3218
  this.element.bib.setAttribute("id", `${this.id}-floater-bib`);
2776
3219
  }
2777
3220
 
@@ -2824,7 +3267,7 @@ class AuroFloatingUI {
2824
3267
  if (this.element.bib) {
2825
3268
  this.element.shadowRoot.append(this.element.bib);
2826
3269
  }
2827
-
3270
+
2828
3271
  // Remove event & keyboard listeners
2829
3272
  if (this.element?.trigger) {
2830
3273
  this.element.trigger.removeEventListener('keydown', this.handleEvent);
@@ -3555,6 +3998,7 @@ var helpTextVersion$1 = '1.0.0';
3555
3998
  * @csspart helpText - The helpText content container.
3556
3999
  * @event auroDropdown-triggerClick - Notifies that the trigger has been clicked.
3557
4000
  * @event auroDropdown-toggled - Notifies that the visibility of the dropdown bib has changed.
4001
+ * @event auroDropdown-idAdded - Notifies consumers that the unique ID for the dropdown bib has been generated.
3558
4002
  */
3559
4003
  class AuroDropdown extends r$1 {
3560
4004
  constructor() {
@@ -3600,7 +4044,9 @@ class AuroDropdown extends r$1 {
3600
4044
  this.rounded = false;
3601
4045
  this.tabIndex = 0;
3602
4046
  this.noToggle = false;
4047
+ this.a11yAutocomplete = 'none';
3603
4048
  this.labeled = true;
4049
+ this.a11yRole = 'combobox';
3604
4050
  this.onDark = false;
3605
4051
 
3606
4052
  // floaterConfig
@@ -3736,6 +4182,16 @@ class AuroDropdown extends r$1 {
3736
4182
  type: Number
3737
4183
  },
3738
4184
 
4185
+ /**
4186
+ * The unique ID for the dropdown bib element.
4187
+ * @private
4188
+ */
4189
+ dropdownId: {
4190
+ type: String,
4191
+ reflect: false,
4192
+ attribute: false
4193
+ },
4194
+
3739
4195
  /**
3740
4196
  * If declared in combination with `bordered` property or `helpText` slot content, will apply red color to both.
3741
4197
  */
@@ -3903,6 +4359,23 @@ class AuroDropdown extends r$1 {
3903
4359
  */
3904
4360
  tabIndex: {
3905
4361
  type: Number
4362
+ },
4363
+
4364
+ /**
4365
+ * The value for the role attribute of the trigger element.
4366
+ */
4367
+ a11yRole: {
4368
+ type: String || undefined,
4369
+ attribute: false,
4370
+ reflect: false
4371
+ },
4372
+
4373
+ /**
4374
+ * The value for the aria-autocomplete attribute of the trigger element.
4375
+ */
4376
+ a11yAutocomplete: {
4377
+ type: String,
4378
+ attribute: false,
3906
4379
  }
3907
4380
  };
3908
4381
  }
@@ -3964,7 +4437,22 @@ class AuroDropdown extends r$1 {
3964
4437
  }
3965
4438
 
3966
4439
  firstUpdated() {
4440
+
4441
+ // Configure the floater to, this will generate the ID for the bib
3967
4442
  this.floater.configure(this, 'auroDropdown');
4443
+
4444
+ /**
4445
+ * @description Let subscribers know that the dropdown ID ha been generated and added.
4446
+ * @event auroDropdown-idAdded
4447
+ * @type {Object<key: 'id', value: string>} - The ID of the dropdown bib element.
4448
+ */
4449
+ this.dispatchEvent(new CustomEvent('auroDropdown-idAdded', {detail: {id: this.floater.element.id}}));
4450
+
4451
+ // Set the bib ID locally if the user hasn't provided a focusable trigger
4452
+ if (!this.triggerContentFocusable) {
4453
+ this.dropdownId = this.floater.element.id;
4454
+ }
4455
+
3968
4456
  this.bibContent = this.floater.element.bib;
3969
4457
 
3970
4458
  // Add the tag name as an attribute if it is different than the component name
@@ -4116,6 +4604,30 @@ class AuroDropdown extends r$1 {
4116
4604
  });
4117
4605
  }
4118
4606
 
4607
+ /*
4608
+ * Sets aria attributes for the trigger element if a custom one is passed in.
4609
+ * @private
4610
+ * @method setTriggerAriaAttributes
4611
+ * @param { HTMLElement } triggerElement - The custom trigger element.
4612
+ */
4613
+ clearTriggerA11yAttributes(triggerElement) {
4614
+
4615
+ if (!triggerElement || !triggerElement.removeAttribute) {
4616
+ return;
4617
+ }
4618
+
4619
+ // Reset appropriate attributes for a11y
4620
+ triggerElement.removeAttribute('aria-labelledby');
4621
+ if (triggerElement.getAttribute('id') === `${this.id}-trigger-element`) {
4622
+ triggerElement.removeAttribute('id');
4623
+ }
4624
+ triggerElement.removeAttribute('role');
4625
+ triggerElement.removeAttribute('aria-expanded');
4626
+
4627
+ triggerElement.removeAttribute('aria-controls');
4628
+ triggerElement.removeAttribute('aria-autocomplete');
4629
+ }
4630
+
4119
4631
  /**
4120
4632
  * Handles changes to the trigger content slot and updates related properties.
4121
4633
  *
@@ -4129,32 +4641,41 @@ class AuroDropdown extends r$1 {
4129
4641
  * @returns {void}
4130
4642
  */
4131
4643
  handleTriggerContentSlotChange(event) {
4644
+
4132
4645
  this.floater.handleTriggerTabIndex();
4133
4646
 
4647
+ // Get the trigger
4648
+ const trigger = this.shadowRoot.querySelector('#trigger');
4649
+
4650
+ // Get the trigger slot
4134
4651
  const triggerSlot = this.shadowRoot.querySelector('.triggerContent slot');
4135
4652
 
4653
+ // If there's a trigger slot
4136
4654
  if (triggerSlot) {
4137
4655
 
4656
+ // Get the content nodes to see if there are any children
4138
4657
  const triggerContentNodes = triggerSlot.assignedNodes();
4139
4658
 
4659
+ // If there are children
4140
4660
  if (triggerContentNodes) {
4141
4661
 
4142
- triggerContentNodes.forEach((node) => {
4143
- if (!this.triggerContentFocusable) {
4144
- this.triggerContentFocusable = this.containsFocusableElement(node);
4145
- }
4146
- });
4147
- }
4148
- }
4662
+ // See if any of them are focusable elemeents
4663
+ this.triggerContentFocusable = triggerContentNodes.some((node) => this.containsFocusableElement(node));
4149
4664
 
4150
- const trigger = this.shadowRoot.querySelector('#trigger');
4665
+ // If any of them are focusable elements
4666
+ if (this.triggerContentFocusable) {
4151
4667
 
4152
- if (!this.triggerContentFocusable) {
4153
- trigger.setAttribute('tabindex', '0');
4154
- trigger.setAttribute('role', 'button');
4155
- } else {
4156
- trigger.removeAttribute('tabindex');
4157
- trigger.removeAttribute('role');
4668
+ // Assume the consumer will be providing their own a11y in whatever they passed in
4669
+ this.clearTriggerA11yAttributes(trigger);
4670
+
4671
+ // Remove the tabindex from the trigger so it doesn't interrupt focus flow
4672
+ trigger.removeAttribute('tabindex');
4673
+ } else {
4674
+
4675
+ // Add the tabindex to the trigger so that it's in the focus flow
4676
+ trigger.setAttribute('tabindex', '0');
4677
+ }
4678
+ }
4158
4679
  }
4159
4680
 
4160
4681
  if (event) {
@@ -4164,6 +4685,7 @@ class AuroDropdown extends r$1 {
4164
4685
 
4165
4686
  if (this.triggerContentSlot) {
4166
4687
  this.setupTriggerFocusEventBinding();
4688
+
4167
4689
  this.hasTriggerContent = this.triggerContentSlot.some((slot) => {
4168
4690
  if (slot.textContent.trim()) {
4169
4691
  return true;
@@ -4231,10 +4753,13 @@ class AuroDropdown extends r$1 {
4231
4753
  id="trigger"
4232
4754
  class="trigger"
4233
4755
  part="trigger"
4234
- aria-labelledby="triggerLabel"
4235
4756
  tabindex="${this.tabIndex}"
4236
4757
  ?showBorder="${this.showTriggerBorders}"
4237
- >
4758
+ role="${o(this.triggerContentFocusable ? undefined : this.a11yRole)}"
4759
+ aria-expanded="${o(this.triggerContentFocusable ? undefined : this.isPopoverVisible)}"
4760
+ aria-controls="${o(this.triggerContentFocusable ? undefined : this.dropdownId)}"
4761
+ aria-labelledby="${o(this.triggerContentFocusable ? undefined : 'triggerLabel')}"
4762
+ >
4238
4763
  <div class="triggerContentWrapper">
4239
4764
  <label class="label" id="triggerLabel" hasTrigger=${this.hasTriggerContent}>
4240
4765
  <slot name="label" @slotchange="${this.handleLabelSlotChange}"></slot>
@@ -4268,12 +4793,12 @@ class AuroDropdown extends r$1 {
4268
4793
  <div id="bibSizer" part="size"></div>
4269
4794
  <${this.dropdownBibTag}
4270
4795
  id="bib"
4271
- role="tooltip"
4272
4796
  ?data-show="${this.isPopoverVisible}"
4273
4797
  ?isfullscreen="${this.isBibFullscreen}"
4274
4798
  ?common="${this.common}"
4275
4799
  ?rounded="${this.common || this.rounded}"
4276
- ?inset="${this.common || this.inset}">
4800
+ ?inset="${this.common || this.inset}"
4801
+ >
4277
4802
  </${this.dropdownBibTag}>
4278
4803
  </div>
4279
4804
  `;
@@ -8264,6 +8789,414 @@ class AuroInputUtilities {
8264
8789
  }
8265
8790
  }
8266
8791
 
8792
+ class DateFormatter {
8793
+
8794
+ constructor() {
8795
+
8796
+ /**
8797
+ * @description Parses a date string into its components.
8798
+ * @param {string} dateStr - Date string to parse.
8799
+ * @param {string} format - Date format to parse.
8800
+ * @returns {Object<key["month" | "day" | "year"]: number>|undefined}
8801
+ */
8802
+ this.parseDate = (dateStr, format = 'mm/dd/yyyy') => {
8803
+
8804
+ // Guard Clause: Date string is defined
8805
+ if (!dateStr) {
8806
+ return undefined;
8807
+ }
8808
+
8809
+ // Assume the separator is a "/" a defined in our code base
8810
+ const separator = '/';
8811
+
8812
+ // Get the parts of the date and format
8813
+ const valueParts = dateStr.split(separator);
8814
+ const formatParts = format.split(separator);
8815
+
8816
+ // Check if the value and format have the correct number of parts
8817
+ if (valueParts.length !== formatParts.length) {
8818
+ throw new Error('AuroDatepickerUtilities | parseDate: Date string and format length do not match');
8819
+ }
8820
+
8821
+ // Holds the result to be returned
8822
+ const result = formatParts.reduce((acc, part, index) => {
8823
+ const value = valueParts[index];
8824
+
8825
+ if ((/m/iu).test(part)) {
8826
+ acc.month = value;
8827
+ } else if ((/d/iu).test(part)) {
8828
+ acc.day = value;
8829
+ } else if ((/y/iu).test(part)) {
8830
+ acc.year = value;
8831
+ }
8832
+
8833
+ return acc;
8834
+ }, {});
8835
+
8836
+ // If we found all the parts, return the result
8837
+ if (result.month && result.year) {
8838
+ return result;
8839
+ }
8840
+
8841
+ // Throw an error to let the dev know we were unable to parse the date string
8842
+ throw new Error('AuroDatepickerUtilities | parseDate: Unable to parse date string');
8843
+ };
8844
+
8845
+ /**
8846
+ * Convert a date object to string format.
8847
+ * @param {Object} date - Date to convert to string.
8848
+ * @returns {Object} Returns the date as a string.
8849
+ */
8850
+ this.getDateAsString = (date) => date.toLocaleDateString(undefined, {
8851
+ year: "numeric",
8852
+ month: "2-digit",
8853
+ day: "2-digit",
8854
+ });
8855
+
8856
+ /**
8857
+ * Converts a date string to a North American date format.
8858
+ * @param {String} dateStr - Date to validate.
8859
+ * @param {String} format - Date format to validate against.
8860
+ * @returns {Boolean}
8861
+ */
8862
+ this.toNorthAmericanFormat = (dateStr, format) => {
8863
+
8864
+ if (format === 'mm/dd/yyyy') {
8865
+ return dateStr;
8866
+ }
8867
+
8868
+ const parsedDate = this.parseDate(dateStr, format);
8869
+
8870
+ if (!parsedDate) {
8871
+ throw new Error('AuroDatepickerUtilities | toNorthAmericanFormat: Unable to parse date string');
8872
+ }
8873
+
8874
+ const { month, day, year } = parsedDate;
8875
+
8876
+ const dateParts = [];
8877
+ if (month) {
8878
+ dateParts.push(month);
8879
+ }
8880
+
8881
+ if (day) {
8882
+ dateParts.push(day);
8883
+ }
8884
+
8885
+ if (year) {
8886
+ dateParts.push(year);
8887
+ }
8888
+
8889
+ return dateParts.join('/');
8890
+ };
8891
+ }
8892
+ }
8893
+ const dateFormatter = new DateFormatter();
8894
+
8895
+ // filepath: dateConstraints.mjs
8896
+ const DATE_UTIL_CONSTRAINTS = {
8897
+ maxDay: 31,
8898
+ maxMonth: 12,
8899
+ maxYear: 2400,
8900
+ minDay: 1,
8901
+ minMonth: 1,
8902
+ minYear: 1900,
8903
+ };
8904
+
8905
+ class AuroDateUtilitiesBase {
8906
+
8907
+ /**
8908
+ * @description The maximum day value allowed by the various utilities in this class.
8909
+ * @readonly
8910
+ * @type {Number}
8911
+ */
8912
+ get maxDay() {
8913
+ return DATE_UTIL_CONSTRAINTS.maxDay;
8914
+ }
8915
+
8916
+ /**
8917
+ * @description The maximum month value allowed by the various utilities in this class.
8918
+ * @readonly
8919
+ * @type {Number}
8920
+ */
8921
+ get maxMonth() {
8922
+ return DATE_UTIL_CONSTRAINTS.maxMonth;
8923
+ }
8924
+
8925
+ /**
8926
+ * @description The maximum year value allowed by the various utilities in this class.
8927
+ * @readonly
8928
+ * @type {Number}
8929
+ */
8930
+ get maxYear() {
8931
+ return DATE_UTIL_CONSTRAINTS.maxYear;
8932
+ }
8933
+
8934
+ /**
8935
+ * @description The minimum day value allowed by the various utilities in this class.
8936
+ * @readonly
8937
+ * @type {Number}
8938
+ */
8939
+ get minDay() {
8940
+ return DATE_UTIL_CONSTRAINTS.minDay;
8941
+ }
8942
+
8943
+ /**
8944
+ * @description The minimum month value allowed by the various utilities in this class.
8945
+ * @readonly
8946
+ * @type {Number}
8947
+ */
8948
+ get minMonth() {
8949
+ return DATE_UTIL_CONSTRAINTS.minMonth;
8950
+ }
8951
+
8952
+ /**
8953
+ * @description The minimum year value allowed by the various utilities in this class.
8954
+ * @readonly
8955
+ * @type {Number}
8956
+ */
8957
+ get minYear() {
8958
+ return DATE_UTIL_CONSTRAINTS.minYear;
8959
+ }
8960
+ }
8961
+
8962
+ /* eslint-disable no-magic-numbers */
8963
+
8964
+ class AuroDateUtilities extends AuroDateUtilitiesBase {
8965
+
8966
+ /**
8967
+ * Returns the current century.
8968
+ * @returns {String} The current century.
8969
+ */
8970
+ getCentury () {
8971
+ return String(new Date().getFullYear()).slice(0, 2);
8972
+ }
8973
+
8974
+ /**
8975
+ * Returns a four digit year.
8976
+ * @param {String} year - The year to convert to four digits.
8977
+ * @returns {String} The four digit year.
8978
+ */
8979
+ getFourDigitYear (year) {
8980
+
8981
+ const strYear = String(year).trim();
8982
+ return strYear.length <= 2 ? this.getCentury() + strYear : strYear;
8983
+ }
8984
+
8985
+ constructor() {
8986
+
8987
+ super();
8988
+
8989
+ /**
8990
+ * Compares two dates to see if they match.
8991
+ * @param {Object} date1 - First date to compare.
8992
+ * @param {Object} date2 - Second date to compare.
8993
+ * @returns {Boolean} Returns true if the dates match.
8994
+ */
8995
+ this.datesMatch = (date1, date2) => new Date(date1).getTime() === new Date(date2).getTime();
8996
+
8997
+ /**
8998
+ * Returns true if value passed in is a valid date.
8999
+ * @param {String} date - Date to validate.
9000
+ * @param {String} format - Date format to validate against.
9001
+ * @returns {Boolean}
9002
+ */
9003
+ this.validDateStr = (date, format) => {
9004
+
9005
+ // The length we expect the date string to be
9006
+ const dateStrLength = format.length;
9007
+
9008
+ // Guard Clause: Date and format are defined
9009
+ if (typeof date === "undefined" || typeof format === "undefined") {
9010
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date and format are required');
9011
+ }
9012
+
9013
+ // Guard Clause: Date should be of type string
9014
+ if (typeof date !== "string") {
9015
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date must be a string');
9016
+ }
9017
+
9018
+ // Guard Clause: Format should be of type string
9019
+ if (typeof format !== "string") {
9020
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Format must be a string');
9021
+ }
9022
+
9023
+ // Guard Clause: Length is what we expect it to be
9024
+ if (date.length !== dateStrLength) {
9025
+ return false;
9026
+ }
9027
+ // Get a formatted date string and parse it
9028
+ const dateParts = dateFormatter.parseDate(date, format);
9029
+
9030
+ // Guard Clause: Date parse succeeded
9031
+ if (!dateParts) {
9032
+ return false;
9033
+ }
9034
+
9035
+ // Create the expected date string based on the date parts
9036
+ const expectedDateStr = `${dateParts.month}/${dateParts.day || "01"}/${this.getFourDigitYear(dateParts.year)}`;
9037
+
9038
+ // Generate a date object that we will extract a string date from to compare to the passed in date string
9039
+ const dateObj = new Date(this.getFourDigitYear(dateParts.year), dateParts.month - 1, dateParts.day || 1);
9040
+
9041
+ // Get the date string of the date object we created from the string date
9042
+ const actualDateStr = dateFormatter.getDateAsString(dateObj);
9043
+
9044
+ // Guard Clause: Generated date matches date string input
9045
+ if (expectedDateStr !== actualDateStr) {
9046
+ return false;
9047
+ }
9048
+
9049
+ // If we passed all other checks, we can assume the date is valid
9050
+ return true;
9051
+ };
9052
+
9053
+ /**
9054
+ * Determines if a string date value matches the format provided.
9055
+ * @param {string} value = The date string value.
9056
+ * @param { string} format = The date format to match against.
9057
+ * @returns {boolean}
9058
+ */
9059
+ this.dateAndFormatMatch = (value, format) => {
9060
+
9061
+ // Ensure we have both values we need to do the comparison
9062
+ if (!value || !format) {
9063
+ throw new Error('AuroFormValidation | dateFormatMatch: value and format are required');
9064
+ }
9065
+
9066
+ // If the lengths are different, they cannot match
9067
+ if (value.length !== format.length) {
9068
+ return false;
9069
+ }
9070
+
9071
+ // Get the parts of the date
9072
+ const dateParts = dateFormatter.parseDate(value, format);
9073
+
9074
+ // Validator for day
9075
+ const dayValueIsValid = (day) => {
9076
+
9077
+ // Guard clause: if there is no day in the dateParts, we can ignore this check.
9078
+ if (!dateParts.day) {
9079
+ return true;
9080
+ }
9081
+
9082
+ // Guard clause: ensure day exists.
9083
+ if (!day) {
9084
+ return false;
9085
+ }
9086
+
9087
+ // Convert day to number
9088
+ const numDay = Number.parseInt(day, 10);
9089
+
9090
+ // Guard clause: ensure day is a valid integer
9091
+ if (Number.isNaN(numDay)) {
9092
+ throw new Error('AuroDatepickerUtilities | dayValueIsValid: Unable to parse day value integer');
9093
+ }
9094
+
9095
+ // Guard clause: ensure day is within the valid range
9096
+ if (numDay < this.minDay || numDay > this.maxDay) {
9097
+ return false;
9098
+ }
9099
+
9100
+ // Default return
9101
+ return true;
9102
+ };
9103
+
9104
+ // Validator for month
9105
+ const monthValueIsValid = (month) => {
9106
+
9107
+ // Guard clause: ensure month exists.
9108
+ if (!month) {
9109
+ return false;
9110
+ }
9111
+
9112
+ // Convert month to number
9113
+ const numMonth = Number.parseInt(month, 10);
9114
+
9115
+ // Guard clause: ensure month is a valid integer
9116
+ if (Number.isNaN(numMonth)) {
9117
+ throw new Error('AuroDatepickerUtilities | monthValueIsValid: Unable to parse month value integer');
9118
+ }
9119
+
9120
+ // Guard clause: ensure month is within the valid range
9121
+ if (numMonth < this.minMonth || numMonth > this.maxMonth) {
9122
+ return false;
9123
+ }
9124
+
9125
+ // Default return
9126
+ return true;
9127
+ };
9128
+
9129
+ // Validator for year
9130
+ const yearIsValid = (_year) => {
9131
+
9132
+ // Guard clause: ensure year exists.
9133
+ if (!_year) {
9134
+ return false;
9135
+ }
9136
+
9137
+ // Get the full year
9138
+ const year = this.getFourDigitYear(_year);
9139
+
9140
+ // Convert year to number
9141
+ const numYear = Number.parseInt(year, 10);
9142
+
9143
+ // Guard clause: ensure year is a valid integer
9144
+ if (Number.isNaN(numYear)) {
9145
+ throw new Error('AuroDatepickerUtilities | yearValueIsValid: Unable to parse year value integer');
9146
+ }
9147
+
9148
+ // Guard clause: ensure year is within the valid range
9149
+ if (numYear < this.minYear || numYear > this.maxYear) {
9150
+ return false;
9151
+ }
9152
+
9153
+ // Default return
9154
+ return true;
9155
+ };
9156
+
9157
+ // Self-contained checks for month, day, and year
9158
+ const checks = [
9159
+ monthValueIsValid(dateParts.month),
9160
+ dayValueIsValid(dateParts.day),
9161
+ yearIsValid(dateParts.year)
9162
+ ];
9163
+
9164
+ // If any of the checks failed, the date format does not match and the result is invalid
9165
+ const isValid = checks.every((check) => check === true);
9166
+
9167
+ // If the check is invalid, return false
9168
+ if (!isValid) {
9169
+ return false;
9170
+ }
9171
+
9172
+ // Default case
9173
+ return true;
9174
+ };
9175
+ }
9176
+ }
9177
+
9178
+ // Export a class instance
9179
+ const dateUtilities = new AuroDateUtilities();
9180
+
9181
+ // Export the class instance methods individually
9182
+ const {
9183
+ datesMatch,
9184
+ validDateStr,
9185
+ dateAndFormatMatch,
9186
+ minDay,
9187
+ minMonth,
9188
+ minYear,
9189
+ maxDay,
9190
+ maxMonth,
9191
+ maxYear
9192
+ } = dateUtilities;
9193
+
9194
+ const {
9195
+ toNorthAmericanFormat,
9196
+ parseDate,
9197
+ getDateAsString
9198
+ } = dateFormatter;
9199
+
8267
9200
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
8268
9201
  // See LICENSE in the project root for license information.
8269
9202
 
@@ -8339,6 +9272,7 @@ let AuroLibraryRuntimeUtils$1$1 = class AuroLibraryRuntimeUtils {
8339
9272
 
8340
9273
 
8341
9274
  class AuroFormValidation {
9275
+
8342
9276
  constructor() {
8343
9277
  this.runtimeUtils = new AuroLibraryRuntimeUtils$1$1();
8344
9278
  }
@@ -8430,17 +9364,17 @@ class AuroFormValidation {
8430
9364
  ]
8431
9365
  }
8432
9366
  };
8433
-
9367
+
8434
9368
  let elementType;
8435
9369
  if (this.runtimeUtils.elementMatch(elem, 'auro-input')) {
8436
9370
  elementType = 'input';
8437
9371
  } else if (this.runtimeUtils.elementMatch(elem, 'auro-counter') || this.runtimeUtils.elementMatch(elem, 'auro-counter-group')) {
8438
9372
  elementType = 'counter';
8439
9373
  }
8440
-
9374
+
8441
9375
  if (elementType) {
8442
9376
  const rules = validationRules[elementType];
8443
-
9377
+
8444
9378
  if (rules) {
8445
9379
  Object.values(rules).flat().forEach(rule => {
8446
9380
  if (rule.check(elem)) {
@@ -8466,48 +9400,82 @@ class AuroFormValidation {
8466
9400
  if (!elem.value.match(emailRegex)) {
8467
9401
  elem.validity = 'patternMismatch';
8468
9402
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
9403
+ return;
8469
9404
  }
8470
9405
  } else if (elem.type === 'credit-card') {
8471
9406
  if (elem.value.length > 0 && elem.value.length < elem.validationCCLength) {
8472
9407
  elem.validity = 'tooShort';
8473
9408
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
9409
+ return;
8474
9410
  }
8475
9411
  } else if (elem.type === 'number') {
8476
9412
  if (elem.max !== undefined && Number(elem.max) < Number(elem.value)) {
8477
9413
  elem.validity = 'rangeOverflow';
8478
9414
  elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
9415
+ return;
8479
9416
  }
8480
9417
 
8481
9418
  if (elem.min !== undefined && elem.value?.length > 0 && Number(elem.min) > Number(elem.value)) {
8482
9419
  elem.validity = 'rangeUnderflow';
8483
9420
  elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
9421
+ return;
8484
9422
  }
8485
- } else if (elem.type === 'date') {
8486
- if (elem.value?.length > 0 && elem.value?.length < elem.lengthForType) {
9423
+ } else if (elem.type === 'date' && elem.value?.length > 0) {
9424
+
9425
+ // Guard Clause: if the value is too short
9426
+ if (elem.value.length < elem.lengthForType) {
9427
+
8487
9428
  elem.validity = 'tooShort';
8488
9429
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
8489
- } else if (elem.value?.length === elem.lengthForType && elem.util.toNorthAmericanFormat(elem.value, elem.format)) {
8490
- const formattedValue = elem.util.toNorthAmericanFormat(elem.value, elem.format);
8491
- const valueDate = new Date(formattedValue.dateForComparison);
9430
+ return;
9431
+ }
9432
+
9433
+ // Guard Clause: If the value is too long for the type
9434
+ if (elem.value?.length > elem.lengthForType) {
9435
+
9436
+ elem.validity = 'tooLong';
9437
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
9438
+ return;
9439
+ }
9440
+
9441
+ // Validate that the date passed was the correct format
9442
+ if (!dateAndFormatMatch(elem.value, elem.format)) {
9443
+ elem.validity = 'patternMismatch';
9444
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || 'Invalid Date Format Entered';
9445
+ return;
9446
+ }
9447
+
9448
+ // Validate that the date passed was a valid date
9449
+ if (!validDateStr(elem.value, elem.format)) {
9450
+ elem.validity = 'invalidDate';
9451
+ elem.errorMessage = elem.setCustomValidityInvalidDate || elem.setCustomValidity || 'Invalid Date Entered';
9452
+ return;
9453
+ }
8492
9454
 
8493
- // validate max
8494
- if (elem.max?.length === elem.lengthForType) {
8495
- const maxDate = new Date(elem.util.toNorthAmericanFormat(elem.max, elem.format).dateForComparison);
9455
+ // Perform the rest of the validation
9456
+ const formattedValue = toNorthAmericanFormat(elem.value, elem.format);
9457
+ const valueDate = new Date(formattedValue);
8496
9458
 
8497
- if (valueDate > maxDate) {
8498
- elem.validity = 'rangeOverflow';
8499
- elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
8500
- }
9459
+ // // Validate max date
9460
+ if (elem.max?.length === elem.lengthForType) {
9461
+
9462
+ const maxDate = new Date(toNorthAmericanFormat(elem.max, elem.format));
9463
+
9464
+ if (valueDate > maxDate) {
9465
+ elem.validity = 'rangeOverflow';
9466
+ elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
9467
+ return;
8501
9468
  }
9469
+ }
8502
9470
 
8503
- // validate min
8504
- if (elem.min?.length === elem.lengthForType) {
8505
- const minDate = new Date(elem.util.toNorthAmericanFormat(elem.min, elem.format).dateForComparison);
9471
+ // Validate min date
9472
+ if (elem.min?.length === elem.lengthForType) {
9473
+ const minDate = new Date(toNorthAmericanFormat(elem.min, elem.format));
8506
9474
 
8507
- if (valueDate < minDate) {
8508
- elem.validity = 'rangeUnderflow';
8509
- elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
8510
- }
9475
+ if (valueDate < minDate) {
9476
+ elem.validity = 'rangeUnderflow';
9477
+ elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
9478
+ return;
8511
9479
  }
8512
9480
  }
8513
9481
  }
@@ -8626,7 +9594,7 @@ class AuroFormValidation {
8626
9594
  if (input.validationMessage.length > 0) {
8627
9595
  elem.errorMessage = input.validationMessage;
8628
9596
  }
8629
- } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
9597
+ } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
8630
9598
  const firstInput = this.inputElements[0];
8631
9599
 
8632
9600
  if (firstInput.validationMessage.length > 0) {
@@ -8748,6 +9716,33 @@ class BaseInput extends r$1 {
8748
9716
  static get properties() {
8749
9717
  return {
8750
9718
 
9719
+ /**
9720
+ * The value for the role attribute.
9721
+ */
9722
+ a11yRole: {
9723
+ type: String,
9724
+ attribute: true,
9725
+ reflect: true
9726
+ },
9727
+
9728
+ /**
9729
+ * The value for the aria-expanded attribute.
9730
+ */
9731
+ a11yExpanded: {
9732
+ type: Boolean,
9733
+ attribute: true,
9734
+ reflect: true
9735
+ },
9736
+
9737
+ /**
9738
+ * The value for the aria-controls attribute.
9739
+ */
9740
+ a11yControls: {
9741
+ type: String,
9742
+ attribute: true,
9743
+ reflect: true
9744
+ },
9745
+
8751
9746
  /**
8752
9747
  * If set, the label will remain fixed in the active position.
8753
9748
  */
@@ -9389,6 +10384,10 @@ class BaseInput extends r$1 {
9389
10384
  } else if (this.type === 'number') {
9390
10385
  this.inputMode = 'numeric';
9391
10386
  }
10387
+
10388
+ if (this.type === "date" && !this.format) {
10389
+ this.format = 'mm/dd/yyyy';
10390
+ }
9392
10391
  }
9393
10392
 
9394
10393
  /**
@@ -10632,6 +11631,7 @@ var helpTextVersion = '1.0.0';
10632
11631
 
10633
11632
  // build the component class
10634
11633
  class AuroInput extends BaseInput {
11634
+
10635
11635
  constructor() {
10636
11636
  super();
10637
11637
 
@@ -10744,7 +11744,7 @@ class AuroInput extends BaseInput {
10744
11744
  ?required="${this.required}"
10745
11745
  ?disabled="${this.disabled}"
10746
11746
  aria-describedby="${this.uniqueId}"
10747
- aria-invalid="${this.validity !== 'valid'}"
11747
+ ?aria-invalid="${this.validity !== 'valid'}"
10748
11748
  placeholder=${this.getPlaceholder()}
10749
11749
  lang="${o(this.lang)}"
10750
11750
  ?activeLabel="${this.activeLabel}"
@@ -10753,7 +11753,10 @@ class AuroInput extends BaseInput {
10753
11753
  autocapitalize="${o(this.autocapitalize ? this.autocapitalize : undefined)}"
10754
11754
  autocomplete="${o(this.autocomplete ? this.autocomplete : undefined)}"
10755
11755
  part="input"
10756
- />
11756
+ role="${o(this.a11yRole)}"
11757
+ aria-expanded="${o(this.a11yExpanded)}"
11758
+ aria-controls="${o(this.a11yControls)}"
11759
+ />
10757
11760
  </div>
10758
11761
  <div
10759
11762
  class="notificationIcons"
@@ -11745,6 +12748,7 @@ var styleCss$3 = i$5`.util_displayInline{display:inline}.util_displayInlineBlock
11745
12748
 
11746
12749
  // build the component class
11747
12750
  class AuroCombobox extends r$1 {
12751
+
11748
12752
  constructor() {
11749
12753
  super();
11750
12754
 
@@ -11756,6 +12760,8 @@ class AuroCombobox extends r$1 {
11756
12760
  * @returns {void} Internal defaults.
11757
12761
  */
11758
12762
  privateDefaults() {
12763
+ this.dropdownOpen = false;
12764
+ this.dropdownId = undefined;
11759
12765
  this.onDark = false;
11760
12766
 
11761
12767
  this.noFilter = false;
@@ -11835,6 +12841,26 @@ class AuroCombobox extends r$1 {
11835
12841
  reflect: true
11836
12842
  },
11837
12843
 
12844
+ /**
12845
+ * ID for the dropdown
12846
+ * @private
12847
+ */
12848
+ dropdownId: {
12849
+ type: String,
12850
+ reflect: false,
12851
+ attribute: false
12852
+ },
12853
+
12854
+ /**
12855
+ * Whether or not the dropdown is open
12856
+ * @private
12857
+ */
12858
+ dropdownOpen: {
12859
+ type: Boolean,
12860
+ reflect: false,
12861
+ attribute: false
12862
+ },
12863
+
11838
12864
  /**
11839
12865
  * When defined, sets persistent validity to `customError` and sets the validation message to the attribute value.
11840
12866
  */
@@ -11996,8 +13022,19 @@ class AuroCombobox extends r$1 {
11996
13022
  * @private
11997
13023
  */
11998
13024
  isDropdownFullscreen: {
11999
- type: Boolean
12000
- }
13025
+ type: Boolean,
13026
+ reflect: false
13027
+ },
13028
+
13029
+ /**
13030
+ * @private
13031
+ * specifies the currently active option
13032
+ */
13033
+ optionActive: {
13034
+ type: Object,
13035
+ reflect: false,
13036
+ attribute: false
13037
+ },
12001
13038
  };
12002
13039
  }
12003
13040
 
@@ -12149,6 +13186,18 @@ class AuroCombobox extends r$1 {
12149
13186
  * @returns {void}
12150
13187
  */
12151
13188
  configureDropdown() {
13189
+
13190
+ // Listen for the ID to be added to the dropdown so we can capture it and use it for accessibility.
13191
+ this.dropdown.addEventListener('auroDropdown-idAdded', (event) => {
13192
+ this.dropdownId = event.detail.id;
13193
+ });
13194
+
13195
+ // Listen for the dropdown to be shown or hidden
13196
+ this.dropdown.addEventListener("auroDropdown-toggled", (ev) => {
13197
+ this.dropdownOpen = ev.detail.expanded;
13198
+ });
13199
+
13200
+ // this.dropdown.addEventListener('auroDropdown-show', () => {
12152
13201
  this.menuWrapper = this.dropdown.querySelector('.menuWrapper');
12153
13202
  this.menuWrapper.append(this.menu);
12154
13203
 
@@ -12162,7 +13211,6 @@ class AuroCombobox extends r$1 {
12162
13211
  this.hideBib = this.hideBib.bind(this);
12163
13212
  this.bibtemplate.addEventListener('close-click', this.hideBib);
12164
13213
 
12165
- this.dropdown.setAttribute('role', 'combobox');
12166
13214
  this.dropdown.addEventListener('auroDropdown-triggerClick', () => {
12167
13215
  this.showBib();
12168
13216
  });
@@ -12178,7 +13226,6 @@ class AuroCombobox extends r$1 {
12178
13226
  this.isDropdownFullscreen = event.detail.strategy === 'fullscreen';
12179
13227
  setTimeout(this.transportInput);
12180
13228
  });
12181
-
12182
13229
  }
12183
13230
 
12184
13231
  /**
@@ -12672,6 +13719,10 @@ class AuroCombobox extends r$1 {
12672
13719
  ?noFlip="${this.noFlip}"
12673
13720
  disableEventShow>
12674
13721
  <${this.inputTag}
13722
+ .a11yRole="${"combobox"}"
13723
+ .a11yExpanded="${this.dropdownOpen}"
13724
+ .a11yControls="${this.dropdownId}"
13725
+ id="${this.id || 'auro-combobox-input'}"
12675
13726
  slot="trigger"
12676
13727
  bordered
12677
13728
  ?onDark="${this.onDark}"