@fkui/logic 6.38.0 → 6.40.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 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
- .reverse()
2175
- .forEach((numChar, index) => {
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).replace(/-/g, "");
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 = /[- .,]+/g;
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.replace(BANK_ACCOUNT_NUMBER_TRIM_REGEXP, "");
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}([-\s]?\d)?$/;
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.substring(0, 4)}-${value.substring(4, 5)}`
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.substring(0, 4);
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.replace(/\s+/g, "");
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.substring(0, 2),
3036
- nowYear: nowIso.substring(2, 4),
3037
- nowMonthDay: nowIso.substring(5, 7) + nowIso.substring(8, 10),
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>[-+])?(?<check>\d{4})$/;
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.substring(0, 4));
3138
+ const year = Number(value.slice(0, 4));
3136
3139
  if (currentYear - year >= 100) {
3137
- return value.substring(2).replace("-", "+");
3140
+ return value.slice(2).replace("-", "+");
3138
3141
  }
3139
- return value.substring(2);
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.replace(/ /g, "");
3171
- value = value.replace(/\D/g, "");
3173
+ value = value.replaceAll(" ", "");
3174
+ value = value.replaceAll(/\D/g, "");
3172
3175
  if (!PLUSGIRO_REGEXP.test(value) ||
3173
- !testLuhnChecksum(value.replace(/\D/g, ""))) {
3176
+ !testLuhnChecksum(value.replaceAll(/\D/g, ""))) {
3174
3177
  return undefined;
3175
3178
  }
3176
3179
  if (hyphenShouldBeAdded(value)) {
3177
- value = `${value.substring(0, value.length - 1)}-${value[value.length - 1]}`;
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.substring(value.length - startOffset, value.length);
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.substring(Math.max(i - step, 0), i)} ${formattedString}`;
3187
+ formattedString = `${value.slice(Math.max(i - step, 0), i)} ${formattedString}`;
3184
3188
  }
3185
3189
  if (value.length === 9) {
3186
- formattedString = value.substring(0, 1) + formattedString;
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.getElementById(id) === null) {
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 (typeof found !== "undefined") {
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.replace(
3853
+ return defaultValue.replaceAll(
3850
3854
  /* eslint-disable-next-line sonarjs/slow-regex -- technical debt */
3851
- /{{\s*([^\s]+)\s*}}/g, (match, key) => {
3855
+ /{{\s*(\S+)\s*}}/g, (match, key) => {
3852
3856
  return String(args[key]) || match;
3853
3857
  });
3854
3858
  }
@@ -3867,83 +3871,6 @@ const TranslationService =
3867
3871
  /* @__PURE__ */
3868
3872
  new TranslationServiceImpl();
3869
3873
 
3870
- /**
3871
- * @internal
3872
- */
3873
- function createFieldsetValidator(element, validationService) {
3874
- /* eslint-disable-next-line no-new, sonarjs/constructor-for-side-effects --
3875
- * technical debt, this should be refactored as to not rely of side-effects
3876
- * of the constructor */
3877
- new FieldsetValidationHandler(element, validationService);
3878
- }
3879
- class FieldsetValidationHandler {
3880
- hasDocumentListener = false;
3881
- documentFocusInRef = undefined;
3882
- element;
3883
- validationService;
3884
- constructor(element, validationService) {
3885
- Object.assign(this);
3886
- this.element = element;
3887
- this.validationService = validationService;
3888
- element.addEventListener("focusin", (event) => {
3889
- this.onFocusIn(event);
3890
- });
3891
- // Handle checking of input by using keyboard (space)
3892
- element.addEventListener("change", this.documentFocusIn.bind(this));
3893
- Array.from(this.element.querySelectorAll("input[type='checkbox'], input[type='radio']"))
3894
- .filter((childElement) => childElement.closest("fieldset") === element)
3895
- .forEach((childElement) => {
3896
- childElement.setAttribute("required", "");
3897
- });
3898
- }
3899
- hasFocusableTarget(target) {
3900
- return target
3901
- ? Array.from(this.element.querySelectorAll("input, label")).some((element) => element === target)
3902
- : false;
3903
- }
3904
- onFocusIn(event) {
3905
- // IE11 (not Chrome / FF) trigger focusin-event on legends and other elements inside the fieldset
3906
- // So we need to check the event target, if it's focusable.
3907
- if (this.hasFocusableTarget(event.target) &&
3908
- !this.hasDocumentListener) {
3909
- this.documentFocusInRef = this.documentFocusIn.bind(this);
3910
- document.addEventListener("focusin", this.documentFocusInRef);
3911
- document.addEventListener("click", this.documentFocusInRef);
3912
- this.hasDocumentListener = true;
3913
- }
3914
- }
3915
- documentFocusIn(event) {
3916
- this.validationService.setTouched(this.element);
3917
- const children = Array.from(this.element.querySelectorAll("input"));
3918
- for (const childElement of children) {
3919
- this.validationService.setTouched(childElement);
3920
- }
3921
- if (!this.hasFocusableTarget(event.target)) {
3922
- this.removeEventListeners();
3923
- }
3924
- else if (event.target.checked) {
3925
- this.validateFieldsetAndChildren();
3926
- }
3927
- }
3928
- removeEventListeners() {
3929
- if (this.hasDocumentListener && this.documentFocusInRef) {
3930
- document.removeEventListener("focusin", this.documentFocusInRef);
3931
- document.removeEventListener("click", this.documentFocusInRef);
3932
- this.hasDocumentListener = false;
3933
- this.validateFieldsetAndChildren();
3934
- }
3935
- }
3936
- validateFieldsetAndChildren() {
3937
- const validatableElements = document.querySelectorAll(`fieldset#${this.element.id}, #${this.element.id} input[type='checkbox'], #${this.element.id} input[type='radio']`);
3938
- validatableElements.forEach((element) => {
3939
- if (element.id) {
3940
- /* eslint-disable-next-line @typescript-eslint/no-floating-promises -- technical debt */
3941
- this.validationService.validateElement(element.id);
3942
- }
3943
- });
3944
- }
3945
- }
3946
-
3947
3874
  /**
3948
3875
  * Builder to create validation error message map.
3949
3876
  *
@@ -4067,6 +3994,84 @@ function getErrorMessages() {
4067
3994
  .build();
4068
3995
  }
4069
3996
 
3997
+ /**
3998
+ * @internal
3999
+ */
4000
+ function createFieldsetValidator(element, validationService) {
4001
+ /* eslint-disable-next-line no-new, sonarjs/constructor-for-side-effects --
4002
+ * technical debt, this should be refactored as to not rely of side-effects
4003
+ * of the constructor */
4004
+ new FieldsetValidationHandler(element, validationService);
4005
+ }
4006
+ class FieldsetValidationHandler {
4007
+ hasDocumentListener = false;
4008
+ documentFocusInRef = undefined;
4009
+ element;
4010
+ validationService;
4011
+ constructor(element, validationService) {
4012
+ Object.assign(this);
4013
+ this.element = element;
4014
+ this.validationService = validationService;
4015
+ element.addEventListener("focusin", (event) => {
4016
+ this.onFocusIn(event);
4017
+ });
4018
+ // Handle checking of input by using keyboard (space)
4019
+ element.addEventListener("change", this.documentFocusIn.bind(this));
4020
+ Array.from(this.element.querySelectorAll("input[type='checkbox'], input[type='radio']"))
4021
+ .filter((childElement) => childElement.closest("fieldset") === element)
4022
+ /* eslint-disable-next-line unicorn/no-array-for-each -- technical debt */
4023
+ .forEach((childElement) => {
4024
+ childElement.setAttribute("required", "");
4025
+ });
4026
+ }
4027
+ hasFocusableTarget(target) {
4028
+ return target
4029
+ ? Array.from(this.element.querySelectorAll("input, label")).some((element) => element === target)
4030
+ : false;
4031
+ }
4032
+ onFocusIn(event) {
4033
+ // IE11 (not Chrome / FF) trigger focusin-event on legends and other elements inside the fieldset
4034
+ // So we need to check the event target, if it's focusable.
4035
+ if (this.hasFocusableTarget(event.target) &&
4036
+ !this.hasDocumentListener) {
4037
+ this.documentFocusInRef = this.documentFocusIn.bind(this);
4038
+ document.addEventListener("focusin", this.documentFocusInRef);
4039
+ document.addEventListener("click", this.documentFocusInRef);
4040
+ this.hasDocumentListener = true;
4041
+ }
4042
+ }
4043
+ documentFocusIn(event) {
4044
+ this.validationService.setTouched(this.element);
4045
+ const children = Array.from(this.element.querySelectorAll("input"));
4046
+ for (const childElement of children) {
4047
+ this.validationService.setTouched(childElement);
4048
+ }
4049
+ if (!this.hasFocusableTarget(event.target)) {
4050
+ this.removeEventListeners();
4051
+ }
4052
+ else if (event.target.checked) {
4053
+ this.validateFieldsetAndChildren();
4054
+ }
4055
+ }
4056
+ removeEventListeners() {
4057
+ if (this.hasDocumentListener && this.documentFocusInRef) {
4058
+ document.removeEventListener("focusin", this.documentFocusInRef);
4059
+ document.removeEventListener("click", this.documentFocusInRef);
4060
+ this.hasDocumentListener = false;
4061
+ this.validateFieldsetAndChildren();
4062
+ }
4063
+ }
4064
+ validateFieldsetAndChildren() {
4065
+ const validatableElements = document.querySelectorAll(`fieldset#${this.element.id}, #${this.element.id} input[type='checkbox'], #${this.element.id} input[type='radio']`);
4066
+ for (const element of validatableElements) {
4067
+ if (element.id) {
4068
+ /* eslint-disable-next-line @typescript-eslint/no-floating-promises -- technical debt */
4069
+ this.validationService.validateElement(element.id);
4070
+ }
4071
+ }
4072
+ }
4073
+ }
4074
+
4070
4075
  /**
4071
4076
  * Returns validation error message candidates in prioritized order.
4072
4077
  *
@@ -4339,7 +4344,7 @@ class ValidationServiceImpl {
4339
4344
  };
4340
4345
  }
4341
4346
  if (typeof src === "string") {
4342
- const element = document.getElementById(src);
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.getElementById(element);
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.getElementById(parent);
4478
+ const element = document.querySelector(`#${parent}`);
4474
4479
  return this.getValidatableElements(element);
4475
4480
  }
4476
4481
  else {
@@ -4625,7 +4630,7 @@ class ValidationServiceImpl {
4625
4630
  }
4626
4631
  getErrorMessage(validatorName, validators, validatorConfigs, elementType) {
4627
4632
  const validatorConfig = validatorConfigs[validatorName];
4628
- if (validatorConfig && validatorConfig.errorMessage) {
4633
+ if (validatorConfig?.errorMessage) {
4629
4634
  return validatorConfig.errorMessage;
4630
4635
  }
4631
4636
  const candidates = getCandidates(validatorName, validators, elementType);
@@ -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 = /^([-−]?\d+)?$/;
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
- const el = document.getElementById(config.id);
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
- return config.length ? value.length <= config.length : true;
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
- return config.length && value ? value.length >= config.length : true;
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 = /^([-+]?\d+)([,.]\d+)?$/;
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 = /^(\+?[-_/() ]*(\d[-_/() ]*?){3,17})$/;
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 = /^[a-zA-Z0-9 .,\-()\r\n?+=!:@*\xC0-\xFF]*$/;
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.removeChild(wrapper.firstChild);
5227
+ wrapper.firstChild.remove();
5220
5228
  }
5221
- wrapper.appendChild(msg);
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
- wrapper.removeChild(msg);
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.appendChild(wrapper);
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
- .reverse()
2173
- .forEach((numChar, index) => {
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).replace(/-/g, "");
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 = /[- .,]+/g;
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.replace(BANK_ACCOUNT_NUMBER_TRIM_REGEXP, "");
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}([-\s]?\d)?$/;
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.substring(0, 4)}-${value.substring(4, 5)}`
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.substring(0, 4);
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.replace(/\s+/g, "");
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.substring(0, 2),
3034
- nowYear: nowIso.substring(2, 4),
3035
- nowMonthDay: nowIso.substring(5, 7) + nowIso.substring(8, 10),
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>[-+])?(?<check>\d{4})$/;
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.substring(0, 4));
3136
+ const year = Number(value.slice(0, 4));
3134
3137
  if (currentYear - year >= 100) {
3135
- return value.substring(2).replace("-", "+");
3138
+ return value.slice(2).replace("-", "+");
3136
3139
  }
3137
- return value.substring(2);
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.replace(/ /g, "");
3169
- value = value.replace(/\D/g, "");
3171
+ value = value.replaceAll(" ", "");
3172
+ value = value.replaceAll(/\D/g, "");
3170
3173
  if (!PLUSGIRO_REGEXP.test(value) ||
3171
- !testLuhnChecksum(value.replace(/\D/g, ""))) {
3174
+ !testLuhnChecksum(value.replaceAll(/\D/g, ""))) {
3172
3175
  return undefined;
3173
3176
  }
3174
3177
  if (hyphenShouldBeAdded(value)) {
3175
- value = `${value.substring(0, value.length - 1)}-${value[value.length - 1]}`;
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.substring(value.length - startOffset, value.length);
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.substring(Math.max(i - step, 0), i)} ${formattedString}`;
3185
+ formattedString = `${value.slice(Math.max(i - step, 0), i)} ${formattedString}`;
3182
3186
  }
3183
3187
  if (value.length === 9) {
3184
- formattedString = value.substring(0, 1) + formattedString;
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.getElementById(id) === null) {
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 (typeof found !== "undefined") {
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.replace(
3851
+ return defaultValue.replaceAll(
3848
3852
  /* eslint-disable-next-line sonarjs/slow-regex -- technical debt */
3849
- /{{\s*([^\s]+)\s*}}/g, (match, key) => {
3853
+ /{{\s*(\S+)\s*}}/g, (match, key) => {
3850
3854
  return String(args[key]) || match;
3851
3855
  });
3852
3856
  }
@@ -3865,83 +3869,6 @@ const TranslationService =
3865
3869
  /* @__PURE__ */
3866
3870
  new TranslationServiceImpl();
3867
3871
 
3868
- /**
3869
- * @internal
3870
- */
3871
- function createFieldsetValidator(element, validationService) {
3872
- /* eslint-disable-next-line no-new, sonarjs/constructor-for-side-effects --
3873
- * technical debt, this should be refactored as to not rely of side-effects
3874
- * of the constructor */
3875
- new FieldsetValidationHandler(element, validationService);
3876
- }
3877
- class FieldsetValidationHandler {
3878
- hasDocumentListener = false;
3879
- documentFocusInRef = undefined;
3880
- element;
3881
- validationService;
3882
- constructor(element, validationService) {
3883
- Object.assign(this);
3884
- this.element = element;
3885
- this.validationService = validationService;
3886
- element.addEventListener("focusin", (event) => {
3887
- this.onFocusIn(event);
3888
- });
3889
- // Handle checking of input by using keyboard (space)
3890
- element.addEventListener("change", this.documentFocusIn.bind(this));
3891
- Array.from(this.element.querySelectorAll("input[type='checkbox'], input[type='radio']"))
3892
- .filter((childElement) => childElement.closest("fieldset") === element)
3893
- .forEach((childElement) => {
3894
- childElement.setAttribute("required", "");
3895
- });
3896
- }
3897
- hasFocusableTarget(target) {
3898
- return target
3899
- ? Array.from(this.element.querySelectorAll("input, label")).some((element) => element === target)
3900
- : false;
3901
- }
3902
- onFocusIn(event) {
3903
- // IE11 (not Chrome / FF) trigger focusin-event on legends and other elements inside the fieldset
3904
- // So we need to check the event target, if it's focusable.
3905
- if (this.hasFocusableTarget(event.target) &&
3906
- !this.hasDocumentListener) {
3907
- this.documentFocusInRef = this.documentFocusIn.bind(this);
3908
- document.addEventListener("focusin", this.documentFocusInRef);
3909
- document.addEventListener("click", this.documentFocusInRef);
3910
- this.hasDocumentListener = true;
3911
- }
3912
- }
3913
- documentFocusIn(event) {
3914
- this.validationService.setTouched(this.element);
3915
- const children = Array.from(this.element.querySelectorAll("input"));
3916
- for (const childElement of children) {
3917
- this.validationService.setTouched(childElement);
3918
- }
3919
- if (!this.hasFocusableTarget(event.target)) {
3920
- this.removeEventListeners();
3921
- }
3922
- else if (event.target.checked) {
3923
- this.validateFieldsetAndChildren();
3924
- }
3925
- }
3926
- removeEventListeners() {
3927
- if (this.hasDocumentListener && this.documentFocusInRef) {
3928
- document.removeEventListener("focusin", this.documentFocusInRef);
3929
- document.removeEventListener("click", this.documentFocusInRef);
3930
- this.hasDocumentListener = false;
3931
- this.validateFieldsetAndChildren();
3932
- }
3933
- }
3934
- validateFieldsetAndChildren() {
3935
- const validatableElements = document.querySelectorAll(`fieldset#${this.element.id}, #${this.element.id} input[type='checkbox'], #${this.element.id} input[type='radio']`);
3936
- validatableElements.forEach((element) => {
3937
- if (element.id) {
3938
- /* eslint-disable-next-line @typescript-eslint/no-floating-promises -- technical debt */
3939
- this.validationService.validateElement(element.id);
3940
- }
3941
- });
3942
- }
3943
- }
3944
-
3945
3872
  /**
3946
3873
  * Builder to create validation error message map.
3947
3874
  *
@@ -4065,6 +3992,84 @@ function getErrorMessages() {
4065
3992
  .build();
4066
3993
  }
4067
3994
 
3995
+ /**
3996
+ * @internal
3997
+ */
3998
+ function createFieldsetValidator(element, validationService) {
3999
+ /* eslint-disable-next-line no-new, sonarjs/constructor-for-side-effects --
4000
+ * technical debt, this should be refactored as to not rely of side-effects
4001
+ * of the constructor */
4002
+ new FieldsetValidationHandler(element, validationService);
4003
+ }
4004
+ class FieldsetValidationHandler {
4005
+ hasDocumentListener = false;
4006
+ documentFocusInRef = undefined;
4007
+ element;
4008
+ validationService;
4009
+ constructor(element, validationService) {
4010
+ Object.assign(this);
4011
+ this.element = element;
4012
+ this.validationService = validationService;
4013
+ element.addEventListener("focusin", (event) => {
4014
+ this.onFocusIn(event);
4015
+ });
4016
+ // Handle checking of input by using keyboard (space)
4017
+ element.addEventListener("change", this.documentFocusIn.bind(this));
4018
+ Array.from(this.element.querySelectorAll("input[type='checkbox'], input[type='radio']"))
4019
+ .filter((childElement) => childElement.closest("fieldset") === element)
4020
+ /* eslint-disable-next-line unicorn/no-array-for-each -- technical debt */
4021
+ .forEach((childElement) => {
4022
+ childElement.setAttribute("required", "");
4023
+ });
4024
+ }
4025
+ hasFocusableTarget(target) {
4026
+ return target
4027
+ ? Array.from(this.element.querySelectorAll("input, label")).some((element) => element === target)
4028
+ : false;
4029
+ }
4030
+ onFocusIn(event) {
4031
+ // IE11 (not Chrome / FF) trigger focusin-event on legends and other elements inside the fieldset
4032
+ // So we need to check the event target, if it's focusable.
4033
+ if (this.hasFocusableTarget(event.target) &&
4034
+ !this.hasDocumentListener) {
4035
+ this.documentFocusInRef = this.documentFocusIn.bind(this);
4036
+ document.addEventListener("focusin", this.documentFocusInRef);
4037
+ document.addEventListener("click", this.documentFocusInRef);
4038
+ this.hasDocumentListener = true;
4039
+ }
4040
+ }
4041
+ documentFocusIn(event) {
4042
+ this.validationService.setTouched(this.element);
4043
+ const children = Array.from(this.element.querySelectorAll("input"));
4044
+ for (const childElement of children) {
4045
+ this.validationService.setTouched(childElement);
4046
+ }
4047
+ if (!this.hasFocusableTarget(event.target)) {
4048
+ this.removeEventListeners();
4049
+ }
4050
+ else if (event.target.checked) {
4051
+ this.validateFieldsetAndChildren();
4052
+ }
4053
+ }
4054
+ removeEventListeners() {
4055
+ if (this.hasDocumentListener && this.documentFocusInRef) {
4056
+ document.removeEventListener("focusin", this.documentFocusInRef);
4057
+ document.removeEventListener("click", this.documentFocusInRef);
4058
+ this.hasDocumentListener = false;
4059
+ this.validateFieldsetAndChildren();
4060
+ }
4061
+ }
4062
+ validateFieldsetAndChildren() {
4063
+ const validatableElements = document.querySelectorAll(`fieldset#${this.element.id}, #${this.element.id} input[type='checkbox'], #${this.element.id} input[type='radio']`);
4064
+ for (const element of validatableElements) {
4065
+ if (element.id) {
4066
+ /* eslint-disable-next-line @typescript-eslint/no-floating-promises -- technical debt */
4067
+ this.validationService.validateElement(element.id);
4068
+ }
4069
+ }
4070
+ }
4071
+ }
4072
+
4068
4073
  /**
4069
4074
  * Returns validation error message candidates in prioritized order.
4070
4075
  *
@@ -4337,7 +4342,7 @@ class ValidationServiceImpl {
4337
4342
  };
4338
4343
  }
4339
4344
  if (typeof src === "string") {
4340
- const element = document.getElementById(src);
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.getElementById(element);
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.getElementById(parent);
4476
+ const element = document.querySelector(`#${parent}`);
4472
4477
  return this.getValidatableElements(element);
4473
4478
  }
4474
4479
  else {
@@ -4623,7 +4628,7 @@ class ValidationServiceImpl {
4623
4628
  }
4624
4629
  getErrorMessage(validatorName, validators, validatorConfigs, elementType) {
4625
4630
  const validatorConfig = validatorConfigs[validatorName];
4626
- if (validatorConfig && validatorConfig.errorMessage) {
4631
+ if (validatorConfig?.errorMessage) {
4627
4632
  return validatorConfig.errorMessage;
4628
4633
  }
4629
4634
  const candidates = getCandidates(validatorName, validators, elementType);
@@ -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 = /^([-−]?\d+)?$/;
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
- const el = document.getElementById(config.id);
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
- return config.length ? value.length <= config.length : true;
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
- return config.length && value ? value.length >= config.length : true;
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 = /^([-+]?\d+)([,.]\d+)?$/;
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 = /^(\+?[-_/() ]*(\d[-_/() ]*?){3,17})$/;
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 = /^[a-zA-Z0-9 .,\-()\r\n?+=!:@*\xC0-\xFF]*$/;
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.removeChild(wrapper.firstChild);
5225
+ wrapper.firstChild.remove();
5218
5226
  }
5219
- wrapper.appendChild(msg);
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
- wrapper.removeChild(msg);
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.appendChild(wrapper);
5249
+ document.body.append(wrapper);
5242
5250
  }
5243
5251
  }
5244
5252
  /**
@@ -283,7 +283,7 @@ export declare interface AllowListValidatorConfig extends ValidatorOptions {
283
283
  */
284
284
  export declare function documentOrderComparator<T extends Node>(a?: T | null, b?: T | null): number;
285
285
 
286
- declare namespace DomUtils {
286
+ export declare namespace DomUtils {
287
287
  export {
288
288
  addFocusListener,
289
289
  documentOrderComparator,
@@ -308,7 +308,6 @@ export declare interface AllowListValidatorConfig extends ValidatorOptions {
308
308
  scrollTo_2 as scrollTo
309
309
  }
310
310
  }
311
- export { DomUtils }
312
311
 
313
312
  /**
314
313
  * @public
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.57.3"
8
+ "packageVersion": "7.57.7"
9
9
  }
10
10
  ]
11
11
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fkui/logic",
3
- "version": "6.38.0",
3
+ "version": "6.40.0",
4
4
  "description": "Logic",
5
5
  "keywords": [
6
6
  "fkui",
@@ -23,18 +23,18 @@
23
23
  "exports": {
24
24
  ".": {
25
25
  "types": "./lib/types/index.d.ts",
26
- "require": "./lib/cjs/index.js",
27
- "import": "./lib/esm/index.js"
26
+ "import": "./lib/esm/index.js",
27
+ "require": "./lib/cjs/index.js"
28
28
  },
29
29
  "./polyfills": {
30
30
  "types": "./lib/types/polyfills.d.ts",
31
- "require": "./lib/cjs/polyfills.js",
32
- "import": "./lib/esm/polyfills.js"
31
+ "import": "./lib/esm/polyfills.js",
32
+ "require": "./lib/cjs/polyfills.js"
33
33
  },
34
34
  "./lib/polyfills": {
35
35
  "types": "./lib/types/polyfills.d.ts",
36
- "require": "./lib/cjs/polyfills.js",
37
- "import": "./lib/esm/polyfills.js"
36
+ "import": "./lib/esm/polyfills.js",
37
+ "require": "./lib/cjs/polyfills.js"
38
38
  }
39
39
  },
40
40
  "main": "lib/cjs/index.js",
@@ -61,11 +61,11 @@
61
61
  "watch": "rollup --config --watch"
62
62
  },
63
63
  "peerDependencies": {
64
- "@fkui/date": "^6.38.0"
64
+ "@fkui/date": "^6.40.0"
65
65
  },
66
66
  "engines": {
67
67
  "node": ">= 20",
68
68
  "npm": ">= 7"
69
69
  },
70
- "gitHead": "ea8e50d8567159581a628106e93ac0e7c1d43a1b"
70
+ "gitHead": "15991b990613b7547983562b965c2d0f11f958c7"
71
71
  }