@fkui/logic 6.37.0 → 6.39.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/lib/cjs/index.js +63 -55
- package/lib/esm/index.js +63 -55
- package/lib/types/index.d.ts +141 -3
- package/lib/types/tsdoc-metadata.json +1 -1
- package/package.json +3 -3
package/lib/cjs/index.js
CHANGED
|
@@ -31,6 +31,7 @@ function isSet(value) {
|
|
|
31
31
|
* @public
|
|
32
32
|
*/
|
|
33
33
|
function isString(value) {
|
|
34
|
+
/* eslint-disable-next-line unicorn/no-instanceof-builtins -- technical debt */
|
|
34
35
|
return typeof value === "string" || value instanceof String;
|
|
35
36
|
}
|
|
36
37
|
|
|
@@ -42,6 +43,7 @@ function isString(value) {
|
|
|
42
43
|
class MissingValueError extends Error {
|
|
43
44
|
constructor(message) {
|
|
44
45
|
super(message);
|
|
46
|
+
this.name = "MissingValueError";
|
|
45
47
|
Object.setPrototypeOf(this, MissingValueError.prototype);
|
|
46
48
|
}
|
|
47
49
|
}
|
|
@@ -197,6 +199,7 @@ class DecoratedError extends Error {
|
|
|
197
199
|
cause;
|
|
198
200
|
constructor(message, cause) {
|
|
199
201
|
super(message);
|
|
202
|
+
this.name = "DecoratedError";
|
|
200
203
|
Object.setPrototypeOf(this, DecoratedError.prototype);
|
|
201
204
|
/* eslint-disable-next-line @typescript-eslint/restrict-plus-operands -- technical debt */
|
|
202
205
|
this.stack += `\nCaused by: ${String(cause.stack)}`;
|
|
@@ -2169,13 +2172,13 @@ function testLuhnChecksum(inputString) {
|
|
|
2169
2172
|
if (/^\d+$/.test(inputString) === false) {
|
|
2170
2173
|
throw new Error("Luhn Checksum test only works on strings containing numbers");
|
|
2171
2174
|
}
|
|
2172
|
-
inputString
|
|
2175
|
+
for (const [index, numChar] of inputString
|
|
2173
2176
|
.split("")
|
|
2174
|
-
.
|
|
2175
|
-
.
|
|
2176
|
-
const digit = parseInt(numChar, 10) * ((index + 1) % 2 === 0 ? 2 : 1);
|
|
2177
|
+
.toReversed()
|
|
2178
|
+
.entries()) {
|
|
2179
|
+
const digit = Number.parseInt(numChar, 10) * ((index + 1) % 2 === 0 ? 2 : 1);
|
|
2177
2180
|
sum += digit >= 10 ? digit - 9 : digit;
|
|
2178
|
-
}
|
|
2181
|
+
}
|
|
2179
2182
|
return sum % 10 === 0;
|
|
2180
2183
|
}
|
|
2181
2184
|
|
|
@@ -2183,7 +2186,7 @@ function testLuhnChecksum(inputString) {
|
|
|
2183
2186
|
* @public
|
|
2184
2187
|
*/
|
|
2185
2188
|
function validChecksum(value) {
|
|
2186
|
-
const yymmddxxxx = value.slice(2).
|
|
2189
|
+
const yymmddxxxx = value.slice(2).replaceAll("-", "");
|
|
2187
2190
|
return testLuhnChecksum(yymmddxxxx);
|
|
2188
2191
|
}
|
|
2189
2192
|
|
|
@@ -2230,7 +2233,7 @@ function findCookie(name) {
|
|
|
2230
2233
|
}
|
|
2231
2234
|
|
|
2232
2235
|
const BANK_ACCOUNT_NUMBER_REGEXP = /^\d{3,16}$/;
|
|
2233
|
-
const BANK_ACCOUNT_NUMBER_TRIM_REGEXP = /[
|
|
2236
|
+
const BANK_ACCOUNT_NUMBER_TRIM_REGEXP = /[ ,.-]+/g;
|
|
2234
2237
|
/**
|
|
2235
2238
|
* @public
|
|
2236
2239
|
*/
|
|
@@ -2239,7 +2242,7 @@ function parseBankAccountNumber(value) {
|
|
|
2239
2242
|
return undefined;
|
|
2240
2243
|
}
|
|
2241
2244
|
// remove hyphen, blank space, period, comma
|
|
2242
|
-
const trimmedValue = value.
|
|
2245
|
+
const trimmedValue = value.replaceAll(BANK_ACCOUNT_NUMBER_TRIM_REGEXP, "");
|
|
2243
2246
|
return BANK_ACCOUNT_NUMBER_REGEXP.test(trimmedValue)
|
|
2244
2247
|
? trimmedValue
|
|
2245
2248
|
: undefined;
|
|
@@ -2264,7 +2267,7 @@ function parseBankgiro(value) {
|
|
|
2264
2267
|
return `${match[1]}-${match[2]}`;
|
|
2265
2268
|
}
|
|
2266
2269
|
|
|
2267
|
-
const CLEARINGNUMBER_REGEXP = /^\d{4}([
|
|
2270
|
+
const CLEARINGNUMBER_REGEXP = /^\d{4}([\s-]?\d)?$/;
|
|
2268
2271
|
/**
|
|
2269
2272
|
* @public
|
|
2270
2273
|
*/
|
|
@@ -2277,7 +2280,7 @@ function parseClearingNumber(value) {
|
|
|
2277
2280
|
}
|
|
2278
2281
|
// add hyphen between number 4 & 5
|
|
2279
2282
|
return value.length === 5
|
|
2280
|
-
? `${value.
|
|
2283
|
+
? `${value.slice(0, 4)}-${value.slice(4, 5)}`
|
|
2281
2284
|
: value;
|
|
2282
2285
|
}
|
|
2283
2286
|
/**
|
|
@@ -2285,7 +2288,7 @@ function parseClearingNumber(value) {
|
|
|
2285
2288
|
*/
|
|
2286
2289
|
function formatClearingNumberForBackend(value) {
|
|
2287
2290
|
// remove the 5th number
|
|
2288
|
-
return value.
|
|
2291
|
+
return value.slice(0, 4);
|
|
2289
2292
|
}
|
|
2290
2293
|
|
|
2291
2294
|
function getDefaultExportFromCjs (x) {
|
|
@@ -2563,7 +2566,7 @@ class FDate {
|
|
|
2563
2566
|
* it increases the month, this is not the desired behaviour so we
|
|
2564
2567
|
* compare the parsed month with the original month, if they differ
|
|
2565
2568
|
* an invalid FDate is returned instead.*/
|
|
2566
|
-
if (date.isValid() && date.month === parseInt(month, 10)) {
|
|
2569
|
+
if (date.isValid() && date.month === Number.parseInt(month, 10)) {
|
|
2567
2570
|
return date;
|
|
2568
2571
|
}
|
|
2569
2572
|
}
|
|
@@ -2726,7 +2729,7 @@ class FDate {
|
|
|
2726
2729
|
if (!this.isValid()) {
|
|
2727
2730
|
return 0;
|
|
2728
2731
|
}
|
|
2729
|
-
const result = parseInt(this.value.format("d"), 10);
|
|
2732
|
+
const result = Number.parseInt(this.value.format("d"), 10);
|
|
2730
2733
|
if (!result) {
|
|
2731
2734
|
return Weekday.SUNDAY;
|
|
2732
2735
|
}
|
|
@@ -2960,7 +2963,7 @@ function parseDate(value) {
|
|
|
2960
2963
|
* @returns Text with whitespace stripped.
|
|
2961
2964
|
*/
|
|
2962
2965
|
function stripWhitespace(text) {
|
|
2963
|
-
return text.
|
|
2966
|
+
return text.replaceAll(/\s+/g, "");
|
|
2964
2967
|
}
|
|
2965
2968
|
|
|
2966
2969
|
const NUMBER_REGEXP$1 = /^(-?\d+)([,.]\d+)?$/;
|
|
@@ -2995,7 +2998,7 @@ function formatNumber(value, decimals) {
|
|
|
2995
2998
|
if (typeof value === "string") {
|
|
2996
2999
|
value = parseNumber(value) ?? "";
|
|
2997
3000
|
}
|
|
2998
|
-
if (typeof value !== "number" || isNaN(value)) {
|
|
3001
|
+
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
2999
3002
|
return undefined;
|
|
3000
3003
|
}
|
|
3001
3004
|
return formatSwedishNotation(value, decimals);
|
|
@@ -3016,14 +3019,14 @@ function parseNumber(value, fractionDigits) {
|
|
|
3016
3019
|
const parsedNumber = isSet(fractionDigits)
|
|
3017
3020
|
? getNumberWithFraction(number, fractionDigits)
|
|
3018
3021
|
: number;
|
|
3019
|
-
return isNaN(parsedNumber) ? undefined : parsedNumber;
|
|
3022
|
+
return Number.isNaN(parsedNumber) ? undefined : parsedNumber;
|
|
3020
3023
|
}
|
|
3021
3024
|
/**
|
|
3022
3025
|
* @internal
|
|
3023
3026
|
*/
|
|
3024
3027
|
function getNumberWithFraction(value, fractionDigits) {
|
|
3025
3028
|
if (fractionDigits < 0) {
|
|
3026
|
-
return NaN;
|
|
3029
|
+
return Number.NaN;
|
|
3027
3030
|
}
|
|
3028
3031
|
const exp = 10 ** fractionDigits;
|
|
3029
3032
|
return Math.sign(value) * (Math.round(Math.abs(value) * exp) / exp);
|
|
@@ -3032,9 +3035,9 @@ function getNumberWithFraction(value, fractionDigits) {
|
|
|
3032
3035
|
function getNowDetails(now) {
|
|
3033
3036
|
const nowIso = now.toString();
|
|
3034
3037
|
return {
|
|
3035
|
-
nowCentury: nowIso.
|
|
3036
|
-
nowYear: nowIso.
|
|
3037
|
-
nowMonthDay: nowIso.
|
|
3038
|
+
nowCentury: nowIso.slice(0, 2),
|
|
3039
|
+
nowYear: nowIso.slice(2, 4),
|
|
3040
|
+
nowMonthDay: nowIso.slice(5, 7) + nowIso.slice(8, 10),
|
|
3038
3041
|
};
|
|
3039
3042
|
}
|
|
3040
3043
|
/**
|
|
@@ -3059,7 +3062,7 @@ function resolveCentury(year, month, day, hasPlus, now) {
|
|
|
3059
3062
|
return (Number(nowCentury) - subtractCenturies).toString();
|
|
3060
3063
|
}
|
|
3061
3064
|
|
|
3062
|
-
const PERSONNUMMER_REGEXP = /^(?<century>\d{2})?(?<year>\d{2})(?<month>\d{2})(?<day>\d{2})(?<sign>[
|
|
3065
|
+
const PERSONNUMMER_REGEXP = /^(?<century>\d{2})?(?<year>\d{2})(?<month>\d{2})(?<day>\d{2})(?<sign>[+-])?(?<check>\d{4})$/;
|
|
3063
3066
|
function getDayWithoutSamordning(day) {
|
|
3064
3067
|
return (Number(day) % 60).toString().padStart(2, "0");
|
|
3065
3068
|
}
|
|
@@ -3132,11 +3135,11 @@ function formatPersonnummer(value) {
|
|
|
3132
3135
|
return undefined;
|
|
3133
3136
|
}
|
|
3134
3137
|
const currentYear = FDate.now().year;
|
|
3135
|
-
const year = Number(value.
|
|
3138
|
+
const year = Number(value.slice(0, 4));
|
|
3136
3139
|
if (currentYear - year >= 100) {
|
|
3137
|
-
return value.
|
|
3140
|
+
return value.slice(2).replace("-", "+");
|
|
3138
3141
|
}
|
|
3139
|
-
return value.
|
|
3142
|
+
return value.slice(2);
|
|
3140
3143
|
}
|
|
3141
3144
|
/**
|
|
3142
3145
|
* Formats personnummer to a 8-digit date.
|
|
@@ -3167,23 +3170,24 @@ function parsePlusgiro(value) {
|
|
|
3167
3170
|
* If the number of digits is odd then the first pair in the string can be a single digit.
|
|
3168
3171
|
* If the number of characters is 9, there will be a space after the first 3 characters.
|
|
3169
3172
|
*/
|
|
3170
|
-
value = value.
|
|
3171
|
-
value = value.
|
|
3173
|
+
value = value.replaceAll(" ", "");
|
|
3174
|
+
value = value.replaceAll(/\D/g, "");
|
|
3172
3175
|
if (!PLUSGIRO_REGEXP.test(value) ||
|
|
3173
|
-
!testLuhnChecksum(value.
|
|
3176
|
+
!testLuhnChecksum(value.replaceAll(/\D/g, ""))) {
|
|
3174
3177
|
return undefined;
|
|
3175
3178
|
}
|
|
3176
3179
|
if (hyphenShouldBeAdded(value)) {
|
|
3177
|
-
|
|
3180
|
+
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- length is 2+ so -1 will return a character */
|
|
3181
|
+
value = `${value.slice(0, -1)}-${value.at(-1)}`;
|
|
3178
3182
|
}
|
|
3179
3183
|
const startOffset = 4;
|
|
3180
|
-
let formattedString = value.
|
|
3184
|
+
let formattedString = value.slice(-startOffset);
|
|
3181
3185
|
const step = 2;
|
|
3182
3186
|
for (let i = value.length - startOffset; i >= (value.length === 9 ? 3 : 1); i -= step) {
|
|
3183
|
-
formattedString = `${value.
|
|
3187
|
+
formattedString = `${value.slice(Math.max(i - step, 0), i)} ${formattedString}`;
|
|
3184
3188
|
}
|
|
3185
3189
|
if (value.length === 9) {
|
|
3186
|
-
formattedString = value.
|
|
3190
|
+
formattedString = value.slice(0, 1) + formattedString;
|
|
3187
3191
|
}
|
|
3188
3192
|
return formattedString;
|
|
3189
3193
|
}
|
|
@@ -3300,7 +3304,7 @@ function documentOrderComparator(a, b) {
|
|
|
3300
3304
|
function isVisible(element) {
|
|
3301
3305
|
return Boolean(element.offsetWidth ||
|
|
3302
3306
|
element.offsetHeight ||
|
|
3303
|
-
element.getClientRects().length);
|
|
3307
|
+
element.getClientRects().length > 0);
|
|
3304
3308
|
}
|
|
3305
3309
|
|
|
3306
3310
|
const FRAMERATE = 60;
|
|
@@ -3680,7 +3684,7 @@ class ElementIdServiceImpl {
|
|
|
3680
3684
|
elementIdMap = new Map();
|
|
3681
3685
|
generateElementId(prefix = "fkui") {
|
|
3682
3686
|
const id = this.nextId(prefix);
|
|
3683
|
-
if (document.
|
|
3687
|
+
if (document.querySelector(`#${id}`) === null) {
|
|
3684
3688
|
return id;
|
|
3685
3689
|
}
|
|
3686
3690
|
return this.generateElementId(prefix);
|
|
@@ -3756,10 +3760,10 @@ class PersistenceService {
|
|
|
3756
3760
|
}
|
|
3757
3761
|
get(key) {
|
|
3758
3762
|
const found = this.find(key);
|
|
3759
|
-
if (
|
|
3763
|
+
if (found !== undefined) {
|
|
3760
3764
|
return found;
|
|
3761
3765
|
}
|
|
3762
|
-
throw Error(`PersistenceService cannot find entry with key "${key}"`);
|
|
3766
|
+
throw new Error(`PersistenceService cannot find entry with key "${key}"`);
|
|
3763
3767
|
}
|
|
3764
3768
|
find(key) {
|
|
3765
3769
|
if (this.cache.has(key)) {
|
|
@@ -3846,9 +3850,9 @@ class DefaultTranslationProvider {
|
|
|
3846
3850
|
: defaultValueOrArgs;
|
|
3847
3851
|
}
|
|
3848
3852
|
interpolate(defaultValue, args) {
|
|
3849
|
-
return defaultValue.
|
|
3853
|
+
return defaultValue.replaceAll(
|
|
3850
3854
|
/* eslint-disable-next-line sonarjs/slow-regex -- technical debt */
|
|
3851
|
-
/{{\s*(
|
|
3855
|
+
/{{\s*(\S+)\s*}}/g, (match, key) => {
|
|
3852
3856
|
return String(args[key]) || match;
|
|
3853
3857
|
});
|
|
3854
3858
|
}
|
|
@@ -3892,6 +3896,7 @@ class FieldsetValidationHandler {
|
|
|
3892
3896
|
element.addEventListener("change", this.documentFocusIn.bind(this));
|
|
3893
3897
|
Array.from(this.element.querySelectorAll("input[type='checkbox'], input[type='radio']"))
|
|
3894
3898
|
.filter((childElement) => childElement.closest("fieldset") === element)
|
|
3899
|
+
/* eslint-disable-next-line unicorn/no-array-for-each -- technical debt */
|
|
3895
3900
|
.forEach((childElement) => {
|
|
3896
3901
|
childElement.setAttribute("required", "");
|
|
3897
3902
|
});
|
|
@@ -3935,12 +3940,12 @@ class FieldsetValidationHandler {
|
|
|
3935
3940
|
}
|
|
3936
3941
|
validateFieldsetAndChildren() {
|
|
3937
3942
|
const validatableElements = document.querySelectorAll(`fieldset#${this.element.id}, #${this.element.id} input[type='checkbox'], #${this.element.id} input[type='radio']`);
|
|
3938
|
-
|
|
3943
|
+
for (const element of validatableElements) {
|
|
3939
3944
|
if (element.id) {
|
|
3940
3945
|
/* eslint-disable-next-line @typescript-eslint/no-floating-promises -- technical debt */
|
|
3941
3946
|
this.validationService.validateElement(element.id);
|
|
3942
3947
|
}
|
|
3943
|
-
}
|
|
3948
|
+
}
|
|
3944
3949
|
}
|
|
3945
3950
|
}
|
|
3946
3951
|
|
|
@@ -4339,7 +4344,7 @@ class ValidationServiceImpl {
|
|
|
4339
4344
|
};
|
|
4340
4345
|
}
|
|
4341
4346
|
if (typeof src === "string") {
|
|
4342
|
-
const element = document.
|
|
4347
|
+
const element = document.querySelector(`#${src}`);
|
|
4343
4348
|
if (!element) {
|
|
4344
4349
|
throw new Error(`Element with id "${src}" not found when calling validateElement(..)`);
|
|
4345
4350
|
}
|
|
@@ -4414,7 +4419,7 @@ class ValidationServiceImpl {
|
|
|
4414
4419
|
return;
|
|
4415
4420
|
}
|
|
4416
4421
|
else if (typeof element === "string") {
|
|
4417
|
-
const found = document.
|
|
4422
|
+
const found = document.querySelector(`#${element}`);
|
|
4418
4423
|
/* eslint-disable-next-line @typescript-eslint/no-deprecated -- internal usage */
|
|
4419
4424
|
this.setState(found, validationState);
|
|
4420
4425
|
}
|
|
@@ -4470,7 +4475,7 @@ class ValidationServiceImpl {
|
|
|
4470
4475
|
return [];
|
|
4471
4476
|
}
|
|
4472
4477
|
else if (typeof parent === "string") {
|
|
4473
|
-
const element = document.
|
|
4478
|
+
const element = document.querySelector(`#${parent}`);
|
|
4474
4479
|
return this.getValidatableElements(element);
|
|
4475
4480
|
}
|
|
4476
4481
|
else {
|
|
@@ -4776,11 +4781,11 @@ const decimalValidator = {
|
|
|
4776
4781
|
Number(config.maxDecimals)
|
|
4777
4782
|
: undefined;
|
|
4778
4783
|
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- technical debt, should actually verfiy value instead */
|
|
4779
|
-
if (config.minDecimals && isNaN(minDecimalsAsNumber)) {
|
|
4784
|
+
if (config.minDecimals && Number.isNaN(minDecimalsAsNumber)) {
|
|
4780
4785
|
throw new Error("config.minDecimals must be a number");
|
|
4781
4786
|
}
|
|
4782
4787
|
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- technical debt, should actually verfiy value instead */
|
|
4783
|
-
if (config.maxDecimals && isNaN(maxDecimalsAsNumber)) {
|
|
4788
|
+
if (config.maxDecimals && Number.isNaN(maxDecimalsAsNumber)) {
|
|
4784
4789
|
throw new Error("config.maxDecimals must be a number");
|
|
4785
4790
|
}
|
|
4786
4791
|
return (isEmpty(valueWithoutWhitespace) ||
|
|
@@ -4827,7 +4832,7 @@ const greaterThanValidator = {
|
|
|
4827
4832
|
},
|
|
4828
4833
|
};
|
|
4829
4834
|
|
|
4830
|
-
const NUMBER_REGEXP = /^([
|
|
4835
|
+
const NUMBER_REGEXP = /^([−-]?\d+)?$/;
|
|
4831
4836
|
const integerValidator = {
|
|
4832
4837
|
name: "integer",
|
|
4833
4838
|
validation(value) {
|
|
@@ -4900,7 +4905,8 @@ const matchesValidator = {
|
|
|
4900
4905
|
}
|
|
4901
4906
|
/** TODO This will crash if the element is not found */
|
|
4902
4907
|
/** TODO This assumes the id references an `<input>` field */
|
|
4903
|
-
|
|
4908
|
+
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- technical debt */
|
|
4909
|
+
const el = document.querySelector(`#${config.id}`);
|
|
4904
4910
|
return el.value === value;
|
|
4905
4911
|
},
|
|
4906
4912
|
};
|
|
@@ -4924,7 +4930,8 @@ const maxDateValidator = {
|
|
|
4924
4930
|
const maxLengthValidator = {
|
|
4925
4931
|
name: "maxLength",
|
|
4926
4932
|
validation(value, _element, config) {
|
|
4927
|
-
|
|
4933
|
+
const { length = 0 } = config;
|
|
4934
|
+
return length > 0 && value ? value.length <= length : true;
|
|
4928
4935
|
},
|
|
4929
4936
|
};
|
|
4930
4937
|
|
|
@@ -4954,7 +4961,8 @@ const minDateValidator = {
|
|
|
4954
4961
|
const minLengthValidator = {
|
|
4955
4962
|
name: "minLength",
|
|
4956
4963
|
validation(value, _element, config) {
|
|
4957
|
-
|
|
4964
|
+
const { length = 0 } = config;
|
|
4965
|
+
return length > 0 && value ? value.length >= length : true;
|
|
4958
4966
|
},
|
|
4959
4967
|
};
|
|
4960
4968
|
|
|
@@ -4979,7 +4987,7 @@ const organisationsnummerValidator = {
|
|
|
4979
4987
|
},
|
|
4980
4988
|
};
|
|
4981
4989
|
|
|
4982
|
-
const PERCENT_REGEXP = /^([
|
|
4990
|
+
const PERCENT_REGEXP = /^([+-]?\d+)([,.]\d+)?$/;
|
|
4983
4991
|
const percentValidator = {
|
|
4984
4992
|
name: "percent",
|
|
4985
4993
|
validation(value) {
|
|
@@ -5049,7 +5057,7 @@ const personnummerYounger = {
|
|
|
5049
5057
|
},
|
|
5050
5058
|
};
|
|
5051
5059
|
|
|
5052
|
-
const PHONE_NUMBER_REGEXP = /^(\+?[
|
|
5060
|
+
const PHONE_NUMBER_REGEXP = /^(\+?[ ()/_-]*(\d[ ()/_-]*?){3,17})$/;
|
|
5053
5061
|
const phoneNumberValidator = {
|
|
5054
5062
|
name: "phoneNumber",
|
|
5055
5063
|
validation(value) {
|
|
@@ -5106,7 +5114,7 @@ const requiredValidator = {
|
|
|
5106
5114
|
},
|
|
5107
5115
|
};
|
|
5108
5116
|
|
|
5109
|
-
const WHITELIST_REGEXP = /^[
|
|
5117
|
+
const WHITELIST_REGEXP = /^[\d\n\r !()*+,.:=?@A-Za-z\u00C0-\u00FF-]*$/;
|
|
5110
5118
|
const whitelistValidator = {
|
|
5111
5119
|
name: "whitelist",
|
|
5112
5120
|
instant: true,
|
|
@@ -5216,13 +5224,13 @@ function alertScreenReader(text, options) {
|
|
|
5216
5224
|
/* eslint-disable-next-line @typescript-eslint/no-floating-promises -- technical debt */
|
|
5217
5225
|
waitForScreenReader(() => {
|
|
5218
5226
|
while (wrapper.firstChild) {
|
|
5219
|
-
wrapper.
|
|
5227
|
+
wrapper.firstChild.remove();
|
|
5220
5228
|
}
|
|
5221
|
-
wrapper.
|
|
5229
|
+
wrapper.append(msg);
|
|
5222
5230
|
setTimeout(() => {
|
|
5223
5231
|
// Remove element if it is still in the DOM.
|
|
5224
5232
|
if (msg.parentElement === wrapper) {
|
|
5225
|
-
|
|
5233
|
+
msg.remove();
|
|
5226
5234
|
}
|
|
5227
5235
|
}, REMOVE_TEXT_DELAY);
|
|
5228
5236
|
});
|
|
@@ -5240,7 +5248,7 @@ function createScreenReaderWrapper(options) {
|
|
|
5240
5248
|
wrapper.id = "fkui-alert-screen-reader";
|
|
5241
5249
|
wrapper.className = "sr-only";
|
|
5242
5250
|
updateProperties(options);
|
|
5243
|
-
document.body.
|
|
5251
|
+
document.body.append(wrapper);
|
|
5244
5252
|
}
|
|
5245
5253
|
}
|
|
5246
5254
|
/**
|
package/lib/esm/index.js
CHANGED
|
@@ -29,6 +29,7 @@ function isSet(value) {
|
|
|
29
29
|
* @public
|
|
30
30
|
*/
|
|
31
31
|
function isString(value) {
|
|
32
|
+
/* eslint-disable-next-line unicorn/no-instanceof-builtins -- technical debt */
|
|
32
33
|
return typeof value === "string" || value instanceof String;
|
|
33
34
|
}
|
|
34
35
|
|
|
@@ -40,6 +41,7 @@ function isString(value) {
|
|
|
40
41
|
class MissingValueError extends Error {
|
|
41
42
|
constructor(message) {
|
|
42
43
|
super(message);
|
|
44
|
+
this.name = "MissingValueError";
|
|
43
45
|
Object.setPrototypeOf(this, MissingValueError.prototype);
|
|
44
46
|
}
|
|
45
47
|
}
|
|
@@ -195,6 +197,7 @@ class DecoratedError extends Error {
|
|
|
195
197
|
cause;
|
|
196
198
|
constructor(message, cause) {
|
|
197
199
|
super(message);
|
|
200
|
+
this.name = "DecoratedError";
|
|
198
201
|
Object.setPrototypeOf(this, DecoratedError.prototype);
|
|
199
202
|
/* eslint-disable-next-line @typescript-eslint/restrict-plus-operands -- technical debt */
|
|
200
203
|
this.stack += `\nCaused by: ${String(cause.stack)}`;
|
|
@@ -2167,13 +2170,13 @@ function testLuhnChecksum(inputString) {
|
|
|
2167
2170
|
if (/^\d+$/.test(inputString) === false) {
|
|
2168
2171
|
throw new Error("Luhn Checksum test only works on strings containing numbers");
|
|
2169
2172
|
}
|
|
2170
|
-
inputString
|
|
2173
|
+
for (const [index, numChar] of inputString
|
|
2171
2174
|
.split("")
|
|
2172
|
-
.
|
|
2173
|
-
.
|
|
2174
|
-
const digit = parseInt(numChar, 10) * ((index + 1) % 2 === 0 ? 2 : 1);
|
|
2175
|
+
.toReversed()
|
|
2176
|
+
.entries()) {
|
|
2177
|
+
const digit = Number.parseInt(numChar, 10) * ((index + 1) % 2 === 0 ? 2 : 1);
|
|
2175
2178
|
sum += digit >= 10 ? digit - 9 : digit;
|
|
2176
|
-
}
|
|
2179
|
+
}
|
|
2177
2180
|
return sum % 10 === 0;
|
|
2178
2181
|
}
|
|
2179
2182
|
|
|
@@ -2181,7 +2184,7 @@ function testLuhnChecksum(inputString) {
|
|
|
2181
2184
|
* @public
|
|
2182
2185
|
*/
|
|
2183
2186
|
function validChecksum(value) {
|
|
2184
|
-
const yymmddxxxx = value.slice(2).
|
|
2187
|
+
const yymmddxxxx = value.slice(2).replaceAll("-", "");
|
|
2185
2188
|
return testLuhnChecksum(yymmddxxxx);
|
|
2186
2189
|
}
|
|
2187
2190
|
|
|
@@ -2228,7 +2231,7 @@ function findCookie(name) {
|
|
|
2228
2231
|
}
|
|
2229
2232
|
|
|
2230
2233
|
const BANK_ACCOUNT_NUMBER_REGEXP = /^\d{3,16}$/;
|
|
2231
|
-
const BANK_ACCOUNT_NUMBER_TRIM_REGEXP = /[
|
|
2234
|
+
const BANK_ACCOUNT_NUMBER_TRIM_REGEXP = /[ ,.-]+/g;
|
|
2232
2235
|
/**
|
|
2233
2236
|
* @public
|
|
2234
2237
|
*/
|
|
@@ -2237,7 +2240,7 @@ function parseBankAccountNumber(value) {
|
|
|
2237
2240
|
return undefined;
|
|
2238
2241
|
}
|
|
2239
2242
|
// remove hyphen, blank space, period, comma
|
|
2240
|
-
const trimmedValue = value.
|
|
2243
|
+
const trimmedValue = value.replaceAll(BANK_ACCOUNT_NUMBER_TRIM_REGEXP, "");
|
|
2241
2244
|
return BANK_ACCOUNT_NUMBER_REGEXP.test(trimmedValue)
|
|
2242
2245
|
? trimmedValue
|
|
2243
2246
|
: undefined;
|
|
@@ -2262,7 +2265,7 @@ function parseBankgiro(value) {
|
|
|
2262
2265
|
return `${match[1]}-${match[2]}`;
|
|
2263
2266
|
}
|
|
2264
2267
|
|
|
2265
|
-
const CLEARINGNUMBER_REGEXP = /^\d{4}([
|
|
2268
|
+
const CLEARINGNUMBER_REGEXP = /^\d{4}([\s-]?\d)?$/;
|
|
2266
2269
|
/**
|
|
2267
2270
|
* @public
|
|
2268
2271
|
*/
|
|
@@ -2275,7 +2278,7 @@ function parseClearingNumber(value) {
|
|
|
2275
2278
|
}
|
|
2276
2279
|
// add hyphen between number 4 & 5
|
|
2277
2280
|
return value.length === 5
|
|
2278
|
-
? `${value.
|
|
2281
|
+
? `${value.slice(0, 4)}-${value.slice(4, 5)}`
|
|
2279
2282
|
: value;
|
|
2280
2283
|
}
|
|
2281
2284
|
/**
|
|
@@ -2283,7 +2286,7 @@ function parseClearingNumber(value) {
|
|
|
2283
2286
|
*/
|
|
2284
2287
|
function formatClearingNumberForBackend(value) {
|
|
2285
2288
|
// remove the 5th number
|
|
2286
|
-
return value.
|
|
2289
|
+
return value.slice(0, 4);
|
|
2287
2290
|
}
|
|
2288
2291
|
|
|
2289
2292
|
function getDefaultExportFromCjs (x) {
|
|
@@ -2561,7 +2564,7 @@ class FDate {
|
|
|
2561
2564
|
* it increases the month, this is not the desired behaviour so we
|
|
2562
2565
|
* compare the parsed month with the original month, if they differ
|
|
2563
2566
|
* an invalid FDate is returned instead.*/
|
|
2564
|
-
if (date.isValid() && date.month === parseInt(month, 10)) {
|
|
2567
|
+
if (date.isValid() && date.month === Number.parseInt(month, 10)) {
|
|
2565
2568
|
return date;
|
|
2566
2569
|
}
|
|
2567
2570
|
}
|
|
@@ -2724,7 +2727,7 @@ class FDate {
|
|
|
2724
2727
|
if (!this.isValid()) {
|
|
2725
2728
|
return 0;
|
|
2726
2729
|
}
|
|
2727
|
-
const result = parseInt(this.value.format("d"), 10);
|
|
2730
|
+
const result = Number.parseInt(this.value.format("d"), 10);
|
|
2728
2731
|
if (!result) {
|
|
2729
2732
|
return Weekday.SUNDAY;
|
|
2730
2733
|
}
|
|
@@ -2958,7 +2961,7 @@ function parseDate(value) {
|
|
|
2958
2961
|
* @returns Text with whitespace stripped.
|
|
2959
2962
|
*/
|
|
2960
2963
|
function stripWhitespace(text) {
|
|
2961
|
-
return text.
|
|
2964
|
+
return text.replaceAll(/\s+/g, "");
|
|
2962
2965
|
}
|
|
2963
2966
|
|
|
2964
2967
|
const NUMBER_REGEXP$1 = /^(-?\d+)([,.]\d+)?$/;
|
|
@@ -2993,7 +2996,7 @@ function formatNumber(value, decimals) {
|
|
|
2993
2996
|
if (typeof value === "string") {
|
|
2994
2997
|
value = parseNumber(value) ?? "";
|
|
2995
2998
|
}
|
|
2996
|
-
if (typeof value !== "number" || isNaN(value)) {
|
|
2999
|
+
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
2997
3000
|
return undefined;
|
|
2998
3001
|
}
|
|
2999
3002
|
return formatSwedishNotation(value, decimals);
|
|
@@ -3014,14 +3017,14 @@ function parseNumber(value, fractionDigits) {
|
|
|
3014
3017
|
const parsedNumber = isSet(fractionDigits)
|
|
3015
3018
|
? getNumberWithFraction(number, fractionDigits)
|
|
3016
3019
|
: number;
|
|
3017
|
-
return isNaN(parsedNumber) ? undefined : parsedNumber;
|
|
3020
|
+
return Number.isNaN(parsedNumber) ? undefined : parsedNumber;
|
|
3018
3021
|
}
|
|
3019
3022
|
/**
|
|
3020
3023
|
* @internal
|
|
3021
3024
|
*/
|
|
3022
3025
|
function getNumberWithFraction(value, fractionDigits) {
|
|
3023
3026
|
if (fractionDigits < 0) {
|
|
3024
|
-
return NaN;
|
|
3027
|
+
return Number.NaN;
|
|
3025
3028
|
}
|
|
3026
3029
|
const exp = 10 ** fractionDigits;
|
|
3027
3030
|
return Math.sign(value) * (Math.round(Math.abs(value) * exp) / exp);
|
|
@@ -3030,9 +3033,9 @@ function getNumberWithFraction(value, fractionDigits) {
|
|
|
3030
3033
|
function getNowDetails(now) {
|
|
3031
3034
|
const nowIso = now.toString();
|
|
3032
3035
|
return {
|
|
3033
|
-
nowCentury: nowIso.
|
|
3034
|
-
nowYear: nowIso.
|
|
3035
|
-
nowMonthDay: nowIso.
|
|
3036
|
+
nowCentury: nowIso.slice(0, 2),
|
|
3037
|
+
nowYear: nowIso.slice(2, 4),
|
|
3038
|
+
nowMonthDay: nowIso.slice(5, 7) + nowIso.slice(8, 10),
|
|
3036
3039
|
};
|
|
3037
3040
|
}
|
|
3038
3041
|
/**
|
|
@@ -3057,7 +3060,7 @@ function resolveCentury(year, month, day, hasPlus, now) {
|
|
|
3057
3060
|
return (Number(nowCentury) - subtractCenturies).toString();
|
|
3058
3061
|
}
|
|
3059
3062
|
|
|
3060
|
-
const PERSONNUMMER_REGEXP = /^(?<century>\d{2})?(?<year>\d{2})(?<month>\d{2})(?<day>\d{2})(?<sign>[
|
|
3063
|
+
const PERSONNUMMER_REGEXP = /^(?<century>\d{2})?(?<year>\d{2})(?<month>\d{2})(?<day>\d{2})(?<sign>[+-])?(?<check>\d{4})$/;
|
|
3061
3064
|
function getDayWithoutSamordning(day) {
|
|
3062
3065
|
return (Number(day) % 60).toString().padStart(2, "0");
|
|
3063
3066
|
}
|
|
@@ -3130,11 +3133,11 @@ function formatPersonnummer(value) {
|
|
|
3130
3133
|
return undefined;
|
|
3131
3134
|
}
|
|
3132
3135
|
const currentYear = FDate.now().year;
|
|
3133
|
-
const year = Number(value.
|
|
3136
|
+
const year = Number(value.slice(0, 4));
|
|
3134
3137
|
if (currentYear - year >= 100) {
|
|
3135
|
-
return value.
|
|
3138
|
+
return value.slice(2).replace("-", "+");
|
|
3136
3139
|
}
|
|
3137
|
-
return value.
|
|
3140
|
+
return value.slice(2);
|
|
3138
3141
|
}
|
|
3139
3142
|
/**
|
|
3140
3143
|
* Formats personnummer to a 8-digit date.
|
|
@@ -3165,23 +3168,24 @@ function parsePlusgiro(value) {
|
|
|
3165
3168
|
* If the number of digits is odd then the first pair in the string can be a single digit.
|
|
3166
3169
|
* If the number of characters is 9, there will be a space after the first 3 characters.
|
|
3167
3170
|
*/
|
|
3168
|
-
value = value.
|
|
3169
|
-
value = value.
|
|
3171
|
+
value = value.replaceAll(" ", "");
|
|
3172
|
+
value = value.replaceAll(/\D/g, "");
|
|
3170
3173
|
if (!PLUSGIRO_REGEXP.test(value) ||
|
|
3171
|
-
!testLuhnChecksum(value.
|
|
3174
|
+
!testLuhnChecksum(value.replaceAll(/\D/g, ""))) {
|
|
3172
3175
|
return undefined;
|
|
3173
3176
|
}
|
|
3174
3177
|
if (hyphenShouldBeAdded(value)) {
|
|
3175
|
-
|
|
3178
|
+
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- length is 2+ so -1 will return a character */
|
|
3179
|
+
value = `${value.slice(0, -1)}-${value.at(-1)}`;
|
|
3176
3180
|
}
|
|
3177
3181
|
const startOffset = 4;
|
|
3178
|
-
let formattedString = value.
|
|
3182
|
+
let formattedString = value.slice(-startOffset);
|
|
3179
3183
|
const step = 2;
|
|
3180
3184
|
for (let i = value.length - startOffset; i >= (value.length === 9 ? 3 : 1); i -= step) {
|
|
3181
|
-
formattedString = `${value.
|
|
3185
|
+
formattedString = `${value.slice(Math.max(i - step, 0), i)} ${formattedString}`;
|
|
3182
3186
|
}
|
|
3183
3187
|
if (value.length === 9) {
|
|
3184
|
-
formattedString = value.
|
|
3188
|
+
formattedString = value.slice(0, 1) + formattedString;
|
|
3185
3189
|
}
|
|
3186
3190
|
return formattedString;
|
|
3187
3191
|
}
|
|
@@ -3298,7 +3302,7 @@ function documentOrderComparator(a, b) {
|
|
|
3298
3302
|
function isVisible(element) {
|
|
3299
3303
|
return Boolean(element.offsetWidth ||
|
|
3300
3304
|
element.offsetHeight ||
|
|
3301
|
-
element.getClientRects().length);
|
|
3305
|
+
element.getClientRects().length > 0);
|
|
3302
3306
|
}
|
|
3303
3307
|
|
|
3304
3308
|
const FRAMERATE = 60;
|
|
@@ -3678,7 +3682,7 @@ class ElementIdServiceImpl {
|
|
|
3678
3682
|
elementIdMap = new Map();
|
|
3679
3683
|
generateElementId(prefix = "fkui") {
|
|
3680
3684
|
const id = this.nextId(prefix);
|
|
3681
|
-
if (document.
|
|
3685
|
+
if (document.querySelector(`#${id}`) === null) {
|
|
3682
3686
|
return id;
|
|
3683
3687
|
}
|
|
3684
3688
|
return this.generateElementId(prefix);
|
|
@@ -3754,10 +3758,10 @@ class PersistenceService {
|
|
|
3754
3758
|
}
|
|
3755
3759
|
get(key) {
|
|
3756
3760
|
const found = this.find(key);
|
|
3757
|
-
if (
|
|
3761
|
+
if (found !== undefined) {
|
|
3758
3762
|
return found;
|
|
3759
3763
|
}
|
|
3760
|
-
throw Error(`PersistenceService cannot find entry with key "${key}"`);
|
|
3764
|
+
throw new Error(`PersistenceService cannot find entry with key "${key}"`);
|
|
3761
3765
|
}
|
|
3762
3766
|
find(key) {
|
|
3763
3767
|
if (this.cache.has(key)) {
|
|
@@ -3844,9 +3848,9 @@ class DefaultTranslationProvider {
|
|
|
3844
3848
|
: defaultValueOrArgs;
|
|
3845
3849
|
}
|
|
3846
3850
|
interpolate(defaultValue, args) {
|
|
3847
|
-
return defaultValue.
|
|
3851
|
+
return defaultValue.replaceAll(
|
|
3848
3852
|
/* eslint-disable-next-line sonarjs/slow-regex -- technical debt */
|
|
3849
|
-
/{{\s*(
|
|
3853
|
+
/{{\s*(\S+)\s*}}/g, (match, key) => {
|
|
3850
3854
|
return String(args[key]) || match;
|
|
3851
3855
|
});
|
|
3852
3856
|
}
|
|
@@ -3890,6 +3894,7 @@ class FieldsetValidationHandler {
|
|
|
3890
3894
|
element.addEventListener("change", this.documentFocusIn.bind(this));
|
|
3891
3895
|
Array.from(this.element.querySelectorAll("input[type='checkbox'], input[type='radio']"))
|
|
3892
3896
|
.filter((childElement) => childElement.closest("fieldset") === element)
|
|
3897
|
+
/* eslint-disable-next-line unicorn/no-array-for-each -- technical debt */
|
|
3893
3898
|
.forEach((childElement) => {
|
|
3894
3899
|
childElement.setAttribute("required", "");
|
|
3895
3900
|
});
|
|
@@ -3933,12 +3938,12 @@ class FieldsetValidationHandler {
|
|
|
3933
3938
|
}
|
|
3934
3939
|
validateFieldsetAndChildren() {
|
|
3935
3940
|
const validatableElements = document.querySelectorAll(`fieldset#${this.element.id}, #${this.element.id} input[type='checkbox'], #${this.element.id} input[type='radio']`);
|
|
3936
|
-
|
|
3941
|
+
for (const element of validatableElements) {
|
|
3937
3942
|
if (element.id) {
|
|
3938
3943
|
/* eslint-disable-next-line @typescript-eslint/no-floating-promises -- technical debt */
|
|
3939
3944
|
this.validationService.validateElement(element.id);
|
|
3940
3945
|
}
|
|
3941
|
-
}
|
|
3946
|
+
}
|
|
3942
3947
|
}
|
|
3943
3948
|
}
|
|
3944
3949
|
|
|
@@ -4337,7 +4342,7 @@ class ValidationServiceImpl {
|
|
|
4337
4342
|
};
|
|
4338
4343
|
}
|
|
4339
4344
|
if (typeof src === "string") {
|
|
4340
|
-
const element = document.
|
|
4345
|
+
const element = document.querySelector(`#${src}`);
|
|
4341
4346
|
if (!element) {
|
|
4342
4347
|
throw new Error(`Element with id "${src}" not found when calling validateElement(..)`);
|
|
4343
4348
|
}
|
|
@@ -4412,7 +4417,7 @@ class ValidationServiceImpl {
|
|
|
4412
4417
|
return;
|
|
4413
4418
|
}
|
|
4414
4419
|
else if (typeof element === "string") {
|
|
4415
|
-
const found = document.
|
|
4420
|
+
const found = document.querySelector(`#${element}`);
|
|
4416
4421
|
/* eslint-disable-next-line @typescript-eslint/no-deprecated -- internal usage */
|
|
4417
4422
|
this.setState(found, validationState);
|
|
4418
4423
|
}
|
|
@@ -4468,7 +4473,7 @@ class ValidationServiceImpl {
|
|
|
4468
4473
|
return [];
|
|
4469
4474
|
}
|
|
4470
4475
|
else if (typeof parent === "string") {
|
|
4471
|
-
const element = document.
|
|
4476
|
+
const element = document.querySelector(`#${parent}`);
|
|
4472
4477
|
return this.getValidatableElements(element);
|
|
4473
4478
|
}
|
|
4474
4479
|
else {
|
|
@@ -4774,11 +4779,11 @@ const decimalValidator = {
|
|
|
4774
4779
|
Number(config.maxDecimals)
|
|
4775
4780
|
: undefined;
|
|
4776
4781
|
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- technical debt, should actually verfiy value instead */
|
|
4777
|
-
if (config.minDecimals && isNaN(minDecimalsAsNumber)) {
|
|
4782
|
+
if (config.minDecimals && Number.isNaN(minDecimalsAsNumber)) {
|
|
4778
4783
|
throw new Error("config.minDecimals must be a number");
|
|
4779
4784
|
}
|
|
4780
4785
|
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- technical debt, should actually verfiy value instead */
|
|
4781
|
-
if (config.maxDecimals && isNaN(maxDecimalsAsNumber)) {
|
|
4786
|
+
if (config.maxDecimals && Number.isNaN(maxDecimalsAsNumber)) {
|
|
4782
4787
|
throw new Error("config.maxDecimals must be a number");
|
|
4783
4788
|
}
|
|
4784
4789
|
return (isEmpty(valueWithoutWhitespace) ||
|
|
@@ -4825,7 +4830,7 @@ const greaterThanValidator = {
|
|
|
4825
4830
|
},
|
|
4826
4831
|
};
|
|
4827
4832
|
|
|
4828
|
-
const NUMBER_REGEXP = /^([
|
|
4833
|
+
const NUMBER_REGEXP = /^([−-]?\d+)?$/;
|
|
4829
4834
|
const integerValidator = {
|
|
4830
4835
|
name: "integer",
|
|
4831
4836
|
validation(value) {
|
|
@@ -4898,7 +4903,8 @@ const matchesValidator = {
|
|
|
4898
4903
|
}
|
|
4899
4904
|
/** TODO This will crash if the element is not found */
|
|
4900
4905
|
/** TODO This assumes the id references an `<input>` field */
|
|
4901
|
-
|
|
4906
|
+
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- technical debt */
|
|
4907
|
+
const el = document.querySelector(`#${config.id}`);
|
|
4902
4908
|
return el.value === value;
|
|
4903
4909
|
},
|
|
4904
4910
|
};
|
|
@@ -4922,7 +4928,8 @@ const maxDateValidator = {
|
|
|
4922
4928
|
const maxLengthValidator = {
|
|
4923
4929
|
name: "maxLength",
|
|
4924
4930
|
validation(value, _element, config) {
|
|
4925
|
-
|
|
4931
|
+
const { length = 0 } = config;
|
|
4932
|
+
return length > 0 && value ? value.length <= length : true;
|
|
4926
4933
|
},
|
|
4927
4934
|
};
|
|
4928
4935
|
|
|
@@ -4952,7 +4959,8 @@ const minDateValidator = {
|
|
|
4952
4959
|
const minLengthValidator = {
|
|
4953
4960
|
name: "minLength",
|
|
4954
4961
|
validation(value, _element, config) {
|
|
4955
|
-
|
|
4962
|
+
const { length = 0 } = config;
|
|
4963
|
+
return length > 0 && value ? value.length >= length : true;
|
|
4956
4964
|
},
|
|
4957
4965
|
};
|
|
4958
4966
|
|
|
@@ -4977,7 +4985,7 @@ const organisationsnummerValidator = {
|
|
|
4977
4985
|
},
|
|
4978
4986
|
};
|
|
4979
4987
|
|
|
4980
|
-
const PERCENT_REGEXP = /^([
|
|
4988
|
+
const PERCENT_REGEXP = /^([+-]?\d+)([,.]\d+)?$/;
|
|
4981
4989
|
const percentValidator = {
|
|
4982
4990
|
name: "percent",
|
|
4983
4991
|
validation(value) {
|
|
@@ -5047,7 +5055,7 @@ const personnummerYounger = {
|
|
|
5047
5055
|
},
|
|
5048
5056
|
};
|
|
5049
5057
|
|
|
5050
|
-
const PHONE_NUMBER_REGEXP = /^(\+?[
|
|
5058
|
+
const PHONE_NUMBER_REGEXP = /^(\+?[ ()/_-]*(\d[ ()/_-]*?){3,17})$/;
|
|
5051
5059
|
const phoneNumberValidator = {
|
|
5052
5060
|
name: "phoneNumber",
|
|
5053
5061
|
validation(value) {
|
|
@@ -5104,7 +5112,7 @@ const requiredValidator = {
|
|
|
5104
5112
|
},
|
|
5105
5113
|
};
|
|
5106
5114
|
|
|
5107
|
-
const WHITELIST_REGEXP = /^[
|
|
5115
|
+
const WHITELIST_REGEXP = /^[\d\n\r !()*+,.:=?@A-Za-z\u00C0-\u00FF-]*$/;
|
|
5108
5116
|
const whitelistValidator = {
|
|
5109
5117
|
name: "whitelist",
|
|
5110
5118
|
instant: true,
|
|
@@ -5214,13 +5222,13 @@ function alertScreenReader(text, options) {
|
|
|
5214
5222
|
/* eslint-disable-next-line @typescript-eslint/no-floating-promises -- technical debt */
|
|
5215
5223
|
waitForScreenReader(() => {
|
|
5216
5224
|
while (wrapper.firstChild) {
|
|
5217
|
-
wrapper.
|
|
5225
|
+
wrapper.firstChild.remove();
|
|
5218
5226
|
}
|
|
5219
|
-
wrapper.
|
|
5227
|
+
wrapper.append(msg);
|
|
5220
5228
|
setTimeout(() => {
|
|
5221
5229
|
// Remove element if it is still in the DOM.
|
|
5222
5230
|
if (msg.parentElement === wrapper) {
|
|
5223
|
-
|
|
5231
|
+
msg.remove();
|
|
5224
5232
|
}
|
|
5225
5233
|
}, REMOVE_TEXT_DELAY);
|
|
5226
5234
|
});
|
|
@@ -5238,7 +5246,7 @@ function createScreenReaderWrapper(options) {
|
|
|
5238
5246
|
wrapper.id = "fkui-alert-screen-reader";
|
|
5239
5247
|
wrapper.className = "sr-only";
|
|
5240
5248
|
updateProperties(options);
|
|
5241
|
-
document.body.
|
|
5249
|
+
document.body.append(wrapper);
|
|
5242
5250
|
}
|
|
5243
5251
|
}
|
|
5244
5252
|
/**
|
package/lib/types/index.d.ts
CHANGED
|
@@ -123,6 +123,15 @@ export declare interface AllowListValidatorConfig extends ValidatorOptions {
|
|
|
123
123
|
values: string | string[] | number | number[];
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Constructs a tuple type of a specific length `N`.
|
|
128
|
+
* Used internally for recursion depth tracking.
|
|
129
|
+
*
|
|
130
|
+
* @public
|
|
131
|
+
* @since v6.38.0
|
|
132
|
+
*/
|
|
133
|
+
export declare type BuildDepth<N extends number, T extends unknown[] = []> = T["length"] extends N ? T : BuildDepth<N, [...T, unknown]>;
|
|
134
|
+
|
|
126
135
|
/**
|
|
127
136
|
* A string of 4-5 digits where last digit may be separated by hyphen, for
|
|
128
137
|
* example "5678-1"
|
|
@@ -147,6 +156,16 @@ export declare interface AllowListValidatorConfig extends ValidatorOptions {
|
|
|
147
156
|
timeLimitSeconds?: number;
|
|
148
157
|
}
|
|
149
158
|
|
|
159
|
+
/**
|
|
160
|
+
* Global registry interface.
|
|
161
|
+
* Consumers (the main project) will merge their specific key types into this.
|
|
162
|
+
*
|
|
163
|
+
* @public
|
|
164
|
+
* @since v6.38.0
|
|
165
|
+
*/
|
|
166
|
+
export declare interface CustomTranslationRegistry {
|
|
167
|
+
}
|
|
168
|
+
|
|
150
169
|
/**
|
|
151
170
|
* A string in format YYYY-MM-DD, for example 2021-02-03
|
|
152
171
|
*
|
|
@@ -264,7 +283,7 @@ export declare interface AllowListValidatorConfig extends ValidatorOptions {
|
|
|
264
283
|
*/
|
|
265
284
|
export declare function documentOrderComparator<T extends Node>(a?: T | null, b?: T | null): number;
|
|
266
285
|
|
|
267
|
-
declare namespace DomUtils {
|
|
286
|
+
export declare namespace DomUtils {
|
|
268
287
|
export {
|
|
269
288
|
addFocusListener,
|
|
270
289
|
documentOrderComparator,
|
|
@@ -289,7 +308,6 @@ export declare interface AllowListValidatorConfig extends ValidatorOptions {
|
|
|
289
308
|
scrollTo_2 as scrollTo
|
|
290
309
|
}
|
|
291
310
|
}
|
|
292
|
-
export { DomUtils }
|
|
293
311
|
|
|
294
312
|
/**
|
|
295
313
|
* @public
|
|
@@ -613,6 +631,17 @@ export declare interface AllowListValidatorConfig extends ValidatorOptions {
|
|
|
613
631
|
*/
|
|
614
632
|
export declare function isVisibleInViewport(element: Element): boolean;
|
|
615
633
|
|
|
634
|
+
/**
|
|
635
|
+
* Joins two path segments.
|
|
636
|
+
*
|
|
637
|
+
* We use generic constraints (`extends ValidKey`) here instead of conditional
|
|
638
|
+
* checks to keep it clean. If K or P is not a string/number, TS will error.
|
|
639
|
+
*
|
|
640
|
+
* @public
|
|
641
|
+
* @since v6.38.0
|
|
642
|
+
*/
|
|
643
|
+
export declare type Join<K extends ValidKey, P extends ValidKey> = `${K}.${P}`;
|
|
644
|
+
|
|
616
645
|
/**
|
|
617
646
|
* @public
|
|
618
647
|
*/
|
|
@@ -658,6 +687,20 @@ export declare interface AllowListValidatorConfig extends ValidatorOptions {
|
|
|
658
687
|
constructor(message?: string);
|
|
659
688
|
}
|
|
660
689
|
|
|
690
|
+
/**
|
|
691
|
+
* Recursively generates a union of all dot-notation paths for object `T`.
|
|
692
|
+
*
|
|
693
|
+
* It uses `PathMap` to calculate paths for properties and then extracts
|
|
694
|
+
* the values using `[keyof T]`.
|
|
695
|
+
*
|
|
696
|
+
* @public
|
|
697
|
+
* @since v6.38.0
|
|
698
|
+
* @typeParam T - The object or array to inspect.
|
|
699
|
+
* @typeParam Depth - The maximum recursion depth (defaults to 6).
|
|
700
|
+
* @returns A union of string paths (e.g., `"user" | "user.name"`).
|
|
701
|
+
*/
|
|
702
|
+
export declare type NestedKeys<T, Depth extends number = 6> = [Depth] extends [never] ? never : T extends object ? PathMap<T, Depth>[keyof T & ValidKey] : never;
|
|
703
|
+
|
|
661
704
|
/**
|
|
662
705
|
* @public
|
|
663
706
|
*/
|
|
@@ -734,6 +777,25 @@ export declare interface AllowListValidatorConfig extends ValidatorOptions {
|
|
|
734
777
|
*/
|
|
735
778
|
export declare function parsePostalCode(value: string): PostalCodeString | undefined;
|
|
736
779
|
|
|
780
|
+
/**
|
|
781
|
+
* Internal helper: "Flattens" the object one level deep.
|
|
782
|
+
*
|
|
783
|
+
* This generates a mapped type where the keys are the property names,
|
|
784
|
+
* and the values are the calculated paths (current key + nested paths).
|
|
785
|
+
*
|
|
786
|
+
* @example
|
|
787
|
+
* ```ts
|
|
788
|
+
* // Input: { user: { name: string } }
|
|
789
|
+
* // Output: { user: "user" | "user.name" }
|
|
790
|
+
* ```
|
|
791
|
+
*
|
|
792
|
+
* @public
|
|
793
|
+
* @since v6.38.0
|
|
794
|
+
*/
|
|
795
|
+
export declare type PathMap<T, Depth extends number> = {
|
|
796
|
+
[K in keyof T & ValidKey]: T[K] extends object ? `${K}` | Join<K, NestedKeys<T[K], Prev<Depth>>> : `${K}`;
|
|
797
|
+
};
|
|
798
|
+
|
|
737
799
|
/**
|
|
738
800
|
* Describes the event that is dispatched during input if no instant validation.
|
|
739
801
|
*
|
|
@@ -809,6 +871,14 @@ export declare interface AllowListValidatorConfig extends ValidatorOptions {
|
|
|
809
871
|
*/
|
|
810
872
|
export declare type PostalCodeString = string;
|
|
811
873
|
|
|
874
|
+
/**
|
|
875
|
+
* Computes `N - 1` at the type level.
|
|
876
|
+
*
|
|
877
|
+
* @public
|
|
878
|
+
* @since v6.38.0
|
|
879
|
+
*/
|
|
880
|
+
export declare type Prev<N extends number> = BuildDepth<N> extends [...infer R, unknown] ? R["length"] : never;
|
|
881
|
+
|
|
812
882
|
/**
|
|
813
883
|
* Save current active element focus on the stack and set focus on element
|
|
814
884
|
*
|
|
@@ -824,6 +894,18 @@ export declare interface AllowListValidatorConfig extends ValidatorOptions {
|
|
|
824
894
|
*/
|
|
825
895
|
export declare function removeFocusListener(elements: HTMLElement[], listener: ((event: Event) => unknown) | (() => unknown)): void;
|
|
826
896
|
|
|
897
|
+
/**
|
|
898
|
+
* Resolves the valid translation keys.
|
|
899
|
+
* If the consumer has defined `Keys` in the registry, use that.
|
|
900
|
+
* Otherwise, fallback to `string` (loose typing).
|
|
901
|
+
*
|
|
902
|
+
* @public
|
|
903
|
+
* @since v6.38.0
|
|
904
|
+
*/
|
|
905
|
+
export declare type ResolveTranslationKey = CustomTranslationRegistry extends {
|
|
906
|
+
Keys: infer K;
|
|
907
|
+
} ? K : string;
|
|
908
|
+
|
|
827
909
|
/**
|
|
828
910
|
* Restore focus to a previous element. Use this in combination with {@link saveFocus}
|
|
829
911
|
*
|
|
@@ -955,8 +1037,54 @@ export declare interface AllowListValidatorConfig extends ValidatorOptions {
|
|
|
955
1037
|
|
|
956
1038
|
/**
|
|
957
1039
|
* @public
|
|
1040
|
+
* @typeParam Key - The valid translation keys. Defaults to `string` for loose typing,
|
|
1041
|
+
* but can be set to a specific union of strings (e.g., via `NestedKeys<Schema>`)
|
|
1042
|
+
* to enforce strict key validation and autocompletion.
|
|
958
1043
|
*/
|
|
959
|
-
export declare
|
|
1044
|
+
export declare interface TranslateFunction<Key = ResolveTranslationKey> {
|
|
1045
|
+
/**
|
|
1046
|
+
* Returns the translation for the key.
|
|
1047
|
+
*
|
|
1048
|
+
* @param key - The translation key.
|
|
1049
|
+
*/
|
|
1050
|
+
(key: Key): string;
|
|
1051
|
+
/**
|
|
1052
|
+
* Returns the translation for the key or the default value if no
|
|
1053
|
+
* translation exists.
|
|
1054
|
+
*
|
|
1055
|
+
* @param key - The translation key.
|
|
1056
|
+
* @param defaultValue - The default value.
|
|
1057
|
+
*/
|
|
1058
|
+
(key: Key, defaultValue: string): string;
|
|
1059
|
+
/**
|
|
1060
|
+
* Returns the translation for the key. The translation is interpolated
|
|
1061
|
+
* with the given arguments.
|
|
1062
|
+
*
|
|
1063
|
+
* @param key - The translation key.
|
|
1064
|
+
* @param args - The interpolation arguments.
|
|
1065
|
+
*/
|
|
1066
|
+
(key: Key, args: Record<string, unknown>): string;
|
|
1067
|
+
/**
|
|
1068
|
+
* Returns the translation for the key or the default value if no
|
|
1069
|
+
* translation exists. The translation is interpolated with the given
|
|
1070
|
+
* arguments.
|
|
1071
|
+
*
|
|
1072
|
+
* @param key - The translation key.
|
|
1073
|
+
* @param defaultValue - The default value.
|
|
1074
|
+
* @param args - The interpolation arguments.
|
|
1075
|
+
*/
|
|
1076
|
+
(key: Key, defaultValue: string, args: Record<string, unknown>): string;
|
|
1077
|
+
/**
|
|
1078
|
+
* Returns the translation for the key or the default value if no
|
|
1079
|
+
* translation exists. The translation is interpolated with the given
|
|
1080
|
+
* arguments.
|
|
1081
|
+
*
|
|
1082
|
+
* @param key - The translation key.
|
|
1083
|
+
* @param defaultValue - The default value.
|
|
1084
|
+
* @param args - The interpolation arguments.
|
|
1085
|
+
*/
|
|
1086
|
+
(key: Key, defaultValue?: string | Record<string, unknown>, args?: Record<string, unknown>): string;
|
|
1087
|
+
}
|
|
960
1088
|
|
|
961
1089
|
/**
|
|
962
1090
|
* @public
|
|
@@ -1380,6 +1508,16 @@ export declare interface AllowListValidatorConfig extends ValidatorOptions {
|
|
|
1380
1508
|
*/
|
|
1381
1509
|
export declare type ValidityNativeEvent = "input" | "change" | "blur" | "validate";
|
|
1382
1510
|
|
|
1511
|
+
/**
|
|
1512
|
+
* Helper type: aliases valid keys to strictly string.
|
|
1513
|
+
* This filters out `symbol`, which cannot be used in template literals.
|
|
1514
|
+
* Only allows "string-key": "value" pairs
|
|
1515
|
+
*
|
|
1516
|
+
* @public
|
|
1517
|
+
* @since v6.38.0
|
|
1518
|
+
*/
|
|
1519
|
+
export declare type ValidKey = string;
|
|
1520
|
+
|
|
1383
1521
|
/**
|
|
1384
1522
|
* @public
|
|
1385
1523
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fkui/logic",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.39.0",
|
|
4
4
|
"description": "Logic",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"fkui",
|
|
@@ -61,11 +61,11 @@
|
|
|
61
61
|
"watch": "rollup --config --watch"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
|
-
"@fkui/date": "^6.
|
|
64
|
+
"@fkui/date": "^6.39.0"
|
|
65
65
|
},
|
|
66
66
|
"engines": {
|
|
67
67
|
"node": ">= 20",
|
|
68
68
|
"npm": ">= 7"
|
|
69
69
|
},
|
|
70
|
-
"gitHead": "
|
|
70
|
+
"gitHead": "dcb4ae0482dae1d80806b45900c8b80771de7372"
|
|
71
71
|
}
|