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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/CHANGELOG.md +19 -1
  2. package/components/checkbox/README.md +1 -1
  3. package/components/checkbox/demo/api.min.js +468 -25
  4. package/components/checkbox/demo/index.min.js +468 -25
  5. package/components/checkbox/demo/readme.md +1 -1
  6. package/components/checkbox/dist/index.js +468 -25
  7. package/components/checkbox/dist/registered.js +468 -25
  8. package/components/combobox/README.md +1 -1
  9. package/components/combobox/demo/api.min.js +1125 -74
  10. package/components/combobox/demo/index.min.js +1125 -74
  11. package/components/combobox/demo/readme.md +1 -1
  12. package/components/combobox/dist/auro-combobox.d.ts +30 -0
  13. package/components/combobox/dist/index.js +1125 -74
  14. package/components/combobox/dist/registered.js +1125 -74
  15. package/components/counter/README.md +1 -1
  16. package/components/counter/demo/api.min.js +570 -45
  17. package/components/counter/demo/index.min.js +570 -45
  18. package/components/counter/demo/readme.md +1 -1
  19. package/components/counter/dist/index.js +570 -45
  20. package/components/counter/dist/registered.js +570 -45
  21. package/components/datepicker/README.md +1 -1
  22. package/components/datepicker/demo/api.min.js +1073 -70
  23. package/components/datepicker/demo/index.min.js +1073 -70
  24. package/components/datepicker/demo/readme.md +1 -1
  25. package/components/datepicker/dist/index.js +1073 -70
  26. package/components/datepicker/dist/registered.js +1073 -70
  27. package/components/dropdown/README.md +1 -1
  28. package/components/dropdown/demo/api.md +8 -5
  29. package/components/dropdown/demo/api.min.js +104 -22
  30. package/components/dropdown/demo/index.min.js +104 -22
  31. package/components/dropdown/demo/readme.md +1 -1
  32. package/components/dropdown/dist/auro-dropdown.d.ts +29 -0
  33. package/components/dropdown/dist/index.js +104 -22
  34. package/components/dropdown/dist/registered.js +104 -22
  35. package/components/form/README.md +1 -1
  36. package/components/form/demo/readme.md +1 -1
  37. package/components/input/README.md +1 -1
  38. package/components/input/demo/api.md +4 -1
  39. package/components/input/demo/api.min.js +503 -25
  40. package/components/input/demo/index.min.js +503 -25
  41. package/components/input/demo/readme.md +1 -1
  42. package/components/input/dist/base-input.d.ts +24 -0
  43. package/components/input/dist/index.js +503 -25
  44. package/components/input/dist/registered.js +503 -25
  45. package/components/menu/README.md +1 -1
  46. package/components/menu/demo/readme.md +1 -1
  47. package/components/radio/README.md +1 -1
  48. package/components/radio/demo/api.min.js +468 -25
  49. package/components/radio/demo/index.min.js +468 -25
  50. package/components/radio/demo/readme.md +1 -1
  51. package/components/radio/dist/index.js +468 -25
  52. package/components/radio/dist/registered.js +468 -25
  53. package/components/select/README.md +1 -1
  54. package/components/select/demo/api.min.js +570 -45
  55. package/components/select/demo/index.min.js +570 -45
  56. package/components/select/demo/readme.md +1 -1
  57. package/components/select/dist/index.js +570 -45
  58. package/components/select/dist/registered.js +570 -45
  59. package/package.json +2 -2
@@ -114,11 +114,420 @@ let AuroLibraryRuntimeUtils$4 = class AuroLibraryRuntimeUtils {
114
114
  }
115
115
  };
116
116
 
117
+ let DateFormatter$1 = class DateFormatter {
118
+
119
+ constructor() {
120
+
121
+ /**
122
+ * @description Parses a date string into its components.
123
+ * @param {string} dateStr - Date string to parse.
124
+ * @param {string} format - Date format to parse.
125
+ * @returns {Object<key["month" | "day" | "year"]: number>|undefined}
126
+ */
127
+ this.parseDate = (dateStr, format = 'mm/dd/yyyy') => {
128
+
129
+ // Guard Clause: Date string is defined
130
+ if (!dateStr) {
131
+ return undefined;
132
+ }
133
+
134
+ // Assume the separator is a "/" a defined in our code base
135
+ const separator = '/';
136
+
137
+ // Get the parts of the date and format
138
+ const valueParts = dateStr.split(separator);
139
+ const formatParts = format.split(separator);
140
+
141
+ // Check if the value and format have the correct number of parts
142
+ if (valueParts.length !== formatParts.length) {
143
+ throw new Error('AuroDatepickerUtilities | parseDate: Date string and format length do not match');
144
+ }
145
+
146
+ // Holds the result to be returned
147
+ const result = formatParts.reduce((acc, part, index) => {
148
+ const value = valueParts[index];
149
+
150
+ if ((/m/iu).test(part)) {
151
+ acc.month = value;
152
+ } else if ((/d/iu).test(part)) {
153
+ acc.day = value;
154
+ } else if ((/y/iu).test(part)) {
155
+ acc.year = value;
156
+ }
157
+
158
+ return acc;
159
+ }, {});
160
+
161
+ // If we found all the parts, return the result
162
+ if (result.month && result.year) {
163
+ return result;
164
+ }
165
+
166
+ // Throw an error to let the dev know we were unable to parse the date string
167
+ throw new Error('AuroDatepickerUtilities | parseDate: Unable to parse date string');
168
+ };
169
+
170
+ /**
171
+ * Convert a date object to string format.
172
+ * @param {Object} date - Date to convert to string.
173
+ * @returns {Object} Returns the date as a string.
174
+ */
175
+ this.getDateAsString = (date) => date.toLocaleDateString(undefined, {
176
+ year: "numeric",
177
+ month: "2-digit",
178
+ day: "2-digit",
179
+ });
180
+
181
+ /**
182
+ * Converts a date string to a North American date format.
183
+ * @param {String} dateStr - Date to validate.
184
+ * @param {String} format - Date format to validate against.
185
+ * @returns {Boolean}
186
+ */
187
+ this.toNorthAmericanFormat = (dateStr, format) => {
188
+
189
+ if (format === 'mm/dd/yyyy') {
190
+ return dateStr;
191
+ }
192
+
193
+ const parsedDate = this.parseDate(dateStr, format);
194
+
195
+ if (!parsedDate) {
196
+ throw new Error('AuroDatepickerUtilities | toNorthAmericanFormat: Unable to parse date string');
197
+ }
198
+
199
+ const { month, day, year } = parsedDate;
200
+
201
+ const dateParts = [];
202
+ if (month) {
203
+ dateParts.push(month);
204
+ }
205
+
206
+ if (day) {
207
+ dateParts.push(day);
208
+ }
209
+
210
+ if (year) {
211
+ dateParts.push(year);
212
+ }
213
+
214
+ return dateParts.join('/');
215
+ };
216
+ }
217
+ };
218
+ const dateFormatter$1 = new DateFormatter$1();
219
+
220
+ // filepath: dateConstraints.mjs
221
+ const DATE_UTIL_CONSTRAINTS$1 = {
222
+ maxDay: 31,
223
+ maxMonth: 12,
224
+ maxYear: 2400,
225
+ minDay: 1,
226
+ minMonth: 1,
227
+ minYear: 1900,
228
+ };
229
+
230
+ let AuroDateUtilitiesBase$1 = class AuroDateUtilitiesBase {
231
+
232
+ /**
233
+ * @description The maximum day value allowed by the various utilities in this class.
234
+ * @readonly
235
+ * @type {Number}
236
+ */
237
+ get maxDay() {
238
+ return DATE_UTIL_CONSTRAINTS$1.maxDay;
239
+ }
240
+
241
+ /**
242
+ * @description The maximum month value allowed by the various utilities in this class.
243
+ * @readonly
244
+ * @type {Number}
245
+ */
246
+ get maxMonth() {
247
+ return DATE_UTIL_CONSTRAINTS$1.maxMonth;
248
+ }
249
+
250
+ /**
251
+ * @description The maximum year value allowed by the various utilities in this class.
252
+ * @readonly
253
+ * @type {Number}
254
+ */
255
+ get maxYear() {
256
+ return DATE_UTIL_CONSTRAINTS$1.maxYear;
257
+ }
258
+
259
+ /**
260
+ * @description The minimum day value allowed by the various utilities in this class.
261
+ * @readonly
262
+ * @type {Number}
263
+ */
264
+ get minDay() {
265
+ return DATE_UTIL_CONSTRAINTS$1.minDay;
266
+ }
267
+
268
+ /**
269
+ * @description The minimum month value allowed by the various utilities in this class.
270
+ * @readonly
271
+ * @type {Number}
272
+ */
273
+ get minMonth() {
274
+ return DATE_UTIL_CONSTRAINTS$1.minMonth;
275
+ }
276
+
277
+ /**
278
+ * @description The minimum year value allowed by the various utilities in this class.
279
+ * @readonly
280
+ * @type {Number}
281
+ */
282
+ get minYear() {
283
+ return DATE_UTIL_CONSTRAINTS$1.minYear;
284
+ }
285
+ };
286
+
287
+ /* eslint-disable no-magic-numbers */
288
+
289
+ let AuroDateUtilities$1 = class AuroDateUtilities extends AuroDateUtilitiesBase$1 {
290
+
291
+ /**
292
+ * Returns the current century.
293
+ * @returns {String} The current century.
294
+ */
295
+ getCentury () {
296
+ return String(new Date().getFullYear()).slice(0, 2);
297
+ }
298
+
299
+ /**
300
+ * Returns a four digit year.
301
+ * @param {String} year - The year to convert to four digits.
302
+ * @returns {String} The four digit year.
303
+ */
304
+ getFourDigitYear (year) {
305
+
306
+ const strYear = String(year).trim();
307
+ return strYear.length <= 2 ? this.getCentury() + strYear : strYear;
308
+ }
309
+
310
+ constructor() {
311
+
312
+ super();
313
+
314
+ /**
315
+ * Compares two dates to see if they match.
316
+ * @param {Object} date1 - First date to compare.
317
+ * @param {Object} date2 - Second date to compare.
318
+ * @returns {Boolean} Returns true if the dates match.
319
+ */
320
+ this.datesMatch = (date1, date2) => new Date(date1).getTime() === new Date(date2).getTime();
321
+
322
+ /**
323
+ * Returns true if value passed in is a valid date.
324
+ * @param {String} date - Date to validate.
325
+ * @param {String} format - Date format to validate against.
326
+ * @returns {Boolean}
327
+ */
328
+ this.validDateStr = (date, format) => {
329
+
330
+ // The length we expect the date string to be
331
+ const dateStrLength = format.length;
332
+
333
+ // Guard Clause: Date and format are defined
334
+ if (typeof date === "undefined" || typeof format === "undefined") {
335
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date and format are required');
336
+ }
337
+
338
+ // Guard Clause: Date should be of type string
339
+ if (typeof date !== "string") {
340
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date must be a string');
341
+ }
342
+
343
+ // Guard Clause: Format should be of type string
344
+ if (typeof format !== "string") {
345
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Format must be a string');
346
+ }
347
+
348
+ // Guard Clause: Length is what we expect it to be
349
+ if (date.length !== dateStrLength) {
350
+ return false;
351
+ }
352
+ // Get a formatted date string and parse it
353
+ const dateParts = dateFormatter$1.parseDate(date, format);
354
+
355
+ // Guard Clause: Date parse succeeded
356
+ if (!dateParts) {
357
+ return false;
358
+ }
359
+
360
+ // Create the expected date string based on the date parts
361
+ const expectedDateStr = `${dateParts.month}/${dateParts.day || "01"}/${this.getFourDigitYear(dateParts.year)}`;
362
+
363
+ // Generate a date object that we will extract a string date from to compare to the passed in date string
364
+ const dateObj = new Date(this.getFourDigitYear(dateParts.year), dateParts.month - 1, dateParts.day || 1);
365
+
366
+ // Get the date string of the date object we created from the string date
367
+ const actualDateStr = dateFormatter$1.getDateAsString(dateObj);
368
+
369
+ // Guard Clause: Generated date matches date string input
370
+ if (expectedDateStr !== actualDateStr) {
371
+ return false;
372
+ }
373
+
374
+ // If we passed all other checks, we can assume the date is valid
375
+ return true;
376
+ };
377
+
378
+ /**
379
+ * Determines if a string date value matches the format provided.
380
+ * @param {string} value = The date string value.
381
+ * @param { string} format = The date format to match against.
382
+ * @returns {boolean}
383
+ */
384
+ this.dateAndFormatMatch = (value, format) => {
385
+
386
+ // Ensure we have both values we need to do the comparison
387
+ if (!value || !format) {
388
+ throw new Error('AuroFormValidation | dateFormatMatch: value and format are required');
389
+ }
390
+
391
+ // If the lengths are different, they cannot match
392
+ if (value.length !== format.length) {
393
+ return false;
394
+ }
395
+
396
+ // Get the parts of the date
397
+ const dateParts = dateFormatter$1.parseDate(value, format);
398
+
399
+ // Validator for day
400
+ const dayValueIsValid = (day) => {
401
+
402
+ // Guard clause: if there is no day in the dateParts, we can ignore this check.
403
+ if (!dateParts.day) {
404
+ return true;
405
+ }
406
+
407
+ // Guard clause: ensure day exists.
408
+ if (!day) {
409
+ return false;
410
+ }
411
+
412
+ // Convert day to number
413
+ const numDay = Number.parseInt(day, 10);
414
+
415
+ // Guard clause: ensure day is a valid integer
416
+ if (Number.isNaN(numDay)) {
417
+ throw new Error('AuroDatepickerUtilities | dayValueIsValid: Unable to parse day value integer');
418
+ }
419
+
420
+ // Guard clause: ensure day is within the valid range
421
+ if (numDay < this.minDay || numDay > this.maxDay) {
422
+ return false;
423
+ }
424
+
425
+ // Default return
426
+ return true;
427
+ };
428
+
429
+ // Validator for month
430
+ const monthValueIsValid = (month) => {
431
+
432
+ // Guard clause: ensure month exists.
433
+ if (!month) {
434
+ return false;
435
+ }
436
+
437
+ // Convert month to number
438
+ const numMonth = Number.parseInt(month, 10);
439
+
440
+ // Guard clause: ensure month is a valid integer
441
+ if (Number.isNaN(numMonth)) {
442
+ throw new Error('AuroDatepickerUtilities | monthValueIsValid: Unable to parse month value integer');
443
+ }
444
+
445
+ // Guard clause: ensure month is within the valid range
446
+ if (numMonth < this.minMonth || numMonth > this.maxMonth) {
447
+ return false;
448
+ }
449
+
450
+ // Default return
451
+ return true;
452
+ };
453
+
454
+ // Validator for year
455
+ const yearIsValid = (_year) => {
456
+
457
+ // Guard clause: ensure year exists.
458
+ if (!_year) {
459
+ return false;
460
+ }
461
+
462
+ // Get the full year
463
+ const year = this.getFourDigitYear(_year);
464
+
465
+ // Convert year to number
466
+ const numYear = Number.parseInt(year, 10);
467
+
468
+ // Guard clause: ensure year is a valid integer
469
+ if (Number.isNaN(numYear)) {
470
+ throw new Error('AuroDatepickerUtilities | yearValueIsValid: Unable to parse year value integer');
471
+ }
472
+
473
+ // Guard clause: ensure year is within the valid range
474
+ if (numYear < this.minYear || numYear > this.maxYear) {
475
+ return false;
476
+ }
477
+
478
+ // Default return
479
+ return true;
480
+ };
481
+
482
+ // Self-contained checks for month, day, and year
483
+ const checks = [
484
+ monthValueIsValid(dateParts.month),
485
+ dayValueIsValid(dateParts.day),
486
+ yearIsValid(dateParts.year)
487
+ ];
488
+
489
+ // If any of the checks failed, the date format does not match and the result is invalid
490
+ const isValid = checks.every((check) => check === true);
491
+
492
+ // If the check is invalid, return false
493
+ if (!isValid) {
494
+ return false;
495
+ }
496
+
497
+ // Default case
498
+ return true;
499
+ };
500
+ }
501
+ };
502
+
503
+ // Export a class instance
504
+ const dateUtilities$1 = new AuroDateUtilities$1();
505
+
506
+ // Export the class instance methods individually
507
+ const {
508
+ datesMatch: datesMatch$1,
509
+ validDateStr: validDateStr$1,
510
+ dateAndFormatMatch: dateAndFormatMatch$1,
511
+ minDay: minDay$1,
512
+ minMonth: minMonth$1,
513
+ minYear: minYear$1,
514
+ maxDay: maxDay$1,
515
+ maxMonth: maxMonth$1,
516
+ maxYear: maxYear$1
517
+ } = dateUtilities$1;
518
+
519
+ const {
520
+ toNorthAmericanFormat: toNorthAmericanFormat$1,
521
+ parseDate: parseDate$1,
522
+ getDateAsString: getDateAsString$1
523
+ } = dateFormatter$1;
524
+
117
525
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
118
526
  // See LICENSE in the project root for license information.
119
527
 
120
528
 
121
529
  let AuroFormValidation$1 = class AuroFormValidation {
530
+
122
531
  constructor() {
123
532
  this.runtimeUtils = new AuroLibraryRuntimeUtils$4();
124
533
  }
@@ -210,17 +619,17 @@ let AuroFormValidation$1 = class AuroFormValidation {
210
619
  ]
211
620
  }
212
621
  };
213
-
622
+
214
623
  let elementType;
215
624
  if (this.runtimeUtils.elementMatch(elem, 'auro-input')) {
216
625
  elementType = 'input';
217
626
  } else if (this.runtimeUtils.elementMatch(elem, 'auro-counter') || this.runtimeUtils.elementMatch(elem, 'auro-counter-group')) {
218
627
  elementType = 'counter';
219
628
  }
220
-
629
+
221
630
  if (elementType) {
222
631
  const rules = validationRules[elementType];
223
-
632
+
224
633
  if (rules) {
225
634
  Object.values(rules).flat().forEach(rule => {
226
635
  if (rule.check(elem)) {
@@ -246,48 +655,82 @@ let AuroFormValidation$1 = class AuroFormValidation {
246
655
  if (!elem.value.match(emailRegex)) {
247
656
  elem.validity = 'patternMismatch';
248
657
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
658
+ return;
249
659
  }
250
660
  } else if (elem.type === 'credit-card') {
251
661
  if (elem.value.length > 0 && elem.value.length < elem.validationCCLength) {
252
662
  elem.validity = 'tooShort';
253
663
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
664
+ return;
254
665
  }
255
666
  } else if (elem.type === 'number') {
256
667
  if (elem.max !== undefined && Number(elem.max) < Number(elem.value)) {
257
668
  elem.validity = 'rangeOverflow';
258
669
  elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
670
+ return;
259
671
  }
260
672
 
261
673
  if (elem.min !== undefined && elem.value?.length > 0 && Number(elem.min) > Number(elem.value)) {
262
674
  elem.validity = 'rangeUnderflow';
263
675
  elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
676
+ return;
264
677
  }
265
- } else if (elem.type === 'date') {
266
- if (elem.value?.length > 0 && elem.value?.length < elem.lengthForType) {
678
+ } else if (elem.type === 'date' && elem.value?.length > 0) {
679
+
680
+ // Guard Clause: if the value is too short
681
+ if (elem.value.length < elem.lengthForType) {
682
+
267
683
  elem.validity = 'tooShort';
268
684
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
269
- } else if (elem.value?.length === elem.lengthForType && elem.util.toNorthAmericanFormat(elem.value, elem.format)) {
270
- const formattedValue = elem.util.toNorthAmericanFormat(elem.value, elem.format);
271
- const valueDate = new Date(formattedValue.dateForComparison);
685
+ return;
686
+ }
687
+
688
+ // Guard Clause: If the value is too long for the type
689
+ if (elem.value?.length > elem.lengthForType) {
690
+
691
+ elem.validity = 'tooLong';
692
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
693
+ return;
694
+ }
695
+
696
+ // Validate that the date passed was the correct format
697
+ if (!dateAndFormatMatch$1(elem.value, elem.format)) {
698
+ elem.validity = 'patternMismatch';
699
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || 'Invalid Date Format Entered';
700
+ return;
701
+ }
702
+
703
+ // Validate that the date passed was a valid date
704
+ if (!validDateStr$1(elem.value, elem.format)) {
705
+ elem.validity = 'invalidDate';
706
+ elem.errorMessage = elem.setCustomValidityInvalidDate || elem.setCustomValidity || 'Invalid Date Entered';
707
+ return;
708
+ }
272
709
 
273
- // validate max
274
- if (elem.max?.length === elem.lengthForType) {
275
- const maxDate = new Date(elem.util.toNorthAmericanFormat(elem.max, elem.format).dateForComparison);
710
+ // Perform the rest of the validation
711
+ const formattedValue = toNorthAmericanFormat$1(elem.value, elem.format);
712
+ const valueDate = new Date(formattedValue);
276
713
 
277
- if (valueDate > maxDate) {
278
- elem.validity = 'rangeOverflow';
279
- elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
280
- }
714
+ // // Validate max date
715
+ if (elem.max?.length === elem.lengthForType) {
716
+
717
+ const maxDate = new Date(toNorthAmericanFormat$1(elem.max, elem.format));
718
+
719
+ if (valueDate > maxDate) {
720
+ elem.validity = 'rangeOverflow';
721
+ elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
722
+ return;
281
723
  }
724
+ }
282
725
 
283
- // validate min
284
- if (elem.min?.length === elem.lengthForType) {
285
- const minDate = new Date(elem.util.toNorthAmericanFormat(elem.min, elem.format).dateForComparison);
726
+ // Validate min date
727
+ if (elem.min?.length === elem.lengthForType) {
728
+ const minDate = new Date(toNorthAmericanFormat$1(elem.min, elem.format));
286
729
 
287
- if (valueDate < minDate) {
288
- elem.validity = 'rangeUnderflow';
289
- elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
290
- }
730
+ if (valueDate < minDate) {
731
+ elem.validity = 'rangeUnderflow';
732
+ elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
733
+ return;
291
734
  }
292
735
  }
293
736
  }
@@ -406,7 +849,7 @@ let AuroFormValidation$1 = class AuroFormValidation {
406
849
  if (input.validationMessage.length > 0) {
407
850
  elem.errorMessage = input.validationMessage;
408
851
  }
409
- } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
852
+ } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
410
853
  const firstInput = this.inputElements[0];
411
854
 
412
855
  if (firstInput.validationMessage.length > 0) {
@@ -2268,7 +2711,7 @@ class AuroFloatingUI {
2268
2711
  /**
2269
2712
  * @private
2270
2713
  * getting called on 'blur' in trigger or `focusin` in document
2271
- *
2714
+ *
2272
2715
  * Hides the bib if focus moves outside of the trigger or bib, unless a 'noHideOnThisFocusLoss' flag is set.
2273
2716
  * This method checks if the currently active element is still within the trigger or bib.
2274
2717
  * If not, and if the bib isn't in fullscreen mode with focus lost, it hides the bib.
@@ -2384,7 +2827,7 @@ class AuroFloatingUI {
2384
2827
  // Close any other dropdown that is already open
2385
2828
  const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
2386
2829
  if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this &&
2387
- existedVisibleFloatingUI.isPopoverVisible &&
2830
+ existedVisibleFloatingUI.element.isPopoverVisible &&
2388
2831
  document.expandedAuroFloater.eventPrefix === this.eventPrefix) {
2389
2832
  document.expandedAuroFloater.hideBib();
2390
2833
  }
@@ -2560,7 +3003,7 @@ class AuroFloatingUI {
2560
3003
  this.id = window.crypto.randomUUID();
2561
3004
  this.element.setAttribute('id', this.id);
2562
3005
  }
2563
-
3006
+
2564
3007
  this.element.bib.setAttribute("id", `${this.id}-floater-bib`);
2565
3008
  }
2566
3009
 
@@ -2613,7 +3056,7 @@ class AuroFloatingUI {
2613
3056
  if (this.element.bib) {
2614
3057
  this.element.shadowRoot.append(this.element.bib);
2615
3058
  }
2616
-
3059
+
2617
3060
  // Remove event & keyboard listeners
2618
3061
  if (this.element?.trigger) {
2619
3062
  this.element.trigger.removeEventListener('keydown', this.handleEvent);
@@ -3344,6 +3787,7 @@ var helpTextVersion$1 = '1.0.0';
3344
3787
  * @csspart helpText - The helpText content container.
3345
3788
  * @event auroDropdown-triggerClick - Notifies that the trigger has been clicked.
3346
3789
  * @event auroDropdown-toggled - Notifies that the visibility of the dropdown bib has changed.
3790
+ * @event auroDropdown-idAdded - Notifies consumers that the unique ID for the dropdown bib has been generated.
3347
3791
  */
3348
3792
  class AuroDropdown extends LitElement {
3349
3793
  constructor() {
@@ -3389,7 +3833,9 @@ class AuroDropdown extends LitElement {
3389
3833
  this.rounded = false;
3390
3834
  this.tabIndex = 0;
3391
3835
  this.noToggle = false;
3836
+ this.a11yAutocomplete = 'none';
3392
3837
  this.labeled = true;
3838
+ this.a11yRole = 'combobox';
3393
3839
  this.onDark = false;
3394
3840
 
3395
3841
  // floaterConfig
@@ -3525,6 +3971,16 @@ class AuroDropdown extends LitElement {
3525
3971
  type: Number
3526
3972
  },
3527
3973
 
3974
+ /**
3975
+ * The unique ID for the dropdown bib element.
3976
+ * @private
3977
+ */
3978
+ dropdownId: {
3979
+ type: String,
3980
+ reflect: false,
3981
+ attribute: false
3982
+ },
3983
+
3528
3984
  /**
3529
3985
  * If declared in combination with `bordered` property or `helpText` slot content, will apply red color to both.
3530
3986
  */
@@ -3692,6 +4148,23 @@ class AuroDropdown extends LitElement {
3692
4148
  */
3693
4149
  tabIndex: {
3694
4150
  type: Number
4151
+ },
4152
+
4153
+ /**
4154
+ * The value for the role attribute of the trigger element.
4155
+ */
4156
+ a11yRole: {
4157
+ type: String || undefined,
4158
+ attribute: false,
4159
+ reflect: false
4160
+ },
4161
+
4162
+ /**
4163
+ * The value for the aria-autocomplete attribute of the trigger element.
4164
+ */
4165
+ a11yAutocomplete: {
4166
+ type: String,
4167
+ attribute: false,
3695
4168
  }
3696
4169
  };
3697
4170
  }
@@ -3753,7 +4226,22 @@ class AuroDropdown extends LitElement {
3753
4226
  }
3754
4227
 
3755
4228
  firstUpdated() {
4229
+
4230
+ // Configure the floater to, this will generate the ID for the bib
3756
4231
  this.floater.configure(this, 'auroDropdown');
4232
+
4233
+ /**
4234
+ * @description Let subscribers know that the dropdown ID ha been generated and added.
4235
+ * @event auroDropdown-idAdded
4236
+ * @type {Object<key: 'id', value: string>} - The ID of the dropdown bib element.
4237
+ */
4238
+ this.dispatchEvent(new CustomEvent('auroDropdown-idAdded', {detail: {id: this.floater.element.id}}));
4239
+
4240
+ // Set the bib ID locally if the user hasn't provided a focusable trigger
4241
+ if (!this.triggerContentFocusable) {
4242
+ this.dropdownId = this.floater.element.id;
4243
+ }
4244
+
3757
4245
  this.bibContent = this.floater.element.bib;
3758
4246
 
3759
4247
  // Add the tag name as an attribute if it is different than the component name
@@ -3905,6 +4393,30 @@ class AuroDropdown extends LitElement {
3905
4393
  });
3906
4394
  }
3907
4395
 
4396
+ /*
4397
+ * Sets aria attributes for the trigger element if a custom one is passed in.
4398
+ * @private
4399
+ * @method setTriggerAriaAttributes
4400
+ * @param { HTMLElement } triggerElement - The custom trigger element.
4401
+ */
4402
+ clearTriggerA11yAttributes(triggerElement) {
4403
+
4404
+ if (!triggerElement || !triggerElement.removeAttribute) {
4405
+ return;
4406
+ }
4407
+
4408
+ // Reset appropriate attributes for a11y
4409
+ triggerElement.removeAttribute('aria-labelledby');
4410
+ if (triggerElement.getAttribute('id') === `${this.id}-trigger-element`) {
4411
+ triggerElement.removeAttribute('id');
4412
+ }
4413
+ triggerElement.removeAttribute('role');
4414
+ triggerElement.removeAttribute('aria-expanded');
4415
+
4416
+ triggerElement.removeAttribute('aria-controls');
4417
+ triggerElement.removeAttribute('aria-autocomplete');
4418
+ }
4419
+
3908
4420
  /**
3909
4421
  * Handles changes to the trigger content slot and updates related properties.
3910
4422
  *
@@ -3918,32 +4430,41 @@ class AuroDropdown extends LitElement {
3918
4430
  * @returns {void}
3919
4431
  */
3920
4432
  handleTriggerContentSlotChange(event) {
4433
+
3921
4434
  this.floater.handleTriggerTabIndex();
3922
4435
 
4436
+ // Get the trigger
4437
+ const trigger = this.shadowRoot.querySelector('#trigger');
4438
+
4439
+ // Get the trigger slot
3923
4440
  const triggerSlot = this.shadowRoot.querySelector('.triggerContent slot');
3924
4441
 
4442
+ // If there's a trigger slot
3925
4443
  if (triggerSlot) {
3926
4444
 
4445
+ // Get the content nodes to see if there are any children
3927
4446
  const triggerContentNodes = triggerSlot.assignedNodes();
3928
4447
 
4448
+ // If there are children
3929
4449
  if (triggerContentNodes) {
3930
4450
 
3931
- triggerContentNodes.forEach((node) => {
3932
- if (!this.triggerContentFocusable) {
3933
- this.triggerContentFocusable = this.containsFocusableElement(node);
3934
- }
3935
- });
3936
- }
3937
- }
4451
+ // See if any of them are focusable elemeents
4452
+ this.triggerContentFocusable = triggerContentNodes.some((node) => this.containsFocusableElement(node));
3938
4453
 
3939
- const trigger = this.shadowRoot.querySelector('#trigger');
4454
+ // If any of them are focusable elements
4455
+ if (this.triggerContentFocusable) {
3940
4456
 
3941
- if (!this.triggerContentFocusable) {
3942
- trigger.setAttribute('tabindex', '0');
3943
- trigger.setAttribute('role', 'button');
3944
- } else {
3945
- trigger.removeAttribute('tabindex');
3946
- trigger.removeAttribute('role');
4457
+ // Assume the consumer will be providing their own a11y in whatever they passed in
4458
+ this.clearTriggerA11yAttributes(trigger);
4459
+
4460
+ // Remove the tabindex from the trigger so it doesn't interrupt focus flow
4461
+ trigger.removeAttribute('tabindex');
4462
+ } else {
4463
+
4464
+ // Add the tabindex to the trigger so that it's in the focus flow
4465
+ trigger.setAttribute('tabindex', '0');
4466
+ }
4467
+ }
3947
4468
  }
3948
4469
 
3949
4470
  if (event) {
@@ -3953,6 +4474,7 @@ class AuroDropdown extends LitElement {
3953
4474
 
3954
4475
  if (this.triggerContentSlot) {
3955
4476
  this.setupTriggerFocusEventBinding();
4477
+
3956
4478
  this.hasTriggerContent = this.triggerContentSlot.some((slot) => {
3957
4479
  if (slot.textContent.trim()) {
3958
4480
  return true;
@@ -4020,10 +4542,13 @@ class AuroDropdown extends LitElement {
4020
4542
  id="trigger"
4021
4543
  class="trigger"
4022
4544
  part="trigger"
4023
- aria-labelledby="triggerLabel"
4024
4545
  tabindex="${this.tabIndex}"
4025
4546
  ?showBorder="${this.showTriggerBorders}"
4026
- >
4547
+ role="${ifDefined(this.triggerContentFocusable ? undefined : this.a11yRole)}"
4548
+ aria-expanded="${ifDefined(this.triggerContentFocusable ? undefined : this.isPopoverVisible)}"
4549
+ aria-controls="${ifDefined(this.triggerContentFocusable ? undefined : this.dropdownId)}"
4550
+ aria-labelledby="${ifDefined(this.triggerContentFocusable ? undefined : 'triggerLabel')}"
4551
+ >
4027
4552
  <div class="triggerContentWrapper">
4028
4553
  <label class="label" id="triggerLabel" hasTrigger=${this.hasTriggerContent}>
4029
4554
  <slot name="label" @slotchange="${this.handleLabelSlotChange}"></slot>
@@ -4057,12 +4582,12 @@ class AuroDropdown extends LitElement {
4057
4582
  <div id="bibSizer" part="size"></div>
4058
4583
  <${this.dropdownBibTag}
4059
4584
  id="bib"
4060
- role="tooltip"
4061
4585
  ?data-show="${this.isPopoverVisible}"
4062
4586
  ?isfullscreen="${this.isBibFullscreen}"
4063
4587
  ?common="${this.common}"
4064
4588
  ?rounded="${this.common || this.rounded}"
4065
- ?inset="${this.common || this.inset}">
4589
+ ?inset="${this.common || this.inset}"
4590
+ >
4066
4591
  </${this.dropdownBibTag}>
4067
4592
  </div>
4068
4593
  `;
@@ -8040,6 +8565,414 @@ class AuroInputUtilities {
8040
8565
  }
8041
8566
  }
8042
8567
 
8568
+ class DateFormatter {
8569
+
8570
+ constructor() {
8571
+
8572
+ /**
8573
+ * @description Parses a date string into its components.
8574
+ * @param {string} dateStr - Date string to parse.
8575
+ * @param {string} format - Date format to parse.
8576
+ * @returns {Object<key["month" | "day" | "year"]: number>|undefined}
8577
+ */
8578
+ this.parseDate = (dateStr, format = 'mm/dd/yyyy') => {
8579
+
8580
+ // Guard Clause: Date string is defined
8581
+ if (!dateStr) {
8582
+ return undefined;
8583
+ }
8584
+
8585
+ // Assume the separator is a "/" a defined in our code base
8586
+ const separator = '/';
8587
+
8588
+ // Get the parts of the date and format
8589
+ const valueParts = dateStr.split(separator);
8590
+ const formatParts = format.split(separator);
8591
+
8592
+ // Check if the value and format have the correct number of parts
8593
+ if (valueParts.length !== formatParts.length) {
8594
+ throw new Error('AuroDatepickerUtilities | parseDate: Date string and format length do not match');
8595
+ }
8596
+
8597
+ // Holds the result to be returned
8598
+ const result = formatParts.reduce((acc, part, index) => {
8599
+ const value = valueParts[index];
8600
+
8601
+ if ((/m/iu).test(part)) {
8602
+ acc.month = value;
8603
+ } else if ((/d/iu).test(part)) {
8604
+ acc.day = value;
8605
+ } else if ((/y/iu).test(part)) {
8606
+ acc.year = value;
8607
+ }
8608
+
8609
+ return acc;
8610
+ }, {});
8611
+
8612
+ // If we found all the parts, return the result
8613
+ if (result.month && result.year) {
8614
+ return result;
8615
+ }
8616
+
8617
+ // Throw an error to let the dev know we were unable to parse the date string
8618
+ throw new Error('AuroDatepickerUtilities | parseDate: Unable to parse date string');
8619
+ };
8620
+
8621
+ /**
8622
+ * Convert a date object to string format.
8623
+ * @param {Object} date - Date to convert to string.
8624
+ * @returns {Object} Returns the date as a string.
8625
+ */
8626
+ this.getDateAsString = (date) => date.toLocaleDateString(undefined, {
8627
+ year: "numeric",
8628
+ month: "2-digit",
8629
+ day: "2-digit",
8630
+ });
8631
+
8632
+ /**
8633
+ * Converts a date string to a North American date format.
8634
+ * @param {String} dateStr - Date to validate.
8635
+ * @param {String} format - Date format to validate against.
8636
+ * @returns {Boolean}
8637
+ */
8638
+ this.toNorthAmericanFormat = (dateStr, format) => {
8639
+
8640
+ if (format === 'mm/dd/yyyy') {
8641
+ return dateStr;
8642
+ }
8643
+
8644
+ const parsedDate = this.parseDate(dateStr, format);
8645
+
8646
+ if (!parsedDate) {
8647
+ throw new Error('AuroDatepickerUtilities | toNorthAmericanFormat: Unable to parse date string');
8648
+ }
8649
+
8650
+ const { month, day, year } = parsedDate;
8651
+
8652
+ const dateParts = [];
8653
+ if (month) {
8654
+ dateParts.push(month);
8655
+ }
8656
+
8657
+ if (day) {
8658
+ dateParts.push(day);
8659
+ }
8660
+
8661
+ if (year) {
8662
+ dateParts.push(year);
8663
+ }
8664
+
8665
+ return dateParts.join('/');
8666
+ };
8667
+ }
8668
+ }
8669
+ const dateFormatter = new DateFormatter();
8670
+
8671
+ // filepath: dateConstraints.mjs
8672
+ const DATE_UTIL_CONSTRAINTS = {
8673
+ maxDay: 31,
8674
+ maxMonth: 12,
8675
+ maxYear: 2400,
8676
+ minDay: 1,
8677
+ minMonth: 1,
8678
+ minYear: 1900,
8679
+ };
8680
+
8681
+ class AuroDateUtilitiesBase {
8682
+
8683
+ /**
8684
+ * @description The maximum day value allowed by the various utilities in this class.
8685
+ * @readonly
8686
+ * @type {Number}
8687
+ */
8688
+ get maxDay() {
8689
+ return DATE_UTIL_CONSTRAINTS.maxDay;
8690
+ }
8691
+
8692
+ /**
8693
+ * @description The maximum month value allowed by the various utilities in this class.
8694
+ * @readonly
8695
+ * @type {Number}
8696
+ */
8697
+ get maxMonth() {
8698
+ return DATE_UTIL_CONSTRAINTS.maxMonth;
8699
+ }
8700
+
8701
+ /**
8702
+ * @description The maximum year value allowed by the various utilities in this class.
8703
+ * @readonly
8704
+ * @type {Number}
8705
+ */
8706
+ get maxYear() {
8707
+ return DATE_UTIL_CONSTRAINTS.maxYear;
8708
+ }
8709
+
8710
+ /**
8711
+ * @description The minimum day value allowed by the various utilities in this class.
8712
+ * @readonly
8713
+ * @type {Number}
8714
+ */
8715
+ get minDay() {
8716
+ return DATE_UTIL_CONSTRAINTS.minDay;
8717
+ }
8718
+
8719
+ /**
8720
+ * @description The minimum month value allowed by the various utilities in this class.
8721
+ * @readonly
8722
+ * @type {Number}
8723
+ */
8724
+ get minMonth() {
8725
+ return DATE_UTIL_CONSTRAINTS.minMonth;
8726
+ }
8727
+
8728
+ /**
8729
+ * @description The minimum year value allowed by the various utilities in this class.
8730
+ * @readonly
8731
+ * @type {Number}
8732
+ */
8733
+ get minYear() {
8734
+ return DATE_UTIL_CONSTRAINTS.minYear;
8735
+ }
8736
+ }
8737
+
8738
+ /* eslint-disable no-magic-numbers */
8739
+
8740
+ class AuroDateUtilities extends AuroDateUtilitiesBase {
8741
+
8742
+ /**
8743
+ * Returns the current century.
8744
+ * @returns {String} The current century.
8745
+ */
8746
+ getCentury () {
8747
+ return String(new Date().getFullYear()).slice(0, 2);
8748
+ }
8749
+
8750
+ /**
8751
+ * Returns a four digit year.
8752
+ * @param {String} year - The year to convert to four digits.
8753
+ * @returns {String} The four digit year.
8754
+ */
8755
+ getFourDigitYear (year) {
8756
+
8757
+ const strYear = String(year).trim();
8758
+ return strYear.length <= 2 ? this.getCentury() + strYear : strYear;
8759
+ }
8760
+
8761
+ constructor() {
8762
+
8763
+ super();
8764
+
8765
+ /**
8766
+ * Compares two dates to see if they match.
8767
+ * @param {Object} date1 - First date to compare.
8768
+ * @param {Object} date2 - Second date to compare.
8769
+ * @returns {Boolean} Returns true if the dates match.
8770
+ */
8771
+ this.datesMatch = (date1, date2) => new Date(date1).getTime() === new Date(date2).getTime();
8772
+
8773
+ /**
8774
+ * Returns true if value passed in is a valid date.
8775
+ * @param {String} date - Date to validate.
8776
+ * @param {String} format - Date format to validate against.
8777
+ * @returns {Boolean}
8778
+ */
8779
+ this.validDateStr = (date, format) => {
8780
+
8781
+ // The length we expect the date string to be
8782
+ const dateStrLength = format.length;
8783
+
8784
+ // Guard Clause: Date and format are defined
8785
+ if (typeof date === "undefined" || typeof format === "undefined") {
8786
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date and format are required');
8787
+ }
8788
+
8789
+ // Guard Clause: Date should be of type string
8790
+ if (typeof date !== "string") {
8791
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date must be a string');
8792
+ }
8793
+
8794
+ // Guard Clause: Format should be of type string
8795
+ if (typeof format !== "string") {
8796
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Format must be a string');
8797
+ }
8798
+
8799
+ // Guard Clause: Length is what we expect it to be
8800
+ if (date.length !== dateStrLength) {
8801
+ return false;
8802
+ }
8803
+ // Get a formatted date string and parse it
8804
+ const dateParts = dateFormatter.parseDate(date, format);
8805
+
8806
+ // Guard Clause: Date parse succeeded
8807
+ if (!dateParts) {
8808
+ return false;
8809
+ }
8810
+
8811
+ // Create the expected date string based on the date parts
8812
+ const expectedDateStr = `${dateParts.month}/${dateParts.day || "01"}/${this.getFourDigitYear(dateParts.year)}`;
8813
+
8814
+ // Generate a date object that we will extract a string date from to compare to the passed in date string
8815
+ const dateObj = new Date(this.getFourDigitYear(dateParts.year), dateParts.month - 1, dateParts.day || 1);
8816
+
8817
+ // Get the date string of the date object we created from the string date
8818
+ const actualDateStr = dateFormatter.getDateAsString(dateObj);
8819
+
8820
+ // Guard Clause: Generated date matches date string input
8821
+ if (expectedDateStr !== actualDateStr) {
8822
+ return false;
8823
+ }
8824
+
8825
+ // If we passed all other checks, we can assume the date is valid
8826
+ return true;
8827
+ };
8828
+
8829
+ /**
8830
+ * Determines if a string date value matches the format provided.
8831
+ * @param {string} value = The date string value.
8832
+ * @param { string} format = The date format to match against.
8833
+ * @returns {boolean}
8834
+ */
8835
+ this.dateAndFormatMatch = (value, format) => {
8836
+
8837
+ // Ensure we have both values we need to do the comparison
8838
+ if (!value || !format) {
8839
+ throw new Error('AuroFormValidation | dateFormatMatch: value and format are required');
8840
+ }
8841
+
8842
+ // If the lengths are different, they cannot match
8843
+ if (value.length !== format.length) {
8844
+ return false;
8845
+ }
8846
+
8847
+ // Get the parts of the date
8848
+ const dateParts = dateFormatter.parseDate(value, format);
8849
+
8850
+ // Validator for day
8851
+ const dayValueIsValid = (day) => {
8852
+
8853
+ // Guard clause: if there is no day in the dateParts, we can ignore this check.
8854
+ if (!dateParts.day) {
8855
+ return true;
8856
+ }
8857
+
8858
+ // Guard clause: ensure day exists.
8859
+ if (!day) {
8860
+ return false;
8861
+ }
8862
+
8863
+ // Convert day to number
8864
+ const numDay = Number.parseInt(day, 10);
8865
+
8866
+ // Guard clause: ensure day is a valid integer
8867
+ if (Number.isNaN(numDay)) {
8868
+ throw new Error('AuroDatepickerUtilities | dayValueIsValid: Unable to parse day value integer');
8869
+ }
8870
+
8871
+ // Guard clause: ensure day is within the valid range
8872
+ if (numDay < this.minDay || numDay > this.maxDay) {
8873
+ return false;
8874
+ }
8875
+
8876
+ // Default return
8877
+ return true;
8878
+ };
8879
+
8880
+ // Validator for month
8881
+ const monthValueIsValid = (month) => {
8882
+
8883
+ // Guard clause: ensure month exists.
8884
+ if (!month) {
8885
+ return false;
8886
+ }
8887
+
8888
+ // Convert month to number
8889
+ const numMonth = Number.parseInt(month, 10);
8890
+
8891
+ // Guard clause: ensure month is a valid integer
8892
+ if (Number.isNaN(numMonth)) {
8893
+ throw new Error('AuroDatepickerUtilities | monthValueIsValid: Unable to parse month value integer');
8894
+ }
8895
+
8896
+ // Guard clause: ensure month is within the valid range
8897
+ if (numMonth < this.minMonth || numMonth > this.maxMonth) {
8898
+ return false;
8899
+ }
8900
+
8901
+ // Default return
8902
+ return true;
8903
+ };
8904
+
8905
+ // Validator for year
8906
+ const yearIsValid = (_year) => {
8907
+
8908
+ // Guard clause: ensure year exists.
8909
+ if (!_year) {
8910
+ return false;
8911
+ }
8912
+
8913
+ // Get the full year
8914
+ const year = this.getFourDigitYear(_year);
8915
+
8916
+ // Convert year to number
8917
+ const numYear = Number.parseInt(year, 10);
8918
+
8919
+ // Guard clause: ensure year is a valid integer
8920
+ if (Number.isNaN(numYear)) {
8921
+ throw new Error('AuroDatepickerUtilities | yearValueIsValid: Unable to parse year value integer');
8922
+ }
8923
+
8924
+ // Guard clause: ensure year is within the valid range
8925
+ if (numYear < this.minYear || numYear > this.maxYear) {
8926
+ return false;
8927
+ }
8928
+
8929
+ // Default return
8930
+ return true;
8931
+ };
8932
+
8933
+ // Self-contained checks for month, day, and year
8934
+ const checks = [
8935
+ monthValueIsValid(dateParts.month),
8936
+ dayValueIsValid(dateParts.day),
8937
+ yearIsValid(dateParts.year)
8938
+ ];
8939
+
8940
+ // If any of the checks failed, the date format does not match and the result is invalid
8941
+ const isValid = checks.every((check) => check === true);
8942
+
8943
+ // If the check is invalid, return false
8944
+ if (!isValid) {
8945
+ return false;
8946
+ }
8947
+
8948
+ // Default case
8949
+ return true;
8950
+ };
8951
+ }
8952
+ }
8953
+
8954
+ // Export a class instance
8955
+ const dateUtilities = new AuroDateUtilities();
8956
+
8957
+ // Export the class instance methods individually
8958
+ const {
8959
+ datesMatch,
8960
+ validDateStr,
8961
+ dateAndFormatMatch,
8962
+ minDay,
8963
+ minMonth,
8964
+ minYear,
8965
+ maxDay,
8966
+ maxMonth,
8967
+ maxYear
8968
+ } = dateUtilities;
8969
+
8970
+ const {
8971
+ toNorthAmericanFormat,
8972
+ parseDate,
8973
+ getDateAsString
8974
+ } = dateFormatter;
8975
+
8043
8976
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
8044
8977
  // See LICENSE in the project root for license information.
8045
8978
 
@@ -8115,6 +9048,7 @@ let AuroLibraryRuntimeUtils$1$1 = class AuroLibraryRuntimeUtils {
8115
9048
 
8116
9049
 
8117
9050
  class AuroFormValidation {
9051
+
8118
9052
  constructor() {
8119
9053
  this.runtimeUtils = new AuroLibraryRuntimeUtils$1$1();
8120
9054
  }
@@ -8206,17 +9140,17 @@ class AuroFormValidation {
8206
9140
  ]
8207
9141
  }
8208
9142
  };
8209
-
9143
+
8210
9144
  let elementType;
8211
9145
  if (this.runtimeUtils.elementMatch(elem, 'auro-input')) {
8212
9146
  elementType = 'input';
8213
9147
  } else if (this.runtimeUtils.elementMatch(elem, 'auro-counter') || this.runtimeUtils.elementMatch(elem, 'auro-counter-group')) {
8214
9148
  elementType = 'counter';
8215
9149
  }
8216
-
9150
+
8217
9151
  if (elementType) {
8218
9152
  const rules = validationRules[elementType];
8219
-
9153
+
8220
9154
  if (rules) {
8221
9155
  Object.values(rules).flat().forEach(rule => {
8222
9156
  if (rule.check(elem)) {
@@ -8242,48 +9176,82 @@ class AuroFormValidation {
8242
9176
  if (!elem.value.match(emailRegex)) {
8243
9177
  elem.validity = 'patternMismatch';
8244
9178
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
9179
+ return;
8245
9180
  }
8246
9181
  } else if (elem.type === 'credit-card') {
8247
9182
  if (elem.value.length > 0 && elem.value.length < elem.validationCCLength) {
8248
9183
  elem.validity = 'tooShort';
8249
9184
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
9185
+ return;
8250
9186
  }
8251
9187
  } else if (elem.type === 'number') {
8252
9188
  if (elem.max !== undefined && Number(elem.max) < Number(elem.value)) {
8253
9189
  elem.validity = 'rangeOverflow';
8254
9190
  elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
9191
+ return;
8255
9192
  }
8256
9193
 
8257
9194
  if (elem.min !== undefined && elem.value?.length > 0 && Number(elem.min) > Number(elem.value)) {
8258
9195
  elem.validity = 'rangeUnderflow';
8259
9196
  elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
9197
+ return;
8260
9198
  }
8261
- } else if (elem.type === 'date') {
8262
- if (elem.value?.length > 0 && elem.value?.length < elem.lengthForType) {
9199
+ } else if (elem.type === 'date' && elem.value?.length > 0) {
9200
+
9201
+ // Guard Clause: if the value is too short
9202
+ if (elem.value.length < elem.lengthForType) {
9203
+
8263
9204
  elem.validity = 'tooShort';
8264
9205
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
8265
- } else if (elem.value?.length === elem.lengthForType && elem.util.toNorthAmericanFormat(elem.value, elem.format)) {
8266
- const formattedValue = elem.util.toNorthAmericanFormat(elem.value, elem.format);
8267
- const valueDate = new Date(formattedValue.dateForComparison);
9206
+ return;
9207
+ }
9208
+
9209
+ // Guard Clause: If the value is too long for the type
9210
+ if (elem.value?.length > elem.lengthForType) {
8268
9211
 
8269
- // validate max
8270
- if (elem.max?.length === elem.lengthForType) {
8271
- const maxDate = new Date(elem.util.toNorthAmericanFormat(elem.max, elem.format).dateForComparison);
9212
+ elem.validity = 'tooLong';
9213
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
9214
+ return;
9215
+ }
9216
+
9217
+ // Validate that the date passed was the correct format
9218
+ if (!dateAndFormatMatch(elem.value, elem.format)) {
9219
+ elem.validity = 'patternMismatch';
9220
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || 'Invalid Date Format Entered';
9221
+ return;
9222
+ }
9223
+
9224
+ // Validate that the date passed was a valid date
9225
+ if (!validDateStr(elem.value, elem.format)) {
9226
+ elem.validity = 'invalidDate';
9227
+ elem.errorMessage = elem.setCustomValidityInvalidDate || elem.setCustomValidity || 'Invalid Date Entered';
9228
+ return;
9229
+ }
8272
9230
 
8273
- if (valueDate > maxDate) {
8274
- elem.validity = 'rangeOverflow';
8275
- elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
8276
- }
9231
+ // Perform the rest of the validation
9232
+ const formattedValue = toNorthAmericanFormat(elem.value, elem.format);
9233
+ const valueDate = new Date(formattedValue);
9234
+
9235
+ // // Validate max date
9236
+ if (elem.max?.length === elem.lengthForType) {
9237
+
9238
+ const maxDate = new Date(toNorthAmericanFormat(elem.max, elem.format));
9239
+
9240
+ if (valueDate > maxDate) {
9241
+ elem.validity = 'rangeOverflow';
9242
+ elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
9243
+ return;
8277
9244
  }
9245
+ }
8278
9246
 
8279
- // validate min
8280
- if (elem.min?.length === elem.lengthForType) {
8281
- const minDate = new Date(elem.util.toNorthAmericanFormat(elem.min, elem.format).dateForComparison);
9247
+ // Validate min date
9248
+ if (elem.min?.length === elem.lengthForType) {
9249
+ const minDate = new Date(toNorthAmericanFormat(elem.min, elem.format));
8282
9250
 
8283
- if (valueDate < minDate) {
8284
- elem.validity = 'rangeUnderflow';
8285
- elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
8286
- }
9251
+ if (valueDate < minDate) {
9252
+ elem.validity = 'rangeUnderflow';
9253
+ elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
9254
+ return;
8287
9255
  }
8288
9256
  }
8289
9257
  }
@@ -8402,7 +9370,7 @@ class AuroFormValidation {
8402
9370
  if (input.validationMessage.length > 0) {
8403
9371
  elem.errorMessage = input.validationMessage;
8404
9372
  }
8405
- } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
9373
+ } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
8406
9374
  const firstInput = this.inputElements[0];
8407
9375
 
8408
9376
  if (firstInput.validationMessage.length > 0) {
@@ -8524,6 +9492,33 @@ class BaseInput extends LitElement {
8524
9492
  static get properties() {
8525
9493
  return {
8526
9494
 
9495
+ /**
9496
+ * The value for the role attribute.
9497
+ */
9498
+ a11yRole: {
9499
+ type: String,
9500
+ attribute: true,
9501
+ reflect: true
9502
+ },
9503
+
9504
+ /**
9505
+ * The value for the aria-expanded attribute.
9506
+ */
9507
+ a11yExpanded: {
9508
+ type: Boolean,
9509
+ attribute: true,
9510
+ reflect: true
9511
+ },
9512
+
9513
+ /**
9514
+ * The value for the aria-controls attribute.
9515
+ */
9516
+ a11yControls: {
9517
+ type: String,
9518
+ attribute: true,
9519
+ reflect: true
9520
+ },
9521
+
8527
9522
  /**
8528
9523
  * If set, the label will remain fixed in the active position.
8529
9524
  */
@@ -9165,6 +10160,10 @@ class BaseInput extends LitElement {
9165
10160
  } else if (this.type === 'number') {
9166
10161
  this.inputMode = 'numeric';
9167
10162
  }
10163
+
10164
+ if (this.type === "date" && !this.format) {
10165
+ this.format = 'mm/dd/yyyy';
10166
+ }
9168
10167
  }
9169
10168
 
9170
10169
  /**
@@ -10408,6 +11407,7 @@ var helpTextVersion = '1.0.0';
10408
11407
 
10409
11408
  // build the component class
10410
11409
  class AuroInput extends BaseInput {
11410
+
10411
11411
  constructor() {
10412
11412
  super();
10413
11413
 
@@ -10520,7 +11520,7 @@ class AuroInput extends BaseInput {
10520
11520
  ?required="${this.required}"
10521
11521
  ?disabled="${this.disabled}"
10522
11522
  aria-describedby="${this.uniqueId}"
10523
- aria-invalid="${this.validity !== 'valid'}"
11523
+ ?aria-invalid="${this.validity !== 'valid'}"
10524
11524
  placeholder=${this.getPlaceholder()}
10525
11525
  lang="${ifDefined(this.lang)}"
10526
11526
  ?activeLabel="${this.activeLabel}"
@@ -10529,7 +11529,10 @@ class AuroInput extends BaseInput {
10529
11529
  autocapitalize="${ifDefined(this.autocapitalize ? this.autocapitalize : undefined)}"
10530
11530
  autocomplete="${ifDefined(this.autocomplete ? this.autocomplete : undefined)}"
10531
11531
  part="input"
10532
- />
11532
+ role="${ifDefined(this.a11yRole)}"
11533
+ aria-expanded="${ifDefined(this.a11yExpanded)}"
11534
+ aria-controls="${ifDefined(this.a11yControls)}"
11535
+ />
10533
11536
  </div>
10534
11537
  <div
10535
11538
  class="notificationIcons"
@@ -11521,6 +12524,7 @@ var styleCss = css`.util_displayInline{display:inline}.util_displayInlineBlock{d
11521
12524
 
11522
12525
  // build the component class
11523
12526
  class AuroCombobox extends LitElement {
12527
+
11524
12528
  constructor() {
11525
12529
  super();
11526
12530
 
@@ -11532,6 +12536,8 @@ class AuroCombobox extends LitElement {
11532
12536
  * @returns {void} Internal defaults.
11533
12537
  */
11534
12538
  privateDefaults() {
12539
+ this.dropdownOpen = false;
12540
+ this.dropdownId = undefined;
11535
12541
  this.onDark = false;
11536
12542
 
11537
12543
  this.noFilter = false;
@@ -11611,6 +12617,26 @@ class AuroCombobox extends LitElement {
11611
12617
  reflect: true
11612
12618
  },
11613
12619
 
12620
+ /**
12621
+ * ID for the dropdown
12622
+ * @private
12623
+ */
12624
+ dropdownId: {
12625
+ type: String,
12626
+ reflect: false,
12627
+ attribute: false
12628
+ },
12629
+
12630
+ /**
12631
+ * Whether or not the dropdown is open
12632
+ * @private
12633
+ */
12634
+ dropdownOpen: {
12635
+ type: Boolean,
12636
+ reflect: false,
12637
+ attribute: false
12638
+ },
12639
+
11614
12640
  /**
11615
12641
  * When defined, sets persistent validity to `customError` and sets the validation message to the attribute value.
11616
12642
  */
@@ -11772,8 +12798,19 @@ class AuroCombobox extends LitElement {
11772
12798
  * @private
11773
12799
  */
11774
12800
  isDropdownFullscreen: {
11775
- type: Boolean
11776
- }
12801
+ type: Boolean,
12802
+ reflect: false
12803
+ },
12804
+
12805
+ /**
12806
+ * @private
12807
+ * specifies the currently active option
12808
+ */
12809
+ optionActive: {
12810
+ type: Object,
12811
+ reflect: false,
12812
+ attribute: false
12813
+ },
11777
12814
  };
11778
12815
  }
11779
12816
 
@@ -11925,6 +12962,18 @@ class AuroCombobox extends LitElement {
11925
12962
  * @returns {void}
11926
12963
  */
11927
12964
  configureDropdown() {
12965
+
12966
+ // Listen for the ID to be added to the dropdown so we can capture it and use it for accessibility.
12967
+ this.dropdown.addEventListener('auroDropdown-idAdded', (event) => {
12968
+ this.dropdownId = event.detail.id;
12969
+ });
12970
+
12971
+ // Listen for the dropdown to be shown or hidden
12972
+ this.dropdown.addEventListener("auroDropdown-toggled", (ev) => {
12973
+ this.dropdownOpen = ev.detail.expanded;
12974
+ });
12975
+
12976
+ // this.dropdown.addEventListener('auroDropdown-show', () => {
11928
12977
  this.menuWrapper = this.dropdown.querySelector('.menuWrapper');
11929
12978
  this.menuWrapper.append(this.menu);
11930
12979
 
@@ -11938,7 +12987,6 @@ class AuroCombobox extends LitElement {
11938
12987
  this.hideBib = this.hideBib.bind(this);
11939
12988
  this.bibtemplate.addEventListener('close-click', this.hideBib);
11940
12989
 
11941
- this.dropdown.setAttribute('role', 'combobox');
11942
12990
  this.dropdown.addEventListener('auroDropdown-triggerClick', () => {
11943
12991
  this.showBib();
11944
12992
  });
@@ -11954,7 +13002,6 @@ class AuroCombobox extends LitElement {
11954
13002
  this.isDropdownFullscreen = event.detail.strategy === 'fullscreen';
11955
13003
  setTimeout(this.transportInput);
11956
13004
  });
11957
-
11958
13005
  }
11959
13006
 
11960
13007
  /**
@@ -12448,6 +13495,10 @@ class AuroCombobox extends LitElement {
12448
13495
  ?noFlip="${this.noFlip}"
12449
13496
  disableEventShow>
12450
13497
  <${this.inputTag}
13498
+ .a11yRole="${"combobox"}"
13499
+ .a11yExpanded="${this.dropdownOpen}"
13500
+ .a11yControls="${this.dropdownId}"
13501
+ id="${this.id || 'auro-combobox-input'}"
12451
13502
  slot="trigger"
12452
13503
  bordered
12453
13504
  ?onDark="${this.onDark}"