@sankhyalabs/core 5.20.0-dev.5 → 5.20.0-dev.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.docs/README.md +3 -1
- package/.docs/classes/ApplicationContext.md +31 -32
- package/.docs/classes/ArrayUtils.md +95 -83
- package/.docs/classes/AuthorizedServiceCaller.md +25 -34
- package/.docs/classes/Change.md +59 -74
- package/.docs/classes/DataUnit.md +1180 -1086
- package/.docs/classes/DataUnitAction.md +25 -42
- package/.docs/classes/DataUnitStorage.md +40 -43
- package/.docs/classes/DateUtils.md +140 -133
- package/.docs/classes/ElementIDUtils.md +123 -122
- package/.docs/classes/ErrorException.md +67 -88
- package/.docs/classes/ErrorTracking.md +20 -23
- package/.docs/classes/FieldComparator.md +35 -39
- package/.docs/classes/FloatingManager.md +195 -198
- package/.docs/classes/HTMLBuilder.md +14 -20
- package/.docs/classes/HttpProvider.md +45 -41
- package/.docs/classes/IDBRepository.md +201 -196
- package/.docs/classes/JSUtils.md +65 -66
- package/.docs/classes/KeyboardManager.md +95 -87
- package/.docs/classes/{MaskFormatter-1.md → MaskFormatter.md} +93 -128
- package/.docs/classes/NumberUtils.md +163 -152
- package/.docs/classes/ObjectUtils.md +206 -70
- package/.docs/classes/OnboardingUtils.md +36 -51
- package/.docs/classes/OverflowWatcher.md +533 -0
- package/.docs/classes/PromiseSync.md +25 -42
- package/.docs/classes/ReadyUtil.md +31 -41
- package/.docs/classes/RequestMetadata.md +29 -30
- package/.docs/classes/SearchUtils.md +18 -20
- package/.docs/classes/SelectionInfo.md +73 -74
- package/.docs/classes/ServiceCanceledException.md +193 -0
- package/.docs/classes/SkwHttpProvider.md +33 -45
- package/.docs/classes/StringUtils.md +297 -322
- package/.docs/classes/TimeFormatter.md +43 -44
- package/.docs/classes/UserAgentUtils.md +17 -20
- package/.docs/classes/VersionUtils.md +15 -18
- package/.docs/classes/WaitingChangeException.md +63 -84
- package/.docs/classes/WarningException.md +67 -88
- package/.docs/enumerations/Action.md +317 -0
- package/.docs/enumerations/ChangeOperation.md +47 -0
- package/.docs/enumerations/DataType.md +57 -0
- package/.docs/enumerations/DependencyType.md +37 -0
- package/.docs/enumerations/OverflowDirection.md +29 -0
- package/.docs/enumerations/SelectionMode.md +27 -0
- package/.docs/enumerations/SortMode.md +27 -0
- package/.docs/enumerations/UserInterface.md +177 -0
- package/.docs/functions/defaultDataLoader.md +25 -0
- package/.docs/{modules.md → globals.md} +27 -36
- package/.docs/interfaces/ChildDescriptor.md +12 -16
- package/.docs/interfaces/ChildLink.md +9 -12
- package/.docs/interfaces/DUActionInterceptor.md +10 -14
- package/.docs/interfaces/ExecutionContext.md +17 -32
- package/.docs/interfaces/FieldDescriptor.md +52 -66
- package/.docs/interfaces/Filter.md +13 -17
- package/.docs/interfaces/IElementIDInfo.md +11 -14
- package/.docs/interfaces/ILoadResult.md +11 -16
- package/.docs/interfaces/IRepository.md +106 -93
- package/.docs/interfaces/IRepositoryIndex.md +23 -30
- package/.docs/interfaces/LoadDataRequest.md +36 -45
- package/.docs/interfaces/LoadDataResponse.md +11 -14
- package/.docs/interfaces/OverFlowWatcherParams.md +67 -0
- package/.docs/interfaces/PageRequest.md +16 -20
- package/.docs/interfaces/PaginationInfo.md +24 -31
- package/.docs/interfaces/PromiseSyncCallback.md +13 -17
- package/.docs/interfaces/QuickFilter.md +17 -21
- package/.docs/interfaces/Record.md +26 -33
- package/.docs/interfaces/SavedRecord.md +33 -41
- package/.docs/interfaces/Sort.md +12 -16
- package/.docs/interfaces/SortingProvider.md +10 -13
- package/.docs/interfaces/UnitMetadata.md +16 -21
- package/.docs/interfaces/WaitingChange.md +16 -20
- package/.docs/namespaces/MaskFormatter/README.md +17 -0
- package/.docs/namespaces/MaskFormatter/type-aliases/MaskCharacter.md +13 -0
- package/.docs/namespaces/MaskFormatter/variables/MaskCharacter.md +13 -0
- package/.docs/type-aliases/DataUnitEventOptions.md +17 -0
- package/.docs/type-aliases/OnOverflowCallBack.md +25 -0
- package/.docs/variables/OVERFLOWED_CLASS_NAME.md +13 -0
- package/dist/dataunit/DataUnit.d.ts +67 -6
- package/dist/dataunit/DataUnit.js +151 -32
- package/dist/dataunit/DataUnit.js.map +1 -1
- package/dist/dataunit/DataUnitHelper.js +6 -5
- package/dist/dataunit/DataUnitHelper.js.map +1 -1
- package/dist/dataunit/formatting/PrettyFormatter.js +8 -6
- package/dist/dataunit/formatting/PrettyFormatter.js.map +1 -1
- package/dist/dataunit/loading/LoadDataRequest.d.ts +1 -1
- package/dist/dataunit/metadata/DataType.js +13 -1
- package/dist/dataunit/metadata/DataType.js.map +1 -1
- package/dist/dataunit/state/action/DataUnitAction.d.ts +5 -1
- package/dist/dataunit/state/action/DataUnitAction.js +4 -0
- package/dist/dataunit/state/action/DataUnitAction.js.map +1 -1
- package/dist/dataunit/state/slice/ChangesSlice.js +12 -11
- package/dist/dataunit/state/slice/ChangesSlice.js.map +1 -1
- package/dist/dataunit/state/slice/InvalidFieldsSlice.js +2 -0
- package/dist/dataunit/state/slice/InvalidFieldsSlice.js.map +1 -1
- package/dist/dataunit/state/slice/LoadingProperties.d.ts +9 -0
- package/dist/dataunit/state/slice/LoadingProperties.js +31 -0
- package/dist/dataunit/state/slice/LoadingProperties.js.map +1 -0
- package/dist/dataunit/state/slice/RecordsSlice.js +1 -1
- package/dist/dataunit/state/slice/RecordsSlice.js.map +1 -1
- package/dist/dataunit/state/slice/SelectionSlice.js +4 -4
- package/dist/dataunit/state/slice/SelectionSlice.js.map +1 -1
- package/dist/exceptions/ServiceCanceledException.d.ts +14 -0
- package/dist/exceptions/ServiceCanceledException.js +13 -0
- package/dist/exceptions/ServiceCanceledException.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/repository/IRepository.d.ts +6 -0
- package/dist/repository/indexeddb/IDBRepository.d.ts +1 -0
- package/dist/repository/indexeddb/IDBRepository.js +3 -0
- package/dist/repository/indexeddb/IDBRepository.js.map +1 -1
- package/dist/utils/DateUtils.js +3 -0
- package/dist/utils/DateUtils.js.map +1 -1
- package/dist/utils/ElementUtils.d.ts +2 -0
- package/dist/utils/ElementUtils.js +9 -0
- package/dist/utils/ElementUtils.js.map +1 -0
- package/dist/utils/MaskFormatter.d.ts +2 -1
- package/dist/utils/MaskFormatter.js +5 -1
- package/dist/utils/MaskFormatter.js.map +1 -1
- package/dist/utils/ObjectUtils.d.ts +38 -0
- package/dist/utils/ObjectUtils.js +51 -0
- package/dist/utils/ObjectUtils.js.map +1 -1
- package/dist/utils/OnboardingUtils.js +1 -1
- package/dist/utils/OnboardingUtils.js.map +1 -1
- package/dist/utils/OverflowWatcher/index.d.ts +59 -0
- package/dist/utils/OverflowWatcher/index.js +188 -0
- package/dist/utils/OverflowWatcher/index.js.map +1 -0
- package/dist/utils/OverflowWatcher/types/overflow-callback.d.ts +6 -0
- package/dist/utils/OverflowWatcher/types/overflow-callback.js +2 -0
- package/dist/utils/OverflowWatcher/types/overflow-callback.js.map +1 -0
- package/dist/utils/OverflowWatcher/types/overflow-direction.d.ts +7 -0
- package/dist/utils/OverflowWatcher/types/overflow-direction.js +9 -0
- package/dist/utils/OverflowWatcher/types/overflow-direction.js.map +1 -0
- package/dist/utils/SortingUtils.d.ts +9 -0
- package/dist/utils/SortingUtils.js +24 -0
- package/dist/utils/SortingUtils.js.map +1 -0
- package/jest.config.ts +3 -1
- package/package.json +12 -4
- package/reports/test-report.xml +175 -0
- package/setupTests.js +7 -0
- package/sonar-project.properties +10 -0
- package/src/dataunit/DataUnit.ts +179 -46
- package/src/dataunit/DataUnitHelper.ts +6 -5
- package/src/dataunit/formatting/PrettyFormatter.ts +7 -6
- package/src/dataunit/loading/LoadDataRequest.ts +1 -1
- package/src/dataunit/metadata/DataType.ts +13 -1
- package/src/dataunit/state/action/DataUnitAction.ts +5 -1
- package/src/dataunit/state/slice/ChangesSlice.ts +15 -14
- package/src/dataunit/state/slice/InvalidFieldsSlice.ts +2 -0
- package/src/dataunit/state/slice/LoadingProperties.ts +37 -0
- package/src/dataunit/state/slice/RecordsSlice.ts +1 -1
- package/src/dataunit/state/slice/SelectionSlice.ts +4 -4
- package/src/dataunit/state/slice/test/RecordsSlice.spec.ts +45 -0
- package/src/dataunit/test/DataUnit.spec.ts +44 -0
- package/src/exceptions/ServiceCanceledException.ts +25 -0
- package/src/index.ts +10 -1
- package/src/repository/IRepository.ts +7 -0
- package/src/repository/indexeddb/IDBRepository.ts +4 -0
- package/src/utils/DateUtils.ts +3 -0
- package/src/utils/ElementUtils.ts +10 -0
- package/src/utils/MaskFormatter.ts +5 -1
- package/src/utils/ObjectUtils.ts +56 -0
- package/src/utils/OnboardingUtils.ts +1 -1
- package/src/utils/OverflowWatcher/index.ts +243 -0
- package/src/utils/OverflowWatcher/types/overflow-callback.ts +6 -0
- package/src/utils/OverflowWatcher/types/overflow-direction.ts +7 -0
- package/src/utils/SortingUtils.ts +30 -0
- package/src/utils/test/objectUtils.spec.ts +109 -0
- package/test/dataunit/formatting/PrettyFormatter.spec.ts +177 -0
- package/test/util/ElementUtils.spec.ts +34 -0
- package/test/util/OverflowWatcher.spec.ts +152 -0
- package/.docs/.nojekyll +0 -1
- package/.docs/enums/Action.md +0 -305
- package/.docs/enums/ChangeOperation.md +0 -52
- package/.docs/enums/DataType.md +0 -63
- package/.docs/enums/DependencyType.md +0 -41
- package/.docs/enums/SelectionMode.md +0 -30
- package/.docs/enums/SortMode.md +0 -30
- package/.docs/enums/UserInterface.md +0 -195
- package/.docs/modules/MaskFormatter.md +0 -37
|
@@ -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,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
|
+
});
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { getFormattedValue } from '../../../src/dataunit/formatting/PrettyFormatter';
|
|
2
|
+
import { DataType, FieldDescriptor, UserInterface } from '../../../src';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* É preciso importart o utilitário DateUtils para que seus métodos
|
|
6
|
+
* estáticos sejam executados no ambiente de testes
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { DateUtils } from '../../../src';
|
|
10
|
+
|
|
11
|
+
describe('getFormattedValue', () => {
|
|
12
|
+
it('should return empty string when value is null', () => {
|
|
13
|
+
const value = null;
|
|
14
|
+
const descriptor = getFileFieldDescriptor();
|
|
15
|
+
expect(getFormattedValue(value, descriptor)).toBe('');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should return empty string when value is not an array', () => {
|
|
19
|
+
const value = 'not an array';
|
|
20
|
+
const descriptor = getFileFieldDescriptor();
|
|
21
|
+
expect(getFormattedValue(value, descriptor)).toBe('');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should return empty string when value is an empty array', () => {
|
|
25
|
+
const value: any[] = [];
|
|
26
|
+
const descriptor = getFileFieldDescriptor();
|
|
27
|
+
expect(getFormattedValue(value, descriptor)).toBe('0 arquivos');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should return file name when value is an array with one file object', () => {
|
|
31
|
+
const value = [{ name: 'file1.txt' }];
|
|
32
|
+
const descriptor = getFileFieldDescriptor();
|
|
33
|
+
expect(getFormattedValue(value, descriptor)).toBe('file1.txt');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should return file count when value is an array with multiple file objects', () => {
|
|
37
|
+
const value = [{ name: 'file1.txt' }, { name: 'file2.txt' }];
|
|
38
|
+
const descriptor = getFileFieldDescriptor();
|
|
39
|
+
expect(getFormattedValue(value, descriptor)).toBe('2 arquivos');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should return empty string for undefined file', () => {
|
|
43
|
+
const value = undefined;
|
|
44
|
+
const descriptor = { userInterface: UserInterface.FILE } as FieldDescriptor;
|
|
45
|
+
expect(getFormattedValue(value, descriptor)).toBe('');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should handle OBJECT type with value field', () => {
|
|
49
|
+
const value = { value: 'code', label: 'label' };
|
|
50
|
+
const descriptor = { dataType: DataType.OBJECT, userInterface: UserInterface.SEARCH } as FieldDescriptor;
|
|
51
|
+
expect(getFormattedValue(value, descriptor)).toBe('code - label');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should return empty string when value is undefined', () => {
|
|
55
|
+
const value = undefined;
|
|
56
|
+
const descriptor = getObjectFieldDescriptor();
|
|
57
|
+
expect(getFormattedValue(value, descriptor)).toBe('');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should return value as string when value is not an object', () => {
|
|
61
|
+
const value = 12345;
|
|
62
|
+
const descriptor = getObjectFieldDescriptor();
|
|
63
|
+
expect(getFormattedValue(value, descriptor)).toBe('12345');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should return value.toString() when value is an object without value property', () => {
|
|
67
|
+
const value = { someProperty: 'someValue' };
|
|
68
|
+
const descriptor = getObjectFieldDescriptor();
|
|
69
|
+
expect(getFormattedValue(value, descriptor)).toBe(value.toString());
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should handle BOOLEAN type', () => {
|
|
73
|
+
expect(getFormattedValue(true, { dataType: DataType.BOOLEAN } as FieldDescriptor)).toBe('Sim');
|
|
74
|
+
expect(getFormattedValue(false, { dataType: DataType.BOOLEAN } as FieldDescriptor)).toBe('Não');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should format numbers correctly', () => {
|
|
78
|
+
const value = 1234.567;
|
|
79
|
+
const descriptor = {
|
|
80
|
+
dataType: DataType.NUMBER,
|
|
81
|
+
properties: { precision: 2, prettyPrecision: 2 },
|
|
82
|
+
} as FieldDescriptor;
|
|
83
|
+
expect(getFormattedValue(value, descriptor)).toBe('1.234,57');
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should format dates correctly', () => {
|
|
87
|
+
const value = new Date('2023-07-01T14:30:00');
|
|
88
|
+
const descriptor = { userInterface: UserInterface.DATE } as FieldDescriptor;
|
|
89
|
+
expect(getFormattedValue(value, descriptor)).toBe('01/07/2023');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should format times correctly', () => {
|
|
93
|
+
const value = new Date('2023-07-01T14:30:00');
|
|
94
|
+
const descriptor = { userInterface: UserInterface.TIME } as FieldDescriptor;
|
|
95
|
+
expect(getFormattedValue(value, descriptor)).toBe('14:30');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('should format datetime correctly', () => {
|
|
99
|
+
const value = new Date('2023-07-01T14:30:00');
|
|
100
|
+
const descriptor = { userInterface: UserInterface.DATETIME } as FieldDescriptor;
|
|
101
|
+
expect(getFormattedValue(value, descriptor)).toBe('01/07/2023 14:30');
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should call toString with correct parameters', () => {
|
|
105
|
+
const value = 123;
|
|
106
|
+
const descriptor = { dataType: DataType.NUMBER } as FieldDescriptor;
|
|
107
|
+
expect(getFormattedValue(value, descriptor)).toBe('123,00');
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('should handle undefined descriptor gracefully', () => {
|
|
111
|
+
const value = 123;
|
|
112
|
+
expect(getFormattedValue(value)).toBe('123');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should format value correctly with OPTIONSELECTOR and matching option', () => {
|
|
116
|
+
const value = 'option1';
|
|
117
|
+
const descriptor = buildOptionSelectorFieldDescriptor();
|
|
118
|
+
expect(getFormattedValue(value, descriptor)).toBe('option1');
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should return value with OPTIONSELECTOR and no matching option', () => {
|
|
122
|
+
const value = 'option2';
|
|
123
|
+
const descriptor = buildOptionSelectorFieldDescriptor();
|
|
124
|
+
expect(getFormattedValue(value, descriptor)).toBe('option2');
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('should format value correctly with OPTIONSELECTOR and value as object', () => {
|
|
128
|
+
const value = { value: 'option1' };
|
|
129
|
+
const descriptor = buildOptionSelectorFieldDescriptor();
|
|
130
|
+
expect(getFormattedValue(value, descriptor)).toBe('option1');
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('should return empty string with OPTIONSELECTOR and value as null', () => {
|
|
134
|
+
const value = null;
|
|
135
|
+
const descriptor = buildOptionSelectorFieldDescriptor();
|
|
136
|
+
expect(getFormattedValue(value, descriptor)).toBe('');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should format value correctly with OPTIONSELECTOR and options as JSON string', () => {
|
|
140
|
+
const value = 'option1';
|
|
141
|
+
const descriptor: FieldDescriptor = {
|
|
142
|
+
userInterface: UserInterface.OPTIONSELECTOR,
|
|
143
|
+
properties: { options: JSON.stringify([{ label: 'Option 1', value: 'option1' }]) },
|
|
144
|
+
} as FieldDescriptor;
|
|
145
|
+
expect(getFormattedValue(value, descriptor)).toBe('option1');
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('should return value with OPTIONSELECTOR and options as empty array', () => {
|
|
149
|
+
const value = 'option1';
|
|
150
|
+
const descriptor: FieldDescriptor = {
|
|
151
|
+
userInterface: UserInterface.OPTIONSELECTOR,
|
|
152
|
+
properties: { options: [] },
|
|
153
|
+
} as FieldDescriptor;
|
|
154
|
+
expect(getFormattedValue(value, descriptor)).toBe('option1');
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('should format masked values correctly', () => {
|
|
158
|
+
const value = '12345678901';
|
|
159
|
+
const descriptor = { properties: { mask: 'cpf' } } as FieldDescriptor;
|
|
160
|
+
expect(getFormattedValue(value, descriptor)).toBe('123.456.789-01');
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
function buildOptionSelectorFieldDescriptor(): FieldDescriptor {
|
|
165
|
+
return {
|
|
166
|
+
userInterface: UserInterface.OPTIONSELECTOR,
|
|
167
|
+
properties: { options: [{ label: 'Option 1', value: 'option1' }] },
|
|
168
|
+
} as FieldDescriptor;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function getFileFieldDescriptor(): FieldDescriptor{
|
|
172
|
+
return { userInterface: UserInterface.FILE } as FieldDescriptor;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function getObjectFieldDescriptor(): FieldDescriptor{
|
|
176
|
+
return { dataType: DataType.OBJECT } as FieldDescriptor;
|
|
177
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { calcMarginSize } from '../../src/utils/ElementUtils';
|
|
2
|
+
import { OverflowDirection } from '../../src';
|
|
3
|
+
|
|
4
|
+
describe('calcMarginSize', () => {
|
|
5
|
+
it('should calculate correctly the size of horizontal margin', () => {
|
|
6
|
+
const element = document.createElement('div');
|
|
7
|
+
element.style.marginLeft = '10px';
|
|
8
|
+
element.style.marginRight = '15px';
|
|
9
|
+
document.body.appendChild(element);
|
|
10
|
+
|
|
11
|
+
const size = calcMarginSize(element, OverflowDirection.HORIZONTAL);
|
|
12
|
+
expect(size).toBe(25);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('should calculate correctly the size of vertical margin', () => {
|
|
16
|
+
const element = document.createElement('div');
|
|
17
|
+
element.style.marginTop = '5px';
|
|
18
|
+
element.style.marginBottom = '20px';
|
|
19
|
+
document.body.appendChild(element);
|
|
20
|
+
|
|
21
|
+
const size = calcMarginSize(element, OverflowDirection.VERTICAL);
|
|
22
|
+
expect(size).toBe(25);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should threat values defined as zero', () => {
|
|
26
|
+
const element = document.createElement('div');
|
|
27
|
+
document.body.appendChild(element);
|
|
28
|
+
|
|
29
|
+
const horizontalSize = calcMarginSize(element, OverflowDirection.HORIZONTAL);
|
|
30
|
+
const verticalSize = calcMarginSize(element, OverflowDirection.VERTICAL);
|
|
31
|
+
expect(horizontalSize).toBe(0);
|
|
32
|
+
expect(verticalSize).toBe(0);
|
|
33
|
+
});
|
|
34
|
+
});
|