@libs-ui/utils 0.2.306 → 0.2.308-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.
Files changed (43) hide show
  1. package/communicate-micro.d.ts +1 -1
  2. package/dangerous-object.d.ts +75 -0
  3. package/date.d.ts +9 -9
  4. package/esm2022/base64.mjs +2 -2
  5. package/esm2022/cache.mjs +17 -14
  6. package/esm2022/color.mjs +66 -14
  7. package/esm2022/communicate-micro.mjs +20 -16
  8. package/esm2022/constants.mjs +1 -1
  9. package/esm2022/crypto-3rd.mjs +3 -3
  10. package/esm2022/crypto.mjs +3 -3
  11. package/esm2022/dangerous-object.mjs +143 -0
  12. package/esm2022/date.mjs +15 -15
  13. package/esm2022/dom.mjs +5 -13
  14. package/esm2022/download.mjs +3 -3
  15. package/esm2022/file.mjs +22 -11
  16. package/esm2022/format-number.mjs +9 -6
  17. package/esm2022/format-text.mjs +13 -15
  18. package/esm2022/function-check-embed-frame.mjs +1 -1
  19. package/esm2022/get-smart-axis-scale.mjs +10 -10
  20. package/esm2022/helpers.mjs +119 -38
  21. package/esm2022/http-params.mjs +2 -2
  22. package/esm2022/index.mjs +2 -1
  23. package/esm2022/inject-token.mjs +2 -2
  24. package/esm2022/key-cache.mjs +6 -6
  25. package/esm2022/key-code.mjs +1 -1
  26. package/esm2022/language.mjs +28 -28
  27. package/esm2022/pattern.mjs +1 -1
  28. package/esm2022/random.mjs +2 -2
  29. package/esm2022/two-way-signal-object.mjs +32 -20
  30. package/esm2022/uri.mjs +9 -6
  31. package/esm2022/url-search-params.mjs +13 -11
  32. package/esm2022/uuid.mjs +2 -2
  33. package/esm2022/xss-filter.mjs +1 -1
  34. package/fesm2022/libs-ui-utils.mjs +646 -346
  35. package/fesm2022/libs-ui-utils.mjs.map +1 -1
  36. package/file.d.ts +1 -1
  37. package/format-text.d.ts +1 -1
  38. package/helpers.d.ts +53 -4
  39. package/http-params.d.ts +1 -1
  40. package/index.d.ts +1 -0
  41. package/inject-token.d.ts +1 -1
  42. package/package.json +2 -2
  43. package/uri.d.ts +1 -1
@@ -1,9 +1,9 @@
1
1
  import DeviceDetector from 'device-detector-js';
2
2
  import Quill from 'quill';
3
- import { fromEvent, tap, takeUntil, mergeMap, startWith, finalize, lastValueFrom, timer, Subject, filter, Observable } from 'rxjs';
3
+ import { fromEvent, tap, takeUntil, mergeMap, startWith, finalize, lastValueFrom, timer, Observable, Subject, filter } from 'rxjs';
4
4
  import CryptoES from 'crypto-es';
5
5
  import { HttpParams } from '@angular/common/http';
6
- import { isSignal, TemplateRef, ElementRef, signal, InjectionToken } from '@angular/core';
6
+ import { TemplateRef, ElementRef, isSignal, signal, InjectionToken } from '@angular/core';
7
7
  import dayjs from 'dayjs';
8
8
  import 'dayjs/locale/en';
9
9
  import 'dayjs/locale/vi';
@@ -90,7 +90,7 @@ const highlightByKeyword = (value, search, ignoreHighlight, classHightLight) =>
90
90
  if (!classHightLight) {
91
91
  classHightLight = 'bg-[#19344a] text-white';
92
92
  }
93
- keysReplace.forEach(key => {
93
+ keysReplace.forEach((key) => {
94
94
  const regExp = new RegExp(key, 'gi');
95
95
  value = value?.replace(regExp, `<span class="${classHightLight}">$&</span>`);
96
96
  });
@@ -119,7 +119,7 @@ const formatTextCompare = (text, options) => {
119
119
  if (!text) {
120
120
  return text;
121
121
  }
122
- text = text.normalize("NFC");
122
+ text = text.normalize('NFC');
123
123
  return formatByOptions(text, options);
124
124
  };
125
125
  const fullNameFormat = (value) => {
@@ -133,7 +133,10 @@ const capitalize = (text, options) => {
133
133
  return text;
134
134
  }
135
135
  text = formatByOptions(text, options);
136
- return text.split(' ').map(word => firstLetterToUpperCase(word)).join(' ');
136
+ return text
137
+ .split(' ')
138
+ .map((word) => firstLetterToUpperCase(word))
139
+ .join(' ');
137
140
  };
138
141
  const firstLetterToUpperCase = (text, options) => {
139
142
  if (!text) {
@@ -159,7 +162,7 @@ const formatByOptions = (text, options) => {
159
162
  text = text.toLowerCase();
160
163
  }
161
164
  if (options?.removeMultipleSpace) {
162
- text = text.replace(/\u200B|\u00A0/g, "");
165
+ text = text.replace(/\u200B|\u00A0/g, '');
163
166
  text = text.replace(/\s+/g, ' ');
164
167
  }
165
168
  if (options?.removeEmoji) {
@@ -177,12 +180,7 @@ const escapeHtml = (str) => {
177
180
  if (!str || typeof str !== 'string') {
178
181
  return str;
179
182
  }
180
- return str
181
- .replace(/&/g, "&amp;")
182
- .replace(/</g, "&lt;")
183
- .replace(/>/g, "&gt;")
184
- .replace(/"/g, "&quot;")
185
- .replace(/'/g, "&#039;");
183
+ return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#039;');
186
184
  };
187
185
  const decodeEscapeHtml = (str) => {
188
186
  const htmlTag = document.createElement('textarea');
@@ -213,9 +211,9 @@ const deleteUnicode = (str) => {
213
211
  str = str.replace(/Ù|Ú|Ụ|Ủ|Ũ|Ư|Ừ|Ứ|Ự|Ử|Ữ/g, 'U');
214
212
  str = str.replace(/Ỳ|Ý|Ỵ|Ỷ|Ỹ/g, 'Y');
215
213
  str = str.replace(/Đ/g, 'D');
216
- str = str.replace(/\u0300|\u0301|\u0303|\u0309|\u0323/g, ""); // ̀ ́ ̃ ̉ ̣ huyền, sắc, ngã, hỏi, nặng
217
- str = str.replace(/\u02C6|\u0306|\u031B/g, ""); // ˆ ̆ ̛ Â, Ê, Ă, Ơ, Ư
218
- return str.normalize("NFC");
214
+ str = str.replace(/\u0300|\u0301|\u0303|\u0309|\u0323/g, ''); // ̀ ́ ̃ ̉ ̣ huyền, sắc, ngã, hỏi, nặng
215
+ str = str.replace(/\u02C6|\u0306|\u031B/g, ''); // ˆ ̆ ̛ Â, Ê, Ă, Ơ, Ư
216
+ return str.normalize('NFC');
219
217
  };
220
218
  const removeEmoji = (text) => {
221
219
  if (!text || !text.trim()) {
@@ -290,10 +288,7 @@ const checkViewInScreen = (container, element, elementScroll, maxTopLeft) => {
290
288
  const limitLeft = leftContainer + scrollLeftContainer + widthContainer;
291
289
  const maxTopItem = top + (maxTopLeft?.top || 0);
292
290
  const maxLeftItem = left + (maxTopLeft?.left || 0);
293
- if (topContainer <= maxTopItem &&
294
- maxTopItem <= limitTop &&
295
- leftContainer <= maxLeftItem &&
296
- maxLeftItem <= limitLeft) {
291
+ if (topContainer <= maxTopItem && maxTopItem <= limitTop && leftContainer <= maxLeftItem && maxLeftItem <= limitLeft) {
297
292
  return true;
298
293
  }
299
294
  return false;
@@ -307,10 +302,7 @@ const checkMouseOverInContainer = (mousePosition, element, rect) => {
307
302
  const limitLeft = left + width;
308
303
  const limitTop = top + height;
309
304
  const { clientX, clientY } = mousePosition;
310
- if (left <= clientX &&
311
- clientX <= limitLeft &&
312
- top <= clientY &&
313
- clientY <= limitTop) {
305
+ if (left <= clientX && clientX <= limitLeft && top <= clientY && clientY <= limitTop) {
314
306
  return true;
315
307
  }
316
308
  return false;
@@ -348,13 +340,11 @@ const getDragEventByElement = (config) => {
348
340
  e.stopPropagation();
349
341
  config.functionMouseMove?.(e);
350
342
  }), takeUntil(mouseup));
351
- return mouseDown.pipe(mergeMap((e) => config.isStartWithMouseDownEvent
352
- ? mousemove.pipe(startWith(e))
353
- : mousemove), takeUntil(config.onDestroy), finalize(removeClass));
343
+ return mouseDown.pipe(mergeMap((e) => (config.isStartWithMouseDownEvent ? mousemove.pipe(startWith(e)) : mousemove)), takeUntil(config.onDestroy), finalize(removeClass));
354
344
  };
355
345
  const getHTMLFromQuill = async (data, options) => {
356
346
  const { replaceNewLineTo = '<br>', replaceTagBRTo, replaceTags, replaceBrToDiv } = options || {};
357
- const delta = (typeof data === 'string') ? await getDeltaFromHTML(data) : data;
347
+ const delta = typeof data === 'string' ? await getDeltaFromHTML(data) : data;
358
348
  if (options?.functionReplaceDelta) {
359
349
  options.functionReplaceDelta(delta);
360
350
  }
@@ -498,17 +488,19 @@ class UtilsUrlSearchParams {
498
488
  return this.instance;
499
489
  }
500
490
  static toStringParamObject(params) {
501
- const paramsArr = Object.keys(params).map(key => {
491
+ const paramsArr = Object.keys(params).map((key) => {
502
492
  return {
503
493
  key,
504
- value: params[key]
494
+ value: params[key],
505
495
  };
506
496
  });
507
497
  return UtilsUrlSearchParams.ToString(paramsArr);
508
498
  }
509
499
  static ToString(params) {
510
500
  let paramsStr = '';
511
- params.sort((item1, item2) => item1.key.localeCompare(item2.key)).forEach((item) => {
501
+ params
502
+ .sort((item1, item2) => item1.key.localeCompare(item2.key))
503
+ .forEach((item) => {
512
504
  const { key, value } = item;
513
505
  paramsStr = `${paramsStr}${paramsStr ? '&' : ''}${key}=${value}`;
514
506
  });
@@ -525,14 +517,14 @@ class UtilsUrlSearchParams {
525
517
  }
526
518
  const params = paramString.replace(/\S+[?]/g, '').split('&');
527
519
  if (params) {
528
- params.forEach(param => {
520
+ params.forEach((param) => {
529
521
  if (param.indexOf('=') < 0) {
530
522
  return;
531
523
  }
532
524
  let [key, value] = param.split('=');
533
525
  key = key.replace(/[?&]+/g, '');
534
526
  value = decodeURIComponent(value.replace(/\+/g, ' '));
535
- if (!paramsBuild.some(param => param.key === key)) {
527
+ if (!paramsBuild.some((param) => param.key === key)) {
536
528
  paramsBuild.push({ key, value });
537
529
  }
538
530
  });
@@ -540,7 +532,7 @@ class UtilsUrlSearchParams {
540
532
  return paramsBuild;
541
533
  }
542
534
  set(key, value) {
543
- const paramByKey = this.params.find(param => param.key === key);
535
+ const paramByKey = this.params.find((param) => param.key === key);
544
536
  if (!paramByKey) {
545
537
  this.params.push({ key, value: decodeURIComponent(value.replace(/\+/g, ' ')) });
546
538
  return;
@@ -548,13 +540,13 @@ class UtilsUrlSearchParams {
548
540
  paramByKey['value'] = value;
549
541
  }
550
542
  get(key) {
551
- return this.params.find(param => param.key === key)?.value;
543
+ return this.params.find((param) => param.key === key)?.value;
552
544
  }
553
545
  has(key) {
554
- return this.params.some(param => param.key === key);
546
+ return this.params.some((param) => param.key === key);
555
547
  }
556
548
  delete(key) {
557
- const index = this.params.findIndex(param => param.key === key);
549
+ const index = this.params.findIndex((param) => param.key === key);
558
550
  if (index >= 0) {
559
551
  this.params.splice(index, 1);
560
552
  }
@@ -568,7 +560,7 @@ class UtilsUrlSearchParams {
568
560
  }
569
561
  getParamObject() {
570
562
  const params = {};
571
- this.params.forEach(item => {
563
+ this.params.forEach((item) => {
572
564
  params[item.key] = item.value;
573
565
  });
574
566
  return params;
@@ -596,7 +588,7 @@ const keyStore$1 = () => {
596
588
  };
597
589
  const encrypt = (plainData) => {
598
590
  if (!keyStore$1()) {
599
- throw Error("lỗi chưa setup key mã hóa");
591
+ throw Error('lỗi chưa setup key mã hóa');
600
592
  }
601
593
  const key = CryptoES.enc.Hex.parse(keyStore$1());
602
594
  const iv = CryptoES.enc.Hex.parse(keyStore$1());
@@ -607,7 +599,7 @@ const encrypt = (plainData) => {
607
599
  };
608
600
  const decrypt = (encryptedData) => {
609
601
  if (!keyStore$1()) {
610
- throw Error("lỗi chưa setup key mã hóa");
602
+ throw Error('lỗi chưa setup key mã hóa');
611
603
  }
612
604
  const key = CryptoES.enc.Hex.parse(keyStore$1());
613
605
  const iv = CryptoES.enc.Hex.parse(keyStore$1());
@@ -638,83 +630,143 @@ const uuid = () => {
638
630
  };
639
631
 
640
632
  /* eslint-disable @typescript-eslint/no-explicit-any */
641
- const UtilsHttpParamsRequestInstance = (options, instance) => {
642
- return new UtilsHttpParamsRequest(options, instance);
643
- };
644
- class UtilsHttpParamsRequest extends HttpParams {
645
- params = new HttpParams();
646
- constructor(options, instance) {
647
- super(options);
648
- if (!instance) {
649
- this.params = new HttpParams(options);
650
- return;
651
- }
652
- if (instance instanceof UtilsHttpParamsRequest) {
653
- this.params = instance.getInstance();
654
- return;
655
- }
656
- if (instance instanceof HttpParams) {
657
- this.params = instance;
658
- return;
659
- }
660
- }
661
- getInstance() {
662
- return this.params;
663
- }
664
- setInstance(instance) {
665
- if (instance instanceof UtilsHttpParamsRequest) {
666
- this.params = instance.getInstance();
667
- return;
668
- }
669
- if (instance instanceof HttpParams) {
670
- this.params = instance;
671
- return;
672
- }
673
- }
674
- set(param, value) {
675
- this.params = this.params.set(param, value);
676
- return this;
633
+ /**
634
+ * Danh sách các constructor name nguy hiểm
635
+ */
636
+ const DANGEROUS_CONSTRUCTOR_NAMES = ['Window', 'Document', 'HTMLDocument', 'HTMLElement', 'Element', 'Node', 'Location', 'Navigator', 'Screen', 'History', 'Storage', 'Console', 'Performance'];
637
+ /**
638
+ * Kiểm tra xem đối tượng có phải là browser global object không
639
+ */
640
+ const isBrowserGlobalObject = (obj) => {
641
+ if (obj === null || typeof obj !== 'object') {
642
+ return false;
677
643
  }
678
- has(param) {
679
- return this.params.has(param);
644
+ return obj instanceof Window || obj instanceof Document || obj === window || obj === document || obj === globalThis;
645
+ };
646
+ /**
647
+ * Kiểm tra xem đối tượng có phải là DOM object không
648
+ */
649
+ const isDOMObject = (obj) => {
650
+ if (obj === null || typeof obj !== 'object') {
651
+ return false;
680
652
  }
681
- get(param) {
682
- return this.params.get(param);
653
+ return obj instanceof HTMLElement || obj instanceof Node || obj instanceof Element;
654
+ };
655
+ /**
656
+ * Kiểm tra xem đối tượng có phải là browser API object không
657
+ */
658
+ const isBrowserAPIObject = (obj) => {
659
+ if (obj === null || typeof obj !== 'object' || typeof window === 'undefined') {
660
+ return false;
683
661
  }
684
- getAll(param) {
685
- return this.params.getAll(param);
662
+ return obj === window.location || obj === window.navigator || obj === window.screen || obj === window.history || obj === window.localStorage || obj === window.sessionStorage || obj === window.console || obj === window.performance;
663
+ };
664
+ /**
665
+ * Kiểm tra constructor name có nằm trong danh sách nguy hiểm không
666
+ */
667
+ const hasDangerousConstructorName = (obj) => {
668
+ if (obj === null || typeof obj !== 'object') {
669
+ return false;
686
670
  }
687
- keys() {
688
- return this.params.keys();
671
+ const constructorName = obj.constructor?.name;
672
+ return constructorName && DANGEROUS_CONSTRUCTOR_NAMES.includes(constructorName);
673
+ };
674
+ /**
675
+ * Kiểm tra xem đối tượng có phải là DOM object hoặc browser object nguy hiểm không
676
+ * Những đối tượng này có thể gây ra circular reference và maximum call stack
677
+ */
678
+ const isDangerousObject = (obj) => {
679
+ if (obj === null || typeof obj !== 'object') {
680
+ return false;
689
681
  }
690
- append(param, value) {
691
- this.params = this.params.append(param, value);
692
- return this;
682
+ return isBrowserGlobalObject(obj) || isDOMObject(obj) || isBrowserAPIObject(obj) || hasDangerousConstructorName(obj);
683
+ };
684
+ /**
685
+ * Kiểm tra đối tượng có phải là Angular/Framework object không
686
+ */
687
+ const isFrameworkObject = (obj) => {
688
+ if (obj === null || typeof obj !== 'object') {
689
+ return false;
693
690
  }
694
- appendAll(params) {
695
- this.params = this.params.appendAll(params);
696
- return this;
691
+ return obj instanceof TemplateRef || obj instanceof ElementRef;
692
+ };
693
+ /**
694
+ * Kiểm tra đối tượng có phải là File/Blob object không
695
+ */
696
+ const isFileObject = (obj) => {
697
+ if (obj === null || typeof obj !== 'object') {
698
+ return false;
697
699
  }
698
- delete(param, value) {
699
- this.params = this.params.delete(param, value);
700
- return this;
700
+ return obj instanceof File || obj instanceof Blob || Object.prototype.toString.call(obj) === '[object File]';
701
+ };
702
+ /**
703
+ * Kiểm tra đối tượng có phải là Built-in object không
704
+ */
705
+ const isBuiltInObject = (obj) => {
706
+ if (obj === null || typeof obj !== 'object') {
707
+ return false;
701
708
  }
702
- toString() {
703
- return this.params.toString();
709
+ return obj instanceof Date || obj instanceof RegExp || obj instanceof HttpParams;
710
+ };
711
+ /**
712
+ * Kiểm tra đối tượng có phải là Async object không
713
+ */
714
+ const isAsyncObject = (obj) => {
715
+ if (obj === null || typeof obj !== 'object') {
716
+ return false;
704
717
  }
705
- }
706
- // Demo su dung GET_PATH_VARIABLE
707
- // interface Person {
708
- // name: string;
709
- // age: number;
710
- // location: string;
711
- // }
712
- // type c = GET_PATH_VARIABLE<Person, unknown>;
713
- // const a: c = {
714
- // "pathVariable-age": 1,
715
- // "pathVariable-location": '12',
716
- // "pathVariable-name": '124',
717
- // };
718
+ return obj instanceof Promise || obj instanceof Observable;
719
+ };
720
+ /**
721
+ * Kiểm tra đối tượng có phải là Special object cần bỏ qua không
722
+ * Bao gồm: Framework objects, File objects, Built-in objects, Async objects
723
+ */
724
+ const isSpecialObject = (obj) => {
725
+ return isFrameworkObject(obj) || isFileObject(obj) || isBuiltInObject(obj) || isAsyncObject(obj);
726
+ };
727
+ /**
728
+ * Kiểm tra đối tượng có phải là dayjs object không
729
+ */
730
+ const isDayjsObject = (obj) => {
731
+ return dayjs.isDayjs(obj);
732
+ };
733
+ /**
734
+ * Kiểm tra đối tượng có phải là object cần bỏ qua trong quá trình convert không
735
+ */
736
+ const isSkippableObject = (obj) => {
737
+ return isDangerousObject(obj) || isSpecialObject(obj);
738
+ };
739
+ /**
740
+ * Kiểm tra đối tượng có phải là Map object không
741
+ */
742
+ const isMapObject = (obj) => {
743
+ return obj instanceof Map;
744
+ };
745
+ /**
746
+ * Kiểm tra đối tượng có phải là Set object không
747
+ */
748
+ const isSetObject = (obj) => {
749
+ return obj instanceof Set;
750
+ };
751
+ /**
752
+ * Kiểm tra đối tượng có phải là Array object không
753
+ */
754
+ const isArrayObject = (obj) => {
755
+ return Array.isArray(obj);
756
+ };
757
+ /**
758
+ * Kiểm tra đối tượng có phải là object cần trả về nguyên trạng không
759
+ * Bao gồm: dangerous objects, special objects, dayjs objects
760
+ */
761
+ const isReturnAsIsObject = (obj) => {
762
+ return isSkippableObject(obj) || isDayjsObject(obj);
763
+ };
764
+ /**
765
+ * Kiểm tra xem đối tượng có an toàn để clone/convert không
766
+ */
767
+ const isSafeToProcess = (obj) => {
768
+ return !isDangerousObject(obj);
769
+ };
718
770
 
719
771
  let key = '12~@#loqwsxacva(3rdhaq12';
720
772
  /**
@@ -732,7 +784,7 @@ const keyStore = () => {
732
784
  };
733
785
  const encrypt3rd = (plainData) => {
734
786
  if (!keyStore()) {
735
- throw Error("lỗi chưa setup key mã hóa");
787
+ throw Error('lỗi chưa setup key mã hóa');
736
788
  }
737
789
  const key = CryptoES.enc.Hex.parse(keyStore());
738
790
  const iv = CryptoES.enc.Hex.parse(keyStore());
@@ -743,7 +795,7 @@ const encrypt3rd = (plainData) => {
743
795
  };
744
796
  const decrypt3rd = (encryptedData) => {
745
797
  if (!keyStore()) {
746
- throw Error("lỗi chưa setup key mã hóa");
798
+ throw Error('lỗi chưa setup key mã hóa');
747
799
  }
748
800
  const key = CryptoES.enc.Hex.parse(keyStore());
749
801
  const iv = CryptoES.enc.Hex.parse(keyStore());
@@ -790,7 +842,9 @@ class UtilsCommunicateMicro {
790
842
  if (!this.subs.get(COMMUNICATE_MICRO_KEY_GET_ALL_MESSAGE)) {
791
843
  this.subs.set(COMMUNICATE_MICRO_KEY_GET_ALL_MESSAGE, UtilsCommunicateMicro.allMessageSub);
792
844
  }
793
- fromEvent(currentWindow, 'message').pipe(takeUntil(onDestroy)).subscribe(e => {
845
+ fromEvent(currentWindow, 'message')
846
+ .pipe(takeUntil(onDestroy))
847
+ .subscribe((e) => {
794
848
  const event = { data: { ...e.data } };
795
849
  const data = event.data;
796
850
  const type = data.type;
@@ -818,7 +872,9 @@ class UtilsCommunicateMicro {
818
872
  this.allMessageSub.next(event);
819
873
  }
820
874
  });
821
- UtilsCommunicateMicro.GetMessage(UtilsCache.typeKeyClearLocalStorage).pipe(filter(e => e.data.response !== UtilsCache.idService), takeUntil(onDestroy)).subscribe(() => {
875
+ UtilsCommunicateMicro.GetMessage(UtilsCache.typeKeyClearLocalStorage)
876
+ .pipe(filter((e) => e.data.response !== UtilsCache.idService), takeUntil(onDestroy))
877
+ .subscribe(() => {
822
878
  console.log('clear all cache by event');
823
879
  UtilsCache.ClearAll();
824
880
  });
@@ -827,10 +883,10 @@ class UtilsCommunicateMicro {
827
883
  data = this.convertData(data);
828
884
  try {
829
885
  if (isEmbedFrame()) {
830
- window?.parent?.postMessage(data, "*");
886
+ window?.parent?.postMessage(data, '*');
831
887
  return;
832
888
  }
833
- window?.top?.postMessage(data, "*");
889
+ window?.top?.postMessage(data, '*');
834
890
  }
835
891
  catch (error) {
836
892
  console.log(error);
@@ -838,8 +894,8 @@ class UtilsCommunicateMicro {
838
894
  }
839
895
  static PostMessageToChildren(data) {
840
896
  data = this.convertData(data);
841
- const iframes = document.querySelectorAll("iframe");
842
- Array.from(iframes).forEach(iframe => {
897
+ const iframes = document.querySelectorAll('iframe');
898
+ Array.from(iframes).forEach((iframe) => {
843
899
  iframe?.contentWindow?.postMessage(data, '*');
844
900
  });
845
901
  }
@@ -877,7 +933,7 @@ class UtilsCommunicateMicro {
877
933
  }
878
934
  static GetMessage(messageType) {
879
935
  if (!this.initdEvent) {
880
- throw Error("chưa khơi tạo hàm lắng nghe sự kiện, gọi UtilsCommunicateMicro.initEvent(window) tại root component");
936
+ throw Error('chưa khơi tạo hàm lắng nghe sự kiện, gọi UtilsCommunicateMicro.initEvent(window) tại root component');
881
937
  }
882
938
  if (typeof messageType === 'string') {
883
939
  let sub = this.subs.get(messageType);
@@ -905,8 +961,8 @@ class UtilsCommunicateMicro {
905
961
  return sub;
906
962
  }
907
963
  static initSubject(subRoot, messageType) {
908
- messageType.forEach(key => {
909
- this.GetMessage(key).subscribe(e => {
964
+ messageType.forEach((key) => {
965
+ this.GetMessage(key).subscribe((e) => {
910
966
  subRoot.next(e);
911
967
  });
912
968
  });
@@ -914,33 +970,33 @@ class UtilsCommunicateMicro {
914
970
  }
915
971
 
916
972
  class UtilsLanguageConstants {
917
- static VI = "vi"; // Tiếng Việt
918
- static EN = "en"; // Tiếng Anh
919
- static FR = "fr"; // Tiếng Pháp
920
- static DE = "de"; // Tiếng Đức
921
- static ES = "es"; // Tiếng Tây Ban Nha
922
- static ZH = "zh"; // Tiếng Trung (Giản thể)
923
- static ZH_TW = "zh-TW"; // Tiếng Trung (Phồn thể)
924
- static JA = "ja"; // Tiếng Nhật
925
- static KO = "ko"; // Tiếng Hàn
926
- static RU = "ru"; // Tiếng Nga
927
- static IT = "it"; // Tiếng Ý
928
- static PT = "pt"; // Tiếng Bồ Đào Nha
929
- static TH = "th"; // Tiếng Thái
930
- static ID = "id"; // Tiếng Indonesia
931
- static MS = "ms"; // Tiếng Malaysia
932
- static AR = "ar"; // Tiếng Ả Rập
933
- static HI = "hi"; // Tiếng Hindi
934
- static BN = "bn"; // Tiếng Bengal
935
- static TR = "tr"; // Tiếng Thổ Nhĩ Kỳ
936
- static NL = "nl"; // Tiếng Hà Lan
937
- static KM = "km"; // Tiếng Khmer (Campuchia)
938
- static LO = "lo"; // Tiếng Lào
939
- static MY = "my"; // Tiếng Miến Điện (Myanmar)
940
- static TL = "tl"; // Tiếng Tagalog (Philippines)
941
- static CEB = "ceb"; // Tiếng Cebuano (Philippines)
942
- static JV = "jv"; // Tiếng Java (Indonesia)
943
- static SU = "su"; // Tiếng Sundanese (Indonesia)
973
+ static VI = 'vi'; // Tiếng Việt
974
+ static EN = 'en'; // Tiếng Anh
975
+ static FR = 'fr'; // Tiếng Pháp
976
+ static DE = 'de'; // Tiếng Đức
977
+ static ES = 'es'; // Tiếng Tây Ban Nha
978
+ static ZH = 'zh'; // Tiếng Trung (Giản thể)
979
+ static ZH_TW = 'zh-TW'; // Tiếng Trung (Phồn thể)
980
+ static JA = 'ja'; // Tiếng Nhật
981
+ static KO = 'ko'; // Tiếng Hàn
982
+ static RU = 'ru'; // Tiếng Nga
983
+ static IT = 'it'; // Tiếng Ý
984
+ static PT = 'pt'; // Tiếng Bồ Đào Nha
985
+ static TH = 'th'; // Tiếng Thái
986
+ static ID = 'id'; // Tiếng Indonesia
987
+ static MS = 'ms'; // Tiếng Malaysia
988
+ static AR = 'ar'; // Tiếng Ả Rập
989
+ static HI = 'hi'; // Tiếng Hindi
990
+ static BN = 'bn'; // Tiếng Bengal
991
+ static TR = 'tr'; // Tiếng Thổ Nhĩ Kỳ
992
+ static NL = 'nl'; // Tiếng Hà Lan
993
+ static KM = 'km'; // Tiếng Khmer (Campuchia)
994
+ static LO = 'lo'; // Tiếng Lào
995
+ static MY = 'my'; // Tiếng Miến Điện (Myanmar)
996
+ static TL = 'tl'; // Tiếng Tagalog (Philippines)
997
+ static CEB = 'ceb'; // Tiếng Cebuano (Philippines)
998
+ static JV = 'jv'; // Tiếng Java (Indonesia)
999
+ static SU = 'su'; // Tiếng Sundanese (Indonesia)
944
1000
  // Ngôn ngữ mặc định
945
1001
  static defaultLang = UtilsLanguageConstants.VI;
946
1002
  // Danh sách các ngôn ngữ được hỗ trợ
@@ -1026,7 +1082,7 @@ class UtilsCache {
1026
1082
  return this.Get(this.languageKeyCache, UtilsLanguageConstants.defaultLang);
1027
1083
  }
1028
1084
  static openDB() {
1029
- return new Promise(resolve => {
1085
+ return new Promise((resolve) => {
1030
1086
  const request = indexedDB.open(this.dbName, this.dbVersion);
1031
1087
  request.onupgradeneeded = (event) => {
1032
1088
  const db = event.target.result;
@@ -1098,7 +1154,7 @@ class UtilsCache {
1098
1154
  clear: () => {
1099
1155
  this.storage = {};
1100
1156
  localStorage.clear();
1101
- }
1157
+ },
1102
1158
  };
1103
1159
  }
1104
1160
  static getLocalStorageFake() {
@@ -1117,7 +1173,7 @@ class UtilsCache {
1117
1173
  },
1118
1174
  clear: () => {
1119
1175
  this.storage = {};
1120
- }
1176
+ },
1121
1177
  };
1122
1178
  }
1123
1179
  static async GetAsync(key, default_value, isKeyMD5 = false) {
@@ -1136,7 +1192,7 @@ class UtilsCache {
1136
1192
  if (data.expire === this.CACHE_EXPIRE_NONE) {
1137
1193
  return resolve(data.json);
1138
1194
  }
1139
- const currentMillisecond = (new Date().valueOf() / 1000);
1195
+ const currentMillisecond = new Date().valueOf() / 1000;
1140
1196
  if (data.expire < currentMillisecond) {
1141
1197
  return resolve(default_value);
1142
1198
  }
@@ -1149,6 +1205,7 @@ class UtilsCache {
1149
1205
  });
1150
1206
  }
1151
1207
  static Get(key, default_value) {
1208
+ // support cho những file không thể inject UtilsCache
1152
1209
  if (!key) {
1153
1210
  return this.GetDefaultValueBySpecificKey(key, default_value);
1154
1211
  }
@@ -1161,7 +1218,7 @@ class UtilsCache {
1161
1218
  if (data.expire === this.CACHE_EXPIRE_NONE) {
1162
1219
  return data.value ?? default_value;
1163
1220
  }
1164
- const currentMillisecond = (new Date().valueOf() / 1000);
1221
+ const currentMillisecond = new Date().valueOf() / 1000;
1165
1222
  if (data.expire < currentMillisecond) {
1166
1223
  return this.GetDefaultValueBySpecificKey(key, default_value);
1167
1224
  }
@@ -1176,11 +1233,12 @@ class UtilsCache {
1176
1233
  return default_value;
1177
1234
  }
1178
1235
  static async SetAsync(key, value, expireTimeBySecond = this.CACHE_EXPIRE_TIME_DEFAULT, isKeyMD5 = false) {
1236
+ // support inject UtilsCache
1179
1237
  return new Promise(async (resolve) => {
1180
1238
  const objectStore = await this.getObjectStore();
1181
1239
  key = isKeyMD5 ? key : md5(key);
1182
1240
  try {
1183
- const currentMillisecond = expireTimeBySecond === this.CACHE_EXPIRE_NONE ? this.CACHE_EXPIRE_NONE : (new Date().valueOf() / 1000) + expireTimeBySecond;
1241
+ const currentMillisecond = expireTimeBySecond === this.CACHE_EXPIRE_NONE ? this.CACHE_EXPIRE_NONE : new Date().valueOf() / 1000 + expireTimeBySecond;
1184
1242
  const data = {
1185
1243
  value: encrypt(JSON.stringify({ json: value, expire: currentMillisecond })),
1186
1244
  };
@@ -1206,10 +1264,11 @@ class UtilsCache {
1206
1264
  });
1207
1265
  }
1208
1266
  static Set(key, value, expireTimeBySecond = this.CACHE_EXPIRE_TIME_DEFAULT) {
1209
- const currentMillisecond = expireTimeBySecond === this.CACHE_EXPIRE_NONE ? this.CACHE_EXPIRE_NONE : (new Date().valueOf() / 1000) + expireTimeBySecond;
1267
+ // support cho những file không inject UtilsCache
1268
+ const currentMillisecond = expireTimeBySecond === this.CACHE_EXPIRE_NONE ? this.CACHE_EXPIRE_NONE : new Date().valueOf() / 1000 + expireTimeBySecond;
1210
1269
  const data = {
1211
1270
  value: value,
1212
- expire: currentMillisecond
1271
+ expire: currentMillisecond,
1213
1272
  };
1214
1273
  try {
1215
1274
  this.LocalStorage.setItem(key, encrypt(JSON.stringify(data)));
@@ -1264,13 +1323,13 @@ class UtilsCache {
1264
1323
  const data = {
1265
1324
  type: this.typeKeyClearLocalStorage,
1266
1325
  response: {
1267
- idEvent: this.idService
1268
- }
1326
+ idEvent: this.idService,
1327
+ },
1269
1328
  };
1270
1329
  UtilsCommunicateMicro.PostMessageToParent(data);
1271
1330
  }
1272
1331
  const keys = [...this.listKeyKeepWhenClearALll];
1273
- Object.keys(this.LocalStorage).forEach(key => {
1332
+ Object.keys(this.LocalStorage).forEach((key) => {
1274
1333
  if (key.includes('kc-callback-')) {
1275
1334
  keys.push(key);
1276
1335
  }
@@ -1316,7 +1375,7 @@ class UtilsCache {
1316
1375
  if (!Array.isArray(data)) {
1317
1376
  return resolve({});
1318
1377
  }
1319
- data.forEach(obj => {
1378
+ data.forEach((obj) => {
1320
1379
  if (obj[this.itemIndexByKey].startsWith(keyCacheStartWith)) {
1321
1380
  this.ClearAsync(obj[this.itemIndexByKey], true);
1322
1381
  }
@@ -1334,7 +1393,7 @@ class UtilsCache {
1334
1393
  if (!keys || !keys.length) {
1335
1394
  return;
1336
1395
  }
1337
- keys.forEach(key => {
1396
+ keys.forEach((key) => {
1338
1397
  if (key.startsWith(keyCache)) {
1339
1398
  this.Clear(key);
1340
1399
  }
@@ -1365,7 +1424,7 @@ dayjs.extend(updateLocale);
1365
1424
  dayjs.extend(utc);
1366
1425
  dayjs.extend(timezone);
1367
1426
  dayjs.extend(customParseFormat);
1368
- let timeZoneSetup = "Asia/Ho_Chi_Minh";
1427
+ let timeZoneSetup = 'Asia/Ho_Chi_Minh';
1369
1428
  const setDefaultTimeZone = (localeZone = timeZoneSetup) => {
1370
1429
  timeZoneSetup = localeZone;
1371
1430
  dayjs.tz.setDefault(localeZone);
@@ -1375,13 +1434,13 @@ const updateFunctionFormatDate = (functionCustom) => {
1375
1434
  functionFormatDate = functionCustom;
1376
1435
  };
1377
1436
  /**
1378
- * @description Lấy đối tượng dayjs theo config
1379
- * @param config nếu không có config sẽ trả về đối tượng dayjs là thời gian hiện tại
1380
- * @param config.date thời gian cần lấy
1381
- * @param config.returnDayjsIfConfigDateNotExist true nếu muốn trả về đối tượng dayjs nếu config.date không có
1382
- * @param config.utc true nếu muốn lấy thời gian UTC
1383
- * @param config.formatOfDate định dạng thời gian đang được truyền vào
1384
- */
1437
+ * @description Lấy đối tượng dayjs theo config
1438
+ * @param config nếu không có config sẽ trả về đối tượng dayjs là thời gian hiện tại
1439
+ * @param config.date thời gian cần lấy
1440
+ * @param config.returnDayjsIfConfigDateNotExist true nếu muốn trả về đối tượng dayjs nếu config.date không có
1441
+ * @param config.utc true nếu muốn lấy thời gian UTC
1442
+ * @param config.formatOfDate định dạng thời gian đang được truyền vào
1443
+ */
1385
1444
  const getDayjs = (config) => {
1386
1445
  if (!config) {
1387
1446
  return dayjs().tz();
@@ -1474,7 +1533,7 @@ const formatDate = (date, formatOutput = 'YYYY/MM/DD HH:mm', lang, formatInput)
1474
1533
  date = getDayjs({ date, formatOfDate: formatInput }).locale(lang);
1475
1534
  if (lang === 'vi') {
1476
1535
  dayjs.updateLocale('vi', {
1477
- monthsShort: 'Thg 1_Thg 2_Thg 3_Thg 4_Thg 5_Thg 6_Thg 7_Thg 8_Thg 9_Thg 10_Thg 11_Thg 12'.split('_')
1536
+ monthsShort: 'Thg 1_Thg 2_Thg 3_Thg 4_Thg 5_Thg 6_Thg 7_Thg 8_Thg 9_Thg 10_Thg 11_Thg 12'.split('_'),
1478
1537
  });
1479
1538
  }
1480
1539
  return date.format(getFormatData(getTypeByFormat(formatOutput), lang)) || '';
@@ -1539,6 +1598,207 @@ const getFormatData = (type, lang) => {
1539
1598
  }
1540
1599
  };
1541
1600
 
1601
+ /* eslint-disable @typescript-eslint/no-explicit-any */
1602
+ const UtilsHttpParamsRequestInstance = (options, instance) => {
1603
+ return new UtilsHttpParamsRequest(options, instance);
1604
+ };
1605
+ class UtilsHttpParamsRequest extends HttpParams {
1606
+ params = new HttpParams();
1607
+ constructor(options, instance) {
1608
+ super(options);
1609
+ if (!instance) {
1610
+ this.params = new HttpParams(options);
1611
+ return;
1612
+ }
1613
+ if (instance instanceof UtilsHttpParamsRequest) {
1614
+ this.params = instance.getInstance();
1615
+ return;
1616
+ }
1617
+ if (instance instanceof HttpParams) {
1618
+ this.params = instance;
1619
+ return;
1620
+ }
1621
+ }
1622
+ getInstance() {
1623
+ return this.params;
1624
+ }
1625
+ setInstance(instance) {
1626
+ if (instance instanceof UtilsHttpParamsRequest) {
1627
+ this.params = instance.getInstance();
1628
+ return;
1629
+ }
1630
+ if (instance instanceof HttpParams) {
1631
+ this.params = instance;
1632
+ return;
1633
+ }
1634
+ }
1635
+ set(param, value) {
1636
+ this.params = this.params.set(param, value);
1637
+ return this;
1638
+ }
1639
+ has(param) {
1640
+ return this.params.has(param);
1641
+ }
1642
+ get(param) {
1643
+ return this.params.get(param);
1644
+ }
1645
+ getAll(param) {
1646
+ return this.params.getAll(param);
1647
+ }
1648
+ keys() {
1649
+ return this.params.keys();
1650
+ }
1651
+ append(param, value) {
1652
+ this.params = this.params.append(param, value);
1653
+ return this;
1654
+ }
1655
+ appendAll(params) {
1656
+ this.params = this.params.appendAll(params);
1657
+ return this;
1658
+ }
1659
+ delete(param, value) {
1660
+ this.params = this.params.delete(param, value);
1661
+ return this;
1662
+ }
1663
+ toString() {
1664
+ return this.params.toString();
1665
+ }
1666
+ }
1667
+ // Demo su dung GET_PATH_VARIABLE
1668
+ // interface Person {
1669
+ // name: string;
1670
+ // age: number;
1671
+ // location: string;
1672
+ // }
1673
+ // type c = GET_PATH_VARIABLE<Person, unknown>;
1674
+ // const a: c = {
1675
+ // "pathVariable-age": 1,
1676
+ // "pathVariable-location": '12',
1677
+ // "pathVariable-name": '124',
1678
+ // };
1679
+
1680
+ /* eslint-disable @typescript-eslint/no-explicit-any */
1681
+ /**
1682
+ * Chuyển đổi một đối tượng hoặc giá trị thành signal
1683
+ * @param data Dữ liệu cần chuyển đổi thành signal
1684
+ * @param cloneDeepIfNotSignal Có thực hiện sao chép sâu dữ liệu trước khi chuyển đổi hay không nếu data không phải signal. Mặc định là true.
1685
+ * Đặt false nếu muốn giữ nguyên tham chiếu đến dữ liệu gốc.
1686
+ * Nếu muốn sao chép sâu đối tượng signal thì đặt cloneDeepIfNotSignal là true và acceptConvertObjectInnerWritableSignal là true.
1687
+ * @param isSignalPrimitiveType Có chuyển đổi các giá trị nguyên thủy (string, number, boolean) thành signal hay không. Mặc định là false.
1688
+ * Đặt true nếu muốn bọc các giá trị nguyên thủy trong signal.
1689
+ * @param acceptConvertObjectInnerWritableSignal Có tiếp tục tìm kiếm và chuyển đổi các đối tượng bên trong signal hay không. Mặc định là false.
1690
+ * Đặt true nếu muốn tìm và chuyển đổi các đối tượng bên trong signal hoặc chính nó thành signal mới.
1691
+ * @returns Dữ liệu đã được chuyển đổi theo kiểu T
1692
+ */
1693
+ const convertObjectToSignal = (data, cloneDeepIfNotSignal = true, isSignalPrimitiveType = false, acceptConvertObjectInnerWritableSignal = false, seen = new WeakMap()) => {
1694
+ if ((data === null || typeof data !== 'object') && !isSignal(data)) {
1695
+ return (isSignalPrimitiveType ? signal(data) : data);
1696
+ }
1697
+ if (seen.has(data)) {
1698
+ return seen.get(data);
1699
+ }
1700
+ if (isSignal(data)) {
1701
+ if (!acceptConvertObjectInnerWritableSignal) {
1702
+ return data;
1703
+ }
1704
+ seen.set(data, convertObjectToSignal(data(), cloneDeepIfNotSignal, isSignalPrimitiveType, acceptConvertObjectInnerWritableSignal, seen));
1705
+ return seen.get(data);
1706
+ }
1707
+ if (isArrayObject(data)) {
1708
+ seen.set(data, signal(data.map((item) => convertObjectToSignal(item, cloneDeepIfNotSignal, isSignalPrimitiveType, acceptConvertObjectInnerWritableSignal, seen))));
1709
+ return seen.get(data);
1710
+ }
1711
+ if (isMapObject(data)) {
1712
+ const mapCopy = new Map();
1713
+ Array.from(data.keys()).forEach((key) => {
1714
+ mapCopy.set(key, convertObjectToSignal(data.get(key), cloneDeepIfNotSignal, isSignalPrimitiveType, acceptConvertObjectInnerWritableSignal));
1715
+ });
1716
+ seen.set(data, signal(mapCopy));
1717
+ return seen.get(data);
1718
+ }
1719
+ // Bỏ qua các đối tượng async
1720
+ if (isAsyncObject(data)) {
1721
+ return data;
1722
+ }
1723
+ data = signal(cloneDeepIfNotSignal ? { ...data } : data);
1724
+ seen.set(data, data);
1725
+ for (const key in data()) {
1726
+ const value = data()[key];
1727
+ // Bỏ qua các đối tượng nguy hiểm và đặc biệt
1728
+ if (isReturnAsIsObject(value)) {
1729
+ continue;
1730
+ }
1731
+ if (Object.prototype.hasOwnProperty.call(data(), key)) {
1732
+ data()[key] = convertObjectToSignal(value, cloneDeepIfNotSignal, isSignalPrimitiveType, acceptConvertObjectInnerWritableSignal);
1733
+ }
1734
+ }
1735
+ return data;
1736
+ };
1737
+ const convertSignalToObject = (data, isCloneDeep = true, seen = new WeakMap()) => {
1738
+ let ignoreCheckSeenHasDataAfterWhile = false;
1739
+ while (isSignal(data) && !seen.has(data)) {
1740
+ const dataConvert = data();
1741
+ if (typeof dataConvert === 'object') {
1742
+ if (dataConvert === null || isReturnAsIsObject(dataConvert)) {
1743
+ return dataConvert;
1744
+ }
1745
+ seen.set(dataConvert, dataConvert);
1746
+ data = dataConvert;
1747
+ ignoreCheckSeenHasDataAfterWhile = true;
1748
+ break;
1749
+ }
1750
+ seen.set(data, dataConvert);
1751
+ data = dataConvert;
1752
+ }
1753
+ if (data === null || typeof data === 'function' || typeof data !== 'object' || isReturnAsIsObject(data)) {
1754
+ return data;
1755
+ }
1756
+ if (!ignoreCheckSeenHasDataAfterWhile && seen.has(data)) {
1757
+ return seen.get(data);
1758
+ }
1759
+ if (isArrayObject(data)) {
1760
+ if (!isSignal(data[0])) {
1761
+ return data;
1762
+ }
1763
+ seen.set(data, data.map((item) => convertSignalToObject(isCloneDeep ? cloneDeep(item) : item, isCloneDeep, seen)));
1764
+ return seen.get(data);
1765
+ }
1766
+ if (isMapObject(data)) {
1767
+ const mapCopy = new Map();
1768
+ Array.from(data.keys()).forEach((key) => {
1769
+ mapCopy.set(key, convertSignalToObject(isCloneDeep ? cloneDeep(data.get(key)) : data.get(key), isCloneDeep));
1770
+ });
1771
+ seen.set(data, mapCopy);
1772
+ return seen.get(data);
1773
+ }
1774
+ if (isSetObject(data)) {
1775
+ const setCopy = new Set();
1776
+ Array.from(data.values()).forEach((value) => {
1777
+ setCopy.add(convertSignalToObject(isCloneDeep ? cloneDeep(value) : value, isCloneDeep));
1778
+ });
1779
+ seen.set(data, setCopy);
1780
+ return seen.get(data);
1781
+ }
1782
+ // Bỏ qua các đối tượng nguy hiểm và đặc biệt
1783
+ if (isReturnAsIsObject(data)) {
1784
+ return data;
1785
+ }
1786
+ const result = isCloneDeep ? {} : data;
1787
+ seen.set(data, result);
1788
+ for (const key in data) {
1789
+ const value = data[key];
1790
+ if (Object.prototype.hasOwnProperty.call(data, key)) {
1791
+ // Bỏ qua các đối tượng nguy hiểm để tránh maximum call stack
1792
+ if (isReturnAsIsObject(value)) {
1793
+ result[key] = value;
1794
+ continue;
1795
+ }
1796
+ result[key] = convertSignalToObject(isCloneDeep ? cloneDeep(value) : value, isCloneDeep);
1797
+ }
1798
+ }
1799
+ return result;
1800
+ };
1801
+
1542
1802
  /* eslint-disable @typescript-eslint/no-explicit-any */
1543
1803
  /**Các hàm tương tự thư viện lodash */
1544
1804
  /**
@@ -1551,7 +1811,10 @@ const getFormatData = (type, lang) => {
1551
1811
  * isNil(0); // false
1552
1812
  * isNil('hello'); // false
1553
1813
  */
1554
- const isNil = (value) => {
1814
+ const isNil = (value, options) => {
1815
+ if (!options?.ignoreUnWrapSignal) {
1816
+ value = convertSignalToObject(value);
1817
+ }
1555
1818
  return value === null || value === undefined;
1556
1819
  };
1557
1820
  /**
@@ -1567,11 +1830,75 @@ const isNil = (value) => {
1567
1830
  * isEmpty([1, 2, 3]); // false
1568
1831
  * isEmpty({ a: 1 }); // false
1569
1832
  */
1570
- const isEmpty = (value) => {
1571
- while (isSignal(value)) {
1572
- value = value();
1833
+ const isEmpty = (value, options) => {
1834
+ if (!options?.ignoreUnWrapSignal) {
1835
+ value = convertSignalToObject(value);
1836
+ }
1837
+ if (options?.ignoreCheckFalsy) {
1838
+ return isEmptyTypeObject(value);
1839
+ }
1840
+ const valueIsFalsy = isFalsy(value, { ignoreUnWrapSignal: options?.ignoreUnWrapSignal, ignoreZero: true, ignoreCheckString: options?.ignoreCheckString });
1841
+ if (options?.ignoreCheckTypeObj) {
1842
+ return valueIsFalsy;
1843
+ }
1844
+ return valueIsFalsy || isEmptyTypeObject(value);
1845
+ };
1846
+ /**
1847
+ * Kiểm tra xem một giá trị có phải là object rỗng hay không
1848
+ * @param value Giá trị cần kiểm tra
1849
+ * @returns true nếu giá trị là object rỗng, false nếu không
1850
+ * @example
1851
+ * isEmptyTypeObject({}); // true
1852
+ * isEmptyTypeObject({ a: 1 }); // false
1853
+ */
1854
+ const isEmptyTypeObject = (value) => {
1855
+ return typeof value === 'object' && (JSON.stringify(value) === '{}' || JSON.stringify(value) === '[]');
1856
+ };
1857
+ /**
1858
+ * Kiểm tra xem một giá trị có phải là null, rỗng, undefined hoặc 0 hay không
1859
+ * @param value Giá trị cần kiểm tra
1860
+ * @param options Cấu hình tùy chọn
1861
+ * @param options.ignoreZero Nếu true, sẽ không kiểm tra giá trị 0
1862
+ * @returns true nếu giá trị là null, rỗng, undefined hoặc 0, false nếu không
1863
+ * @example
1864
+ * isTruthy(null); // false
1865
+ * isTruthy(''); // false
1866
+ * isTruthy(undefined); // false
1867
+ * isTruthy(0); // false
1868
+ * isTruthy({}); // false
1869
+ * isTruthy(0, { ignoreZero: true }); // true
1870
+ */
1871
+ const isTruthy = (value, options) => {
1872
+ return !isFalsy(value, options);
1873
+ };
1874
+ /**
1875
+ * Kiểm tra xem một giá trị có phải là null, rỗng, undefined hoặc 0 hay không
1876
+ * @param value Giá trị cần kiểm tra
1877
+ * @param options Cấu hình tùy chọn
1878
+ * @param options.ignoreZero Nếu true, sẽ không kiểm tra giá trị 0
1879
+ * @returns true nếu giá trị là null, rỗng, undefined hoặc 0, false nếu không
1880
+ * @example
1881
+ * isFalsy(null); // true
1882
+ * isFalsy(''); // true
1883
+ * isFalsy(undefined); // true
1884
+ * isFalsy(0); // true
1885
+ * isFalsy({}); // false
1886
+ * isFalsy(0, { ignoreZero: true }); // false
1887
+ */
1888
+ const isFalsy = (value, options) => {
1889
+ if (!options?.ignoreUnWrapSignal) {
1890
+ value = convertSignalToObject(value);
1891
+ }
1892
+ if (isNil(value, { ignoreUnWrapSignal: options?.ignoreUnWrapSignal })) {
1893
+ return true;
1573
1894
  }
1574
- return value === null || value === '' || value === undefined || (typeof value === 'object' && (JSON.stringify(value) === '{}' || JSON.stringify(value) === '[]'));
1895
+ if (options?.ignoreZero) {
1896
+ return value === '';
1897
+ }
1898
+ if (options?.ignoreCheckString) {
1899
+ return value === 0;
1900
+ }
1901
+ return value === '' || value === 0;
1575
1902
  };
1576
1903
  /**
1577
1904
  * Loại bỏ các thuộc tính của đối tượng dựa trên một hàm điều kiện
@@ -1587,7 +1914,7 @@ const omitBy = (objData, predicate) => {
1587
1914
  return objData;
1588
1915
  }
1589
1916
  const newObj = {};
1590
- Object.keys(objData).forEach(key => {
1917
+ Object.keys(objData).forEach((key) => {
1591
1918
  const valueOfKey = get(objData, key);
1592
1919
  if (!predicate(valueOfKey)) {
1593
1920
  set(newObj, key, valueOfKey);
@@ -1674,7 +2001,12 @@ const get = (obj, path, defaultValue = undefined, keepLastValueIfSignal) => {
1674
2001
  if (obj instanceof DOMRect) {
1675
2002
  return obj[path];
1676
2003
  }
1677
- const paths = Array.isArray(path) ? path : path.replace(/\[(\d+)]/g, '.$1').split('.').filter(key => key);
2004
+ const paths = Array.isArray(path)
2005
+ ? path
2006
+ : path
2007
+ .replace(/\[(\d+)]/g, '.$1')
2008
+ .split('.')
2009
+ .filter((key) => key);
1678
2010
  for (const index in paths) {
1679
2011
  const key = paths[index];
1680
2012
  if (obj instanceof CSSStyleDeclaration) {
@@ -1704,29 +2036,34 @@ const get = (obj, path, defaultValue = undefined, keepLastValueIfSignal) => {
1704
2036
  * const obj = { a: { b: 1 } };
1705
2037
  * set(obj, 'a.b', 2); // { a: { b: 2 } }
1706
2038
  */
1707
- const set = (obj, path, value) => {
1708
- if (!obj || (typeof obj !== "object" && !isSignal(obj)) || (isSignal(obj) && typeof obj() !== "object")) {
1709
- throw new Error("The first argument must be an object");
2039
+ const set = (obj, path, value, options) => {
2040
+ if (!obj || (typeof obj !== 'object' && !isSignal(obj)) || (isSignal(obj) && typeof obj() !== 'object')) {
2041
+ throw new Error('The first argument must be an object');
1710
2042
  }
1711
2043
  if (obj instanceof HttpParams) {
1712
2044
  return obj.set(`${path}`, value);
1713
2045
  }
1714
- const pathArray = Array.isArray(path) ? path : path.replace(/\[(\d+)]/g, '.[$1]').split('.').filter(key => key);
2046
+ const pathArray = Array.isArray(path)
2047
+ ? path
2048
+ : path
2049
+ .replace(/\[(\d+)]/g, '.[$1]')
2050
+ .split('.')
2051
+ .filter((key) => key);
1715
2052
  let currentObjectByKey = isSignal(obj) ? obj() : obj;
1716
2053
  let preObjectByKey = obj;
1717
2054
  pathArray.forEach((key, index) => {
1718
2055
  if (index < pathArray.length - 1) {
1719
- if (!(key in currentObjectByKey) || (typeof currentObjectByKey[key] !== "object" && !isSignal(currentObjectByKey[key]))) {
2056
+ if (!(key in currentObjectByKey) || (typeof currentObjectByKey[key] !== 'object' && !isSignal(currentObjectByKey[key]))) {
1720
2057
  const nextKey = pathArray[index + 1];
1721
2058
  key = key.replace(/\[(\d+)]/g, '$1');
1722
- currentObjectByKey[key] = /\[(\d+)]/g.test(nextKey) ? [] : {};
2059
+ currentObjectByKey[key] = /\[(\d+)]/g.test(nextKey) ? (options?.valueDefaultPathArrayUndefined ?? []) : (options?.valueDefaultPathObjectUndefined ?? {});
1723
2060
  }
1724
2061
  currentObjectByKey = key ? currentObjectByKey[key] : currentObjectByKey;
1725
2062
  preObjectByKey = currentObjectByKey;
1726
2063
  currentObjectByKey = isSignal(currentObjectByKey) ? currentObjectByKey() : currentObjectByKey;
1727
2064
  return;
1728
2065
  }
1729
- if (typeof currentObjectByKey !== "object") {
2066
+ if (typeof currentObjectByKey !== 'object') {
1730
2067
  return;
1731
2068
  }
1732
2069
  // Gán giá trị ở cuối đường dẫn
@@ -1778,7 +2115,7 @@ const set = (obj, path, value) => {
1778
2115
  * // clone là một bản sao hoàn toàn độc lập của obj
1779
2116
  */
1780
2117
  const cloneDeep = (data, options = { ignoreSignal: false }, seen = new WeakMap()) => {
1781
- if (data === null || (typeof data !== 'object' && !isSignal(data))) {
2118
+ if (data === null || (typeof data !== 'object' && !isSignal(data)) || isDangerousObject(data)) {
1782
2119
  return data;
1783
2120
  }
1784
2121
  if (seen.has(data)) {
@@ -1807,19 +2144,16 @@ const cloneDeep = (data, options = { ignoreSignal: false }, seen = new WeakMap()
1807
2144
  if (data instanceof Set) {
1808
2145
  const setCopy = new Set();
1809
2146
  seen.set(data, setCopy);
1810
- data.forEach(val => {
2147
+ data.forEach((val) => {
1811
2148
  setCopy.add(cloneDeep(val, options, seen));
1812
2149
  });
1813
2150
  return setCopy;
1814
2151
  }
1815
2152
  if (Array.isArray(data)) {
1816
- seen.set(data, data.map(item => cloneDeep(item, options, seen)));
2153
+ seen.set(data, data.map((item) => cloneDeep(item, options, seen)));
1817
2154
  return seen.get(data);
1818
2155
  }
1819
- if (data instanceof File || data instanceof Blob || Object.prototype.toString.call(data) === '[object File]') {
1820
- return data;
1821
- }
1822
- if (data instanceof TemplateRef || data instanceof ElementRef || data instanceof Element || data instanceof Promise || data instanceof Observable) {
2156
+ if (isReturnAsIsObject(data)) {
1823
2157
  return data;
1824
2158
  }
1825
2159
  if (isSignal(data)) {
@@ -1837,11 +2171,19 @@ const cloneDeep = (data, options = { ignoreSignal: false }, seen = new WeakMap()
1837
2171
  result[key] = new UtilsHttpParamsRequest(undefined, value);
1838
2172
  continue;
1839
2173
  }
2174
+ if (value instanceof Date) {
2175
+ result[key] = new Date(value.getTime());
2176
+ continue;
2177
+ }
1840
2178
  if (dayjs.isDayjs(value)) {
1841
2179
  result[key] = getDayjs({ date: value.valueOf() });
1842
2180
  continue;
1843
2181
  }
1844
- if (value instanceof TemplateRef || value instanceof ElementRef || value instanceof Element || value instanceof Promise || value instanceof Observable) {
2182
+ if (value instanceof RegExp) {
2183
+ result[key] = new RegExp(value.source, value.flags);
2184
+ continue;
2185
+ }
2186
+ if (isReturnAsIsObject(data)) {
1845
2187
  result[key] = value;
1846
2188
  continue;
1847
2189
  }
@@ -1973,6 +2315,11 @@ const range = (start, end, step) => {
1973
2315
  * isEqual({a:1}, {a:1}); // true
1974
2316
  */
1975
2317
  const isEqual = (value1, value2, options) => {
2318
+ // Handle signals
2319
+ if (!options?.ignoreUnWrapSignal) {
2320
+ value1 = convertSignalToObject(value1);
2321
+ value2 = convertSignalToObject(value2);
2322
+ }
1976
2323
  const { exactlyPosition = false, ignoreExactlyDataType = false } = options || {};
1977
2324
  if (value1 === value2 || (value1 === null && value2 === null) || (value1 === undefined && value2 === undefined)) {
1978
2325
  return true;
@@ -1980,13 +2327,6 @@ const isEqual = (value1, value2, options) => {
1980
2327
  if (ignoreExactlyDataType) {
1981
2328
  return isEqual(isNil(value1) ? undefined : `${value1}`, isNil(value2) ? undefined : `${value2}`);
1982
2329
  }
1983
- // Handle signals
1984
- while (isSignal(value1)) {
1985
- value1 = value1();
1986
- }
1987
- while (isSignal(value2)) {
1988
- value2 = value2();
1989
- }
1990
2330
  if (typeof value1 !== 'object' || typeof value2 !== 'object' || (Array.isArray(value1) && !Array.isArray(value2)) || (!Array.isArray(value1) && Array.isArray(value2))) {
1991
2331
  return false;
1992
2332
  }
@@ -1995,7 +2335,7 @@ const isEqual = (value1, value2, options) => {
1995
2335
  return false;
1996
2336
  }
1997
2337
  if (!exactlyPosition) {
1998
- return !value1.some(item => !value2.includes(item));
2338
+ return !value1.some((item) => !value2.includes(item));
1999
2339
  }
2000
2340
  return !value1.some((item, index) => !isEqual(item, value2[index], options));
2001
2341
  }
@@ -2028,7 +2368,7 @@ const uniqBy = (data, key) => {
2028
2368
  // Xử lý mảng chứa signal values
2029
2369
  if (data[0] && isSignal(data[0])) {
2030
2370
  const seen = new Set();
2031
- return data.filter(item => {
2371
+ return data.filter((item) => {
2032
2372
  const value = `${get(item, '')}`;
2033
2373
  if (seen.has(value)) {
2034
2374
  return false;
@@ -2041,7 +2381,7 @@ const uniqBy = (data, key) => {
2041
2381
  return Array.from(new Set(data));
2042
2382
  }
2043
2383
  const dataUnique = keyBy(data, key);
2044
- return Object.keys(dataUnique).map(key => dataUnique[key]);
2384
+ return Object.keys(dataUnique).map((key) => dataUnique[key]);
2045
2385
  };
2046
2386
  const generateInterface = (obj, interfaceName) => {
2047
2387
  const generateType = (value) => {
@@ -2090,11 +2430,10 @@ const generateInterface = (obj, interfaceName) => {
2090
2430
  return interfaceStr;
2091
2431
  };
2092
2432
 
2093
- ;
2094
2433
  const step = 20;
2095
2434
  const percent = 0.05;
2096
2435
  const colorStepContrastFromOrigin = (color, stepNumber) => {
2097
- return colorContrastFromOrigin(color).find(item => item.step === stepNumber);
2436
+ return colorContrastFromOrigin(color).find((item) => item.step === stepNumber);
2098
2437
  };
2099
2438
  const colorContrastFromOrigin = (color) => {
2100
2439
  const parsedColorsArray = parseColorValues(color);
@@ -2129,10 +2468,10 @@ const parseColorValues = (colorValues) => {
2129
2468
  return colorValuesArray;
2130
2469
  };
2131
2470
  const calculateShades = (colorValue) => {
2132
- return calculate(colorValue, rgbShade).concat("000000");
2471
+ return calculate(colorValue, rgbShade).concat('000000');
2133
2472
  };
2134
2473
  const calculateTints = (colorValue) => {
2135
- return calculate(colorValue, rgbTint).concat("ffffff");
2474
+ return calculate(colorValue, rgbTint).concat('ffffff');
2136
2475
  };
2137
2476
  const calculate = (colorValue, shadeOrTint) => {
2138
2477
  const color = hexToRGB(colorValue);
@@ -2142,11 +2481,21 @@ const calculate = (colorValue, shadeOrTint) => {
2142
2481
  }
2143
2482
  return shadeValues;
2144
2483
  };
2145
- const rgbShade = (rgb, i) => { return { red: rgb.red * (1 - percent * i), green: rgb.green * (1 - percent * i), blue: rgb.blue * (1 - percent * i) }; };
2146
- const rgbTint = (rgb, i) => { return { red: rgb.red + (255 - rgb.red) * i * percent, green: rgb.green + (255 - rgb.green) * i * percent, blue: rgb.blue + (255 - rgb.blue) * i * percent }; };
2147
- const rgbToHex = (rgb) => { return intToHex(rgb.red) + intToHex(rgb.green) + intToHex(rgb.blue); };
2148
- const hexToRGB = (colorValue) => { return { red: parseInt(colorValue.substr(0, 2), 16), green: parseInt(colorValue.substr(2, 2), 16), blue: parseInt(colorValue.substr(4, 2), 16) }; };
2149
- const intToHex = (rgbint) => { return pad(Math.min(Math.max(Math.round(rgbint), 0), 255).toString(16), 2); };
2484
+ const rgbShade = (rgb, i) => {
2485
+ return { red: rgb.red * (1 - percent * i), green: rgb.green * (1 - percent * i), blue: rgb.blue * (1 - percent * i) };
2486
+ };
2487
+ const rgbTint = (rgb, i) => {
2488
+ return { red: rgb.red + (255 - rgb.red) * i * percent, green: rgb.green + (255 - rgb.green) * i * percent, blue: rgb.blue + (255 - rgb.blue) * i * percent };
2489
+ };
2490
+ const rgbToHex = (rgb) => {
2491
+ return intToHex(rgb.red) + intToHex(rgb.green) + intToHex(rgb.blue);
2492
+ };
2493
+ const hexToRGB = (colorValue) => {
2494
+ return { red: parseInt(colorValue.substr(0, 2), 16), green: parseInt(colorValue.substr(2, 2), 16), blue: parseInt(colorValue.substr(4, 2), 16) };
2495
+ };
2496
+ const intToHex = (rgbint) => {
2497
+ return pad(Math.min(Math.max(Math.round(rgbint), 0), 255).toString(16), 2);
2498
+ };
2150
2499
  const pad = (number, length) => {
2151
2500
  let str = '' + number;
2152
2501
  while (str.length < length) {
@@ -2154,9 +2503,52 @@ const pad = (number, length) => {
2154
2503
  }
2155
2504
  return str;
2156
2505
  };
2157
- const listColorDefine = ['#E62222', '#B81B1B', '#EB4E4E', '#F97316', '#C75C12', '#FA8F45', '#FFB700', '#CC9200', '#FFC533', '#84CC16', '#6AA312', '#9dd645', '#00BC62', '#00A757', '#33DA8A', '#06B6D4', '#1B59C4', '#4E8CF7', '#0EA5E9',
2158
- '#1B59C4', '#4E8CF7', '#226FF5', '#1B59C4', '#4E8CF7', '#6366F1', '#4F52C1', '#8285F4', '#5B04B3', '#49038F', '#7C36C2', '#D946EF', '#AE38BF', '#E16BF2', '#EC4899', '#BD3A7A', '#F06DAD', '#F43F5E', '#C3324B', '#F6657E', '#757380', '#5E5C66', '#918F99',
2159
- '#202020', '#1A1A1A', '#4D4D4D'
2506
+ const listColorDefine = [
2507
+ '#E62222',
2508
+ '#B81B1B',
2509
+ '#EB4E4E',
2510
+ '#F97316',
2511
+ '#C75C12',
2512
+ '#FA8F45',
2513
+ '#FFB700',
2514
+ '#CC9200',
2515
+ '#FFC533',
2516
+ '#84CC16',
2517
+ '#6AA312',
2518
+ '#9dd645',
2519
+ '#00BC62',
2520
+ '#00A757',
2521
+ '#33DA8A',
2522
+ '#06B6D4',
2523
+ '#1B59C4',
2524
+ '#4E8CF7',
2525
+ '#0EA5E9',
2526
+ '#1B59C4',
2527
+ '#4E8CF7',
2528
+ '#226FF5',
2529
+ '#1B59C4',
2530
+ '#4E8CF7',
2531
+ '#6366F1',
2532
+ '#4F52C1',
2533
+ '#8285F4',
2534
+ '#5B04B3',
2535
+ '#49038F',
2536
+ '#7C36C2',
2537
+ '#D946EF',
2538
+ '#AE38BF',
2539
+ '#E16BF2',
2540
+ '#EC4899',
2541
+ '#BD3A7A',
2542
+ '#F06DAD',
2543
+ '#F43F5E',
2544
+ '#C3324B',
2545
+ '#F6657E',
2546
+ '#757380',
2547
+ '#5E5C66',
2548
+ '#918F99',
2549
+ '#202020',
2550
+ '#1A1A1A',
2551
+ '#4D4D4D',
2160
2552
  ];
2161
2553
  const getColorById = (str) => {
2162
2554
  let hashString = 0;
@@ -2165,7 +2557,7 @@ const getColorById = (str) => {
2165
2557
  }
2166
2558
  for (let i = 0; i < str.length; i++) {
2167
2559
  const char = str.charCodeAt(i);
2168
- hashString = ((hashString << 5) - hashString) + char;
2560
+ hashString = (hashString << 5) - hashString + char;
2169
2561
  hashString = hashString & hashString;
2170
2562
  }
2171
2563
  return listColorDefine[Math.abs(hashString) % listColorDefine.length];
@@ -2305,8 +2697,8 @@ const getKeyCacheByArrayObject = (keyCache, argumentsValue) => {
2305
2697
  keyBuild = `${keyBuild}${JSON.stringify(item)}`;
2306
2698
  return;
2307
2699
  }
2308
- const keys = (item instanceof HttpParams ? item.keys() : Object.keys(item)).sort(((str1, str2) => str1.localeCompare(str2)));
2309
- keys.forEach(key => {
2700
+ const keys = (item instanceof HttpParams ? item.keys() : Object.keys(item)).sort((str1, str2) => str1.localeCompare(str2));
2701
+ keys.forEach((key) => {
2310
2702
  if (key.toLocaleLowerCase() === 'pem') {
2311
2703
  return;
2312
2704
  }
@@ -2350,7 +2742,7 @@ const viewDataNumberByLanguage = (value, acceptNegativeValue, parseFixed = 1, ig
2350
2742
  return Math.round(value * fixed) / fixed;
2351
2743
  };
2352
2744
  if (parseFixed > (floatStr?.length || 0)) {
2353
- const maxParseFixed = (acceptNegativeValue && +value < 0) ? 17 : 16;
2745
+ const maxParseFixed = acceptNegativeValue && +value < 0 ? 17 : 16;
2354
2746
  const fixed = maxParseFixed - (intStr?.length || 0);
2355
2747
  parseFixed = parseFixed < fixed ? parseFixed : fixed;
2356
2748
  }
@@ -2377,7 +2769,10 @@ const viewDataNumberByLanguage = (value, acceptNegativeValue, parseFixed = 1, ig
2377
2769
  if (lang === UtilsLanguageConstants.EN) {
2378
2770
  return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
2379
2771
  }
2380
- return value.toString().replace('.', ',').replace(/\B(?=(\d{3})+(?!\d))/g, '.');
2772
+ return value
2773
+ .toString()
2774
+ .replace('.', ',')
2775
+ .replace(/\B(?=(\d{3})+(?!\d))/g, '.');
2381
2776
  }
2382
2777
  };
2383
2778
 
@@ -2391,120 +2786,14 @@ const xssFilter = async (data) => {
2391
2786
  return await functionXssFilter(data);
2392
2787
  };
2393
2788
 
2394
- /* eslint-disable @typescript-eslint/no-explicit-any */
2395
- /**
2396
- * Chuyển đổi một đối tượng hoặc giá trị thành signal
2397
- * @param data Dữ liệu cần chuyển đổi thành signal
2398
- * @param cloneDeepIfNotSignal Có thực hiện sao chép sâu dữ liệu trước khi chuyển đổi hay không nếu data không phải signal. Mặc định là true.
2399
- * Đặt false nếu muốn giữ nguyên tham chiếu đến dữ liệu gốc.
2400
- * Nếu muốn sao chép sâu đối tượng signal thì đặt cloneDeepIfNotSignal là true và acceptConvertObjectInnerWritableSignal là true.
2401
- * @param isSignalPrimitiveType Có chuyển đổi các giá trị nguyên thủy (string, number, boolean) thành signal hay không. Mặc định là false.
2402
- * Đặt true nếu muốn bọc các giá trị nguyên thủy trong signal.
2403
- * @param acceptConvertObjectInnerWritableSignal Có tiếp tục tìm kiếm và chuyển đổi các đối tượng bên trong signal hay không. Mặc định là false.
2404
- * Đặt true nếu muốn tìm và chuyển đổi các đối tượng bên trong signal hoặc chính nó thành signal mới.
2405
- * @returns Dữ liệu đã được chuyển đổi theo kiểu T
2406
- */
2407
- const convertObjectToSignal = (data, cloneDeepIfNotSignal = true, isSignalPrimitiveType = false, acceptConvertObjectInnerWritableSignal = false, seen = new WeakMap()) => {
2408
- if ((data === null || typeof data !== 'object') && !isSignal(data)) {
2409
- return (isSignalPrimitiveType ? signal(data) : data);
2410
- }
2411
- if (seen.has(data)) {
2412
- return seen.get(data);
2413
- }
2414
- if (isSignal(data)) {
2415
- if (!acceptConvertObjectInnerWritableSignal) {
2416
- return data;
2417
- }
2418
- seen.set(data, convertObjectToSignal(data(), cloneDeepIfNotSignal, isSignalPrimitiveType, acceptConvertObjectInnerWritableSignal, seen));
2419
- return seen.get(data);
2420
- }
2421
- if (Array.isArray(data)) {
2422
- seen.set(data, signal(data.map(item => convertObjectToSignal(item, cloneDeepIfNotSignal, isSignalPrimitiveType, acceptConvertObjectInnerWritableSignal, seen))));
2423
- return seen.get(data);
2424
- }
2425
- if (data instanceof Map) {
2426
- const mapCopy = new Map();
2427
- Array.from(data.keys()).forEach(key => {
2428
- mapCopy.set(key, convertObjectToSignal(data.get(key), cloneDeepIfNotSignal, isSignalPrimitiveType, acceptConvertObjectInnerWritableSignal));
2429
- });
2430
- seen.set(data, signal(mapCopy));
2431
- return seen.get(data);
2432
- }
2433
- if (data instanceof Promise || data instanceof Observable) {
2434
- return data;
2435
- }
2436
- data = signal(cloneDeepIfNotSignal ? { ...data } : data);
2437
- seen.set(data, data);
2438
- for (const key in data()) {
2439
- const value = data()[key];
2440
- if (value instanceof TemplateRef || value instanceof File || value instanceof Blob || Object.prototype.toString.call(value) === '[object File]' || value instanceof ElementRef || value instanceof Element || value instanceof Date || value instanceof RegExp || value instanceof Set || value instanceof Map || value instanceof Promise || value instanceof Observable || value instanceof HttpParams) {
2441
- continue;
2442
- }
2443
- if (Object.prototype.hasOwnProperty.call(data(), key)) {
2444
- data()[key] = convertObjectToSignal(value, cloneDeepIfNotSignal, isSignalPrimitiveType, acceptConvertObjectInnerWritableSignal);
2445
- }
2446
- }
2447
- return data;
2448
- };
2449
- const convertSignalToObject = (data, isCloneDeep = true, seen = new WeakMap()) => {
2450
- let ignoreCheckSeenHasDataAfterWhile = false;
2451
- while (isSignal(data) && !seen.has(data)) {
2452
- const dataConvert = data();
2453
- if (typeof dataConvert === 'object') {
2454
- if (dataConvert === null) {
2455
- return dataConvert;
2456
- }
2457
- seen.set(dataConvert, dataConvert);
2458
- data = dataConvert;
2459
- ignoreCheckSeenHasDataAfterWhile = true;
2460
- break;
2461
- }
2462
- seen.set(data, dataConvert);
2463
- data = dataConvert;
2464
- }
2465
- if (data === null || typeof data === 'function' || typeof data !== 'object') {
2466
- return data;
2467
- }
2468
- if (!ignoreCheckSeenHasDataAfterWhile && seen.has(data)) {
2469
- return seen.get(data);
2470
- }
2471
- if (Array.isArray(data)) {
2472
- if (!isSignal(data[0])) {
2473
- return data;
2474
- }
2475
- seen.set(data, data.map(item => convertSignalToObject((isCloneDeep ? cloneDeep(item) : item), isCloneDeep, seen)));
2476
- return seen.get(data);
2477
- }
2478
- if (data instanceof Map) {
2479
- const mapCopy = new Map();
2480
- Array.from(data.keys()).forEach(key => {
2481
- mapCopy.set(key, convertSignalToObject(isCloneDeep ? cloneDeep(data.get(key)) : data.get(key), isCloneDeep));
2482
- });
2483
- seen.set(data, mapCopy);
2484
- return seen.get(data);
2485
- }
2486
- if (data instanceof File || data instanceof Blob || Object.prototype.toString.call(data) === '[object File]') {
2487
- return data;
2488
- }
2489
- if (data instanceof TemplateRef || data instanceof ElementRef || data instanceof Element || data instanceof Promise || data instanceof Observable || data instanceof HttpParams) {
2490
- return data;
2491
- }
2492
- const result = isCloneDeep ? {} : data;
2493
- seen.set(data, result);
2494
- for (const key in data) {
2495
- const value = data[key];
2496
- if (Object.prototype.hasOwnProperty.call(data, key)) {
2497
- result[key] = convertSignalToObject(isCloneDeep ? cloneDeep(value) : value, isCloneDeep);
2498
- }
2499
- }
2500
- return result;
2501
- };
2502
-
2503
2789
  const ENCODE_URI_PATTERN = /%([0-9A-F]{2})/g;
2504
2790
  const decodeURI = (value) => {
2505
- return decodeURIComponent(value.split('').map((c) => {
2791
+ return decodeURIComponent(value
2792
+ .split('')
2793
+ .map((c) => {
2506
2794
  return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
2507
- }).join(''));
2795
+ })
2796
+ .join(''));
2508
2797
  };
2509
2798
  const encodeURI = (value) => {
2510
2799
  return encodeURIComponent(value).replace(ENCODE_URI_PATTERN, (match, p1) => {
@@ -2512,7 +2801,7 @@ const encodeURI = (value) => {
2512
2801
  });
2513
2802
  };
2514
2803
  const endCodeUrl = (params, isBody) => {
2515
- params = omitBy(params, param => param === '' || isNil(param));
2804
+ params = omitBy(params, (param) => param === '' || isNil(param));
2516
2805
  let res = '';
2517
2806
  for (const p in params) {
2518
2807
  res += `&${p}=${encodeURIComponent(params[p])}`;
@@ -2590,7 +2879,7 @@ const downloadFileByUrl = async (fileUrl, filename, onlyOpen) => {
2590
2879
  const downloadImageFromELement = (imageElement, typeFileDownload, nameFile) => {
2591
2880
  const parentElement = imageElement?.src;
2592
2881
  const blobData = convertBase64ToBlob(parentElement);
2593
- const blob = new Blob([blobData], { type: typeFileDownload || "image/png" });
2882
+ const blob = new Blob([blobData], { type: typeFileDownload || 'image/png' });
2594
2883
  const url = window.URL.createObjectURL(blob);
2595
2884
  const link = document.createElement('a');
2596
2885
  link.href = url;
@@ -2602,12 +2891,22 @@ const LINK_IMAGE_ERROR_TOKEN_INJECT = new InjectionToken('LINK_IMAGE_ERROR_TOKEN
2602
2891
  const PROCESS_BAR_STANDARD_CONFIG_DEFAULT_TOKEN_INJECT = new InjectionToken('PROCESS_BAR_STANDARD_CONFIG_DEFAULT_TOKEN_INJECT');
2603
2892
  const PROCESS_BAR_STEPS_CONFIG_DEFAULT_TOKEN_INJECT = new InjectionToken('PROCESS_BAR_STEPS_CONFIG_DEFAULT_TOKEN_INJECT');
2604
2893
 
2605
- const isTypeImage = (file) => file.type.match(/image.*/) ? true : false;
2606
- const isTypeVideo = (file) => file.type.match(/video.*/) ? true : false;
2607
- const isTypeAudio = (file) => file.type.match(/audio.*/) ? true : false;
2608
- const isTypeFile = (file) => file instanceof File || Object.prototype.toString.call(file) === '[object File]' ? true : false;
2894
+ const isTypeImage = (file) => (file.type.match(/image.*/) ? true : false);
2895
+ const isTypeVideo = (file) => (file.type.match(/video.*/) ? true : false);
2896
+ const isTypeAudio = (file) => (file.type.match(/audio.*/) ? true : false);
2897
+ const isTypeFile = (file) => (file instanceof File || Object.prototype.toString.call(file) === '[object File]' ? true : false);
2609
2898
  const ExcelExtList = ['xls', 'xlsx', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'];
2610
- const DocumentExtList = ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf', 'json', 'xml', 'application/msword',
2899
+ const DocumentExtList = [
2900
+ 'doc',
2901
+ 'docx',
2902
+ 'xls',
2903
+ 'xlsx',
2904
+ 'ppt',
2905
+ 'pptx',
2906
+ 'pdf',
2907
+ 'json',
2908
+ 'xml',
2909
+ 'application/msword',
2611
2910
  'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
2612
2911
  'application/vnd.ms-excel',
2613
2912
  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
@@ -2615,7 +2914,8 @@ const DocumentExtList = ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf', 'js
2615
2914
  'application/vnd.openxmlformats-officedocument.presentationml.presentation',
2616
2915
  'application/pdf',
2617
2916
  'application/json',
2618
- 'application/xml'];
2917
+ 'application/xml',
2918
+ ];
2619
2919
  const isIncludeDocumentExtList = (ext, listExt = DocumentExtList) => listExt.includes(ext) || listExt.includes(`application/${ext}`);
2620
2920
  const ImageExtList = ['gif', 'jpg', 'jpeg', 'png', 'image/gif', 'image/jpeg', 'image/jpeg', 'image/png'];
2621
2921
  const isIncludeImageExtList = (ext, listExt = ImageExtList) => listExt.includes(ext);
@@ -2640,7 +2940,7 @@ const getFileExtension = (file) => {
2640
2940
  fileName = url.split('/').pop() || '';
2641
2941
  set(file, 'name', fileName);
2642
2942
  }
2643
- const dots = fileName.split(".");
2943
+ const dots = fileName.split('.');
2644
2944
  if (!dots) {
2645
2945
  return;
2646
2946
  }
@@ -2743,12 +3043,12 @@ const getSmartAxisScale = (originalMaxData, options) => {
2743
3043
  }
2744
3044
  const maxValuePositive = maxValue - Math.abs(minValue);
2745
3045
  tickCount = maxValuePositive - originalMaxData > Math.abs(step) && tickCount - 1 >= minTickCount ? tickCount - 1 : tickCount;
2746
- maxValue = (step * tickCount * scaleDirection) - (minValue * scaleDirection);
3046
+ maxValue = step * tickCount * scaleDirection - minValue * scaleDirection;
2747
3047
  return {
2748
3048
  stepSize: Math.abs(step),
2749
3049
  max: maxValue,
2750
3050
  min: minValue,
2751
- tickAmount: tickCount
3051
+ tickAmount: tickCount,
2752
3052
  };
2753
3053
  }
2754
3054
  }
@@ -2763,7 +3063,7 @@ const getSmartAxisScale = (originalMaxData, options) => {
2763
3063
  stepSize: Math.abs(step),
2764
3064
  max: maxValue,
2765
3065
  min: 0,
2766
- tickAmount: minTickCount
3066
+ tickAmount: minTickCount,
2767
3067
  };
2768
3068
  };
2769
3069
  // Cache cho các giá trị lũy thừa 10 để tối ưu hiệu suất
@@ -2819,7 +3119,7 @@ const getStepCandidates = (maxData, minStep, minNegative, acceptStepIsTypeFloat
2819
3119
  const checkAndSetNegativeSteps = (stepCandidates, acceptNegative, minNegative) => {
2820
3120
  if (acceptNegative && minNegative < 0) {
2821
3121
  // Tạo các step âm và thêm vào đầu danh sách
2822
- const negativeSteps = [...stepCandidates].map(step => -step);
3122
+ const negativeSteps = [...stepCandidates].map((step) => -step);
2823
3123
  stepCandidates.unshift(...negativeSteps);
2824
3124
  }
2825
3125
  };
@@ -2832,20 +3132,20 @@ const checkAndSetNegativeSteps = (stepCandidates, acceptNegative, minNegative) =
2832
3132
  const validateInputs = (maxData, options) => {
2833
3133
  // Kiểm tra maxData âm khi không chấp nhận giá trị âm
2834
3134
  if (maxData < 0 && !options?.acceptNegative) {
2835
- throw new Error("maxData is less than 0 and acceptNegative is false");
3135
+ throw new Error('maxData is less than 0 and acceptNegative is false');
2836
3136
  }
2837
3137
  if (options?.acceptNegative) {
2838
3138
  // Kiểm tra minNegative có được cung cấp không
2839
3139
  if (isNil(options.minNegative)) {
2840
- throw new Error("minNegative is required when acceptNegative is true");
3140
+ throw new Error('minNegative is required when acceptNegative is true');
2841
3141
  }
2842
3142
  // Kiểm tra maxData phải >= minNegative
2843
3143
  if (maxData < options.minNegative) {
2844
- throw new Error("maxData is less than minNegative");
3144
+ throw new Error('maxData is less than minNegative');
2845
3145
  }
2846
3146
  // Kiểm tra minNegative phải là số âm
2847
3147
  if (options.minNegative >= 0) {
2848
- throw new Error("minNegative must be negative");
3148
+ throw new Error('minNegative must be negative');
2849
3149
  }
2850
3150
  }
2851
3151
  };
@@ -2865,7 +3165,7 @@ const revealString = (encoded) => {
2865
3165
  const decoded = base
2866
3166
  .split('')
2867
3167
  .reverse()
2868
- .map(c => String.fromCharCode(c.charCodeAt(0) ^ xorKey))
3168
+ .map((c) => String.fromCharCode(c.charCodeAt(0) ^ xorKey))
2869
3169
  .join('');
2870
3170
  return decoded;
2871
3171
  };
@@ -2896,5 +3196,5 @@ const createUniqueRandomIntGenerator = (min, max) => {
2896
3196
  * Generated bundle index. Do not edit.
2897
3197
  */
2898
3198
 
2899
- export { AudioExtList, CHARACTER_DATA_EMPTY, COMMUNICATE_MICRO_KEY_GET_ALL_MESSAGE, COMMUNICATE_MICRO_PREFIX_TYPE, DEFAULT_START_PAGE_0, DocumentExtList, ENCODE_URI_PATTERN, ERROR_MESSAGE_EMPTY_VALID, ERROR_MESSAGE_MAX_LENGTH, ERROR_MESSAGE_MAX_VALID, ERROR_MESSAGE_MIN_LENGTH, ERROR_MESSAGE_MIN_VALID, ERROR_MESSAGE_PATTEN_VALID, ExcelExtList, ImageExtList, LINK_IMAGE_ERROR_TOKEN_INJECT, PROCESS_BAR_STANDARD_CONFIG_DEFAULT_TOKEN_INJECT, PROCESS_BAR_STEPS_CONFIG_DEFAULT_TOKEN_INJECT, UtilsCache, UtilsCommunicateMicro, UtilsCommunicateMicroKeyGlobal, UtilsHttpParamsRequest, UtilsHttpParamsRequestInstance, UtilsKeyCodeConstant, UtilsLanguageConstants, UtilsUrlSearchParams, VideoExtList, base64Decode, base64Encode, capitalize, checkMouseOverInContainer, checkViewInScreen, cloneDeep, cloneIBoundingClientRect, colorContrastFromOrigin, colorStepContrastFromOrigin, convertBase64ToBlob, convertBlobToFile, convertFileToBase64, convertFileToBase64_ObjectUrl, convertHtmlToDivBlocks, convertObjectToSignal, convertSignalToObject, convertUrlToFile, createUniqueRandomIntGenerator, decodeEscapeHtml, decodeURI, decrypt, decrypt3rd, deleteUnicode, downloadFileByUrl, downloadFileByUrlUseXmlRequest, downloadImageFromELement, encodeURI, encrypt, encrypt3rd, endCodeUrl, escapeHtml, firstLetterToUpperCase, formatDate, formatNumber, formatTextCompare, fullNameFormat, generateInterface, get, getColorById, getDayjs, getDeltaFromHTML, getDeviceInfo, getDocumentByString, getDragEventByElement, getEventNameHandleClick, getFileExtension, getHTMLFromQuill, getKeyCacheByArrayObject, getLabelBySizeFile, getPlatFromBrowser, getSmartAxisScale, getViewport, groupBy, highlightByKeyword, insertContentWithRange, isDifferenceDay, isDifferenceMonth, isDifferenceYear, isEmbedFrame, isEmpty, isEqual, isIncludeAudioExtList, isIncludeDocumentExtList, isIncludeImageExtList, isIncludeVideoExtList, isNil, isTypeAudio, isTypeFile, isTypeImage, isTypeVideo, keyBy, listColorDefine, md5, omitBy, patternAccount, patternDomain, patternEmail, patternEmoji, patternEncodeUri, patternGetFieldByRuleFieldReplace, patternHostUrl, patternKey, patternMobilePhone, patternName, patternNameProfile, patternNameSpecial, patternNameUtf8, patternNumber, patternPem, patternPhone, patternPhoneNormal, patternRuleFieldReplace, patternTax, patternUrl, processPasteData, protectString, range, removeEmoji, revealString, rgbToHex, set, setCaretPosition, setDefaultTimeZone, setKeyCrypto, setKeyCrypto3rd, setStylesElement, uniqBy, updateFunctionCheckEmbedFrame, updateFunctionFormatDate, updateFunctionXssFilter, uppercaseByPosition, uuid, viewDataNumberByLanguage, xssFilter };
3199
+ export { AudioExtList, CHARACTER_DATA_EMPTY, COMMUNICATE_MICRO_KEY_GET_ALL_MESSAGE, COMMUNICATE_MICRO_PREFIX_TYPE, DEFAULT_START_PAGE_0, DocumentExtList, ENCODE_URI_PATTERN, ERROR_MESSAGE_EMPTY_VALID, ERROR_MESSAGE_MAX_LENGTH, ERROR_MESSAGE_MAX_VALID, ERROR_MESSAGE_MIN_LENGTH, ERROR_MESSAGE_MIN_VALID, ERROR_MESSAGE_PATTEN_VALID, ExcelExtList, ImageExtList, LINK_IMAGE_ERROR_TOKEN_INJECT, PROCESS_BAR_STANDARD_CONFIG_DEFAULT_TOKEN_INJECT, PROCESS_BAR_STEPS_CONFIG_DEFAULT_TOKEN_INJECT, UtilsCache, UtilsCommunicateMicro, UtilsCommunicateMicroKeyGlobal, UtilsHttpParamsRequest, UtilsHttpParamsRequestInstance, UtilsKeyCodeConstant, UtilsLanguageConstants, UtilsUrlSearchParams, VideoExtList, base64Decode, base64Encode, capitalize, checkMouseOverInContainer, checkViewInScreen, cloneDeep, cloneIBoundingClientRect, colorContrastFromOrigin, colorStepContrastFromOrigin, convertBase64ToBlob, convertBlobToFile, convertFileToBase64, convertFileToBase64_ObjectUrl, convertHtmlToDivBlocks, convertObjectToSignal, convertSignalToObject, convertUrlToFile, createUniqueRandomIntGenerator, decodeEscapeHtml, decodeURI, decrypt, decrypt3rd, deleteUnicode, downloadFileByUrl, downloadFileByUrlUseXmlRequest, downloadImageFromELement, encodeURI, encrypt, encrypt3rd, endCodeUrl, escapeHtml, firstLetterToUpperCase, formatDate, formatNumber, formatTextCompare, fullNameFormat, generateInterface, get, getColorById, getDayjs, getDeltaFromHTML, getDeviceInfo, getDocumentByString, getDragEventByElement, getEventNameHandleClick, getFileExtension, getHTMLFromQuill, getKeyCacheByArrayObject, getLabelBySizeFile, getPlatFromBrowser, getSmartAxisScale, getViewport, groupBy, hasDangerousConstructorName, highlightByKeyword, insertContentWithRange, isArrayObject, isAsyncObject, isBrowserAPIObject, isBrowserGlobalObject, isBuiltInObject, isDOMObject, isDangerousObject, isDayjsObject, isDifferenceDay, isDifferenceMonth, isDifferenceYear, isEmbedFrame, isEmpty, isEqual, isFalsy, isFileObject, isFrameworkObject, isIncludeAudioExtList, isIncludeDocumentExtList, isIncludeImageExtList, isIncludeVideoExtList, isMapObject, isNil, isReturnAsIsObject, isSafeToProcess, isSetObject, isSkippableObject, isSpecialObject, isTruthy, isTypeAudio, isTypeFile, isTypeImage, isTypeVideo, keyBy, listColorDefine, md5, omitBy, patternAccount, patternDomain, patternEmail, patternEmoji, patternEncodeUri, patternGetFieldByRuleFieldReplace, patternHostUrl, patternKey, patternMobilePhone, patternName, patternNameProfile, patternNameSpecial, patternNameUtf8, patternNumber, patternPem, patternPhone, patternPhoneNormal, patternRuleFieldReplace, patternTax, patternUrl, processPasteData, protectString, range, removeEmoji, revealString, rgbToHex, set, setCaretPosition, setDefaultTimeZone, setKeyCrypto, setKeyCrypto3rd, setStylesElement, uniqBy, updateFunctionCheckEmbedFrame, updateFunctionFormatDate, updateFunctionXssFilter, uppercaseByPosition, uuid, viewDataNumberByLanguage, xssFilter };
2900
3200
  //# sourceMappingURL=libs-ui-utils.mjs.map