@etsoo/shared 1.2.80 → 1.2.82

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.
Files changed (40) hide show
  1. package/.github/workflows/main.yml +5 -3
  2. package/__tests__/Utils.ts +10 -0
  3. package/lib/cjs/DateUtils.js +1 -1
  4. package/lib/cjs/DomUtils.js +4 -4
  5. package/lib/cjs/NumberUtils.js +4 -4
  6. package/lib/cjs/StorageUtils.js +2 -2
  7. package/lib/cjs/Utils.d.ts +8 -0
  8. package/lib/cjs/Utils.js +59 -2
  9. package/lib/cjs/node/NodeStorage.js +5 -6
  10. package/lib/cjs/storage/IStorage.d.ts +1 -1
  11. package/lib/cjs/storage/WindowStorage.d.ts +1 -1
  12. package/lib/cjs/test/MockDOMRect.js +8 -0
  13. package/lib/cjs/test/MockResizeObserver.js +2 -2
  14. package/lib/cjs/types/ContentDisposition.js +3 -0
  15. package/lib/cjs/types/DataError.js +4 -0
  16. package/lib/cjs/types/EColor.js +4 -0
  17. package/lib/cjs/types/EHistory.js +7 -6
  18. package/lib/cjs/types/EventClass.js +7 -5
  19. package/lib/mjs/DateUtils.js +1 -1
  20. package/lib/mjs/DomUtils.js +4 -4
  21. package/lib/mjs/NumberUtils.js +4 -4
  22. package/lib/mjs/StorageUtils.js +2 -2
  23. package/lib/mjs/Utils.d.ts +8 -0
  24. package/lib/mjs/Utils.js +59 -2
  25. package/lib/mjs/node/NodeStorage.js +5 -6
  26. package/lib/mjs/storage/IStorage.d.ts +1 -1
  27. package/lib/mjs/storage/WindowStorage.d.ts +1 -1
  28. package/lib/mjs/test/MockDOMRect.js +8 -0
  29. package/lib/mjs/test/MockResizeObserver.js +2 -2
  30. package/lib/mjs/types/ContentDisposition.js +3 -0
  31. package/lib/mjs/types/DataError.js +4 -0
  32. package/lib/mjs/types/EColor.js +4 -0
  33. package/lib/mjs/types/EHistory.js +7 -6
  34. package/lib/mjs/types/EventClass.js +7 -5
  35. package/package.json +6 -6
  36. package/src/Utils.ts +67 -3
  37. package/src/storage/IStorage.ts +1 -1
  38. package/src/storage/WindowStorage.ts +1 -1
  39. package/tsconfig.cjs.json +3 -1
  40. package/tsconfig.json +4 -2
@@ -11,6 +11,10 @@ on:
11
11
  # release:
12
12
  # types: [created]
13
13
 
14
+ permissions:
15
+ id-token: write # Required for OIDC
16
+ contents: read
17
+
14
18
  jobs:
15
19
  # Publish to NPM
16
20
  publish-npm:
@@ -44,6 +48,4 @@ jobs:
44
48
 
45
49
  # Publish to npm
46
50
  # For scoped package, make it public for free service
47
- - run: npm publish --access public
48
- env:
49
- NODE_AUTH_TOKEN: ${{ secrets.ETSOONpmToken }}
51
+ - run: npm publish
@@ -328,6 +328,16 @@ test("Tests for mergeClasses", () => {
328
328
  expect(Utils.mergeClasses("a", "", "b ", undefined, "c")).toBe("a b c");
329
329
  });
330
330
 
331
+ test("Tests for formatName", () => {
332
+ expect(Utils.formatName("青岛亿速思维网络科技有限公司", 6)).toBe(
333
+ "青岛亿速思维"
334
+ );
335
+ expect(Utils.formatName("亿速思维(中国)网络科技有限公司", 6)).toBe(
336
+ "亿速思维(中国)"
337
+ );
338
+ expect(Utils.formatName("John Smith", 6)).toBe("John Smith");
339
+ });
340
+
331
341
  test("Tests for getNestedValue", () => {
332
342
  const obj = { jsonData: { photoSize: [200, 100], supportResizing: true } };
333
343
  expect(Utils.getNestedValue(obj, "jsonData.supportResizing")).toBeTruthy();
@@ -74,7 +74,7 @@ var DateUtils;
74
74
  if (parsed == null)
75
75
  return undefined;
76
76
  // Default options
77
- options ?? (options = DateUtils.DayFormat);
77
+ options ??= DateUtils.DayFormat;
78
78
  // Default options
79
79
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat
80
80
  let opt;
@@ -309,7 +309,7 @@ var DomUtils;
309
309
  * @returns Result
310
310
  */
311
311
  function isWechatClient(data) {
312
- data ?? (data = parseUserAgent());
312
+ data ??= parseUserAgent();
313
313
  if (!data)
314
314
  return false;
315
315
  return data.brands.some((item) => item.brand.toLowerCase() === "micromessenger");
@@ -497,7 +497,7 @@ var DomUtils;
497
497
  * @returns User agent data
498
498
  */
499
499
  function parseUserAgent(ua) {
500
- ua ?? (ua = globalThis.navigator.userAgent);
500
+ ua ??= globalThis.navigator.userAgent;
501
501
  if (!ua) {
502
502
  return null;
503
503
  }
@@ -583,7 +583,7 @@ var DomUtils;
583
583
  */
584
584
  function setFocus(name, container) {
585
585
  const elementName = typeof name === "string" ? name : Object.keys(name)[0];
586
- container ?? (container = document.body);
586
+ container ??= document.body;
587
587
  const element = container.querySelector(`[name="${elementName}"]`);
588
588
  if (element != null)
589
589
  element.focus();
@@ -603,7 +603,7 @@ var DomUtils;
603
603
  const errorPD = Utils_1.Utils.getResult(preventDefault, errorType) ?? true;
604
604
  window.onerror = (message, source, lineNo, colNo, error) => {
605
605
  // Default source
606
- source || (source = window.location.href);
606
+ source ||= window.location.href;
607
607
  let data;
608
608
  if (typeof message === "string") {
609
609
  data = {
@@ -43,14 +43,14 @@ var NumberUtils;
43
43
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat
44
44
  options.style = "currency";
45
45
  options.currency = currency;
46
- options.currencyDisplay ?? (options.currencyDisplay = "narrowSymbol");
46
+ options.currencyDisplay ??= "narrowSymbol";
47
47
  }
48
48
  if (isInteger) {
49
- options.minimumFractionDigits ?? (options.minimumFractionDigits = 0);
50
- options.maximumFractionDigits ?? (options.maximumFractionDigits = 0);
49
+ options.minimumFractionDigits ??= 0;
50
+ options.maximumFractionDigits ??= 0;
51
51
  }
52
52
  else
53
- options.minimumFractionDigits ?? (options.minimumFractionDigits = 2);
53
+ options.minimumFractionDigits ??= 2;
54
54
  return format(input, locale, options);
55
55
  }
56
56
  NumberUtils.formatMoney = formatMoney;
@@ -4,8 +4,8 @@ exports.StorageUtils = void 0;
4
4
  const NodeStorage_1 = require("./node/NodeStorage");
5
5
  const Utils_1 = require("./Utils");
6
6
  // Mock node
7
- globalThis.localStorage ?? (globalThis.localStorage = new NodeStorage_1.NodeStorage());
8
- globalThis.sessionStorage ?? (globalThis.sessionStorage = new NodeStorage_1.NodeStorage());
7
+ globalThis.localStorage ??= new NodeStorage_1.NodeStorage();
8
+ globalThis.sessionStorage ??= new NodeStorage_1.NodeStorage();
9
9
  /**
10
10
  * Storage utilities
11
11
  * NodeStorage needs data persistance
@@ -132,6 +132,14 @@ export declare namespace Utils {
132
132
  export function excludeAsync<T extends {
133
133
  [P in D]: IdType;
134
134
  }, D extends string = "id">(items: Promise<T[] | undefined>, field: D, ...excludedValues: T[D][]): Promise<T[] | undefined>;
135
+ /**
136
+ * Format name
137
+ * @param name Input name
138
+ * @param maxChars Max chars
139
+ * @param maxParts Max parts (optional)
140
+ * @returns Formatted name
141
+ */
142
+ export function formatName(name: string, maxChars: number, maxParts?: number): string;
135
143
  /**
136
144
  * Format inital character to lower case or upper case
137
145
  * @param input Input string
package/lib/cjs/Utils.js CHANGED
@@ -139,7 +139,7 @@ var Utils;
139
139
  */
140
140
  function addBlankItem(options, idField, labelField, blankLabel) {
141
141
  // Avoid duplicate blank items
142
- idField ?? (idField = "id");
142
+ idField ??= "id";
143
143
  if (options.length === 0 || Reflect.get(options[0], idField) !== "") {
144
144
  const blankItem = {
145
145
  [idField]: "",
@@ -207,6 +207,63 @@ var Utils;
207
207
  return exclude(result, field, ...excludedValues);
208
208
  }
209
209
  Utils.excludeAsync = excludeAsync;
210
+ /**
211
+ * Format name
212
+ * @param name Input name
213
+ * @param maxChars Max chars
214
+ * @param maxParts Max parts (optional)
215
+ * @returns Formatted name
216
+ */
217
+ function formatName(name, maxChars, maxParts) {
218
+ name = name.trim();
219
+ const parts = name.split(/\s+/);
220
+ const max = maxParts ?? Math.floor(maxChars / 3);
221
+ const effectiveMax = max < 2 ? 2 : max;
222
+ if (parts.length >= effectiveMax) {
223
+ return parts.slice(0, effectiveMax).join(" ");
224
+ }
225
+ else if (name.length > maxChars) {
226
+ let endIndex = maxChars;
227
+ const brackets = {
228
+ "(": ")",
229
+ "(": ")",
230
+ "[": "]"
231
+ };
232
+ // Count unmatched brackets for each type
233
+ for (const [start, end] of Object.entries(brackets)) {
234
+ let count = 0;
235
+ // Count opening and closing brackets in the substring
236
+ for (let i = 0; i < maxChars; i++) {
237
+ if (name[i] === start)
238
+ count++;
239
+ else if (name[i] === end)
240
+ count--;
241
+ }
242
+ if (count > 0) {
243
+ // Find matching end brackets
244
+ for (let i = maxChars; i < name.length && count > 0; i++) {
245
+ if (name[i] === start) {
246
+ count++;
247
+ }
248
+ else if (name[i] === end) {
249
+ count--;
250
+ if (count === 0) {
251
+ endIndex = i + 1;
252
+ }
253
+ }
254
+ }
255
+ if (count === 0) {
256
+ return name.substring(0, endIndex);
257
+ }
258
+ }
259
+ }
260
+ return name.substring(0, endIndex);
261
+ }
262
+ else {
263
+ return name;
264
+ }
265
+ }
266
+ Utils.formatName = formatName;
210
267
  /**
211
268
  * Format inital character to lower case or upper case
212
269
  * @param input Input string
@@ -578,7 +635,7 @@ var Utils;
578
635
  Utils.setLabels = (source, labels, reference) => {
579
636
  Object.keys(source).forEach((key) => {
580
637
  // Reference key
581
- const labelKey = reference == null ? key : reference[key] ?? key;
638
+ const labelKey = reference == null ? key : (reference[key] ?? key);
582
639
  // Label
583
640
  const label = labels[labelKey];
584
641
  if (label != null) {
@@ -6,15 +6,14 @@ exports.NodeStorage = void 0;
6
6
  * Please take care of the persistence with source property
7
7
  */
8
8
  class NodeStorage {
9
+ /**
10
+ * Storage source
11
+ */
12
+ source = [];
9
13
  /**
10
14
  * Constructor
11
15
  */
12
- constructor() {
13
- /**
14
- * Storage source
15
- */
16
- this.source = [];
17
- }
16
+ constructor() { }
18
17
  /**
19
18
  * Returns the number of key/value pairs currently present in the list
20
19
  */
@@ -63,5 +63,5 @@ export interface IStorage {
63
63
  * @param key Key name
64
64
  * @param data Data, null for removal
65
65
  */
66
- setPersistedData(key: string, data: unknown): void;
66
+ setPersistedData<T>(key: string, data: T): void;
67
67
  }
@@ -65,5 +65,5 @@ export declare class WindowStorage implements IStorage {
65
65
  * @param key Key name
66
66
  * @param data Data, null for removal
67
67
  */
68
- setPersistedData(key: string, data: unknown): void;
68
+ setPersistedData<T>(key: string, data: T): void;
69
69
  }
@@ -5,6 +5,14 @@ exports.MockDOMRect = void 0;
5
5
  * A mock implementation of DOMRect for testing purposes
6
6
  */
7
7
  class MockDOMRect {
8
+ bottom;
9
+ height;
10
+ left;
11
+ right;
12
+ top;
13
+ width;
14
+ x;
15
+ y;
8
16
  toJSON() {
9
17
  return JSON.stringify({
10
18
  bottom: this.bottom,
@@ -5,9 +5,9 @@ exports.MockResizeObserver = void 0;
5
5
  * Mock implementation of ResizeObserver for testing purposes
6
6
  */
7
7
  class MockResizeObserver {
8
+ callbacks = [];
9
+ elements = [];
8
10
  constructor(callback) {
9
- this.callbacks = [];
10
- this.elements = [];
11
11
  this.callbacks.push(callback);
12
12
  }
13
13
  observe(element) {
@@ -7,6 +7,9 @@ const Utils_1 = require("../Utils");
7
7
  * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
8
8
  */
9
9
  class ContentDisposition {
10
+ type;
11
+ filename;
12
+ name;
10
13
  constructor(type, filename, name) {
11
14
  this.type = type;
12
15
  this.filename = filename;
@@ -7,6 +7,10 @@ exports.DataError = void 0;
7
7
  *
8
8
  */
9
9
  class DataError extends Error {
10
+ /**
11
+ * Custom data
12
+ */
13
+ data;
10
14
  /**
11
15
  * Constructor
12
16
  * @param message Error message
@@ -5,6 +5,10 @@ exports.EColor = void 0;
5
5
  * Etsoo implmented Color
6
6
  */
7
7
  class EColor {
8
+ r;
9
+ g;
10
+ b;
11
+ alpha;
8
12
  /**
9
13
  * Adjust value
10
14
  * @param value Current value
@@ -21,6 +21,13 @@ exports.EHistoryNavigateEvent = EHistoryNavigateEvent;
21
21
  * ETSOO Extended abstract history class
22
22
  */
23
23
  class EHistory extends EventClass_1.EventClass {
24
+ maxDepth;
25
+ // Index
26
+ _index = -1;
27
+ /**
28
+ * States
29
+ */
30
+ states = [];
24
31
  /**
25
32
  * States length
26
33
  */
@@ -48,12 +55,6 @@ class EHistory extends EventClass_1.EventClass {
48
55
  constructor(maxDepth = 20) {
49
56
  super();
50
57
  this.maxDepth = maxDepth;
51
- // Index
52
- this._index = -1;
53
- /**
54
- * States
55
- */
56
- this.states = [];
57
58
  }
58
59
  /**
59
60
  * Back to the previous state
@@ -7,12 +7,17 @@ exports.EventClass = exports.EventBase = void 0;
7
7
  * D for data
8
8
  */
9
9
  class EventBase {
10
+ target;
11
+ type;
12
+ data;
13
+ _propagationStopped = false;
10
14
  /**
11
15
  * stopImmediatePropagation called
12
16
  */
13
17
  get propagationStopped() {
14
18
  return this._propagationStopped;
15
19
  }
20
+ _timeStamp;
16
21
  /**
17
22
  * Time stamp
18
23
  */
@@ -27,7 +32,6 @@ class EventBase {
27
32
  this.target = target;
28
33
  this.type = type;
29
34
  this.data = data;
30
- this._propagationStopped = false;
31
35
  this._timeStamp = Date.now();
32
36
  }
33
37
  /**
@@ -44,10 +48,8 @@ exports.EventBase = EventBase;
44
48
  * D for data
45
49
  */
46
50
  class EventClass {
47
- constructor() {
48
- // Listeners
49
- this.listeners = new Map();
50
- }
51
+ // Listeners
52
+ listeners = new Map();
51
53
  /**
52
54
  * Has specific type and callback events
53
55
  * @param type Type
@@ -71,7 +71,7 @@ export var DateUtils;
71
71
  if (parsed == null)
72
72
  return undefined;
73
73
  // Default options
74
- options ?? (options = DateUtils.DayFormat);
74
+ options ??= DateUtils.DayFormat;
75
75
  // Default options
76
76
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat
77
77
  let opt;
@@ -306,7 +306,7 @@ export var DomUtils;
306
306
  * @returns Result
307
307
  */
308
308
  function isWechatClient(data) {
309
- data ?? (data = parseUserAgent());
309
+ data ??= parseUserAgent();
310
310
  if (!data)
311
311
  return false;
312
312
  return data.brands.some((item) => item.brand.toLowerCase() === "micromessenger");
@@ -494,7 +494,7 @@ export var DomUtils;
494
494
  * @returns User agent data
495
495
  */
496
496
  function parseUserAgent(ua) {
497
- ua ?? (ua = globalThis.navigator.userAgent);
497
+ ua ??= globalThis.navigator.userAgent;
498
498
  if (!ua) {
499
499
  return null;
500
500
  }
@@ -580,7 +580,7 @@ export var DomUtils;
580
580
  */
581
581
  function setFocus(name, container) {
582
582
  const elementName = typeof name === "string" ? name : Object.keys(name)[0];
583
- container ?? (container = document.body);
583
+ container ??= document.body;
584
584
  const element = container.querySelector(`[name="${elementName}"]`);
585
585
  if (element != null)
586
586
  element.focus();
@@ -600,7 +600,7 @@ export var DomUtils;
600
600
  const errorPD = Utils.getResult(preventDefault, errorType) ?? true;
601
601
  window.onerror = (message, source, lineNo, colNo, error) => {
602
602
  // Default source
603
- source || (source = window.location.href);
603
+ source ||= window.location.href;
604
604
  let data;
605
605
  if (typeof message === "string") {
606
606
  data = {
@@ -40,14 +40,14 @@ export var NumberUtils;
40
40
  // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat
41
41
  options.style = "currency";
42
42
  options.currency = currency;
43
- options.currencyDisplay ?? (options.currencyDisplay = "narrowSymbol");
43
+ options.currencyDisplay ??= "narrowSymbol";
44
44
  }
45
45
  if (isInteger) {
46
- options.minimumFractionDigits ?? (options.minimumFractionDigits = 0);
47
- options.maximumFractionDigits ?? (options.maximumFractionDigits = 0);
46
+ options.minimumFractionDigits ??= 0;
47
+ options.maximumFractionDigits ??= 0;
48
48
  }
49
49
  else
50
- options.minimumFractionDigits ?? (options.minimumFractionDigits = 2);
50
+ options.minimumFractionDigits ??= 2;
51
51
  return format(input, locale, options);
52
52
  }
53
53
  NumberUtils.formatMoney = formatMoney;
@@ -1,8 +1,8 @@
1
1
  import { NodeStorage } from "./node/NodeStorage";
2
2
  import { Utils } from "./Utils";
3
3
  // Mock node
4
- globalThis.localStorage ?? (globalThis.localStorage = new NodeStorage());
5
- globalThis.sessionStorage ?? (globalThis.sessionStorage = new NodeStorage());
4
+ globalThis.localStorage ??= new NodeStorage();
5
+ globalThis.sessionStorage ??= new NodeStorage();
6
6
  /**
7
7
  * Storage utilities
8
8
  * NodeStorage needs data persistance
@@ -132,6 +132,14 @@ export declare namespace Utils {
132
132
  export function excludeAsync<T extends {
133
133
  [P in D]: IdType;
134
134
  }, D extends string = "id">(items: Promise<T[] | undefined>, field: D, ...excludedValues: T[D][]): Promise<T[] | undefined>;
135
+ /**
136
+ * Format name
137
+ * @param name Input name
138
+ * @param maxChars Max chars
139
+ * @param maxParts Max parts (optional)
140
+ * @returns Formatted name
141
+ */
142
+ export function formatName(name: string, maxChars: number, maxParts?: number): string;
135
143
  /**
136
144
  * Format inital character to lower case or upper case
137
145
  * @param input Input string
package/lib/mjs/Utils.js CHANGED
@@ -136,7 +136,7 @@ export var Utils;
136
136
  */
137
137
  function addBlankItem(options, idField, labelField, blankLabel) {
138
138
  // Avoid duplicate blank items
139
- idField ?? (idField = "id");
139
+ idField ??= "id";
140
140
  if (options.length === 0 || Reflect.get(options[0], idField) !== "") {
141
141
  const blankItem = {
142
142
  [idField]: "",
@@ -204,6 +204,63 @@ export var Utils;
204
204
  return exclude(result, field, ...excludedValues);
205
205
  }
206
206
  Utils.excludeAsync = excludeAsync;
207
+ /**
208
+ * Format name
209
+ * @param name Input name
210
+ * @param maxChars Max chars
211
+ * @param maxParts Max parts (optional)
212
+ * @returns Formatted name
213
+ */
214
+ function formatName(name, maxChars, maxParts) {
215
+ name = name.trim();
216
+ const parts = name.split(/\s+/);
217
+ const max = maxParts ?? Math.floor(maxChars / 3);
218
+ const effectiveMax = max < 2 ? 2 : max;
219
+ if (parts.length >= effectiveMax) {
220
+ return parts.slice(0, effectiveMax).join(" ");
221
+ }
222
+ else if (name.length > maxChars) {
223
+ let endIndex = maxChars;
224
+ const brackets = {
225
+ "(": ")",
226
+ "(": ")",
227
+ "[": "]"
228
+ };
229
+ // Count unmatched brackets for each type
230
+ for (const [start, end] of Object.entries(brackets)) {
231
+ let count = 0;
232
+ // Count opening and closing brackets in the substring
233
+ for (let i = 0; i < maxChars; i++) {
234
+ if (name[i] === start)
235
+ count++;
236
+ else if (name[i] === end)
237
+ count--;
238
+ }
239
+ if (count > 0) {
240
+ // Find matching end brackets
241
+ for (let i = maxChars; i < name.length && count > 0; i++) {
242
+ if (name[i] === start) {
243
+ count++;
244
+ }
245
+ else if (name[i] === end) {
246
+ count--;
247
+ if (count === 0) {
248
+ endIndex = i + 1;
249
+ }
250
+ }
251
+ }
252
+ if (count === 0) {
253
+ return name.substring(0, endIndex);
254
+ }
255
+ }
256
+ }
257
+ return name.substring(0, endIndex);
258
+ }
259
+ else {
260
+ return name;
261
+ }
262
+ }
263
+ Utils.formatName = formatName;
207
264
  /**
208
265
  * Format inital character to lower case or upper case
209
266
  * @param input Input string
@@ -575,7 +632,7 @@ export var Utils;
575
632
  Utils.setLabels = (source, labels, reference) => {
576
633
  Object.keys(source).forEach((key) => {
577
634
  // Reference key
578
- const labelKey = reference == null ? key : reference[key] ?? key;
635
+ const labelKey = reference == null ? key : (reference[key] ?? key);
579
636
  // Label
580
637
  const label = labels[labelKey];
581
638
  if (label != null) {
@@ -3,15 +3,14 @@
3
3
  * Please take care of the persistence with source property
4
4
  */
5
5
  export class NodeStorage {
6
+ /**
7
+ * Storage source
8
+ */
9
+ source = [];
6
10
  /**
7
11
  * Constructor
8
12
  */
9
- constructor() {
10
- /**
11
- * Storage source
12
- */
13
- this.source = [];
14
- }
13
+ constructor() { }
15
14
  /**
16
15
  * Returns the number of key/value pairs currently present in the list
17
16
  */
@@ -63,5 +63,5 @@ export interface IStorage {
63
63
  * @param key Key name
64
64
  * @param data Data, null for removal
65
65
  */
66
- setPersistedData(key: string, data: unknown): void;
66
+ setPersistedData<T>(key: string, data: T): void;
67
67
  }
@@ -65,5 +65,5 @@ export declare class WindowStorage implements IStorage {
65
65
  * @param key Key name
66
66
  * @param data Data, null for removal
67
67
  */
68
- setPersistedData(key: string, data: unknown): void;
68
+ setPersistedData<T>(key: string, data: T): void;
69
69
  }
@@ -2,6 +2,14 @@
2
2
  * A mock implementation of DOMRect for testing purposes
3
3
  */
4
4
  export class MockDOMRect {
5
+ bottom;
6
+ height;
7
+ left;
8
+ right;
9
+ top;
10
+ width;
11
+ x;
12
+ y;
5
13
  toJSON() {
6
14
  return JSON.stringify({
7
15
  bottom: this.bottom,
@@ -2,9 +2,9 @@
2
2
  * Mock implementation of ResizeObserver for testing purposes
3
3
  */
4
4
  export class MockResizeObserver {
5
+ callbacks = [];
6
+ elements = [];
5
7
  constructor(callback) {
6
- this.callbacks = [];
7
- this.elements = [];
8
8
  this.callbacks.push(callback);
9
9
  }
10
10
  observe(element) {
@@ -4,6 +4,9 @@ import { Utils } from "../Utils";
4
4
  * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
5
5
  */
6
6
  export class ContentDisposition {
7
+ type;
8
+ filename;
9
+ name;
7
10
  constructor(type, filename, name) {
8
11
  this.type = type;
9
12
  this.filename = filename;
@@ -4,6 +4,10 @@
4
4
  *
5
5
  */
6
6
  export class DataError extends Error {
7
+ /**
8
+ * Custom data
9
+ */
10
+ data;
7
11
  /**
8
12
  * Constructor
9
13
  * @param message Error message
@@ -2,6 +2,10 @@
2
2
  * Etsoo implmented Color
3
3
  */
4
4
  export class EColor {
5
+ r;
6
+ g;
7
+ b;
8
+ alpha;
5
9
  /**
6
10
  * Adjust value
7
11
  * @param value Current value
@@ -16,6 +16,13 @@ export class EHistoryNavigateEvent extends EventBase {
16
16
  * ETSOO Extended abstract history class
17
17
  */
18
18
  export class EHistory extends EventClass {
19
+ maxDepth;
20
+ // Index
21
+ _index = -1;
22
+ /**
23
+ * States
24
+ */
25
+ states = [];
19
26
  /**
20
27
  * States length
21
28
  */
@@ -43,12 +50,6 @@ export class EHistory extends EventClass {
43
50
  constructor(maxDepth = 20) {
44
51
  super();
45
52
  this.maxDepth = maxDepth;
46
- // Index
47
- this._index = -1;
48
- /**
49
- * States
50
- */
51
- this.states = [];
52
53
  }
53
54
  /**
54
55
  * Back to the previous state
@@ -4,12 +4,17 @@
4
4
  * D for data
5
5
  */
6
6
  export class EventBase {
7
+ target;
8
+ type;
9
+ data;
10
+ _propagationStopped = false;
7
11
  /**
8
12
  * stopImmediatePropagation called
9
13
  */
10
14
  get propagationStopped() {
11
15
  return this._propagationStopped;
12
16
  }
17
+ _timeStamp;
13
18
  /**
14
19
  * Time stamp
15
20
  */
@@ -24,7 +29,6 @@ export class EventBase {
24
29
  this.target = target;
25
30
  this.type = type;
26
31
  this.data = data;
27
- this._propagationStopped = false;
28
32
  this._timeStamp = Date.now();
29
33
  }
30
34
  /**
@@ -40,10 +44,8 @@ export class EventBase {
40
44
  * D for data
41
45
  */
42
46
  export class EventClass {
43
- constructor() {
44
- // Listeners
45
- this.listeners = new Map();
46
- }
47
+ // Listeners
48
+ listeners = new Map();
47
49
  /**
48
50
  * Has specific type and callback events
49
51
  * @param type Type
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/shared",
3
- "version": "1.2.80",
3
+ "version": "1.2.82",
4
4
  "description": "TypeScript shared utilities and functions",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/mjs/index.js",
@@ -36,10 +36,10 @@
36
36
  },
37
37
  "homepage": "https://github.com/ETSOO/Shared#readme",
38
38
  "devDependencies": {
39
- "@types/node": "^24.10.1",
40
- "@vitejs/plugin-react": "^5.1.1",
41
- "jsdom": "^27.2.0",
42
- "typescript": "^5.9.3",
43
- "vitest": "^4.0.10"
39
+ "@types/node": "^25.5.2",
40
+ "@vitejs/plugin-react": "^6.0.1",
41
+ "jsdom": "^29.0.1",
42
+ "typescript": "^6.0.2",
43
+ "vitest": "^4.1.2"
44
44
  }
45
45
  }
package/src/Utils.ts CHANGED
@@ -355,6 +355,70 @@ export namespace Utils {
355
355
  return exclude(result, field, ...excludedValues);
356
356
  }
357
357
 
358
+ /**
359
+ * Format name
360
+ * @param name Input name
361
+ * @param maxChars Max chars
362
+ * @param maxParts Max parts (optional)
363
+ * @returns Formatted name
364
+ */
365
+ export function formatName(
366
+ name: string,
367
+ maxChars: number,
368
+ maxParts?: number
369
+ ): string {
370
+ name = name.trim();
371
+
372
+ const parts = name.split(/\s+/);
373
+
374
+ const max = maxParts ?? Math.floor(maxChars / 3);
375
+ const effectiveMax = max < 2 ? 2 : max;
376
+
377
+ if (parts.length >= effectiveMax) {
378
+ return parts.slice(0, effectiveMax).join(" ");
379
+ } else if (name.length > maxChars) {
380
+ let endIndex = maxChars;
381
+ const brackets: Record<string, string> = {
382
+ "(": ")",
383
+ "(": ")",
384
+ "[": "]"
385
+ };
386
+
387
+ // Count unmatched brackets for each type
388
+ for (const [start, end] of Object.entries(brackets)) {
389
+ let count = 0;
390
+
391
+ // Count opening and closing brackets in the substring
392
+ for (let i = 0; i < maxChars; i++) {
393
+ if (name[i] === start) count++;
394
+ else if (name[i] === end) count--;
395
+ }
396
+
397
+ if (count > 0) {
398
+ // Find matching end brackets
399
+ for (let i = maxChars; i < name.length && count > 0; i++) {
400
+ if (name[i] === start) {
401
+ count++;
402
+ } else if (name[i] === end) {
403
+ count--;
404
+ if (count === 0) {
405
+ endIndex = i + 1;
406
+ }
407
+ }
408
+ }
409
+
410
+ if (count === 0) {
411
+ return name.substring(0, endIndex);
412
+ }
413
+ }
414
+ }
415
+
416
+ return name.substring(0, endIndex);
417
+ } else {
418
+ return name;
419
+ }
420
+ }
421
+
358
422
  /**
359
423
  * Format inital character to lower case or upper case
360
424
  * @param input Input string
@@ -823,7 +887,7 @@ export namespace Utils {
823
887
  ) => {
824
888
  Object.keys(source).forEach((key) => {
825
889
  // Reference key
826
- const labelKey = reference == null ? key : reference[key] ?? key;
890
+ const labelKey = reference == null ? key : (reference[key] ?? key);
827
891
 
828
892
  // Label
829
893
  const label = labels[labelKey];
@@ -963,8 +1027,8 @@ export namespace Utils {
963
1027
  index1 === -1
964
1028
  ? index2
965
1029
  : index2 === -1
966
- ? index1
967
- : Math.min(index1, index2);
1030
+ ? index1
1031
+ : Math.min(index1, index2);
968
1032
  root = path.substring(0, index + 1);
969
1033
  dir = path.substring(0, lastIndex);
970
1034
  if (dir === "") dir = root;
@@ -73,5 +73,5 @@ export interface IStorage {
73
73
  * @param key Key name
74
74
  * @param data Data, null for removal
75
75
  */
76
- setPersistedData(key: string, data: unknown): void;
76
+ setPersistedData<T>(key: string, data: T): void;
77
77
  }
@@ -141,7 +141,7 @@ export class WindowStorage implements IStorage {
141
141
  * @param key Key name
142
142
  * @param data Data, null for removal
143
143
  */
144
- setPersistedData(key: string, data: unknown) {
144
+ setPersistedData<T>(key: string, data: T) {
145
145
  StorageUtils.setLocalData(key, data);
146
146
  }
147
147
  }
package/tsconfig.cjs.json CHANGED
@@ -1,15 +1,17 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  /* Visit https://aka.ms/tsconfig.json to read more about this file */
4
- "target": "ES2020",
4
+ "target": "ES2025",
5
5
  "module": "NodeNext",
6
6
  "moduleResolution": "NodeNext",
7
7
  "isolatedModules": true,
8
+ "rootDir": "./src",
8
9
  "outDir": "./lib/cjs",
9
10
  "noEmit": false,
10
11
  "declaration": true,
11
12
  "strict": true,
12
13
  "esModuleInterop": true,
14
+ "types": ["node"],
13
15
  "skipLibCheck": true,
14
16
  "forceConsistentCasingInFileNames": true,
15
17
  "lib": ["dom", "dom.iterable", "ESNext"]
package/tsconfig.json CHANGED
@@ -1,15 +1,17 @@
1
1
  {
2
2
  "compilerOptions": {
3
3
  /* Visit https://aka.ms/tsconfig.json to read more about this file */
4
- "target": "ES2020",
5
- "module": "ES2020",
4
+ "target": "ES2025",
5
+ "module": "ESNext",
6
6
  "moduleResolution": "bundler",
7
7
  "isolatedModules": true,
8
+ "rootDir": "./src",
8
9
  "outDir": "./lib/mjs",
9
10
  "noEmit": false,
10
11
  "declaration": true,
11
12
  "strict": true,
12
13
  "esModuleInterop": true,
14
+ "types": ["node"],
13
15
  "skipLibCheck": true,
14
16
  "forceConsistentCasingInFileNames": true,
15
17
  "lib": ["dom", "dom.iterable", "esnext"]