@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
@@ -405,11 +405,420 @@ var styleCss$1 = i$5`:host{display:block;padding-bottom:var(--ds-size-150, 0.75r
405
405
 
406
406
  var colorCss$1 = i$5`:host legend{color:var(--ds-auro-radio-group-label-color)}:host([disabled]){--ds-auro-radio-group-label-color: var(--ds-basic-color-texticon-disabled, #d0d0d0)}:host([onDark]){--ds-auro-radio-group-label-color: var(--ds-basic-color-texticon-inverse, #ffffff)}:host([onDark][disabled]){--ds-auro-radio-group-label-color: var(--ds-basic-color-texticon-inverse-disabled, #7e8894)}`;
407
407
 
408
+ class DateFormatter {
409
+
410
+ constructor() {
411
+
412
+ /**
413
+ * @description Parses a date string into its components.
414
+ * @param {string} dateStr - Date string to parse.
415
+ * @param {string} format - Date format to parse.
416
+ * @returns {Object<key["month" | "day" | "year"]: number>|undefined}
417
+ */
418
+ this.parseDate = (dateStr, format = 'mm/dd/yyyy') => {
419
+
420
+ // Guard Clause: Date string is defined
421
+ if (!dateStr) {
422
+ return undefined;
423
+ }
424
+
425
+ // Assume the separator is a "/" a defined in our code base
426
+ const separator = '/';
427
+
428
+ // Get the parts of the date and format
429
+ const valueParts = dateStr.split(separator);
430
+ const formatParts = format.split(separator);
431
+
432
+ // Check if the value and format have the correct number of parts
433
+ if (valueParts.length !== formatParts.length) {
434
+ throw new Error('AuroDatepickerUtilities | parseDate: Date string and format length do not match');
435
+ }
436
+
437
+ // Holds the result to be returned
438
+ const result = formatParts.reduce((acc, part, index) => {
439
+ const value = valueParts[index];
440
+
441
+ if ((/m/iu).test(part)) {
442
+ acc.month = value;
443
+ } else if ((/d/iu).test(part)) {
444
+ acc.day = value;
445
+ } else if ((/y/iu).test(part)) {
446
+ acc.year = value;
447
+ }
448
+
449
+ return acc;
450
+ }, {});
451
+
452
+ // If we found all the parts, return the result
453
+ if (result.month && result.year) {
454
+ return result;
455
+ }
456
+
457
+ // Throw an error to let the dev know we were unable to parse the date string
458
+ throw new Error('AuroDatepickerUtilities | parseDate: Unable to parse date string');
459
+ };
460
+
461
+ /**
462
+ * Convert a date object to string format.
463
+ * @param {Object} date - Date to convert to string.
464
+ * @returns {Object} Returns the date as a string.
465
+ */
466
+ this.getDateAsString = (date) => date.toLocaleDateString(undefined, {
467
+ year: "numeric",
468
+ month: "2-digit",
469
+ day: "2-digit",
470
+ });
471
+
472
+ /**
473
+ * Converts a date string to a North American date format.
474
+ * @param {String} dateStr - Date to validate.
475
+ * @param {String} format - Date format to validate against.
476
+ * @returns {Boolean}
477
+ */
478
+ this.toNorthAmericanFormat = (dateStr, format) => {
479
+
480
+ if (format === 'mm/dd/yyyy') {
481
+ return dateStr;
482
+ }
483
+
484
+ const parsedDate = this.parseDate(dateStr, format);
485
+
486
+ if (!parsedDate) {
487
+ throw new Error('AuroDatepickerUtilities | toNorthAmericanFormat: Unable to parse date string');
488
+ }
489
+
490
+ const { month, day, year } = parsedDate;
491
+
492
+ const dateParts = [];
493
+ if (month) {
494
+ dateParts.push(month);
495
+ }
496
+
497
+ if (day) {
498
+ dateParts.push(day);
499
+ }
500
+
501
+ if (year) {
502
+ dateParts.push(year);
503
+ }
504
+
505
+ return dateParts.join('/');
506
+ };
507
+ }
508
+ }
509
+ const dateFormatter = new DateFormatter();
510
+
511
+ // filepath: dateConstraints.mjs
512
+ const DATE_UTIL_CONSTRAINTS = {
513
+ maxDay: 31,
514
+ maxMonth: 12,
515
+ maxYear: 2400,
516
+ minDay: 1,
517
+ minMonth: 1,
518
+ minYear: 1900,
519
+ };
520
+
521
+ class AuroDateUtilitiesBase {
522
+
523
+ /**
524
+ * @description The maximum day value allowed by the various utilities in this class.
525
+ * @readonly
526
+ * @type {Number}
527
+ */
528
+ get maxDay() {
529
+ return DATE_UTIL_CONSTRAINTS.maxDay;
530
+ }
531
+
532
+ /**
533
+ * @description The maximum month value allowed by the various utilities in this class.
534
+ * @readonly
535
+ * @type {Number}
536
+ */
537
+ get maxMonth() {
538
+ return DATE_UTIL_CONSTRAINTS.maxMonth;
539
+ }
540
+
541
+ /**
542
+ * @description The maximum year value allowed by the various utilities in this class.
543
+ * @readonly
544
+ * @type {Number}
545
+ */
546
+ get maxYear() {
547
+ return DATE_UTIL_CONSTRAINTS.maxYear;
548
+ }
549
+
550
+ /**
551
+ * @description The minimum day value allowed by the various utilities in this class.
552
+ * @readonly
553
+ * @type {Number}
554
+ */
555
+ get minDay() {
556
+ return DATE_UTIL_CONSTRAINTS.minDay;
557
+ }
558
+
559
+ /**
560
+ * @description The minimum month value allowed by the various utilities in this class.
561
+ * @readonly
562
+ * @type {Number}
563
+ */
564
+ get minMonth() {
565
+ return DATE_UTIL_CONSTRAINTS.minMonth;
566
+ }
567
+
568
+ /**
569
+ * @description The minimum year value allowed by the various utilities in this class.
570
+ * @readonly
571
+ * @type {Number}
572
+ */
573
+ get minYear() {
574
+ return DATE_UTIL_CONSTRAINTS.minYear;
575
+ }
576
+ }
577
+
578
+ /* eslint-disable no-magic-numbers */
579
+
580
+ class AuroDateUtilities extends AuroDateUtilitiesBase {
581
+
582
+ /**
583
+ * Returns the current century.
584
+ * @returns {String} The current century.
585
+ */
586
+ getCentury () {
587
+ return String(new Date().getFullYear()).slice(0, 2);
588
+ }
589
+
590
+ /**
591
+ * Returns a four digit year.
592
+ * @param {String} year - The year to convert to four digits.
593
+ * @returns {String} The four digit year.
594
+ */
595
+ getFourDigitYear (year) {
596
+
597
+ const strYear = String(year).trim();
598
+ return strYear.length <= 2 ? this.getCentury() + strYear : strYear;
599
+ }
600
+
601
+ constructor() {
602
+
603
+ super();
604
+
605
+ /**
606
+ * Compares two dates to see if they match.
607
+ * @param {Object} date1 - First date to compare.
608
+ * @param {Object} date2 - Second date to compare.
609
+ * @returns {Boolean} Returns true if the dates match.
610
+ */
611
+ this.datesMatch = (date1, date2) => new Date(date1).getTime() === new Date(date2).getTime();
612
+
613
+ /**
614
+ * Returns true if value passed in is a valid date.
615
+ * @param {String} date - Date to validate.
616
+ * @param {String} format - Date format to validate against.
617
+ * @returns {Boolean}
618
+ */
619
+ this.validDateStr = (date, format) => {
620
+
621
+ // The length we expect the date string to be
622
+ const dateStrLength = format.length;
623
+
624
+ // Guard Clause: Date and format are defined
625
+ if (typeof date === "undefined" || typeof format === "undefined") {
626
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date and format are required');
627
+ }
628
+
629
+ // Guard Clause: Date should be of type string
630
+ if (typeof date !== "string") {
631
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Date must be a string');
632
+ }
633
+
634
+ // Guard Clause: Format should be of type string
635
+ if (typeof format !== "string") {
636
+ throw new Error('AuroDatepickerUtilities | validateDateStr: Format must be a string');
637
+ }
638
+
639
+ // Guard Clause: Length is what we expect it to be
640
+ if (date.length !== dateStrLength) {
641
+ return false;
642
+ }
643
+ // Get a formatted date string and parse it
644
+ const dateParts = dateFormatter.parseDate(date, format);
645
+
646
+ // Guard Clause: Date parse succeeded
647
+ if (!dateParts) {
648
+ return false;
649
+ }
650
+
651
+ // Create the expected date string based on the date parts
652
+ const expectedDateStr = `${dateParts.month}/${dateParts.day || "01"}/${this.getFourDigitYear(dateParts.year)}`;
653
+
654
+ // Generate a date object that we will extract a string date from to compare to the passed in date string
655
+ const dateObj = new Date(this.getFourDigitYear(dateParts.year), dateParts.month - 1, dateParts.day || 1);
656
+
657
+ // Get the date string of the date object we created from the string date
658
+ const actualDateStr = dateFormatter.getDateAsString(dateObj);
659
+
660
+ // Guard Clause: Generated date matches date string input
661
+ if (expectedDateStr !== actualDateStr) {
662
+ return false;
663
+ }
664
+
665
+ // If we passed all other checks, we can assume the date is valid
666
+ return true;
667
+ };
668
+
669
+ /**
670
+ * Determines if a string date value matches the format provided.
671
+ * @param {string} value = The date string value.
672
+ * @param { string} format = The date format to match against.
673
+ * @returns {boolean}
674
+ */
675
+ this.dateAndFormatMatch = (value, format) => {
676
+
677
+ // Ensure we have both values we need to do the comparison
678
+ if (!value || !format) {
679
+ throw new Error('AuroFormValidation | dateFormatMatch: value and format are required');
680
+ }
681
+
682
+ // If the lengths are different, they cannot match
683
+ if (value.length !== format.length) {
684
+ return false;
685
+ }
686
+
687
+ // Get the parts of the date
688
+ const dateParts = dateFormatter.parseDate(value, format);
689
+
690
+ // Validator for day
691
+ const dayValueIsValid = (day) => {
692
+
693
+ // Guard clause: if there is no day in the dateParts, we can ignore this check.
694
+ if (!dateParts.day) {
695
+ return true;
696
+ }
697
+
698
+ // Guard clause: ensure day exists.
699
+ if (!day) {
700
+ return false;
701
+ }
702
+
703
+ // Convert day to number
704
+ const numDay = Number.parseInt(day, 10);
705
+
706
+ // Guard clause: ensure day is a valid integer
707
+ if (Number.isNaN(numDay)) {
708
+ throw new Error('AuroDatepickerUtilities | dayValueIsValid: Unable to parse day value integer');
709
+ }
710
+
711
+ // Guard clause: ensure day is within the valid range
712
+ if (numDay < this.minDay || numDay > this.maxDay) {
713
+ return false;
714
+ }
715
+
716
+ // Default return
717
+ return true;
718
+ };
719
+
720
+ // Validator for month
721
+ const monthValueIsValid = (month) => {
722
+
723
+ // Guard clause: ensure month exists.
724
+ if (!month) {
725
+ return false;
726
+ }
727
+
728
+ // Convert month to number
729
+ const numMonth = Number.parseInt(month, 10);
730
+
731
+ // Guard clause: ensure month is a valid integer
732
+ if (Number.isNaN(numMonth)) {
733
+ throw new Error('AuroDatepickerUtilities | monthValueIsValid: Unable to parse month value integer');
734
+ }
735
+
736
+ // Guard clause: ensure month is within the valid range
737
+ if (numMonth < this.minMonth || numMonth > this.maxMonth) {
738
+ return false;
739
+ }
740
+
741
+ // Default return
742
+ return true;
743
+ };
744
+
745
+ // Validator for year
746
+ const yearIsValid = (_year) => {
747
+
748
+ // Guard clause: ensure year exists.
749
+ if (!_year) {
750
+ return false;
751
+ }
752
+
753
+ // Get the full year
754
+ const year = this.getFourDigitYear(_year);
755
+
756
+ // Convert year to number
757
+ const numYear = Number.parseInt(year, 10);
758
+
759
+ // Guard clause: ensure year is a valid integer
760
+ if (Number.isNaN(numYear)) {
761
+ throw new Error('AuroDatepickerUtilities | yearValueIsValid: Unable to parse year value integer');
762
+ }
763
+
764
+ // Guard clause: ensure year is within the valid range
765
+ if (numYear < this.minYear || numYear > this.maxYear) {
766
+ return false;
767
+ }
768
+
769
+ // Default return
770
+ return true;
771
+ };
772
+
773
+ // Self-contained checks for month, day, and year
774
+ const checks = [
775
+ monthValueIsValid(dateParts.month),
776
+ dayValueIsValid(dateParts.day),
777
+ yearIsValid(dateParts.year)
778
+ ];
779
+
780
+ // If any of the checks failed, the date format does not match and the result is invalid
781
+ const isValid = checks.every((check) => check === true);
782
+
783
+ // If the check is invalid, return false
784
+ if (!isValid) {
785
+ return false;
786
+ }
787
+
788
+ // Default case
789
+ return true;
790
+ };
791
+ }
792
+ }
793
+
794
+ // Export a class instance
795
+ const dateUtilities = new AuroDateUtilities();
796
+
797
+ // Export the class instance methods individually
798
+ const {
799
+ datesMatch,
800
+ validDateStr,
801
+ dateAndFormatMatch,
802
+ minDay,
803
+ minMonth,
804
+ minYear,
805
+ maxDay,
806
+ maxMonth,
807
+ maxYear
808
+ } = dateUtilities;
809
+
810
+ const {
811
+ toNorthAmericanFormat,
812
+ parseDate,
813
+ getDateAsString
814
+ } = dateFormatter;
815
+
408
816
  // Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
409
817
  // See LICENSE in the project root for license information.
410
818
 
411
819
 
412
820
  class AuroFormValidation {
821
+
413
822
  constructor() {
414
823
  this.runtimeUtils = new AuroLibraryRuntimeUtils$1();
415
824
  }
@@ -501,17 +910,17 @@ class AuroFormValidation {
501
910
  ]
502
911
  }
503
912
  };
504
-
913
+
505
914
  let elementType;
506
915
  if (this.runtimeUtils.elementMatch(elem, 'auro-input')) {
507
916
  elementType = 'input';
508
917
  } else if (this.runtimeUtils.elementMatch(elem, 'auro-counter') || this.runtimeUtils.elementMatch(elem, 'auro-counter-group')) {
509
918
  elementType = 'counter';
510
919
  }
511
-
920
+
512
921
  if (elementType) {
513
922
  const rules = validationRules[elementType];
514
-
923
+
515
924
  if (rules) {
516
925
  Object.values(rules).flat().forEach(rule => {
517
926
  if (rule.check(elem)) {
@@ -537,48 +946,82 @@ class AuroFormValidation {
537
946
  if (!elem.value.match(emailRegex)) {
538
947
  elem.validity = 'patternMismatch';
539
948
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
949
+ return;
540
950
  }
541
951
  } else if (elem.type === 'credit-card') {
542
952
  if (elem.value.length > 0 && elem.value.length < elem.validationCCLength) {
543
953
  elem.validity = 'tooShort';
544
954
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
955
+ return;
545
956
  }
546
957
  } else if (elem.type === 'number') {
547
958
  if (elem.max !== undefined && Number(elem.max) < Number(elem.value)) {
548
959
  elem.validity = 'rangeOverflow';
549
960
  elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
961
+ return;
550
962
  }
551
963
 
552
964
  if (elem.min !== undefined && elem.value?.length > 0 && Number(elem.min) > Number(elem.value)) {
553
965
  elem.validity = 'rangeUnderflow';
554
966
  elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
967
+ return;
555
968
  }
556
- } else if (elem.type === 'date') {
557
- if (elem.value?.length > 0 && elem.value?.length < elem.lengthForType) {
969
+ } else if (elem.type === 'date' && elem.value?.length > 0) {
970
+
971
+ // Guard Clause: if the value is too short
972
+ if (elem.value.length < elem.lengthForType) {
973
+
558
974
  elem.validity = 'tooShort';
559
975
  elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
560
- } else if (elem.value?.length === elem.lengthForType && elem.util.toNorthAmericanFormat(elem.value, elem.format)) {
561
- const formattedValue = elem.util.toNorthAmericanFormat(elem.value, elem.format);
562
- const valueDate = new Date(formattedValue.dateForComparison);
563
-
564
- // validate max
565
- if (elem.max?.length === elem.lengthForType) {
566
- const maxDate = new Date(elem.util.toNorthAmericanFormat(elem.max, elem.format).dateForComparison);
567
-
568
- if (valueDate > maxDate) {
569
- elem.validity = 'rangeOverflow';
570
- elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
571
- }
976
+ return;
977
+ }
978
+
979
+ // Guard Clause: If the value is too long for the type
980
+ if (elem.value?.length > elem.lengthForType) {
981
+
982
+ elem.validity = 'tooLong';
983
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
984
+ return;
985
+ }
986
+
987
+ // Validate that the date passed was the correct format
988
+ if (!dateAndFormatMatch(elem.value, elem.format)) {
989
+ elem.validity = 'patternMismatch';
990
+ elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || 'Invalid Date Format Entered';
991
+ return;
992
+ }
993
+
994
+ // Validate that the date passed was a valid date
995
+ if (!validDateStr(elem.value, elem.format)) {
996
+ elem.validity = 'invalidDate';
997
+ elem.errorMessage = elem.setCustomValidityInvalidDate || elem.setCustomValidity || 'Invalid Date Entered';
998
+ return;
999
+ }
1000
+
1001
+ // Perform the rest of the validation
1002
+ const formattedValue = toNorthAmericanFormat(elem.value, elem.format);
1003
+ const valueDate = new Date(formattedValue);
1004
+
1005
+ // // Validate max date
1006
+ if (elem.max?.length === elem.lengthForType) {
1007
+
1008
+ const maxDate = new Date(toNorthAmericanFormat(elem.max, elem.format));
1009
+
1010
+ if (valueDate > maxDate) {
1011
+ elem.validity = 'rangeOverflow';
1012
+ elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
1013
+ return;
572
1014
  }
1015
+ }
573
1016
 
574
- // validate min
575
- if (elem.min?.length === elem.lengthForType) {
576
- const minDate = new Date(elem.util.toNorthAmericanFormat(elem.min, elem.format).dateForComparison);
1017
+ // Validate min date
1018
+ if (elem.min?.length === elem.lengthForType) {
1019
+ const minDate = new Date(toNorthAmericanFormat(elem.min, elem.format));
577
1020
 
578
- if (valueDate < minDate) {
579
- elem.validity = 'rangeUnderflow';
580
- elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
581
- }
1021
+ if (valueDate < minDate) {
1022
+ elem.validity = 'rangeUnderflow';
1023
+ elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
1024
+ return;
582
1025
  }
583
1026
  }
584
1027
  }
@@ -697,7 +1140,7 @@ class AuroFormValidation {
697
1140
  if (input.validationMessage.length > 0) {
698
1141
  elem.errorMessage = input.validationMessage;
699
1142
  }
700
- } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
1143
+ } else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
701
1144
  const firstInput = this.inputElements[0];
702
1145
 
703
1146
  if (firstInput.validationMessage.length > 0) {