@oscarpalmer/tabela 0.10.0 → 0.12.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 (69) hide show
  1. package/dist/components/body.component.js +1 -0
  2. package/dist/components/column.component.js +4 -4
  3. package/dist/components/group.component.js +28 -0
  4. package/dist/components/row.component.js +11 -8
  5. package/dist/helpers/dom.helpers.js +1 -1
  6. package/dist/managers/column.manager.js +9 -8
  7. package/dist/managers/data.manager.js +95 -30
  8. package/dist/managers/event.manager.js +42 -23
  9. package/dist/managers/filter.manager.js +16 -10
  10. package/dist/managers/group.manager.js +46 -0
  11. package/dist/managers/navigation.manager.js +73 -0
  12. package/dist/managers/render.manager.js +61 -31
  13. package/dist/managers/row.manager.js +7 -7
  14. package/dist/managers/selection.manager.js +49 -46
  15. package/dist/managers/sort.manager.js +37 -9
  16. package/dist/models/group.model.js +0 -0
  17. package/dist/models/selection.model.js +0 -0
  18. package/dist/tabela.full.js +682 -591
  19. package/dist/tabela.js +31 -10
  20. package/package.json +1 -1
  21. package/src/components/body.component.ts +2 -0
  22. package/src/components/column.component.ts +6 -6
  23. package/src/components/group.component.ts +43 -0
  24. package/src/components/row.component.ts +14 -9
  25. package/src/helpers/dom.helpers.ts +3 -1
  26. package/src/managers/column.manager.ts +13 -15
  27. package/src/managers/data.manager.ts +176 -38
  28. package/src/managers/event.manager.ts +68 -41
  29. package/src/managers/filter.manager.ts +29 -20
  30. package/src/managers/group.manager.ts +79 -0
  31. package/src/managers/navigation.manager.ts +146 -0
  32. package/src/managers/render.manager.ts +84 -40
  33. package/src/managers/row.manager.ts +9 -14
  34. package/src/managers/selection.manager.ts +68 -67
  35. package/src/managers/sort.manager.ts +85 -22
  36. package/src/models/column.model.ts +2 -2
  37. package/src/models/data.model.ts +14 -3
  38. package/src/models/filter.model.ts +11 -3
  39. package/src/models/group.model.ts +4 -0
  40. package/src/models/render.model.ts +3 -1
  41. package/src/models/selection.model.ts +9 -0
  42. package/src/models/sort.model.ts +11 -3
  43. package/src/models/tabela.model.ts +14 -36
  44. package/src/models/tabela.options.ts +3 -2
  45. package/src/tabela.ts +43 -19
  46. package/types/components/column.component.d.ts +3 -3
  47. package/types/components/group.component.d.ts +14 -0
  48. package/types/components/row.component.d.ts +2 -2
  49. package/types/helpers/style.helper.d.ts +1 -1
  50. package/types/managers/column.manager.d.ts +6 -7
  51. package/types/managers/data.manager.d.ts +7 -6
  52. package/types/managers/event.manager.d.ts +3 -6
  53. package/types/managers/filter.manager.d.ts +11 -11
  54. package/types/managers/group.manager.d.ts +17 -0
  55. package/types/managers/navigation.manager.d.ts +10 -0
  56. package/types/managers/render.manager.d.ts +6 -7
  57. package/types/managers/row.manager.d.ts +4 -5
  58. package/types/managers/selection.manager.d.ts +12 -7
  59. package/types/managers/sort.manager.d.ts +11 -9
  60. package/types/models/column.model.d.ts +2 -2
  61. package/types/models/data.model.d.ts +13 -3
  62. package/types/models/filter.model.d.ts +10 -3
  63. package/types/models/group.model.d.ts +4 -0
  64. package/types/models/render.model.d.ts +2 -1
  65. package/types/models/selection.model.d.ts +8 -0
  66. package/types/models/sort.model.d.ts +10 -3
  67. package/types/models/tabela.model.d.ts +14 -33
  68. package/types/models/tabela.options.d.ts +3 -2
  69. package/types/tabela.d.ts +4 -1
package/dist/tabela.js CHANGED
@@ -2,13 +2,15 @@ import { BodyComponent } from "./components/body.component.js";
2
2
  import { FooterComponent } from "./components/footer.component.js";
3
3
  import { HeaderComponent } from "./components/header.component.js";
4
4
  import { ColumnManager } from "./managers/column.manager.js";
5
+ import { SortManager } from "./managers/sort.manager.js";
5
6
  import { DataManager } from "./managers/data.manager.js";
6
7
  import { EventManager } from "./managers/event.manager.js";
7
8
  import { FilterManager } from "./managers/filter.manager.js";
9
+ import { GroupManager } from "./managers/group.manager.js";
10
+ import { NavigationManager } from "./managers/navigation.manager.js";
11
+ import { RenderManager } from "./managers/render.manager.js";
8
12
  import { RowManager } from "./managers/row.manager.js";
9
13
  import { SelectionManager } from "./managers/selection.manager.js";
10
- import { SortManager } from "./managers/sort.manager.js";
11
- import { RenderManager } from "./managers/render.manager.js";
12
14
  var Tabela = class {
13
15
  #components = {
14
16
  header: void 0,
@@ -16,12 +18,15 @@ var Tabela = class {
16
18
  footer: void 0
17
19
  };
18
20
  #element;
21
+ #id = getId();
19
22
  #key;
20
23
  #managers = {
21
24
  column: void 0,
22
25
  data: void 0,
23
26
  event: void 0,
24
27
  filter: void 0,
28
+ group: void 0,
29
+ navigation: void 0,
25
30
  render: void 0,
26
31
  row: void 0,
27
32
  selection: void 0,
@@ -44,14 +49,24 @@ var Tabela = class {
44
49
  this.#components.header = new HeaderComponent();
45
50
  this.#components.body = new BodyComponent();
46
51
  this.#components.footer = new FooterComponent();
47
- this.#managers.column = new ColumnManager(this.#managers, this.#components, options.columns);
48
- this.#managers.data = new DataManager(this.#managers, this.#components, options.key);
49
- this.#managers.event = new EventManager(this.#element, this.#managers);
50
- this.#managers.filter = new FilterManager(this.#managers);
51
- this.#managers.render = new RenderManager(this.#managers, this.#components);
52
- this.#managers.row = new RowManager(this.#managers, options.rowHeight);
53
- this.#managers.selection = new SelectionManager(this.#element, this.#managers);
54
- this.#managers.sort = new SortManager(this.#managers);
52
+ const state = {
53
+ element,
54
+ options,
55
+ components: this.#components,
56
+ id: this.#id,
57
+ key: this.#key,
58
+ managers: this.#managers
59
+ };
60
+ this.#managers.column = new ColumnManager(state);
61
+ this.#managers.data = new DataManager(state);
62
+ this.#managers.event = new EventManager(state);
63
+ this.#managers.filter = new FilterManager(state);
64
+ this.#managers.group = new GroupManager(state);
65
+ this.#managers.navigation = new NavigationManager(state);
66
+ this.#managers.render = new RenderManager(state);
67
+ this.#managers.row = new RowManager(state);
68
+ this.#managers.selection = new SelectionManager(state);
69
+ this.#managers.sort = new SortManager(state);
55
70
  element.append(this.#components.header.elements.group, this.#components.body.elements.group, this.#components.footer.elements.group);
56
71
  this.#managers.data.set(options.data);
57
72
  this.data = this.#managers.data.handlers;
@@ -72,6 +87,7 @@ var Tabela = class {
72
87
  managers.filter.destroy();
73
88
  managers.render.destroy();
74
89
  managers.row.destroy();
90
+ managers.selection.destroy();
75
91
  managers.sort.destroy();
76
92
  element.innerHTML = "";
77
93
  element.role = "";
@@ -81,4 +97,9 @@ var Tabela = class {
81
97
  this.#element = void 0;
82
98
  }
83
99
  };
100
+ function getId() {
101
+ id += 1;
102
+ return id;
103
+ }
104
+ var id = 0;
84
105
  export { Tabela };
package/package.json CHANGED
@@ -46,5 +46,5 @@
46
46
  },
47
47
  "type": "module",
48
48
  "types": "./types/index.d.ts",
49
- "version": "0.10.0"
49
+ "version": "0.12.0"
50
50
  }
@@ -22,6 +22,8 @@ export class BodyComponent {
22
22
 
23
23
  group.tabIndex = 0;
24
24
 
25
+ group.setAttribute('data-event', 'body');
26
+
25
27
  group.append(this.elements.faker);
26
28
  }
27
29
 
@@ -1,21 +1,21 @@
1
1
  import {createElement} from '../helpers/dom.helpers';
2
- import type {TabelaColumn, TabelaColumnOptions} from '../models/column.model';
2
+ import type {Column, TabelaColumn} from '../models/column.model';
3
3
 
4
4
  export class ColumnComponent {
5
5
  elements: ColumnElements;
6
- options: TabelaColumn;
6
+ options: Column;
7
7
 
8
- constructor(options: TabelaColumnOptions) {
8
+ constructor(column: TabelaColumn) {
9
9
  const width =
10
10
  Number.parseInt(getComputedStyle(document.body).fontSize, 10) *
11
- (options.width ?? options.title.length * 1.5);
11
+ (column.width ?? column.title.length * 1.5);
12
12
 
13
13
  this.options = {
14
- ...options,
14
+ ...column,
15
15
  width,
16
16
  };
17
17
 
18
- this.elements = createHeading(options.field, options.title, width);
18
+ this.elements = createHeading(this.options.field, this.options.title, width);
19
19
  }
20
20
 
21
21
  destroy(): void {
@@ -0,0 +1,43 @@
1
+ import {createElement} from '../helpers/dom.helpers';
2
+ import type {State} from '../models/tabela.model';
3
+
4
+ export class GroupComponent {
5
+ element: HTMLElement | undefined;
6
+
7
+ expanded = true;
8
+
9
+ filtered = 0;
10
+
11
+ selected = 0;
12
+
13
+ total = 0;
14
+
15
+ constructor(
16
+ readonly key: string,
17
+ readonly label: string,
18
+ readonly value: unknown,
19
+ ) {}
20
+ }
21
+
22
+ export function renderGroup(state: State, component: GroupComponent): void {
23
+ component.element ??= createElement(
24
+ 'div',
25
+ {
26
+ className: 'tabela__row tabela__row--group',
27
+ innerHTML: `<div class="tabela__cell tabela__cell--group" role="cell">
28
+ <button class="tabela__button tabela__button--group" data-event="group" data-key="${component.key}" type="button">
29
+ <span aria-hidden="true"></span>
30
+ <span>Open/close</span>
31
+ </button>
32
+ <p>${component.label}</p>
33
+ </div>`,
34
+ role: 'row',
35
+ },
36
+ {},
37
+ {
38
+ height: `${state.options.rowHeight}px`,
39
+ },
40
+ );
41
+ }
42
+
43
+ export function updateGroup(state: State, component: GroupComponent): void {}
@@ -2,7 +2,7 @@ import type {Key} from '@oscarpalmer/atoms/models';
2
2
  import {setAttributes} from '@oscarpalmer/toretto/attribute';
3
3
  import {createCell, createRow} from '../helpers/dom.helpers';
4
4
  import type {RenderElementPool} from '../models/render.model';
5
- import type {TabelaManagers} from '../models/tabela.model';
5
+ import type {State} from '../models/tabela.model';
6
6
 
7
7
  export function removeRow(pool: RenderElementPool, row: RowComponent): void {
8
8
  if (row.element != null) {
@@ -17,19 +17,23 @@ export function removeRow(pool: RenderElementPool, row: RowComponent): void {
17
17
  row.cells = {};
18
18
  }
19
19
 
20
- export function renderRow(managers: TabelaManagers, row: RowComponent): void {
21
- const element = row.element ?? managers.render.pool.rows.shift() ?? createRow();
20
+ export function renderRow(state: State, row: RowComponent): void {
21
+ const element = row.element ?? state.managers.render.pool.rows.shift() ?? createRow();
22
22
 
23
23
  row.element = element;
24
24
 
25
25
  element.innerHTML = '';
26
26
 
27
- const selected = managers.selection.items.has(row.key);
27
+ const selected = state.managers.selection.items.has(row.key);
28
+
29
+ const key = String(row.key);
28
30
 
29
31
  setAttributes(element, {
30
32
  'aria-selected': String(selected),
33
+ 'data-active': String(state.managers.navigation.active === row.key),
31
34
  'data-event': 'row',
32
- 'data-key': String(row.key),
35
+ 'data-key': key,
36
+ id: `tabela_${state.id}_row_${key}`,
33
37
  });
34
38
 
35
39
  element.classList.add('tabela__row--body');
@@ -40,10 +44,10 @@ export function renderRow(managers: TabelaManagers, row: RowComponent): void {
40
44
  element.classList.remove('tabela__row--selected');
41
45
  }
42
46
 
43
- const columns = managers.column.items;
47
+ const columns = state.managers.column.items;
44
48
  const {length} = columns;
45
49
 
46
- const data = managers.data.values.objects.mapped.get(row.key);
50
+ const data = state.managers.data.values.objects.mapped.get(row.key);
47
51
 
48
52
  if (data == null) {
49
53
  return;
@@ -52,10 +56,11 @@ export function renderRow(managers: TabelaManagers, row: RowComponent): void {
52
56
  for (let index = 0; index < length; index += 1) {
53
57
  const {options} = columns[index];
54
58
 
55
- managers.render.pool.cells[options.field] ??= [];
59
+ state.managers.render.pool.cells[options.field] ??= [];
56
60
 
57
61
  const cell =
58
- managers.render.pool.cells[columns[index].options.field].shift() ?? createCell(options.width);
62
+ state.managers.render.pool.cells[columns[index].options.field].shift() ??
63
+ createCell(options.width);
59
64
 
60
65
  cell.textContent = String(data[options.field]);
61
66
 
@@ -80,7 +80,9 @@ export function createRow(): HTMLDivElement {
80
80
  role: 'row',
81
81
  },
82
82
  {},
83
- {},
83
+ {
84
+ height: '32px',
85
+ },
84
86
  );
85
87
 
86
88
  return row;
@@ -1,16 +1,12 @@
1
1
  import {ColumnComponent} from '../components/column.component';
2
- import type {TabelaColumnOptions} from '../models/column.model';
3
- import type {TabelaComponents, TabelaManagers} from '../models/tabela.model';
2
+ import type {TabelaColumn} from '../models/column.model';
3
+ import type {State} from '../models/tabela.model';
4
4
 
5
5
  export class ColumnManager {
6
- readonly items: ColumnComponent[] = [];
7
-
8
- constructor(
9
- public managers: TabelaManagers,
10
- public components: TabelaComponents,
11
- columns: TabelaColumnOptions[],
12
- ) {
13
- this.set(columns);
6
+ items: ColumnComponent[] = [];
7
+
8
+ constructor(public state: State) {
9
+ this.set(state.options.columns);
14
10
  }
15
11
 
16
12
  destroy(): void {
@@ -20,7 +16,8 @@ export class ColumnManager {
20
16
  this.items[index].destroy();
21
17
  }
22
18
 
23
- this.items.length = 0;
19
+ this.items = undefined as never;
20
+ this.state = undefined as never;
24
21
  }
25
22
 
26
23
  remove(field: string): void;
@@ -28,7 +25,8 @@ export class ColumnManager {
28
25
  remove(fields: string[]): void;
29
26
 
30
27
  remove(value: unknown): void {
31
- const {components, items, managers} = this;
28
+ const {items, state} = this;
29
+ const {components, managers} = state;
32
30
 
33
31
  const fields = (Array.isArray(value) ? value : [value]).filter(
34
32
  item => typeof item === 'string',
@@ -58,9 +56,9 @@ export class ColumnManager {
58
56
  managers.render.removeCells(fields);
59
57
  }
60
58
 
61
- set(columns: TabelaColumnOptions[]): void {
62
- const {components, items} = this;
63
- const {footer, header} = components;
59
+ set(columns: TabelaColumn[]): void {
60
+ const {items, state} = this;
61
+ const {footer, header} = state.components;
64
62
 
65
63
  items.splice(0, items.length, ...columns.map(column => new ColumnComponent(column)));
66
64
 
@@ -1,9 +1,12 @@
1
- import {push, sort} from '@oscarpalmer/atoms/array';
1
+ import {select, sort} from '@oscarpalmer/atoms/array';
2
2
  import {toMap} from '@oscarpalmer/atoms/array/to-map';
3
- import {isPlainObject} from '@oscarpalmer/atoms/is';
3
+ import {toRecord} from '@oscarpalmer/atoms/array/to-record';
4
4
  import type {Key, PlainObject} from '@oscarpalmer/atoms/models';
5
- import type {DataValues} from '../models/data.model';
6
- import type {TabelaComponents, TabelaData, TabelaManagers} from '../models/tabela.model';
5
+ import type {DataValues, TabelaData} from '../models/data.model';
6
+ import type {State} from '../models/tabela.model';
7
+ import {GroupComponent} from '../components/group.component';
8
+ import {sortWithGroups} from './sort.manager';
9
+ import {isPlainObject} from '@oscarpalmer/atoms/is';
7
10
 
8
11
  export class DataManager {
9
12
  handlers = Object.freeze({
@@ -15,7 +18,7 @@ export class DataManager {
15
18
  update: data => void this.update(data),
16
19
  } satisfies TabelaData);
17
20
 
18
- readonly values: DataValues = {
21
+ values: DataValues = {
19
22
  keys: {
20
23
  original: [],
21
24
  },
@@ -25,24 +28,61 @@ export class DataManager {
25
28
  },
26
29
  };
27
30
 
31
+ get keys(): Array<GroupComponent | Key> {
32
+ return this.values.keys.active ?? this.values.keys.original;
33
+ }
34
+
28
35
  get size(): number {
29
- return this.values.keys.active?.length ?? this.values.keys.original.length;
36
+ return this.keys.length;
30
37
  }
31
38
 
32
- constructor(
33
- public managers: TabelaManagers,
34
- public components: TabelaComponents,
35
- public field: string,
36
- ) {}
39
+ constructor(public state: State) {}
37
40
 
38
41
  async add(data: PlainObject[], render: boolean): Promise<void> {
39
- const {field, values} = this;
42
+ const {state, values} = this;
43
+ const {length} = data;
40
44
 
41
- push(values.objects.array, data);
45
+ const updates: PlainObject[] = [];
42
46
 
43
- values.objects.mapped = toMap(values.objects.array, field) as Map<Key, PlainObject>;
47
+ for (let index = 0; index < length; index += 1) {
48
+ const item = data[index];
49
+ const key = item[state.key] as Key;
44
50
 
45
- if (render) {
51
+ if (values.objects.mapped.has(key)) {
52
+ updates.push(item);
53
+
54
+ continue;
55
+ }
56
+
57
+ values.objects.array.push(item);
58
+ values.objects.mapped.set(key, item);
59
+
60
+ if (!state.managers.group.enabled) {
61
+ continue;
62
+ }
63
+
64
+ const groupKey = item[state.managers.group.field] as unknown;
65
+
66
+ let group = state.managers.group.get(groupKey);
67
+
68
+ if (group == null) {
69
+ group = new GroupComponent(String(groupKey), String(groupKey), groupKey);
70
+
71
+ values.objects.array.push(group);
72
+
73
+ state.managers.group.add(group);
74
+ }
75
+
76
+ if (!group.expanded) {
77
+ state.managers.group.collapsed.add(key);
78
+ }
79
+
80
+ group.total += 1;
81
+ }
82
+
83
+ if (updates.length > 0) {
84
+ void this.update(updates);
85
+ } else if (render) {
46
86
  this.render();
47
87
  }
48
88
  }
@@ -63,21 +103,31 @@ export class DataManager {
63
103
  values.objects.array.length = 0;
64
104
 
65
105
  this.handlers = undefined as never;
106
+ this.state = undefined as never;
107
+ this.values = undefined as never;
66
108
  }
67
109
 
68
110
  get(active?: boolean): PlainObject[] {
69
111
  const {values} = this;
70
112
 
71
113
  return (active ?? false)
72
- ? (values.keys.active?.map(key => values.objects.mapped.get(key) as PlainObject) ?? [])
73
- : values.objects.array;
114
+ ? select(
115
+ values.keys.active ?? [],
116
+ key => !(key instanceof GroupComponent),
117
+ key => values.objects.mapped.get(key as Key)!,
118
+ )
119
+ : (values.objects.array.filter(item => !(item instanceof GroupComponent)) as PlainObject[]);
120
+ }
121
+
122
+ getIndex(key: Key): number {
123
+ return this.keys.indexOf(key);
74
124
  }
75
125
 
76
126
  async remove(items: Array<Key | PlainObject>, render: boolean): Promise<void> {
77
- const {field, managers, values} = this;
127
+ const {state, values} = this;
78
128
 
79
129
  const keys = items
80
- .map(value => (isPlainObject(value) ? value[field] : value) as Key)
130
+ .map(value => (isPlainObject(value) ? value[state.key] : value) as Key)
81
131
  .filter(key => values.objects.mapped.has(key)) as Key[];
82
132
 
83
133
  const {length} = keys;
@@ -91,15 +141,49 @@ export class DataManager {
91
141
 
92
142
  values.objects.mapped.delete(key);
93
143
 
94
- const arrayIndex = values.objects.array.findIndex(object => object[field] === key);
144
+ const arrayIndex = values.objects.array.findIndex(
145
+ item => !(item instanceof GroupComponent) && item[state.key] === key,
146
+ );
147
+
148
+ let item: PlainObject | undefined;
95
149
 
96
150
  if (arrayIndex > -1) {
97
- values.objects.array.splice(arrayIndex, 1);
151
+ [item] = values.objects.array.splice(arrayIndex, 1) as PlainObject[];
98
152
  }
99
153
 
100
154
  values.keys.original.splice(values.keys.original.indexOf(key), 1);
101
155
 
102
- managers.row.remove(key);
156
+ state.managers.row.remove(key);
157
+
158
+ if (!state.managers.group.enabled || item == null) {
159
+ continue;
160
+ }
161
+
162
+ state.managers.group.collapsed.delete(key);
163
+
164
+ const groupKey = item[state.managers.group.field] as unknown;
165
+
166
+ const group = state.managers.group.get(groupKey);
167
+
168
+ if (group == null) {
169
+ continue;
170
+ }
171
+
172
+ group.total -= 1;
173
+
174
+ if (group.total > 0) {
175
+ continue;
176
+ }
177
+
178
+ const groupIndex = values.objects.array.findIndex(
179
+ item => item instanceof GroupComponent && item.value === groupKey,
180
+ );
181
+
182
+ if (groupIndex > -1) {
183
+ values.objects.array.splice(groupIndex, 1);
184
+ }
185
+
186
+ state.managers.group.remove(group);
103
187
  }
104
188
 
105
189
  if (render) {
@@ -108,30 +192,82 @@ export class DataManager {
108
192
  }
109
193
 
110
194
  render(): void {
111
- const {field, managers, values} = this;
195
+ const {state, values} = this;
196
+
197
+ if (state.managers.group.enabled) {
198
+ sortWithGroups(state, values.objects.array, [
199
+ {
200
+ direction: 'ascending',
201
+ key: state.key,
202
+ },
203
+ ]);
204
+ } else {
205
+ sort(values.objects.array as PlainObject[], [
206
+ {
207
+ direction: 'ascending',
208
+ key: state.key,
209
+ },
210
+ ]);
211
+ }
112
212
 
113
- values.keys.original = sort(values.objects.array.map(item => item[field] as Key));
213
+ values.keys.original = values.objects.array.map(item =>
214
+ item instanceof GroupComponent ? item : (item[state.key] as Key),
215
+ );
114
216
 
115
- if (Object.keys(managers.filter.items).length > 0) {
116
- managers.filter.filter();
117
- } else if (managers.sort.items.length > 0) {
118
- managers.sort.sort();
217
+ values.objects.mapped = toMap(
218
+ values.objects.array.filter(item => !(item instanceof GroupComponent)) as PlainObject[],
219
+ item => item[state.key] as Key,
220
+ );
221
+
222
+ if (Object.keys(state.managers.filter.items).length > 0) {
223
+ state.managers.filter.filter();
224
+ } else if (state.managers.sort.items.length > 0) {
225
+ state.managers.sort.sort();
119
226
  } else {
120
- managers.render.update(true);
227
+ state.managers.render.update(true, true);
121
228
  }
122
229
  }
123
230
 
124
231
  set(data: PlainObject[]): void {
125
- const {field, values} = this;
232
+ const {state, values} = this;
233
+
234
+ const array: Array<GroupComponent | PlainObject> = data.slice();
235
+
236
+ if (state.managers.group.enabled) {
237
+ const grouped = toRecord.arrays(data, state.managers.group.field) as Record<
238
+ string,
239
+ PlainObject[]
240
+ >;
241
+
242
+ const entries = Object.entries(grouped);
243
+ const {length} = entries;
244
+
245
+ const groups: GroupComponent[] = [];
246
+
247
+ for (let index = 0; index < length; index += 1) {
248
+ const [value, items] = entries[index];
249
+
250
+ const key = String(value);
251
+
252
+ const group = new GroupComponent(key, key, value);
253
+
254
+ group.total = items.length;
255
+
256
+ groups.push(group);
257
+
258
+ array.push(group);
259
+ }
260
+
261
+ state.managers.group.set(groups);
262
+ }
126
263
 
127
- values.objects.mapped = toMap(data, field) as Map<Key, PlainObject>;
128
- values.objects.array = data;
264
+ values.objects.array = array;
129
265
 
130
266
  this.render();
131
267
  }
132
268
 
133
269
  async synchronize(data: PlainObject[], remove?: boolean): Promise<void> {
134
- const {field, values} = this;
270
+ const {state, values} = this;
135
271
 
136
272
  const add: PlainObject[] = [];
137
273
  const updated: PlainObject[] = [];
@@ -142,7 +278,7 @@ export class DataManager {
142
278
 
143
279
  for (let index = 0; index < length; index += 1) {
144
280
  const object = data[index];
145
- const key = object[field] as Key;
281
+ const key = object[state.key] as Key;
146
282
 
147
283
  if (values.objects.mapped.has(key)) {
148
284
  updated.push(object);
@@ -158,7 +294,9 @@ export class DataManager {
158
294
  }
159
295
 
160
296
  if (remove ?? false) {
161
- const toRemove = values.keys.original.filter(key => !keys.has(key));
297
+ const toRemove = values.keys.original.filter(
298
+ key => !(key instanceof GroupComponent) && !keys.has(key),
299
+ ) as Key[];
162
300
 
163
301
  if (toRemove.length > 0) {
164
302
  await this.remove(toRemove, false);
@@ -177,19 +315,19 @@ export class DataManager {
177
315
  }
178
316
 
179
317
  async update(data: PlainObject[]): Promise<void> {
180
- const {field, managers, values} = this;
318
+ const {state, values} = this;
181
319
 
182
320
  const {length} = data;
183
321
 
184
322
  for (let index = 0; index < length; index += 1) {
185
323
  const object = data[index];
186
- const key = object[field] as Key;
324
+ const key = object[state.key] as Key;
187
325
  const value = values.objects.mapped.get(key);
188
326
 
189
327
  if (value != null) {
190
328
  values.objects.mapped.set(key, {...value, ...object} as PlainObject);
191
329
 
192
- managers.row.update(key);
330
+ state.managers.row.update(key);
193
331
  }
194
332
  }
195
333
  }