@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 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
  }
@@ -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
- validatableElements.forEach((element) => {
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.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 {
@@ -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
  }
@@ -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
- validatableElements.forEach((element) => {
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.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 {
@@ -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
  /**
@@ -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 type TranslateFunction = (key: string, defaultValueOrArgs?: string | Record<string, unknown>, args?: Record<string, unknown>) => string;
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
  */
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.56.3"
8
+ "packageVersion": "7.57.6"
9
9
  }
10
10
  ]
11
11
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fkui/logic",
3
- "version": "6.37.0",
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.37.0"
64
+ "@fkui/date": "^6.39.0"
65
65
  },
66
66
  "engines": {
67
67
  "node": ">= 20",
68
68
  "npm": ">= 7"
69
69
  },
70
- "gitHead": "15bcc047ba64657946b3e429cbf68abae064ebcc"
70
+ "gitHead": "dcb4ae0482dae1d80806b45900c8b80771de7372"
71
71
  }