@oscarpalmer/tabela 0.11.0 → 0.13.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 (159) hide show
  1. package/dist/body.component-_VDOpJhV.d.mts +10 -0
  2. package/dist/body.model-2iwsovAV.d.mts +7 -0
  3. package/dist/column.component-Bx46r3JI.d.mts +16 -0
  4. package/dist/column.model-D-aw4EU4.d.mts +16 -0
  5. package/dist/components/body.component.d.mts +2 -0
  6. package/dist/components/{body.component.js → body.component.mjs} +6 -3
  7. package/dist/components/column.component.d.mts +2 -0
  8. package/dist/components/{column.component.js → column.component.mjs} +12 -9
  9. package/dist/components/footer.component.d.mts +2 -0
  10. package/dist/components/{footer.component.js → footer.component.mjs} +7 -4
  11. package/dist/components/group.component.d.mts +2 -0
  12. package/dist/components/group.component.mjs +51 -0
  13. package/dist/components/header.component.d.mts +2 -0
  14. package/dist/components/{header.component.js → header.component.mjs} +6 -3
  15. package/dist/components/row.component.d.mts +2 -0
  16. package/dist/components/{row.component.js → row.component.mjs} +11 -7
  17. package/dist/filter.model-7ukJrtil.d.mts +16 -0
  18. package/dist/footer.component-Curiab8j.d.mts +12 -0
  19. package/dist/footer.model-DhqoS6ds.d.mts +8 -0
  20. package/dist/group.component-Cq1YYbfJ.d.mts +285 -0
  21. package/dist/group.model-BsKFwHbt.d.mts +10 -0
  22. package/dist/header.component-BjjlpZIg.d.mts +12 -0
  23. package/dist/header.model-DN_KzUCV.d.mts +7 -0
  24. package/dist/helpers/dom.helpers.d.mts +12 -0
  25. package/dist/helpers/{dom.helpers.js → dom.helpers.mjs} +14 -10
  26. package/dist/helpers/misc.helpers.d.mts +6 -0
  27. package/dist/helpers/{misc.helpers.js → misc.helpers.mjs} +3 -1
  28. package/dist/helpers/style.helper.d.mts +6 -0
  29. package/dist/helpers/style.helper.mjs +8 -0
  30. package/dist/index.d.mts +7 -0
  31. package/dist/{index.js → index.mjs} +3 -1
  32. package/dist/managers/column.manager.d.mts +2 -0
  33. package/dist/managers/{column.manager.js → column.manager.mjs} +6 -1
  34. package/dist/managers/data.manager.d.mts +2 -0
  35. package/dist/managers/data.manager.mjs +222 -0
  36. package/dist/managers/event.manager.d.mts +2 -0
  37. package/dist/managers/{event.manager.js → event.manager.mjs} +12 -8
  38. package/dist/managers/filter.manager.d.mts +2 -0
  39. package/dist/managers/{filter.manager.js → filter.manager.mjs} +25 -11
  40. package/dist/managers/group.manager.d.mts +2 -0
  41. package/dist/managers/group.manager.mjs +73 -0
  42. package/dist/managers/navigation.manager.d.mts +2 -0
  43. package/dist/managers/{navigation.manager.js → navigation.manager.mjs} +27 -24
  44. package/dist/managers/render.manager.d.mts +2 -0
  45. package/dist/managers/render.manager.mjs +144 -0
  46. package/dist/managers/row.manager.d.mts +2 -0
  47. package/dist/managers/{row.manager.js → row.manager.mjs} +18 -11
  48. package/dist/managers/selection.manager.d.mts +2 -0
  49. package/dist/managers/{selection.manager.js → selection.manager.mjs} +57 -48
  50. package/dist/managers/sort.manager.d.mts +2 -0
  51. package/dist/managers/{sort.manager.js → sort.manager.mjs} +32 -2
  52. package/dist/managers/style.manager.d.mts +2 -0
  53. package/dist/managers/style.manager.mjs +149 -0
  54. package/dist/models/body.model.d.mts +2 -0
  55. package/dist/models/body.model.mjs +1 -0
  56. package/dist/models/column.model.d.mts +2 -0
  57. package/dist/models/column.model.mjs +1 -0
  58. package/dist/models/data.model.d.mts +2 -0
  59. package/dist/models/data.model.mjs +1 -0
  60. package/dist/models/filter.model.d.mts +2 -0
  61. package/dist/models/filter.model.mjs +1 -0
  62. package/dist/models/footer.model.d.mts +2 -0
  63. package/dist/models/footer.model.mjs +1 -0
  64. package/dist/models/group.model.d.mts +2 -0
  65. package/dist/models/group.model.mjs +1 -0
  66. package/dist/models/header.model.d.mts +2 -0
  67. package/dist/models/header.model.mjs +1 -0
  68. package/dist/models/render.model.d.mts +2 -0
  69. package/dist/models/render.model.mjs +1 -0
  70. package/dist/models/selection.model.d.mts +2 -0
  71. package/dist/models/selection.model.mjs +1 -0
  72. package/dist/models/sort.model.d.mts +2 -0
  73. package/dist/models/sort.model.mjs +1 -0
  74. package/dist/models/style.model.d.mts +23 -0
  75. package/dist/models/style.model.mjs +23 -0
  76. package/dist/models/tabela.model.d.mts +2 -0
  77. package/dist/models/tabela.model.mjs +1 -0
  78. package/dist/models/tabela.options.d.mts +2 -0
  79. package/dist/models/tabela.options.mjs +1 -0
  80. package/dist/selection.model-rwQe9fco.d.mts +12 -0
  81. package/dist/sort.model-CauImaLu.d.mts +15 -0
  82. package/dist/tabela.d.mts +21 -0
  83. package/dist/{tabela.full.js → tabela.full.mjs} +1407 -1124
  84. package/dist/tabela.mjs +126 -0
  85. package/dist/tabela.options-RkZvfptB.d.mts +14 -0
  86. package/package.json +45 -37
  87. package/src/components/body.component.ts +4 -3
  88. package/src/components/column.component.ts +19 -24
  89. package/src/components/footer.component.ts +8 -3
  90. package/src/components/group.component.ts +85 -0
  91. package/src/components/header.component.ts +3 -2
  92. package/src/components/row.component.ts +10 -8
  93. package/src/helpers/dom.helpers.ts +24 -20
  94. package/src/helpers/style.helper.ts +1 -1
  95. package/src/managers/column.manager.ts +8 -4
  96. package/src/managers/data.manager.ts +265 -61
  97. package/src/managers/event.manager.ts +14 -11
  98. package/src/managers/filter.manager.ts +38 -19
  99. package/src/managers/group.manager.ts +131 -0
  100. package/src/managers/navigation.manager.ts +25 -23
  101. package/src/managers/render.manager.ts +84 -32
  102. package/src/managers/row.manager.ts +23 -11
  103. package/src/managers/selection.manager.ts +68 -54
  104. package/src/managers/sort.manager.ts +81 -16
  105. package/src/managers/style.manager.ts +156 -0
  106. package/src/models/column.model.ts +2 -2
  107. package/src/models/data.model.ts +23 -9
  108. package/src/models/filter.model.ts +11 -3
  109. package/src/models/group.model.ts +8 -0
  110. package/src/models/render.model.ts +2 -2
  111. package/src/models/selection.model.ts +9 -0
  112. package/src/models/sort.model.ts +11 -3
  113. package/src/models/style.model.ts +39 -0
  114. package/src/models/tabela.model.ts +14 -46
  115. package/src/models/tabela.options.ts +3 -2
  116. package/src/tabela.ts +72 -41
  117. package/dist/helpers/style.helper.js +0 -6
  118. package/dist/managers/data.manager.js +0 -120
  119. package/dist/managers/render.manager.js +0 -110
  120. package/dist/models/body.model.js +0 -0
  121. package/dist/models/column.model.js +0 -0
  122. package/dist/models/data.model.js +0 -0
  123. package/dist/models/filter.model.js +0 -0
  124. package/dist/models/footer.model.js +0 -0
  125. package/dist/models/header.model.js +0 -0
  126. package/dist/models/render.model.js +0 -0
  127. package/dist/models/sort.model.js +0 -0
  128. package/dist/models/tabela.model.js +0 -0
  129. package/dist/models/tabela.options.js +0 -0
  130. package/dist/tabela.js +0 -102
  131. package/types/components/body.component.d.ts +0 -6
  132. package/types/components/column.component.d.ts +0 -13
  133. package/types/components/footer.component.d.ts +0 -8
  134. package/types/components/header.component.d.ts +0 -8
  135. package/types/components/row.component.d.ts +0 -11
  136. package/types/helpers/dom.helpers.d.ts +0 -10
  137. package/types/helpers/misc.helpers.d.ts +0 -2
  138. package/types/helpers/style.helper.d.ts +0 -1
  139. package/types/index.d.ts +0 -4
  140. package/types/managers/column.manager.d.ts +0 -12
  141. package/types/managers/data.manager.d.ts +0 -27
  142. package/types/managers/event.manager.d.ts +0 -7
  143. package/types/managers/filter.manager.d.ts +0 -19
  144. package/types/managers/navigation.manager.d.ts +0 -10
  145. package/types/managers/render.manager.d.ts +0 -16
  146. package/types/managers/row.manager.d.ts +0 -13
  147. package/types/managers/selection.manager.d.ts +0 -18
  148. package/types/managers/sort.manager.d.ts +0 -26
  149. package/types/models/body.model.d.ts +0 -4
  150. package/types/models/column.model.d.ts +0 -13
  151. package/types/models/data.model.d.ts +0 -14
  152. package/types/models/filter.model.d.ts +0 -6
  153. package/types/models/footer.model.d.ts +0 -5
  154. package/types/models/header.model.d.ts +0 -4
  155. package/types/models/render.model.d.ts +0 -13
  156. package/types/models/sort.model.d.ts +0 -5
  157. package/types/models/tabela.model.d.ts +0 -69
  158. package/types/models/tabela.options.d.ts +0 -9
  159. package/types/tabela.d.ts +0 -12
@@ -1,9 +1,15 @@
1
- import {push, sort} from '@oscarpalmer/atoms/array';
1
+ import {chunk, select, sort} from '@oscarpalmer/atoms/array';
2
2
  import {toMap} from '@oscarpalmer/atoms/array/to-map';
3
+ import {toRecord} from '@oscarpalmer/atoms/array/to-record';
3
4
  import {isPlainObject} from '@oscarpalmer/atoms/is';
4
5
  import type {Key, PlainObject} from '@oscarpalmer/atoms/models';
5
- import type {DataValues} from '../models/data.model';
6
- import type {TabelaData, TabelaState} from '../models/tabela.model';
6
+ import {delay} from '@oscarpalmer/atoms/promise/delay';
7
+ import {getValue} from '@oscarpalmer/atoms/value/handle';
8
+ import {GroupComponent, updateGroup} from '../components/group.component';
9
+ import type {DataItem, DataState, TabelaData} from '../models/data.model';
10
+ import type {State} from '../models/tabela.model';
11
+ import {sortWithGroups} from './sort.manager';
12
+ import type {ColumnComponent} from '../components/column.component';
7
13
 
8
14
  export class DataManager {
9
15
  handlers = Object.freeze({
@@ -15,127 +21,322 @@ export class DataManager {
15
21
  update: data => void this.update(data),
16
22
  } satisfies TabelaData);
17
23
 
18
- values: DataValues = {
19
- keys: {
20
- original: [],
21
- },
22
- objects: {
23
- mapped: new Map(),
24
- array: [],
25
- },
26
- };
24
+ state: DataState;
25
+
26
+ get items(): DataItem[] {
27
+ return this.state.items.active ?? this.state.items.original;
28
+ }
27
29
 
28
30
  get size(): number {
29
- return this.values.keys.active?.length ?? this.values.keys.original.length;
31
+ return this.items.length;
30
32
  }
31
33
 
32
- constructor(public state: TabelaState) {}
34
+ constructor(state: State) {
35
+ this.state = {
36
+ ...state,
37
+ items: {
38
+ original: [],
39
+ },
40
+ values: {
41
+ array: [],
42
+ mapped: new Map(),
43
+ },
44
+ };
45
+ }
33
46
 
34
47
  async add(data: PlainObject[], render: boolean): Promise<void> {
35
- const {state, values} = this;
48
+ const {state} = this;
36
49
 
37
- push(values.objects.array, data);
50
+ const groups: GroupComponent[] = [];
51
+ const updates: PlainObject[] = [];
38
52
 
39
- values.objects.mapped = toMap(values.objects.array, state.key) as Map<Key, PlainObject>;
53
+ let groupColumn: ColumnComponent | undefined;
54
+ let {length} = data;
40
55
 
41
- if (render) {
56
+ for (let index = 0; index < length; index += 1) {
57
+ const item = data[index];
58
+ const key = getValue(item, state.key) as Key;
59
+
60
+ if (state.values.mapped.has(key)) {
61
+ updates.push(item);
62
+
63
+ continue;
64
+ }
65
+
66
+ state.values.array.push(item);
67
+ state.values.mapped.set(key, item);
68
+
69
+ if (!state.managers.group.enabled) {
70
+ continue;
71
+ }
72
+
73
+ const groupValue = getValue(item, state.managers.group.field) as unknown;
74
+
75
+ let group = state.managers.group.get(groupValue);
76
+
77
+ if (group == null) {
78
+ groupColumn ??= state.managers.column.get(state.managers.group.field);
79
+
80
+ group = new GroupComponent(
81
+ `${groupColumn?.options.title ?? state.managers.group.field}: ${groupValue}`,
82
+ groupValue,
83
+ );
84
+
85
+ state.values.array.push(group);
86
+ state.managers.group.add(group);
87
+ }
88
+
89
+ if (!group.expanded) {
90
+ state.managers.group.collapsed.add(key);
91
+ }
92
+
93
+ group.total += 1;
94
+
95
+ groups.push(group);
96
+ }
97
+
98
+ length = groups.length;
99
+
100
+ for (let index = 0; index < length; index += 1) {
101
+ updateGroup(state, groups[index]);
102
+ }
103
+
104
+ if (updates.length > 0) {
105
+ void this.update(updates);
106
+ } else if (render) {
42
107
  this.render();
43
108
  }
44
109
  }
45
110
 
46
111
  clear(): void {
47
- if (this.values.objects.array.length > 0) {
48
- this.set([]);
112
+ if (this.state.values.array.length > 0) {
113
+ void this.removeItems([], true, true);
49
114
  }
50
115
  }
51
116
 
52
117
  destroy(): void {
53
- const {values} = this;
118
+ const {state} = this;
54
119
 
55
- values.objects.mapped.clear();
120
+ state.values.mapped.clear();
56
121
 
57
- values.keys.active = undefined;
58
- values.keys.original.length = 0;
59
- values.objects.array.length = 0;
122
+ state.items.active = undefined;
123
+ state.items.original.length = 0;
124
+ state.values.array.length = 0;
60
125
 
61
126
  this.handlers = undefined as never;
62
127
  this.state = undefined as never;
63
- this.values = undefined as never;
64
128
  }
65
129
 
66
130
  get(active?: boolean): PlainObject[] {
67
- const {values} = this;
131
+ const {state} = this;
68
132
 
69
133
  return (active ?? false)
70
- ? (values.keys.active?.map(key => values.objects.mapped.get(key) as PlainObject) ?? [])
71
- : values.objects.array;
134
+ ? select(
135
+ state.items.active ?? [],
136
+ key => !(key instanceof GroupComponent),
137
+ key => state.values.mapped.get(key as Key)!,
138
+ )
139
+ : (state.values.array.filter(item => !(item instanceof GroupComponent)) as PlainObject[]);
72
140
  }
73
141
 
74
- getIndex(key: Key): number {
75
- const {values} = this;
142
+ getIndex(item: DataItem): number {
143
+ if (item instanceof GroupComponent) {
144
+ return this.items.indexOf(item);
145
+ }
76
146
 
77
- return (values.keys.active ?? values.keys.original).indexOf(key);
147
+ return this.items.findIndex(value =>
148
+ value instanceof GroupComponent ? value.key === item : value === item,
149
+ );
78
150
  }
79
151
 
80
152
  async remove(items: Array<Key | PlainObject>, render: boolean): Promise<void> {
81
- const {state, values} = this;
153
+ const {state} = this;
82
154
 
83
- const keys = items
84
- .map(value => (isPlainObject(value) ? value[state.key] : value) as Key)
85
- .filter(key => values.objects.mapped.has(key)) as Key[];
155
+ const keys = items.map(
156
+ value => (isPlainObject(value) ? getValue(value, state.key) : value) as Key,
157
+ );
86
158
 
87
159
  const {length} = keys;
88
160
 
89
- if (length === 0) {
90
- return;
161
+ if (length > 0) {
162
+ return this.removeItems(keys, false, render === true);
91
163
  }
164
+ }
165
+
166
+ async removeItems(items: DataItem[], clear: boolean, render: boolean): Promise<void> {
167
+ const {state} = this;
92
168
 
93
- for (let keyIndex = 0; keyIndex < length; keyIndex += 1) {
94
- const key = keys[keyIndex];
169
+ if (clear) {
170
+ state.items.active = undefined;
171
+ state.items.original = [];
172
+ state.values.array = [];
95
173
 
96
- values.objects.mapped.delete(key);
174
+ state.values.mapped.clear();
97
175
 
98
- const arrayIndex = values.objects.array.findIndex(object => object[state.key] === key);
176
+ state.managers.row.clear();
99
177
 
100
- if (arrayIndex > -1) {
101
- values.objects.array.splice(arrayIndex, 1);
178
+ if (state.managers.group.enabled) {
179
+ state.managers.group.clear();
102
180
  }
103
181
 
104
- values.keys.original.splice(values.keys.original.indexOf(key), 1);
182
+ return this.render();
183
+ }
184
+
185
+ const groups: GroupComponent[] = [];
186
+
187
+ const chunked = chunk(items);
188
+ const chunkedLength = chunked.length;
189
+
190
+ for (let chunkedIndex = 0; chunkedIndex < chunkedLength; chunkedIndex += 1) {
191
+ const chunk = chunked[chunkedIndex];
192
+ const chunkLength = chunk.length;
193
+
194
+ for (let itemIndex = 0; itemIndex < chunkLength; itemIndex += 1) {
195
+ const item = chunk[itemIndex];
196
+ const dataIndex = state.items.original.indexOf(item);
197
+
198
+ let dataValue: PlainObject | undefined;
199
+
200
+ [dataValue] = state.values.array.splice(dataIndex, 1) as PlainObject[];
105
201
 
106
- state.managers.row.remove(key);
202
+ state.items.original.splice(dataIndex, 1);
203
+ state.managers.row.remove(item as never);
204
+ state.values.mapped.delete(item as Key);
205
+
206
+ if (!state.managers.group.enabled || item instanceof GroupComponent) {
207
+ continue;
208
+ }
209
+
210
+ state.managers.group.collapsed.delete(item as never);
211
+
212
+ const groupKey = getValue(dataValue, state.managers.group.field) as unknown;
213
+
214
+ const group = state.managers.group.get(groupKey);
215
+
216
+ if (group == null) {
217
+ continue;
218
+ }
219
+
220
+ group.total -= 1;
221
+
222
+ if (group.total > 0) {
223
+ groups.push(group);
224
+
225
+ continue;
226
+ }
227
+
228
+ let groupIndex = groups.indexOf(group);
229
+
230
+ if (groupIndex > -1) {
231
+ groups.splice(groupIndex, 1);
232
+ }
233
+
234
+ groupIndex = state.values.array.indexOf(group);
235
+
236
+ if (groupIndex > -1) {
237
+ state.items.original.splice(groupIndex, 1);
238
+ state.values.array.splice(groupIndex, 1);
239
+ }
240
+
241
+ state.managers.group.remove(group);
242
+
243
+ if (items.length >= 10_000) {
244
+ await delay(25);
245
+ }
246
+ }
247
+ }
248
+
249
+ const {length} = groups;
250
+
251
+ for (let index = 0; index < length; index += 1) {
252
+ updateGroup(state, groups[index]);
107
253
  }
108
254
 
109
255
  if (render) {
110
- this.render();
256
+ return this.render();
111
257
  }
112
258
  }
113
259
 
114
260
  render(): void {
115
- const {state, values} = this;
261
+ const {state} = this;
262
+
263
+ if (state.managers.group.enabled) {
264
+ sortWithGroups(state, state.values.array, [
265
+ {
266
+ direction: 'ascending',
267
+ key: state.key,
268
+ },
269
+ ]);
270
+ } else {
271
+ sort(state.values.array as PlainObject[], [
272
+ {
273
+ direction: 'ascending',
274
+ key: state.key,
275
+ },
276
+ ]);
277
+ }
116
278
 
117
- values.keys.original = sort(values.objects.array.map(item => item[state.key] as Key));
279
+ state.items.original = state.values.array.map(item =>
280
+ item instanceof GroupComponent ? item : (getValue(item, state.key) as Key),
281
+ );
282
+
283
+ state.values.mapped = toMap(
284
+ state.values.array.filter(item => !(item instanceof GroupComponent)) as PlainObject[],
285
+ item => getValue(item, state.key) as Key,
286
+ );
118
287
 
119
288
  if (Object.keys(state.managers.filter.items).length > 0) {
120
289
  state.managers.filter.filter();
121
290
  } else if (state.managers.sort.items.length > 0) {
122
291
  state.managers.sort.sort();
123
292
  } else {
124
- state.managers.render.update(true);
293
+ state.managers.render.update(true, true);
125
294
  }
126
295
  }
127
296
 
128
297
  set(data: PlainObject[]): void {
129
- const {state, values} = this;
298
+ const {state} = this;
299
+
300
+ const array: Array<GroupComponent | PlainObject> = data.slice();
301
+
302
+ if (state.managers.group.enabled) {
303
+ const column = state.managers.column.get(state.managers.group.field);
304
+
305
+ const grouped = toRecord.arrays(data, state.managers.group.field) as Record<
306
+ string,
307
+ PlainObject[]
308
+ >;
309
+
310
+ const entries = Object.entries(grouped);
311
+ const {length} = entries;
312
+
313
+ const groups: GroupComponent[] = [];
130
314
 
131
- values.objects.mapped = toMap(data, state.key) as Map<Key, PlainObject>;
132
- values.objects.array = data;
315
+ for (let index = 0; index < length; index += 1) {
316
+ const [value, items] = entries[index];
317
+
318
+ const group = new GroupComponent(
319
+ `${column?.options.title ?? state.managers.group.field}: ${value}`,
320
+ value,
321
+ );
322
+
323
+ group.total = items.length;
324
+
325
+ groups.push(group);
326
+
327
+ array.push(group);
328
+ }
329
+
330
+ state.managers.group.set(groups);
331
+ }
332
+
333
+ state.values.array = array;
133
334
 
134
335
  this.render();
135
336
  }
136
337
 
137
338
  async synchronize(data: PlainObject[], remove?: boolean): Promise<void> {
138
- const {state, values} = this;
339
+ const {state} = this;
139
340
 
140
341
  const add: PlainObject[] = [];
141
342
  const updated: PlainObject[] = [];
@@ -146,9 +347,9 @@ export class DataManager {
146
347
 
147
348
  for (let index = 0; index < length; index += 1) {
148
349
  const object = data[index];
149
- const key = object[state.key] as Key;
350
+ const key = getValue(object, state.key) as Key;
150
351
 
151
- if (values.objects.mapped.has(key)) {
352
+ if (state.values.mapped.has(key)) {
152
353
  updated.push(object);
153
354
  } else {
154
355
  add.push(object);
@@ -162,7 +363,9 @@ export class DataManager {
162
363
  }
163
364
 
164
365
  if (remove ?? false) {
165
- const toRemove = values.keys.original.filter(key => !keys.has(key));
366
+ const toRemove = state.items.original.filter(
367
+ key => !(key instanceof GroupComponent) && !keys.has(key),
368
+ ) as Key[];
166
369
 
167
370
  if (toRemove.length > 0) {
168
371
  await this.remove(toRemove, false);
@@ -181,17 +384,18 @@ export class DataManager {
181
384
  }
182
385
 
183
386
  async update(data: PlainObject[]): Promise<void> {
184
- const {state, values} = this;
387
+ const {state} = this;
185
388
 
186
389
  const {length} = data;
187
390
 
188
391
  for (let index = 0; index < length; index += 1) {
189
392
  const object = data[index];
190
- const key = object[state.key] as Key;
191
- const value = values.objects.mapped.get(key);
393
+
394
+ const key = getValue(object, state.key) as Key;
395
+ const value = state.values.mapped.get(key);
192
396
 
193
397
  if (value != null) {
194
- values.objects.mapped.set(key, {...value, ...object} as PlainObject);
398
+ state.values.mapped.set(key, {...value, ...object} as PlainObject);
195
399
 
196
400
  state.managers.row.update(key);
197
401
  }
@@ -1,9 +1,9 @@
1
1
  import {on} from '@oscarpalmer/toretto/event';
2
2
  import {findAncestor} from '@oscarpalmer/toretto/find';
3
- import type {TabelaState} from '../models/tabela.model';
3
+ import type {State} from '../models/tabela.model';
4
4
 
5
5
  export class EventManager {
6
- constructor(public state: TabelaState) {
6
+ constructor(public state: State) {
7
7
  mapped.set(state.element, this);
8
8
  }
9
9
 
@@ -25,7 +25,7 @@ export class EventManager {
25
25
 
26
26
  function onClick(event: MouseEvent): void {
27
27
  const target = findAncestor(event, '[data-event]');
28
- const table = findAncestor(event, '.tabela');
28
+ const table = findAncestor(event, '.tabela__table');
29
29
 
30
30
  if (!(target instanceof HTMLElement) || !(table instanceof HTMLElement)) {
31
31
  return;
@@ -40,6 +40,10 @@ function onClick(event: MouseEvent): void {
40
40
  const type = target?.getAttribute('data-event');
41
41
 
42
42
  switch (type) {
43
+ case 'group':
44
+ manager.state.managers.group.handle(target);
45
+ break;
46
+
43
47
  case 'heading':
44
48
  manager.onSort(event, target);
45
49
  break;
@@ -55,7 +59,7 @@ function onClick(event: MouseEvent): void {
55
59
 
56
60
  function onKeydown(event: KeyboardEvent): void {
57
61
  const target = findAncestor(event, '[data-event]');
58
- const table = findAncestor(event, '.tabela');
62
+ const table = findAncestor(event, '.tabela__table');
59
63
 
60
64
  if (!(target instanceof HTMLElement) || !(table instanceof HTMLElement)) {
61
65
  return;
@@ -67,16 +71,15 @@ function onKeydown(event: KeyboardEvent): void {
67
71
  return;
68
72
  }
69
73
 
70
- const type = target?.getAttribute('data-event');
74
+ if (event.key === ' ') {
75
+ event.preventDefault();
71
76
 
72
- switch (type) {
73
- case 'body':
74
- manager.state.managers.navigation.handle(event);
75
- break;
77
+ // TODO: it's on the way
76
78
 
77
- default:
78
- break;
79
+ return;
79
80
  }
81
+
82
+ manager.state.managers.navigation.handle(event);
80
83
  }
81
84
 
82
85
  const mapped = new WeakMap<HTMLElement, EventManager>();
@@ -1,10 +1,11 @@
1
- import type {Key} from '@oscarpalmer/atoms/models';
2
1
  import {getNumber} from '@oscarpalmer/atoms/number';
3
2
  import {getString} from '@oscarpalmer/atoms/string';
4
3
  import {endsWith, includes, startsWith} from '@oscarpalmer/atoms/string/match';
5
4
  import {equal} from '@oscarpalmer/atoms/value/equal';
6
- import type {FilterComparison, FilterItem} from '../models/filter.model';
7
- import type {TabelaFilter, TabelaState} from '../models/tabela.model';
5
+ import {GroupComponent} from '../components/group.component';
6
+ import type {DataItem} from '../models/data.model';
7
+ import type {TabelaFilter, TabelaFilterComparison, TabelaFilterItem} from '../models/filter.model';
8
+ import type {State} from '../models/tabela.model';
8
9
 
9
10
  export class FilterManager {
10
11
  handlers = Object.freeze({
@@ -14,17 +15,17 @@ export class FilterManager {
14
15
  set: items => this.set(items),
15
16
  } satisfies TabelaFilter);
16
17
 
17
- items: Record<string, FilterItem[]> = {};
18
+ items: Record<string, TabelaFilterItem[]> = {};
18
19
 
19
- constructor(public state: TabelaState) {}
20
+ constructor(public state: State) {}
20
21
 
21
- add(item: FilterItem): void {
22
+ add(item: TabelaFilterItem): void {
22
23
  if (this.items[item.field] == null) {
23
24
  this.items[item.field] = [];
24
25
  } else {
25
26
  const index = this.items[item.field].findIndex(existing => equal(existing, item));
26
27
 
27
- if (index !== -1) {
28
+ if (index > -1) {
28
29
  return;
29
30
  }
30
31
  }
@@ -51,14 +52,21 @@ export class FilterManager {
51
52
  filter(): void {
52
53
  const {state} = this;
53
54
 
54
- const filtered: Key[] = [];
55
+ const filtered: DataItem[] = [];
55
56
  const filters = Object.entries(this.items);
56
57
 
57
- const keysLength = state.managers.data.values.keys.original.length;
58
+ const itemsLength = state.managers.data.state.items.original.length;
58
59
 
59
- rowLoop: for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
60
- const key = state.managers.data.values.keys.original[keyIndex];
61
- const row = state.managers.data.values.objects.mapped.get(key);
60
+ rowLoop: for (let itemIndex = 0; itemIndex < itemsLength; itemIndex += 1) {
61
+ const item = state.managers.data.state.items.original[itemIndex];
62
+
63
+ if (item instanceof GroupComponent) {
64
+ filtered.push(item);
65
+
66
+ continue;
67
+ }
68
+
69
+ const row = state.managers.data.state.values.mapped.get(item);
62
70
 
63
71
  if (row == null) {
64
72
  continue;
@@ -80,10 +88,10 @@ export class FilterManager {
80
88
  continue rowLoop;
81
89
  }
82
90
 
83
- filtered.push(key);
91
+ filtered.push(item);
84
92
  }
85
93
 
86
- state.managers.data.values.keys.active = filtered;
94
+ state.managers.data.state.items.active = filtered;
87
95
 
88
96
  if (state.managers.sort.items.length > 0) {
89
97
  state.managers.sort.sort();
@@ -92,13 +100,24 @@ export class FilterManager {
92
100
  }
93
101
  }
94
102
 
95
- remove(value: string | FilterItem): void {
103
+ remove(value: string | TabelaFilterItem): void {
96
104
  if (typeof value === 'string') {
97
105
  if (this.items[value] == null) {
98
106
  return;
99
107
  }
100
108
 
101
- const keyed: Record<string, FilterItem[]> = {};
109
+ const keyed: Record<string, TabelaFilterItem[]> = {};
110
+
111
+ const filters = Object.keys(this.items);
112
+ const {length} = filters;
113
+
114
+ for (let index = 0; index < length; index += 1) {
115
+ const field = filters[index];
116
+
117
+ if (field !== value) {
118
+ keyed[field] = this.items[field];
119
+ }
120
+ }
102
121
 
103
122
  this.items = keyed;
104
123
  } else {
@@ -118,8 +137,8 @@ export class FilterManager {
118
137
  this.filter();
119
138
  }
120
139
 
121
- set(items: FilterItem[]): void {
122
- const keyed: Record<string, FilterItem[]> = {};
140
+ set(items: TabelaFilterItem[]): void {
141
+ const keyed: Record<string, TabelaFilterItem[]> = {};
123
142
 
124
143
  const {length} = items;
125
144
 
@@ -137,7 +156,7 @@ export class FilterManager {
137
156
  }
138
157
  }
139
158
 
140
- const comparators: Record<FilterComparison, (row: unknown, filter: unknown) => boolean> = {
159
+ const comparators: Record<TabelaFilterComparison, (row: unknown, filter: unknown) => boolean> = {
141
160
  contains: (row, filter) => includes(getString(row), getString(filter), true),
142
161
  'ends-with': (row, filter) => endsWith(getString(row), getString(filter), true),
143
162
  equals: (row, filter) => equalizer(row, filter),