@oscarpalmer/tabela 0.13.0 → 0.14.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 (131) hide show
  1. package/dist/components/{body.component.mjs → body.component.js} +3 -6
  2. package/dist/components/{column.component.mjs → column.component.js} +5 -8
  3. package/dist/components/{footer.component.mjs → footer.component.js} +4 -7
  4. package/dist/components/group.component.js +28 -0
  5. package/dist/components/{header.component.mjs → header.component.js} +3 -6
  6. package/dist/components/{row.component.mjs → row.component.js} +7 -11
  7. package/dist/helpers/{dom.helpers.mjs → dom.helpers.js} +9 -13
  8. package/dist/helpers/{misc.helpers.mjs → misc.helpers.js} +1 -3
  9. package/dist/helpers/style.helper.js +6 -0
  10. package/dist/{index.mjs → index.js} +1 -3
  11. package/dist/managers/{column.manager.mjs → column.manager.js} +1 -6
  12. package/dist/managers/data.manager.js +181 -0
  13. package/dist/managers/{event.manager.mjs → event.manager.js} +8 -9
  14. package/dist/managers/{filter.manager.mjs → filter.manager.js} +14 -23
  15. package/dist/managers/group.manager.js +46 -0
  16. package/dist/managers/{navigation.manager.mjs → navigation.manager.js} +24 -27
  17. package/dist/managers/{render.manager.mjs → render.manager.js} +26 -35
  18. package/dist/managers/{row.manager.mjs → row.manager.js} +11 -18
  19. package/dist/managers/{selection.manager.mjs → selection.manager.js} +28 -32
  20. package/dist/managers/{sort.manager.mjs → sort.manager.js} +9 -12
  21. package/dist/models/body.model.js +0 -0
  22. package/dist/models/column.model.js +0 -0
  23. package/dist/models/data.model.js +0 -0
  24. package/dist/models/filter.model.js +0 -0
  25. package/dist/models/footer.model.js +0 -0
  26. package/dist/models/group.model.js +0 -0
  27. package/dist/models/header.model.js +0 -0
  28. package/dist/models/render.model.js +0 -0
  29. package/dist/models/selection.model.js +0 -0
  30. package/dist/models/sort.model.js +0 -0
  31. package/dist/models/tabela.model.js +0 -0
  32. package/dist/models/tabela.options.js +0 -0
  33. package/dist/{tabela.full.mjs → tabela.full.js} +860 -1049
  34. package/dist/tabela.js +105 -0
  35. package/package.json +1 -1
  36. package/src/components/body.component.ts +10 -7
  37. package/src/components/column.component.ts +19 -15
  38. package/src/components/footer.component.ts +7 -10
  39. package/src/components/group.component.ts +34 -12
  40. package/src/components/header.component.ts +6 -5
  41. package/src/components/row.component.ts +27 -19
  42. package/src/helpers/dom.helpers.ts +18 -22
  43. package/src/helpers/misc.helpers.ts +5 -0
  44. package/src/managers/data.manager.ts +80 -77
  45. package/src/managers/event.manager.ts +21 -10
  46. package/src/managers/filter.manager.ts +34 -21
  47. package/src/managers/group.manager.ts +18 -9
  48. package/src/managers/navigation.manager.ts +46 -49
  49. package/src/managers/render.manager.ts +34 -21
  50. package/src/managers/row.manager.ts +1 -1
  51. package/src/managers/selection.manager.ts +37 -35
  52. package/src/managers/sort.manager.ts +47 -34
  53. package/src/managers/style.manager.ts +40 -25
  54. package/src/models/column.model.ts +2 -6
  55. package/src/models/data.model.ts +7 -8
  56. package/src/models/dom.model.ts +33 -0
  57. package/src/models/event.model.ts +7 -0
  58. package/src/models/filter.model.ts +20 -0
  59. package/src/models/group.model.ts +4 -0
  60. package/src/models/sort.model.ts +4 -0
  61. package/src/models/style.model.ts +32 -20
  62. package/src/models/tabela.model.ts +1 -0
  63. package/src/tabela.ts +20 -22
  64. package/dist/body.component-_VDOpJhV.d.mts +0 -10
  65. package/dist/body.model-2iwsovAV.d.mts +0 -7
  66. package/dist/column.component-Bx46r3JI.d.mts +0 -16
  67. package/dist/column.model-D-aw4EU4.d.mts +0 -16
  68. package/dist/components/body.component.d.mts +0 -2
  69. package/dist/components/column.component.d.mts +0 -2
  70. package/dist/components/footer.component.d.mts +0 -2
  71. package/dist/components/group.component.d.mts +0 -2
  72. package/dist/components/group.component.mjs +0 -51
  73. package/dist/components/header.component.d.mts +0 -2
  74. package/dist/components/row.component.d.mts +0 -2
  75. package/dist/filter.model-7ukJrtil.d.mts +0 -16
  76. package/dist/footer.component-Curiab8j.d.mts +0 -12
  77. package/dist/footer.model-DhqoS6ds.d.mts +0 -8
  78. package/dist/group.component-Cq1YYbfJ.d.mts +0 -285
  79. package/dist/group.model-BsKFwHbt.d.mts +0 -10
  80. package/dist/header.component-BjjlpZIg.d.mts +0 -12
  81. package/dist/header.model-DN_KzUCV.d.mts +0 -7
  82. package/dist/helpers/dom.helpers.d.mts +0 -12
  83. package/dist/helpers/misc.helpers.d.mts +0 -6
  84. package/dist/helpers/style.helper.d.mts +0 -6
  85. package/dist/helpers/style.helper.mjs +0 -8
  86. package/dist/index.d.mts +0 -7
  87. package/dist/managers/column.manager.d.mts +0 -2
  88. package/dist/managers/data.manager.d.mts +0 -2
  89. package/dist/managers/data.manager.mjs +0 -222
  90. package/dist/managers/event.manager.d.mts +0 -2
  91. package/dist/managers/filter.manager.d.mts +0 -2
  92. package/dist/managers/group.manager.d.mts +0 -2
  93. package/dist/managers/group.manager.mjs +0 -73
  94. package/dist/managers/navigation.manager.d.mts +0 -2
  95. package/dist/managers/render.manager.d.mts +0 -2
  96. package/dist/managers/row.manager.d.mts +0 -2
  97. package/dist/managers/selection.manager.d.mts +0 -2
  98. package/dist/managers/sort.manager.d.mts +0 -2
  99. package/dist/managers/style.manager.d.mts +0 -2
  100. package/dist/managers/style.manager.mjs +0 -149
  101. package/dist/models/body.model.d.mts +0 -2
  102. package/dist/models/body.model.mjs +0 -1
  103. package/dist/models/column.model.d.mts +0 -2
  104. package/dist/models/column.model.mjs +0 -1
  105. package/dist/models/data.model.d.mts +0 -2
  106. package/dist/models/data.model.mjs +0 -1
  107. package/dist/models/filter.model.d.mts +0 -2
  108. package/dist/models/filter.model.mjs +0 -1
  109. package/dist/models/footer.model.d.mts +0 -2
  110. package/dist/models/footer.model.mjs +0 -1
  111. package/dist/models/group.model.d.mts +0 -2
  112. package/dist/models/group.model.mjs +0 -1
  113. package/dist/models/header.model.d.mts +0 -2
  114. package/dist/models/header.model.mjs +0 -1
  115. package/dist/models/render.model.d.mts +0 -2
  116. package/dist/models/render.model.mjs +0 -1
  117. package/dist/models/selection.model.d.mts +0 -2
  118. package/dist/models/selection.model.mjs +0 -1
  119. package/dist/models/sort.model.d.mts +0 -2
  120. package/dist/models/sort.model.mjs +0 -1
  121. package/dist/models/style.model.d.mts +0 -23
  122. package/dist/models/style.model.mjs +0 -23
  123. package/dist/models/tabela.model.d.mts +0 -2
  124. package/dist/models/tabela.model.mjs +0 -1
  125. package/dist/models/tabela.options.d.mts +0 -2
  126. package/dist/models/tabela.options.mjs +0 -1
  127. package/dist/selection.model-rwQe9fco.d.mts +0 -12
  128. package/dist/sort.model-CauImaLu.d.mts +0 -15
  129. package/dist/tabela.d.mts +0 -21
  130. package/dist/tabela.mjs +0 -126
  131. package/dist/tabela.options-RkZvfptB.d.mts +0 -14
@@ -5,36 +5,38 @@ import {isPlainObject} from '@oscarpalmer/atoms/is';
5
5
  import type {Key, PlainObject} from '@oscarpalmer/atoms/models';
6
6
  import {delay} from '@oscarpalmer/atoms/promise/delay';
7
7
  import {getValue} from '@oscarpalmer/atoms/value/handle';
8
+ import type {ColumnComponent} from '../components/column.component';
8
9
  import {GroupComponent, updateGroup} from '../components/group.component';
9
- import type {DataItem, DataState, TabelaData} from '../models/data.model';
10
+ import type {DataState, DataValue, TabelaData} from '../models/data.model';
11
+ import {SORT_ASCENDING} from '../models/sort.model';
10
12
  import type {State} from '../models/tabela.model';
11
13
  import {sortWithGroups} from './sort.manager';
12
- import type {ColumnComponent} from '../components/column.component';
14
+ import {isGroupKey} from '../helpers/misc.helpers';
13
15
 
14
16
  export class DataManager {
15
- handlers = Object.freeze({
17
+ handlers: TabelaData = {
16
18
  add: data => void this.add(data, true),
17
- clear: () => void this.clear(),
19
+ clear: () => this.clear(),
18
20
  get: active => this.get(active),
19
21
  remove: items => void this.remove(items, true),
20
- synchronize: (data, remove) => void this.synchronize(data, remove),
21
- update: data => void this.update(data),
22
- } satisfies TabelaData);
22
+ synchronize: (data, remove) => void this.synchronize(data, remove === true),
23
+ update: data => void this.update(data, true),
24
+ };
23
25
 
24
26
  state: DataState;
25
27
 
26
- get items(): DataItem[] {
27
- return this.state.items.active ?? this.state.items.original;
28
+ get keys(): Key[] {
29
+ return this.state.keys.active ?? this.state.keys.original;
28
30
  }
29
31
 
30
32
  get size(): number {
31
- return this.items.length;
33
+ return this.keys.length;
32
34
  }
33
35
 
34
36
  constructor(state: State) {
35
37
  this.state = {
36
38
  ...state,
37
- items: {
39
+ keys: {
38
40
  original: [],
39
41
  },
40
42
  values: {
@@ -53,6 +55,8 @@ export class DataManager {
53
55
  let groupColumn: ColumnComponent | undefined;
54
56
  let {length} = data;
55
57
 
58
+ let added = 0;
59
+
56
60
  for (let index = 0; index < length; index += 1) {
57
61
  const item = data[index];
58
62
  const key = getValue(item, state.key) as Key;
@@ -66,23 +70,25 @@ export class DataManager {
66
70
  state.values.array.push(item);
67
71
  state.values.mapped.set(key, item);
68
72
 
73
+ added += 1;
74
+
69
75
  if (!state.managers.group.enabled) {
70
76
  continue;
71
77
  }
72
78
 
73
- const groupValue = getValue(item, state.managers.group.field) as unknown;
79
+ const groupValue = getValue(item, state.managers.group.field) as Key;
74
80
 
75
- let group = state.managers.group.get(groupValue);
81
+ let group = state.managers.group.getForValue(groupValue);
76
82
 
77
83
  if (group == null) {
78
84
  groupColumn ??= state.managers.column.get(state.managers.group.field);
79
85
 
80
86
  group = new GroupComponent(
81
- `${groupColumn?.options.title ?? state.managers.group.field}: ${groupValue}`,
87
+ `${groupColumn?.options.label ?? state.managers.group.field}: ${groupValue}`,
82
88
  groupValue,
83
89
  );
84
90
 
85
- state.values.array.push(group);
91
+ state.values.array.push(group.key);
86
92
  state.managers.group.add(group);
87
93
  }
88
94
 
@@ -101,9 +107,9 @@ export class DataManager {
101
107
  updateGroup(state, groups[index]);
102
108
  }
103
109
 
104
- if (updates.length > 0) {
105
- void this.update(updates);
106
- } else if (render) {
110
+ await this.update(updates, added === 0);
111
+
112
+ if (added > 0 && render) {
107
113
  this.render();
108
114
  }
109
115
  }
@@ -119,8 +125,8 @@ export class DataManager {
119
125
 
120
126
  state.values.mapped.clear();
121
127
 
122
- state.items.active = undefined;
123
- state.items.original.length = 0;
128
+ state.keys.active = undefined;
129
+ state.keys.original.length = 0;
124
130
  state.values.array.length = 0;
125
131
 
126
132
  this.handlers = undefined as never;
@@ -132,29 +138,23 @@ export class DataManager {
132
138
 
133
139
  return (active ?? false)
134
140
  ? select(
135
- state.items.active ?? [],
136
- key => !(key instanceof GroupComponent),
141
+ state.keys.active ?? [],
142
+ key => !isGroupKey(key),
137
143
  key => state.values.mapped.get(key as Key)!,
138
144
  )
139
- : (state.values.array.filter(item => !(item instanceof GroupComponent)) as PlainObject[]);
145
+ : (state.values.array.filter(item => !isGroupKey(item)) as PlainObject[]);
140
146
  }
141
147
 
142
- getIndex(item: DataItem): number {
143
- if (item instanceof GroupComponent) {
144
- return this.items.indexOf(item);
145
- }
146
-
147
- return this.items.findIndex(value =>
148
- value instanceof GroupComponent ? value.key === item : value === item,
149
- );
148
+ getIndex(item: Key): number {
149
+ return this.keys.indexOf(item);
150
150
  }
151
151
 
152
152
  async remove(items: Array<Key | PlainObject>, render: boolean): Promise<void> {
153
153
  const {state} = this;
154
154
 
155
- const keys = items.map(
156
- value => (isPlainObject(value) ? getValue(value, state.key) : value) as Key,
157
- );
155
+ const keys = items
156
+ .map(value => (isPlainObject(value) ? getValue(value, state.key) : value) as Key)
157
+ .filter(key => !isGroupKey(key));
158
158
 
159
159
  const {length} = keys;
160
160
 
@@ -163,12 +163,12 @@ export class DataManager {
163
163
  }
164
164
  }
165
165
 
166
- async removeItems(items: DataItem[], clear: boolean, render: boolean): Promise<void> {
166
+ async removeItems(keys: Key[], clear: boolean, render: boolean): Promise<void> {
167
167
  const {state} = this;
168
168
 
169
169
  if (clear) {
170
- state.items.active = undefined;
171
- state.items.original = [];
170
+ state.keys.active = undefined;
171
+ state.keys.original = [];
172
172
  state.values.array = [];
173
173
 
174
174
  state.values.mapped.clear();
@@ -184,34 +184,34 @@ export class DataManager {
184
184
 
185
185
  const groups: GroupComponent[] = [];
186
186
 
187
- const chunked = chunk(items);
187
+ const chunked = chunk(keys);
188
188
  const chunkedLength = chunked.length;
189
189
 
190
190
  for (let chunkedIndex = 0; chunkedIndex < chunkedLength; chunkedIndex += 1) {
191
191
  const chunk = chunked[chunkedIndex];
192
192
  const chunkLength = chunk.length;
193
193
 
194
- for (let itemIndex = 0; itemIndex < chunkLength; itemIndex += 1) {
195
- const item = chunk[itemIndex];
196
- const dataIndex = state.items.original.indexOf(item);
194
+ for (let keyIndex = 0; keyIndex < chunkLength; keyIndex += 1) {
195
+ const key = chunk[keyIndex];
196
+ const dataIndex = state.keys.original.indexOf(key);
197
197
 
198
198
  let dataValue: PlainObject | undefined;
199
199
 
200
200
  [dataValue] = state.values.array.splice(dataIndex, 1) as PlainObject[];
201
201
 
202
- state.items.original.splice(dataIndex, 1);
203
- state.managers.row.remove(item as never);
204
- state.values.mapped.delete(item as Key);
202
+ state.keys.original.splice(dataIndex, 1);
203
+ state.managers.row.remove(key as never);
204
+ state.values.mapped.delete(key as Key);
205
205
 
206
- if (!state.managers.group.enabled || item instanceof GroupComponent) {
206
+ if (!state.managers.group.enabled || isGroupKey(key)) {
207
207
  continue;
208
208
  }
209
209
 
210
- state.managers.group.collapsed.delete(item as never);
210
+ state.managers.group.collapsed.delete(key as never);
211
211
 
212
- const groupKey = getValue(dataValue, state.managers.group.field) as unknown;
212
+ const groupValue = getValue(dataValue, state.managers.group.field) as unknown;
213
213
 
214
- const group = state.managers.group.get(groupKey);
214
+ const group = state.managers.group.getForValue(groupValue);
215
215
 
216
216
  if (group == null) {
217
217
  continue;
@@ -231,16 +231,16 @@ export class DataManager {
231
231
  groups.splice(groupIndex, 1);
232
232
  }
233
233
 
234
- groupIndex = state.values.array.indexOf(group);
234
+ groupIndex = state.values.array.indexOf(group.key);
235
235
 
236
236
  if (groupIndex > -1) {
237
- state.items.original.splice(groupIndex, 1);
237
+ state.keys.original.splice(groupIndex, 1);
238
238
  state.values.array.splice(groupIndex, 1);
239
239
  }
240
240
 
241
241
  state.managers.group.remove(group);
242
242
 
243
- if (items.length >= 10_000) {
243
+ if (keys.length >= 10_000) {
244
244
  await delay(25);
245
245
  }
246
246
  }
@@ -263,25 +263,25 @@ export class DataManager {
263
263
  if (state.managers.group.enabled) {
264
264
  sortWithGroups(state, state.values.array, [
265
265
  {
266
- direction: 'ascending',
266
+ direction: SORT_ASCENDING,
267
267
  key: state.key,
268
268
  },
269
269
  ]);
270
270
  } else {
271
271
  sort(state.values.array as PlainObject[], [
272
272
  {
273
- direction: 'ascending',
273
+ direction: SORT_ASCENDING,
274
274
  key: state.key,
275
275
  },
276
276
  ]);
277
277
  }
278
278
 
279
- state.items.original = state.values.array.map(item =>
280
- item instanceof GroupComponent ? item : (getValue(item, state.key) as Key),
279
+ state.keys.original = state.values.array.map(item =>
280
+ typeof item === 'string' ? item : (getValue(item, state.key) as Key),
281
281
  );
282
282
 
283
283
  state.values.mapped = toMap(
284
- state.values.array.filter(item => !(item instanceof GroupComponent)) as PlainObject[],
284
+ state.values.array.filter(item => !isGroupKey(item)) as PlainObject[],
285
285
  item => getValue(item, state.key) as Key,
286
286
  );
287
287
 
@@ -297,7 +297,7 @@ export class DataManager {
297
297
  set(data: PlainObject[]): void {
298
298
  const {state} = this;
299
299
 
300
- const array: Array<GroupComponent | PlainObject> = data.slice();
300
+ const array: DataValue[] = data.slice();
301
301
 
302
302
  if (state.managers.group.enabled) {
303
303
  const column = state.managers.column.get(state.managers.group.field);
@@ -316,7 +316,7 @@ export class DataManager {
316
316
  const [value, items] = entries[index];
317
317
 
318
318
  const group = new GroupComponent(
319
- `${column?.options.title ?? state.managers.group.field}: ${value}`,
319
+ `${column?.options.label ?? state.managers.group.field}: ${value}`,
320
320
  value,
321
321
  );
322
322
 
@@ -324,7 +324,7 @@ export class DataManager {
324
324
 
325
325
  groups.push(group);
326
326
 
327
- array.push(group);
327
+ array.push(group.key);
328
328
  }
329
329
 
330
330
  state.managers.group.set(groups);
@@ -335,10 +335,10 @@ export class DataManager {
335
335
  this.render();
336
336
  }
337
337
 
338
- async synchronize(data: PlainObject[], remove?: boolean): Promise<void> {
338
+ async synchronize(data: PlainObject[], remove: boolean): Promise<void> {
339
339
  const {state} = this;
340
340
 
341
- const add: PlainObject[] = [];
341
+ const added: PlainObject[] = [];
342
342
  const updated: PlainObject[] = [];
343
343
 
344
344
  const keys = new Set<Key>([]);
@@ -352,7 +352,7 @@ export class DataManager {
352
352
  if (state.values.mapped.has(key)) {
353
353
  updated.push(object);
354
354
  } else {
355
- add.push(object);
355
+ added.push(object);
356
356
  }
357
357
 
358
358
  keys.add(key);
@@ -362,9 +362,9 @@ export class DataManager {
362
362
  return;
363
363
  }
364
364
 
365
- if (remove ?? false) {
366
- const toRemove = state.items.original.filter(
367
- key => !(key instanceof GroupComponent) && !keys.has(key),
365
+ if (remove) {
366
+ const toRemove = state.keys.original.filter(
367
+ key => !isGroupKey(key) && !keys.has(key),
368
368
  ) as Key[];
369
369
 
370
370
  if (toRemove.length > 0) {
@@ -372,31 +372,34 @@ export class DataManager {
372
372
  }
373
373
  }
374
374
 
375
- await this.update(updated);
375
+ await this.update(updated, added.length === 0);
376
376
 
377
- if (add.length > 0) {
378
- await this.add(add, false);
379
- }
377
+ await this.add(added, false);
380
378
 
381
- if (add.length > 0 || (remove ?? false)) {
379
+ if (added.length > 0 || remove) {
382
380
  this.render();
383
381
  }
384
382
  }
385
383
 
386
- async update(data: PlainObject[]): Promise<void> {
384
+ async update(data: PlainObject[], render: boolean): Promise<void> {
387
385
  const {state} = this;
388
386
 
389
387
  const {length} = data;
390
388
 
391
- for (let index = 0; index < length; index += 1) {
392
- const object = data[index];
389
+ for (let dataIndex = 0; dataIndex < length; dataIndex += 1) {
390
+ const dataItem = data[dataIndex];
393
391
 
394
- const key = getValue(object, state.key) as Key;
395
- const value = state.values.mapped.get(key);
392
+ const key = getValue(dataItem, state.key) as Key;
393
+
394
+ const keyIndex = state.keys.original.indexOf(key);
395
+
396
+ if (keyIndex === -1) {
397
+ continue;
398
+ }
396
399
 
397
- if (value != null) {
398
- state.values.mapped.set(key, {...value, ...object} as PlainObject);
400
+ Object.assign(state.values.array[keyIndex], dataItem);
399
401
 
402
+ if (render) {
400
403
  state.managers.row.update(key);
401
404
  }
402
405
  }
@@ -1,6 +1,13 @@
1
1
  import {on} from '@oscarpalmer/toretto/event';
2
2
  import {findAncestor} from '@oscarpalmer/toretto/find';
3
3
  import type {State} from '../models/tabela.model';
4
+ import {
5
+ ATTRIBUTE_DATA_EVENT,
6
+ ATTRIBUTE_DATA_FIELD,
7
+ ATTRIBUTE_DATA_SORT_DIRECTION,
8
+ } from '../models/dom.model';
9
+ import {CSS_TABLE} from '../models/style.model';
10
+ import {EVENT_GROUP, EVENT_HEADING, EVENT_ROW} from '../models/event.model';
4
11
 
5
12
  export class EventManager {
6
13
  constructor(public state: State) {
@@ -14,8 +21,8 @@ export class EventManager {
14
21
  }
15
22
 
16
23
  onSort(event: MouseEvent, target: HTMLElement): void {
17
- const direction = target.getAttribute('data-sort-direction');
18
- const field = target.getAttribute('data-field');
24
+ const direction = target.getAttribute(ATTRIBUTE_DATA_SORT_DIRECTION);
25
+ const field = target.getAttribute(ATTRIBUTE_DATA_FIELD);
19
26
 
20
27
  if (field != null) {
21
28
  this.state.managers.sort.toggle(event, field, direction);
@@ -24,8 +31,8 @@ export class EventManager {
24
31
  }
25
32
 
26
33
  function onClick(event: MouseEvent): void {
27
- const target = findAncestor(event, '[data-event]');
28
- const table = findAncestor(event, '.tabela__table');
34
+ const target = findAncestor(event, eventAttribute);
35
+ const table = findAncestor(event, tableClassName);
29
36
 
30
37
  if (!(target instanceof HTMLElement) || !(table instanceof HTMLElement)) {
31
38
  return;
@@ -37,18 +44,18 @@ function onClick(event: MouseEvent): void {
37
44
  return;
38
45
  }
39
46
 
40
- const type = target?.getAttribute('data-event');
47
+ const type = target?.getAttribute(ATTRIBUTE_DATA_EVENT);
41
48
 
42
49
  switch (type) {
43
- case 'group':
50
+ case EVENT_GROUP:
44
51
  manager.state.managers.group.handle(target);
45
52
  break;
46
53
 
47
- case 'heading':
54
+ case EVENT_HEADING:
48
55
  manager.onSort(event, target);
49
56
  break;
50
57
 
51
- case 'row':
58
+ case EVENT_ROW:
52
59
  manager.state.managers.selection.handle(event, target);
53
60
  break;
54
61
 
@@ -58,8 +65,8 @@ function onClick(event: MouseEvent): void {
58
65
  }
59
66
 
60
67
  function onKeydown(event: KeyboardEvent): void {
61
- const target = findAncestor(event, '[data-event]');
62
- const table = findAncestor(event, '.tabela__table');
68
+ const target = findAncestor(event, eventAttribute);
69
+ const table = findAncestor(event, tableClassName);
63
70
 
64
71
  if (!(target instanceof HTMLElement) || !(table instanceof HTMLElement)) {
65
72
  return;
@@ -82,7 +89,11 @@ function onKeydown(event: KeyboardEvent): void {
82
89
  manager.state.managers.navigation.handle(event);
83
90
  }
84
91
 
92
+ const eventAttribute = `[${ATTRIBUTE_DATA_EVENT}]`;
93
+
85
94
  const mapped = new WeakMap<HTMLElement, EventManager>();
86
95
 
96
+ const tableClassName = `.${CSS_TABLE}`;
97
+
87
98
  on(document, 'click', onClick);
88
99
  on(document, 'keydown', onKeydown, {passive: false});
@@ -1,19 +1,32 @@
1
+ import type {Key} from '@oscarpalmer/atoms/models';
1
2
  import {getNumber} from '@oscarpalmer/atoms/number';
2
3
  import {getString} from '@oscarpalmer/atoms/string';
3
4
  import {endsWith, includes, startsWith} from '@oscarpalmer/atoms/string/match';
4
5
  import {equal} from '@oscarpalmer/atoms/value/equal';
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';
6
+ import {isGroupKey} from '../helpers/misc.helpers';
7
+ import {
8
+ FILTER_CONTAINS,
9
+ FILTER_ENDS_WITH,
10
+ FILTER_EQUALS,
11
+ FILTER_GREATER_THAN,
12
+ FILTER_GREATER_THAN_OR_EQUAL,
13
+ FILTER_LESS_THAN,
14
+ FILTER_LESS_THAN_OR_EQUAL,
15
+ FILTER_NOT_CONTAINS,
16
+ FILTER_NOT_EQUALS,
17
+ FILTER_STARTS_WITH,
18
+ type TabelaFilter,
19
+ type TabelaFilterItem,
20
+ } from '../models/filter.model';
8
21
  import type {State} from '../models/tabela.model';
9
22
 
10
23
  export class FilterManager {
11
- handlers = Object.freeze({
24
+ handlers: TabelaFilter = {
12
25
  add: item => this.add(item),
13
26
  clear: () => this.clear(),
14
27
  remove: value => this.remove(value),
15
28
  set: items => this.set(items),
16
- } satisfies TabelaFilter);
29
+ };
17
30
 
18
31
  items: Record<string, TabelaFilterItem[]> = {};
19
32
 
@@ -52,15 +65,15 @@ export class FilterManager {
52
65
  filter(): void {
53
66
  const {state} = this;
54
67
 
55
- const filtered: DataItem[] = [];
68
+ const filtered: Key[] = [];
56
69
  const filters = Object.entries(this.items);
57
70
 
58
- const itemsLength = state.managers.data.state.items.original.length;
71
+ const itemsLength = state.managers.data.state.keys.original.length;
59
72
 
60
73
  rowLoop: for (let itemIndex = 0; itemIndex < itemsLength; itemIndex += 1) {
61
- const item = state.managers.data.state.items.original[itemIndex];
74
+ const item = state.managers.data.state.keys.original[itemIndex];
62
75
 
63
- if (item instanceof GroupComponent) {
76
+ if (isGroupKey(item)) {
64
77
  filtered.push(item);
65
78
 
66
79
  continue;
@@ -91,7 +104,7 @@ export class FilterManager {
91
104
  filtered.push(item);
92
105
  }
93
106
 
94
- state.managers.data.state.items.active = filtered;
107
+ state.managers.data.state.keys.active = filtered;
95
108
 
96
109
  if (state.managers.sort.items.length > 0) {
97
110
  state.managers.sort.sort();
@@ -156,17 +169,17 @@ export class FilterManager {
156
169
  }
157
170
  }
158
171
 
159
- const comparators: Record<TabelaFilterComparison, (row: unknown, filter: unknown) => boolean> = {
160
- contains: (row, filter) => includes(getString(row), getString(filter), true),
161
- 'ends-with': (row, filter) => endsWith(getString(row), getString(filter), true),
162
- equals: (row, filter) => equalizer(row, filter),
163
- 'greater-than': (row, filter) => getNumber(row) > getNumber(filter),
164
- 'greater-than-or-equal': (row, filter) => getNumber(row) >= getNumber(filter),
165
- 'less-than': (row, filter) => getNumber(row) < getNumber(filter),
166
- 'less-than-or-equal': (row, filter) => getNumber(row) <= getNumber(filter),
167
- 'not-contains': (row, filter) => !includes(getString(row), getString(filter), true),
168
- 'not-equals': (row, filter) => !equalizer(row, filter),
169
- 'starts-with': (row, filter) => startsWith(getString(row), getString(filter), true),
172
+ const comparators: Record<string, (row: unknown, filter: unknown) => boolean> = {
173
+ [FILTER_CONTAINS]: (row, filter) => includes(getString(row), getString(filter), true),
174
+ [FILTER_ENDS_WITH]: (row, filter) => endsWith(getString(row), getString(filter), true),
175
+ [FILTER_EQUALS]: (row, filter) => equalizer(row, filter),
176
+ [FILTER_GREATER_THAN]: (row, filter) => getNumber(row) > getNumber(filter),
177
+ [FILTER_GREATER_THAN_OR_EQUAL]: (row, filter) => getNumber(row) >= getNumber(filter),
178
+ [FILTER_LESS_THAN]: (row, filter) => getNumber(row) < getNumber(filter),
179
+ [FILTER_LESS_THAN_OR_EQUAL]: (row, filter) => getNumber(row) <= getNumber(filter),
180
+ [FILTER_NOT_CONTAINS]: (row, filter) => !includes(getString(row), getString(filter), true),
181
+ [FILTER_NOT_EQUALS]: (row, filter) => !equalizer(row, filter),
182
+ [FILTER_STARTS_WITH]: (row, filter) => startsWith(getString(row), getString(filter), true),
170
183
  };
171
184
 
172
185
  const equalizer = equal.initialize({
@@ -1,4 +1,5 @@
1
1
  import {sort} from '@oscarpalmer/atoms/array';
2
+ import {toMap} from '@oscarpalmer/atoms/array/to-map';
2
3
  import {toRecord} from '@oscarpalmer/atoms/array/to-record';
3
4
  import {isNullableOrWhitespace} from '@oscarpalmer/atoms/is';
4
5
  import type {Key, Simplify} from '@oscarpalmer/atoms/models';
@@ -14,7 +15,7 @@ export class GroupManager {
14
15
 
15
16
  field!: string;
16
17
 
17
- handlers = Object.freeze({
18
+ handlers: TabelaGroup = {
18
19
  set: (group?: string) => {
19
20
  if (group === this.field) {
20
21
  return;
@@ -25,10 +26,12 @@ export class GroupManager {
25
26
 
26
27
  this.state.managers.data.set(this.state.managers.data.get());
27
28
  },
28
- } satisfies TabelaGroup);
29
+ };
29
30
 
30
31
  items: GroupComponent[] = [];
31
32
 
33
+ mapped = new Map<string, GroupComponent>();
34
+
32
35
  order: Record<never, number> = {};
33
36
 
34
37
  constructor(public state: State) {
@@ -67,15 +70,19 @@ export class GroupManager {
67
70
  this.state = undefined as never;
68
71
  }
69
72
 
70
- get(value: unknown) {
73
+ getForKey(key: string): GroupComponent | undefined {
74
+ return this.mapped.get(key);
75
+ }
76
+
77
+ getForValue(value: unknown): GroupComponent | undefined {
71
78
  const asString = getString(value);
72
79
 
73
80
  return this.items.find(item => item.value.stringified === asString);
74
81
  }
75
82
 
76
83
  handle(button: HTMLElement): void {
77
- const value = button.dataset.key?.replace(`tabela_${this.state.id}_group:`, '');
78
- const group = this.get(value);
84
+ const key = button.dataset.key?.replace(`${this.state.prefix}_`, '');
85
+ const group = this.getForKey(key ?? '');
79
86
 
80
87
  if (group == null) {
81
88
  return;
@@ -87,15 +94,15 @@ export class GroupManager {
87
94
 
88
95
  const index = items.indexOf(group);
89
96
 
90
- let first = state.managers.data.state.items.original.indexOf(items[index]) + 1;
97
+ let first = state.managers.data.state.keys.original.indexOf(group.key) + 1;
91
98
 
92
99
  const last =
93
100
  items[index + 1] == null
94
- ? state.managers.data.state.items.original.length - 1
95
- : state.managers.data.state.items.original.indexOf(items[index + 1]) - 1;
101
+ ? state.managers.data.state.keys.original.length - 1
102
+ : state.managers.data.state.keys.original.indexOf(items[index + 1].key) - 1;
96
103
 
97
104
  for (; first <= last; first += 1) {
98
- const key = state.managers.data.state.items.original[first] as Key;
105
+ const key = state.managers.data.state.keys.original[first] as Key;
99
106
 
100
107
  if (group.expanded) {
101
108
  collapsed.delete(key);
@@ -122,6 +129,8 @@ export class GroupManager {
122
129
  set(items: GroupComponent[]) {
123
130
  this.items = sort(items, item => item.label);
124
131
 
132
+ this.mapped = toMap(items, group => group.key);
133
+
125
134
  this.order = toRecord(
126
135
  items as Simplify<GroupComponent>[],
127
136
  group => group.value.stringified,