@sankhyalabs/core 5.20.0-dev.8 → 5.20.0-dev.81

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 (208) hide show
  1. package/.docs/classes/Base64Utils.md +39 -0
  2. package/.docs/classes/Change.md +11 -11
  3. package/.docs/classes/ColumnFilterManager.md +145 -0
  4. package/.docs/classes/DataUnit.md +429 -139
  5. package/.docs/classes/DataUnitInMemoryLoader.md +303 -0
  6. package/.docs/classes/DataUnitLoaderUtils.md +151 -0
  7. package/.docs/classes/DateUtils.md +8 -8
  8. package/.docs/classes/FieldComparator.md +2 -2
  9. package/.docs/classes/IDBRepository.md +22 -0
  10. package/.docs/classes/KeyboardManager.md +99 -9
  11. package/.docs/classes/LockManager.md +249 -0
  12. package/.docs/classes/MaskFormatter.md +66 -14
  13. package/.docs/classes/ObjectUtils.md +189 -0
  14. package/.docs/classes/OverflowWatcher.md +533 -0
  15. package/.docs/classes/SelectionInfo.md +25 -11
  16. package/.docs/classes/ServiceCanceledException.md +193 -0
  17. package/.docs/classes/ServiceUtils.md +67 -0
  18. package/.docs/classes/SilentException.md +193 -0
  19. package/.docs/classes/StringUtils.md +33 -9
  20. package/.docs/classes/UserAgentUtils.md +15 -1
  21. package/.docs/enumerations/Action.md +41 -21
  22. package/.docs/enumerations/ChangeOperation.md +4 -4
  23. package/.docs/enumerations/LockManagerOperation.md +33 -0
  24. package/.docs/enumerations/OverflowDirection.md +29 -0
  25. package/.docs/enumerations/RECORD_DATE_FORMAT.md +27 -0
  26. package/.docs/enumerations/SelectionMode.md +2 -2
  27. package/.docs/enumerations/StorageType.md +37 -0
  28. package/.docs/enumerations/UserInterface.md +15 -5
  29. package/.docs/globals.md +25 -0
  30. package/.docs/interfaces/DUActionInterceptor.md +1 -1
  31. package/.docs/interfaces/DataUnitInMemoryLoaderConfig.md +37 -0
  32. package/.docs/interfaces/IRepository.md +18 -0
  33. package/.docs/interfaces/LoadDataRequest.md +1 -1
  34. package/.docs/interfaces/OverFlowWatcherParams.md +67 -0
  35. package/.docs/interfaces/PageRequest.md +3 -3
  36. package/.docs/interfaces/PaginationInfo.md +25 -0
  37. package/.docs/interfaces/PaginationInfoBuilderParams.md +37 -0
  38. package/.docs/interfaces/QuickFilter.md +3 -3
  39. package/.docs/interfaces/Record.md +4 -4
  40. package/.docs/interfaces/SavedRecord.md +5 -5
  41. package/.docs/interfaces/WaitingChange.md +3 -3
  42. package/.docs/namespaces/MaskFormatter/type-aliases/MaskCharacter.md +1 -1
  43. package/.docs/namespaces/MaskFormatter/variables/MaskCharacter.md +1 -1
  44. package/.docs/type-aliases/DataUnitEventOptions.md +17 -0
  45. package/.docs/type-aliases/OnOverflowCallBack.md +25 -0
  46. package/.docs/variables/OVERFLOWED_CLASS_NAME.md +13 -0
  47. package/.releaserc +1 -0
  48. package/bun.lockb +0 -0
  49. package/dist/dataunit/DataUnit.d.ts +92 -13
  50. package/dist/dataunit/DataUnit.js +227 -71
  51. package/dist/dataunit/DataUnit.js.map +1 -1
  52. package/dist/dataunit/DataUnitHelper.js +6 -5
  53. package/dist/dataunit/DataUnitHelper.js.map +1 -1
  54. package/dist/dataunit/formatting/PrettyFormatter.js +17 -6
  55. package/dist/dataunit/formatting/PrettyFormatter.js.map +1 -1
  56. package/dist/dataunit/loader/DataUnitInMemoryLoaderConfig.d.ts +9 -0
  57. package/dist/dataunit/loader/DataUnitInMemoryLoaderConfig.js +6 -0
  58. package/dist/dataunit/loader/DataUnitInMemoryLoaderConfig.js.map +1 -0
  59. package/dist/dataunit/loader/dataUnitInMemoryLoader.d.ts +25 -0
  60. package/dist/dataunit/loader/dataUnitInMemoryLoader.js +131 -0
  61. package/dist/dataunit/loader/dataUnitInMemoryLoader.js.map +1 -0
  62. package/dist/dataunit/loader/utils/dataUnitLoaderUtils.d.ts +20 -0
  63. package/dist/dataunit/loader/utils/dataUnitLoaderUtils.js +62 -0
  64. package/dist/dataunit/loader/utils/dataUnitLoaderUtils.js.map +1 -0
  65. package/dist/dataunit/loading/LoadDataRequest.d.ts +1 -1
  66. package/dist/dataunit/loading/PaginationInfo.d.ts +8 -0
  67. package/dist/dataunit/metadata/DataType.js +7 -1
  68. package/dist/dataunit/metadata/DataType.js.map +1 -1
  69. package/dist/dataunit/metadata/UnitMetadata.d.ts +1 -0
  70. package/dist/dataunit/metadata/UnitMetadata.js +1 -0
  71. package/dist/dataunit/metadata/UnitMetadata.js.map +1 -1
  72. package/dist/dataunit/sorting/FieldComparator.d.ts +2 -2
  73. package/dist/dataunit/sorting/FieldComparator.js +4 -9
  74. package/dist/dataunit/sorting/FieldComparator.js.map +1 -1
  75. package/dist/dataunit/state/action/DataUnitAction.d.ts +2 -0
  76. package/dist/dataunit/state/action/DataUnitAction.js +2 -0
  77. package/dist/dataunit/state/action/DataUnitAction.js.map +1 -1
  78. package/dist/dataunit/state/slice/LoadingControlSlice.js +16 -0
  79. package/dist/dataunit/state/slice/LoadingControlSlice.js.map +1 -1
  80. package/dist/dataunit/state/slice/RecordsSlice.js +1 -1
  81. package/dist/dataunit/state/slice/RecordsSlice.js.map +1 -1
  82. package/dist/dataunit/state/slice/SelectionSlice.js +4 -4
  83. package/dist/dataunit/state/slice/SelectionSlice.js.map +1 -1
  84. package/dist/exceptions/ServiceCanceledException.d.ts +14 -0
  85. package/dist/exceptions/ServiceCanceledException.js +13 -0
  86. package/dist/exceptions/ServiceCanceledException.js.map +1 -0
  87. package/dist/exceptions/SilentException.d.ts +14 -0
  88. package/dist/exceptions/SilentException.js +13 -0
  89. package/dist/exceptions/SilentException.js.map +1 -0
  90. package/dist/index.d.ts +13 -2
  91. package/dist/index.js +12 -1
  92. package/dist/index.js.map +1 -1
  93. package/dist/repository/IRepository.d.ts +6 -0
  94. package/dist/repository/indexeddb/IDBRepository.d.ts +1 -0
  95. package/dist/repository/indexeddb/IDBRepository.js +3 -0
  96. package/dist/repository/indexeddb/IDBRepository.js.map +1 -1
  97. package/dist/utils/Base64Utils.d.ts +7 -0
  98. package/dist/utils/Base64Utils.js +13 -0
  99. package/dist/utils/Base64Utils.js.map +1 -0
  100. package/dist/utils/CacheManager/index.d.ts +52 -0
  101. package/dist/utils/CacheManager/index.js +101 -0
  102. package/dist/utils/CacheManager/index.js.map +1 -0
  103. package/dist/utils/CacheManager/interfaces/index.d.ts +5 -0
  104. package/dist/utils/CacheManager/interfaces/index.js +7 -0
  105. package/dist/utils/CacheManager/interfaces/index.js.map +1 -0
  106. package/dist/utils/ColumnFilterManager.d.ts +19 -0
  107. package/dist/utils/ColumnFilterManager.js +73 -0
  108. package/dist/utils/ColumnFilterManager.js.map +1 -0
  109. package/dist/utils/DateUtils.js +3 -0
  110. package/dist/utils/DateUtils.js.map +1 -1
  111. package/dist/utils/ElementUtils.d.ts +2 -0
  112. package/dist/utils/ElementUtils.js +9 -0
  113. package/dist/utils/ElementUtils.js.map +1 -0
  114. package/dist/utils/KeyboardManager/index.d.ts +9 -0
  115. package/dist/utils/KeyboardManager/index.js +45 -1
  116. package/dist/utils/KeyboardManager/index.js.map +1 -1
  117. package/dist/utils/KeyboardManager/interface.d.ts +1 -0
  118. package/dist/utils/LockManager.d.ts +58 -0
  119. package/dist/utils/LockManager.js +188 -0
  120. package/dist/utils/LockManager.js.map +1 -0
  121. package/dist/utils/MaskFormatter.d.ts +16 -1
  122. package/dist/utils/MaskFormatter.js +82 -2
  123. package/dist/utils/MaskFormatter.js.map +1 -1
  124. package/dist/utils/ObjectUtils.d.ts +52 -0
  125. package/dist/utils/ObjectUtils.js +71 -0
  126. package/dist/utils/ObjectUtils.js.map +1 -1
  127. package/dist/utils/OnboardingUtils.js +1 -1
  128. package/dist/utils/OnboardingUtils.js.map +1 -1
  129. package/dist/utils/OverflowWatcher/index.d.ts +59 -0
  130. package/dist/utils/OverflowWatcher/index.js +188 -0
  131. package/dist/utils/OverflowWatcher/index.js.map +1 -0
  132. package/dist/utils/OverflowWatcher/types/overflow-callback.d.ts +6 -0
  133. package/dist/utils/OverflowWatcher/types/overflow-callback.js +2 -0
  134. package/dist/utils/OverflowWatcher/types/overflow-callback.js.map +1 -0
  135. package/dist/utils/OverflowWatcher/types/overflow-direction.d.ts +7 -0
  136. package/dist/utils/OverflowWatcher/types/overflow-direction.js +9 -0
  137. package/dist/utils/OverflowWatcher/types/overflow-direction.js.map +1 -0
  138. package/dist/utils/ServiceUtils.d.ts +24 -0
  139. package/dist/utils/ServiceUtils.js +40 -0
  140. package/dist/utils/ServiceUtils.js.map +1 -0
  141. package/dist/utils/SortingUtils.d.ts +9 -0
  142. package/dist/utils/SortingUtils.js +24 -0
  143. package/dist/utils/SortingUtils.js.map +1 -0
  144. package/dist/utils/StringUtils.d.ts +6 -0
  145. package/dist/utils/StringUtils.js +23 -6
  146. package/dist/utils/StringUtils.js.map +1 -1
  147. package/dist/utils/UserAgentUtils/index.d.ts +1 -0
  148. package/dist/utils/UserAgentUtils/index.js +5 -0
  149. package/dist/utils/UserAgentUtils/index.js.map +1 -1
  150. package/jest.config.ts +2 -0
  151. package/package.json +2 -1
  152. package/reports/test-report.xml +760 -0
  153. package/setupTests.js +7 -0
  154. package/sonar-project.properties +6 -3
  155. package/src/dataunit/DataUnit.ts +278 -86
  156. package/src/dataunit/DataUnitHelper.ts +6 -5
  157. package/src/dataunit/formatting/PrettyFormatter.ts +19 -6
  158. package/src/dataunit/loader/DataUnitInMemoryLoaderConfig.ts +10 -0
  159. package/src/dataunit/loader/dataUnitInMemoryLoader.ts +176 -0
  160. package/src/dataunit/loader/utils/dataUnitLoaderUtils.ts +86 -0
  161. package/src/dataunit/loading/LoadDataRequest.ts +1 -1
  162. package/src/dataunit/loading/PaginationInfo.ts +10 -0
  163. package/src/dataunit/metadata/DataType.ts +8 -1
  164. package/src/dataunit/metadata/UnitMetadata.ts +1 -0
  165. package/src/dataunit/sorting/FieldComparator.ts +18 -32
  166. package/src/dataunit/state/action/DataUnitAction.ts +2 -0
  167. package/src/dataunit/state/slice/LoadingControlSlice.ts +42 -0
  168. package/src/dataunit/state/slice/RecordsSlice.ts +1 -1
  169. package/src/dataunit/state/slice/SelectionSlice.ts +4 -4
  170. package/src/dataunit/state/slice/test/RecordsSlice.spec.ts +45 -0
  171. package/src/dataunit/test/DataUnit.spec.ts +44 -0
  172. package/src/exceptions/ServiceCanceledException.ts +25 -0
  173. package/src/exceptions/SilentException.ts +25 -0
  174. package/src/index.ts +32 -1
  175. package/src/repository/IRepository.ts +7 -0
  176. package/src/repository/indexeddb/IDBRepository.ts +4 -0
  177. package/src/utils/Base64Utils.ts +13 -0
  178. package/src/utils/CacheManager/index.ts +103 -0
  179. package/src/utils/CacheManager/interfaces/index.ts +5 -0
  180. package/src/utils/ColumnFilterManager.ts +104 -0
  181. package/src/utils/DateUtils.ts +3 -0
  182. package/src/utils/ElementUtils.ts +10 -0
  183. package/src/utils/KeyboardManager/index.ts +57 -0
  184. package/src/utils/KeyboardManager/interface.ts +1 -0
  185. package/src/utils/LockManager.ts +207 -0
  186. package/src/utils/MaskFormatter.ts +93 -2
  187. package/src/utils/ObjectUtils.ts +77 -0
  188. package/src/utils/OnboardingUtils.ts +1 -1
  189. package/src/utils/OverflowWatcher/index.ts +243 -0
  190. package/src/utils/OverflowWatcher/types/overflow-callback.ts +6 -0
  191. package/src/utils/OverflowWatcher/types/overflow-direction.ts +7 -0
  192. package/src/utils/ServiceUtils.ts +36 -0
  193. package/src/utils/SortingUtils.ts +30 -0
  194. package/src/utils/StringUtils.ts +23 -6
  195. package/src/utils/UserAgentUtils/index.ts +6 -1
  196. package/test/dataunit/formatting/PrettyFormatter.spec.ts +177 -0
  197. package/test/dataunit/loader/dataUnitInMemoryLoader.spec.ts +221 -0
  198. package/test/dataunit/loader/utils/dataUnitLoaderUtils.spec.ts +158 -0
  199. package/test/testCases/NumberUtilsTestCases.ts +190 -0
  200. package/test/testCases/StringUtilsTestCases.ts +435 -0
  201. package/test/testCases/TimeFormatterTestUtils.ts +43 -0
  202. package/test/util/ColumnFilterManager.spec.ts +133 -0
  203. package/test/util/ElementUtils.spec.ts +34 -0
  204. package/test/util/NumberUtils.spec.ts +72 -150
  205. package/test/util/ObjectUtils.spec.ts +572 -0
  206. package/test/util/OverflowWatcher.spec.ts +152 -0
  207. package/test/util/StringUtils.spec.ts +260 -36
  208. package/test/util/TimeFormatter.spec.ts +65 -18
@@ -0,0 +1,207 @@
1
+ import { StringUtils } from "./StringUtils.js";
2
+ /**
3
+ * Define os tipos de operação que o locker pode controlar
4
+ */
5
+ export enum LockManagerOperation {
6
+ /**
7
+ Operação de lock utilizada para controlar cliques nos botoes da taskbar.
8
+ */
9
+ TASKBAR_CLICK = "taskbar_click",
10
+ /**
11
+ Operação de lock utilizada para controlar carregamento da aplicação.
12
+ */
13
+ APP_LOADING = "app_loading"
14
+ }
15
+
16
+ type Lock = {
17
+ promise?: Promise<unknown>,
18
+ resolve?: () => void,
19
+ done: boolean
20
+ }
21
+
22
+ export class LockManager {
23
+ private static _locks = new Map<string, Array<Lock>>();
24
+
25
+ /**
26
+ * Nome do atributo que será utilizado para controlar contexto de locks nos elementos da DOM.
27
+ */
28
+ public static ATTRIBUTE_NAME = "data-locker-manger-context-id";
29
+
30
+ private static buildContextID(): string {
31
+ return StringUtils.generateUUID();
32
+ }
33
+
34
+ private static buildLockerID(ctxId: string | HTMLElement, operation: LockManagerOperation): string | undefined {
35
+ if (ctxId == undefined) return undefined;
36
+
37
+ let resolvedID: any = ctxId;
38
+
39
+ if (resolvedID instanceof HTMLElement) {
40
+ resolvedID = (ctxId as HTMLElement).getAttribute(LockManager.ATTRIBUTE_NAME);
41
+ if (!resolvedID) return undefined;
42
+ }
43
+
44
+ return `${resolvedID}_${operation}`;
45
+ }
46
+
47
+ private static findExistingCtxId = (element: HTMLElement): string | null => {
48
+ let currentElement: HTMLElement | null = element;
49
+
50
+ while (currentElement) {
51
+ if (currentElement.hasAttribute(LockManager.ATTRIBUTE_NAME)) {
52
+ return currentElement.getAttribute(LockManager.ATTRIBUTE_NAME);
53
+ }
54
+
55
+ const childWithCtxId = Array.from(currentElement.children).find(child =>
56
+ (child instanceof HTMLElement) && child.hasAttribute(LockManager.ATTRIBUTE_NAME)
57
+ ) as HTMLElement | undefined;
58
+
59
+ if (childWithCtxId) {
60
+ return childWithCtxId.getAttribute(LockManager.ATTRIBUTE_NAME);
61
+ }
62
+
63
+ currentElement = currentElement.parentElement;
64
+ }
65
+
66
+ return null;
67
+ }
68
+
69
+ private static traverseAndAddAttr = (element: HTMLElement, ctxId: string): void => {
70
+ if (element.tagName.startsWith('EZ-') || element.tagName.startsWith('SNK-')) {
71
+ element.setAttribute(LockManager.ATTRIBUTE_NAME, ctxId);
72
+ }
73
+ Array.from(element.children).forEach((child) => {
74
+ if (child instanceof HTMLElement) {
75
+ LockManager.traverseAndAddAttr(child, ctxId);
76
+ }
77
+ });
78
+ };
79
+
80
+ /**
81
+ * Cria um contexto de locker, caso nao exista, para todos elementos pais iniciados com ez- ou snk-.
82
+ *
83
+ * @param startElement - Elemento de de onde o lock deve começar.
84
+ *
85
+ * @returns - O id do locker, que pode ser usado para iniciar ou aguardar um lock do contexto.
86
+ */
87
+ public static addLockManagerCtxId(startElement: HTMLElement): string {
88
+ try {
89
+ if (!startElement) {
90
+ console.error("Elemento inicial não fornecido.");
91
+ return "";
92
+ }
93
+
94
+ const ctxId = LockManager.findExistingCtxId(startElement) ?? LockManager.buildContextID();
95
+ let currentElement: HTMLElement | null = startElement;
96
+ LockManager.traverseAndAddAttr(currentElement, ctxId);
97
+ return ctxId;
98
+ } catch (err) {
99
+ console.warn(`Erro ao registrar locks para o elemento: ${startElement?.tagName}`, err);
100
+ return "";
101
+ }
102
+ }
103
+
104
+ /**
105
+ * Reseta todos os locks existentes para um determinado contexto e operação de forma assíncrona
106
+ * @param id - ID do contexto ou elemento HTML contendo contexto
107
+ * @param operation - Operação específica para resetar os locks
108
+ * @returns Promise que será resolvida quando todos os locks forem resetados
109
+ */
110
+ public static async resetLocks(id: string | HTMLElement, operation: LockManagerOperation): Promise<void> {
111
+ const lockerId = this.buildLockerID(id, operation);
112
+ if (!lockerId) return;
113
+
114
+ const currentLocks = this._locks.get(lockerId);
115
+
116
+ if (currentLocks?.length) {
117
+ await Promise.all(currentLocks.map(lock => {
118
+ lock.done = true;
119
+ lock.resolve?.();
120
+ return lock.promise;
121
+ }));
122
+
123
+ this._locks.delete(lockerId);
124
+ }
125
+ }
126
+
127
+
128
+ /**
129
+ * Inicia um locker baseado em um contexto e uma operação.
130
+ *
131
+ * @param id - Pode ser um ID do contexto de locker, ou, o elemento contendo um contexto de locker.
132
+ * @param operation - Operação do contexto que o lock deve ser feito.
133
+ *
134
+ * @returns - Uma função que fara a liberação do lock.
135
+ */
136
+ public static lock(id: string | HTMLElement, operation: LockManagerOperation): () => void {
137
+ const lockerId = LockManager.buildLockerID(id, operation);
138
+
139
+ if (!lockerId) return () => { };
140
+
141
+ const lock: Lock = { done: false };
142
+ const promise = new Promise<void>(resolve => lock.resolve = resolve);
143
+ lock.promise = promise;
144
+
145
+ const currentLocks = LockManager._locks.get(lockerId) ?? [];
146
+ currentLocks.push(lock);
147
+ LockManager._locks.set(lockerId, currentLocks);
148
+
149
+ return () => {
150
+ lock.done = true;
151
+ lock.resolve?.();
152
+ }
153
+ }
154
+
155
+ /**
156
+ * Aguarda todos os lockers de um contexto e operação serem resolvidos.
157
+ *
158
+ * @param id - Pode ser um ID do contexto de locker, ou, o elemento contendo um contexto de locker.
159
+ * @param operation - Operação do contexto que devera aguardar.
160
+ *
161
+ * @returns - Promise que será resolvida quando todos lockers forem finalizados.
162
+ */
163
+ public static async whenResolve(id: string | HTMLElement, operation: LockManagerOperation, debounce?: number, timeOut?: number): Promise<void> {
164
+ const lockerId = LockManager.buildLockerID(id, operation);
165
+
166
+ if (!lockerId) return;
167
+
168
+ if (debounce) await new Promise(resolve => setTimeout(resolve, debounce));
169
+
170
+ const startTime = Date.now();
171
+
172
+ while (LockManager._locks.get(lockerId)?.length) {
173
+
174
+ if (timeOut && Date.now() - startTime >= timeOut) {
175
+ await this.resetLocks(id, operation);
176
+ return;
177
+ }
178
+
179
+ const locks: Array<Lock> = LockManager._locks.get(lockerId) ?? [];
180
+ await Promise.all(locks.map(lock => lock.promise));
181
+
182
+ //Aguarda listeners da tela reagirem as mudancas de estado do dataunit
183
+ await new Promise(resolve => setTimeout(resolve, debounce || 200));
184
+
185
+ LockManager._locks.set(lockerId, locks.filter(lock => !lock.done));
186
+ }
187
+
188
+ }
189
+
190
+ public static async whenHasLock(id: string | HTMLElement, operation: LockManagerOperation, timeOut?: number): Promise<void> {
191
+ const lockerId = LockManager.buildLockerID(id, operation);
192
+
193
+ if (!lockerId) return;
194
+
195
+ const startTime = Date.now();
196
+
197
+ while (!LockManager._locks.get(lockerId)?.length) {
198
+
199
+ if (timeOut && Date.now() - startTime >= timeOut) {
200
+ await this.resetLocks(id, operation);
201
+ return;
202
+ }
203
+
204
+ await new Promise(resolve => setTimeout(resolve, 200));
205
+ }
206
+ }
207
+ }
@@ -58,7 +58,8 @@ export class MaskFormatter {
58
58
  "cnpj": "##.###.###/####-##",
59
59
  "cpf": "###.###.###-##",
60
60
  "phone": "(##) ####-####",
61
- "cep": "##.###-###"
61
+ "cep": "##.###-###",
62
+ "cor_rgb" : "'#AAAAAA"
62
63
  };
63
64
 
64
65
 
@@ -92,13 +93,103 @@ export class MaskFormatter {
92
93
  this.mask = mask;
93
94
  }
94
95
 
96
+
97
+ /**
98
+ * Aplica a máscara quando o input é alterado
99
+ *
100
+ * @param value Valor a ser aplicado com a máscara.
101
+ * @return O valor processado de acordo com o padrão.
102
+ */
103
+ public applyMask(value: string) {
104
+ if (this.mask === MaskFormatter.DEFAULT_MASKS.cor_rgb) {
105
+ value = value.replace("#", "")
106
+
107
+ const expectedFormattedValue = this.format(value.replace(/\s/g, ""));
108
+
109
+ if (value === expectedFormattedValue) {
110
+ return value;
111
+ }
112
+
113
+ if (value.length >= 6) {
114
+ const formattedValue = this.format(value);
115
+ return formattedValue;
116
+ } else {
117
+ return value;
118
+ }
119
+ }
120
+
121
+ const expectedFormattedValue = this.format(value.replace(/\s/g, ""));
122
+
123
+ if (value === expectedFormattedValue) {
124
+ return value;
125
+ }
126
+ const maskPlaceholders = this.mask.match(/[UAL#?*']/g) || [];
127
+ const placeholderCount = maskPlaceholders.length;
128
+
129
+ const validValue = value.split('').filter((char, index) => {
130
+ const placeholder = maskPlaceholders[index];
131
+ if (!placeholder) return false;
132
+
133
+ switch (placeholder) {
134
+ case MaskFormatter.DIGIT_KEY:
135
+ return /\d/.test(char);
136
+ case MaskFormatter.UPPERCASE_KEY:
137
+ return /[a-zA-Z]/.test(char);
138
+ case MaskFormatter.LOWERCASE_KEY:
139
+ return /[a-zA-Z]/.test(char);
140
+ case MaskFormatter.ALPHA_NUMERIC_KEY:
141
+ return /[a-zA-Z0-9]/.test(char);
142
+ case MaskFormatter.CHARACTER_KEY:
143
+ return /[a-zA-Z]/.test(char);
144
+ case MaskFormatter.ANYTHING_KEY:
145
+ return true;
146
+ case MaskFormatter.LITERAL_KEY:
147
+ const literalChar = this.mask.charAt(index);
148
+ return char === literalChar;
149
+ default:
150
+ return false;
151
+ }
152
+ });
153
+
154
+ if (validValue.length >= placeholderCount) {
155
+ const formattedValue = this.format(validValue.join(''));
156
+ return formattedValue;
157
+ } else {
158
+ const partialValue = validValue.join('');
159
+ return partialValue;
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Remove a máscara formatando a string retornando sem máscara
165
+ *
166
+ * @param value Valor a ser formatado com máscara.
167
+ * @return O valor processado de acordo com o padrão.
168
+ */
169
+ public removeMask(value: string): string {
170
+ const maskString = this.mask.replace("#", "");
171
+ const maskElements = maskString.split("");
172
+
173
+ let valueMapped = value
174
+
175
+ maskElements.forEach(maskChar => {
176
+ valueMapped = valueMapped.replace(maskChar, "")
177
+ })
178
+
179
+ return valueMapped;
180
+ }
181
+
95
182
  /**
96
183
  * Formata a string passada baseada na máscara definda pelo atributo mask.
97
184
  *
98
185
  * @param value Valor a ser formatado.
186
+ * @param trimBefore Executa um trim para remover espaços em branco.
99
187
  * @return O valor processado de acordo com o padrão.
100
188
  */
101
- public format(value: string): string {
189
+ public format(value: string, trimBefore: boolean = false): string {
190
+ if(trimBefore){
191
+ value = value.trim();
192
+ }
102
193
  let result: string = '';
103
194
  const index: Array<number> = [0];
104
195
 
@@ -84,4 +84,81 @@ export default class ObjectUtils{
84
84
  public static equals(obj1: any, obj2: any): any {
85
85
  return ObjectUtils.objectToString(obj1) === ObjectUtils.objectToString(obj2);
86
86
  }
87
+
88
+ /**
89
+ * Compara se o valor de dois items são equivalentes.
90
+ * Comparando tanto o valor do item em si, quanto sua propriedade "value"
91
+ *
92
+ * @param obj1 - Objeto a ser comparado.
93
+ * @param obj2 - Objeto a ser comparado.
94
+ * @param propToCompare - propriedade que deve ser comparada.
95
+ * @returns - Se o objeto 1 é equivalente ao objeto 2.
96
+ *
97
+ * * @example
98
+ * hasEquivalentProps('123', {value: '123', label: teste}, 'value') | Retorna: true
99
+ * @example
100
+ * hasEquivalentProps('xpto', {value: '123', label: teste}, 'propName') | Retorna: false
101
+ */
102
+ public static hasEquivalentProps(obj1: any, obj2: any, propToCompare:string = "value"): boolean{
103
+ return this.getComparableProp(obj1, propToCompare) == this.getComparableProp(obj2, propToCompare);
104
+ }
105
+
106
+ private static getComparableProp(value: any, propToCompare:string = "value"): boolean{
107
+ if (typeof value === 'object' && value !== null && propToCompare in value) {
108
+ return value[propToCompare];
109
+ }
110
+ return value;
111
+ }
112
+
113
+ /**
114
+ * Verifica se o objeto está vazio (sem atributos).
115
+ *
116
+ * @param obj - Objeto a ser verificado.
117
+ * @returns - True caso o objeto esteja vazio.
118
+ */
119
+ public static isEmpty(obj: object): boolean{
120
+ return Object.keys(obj).length === 0 && obj.constructor === Object;
121
+ }
122
+
123
+ /**
124
+ * Verifica se o objeto está vazio (sem atributos) e retorna true caso seja undefined ou null.
125
+ *
126
+ * @param obj - Objeto a ser verificado.
127
+ * @returns - True caso o objeto esteja vazio.
128
+ */
129
+ public static isEmptySafetyCheck(obj: object): boolean{
130
+ if(obj === null || obj === undefined) return true;
131
+ return Object.keys(obj).length === 0 && obj.constructor === Object;
132
+ }
133
+
134
+ /**
135
+ * Verifica se o objeto NÃO está vazio (sem atributos).
136
+ *
137
+ * @param obj - Objeto a ser verificado.
138
+ * @returns - True caso o objeto NÃO esteja vazio
139
+ */
140
+ public static isNotEmpty(obj: object): boolean{
141
+ return !this.isEmpty(obj);
142
+ }
143
+
144
+ /**
145
+ * Verifica se o objeto NÃO está vazio (sem atributos) e retorna false caso objeto seja null ou undefined.
146
+ *
147
+ * @param obj - Objeto a ser verificado.
148
+ * @returns - True caso o objeto NÃO esteja vazio
149
+ */
150
+ public static isNotEmptySafetyCheck(obj: object): boolean{
151
+ return !this.isEmptySafetyCheck(obj);
152
+ }
153
+
154
+ /**
155
+ * Busca a propriedade de um objeto baseado em seu caminho.
156
+ *
157
+ * @param obj - Objeto a ser verificado.
158
+ * @param keyPath - Caminho da propriedade a ser buscada.
159
+ * @returns - O valor da propriedade caso ela exista.
160
+ */
161
+ public static getProp(obj: Record<string, any>, keyPath: string): Record<string, any> | undefined {
162
+ return keyPath.split('.').reduce((previous, current) => previous?.[current], obj);
163
+ }
87
164
  }
@@ -32,7 +32,7 @@ export class OnboardingUtils {
32
32
  }
33
33
 
34
34
  private register(ctx: EnvironmentContext){
35
- (window as any).userGuiding.identify(`${ctx.userID}-${ctx.userName}-${ctx.clientGaId}`, ctx);
35
+ (window as any).userGuiding.identify(`${encodeURIComponent(ctx.userID)}-${encodeURIComponent(ctx.userName)}-${encodeURIComponent(ctx.clientGaId)}`, ctx);
36
36
  }
37
37
  }
38
38
 
@@ -0,0 +1,243 @@
1
+ import { JSUtils } from "../JSUtils.js";
2
+ import { OverflowDirection } from "./types/overflow-direction.js"
3
+ import { OnOverflowCallBack } from "./types/overflow-callback.js"
4
+ import { calcMarginSize } from '../ElementUtils.js';
5
+
6
+ export * from "./types/overflow-direction.js";
7
+ export * from "./types/overflow-callback.js";
8
+
9
+ export const OVERFLOWED_CLASS_NAME = 'overflowed';
10
+
11
+ export default class OverflowWatcher {
12
+ private _onResize:OnOverflowCallBack;
13
+ private _resizeObserver:ResizeObserver;
14
+ private _lastContainerSize:number|undefined = undefined;
15
+ private _lastContainerInstance: HTMLElement | undefined = undefined;
16
+ private _scrollDirection = OverflowDirection.HORIZONTAL;
17
+ private _propSize:string;
18
+ private _hiddenItemsProps:Map<Element, SizeProps> = new Map();
19
+ private _notOverFlowPros:Map<string, SizeProps> = new Map();
20
+ private _deltaSize:number;
21
+ private _notOverFlow: string[] = [];
22
+
23
+ readonly DATA_ELEMENT_ID = 'data-element-id';
24
+
25
+ /**
26
+ * Cria uma instancia do OverflowWatcher
27
+ *
28
+ * @param element - Elemento HTML que o overflow será observado.
29
+ * @param callback - Função que sera chamada quando ocorrer overflow no elemento.
30
+ * @param overFlowDirection - Indica direção que o overflow será monitorado.
31
+ * @param deltaSize - Variação de tamanho que será considerada como overflow.
32
+ * @param debounce - Tempo até execução do callback em milissegundos.
33
+ * @param notOverFlow - Lista de ids ou data-element-ids dos elementos que não devem sofrer overFlow.
34
+ */
35
+ constructor({
36
+ element,
37
+ callback,
38
+ overFlowDirection = OverflowDirection.HORIZONTAL,
39
+ debounce = 200,
40
+ deltaSize = 0,
41
+ notOverFlow = []
42
+ }: OverFlowWatcherParams){
43
+ this._onResize = callback;
44
+ this._scrollDirection = overFlowDirection;
45
+ this._propSize = (OverflowDirection.HORIZONTAL === overFlowDirection) ? "width" : "height";
46
+ this._resizeObserver = new ResizeObserver(JSUtils.debounce((entries: ResizeObserverEntry[]) => this.handleResize(entries), debounce));
47
+ this._resizeObserver.observe(element);
48
+ this._deltaSize = deltaSize;
49
+ this._notOverFlow = notOverFlow;
50
+ }
51
+
52
+ public addNotOverFlowElement(elementId: string){
53
+ if(!this._notOverFlow.includes(elementId)){
54
+ this._notOverFlow.push(elementId);
55
+ }
56
+ }
57
+
58
+ public destroy(){
59
+ this._resizeObserver.disconnect();
60
+ }
61
+
62
+ public forceUpdate(){
63
+ if(this._lastContainerSize && this._lastContainerInstance){
64
+ this.updateOverFlowedItems(this._lastContainerInstance, this._lastContainerSize);
65
+ }
66
+ }
67
+
68
+ private handleResize(entries: ResizeObserverEntry[]){
69
+ if(!entries || entries.length === 0) return;
70
+
71
+ const container = entries[0];
72
+ const containerSize:number = (container.contentRect as any)[this._propSize];
73
+ if(!containerSize) return;
74
+
75
+ if(this.hasChangedSize(containerSize)){
76
+ this.updateOverFlowedItems(container.target as HTMLElement, containerSize);
77
+ }
78
+ }
79
+
80
+ private updateOverFlowedItems(container: HTMLElement, containerSize: number){
81
+ const children:Element[] = Array.from(container.children);
82
+ this.registerNotOverflowProps(children);
83
+ this.proccessElements(containerSize, children);
84
+ this._lastContainerSize = containerSize;
85
+ this._lastContainerInstance = container;
86
+ }
87
+
88
+ private registerNotOverflowProps(children: Element[]) {
89
+ children.forEach(childElement => {
90
+ const id = childElement.id || this.getDataElementId(childElement);
91
+ if (this.canNotRegisterNotOverFlow(id)) return;
92
+ this._notOverFlowPros.set(id, this.getElementSizeProps(childElement));
93
+ });
94
+ }
95
+
96
+ private canNotRegisterNotOverFlow(id: string) {
97
+ return !id || !this._notOverFlow.includes(id) || this._notOverFlowPros.has(id);
98
+ }
99
+
100
+ private hasChangedSize(elementSize: number):boolean{
101
+ if(!this._lastContainerSize) return true;
102
+ const variation = elementSize - this._lastContainerSize;
103
+
104
+ if(variation < 0){
105
+ const absoluteVariation = Math.abs(variation);
106
+ return (absoluteVariation > this._deltaSize);
107
+ }
108
+
109
+ return variation > 0;
110
+ }
111
+
112
+ private proccessElements(elementSize:number, children:Element[]){
113
+ if(children.length === 0) return;
114
+
115
+ const childrenSize = this.calcChildrenSize(children);
116
+ let diff = Number((elementSize - childrenSize).toFixed(4));
117
+
118
+ if(diff > 0){
119
+ this.clearOverFlow();
120
+ return;
121
+ }
122
+
123
+ this.proccessElementsOverFlow(children, elementSize);
124
+ }
125
+
126
+ private clearOverFlow(){
127
+ this._hiddenItemsProps = new Map();
128
+ this._onResize([]);
129
+ }
130
+
131
+ private proccessElementsOverFlow(allElements:Element[], avaliableSize:number){
132
+ const elementsThatFit: Element[] = [];
133
+ const avaliableSizeConsideringDelta = (avaliableSize - this._deltaSize);
134
+
135
+ let sumElementsSize = 0;
136
+ for (const element of allElements) {
137
+ sumElementsSize += this.calcElementSize(element);
138
+ if(this.exceedsAvaliableSize(sumElementsSize, elementsThatFit, avaliableSizeConsideringDelta)) break;
139
+ elementsThatFit.push(element);
140
+ }
141
+
142
+ const overFlowedElements = allElements.filter(element => this.isElementOverFlowing(elementsThatFit, element));
143
+
144
+ overFlowedElements.forEach(overFlowed => {
145
+ if(!this._hiddenItemsProps.has(overFlowed)){
146
+ this.registerElementSize(overFlowed);
147
+ }
148
+ });
149
+
150
+ this._onResize(overFlowedElements);
151
+ }
152
+
153
+ private isElementOverFlowing(elementsThatFit: Element[], element: Element) {
154
+ return !elementsThatFit.includes(element) && this.canOverFlowElement(element);
155
+ }
156
+
157
+ private canOverFlowElement(element: Element) {
158
+ return !this._notOverFlow.includes(element.id)
159
+ && !this._notOverFlow.includes(this.getDataElementId(element));
160
+ }
161
+
162
+ private getDataElementId(element: Element): string {
163
+ return (element as HTMLElement).getAttribute('data-element-id') ?? "";
164
+ }
165
+
166
+ private exceedsAvaliableSize(sumElementsSize: number, elements: Element[], avaliableSize: number): boolean {
167
+ if(!this._notOverFlow.length) return sumElementsSize > avaliableSize
168
+
169
+ const elementIdsToCalculate = this.canNotOverFlowNotIncludedIds(elements);
170
+ if(!elementIdsToCalculate.length) return sumElementsSize > avaliableSize
171
+
172
+ const variation = this.calculateVariation(elementIdsToCalculate);
173
+ const occupiedSize = sumElementsSize + variation;
174
+ return occupiedSize > avaliableSize;
175
+ }
176
+
177
+ private calculateVariation(elementIdsToCalculate: string[]) {
178
+ let variation = 0
179
+ elementIdsToCalculate.forEach(id => {
180
+ const sizeProps = this._notOverFlowPros.get(id);
181
+ variation += sizeProps?.size ?? 0;
182
+ variation += sizeProps?.margin ?? 0;
183
+ });
184
+ return variation;
185
+ }
186
+
187
+ private canNotOverFlowNotIncludedIds(elements: Element[]): string[]{
188
+ const elementsIdList = elements.map(el => el.id || this.getDataElementId(el)).filter(id => !!id);
189
+ return this._notOverFlow.filter(id => !elementsIdList.includes(id));
190
+ }
191
+
192
+ private registerElementSize(element: Element) {
193
+ const sizeProps = this.getElementSizeProps(element);
194
+ this._hiddenItemsProps.set(element, sizeProps);
195
+ }
196
+
197
+ private getElementSizeProps(element: Element) {
198
+ const sizeProps: SizeProps = {
199
+ size: (element.getBoundingClientRect() as any)[this._propSize],
200
+ margin: calcMarginSize(element, this._scrollDirection),
201
+ };
202
+ return sizeProps;
203
+ }
204
+
205
+ private calcChildrenSize(children:Element[]):number{
206
+ let sumChildren = 0;
207
+ sumChildren += this._deltaSize;
208
+ Array.from(children).forEach(el => sumChildren += this.calcElementSize(el));
209
+ return sumChildren;
210
+ }
211
+
212
+ private calcElementSize(el: Element) {
213
+ let size = 0
214
+ if (this.isOverFlowed(el)) {
215
+ const sizeProps = this._hiddenItemsProps.get(el);
216
+ size += sizeProps?.size ?? 0;
217
+ size += sizeProps?.margin ?? 0;
218
+ return size;
219
+ }
220
+
221
+ size += (el.getBoundingClientRect() as any)[this._propSize];
222
+ size += calcMarginSize(el, this._scrollDirection);
223
+ return size;
224
+ }
225
+
226
+ private isOverFlowed(el: Element) {
227
+ return el.classList.contains(OVERFLOWED_CLASS_NAME);
228
+ }
229
+ }
230
+
231
+ export interface OverFlowWatcherParams {
232
+ element:HTMLElement,
233
+ callback:OnOverflowCallBack,
234
+ overFlowDirection?:OverflowDirection,
235
+ deltaSize?:number,
236
+ debounce?: number,
237
+ notOverFlow?: string[]
238
+ }
239
+
240
+ interface SizeProps {
241
+ size: number,
242
+ margin: number,
243
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Callback que será chamado quando o overflow de um elemento for alterado.
3
+ *
4
+ * @param elementsOverFlow - Conjunto de elementos filhos que estão causando overflow no elemento pai.
5
+ */
6
+ export type OnOverflowCallBack = (elementsOverFlow:Array<Element>) => void;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Define em qual direção o overflow será observado
3
+ */
4
+ export enum OverflowDirection {
5
+ 'VERTICAL',
6
+ 'HORIZONTAL'
7
+ }