@sankhyalabs/core 0.0.0-bugfix-dev-32613.0 → 0.0.0-bugfix-dev-KB-43388.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) 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 +1025 -1078
  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 +179 -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} +81 -120
  21. package/.docs/classes/NumberUtils.md +163 -152
  22. package/.docs/classes/ObjectUtils.md +66 -71
  23. package/.docs/classes/OnboardingUtils.md +36 -51
  24. package/.docs/classes/OverflowWatcher.md +515 -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 +59 -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 +297 -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} +25 -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 +88 -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/OnOverflowCallBack.md +25 -0
  74. package/.docs/variables/OVERFLOWED_CLASS_NAME.md +13 -0
  75. package/.releaserc +10 -10
  76. package/dist/dataunit/DataUnit.d.ts +24 -2
  77. package/dist/dataunit/DataUnit.js +49 -9
  78. package/dist/dataunit/DataUnit.js.map +1 -1
  79. package/dist/dataunit/formatting/PrettyFormatter.js +9 -5
  80. package/dist/dataunit/formatting/PrettyFormatter.js.map +1 -1
  81. package/dist/dataunit/metadata/DataType.js +10 -1
  82. package/dist/dataunit/metadata/DataType.js.map +1 -1
  83. package/dist/dataunit/state/action/DataUnitAction.d.ts +3 -1
  84. package/dist/dataunit/state/action/DataUnitAction.js +2 -0
  85. package/dist/dataunit/state/action/DataUnitAction.js.map +1 -1
  86. package/dist/dataunit/state/slice/ChangesSlice.js +12 -11
  87. package/dist/dataunit/state/slice/ChangesSlice.js.map +1 -1
  88. package/dist/dataunit/state/slice/InvalidFieldsSlice.js +2 -0
  89. package/dist/dataunit/state/slice/InvalidFieldsSlice.js.map +1 -1
  90. package/dist/dataunit/state/slice/LoadingProperties.d.ts +9 -0
  91. package/dist/dataunit/state/slice/LoadingProperties.js +31 -0
  92. package/dist/dataunit/state/slice/LoadingProperties.js.map +1 -0
  93. package/dist/dataunit/state/slice/SelectionSlice.js +3 -2
  94. package/dist/dataunit/state/slice/SelectionSlice.js.map +1 -1
  95. package/dist/index.d.ts +2 -1
  96. package/dist/index.js +2 -1
  97. package/dist/index.js.map +1 -1
  98. package/dist/utils/ElementUtils.d.ts +2 -0
  99. package/dist/utils/ElementUtils.js +9 -0
  100. package/dist/utils/ElementUtils.js.map +1 -0
  101. package/dist/utils/OverflowWatcher/index.d.ts +58 -0
  102. package/dist/utils/OverflowWatcher/index.js +183 -0
  103. package/dist/utils/OverflowWatcher/index.js.map +1 -0
  104. package/dist/utils/OverflowWatcher/types/overflow-callback.d.ts +6 -0
  105. package/dist/utils/OverflowWatcher/types/overflow-callback.js +2 -0
  106. package/dist/utils/OverflowWatcher/types/overflow-callback.js.map +1 -0
  107. package/dist/utils/OverflowWatcher/types/overflow-direction.d.ts +7 -0
  108. package/dist/utils/OverflowWatcher/types/overflow-direction.js +9 -0
  109. package/dist/utils/OverflowWatcher/types/overflow-direction.js.map +1 -0
  110. package/jest.config.ts +3 -1
  111. package/package.json +12 -4
  112. package/reports/test-report.xml +125 -0
  113. package/setupTests.js +1 -0
  114. package/sonar-project.properties +10 -0
  115. package/src/dataunit/DataUnit.ts +53 -10
  116. package/src/dataunit/formatting/PrettyFormatter.ts +8 -5
  117. package/src/dataunit/metadata/DataType.ts +10 -1
  118. package/src/dataunit/state/action/DataUnitAction.ts +3 -1
  119. package/src/dataunit/state/slice/ChangesSlice.ts +15 -14
  120. package/src/dataunit/state/slice/InvalidFieldsSlice.ts +2 -0
  121. package/src/dataunit/state/slice/LoadingProperties.ts +37 -0
  122. package/src/dataunit/state/slice/SelectionSlice.ts +3 -2
  123. package/src/index.ts +6 -0
  124. package/src/utils/ElementUtils.ts +10 -0
  125. package/src/utils/OverflowWatcher/index.ts +237 -0
  126. package/src/utils/OverflowWatcher/types/overflow-callback.ts +6 -0
  127. package/src/utils/OverflowWatcher/types/overflow-direction.ts +7 -0
  128. package/test/util/ElementUtils.spec.ts +34 -0
  129. package/test/util/OverflowWatcher.spec.ts +143 -0
  130. package/.docs/.nojekyll +0 -1
  131. package/.docs/enums/Action.md +0 -305
  132. package/.docs/enums/ChangeOperation.md +0 -52
  133. package/.docs/enums/DataType.md +0 -63
  134. package/.docs/enums/DependencyType.md +0 -41
  135. package/.docs/enums/SelectionMode.md +0 -30
  136. package/.docs/enums/SortMode.md +0 -30
  137. package/.docs/enums/UserInterface.md +0 -195
  138. package/.docs/modules/MaskFormatter.md +0 -37
@@ -25,6 +25,7 @@ import { getFormattedValue } from "./formatting/PrettyFormatter.js";
25
25
  import { v4 as uuid } from "uuid";
26
26
  import { DataUnitStorage } from "./DataUnitStorage.js";
27
27
  import { getInvalidFieldMessage, InvalidFieldsReducer } from "./state/slice/InvalidFieldsSlice.js";
28
+ import { getLoadingProperties, LoadingPropertiesReducer } from "./state/slice/LoadingProperties.js";
28
29
 
29
30
  /***
30
31
  * `DataUnit`: Atua como uma camada de abstração entre o back-end e a interface do usuário.
@@ -61,6 +62,7 @@ export default class DataUnit {
61
62
  this._stateManager = new StateManager(
62
63
  [
63
64
  HistReducer,
65
+ LoadingPropertiesReducer,
64
66
  UnitMetadataReducer,
65
67
  LoadingControlReducer,
66
68
  RecordsReducer,
@@ -114,6 +116,27 @@ export default class DataUnit {
114
116
  this._interceptors = [];
115
117
  }
116
118
 
119
+ /**
120
+ * Adiciona uma propriedade transacional que será envida aos
121
+ * loaders (dataLoader, saveLoader, removeLoader e recordLoader) na chamada.
122
+ * Essas propriedades serão limpas ao final da execução de cada método.
123
+ *
124
+ * @param name - Nome da propriedade
125
+ * @param value - Valor da propriedade
126
+ *
127
+ */
128
+ public addGlobalLoaderProp(name: string, value: string):void{
129
+ this.dispatchAction(Action.LOADING_PROPERTY_ADDED, {[name]: value});
130
+ }
131
+
132
+ /**
133
+ * Retorna as propriedades transacionais adicionados anteriores à chamada.
134
+ *
135
+ * @returns - Todas as propriedades desde o final do último loader.
136
+ */
137
+ public getGlobalLoaderProps(): Map<string, string>{
138
+ return getLoadingProperties(this._stateManager) || new Map();
139
+ }
117
140
 
118
141
  public get dataUnitId(): string{
119
142
  return this._uuid;
@@ -215,22 +238,24 @@ export default class DataUnit {
215
238
  if (await this.dispatchAction(Action.LOADING_DATA, request, executionCtx)) {
216
239
  if (this.dataLoader) {
217
240
  this.dataLoader(this, request).then(
218
- response => {
219
- this.dispatchAction(
241
+ async response => {
242
+ await this.dispatchAction(
220
243
  Action.DATA_LOADED,
221
244
  {...response, keepSelection: request.keepSelection, filters: request.filters},
222
245
  executionCtx
223
246
  );
247
+
248
+ await this.dispatchAction(Action.LOADING_PROPERTIES_CLEANED);
224
249
 
225
250
  if(selectFirstRecord){
226
251
  this.requestSelectFirst(executionCtx);
227
252
  }
228
-
229
253
  resolve(response);
230
254
  }
231
255
  ).catch(error => {
232
256
  console.error(error);
233
257
  const {errorCode} = error;
258
+ this.dispatchAction(Action.LOADING_PROPERTIES_CLEANED);
234
259
  fail(new ErrorException("Erro ao carregar registros", error, errorCode))
235
260
  });
236
261
  }
@@ -431,6 +456,7 @@ export default class DataUnit {
431
456
  const changes: Array<Change> = this.getAllChangesToSave();
432
457
 
433
458
  this.saveLoader(this, changes).then((records) => {
459
+ this.dispatchAction(Action.LOADING_PROPERTIES_CLEANED);
434
460
  const recordsByDataUnit = this.getRecordsByDataUnit(records);
435
461
 
436
462
  const dispatchPromisses = [];
@@ -445,9 +471,11 @@ export default class DataUnit {
445
471
  Promise.all(dispatchPromisses).then(() => resolve());
446
472
  }).catch(cause => {
447
473
  const {errorCode} = cause;
474
+ this.dispatchAction(Action.LOADING_PROPERTIES_CLEANED);
448
475
  fail(new ErrorException("Erro ao salvar alterações", cause, errorCode));
449
476
  });
450
477
  } else {
478
+ this.dispatchAction(Action.LOADING_PROPERTIES_CLEANED);
451
479
  resolve();
452
480
  }
453
481
  });
@@ -536,6 +564,7 @@ export default class DataUnit {
536
564
  public async removeRecords(recordIds: Array<string>, cachedRecords: Array<Record>, buffered: boolean = false, executionCtx?: ExecutionContext, silent: boolean = false): Promise<Array<string>> {
537
565
  if (recordIds) {
538
566
  if (buffered || !this.removeLoader) {
567
+ this.dispatchAction(Action.LOADING_PROPERTIES_CLEANED);
539
568
  this.dispatchAction(Action.RECORDS_REMOVED, { records: recordIds, cachedRecords, buffered: true }, executionCtx);
540
569
  } else {
541
570
  if (await this.dispatchAction(Action.REMOVING_RECORDS, {silent}, executionCtx)) {
@@ -553,9 +582,11 @@ export default class DataUnit {
553
582
  const selectionAfterRemove = [currentRecordsKeys[nextIndex]];
554
583
 
555
584
  this.dispatchAction(Action.RECORDS_REMOVED, { records: removedIds, cachedRecords, removedIndex, buffered: false, selectionAfterRemove }, executionCtx);
585
+ this.dispatchAction(Action.LOADING_PROPERTIES_CLEANED);
556
586
  resolve(removedIds);
557
587
  }
558
588
  ).catch(error => {
589
+ this.dispatchAction(Action.LOADING_PROPERTIES_CLEANED);
559
590
  const {errorCode} = error;
560
591
  fail(new ErrorException("Erro ao remover registros", error, errorCode))
561
592
  });
@@ -612,15 +643,14 @@ export default class DataUnit {
612
643
  *
613
644
  */
614
645
  public getFormattedValue(fieldName: string, value?: any): string {
615
-
616
646
  const descriptor = this.getField(fieldName);
617
- if (value == undefined) {
647
+ if (value === undefined) {
618
648
  value = this.getFieldValue(fieldName);
619
649
  } else if (typeof value === "string" && descriptor?.dataType != DataType.TEXT){
620
650
  value = this.valueFromString(fieldName, value);
621
651
  }
622
652
 
623
- if(value == undefined){
653
+ if(value === undefined){
624
654
  return "";
625
655
  }
626
656
 
@@ -1500,7 +1530,7 @@ export default class DataUnit {
1500
1530
  * @param observer - Função que recebe como parâmetro as ações que serão monitoradas.
1501
1531
  *
1502
1532
  */
1503
- public subscribe(observer: (action: DataUnitAction) => void) {
1533
+ public subscribe(observer: (action: DataUnitAction) => void | Promise<void>) {
1504
1534
  this._observers.push(observer);
1505
1535
  }
1506
1536
 
@@ -1527,12 +1557,16 @@ export default class DataUnit {
1527
1557
  const selection = getSelection(this._stateManager);
1528
1558
  this.dispatchAction(Action.LOADING_RECORD, selection);
1529
1559
 
1530
- if(!this.dataLoader) return;
1531
- if(!this.recordLoader) return;
1560
+ if(!this.recordLoader || !this.dataLoader) {
1561
+ this.dispatchAction(Action.LOADING_PROPERTIES_CLEANED);
1562
+ return;
1563
+ }
1532
1564
 
1533
1565
  this.recordLoader(this, selection).then(response => {
1534
1566
  this.dispatchAction(Action.RECORD_LOADED, response)
1567
+ this.dispatchAction(Action.LOADING_PROPERTIES_CLEANED);
1535
1568
  }).catch(cause => {
1569
+ this.dispatchAction(Action.LOADING_PROPERTIES_CLEANED);
1536
1570
  const {errorCode} = cause;
1537
1571
  fail(new ErrorException("Erro ao recarregar registro", cause, errorCode));
1538
1572
  });
@@ -1697,12 +1731,21 @@ export default class DataUnit {
1697
1731
  return selection?.recordIds || [];
1698
1732
  }
1699
1733
 
1734
+ /**
1735
+ * Adiciona um campo stand-alone ao dataUnit.
1736
+ *
1737
+ * @deprecated - metodo depreciado, utilizar o metodo addField
1738
+ */
1739
+ public addStandAloneField() : void {
1740
+ console.warn("metodo depreciado, para adicionar um campo standAlone, utilizar o metodo addField")
1741
+ }
1742
+
1700
1743
  /**
1701
1744
  * Adiciona um campo stand-alone ao dataUnit.
1702
1745
  *
1703
1746
  * @param field - Campo a ser adicionado.
1704
1747
  */
1705
- public addStandAloneField(field: Omit<FieldDescriptor, 'standAlone'>) : void {
1748
+ public addField(field: Omit<FieldDescriptor, 'standAlone'>) : void {
1706
1749
  const standAloneField = {...field, standAlone: true};
1707
1750
  this.metadata = {...this.metadata, fields: [...this.metadata.fields, standAloneField]};
1708
1751
  }
@@ -10,10 +10,10 @@ export const getFormattedValue = (value: any, descriptor?: FieldDescriptor) => {
10
10
  }
11
11
 
12
12
  if(descriptor?.dataType === DataType.OBJECT){
13
- if(Object.hasOwn(value, "value")){
13
+ if(value && Object.hasOwn(value, "value")){
14
14
  return getSearchFormat(value, descriptor);
15
15
  }
16
- return value == undefined ? "" : value.toString();
16
+ return !value ? "" : value.toString();
17
17
  }
18
18
 
19
19
  if(descriptor?.userInterface === UserInterface.OPTIONSELECTOR){
@@ -53,6 +53,7 @@ export const getFormattedValue = (value: any, descriptor?: FieldDescriptor) => {
53
53
  }
54
54
 
55
55
  const getNumberFormat = (value: any, descriptor: FieldDescriptor) => {
56
+ if(!value) return "";
56
57
  if(descriptor.userInterface === UserInterface.INTEGERNUMBER){
57
58
  return value;
58
59
  }
@@ -79,10 +80,12 @@ const getOptionFormat = (value: any, descriptor: FieldDescriptor) => {
79
80
  options = JSON.parse(prop);
80
81
  } else {
81
82
  options = {};
82
- prop.forEach(opt => options[opt.label] = opt.value);
83
+ if(prop != undefined){
84
+ prop.forEach(opt => options[opt.label] = opt.value);
85
+ }
83
86
  }
84
87
 
85
- if(typeof value === "object"){
88
+ if(value && typeof value === "object" ){
86
89
  value = value.value
87
90
  }
88
91
 
@@ -90,7 +93,7 @@ const getOptionFormat = (value: any, descriptor: FieldDescriptor) => {
90
93
  return options[value];
91
94
  }
92
95
 
93
- return value;
96
+ return value ?? "";
94
97
  }
95
98
 
96
99
 
@@ -67,7 +67,16 @@ export const getConvertedValue = (dataType: DataType, value: any): any => {
67
67
  case DataType.NUMBER:
68
68
  return value === "" || isNaN(Number(value)) ? null : Number(value);
69
69
  case DataType.OBJECT:
70
- return typeof value === "string" ? JSON.parse(value) : value;
70
+ //Caso de uso campo DataType do tipo STRING e UserInterface do tipo TEXT, que tem relacionamento (TGFPRO.GRUPOPIS)
71
+ if(typeof value === "string") {
72
+ try{
73
+ return JSON.parse(value);
74
+ }catch(e){
75
+ console.warn(`Erro ao fazer parse do valor ${value} para objeto, dataType: ${dataType}`);
76
+ }
77
+ }
78
+
79
+ return value;
71
80
  case DataType.BOOLEAN:
72
81
  if (typeof value === "string") {
73
82
  return Boolean(value === 'true');
@@ -63,6 +63,8 @@ export enum Action{
63
63
  CHILD_CHANGED = "childChanged",
64
64
 
65
65
  FIELD_INVALIDATED = "fieldInvalidated",
66
- INVALIDATE_CLEAN = "invalidateClean"
66
+ INVALIDATE_CLEAN = "invalidateClean",
67
67
 
68
+ LOADING_PROPERTY_ADDED = "loadingPropertyAdded",
69
+ LOADING_PROPERTIES_CLEANED = "loadingPropertiesCleaned"
68
70
  }
@@ -94,27 +94,28 @@ export const getChangedFieldValue = (fieldName: string, record: Record, stateMan
94
94
  }
95
95
 
96
96
  export const getChangesToSave = (dataUnit: string, stateManager: StateManager): Array<Change> => {
97
- const result: Array<Change> = [];
98
-
97
+
99
98
  const changes = getChanges(stateManager);
100
99
  const selectedRecords = getSelectionRecords(stateManager) || [];
101
- const records: Set<Record> = new Set(
100
+ const records: Map<string, Record> = new Map(
102
101
  getRecords(stateManager)
103
102
  .concat(
104
- selectedRecords
105
- .filter(record => !isAddedRecord(record.__record__id__, stateManager)
106
- )
103
+ selectedRecords.filter(record => !isAddedRecord(record.__record__id__, stateManager))
107
104
  )
105
+ .map(r => [r.__record__id__, r])
108
106
  );
109
-
110
- records?.forEach(r => {
111
- if(changes){
112
- const c = changes.get(r.__record__id__);
113
- if (c) {
114
- result.push(new Change(dataUnit, r, c, ChangeOperation.UPDATE, r.__record__source__id__));
107
+
108
+ const result: Array<Change> = [];
109
+
110
+ if(changes != undefined){
111
+ Array.from(changes.entries())
112
+ .forEach(([recordId, change]) =>{
113
+ const record = records.get(recordId);
114
+ if(record != undefined){
115
+ result.push(new Change(dataUnit, record, change, ChangeOperation.UPDATE, record.__record__source__id__));
115
116
  }
116
- }
117
- });
117
+ });
118
+ }
118
119
 
119
120
  const addedRecords = getAddedRecords(stateManager);
120
121
  if (addedRecords) {
@@ -15,6 +15,8 @@ class InvalidFieldsReducerImpl implements ActionReducer{
15
15
  return makeInvalid(currentState, action.payload);
16
16
  case Action.INVALIDATE_CLEAN:
17
17
  return clearRecord(currentState, action.payload);
18
+ case Action.EDITION_CANCELED:
19
+ return undefined;
18
20
  }
19
21
 
20
22
  return currentState;
@@ -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
+ }
@@ -17,7 +17,8 @@ class SelectionReducerImpl implements ActionReducer {
17
17
  return !action.payload?.keepSelection ? undefined : currentState;
18
18
  case Action.RECORDS_ADDED:
19
19
  case Action.RECORDS_COPIED:
20
- return {currentSelection: action.payload.map((r: Record)=>r.__record__id__), lastSelection: currentState?.currentSelection};
20
+ const lastSelection = currentState?.currentSelection || [];
21
+ return {currentSelection: action.payload.map((r: Record)=>r.__record__id__), lastSelection};
21
22
  case Action.DATA_SAVED:
22
23
  return {currentSelection: updateSavedIds(stateManager, action.payload.records)};
23
24
  case Action.RECORDS_REMOVED:
@@ -67,7 +68,7 @@ class SelectionReducerImpl implements ActionReducer {
67
68
  if(currentState?.lastSelection){
68
69
  return { currentSelection: currentState.lastSelection };
69
70
  }
70
- break;
71
+ return { currentSelection: [] }
71
72
  }
72
73
 
73
74
  return currentState;
package/src/index.ts CHANGED
@@ -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,9 @@ export {
106
107
  defaultDataLoader,
107
108
  KeyboardManager,
108
109
  SearchUtils,
110
+ OverflowWatcher,
111
+ OnOverflowCallBack,
112
+ OverflowDirection,
113
+ OverFlowWatcherParams,
114
+ OVERFLOWED_CLASS_NAME
109
115
  };
@@ -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
+ }
@@ -0,0 +1,237 @@
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 destroy(){
53
+ this._resizeObserver.disconnect();
54
+ }
55
+
56
+ public forceUpdate(){
57
+ if(this._lastContainerSize && this._lastContainerInstance){
58
+ this.updateOverFlowedItems(this._lastContainerInstance, this._lastContainerSize);
59
+ }
60
+ }
61
+
62
+ private handleResize(entries: ResizeObserverEntry[]){
63
+ if(!entries || entries.length === 0) return;
64
+
65
+ const container = entries[0];
66
+ const containerSize:number = (container.contentRect as any)[this._propSize];
67
+ if(!containerSize) return;
68
+
69
+ if(this.hasChangedSize(containerSize)){
70
+ this.updateOverFlowedItems(container.target as HTMLElement, containerSize);
71
+ }
72
+ }
73
+
74
+ private updateOverFlowedItems(container: HTMLElement, containerSize: number){
75
+ const children:Element[] = Array.from(container.children);
76
+ this.registerNotOverflowProps(children);
77
+ this.proccessElements(containerSize, children);
78
+ this._lastContainerSize = containerSize;
79
+ this._lastContainerInstance = container;
80
+ }
81
+
82
+ private registerNotOverflowProps(children: Element[]) {
83
+ children.forEach(childElement => {
84
+ const id = childElement.id || this.getDataElementId(childElement);
85
+ if (this.canNotRegisterNotOverFlow(id)) return;
86
+ this._notOverFlowPros.set(id, this.getElementSizeProps(childElement));
87
+ });
88
+ }
89
+
90
+ private canNotRegisterNotOverFlow(id: string) {
91
+ return !id || !this._notOverFlow.includes(id) || this._notOverFlowPros.has(id);
92
+ }
93
+
94
+ private hasChangedSize(elementSize: number):boolean{
95
+ if(!this._lastContainerSize) return true;
96
+ const variation = elementSize - this._lastContainerSize;
97
+
98
+ if(variation < 0){
99
+ const absoluteVariation = Math.abs(variation);
100
+ return (absoluteVariation > this._deltaSize);
101
+ }
102
+
103
+ return variation > 0;
104
+ }
105
+
106
+ private proccessElements(elementSize:number, children:Element[]){
107
+ if(children.length === 0) return;
108
+
109
+ const childrenSize = this.calcChildrenSize(children);
110
+ let diff = Number((elementSize - childrenSize).toFixed(4));
111
+
112
+ if(diff > 0){
113
+ this.clearOverFlow();
114
+ return;
115
+ }
116
+
117
+ this.proccessElementsOverFlow(children, elementSize);
118
+ }
119
+
120
+ private clearOverFlow(){
121
+ this._hiddenItemsProps = new Map();
122
+ this._onResize([]);
123
+ }
124
+
125
+ private proccessElementsOverFlow(allElements:Element[], avaliableSize:number){
126
+ const elementsThatFit: Element[] = [];
127
+ const avaliableSizeConsideringDelta = (avaliableSize - this._deltaSize);
128
+
129
+ let sumElementsSize = 0;
130
+ for (const element of allElements) {
131
+ sumElementsSize += this.calcElementSize(element);
132
+ if(this.exceedsAvaliableSize(sumElementsSize, elementsThatFit, avaliableSizeConsideringDelta)) break;
133
+ elementsThatFit.push(element);
134
+ }
135
+
136
+ const overFlowedElements = allElements.filter(element => this.isElementOverFlowing(elementsThatFit, element));
137
+
138
+ overFlowedElements.forEach(overFlowed => {
139
+ if(!this._hiddenItemsProps.has(overFlowed)){
140
+ this.registerElementSize(overFlowed);
141
+ }
142
+ });
143
+
144
+ this._onResize(overFlowedElements);
145
+ }
146
+
147
+ private isElementOverFlowing(elementsThatFit: Element[], element: Element) {
148
+ return !elementsThatFit.includes(element) && this.canOverFlowElement(element);
149
+ }
150
+
151
+ private canOverFlowElement(element: Element) {
152
+ return !this._notOverFlow.includes(element.id)
153
+ && !this._notOverFlow.includes(this.getDataElementId(element));
154
+ }
155
+
156
+ private getDataElementId(element: Element): string {
157
+ return (element as HTMLElement).getAttribute('data-element-id') ?? "";
158
+ }
159
+
160
+ private exceedsAvaliableSize(sumElementsSize: number, elements: Element[], avaliableSize: number): boolean {
161
+ if(!this._notOverFlow.length) return sumElementsSize > avaliableSize
162
+
163
+ const elementIdsToCalculate = this.canNotOverFlowNotIncludedIds(elements);
164
+ if(!elementIdsToCalculate.length) return sumElementsSize > avaliableSize
165
+
166
+ const variation = this.calculateVariation(elementIdsToCalculate);
167
+ const occupiedSize = sumElementsSize + variation;
168
+ return occupiedSize > avaliableSize;
169
+ }
170
+
171
+ private calculateVariation(elementIdsToCalculate: string[]) {
172
+ let variation = 0
173
+ elementIdsToCalculate.forEach(id => {
174
+ const sizeProps = this._notOverFlowPros.get(id);
175
+ variation += sizeProps?.size ?? 0;
176
+ variation += sizeProps?.margin ?? 0;
177
+ });
178
+ return variation;
179
+ }
180
+
181
+ private canNotOverFlowNotIncludedIds(elements: Element[]): string[]{
182
+ const elementsIdList = elements.map(el => el.id || this.getDataElementId(el)).filter(id => !!id);
183
+ return this._notOverFlow.filter(id => !elementsIdList.includes(id));
184
+ }
185
+
186
+ private registerElementSize(element: Element) {
187
+ const sizeProps = this.getElementSizeProps(element);
188
+ this._hiddenItemsProps.set(element, sizeProps);
189
+ }
190
+
191
+ private getElementSizeProps(element: Element) {
192
+ const sizeProps: SizeProps = {
193
+ size: (element.getBoundingClientRect() as any)[this._propSize],
194
+ margin: calcMarginSize(element, this._scrollDirection),
195
+ };
196
+ return sizeProps;
197
+ }
198
+
199
+ private calcChildrenSize(children:Element[]):number{
200
+ let sumChildren = 0;
201
+ sumChildren += this._deltaSize;
202
+ Array.from(children).forEach(el => sumChildren += this.calcElementSize(el));
203
+ return sumChildren;
204
+ }
205
+
206
+ private calcElementSize(el: Element) {
207
+ let size = 0
208
+ if (this.isOverFlowed(el)) {
209
+ const sizeProps = this._hiddenItemsProps.get(el);
210
+ size += sizeProps?.size ?? 0;
211
+ size += sizeProps?.margin ?? 0;
212
+ return size;
213
+ }
214
+
215
+ size += (el.getBoundingClientRect() as any)[this._propSize];
216
+ size += calcMarginSize(el, this._scrollDirection);
217
+ return size;
218
+ }
219
+
220
+ private isOverFlowed(el: Element) {
221
+ return el.classList.contains(OVERFLOWED_CLASS_NAME);
222
+ }
223
+ }
224
+
225
+ export interface OverFlowWatcherParams {
226
+ element:HTMLElement,
227
+ callback:OnOverflowCallBack,
228
+ overFlowDirection?:OverflowDirection,
229
+ deltaSize?:number,
230
+ debounce?: number,
231
+ notOverFlow?: string[]
232
+ }
233
+
234
+ interface SizeProps {
235
+ size: number,
236
+ margin: number,
237
+ }
@@ -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
+ }