@aurodesignsystem/auro-formkit 3.0.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.
- package/CHANGELOG.md +18 -0
- package/components/checkbox/README.md +1 -1
- package/components/checkbox/demo/api.min.js +468 -25
- package/components/checkbox/demo/index.min.js +468 -25
- package/components/checkbox/demo/readme.md +1 -1
- package/components/checkbox/dist/index.js +468 -25
- package/components/checkbox/dist/registered.js +468 -25
- package/components/combobox/README.md +1 -1
- package/components/combobox/demo/api.min.js +1125 -74
- package/components/combobox/demo/index.min.js +1125 -74
- package/components/combobox/demo/readme.md +1 -1
- package/components/combobox/dist/auro-combobox.d.ts +30 -0
- package/components/combobox/dist/index.js +1125 -74
- package/components/combobox/dist/registered.js +1125 -74
- package/components/counter/README.md +1 -1
- package/components/counter/demo/api.min.js +570 -45
- package/components/counter/demo/index.min.js +570 -45
- package/components/counter/demo/readme.md +1 -1
- package/components/counter/dist/index.js +570 -45
- package/components/counter/dist/registered.js +570 -45
- package/components/datepicker/README.md +1 -1
- package/components/datepicker/demo/api.min.js +1073 -70
- package/components/datepicker/demo/index.min.js +1073 -70
- package/components/datepicker/demo/readme.md +1 -1
- package/components/datepicker/dist/index.js +1073 -70
- package/components/datepicker/dist/registered.js +1073 -70
- package/components/dropdown/README.md +1 -1
- package/components/dropdown/demo/api.md +8 -5
- package/components/dropdown/demo/api.min.js +104 -22
- package/components/dropdown/demo/index.min.js +104 -22
- package/components/dropdown/demo/readme.md +1 -1
- package/components/dropdown/dist/auro-dropdown.d.ts +29 -0
- package/components/dropdown/dist/index.js +104 -22
- package/components/dropdown/dist/registered.js +104 -22
- package/components/form/README.md +1 -1
- package/components/form/demo/readme.md +1 -1
- package/components/input/README.md +1 -1
- package/components/input/demo/api.md +4 -1
- package/components/input/demo/api.min.js +503 -25
- package/components/input/demo/index.min.js +503 -25
- package/components/input/demo/readme.md +1 -1
- package/components/input/dist/base-input.d.ts +24 -0
- package/components/input/dist/index.js +503 -25
- package/components/input/dist/registered.js +503 -25
- package/components/menu/README.md +1 -1
- package/components/menu/demo/readme.md +1 -1
- package/components/radio/README.md +1 -1
- package/components/radio/demo/api.min.js +468 -25
- package/components/radio/demo/index.min.js +468 -25
- package/components/radio/demo/readme.md +1 -1
- package/components/radio/dist/index.js +468 -25
- package/components/radio/dist/registered.js +468 -25
- package/components/select/README.md +1 -1
- package/components/select/demo/api.min.js +570 -45
- package/components/select/demo/index.min.js +570 -45
- package/components/select/demo/readme.md +1 -1
- package/components/select/dist/index.js +570 -45
- package/components/select/dist/registered.js +570 -45
- package/package.json +2 -2
|
@@ -915,11 +915,420 @@ let AuroIcon$2 = class AuroIcon extends BaseIcon$2 {
|
|
|
915
915
|
|
|
916
916
|
var iconVersion$2 = '8.0.1';
|
|
917
917
|
|
|
918
|
+
class DateFormatter {
|
|
919
|
+
|
|
920
|
+
constructor() {
|
|
921
|
+
|
|
922
|
+
/**
|
|
923
|
+
* @description Parses a date string into its components.
|
|
924
|
+
* @param {string} dateStr - Date string to parse.
|
|
925
|
+
* @param {string} format - Date format to parse.
|
|
926
|
+
* @returns {Object<key["month" | "day" | "year"]: number>|undefined}
|
|
927
|
+
*/
|
|
928
|
+
this.parseDate = (dateStr, format = 'mm/dd/yyyy') => {
|
|
929
|
+
|
|
930
|
+
// Guard Clause: Date string is defined
|
|
931
|
+
if (!dateStr) {
|
|
932
|
+
return undefined;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
// Assume the separator is a "/" a defined in our code base
|
|
936
|
+
const separator = '/';
|
|
937
|
+
|
|
938
|
+
// Get the parts of the date and format
|
|
939
|
+
const valueParts = dateStr.split(separator);
|
|
940
|
+
const formatParts = format.split(separator);
|
|
941
|
+
|
|
942
|
+
// Check if the value and format have the correct number of parts
|
|
943
|
+
if (valueParts.length !== formatParts.length) {
|
|
944
|
+
throw new Error('AuroDatepickerUtilities | parseDate: Date string and format length do not match');
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
// Holds the result to be returned
|
|
948
|
+
const result = formatParts.reduce((acc, part, index) => {
|
|
949
|
+
const value = valueParts[index];
|
|
950
|
+
|
|
951
|
+
if ((/m/iu).test(part)) {
|
|
952
|
+
acc.month = value;
|
|
953
|
+
} else if ((/d/iu).test(part)) {
|
|
954
|
+
acc.day = value;
|
|
955
|
+
} else if ((/y/iu).test(part)) {
|
|
956
|
+
acc.year = value;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
return acc;
|
|
960
|
+
}, {});
|
|
961
|
+
|
|
962
|
+
// If we found all the parts, return the result
|
|
963
|
+
if (result.month && result.year) {
|
|
964
|
+
return result;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
// Throw an error to let the dev know we were unable to parse the date string
|
|
968
|
+
throw new Error('AuroDatepickerUtilities | parseDate: Unable to parse date string');
|
|
969
|
+
};
|
|
970
|
+
|
|
971
|
+
/**
|
|
972
|
+
* Convert a date object to string format.
|
|
973
|
+
* @param {Object} date - Date to convert to string.
|
|
974
|
+
* @returns {Object} Returns the date as a string.
|
|
975
|
+
*/
|
|
976
|
+
this.getDateAsString = (date) => date.toLocaleDateString(undefined, {
|
|
977
|
+
year: "numeric",
|
|
978
|
+
month: "2-digit",
|
|
979
|
+
day: "2-digit",
|
|
980
|
+
});
|
|
981
|
+
|
|
982
|
+
/**
|
|
983
|
+
* Converts a date string to a North American date format.
|
|
984
|
+
* @param {String} dateStr - Date to validate.
|
|
985
|
+
* @param {String} format - Date format to validate against.
|
|
986
|
+
* @returns {Boolean}
|
|
987
|
+
*/
|
|
988
|
+
this.toNorthAmericanFormat = (dateStr, format) => {
|
|
989
|
+
|
|
990
|
+
if (format === 'mm/dd/yyyy') {
|
|
991
|
+
return dateStr;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
const parsedDate = this.parseDate(dateStr, format);
|
|
995
|
+
|
|
996
|
+
if (!parsedDate) {
|
|
997
|
+
throw new Error('AuroDatepickerUtilities | toNorthAmericanFormat: Unable to parse date string');
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
const { month, day, year } = parsedDate;
|
|
1001
|
+
|
|
1002
|
+
const dateParts = [];
|
|
1003
|
+
if (month) {
|
|
1004
|
+
dateParts.push(month);
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
if (day) {
|
|
1008
|
+
dateParts.push(day);
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
if (year) {
|
|
1012
|
+
dateParts.push(year);
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
return dateParts.join('/');
|
|
1016
|
+
};
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
const dateFormatter = new DateFormatter();
|
|
1020
|
+
|
|
1021
|
+
// filepath: dateConstraints.mjs
|
|
1022
|
+
const DATE_UTIL_CONSTRAINTS = {
|
|
1023
|
+
maxDay: 31,
|
|
1024
|
+
maxMonth: 12,
|
|
1025
|
+
maxYear: 2400,
|
|
1026
|
+
minDay: 1,
|
|
1027
|
+
minMonth: 1,
|
|
1028
|
+
minYear: 1900,
|
|
1029
|
+
};
|
|
1030
|
+
|
|
1031
|
+
class AuroDateUtilitiesBase {
|
|
1032
|
+
|
|
1033
|
+
/**
|
|
1034
|
+
* @description The maximum day value allowed by the various utilities in this class.
|
|
1035
|
+
* @readonly
|
|
1036
|
+
* @type {Number}
|
|
1037
|
+
*/
|
|
1038
|
+
get maxDay() {
|
|
1039
|
+
return DATE_UTIL_CONSTRAINTS.maxDay;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
/**
|
|
1043
|
+
* @description The maximum month value allowed by the various utilities in this class.
|
|
1044
|
+
* @readonly
|
|
1045
|
+
* @type {Number}
|
|
1046
|
+
*/
|
|
1047
|
+
get maxMonth() {
|
|
1048
|
+
return DATE_UTIL_CONSTRAINTS.maxMonth;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
/**
|
|
1052
|
+
* @description The maximum year value allowed by the various utilities in this class.
|
|
1053
|
+
* @readonly
|
|
1054
|
+
* @type {Number}
|
|
1055
|
+
*/
|
|
1056
|
+
get maxYear() {
|
|
1057
|
+
return DATE_UTIL_CONSTRAINTS.maxYear;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
/**
|
|
1061
|
+
* @description The minimum day value allowed by the various utilities in this class.
|
|
1062
|
+
* @readonly
|
|
1063
|
+
* @type {Number}
|
|
1064
|
+
*/
|
|
1065
|
+
get minDay() {
|
|
1066
|
+
return DATE_UTIL_CONSTRAINTS.minDay;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
/**
|
|
1070
|
+
* @description The minimum month value allowed by the various utilities in this class.
|
|
1071
|
+
* @readonly
|
|
1072
|
+
* @type {Number}
|
|
1073
|
+
*/
|
|
1074
|
+
get minMonth() {
|
|
1075
|
+
return DATE_UTIL_CONSTRAINTS.minMonth;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
/**
|
|
1079
|
+
* @description The minimum year value allowed by the various utilities in this class.
|
|
1080
|
+
* @readonly
|
|
1081
|
+
* @type {Number}
|
|
1082
|
+
*/
|
|
1083
|
+
get minYear() {
|
|
1084
|
+
return DATE_UTIL_CONSTRAINTS.minYear;
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
/* eslint-disable no-magic-numbers */
|
|
1089
|
+
|
|
1090
|
+
class AuroDateUtilities extends AuroDateUtilitiesBase {
|
|
1091
|
+
|
|
1092
|
+
/**
|
|
1093
|
+
* Returns the current century.
|
|
1094
|
+
* @returns {String} The current century.
|
|
1095
|
+
*/
|
|
1096
|
+
getCentury () {
|
|
1097
|
+
return String(new Date().getFullYear()).slice(0, 2);
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
/**
|
|
1101
|
+
* Returns a four digit year.
|
|
1102
|
+
* @param {String} year - The year to convert to four digits.
|
|
1103
|
+
* @returns {String} The four digit year.
|
|
1104
|
+
*/
|
|
1105
|
+
getFourDigitYear (year) {
|
|
1106
|
+
|
|
1107
|
+
const strYear = String(year).trim();
|
|
1108
|
+
return strYear.length <= 2 ? this.getCentury() + strYear : strYear;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
constructor() {
|
|
1112
|
+
|
|
1113
|
+
super();
|
|
1114
|
+
|
|
1115
|
+
/**
|
|
1116
|
+
* Compares two dates to see if they match.
|
|
1117
|
+
* @param {Object} date1 - First date to compare.
|
|
1118
|
+
* @param {Object} date2 - Second date to compare.
|
|
1119
|
+
* @returns {Boolean} Returns true if the dates match.
|
|
1120
|
+
*/
|
|
1121
|
+
this.datesMatch = (date1, date2) => new Date(date1).getTime() === new Date(date2).getTime();
|
|
1122
|
+
|
|
1123
|
+
/**
|
|
1124
|
+
* Returns true if value passed in is a valid date.
|
|
1125
|
+
* @param {String} date - Date to validate.
|
|
1126
|
+
* @param {String} format - Date format to validate against.
|
|
1127
|
+
* @returns {Boolean}
|
|
1128
|
+
*/
|
|
1129
|
+
this.validDateStr = (date, format) => {
|
|
1130
|
+
|
|
1131
|
+
// The length we expect the date string to be
|
|
1132
|
+
const dateStrLength = format.length;
|
|
1133
|
+
|
|
1134
|
+
// Guard Clause: Date and format are defined
|
|
1135
|
+
if (typeof date === "undefined" || typeof format === "undefined") {
|
|
1136
|
+
throw new Error('AuroDatepickerUtilities | validateDateStr: Date and format are required');
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
// Guard Clause: Date should be of type string
|
|
1140
|
+
if (typeof date !== "string") {
|
|
1141
|
+
throw new Error('AuroDatepickerUtilities | validateDateStr: Date must be a string');
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
// Guard Clause: Format should be of type string
|
|
1145
|
+
if (typeof format !== "string") {
|
|
1146
|
+
throw new Error('AuroDatepickerUtilities | validateDateStr: Format must be a string');
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
// Guard Clause: Length is what we expect it to be
|
|
1150
|
+
if (date.length !== dateStrLength) {
|
|
1151
|
+
return false;
|
|
1152
|
+
}
|
|
1153
|
+
// Get a formatted date string and parse it
|
|
1154
|
+
const dateParts = dateFormatter.parseDate(date, format);
|
|
1155
|
+
|
|
1156
|
+
// Guard Clause: Date parse succeeded
|
|
1157
|
+
if (!dateParts) {
|
|
1158
|
+
return false;
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
// Create the expected date string based on the date parts
|
|
1162
|
+
const expectedDateStr = `${dateParts.month}/${dateParts.day || "01"}/${this.getFourDigitYear(dateParts.year)}`;
|
|
1163
|
+
|
|
1164
|
+
// Generate a date object that we will extract a string date from to compare to the passed in date string
|
|
1165
|
+
const dateObj = new Date(this.getFourDigitYear(dateParts.year), dateParts.month - 1, dateParts.day || 1);
|
|
1166
|
+
|
|
1167
|
+
// Get the date string of the date object we created from the string date
|
|
1168
|
+
const actualDateStr = dateFormatter.getDateAsString(dateObj);
|
|
1169
|
+
|
|
1170
|
+
// Guard Clause: Generated date matches date string input
|
|
1171
|
+
if (expectedDateStr !== actualDateStr) {
|
|
1172
|
+
return false;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
// If we passed all other checks, we can assume the date is valid
|
|
1176
|
+
return true;
|
|
1177
|
+
};
|
|
1178
|
+
|
|
1179
|
+
/**
|
|
1180
|
+
* Determines if a string date value matches the format provided.
|
|
1181
|
+
* @param {string} value = The date string value.
|
|
1182
|
+
* @param { string} format = The date format to match against.
|
|
1183
|
+
* @returns {boolean}
|
|
1184
|
+
*/
|
|
1185
|
+
this.dateAndFormatMatch = (value, format) => {
|
|
1186
|
+
|
|
1187
|
+
// Ensure we have both values we need to do the comparison
|
|
1188
|
+
if (!value || !format) {
|
|
1189
|
+
throw new Error('AuroFormValidation | dateFormatMatch: value and format are required');
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
// If the lengths are different, they cannot match
|
|
1193
|
+
if (value.length !== format.length) {
|
|
1194
|
+
return false;
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
// Get the parts of the date
|
|
1198
|
+
const dateParts = dateFormatter.parseDate(value, format);
|
|
1199
|
+
|
|
1200
|
+
// Validator for day
|
|
1201
|
+
const dayValueIsValid = (day) => {
|
|
1202
|
+
|
|
1203
|
+
// Guard clause: if there is no day in the dateParts, we can ignore this check.
|
|
1204
|
+
if (!dateParts.day) {
|
|
1205
|
+
return true;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
// Guard clause: ensure day exists.
|
|
1209
|
+
if (!day) {
|
|
1210
|
+
return false;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
// Convert day to number
|
|
1214
|
+
const numDay = Number.parseInt(day, 10);
|
|
1215
|
+
|
|
1216
|
+
// Guard clause: ensure day is a valid integer
|
|
1217
|
+
if (Number.isNaN(numDay)) {
|
|
1218
|
+
throw new Error('AuroDatepickerUtilities | dayValueIsValid: Unable to parse day value integer');
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
// Guard clause: ensure day is within the valid range
|
|
1222
|
+
if (numDay < this.minDay || numDay > this.maxDay) {
|
|
1223
|
+
return false;
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
// Default return
|
|
1227
|
+
return true;
|
|
1228
|
+
};
|
|
1229
|
+
|
|
1230
|
+
// Validator for month
|
|
1231
|
+
const monthValueIsValid = (month) => {
|
|
1232
|
+
|
|
1233
|
+
// Guard clause: ensure month exists.
|
|
1234
|
+
if (!month) {
|
|
1235
|
+
return false;
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
// Convert month to number
|
|
1239
|
+
const numMonth = Number.parseInt(month, 10);
|
|
1240
|
+
|
|
1241
|
+
// Guard clause: ensure month is a valid integer
|
|
1242
|
+
if (Number.isNaN(numMonth)) {
|
|
1243
|
+
throw new Error('AuroDatepickerUtilities | monthValueIsValid: Unable to parse month value integer');
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
// Guard clause: ensure month is within the valid range
|
|
1247
|
+
if (numMonth < this.minMonth || numMonth > this.maxMonth) {
|
|
1248
|
+
return false;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
// Default return
|
|
1252
|
+
return true;
|
|
1253
|
+
};
|
|
1254
|
+
|
|
1255
|
+
// Validator for year
|
|
1256
|
+
const yearIsValid = (_year) => {
|
|
1257
|
+
|
|
1258
|
+
// Guard clause: ensure year exists.
|
|
1259
|
+
if (!_year) {
|
|
1260
|
+
return false;
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
// Get the full year
|
|
1264
|
+
const year = this.getFourDigitYear(_year);
|
|
1265
|
+
|
|
1266
|
+
// Convert year to number
|
|
1267
|
+
const numYear = Number.parseInt(year, 10);
|
|
1268
|
+
|
|
1269
|
+
// Guard clause: ensure year is a valid integer
|
|
1270
|
+
if (Number.isNaN(numYear)) {
|
|
1271
|
+
throw new Error('AuroDatepickerUtilities | yearValueIsValid: Unable to parse year value integer');
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
// Guard clause: ensure year is within the valid range
|
|
1275
|
+
if (numYear < this.minYear || numYear > this.maxYear) {
|
|
1276
|
+
return false;
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
// Default return
|
|
1280
|
+
return true;
|
|
1281
|
+
};
|
|
1282
|
+
|
|
1283
|
+
// Self-contained checks for month, day, and year
|
|
1284
|
+
const checks = [
|
|
1285
|
+
monthValueIsValid(dateParts.month),
|
|
1286
|
+
dayValueIsValid(dateParts.day),
|
|
1287
|
+
yearIsValid(dateParts.year)
|
|
1288
|
+
];
|
|
1289
|
+
|
|
1290
|
+
// If any of the checks failed, the date format does not match and the result is invalid
|
|
1291
|
+
const isValid = checks.every((check) => check === true);
|
|
1292
|
+
|
|
1293
|
+
// If the check is invalid, return false
|
|
1294
|
+
if (!isValid) {
|
|
1295
|
+
return false;
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
// Default case
|
|
1299
|
+
return true;
|
|
1300
|
+
};
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
// Export a class instance
|
|
1305
|
+
const dateUtilities = new AuroDateUtilities();
|
|
1306
|
+
|
|
1307
|
+
// Export the class instance methods individually
|
|
1308
|
+
const {
|
|
1309
|
+
datesMatch,
|
|
1310
|
+
validDateStr,
|
|
1311
|
+
dateAndFormatMatch,
|
|
1312
|
+
minDay,
|
|
1313
|
+
minMonth,
|
|
1314
|
+
minYear,
|
|
1315
|
+
maxDay,
|
|
1316
|
+
maxMonth,
|
|
1317
|
+
maxYear
|
|
1318
|
+
} = dateUtilities;
|
|
1319
|
+
|
|
1320
|
+
const {
|
|
1321
|
+
toNorthAmericanFormat,
|
|
1322
|
+
parseDate,
|
|
1323
|
+
getDateAsString
|
|
1324
|
+
} = dateFormatter;
|
|
1325
|
+
|
|
918
1326
|
// Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
|
|
919
1327
|
// See LICENSE in the project root for license information.
|
|
920
1328
|
|
|
921
1329
|
|
|
922
1330
|
class AuroFormValidation {
|
|
1331
|
+
|
|
923
1332
|
constructor() {
|
|
924
1333
|
this.runtimeUtils = new AuroLibraryRuntimeUtils$3();
|
|
925
1334
|
}
|
|
@@ -1011,17 +1420,17 @@ class AuroFormValidation {
|
|
|
1011
1420
|
]
|
|
1012
1421
|
}
|
|
1013
1422
|
};
|
|
1014
|
-
|
|
1423
|
+
|
|
1015
1424
|
let elementType;
|
|
1016
1425
|
if (this.runtimeUtils.elementMatch(elem, 'auro-input')) {
|
|
1017
1426
|
elementType = 'input';
|
|
1018
1427
|
} else if (this.runtimeUtils.elementMatch(elem, 'auro-counter') || this.runtimeUtils.elementMatch(elem, 'auro-counter-group')) {
|
|
1019
1428
|
elementType = 'counter';
|
|
1020
1429
|
}
|
|
1021
|
-
|
|
1430
|
+
|
|
1022
1431
|
if (elementType) {
|
|
1023
1432
|
const rules = validationRules[elementType];
|
|
1024
|
-
|
|
1433
|
+
|
|
1025
1434
|
if (rules) {
|
|
1026
1435
|
Object.values(rules).flat().forEach(rule => {
|
|
1027
1436
|
if (rule.check(elem)) {
|
|
@@ -1047,48 +1456,82 @@ class AuroFormValidation {
|
|
|
1047
1456
|
if (!elem.value.match(emailRegex)) {
|
|
1048
1457
|
elem.validity = 'patternMismatch';
|
|
1049
1458
|
elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
|
|
1459
|
+
return;
|
|
1050
1460
|
}
|
|
1051
1461
|
} else if (elem.type === 'credit-card') {
|
|
1052
1462
|
if (elem.value.length > 0 && elem.value.length < elem.validationCCLength) {
|
|
1053
1463
|
elem.validity = 'tooShort';
|
|
1054
1464
|
elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
|
|
1465
|
+
return;
|
|
1055
1466
|
}
|
|
1056
1467
|
} else if (elem.type === 'number') {
|
|
1057
1468
|
if (elem.max !== undefined && Number(elem.max) < Number(elem.value)) {
|
|
1058
1469
|
elem.validity = 'rangeOverflow';
|
|
1059
1470
|
elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
|
|
1471
|
+
return;
|
|
1060
1472
|
}
|
|
1061
1473
|
|
|
1062
1474
|
if (elem.min !== undefined && elem.value?.length > 0 && Number(elem.min) > Number(elem.value)) {
|
|
1063
1475
|
elem.validity = 'rangeUnderflow';
|
|
1064
1476
|
elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
|
|
1477
|
+
return;
|
|
1065
1478
|
}
|
|
1066
|
-
} else if (elem.type === 'date') {
|
|
1067
|
-
|
|
1479
|
+
} else if (elem.type === 'date' && elem.value?.length > 0) {
|
|
1480
|
+
|
|
1481
|
+
// Guard Clause: if the value is too short
|
|
1482
|
+
if (elem.value.length < elem.lengthForType) {
|
|
1483
|
+
|
|
1068
1484
|
elem.validity = 'tooShort';
|
|
1069
1485
|
elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1486
|
+
return;
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
// Guard Clause: If the value is too long for the type
|
|
1490
|
+
if (elem.value?.length > elem.lengthForType) {
|
|
1073
1491
|
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1492
|
+
elem.validity = 'tooLong';
|
|
1493
|
+
elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
|
|
1494
|
+
return;
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
// Validate that the date passed was the correct format
|
|
1498
|
+
if (!dateAndFormatMatch(elem.value, elem.format)) {
|
|
1499
|
+
elem.validity = 'patternMismatch';
|
|
1500
|
+
elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || 'Invalid Date Format Entered';
|
|
1501
|
+
return;
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
// Validate that the date passed was a valid date
|
|
1505
|
+
if (!validDateStr(elem.value, elem.format)) {
|
|
1506
|
+
elem.validity = 'invalidDate';
|
|
1507
|
+
elem.errorMessage = elem.setCustomValidityInvalidDate || elem.setCustomValidity || 'Invalid Date Entered';
|
|
1508
|
+
return;
|
|
1509
|
+
}
|
|
1077
1510
|
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1511
|
+
// Perform the rest of the validation
|
|
1512
|
+
const formattedValue = toNorthAmericanFormat(elem.value, elem.format);
|
|
1513
|
+
const valueDate = new Date(formattedValue);
|
|
1514
|
+
|
|
1515
|
+
// // Validate max date
|
|
1516
|
+
if (elem.max?.length === elem.lengthForType) {
|
|
1517
|
+
|
|
1518
|
+
const maxDate = new Date(toNorthAmericanFormat(elem.max, elem.format));
|
|
1519
|
+
|
|
1520
|
+
if (valueDate > maxDate) {
|
|
1521
|
+
elem.validity = 'rangeOverflow';
|
|
1522
|
+
elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
|
|
1523
|
+
return;
|
|
1082
1524
|
}
|
|
1525
|
+
}
|
|
1083
1526
|
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1527
|
+
// Validate min date
|
|
1528
|
+
if (elem.min?.length === elem.lengthForType) {
|
|
1529
|
+
const minDate = new Date(toNorthAmericanFormat(elem.min, elem.format));
|
|
1087
1530
|
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1531
|
+
if (valueDate < minDate) {
|
|
1532
|
+
elem.validity = 'rangeUnderflow';
|
|
1533
|
+
elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
|
|
1534
|
+
return;
|
|
1092
1535
|
}
|
|
1093
1536
|
}
|
|
1094
1537
|
}
|
|
@@ -1207,7 +1650,7 @@ class AuroFormValidation {
|
|
|
1207
1650
|
if (input.validationMessage.length > 0) {
|
|
1208
1651
|
elem.errorMessage = input.validationMessage;
|
|
1209
1652
|
}
|
|
1210
|
-
} else if (this.inputElements?.length > 0
|
|
1653
|
+
} else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
|
|
1211
1654
|
const firstInput = this.inputElements[0];
|
|
1212
1655
|
|
|
1213
1656
|
if (firstInput.validationMessage.length > 0) {
|
|
@@ -3435,7 +3878,7 @@ class AuroFloatingUI {
|
|
|
3435
3878
|
/**
|
|
3436
3879
|
* @private
|
|
3437
3880
|
* getting called on 'blur' in trigger or `focusin` in document
|
|
3438
|
-
*
|
|
3881
|
+
*
|
|
3439
3882
|
* Hides the bib if focus moves outside of the trigger or bib, unless a 'noHideOnThisFocusLoss' flag is set.
|
|
3440
3883
|
* This method checks if the currently active element is still within the trigger or bib.
|
|
3441
3884
|
* If not, and if the bib isn't in fullscreen mode with focus lost, it hides the bib.
|
|
@@ -3551,7 +3994,7 @@ class AuroFloatingUI {
|
|
|
3551
3994
|
// Close any other dropdown that is already open
|
|
3552
3995
|
const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
|
|
3553
3996
|
if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this &&
|
|
3554
|
-
existedVisibleFloatingUI.isPopoverVisible &&
|
|
3997
|
+
existedVisibleFloatingUI.element.isPopoverVisible &&
|
|
3555
3998
|
document.expandedAuroFloater.eventPrefix === this.eventPrefix) {
|
|
3556
3999
|
document.expandedAuroFloater.hideBib();
|
|
3557
4000
|
}
|
|
@@ -3727,7 +4170,7 @@ class AuroFloatingUI {
|
|
|
3727
4170
|
this.id = window.crypto.randomUUID();
|
|
3728
4171
|
this.element.setAttribute('id', this.id);
|
|
3729
4172
|
}
|
|
3730
|
-
|
|
4173
|
+
|
|
3731
4174
|
this.element.bib.setAttribute("id", `${this.id}-floater-bib`);
|
|
3732
4175
|
}
|
|
3733
4176
|
|
|
@@ -3780,7 +4223,7 @@ class AuroFloatingUI {
|
|
|
3780
4223
|
if (this.element.bib) {
|
|
3781
4224
|
this.element.shadowRoot.append(this.element.bib);
|
|
3782
4225
|
}
|
|
3783
|
-
|
|
4226
|
+
|
|
3784
4227
|
// Remove event & keyboard listeners
|
|
3785
4228
|
if (this.element?.trigger) {
|
|
3786
4229
|
this.element.trigger.removeEventListener('keydown', this.handleEvent);
|
|
@@ -4509,6 +4952,7 @@ var helpTextVersion = '1.0.0';
|
|
|
4509
4952
|
* @csspart helpText - The helpText content container.
|
|
4510
4953
|
* @event auroDropdown-triggerClick - Notifies that the trigger has been clicked.
|
|
4511
4954
|
* @event auroDropdown-toggled - Notifies that the visibility of the dropdown bib has changed.
|
|
4955
|
+
* @event auroDropdown-idAdded - Notifies consumers that the unique ID for the dropdown bib has been generated.
|
|
4512
4956
|
*/
|
|
4513
4957
|
class AuroDropdown extends LitElement {
|
|
4514
4958
|
constructor() {
|
|
@@ -4554,7 +4998,9 @@ class AuroDropdown extends LitElement {
|
|
|
4554
4998
|
this.rounded = false;
|
|
4555
4999
|
this.tabIndex = 0;
|
|
4556
5000
|
this.noToggle = false;
|
|
5001
|
+
this.a11yAutocomplete = 'none';
|
|
4557
5002
|
this.labeled = true;
|
|
5003
|
+
this.a11yRole = 'combobox';
|
|
4558
5004
|
this.onDark = false;
|
|
4559
5005
|
|
|
4560
5006
|
// floaterConfig
|
|
@@ -4690,6 +5136,16 @@ class AuroDropdown extends LitElement {
|
|
|
4690
5136
|
type: Number
|
|
4691
5137
|
},
|
|
4692
5138
|
|
|
5139
|
+
/**
|
|
5140
|
+
* The unique ID for the dropdown bib element.
|
|
5141
|
+
* @private
|
|
5142
|
+
*/
|
|
5143
|
+
dropdownId: {
|
|
5144
|
+
type: String,
|
|
5145
|
+
reflect: false,
|
|
5146
|
+
attribute: false
|
|
5147
|
+
},
|
|
5148
|
+
|
|
4693
5149
|
/**
|
|
4694
5150
|
* If declared in combination with `bordered` property or `helpText` slot content, will apply red color to both.
|
|
4695
5151
|
*/
|
|
@@ -4852,6 +5308,23 @@ class AuroDropdown extends LitElement {
|
|
|
4852
5308
|
*/
|
|
4853
5309
|
tabIndex: {
|
|
4854
5310
|
type: Number
|
|
5311
|
+
},
|
|
5312
|
+
|
|
5313
|
+
/**
|
|
5314
|
+
* The value for the role attribute of the trigger element.
|
|
5315
|
+
*/
|
|
5316
|
+
a11yRole: {
|
|
5317
|
+
type: String || undefined,
|
|
5318
|
+
attribute: false,
|
|
5319
|
+
reflect: false
|
|
5320
|
+
},
|
|
5321
|
+
|
|
5322
|
+
/**
|
|
5323
|
+
* The value for the aria-autocomplete attribute of the trigger element.
|
|
5324
|
+
*/
|
|
5325
|
+
a11yAutocomplete: {
|
|
5326
|
+
type: String,
|
|
5327
|
+
attribute: false,
|
|
4855
5328
|
}
|
|
4856
5329
|
};
|
|
4857
5330
|
}
|
|
@@ -4902,7 +5375,22 @@ class AuroDropdown extends LitElement {
|
|
|
4902
5375
|
}
|
|
4903
5376
|
|
|
4904
5377
|
firstUpdated() {
|
|
5378
|
+
|
|
5379
|
+
// Configure the floater to, this will generate the ID for the bib
|
|
4905
5380
|
this.floater.configure(this, 'auroDropdown');
|
|
5381
|
+
|
|
5382
|
+
/**
|
|
5383
|
+
* @description Let subscribers know that the dropdown ID ha been generated and added.
|
|
5384
|
+
* @event auroDropdown-idAdded
|
|
5385
|
+
* @type {Object<key: 'id', value: string>} - The ID of the dropdown bib element.
|
|
5386
|
+
*/
|
|
5387
|
+
this.dispatchEvent(new CustomEvent('auroDropdown-idAdded', {detail: {id: this.floater.element.id}}));
|
|
5388
|
+
|
|
5389
|
+
// Set the bib ID locally if the user hasn't provided a focusable trigger
|
|
5390
|
+
if (!this.triggerContentFocusable) {
|
|
5391
|
+
this.dropdownId = this.floater.element.id;
|
|
5392
|
+
}
|
|
5393
|
+
|
|
4906
5394
|
this.bibContent = this.floater.element.bib;
|
|
4907
5395
|
|
|
4908
5396
|
// Add the tag name as an attribute if it is different than the component name
|
|
@@ -5054,6 +5542,30 @@ class AuroDropdown extends LitElement {
|
|
|
5054
5542
|
});
|
|
5055
5543
|
}
|
|
5056
5544
|
|
|
5545
|
+
/*
|
|
5546
|
+
* Sets aria attributes for the trigger element if a custom one is passed in.
|
|
5547
|
+
* @private
|
|
5548
|
+
* @method setTriggerAriaAttributes
|
|
5549
|
+
* @param { HTMLElement } triggerElement - The custom trigger element.
|
|
5550
|
+
*/
|
|
5551
|
+
clearTriggerA11yAttributes(triggerElement) {
|
|
5552
|
+
|
|
5553
|
+
if (!triggerElement || !triggerElement.removeAttribute) {
|
|
5554
|
+
return;
|
|
5555
|
+
}
|
|
5556
|
+
|
|
5557
|
+
// Reset appropriate attributes for a11y
|
|
5558
|
+
triggerElement.removeAttribute('aria-labelledby');
|
|
5559
|
+
if (triggerElement.getAttribute('id') === `${this.id}-trigger-element`) {
|
|
5560
|
+
triggerElement.removeAttribute('id');
|
|
5561
|
+
}
|
|
5562
|
+
triggerElement.removeAttribute('role');
|
|
5563
|
+
triggerElement.removeAttribute('aria-expanded');
|
|
5564
|
+
|
|
5565
|
+
triggerElement.removeAttribute('aria-controls');
|
|
5566
|
+
triggerElement.removeAttribute('aria-autocomplete');
|
|
5567
|
+
}
|
|
5568
|
+
|
|
5057
5569
|
/**
|
|
5058
5570
|
* Handles changes to the trigger content slot and updates related properties.
|
|
5059
5571
|
*
|
|
@@ -5067,32 +5579,41 @@ class AuroDropdown extends LitElement {
|
|
|
5067
5579
|
* @returns {void}
|
|
5068
5580
|
*/
|
|
5069
5581
|
handleTriggerContentSlotChange(event) {
|
|
5582
|
+
|
|
5070
5583
|
this.floater.handleTriggerTabIndex();
|
|
5071
5584
|
|
|
5585
|
+
// Get the trigger
|
|
5586
|
+
const trigger = this.shadowRoot.querySelector('#trigger');
|
|
5587
|
+
|
|
5588
|
+
// Get the trigger slot
|
|
5072
5589
|
const triggerSlot = this.shadowRoot.querySelector('.triggerContent slot');
|
|
5073
5590
|
|
|
5591
|
+
// If there's a trigger slot
|
|
5074
5592
|
if (triggerSlot) {
|
|
5075
5593
|
|
|
5594
|
+
// Get the content nodes to see if there are any children
|
|
5076
5595
|
const triggerContentNodes = triggerSlot.assignedNodes();
|
|
5077
5596
|
|
|
5597
|
+
// If there are children
|
|
5078
5598
|
if (triggerContentNodes) {
|
|
5079
5599
|
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
this.triggerContentFocusable = this.containsFocusableElement(node);
|
|
5083
|
-
}
|
|
5084
|
-
});
|
|
5085
|
-
}
|
|
5086
|
-
}
|
|
5600
|
+
// See if any of them are focusable elemeents
|
|
5601
|
+
this.triggerContentFocusable = triggerContentNodes.some((node) => this.containsFocusableElement(node));
|
|
5087
5602
|
|
|
5088
|
-
|
|
5603
|
+
// If any of them are focusable elements
|
|
5604
|
+
if (this.triggerContentFocusable) {
|
|
5089
5605
|
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5606
|
+
// Assume the consumer will be providing their own a11y in whatever they passed in
|
|
5607
|
+
this.clearTriggerA11yAttributes(trigger);
|
|
5608
|
+
|
|
5609
|
+
// Remove the tabindex from the trigger so it doesn't interrupt focus flow
|
|
5610
|
+
trigger.removeAttribute('tabindex');
|
|
5611
|
+
} else {
|
|
5612
|
+
|
|
5613
|
+
// Add the tabindex to the trigger so that it's in the focus flow
|
|
5614
|
+
trigger.setAttribute('tabindex', '0');
|
|
5615
|
+
}
|
|
5616
|
+
}
|
|
5096
5617
|
}
|
|
5097
5618
|
|
|
5098
5619
|
if (event) {
|
|
@@ -5102,6 +5623,7 @@ class AuroDropdown extends LitElement {
|
|
|
5102
5623
|
|
|
5103
5624
|
if (this.triggerContentSlot) {
|
|
5104
5625
|
this.setupTriggerFocusEventBinding();
|
|
5626
|
+
|
|
5105
5627
|
this.hasTriggerContent = this.triggerContentSlot.some((slot) => {
|
|
5106
5628
|
if (slot.textContent.trim()) {
|
|
5107
5629
|
return true;
|
|
@@ -5169,10 +5691,13 @@ class AuroDropdown extends LitElement {
|
|
|
5169
5691
|
id="trigger"
|
|
5170
5692
|
class="trigger"
|
|
5171
5693
|
part="trigger"
|
|
5172
|
-
aria-labelledby="triggerLabel"
|
|
5173
5694
|
tabindex="${this.tabIndex}"
|
|
5174
5695
|
?showBorder="${this.showTriggerBorders}"
|
|
5175
|
-
|
|
5696
|
+
role="${ifDefined(this.triggerContentFocusable ? undefined : this.a11yRole)}"
|
|
5697
|
+
aria-expanded="${ifDefined(this.triggerContentFocusable ? undefined : this.isPopoverVisible)}"
|
|
5698
|
+
aria-controls="${ifDefined(this.triggerContentFocusable ? undefined : this.dropdownId)}"
|
|
5699
|
+
aria-labelledby="${ifDefined(this.triggerContentFocusable ? undefined : 'triggerLabel')}"
|
|
5700
|
+
>
|
|
5176
5701
|
<div class="triggerContentWrapper">
|
|
5177
5702
|
<label class="label" id="triggerLabel" hasTrigger=${this.hasTriggerContent}>
|
|
5178
5703
|
<slot name="label" @slotchange="${this.handleLabelSlotChange}"></slot>
|
|
@@ -5206,12 +5731,12 @@ class AuroDropdown extends LitElement {
|
|
|
5206
5731
|
<div id="bibSizer" part="size"></div>
|
|
5207
5732
|
<${this.dropdownBibTag}
|
|
5208
5733
|
id="bib"
|
|
5209
|
-
role="tooltip"
|
|
5210
5734
|
?data-show="${this.isPopoverVisible}"
|
|
5211
5735
|
?isfullscreen="${this.isBibFullscreen}"
|
|
5212
5736
|
?common="${this.common}"
|
|
5213
5737
|
?rounded="${this.common || this.rounded}"
|
|
5214
|
-
?inset="${this.common || this.inset}"
|
|
5738
|
+
?inset="${this.common || this.inset}"
|
|
5739
|
+
>
|
|
5215
5740
|
</${this.dropdownBibTag}>
|
|
5216
5741
|
</div>
|
|
5217
5742
|
`;
|