@sankhyalabs/core 5.20.0-dev.4 → 5.20.0-dev.40

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 (163) hide show
  1. package/.docs/README.md +3 -1
  2. package/.docs/classes/ApplicationContext.md +31 -32
  3. package/.docs/classes/ArrayUtils.md +95 -83
  4. package/.docs/classes/AuthorizedServiceCaller.md +25 -34
  5. package/.docs/classes/Change.md +59 -74
  6. package/.docs/classes/DataUnit.md +1110 -1086
  7. package/.docs/classes/DataUnitAction.md +25 -42
  8. package/.docs/classes/DataUnitStorage.md +40 -43
  9. package/.docs/classes/DateUtils.md +133 -126
  10. package/.docs/classes/ElementIDUtils.md +123 -122
  11. package/.docs/classes/ErrorException.md +67 -88
  12. package/.docs/classes/ErrorTracking.md +20 -23
  13. package/.docs/classes/FieldComparator.md +35 -39
  14. package/.docs/classes/FloatingManager.md +195 -198
  15. package/.docs/classes/HTMLBuilder.md +14 -20
  16. package/.docs/classes/HttpProvider.md +45 -41
  17. package/.docs/classes/IDBRepository.md +201 -196
  18. package/.docs/classes/JSUtils.md +65 -66
  19. package/.docs/classes/KeyboardManager.md +95 -87
  20. package/.docs/classes/{MaskFormatter-1.md → MaskFormatter.md} +93 -128
  21. package/.docs/classes/NumberUtils.md +163 -152
  22. package/.docs/classes/ObjectUtils.md +206 -70
  23. package/.docs/classes/OnboardingUtils.md +36 -51
  24. package/.docs/classes/OverflowWatcher.md +533 -0
  25. package/.docs/classes/PromiseSync.md +25 -42
  26. package/.docs/classes/ReadyUtil.md +31 -41
  27. package/.docs/classes/RequestMetadata.md +29 -30
  28. package/.docs/classes/SearchUtils.md +18 -20
  29. package/.docs/classes/SelectionInfo.md +73 -74
  30. package/.docs/classes/SkwHttpProvider.md +33 -45
  31. package/.docs/classes/StringUtils.md +297 -322
  32. package/.docs/classes/TimeFormatter.md +43 -44
  33. package/.docs/classes/UserAgentUtils.md +17 -20
  34. package/.docs/classes/VersionUtils.md +15 -18
  35. package/.docs/classes/WaitingChangeException.md +63 -84
  36. package/.docs/classes/WarningException.md +67 -88
  37. package/.docs/enumerations/Action.md +307 -0
  38. package/.docs/enumerations/ChangeOperation.md +47 -0
  39. package/.docs/enumerations/DataType.md +57 -0
  40. package/.docs/enumerations/DependencyType.md +37 -0
  41. package/.docs/enumerations/OverflowDirection.md +29 -0
  42. package/.docs/enumerations/SelectionMode.md +27 -0
  43. package/.docs/enumerations/SortMode.md +27 -0
  44. package/.docs/enumerations/UserInterface.md +177 -0
  45. package/.docs/functions/defaultDataLoader.md +25 -0
  46. package/.docs/{modules.md → globals.md} +26 -36
  47. package/.docs/interfaces/ChildDescriptor.md +12 -16
  48. package/.docs/interfaces/ChildLink.md +9 -12
  49. package/.docs/interfaces/DUActionInterceptor.md +10 -14
  50. package/.docs/interfaces/ExecutionContext.md +17 -32
  51. package/.docs/interfaces/FieldDescriptor.md +52 -66
  52. package/.docs/interfaces/Filter.md +13 -17
  53. package/.docs/interfaces/IElementIDInfo.md +11 -14
  54. package/.docs/interfaces/ILoadResult.md +11 -16
  55. package/.docs/interfaces/IRepository.md +106 -93
  56. package/.docs/interfaces/IRepositoryIndex.md +23 -30
  57. package/.docs/interfaces/LoadDataRequest.md +36 -45
  58. package/.docs/interfaces/LoadDataResponse.md +11 -14
  59. package/.docs/interfaces/OverFlowWatcherParams.md +67 -0
  60. package/.docs/interfaces/PageRequest.md +16 -20
  61. package/.docs/interfaces/PaginationInfo.md +24 -31
  62. package/.docs/interfaces/PromiseSyncCallback.md +13 -17
  63. package/.docs/interfaces/QuickFilter.md +17 -21
  64. package/.docs/interfaces/Record.md +26 -33
  65. package/.docs/interfaces/SavedRecord.md +33 -41
  66. package/.docs/interfaces/Sort.md +12 -16
  67. package/.docs/interfaces/SortingProvider.md +10 -13
  68. package/.docs/interfaces/UnitMetadata.md +16 -21
  69. package/.docs/interfaces/WaitingChange.md +16 -20
  70. package/.docs/namespaces/MaskFormatter/README.md +17 -0
  71. package/.docs/namespaces/MaskFormatter/type-aliases/MaskCharacter.md +13 -0
  72. package/.docs/namespaces/MaskFormatter/variables/MaskCharacter.md +13 -0
  73. package/.docs/type-aliases/DataUnitEventOptions.md +17 -0
  74. package/.docs/type-aliases/OnOverflowCallBack.md +25 -0
  75. package/.docs/variables/OVERFLOWED_CLASS_NAME.md +13 -0
  76. package/dist/dataunit/DataUnit.d.ts +45 -6
  77. package/dist/dataunit/DataUnit.js +116 -30
  78. package/dist/dataunit/DataUnit.js.map +1 -1
  79. package/dist/dataunit/formatting/PrettyFormatter.js +11 -7
  80. package/dist/dataunit/formatting/PrettyFormatter.js.map +1 -1
  81. package/dist/dataunit/loading/LoadDataRequest.d.ts +1 -1
  82. package/dist/dataunit/metadata/DataType.js +13 -1
  83. package/dist/dataunit/metadata/DataType.js.map +1 -1
  84. package/dist/dataunit/state/action/DataUnitAction.d.ts +4 -1
  85. package/dist/dataunit/state/action/DataUnitAction.js +3 -0
  86. package/dist/dataunit/state/action/DataUnitAction.js.map +1 -1
  87. package/dist/dataunit/state/slice/ChangesSlice.js +12 -11
  88. package/dist/dataunit/state/slice/ChangesSlice.js.map +1 -1
  89. package/dist/dataunit/state/slice/InvalidFieldsSlice.js +2 -0
  90. package/dist/dataunit/state/slice/InvalidFieldsSlice.js.map +1 -1
  91. package/dist/dataunit/state/slice/LoadingProperties.d.ts +9 -0
  92. package/dist/dataunit/state/slice/LoadingProperties.js +31 -0
  93. package/dist/dataunit/state/slice/LoadingProperties.js.map +1 -0
  94. package/dist/dataunit/state/slice/SelectionSlice.js +4 -4
  95. package/dist/dataunit/state/slice/SelectionSlice.js.map +1 -1
  96. package/dist/index.d.ts +3 -2
  97. package/dist/index.js +2 -1
  98. package/dist/index.js.map +1 -1
  99. package/dist/repository/IRepository.d.ts +6 -0
  100. package/dist/repository/indexeddb/IDBRepository.d.ts +1 -0
  101. package/dist/repository/indexeddb/IDBRepository.js +3 -0
  102. package/dist/repository/indexeddb/IDBRepository.js.map +1 -1
  103. package/dist/utils/ElementUtils.d.ts +2 -0
  104. package/dist/utils/ElementUtils.js +9 -0
  105. package/dist/utils/ElementUtils.js.map +1 -0
  106. package/dist/utils/MaskFormatter.d.ts +2 -1
  107. package/dist/utils/MaskFormatter.js +5 -1
  108. package/dist/utils/MaskFormatter.js.map +1 -1
  109. package/dist/utils/ObjectUtils.d.ts +38 -0
  110. package/dist/utils/ObjectUtils.js +51 -0
  111. package/dist/utils/ObjectUtils.js.map +1 -1
  112. package/dist/utils/OnboardingUtils.js +1 -1
  113. package/dist/utils/OnboardingUtils.js.map +1 -1
  114. package/dist/utils/OverflowWatcher/index.d.ts +59 -0
  115. package/dist/utils/OverflowWatcher/index.js +188 -0
  116. package/dist/utils/OverflowWatcher/index.js.map +1 -0
  117. package/dist/utils/OverflowWatcher/types/overflow-callback.d.ts +6 -0
  118. package/dist/utils/OverflowWatcher/types/overflow-callback.js +2 -0
  119. package/dist/utils/OverflowWatcher/types/overflow-callback.js.map +1 -0
  120. package/dist/utils/OverflowWatcher/types/overflow-direction.d.ts +7 -0
  121. package/dist/utils/OverflowWatcher/types/overflow-direction.js +9 -0
  122. package/dist/utils/OverflowWatcher/types/overflow-direction.js.map +1 -0
  123. package/dist/utils/SortingUtils.d.ts +9 -0
  124. package/dist/utils/SortingUtils.js +24 -0
  125. package/dist/utils/SortingUtils.js.map +1 -0
  126. package/jest.config.ts +3 -1
  127. package/package.json +12 -4
  128. package/reports/test-report.xml +166 -0
  129. package/setupTests.js +7 -0
  130. package/sonar-project.properties +10 -0
  131. package/src/dataunit/DataUnit.ts +139 -40
  132. package/src/dataunit/formatting/PrettyFormatter.ts +10 -7
  133. package/src/dataunit/loading/LoadDataRequest.ts +1 -1
  134. package/src/dataunit/metadata/DataType.ts +13 -1
  135. package/src/dataunit/state/action/DataUnitAction.ts +4 -1
  136. package/src/dataunit/state/slice/ChangesSlice.ts +15 -14
  137. package/src/dataunit/state/slice/InvalidFieldsSlice.ts +2 -0
  138. package/src/dataunit/state/slice/LoadingProperties.ts +37 -0
  139. package/src/dataunit/state/slice/SelectionSlice.ts +4 -4
  140. package/src/index.ts +8 -1
  141. package/src/repository/IRepository.ts +7 -0
  142. package/src/repository/indexeddb/IDBRepository.ts +4 -0
  143. package/src/utils/ElementUtils.ts +10 -0
  144. package/src/utils/MaskFormatter.ts +5 -1
  145. package/src/utils/ObjectUtils.ts +56 -0
  146. package/src/utils/OnboardingUtils.ts +1 -1
  147. package/src/utils/OverflowWatcher/index.ts +243 -0
  148. package/src/utils/OverflowWatcher/types/overflow-callback.ts +6 -0
  149. package/src/utils/OverflowWatcher/types/overflow-direction.ts +7 -0
  150. package/src/utils/SortingUtils.ts +30 -0
  151. package/src/utils/test/objectUtils.spec.ts +109 -0
  152. package/test/dataunit/formatting/PrettyFormatter.spec.ts +177 -0
  153. package/test/util/ElementUtils.spec.ts +34 -0
  154. package/test/util/OverflowWatcher.spec.ts +152 -0
  155. package/.docs/.nojekyll +0 -1
  156. package/.docs/enums/Action.md +0 -305
  157. package/.docs/enums/ChangeOperation.md +0 -52
  158. package/.docs/enums/DataType.md +0 -63
  159. package/.docs/enums/DependencyType.md +0 -41
  160. package/.docs/enums/SelectionMode.md +0 -30
  161. package/.docs/enums/SortMode.md +0 -30
  162. package/.docs/enums/UserInterface.md +0 -195
  163. package/.docs/modules/MaskFormatter.md +0 -37
@@ -0,0 +1,37 @@
1
+
2
+ import { ActionReducer, StateAction } from "../StateManager.js";
3
+ import { Action } from "../action/DataUnitAction.js";
4
+ import StateManager from "../StateManager.js";
5
+
6
+ class LoadingPropertiesImpl implements ActionReducer{
7
+
8
+ public sliceName: string = "loadingProperties";
9
+
10
+ public reduce(_stateManager:StateManager, currentState: Map<string, string>, action: StateAction): Map<string, string>|undefined {
11
+ switch(action.type){
12
+ case Action.LOADING_PROPERTY_ADDED:
13
+ return buildNewState(currentState, action.payload);
14
+ case Action.LOADING_PROPERTIES_CLEANED:
15
+ return undefined;
16
+ }
17
+ return currentState;
18
+ }
19
+ }
20
+
21
+ export const LoadingPropertiesReducer = new LoadingPropertiesImpl();
22
+
23
+ export const getLoadingProperties = (stateManager: StateManager): Map<string, string>|undefined => {
24
+ return stateManager.select(LoadingPropertiesReducer.sliceName, (state: Map<string, string>) => state);
25
+ };
26
+
27
+ function buildNewState(currentState: Map<string, string>, payload: any): Map<string, string>{
28
+ const newState = new Map(currentState);
29
+ if(payload != undefined){
30
+ for (const [key, value] of Object.entries(payload)) {
31
+ if(typeof key === "string" && typeof value === "string"){
32
+ newState.set(key, value);
33
+ }
34
+ }
35
+ }
36
+ return newState;
37
+ }
@@ -31,7 +31,7 @@ class SelectionReducerImpl implements ActionReducer {
31
31
  if (currentRecords && currentRecords.size > 0) {
32
32
  let index: number;
33
33
  if (!currentState || currentSelection.length === 0) {
34
- index = action.type === Action.PREVIOUS_SELECTED ? 0 : Math.min(1, currentRecords.size);
34
+ index = action.type === Action.PREVIOUS_SELECTED ? 0 : Math.min(0, currentRecords.size);
35
35
  } else {
36
36
  index = getItemIndex(currentSelection[0], currentRecords) + (action.type === Action.PREVIOUS_SELECTED ? -1 : 1);
37
37
  }
@@ -68,7 +68,7 @@ class SelectionReducerImpl implements ActionReducer {
68
68
  if(currentState?.lastSelection){
69
69
  return { currentSelection: currentState.lastSelection };
70
70
  }
71
- return { currentSelection: [] }
71
+ return { currentSelection: currentState?.currentSelection || [] }
72
72
  }
73
73
 
74
74
  return currentState;
@@ -94,8 +94,8 @@ export const getSelection = (stateManager: StateManager): Array<string> => {
94
94
  export const getSelectionInfo = (stateManager: StateManager): SelectionInfo => {
95
95
 
96
96
  const selection = getSelectionState(stateManager);
97
+ const currentRequest = getCurrentRequest(stateManager);
97
98
  if(selection && selection.mode === SelectionMode.ALL_RECORDS){
98
- const currentRequest = getCurrentRequest(stateManager);
99
99
  const paginationInfo: PaginationInfo | undefined = getPaginationInfo(stateManager);
100
100
  return new SelectionInfo(
101
101
  [],
@@ -106,7 +106,7 @@ export const getSelectionInfo = (stateManager: StateManager): SelectionInfo => {
106
106
  );
107
107
  }
108
108
 
109
- return new SelectionInfo(getSelectionRecords(stateManager) || [], SelectionMode.SOME_RECORDS, undefined);
109
+ return new SelectionInfo(getSelectionRecords(stateManager) || [], SelectionMode.SOME_RECORDS, undefined, undefined, currentRequest?.sort);
110
110
  }
111
111
 
112
112
  export const hasNext = (stateManager: StateManager): boolean => {
package/src/index.ts CHANGED
@@ -9,7 +9,7 @@ import { HttpProvider } from "./http/HttpProvider.js";
9
9
  import { SkwHttpProvider } from "./http/SkwHttpProvider.js";
10
10
  import { RequestMetadata } from "./http/RequestMetadata.js";
11
11
  import { AuthorizedServiceCaller } from "./http/AuthorizedServiceCaller.js";
12
- import DataUnit, {SavedRecord, Record, Change, ChangeOperation, DUActionInterceptor, WaitingChange, PageRequest, QuickFilter, SelectionMode, SelectionInfo} from "./dataunit/DataUnit.js";
12
+ import DataUnit, {SavedRecord, Record, Change, ChangeOperation, DUActionInterceptor, WaitingChange, PageRequest, QuickFilter, SelectionMode, SelectionInfo, DataUnitEventOptions} from "./dataunit/DataUnit.js";
13
13
  import { DataType } from "./dataunit/metadata/DataType.js";
14
14
  import { UnitMetadata, FieldDescriptor, UserInterface, Sort, SortMode, SortingProvider, Filter, DependencyType, ChildDescriptor, ChildLink } from "./dataunit/metadata/UnitMetadata.js";
15
15
  import { DataUnitAction, Action, ExecutionContext } from "./dataunit/state/action/DataUnitAction.js";
@@ -39,6 +39,7 @@ import { IRepositoryIndex } from "./repository/indexeddb/IRepositoryIndex.js"
39
39
  import { FieldComparator } from "./dataunit/sorting/FieldComparator.js";
40
40
  import { KeyboardManager } from "./utils/KeyboardManager/index.js";
41
41
  import { SearchUtils } from "./utils/SearchUtils.js";
42
+ import OverflowWatcher, { OnOverflowCallBack, OverflowDirection, OverFlowWatcherParams, OVERFLOWED_CLASS_NAME } from "./utils/OverflowWatcher/index.js";
42
43
 
43
44
  /*Classes públicas no pacote*/
44
45
  export {
@@ -106,4 +107,10 @@ export {
106
107
  defaultDataLoader,
107
108
  KeyboardManager,
108
109
  SearchUtils,
110
+ OverflowWatcher,
111
+ OnOverflowCallBack,
112
+ OverflowDirection,
113
+ OverFlowWatcherParams,
114
+ OVERFLOWED_CLASS_NAME,
115
+ DataUnitEventOptions
109
116
  };
@@ -79,4 +79,11 @@ export interface IRepository<T>{
79
79
  * @returns Promessa de quantidade
80
80
  */
81
81
  count(): Promise<number>;
82
+
83
+ /**
84
+ * Retorna todos os registros que estão em cache no momento
85
+ *
86
+ * @returns Todos registros que estão em cache no momento
87
+ */
88
+ getFromCache(): Array<T> | undefined
82
89
  }
@@ -320,6 +320,10 @@ export class IDBRepository<T> implements IRepository<T>{
320
320
  const tx = db.transaction(this._addedStoreName);
321
321
  return tx.objectStore(this._addedStoreName).getAll();
322
322
  }
323
+
324
+ public getFromCache(): Array<T> | undefined{
325
+ return undefined;
326
+ }
323
327
  }
324
328
 
325
329
  /**
@@ -0,0 +1,10 @@
1
+ import { OverflowDirection } from './OverflowWatcher/types/overflow-direction.js';
2
+
3
+ export function calcMarginSize(el:Element, scrollDirection: OverflowDirection){
4
+ const computedStyle = getComputedStyle(el);
5
+ if(OverflowDirection.HORIZONTAL === scrollDirection){
6
+ return (parseInt(computedStyle.marginLeft || '0') + parseInt(computedStyle.marginRight || '0'));
7
+ }
8
+
9
+ return (parseInt(computedStyle.marginTop || '0') + parseInt(computedStyle.marginBottom || '0'));
10
+ }
@@ -96,9 +96,13 @@ export class MaskFormatter {
96
96
  * Formata a string passada baseada na máscara definda pelo atributo mask.
97
97
  *
98
98
  * @param value Valor a ser formatado.
99
+ * @param trimBefore Executa um trim para remover espaços em branco.
99
100
  * @return O valor processado de acordo com o padrão.
100
101
  */
101
- public format(value: string): string {
102
+ public format(value: string, trimBefore: boolean = false): string {
103
+ if(trimBefore){
104
+ value = value.trim();
105
+ }
102
106
  let result: string = '';
103
107
  const index: Array<number> = [0];
104
108
 
@@ -84,4 +84,60 @@ 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 NÃO está vazio (sem atributos).
125
+ *
126
+ * @param obj - Objeto a ser verificado.
127
+ * @returns - True caso o objeto NÃO esteja vazio
128
+ */
129
+ public static isNotEmpty(obj: object): boolean{
130
+ return !this.isEmpty(obj);
131
+ }
132
+
133
+ /**
134
+ * Busca a propriedade de um objeto baseado em seu caminho.
135
+ *
136
+ * @param obj - Objeto a ser verificado.
137
+ * @param keyPath - Caminho da propriedade a ser buscada.
138
+ * @returns - O valor da propriedade caso ela exista.
139
+ */
140
+ public static getProp(obj: Record<string, any>, keyPath: string): Record<string, any> | undefined {
141
+ return keyPath.split('.').reduce((previous, current) => previous?.[current], obj);
142
+ }
87
143
  }
@@ -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
+ }
@@ -0,0 +1,30 @@
1
+ import DataUnit from "../dataunit/DataUnit.js";
2
+ import { FieldDescriptor, Sort, SortMode } from "../dataunit/metadata/UnitMetadata.js";
3
+ import { FieldComparator } from "../dataunit/sorting/FieldComparator.js";
4
+ import { Record } from '../dataunit/DataUnit.js';
5
+
6
+ /**
7
+ * `SortingUtils`: Utilizado para auxiliar na ordenacao de registros.
8
+ */
9
+ export default class SortingUtils {
10
+
11
+ public static getSortingFunction(dataUnit: DataUnit, sorting?: Array<Sort>): ((recordA: Record, recordB: Record) => number) | undefined {
12
+
13
+ if (sorting == undefined || sorting.length == 0) {
14
+ return undefined;
15
+ }
16
+
17
+ return (recordA, recordB) => {
18
+ for (const sort of sorting) {
19
+ if (sort.field){
20
+ const result = FieldComparator.compare(dataUnit.getField(sort.field) as FieldDescriptor, recordA, recordB, sort.mode === SortMode.ASC);
21
+ if (result != 0) {
22
+ return result;
23
+ }
24
+ }
25
+ }
26
+ return 0;
27
+ };
28
+ }
29
+
30
+ }
@@ -0,0 +1,109 @@
1
+ import ObjectUtils from '../ObjectUtils'
2
+
3
+ describe("ObjectUtils", () => {
4
+ describe('hasEquivalentValues', () => {
5
+ it('should return true if both objects have the same property value', () => {
6
+ const obj1 = { value: 10 };
7
+ const obj2 = { value: 10 };
8
+ expect(ObjectUtils.hasEquivalentProps(obj1, obj2)).toBe(true);
9
+ });
10
+
11
+ it('should return false if both objects have different property values', () => {
12
+ const obj1 = { value: 10 };
13
+ const obj2 = { value: 20 };
14
+ expect(ObjectUtils.hasEquivalentProps(obj1, obj2)).toBe(false);
15
+ });
16
+
17
+ it('should return true if both objects are equivalent with custom property to compare', () => {
18
+ const obj1 = { customProp: 'hello' };
19
+ const obj2 = { customProp: 'hello' };
20
+ expect(ObjectUtils.hasEquivalentProps(obj1, obj2, 'customProp')).toBe(true);
21
+ });
22
+
23
+ it('should return false if both objects are not equivalent with custom property to compare', () => {
24
+ const obj1 = { customProp: 'hello' };
25
+ const obj2 = { customProp: 'world' };
26
+ expect(ObjectUtils.hasEquivalentProps(obj1, obj2, 'customProp')).toBe(false);
27
+ });
28
+
29
+ it('should return false if one object does not have the property', () => {
30
+ const obj1 = { value: 10 };
31
+ const obj2 = { anotherProp: 10 };
32
+ expect(ObjectUtils.hasEquivalentProps(obj1, obj2)).toBe(false);
33
+ });
34
+
35
+ it('should return true if comparing primitive values directly', () => {
36
+ const obj1 = 5;
37
+ const obj2 = 5;
38
+ expect(ObjectUtils.hasEquivalentProps(obj1, obj2)).toBe(true);
39
+ });
40
+
41
+ it('should return false if comparing different primitive values', () => {
42
+ const obj1 = 5;
43
+ const obj2 = 10;
44
+ expect(ObjectUtils.hasEquivalentProps(obj1, obj2)).toBe(false);
45
+ });
46
+
47
+ it('should return true when comparing object with a null value', () => {
48
+ const obj1 = null;
49
+ const obj2 = null;
50
+ expect(ObjectUtils.hasEquivalentProps(obj1, obj2)).toBe(true);
51
+ });
52
+
53
+ it('should return false when comparing object with null and non-null value', () => {
54
+ const obj1 = null;
55
+ const obj2 = { value: 5 };
56
+ expect(ObjectUtils.hasEquivalentProps(obj1, obj2)).toBe(false);
57
+ });
58
+
59
+ it('should return true when comparing non-object values that are equal', () => {
60
+ const obj1 = 'same';
61
+ const obj2 = 'same';
62
+ expect(ObjectUtils.hasEquivalentProps(obj1, obj2)).toBe(true);
63
+ });
64
+
65
+ });
66
+
67
+
68
+ it("should get an object value based on its path", async () => {
69
+ const obj = {
70
+ food: {
71
+ fruits: {
72
+ apple: 1,
73
+ banana: 2
74
+ }
75
+ }
76
+ };
77
+
78
+ const value = ObjectUtils.getProp(obj, "food.fruits.banana");
79
+ expect(value).toBe(2);
80
+ });
81
+
82
+ it("should get an object value based on its path", async () => {
83
+ const food = {
84
+ fruits: {
85
+ apple: 1,
86
+ banana: 2
87
+ }
88
+ }
89
+
90
+ const obj = { food };
91
+
92
+ const value = ObjectUtils.getProp(obj, "food");
93
+ expect(JSON.stringify(value)).toBe(JSON.stringify(food));
94
+ });
95
+
96
+ it("should return undefined if the path doesn't exist in the object", async () => {
97
+ const obj = {
98
+ food: {
99
+ fruits: {
100
+ apple: 1,
101
+ banana: 2
102
+ }
103
+ }
104
+ };
105
+
106
+ const value = ObjectUtils.getProp(obj, "vegetables");
107
+ expect(value).toBe(undefined);
108
+ });
109
+ });