@aurodesignsystem-dev/auro-formkit 0.0.0-pr1489.4 → 0.0.0-pr1490.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.
- package/components/checkbox/demo/customize.min.js +249 -125
- package/components/checkbox/demo/getting-started.min.js +249 -125
- package/components/checkbox/demo/index.min.js +249 -125
- package/components/checkbox/demo/styles.min.css +1 -1
- package/components/checkbox/dist/index.js +249 -125
- package/components/checkbox/dist/registered.js +249 -125
- package/components/combobox/demo/customize.min.js +502 -254
- package/components/combobox/demo/getting-started.min.js +502 -254
- package/components/combobox/demo/index.min.js +502 -254
- package/components/combobox/demo/styles.min.css +1 -1
- package/components/combobox/dist/index.js +502 -254
- package/components/combobox/dist/registered.js +502 -254
- package/components/counter/demo/customize.min.js +250 -126
- package/components/counter/demo/index.min.js +250 -126
- package/components/counter/demo/styles.min.css +1 -1
- package/components/counter/dist/index.js +249 -125
- package/components/counter/dist/registered.js +249 -125
- package/components/datepicker/demo/accessibility.md +9 -6
- package/components/datepicker/demo/api.md +1 -1
- package/components/datepicker/demo/customize.min.js +1544 -527
- package/components/datepicker/demo/index.md +6 -4
- package/components/datepicker/demo/index.min.js +1560 -532
- package/components/datepicker/demo/keyboard-behavior.md +15 -15
- package/components/datepicker/demo/styles.min.css +1 -1
- package/components/datepicker/demo/voiceover.md +5 -3
- package/components/datepicker/demo/why-datepicker.md +2 -2
- package/components/datepicker/dist/index.js +1536 -519
- package/components/datepicker/dist/registered.js +1536 -519
- package/components/datepicker/dist/src/auro-calendar-cell.d.ts +50 -15
- package/components/datepicker/dist/src/auro-calendar-month.d.ts +9 -0
- package/components/datepicker/dist/src/auro-calendar.d.ts +161 -8
- package/components/datepicker/dist/src/auro-datepicker.d.ts +5 -7
- package/components/dropdown/demo/customize.min.js +1 -1
- package/components/dropdown/demo/getting-started.min.js +1 -1
- package/components/dropdown/demo/index.min.js +1 -1
- package/components/dropdown/demo/styles.min.css +1 -1
- package/components/dropdown/dist/index.js +1 -1
- package/components/dropdown/dist/registered.js +1 -1
- package/components/form/demo/customize.min.js +3263 -1378
- package/components/form/demo/getting-started.min.js +3263 -1378
- package/components/form/demo/index.min.js +3263 -1378
- package/components/form/demo/registerDemoDeps.min.js +3263 -1378
- package/components/form/demo/styles.min.css +1 -1
- package/components/input/demo/customize.min.js +249 -125
- package/components/input/demo/getting-started.min.js +249 -125
- package/components/input/demo/index.min.js +249 -125
- package/components/input/demo/styles.min.css +1 -1
- package/components/input/dist/index.js +249 -125
- package/components/input/dist/registered.js +249 -125
- package/components/menu/demo/styles.min.css +1 -1
- package/components/radio/demo/customize.min.js +249 -125
- package/components/radio/demo/getting-started.min.js +249 -125
- package/components/radio/demo/index.min.js +249 -125
- package/components/radio/demo/styles.min.css +1 -1
- package/components/radio/dist/index.js +249 -125
- package/components/radio/dist/registered.js +249 -125
- package/components/select/demo/customize.min.js +250 -126
- package/components/select/demo/getting-started.min.js +250 -126
- package/components/select/demo/index.min.js +250 -126
- package/components/select/demo/styles.min.css +1 -1
- package/components/select/dist/index.js +250 -126
- package/components/select/dist/registered.js +250 -126
- package/custom-elements.json +964 -637
- package/package.json +8 -8
|
@@ -258,109 +258,236 @@ let p$2 = class p{registerComponent(t,a){customElements.get(t)||customElements.d
|
|
|
258
258
|
|
|
259
259
|
var iconVersion$1 = '9.1.2';
|
|
260
260
|
|
|
261
|
-
|
|
261
|
+
/**
|
|
262
|
+
* @description Splits a date string into its parts according to the provided format. Does NOT validate that the result is a real calendar date — use `parseDate` when validation is required.
|
|
263
|
+
* @param {string} dateStr - Date string to parse.
|
|
264
|
+
* @param {string} format - Date format to parse.
|
|
265
|
+
* @returns {{ month?: string, day?: string, year?: string }|undefined}
|
|
266
|
+
*/
|
|
267
|
+
function getDateParts(dateStr, format) {
|
|
268
|
+
if (!dateStr) {
|
|
269
|
+
return undefined;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const formatSeparatorMatch = format.match(/[/.-]/);
|
|
273
|
+
let valueParts;
|
|
274
|
+
let formatParts;
|
|
275
|
+
|
|
276
|
+
if (formatSeparatorMatch) {
|
|
277
|
+
const separator = formatSeparatorMatch[0];
|
|
278
|
+
valueParts = dateStr.split(separator);
|
|
279
|
+
formatParts = format.split(separator);
|
|
280
|
+
} else {
|
|
281
|
+
if (dateStr.match(/[/.-]/)) {
|
|
282
|
+
throw new Error(
|
|
283
|
+
"AuroDatepickerUtilities | parseDate: Date string has no separators",
|
|
284
|
+
);
|
|
285
|
+
}
|
|
262
286
|
|
|
263
|
-
|
|
287
|
+
if (dateStr.length !== format.length) {
|
|
288
|
+
throw new Error(
|
|
289
|
+
"AuroDatepickerUtilities | parseDate: Date string and format length do not match",
|
|
290
|
+
);
|
|
291
|
+
}
|
|
264
292
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
* @param {string} format - Date format to parse.
|
|
269
|
-
* @returns {Object<key["month" | "day" | "year"]: number>|undefined}
|
|
270
|
-
*/
|
|
271
|
-
this.parseDate = (dateStr, format = 'mm/dd/yyyy') => {
|
|
293
|
+
valueParts = [dateStr];
|
|
294
|
+
formatParts = [format];
|
|
295
|
+
}
|
|
272
296
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
297
|
+
if (valueParts.length !== formatParts.length) {
|
|
298
|
+
throw new Error(
|
|
299
|
+
`AuroDatepickerUtilities | parseDate: Date string and format do not match : ${dateStr} vs ${format}`,
|
|
300
|
+
);
|
|
301
|
+
}
|
|
277
302
|
|
|
278
|
-
|
|
279
|
-
|
|
303
|
+
const result = formatParts.reduce((acc, part, index) => {
|
|
304
|
+
const value = valueParts[index];
|
|
280
305
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
306
|
+
if (/m/iu.test(part) && part.length === value.length) {
|
|
307
|
+
acc.month = value;
|
|
308
|
+
} else if (/d/iu.test(part) && part.length === value.length) {
|
|
309
|
+
acc.day = value;
|
|
310
|
+
} else if (/y/iu.test(part) && part.length === value.length) {
|
|
311
|
+
acc.year = value;
|
|
312
|
+
}
|
|
284
313
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
throw new Error('AuroDatepickerUtilities | parseDate: Date string and format length do not match');
|
|
288
|
-
}
|
|
314
|
+
return acc;
|
|
315
|
+
}, {});
|
|
289
316
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
317
|
+
if (!result.month && !result.day && !result.year) {
|
|
318
|
+
throw new Error(
|
|
319
|
+
"AuroDatepickerUtilities | parseDate: Unable to parse date string",
|
|
320
|
+
);
|
|
321
|
+
}
|
|
293
322
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
} else if ((/d/iu).test(part)) {
|
|
297
|
-
acc.day = value;
|
|
298
|
-
} else if ((/y/iu).test(part)) {
|
|
299
|
-
acc.year = value;
|
|
300
|
-
}
|
|
323
|
+
return result;
|
|
324
|
+
}
|
|
301
325
|
|
|
302
|
-
|
|
303
|
-
|
|
326
|
+
function isCalendarDate(year, month, day) {
|
|
327
|
+
let yearNumber = Number(year);
|
|
328
|
+
const monthNumber = Number(month);
|
|
329
|
+
const dayNumber = Number(day);
|
|
304
330
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
331
|
+
if (
|
|
332
|
+
!Number.isInteger(yearNumber) ||
|
|
333
|
+
!Number.isInteger(monthNumber) ||
|
|
334
|
+
!Number.isInteger(dayNumber)
|
|
335
|
+
) {
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
309
338
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
339
|
+
// Handle 2-digit years by converting them to 4-digit years based on a cutoff. This allows for parsing of 2-digit year formats while still validating the resulting date.
|
|
340
|
+
if (yearNumber < 100 && yearNumber >= 50) {
|
|
341
|
+
yearNumber += 1900;
|
|
342
|
+
} else if (yearNumber < 50) {
|
|
343
|
+
yearNumber += 2000;
|
|
344
|
+
}
|
|
313
345
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
* @param {Object} date - Date to convert to string.
|
|
317
|
-
* @param {String} locale - Optional locale to use for the date string. Defaults to user's locale.
|
|
318
|
-
* @returns {String} Returns the date as a string.
|
|
319
|
-
*/
|
|
320
|
-
this.getDateAsString = (date, locale = undefined) => date.toLocaleDateString(locale, {
|
|
321
|
-
year: "numeric",
|
|
322
|
-
month: "2-digit",
|
|
323
|
-
day: "2-digit",
|
|
324
|
-
});
|
|
346
|
+
const stringified = `${String(yearNumber).padStart(4, "0")}-${String(monthNumber).padStart(2, "0")}-${String(dayNumber).padStart(2, "0")}`;
|
|
347
|
+
const date = new Date(stringified.replace(/[.-]/g, "/"));
|
|
325
348
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
* @returns {Boolean}
|
|
331
|
-
*/
|
|
332
|
-
this.toNorthAmericanFormat = (dateStr, format) => {
|
|
349
|
+
return (
|
|
350
|
+
!Number.isNaN(date.getTime()) && toISOFormatString(date) === stringified
|
|
351
|
+
);
|
|
352
|
+
}
|
|
333
353
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
354
|
+
/**
|
|
355
|
+
* @description Parses a date string into its components and validates that the result is a real calendar date. Use `getDateParts` instead when raw splitting without validation is needed (e.g. for in-progress input).
|
|
356
|
+
*
|
|
357
|
+
* Partial formats are supported: components absent from `format` default to `year → "0"`,
|
|
358
|
+
* `month → "01"`, `day → "01"` for calendar validation only. The returned object contains
|
|
359
|
+
* only the fields actually present in the format string — missing fields are never injected.
|
|
360
|
+
* @param {string} dateStr - Date string to parse.
|
|
361
|
+
* @param {string} format - Date format to parse.
|
|
362
|
+
* @returns {{ month?: string, day?: string, year?: string }|undefined}
|
|
363
|
+
* @throws {Error} Throws when the parsed result does not represent a valid calendar date.
|
|
364
|
+
*/
|
|
365
|
+
function parseDate(dateStr, format = "mm/dd/yyyy") {
|
|
366
|
+
if (!dateStr || !format) {
|
|
367
|
+
return undefined;
|
|
368
|
+
}
|
|
369
|
+
const result = getDateParts(dateStr.trim(), format);
|
|
337
370
|
|
|
338
|
-
|
|
371
|
+
if (!result) {
|
|
372
|
+
return undefined;
|
|
373
|
+
}
|
|
339
374
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
375
|
+
const lowerFormat = format.toLowerCase();
|
|
376
|
+
const year = lowerFormat.includes("yy") ? result.year : "0";
|
|
377
|
+
const month = lowerFormat.includes("mm") ? result.month : "01";
|
|
378
|
+
const day = lowerFormat.includes("dd") ? result.day : "01";
|
|
343
379
|
|
|
344
|
-
|
|
380
|
+
if (isCalendarDate(year, month, day)) {
|
|
381
|
+
return result;
|
|
382
|
+
}
|
|
345
383
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
384
|
+
throw new Error(
|
|
385
|
+
`AuroDatepickerUtilities | parseDate: Date string is not a valid date ${JSON.stringify(result)} with format ${format}`,
|
|
386
|
+
);
|
|
387
|
+
}
|
|
350
388
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
389
|
+
/**
|
|
390
|
+
* Convert a date object to string format.
|
|
391
|
+
* @param {Object} date - Date to convert to string.
|
|
392
|
+
* @param {String} locale - Optional locale to use for the date string. Defaults to user's locale.
|
|
393
|
+
* @returns {String} Returns the date as a string.
|
|
394
|
+
*/
|
|
395
|
+
function getDateAsString(date, locale = undefined) {
|
|
396
|
+
return date.toLocaleDateString(locale, {
|
|
397
|
+
year: "numeric",
|
|
398
|
+
month: "2-digit",
|
|
399
|
+
day: "2-digit",
|
|
400
|
+
});
|
|
401
|
+
}
|
|
354
402
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
403
|
+
/**
|
|
404
|
+
* Converts a date string to a North American date format.
|
|
405
|
+
* @param {String} dateStr - Date to validate.
|
|
406
|
+
* @param {String} format - Date format to validate against.
|
|
407
|
+
* @returns {String}
|
|
408
|
+
*/
|
|
409
|
+
function toNorthAmericanFormat$1(dateStr, format) {
|
|
410
|
+
if (format === "mm/dd/yyyy") {
|
|
411
|
+
return dateStr;
|
|
412
|
+
}
|
|
358
413
|
|
|
359
|
-
|
|
360
|
-
|
|
414
|
+
const parsedDate = parseDate(dateStr, format);
|
|
415
|
+
|
|
416
|
+
if (!parsedDate) {
|
|
417
|
+
throw new Error(
|
|
418
|
+
"AuroDatepickerUtilities | toNorthAmericanFormat: Unable to parse date string",
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const { month, day, year } = parsedDate;
|
|
423
|
+
|
|
424
|
+
return [month, day, year].filter(Boolean).join("/");
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Validates that a date string matches the provided format and represents a real calendar date.
|
|
429
|
+
*
|
|
430
|
+
* @param {string} dateStr - Date string to validate.
|
|
431
|
+
* @param {string} [format="yyyy-mm-dd"] - Format of the date string.
|
|
432
|
+
* @returns {boolean} True when the date string is valid for the provided format, otherwise false.
|
|
433
|
+
*/
|
|
434
|
+
function isValidDate(dateStr, format = "yyyy-mm-dd") {
|
|
435
|
+
try {
|
|
436
|
+
if (typeof dateStr !== "string" || !dateStr || format?.length < 8) {
|
|
437
|
+
return false;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
if (parseDate(dateStr, format)) {
|
|
441
|
+
return true;
|
|
442
|
+
}
|
|
443
|
+
} catch (error) {
|
|
444
|
+
return false;
|
|
445
|
+
}
|
|
446
|
+
return false;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Converts a JavaScript Date instance to a simple ISO-like date string. This returns only the calendar date portion without any time or timezone information.
|
|
451
|
+
*
|
|
452
|
+
* @param {Date} date - Date instance to convert to an ISO-like string.
|
|
453
|
+
* @returns {string} A string in the format "yyyy-mm-dd" representing the provided date.
|
|
454
|
+
* @throws {Error} Throws an error when the input is not a valid Date instance.
|
|
455
|
+
*/
|
|
456
|
+
function toISOFormatString(date) {
|
|
457
|
+
if (!(date instanceof Date) || Number.isNaN(date.getTime())) {
|
|
458
|
+
throw new Error(
|
|
459
|
+
"AuroDatepickerUtilities | toISOFormatString: Input must be a valid Date instance",
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
return `${String(date.getFullYear()).padStart(4, "0")}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}`;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Converts a date string into a JavaScript Date instance. This method supports ISO formatted strings and other formats that can be parsed by the formatter.
|
|
467
|
+
*
|
|
468
|
+
* @param {String} dateStr - Date string to convert into a Date object.
|
|
469
|
+
* @param {String} format - Date format used to parse the string when it is not in ISO format.
|
|
470
|
+
* @returns {Date|null} Returns a Date instance for valid input or null for non-string input.
|
|
471
|
+
* @throws {Error} Throws when parsing fails for non-ISO string input.
|
|
472
|
+
*/
|
|
473
|
+
function stringToDateInstance(dateStr, format = "yyyy-mm-dd") {
|
|
474
|
+
if (typeof dateStr !== "string") {
|
|
475
|
+
return null;
|
|
361
476
|
}
|
|
477
|
+
|
|
478
|
+
const { month, day, year } = parseDate(dateStr, format);
|
|
479
|
+
return new Date(`${year}/${month}/${day}`);
|
|
362
480
|
}
|
|
363
|
-
|
|
481
|
+
|
|
482
|
+
const dateFormatter = {
|
|
483
|
+
parseDate,
|
|
484
|
+
getDateParts,
|
|
485
|
+
getDateAsString,
|
|
486
|
+
toNorthAmericanFormat: toNorthAmericanFormat$1,
|
|
487
|
+
isValidDate,
|
|
488
|
+
toISOFormatString,
|
|
489
|
+
stringToDateInstance,
|
|
490
|
+
};
|
|
364
491
|
|
|
365
492
|
// filepath: dateConstraints.mjs
|
|
366
493
|
const DATE_UTIL_CONSTRAINTS = {
|
|
@@ -432,12 +559,11 @@ class AuroDateUtilitiesBase {
|
|
|
432
559
|
/* eslint-disable no-magic-numbers */
|
|
433
560
|
|
|
434
561
|
class AuroDateUtilities extends AuroDateUtilitiesBase {
|
|
435
|
-
|
|
436
562
|
/**
|
|
437
563
|
* Returns the current century.
|
|
438
564
|
* @returns {String} The current century.
|
|
439
565
|
*/
|
|
440
|
-
getCentury
|
|
566
|
+
getCentury() {
|
|
441
567
|
return String(new Date().getFullYear()).slice(0, 2);
|
|
442
568
|
}
|
|
443
569
|
|
|
@@ -446,14 +572,12 @@ class AuroDateUtilities extends AuroDateUtilitiesBase {
|
|
|
446
572
|
* @param {String} year - The year to convert to four digits.
|
|
447
573
|
* @returns {String} The four digit year.
|
|
448
574
|
*/
|
|
449
|
-
getFourDigitYear
|
|
450
|
-
|
|
575
|
+
getFourDigitYear(year) {
|
|
451
576
|
const strYear = String(year).trim();
|
|
452
577
|
return strYear.length <= 2 ? this.getCentury() + strYear : strYear;
|
|
453
578
|
}
|
|
454
579
|
|
|
455
580
|
constructor() {
|
|
456
|
-
|
|
457
581
|
super();
|
|
458
582
|
|
|
459
583
|
/**
|
|
@@ -462,7 +586,8 @@ class AuroDateUtilities extends AuroDateUtilitiesBase {
|
|
|
462
586
|
* @param {Object} date2 - Second date to compare.
|
|
463
587
|
* @returns {Boolean} Returns true if the dates match.
|
|
464
588
|
*/
|
|
465
|
-
this.datesMatch = (date1, date2) =>
|
|
589
|
+
this.datesMatch = (date1, date2) =>
|
|
590
|
+
new Date(date1).getTime() === new Date(date2).getTime();
|
|
466
591
|
|
|
467
592
|
/**
|
|
468
593
|
* Returns true if value passed in is a valid date.
|
|
@@ -471,53 +596,41 @@ class AuroDateUtilities extends AuroDateUtilitiesBase {
|
|
|
471
596
|
* @returns {Boolean}
|
|
472
597
|
*/
|
|
473
598
|
this.validDateStr = (date, format) => {
|
|
474
|
-
|
|
475
599
|
// The length we expect the date string to be
|
|
476
|
-
const dateStrLength = format
|
|
600
|
+
const dateStrLength = format?.length || 0;
|
|
477
601
|
|
|
478
602
|
// Guard Clause: Date and format are defined
|
|
479
603
|
if (typeof date === "undefined" || typeof format === "undefined") {
|
|
480
|
-
throw new Error(
|
|
604
|
+
throw new Error(
|
|
605
|
+
"AuroDatepickerUtilities | validateDateStr: Date and format are required",
|
|
606
|
+
);
|
|
481
607
|
}
|
|
482
608
|
|
|
483
609
|
// Guard Clause: Date should be of type string
|
|
484
610
|
if (typeof date !== "string") {
|
|
485
|
-
throw new Error(
|
|
611
|
+
throw new Error(
|
|
612
|
+
"AuroDatepickerUtilities | validateDateStr: Date must be a string",
|
|
613
|
+
);
|
|
486
614
|
}
|
|
487
615
|
|
|
488
616
|
// Guard Clause: Format should be of type string
|
|
489
617
|
if (typeof format !== "string") {
|
|
490
|
-
throw new Error(
|
|
618
|
+
throw new Error(
|
|
619
|
+
"AuroDatepickerUtilities | validateDateStr: Format must be a string",
|
|
620
|
+
);
|
|
491
621
|
}
|
|
492
622
|
|
|
493
623
|
// Guard Clause: Length is what we expect it to be
|
|
494
624
|
if (date.length !== dateStrLength) {
|
|
495
625
|
return false;
|
|
496
626
|
}
|
|
497
|
-
// Get a formatted date string and parse it
|
|
498
|
-
const dateParts = dateFormatter.parseDate(date, format);
|
|
499
627
|
|
|
500
|
-
//
|
|
501
|
-
|
|
628
|
+
// Get a formatted date string and parse and validate it
|
|
629
|
+
try {
|
|
630
|
+
return Boolean(dateFormatter.parseDate(date, format));
|
|
631
|
+
} catch (error) {
|
|
502
632
|
return false;
|
|
503
633
|
}
|
|
504
|
-
|
|
505
|
-
// Create the expected date string based on the date parts
|
|
506
|
-
const expectedDateStr = `${dateParts.month}/${dateParts.day || "01"}/${this.getFourDigitYear(dateParts.year)}`;
|
|
507
|
-
|
|
508
|
-
// Generate a date object that we will extract a string date from to compare to the passed in date string
|
|
509
|
-
const dateObj = new Date(this.getFourDigitYear(dateParts.year), dateParts.month - 1, dateParts.day || 1);
|
|
510
|
-
|
|
511
|
-
// Get the date string of the date object we created from the string date
|
|
512
|
-
const actualDateStr = dateFormatter.getDateAsString(dateObj, "en-US");
|
|
513
|
-
|
|
514
|
-
// Guard Clause: Generated date matches date string input
|
|
515
|
-
if (expectedDateStr !== actualDateStr) {
|
|
516
|
-
return false;
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
// If we passed all other checks, we can assume the date is valid
|
|
520
|
-
return true;
|
|
521
634
|
};
|
|
522
635
|
|
|
523
636
|
/**
|
|
@@ -527,10 +640,11 @@ class AuroDateUtilities extends AuroDateUtilitiesBase {
|
|
|
527
640
|
* @returns {boolean}
|
|
528
641
|
*/
|
|
529
642
|
this.dateAndFormatMatch = (value, format) => {
|
|
530
|
-
|
|
531
643
|
// Ensure we have both values we need to do the comparison
|
|
532
644
|
if (!value || !format) {
|
|
533
|
-
throw new Error(
|
|
645
|
+
throw new Error(
|
|
646
|
+
"AuroFormValidation | dateFormatMatch: value and format are required",
|
|
647
|
+
);
|
|
534
648
|
}
|
|
535
649
|
|
|
536
650
|
// If the lengths are different, they cannot match
|
|
@@ -539,11 +653,10 @@ class AuroDateUtilities extends AuroDateUtilitiesBase {
|
|
|
539
653
|
}
|
|
540
654
|
|
|
541
655
|
// Get the parts of the date
|
|
542
|
-
const dateParts = dateFormatter.
|
|
656
|
+
const dateParts = dateFormatter.getDateParts(value, format);
|
|
543
657
|
|
|
544
658
|
// Validator for day
|
|
545
659
|
const dayValueIsValid = (day) => {
|
|
546
|
-
|
|
547
660
|
// Guard clause: if there is no day in the dateParts, we can ignore this check.
|
|
548
661
|
if (!dateParts.day) {
|
|
549
662
|
return true;
|
|
@@ -559,7 +672,9 @@ class AuroDateUtilities extends AuroDateUtilitiesBase {
|
|
|
559
672
|
|
|
560
673
|
// Guard clause: ensure day is a valid integer
|
|
561
674
|
if (Number.isNaN(numDay)) {
|
|
562
|
-
throw new Error(
|
|
675
|
+
throw new Error(
|
|
676
|
+
"AuroDatepickerUtilities | dayValueIsValid: Unable to parse day value integer",
|
|
677
|
+
);
|
|
563
678
|
}
|
|
564
679
|
|
|
565
680
|
// Guard clause: ensure day is within the valid range
|
|
@@ -573,6 +688,10 @@ class AuroDateUtilities extends AuroDateUtilitiesBase {
|
|
|
573
688
|
|
|
574
689
|
// Validator for month
|
|
575
690
|
const monthValueIsValid = (month) => {
|
|
691
|
+
// Guard clause: if there is no month in the dateParts, we can ignore this check.
|
|
692
|
+
if (!dateParts.month) {
|
|
693
|
+
return true;
|
|
694
|
+
}
|
|
576
695
|
|
|
577
696
|
// Guard clause: ensure month exists.
|
|
578
697
|
if (!month) {
|
|
@@ -584,7 +703,9 @@ class AuroDateUtilities extends AuroDateUtilitiesBase {
|
|
|
584
703
|
|
|
585
704
|
// Guard clause: ensure month is a valid integer
|
|
586
705
|
if (Number.isNaN(numMonth)) {
|
|
587
|
-
throw new Error(
|
|
706
|
+
throw new Error(
|
|
707
|
+
"AuroDatepickerUtilities | monthValueIsValid: Unable to parse month value integer",
|
|
708
|
+
);
|
|
588
709
|
}
|
|
589
710
|
|
|
590
711
|
// Guard clause: ensure month is within the valid range
|
|
@@ -598,6 +719,10 @@ class AuroDateUtilities extends AuroDateUtilitiesBase {
|
|
|
598
719
|
|
|
599
720
|
// Validator for year
|
|
600
721
|
const yearIsValid = (_year) => {
|
|
722
|
+
// Guard clause: if there is no year in the dateParts, we can ignore this check.
|
|
723
|
+
if (!dateParts.year) {
|
|
724
|
+
return true;
|
|
725
|
+
}
|
|
601
726
|
|
|
602
727
|
// Guard clause: ensure year exists.
|
|
603
728
|
if (!_year) {
|
|
@@ -612,7 +737,9 @@ class AuroDateUtilities extends AuroDateUtilitiesBase {
|
|
|
612
737
|
|
|
613
738
|
// Guard clause: ensure year is a valid integer
|
|
614
739
|
if (Number.isNaN(numYear)) {
|
|
615
|
-
throw new Error(
|
|
740
|
+
throw new Error(
|
|
741
|
+
"AuroDatepickerUtilities | yearValueIsValid: Unable to parse year value integer",
|
|
742
|
+
);
|
|
616
743
|
}
|
|
617
744
|
|
|
618
745
|
// Guard clause: ensure year is within the valid range
|
|
@@ -628,7 +755,7 @@ class AuroDateUtilities extends AuroDateUtilitiesBase {
|
|
|
628
755
|
const checks = [
|
|
629
756
|
monthValueIsValid(dateParts.month),
|
|
630
757
|
dayValueIsValid(dateParts.day),
|
|
631
|
-
yearIsValid(dateParts.year)
|
|
758
|
+
yearIsValid(dateParts.year),
|
|
632
759
|
];
|
|
633
760
|
|
|
634
761
|
// If any of the checks failed, the date format does not match and the result is invalid
|
|
@@ -662,10 +789,7 @@ const {
|
|
|
662
789
|
} = dateUtilities;
|
|
663
790
|
|
|
664
791
|
const {
|
|
665
|
-
toNorthAmericanFormat
|
|
666
|
-
parseDate,
|
|
667
|
-
getDateAsString
|
|
668
|
-
} = dateFormatter;
|
|
792
|
+
toNorthAmericanFormat} = dateFormatter;
|
|
669
793
|
|
|
670
794
|
// Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
|
|
671
795
|
// See LICENSE in the project root for license information.
|
|
@@ -1471,7 +1595,7 @@ class AuroHelpText extends LitElement {
|
|
|
1471
1595
|
}
|
|
1472
1596
|
}
|
|
1473
1597
|
|
|
1474
|
-
var formkitVersion = '
|
|
1598
|
+
var formkitVersion = '202606012111';
|
|
1475
1599
|
|
|
1476
1600
|
// Copyright (c) 2026 Alaska Airlines. All rights reserved. Licensed under the Apache-2.0 license
|
|
1477
1601
|
// See LICENSE in the project root for license information.
|
|
@@ -35,17 +35,19 @@ The calendar uses the WAI-ARIA grid pattern for screen reader navigation:
|
|
|
35
35
|
| `role="rowgroup"` | Header / body groups | Groups the day-of-week header row and the week rows. |
|
|
36
36
|
| `role="row"` | Week row | Groups each week of date cells. |
|
|
37
37
|
| `role="columnheader"` | Day-of-week header | Each day-of-week abbreviation. Rendered as an `<abbr>` element with the full day name in the `title` attribute so screen readers can announce the expanded form. |
|
|
38
|
-
| `role="gridcell"` | In-range date cell | Each selectable date cell. Includes `aria-selected`, `aria-current="date"` (for today), and a visually-hidden text label. |
|
|
38
|
+
| `role="gridcell"` | In-range date cell, active-descendant proxy | Each selectable date cell. Includes `aria-selected`, `aria-current="date"` (for today), and a visually-hidden text label. A proxy `<span>` inside the calendar grid wrapper mirrors the active cell's ARIA attributes for `aria-activedescendant`. |
|
|
39
39
|
| `role="presentation"` | Out-of-range date cell | Cells outside the valid min/max range. Also receive `aria-hidden="true"` and `tabindex="-1"` to remove them from both the accessibility tree and the tab order. |
|
|
40
40
|
| `aria-disabled="true"` | Blackout date cell | Cells matching the `blackout` dates list. Unlike out-of-range cells, blackout cells **remain focusable** via arrow-key navigation so screen reader users can discover them. The cell's label includes ", unavailable" to communicate that the date cannot be selected. |
|
|
41
41
|
| `aria-selected` | Date cell button | `"true"` for the selected date(s), `"false"` for all other in-range cells. |
|
|
42
|
-
| Accessible name | Date cell button | Provided via visually-hidden text content (not an `aria-label` attribute). Localized label built from `Intl.DateTimeFormat` (weekday, month, day, year), plus the range position label (e.g., "range start") and availability status (", unavailable" for blackout dates). |
|
|
42
|
+
| Accessible name | Date cell button | Provided via visually-hidden text content (not an `aria-label` attribute). Localized label built from `Intl.DateTimeFormat` (weekday, month, day, year), plus any date slot content (e.g. prices), the range position label (e.g., "range start"), and availability status (", unavailable" for blackout dates). |
|
|
43
43
|
|
|
44
44
|
<auro-header level="2" id="focusManagement">Focus Management</auro-header>
|
|
45
45
|
The component uses `delegatesFocus: true` on its shadow root, meaning focus is automatically delegated to the first focusable element inside the component (the date input).
|
|
46
46
|
|
|
47
|
-
<auro-header level="3" id="
|
|
48
|
-
The calendar grid uses
|
|
47
|
+
<auro-header level="3" id="ariaActivedescendant">aria-activedescendant</auro-header>
|
|
48
|
+
The calendar grid uses an **`aria-activedescendant`** pattern for keyboard navigation. DOM focus remains on a wrapper element (`#calendarGrid`) while `aria-activedescendant` points to a proxy `<span>` that mirrors the active cell's ARIA attributes (`aria-label`, `aria-selected`, `aria-current`, `aria-disabled`). This approach keeps the screen reader in sync with the visually active cell without moving DOM focus on every keystroke, which prevents duplicate announcements during rapid arrow-key navigation.
|
|
49
|
+
|
|
50
|
+
The active cell receives a `.visualFocus` CSS class to display a visible focus ring, since the native `:focus-visible` pseudo-class applies to the grid wrapper (which holds actual DOM focus), not to individual cells.
|
|
49
51
|
|
|
50
52
|
The initial active cell is determined in priority order:
|
|
51
53
|
|
|
@@ -55,11 +57,12 @@ The initial active cell is determined in priority order:
|
|
|
55
57
|
4. The first past enabled date.
|
|
56
58
|
|
|
57
59
|
<auro-header level="3" id="focusOnOpen">Focus on Open</auro-header>
|
|
58
|
-
When the calendar bib opens, focus moves to the active date cell
|
|
60
|
+
When the calendar bib opens, focus moves to the calendar grid wrapper (`#calendarGrid`). The `aria-activedescendant` attribute points to a proxy element that carries the active date cell's label, so screen readers announce the active date. This applies to both desktop and fullscreen modes.
|
|
59
61
|
|
|
60
62
|
<auro-header level="2" id="screenReaderAnnouncements">Screen Reader Announcements</auro-header>
|
|
61
63
|
- **Date selection** — When a date is selected, the calendar's live region (`aria-live="assertive"`) announces the formatted date (e.g., "Wednesday, January 15, 2025"). For range datepickers, both the start and end date selections are announced.
|
|
62
|
-
- **
|
|
64
|
+
- **Debounced navigation announcement** — During arrow-key navigation, a debounced live region (150 ms) announces the full date context (date, slot content, range position, availability) after the user pauses. This prevents overlapping announcements during rapid navigation.
|
|
65
|
+
- **Date cell labels** — Each date cell contains a visually-hidden `<span class="srOnly">` with the full localized label, including any date slot content (e.g. prices). VoiceOver reads this content instead of `aria-label`, which iOS VoiceOver does not reliably announce on buttons.
|
|
63
66
|
- **Validation errors** — When a validation error occurs, the error message is rendered with `role="alert"` and `aria-live="assertive"`, causing it to be announced immediately without requiring focus.
|
|
64
67
|
- **Help text** — The help text content is associated with the input so that screen readers announce it as part of the element description when focused.
|
|
65
68
|
|
|
@@ -9,7 +9,7 @@ The `auro-datepicker` component provides users with a way to select a date or da
|
|
|
9
9
|
|
|
10
10
|
| Property | Attribute | Modifiers | Type | Default | Description |
|
|
11
11
|
|-----------------------------------|-----------------------------------|-----------|--------------------------------------------------|--------------------------------------------------|--------------------------------------------------|
|
|
12
|
-
| `appearance` | `appearance` | | `
|
|
12
|
+
| `appearance` | `appearance` | | `'default' \| 'inverse'` | "'default'" | Defines whether the component will be on lighter or darker backgrounds. |
|
|
13
13
|
| `autoPlacement` | `autoPlacement` | | `boolean` | "false" | If declared, bib's position will be automatically calculated where to appear. |
|
|
14
14
|
| `blackoutDates` | `blackoutDates` | | `array` | [] | Array of dates that cannot be selected. Dates should be in ISO format (YYYY-MM-DD). |
|
|
15
15
|
| `blackoutLabel` | `blackoutLabel` | | `string` | "unavailable" | Label announced for blackout (disabled but in-range) date cells. |
|