@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
@@ -164,11 +164,420 @@ let AuroLibraryRuntimeUtils$4 = class AuroLibraryRuntimeUtils {
164
164
  }
165
165
  };
166
166
 
167
+ let DateFormatter$1 = class DateFormatter {
168
+
169
+ constructor() {
170
+
171
+ /**
172
+ * @description Parses a date string into its components.
173
+ * @param {string} dateStr - Date string to parse.
174
+ * @param {string} format - Date format to parse.
175
+ * @returns {Object<key["month" | "day" | "year"]: number>|undefined}
176
+ */
177
+ this.parseDate = (dateStr, format = 'mm/dd/yyyy') => {
178
+
179
+ // Guard Clause: Date string is defined
180
+ if (!dateStr) {
181
+ return undefined;
182
+ }
183
+
184
+ // Assume the separator is a "/" a defined in our code base
185
+ const separator = '/';
186
+
187
+ // Get the parts of the date and format
188
+ const valueParts = dateStr.split(separator);
189
+ const formatParts = format.split(separator);
190
+
191
+ // Check if the value and format have the correct number of parts
192
+ if (valueParts.length !== formatParts.length) {
193
+ throw new Error('AuroDatepickerUtilities | parseDate: Date string and format length do not match');
194
+ }
195
+
196
+ // Holds the result to be returned
197
+ const result = formatParts.reduce((acc, part, index) => {
198
+ const value = valueParts[index];
199
+
200
+ if ((/m/iu).test(part)) {
201
+ acc.month = value;
202
+ } else if ((/d/iu).test(part)) {
203
+ acc.day = value;
204
+ } else if ((/y/iu).test(part)) {
205
+ acc.year = value;
206
+ }
207
+
208
+ return acc;
209
+ }, {});
210
+
211
+ // If we found all the parts, return the result
212
+ if (result.month && result.year) {
213
+ return result;
214
+ }
215
+
216
+ // Throw an error to let the dev know we were unable to parse the date string
217
+ throw new Error('AuroDatepickerUtilities | parseDate: Unable to parse date string');
218
+ };
219
+
220
+ /**
221
+ * Convert a date object to string format.
222
+ * @param {Object} date - Date to convert to string.
223
+ * @returns {Object} Returns the date as a string.
224
+ */
225
+ this.getDateAsString = (date) => date.toLocaleDateString(undefined, {
226
+ year: "numeric",
227
+ month: "2-digit",
228
+ day: "2-digit",
229
+ });
230
+
231
+ /**
232
+ * Converts a date string to a North American date format.
233
+ * @param {String} dateStr - Date to validate.
234
+ * @param {String} format - Date format to validate against.
235
+ * @returns {Boolean}
236
+ */
237
+ this.toNorthAmericanFormat = (dateStr, format) => {
238
+
239
+ if (format === 'mm/dd/yyyy') {
240
+ return dateStr;
241
+ }
242
+
243
+ const parsedDate = this.parseDate(dateStr, format);
244
+
245
+ if (!parsedDate) {
246
+ throw new Error('AuroDatepickerUtilities | toNorthAmericanFormat: Unable to parse date string');
247
+ }
248
+
249
+ const { month, day, year } = parsedDate;
250
+
251
+ const dateParts = [];
252
+ if (month) {
253
+ dateParts.push(month);
254
+ }
255
+
256
+ if (day) {
257
+ dateParts.push(day);
258
+ }
259
+
260
+ if (year) {
261
+ dateParts.push(year);
262
+ }
263
+
264
+ return dateParts.join('/');
265
+ };
266
+ }
267
+ };
268
+ const dateFormatter$1 = new DateFormatter$1();
269
+
270
+ // filepath: dateConstraints.mjs
271
+ const DATE_UTIL_CONSTRAINTS$1 = {
272
+ maxDay: 31,
273
+ maxMonth: 12,
274
+ maxYear: 2400,
275
+ minDay: 1,
276
+ minMonth: 1,
277
+ minYear: 1900,
278
+ };
279
+
280
+ let AuroDateUtilitiesBase$1 = class AuroDateUtilitiesBase {
281
+
282
+ /**
283
+ * @description The maximum day value allowed by the various utilities in this class.
284
+ * @readonly
285
+ * @type {Number}
286
+ */
287
+ get maxDay() {
288
+ return DATE_UTIL_CONSTRAINTS$1.maxDay;
289
+ }
290
+
291
+ /**
292
+ * @description The maximum month value allowed by the various utilities in this class.
293
+ * @readonly
294
+ * @type {Number}
295
+ */
296
+ get maxMonth() {
297
+ return DATE_UTIL_CONSTRAINTS$1.maxMonth;
298
+ }
299
+
300
+ /**
301
+ * @description The maximum year value allowed by the various utilities in this class.
302
+ * @readonly
303
+ * @type {Number}
304
+ */
305
+ get maxYear() {
306
+ return DATE_UTIL_CONSTRAINTS$1.maxYear;
307
+ }
308
+
309
+ /**
310
+ * @description The minimum day value allowed by the various utilities in this class.
311
+ * @readonly
312
+ * @type {Number}
313
+ */
314
+ get minDay() {
315
+ return DATE_UTIL_CONSTRAINTS$1.minDay;
316
+ }
317
+
318
+ /**
319
+ * @description The minimum month value allowed by the various utilities in this class.
320
+ * @readonly
321
+ * @type {Number}
322
+ */
323
+ get minMonth() {
324
+ return DATE_UTIL_CONSTRAINTS$1.minMonth;
325
+ }
326
+
327
+ /**
328
+ * @description The minimum year value allowed by the various utilities in this class.
329
+ * @readonly
330
+ * @type {Number}
331
+ */
332
+ get minYear() {
333
+ return DATE_UTIL_CONSTRAINTS$1.minYear;
334
+ }
335
+ };
336
+
337
+ /* eslint-disable no-magic-numbers */
338
+
339
+ let AuroDateUtilities$1 = class AuroDateUtilities extends AuroDateUtilitiesBase$1 {
340
+
341
+ /**
342
+ * Returns the current century.
343
+ * @returns {String} The current century.
344
+ */
345
+ getCentury () {
346
+ return String(new Date().getFullYear()).slice(0, 2);
347
+ }
348
+
349
+ /**
350
+ * Returns a four digit year.
351
+ * @param {String} year - The year to convert to four digits.
352
+ * @returns {String} The four digit year.
353
+ */
354
+ getFourDigitYear (year) {
355
+
356
+ const strYear = String(year).trim();
357
+ return strYear.length <= 2 ? this.getCentury() + strYear : strYear;
358
+ }
359
+
360
+ constructor() {
361
+
362
+ super();
363
+
364
+ /**
365
+ * Compares two dates to see if they match.
366
+ * @param {Object} date1 - First date to compare.
367
+ * @param {Object} date2 - Second date to compare.
368
+ * @returns {Boolean} Returns true if the dates match.
369
+ */
370
+ this.datesMatch = (date1, date2) => new Date(date1).getTime() === new Date(date2).getTime();
371
+
372
+ /**
373
+ * Returns true if value passed in is a valid date.
374
+ * @param {String} date - Date to validate.
375
+ * @param {String} format - Date format to validate against.
376
+ * @returns {Boolean}
377
+ */
378
+ this.validDateStr = (date, format) => {
379
+
380
+ // The length we expect the date string to be
381
+ const dateStrLength = format.length;
382
+
383
+ // Guard Clause: Date and format are defined
384
+ if (typeof date === "undefined" || typeof format === "undefined") {
385
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date and format are required');
386
+ }
387
+
388
+ // Guard Clause: Date should be of type string
389
+ if (typeof date !== "string") {
390
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date must be a string');
391
+ }
392
+
393
+ // Guard Clause: Format should be of type string
394
+ if (typeof format !== "string") {
395
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Format must be a string');
396
+ }
397
+
398
+ // Guard Clause: Length is what we expect it to be
399
+ if (date.length !== dateStrLength) {
400
+ return false;
401
+ }
402
+ // Get a formatted date string and parse it
403
+ const dateParts = dateFormatter$1.parseDate(date, format);
404
+
405
+ // Guard Clause: Date parse succeeded
406
+ if (!dateParts) {
407
+ return false;
408
+ }
409
+
410
+ // Create the expected date string based on the date parts
411
+ const expectedDateStr = `${dateParts.month}/${dateParts.day || "01"}/${this.getFourDigitYear(dateParts.year)}`;
412
+
413
+ // Generate a date object that we will extract a string date from to compare to the passed in date string
414
+ const dateObj = new Date(this.getFourDigitYear(dateParts.year), dateParts.month - 1, dateParts.day || 1);
415
+
416
+ // Get the date string of the date object we created from the string date
417
+ const actualDateStr = dateFormatter$1.getDateAsString(dateObj);
418
+
419
+ // Guard Clause: Generated date matches date string input
420
+ if (expectedDateStr !== actualDateStr) {
421
+ return false;
422
+ }
423
+
424
+ // If we passed all other checks, we can assume the date is valid
425
+ return true;
426
+ };
427
+
428
+ /**
429
+ * Determines if a string date value matches the format provided.
430
+ * @param {string} value = The date string value.
431
+ * @param { string} format = The date format to match against.
432
+ * @returns {boolean}
433
+ */
434
+ this.dateAndFormatMatch = (value, format) => {
435
+
436
+ // Ensure we have both values we need to do the comparison
437
+ if (!value || !format) {
438
+ throw new Error('AuroFormValidation | dateFormatMatch: value and format are required');
439
+ }
440
+
441
+ // If the lengths are different, they cannot match
442
+ if (value.length !== format.length) {
443
+ return false;
444
+ }
445
+
446
+ // Get the parts of the date
447
+ const dateParts = dateFormatter$1.parseDate(value, format);
448
+
449
+ // Validator for day
450
+ const dayValueIsValid = (day) => {
451
+
452
+ // Guard clause: if there is no day in the dateParts, we can ignore this check.
453
+ if (!dateParts.day) {
454
+ return true;
455
+ }
456
+
457
+ // Guard clause: ensure day exists.
458
+ if (!day) {
459
+ return false;
460
+ }
461
+
462
+ // Convert day to number
463
+ const numDay = Number.parseInt(day, 10);
464
+
465
+ // Guard clause: ensure day is a valid integer
466
+ if (Number.isNaN(numDay)) {
467
+ throw new Error('AuroDatepickerUtilities | dayValueIsValid: Unable to parse day value integer');
468
+ }
469
+
470
+ // Guard clause: ensure day is within the valid range
471
+ if (numDay < this.minDay || numDay > this.maxDay) {
472
+ return false;
473
+ }
474
+
475
+ // Default return
476
+ return true;
477
+ };
478
+
479
+ // Validator for month
480
+ const monthValueIsValid = (month) => {
481
+
482
+ // Guard clause: ensure month exists.
483
+ if (!month) {
484
+ return false;
485
+ }
486
+
487
+ // Convert month to number
488
+ const numMonth = Number.parseInt(month, 10);
489
+
490
+ // Guard clause: ensure month is a valid integer
491
+ if (Number.isNaN(numMonth)) {
492
+ throw new Error('AuroDatepickerUtilities | monthValueIsValid: Unable to parse month value integer');
493
+ }
494
+
495
+ // Guard clause: ensure month is within the valid range
496
+ if (numMonth < this.minMonth || numMonth > this.maxMonth) {
497
+ return false;
498
+ }
499
+
500
+ // Default return
501
+ return true;
502
+ };
503
+
504
+ // Validator for year
505
+ const yearIsValid = (_year) => {
506
+
507
+ // Guard clause: ensure year exists.
508
+ if (!_year) {
509
+ return false;
510
+ }
511
+
512
+ // Get the full year
513
+ const year = this.getFourDigitYear(_year);
514
+
515
+ // Convert year to number
516
+ const numYear = Number.parseInt(year, 10);
517
+
518
+ // Guard clause: ensure year is a valid integer
519
+ if (Number.isNaN(numYear)) {
520
+ throw new Error('AuroDatepickerUtilities | yearValueIsValid: Unable to parse year value integer');
521
+ }
522
+
523
+ // Guard clause: ensure year is within the valid range
524
+ if (numYear < this.minYear || numYear > this.maxYear) {
525
+ return false;
526
+ }
527
+
528
+ // Default return
529
+ return true;
530
+ };
531
+
532
+ // Self-contained checks for month, day, and year
533
+ const checks = [
534
+ monthValueIsValid(dateParts.month),
535
+ dayValueIsValid(dateParts.day),
536
+ yearIsValid(dateParts.year)
537
+ ];
538
+
539
+ // If any of the checks failed, the date format does not match and the result is invalid
540
+ const isValid = checks.every((check) => check === true);
541
+
542
+ // If the check is invalid, return false
543
+ if (!isValid) {
544
+ return false;
545
+ }
546
+
547
+ // Default case
548
+ return true;
549
+ };
550
+ }
551
+ };
552
+
553
+ // Export a class instance
554
+ const dateUtilities$1 = new AuroDateUtilities$1();
555
+
556
+ // Export the class instance methods individually
557
+ const {
558
+ datesMatch: datesMatch$1,
559
+ validDateStr: validDateStr$1,
560
+ dateAndFormatMatch: dateAndFormatMatch$1,
561
+ minDay: minDay$1,
562
+ minMonth: minMonth$1,
563
+ minYear: minYear$1,
564
+ maxDay: maxDay$1,
565
+ maxMonth: maxMonth$1,
566
+ maxYear: maxYear$1
567
+ } = dateUtilities$1;
568
+
569
+ const {
570
+ toNorthAmericanFormat: toNorthAmericanFormat$1,
571
+ parseDate: parseDate$1,
572
+ getDateAsString: getDateAsString$1
573
+ } = dateFormatter$1;
574
+
167
575
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
168
576
  // See LICENSE in the project root for license information.
169
577
 
170
578
 
171
579
  let AuroFormValidation$1 = class AuroFormValidation {
580
+
172
581
  constructor() {
173
582
  this.runtimeUtils = new AuroLibraryRuntimeUtils$4();
174
583
  }
@@ -260,17 +669,17 @@ let AuroFormValidation$1 = class AuroFormValidation {
260
669
  ]
261
670
  }
262
671
  };
263
-
672
+
264
673
  let elementType;
265
674
  if (this.runtimeUtils.elementMatch(elem, 'auro-input')) {
266
675
  elementType = 'input';
267
676
  } else if (this.runtimeUtils.elementMatch(elem, 'auro-counter') || this.runtimeUtils.elementMatch(elem, 'auro-counter-group')) {
268
677
  elementType = 'counter';
269
678
  }
270
-
679
+
271
680
  if (elementType) {
272
681
  const rules = validationRules[elementType];
273
-
682
+
274
683
  if (rules) {
275
684
  Object.values(rules).flat().forEach(rule => {
276
685
  if (rule.check(elem)) {
@@ -296,48 +705,82 @@ let AuroFormValidation$1 = class AuroFormValidation {
296
705
  if (!elem.value.match(emailRegex)) {
297
706
  elem.validity = 'patternMismatch';
298
707
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
708
+ return;
299
709
  }
300
710
  } else if (elem.type === 'credit-card') {
301
711
  if (elem.value.length > 0 && elem.value.length < elem.validationCCLength) {
302
712
  elem.validity = 'tooShort';
303
713
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
714
+ return;
304
715
  }
305
716
  } else if (elem.type === 'number') {
306
717
  if (elem.max !== undefined && Number(elem.max) < Number(elem.value)) {
307
718
  elem.validity = 'rangeOverflow';
308
719
  elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
720
+ return;
309
721
  }
310
722
 
311
723
  if (elem.min !== undefined && elem.value?.length > 0 && Number(elem.min) > Number(elem.value)) {
312
724
  elem.validity = 'rangeUnderflow';
313
725
  elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
726
+ return;
314
727
  }
315
- } else if (elem.type === 'date') {
316
- if (elem.value?.length > 0 && elem.value?.length < elem.lengthForType) {
728
+ } else if (elem.type === 'date' && elem.value?.length > 0) {
729
+
730
+ // Guard Clause: if the value is too short
731
+ if (elem.value.length < elem.lengthForType) {
732
+
317
733
  elem.validity = 'tooShort';
318
734
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
319
- } else if (elem.value?.length === elem.lengthForType && elem.util.toNorthAmericanFormat(elem.value, elem.format)) {
320
- const formattedValue = elem.util.toNorthAmericanFormat(elem.value, elem.format);
321
- const valueDate = new Date(formattedValue.dateForComparison);
735
+ return;
736
+ }
737
+
738
+ // Guard Clause: If the value is too long for the type
739
+ if (elem.value?.length > elem.lengthForType) {
740
+
741
+ elem.validity = 'tooLong';
742
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
743
+ return;
744
+ }
745
+
746
+ // Validate that the date passed was the correct format
747
+ if (!dateAndFormatMatch$1(elem.value, elem.format)) {
748
+ elem.validity = 'patternMismatch';
749
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || 'Invalid Date Format Entered';
750
+ return;
751
+ }
752
+
753
+ // Validate that the date passed was a valid date
754
+ if (!validDateStr$1(elem.value, elem.format)) {
755
+ elem.validity = 'invalidDate';
756
+ elem.errorMessage = elem.setCustomValidityInvalidDate || elem.setCustomValidity || 'Invalid Date Entered';
757
+ return;
758
+ }
322
759
 
323
- // validate max
324
- if (elem.max?.length === elem.lengthForType) {
325
- const maxDate = new Date(elem.util.toNorthAmericanFormat(elem.max, elem.format).dateForComparison);
760
+ // Perform the rest of the validation
761
+ const formattedValue = toNorthAmericanFormat$1(elem.value, elem.format);
762
+ const valueDate = new Date(formattedValue);
326
763
 
327
- if (valueDate > maxDate) {
328
- elem.validity = 'rangeOverflow';
329
- elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
330
- }
764
+ // // Validate max date
765
+ if (elem.max?.length === elem.lengthForType) {
766
+
767
+ const maxDate = new Date(toNorthAmericanFormat$1(elem.max, elem.format));
768
+
769
+ if (valueDate > maxDate) {
770
+ elem.validity = 'rangeOverflow';
771
+ elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
772
+ return;
331
773
  }
774
+ }
332
775
 
333
- // validate min
334
- if (elem.min?.length === elem.lengthForType) {
335
- const minDate = new Date(elem.util.toNorthAmericanFormat(elem.min, elem.format).dateForComparison);
776
+ // Validate min date
777
+ if (elem.min?.length === elem.lengthForType) {
778
+ const minDate = new Date(toNorthAmericanFormat$1(elem.min, elem.format));
336
779
 
337
- if (valueDate < minDate) {
338
- elem.validity = 'rangeUnderflow';
339
- elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
340
- }
780
+ if (valueDate < minDate) {
781
+ elem.validity = 'rangeUnderflow';
782
+ elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
783
+ return;
341
784
  }
342
785
  }
343
786
  }
@@ -456,7 +899,7 @@ let AuroFormValidation$1 = class AuroFormValidation {
456
899
  if (input.validationMessage.length > 0) {
457
900
  elem.errorMessage = input.validationMessage;
458
901
  }
459
- } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
902
+ } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
460
903
  const firstInput = this.inputElements[0];
461
904
 
462
905
  if (firstInput.validationMessage.length > 0) {
@@ -2337,7 +2780,7 @@ class AuroFloatingUI {
2337
2780
  /**
2338
2781
  * @private
2339
2782
  * getting called on 'blur' in trigger or `focusin` in document
2340
- *
2783
+ *
2341
2784
  * Hides the bib if focus moves outside of the trigger or bib, unless a 'noHideOnThisFocusLoss' flag is set.
2342
2785
  * This method checks if the currently active element is still within the trigger or bib.
2343
2786
  * If not, and if the bib isn't in fullscreen mode with focus lost, it hides the bib.
@@ -2453,7 +2896,7 @@ class AuroFloatingUI {
2453
2896
  // Close any other dropdown that is already open
2454
2897
  const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
2455
2898
  if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this &&
2456
- existedVisibleFloatingUI.isPopoverVisible &&
2899
+ existedVisibleFloatingUI.element.isPopoverVisible &&
2457
2900
  document.expandedAuroFloater.eventPrefix === this.eventPrefix) {
2458
2901
  document.expandedAuroFloater.hideBib();
2459
2902
  }
@@ -2629,7 +3072,7 @@ class AuroFloatingUI {
2629
3072
  this.id = window.crypto.randomUUID();
2630
3073
  this.element.setAttribute('id', this.id);
2631
3074
  }
2632
-
3075
+
2633
3076
  this.element.bib.setAttribute("id", `${this.id}-floater-bib`);
2634
3077
  }
2635
3078
 
@@ -2682,7 +3125,7 @@ class AuroFloatingUI {
2682
3125
  if (this.element.bib) {
2683
3126
  this.element.shadowRoot.append(this.element.bib);
2684
3127
  }
2685
-
3128
+
2686
3129
  // Remove event & keyboard listeners
2687
3130
  if (this.element?.trigger) {
2688
3131
  this.element.trigger.removeEventListener('keydown', this.handleEvent);
@@ -3072,7 +3515,6 @@ var tokensCss$1$2 = i$5`:host{--ds-auro-dropdown-label-text-color: var(--ds-basi
3072
3515
 
3073
3516
  const DESIGN_TOKEN_BREAKPOINT_PREFIX = '--ds-grid-breakpoint-';
3074
3517
  const DESIGN_TOKEN_BREAKPOINT_OPTIONS = [
3075
- 'xl',
3076
3518
  'lg',
3077
3519
  'md',
3078
3520
  'sm',
@@ -3144,7 +3586,6 @@ class AuroDropdownBib extends r$1 {
3144
3586
 
3145
3587
  set mobileFullscreenBreakpoint(value) {
3146
3588
  // verify the defined breakpoint is valid and exit out if not
3147
- // 'disabled' is a design token breakpoint so it acts as our "undefined" value
3148
3589
  const validatedValue = DESIGN_TOKEN_BREAKPOINT_OPTIONS.includes(value) ? value : undefined;
3149
3590
  if (!validatedValue) {
3150
3591
  this._mobileBreakpointValue = undefined;
@@ -3413,6 +3854,7 @@ var helpTextVersion$1 = '1.0.0';
3413
3854
  * @csspart helpText - The helpText content container.
3414
3855
  * @event auroDropdown-triggerClick - Notifies that the trigger has been clicked.
3415
3856
  * @event auroDropdown-toggled - Notifies that the visibility of the dropdown bib has changed.
3857
+ * @event auroDropdown-idAdded - Notifies consumers that the unique ID for the dropdown bib has been generated.
3416
3858
  */
3417
3859
  class AuroDropdown extends r$1 {
3418
3860
  constructor() {
@@ -3458,7 +3900,9 @@ class AuroDropdown extends r$1 {
3458
3900
  this.rounded = false;
3459
3901
  this.tabIndex = 0;
3460
3902
  this.noToggle = false;
3903
+ this.a11yAutocomplete = 'none';
3461
3904
  this.labeled = true;
3905
+ this.a11yRole = 'combobox';
3462
3906
  this.onDark = false;
3463
3907
 
3464
3908
  // floaterConfig
@@ -3594,6 +4038,16 @@ class AuroDropdown extends r$1 {
3594
4038
  type: Number
3595
4039
  },
3596
4040
 
4041
+ /**
4042
+ * The unique ID for the dropdown bib element.
4043
+ * @private
4044
+ */
4045
+ dropdownId: {
4046
+ type: String,
4047
+ reflect: false,
4048
+ attribute: false
4049
+ },
4050
+
3597
4051
  /**
3598
4052
  * If declared in combination with `bordered` property or `helpText` slot content, will apply red color to both.
3599
4053
  */
@@ -3657,12 +4111,7 @@ class AuroDropdown extends r$1 {
3657
4111
  },
3658
4112
 
3659
4113
  /**
3660
- * Defines the screen size breakpoint (`xs`, `sm`, `md`, `lg`, `xl`, `disabled`)
3661
- * at which the dropdown switches to fullscreen mode on mobile. `disabled` indicates a dropdown should _never_ enter fullscreen.
3662
- *
3663
- * When expanded, the dropdown will automatically display in fullscreen mode
3664
- * if the screen size is equal to or smaller than the selected breakpoint.
3665
- * @default sm
4114
+ * 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.
3666
4115
  */
3667
4116
  fullscreenBreakpoint: {
3668
4117
  type: String,
@@ -3761,6 +4210,23 @@ class AuroDropdown extends r$1 {
3761
4210
  */
3762
4211
  tabIndex: {
3763
4212
  type: Number
4213
+ },
4214
+
4215
+ /**
4216
+ * The value for the role attribute of the trigger element.
4217
+ */
4218
+ a11yRole: {
4219
+ type: String || undefined,
4220
+ attribute: false,
4221
+ reflect: false
4222
+ },
4223
+
4224
+ /**
4225
+ * The value for the aria-autocomplete attribute of the trigger element.
4226
+ */
4227
+ a11yAutocomplete: {
4228
+ type: String,
4229
+ attribute: false,
3764
4230
  }
3765
4231
  };
3766
4232
  }
@@ -3785,15 +4251,6 @@ class AuroDropdown extends r$1 {
3785
4251
  AuroLibraryRuntimeUtils$1$2.prototype.registerComponent(name, AuroDropdown);
3786
4252
  }
3787
4253
 
3788
- /**
3789
- * Accessor for reusing the focusable entity query string.
3790
- * @private
3791
- * @returns {string}
3792
- */
3793
- get focusableEntityQuery () {
3794
- return 'auro-input, [auro-input], auro-button, [auro-button], button, input';
3795
- }
3796
-
3797
4254
  connectedCallback() {
3798
4255
  super.connectedCallback();
3799
4256
  }
@@ -3807,8 +4264,6 @@ class AuroDropdown extends r$1 {
3807
4264
  updated(changedProperties) {
3808
4265
  this.floater.handleUpdate(changedProperties);
3809
4266
 
3810
- // Note: `disabled` is not a breakpoint (it is not a screen size),
3811
- // so it looks like we never consume this - however, dropdownBib handles this in the setter as "undefined"
3812
4267
  if (changedProperties.has('fullscreenBreakpoint')) {
3813
4268
  this.bibContent.mobileFullscreenBreakpoint = this.fullscreenBreakpoint;
3814
4269
  }
@@ -3822,7 +4277,22 @@ class AuroDropdown extends r$1 {
3822
4277
  }
3823
4278
 
3824
4279
  firstUpdated() {
4280
+
4281
+ // Configure the floater to, this will generate the ID for the bib
3825
4282
  this.floater.configure(this, 'auroDropdown');
4283
+
4284
+ /**
4285
+ * @description Let subscribers know that the dropdown ID ha been generated and added.
4286
+ * @event auroDropdown-idAdded
4287
+ * @type {Object<key: 'id', value: string>} - The ID of the dropdown bib element.
4288
+ */
4289
+ this.dispatchEvent(new CustomEvent('auroDropdown-idAdded', {detail: {id: this.floater.element.id}}));
4290
+
4291
+ // Set the bib ID locally if the user hasn't provided a focusable trigger
4292
+ if (!this.triggerContentFocusable) {
4293
+ this.dropdownId = this.floater.element.id;
4294
+ }
4295
+
3826
4296
  this.bibContent = this.floater.element.bib;
3827
4297
 
3828
4298
  // Add the tag name as an attribute if it is different than the component name
@@ -3944,7 +4414,7 @@ class AuroDropdown extends r$1 {
3944
4414
 
3945
4415
  this.triggerContentSlot.forEach((node) => {
3946
4416
  if (node.querySelectorAll) {
3947
- const auroElements = node.querySelectorAll(this.focusableEntityQuery);
4417
+ const auroElements = node.querySelectorAll('auro-input, [auro-input], auro-button, [auro-button], button, input');
3948
4418
  auroElements.forEach((auroEl) => {
3949
4419
  auroEl.addEventListener('focus', this.bindFocusEventToTrigger);
3950
4420
  auroEl.addEventListener('blur', this.bindFocusEventToTrigger);
@@ -3965,7 +4435,7 @@ class AuroDropdown extends r$1 {
3965
4435
 
3966
4436
  this.triggerContentSlot.forEach((node) => {
3967
4437
  if (node.querySelectorAll) {
3968
- const auroElements = node.querySelectorAll(this.focusableEntityQuery);
4438
+ const auroElements = node.querySelectorAll('auro-input, [auro-input], auro-button, [auro-button], button, input');
3969
4439
  auroElements.forEach((auroEl) => {
3970
4440
  auroEl.removeEventListener('focus', this.bindFocusEventToTrigger);
3971
4441
  auroEl.removeEventListener('blur', this.bindFocusEventToTrigger);
@@ -3974,6 +4444,30 @@ class AuroDropdown extends r$1 {
3974
4444
  });
3975
4445
  }
3976
4446
 
4447
+ /*
4448
+ * Sets aria attributes for the trigger element if a custom one is passed in.
4449
+ * @private
4450
+ * @method setTriggerAriaAttributes
4451
+ * @param { HTMLElement } triggerElement - The custom trigger element.
4452
+ */
4453
+ clearTriggerA11yAttributes(triggerElement) {
4454
+
4455
+ if (!triggerElement || !triggerElement.removeAttribute) {
4456
+ return;
4457
+ }
4458
+
4459
+ // Reset appropriate attributes for a11y
4460
+ triggerElement.removeAttribute('aria-labelledby');
4461
+ if (triggerElement.getAttribute('id') === `${this.id}-trigger-element`) {
4462
+ triggerElement.removeAttribute('id');
4463
+ }
4464
+ triggerElement.removeAttribute('role');
4465
+ triggerElement.removeAttribute('aria-expanded');
4466
+
4467
+ triggerElement.removeAttribute('aria-controls');
4468
+ triggerElement.removeAttribute('aria-autocomplete');
4469
+ }
4470
+
3977
4471
  /**
3978
4472
  * Handles changes to the trigger content slot and updates related properties.
3979
4473
  *
@@ -3987,32 +4481,41 @@ class AuroDropdown extends r$1 {
3987
4481
  * @returns {void}
3988
4482
  */
3989
4483
  handleTriggerContentSlotChange(event) {
4484
+
3990
4485
  this.floater.handleTriggerTabIndex();
3991
4486
 
4487
+ // Get the trigger
4488
+ const trigger = this.shadowRoot.querySelector('#trigger');
4489
+
4490
+ // Get the trigger slot
3992
4491
  const triggerSlot = this.shadowRoot.querySelector('.triggerContent slot');
3993
4492
 
4493
+ // If there's a trigger slot
3994
4494
  if (triggerSlot) {
3995
4495
 
4496
+ // Get the content nodes to see if there are any children
3996
4497
  const triggerContentNodes = triggerSlot.assignedNodes();
3997
4498
 
4499
+ // If there are children
3998
4500
  if (triggerContentNodes) {
3999
4501
 
4000
- triggerContentNodes.forEach((node) => {
4001
- if (!this.triggerContentFocusable) {
4002
- this.triggerContentFocusable = this.containsFocusableElement(node);
4003
- }
4004
- });
4005
- }
4006
- }
4502
+ // See if any of them are focusable elemeents
4503
+ this.triggerContentFocusable = triggerContentNodes.some((node) => this.containsFocusableElement(node));
4007
4504
 
4008
- const trigger = this.shadowRoot.querySelector('#trigger');
4505
+ // If any of them are focusable elements
4506
+ if (this.triggerContentFocusable) {
4009
4507
 
4010
- if (!this.triggerContentFocusable) {
4011
- trigger.setAttribute('tabindex', '0');
4012
- trigger.setAttribute('role', 'button');
4013
- } else {
4014
- trigger.removeAttribute('tabindex');
4015
- trigger.removeAttribute('role');
4508
+ // Assume the consumer will be providing their own a11y in whatever they passed in
4509
+ this.clearTriggerA11yAttributes(trigger);
4510
+
4511
+ // Remove the tabindex from the trigger so it doesn't interrupt focus flow
4512
+ trigger.removeAttribute('tabindex');
4513
+ } else {
4514
+
4515
+ // Add the tabindex to the trigger so that it's in the focus flow
4516
+ trigger.setAttribute('tabindex', '0');
4517
+ }
4518
+ }
4016
4519
  }
4017
4520
 
4018
4521
  if (event) {
@@ -4022,6 +4525,7 @@ class AuroDropdown extends r$1 {
4022
4525
 
4023
4526
  if (this.triggerContentSlot) {
4024
4527
  this.setupTriggerFocusEventBinding();
4528
+
4025
4529
  this.hasTriggerContent = this.triggerContentSlot.some((slot) => {
4026
4530
  if (slot.textContent.trim()) {
4027
4531
  return true;
@@ -4089,10 +4593,13 @@ class AuroDropdown extends r$1 {
4089
4593
  id="trigger"
4090
4594
  class="trigger"
4091
4595
  part="trigger"
4092
- aria-labelledby="triggerLabel"
4093
4596
  tabindex="${this.tabIndex}"
4094
4597
  ?showBorder="${this.showTriggerBorders}"
4095
- >
4598
+ role="${o(this.triggerContentFocusable ? undefined : this.a11yRole)}"
4599
+ aria-expanded="${o(this.triggerContentFocusable ? undefined : this.isPopoverVisible)}"
4600
+ aria-controls="${o(this.triggerContentFocusable ? undefined : this.dropdownId)}"
4601
+ aria-labelledby="${o(this.triggerContentFocusable ? undefined : 'triggerLabel')}"
4602
+ >
4096
4603
  <div class="triggerContentWrapper">
4097
4604
  <label class="label" id="triggerLabel" hasTrigger=${this.hasTriggerContent}>
4098
4605
  <slot name="label" @slotchange="${this.handleLabelSlotChange}"></slot>
@@ -4126,12 +4633,12 @@ class AuroDropdown extends r$1 {
4126
4633
  <div id="bibSizer" part="size"></div>
4127
4634
  <${this.dropdownBibTag}
4128
4635
  id="bib"
4129
- role="tooltip"
4130
4636
  ?data-show="${this.isPopoverVisible}"
4131
4637
  ?isfullscreen="${this.isBibFullscreen}"
4132
4638
  ?common="${this.common}"
4133
4639
  ?rounded="${this.common || this.rounded}"
4134
- ?inset="${this.common || this.inset}">
4640
+ ?inset="${this.common || this.inset}"
4641
+ >
4135
4642
  </${this.dropdownBibTag}>
4136
4643
  </div>
4137
4644
  `;
@@ -7953,175 +8460,583 @@ class AuroInputUtilities {
7953
8460
  blocks.dd = { mask: IMask.MaskedRange, from: 1, to: 31 };
7954
8461
  }
7955
8462
 
7956
- return {
7957
- mask: Date,
7958
- pattern: dateFormat,
7959
- blocks,
7960
- format(date) {
7961
- if (!date) {
7962
- return '';
7963
- }
8463
+ return {
8464
+ mask: Date,
8465
+ pattern: dateFormat,
8466
+ blocks,
8467
+ format(date) {
8468
+ if (!date) {
8469
+ return '';
8470
+ }
8471
+
8472
+ const day = date.getDate()
8473
+ .toString()
8474
+ .padStart(2, '0');
8475
+ const month = (date.getMonth() + 1)
8476
+ .toString()
8477
+ .padStart(2, '0');
8478
+ const year = date
8479
+ .getFullYear()
8480
+ .toString();
8481
+ const shortYear = year.slice(-2);
8482
+
8483
+ let formattedDate = this.mask;
8484
+
8485
+ if (formattedDate.includes('dd')) {
8486
+ formattedDate = formattedDate.replace('dd', day);
8487
+ }
8488
+
8489
+ if (formattedDate.includes('mm')) {
8490
+ formattedDate = formattedDate.replace('mm', month);
8491
+ }
8492
+
8493
+ if (formattedDate.includes('yyyy')) {
8494
+ formattedDate = formattedDate.replace('yyyy', year);
8495
+ }
8496
+
8497
+ if (formattedDate.includes('yy')) {
8498
+ formattedDate = formattedDate.replace('yy', shortYear);
8499
+ }
8500
+
8501
+ return formattedDate;
8502
+ },
8503
+ parse(str) {
8504
+ if (!str) {
8505
+ return null;
8506
+ }
8507
+
8508
+ const parts = str.split('/');
8509
+ const formatParts = this.mask.split('/');
8510
+
8511
+ let day = 1, month, year = new Date().getFullYear();
8512
+
8513
+ formatParts.forEach((part, index) => {
8514
+ if (part === 'dd') {
8515
+ day = parseInt(parts[index]) || 1;
8516
+ }
8517
+
8518
+ if (part === 'mm') {
8519
+ month = parseInt(parts[index]) - 1;
8520
+ }
8521
+
8522
+ if (part === 'yyyy') {
8523
+ year = parseInt(parts[index]);
8524
+ }
8525
+
8526
+ if (part === 'yy') {
8527
+ year = parseInt(parts[index]);
8528
+ year = year <= 25 ? 2000 + year : 1900 + year;
8529
+ }
8530
+ });
8531
+
8532
+ if (isNaN(month) || isNaN(year)) {
8533
+ return null;
8534
+ }
8535
+ return new Date(year, month, day);
8536
+ },
8537
+ lazy: true,
8538
+ placeholderChar: ''
8539
+ };
8540
+ }
8541
+ }
8542
+
8543
+ if (format) {
8544
+ return {
8545
+ mask: format,
8546
+ placeholderChar: '',
8547
+ lazy: true
8548
+ };
8549
+ }
8550
+
8551
+ return {};
8552
+ }
8553
+
8554
+ /**
8555
+ * @private
8556
+ * @param {string} dateStr - Date string to format.
8557
+ * @param {string} format - Date format to use.
8558
+ * @returns {void}
8559
+ */
8560
+ toNorthAmericanFormat(dateStr, format) {
8561
+ const parsedDate = this.parseDate(dateStr, format);
8562
+
8563
+ if (!parsedDate) {
8564
+ return parsedDate;
8565
+ }
8566
+
8567
+ const { month, day, year } = parsedDate;
8568
+ const fullYear = (year && year.length === 2) ? `20${year}` : year;
8569
+ const currentYear = new Date().getFullYear();
8570
+
8571
+ const dateParts = [];
8572
+ if (month) {
8573
+ dateParts.push(month);
8574
+ }
8575
+
8576
+ if (day) {
8577
+ dateParts.push(day);
8578
+ }
8579
+
8580
+ if (year) {
8581
+ dateParts.push(year);
8582
+ }
8583
+
8584
+ const comparisonParts = [
8585
+ month || '01',
8586
+ day || '01',
8587
+ fullYear || currentYear
8588
+ ];
8589
+
8590
+ return {
8591
+ formattedDate: dateParts.join('/'),
8592
+ dateForComparison: comparisonParts.join('/')
8593
+ };
8594
+ }
8595
+
8596
+ /**
8597
+ * @private
8598
+ * @param {string} dateStr - Date string to parse.
8599
+ * @param {string} format - Date format to parse.
8600
+ * @returns {void}
8601
+ */
8602
+ parseDate(dateStr, format) {
8603
+ const dateFormat = format || "mm/dd/yyyy";
8604
+
8605
+ // Define mappings for date components with named capture groups
8606
+ const formatPatterns = {
8607
+ 'yyyy': '(?<year>\\d{4})',
8608
+ 'yy': '(?<year>\\d{2})',
8609
+ 'mm': '(?<month>\\d{2})',
8610
+ 'dd': '(?<day>\\d{2})'
8611
+ };
8612
+
8613
+ // Escape slashes and replace format components with regex patterns
8614
+ let regexPattern = dateFormat.replace(/(?:yyyy|yy|mm|dd)/gu, (match) => formatPatterns[match]);
8615
+ regexPattern = `^${regexPattern}$`;
8616
+
8617
+ const regex = new RegExp(regexPattern, 'u');
8618
+ const match = dateStr.match(regex);
8619
+
8620
+ if (match && match.groups) {
8621
+ return {
8622
+ year: match.groups.year,
8623
+ month: match.groups.month,
8624
+ day: match.groups.day
8625
+ };
8626
+ }
8627
+
8628
+ return undefined;
8629
+ }
8630
+ }
8631
+
8632
+ class DateFormatter {
8633
+
8634
+ constructor() {
8635
+
8636
+ /**
8637
+ * @description Parses a date string into its components.
8638
+ * @param {string} dateStr - Date string to parse.
8639
+ * @param {string} format - Date format to parse.
8640
+ * @returns {Object<key["month" | "day" | "year"]: number>|undefined}
8641
+ */
8642
+ this.parseDate = (dateStr, format = 'mm/dd/yyyy') => {
8643
+
8644
+ // Guard Clause: Date string is defined
8645
+ if (!dateStr) {
8646
+ return undefined;
8647
+ }
8648
+
8649
+ // Assume the separator is a "/" a defined in our code base
8650
+ const separator = '/';
8651
+
8652
+ // Get the parts of the date and format
8653
+ const valueParts = dateStr.split(separator);
8654
+ const formatParts = format.split(separator);
8655
+
8656
+ // Check if the value and format have the correct number of parts
8657
+ if (valueParts.length !== formatParts.length) {
8658
+ throw new Error('AuroDatepickerUtilities | parseDate: Date string and format length do not match');
8659
+ }
8660
+
8661
+ // Holds the result to be returned
8662
+ const result = formatParts.reduce((acc, part, index) => {
8663
+ const value = valueParts[index];
8664
+
8665
+ if ((/m/iu).test(part)) {
8666
+ acc.month = value;
8667
+ } else if ((/d/iu).test(part)) {
8668
+ acc.day = value;
8669
+ } else if ((/y/iu).test(part)) {
8670
+ acc.year = value;
8671
+ }
8672
+
8673
+ return acc;
8674
+ }, {});
8675
+
8676
+ // If we found all the parts, return the result
8677
+ if (result.month && result.year) {
8678
+ return result;
8679
+ }
8680
+
8681
+ // Throw an error to let the dev know we were unable to parse the date string
8682
+ throw new Error('AuroDatepickerUtilities | parseDate: Unable to parse date string');
8683
+ };
8684
+
8685
+ /**
8686
+ * Convert a date object to string format.
8687
+ * @param {Object} date - Date to convert to string.
8688
+ * @returns {Object} Returns the date as a string.
8689
+ */
8690
+ this.getDateAsString = (date) => date.toLocaleDateString(undefined, {
8691
+ year: "numeric",
8692
+ month: "2-digit",
8693
+ day: "2-digit",
8694
+ });
8695
+
8696
+ /**
8697
+ * Converts a date string to a North American date format.
8698
+ * @param {String} dateStr - Date to validate.
8699
+ * @param {String} format - Date format to validate against.
8700
+ * @returns {Boolean}
8701
+ */
8702
+ this.toNorthAmericanFormat = (dateStr, format) => {
8703
+
8704
+ if (format === 'mm/dd/yyyy') {
8705
+ return dateStr;
8706
+ }
8707
+
8708
+ const parsedDate = this.parseDate(dateStr, format);
8709
+
8710
+ if (!parsedDate) {
8711
+ throw new Error('AuroDatepickerUtilities | toNorthAmericanFormat: Unable to parse date string');
8712
+ }
8713
+
8714
+ const { month, day, year } = parsedDate;
8715
+
8716
+ const dateParts = [];
8717
+ if (month) {
8718
+ dateParts.push(month);
8719
+ }
8720
+
8721
+ if (day) {
8722
+ dateParts.push(day);
8723
+ }
8724
+
8725
+ if (year) {
8726
+ dateParts.push(year);
8727
+ }
8728
+
8729
+ return dateParts.join('/');
8730
+ };
8731
+ }
8732
+ }
8733
+ const dateFormatter = new DateFormatter();
8734
+
8735
+ // filepath: dateConstraints.mjs
8736
+ const DATE_UTIL_CONSTRAINTS = {
8737
+ maxDay: 31,
8738
+ maxMonth: 12,
8739
+ maxYear: 2400,
8740
+ minDay: 1,
8741
+ minMonth: 1,
8742
+ minYear: 1900,
8743
+ };
8744
+
8745
+ class AuroDateUtilitiesBase {
8746
+
8747
+ /**
8748
+ * @description The maximum day value allowed by the various utilities in this class.
8749
+ * @readonly
8750
+ * @type {Number}
8751
+ */
8752
+ get maxDay() {
8753
+ return DATE_UTIL_CONSTRAINTS.maxDay;
8754
+ }
8755
+
8756
+ /**
8757
+ * @description The maximum month value allowed by the various utilities in this class.
8758
+ * @readonly
8759
+ * @type {Number}
8760
+ */
8761
+ get maxMonth() {
8762
+ return DATE_UTIL_CONSTRAINTS.maxMonth;
8763
+ }
8764
+
8765
+ /**
8766
+ * @description The maximum year value allowed by the various utilities in this class.
8767
+ * @readonly
8768
+ * @type {Number}
8769
+ */
8770
+ get maxYear() {
8771
+ return DATE_UTIL_CONSTRAINTS.maxYear;
8772
+ }
8773
+
8774
+ /**
8775
+ * @description The minimum day value allowed by the various utilities in this class.
8776
+ * @readonly
8777
+ * @type {Number}
8778
+ */
8779
+ get minDay() {
8780
+ return DATE_UTIL_CONSTRAINTS.minDay;
8781
+ }
8782
+
8783
+ /**
8784
+ * @description The minimum month value allowed by the various utilities in this class.
8785
+ * @readonly
8786
+ * @type {Number}
8787
+ */
8788
+ get minMonth() {
8789
+ return DATE_UTIL_CONSTRAINTS.minMonth;
8790
+ }
8791
+
8792
+ /**
8793
+ * @description The minimum year value allowed by the various utilities in this class.
8794
+ * @readonly
8795
+ * @type {Number}
8796
+ */
8797
+ get minYear() {
8798
+ return DATE_UTIL_CONSTRAINTS.minYear;
8799
+ }
8800
+ }
8801
+
8802
+ /* eslint-disable no-magic-numbers */
8803
+
8804
+ class AuroDateUtilities extends AuroDateUtilitiesBase {
8805
+
8806
+ /**
8807
+ * Returns the current century.
8808
+ * @returns {String} The current century.
8809
+ */
8810
+ getCentury () {
8811
+ return String(new Date().getFullYear()).slice(0, 2);
8812
+ }
8813
+
8814
+ /**
8815
+ * Returns a four digit year.
8816
+ * @param {String} year - The year to convert to four digits.
8817
+ * @returns {String} The four digit year.
8818
+ */
8819
+ getFourDigitYear (year) {
8820
+
8821
+ const strYear = String(year).trim();
8822
+ return strYear.length <= 2 ? this.getCentury() + strYear : strYear;
8823
+ }
8824
+
8825
+ constructor() {
8826
+
8827
+ super();
8828
+
8829
+ /**
8830
+ * Compares two dates to see if they match.
8831
+ * @param {Object} date1 - First date to compare.
8832
+ * @param {Object} date2 - Second date to compare.
8833
+ * @returns {Boolean} Returns true if the dates match.
8834
+ */
8835
+ this.datesMatch = (date1, date2) => new Date(date1).getTime() === new Date(date2).getTime();
8836
+
8837
+ /**
8838
+ * Returns true if value passed in is a valid date.
8839
+ * @param {String} date - Date to validate.
8840
+ * @param {String} format - Date format to validate against.
8841
+ * @returns {Boolean}
8842
+ */
8843
+ this.validDateStr = (date, format) => {
8844
+
8845
+ // The length we expect the date string to be
8846
+ const dateStrLength = format.length;
8847
+
8848
+ // Guard Clause: Date and format are defined
8849
+ if (typeof date === "undefined" || typeof format === "undefined") {
8850
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date and format are required');
8851
+ }
8852
+
8853
+ // Guard Clause: Date should be of type string
8854
+ if (typeof date !== "string") {
8855
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date must be a string');
8856
+ }
8857
+
8858
+ // Guard Clause: Format should be of type string
8859
+ if (typeof format !== "string") {
8860
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Format must be a string');
8861
+ }
8862
+
8863
+ // Guard Clause: Length is what we expect it to be
8864
+ if (date.length !== dateStrLength) {
8865
+ return false;
8866
+ }
8867
+ // Get a formatted date string and parse it
8868
+ const dateParts = dateFormatter.parseDate(date, format);
8869
+
8870
+ // Guard Clause: Date parse succeeded
8871
+ if (!dateParts) {
8872
+ return false;
8873
+ }
7964
8874
 
7965
- const day = date.getDate()
7966
- .toString()
7967
- .padStart(2, '0');
7968
- const month = (date.getMonth() + 1)
7969
- .toString()
7970
- .padStart(2, '0');
7971
- const year = date
7972
- .getFullYear()
7973
- .toString();
7974
- const shortYear = year.slice(-2);
8875
+ // Create the expected date string based on the date parts
8876
+ const expectedDateStr = `${dateParts.month}/${dateParts.day || "01"}/${this.getFourDigitYear(dateParts.year)}`;
7975
8877
 
7976
- let formattedDate = this.mask;
8878
+ // Generate a date object that we will extract a string date from to compare to the passed in date string
8879
+ const dateObj = new Date(this.getFourDigitYear(dateParts.year), dateParts.month - 1, dateParts.day || 1);
7977
8880
 
7978
- if (formattedDate.includes('dd')) {
7979
- formattedDate = formattedDate.replace('dd', day);
7980
- }
8881
+ // Get the date string of the date object we created from the string date
8882
+ const actualDateStr = dateFormatter.getDateAsString(dateObj);
7981
8883
 
7982
- if (formattedDate.includes('mm')) {
7983
- formattedDate = formattedDate.replace('mm', month);
7984
- }
8884
+ // Guard Clause: Generated date matches date string input
8885
+ if (expectedDateStr !== actualDateStr) {
8886
+ return false;
8887
+ }
7985
8888
 
7986
- if (formattedDate.includes('yyyy')) {
7987
- formattedDate = formattedDate.replace('yyyy', year);
7988
- }
8889
+ // If we passed all other checks, we can assume the date is valid
8890
+ return true;
8891
+ };
7989
8892
 
7990
- if (formattedDate.includes('yy')) {
7991
- formattedDate = formattedDate.replace('yy', shortYear);
7992
- }
8893
+ /**
8894
+ * Determines if a string date value matches the format provided.
8895
+ * @param {string} value = The date string value.
8896
+ * @param { string} format = The date format to match against.
8897
+ * @returns {boolean}
8898
+ */
8899
+ this.dateAndFormatMatch = (value, format) => {
7993
8900
 
7994
- return formattedDate;
7995
- },
7996
- parse(str) {
7997
- if (!str) {
7998
- return null;
7999
- }
8901
+ // Ensure we have both values we need to do the comparison
8902
+ if (!value || !format) {
8903
+ throw new Error('AuroFormValidation | dateFormatMatch: value and format are required');
8904
+ }
8000
8905
 
8001
- const parts = str.split('/');
8002
- const formatParts = this.mask.split('/');
8906
+ // If the lengths are different, they cannot match
8907
+ if (value.length !== format.length) {
8908
+ return false;
8909
+ }
8003
8910
 
8004
- let day = 1, month, year = new Date().getFullYear();
8911
+ // Get the parts of the date
8912
+ const dateParts = dateFormatter.parseDate(value, format);
8005
8913
 
8006
- formatParts.forEach((part, index) => {
8007
- if (part === 'dd') {
8008
- day = parseInt(parts[index]) || 1;
8009
- }
8914
+ // Validator for day
8915
+ const dayValueIsValid = (day) => {
8010
8916
 
8011
- if (part === 'mm') {
8012
- month = parseInt(parts[index]) - 1;
8013
- }
8917
+ // Guard clause: if there is no day in the dateParts, we can ignore this check.
8918
+ if (!dateParts.day) {
8919
+ return true;
8920
+ }
8014
8921
 
8015
- if (part === 'yyyy') {
8016
- year = parseInt(parts[index]);
8017
- }
8922
+ // Guard clause: ensure day exists.
8923
+ if (!day) {
8924
+ return false;
8925
+ }
8018
8926
 
8019
- if (part === 'yy') {
8020
- year = parseInt(parts[index]);
8021
- year = year <= 25 ? 2000 + year : 1900 + year;
8022
- }
8023
- });
8927
+ // Convert day to number
8928
+ const numDay = Number.parseInt(day, 10);
8024
8929
 
8025
- if (isNaN(month) || isNaN(year)) {
8026
- return null;
8027
- }
8028
- return new Date(year, month, day);
8029
- },
8030
- lazy: true,
8031
- placeholderChar: ''
8032
- };
8033
- }
8034
- }
8930
+ // Guard clause: ensure day is a valid integer
8931
+ if (Number.isNaN(numDay)) {
8932
+ throw new Error('AuroDatepickerUtilities | dayValueIsValid: Unable to parse day value integer');
8933
+ }
8035
8934
 
8036
- if (format) {
8037
- return {
8038
- mask: format,
8039
- placeholderChar: '',
8040
- lazy: true
8041
- };
8042
- }
8935
+ // Guard clause: ensure day is within the valid range
8936
+ if (numDay < this.minDay || numDay > this.maxDay) {
8937
+ return false;
8938
+ }
8043
8939
 
8044
- return {};
8045
- }
8940
+ // Default return
8941
+ return true;
8942
+ };
8046
8943
 
8047
- /**
8048
- * @private
8049
- * @param {string} dateStr - Date string to format.
8050
- * @param {string} format - Date format to use.
8051
- * @returns {void}
8052
- */
8053
- toNorthAmericanFormat(dateStr, format) {
8054
- const parsedDate = this.parseDate(dateStr, format);
8944
+ // Validator for month
8945
+ const monthValueIsValid = (month) => {
8055
8946
 
8056
- if (!parsedDate) {
8057
- return parsedDate;
8058
- }
8947
+ // Guard clause: ensure month exists.
8948
+ if (!month) {
8949
+ return false;
8950
+ }
8059
8951
 
8060
- const { month, day, year } = parsedDate;
8061
- const fullYear = (year && year.length === 2) ? `20${year}` : year;
8062
- const currentYear = new Date().getFullYear();
8952
+ // Convert month to number
8953
+ const numMonth = Number.parseInt(month, 10);
8063
8954
 
8064
- const dateParts = [];
8065
- if (month) {
8066
- dateParts.push(month);
8067
- }
8955
+ // Guard clause: ensure month is a valid integer
8956
+ if (Number.isNaN(numMonth)) {
8957
+ throw new Error('AuroDatepickerUtilities | monthValueIsValid: Unable to parse month value integer');
8958
+ }
8068
8959
 
8069
- if (day) {
8070
- dateParts.push(day);
8071
- }
8960
+ // Guard clause: ensure month is within the valid range
8961
+ if (numMonth < this.minMonth || numMonth > this.maxMonth) {
8962
+ return false;
8963
+ }
8072
8964
 
8073
- if (year) {
8074
- dateParts.push(year);
8075
- }
8965
+ // Default return
8966
+ return true;
8967
+ };
8076
8968
 
8077
- const comparisonParts = [
8078
- month || '01',
8079
- day || '01',
8080
- fullYear || currentYear
8081
- ];
8969
+ // Validator for year
8970
+ const yearIsValid = (_year) => {
8082
8971
 
8083
- return {
8084
- formattedDate: dateParts.join('/'),
8085
- dateForComparison: comparisonParts.join('/')
8086
- };
8087
- }
8972
+ // Guard clause: ensure year exists.
8973
+ if (!_year) {
8974
+ return false;
8975
+ }
8088
8976
 
8089
- /**
8090
- * @private
8091
- * @param {string} dateStr - Date string to parse.
8092
- * @param {string} format - Date format to parse.
8093
- * @returns {void}
8094
- */
8095
- parseDate(dateStr, format) {
8096
- const dateFormat = format || "mm/dd/yyyy";
8977
+ // Get the full year
8978
+ const year = this.getFourDigitYear(_year);
8097
8979
 
8098
- // Define mappings for date components with named capture groups
8099
- const formatPatterns = {
8100
- 'yyyy': '(?<year>\\d{4})',
8101
- 'yy': '(?<year>\\d{2})',
8102
- 'mm': '(?<month>\\d{2})',
8103
- 'dd': '(?<day>\\d{2})'
8104
- };
8980
+ // Convert year to number
8981
+ const numYear = Number.parseInt(year, 10);
8105
8982
 
8106
- // Escape slashes and replace format components with regex patterns
8107
- let regexPattern = dateFormat.replace(/(?:yyyy|yy|mm|dd)/gu, (match) => formatPatterns[match]);
8108
- regexPattern = `^${regexPattern}$`;
8983
+ // Guard clause: ensure year is a valid integer
8984
+ if (Number.isNaN(numYear)) {
8985
+ throw new Error('AuroDatepickerUtilities | yearValueIsValid: Unable to parse year value integer');
8986
+ }
8109
8987
 
8110
- const regex = new RegExp(regexPattern, 'u');
8111
- const match = dateStr.match(regex);
8988
+ // Guard clause: ensure year is within the valid range
8989
+ if (numYear < this.minYear || numYear > this.maxYear) {
8990
+ return false;
8991
+ }
8112
8992
 
8113
- if (match && match.groups) {
8114
- return {
8115
- year: match.groups.year,
8116
- month: match.groups.month,
8117
- day: match.groups.day
8993
+ // Default return
8994
+ return true;
8118
8995
  };
8119
- }
8120
8996
 
8121
- return undefined;
8997
+ // Self-contained checks for month, day, and year
8998
+ const checks = [
8999
+ monthValueIsValid(dateParts.month),
9000
+ dayValueIsValid(dateParts.day),
9001
+ yearIsValid(dateParts.year)
9002
+ ];
9003
+
9004
+ // If any of the checks failed, the date format does not match and the result is invalid
9005
+ const isValid = checks.every((check) => check === true);
9006
+
9007
+ // If the check is invalid, return false
9008
+ if (!isValid) {
9009
+ return false;
9010
+ }
9011
+
9012
+ // Default case
9013
+ return true;
9014
+ };
8122
9015
  }
8123
9016
  }
8124
9017
 
9018
+ // Export a class instance
9019
+ const dateUtilities = new AuroDateUtilities();
9020
+
9021
+ // Export the class instance methods individually
9022
+ const {
9023
+ datesMatch,
9024
+ validDateStr,
9025
+ dateAndFormatMatch,
9026
+ minDay,
9027
+ minMonth,
9028
+ minYear,
9029
+ maxDay,
9030
+ maxMonth,
9031
+ maxYear
9032
+ } = dateUtilities;
9033
+
9034
+ const {
9035
+ toNorthAmericanFormat,
9036
+ parseDate,
9037
+ getDateAsString
9038
+ } = dateFormatter;
9039
+
8125
9040
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
8126
9041
  // See LICENSE in the project root for license information.
8127
9042
 
@@ -8197,6 +9112,7 @@ let AuroLibraryRuntimeUtils$1$1 = class AuroLibraryRuntimeUtils {
8197
9112
 
8198
9113
 
8199
9114
  class AuroFormValidation {
9115
+
8200
9116
  constructor() {
8201
9117
  this.runtimeUtils = new AuroLibraryRuntimeUtils$1$1();
8202
9118
  }
@@ -8288,17 +9204,17 @@ class AuroFormValidation {
8288
9204
  ]
8289
9205
  }
8290
9206
  };
8291
-
9207
+
8292
9208
  let elementType;
8293
9209
  if (this.runtimeUtils.elementMatch(elem, 'auro-input')) {
8294
9210
  elementType = 'input';
8295
9211
  } else if (this.runtimeUtils.elementMatch(elem, 'auro-counter') || this.runtimeUtils.elementMatch(elem, 'auro-counter-group')) {
8296
9212
  elementType = 'counter';
8297
9213
  }
8298
-
9214
+
8299
9215
  if (elementType) {
8300
9216
  const rules = validationRules[elementType];
8301
-
9217
+
8302
9218
  if (rules) {
8303
9219
  Object.values(rules).flat().forEach(rule => {
8304
9220
  if (rule.check(elem)) {
@@ -8324,48 +9240,82 @@ class AuroFormValidation {
8324
9240
  if (!elem.value.match(emailRegex)) {
8325
9241
  elem.validity = 'patternMismatch';
8326
9242
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
9243
+ return;
8327
9244
  }
8328
9245
  } else if (elem.type === 'credit-card') {
8329
9246
  if (elem.value.length > 0 && elem.value.length < elem.validationCCLength) {
8330
9247
  elem.validity = 'tooShort';
8331
9248
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
9249
+ return;
8332
9250
  }
8333
9251
  } else if (elem.type === 'number') {
8334
9252
  if (elem.max !== undefined && Number(elem.max) < Number(elem.value)) {
8335
9253
  elem.validity = 'rangeOverflow';
8336
9254
  elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
9255
+ return;
8337
9256
  }
8338
9257
 
8339
9258
  if (elem.min !== undefined && elem.value?.length > 0 && Number(elem.min) > Number(elem.value)) {
8340
9259
  elem.validity = 'rangeUnderflow';
8341
9260
  elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
9261
+ return;
8342
9262
  }
8343
- } else if (elem.type === 'date') {
8344
- if (elem.value?.length > 0 && elem.value?.length < elem.lengthForType) {
9263
+ } else if (elem.type === 'date' && elem.value?.length > 0) {
9264
+
9265
+ // Guard Clause: if the value is too short
9266
+ if (elem.value.length < elem.lengthForType) {
9267
+
8345
9268
  elem.validity = 'tooShort';
8346
9269
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
8347
- } else if (elem.value?.length === elem.lengthForType && elem.util.toNorthAmericanFormat(elem.value, elem.format)) {
8348
- const formattedValue = elem.util.toNorthAmericanFormat(elem.value, elem.format);
8349
- const valueDate = new Date(formattedValue.dateForComparison);
9270
+ return;
9271
+ }
9272
+
9273
+ // Guard Clause: If the value is too long for the type
9274
+ if (elem.value?.length > elem.lengthForType) {
9275
+
9276
+ elem.validity = 'tooLong';
9277
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
9278
+ return;
9279
+ }
9280
+
9281
+ // Validate that the date passed was the correct format
9282
+ if (!dateAndFormatMatch(elem.value, elem.format)) {
9283
+ elem.validity = 'patternMismatch';
9284
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || 'Invalid Date Format Entered';
9285
+ return;
9286
+ }
9287
+
9288
+ // Validate that the date passed was a valid date
9289
+ if (!validDateStr(elem.value, elem.format)) {
9290
+ elem.validity = 'invalidDate';
9291
+ elem.errorMessage = elem.setCustomValidityInvalidDate || elem.setCustomValidity || 'Invalid Date Entered';
9292
+ return;
9293
+ }
8350
9294
 
8351
- // validate max
8352
- if (elem.max?.length === elem.lengthForType) {
8353
- const maxDate = new Date(elem.util.toNorthAmericanFormat(elem.max, elem.format).dateForComparison);
9295
+ // Perform the rest of the validation
9296
+ const formattedValue = toNorthAmericanFormat(elem.value, elem.format);
9297
+ const valueDate = new Date(formattedValue);
8354
9298
 
8355
- if (valueDate > maxDate) {
8356
- elem.validity = 'rangeOverflow';
8357
- elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
8358
- }
9299
+ // // Validate max date
9300
+ if (elem.max?.length === elem.lengthForType) {
9301
+
9302
+ const maxDate = new Date(toNorthAmericanFormat(elem.max, elem.format));
9303
+
9304
+ if (valueDate > maxDate) {
9305
+ elem.validity = 'rangeOverflow';
9306
+ elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
9307
+ return;
8359
9308
  }
9309
+ }
8360
9310
 
8361
- // validate min
8362
- if (elem.min?.length === elem.lengthForType) {
8363
- const minDate = new Date(elem.util.toNorthAmericanFormat(elem.min, elem.format).dateForComparison);
9311
+ // Validate min date
9312
+ if (elem.min?.length === elem.lengthForType) {
9313
+ const minDate = new Date(toNorthAmericanFormat(elem.min, elem.format));
8364
9314
 
8365
- if (valueDate < minDate) {
8366
- elem.validity = 'rangeUnderflow';
8367
- elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
8368
- }
9315
+ if (valueDate < minDate) {
9316
+ elem.validity = 'rangeUnderflow';
9317
+ elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
9318
+ return;
8369
9319
  }
8370
9320
  }
8371
9321
  }
@@ -8484,7 +9434,7 @@ class AuroFormValidation {
8484
9434
  if (input.validationMessage.length > 0) {
8485
9435
  elem.errorMessage = input.validationMessage;
8486
9436
  }
8487
- } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
9437
+ } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
8488
9438
  const firstInput = this.inputElements[0];
8489
9439
 
8490
9440
  if (firstInput.validationMessage.length > 0) {
@@ -8606,6 +9556,33 @@ class BaseInput extends r$1 {
8606
9556
  static get properties() {
8607
9557
  return {
8608
9558
 
9559
+ /**
9560
+ * The value for the role attribute.
9561
+ */
9562
+ a11yRole: {
9563
+ type: String,
9564
+ attribute: true,
9565
+ reflect: true
9566
+ },
9567
+
9568
+ /**
9569
+ * The value for the aria-expanded attribute.
9570
+ */
9571
+ a11yExpanded: {
9572
+ type: Boolean,
9573
+ attribute: true,
9574
+ reflect: true
9575
+ },
9576
+
9577
+ /**
9578
+ * The value for the aria-controls attribute.
9579
+ */
9580
+ a11yControls: {
9581
+ type: String,
9582
+ attribute: true,
9583
+ reflect: true
9584
+ },
9585
+
8609
9586
  /**
8610
9587
  * If set, the label will remain fixed in the active position.
8611
9588
  */
@@ -9247,6 +10224,10 @@ class BaseInput extends r$1 {
9247
10224
  } else if (this.type === 'number') {
9248
10225
  this.inputMode = 'numeric';
9249
10226
  }
10227
+
10228
+ if (this.type === "date" && !this.format) {
10229
+ this.format = 'mm/dd/yyyy';
10230
+ }
9250
10231
  }
9251
10232
 
9252
10233
  /**
@@ -10490,6 +11471,7 @@ var helpTextVersion = '1.0.0';
10490
11471
 
10491
11472
  // build the component class
10492
11473
  class AuroInput extends BaseInput {
11474
+
10493
11475
  constructor() {
10494
11476
  super();
10495
11477
 
@@ -10602,7 +11584,7 @@ class AuroInput extends BaseInput {
10602
11584
  ?required="${this.required}"
10603
11585
  ?disabled="${this.disabled}"
10604
11586
  aria-describedby="${this.uniqueId}"
10605
- aria-invalid="${this.validity !== 'valid'}"
11587
+ ?aria-invalid="${this.validity !== 'valid'}"
10606
11588
  placeholder=${this.getPlaceholder()}
10607
11589
  lang="${o(this.lang)}"
10608
11590
  ?activeLabel="${this.activeLabel}"
@@ -10611,7 +11593,10 @@ class AuroInput extends BaseInput {
10611
11593
  autocapitalize="${o(this.autocapitalize ? this.autocapitalize : undefined)}"
10612
11594
  autocomplete="${o(this.autocomplete ? this.autocomplete : undefined)}"
10613
11595
  part="input"
10614
- />
11596
+ role="${o(this.a11yRole)}"
11597
+ aria-expanded="${o(this.a11yExpanded)}"
11598
+ aria-controls="${o(this.a11yControls)}"
11599
+ />
10615
11600
  </div>
10616
11601
  <div
10617
11602
  class="notificationIcons"
@@ -11603,6 +12588,7 @@ var styleCss$3 = i$5`.util_displayInline{display:inline}.util_displayInlineBlock
11603
12588
 
11604
12589
  // build the component class
11605
12590
  class AuroCombobox extends r$1 {
12591
+
11606
12592
  constructor() {
11607
12593
  super();
11608
12594
 
@@ -11614,6 +12600,8 @@ class AuroCombobox extends r$1 {
11614
12600
  * @returns {void} Internal defaults.
11615
12601
  */
11616
12602
  privateDefaults() {
12603
+ this.dropdownOpen = false;
12604
+ this.dropdownId = undefined;
11617
12605
  this.onDark = false;
11618
12606
 
11619
12607
  this.noFilter = false;
@@ -11693,6 +12681,26 @@ class AuroCombobox extends r$1 {
11693
12681
  reflect: true
11694
12682
  },
11695
12683
 
12684
+ /**
12685
+ * ID for the dropdown
12686
+ * @private
12687
+ */
12688
+ dropdownId: {
12689
+ type: String,
12690
+ reflect: false,
12691
+ attribute: false
12692
+ },
12693
+
12694
+ /**
12695
+ * Whether or not the dropdown is open
12696
+ * @private
12697
+ */
12698
+ dropdownOpen: {
12699
+ type: Boolean,
12700
+ reflect: false,
12701
+ attribute: false
12702
+ },
12703
+
11696
12704
  /**
11697
12705
  * When defined, sets persistent validity to `customError` and sets the validation message to the attribute value.
11698
12706
  */
@@ -11838,11 +12846,8 @@ class AuroCombobox extends r$1 {
11838
12846
  },
11839
12847
 
11840
12848
  /**
11841
- * Defines the screen size breakpoint (`xs`, `sm`, `md`, `lg`, `xl`, `disabled`)
11842
- * at which the dropdown switches to fullscreen mode on mobile. `disabled` indicates a dropdown should _never_ enter fullscreen.
11843
- *
11844
- * When expanded, the dropdown will automatically display in fullscreen mode
11845
- * if the screen size is equal to or smaller than the selected breakpoint.
12849
+ * Defines the screen size breakpoint (`lg`, `md`, `sm`, or `xs`) at which the dropdown switches to fullscreen mode on mobile.
12850
+ * When expanded, the dropdown will automatically display in fullscreen mode if the screen size is equal to or smaller than the selected breakpoint.
11846
12851
  * @default sm
11847
12852
  */
11848
12853
  fullscreenBreakpoint: {
@@ -11854,8 +12859,19 @@ class AuroCombobox extends r$1 {
11854
12859
  * @private
11855
12860
  */
11856
12861
  isDropdownFullscreen: {
11857
- type: Boolean
11858
- }
12862
+ type: Boolean,
12863
+ reflect: false
12864
+ },
12865
+
12866
+ /**
12867
+ * @private
12868
+ * specifies the currently active option
12869
+ */
12870
+ optionActive: {
12871
+ type: Object,
12872
+ reflect: false,
12873
+ attribute: false
12874
+ },
11859
12875
  };
11860
12876
  }
11861
12877
 
@@ -12007,6 +13023,18 @@ class AuroCombobox extends r$1 {
12007
13023
  * @returns {void}
12008
13024
  */
12009
13025
  configureDropdown() {
13026
+
13027
+ // Listen for the ID to be added to the dropdown so we can capture it and use it for accessibility.
13028
+ this.dropdown.addEventListener('auroDropdown-idAdded', (event) => {
13029
+ this.dropdownId = event.detail.id;
13030
+ });
13031
+
13032
+ // Listen for the dropdown to be shown or hidden
13033
+ this.dropdown.addEventListener("auroDropdown-toggled", (ev) => {
13034
+ this.dropdownOpen = ev.detail.expanded;
13035
+ });
13036
+
13037
+ // this.dropdown.addEventListener('auroDropdown-show', () => {
12010
13038
  this.menuWrapper = this.dropdown.querySelector('.menuWrapper');
12011
13039
  this.menuWrapper.append(this.menu);
12012
13040
 
@@ -12020,7 +13048,6 @@ class AuroCombobox extends r$1 {
12020
13048
  this.hideBib = this.hideBib.bind(this);
12021
13049
  this.bibtemplate.addEventListener('close-click', this.hideBib);
12022
13050
 
12023
- this.dropdown.setAttribute('role', 'combobox');
12024
13051
  this.dropdown.addEventListener('auroDropdown-triggerClick', () => {
12025
13052
  this.showBib();
12026
13053
  });
@@ -12036,7 +13063,6 @@ class AuroCombobox extends r$1 {
12036
13063
  this.isDropdownFullscreen = event.detail.strategy === 'fullscreen';
12037
13064
  setTimeout(this.transportInput);
12038
13065
  });
12039
-
12040
13066
  }
12041
13067
 
12042
13068
  /**
@@ -12530,6 +13556,10 @@ class AuroCombobox extends r$1 {
12530
13556
  ?noFlip="${this.noFlip}"
12531
13557
  disableEventShow>
12532
13558
  <${this.inputTag}
13559
+ .a11yRole="${"combobox"}"
13560
+ .a11yExpanded="${this.dropdownOpen}"
13561
+ .a11yControls="${this.dropdownId}"
13562
+ id="${this.id || 'auro-combobox-input'}"
12533
13563
  slot="trigger"
12534
13564
  bordered
12535
13565
  ?onDark="${this.onDark}"