@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
|
@@ -962,11 +962,420 @@ let AuroIcon$2 = class AuroIcon extends BaseIcon$2 {
|
|
|
962
962
|
|
|
963
963
|
var iconVersion$2 = '8.0.1';
|
|
964
964
|
|
|
965
|
+
class DateFormatter {
|
|
966
|
+
|
|
967
|
+
constructor() {
|
|
968
|
+
|
|
969
|
+
/**
|
|
970
|
+
* @description Parses a date string into its components.
|
|
971
|
+
* @param {string} dateStr - Date string to parse.
|
|
972
|
+
* @param {string} format - Date format to parse.
|
|
973
|
+
* @returns {Object<key["month" | "day" | "year"]: number>|undefined}
|
|
974
|
+
*/
|
|
975
|
+
this.parseDate = (dateStr, format = 'mm/dd/yyyy') => {
|
|
976
|
+
|
|
977
|
+
// Guard Clause: Date string is defined
|
|
978
|
+
if (!dateStr) {
|
|
979
|
+
return undefined;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
// Assume the separator is a "/" a defined in our code base
|
|
983
|
+
const separator = '/';
|
|
984
|
+
|
|
985
|
+
// Get the parts of the date and format
|
|
986
|
+
const valueParts = dateStr.split(separator);
|
|
987
|
+
const formatParts = format.split(separator);
|
|
988
|
+
|
|
989
|
+
// Check if the value and format have the correct number of parts
|
|
990
|
+
if (valueParts.length !== formatParts.length) {
|
|
991
|
+
throw new Error('AuroDatepickerUtilities | parseDate: Date string and format length do not match');
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
// Holds the result to be returned
|
|
995
|
+
const result = formatParts.reduce((acc, part, index) => {
|
|
996
|
+
const value = valueParts[index];
|
|
997
|
+
|
|
998
|
+
if ((/m/iu).test(part)) {
|
|
999
|
+
acc.month = value;
|
|
1000
|
+
} else if ((/d/iu).test(part)) {
|
|
1001
|
+
acc.day = value;
|
|
1002
|
+
} else if ((/y/iu).test(part)) {
|
|
1003
|
+
acc.year = value;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
return acc;
|
|
1007
|
+
}, {});
|
|
1008
|
+
|
|
1009
|
+
// If we found all the parts, return the result
|
|
1010
|
+
if (result.month && result.year) {
|
|
1011
|
+
return result;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
// Throw an error to let the dev know we were unable to parse the date string
|
|
1015
|
+
throw new Error('AuroDatepickerUtilities | parseDate: Unable to parse date string');
|
|
1016
|
+
};
|
|
1017
|
+
|
|
1018
|
+
/**
|
|
1019
|
+
* Convert a date object to string format.
|
|
1020
|
+
* @param {Object} date - Date to convert to string.
|
|
1021
|
+
* @returns {Object} Returns the date as a string.
|
|
1022
|
+
*/
|
|
1023
|
+
this.getDateAsString = (date) => date.toLocaleDateString(undefined, {
|
|
1024
|
+
year: "numeric",
|
|
1025
|
+
month: "2-digit",
|
|
1026
|
+
day: "2-digit",
|
|
1027
|
+
});
|
|
1028
|
+
|
|
1029
|
+
/**
|
|
1030
|
+
* Converts a date string to a North American date format.
|
|
1031
|
+
* @param {String} dateStr - Date to validate.
|
|
1032
|
+
* @param {String} format - Date format to validate against.
|
|
1033
|
+
* @returns {Boolean}
|
|
1034
|
+
*/
|
|
1035
|
+
this.toNorthAmericanFormat = (dateStr, format) => {
|
|
1036
|
+
|
|
1037
|
+
if (format === 'mm/dd/yyyy') {
|
|
1038
|
+
return dateStr;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
const parsedDate = this.parseDate(dateStr, format);
|
|
1042
|
+
|
|
1043
|
+
if (!parsedDate) {
|
|
1044
|
+
throw new Error('AuroDatepickerUtilities | toNorthAmericanFormat: Unable to parse date string');
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
const { month, day, year } = parsedDate;
|
|
1048
|
+
|
|
1049
|
+
const dateParts = [];
|
|
1050
|
+
if (month) {
|
|
1051
|
+
dateParts.push(month);
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
if (day) {
|
|
1055
|
+
dateParts.push(day);
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
if (year) {
|
|
1059
|
+
dateParts.push(year);
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
return dateParts.join('/');
|
|
1063
|
+
};
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
const dateFormatter = new DateFormatter();
|
|
1067
|
+
|
|
1068
|
+
// filepath: dateConstraints.mjs
|
|
1069
|
+
const DATE_UTIL_CONSTRAINTS = {
|
|
1070
|
+
maxDay: 31,
|
|
1071
|
+
maxMonth: 12,
|
|
1072
|
+
maxYear: 2400,
|
|
1073
|
+
minDay: 1,
|
|
1074
|
+
minMonth: 1,
|
|
1075
|
+
minYear: 1900,
|
|
1076
|
+
};
|
|
1077
|
+
|
|
1078
|
+
class AuroDateUtilitiesBase {
|
|
1079
|
+
|
|
1080
|
+
/**
|
|
1081
|
+
* @description The maximum day value allowed by the various utilities in this class.
|
|
1082
|
+
* @readonly
|
|
1083
|
+
* @type {Number}
|
|
1084
|
+
*/
|
|
1085
|
+
get maxDay() {
|
|
1086
|
+
return DATE_UTIL_CONSTRAINTS.maxDay;
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
/**
|
|
1090
|
+
* @description The maximum month value allowed by the various utilities in this class.
|
|
1091
|
+
* @readonly
|
|
1092
|
+
* @type {Number}
|
|
1093
|
+
*/
|
|
1094
|
+
get maxMonth() {
|
|
1095
|
+
return DATE_UTIL_CONSTRAINTS.maxMonth;
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
/**
|
|
1099
|
+
* @description The maximum year value allowed by the various utilities in this class.
|
|
1100
|
+
* @readonly
|
|
1101
|
+
* @type {Number}
|
|
1102
|
+
*/
|
|
1103
|
+
get maxYear() {
|
|
1104
|
+
return DATE_UTIL_CONSTRAINTS.maxYear;
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
/**
|
|
1108
|
+
* @description The minimum day value allowed by the various utilities in this class.
|
|
1109
|
+
* @readonly
|
|
1110
|
+
* @type {Number}
|
|
1111
|
+
*/
|
|
1112
|
+
get minDay() {
|
|
1113
|
+
return DATE_UTIL_CONSTRAINTS.minDay;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
/**
|
|
1117
|
+
* @description The minimum month value allowed by the various utilities in this class.
|
|
1118
|
+
* @readonly
|
|
1119
|
+
* @type {Number}
|
|
1120
|
+
*/
|
|
1121
|
+
get minMonth() {
|
|
1122
|
+
return DATE_UTIL_CONSTRAINTS.minMonth;
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
/**
|
|
1126
|
+
* @description The minimum year value allowed by the various utilities in this class.
|
|
1127
|
+
* @readonly
|
|
1128
|
+
* @type {Number}
|
|
1129
|
+
*/
|
|
1130
|
+
get minYear() {
|
|
1131
|
+
return DATE_UTIL_CONSTRAINTS.minYear;
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
/* eslint-disable no-magic-numbers */
|
|
1136
|
+
|
|
1137
|
+
class AuroDateUtilities extends AuroDateUtilitiesBase {
|
|
1138
|
+
|
|
1139
|
+
/**
|
|
1140
|
+
* Returns the current century.
|
|
1141
|
+
* @returns {String} The current century.
|
|
1142
|
+
*/
|
|
1143
|
+
getCentury () {
|
|
1144
|
+
return String(new Date().getFullYear()).slice(0, 2);
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
/**
|
|
1148
|
+
* Returns a four digit year.
|
|
1149
|
+
* @param {String} year - The year to convert to four digits.
|
|
1150
|
+
* @returns {String} The four digit year.
|
|
1151
|
+
*/
|
|
1152
|
+
getFourDigitYear (year) {
|
|
1153
|
+
|
|
1154
|
+
const strYear = String(year).trim();
|
|
1155
|
+
return strYear.length <= 2 ? this.getCentury() + strYear : strYear;
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
constructor() {
|
|
1159
|
+
|
|
1160
|
+
super();
|
|
1161
|
+
|
|
1162
|
+
/**
|
|
1163
|
+
* Compares two dates to see if they match.
|
|
1164
|
+
* @param {Object} date1 - First date to compare.
|
|
1165
|
+
* @param {Object} date2 - Second date to compare.
|
|
1166
|
+
* @returns {Boolean} Returns true if the dates match.
|
|
1167
|
+
*/
|
|
1168
|
+
this.datesMatch = (date1, date2) => new Date(date1).getTime() === new Date(date2).getTime();
|
|
1169
|
+
|
|
1170
|
+
/**
|
|
1171
|
+
* Returns true if value passed in is a valid date.
|
|
1172
|
+
* @param {String} date - Date to validate.
|
|
1173
|
+
* @param {String} format - Date format to validate against.
|
|
1174
|
+
* @returns {Boolean}
|
|
1175
|
+
*/
|
|
1176
|
+
this.validDateStr = (date, format) => {
|
|
1177
|
+
|
|
1178
|
+
// The length we expect the date string to be
|
|
1179
|
+
const dateStrLength = format.length;
|
|
1180
|
+
|
|
1181
|
+
// Guard Clause: Date and format are defined
|
|
1182
|
+
if (typeof date === "undefined" || typeof format === "undefined") {
|
|
1183
|
+
throw new Error('AuroDatepickerUtilities | validateDateStr: Date and format are required');
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
// Guard Clause: Date should be of type string
|
|
1187
|
+
if (typeof date !== "string") {
|
|
1188
|
+
throw new Error('AuroDatepickerUtilities | validateDateStr: Date must be a string');
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
// Guard Clause: Format should be of type string
|
|
1192
|
+
if (typeof format !== "string") {
|
|
1193
|
+
throw new Error('AuroDatepickerUtilities | validateDateStr: Format must be a string');
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
// Guard Clause: Length is what we expect it to be
|
|
1197
|
+
if (date.length !== dateStrLength) {
|
|
1198
|
+
return false;
|
|
1199
|
+
}
|
|
1200
|
+
// Get a formatted date string and parse it
|
|
1201
|
+
const dateParts = dateFormatter.parseDate(date, format);
|
|
1202
|
+
|
|
1203
|
+
// Guard Clause: Date parse succeeded
|
|
1204
|
+
if (!dateParts) {
|
|
1205
|
+
return false;
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
// Create the expected date string based on the date parts
|
|
1209
|
+
const expectedDateStr = `${dateParts.month}/${dateParts.day || "01"}/${this.getFourDigitYear(dateParts.year)}`;
|
|
1210
|
+
|
|
1211
|
+
// Generate a date object that we will extract a string date from to compare to the passed in date string
|
|
1212
|
+
const dateObj = new Date(this.getFourDigitYear(dateParts.year), dateParts.month - 1, dateParts.day || 1);
|
|
1213
|
+
|
|
1214
|
+
// Get the date string of the date object we created from the string date
|
|
1215
|
+
const actualDateStr = dateFormatter.getDateAsString(dateObj);
|
|
1216
|
+
|
|
1217
|
+
// Guard Clause: Generated date matches date string input
|
|
1218
|
+
if (expectedDateStr !== actualDateStr) {
|
|
1219
|
+
return false;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
// If we passed all other checks, we can assume the date is valid
|
|
1223
|
+
return true;
|
|
1224
|
+
};
|
|
1225
|
+
|
|
1226
|
+
/**
|
|
1227
|
+
* Determines if a string date value matches the format provided.
|
|
1228
|
+
* @param {string} value = The date string value.
|
|
1229
|
+
* @param { string} format = The date format to match against.
|
|
1230
|
+
* @returns {boolean}
|
|
1231
|
+
*/
|
|
1232
|
+
this.dateAndFormatMatch = (value, format) => {
|
|
1233
|
+
|
|
1234
|
+
// Ensure we have both values we need to do the comparison
|
|
1235
|
+
if (!value || !format) {
|
|
1236
|
+
throw new Error('AuroFormValidation | dateFormatMatch: value and format are required');
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
// If the lengths are different, they cannot match
|
|
1240
|
+
if (value.length !== format.length) {
|
|
1241
|
+
return false;
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
// Get the parts of the date
|
|
1245
|
+
const dateParts = dateFormatter.parseDate(value, format);
|
|
1246
|
+
|
|
1247
|
+
// Validator for day
|
|
1248
|
+
const dayValueIsValid = (day) => {
|
|
1249
|
+
|
|
1250
|
+
// Guard clause: if there is no day in the dateParts, we can ignore this check.
|
|
1251
|
+
if (!dateParts.day) {
|
|
1252
|
+
return true;
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
// Guard clause: ensure day exists.
|
|
1256
|
+
if (!day) {
|
|
1257
|
+
return false;
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
// Convert day to number
|
|
1261
|
+
const numDay = Number.parseInt(day, 10);
|
|
1262
|
+
|
|
1263
|
+
// Guard clause: ensure day is a valid integer
|
|
1264
|
+
if (Number.isNaN(numDay)) {
|
|
1265
|
+
throw new Error('AuroDatepickerUtilities | dayValueIsValid: Unable to parse day value integer');
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
// Guard clause: ensure day is within the valid range
|
|
1269
|
+
if (numDay < this.minDay || numDay > this.maxDay) {
|
|
1270
|
+
return false;
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
// Default return
|
|
1274
|
+
return true;
|
|
1275
|
+
};
|
|
1276
|
+
|
|
1277
|
+
// Validator for month
|
|
1278
|
+
const monthValueIsValid = (month) => {
|
|
1279
|
+
|
|
1280
|
+
// Guard clause: ensure month exists.
|
|
1281
|
+
if (!month) {
|
|
1282
|
+
return false;
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
// Convert month to number
|
|
1286
|
+
const numMonth = Number.parseInt(month, 10);
|
|
1287
|
+
|
|
1288
|
+
// Guard clause: ensure month is a valid integer
|
|
1289
|
+
if (Number.isNaN(numMonth)) {
|
|
1290
|
+
throw new Error('AuroDatepickerUtilities | monthValueIsValid: Unable to parse month value integer');
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
// Guard clause: ensure month is within the valid range
|
|
1294
|
+
if (numMonth < this.minMonth || numMonth > this.maxMonth) {
|
|
1295
|
+
return false;
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
// Default return
|
|
1299
|
+
return true;
|
|
1300
|
+
};
|
|
1301
|
+
|
|
1302
|
+
// Validator for year
|
|
1303
|
+
const yearIsValid = (_year) => {
|
|
1304
|
+
|
|
1305
|
+
// Guard clause: ensure year exists.
|
|
1306
|
+
if (!_year) {
|
|
1307
|
+
return false;
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
// Get the full year
|
|
1311
|
+
const year = this.getFourDigitYear(_year);
|
|
1312
|
+
|
|
1313
|
+
// Convert year to number
|
|
1314
|
+
const numYear = Number.parseInt(year, 10);
|
|
1315
|
+
|
|
1316
|
+
// Guard clause: ensure year is a valid integer
|
|
1317
|
+
if (Number.isNaN(numYear)) {
|
|
1318
|
+
throw new Error('AuroDatepickerUtilities | yearValueIsValid: Unable to parse year value integer');
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
// Guard clause: ensure year is within the valid range
|
|
1322
|
+
if (numYear < this.minYear || numYear > this.maxYear) {
|
|
1323
|
+
return false;
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
// Default return
|
|
1327
|
+
return true;
|
|
1328
|
+
};
|
|
1329
|
+
|
|
1330
|
+
// Self-contained checks for month, day, and year
|
|
1331
|
+
const checks = [
|
|
1332
|
+
monthValueIsValid(dateParts.month),
|
|
1333
|
+
dayValueIsValid(dateParts.day),
|
|
1334
|
+
yearIsValid(dateParts.year)
|
|
1335
|
+
];
|
|
1336
|
+
|
|
1337
|
+
// If any of the checks failed, the date format does not match and the result is invalid
|
|
1338
|
+
const isValid = checks.every((check) => check === true);
|
|
1339
|
+
|
|
1340
|
+
// If the check is invalid, return false
|
|
1341
|
+
if (!isValid) {
|
|
1342
|
+
return false;
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
// Default case
|
|
1346
|
+
return true;
|
|
1347
|
+
};
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
// Export a class instance
|
|
1352
|
+
const dateUtilities = new AuroDateUtilities();
|
|
1353
|
+
|
|
1354
|
+
// Export the class instance methods individually
|
|
1355
|
+
const {
|
|
1356
|
+
datesMatch,
|
|
1357
|
+
validDateStr,
|
|
1358
|
+
dateAndFormatMatch,
|
|
1359
|
+
minDay,
|
|
1360
|
+
minMonth,
|
|
1361
|
+
minYear,
|
|
1362
|
+
maxDay,
|
|
1363
|
+
maxMonth,
|
|
1364
|
+
maxYear
|
|
1365
|
+
} = dateUtilities;
|
|
1366
|
+
|
|
1367
|
+
const {
|
|
1368
|
+
toNorthAmericanFormat,
|
|
1369
|
+
parseDate,
|
|
1370
|
+
getDateAsString
|
|
1371
|
+
} = dateFormatter;
|
|
1372
|
+
|
|
965
1373
|
// Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
|
|
966
1374
|
// See LICENSE in the project root for license information.
|
|
967
1375
|
|
|
968
1376
|
|
|
969
1377
|
class AuroFormValidation {
|
|
1378
|
+
|
|
970
1379
|
constructor() {
|
|
971
1380
|
this.runtimeUtils = new AuroLibraryRuntimeUtils$3();
|
|
972
1381
|
}
|
|
@@ -1058,17 +1467,17 @@ class AuroFormValidation {
|
|
|
1058
1467
|
]
|
|
1059
1468
|
}
|
|
1060
1469
|
};
|
|
1061
|
-
|
|
1470
|
+
|
|
1062
1471
|
let elementType;
|
|
1063
1472
|
if (this.runtimeUtils.elementMatch(elem, 'auro-input')) {
|
|
1064
1473
|
elementType = 'input';
|
|
1065
1474
|
} else if (this.runtimeUtils.elementMatch(elem, 'auro-counter') || this.runtimeUtils.elementMatch(elem, 'auro-counter-group')) {
|
|
1066
1475
|
elementType = 'counter';
|
|
1067
1476
|
}
|
|
1068
|
-
|
|
1477
|
+
|
|
1069
1478
|
if (elementType) {
|
|
1070
1479
|
const rules = validationRules[elementType];
|
|
1071
|
-
|
|
1480
|
+
|
|
1072
1481
|
if (rules) {
|
|
1073
1482
|
Object.values(rules).flat().forEach(rule => {
|
|
1074
1483
|
if (rule.check(elem)) {
|
|
@@ -1094,48 +1503,82 @@ class AuroFormValidation {
|
|
|
1094
1503
|
if (!elem.value.match(emailRegex)) {
|
|
1095
1504
|
elem.validity = 'patternMismatch';
|
|
1096
1505
|
elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
|
|
1506
|
+
return;
|
|
1097
1507
|
}
|
|
1098
1508
|
} else if (elem.type === 'credit-card') {
|
|
1099
1509
|
if (elem.value.length > 0 && elem.value.length < elem.validationCCLength) {
|
|
1100
1510
|
elem.validity = 'tooShort';
|
|
1101
1511
|
elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
|
|
1512
|
+
return;
|
|
1102
1513
|
}
|
|
1103
1514
|
} else if (elem.type === 'number') {
|
|
1104
1515
|
if (elem.max !== undefined && Number(elem.max) < Number(elem.value)) {
|
|
1105
1516
|
elem.validity = 'rangeOverflow';
|
|
1106
1517
|
elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
|
|
1518
|
+
return;
|
|
1107
1519
|
}
|
|
1108
1520
|
|
|
1109
1521
|
if (elem.min !== undefined && elem.value?.length > 0 && Number(elem.min) > Number(elem.value)) {
|
|
1110
1522
|
elem.validity = 'rangeUnderflow';
|
|
1111
1523
|
elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
|
|
1524
|
+
return;
|
|
1112
1525
|
}
|
|
1113
|
-
} else if (elem.type === 'date') {
|
|
1114
|
-
|
|
1526
|
+
} else if (elem.type === 'date' && elem.value?.length > 0) {
|
|
1527
|
+
|
|
1528
|
+
// Guard Clause: if the value is too short
|
|
1529
|
+
if (elem.value.length < elem.lengthForType) {
|
|
1530
|
+
|
|
1115
1531
|
elem.validity = 'tooShort';
|
|
1116
1532
|
elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1533
|
+
return;
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
// Guard Clause: If the value is too long for the type
|
|
1537
|
+
if (elem.value?.length > elem.lengthForType) {
|
|
1120
1538
|
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1539
|
+
elem.validity = 'tooLong';
|
|
1540
|
+
elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || '';
|
|
1541
|
+
return;
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
// Validate that the date passed was the correct format
|
|
1545
|
+
if (!dateAndFormatMatch(elem.value, elem.format)) {
|
|
1546
|
+
elem.validity = 'patternMismatch';
|
|
1547
|
+
elem.errorMessage = elem.setCustomValidityForType || elem.setCustomValidity || 'Invalid Date Format Entered';
|
|
1548
|
+
return;
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
// Validate that the date passed was a valid date
|
|
1552
|
+
if (!validDateStr(elem.value, elem.format)) {
|
|
1553
|
+
elem.validity = 'invalidDate';
|
|
1554
|
+
elem.errorMessage = elem.setCustomValidityInvalidDate || elem.setCustomValidity || 'Invalid Date Entered';
|
|
1555
|
+
return;
|
|
1556
|
+
}
|
|
1124
1557
|
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1558
|
+
// Perform the rest of the validation
|
|
1559
|
+
const formattedValue = toNorthAmericanFormat(elem.value, elem.format);
|
|
1560
|
+
const valueDate = new Date(formattedValue);
|
|
1561
|
+
|
|
1562
|
+
// // Validate max date
|
|
1563
|
+
if (elem.max?.length === elem.lengthForType) {
|
|
1564
|
+
|
|
1565
|
+
const maxDate = new Date(toNorthAmericanFormat(elem.max, elem.format));
|
|
1566
|
+
|
|
1567
|
+
if (valueDate > maxDate) {
|
|
1568
|
+
elem.validity = 'rangeOverflow';
|
|
1569
|
+
elem.errorMessage = elem.setCustomValidityRangeOverflow || elem.setCustomValidity || '';
|
|
1570
|
+
return;
|
|
1129
1571
|
}
|
|
1572
|
+
}
|
|
1130
1573
|
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1574
|
+
// Validate min date
|
|
1575
|
+
if (elem.min?.length === elem.lengthForType) {
|
|
1576
|
+
const minDate = new Date(toNorthAmericanFormat(elem.min, elem.format));
|
|
1134
1577
|
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1578
|
+
if (valueDate < minDate) {
|
|
1579
|
+
elem.validity = 'rangeUnderflow';
|
|
1580
|
+
elem.errorMessage = elem.setCustomValidityRangeUnderflow || elem.setCustomValidity || '';
|
|
1581
|
+
return;
|
|
1139
1582
|
}
|
|
1140
1583
|
}
|
|
1141
1584
|
}
|
|
@@ -1254,7 +1697,7 @@ class AuroFormValidation {
|
|
|
1254
1697
|
if (input.validationMessage.length > 0) {
|
|
1255
1698
|
elem.errorMessage = input.validationMessage;
|
|
1256
1699
|
}
|
|
1257
|
-
} else if (this.inputElements?.length > 0
|
|
1700
|
+
} else if (this.inputElements?.length > 0 && elem.errorMessage === '') {
|
|
1258
1701
|
const firstInput = this.inputElements[0];
|
|
1259
1702
|
|
|
1260
1703
|
if (firstInput.validationMessage.length > 0) {
|
|
@@ -3482,7 +3925,7 @@ class AuroFloatingUI {
|
|
|
3482
3925
|
/**
|
|
3483
3926
|
* @private
|
|
3484
3927
|
* getting called on 'blur' in trigger or `focusin` in document
|
|
3485
|
-
*
|
|
3928
|
+
*
|
|
3486
3929
|
* Hides the bib if focus moves outside of the trigger or bib, unless a 'noHideOnThisFocusLoss' flag is set.
|
|
3487
3930
|
* This method checks if the currently active element is still within the trigger or bib.
|
|
3488
3931
|
* If not, and if the bib isn't in fullscreen mode with focus lost, it hides the bib.
|
|
@@ -3598,7 +4041,7 @@ class AuroFloatingUI {
|
|
|
3598
4041
|
// Close any other dropdown that is already open
|
|
3599
4042
|
const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
|
|
3600
4043
|
if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this &&
|
|
3601
|
-
existedVisibleFloatingUI.isPopoverVisible &&
|
|
4044
|
+
existedVisibleFloatingUI.element.isPopoverVisible &&
|
|
3602
4045
|
document.expandedAuroFloater.eventPrefix === this.eventPrefix) {
|
|
3603
4046
|
document.expandedAuroFloater.hideBib();
|
|
3604
4047
|
}
|
|
@@ -3774,7 +4217,7 @@ class AuroFloatingUI {
|
|
|
3774
4217
|
this.id = window.crypto.randomUUID();
|
|
3775
4218
|
this.element.setAttribute('id', this.id);
|
|
3776
4219
|
}
|
|
3777
|
-
|
|
4220
|
+
|
|
3778
4221
|
this.element.bib.setAttribute("id", `${this.id}-floater-bib`);
|
|
3779
4222
|
}
|
|
3780
4223
|
|
|
@@ -3827,7 +4270,7 @@ class AuroFloatingUI {
|
|
|
3827
4270
|
if (this.element.bib) {
|
|
3828
4271
|
this.element.shadowRoot.append(this.element.bib);
|
|
3829
4272
|
}
|
|
3830
|
-
|
|
4273
|
+
|
|
3831
4274
|
// Remove event & keyboard listeners
|
|
3832
4275
|
if (this.element?.trigger) {
|
|
3833
4276
|
this.element.trigger.removeEventListener('keydown', this.handleEvent);
|
|
@@ -4556,6 +4999,7 @@ var helpTextVersion = '1.0.0';
|
|
|
4556
4999
|
* @csspart helpText - The helpText content container.
|
|
4557
5000
|
* @event auroDropdown-triggerClick - Notifies that the trigger has been clicked.
|
|
4558
5001
|
* @event auroDropdown-toggled - Notifies that the visibility of the dropdown bib has changed.
|
|
5002
|
+
* @event auroDropdown-idAdded - Notifies consumers that the unique ID for the dropdown bib has been generated.
|
|
4559
5003
|
*/
|
|
4560
5004
|
class AuroDropdown extends r {
|
|
4561
5005
|
constructor() {
|
|
@@ -4601,7 +5045,9 @@ class AuroDropdown extends r {
|
|
|
4601
5045
|
this.rounded = false;
|
|
4602
5046
|
this.tabIndex = 0;
|
|
4603
5047
|
this.noToggle = false;
|
|
5048
|
+
this.a11yAutocomplete = 'none';
|
|
4604
5049
|
this.labeled = true;
|
|
5050
|
+
this.a11yRole = 'combobox';
|
|
4605
5051
|
this.onDark = false;
|
|
4606
5052
|
|
|
4607
5053
|
// floaterConfig
|
|
@@ -4737,6 +5183,16 @@ class AuroDropdown extends r {
|
|
|
4737
5183
|
type: Number
|
|
4738
5184
|
},
|
|
4739
5185
|
|
|
5186
|
+
/**
|
|
5187
|
+
* The unique ID for the dropdown bib element.
|
|
5188
|
+
* @private
|
|
5189
|
+
*/
|
|
5190
|
+
dropdownId: {
|
|
5191
|
+
type: String,
|
|
5192
|
+
reflect: false,
|
|
5193
|
+
attribute: false
|
|
5194
|
+
},
|
|
5195
|
+
|
|
4740
5196
|
/**
|
|
4741
5197
|
* If declared in combination with `bordered` property or `helpText` slot content, will apply red color to both.
|
|
4742
5198
|
*/
|
|
@@ -4899,6 +5355,23 @@ class AuroDropdown extends r {
|
|
|
4899
5355
|
*/
|
|
4900
5356
|
tabIndex: {
|
|
4901
5357
|
type: Number
|
|
5358
|
+
},
|
|
5359
|
+
|
|
5360
|
+
/**
|
|
5361
|
+
* The value for the role attribute of the trigger element.
|
|
5362
|
+
*/
|
|
5363
|
+
a11yRole: {
|
|
5364
|
+
type: String || undefined,
|
|
5365
|
+
attribute: false,
|
|
5366
|
+
reflect: false
|
|
5367
|
+
},
|
|
5368
|
+
|
|
5369
|
+
/**
|
|
5370
|
+
* The value for the aria-autocomplete attribute of the trigger element.
|
|
5371
|
+
*/
|
|
5372
|
+
a11yAutocomplete: {
|
|
5373
|
+
type: String,
|
|
5374
|
+
attribute: false,
|
|
4902
5375
|
}
|
|
4903
5376
|
};
|
|
4904
5377
|
}
|
|
@@ -4949,7 +5422,22 @@ class AuroDropdown extends r {
|
|
|
4949
5422
|
}
|
|
4950
5423
|
|
|
4951
5424
|
firstUpdated() {
|
|
5425
|
+
|
|
5426
|
+
// Configure the floater to, this will generate the ID for the bib
|
|
4952
5427
|
this.floater.configure(this, 'auroDropdown');
|
|
5428
|
+
|
|
5429
|
+
/**
|
|
5430
|
+
* @description Let subscribers know that the dropdown ID ha been generated and added.
|
|
5431
|
+
* @event auroDropdown-idAdded
|
|
5432
|
+
* @type {Object<key: 'id', value: string>} - The ID of the dropdown bib element.
|
|
5433
|
+
*/
|
|
5434
|
+
this.dispatchEvent(new CustomEvent('auroDropdown-idAdded', {detail: {id: this.floater.element.id}}));
|
|
5435
|
+
|
|
5436
|
+
// Set the bib ID locally if the user hasn't provided a focusable trigger
|
|
5437
|
+
if (!this.triggerContentFocusable) {
|
|
5438
|
+
this.dropdownId = this.floater.element.id;
|
|
5439
|
+
}
|
|
5440
|
+
|
|
4953
5441
|
this.bibContent = this.floater.element.bib;
|
|
4954
5442
|
|
|
4955
5443
|
// Add the tag name as an attribute if it is different than the component name
|
|
@@ -5101,6 +5589,30 @@ class AuroDropdown extends r {
|
|
|
5101
5589
|
});
|
|
5102
5590
|
}
|
|
5103
5591
|
|
|
5592
|
+
/*
|
|
5593
|
+
* Sets aria attributes for the trigger element if a custom one is passed in.
|
|
5594
|
+
* @private
|
|
5595
|
+
* @method setTriggerAriaAttributes
|
|
5596
|
+
* @param { HTMLElement } triggerElement - The custom trigger element.
|
|
5597
|
+
*/
|
|
5598
|
+
clearTriggerA11yAttributes(triggerElement) {
|
|
5599
|
+
|
|
5600
|
+
if (!triggerElement || !triggerElement.removeAttribute) {
|
|
5601
|
+
return;
|
|
5602
|
+
}
|
|
5603
|
+
|
|
5604
|
+
// Reset appropriate attributes for a11y
|
|
5605
|
+
triggerElement.removeAttribute('aria-labelledby');
|
|
5606
|
+
if (triggerElement.getAttribute('id') === `${this.id}-trigger-element`) {
|
|
5607
|
+
triggerElement.removeAttribute('id');
|
|
5608
|
+
}
|
|
5609
|
+
triggerElement.removeAttribute('role');
|
|
5610
|
+
triggerElement.removeAttribute('aria-expanded');
|
|
5611
|
+
|
|
5612
|
+
triggerElement.removeAttribute('aria-controls');
|
|
5613
|
+
triggerElement.removeAttribute('aria-autocomplete');
|
|
5614
|
+
}
|
|
5615
|
+
|
|
5104
5616
|
/**
|
|
5105
5617
|
* Handles changes to the trigger content slot and updates related properties.
|
|
5106
5618
|
*
|
|
@@ -5114,32 +5626,41 @@ class AuroDropdown extends r {
|
|
|
5114
5626
|
* @returns {void}
|
|
5115
5627
|
*/
|
|
5116
5628
|
handleTriggerContentSlotChange(event) {
|
|
5629
|
+
|
|
5117
5630
|
this.floater.handleTriggerTabIndex();
|
|
5118
5631
|
|
|
5632
|
+
// Get the trigger
|
|
5633
|
+
const trigger = this.shadowRoot.querySelector('#trigger');
|
|
5634
|
+
|
|
5635
|
+
// Get the trigger slot
|
|
5119
5636
|
const triggerSlot = this.shadowRoot.querySelector('.triggerContent slot');
|
|
5120
5637
|
|
|
5638
|
+
// If there's a trigger slot
|
|
5121
5639
|
if (triggerSlot) {
|
|
5122
5640
|
|
|
5641
|
+
// Get the content nodes to see if there are any children
|
|
5123
5642
|
const triggerContentNodes = triggerSlot.assignedNodes();
|
|
5124
5643
|
|
|
5644
|
+
// If there are children
|
|
5125
5645
|
if (triggerContentNodes) {
|
|
5126
5646
|
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
this.triggerContentFocusable = this.containsFocusableElement(node);
|
|
5130
|
-
}
|
|
5131
|
-
});
|
|
5132
|
-
}
|
|
5133
|
-
}
|
|
5647
|
+
// See if any of them are focusable elemeents
|
|
5648
|
+
this.triggerContentFocusable = triggerContentNodes.some((node) => this.containsFocusableElement(node));
|
|
5134
5649
|
|
|
5135
|
-
|
|
5650
|
+
// If any of them are focusable elements
|
|
5651
|
+
if (this.triggerContentFocusable) {
|
|
5136
5652
|
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5142
|
-
|
|
5653
|
+
// Assume the consumer will be providing their own a11y in whatever they passed in
|
|
5654
|
+
this.clearTriggerA11yAttributes(trigger);
|
|
5655
|
+
|
|
5656
|
+
// Remove the tabindex from the trigger so it doesn't interrupt focus flow
|
|
5657
|
+
trigger.removeAttribute('tabindex');
|
|
5658
|
+
} else {
|
|
5659
|
+
|
|
5660
|
+
// Add the tabindex to the trigger so that it's in the focus flow
|
|
5661
|
+
trigger.setAttribute('tabindex', '0');
|
|
5662
|
+
}
|
|
5663
|
+
}
|
|
5143
5664
|
}
|
|
5144
5665
|
|
|
5145
5666
|
if (event) {
|
|
@@ -5149,6 +5670,7 @@ class AuroDropdown extends r {
|
|
|
5149
5670
|
|
|
5150
5671
|
if (this.triggerContentSlot) {
|
|
5151
5672
|
this.setupTriggerFocusEventBinding();
|
|
5673
|
+
|
|
5152
5674
|
this.hasTriggerContent = this.triggerContentSlot.some((slot) => {
|
|
5153
5675
|
if (slot.textContent.trim()) {
|
|
5154
5676
|
return true;
|
|
@@ -5216,10 +5738,13 @@ class AuroDropdown extends r {
|
|
|
5216
5738
|
id="trigger"
|
|
5217
5739
|
class="trigger"
|
|
5218
5740
|
part="trigger"
|
|
5219
|
-
aria-labelledby="triggerLabel"
|
|
5220
5741
|
tabindex="${this.tabIndex}"
|
|
5221
5742
|
?showBorder="${this.showTriggerBorders}"
|
|
5222
|
-
|
|
5743
|
+
role="${o(this.triggerContentFocusable ? undefined : this.a11yRole)}"
|
|
5744
|
+
aria-expanded="${o(this.triggerContentFocusable ? undefined : this.isPopoverVisible)}"
|
|
5745
|
+
aria-controls="${o(this.triggerContentFocusable ? undefined : this.dropdownId)}"
|
|
5746
|
+
aria-labelledby="${o(this.triggerContentFocusable ? undefined : 'triggerLabel')}"
|
|
5747
|
+
>
|
|
5223
5748
|
<div class="triggerContentWrapper">
|
|
5224
5749
|
<label class="label" id="triggerLabel" hasTrigger=${this.hasTriggerContent}>
|
|
5225
5750
|
<slot name="label" @slotchange="${this.handleLabelSlotChange}"></slot>
|
|
@@ -5253,12 +5778,12 @@ class AuroDropdown extends r {
|
|
|
5253
5778
|
<div id="bibSizer" part="size"></div>
|
|
5254
5779
|
<${this.dropdownBibTag}
|
|
5255
5780
|
id="bib"
|
|
5256
|
-
role="tooltip"
|
|
5257
5781
|
?data-show="${this.isPopoverVisible}"
|
|
5258
5782
|
?isfullscreen="${this.isBibFullscreen}"
|
|
5259
5783
|
?common="${this.common}"
|
|
5260
5784
|
?rounded="${this.common || this.rounded}"
|
|
5261
|
-
?inset="${this.common || this.inset}"
|
|
5785
|
+
?inset="${this.common || this.inset}"
|
|
5786
|
+
>
|
|
5262
5787
|
</${this.dropdownBibTag}>
|
|
5263
5788
|
</div>
|
|
5264
5789
|
`;
|