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

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 (49) hide show
  1. package/CHANGELOG.md +9 -3
  2. package/components/checkbox/demo/api.min.js +468 -25
  3. package/components/checkbox/demo/index.min.js +468 -25
  4. package/components/checkbox/dist/index.js +468 -25
  5. package/components/checkbox/dist/registered.js +468 -25
  6. package/components/combobox/demo/api.md +1 -1
  7. package/components/combobox/demo/api.min.js +1265 -235
  8. package/components/combobox/demo/index.min.js +1265 -235
  9. package/components/combobox/dist/auro-combobox.d.ts +32 -5
  10. package/components/combobox/dist/index.js +1130 -100
  11. package/components/combobox/dist/registered.js +1130 -100
  12. package/components/counter/demo/api.md +1 -1
  13. package/components/counter/demo/api.min.js +575 -71
  14. package/components/counter/demo/index.min.js +575 -71
  15. package/components/counter/dist/auro-counter-group.d.ts +2 -5
  16. package/components/counter/dist/index.js +575 -71
  17. package/components/counter/dist/registered.js +575 -71
  18. package/components/datepicker/demo/api.md +0 -1
  19. package/components/datepicker/demo/api.min.js +1077 -106
  20. package/components/datepicker/demo/index.min.js +1077 -106
  21. package/components/datepicker/dist/auro-datepicker.d.ts +0 -13
  22. package/components/datepicker/dist/index.js +1077 -106
  23. package/components/datepicker/dist/registered.js +1077 -106
  24. package/components/dropdown/demo/api.md +9 -6
  25. package/components/dropdown/demo/api.min.js +107 -43
  26. package/components/dropdown/demo/index.md +0 -83
  27. package/components/dropdown/demo/index.min.js +107 -43
  28. package/components/dropdown/dist/auro-dropdown.d.ts +30 -12
  29. package/components/dropdown/dist/index.js +107 -43
  30. package/components/dropdown/dist/registered.js +107 -43
  31. package/components/input/demo/api.md +4 -1
  32. package/components/input/demo/api.min.js +503 -25
  33. package/components/input/demo/index.min.js +503 -25
  34. package/components/input/dist/base-input.d.ts +24 -0
  35. package/components/input/dist/index.js +503 -25
  36. package/components/input/dist/registered.js +503 -25
  37. package/components/radio/demo/api.min.js +468 -25
  38. package/components/radio/demo/index.min.js +468 -25
  39. package/components/radio/dist/index.js +468 -25
  40. package/components/radio/dist/registered.js +468 -25
  41. package/components/select/demo/api.md +1 -1
  42. package/components/select/demo/api.min.js +575 -71
  43. package/components/select/demo/index.md +1 -46
  44. package/components/select/demo/index.min.js +575 -71
  45. package/components/select/dist/auro-select.d.ts +2 -5
  46. package/components/select/dist/index.js +575 -71
  47. package/components/select/dist/registered.js +575 -71
  48. package/package.json +2 -2
  49. package/components/form/demo/autocomplete.html +0 -15
@@ -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);
@@ -3214,7 +3657,6 @@ var tokensCss$1$2 = i$5`:host{--ds-auro-dropdown-label-text-color: var(--ds-basi
3214
3657
 
3215
3658
  const DESIGN_TOKEN_BREAKPOINT_PREFIX = '--ds-grid-breakpoint-';
3216
3659
  const DESIGN_TOKEN_BREAKPOINT_OPTIONS = [
3217
- 'xl',
3218
3660
  'lg',
3219
3661
  'md',
3220
3662
  'sm',
@@ -3286,7 +3728,6 @@ class AuroDropdownBib extends r$1 {
3286
3728
 
3287
3729
  set mobileFullscreenBreakpoint(value) {
3288
3730
  // verify the defined breakpoint is valid and exit out if not
3289
- // 'disabled' is a design token breakpoint so it acts as our "undefined" value
3290
3731
  const validatedValue = DESIGN_TOKEN_BREAKPOINT_OPTIONS.includes(value) ? value : undefined;
3291
3732
  if (!validatedValue) {
3292
3733
  this._mobileBreakpointValue = undefined;
@@ -3555,6 +3996,7 @@ var helpTextVersion$1 = '1.0.0';
3555
3996
  * @csspart helpText - The helpText content container.
3556
3997
  * @event auroDropdown-triggerClick - Notifies that the trigger has been clicked.
3557
3998
  * @event auroDropdown-toggled - Notifies that the visibility of the dropdown bib has changed.
3999
+ * @event auroDropdown-idAdded - Notifies consumers that the unique ID for the dropdown bib has been generated.
3558
4000
  */
3559
4001
  class AuroDropdown extends r$1 {
3560
4002
  constructor() {
@@ -3600,7 +4042,9 @@ class AuroDropdown extends r$1 {
3600
4042
  this.rounded = false;
3601
4043
  this.tabIndex = 0;
3602
4044
  this.noToggle = false;
4045
+ this.a11yAutocomplete = 'none';
3603
4046
  this.labeled = true;
4047
+ this.a11yRole = 'combobox';
3604
4048
  this.onDark = false;
3605
4049
 
3606
4050
  // floaterConfig
@@ -3736,6 +4180,16 @@ class AuroDropdown extends r$1 {
3736
4180
  type: Number
3737
4181
  },
3738
4182
 
4183
+ /**
4184
+ * The unique ID for the dropdown bib element.
4185
+ * @private
4186
+ */
4187
+ dropdownId: {
4188
+ type: String,
4189
+ reflect: false,
4190
+ attribute: false
4191
+ },
4192
+
3739
4193
  /**
3740
4194
  * If declared in combination with `bordered` property or `helpText` slot content, will apply red color to both.
3741
4195
  */
@@ -3799,12 +4253,7 @@ class AuroDropdown extends r$1 {
3799
4253
  },
3800
4254
 
3801
4255
  /**
3802
- * Defines the screen size breakpoint (`xs`, `sm`, `md`, `lg`, `xl`, `disabled`)
3803
- * at which the dropdown switches to fullscreen mode on mobile. `disabled` indicates a dropdown should _never_ enter fullscreen.
3804
- *
3805
- * When expanded, the dropdown will automatically display in fullscreen mode
3806
- * if the screen size is equal to or smaller than the selected breakpoint.
3807
- * @default sm
4256
+ * Defines the screen size breakpoint (`lg`, `md`, `sm`, or `xs`) at which the dropdown switches to fullscreen mode on mobile. When expanded, the dropdown will automatically display in fullscreen mode if the screen size is equal to or smaller than the selected breakpoint.
3808
4257
  */
3809
4258
  fullscreenBreakpoint: {
3810
4259
  type: String,
@@ -3903,6 +4352,23 @@ class AuroDropdown extends r$1 {
3903
4352
  */
3904
4353
  tabIndex: {
3905
4354
  type: Number
4355
+ },
4356
+
4357
+ /**
4358
+ * The value for the role attribute of the trigger element.
4359
+ */
4360
+ a11yRole: {
4361
+ type: String || undefined,
4362
+ attribute: false,
4363
+ reflect: false
4364
+ },
4365
+
4366
+ /**
4367
+ * The value for the aria-autocomplete attribute of the trigger element.
4368
+ */
4369
+ a11yAutocomplete: {
4370
+ type: String,
4371
+ attribute: false,
3906
4372
  }
3907
4373
  };
3908
4374
  }
@@ -3927,15 +4393,6 @@ class AuroDropdown extends r$1 {
3927
4393
  AuroLibraryRuntimeUtils$1$2.prototype.registerComponent(name, AuroDropdown);
3928
4394
  }
3929
4395
 
3930
- /**
3931
- * Accessor for reusing the focusable entity query string.
3932
- * @private
3933
- * @returns {string}
3934
- */
3935
- get focusableEntityQuery () {
3936
- return 'auro-input, [auro-input], auro-button, [auro-button], button, input';
3937
- }
3938
-
3939
4396
  connectedCallback() {
3940
4397
  super.connectedCallback();
3941
4398
  }
@@ -3949,8 +4406,6 @@ class AuroDropdown extends r$1 {
3949
4406
  updated(changedProperties) {
3950
4407
  this.floater.handleUpdate(changedProperties);
3951
4408
 
3952
- // Note: `disabled` is not a breakpoint (it is not a screen size),
3953
- // so it looks like we never consume this - however, dropdownBib handles this in the setter as "undefined"
3954
4409
  if (changedProperties.has('fullscreenBreakpoint')) {
3955
4410
  this.bibContent.mobileFullscreenBreakpoint = this.fullscreenBreakpoint;
3956
4411
  }
@@ -3964,7 +4419,22 @@ class AuroDropdown extends r$1 {
3964
4419
  }
3965
4420
 
3966
4421
  firstUpdated() {
4422
+
4423
+ // Configure the floater to, this will generate the ID for the bib
3967
4424
  this.floater.configure(this, 'auroDropdown');
4425
+
4426
+ /**
4427
+ * @description Let subscribers know that the dropdown ID ha been generated and added.
4428
+ * @event auroDropdown-idAdded
4429
+ * @type {Object<key: 'id', value: string>} - The ID of the dropdown bib element.
4430
+ */
4431
+ this.dispatchEvent(new CustomEvent('auroDropdown-idAdded', {detail: {id: this.floater.element.id}}));
4432
+
4433
+ // Set the bib ID locally if the user hasn't provided a focusable trigger
4434
+ if (!this.triggerContentFocusable) {
4435
+ this.dropdownId = this.floater.element.id;
4436
+ }
4437
+
3968
4438
  this.bibContent = this.floater.element.bib;
3969
4439
 
3970
4440
  // Add the tag name as an attribute if it is different than the component name
@@ -4086,7 +4556,7 @@ class AuroDropdown extends r$1 {
4086
4556
 
4087
4557
  this.triggerContentSlot.forEach((node) => {
4088
4558
  if (node.querySelectorAll) {
4089
- const auroElements = node.querySelectorAll(this.focusableEntityQuery);
4559
+ const auroElements = node.querySelectorAll('auro-input, [auro-input], auro-button, [auro-button], button, input');
4090
4560
  auroElements.forEach((auroEl) => {
4091
4561
  auroEl.addEventListener('focus', this.bindFocusEventToTrigger);
4092
4562
  auroEl.addEventListener('blur', this.bindFocusEventToTrigger);
@@ -4107,7 +4577,7 @@ class AuroDropdown extends r$1 {
4107
4577
 
4108
4578
  this.triggerContentSlot.forEach((node) => {
4109
4579
  if (node.querySelectorAll) {
4110
- const auroElements = node.querySelectorAll(this.focusableEntityQuery);
4580
+ const auroElements = node.querySelectorAll('auro-input, [auro-input], auro-button, [auro-button], button, input');
4111
4581
  auroElements.forEach((auroEl) => {
4112
4582
  auroEl.removeEventListener('focus', this.bindFocusEventToTrigger);
4113
4583
  auroEl.removeEventListener('blur', this.bindFocusEventToTrigger);
@@ -4116,6 +4586,30 @@ class AuroDropdown extends r$1 {
4116
4586
  });
4117
4587
  }
4118
4588
 
4589
+ /*
4590
+ * Sets aria attributes for the trigger element if a custom one is passed in.
4591
+ * @private
4592
+ * @method setTriggerAriaAttributes
4593
+ * @param { HTMLElement } triggerElement - The custom trigger element.
4594
+ */
4595
+ clearTriggerA11yAttributes(triggerElement) {
4596
+
4597
+ if (!triggerElement || !triggerElement.removeAttribute) {
4598
+ return;
4599
+ }
4600
+
4601
+ // Reset appropriate attributes for a11y
4602
+ triggerElement.removeAttribute('aria-labelledby');
4603
+ if (triggerElement.getAttribute('id') === `${this.id}-trigger-element`) {
4604
+ triggerElement.removeAttribute('id');
4605
+ }
4606
+ triggerElement.removeAttribute('role');
4607
+ triggerElement.removeAttribute('aria-expanded');
4608
+
4609
+ triggerElement.removeAttribute('aria-controls');
4610
+ triggerElement.removeAttribute('aria-autocomplete');
4611
+ }
4612
+
4119
4613
  /**
4120
4614
  * Handles changes to the trigger content slot and updates related properties.
4121
4615
  *
@@ -4129,32 +4623,41 @@ class AuroDropdown extends r$1 {
4129
4623
  * @returns {void}
4130
4624
  */
4131
4625
  handleTriggerContentSlotChange(event) {
4626
+
4132
4627
  this.floater.handleTriggerTabIndex();
4133
4628
 
4629
+ // Get the trigger
4630
+ const trigger = this.shadowRoot.querySelector('#trigger');
4631
+
4632
+ // Get the trigger slot
4134
4633
  const triggerSlot = this.shadowRoot.querySelector('.triggerContent slot');
4135
4634
 
4635
+ // If there's a trigger slot
4136
4636
  if (triggerSlot) {
4137
4637
 
4638
+ // Get the content nodes to see if there are any children
4138
4639
  const triggerContentNodes = triggerSlot.assignedNodes();
4139
4640
 
4641
+ // If there are children
4140
4642
  if (triggerContentNodes) {
4141
4643
 
4142
- triggerContentNodes.forEach((node) => {
4143
- if (!this.triggerContentFocusable) {
4144
- this.triggerContentFocusable = this.containsFocusableElement(node);
4145
- }
4146
- });
4147
- }
4148
- }
4644
+ // See if any of them are focusable elemeents
4645
+ this.triggerContentFocusable = triggerContentNodes.some((node) => this.containsFocusableElement(node));
4149
4646
 
4150
- const trigger = this.shadowRoot.querySelector('#trigger');
4647
+ // If any of them are focusable elements
4648
+ if (this.triggerContentFocusable) {
4151
4649
 
4152
- if (!this.triggerContentFocusable) {
4153
- trigger.setAttribute('tabindex', '0');
4154
- trigger.setAttribute('role', 'button');
4155
- } else {
4156
- trigger.removeAttribute('tabindex');
4157
- trigger.removeAttribute('role');
4650
+ // Assume the consumer will be providing their own a11y in whatever they passed in
4651
+ this.clearTriggerA11yAttributes(trigger);
4652
+
4653
+ // Remove the tabindex from the trigger so it doesn't interrupt focus flow
4654
+ trigger.removeAttribute('tabindex');
4655
+ } else {
4656
+
4657
+ // Add the tabindex to the trigger so that it's in the focus flow
4658
+ trigger.setAttribute('tabindex', '0');
4659
+ }
4660
+ }
4158
4661
  }
4159
4662
 
4160
4663
  if (event) {
@@ -4164,6 +4667,7 @@ class AuroDropdown extends r$1 {
4164
4667
 
4165
4668
  if (this.triggerContentSlot) {
4166
4669
  this.setupTriggerFocusEventBinding();
4670
+
4167
4671
  this.hasTriggerContent = this.triggerContentSlot.some((slot) => {
4168
4672
  if (slot.textContent.trim()) {
4169
4673
  return true;
@@ -4231,10 +4735,13 @@ class AuroDropdown extends r$1 {
4231
4735
  id="trigger"
4232
4736
  class="trigger"
4233
4737
  part="trigger"
4234
- aria-labelledby="triggerLabel"
4235
4738
  tabindex="${this.tabIndex}"
4236
4739
  ?showBorder="${this.showTriggerBorders}"
4237
- >
4740
+ role="${o(this.triggerContentFocusable ? undefined : this.a11yRole)}"
4741
+ aria-expanded="${o(this.triggerContentFocusable ? undefined : this.isPopoverVisible)}"
4742
+ aria-controls="${o(this.triggerContentFocusable ? undefined : this.dropdownId)}"
4743
+ aria-labelledby="${o(this.triggerContentFocusable ? undefined : 'triggerLabel')}"
4744
+ >
4238
4745
  <div class="triggerContentWrapper">
4239
4746
  <label class="label" id="triggerLabel" hasTrigger=${this.hasTriggerContent}>
4240
4747
  <slot name="label" @slotchange="${this.handleLabelSlotChange}"></slot>
@@ -4268,12 +4775,12 @@ class AuroDropdown extends r$1 {
4268
4775
  <div id="bibSizer" part="size"></div>
4269
4776
  <${this.dropdownBibTag}
4270
4777
  id="bib"
4271
- role="tooltip"
4272
4778
  ?data-show="${this.isPopoverVisible}"
4273
4779
  ?isfullscreen="${this.isBibFullscreen}"
4274
4780
  ?common="${this.common}"
4275
4781
  ?rounded="${this.common || this.rounded}"
4276
- ?inset="${this.common || this.inset}">
4782
+ ?inset="${this.common || this.inset}"
4783
+ >
4277
4784
  </${this.dropdownBibTag}>
4278
4785
  </div>
4279
4786
  `;
@@ -8095,175 +8602,583 @@ class AuroInputUtilities {
8095
8602
  blocks.dd = { mask: IMask.MaskedRange, from: 1, to: 31 };
8096
8603
  }
8097
8604
 
8098
- return {
8099
- mask: Date,
8100
- pattern: dateFormat,
8101
- blocks,
8102
- format(date) {
8103
- if (!date) {
8104
- return '';
8105
- }
8605
+ return {
8606
+ mask: Date,
8607
+ pattern: dateFormat,
8608
+ blocks,
8609
+ format(date) {
8610
+ if (!date) {
8611
+ return '';
8612
+ }
8613
+
8614
+ const day = date.getDate()
8615
+ .toString()
8616
+ .padStart(2, '0');
8617
+ const month = (date.getMonth() + 1)
8618
+ .toString()
8619
+ .padStart(2, '0');
8620
+ const year = date
8621
+ .getFullYear()
8622
+ .toString();
8623
+ const shortYear = year.slice(-2);
8624
+
8625
+ let formattedDate = this.mask;
8626
+
8627
+ if (formattedDate.includes('dd')) {
8628
+ formattedDate = formattedDate.replace('dd', day);
8629
+ }
8630
+
8631
+ if (formattedDate.includes('mm')) {
8632
+ formattedDate = formattedDate.replace('mm', month);
8633
+ }
8634
+
8635
+ if (formattedDate.includes('yyyy')) {
8636
+ formattedDate = formattedDate.replace('yyyy', year);
8637
+ }
8638
+
8639
+ if (formattedDate.includes('yy')) {
8640
+ formattedDate = formattedDate.replace('yy', shortYear);
8641
+ }
8642
+
8643
+ return formattedDate;
8644
+ },
8645
+ parse(str) {
8646
+ if (!str) {
8647
+ return null;
8648
+ }
8649
+
8650
+ const parts = str.split('/');
8651
+ const formatParts = this.mask.split('/');
8652
+
8653
+ let day = 1, month, year = new Date().getFullYear();
8654
+
8655
+ formatParts.forEach((part, index) => {
8656
+ if (part === 'dd') {
8657
+ day = parseInt(parts[index]) || 1;
8658
+ }
8659
+
8660
+ if (part === 'mm') {
8661
+ month = parseInt(parts[index]) - 1;
8662
+ }
8663
+
8664
+ if (part === 'yyyy') {
8665
+ year = parseInt(parts[index]);
8666
+ }
8667
+
8668
+ if (part === 'yy') {
8669
+ year = parseInt(parts[index]);
8670
+ year = year <= 25 ? 2000 + year : 1900 + year;
8671
+ }
8672
+ });
8673
+
8674
+ if (isNaN(month) || isNaN(year)) {
8675
+ return null;
8676
+ }
8677
+ return new Date(year, month, day);
8678
+ },
8679
+ lazy: true,
8680
+ placeholderChar: ''
8681
+ };
8682
+ }
8683
+ }
8684
+
8685
+ if (format) {
8686
+ return {
8687
+ mask: format,
8688
+ placeholderChar: '',
8689
+ lazy: true
8690
+ };
8691
+ }
8692
+
8693
+ return {};
8694
+ }
8695
+
8696
+ /**
8697
+ * @private
8698
+ * @param {string} dateStr - Date string to format.
8699
+ * @param {string} format - Date format to use.
8700
+ * @returns {void}
8701
+ */
8702
+ toNorthAmericanFormat(dateStr, format) {
8703
+ const parsedDate = this.parseDate(dateStr, format);
8704
+
8705
+ if (!parsedDate) {
8706
+ return parsedDate;
8707
+ }
8708
+
8709
+ const { month, day, year } = parsedDate;
8710
+ const fullYear = (year && year.length === 2) ? `20${year}` : year;
8711
+ const currentYear = new Date().getFullYear();
8712
+
8713
+ const dateParts = [];
8714
+ if (month) {
8715
+ dateParts.push(month);
8716
+ }
8717
+
8718
+ if (day) {
8719
+ dateParts.push(day);
8720
+ }
8721
+
8722
+ if (year) {
8723
+ dateParts.push(year);
8724
+ }
8725
+
8726
+ const comparisonParts = [
8727
+ month || '01',
8728
+ day || '01',
8729
+ fullYear || currentYear
8730
+ ];
8731
+
8732
+ return {
8733
+ formattedDate: dateParts.join('/'),
8734
+ dateForComparison: comparisonParts.join('/')
8735
+ };
8736
+ }
8737
+
8738
+ /**
8739
+ * @private
8740
+ * @param {string} dateStr - Date string to parse.
8741
+ * @param {string} format - Date format to parse.
8742
+ * @returns {void}
8743
+ */
8744
+ parseDate(dateStr, format) {
8745
+ const dateFormat = format || "mm/dd/yyyy";
8746
+
8747
+ // Define mappings for date components with named capture groups
8748
+ const formatPatterns = {
8749
+ 'yyyy': '(?<year>\\d{4})',
8750
+ 'yy': '(?<year>\\d{2})',
8751
+ 'mm': '(?<month>\\d{2})',
8752
+ 'dd': '(?<day>\\d{2})'
8753
+ };
8754
+
8755
+ // Escape slashes and replace format components with regex patterns
8756
+ let regexPattern = dateFormat.replace(/(?:yyyy|yy|mm|dd)/gu, (match) => formatPatterns[match]);
8757
+ regexPattern = `^${regexPattern}$`;
8758
+
8759
+ const regex = new RegExp(regexPattern, 'u');
8760
+ const match = dateStr.match(regex);
8761
+
8762
+ if (match && match.groups) {
8763
+ return {
8764
+ year: match.groups.year,
8765
+ month: match.groups.month,
8766
+ day: match.groups.day
8767
+ };
8768
+ }
8769
+
8770
+ return undefined;
8771
+ }
8772
+ }
8773
+
8774
+ class DateFormatter {
8775
+
8776
+ constructor() {
8777
+
8778
+ /**
8779
+ * @description Parses a date string into its components.
8780
+ * @param {string} dateStr - Date string to parse.
8781
+ * @param {string} format - Date format to parse.
8782
+ * @returns {Object<key["month" | "day" | "year"]: number>|undefined}
8783
+ */
8784
+ this.parseDate = (dateStr, format = 'mm/dd/yyyy') => {
8785
+
8786
+ // Guard Clause: Date string is defined
8787
+ if (!dateStr) {
8788
+ return undefined;
8789
+ }
8790
+
8791
+ // Assume the separator is a "/" a defined in our code base
8792
+ const separator = '/';
8793
+
8794
+ // Get the parts of the date and format
8795
+ const valueParts = dateStr.split(separator);
8796
+ const formatParts = format.split(separator);
8797
+
8798
+ // Check if the value and format have the correct number of parts
8799
+ if (valueParts.length !== formatParts.length) {
8800
+ throw new Error('AuroDatepickerUtilities | parseDate: Date string and format length do not match');
8801
+ }
8802
+
8803
+ // Holds the result to be returned
8804
+ const result = formatParts.reduce((acc, part, index) => {
8805
+ const value = valueParts[index];
8806
+
8807
+ if ((/m/iu).test(part)) {
8808
+ acc.month = value;
8809
+ } else if ((/d/iu).test(part)) {
8810
+ acc.day = value;
8811
+ } else if ((/y/iu).test(part)) {
8812
+ acc.year = value;
8813
+ }
8814
+
8815
+ return acc;
8816
+ }, {});
8817
+
8818
+ // If we found all the parts, return the result
8819
+ if (result.month && result.year) {
8820
+ return result;
8821
+ }
8822
+
8823
+ // Throw an error to let the dev know we were unable to parse the date string
8824
+ throw new Error('AuroDatepickerUtilities | parseDate: Unable to parse date string');
8825
+ };
8826
+
8827
+ /**
8828
+ * Convert a date object to string format.
8829
+ * @param {Object} date - Date to convert to string.
8830
+ * @returns {Object} Returns the date as a string.
8831
+ */
8832
+ this.getDateAsString = (date) => date.toLocaleDateString(undefined, {
8833
+ year: "numeric",
8834
+ month: "2-digit",
8835
+ day: "2-digit",
8836
+ });
8837
+
8838
+ /**
8839
+ * Converts a date string to a North American date format.
8840
+ * @param {String} dateStr - Date to validate.
8841
+ * @param {String} format - Date format to validate against.
8842
+ * @returns {Boolean}
8843
+ */
8844
+ this.toNorthAmericanFormat = (dateStr, format) => {
8845
+
8846
+ if (format === 'mm/dd/yyyy') {
8847
+ return dateStr;
8848
+ }
8849
+
8850
+ const parsedDate = this.parseDate(dateStr, format);
8851
+
8852
+ if (!parsedDate) {
8853
+ throw new Error('AuroDatepickerUtilities | toNorthAmericanFormat: Unable to parse date string');
8854
+ }
8855
+
8856
+ const { month, day, year } = parsedDate;
8857
+
8858
+ const dateParts = [];
8859
+ if (month) {
8860
+ dateParts.push(month);
8861
+ }
8862
+
8863
+ if (day) {
8864
+ dateParts.push(day);
8865
+ }
8866
+
8867
+ if (year) {
8868
+ dateParts.push(year);
8869
+ }
8870
+
8871
+ return dateParts.join('/');
8872
+ };
8873
+ }
8874
+ }
8875
+ const dateFormatter = new DateFormatter();
8876
+
8877
+ // filepath: dateConstraints.mjs
8878
+ const DATE_UTIL_CONSTRAINTS = {
8879
+ maxDay: 31,
8880
+ maxMonth: 12,
8881
+ maxYear: 2400,
8882
+ minDay: 1,
8883
+ minMonth: 1,
8884
+ minYear: 1900,
8885
+ };
8886
+
8887
+ class AuroDateUtilitiesBase {
8888
+
8889
+ /**
8890
+ * @description The maximum day value allowed by the various utilities in this class.
8891
+ * @readonly
8892
+ * @type {Number}
8893
+ */
8894
+ get maxDay() {
8895
+ return DATE_UTIL_CONSTRAINTS.maxDay;
8896
+ }
8897
+
8898
+ /**
8899
+ * @description The maximum month value allowed by the various utilities in this class.
8900
+ * @readonly
8901
+ * @type {Number}
8902
+ */
8903
+ get maxMonth() {
8904
+ return DATE_UTIL_CONSTRAINTS.maxMonth;
8905
+ }
8906
+
8907
+ /**
8908
+ * @description The maximum year value allowed by the various utilities in this class.
8909
+ * @readonly
8910
+ * @type {Number}
8911
+ */
8912
+ get maxYear() {
8913
+ return DATE_UTIL_CONSTRAINTS.maxYear;
8914
+ }
8915
+
8916
+ /**
8917
+ * @description The minimum day value allowed by the various utilities in this class.
8918
+ * @readonly
8919
+ * @type {Number}
8920
+ */
8921
+ get minDay() {
8922
+ return DATE_UTIL_CONSTRAINTS.minDay;
8923
+ }
8924
+
8925
+ /**
8926
+ * @description The minimum month value allowed by the various utilities in this class.
8927
+ * @readonly
8928
+ * @type {Number}
8929
+ */
8930
+ get minMonth() {
8931
+ return DATE_UTIL_CONSTRAINTS.minMonth;
8932
+ }
8933
+
8934
+ /**
8935
+ * @description The minimum year value allowed by the various utilities in this class.
8936
+ * @readonly
8937
+ * @type {Number}
8938
+ */
8939
+ get minYear() {
8940
+ return DATE_UTIL_CONSTRAINTS.minYear;
8941
+ }
8942
+ }
8943
+
8944
+ /* eslint-disable no-magic-numbers */
8945
+
8946
+ class AuroDateUtilities extends AuroDateUtilitiesBase {
8947
+
8948
+ /**
8949
+ * Returns the current century.
8950
+ * @returns {String} The current century.
8951
+ */
8952
+ getCentury () {
8953
+ return String(new Date().getFullYear()).slice(0, 2);
8954
+ }
8955
+
8956
+ /**
8957
+ * Returns a four digit year.
8958
+ * @param {String} year - The year to convert to four digits.
8959
+ * @returns {String} The four digit year.
8960
+ */
8961
+ getFourDigitYear (year) {
8962
+
8963
+ const strYear = String(year).trim();
8964
+ return strYear.length <= 2 ? this.getCentury() + strYear : strYear;
8965
+ }
8966
+
8967
+ constructor() {
8968
+
8969
+ super();
8970
+
8971
+ /**
8972
+ * Compares two dates to see if they match.
8973
+ * @param {Object} date1 - First date to compare.
8974
+ * @param {Object} date2 - Second date to compare.
8975
+ * @returns {Boolean} Returns true if the dates match.
8976
+ */
8977
+ this.datesMatch = (date1, date2) => new Date(date1).getTime() === new Date(date2).getTime();
8978
+
8979
+ /**
8980
+ * Returns true if value passed in is a valid date.
8981
+ * @param {String} date - Date to validate.
8982
+ * @param {String} format - Date format to validate against.
8983
+ * @returns {Boolean}
8984
+ */
8985
+ this.validDateStr = (date, format) => {
8986
+
8987
+ // The length we expect the date string to be
8988
+ const dateStrLength = format.length;
8989
+
8990
+ // Guard Clause: Date and format are defined
8991
+ if (typeof date === "undefined" || typeof format === "undefined") {
8992
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date and format are required');
8993
+ }
8994
+
8995
+ // Guard Clause: Date should be of type string
8996
+ if (typeof date !== "string") {
8997
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date must be a string');
8998
+ }
8999
+
9000
+ // Guard Clause: Format should be of type string
9001
+ if (typeof format !== "string") {
9002
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Format must be a string');
9003
+ }
9004
+
9005
+ // Guard Clause: Length is what we expect it to be
9006
+ if (date.length !== dateStrLength) {
9007
+ return false;
9008
+ }
9009
+ // Get a formatted date string and parse it
9010
+ const dateParts = dateFormatter.parseDate(date, format);
9011
+
9012
+ // Guard Clause: Date parse succeeded
9013
+ if (!dateParts) {
9014
+ return false;
9015
+ }
8106
9016
 
8107
- const day = date.getDate()
8108
- .toString()
8109
- .padStart(2, '0');
8110
- const month = (date.getMonth() + 1)
8111
- .toString()
8112
- .padStart(2, '0');
8113
- const year = date
8114
- .getFullYear()
8115
- .toString();
8116
- const shortYear = year.slice(-2);
9017
+ // Create the expected date string based on the date parts
9018
+ const expectedDateStr = `${dateParts.month}/${dateParts.day || "01"}/${this.getFourDigitYear(dateParts.year)}`;
8117
9019
 
8118
- let formattedDate = this.mask;
9020
+ // Generate a date object that we will extract a string date from to compare to the passed in date string
9021
+ const dateObj = new Date(this.getFourDigitYear(dateParts.year), dateParts.month - 1, dateParts.day || 1);
8119
9022
 
8120
- if (formattedDate.includes('dd')) {
8121
- formattedDate = formattedDate.replace('dd', day);
8122
- }
9023
+ // Get the date string of the date object we created from the string date
9024
+ const actualDateStr = dateFormatter.getDateAsString(dateObj);
8123
9025
 
8124
- if (formattedDate.includes('mm')) {
8125
- formattedDate = formattedDate.replace('mm', month);
8126
- }
9026
+ // Guard Clause: Generated date matches date string input
9027
+ if (expectedDateStr !== actualDateStr) {
9028
+ return false;
9029
+ }
8127
9030
 
8128
- if (formattedDate.includes('yyyy')) {
8129
- formattedDate = formattedDate.replace('yyyy', year);
8130
- }
9031
+ // If we passed all other checks, we can assume the date is valid
9032
+ return true;
9033
+ };
8131
9034
 
8132
- if (formattedDate.includes('yy')) {
8133
- formattedDate = formattedDate.replace('yy', shortYear);
8134
- }
9035
+ /**
9036
+ * Determines if a string date value matches the format provided.
9037
+ * @param {string} value = The date string value.
9038
+ * @param { string} format = The date format to match against.
9039
+ * @returns {boolean}
9040
+ */
9041
+ this.dateAndFormatMatch = (value, format) => {
8135
9042
 
8136
- return formattedDate;
8137
- },
8138
- parse(str) {
8139
- if (!str) {
8140
- return null;
8141
- }
9043
+ // Ensure we have both values we need to do the comparison
9044
+ if (!value || !format) {
9045
+ throw new Error('AuroFormValidation | dateFormatMatch: value and format are required');
9046
+ }
8142
9047
 
8143
- const parts = str.split('/');
8144
- const formatParts = this.mask.split('/');
9048
+ // If the lengths are different, they cannot match
9049
+ if (value.length !== format.length) {
9050
+ return false;
9051
+ }
8145
9052
 
8146
- let day = 1, month, year = new Date().getFullYear();
9053
+ // Get the parts of the date
9054
+ const dateParts = dateFormatter.parseDate(value, format);
8147
9055
 
8148
- formatParts.forEach((part, index) => {
8149
- if (part === 'dd') {
8150
- day = parseInt(parts[index]) || 1;
8151
- }
9056
+ // Validator for day
9057
+ const dayValueIsValid = (day) => {
8152
9058
 
8153
- if (part === 'mm') {
8154
- month = parseInt(parts[index]) - 1;
8155
- }
9059
+ // Guard clause: if there is no day in the dateParts, we can ignore this check.
9060
+ if (!dateParts.day) {
9061
+ return true;
9062
+ }
8156
9063
 
8157
- if (part === 'yyyy') {
8158
- year = parseInt(parts[index]);
8159
- }
9064
+ // Guard clause: ensure day exists.
9065
+ if (!day) {
9066
+ return false;
9067
+ }
8160
9068
 
8161
- if (part === 'yy') {
8162
- year = parseInt(parts[index]);
8163
- year = year <= 25 ? 2000 + year : 1900 + year;
8164
- }
8165
- });
9069
+ // Convert day to number
9070
+ const numDay = Number.parseInt(day, 10);
8166
9071
 
8167
- if (isNaN(month) || isNaN(year)) {
8168
- return null;
8169
- }
8170
- return new Date(year, month, day);
8171
- },
8172
- lazy: true,
8173
- placeholderChar: ''
8174
- };
8175
- }
8176
- }
9072
+ // Guard clause: ensure day is a valid integer
9073
+ if (Number.isNaN(numDay)) {
9074
+ throw new Error('AuroDatepickerUtilities | dayValueIsValid: Unable to parse day value integer');
9075
+ }
8177
9076
 
8178
- if (format) {
8179
- return {
8180
- mask: format,
8181
- placeholderChar: '',
8182
- lazy: true
8183
- };
8184
- }
9077
+ // Guard clause: ensure day is within the valid range
9078
+ if (numDay < this.minDay || numDay > this.maxDay) {
9079
+ return false;
9080
+ }
8185
9081
 
8186
- return {};
8187
- }
9082
+ // Default return
9083
+ return true;
9084
+ };
8188
9085
 
8189
- /**
8190
- * @private
8191
- * @param {string} dateStr - Date string to format.
8192
- * @param {string} format - Date format to use.
8193
- * @returns {void}
8194
- */
8195
- toNorthAmericanFormat(dateStr, format) {
8196
- const parsedDate = this.parseDate(dateStr, format);
9086
+ // Validator for month
9087
+ const monthValueIsValid = (month) => {
8197
9088
 
8198
- if (!parsedDate) {
8199
- return parsedDate;
8200
- }
9089
+ // Guard clause: ensure month exists.
9090
+ if (!month) {
9091
+ return false;
9092
+ }
8201
9093
 
8202
- const { month, day, year } = parsedDate;
8203
- const fullYear = (year && year.length === 2) ? `20${year}` : year;
8204
- const currentYear = new Date().getFullYear();
9094
+ // Convert month to number
9095
+ const numMonth = Number.parseInt(month, 10);
8205
9096
 
8206
- const dateParts = [];
8207
- if (month) {
8208
- dateParts.push(month);
8209
- }
9097
+ // Guard clause: ensure month is a valid integer
9098
+ if (Number.isNaN(numMonth)) {
9099
+ throw new Error('AuroDatepickerUtilities | monthValueIsValid: Unable to parse month value integer');
9100
+ }
8210
9101
 
8211
- if (day) {
8212
- dateParts.push(day);
8213
- }
9102
+ // Guard clause: ensure month is within the valid range
9103
+ if (numMonth < this.minMonth || numMonth > this.maxMonth) {
9104
+ return false;
9105
+ }
8214
9106
 
8215
- if (year) {
8216
- dateParts.push(year);
8217
- }
9107
+ // Default return
9108
+ return true;
9109
+ };
8218
9110
 
8219
- const comparisonParts = [
8220
- month || '01',
8221
- day || '01',
8222
- fullYear || currentYear
8223
- ];
9111
+ // Validator for year
9112
+ const yearIsValid = (_year) => {
8224
9113
 
8225
- return {
8226
- formattedDate: dateParts.join('/'),
8227
- dateForComparison: comparisonParts.join('/')
8228
- };
8229
- }
9114
+ // Guard clause: ensure year exists.
9115
+ if (!_year) {
9116
+ return false;
9117
+ }
8230
9118
 
8231
- /**
8232
- * @private
8233
- * @param {string} dateStr - Date string to parse.
8234
- * @param {string} format - Date format to parse.
8235
- * @returns {void}
8236
- */
8237
- parseDate(dateStr, format) {
8238
- const dateFormat = format || "mm/dd/yyyy";
9119
+ // Get the full year
9120
+ const year = this.getFourDigitYear(_year);
8239
9121
 
8240
- // Define mappings for date components with named capture groups
8241
- const formatPatterns = {
8242
- 'yyyy': '(?<year>\\d{4})',
8243
- 'yy': '(?<year>\\d{2})',
8244
- 'mm': '(?<month>\\d{2})',
8245
- 'dd': '(?<day>\\d{2})'
8246
- };
9122
+ // Convert year to number
9123
+ const numYear = Number.parseInt(year, 10);
8247
9124
 
8248
- // Escape slashes and replace format components with regex patterns
8249
- let regexPattern = dateFormat.replace(/(?:yyyy|yy|mm|dd)/gu, (match) => formatPatterns[match]);
8250
- regexPattern = `^${regexPattern}$`;
9125
+ // Guard clause: ensure year is a valid integer
9126
+ if (Number.isNaN(numYear)) {
9127
+ throw new Error('AuroDatepickerUtilities | yearValueIsValid: Unable to parse year value integer');
9128
+ }
8251
9129
 
8252
- const regex = new RegExp(regexPattern, 'u');
8253
- const match = dateStr.match(regex);
9130
+ // Guard clause: ensure year is within the valid range
9131
+ if (numYear < this.minYear || numYear > this.maxYear) {
9132
+ return false;
9133
+ }
8254
9134
 
8255
- if (match && match.groups) {
8256
- return {
8257
- year: match.groups.year,
8258
- month: match.groups.month,
8259
- day: match.groups.day
9135
+ // Default return
9136
+ return true;
8260
9137
  };
8261
- }
8262
9138
 
8263
- return undefined;
9139
+ // Self-contained checks for month, day, and year
9140
+ const checks = [
9141
+ monthValueIsValid(dateParts.month),
9142
+ dayValueIsValid(dateParts.day),
9143
+ yearIsValid(dateParts.year)
9144
+ ];
9145
+
9146
+ // If any of the checks failed, the date format does not match and the result is invalid
9147
+ const isValid = checks.every((check) => check === true);
9148
+
9149
+ // If the check is invalid, return false
9150
+ if (!isValid) {
9151
+ return false;
9152
+ }
9153
+
9154
+ // Default case
9155
+ return true;
9156
+ };
8264
9157
  }
8265
9158
  }
8266
9159
 
9160
+ // Export a class instance
9161
+ const dateUtilities = new AuroDateUtilities();
9162
+
9163
+ // Export the class instance methods individually
9164
+ const {
9165
+ datesMatch,
9166
+ validDateStr,
9167
+ dateAndFormatMatch,
9168
+ minDay,
9169
+ minMonth,
9170
+ minYear,
9171
+ maxDay,
9172
+ maxMonth,
9173
+ maxYear
9174
+ } = dateUtilities;
9175
+
9176
+ const {
9177
+ toNorthAmericanFormat,
9178
+ parseDate,
9179
+ getDateAsString
9180
+ } = dateFormatter;
9181
+
8267
9182
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
8268
9183
  // See LICENSE in the project root for license information.
8269
9184
 
@@ -8339,6 +9254,7 @@ let AuroLibraryRuntimeUtils$1$1 = class AuroLibraryRuntimeUtils {
8339
9254
 
8340
9255
 
8341
9256
  class AuroFormValidation {
9257
+
8342
9258
  constructor() {
8343
9259
  this.runtimeUtils = new AuroLibraryRuntimeUtils$1$1();
8344
9260
  }
@@ -8430,17 +9346,17 @@ class AuroFormValidation {
8430
9346
  ]
8431
9347
  }
8432
9348
  };
8433
-
9349
+
8434
9350
  let elementType;
8435
9351
  if (this.runtimeUtils.elementMatch(elem, 'auro-input')) {
8436
9352
  elementType = 'input';
8437
9353
  } else if (this.runtimeUtils.elementMatch(elem, 'auro-counter') || this.runtimeUtils.elementMatch(elem, 'auro-counter-group')) {
8438
9354
  elementType = 'counter';
8439
9355
  }
8440
-
9356
+
8441
9357
  if (elementType) {
8442
9358
  const rules = validationRules[elementType];
8443
-
9359
+
8444
9360
  if (rules) {
8445
9361
  Object.values(rules).flat().forEach(rule => {
8446
9362
  if (rule.check(elem)) {
@@ -8466,48 +9382,82 @@ class AuroFormValidation {
8466
9382
  if (!elem.value.match(emailRegex)) {
8467
9383
  elem.validity = 'patternMismatch';
8468
9384
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
9385
+ return;
8469
9386
  }
8470
9387
  } else if (elem.type === 'credit-card') {
8471
9388
  if (elem.value.length > 0 && elem.value.length < elem.validationCCLength) {
8472
9389
  elem.validity = 'tooShort';
8473
9390
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
9391
+ return;
8474
9392
  }
8475
9393
  } else if (elem.type === 'number') {
8476
9394
  if (elem.max !== undefined && Number(elem.max) < Number(elem.value)) {
8477
9395
  elem.validity = 'rangeOverflow';
8478
9396
  elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
9397
+ return;
8479
9398
  }
8480
9399
 
8481
9400
  if (elem.min !== undefined && elem.value?.length > 0 && Number(elem.min) > Number(elem.value)) {
8482
9401
  elem.validity = 'rangeUnderflow';
8483
9402
  elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
9403
+ return;
8484
9404
  }
8485
- } else if (elem.type === 'date') {
8486
- if (elem.value?.length > 0 && elem.value?.length < elem.lengthForType) {
9405
+ } else if (elem.type === 'date' && elem.value?.length > 0) {
9406
+
9407
+ // Guard Clause: if the value is too short
9408
+ if (elem.value.length < elem.lengthForType) {
9409
+
8487
9410
  elem.validity = 'tooShort';
8488
9411
  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);
9412
+ return;
9413
+ }
9414
+
9415
+ // Guard Clause: If the value is too long for the type
9416
+ if (elem.value?.length > elem.lengthForType) {
9417
+
9418
+ elem.validity = 'tooLong';
9419
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
9420
+ return;
9421
+ }
9422
+
9423
+ // Validate that the date passed was the correct format
9424
+ if (!dateAndFormatMatch(elem.value, elem.format)) {
9425
+ elem.validity = 'patternMismatch';
9426
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || 'Invalid Date Format Entered';
9427
+ return;
9428
+ }
9429
+
9430
+ // Validate that the date passed was a valid date
9431
+ if (!validDateStr(elem.value, elem.format)) {
9432
+ elem.validity = 'invalidDate';
9433
+ elem.errorMessage = elem.setCustomValidityInvalidDate || elem.setCustomValidity || 'Invalid Date Entered';
9434
+ return;
9435
+ }
8492
9436
 
8493
- // validate max
8494
- if (elem.max?.length === elem.lengthForType) {
8495
- const maxDate = new Date(elem.util.toNorthAmericanFormat(elem.max, elem.format).dateForComparison);
9437
+ // Perform the rest of the validation
9438
+ const formattedValue = toNorthAmericanFormat(elem.value, elem.format);
9439
+ const valueDate = new Date(formattedValue);
8496
9440
 
8497
- if (valueDate > maxDate) {
8498
- elem.validity = 'rangeOverflow';
8499
- elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
8500
- }
9441
+ // // Validate max date
9442
+ if (elem.max?.length === elem.lengthForType) {
9443
+
9444
+ const maxDate = new Date(toNorthAmericanFormat(elem.max, elem.format));
9445
+
9446
+ if (valueDate > maxDate) {
9447
+ elem.validity = 'rangeOverflow';
9448
+ elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
9449
+ return;
8501
9450
  }
9451
+ }
8502
9452
 
8503
- // validate min
8504
- if (elem.min?.length === elem.lengthForType) {
8505
- const minDate = new Date(elem.util.toNorthAmericanFormat(elem.min, elem.format).dateForComparison);
9453
+ // Validate min date
9454
+ if (elem.min?.length === elem.lengthForType) {
9455
+ const minDate = new Date(toNorthAmericanFormat(elem.min, elem.format));
8506
9456
 
8507
- if (valueDate < minDate) {
8508
- elem.validity = 'rangeUnderflow';
8509
- elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
8510
- }
9457
+ if (valueDate < minDate) {
9458
+ elem.validity = 'rangeUnderflow';
9459
+ elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
9460
+ return;
8511
9461
  }
8512
9462
  }
8513
9463
  }
@@ -8626,7 +9576,7 @@ class AuroFormValidation {
8626
9576
  if (input.validationMessage.length > 0) {
8627
9577
  elem.errorMessage = input.validationMessage;
8628
9578
  }
8629
- } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
9579
+ } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
8630
9580
  const firstInput = this.inputElements[0];
8631
9581
 
8632
9582
  if (firstInput.validationMessage.length > 0) {
@@ -8748,6 +9698,33 @@ class BaseInput extends r$1 {
8748
9698
  static get properties() {
8749
9699
  return {
8750
9700
 
9701
+ /**
9702
+ * The value for the role attribute.
9703
+ */
9704
+ a11yRole: {
9705
+ type: String,
9706
+ attribute: true,
9707
+ reflect: true
9708
+ },
9709
+
9710
+ /**
9711
+ * The value for the aria-expanded attribute.
9712
+ */
9713
+ a11yExpanded: {
9714
+ type: Boolean,
9715
+ attribute: true,
9716
+ reflect: true
9717
+ },
9718
+
9719
+ /**
9720
+ * The value for the aria-controls attribute.
9721
+ */
9722
+ a11yControls: {
9723
+ type: String,
9724
+ attribute: true,
9725
+ reflect: true
9726
+ },
9727
+
8751
9728
  /**
8752
9729
  * If set, the label will remain fixed in the active position.
8753
9730
  */
@@ -9389,6 +10366,10 @@ class BaseInput extends r$1 {
9389
10366
  } else if (this.type === 'number') {
9390
10367
  this.inputMode = 'numeric';
9391
10368
  }
10369
+
10370
+ if (this.type === "date" && !this.format) {
10371
+ this.format = 'mm/dd/yyyy';
10372
+ }
9392
10373
  }
9393
10374
 
9394
10375
  /**
@@ -10632,6 +11613,7 @@ var helpTextVersion = '1.0.0';
10632
11613
 
10633
11614
  // build the component class
10634
11615
  class AuroInput extends BaseInput {
11616
+
10635
11617
  constructor() {
10636
11618
  super();
10637
11619
 
@@ -10744,7 +11726,7 @@ class AuroInput extends BaseInput {
10744
11726
  ?required="${this.required}"
10745
11727
  ?disabled="${this.disabled}"
10746
11728
  aria-describedby="${this.uniqueId}"
10747
- aria-invalid="${this.validity !== 'valid'}"
11729
+ ?aria-invalid="${this.validity !== 'valid'}"
10748
11730
  placeholder=${this.getPlaceholder()}
10749
11731
  lang="${o(this.lang)}"
10750
11732
  ?activeLabel="${this.activeLabel}"
@@ -10753,7 +11735,10 @@ class AuroInput extends BaseInput {
10753
11735
  autocapitalize="${o(this.autocapitalize ? this.autocapitalize : undefined)}"
10754
11736
  autocomplete="${o(this.autocomplete ? this.autocomplete : undefined)}"
10755
11737
  part="input"
10756
- />
11738
+ role="${o(this.a11yRole)}"
11739
+ aria-expanded="${o(this.a11yExpanded)}"
11740
+ aria-controls="${o(this.a11yControls)}"
11741
+ />
10757
11742
  </div>
10758
11743
  <div
10759
11744
  class="notificationIcons"
@@ -11745,6 +12730,7 @@ var styleCss$3 = i$5`.util_displayInline{display:inline}.util_displayInlineBlock
11745
12730
 
11746
12731
  // build the component class
11747
12732
  class AuroCombobox extends r$1 {
12733
+
11748
12734
  constructor() {
11749
12735
  super();
11750
12736
 
@@ -11756,6 +12742,8 @@ class AuroCombobox extends r$1 {
11756
12742
  * @returns {void} Internal defaults.
11757
12743
  */
11758
12744
  privateDefaults() {
12745
+ this.dropdownOpen = false;
12746
+ this.dropdownId = undefined;
11759
12747
  this.onDark = false;
11760
12748
 
11761
12749
  this.noFilter = false;
@@ -11835,6 +12823,26 @@ class AuroCombobox extends r$1 {
11835
12823
  reflect: true
11836
12824
  },
11837
12825
 
12826
+ /**
12827
+ * ID for the dropdown
12828
+ * @private
12829
+ */
12830
+ dropdownId: {
12831
+ type: String,
12832
+ reflect: false,
12833
+ attribute: false
12834
+ },
12835
+
12836
+ /**
12837
+ * Whether or not the dropdown is open
12838
+ * @private
12839
+ */
12840
+ dropdownOpen: {
12841
+ type: Boolean,
12842
+ reflect: false,
12843
+ attribute: false
12844
+ },
12845
+
11838
12846
  /**
11839
12847
  * When defined, sets persistent validity to `customError` and sets the validation message to the attribute value.
11840
12848
  */
@@ -11980,11 +12988,8 @@ class AuroCombobox extends r$1 {
11980
12988
  },
11981
12989
 
11982
12990
  /**
11983
- * Defines the screen size breakpoint (`xs`, `sm`, `md`, `lg`, `xl`, `disabled`)
11984
- * at which the dropdown switches to fullscreen mode on mobile. `disabled` indicates a dropdown should _never_ enter fullscreen.
11985
- *
11986
- * When expanded, the dropdown will automatically display in fullscreen mode
11987
- * if the screen size is equal to or smaller than the selected breakpoint.
12991
+ * Defines the screen size breakpoint (`lg`, `md`, `sm`, or `xs`) at which the dropdown switches to fullscreen mode on mobile.
12992
+ * When expanded, the dropdown will automatically display in fullscreen mode if the screen size is equal to or smaller than the selected breakpoint.
11988
12993
  * @default sm
11989
12994
  */
11990
12995
  fullscreenBreakpoint: {
@@ -11996,8 +13001,19 @@ class AuroCombobox extends r$1 {
11996
13001
  * @private
11997
13002
  */
11998
13003
  isDropdownFullscreen: {
11999
- type: Boolean
12000
- }
13004
+ type: Boolean,
13005
+ reflect: false
13006
+ },
13007
+
13008
+ /**
13009
+ * @private
13010
+ * specifies the currently active option
13011
+ */
13012
+ optionActive: {
13013
+ type: Object,
13014
+ reflect: false,
13015
+ attribute: false
13016
+ },
12001
13017
  };
12002
13018
  }
12003
13019
 
@@ -12149,6 +13165,18 @@ class AuroCombobox extends r$1 {
12149
13165
  * @returns {void}
12150
13166
  */
12151
13167
  configureDropdown() {
13168
+
13169
+ // Listen for the ID to be added to the dropdown so we can capture it and use it for accessibility.
13170
+ this.dropdown.addEventListener('auroDropdown-idAdded', (event) => {
13171
+ this.dropdownId = event.detail.id;
13172
+ });
13173
+
13174
+ // Listen for the dropdown to be shown or hidden
13175
+ this.dropdown.addEventListener("auroDropdown-toggled", (ev) => {
13176
+ this.dropdownOpen = ev.detail.expanded;
13177
+ });
13178
+
13179
+ // this.dropdown.addEventListener('auroDropdown-show', () => {
12152
13180
  this.menuWrapper = this.dropdown.querySelector('.menuWrapper');
12153
13181
  this.menuWrapper.append(this.menu);
12154
13182
 
@@ -12162,7 +13190,6 @@ class AuroCombobox extends r$1 {
12162
13190
  this.hideBib = this.hideBib.bind(this);
12163
13191
  this.bibtemplate.addEventListener('close-click', this.hideBib);
12164
13192
 
12165
- this.dropdown.setAttribute('role', 'combobox');
12166
13193
  this.dropdown.addEventListener('auroDropdown-triggerClick', () => {
12167
13194
  this.showBib();
12168
13195
  });
@@ -12178,7 +13205,6 @@ class AuroCombobox extends r$1 {
12178
13205
  this.isDropdownFullscreen = event.detail.strategy === 'fullscreen';
12179
13206
  setTimeout(this.transportInput);
12180
13207
  });
12181
-
12182
13208
  }
12183
13209
 
12184
13210
  /**
@@ -12672,6 +13698,10 @@ class AuroCombobox extends r$1 {
12672
13698
  ?noFlip="${this.noFlip}"
12673
13699
  disableEventShow>
12674
13700
  <${this.inputTag}
13701
+ .a11yRole="${"combobox"}"
13702
+ .a11yExpanded="${this.dropdownOpen}"
13703
+ .a11yControls="${this.dropdownId}"
13704
+ id="${this.id || 'auro-combobox-input'}"
12675
13705
  slot="trigger"
12676
13706
  bordered
12677
13707
  ?onDark="${this.onDark}"