@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
@@ -31,6 +31,414 @@ const t$2=globalThis,i$3=t$2.trustedTypes,s$2=i$3?i$3.createPolicy("lit-html",{c
31
31
  */
32
32
  const a=Symbol.for(""),o$2=t=>{if(t?.r===a)return t?._$litStatic$},s$1=t=>({_$litStatic$:t,r:a}),i$1=(t,...r)=>({_$litStatic$:r.reduce(((r,e,a)=>r+(t=>{if(void 0!==t._$litStatic$)return t._$litStatic$;throw Error(`Value passed to 'literal' function must be a 'literal' result: ${t}. Use 'unsafeStatic' to pass non-literal values, but\n take care to ensure page security.`)})(e)+t[a+1]),t[0]),r:a}),l=new Map,n$1=t=>(r,...e)=>{const a=e.length;let s,i;const n=[],u=[];let c,$=0,f=false;for(;$<a;){for(c=r[$];$<a&&void 0!==(i=e[$],s=o$2(i));)c+=s+r[++$],f=true;$!==a&&u.push(i),n.push(c),$++;}if($===a&&n.push(r[a]),f){const t=n.join("$$lit$$");void 0===(r=l.get(t))&&(n.raw=n,l.set(t,r=n)),e=u;}return t(r,...e)},u$2=n$1(x);
33
33
 
34
+ let DateFormatter$1 = class DateFormatter {
35
+
36
+ constructor() {
37
+
38
+ /**
39
+ * @description Parses a date string into its components.
40
+ * @param {string} dateStr - Date string to parse.
41
+ * @param {string} format - Date format to parse.
42
+ * @returns {Object<key["month" | "day" | "year"]: number>|undefined}
43
+ */
44
+ this.parseDate = (dateStr, format = 'mm/dd/yyyy') => {
45
+
46
+ // Guard Clause: Date string is defined
47
+ if (!dateStr) {
48
+ return undefined;
49
+ }
50
+
51
+ // Assume the separator is a "/" a defined in our code base
52
+ const separator = '/';
53
+
54
+ // Get the parts of the date and format
55
+ const valueParts = dateStr.split(separator);
56
+ const formatParts = format.split(separator);
57
+
58
+ // Check if the value and format have the correct number of parts
59
+ if (valueParts.length !== formatParts.length) {
60
+ throw new Error('AuroDatepickerUtilities | parseDate: Date string and format length do not match');
61
+ }
62
+
63
+ // Holds the result to be returned
64
+ const result = formatParts.reduce((acc, part, index) => {
65
+ const value = valueParts[index];
66
+
67
+ if ((/m/iu).test(part)) {
68
+ acc.month = value;
69
+ } else if ((/d/iu).test(part)) {
70
+ acc.day = value;
71
+ } else if ((/y/iu).test(part)) {
72
+ acc.year = value;
73
+ }
74
+
75
+ return acc;
76
+ }, {});
77
+
78
+ // If we found all the parts, return the result
79
+ if (result.month && result.year) {
80
+ return result;
81
+ }
82
+
83
+ // Throw an error to let the dev know we were unable to parse the date string
84
+ throw new Error('AuroDatepickerUtilities | parseDate: Unable to parse date string');
85
+ };
86
+
87
+ /**
88
+ * Convert a date object to string format.
89
+ * @param {Object} date - Date to convert to string.
90
+ * @returns {Object} Returns the date as a string.
91
+ */
92
+ this.getDateAsString = (date) => date.toLocaleDateString(undefined, {
93
+ year: "numeric",
94
+ month: "2-digit",
95
+ day: "2-digit",
96
+ });
97
+
98
+ /**
99
+ * Converts a date string to a North American date format.
100
+ * @param {String} dateStr - Date to validate.
101
+ * @param {String} format - Date format to validate against.
102
+ * @returns {Boolean}
103
+ */
104
+ this.toNorthAmericanFormat = (dateStr, format) => {
105
+
106
+ if (format === 'mm/dd/yyyy') {
107
+ return dateStr;
108
+ }
109
+
110
+ const parsedDate = this.parseDate(dateStr, format);
111
+
112
+ if (!parsedDate) {
113
+ throw new Error('AuroDatepickerUtilities | toNorthAmericanFormat: Unable to parse date string');
114
+ }
115
+
116
+ const { month, day, year } = parsedDate;
117
+
118
+ const dateParts = [];
119
+ if (month) {
120
+ dateParts.push(month);
121
+ }
122
+
123
+ if (day) {
124
+ dateParts.push(day);
125
+ }
126
+
127
+ if (year) {
128
+ dateParts.push(year);
129
+ }
130
+
131
+ return dateParts.join('/');
132
+ };
133
+ }
134
+ };
135
+ const dateFormatter$1 = new DateFormatter$1();
136
+
137
+ // filepath: dateConstraints.mjs
138
+ const DATE_UTIL_CONSTRAINTS$1 = {
139
+ maxDay: 31,
140
+ maxMonth: 12,
141
+ maxYear: 2400,
142
+ minDay: 1,
143
+ minMonth: 1,
144
+ minYear: 1900,
145
+ };
146
+
147
+ let AuroDateUtilitiesBase$1 = class AuroDateUtilitiesBase {
148
+
149
+ /**
150
+ * @description The maximum day value allowed by the various utilities in this class.
151
+ * @readonly
152
+ * @type {Number}
153
+ */
154
+ get maxDay() {
155
+ return DATE_UTIL_CONSTRAINTS$1.maxDay;
156
+ }
157
+
158
+ /**
159
+ * @description The maximum month value allowed by the various utilities in this class.
160
+ * @readonly
161
+ * @type {Number}
162
+ */
163
+ get maxMonth() {
164
+ return DATE_UTIL_CONSTRAINTS$1.maxMonth;
165
+ }
166
+
167
+ /**
168
+ * @description The maximum year value allowed by the various utilities in this class.
169
+ * @readonly
170
+ * @type {Number}
171
+ */
172
+ get maxYear() {
173
+ return DATE_UTIL_CONSTRAINTS$1.maxYear;
174
+ }
175
+
176
+ /**
177
+ * @description The minimum day value allowed by the various utilities in this class.
178
+ * @readonly
179
+ * @type {Number}
180
+ */
181
+ get minDay() {
182
+ return DATE_UTIL_CONSTRAINTS$1.minDay;
183
+ }
184
+
185
+ /**
186
+ * @description The minimum month value allowed by the various utilities in this class.
187
+ * @readonly
188
+ * @type {Number}
189
+ */
190
+ get minMonth() {
191
+ return DATE_UTIL_CONSTRAINTS$1.minMonth;
192
+ }
193
+
194
+ /**
195
+ * @description The minimum year value allowed by the various utilities in this class.
196
+ * @readonly
197
+ * @type {Number}
198
+ */
199
+ get minYear() {
200
+ return DATE_UTIL_CONSTRAINTS$1.minYear;
201
+ }
202
+ };
203
+
204
+ /* eslint-disable no-magic-numbers */
205
+
206
+ let AuroDateUtilities$1 = class AuroDateUtilities extends AuroDateUtilitiesBase$1 {
207
+
208
+ /**
209
+ * Returns the current century.
210
+ * @returns {String} The current century.
211
+ */
212
+ getCentury () {
213
+ return String(new Date().getFullYear()).slice(0, 2);
214
+ }
215
+
216
+ /**
217
+ * Returns a four digit year.
218
+ * @param {String} year - The year to convert to four digits.
219
+ * @returns {String} The four digit year.
220
+ */
221
+ getFourDigitYear (year) {
222
+
223
+ const strYear = String(year).trim();
224
+ return strYear.length <= 2 ? this.getCentury() + strYear : strYear;
225
+ }
226
+
227
+ constructor() {
228
+
229
+ super();
230
+
231
+ /**
232
+ * Compares two dates to see if they match.
233
+ * @param {Object} date1 - First date to compare.
234
+ * @param {Object} date2 - Second date to compare.
235
+ * @returns {Boolean} Returns true if the dates match.
236
+ */
237
+ this.datesMatch = (date1, date2) => new Date(date1).getTime() === new Date(date2).getTime();
238
+
239
+ /**
240
+ * Returns true if value passed in is a valid date.
241
+ * @param {String} date - Date to validate.
242
+ * @param {String} format - Date format to validate against.
243
+ * @returns {Boolean}
244
+ */
245
+ this.validDateStr = (date, format) => {
246
+
247
+ // The length we expect the date string to be
248
+ const dateStrLength = format.length;
249
+
250
+ // Guard Clause: Date and format are defined
251
+ if (typeof date === "undefined" || typeof format === "undefined") {
252
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date and format are required');
253
+ }
254
+
255
+ // Guard Clause: Date should be of type string
256
+ if (typeof date !== "string") {
257
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date must be a string');
258
+ }
259
+
260
+ // Guard Clause: Format should be of type string
261
+ if (typeof format !== "string") {
262
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Format must be a string');
263
+ }
264
+
265
+ // Guard Clause: Length is what we expect it to be
266
+ if (date.length !== dateStrLength) {
267
+ return false;
268
+ }
269
+ // Get a formatted date string and parse it
270
+ const dateParts = dateFormatter$1.parseDate(date, format);
271
+
272
+ // Guard Clause: Date parse succeeded
273
+ if (!dateParts) {
274
+ return false;
275
+ }
276
+
277
+ // Create the expected date string based on the date parts
278
+ const expectedDateStr = `${dateParts.month}/${dateParts.day || "01"}/${this.getFourDigitYear(dateParts.year)}`;
279
+
280
+ // Generate a date object that we will extract a string date from to compare to the passed in date string
281
+ const dateObj = new Date(this.getFourDigitYear(dateParts.year), dateParts.month - 1, dateParts.day || 1);
282
+
283
+ // Get the date string of the date object we created from the string date
284
+ const actualDateStr = dateFormatter$1.getDateAsString(dateObj);
285
+
286
+ // Guard Clause: Generated date matches date string input
287
+ if (expectedDateStr !== actualDateStr) {
288
+ return false;
289
+ }
290
+
291
+ // If we passed all other checks, we can assume the date is valid
292
+ return true;
293
+ };
294
+
295
+ /**
296
+ * Determines if a string date value matches the format provided.
297
+ * @param {string} value = The date string value.
298
+ * @param { string} format = The date format to match against.
299
+ * @returns {boolean}
300
+ */
301
+ this.dateAndFormatMatch = (value, format) => {
302
+
303
+ // Ensure we have both values we need to do the comparison
304
+ if (!value || !format) {
305
+ throw new Error('AuroFormValidation | dateFormatMatch: value and format are required');
306
+ }
307
+
308
+ // If the lengths are different, they cannot match
309
+ if (value.length !== format.length) {
310
+ return false;
311
+ }
312
+
313
+ // Get the parts of the date
314
+ const dateParts = dateFormatter$1.parseDate(value, format);
315
+
316
+ // Validator for day
317
+ const dayValueIsValid = (day) => {
318
+
319
+ // Guard clause: if there is no day in the dateParts, we can ignore this check.
320
+ if (!dateParts.day) {
321
+ return true;
322
+ }
323
+
324
+ // Guard clause: ensure day exists.
325
+ if (!day) {
326
+ return false;
327
+ }
328
+
329
+ // Convert day to number
330
+ const numDay = Number.parseInt(day, 10);
331
+
332
+ // Guard clause: ensure day is a valid integer
333
+ if (Number.isNaN(numDay)) {
334
+ throw new Error('AuroDatepickerUtilities | dayValueIsValid: Unable to parse day value integer');
335
+ }
336
+
337
+ // Guard clause: ensure day is within the valid range
338
+ if (numDay < this.minDay || numDay > this.maxDay) {
339
+ return false;
340
+ }
341
+
342
+ // Default return
343
+ return true;
344
+ };
345
+
346
+ // Validator for month
347
+ const monthValueIsValid = (month) => {
348
+
349
+ // Guard clause: ensure month exists.
350
+ if (!month) {
351
+ return false;
352
+ }
353
+
354
+ // Convert month to number
355
+ const numMonth = Number.parseInt(month, 10);
356
+
357
+ // Guard clause: ensure month is a valid integer
358
+ if (Number.isNaN(numMonth)) {
359
+ throw new Error('AuroDatepickerUtilities | monthValueIsValid: Unable to parse month value integer');
360
+ }
361
+
362
+ // Guard clause: ensure month is within the valid range
363
+ if (numMonth < this.minMonth || numMonth > this.maxMonth) {
364
+ return false;
365
+ }
366
+
367
+ // Default return
368
+ return true;
369
+ };
370
+
371
+ // Validator for year
372
+ const yearIsValid = (_year) => {
373
+
374
+ // Guard clause: ensure year exists.
375
+ if (!_year) {
376
+ return false;
377
+ }
378
+
379
+ // Get the full year
380
+ const year = this.getFourDigitYear(_year);
381
+
382
+ // Convert year to number
383
+ const numYear = Number.parseInt(year, 10);
384
+
385
+ // Guard clause: ensure year is a valid integer
386
+ if (Number.isNaN(numYear)) {
387
+ throw new Error('AuroDatepickerUtilities | yearValueIsValid: Unable to parse year value integer');
388
+ }
389
+
390
+ // Guard clause: ensure year is within the valid range
391
+ if (numYear < this.minYear || numYear > this.maxYear) {
392
+ return false;
393
+ }
394
+
395
+ // Default return
396
+ return true;
397
+ };
398
+
399
+ // Self-contained checks for month, day, and year
400
+ const checks = [
401
+ monthValueIsValid(dateParts.month),
402
+ dayValueIsValid(dateParts.day),
403
+ yearIsValid(dateParts.year)
404
+ ];
405
+
406
+ // If any of the checks failed, the date format does not match and the result is invalid
407
+ const isValid = checks.every((check) => check === true);
408
+
409
+ // If the check is invalid, return false
410
+ if (!isValid) {
411
+ return false;
412
+ }
413
+
414
+ // Default case
415
+ return true;
416
+ };
417
+ }
418
+ };
419
+
420
+ // Export a class instance
421
+ const dateUtilities$1 = new AuroDateUtilities$1();
422
+
423
+ // Export the class instance methods individually
424
+ const {
425
+ datesMatch: datesMatch$1,
426
+ validDateStr: validDateStr$1,
427
+ dateAndFormatMatch: dateAndFormatMatch$1,
428
+ minDay: minDay$1,
429
+ minMonth: minMonth$1,
430
+ minYear: minYear$1,
431
+ maxDay: maxDay$1,
432
+ maxMonth: maxMonth$1,
433
+ maxYear: maxYear$1
434
+ } = dateUtilities$1;
435
+
436
+ const {
437
+ toNorthAmericanFormat: toNorthAmericanFormat$1,
438
+ parseDate: parseDate$1,
439
+ getDateAsString: getDateAsString$1
440
+ } = dateFormatter$1;
441
+
34
442
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
35
443
  // See LICENSE in the project root for license information.
36
444
 
@@ -106,6 +514,7 @@ let AuroLibraryRuntimeUtils$4 = class AuroLibraryRuntimeUtils {
106
514
 
107
515
 
108
516
  let AuroFormValidation$1 = class AuroFormValidation {
517
+
109
518
  constructor() {
110
519
  this.runtimeUtils = new AuroLibraryRuntimeUtils$4();
111
520
  }
@@ -197,17 +606,17 @@ let AuroFormValidation$1 = class AuroFormValidation {
197
606
  ]
198
607
  }
199
608
  };
200
-
609
+
201
610
  let elementType;
202
611
  if (this.runtimeUtils.elementMatch(elem, 'auro-input')) {
203
612
  elementType = 'input';
204
613
  } else if (this.runtimeUtils.elementMatch(elem, 'auro-counter') || this.runtimeUtils.elementMatch(elem, 'auro-counter-group')) {
205
614
  elementType = 'counter';
206
615
  }
207
-
616
+
208
617
  if (elementType) {
209
618
  const rules = validationRules[elementType];
210
-
619
+
211
620
  if (rules) {
212
621
  Object.values(rules).flat().forEach(rule => {
213
622
  if (rule.check(elem)) {
@@ -233,48 +642,82 @@ let AuroFormValidation$1 = class AuroFormValidation {
233
642
  if (!elem.value.match(emailRegex)) {
234
643
  elem.validity = 'patternMismatch';
235
644
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
645
+ return;
236
646
  }
237
647
  } else if (elem.type === 'credit-card') {
238
648
  if (elem.value.length > 0 && elem.value.length < elem.validationCCLength) {
239
649
  elem.validity = 'tooShort';
240
650
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
651
+ return;
241
652
  }
242
653
  } else if (elem.type === 'number') {
243
654
  if (elem.max !== undefined && Number(elem.max) < Number(elem.value)) {
244
655
  elem.validity = 'rangeOverflow';
245
656
  elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
657
+ return;
246
658
  }
247
659
 
248
660
  if (elem.min !== undefined && elem.value?.length > 0 && Number(elem.min) > Number(elem.value)) {
249
661
  elem.validity = 'rangeUnderflow';
250
662
  elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
663
+ return;
251
664
  }
252
- } else if (elem.type === 'date') {
253
- if (elem.value?.length > 0 && elem.value?.length < elem.lengthForType) {
665
+ } else if (elem.type === 'date' && elem.value?.length > 0) {
666
+
667
+ // Guard Clause: if the value is too short
668
+ if (elem.value.length < elem.lengthForType) {
669
+
254
670
  elem.validity = 'tooShort';
255
671
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
256
- } else if (elem.value?.length === elem.lengthForType && elem.util.toNorthAmericanFormat(elem.value, elem.format)) {
257
- const formattedValue = elem.util.toNorthAmericanFormat(elem.value, elem.format);
258
- const valueDate = new Date(formattedValue.dateForComparison);
672
+ return;
673
+ }
674
+
675
+ // Guard Clause: If the value is too long for the type
676
+ if (elem.value?.length > elem.lengthForType) {
259
677
 
260
- // validate max
261
- if (elem.max?.length === elem.lengthForType) {
262
- const maxDate = new Date(elem.util.toNorthAmericanFormat(elem.max, elem.format).dateForComparison);
678
+ elem.validity = 'tooLong';
679
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
680
+ return;
681
+ }
682
+
683
+ // Validate that the date passed was the correct format
684
+ if (!dateAndFormatMatch$1(elem.value, elem.format)) {
685
+ elem.validity = 'patternMismatch';
686
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || 'Invalid Date Format Entered';
687
+ return;
688
+ }
689
+
690
+ // Validate that the date passed was a valid date
691
+ if (!validDateStr$1(elem.value, elem.format)) {
692
+ elem.validity = 'invalidDate';
693
+ elem.errorMessage = elem.setCustomValidityInvalidDate || elem.setCustomValidity || 'Invalid Date Entered';
694
+ return;
695
+ }
263
696
 
264
- if (valueDate > maxDate) {
265
- elem.validity = 'rangeOverflow';
266
- elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
267
- }
697
+ // Perform the rest of the validation
698
+ const formattedValue = toNorthAmericanFormat$1(elem.value, elem.format);
699
+ const valueDate = new Date(formattedValue);
700
+
701
+ // // Validate max date
702
+ if (elem.max?.length === elem.lengthForType) {
703
+
704
+ const maxDate = new Date(toNorthAmericanFormat$1(elem.max, elem.format));
705
+
706
+ if (valueDate > maxDate) {
707
+ elem.validity = 'rangeOverflow';
708
+ elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
709
+ return;
268
710
  }
711
+ }
269
712
 
270
- // validate min
271
- if (elem.min?.length === elem.lengthForType) {
272
- const minDate = new Date(elem.util.toNorthAmericanFormat(elem.min, elem.format).dateForComparison);
713
+ // Validate min date
714
+ if (elem.min?.length === elem.lengthForType) {
715
+ const minDate = new Date(toNorthAmericanFormat$1(elem.min, elem.format));
273
716
 
274
- if (valueDate < minDate) {
275
- elem.validity = 'rangeUnderflow';
276
- elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
277
- }
717
+ if (valueDate < minDate) {
718
+ elem.validity = 'rangeUnderflow';
719
+ elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
720
+ return;
278
721
  }
279
722
  }
280
723
  }
@@ -393,7 +836,7 @@ let AuroFormValidation$1 = class AuroFormValidation {
393
836
  if (input.validationMessage.length > 0) {
394
837
  elem.errorMessage = input.validationMessage;
395
838
  }
396
- } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
839
+ } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
397
840
  const firstInput = this.inputElements[0];
398
841
 
399
842
  if (firstInput.validationMessage.length > 0) {
@@ -13760,7 +14203,7 @@ class AuroFloatingUI {
13760
14203
  /**
13761
14204
  * @private
13762
14205
  * getting called on 'blur' in trigger or `focusin` in document
13763
- *
14206
+ *
13764
14207
  * Hides the bib if focus moves outside of the trigger or bib, unless a 'noHideOnThisFocusLoss' flag is set.
13765
14208
  * This method checks if the currently active element is still within the trigger or bib.
13766
14209
  * If not, and if the bib isn't in fullscreen mode with focus lost, it hides the bib.
@@ -13876,7 +14319,7 @@ class AuroFloatingUI {
13876
14319
  // Close any other dropdown that is already open
13877
14320
  const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
13878
14321
  if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this &&
13879
- existedVisibleFloatingUI.isPopoverVisible &&
14322
+ existedVisibleFloatingUI.element.isPopoverVisible &&
13880
14323
  document.expandedAuroFloater.eventPrefix === this.eventPrefix) {
13881
14324
  document.expandedAuroFloater.hideBib();
13882
14325
  }
@@ -14052,7 +14495,7 @@ class AuroFloatingUI {
14052
14495
  this.id = window.crypto.randomUUID();
14053
14496
  this.element.setAttribute('id', this.id);
14054
14497
  }
14055
-
14498
+
14056
14499
  this.element.bib.setAttribute("id", `${this.id}-floater-bib`);
14057
14500
  }
14058
14501
 
@@ -14105,7 +14548,7 @@ class AuroFloatingUI {
14105
14548
  if (this.element.bib) {
14106
14549
  this.element.shadowRoot.append(this.element.bib);
14107
14550
  }
14108
-
14551
+
14109
14552
  // Remove event & keyboard listeners
14110
14553
  if (this.element?.trigger) {
14111
14554
  this.element.trigger.removeEventListener('keydown', this.handleEvent);
@@ -14495,7 +14938,6 @@ var tokensCss$1$1 = i$5`:host{--ds-auro-dropdown-label-text-color: var(--ds-basi
14495
14938
 
14496
14939
  const DESIGN_TOKEN_BREAKPOINT_PREFIX = '--ds-grid-breakpoint-';
14497
14940
  const DESIGN_TOKEN_BREAKPOINT_OPTIONS = [
14498
- 'xl',
14499
14941
  'lg',
14500
14942
  'md',
14501
14943
  'sm',
@@ -14567,7 +15009,6 @@ class AuroDropdownBib extends r$2 {
14567
15009
 
14568
15010
  set mobileFullscreenBreakpoint(value) {
14569
15011
  // verify the defined breakpoint is valid and exit out if not
14570
- // 'disabled' is a design token breakpoint so it acts as our "undefined" value
14571
15012
  const validatedValue = DESIGN_TOKEN_BREAKPOINT_OPTIONS.includes(value) ? value : undefined;
14572
15013
  if (!validatedValue) {
14573
15014
  this._mobileBreakpointValue = undefined;
@@ -14836,6 +15277,7 @@ var helpTextVersion$1 = '1.0.0';
14836
15277
  * @csspart helpText - The helpText content container.
14837
15278
  * @event auroDropdown-triggerClick - Notifies that the trigger has been clicked.
14838
15279
  * @event auroDropdown-toggled - Notifies that the visibility of the dropdown bib has changed.
15280
+ * @event auroDropdown-idAdded - Notifies consumers that the unique ID for the dropdown bib has been generated.
14839
15281
  */
14840
15282
  class AuroDropdown extends r$2 {
14841
15283
  constructor() {
@@ -14881,7 +15323,9 @@ class AuroDropdown extends r$2 {
14881
15323
  this.rounded = false;
14882
15324
  this.tabIndex = 0;
14883
15325
  this.noToggle = false;
15326
+ this.a11yAutocomplete = 'none';
14884
15327
  this.labeled = true;
15328
+ this.a11yRole = 'combobox';
14885
15329
  this.onDark = false;
14886
15330
 
14887
15331
  // floaterConfig
@@ -15017,6 +15461,16 @@ class AuroDropdown extends r$2 {
15017
15461
  type: Number
15018
15462
  },
15019
15463
 
15464
+ /**
15465
+ * The unique ID for the dropdown bib element.
15466
+ * @private
15467
+ */
15468
+ dropdownId: {
15469
+ type: String,
15470
+ reflect: false,
15471
+ attribute: false
15472
+ },
15473
+
15020
15474
  /**
15021
15475
  * If declared in combination with `bordered` property or `helpText` slot content, will apply red color to both.
15022
15476
  */
@@ -15080,12 +15534,7 @@ class AuroDropdown extends r$2 {
15080
15534
  },
15081
15535
 
15082
15536
  /**
15083
- * Defines the screen size breakpoint (`xs`, `sm`, `md`, `lg`, `xl`, `disabled`)
15084
- * at which the dropdown switches to fullscreen mode on mobile. `disabled` indicates a dropdown should _never_ enter fullscreen.
15085
- *
15086
- * When expanded, the dropdown will automatically display in fullscreen mode
15087
- * if the screen size is equal to or smaller than the selected breakpoint.
15088
- * @default sm
15537
+ * 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.
15089
15538
  */
15090
15539
  fullscreenBreakpoint: {
15091
15540
  type: String,
@@ -15184,6 +15633,23 @@ class AuroDropdown extends r$2 {
15184
15633
  */
15185
15634
  tabIndex: {
15186
15635
  type: Number
15636
+ },
15637
+
15638
+ /**
15639
+ * The value for the role attribute of the trigger element.
15640
+ */
15641
+ a11yRole: {
15642
+ type: String || undefined,
15643
+ attribute: false,
15644
+ reflect: false
15645
+ },
15646
+
15647
+ /**
15648
+ * The value for the aria-autocomplete attribute of the trigger element.
15649
+ */
15650
+ a11yAutocomplete: {
15651
+ type: String,
15652
+ attribute: false,
15187
15653
  }
15188
15654
  };
15189
15655
  }
@@ -15208,15 +15674,6 @@ class AuroDropdown extends r$2 {
15208
15674
  AuroLibraryRuntimeUtils$1$1.prototype.registerComponent(name, AuroDropdown);
15209
15675
  }
15210
15676
 
15211
- /**
15212
- * Accessor for reusing the focusable entity query string.
15213
- * @private
15214
- * @returns {string}
15215
- */
15216
- get focusableEntityQuery () {
15217
- return 'auro-input, [auro-input], auro-button, [auro-button], button, input';
15218
- }
15219
-
15220
15677
  connectedCallback() {
15221
15678
  super.connectedCallback();
15222
15679
  }
@@ -15230,8 +15687,6 @@ class AuroDropdown extends r$2 {
15230
15687
  updated(changedProperties) {
15231
15688
  this.floater.handleUpdate(changedProperties);
15232
15689
 
15233
- // Note: `disabled` is not a breakpoint (it is not a screen size),
15234
- // so it looks like we never consume this - however, dropdownBib handles this in the setter as "undefined"
15235
15690
  if (changedProperties.has('fullscreenBreakpoint')) {
15236
15691
  this.bibContent.mobileFullscreenBreakpoint = this.fullscreenBreakpoint;
15237
15692
  }
@@ -15245,7 +15700,22 @@ class AuroDropdown extends r$2 {
15245
15700
  }
15246
15701
 
15247
15702
  firstUpdated() {
15703
+
15704
+ // Configure the floater to, this will generate the ID for the bib
15248
15705
  this.floater.configure(this, 'auroDropdown');
15706
+
15707
+ /**
15708
+ * @description Let subscribers know that the dropdown ID ha been generated and added.
15709
+ * @event auroDropdown-idAdded
15710
+ * @type {Object<key: 'id', value: string>} - The ID of the dropdown bib element.
15711
+ */
15712
+ this.dispatchEvent(new CustomEvent('auroDropdown-idAdded', {detail: {id: this.floater.element.id}}));
15713
+
15714
+ // Set the bib ID locally if the user hasn't provided a focusable trigger
15715
+ if (!this.triggerContentFocusable) {
15716
+ this.dropdownId = this.floater.element.id;
15717
+ }
15718
+
15249
15719
  this.bibContent = this.floater.element.bib;
15250
15720
 
15251
15721
  // Add the tag name as an attribute if it is different than the component name
@@ -15367,7 +15837,7 @@ class AuroDropdown extends r$2 {
15367
15837
 
15368
15838
  this.triggerContentSlot.forEach((node) => {
15369
15839
  if (node.querySelectorAll) {
15370
- const auroElements = node.querySelectorAll(this.focusableEntityQuery);
15840
+ const auroElements = node.querySelectorAll('auro-input, [auro-input], auro-button, [auro-button], button, input');
15371
15841
  auroElements.forEach((auroEl) => {
15372
15842
  auroEl.addEventListener('focus', this.bindFocusEventToTrigger);
15373
15843
  auroEl.addEventListener('blur', this.bindFocusEventToTrigger);
@@ -15388,7 +15858,7 @@ class AuroDropdown extends r$2 {
15388
15858
 
15389
15859
  this.triggerContentSlot.forEach((node) => {
15390
15860
  if (node.querySelectorAll) {
15391
- const auroElements = node.querySelectorAll(this.focusableEntityQuery);
15861
+ const auroElements = node.querySelectorAll('auro-input, [auro-input], auro-button, [auro-button], button, input');
15392
15862
  auroElements.forEach((auroEl) => {
15393
15863
  auroEl.removeEventListener('focus', this.bindFocusEventToTrigger);
15394
15864
  auroEl.removeEventListener('blur', this.bindFocusEventToTrigger);
@@ -15397,6 +15867,30 @@ class AuroDropdown extends r$2 {
15397
15867
  });
15398
15868
  }
15399
15869
 
15870
+ /*
15871
+ * Sets aria attributes for the trigger element if a custom one is passed in.
15872
+ * @private
15873
+ * @method setTriggerAriaAttributes
15874
+ * @param { HTMLElement } triggerElement - The custom trigger element.
15875
+ */
15876
+ clearTriggerA11yAttributes(triggerElement) {
15877
+
15878
+ if (!triggerElement || !triggerElement.removeAttribute) {
15879
+ return;
15880
+ }
15881
+
15882
+ // Reset appropriate attributes for a11y
15883
+ triggerElement.removeAttribute('aria-labelledby');
15884
+ if (triggerElement.getAttribute('id') === `${this.id}-trigger-element`) {
15885
+ triggerElement.removeAttribute('id');
15886
+ }
15887
+ triggerElement.removeAttribute('role');
15888
+ triggerElement.removeAttribute('aria-expanded');
15889
+
15890
+ triggerElement.removeAttribute('aria-controls');
15891
+ triggerElement.removeAttribute('aria-autocomplete');
15892
+ }
15893
+
15400
15894
  /**
15401
15895
  * Handles changes to the trigger content slot and updates related properties.
15402
15896
  *
@@ -15410,32 +15904,41 @@ class AuroDropdown extends r$2 {
15410
15904
  * @returns {void}
15411
15905
  */
15412
15906
  handleTriggerContentSlotChange(event) {
15907
+
15413
15908
  this.floater.handleTriggerTabIndex();
15414
15909
 
15910
+ // Get the trigger
15911
+ const trigger = this.shadowRoot.querySelector('#trigger');
15912
+
15913
+ // Get the trigger slot
15415
15914
  const triggerSlot = this.shadowRoot.querySelector('.triggerContent slot');
15416
15915
 
15916
+ // If there's a trigger slot
15417
15917
  if (triggerSlot) {
15418
15918
 
15919
+ // Get the content nodes to see if there are any children
15419
15920
  const triggerContentNodes = triggerSlot.assignedNodes();
15420
15921
 
15922
+ // If there are children
15421
15923
  if (triggerContentNodes) {
15422
15924
 
15423
- triggerContentNodes.forEach((node) => {
15424
- if (!this.triggerContentFocusable) {
15425
- this.triggerContentFocusable = this.containsFocusableElement(node);
15426
- }
15427
- });
15428
- }
15429
- }
15925
+ // See if any of them are focusable elemeents
15926
+ this.triggerContentFocusable = triggerContentNodes.some((node) => this.containsFocusableElement(node));
15430
15927
 
15431
- const trigger = this.shadowRoot.querySelector('#trigger');
15928
+ // If any of them are focusable elements
15929
+ if (this.triggerContentFocusable) {
15432
15930
 
15433
- if (!this.triggerContentFocusable) {
15434
- trigger.setAttribute('tabindex', '0');
15435
- trigger.setAttribute('role', 'button');
15436
- } else {
15437
- trigger.removeAttribute('tabindex');
15438
- trigger.removeAttribute('role');
15931
+ // Assume the consumer will be providing their own a11y in whatever they passed in
15932
+ this.clearTriggerA11yAttributes(trigger);
15933
+
15934
+ // Remove the tabindex from the trigger so it doesn't interrupt focus flow
15935
+ trigger.removeAttribute('tabindex');
15936
+ } else {
15937
+
15938
+ // Add the tabindex to the trigger so that it's in the focus flow
15939
+ trigger.setAttribute('tabindex', '0');
15940
+ }
15941
+ }
15439
15942
  }
15440
15943
 
15441
15944
  if (event) {
@@ -15445,6 +15948,7 @@ class AuroDropdown extends r$2 {
15445
15948
 
15446
15949
  if (this.triggerContentSlot) {
15447
15950
  this.setupTriggerFocusEventBinding();
15951
+
15448
15952
  this.hasTriggerContent = this.triggerContentSlot.some((slot) => {
15449
15953
  if (slot.textContent.trim()) {
15450
15954
  return true;
@@ -15512,10 +16016,13 @@ class AuroDropdown extends r$2 {
15512
16016
  id="trigger"
15513
16017
  class="trigger"
15514
16018
  part="trigger"
15515
- aria-labelledby="triggerLabel"
15516
16019
  tabindex="${this.tabIndex}"
15517
16020
  ?showBorder="${this.showTriggerBorders}"
15518
- >
16021
+ role="${o(this.triggerContentFocusable ? undefined : this.a11yRole)}"
16022
+ aria-expanded="${o(this.triggerContentFocusable ? undefined : this.isPopoverVisible)}"
16023
+ aria-controls="${o(this.triggerContentFocusable ? undefined : this.dropdownId)}"
16024
+ aria-labelledby="${o(this.triggerContentFocusable ? undefined : 'triggerLabel')}"
16025
+ >
15519
16026
  <div class="triggerContentWrapper">
15520
16027
  <label class="label" id="triggerLabel" hasTrigger=${this.hasTriggerContent}>
15521
16028
  <slot name="label" @slotchange="${this.handleLabelSlotChange}"></slot>
@@ -15549,12 +16056,12 @@ class AuroDropdown extends r$2 {
15549
16056
  <div id="bibSizer" part="size"></div>
15550
16057
  <${this.dropdownBibTag}
15551
16058
  id="bib"
15552
- role="tooltip"
15553
16059
  ?data-show="${this.isPopoverVisible}"
15554
16060
  ?isfullscreen="${this.isBibFullscreen}"
15555
16061
  ?common="${this.common}"
15556
16062
  ?rounded="${this.common || this.rounded}"
15557
- ?inset="${this.common || this.inset}">
16063
+ ?inset="${this.common || this.inset}"
16064
+ >
15558
16065
  </${this.dropdownBibTag}>
15559
16066
  </div>
15560
16067
  `;
@@ -19545,6 +20052,414 @@ class AuroInputUtilities {
19545
20052
  }
19546
20053
  }
19547
20054
 
20055
+ class DateFormatter {
20056
+
20057
+ constructor() {
20058
+
20059
+ /**
20060
+ * @description Parses a date string into its components.
20061
+ * @param {string} dateStr - Date string to parse.
20062
+ * @param {string} format - Date format to parse.
20063
+ * @returns {Object<key["month" | "day" | "year"]: number>|undefined}
20064
+ */
20065
+ this.parseDate = (dateStr, format = 'mm/dd/yyyy') => {
20066
+
20067
+ // Guard Clause: Date string is defined
20068
+ if (!dateStr) {
20069
+ return undefined;
20070
+ }
20071
+
20072
+ // Assume the separator is a "/" a defined in our code base
20073
+ const separator = '/';
20074
+
20075
+ // Get the parts of the date and format
20076
+ const valueParts = dateStr.split(separator);
20077
+ const formatParts = format.split(separator);
20078
+
20079
+ // Check if the value and format have the correct number of parts
20080
+ if (valueParts.length !== formatParts.length) {
20081
+ throw new Error('AuroDatepickerUtilities | parseDate: Date string and format length do not match');
20082
+ }
20083
+
20084
+ // Holds the result to be returned
20085
+ const result = formatParts.reduce((acc, part, index) => {
20086
+ const value = valueParts[index];
20087
+
20088
+ if ((/m/iu).test(part)) {
20089
+ acc.month = value;
20090
+ } else if ((/d/iu).test(part)) {
20091
+ acc.day = value;
20092
+ } else if ((/y/iu).test(part)) {
20093
+ acc.year = value;
20094
+ }
20095
+
20096
+ return acc;
20097
+ }, {});
20098
+
20099
+ // If we found all the parts, return the result
20100
+ if (result.month && result.year) {
20101
+ return result;
20102
+ }
20103
+
20104
+ // Throw an error to let the dev know we were unable to parse the date string
20105
+ throw new Error('AuroDatepickerUtilities | parseDate: Unable to parse date string');
20106
+ };
20107
+
20108
+ /**
20109
+ * Convert a date object to string format.
20110
+ * @param {Object} date - Date to convert to string.
20111
+ * @returns {Object} Returns the date as a string.
20112
+ */
20113
+ this.getDateAsString = (date) => date.toLocaleDateString(undefined, {
20114
+ year: "numeric",
20115
+ month: "2-digit",
20116
+ day: "2-digit",
20117
+ });
20118
+
20119
+ /**
20120
+ * Converts a date string to a North American date format.
20121
+ * @param {String} dateStr - Date to validate.
20122
+ * @param {String} format - Date format to validate against.
20123
+ * @returns {Boolean}
20124
+ */
20125
+ this.toNorthAmericanFormat = (dateStr, format) => {
20126
+
20127
+ if (format === 'mm/dd/yyyy') {
20128
+ return dateStr;
20129
+ }
20130
+
20131
+ const parsedDate = this.parseDate(dateStr, format);
20132
+
20133
+ if (!parsedDate) {
20134
+ throw new Error('AuroDatepickerUtilities | toNorthAmericanFormat: Unable to parse date string');
20135
+ }
20136
+
20137
+ const { month, day, year } = parsedDate;
20138
+
20139
+ const dateParts = [];
20140
+ if (month) {
20141
+ dateParts.push(month);
20142
+ }
20143
+
20144
+ if (day) {
20145
+ dateParts.push(day);
20146
+ }
20147
+
20148
+ if (year) {
20149
+ dateParts.push(year);
20150
+ }
20151
+
20152
+ return dateParts.join('/');
20153
+ };
20154
+ }
20155
+ }
20156
+ const dateFormatter = new DateFormatter();
20157
+
20158
+ // filepath: dateConstraints.mjs
20159
+ const DATE_UTIL_CONSTRAINTS = {
20160
+ maxDay: 31,
20161
+ maxMonth: 12,
20162
+ maxYear: 2400,
20163
+ minDay: 1,
20164
+ minMonth: 1,
20165
+ minYear: 1900,
20166
+ };
20167
+
20168
+ class AuroDateUtilitiesBase {
20169
+
20170
+ /**
20171
+ * @description The maximum day value allowed by the various utilities in this class.
20172
+ * @readonly
20173
+ * @type {Number}
20174
+ */
20175
+ get maxDay() {
20176
+ return DATE_UTIL_CONSTRAINTS.maxDay;
20177
+ }
20178
+
20179
+ /**
20180
+ * @description The maximum month value allowed by the various utilities in this class.
20181
+ * @readonly
20182
+ * @type {Number}
20183
+ */
20184
+ get maxMonth() {
20185
+ return DATE_UTIL_CONSTRAINTS.maxMonth;
20186
+ }
20187
+
20188
+ /**
20189
+ * @description The maximum year value allowed by the various utilities in this class.
20190
+ * @readonly
20191
+ * @type {Number}
20192
+ */
20193
+ get maxYear() {
20194
+ return DATE_UTIL_CONSTRAINTS.maxYear;
20195
+ }
20196
+
20197
+ /**
20198
+ * @description The minimum day value allowed by the various utilities in this class.
20199
+ * @readonly
20200
+ * @type {Number}
20201
+ */
20202
+ get minDay() {
20203
+ return DATE_UTIL_CONSTRAINTS.minDay;
20204
+ }
20205
+
20206
+ /**
20207
+ * @description The minimum month value allowed by the various utilities in this class.
20208
+ * @readonly
20209
+ * @type {Number}
20210
+ */
20211
+ get minMonth() {
20212
+ return DATE_UTIL_CONSTRAINTS.minMonth;
20213
+ }
20214
+
20215
+ /**
20216
+ * @description The minimum year value allowed by the various utilities in this class.
20217
+ * @readonly
20218
+ * @type {Number}
20219
+ */
20220
+ get minYear() {
20221
+ return DATE_UTIL_CONSTRAINTS.minYear;
20222
+ }
20223
+ }
20224
+
20225
+ /* eslint-disable no-magic-numbers */
20226
+
20227
+ class AuroDateUtilities extends AuroDateUtilitiesBase {
20228
+
20229
+ /**
20230
+ * Returns the current century.
20231
+ * @returns {String} The current century.
20232
+ */
20233
+ getCentury () {
20234
+ return String(new Date().getFullYear()).slice(0, 2);
20235
+ }
20236
+
20237
+ /**
20238
+ * Returns a four digit year.
20239
+ * @param {String} year - The year to convert to four digits.
20240
+ * @returns {String} The four digit year.
20241
+ */
20242
+ getFourDigitYear (year) {
20243
+
20244
+ const strYear = String(year).trim();
20245
+ return strYear.length <= 2 ? this.getCentury() + strYear : strYear;
20246
+ }
20247
+
20248
+ constructor() {
20249
+
20250
+ super();
20251
+
20252
+ /**
20253
+ * Compares two dates to see if they match.
20254
+ * @param {Object} date1 - First date to compare.
20255
+ * @param {Object} date2 - Second date to compare.
20256
+ * @returns {Boolean} Returns true if the dates match.
20257
+ */
20258
+ this.datesMatch = (date1, date2) => new Date(date1).getTime() === new Date(date2).getTime();
20259
+
20260
+ /**
20261
+ * Returns true if value passed in is a valid date.
20262
+ * @param {String} date - Date to validate.
20263
+ * @param {String} format - Date format to validate against.
20264
+ * @returns {Boolean}
20265
+ */
20266
+ this.validDateStr = (date, format) => {
20267
+
20268
+ // The length we expect the date string to be
20269
+ const dateStrLength = format.length;
20270
+
20271
+ // Guard Clause: Date and format are defined
20272
+ if (typeof date === "undefined" || typeof format === "undefined") {
20273
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date and format are required');
20274
+ }
20275
+
20276
+ // Guard Clause: Date should be of type string
20277
+ if (typeof date !== "string") {
20278
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date must be a string');
20279
+ }
20280
+
20281
+ // Guard Clause: Format should be of type string
20282
+ if (typeof format !== "string") {
20283
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Format must be a string');
20284
+ }
20285
+
20286
+ // Guard Clause: Length is what we expect it to be
20287
+ if (date.length !== dateStrLength) {
20288
+ return false;
20289
+ }
20290
+ // Get a formatted date string and parse it
20291
+ const dateParts = dateFormatter.parseDate(date, format);
20292
+
20293
+ // Guard Clause: Date parse succeeded
20294
+ if (!dateParts) {
20295
+ return false;
20296
+ }
20297
+
20298
+ // Create the expected date string based on the date parts
20299
+ const expectedDateStr = `${dateParts.month}/${dateParts.day || "01"}/${this.getFourDigitYear(dateParts.year)}`;
20300
+
20301
+ // Generate a date object that we will extract a string date from to compare to the passed in date string
20302
+ const dateObj = new Date(this.getFourDigitYear(dateParts.year), dateParts.month - 1, dateParts.day || 1);
20303
+
20304
+ // Get the date string of the date object we created from the string date
20305
+ const actualDateStr = dateFormatter.getDateAsString(dateObj);
20306
+
20307
+ // Guard Clause: Generated date matches date string input
20308
+ if (expectedDateStr !== actualDateStr) {
20309
+ return false;
20310
+ }
20311
+
20312
+ // If we passed all other checks, we can assume the date is valid
20313
+ return true;
20314
+ };
20315
+
20316
+ /**
20317
+ * Determines if a string date value matches the format provided.
20318
+ * @param {string} value = The date string value.
20319
+ * @param { string} format = The date format to match against.
20320
+ * @returns {boolean}
20321
+ */
20322
+ this.dateAndFormatMatch = (value, format) => {
20323
+
20324
+ // Ensure we have both values we need to do the comparison
20325
+ if (!value || !format) {
20326
+ throw new Error('AuroFormValidation | dateFormatMatch: value and format are required');
20327
+ }
20328
+
20329
+ // If the lengths are different, they cannot match
20330
+ if (value.length !== format.length) {
20331
+ return false;
20332
+ }
20333
+
20334
+ // Get the parts of the date
20335
+ const dateParts = dateFormatter.parseDate(value, format);
20336
+
20337
+ // Validator for day
20338
+ const dayValueIsValid = (day) => {
20339
+
20340
+ // Guard clause: if there is no day in the dateParts, we can ignore this check.
20341
+ if (!dateParts.day) {
20342
+ return true;
20343
+ }
20344
+
20345
+ // Guard clause: ensure day exists.
20346
+ if (!day) {
20347
+ return false;
20348
+ }
20349
+
20350
+ // Convert day to number
20351
+ const numDay = Number.parseInt(day, 10);
20352
+
20353
+ // Guard clause: ensure day is a valid integer
20354
+ if (Number.isNaN(numDay)) {
20355
+ throw new Error('AuroDatepickerUtilities | dayValueIsValid: Unable to parse day value integer');
20356
+ }
20357
+
20358
+ // Guard clause: ensure day is within the valid range
20359
+ if (numDay < this.minDay || numDay > this.maxDay) {
20360
+ return false;
20361
+ }
20362
+
20363
+ // Default return
20364
+ return true;
20365
+ };
20366
+
20367
+ // Validator for month
20368
+ const monthValueIsValid = (month) => {
20369
+
20370
+ // Guard clause: ensure month exists.
20371
+ if (!month) {
20372
+ return false;
20373
+ }
20374
+
20375
+ // Convert month to number
20376
+ const numMonth = Number.parseInt(month, 10);
20377
+
20378
+ // Guard clause: ensure month is a valid integer
20379
+ if (Number.isNaN(numMonth)) {
20380
+ throw new Error('AuroDatepickerUtilities | monthValueIsValid: Unable to parse month value integer');
20381
+ }
20382
+
20383
+ // Guard clause: ensure month is within the valid range
20384
+ if (numMonth < this.minMonth || numMonth > this.maxMonth) {
20385
+ return false;
20386
+ }
20387
+
20388
+ // Default return
20389
+ return true;
20390
+ };
20391
+
20392
+ // Validator for year
20393
+ const yearIsValid = (_year) => {
20394
+
20395
+ // Guard clause: ensure year exists.
20396
+ if (!_year) {
20397
+ return false;
20398
+ }
20399
+
20400
+ // Get the full year
20401
+ const year = this.getFourDigitYear(_year);
20402
+
20403
+ // Convert year to number
20404
+ const numYear = Number.parseInt(year, 10);
20405
+
20406
+ // Guard clause: ensure year is a valid integer
20407
+ if (Number.isNaN(numYear)) {
20408
+ throw new Error('AuroDatepickerUtilities | yearValueIsValid: Unable to parse year value integer');
20409
+ }
20410
+
20411
+ // Guard clause: ensure year is within the valid range
20412
+ if (numYear < this.minYear || numYear > this.maxYear) {
20413
+ return false;
20414
+ }
20415
+
20416
+ // Default return
20417
+ return true;
20418
+ };
20419
+
20420
+ // Self-contained checks for month, day, and year
20421
+ const checks = [
20422
+ monthValueIsValid(dateParts.month),
20423
+ dayValueIsValid(dateParts.day),
20424
+ yearIsValid(dateParts.year)
20425
+ ];
20426
+
20427
+ // If any of the checks failed, the date format does not match and the result is invalid
20428
+ const isValid = checks.every((check) => check === true);
20429
+
20430
+ // If the check is invalid, return false
20431
+ if (!isValid) {
20432
+ return false;
20433
+ }
20434
+
20435
+ // Default case
20436
+ return true;
20437
+ };
20438
+ }
20439
+ }
20440
+
20441
+ // Export a class instance
20442
+ const dateUtilities = new AuroDateUtilities();
20443
+
20444
+ // Export the class instance methods individually
20445
+ const {
20446
+ datesMatch,
20447
+ validDateStr,
20448
+ dateAndFormatMatch,
20449
+ minDay,
20450
+ minMonth,
20451
+ minYear,
20452
+ maxDay,
20453
+ maxMonth,
20454
+ maxYear
20455
+ } = dateUtilities;
20456
+
20457
+ const {
20458
+ toNorthAmericanFormat,
20459
+ parseDate,
20460
+ getDateAsString
20461
+ } = dateFormatter;
20462
+
19548
20463
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
19549
20464
  // See LICENSE in the project root for license information.
19550
20465
 
@@ -19620,6 +20535,7 @@ let AuroLibraryRuntimeUtils$1 = class AuroLibraryRuntimeUtils {
19620
20535
 
19621
20536
 
19622
20537
  class AuroFormValidation {
20538
+
19623
20539
  constructor() {
19624
20540
  this.runtimeUtils = new AuroLibraryRuntimeUtils$1();
19625
20541
  }
@@ -19711,17 +20627,17 @@ class AuroFormValidation {
19711
20627
  ]
19712
20628
  }
19713
20629
  };
19714
-
20630
+
19715
20631
  let elementType;
19716
20632
  if (this.runtimeUtils.elementMatch(elem, 'auro-input')) {
19717
20633
  elementType = 'input';
19718
20634
  } else if (this.runtimeUtils.elementMatch(elem, 'auro-counter') || this.runtimeUtils.elementMatch(elem, 'auro-counter-group')) {
19719
20635
  elementType = 'counter';
19720
20636
  }
19721
-
20637
+
19722
20638
  if (elementType) {
19723
20639
  const rules = validationRules[elementType];
19724
-
20640
+
19725
20641
  if (rules) {
19726
20642
  Object.values(rules).flat().forEach(rule => {
19727
20643
  if (rule.check(elem)) {
@@ -19747,48 +20663,82 @@ class AuroFormValidation {
19747
20663
  if (!elem.value.match(emailRegex)) {
19748
20664
  elem.validity = 'patternMismatch';
19749
20665
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
20666
+ return;
19750
20667
  }
19751
20668
  } else if (elem.type === 'credit-card') {
19752
20669
  if (elem.value.length > 0 && elem.value.length < elem.validationCCLength) {
19753
20670
  elem.validity = 'tooShort';
19754
20671
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
20672
+ return;
19755
20673
  }
19756
20674
  } else if (elem.type === 'number') {
19757
20675
  if (elem.max !== undefined && Number(elem.max) < Number(elem.value)) {
19758
20676
  elem.validity = 'rangeOverflow';
19759
20677
  elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
20678
+ return;
19760
20679
  }
19761
20680
 
19762
20681
  if (elem.min !== undefined && elem.value?.length > 0 && Number(elem.min) > Number(elem.value)) {
19763
20682
  elem.validity = 'rangeUnderflow';
19764
20683
  elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
20684
+ return;
19765
20685
  }
19766
- } else if (elem.type === 'date') {
19767
- if (elem.value?.length > 0 && elem.value?.length < elem.lengthForType) {
20686
+ } else if (elem.type === 'date' && elem.value?.length > 0) {
20687
+
20688
+ // Guard Clause: if the value is too short
20689
+ if (elem.value.length < elem.lengthForType) {
20690
+
19768
20691
  elem.validity = 'tooShort';
19769
20692
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
19770
- } else if (elem.value?.length === elem.lengthForType && elem.util.toNorthAmericanFormat(elem.value, elem.format)) {
19771
- const formattedValue = elem.util.toNorthAmericanFormat(elem.value, elem.format);
19772
- const valueDate = new Date(formattedValue.dateForComparison);
20693
+ return;
20694
+ }
20695
+
20696
+ // Guard Clause: If the value is too long for the type
20697
+ if (elem.value?.length > elem.lengthForType) {
19773
20698
 
19774
- // validate max
19775
- if (elem.max?.length === elem.lengthForType) {
19776
- const maxDate = new Date(elem.util.toNorthAmericanFormat(elem.max, elem.format).dateForComparison);
20699
+ elem.validity = 'tooLong';
20700
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
20701
+ return;
20702
+ }
20703
+
20704
+ // Validate that the date passed was the correct format
20705
+ if (!dateAndFormatMatch(elem.value, elem.format)) {
20706
+ elem.validity = 'patternMismatch';
20707
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || 'Invalid Date Format Entered';
20708
+ return;
20709
+ }
20710
+
20711
+ // Validate that the date passed was a valid date
20712
+ if (!validDateStr(elem.value, elem.format)) {
20713
+ elem.validity = 'invalidDate';
20714
+ elem.errorMessage = elem.setCustomValidityInvalidDate || elem.setCustomValidity || 'Invalid Date Entered';
20715
+ return;
20716
+ }
19777
20717
 
19778
- if (valueDate > maxDate) {
19779
- elem.validity = 'rangeOverflow';
19780
- elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
19781
- }
20718
+ // Perform the rest of the validation
20719
+ const formattedValue = toNorthAmericanFormat(elem.value, elem.format);
20720
+ const valueDate = new Date(formattedValue);
20721
+
20722
+ // // Validate max date
20723
+ if (elem.max?.length === elem.lengthForType) {
20724
+
20725
+ const maxDate = new Date(toNorthAmericanFormat(elem.max, elem.format));
20726
+
20727
+ if (valueDate > maxDate) {
20728
+ elem.validity = 'rangeOverflow';
20729
+ elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
20730
+ return;
19782
20731
  }
20732
+ }
19783
20733
 
19784
- // validate min
19785
- if (elem.min?.length === elem.lengthForType) {
19786
- const minDate = new Date(elem.util.toNorthAmericanFormat(elem.min, elem.format).dateForComparison);
20734
+ // Validate min date
20735
+ if (elem.min?.length === elem.lengthForType) {
20736
+ const minDate = new Date(toNorthAmericanFormat(elem.min, elem.format));
19787
20737
 
19788
- if (valueDate < minDate) {
19789
- elem.validity = 'rangeUnderflow';
19790
- elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
19791
- }
20738
+ if (valueDate < minDate) {
20739
+ elem.validity = 'rangeUnderflow';
20740
+ elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
20741
+ return;
19792
20742
  }
19793
20743
  }
19794
20744
  }
@@ -19907,7 +20857,7 @@ class AuroFormValidation {
19907
20857
  if (input.validationMessage.length > 0) {
19908
20858
  elem.errorMessage = input.validationMessage;
19909
20859
  }
19910
- } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
20860
+ } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
19911
20861
  const firstInput = this.inputElements[0];
19912
20862
 
19913
20863
  if (firstInput.validationMessage.length > 0) {
@@ -20029,6 +20979,33 @@ class BaseInput extends r$2 {
20029
20979
  static get properties() {
20030
20980
  return {
20031
20981
 
20982
+ /**
20983
+ * The value for the role attribute.
20984
+ */
20985
+ a11yRole: {
20986
+ type: String,
20987
+ attribute: true,
20988
+ reflect: true
20989
+ },
20990
+
20991
+ /**
20992
+ * The value for the aria-expanded attribute.
20993
+ */
20994
+ a11yExpanded: {
20995
+ type: Boolean,
20996
+ attribute: true,
20997
+ reflect: true
20998
+ },
20999
+
21000
+ /**
21001
+ * The value for the aria-controls attribute.
21002
+ */
21003
+ a11yControls: {
21004
+ type: String,
21005
+ attribute: true,
21006
+ reflect: true
21007
+ },
21008
+
20032
21009
  /**
20033
21010
  * If set, the label will remain fixed in the active position.
20034
21011
  */
@@ -20670,6 +21647,10 @@ class BaseInput extends r$2 {
20670
21647
  } else if (this.type === 'number') {
20671
21648
  this.inputMode = 'numeric';
20672
21649
  }
21650
+
21651
+ if (this.type === "date" && !this.format) {
21652
+ this.format = 'mm/dd/yyyy';
21653
+ }
20673
21654
  }
20674
21655
 
20675
21656
  /**
@@ -21913,6 +22894,7 @@ var helpTextVersion = '1.0.0';
21913
22894
 
21914
22895
  // build the component class
21915
22896
  class AuroInput extends BaseInput {
22897
+
21916
22898
  constructor() {
21917
22899
  super();
21918
22900
 
@@ -22025,7 +23007,7 @@ class AuroInput extends BaseInput {
22025
23007
  ?required="${this.required}"
22026
23008
  ?disabled="${this.disabled}"
22027
23009
  aria-describedby="${this.uniqueId}"
22028
- aria-invalid="${this.validity !== 'valid'}"
23010
+ ?aria-invalid="${this.validity !== 'valid'}"
22029
23011
  placeholder=${this.getPlaceholder()}
22030
23012
  lang="${o(this.lang)}"
22031
23013
  ?activeLabel="${this.activeLabel}"
@@ -22034,7 +23016,10 @@ class AuroInput extends BaseInput {
22034
23016
  autocapitalize="${o(this.autocapitalize ? this.autocapitalize : undefined)}"
22035
23017
  autocomplete="${o(this.autocomplete ? this.autocomplete : undefined)}"
22036
23018
  part="input"
22037
- />
23019
+ role="${o(this.a11yRole)}"
23020
+ aria-expanded="${o(this.a11yExpanded)}"
23021
+ aria-controls="${o(this.a11yControls)}"
23022
+ />
22038
23023
  </div>
22039
23024
  <div
22040
23025
  class="notificationIcons"
@@ -22180,7 +23165,6 @@ class AuroDatePicker extends r$2 {
22180
23165
  this.calendarEndDate = undefined;
22181
23166
  this.calendarFocusDate = this.value;
22182
23167
  this.format = 'mm/dd/yyyy';
22183
- this.fullscreenBreakpoint = 'sm';
22184
23168
  this.monthNames = [
22185
23169
  'January',
22186
23170
  'February',
@@ -22318,19 +23302,6 @@ class AuroDatePicker extends r$2 {
22318
23302
  reflect: true
22319
23303
  },
22320
23304
 
22321
- /**
22322
- * Defines the screen size breakpoint (`xs`, `sm`, `md`, `lg`, `xl`, `disabled`)
22323
- * at which the dropdown switches to fullscreen mode on mobile. `disabled` indicates a dropdown should _never_ enter fullscreen.
22324
- *
22325
- * When expanded, the dropdown will automatically display in fullscreen mode
22326
- * if the screen size is equal to or smaller than the selected breakpoint.
22327
- * @default sm
22328
- */
22329
- fullscreenBreakpoint: {
22330
- type: String,
22331
- reflect: true
22332
- },
22333
-
22334
23305
  /**
22335
23306
  * If declared, make bib.fullscreen.headline in HeadingDisplay.
22336
23307
  * Otherwise, Heading 600.
@@ -23157,7 +24128,7 @@ class AuroDatePicker extends r$2 {
23157
24128
  ?disabled="${this.disabled}"
23158
24129
  ?error="${this.validity !== undefined && this.validity !== 'valid'}"
23159
24130
  disableEventShow
23160
- .fullscreenBreakpoint="${this.fullscreenBreakpoint}"
24131
+ fullscreenBreakpoint="sm"
23161
24132
  .placement="${this.placement}"
23162
24133
  .offset="${this.offset}"
23163
24134
  ?autoPlacement="${this.autoPlacement}"