@oscarpalmer/tabela 0.14.0 → 0.15.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 (126) hide show
  1. package/dist/components/body.component.d.mts +11 -0
  2. package/dist/components/body.component.mjs +28 -0
  3. package/dist/components/column.component.d.mts +16 -0
  4. package/dist/components/column.component.mjs +46 -0
  5. package/dist/components/footer.component.d.mts +13 -0
  6. package/dist/components/{footer.component.js → footer.component.mjs} +9 -6
  7. package/dist/components/group.component.d.mts +20 -0
  8. package/dist/components/group.component.mjs +57 -0
  9. package/dist/components/header.component.d.mts +13 -0
  10. package/dist/components/header.component.mjs +25 -0
  11. package/dist/components/row.component.d.mts +15 -0
  12. package/dist/components/row.component.mjs +56 -0
  13. package/dist/helpers/dom.helpers.d.mts +12 -0
  14. package/dist/helpers/dom.helpers.mjs +43 -0
  15. package/dist/helpers/misc.helpers.d.mts +12 -0
  16. package/dist/helpers/misc.helpers.mjs +20 -0
  17. package/dist/helpers/style.helper.d.mts +6 -0
  18. package/dist/helpers/style.helper.mjs +8 -0
  19. package/dist/index.d.mts +7 -0
  20. package/dist/{index.js → index.mjs} +3 -1
  21. package/dist/managers/column.manager.d.mts +17 -0
  22. package/dist/managers/{column.manager.js → column.manager.mjs} +11 -6
  23. package/dist/managers/data.manager.d.mts +27 -0
  24. package/dist/managers/data.manager.mjs +256 -0
  25. package/dist/managers/event.manager.d.mts +18 -0
  26. package/dist/managers/event.manager.mjs +79 -0
  27. package/dist/managers/filter.manager.d.mts +18 -0
  28. package/dist/managers/filter.manager.mjs +115 -0
  29. package/dist/managers/group.manager.d.mts +27 -0
  30. package/dist/managers/group.manager.mjs +93 -0
  31. package/dist/managers/navigation.manager.d.mts +15 -0
  32. package/dist/managers/navigation.manager.mjs +80 -0
  33. package/dist/managers/render.manager.d.mts +19 -0
  34. package/dist/managers/render.manager.mjs +157 -0
  35. package/dist/managers/row.manager.d.mts +19 -0
  36. package/dist/managers/row.manager.mjs +45 -0
  37. package/dist/managers/selection.manager.d.mts +23 -0
  38. package/dist/managers/{selection.manager.js → selection.manager.mjs} +38 -31
  39. package/dist/managers/sort.manager.d.mts +23 -0
  40. package/dist/managers/sort.manager.mjs +147 -0
  41. package/dist/managers/style.manager.d.mts +9 -0
  42. package/dist/managers/style.manager.mjs +181 -0
  43. package/dist/models/body.model.d.mts +7 -0
  44. package/dist/models/body.model.mjs +1 -0
  45. package/dist/models/column.model.d.mts +13 -0
  46. package/dist/models/column.model.mjs +1 -0
  47. package/dist/models/data.model.d.mts +28 -0
  48. package/dist/models/data.model.mjs +1 -0
  49. package/dist/models/dom.model.d.mts +19 -0
  50. package/dist/models/dom.model.mjs +19 -0
  51. package/dist/models/event.model.d.mts +99 -0
  52. package/dist/models/event.model.mjs +53 -0
  53. package/dist/models/filter.model.d.mts +26 -0
  54. package/dist/models/filter.model.mjs +13 -0
  55. package/dist/models/footer.model.d.mts +8 -0
  56. package/dist/models/footer.model.mjs +1 -0
  57. package/dist/models/group.model.d.mts +19 -0
  58. package/dist/models/group.model.mjs +5 -0
  59. package/dist/models/header.model.d.mts +7 -0
  60. package/dist/models/header.model.mjs +1 -0
  61. package/dist/models/render.model.d.mts +22 -0
  62. package/dist/models/render.model.mjs +1 -0
  63. package/dist/models/selection.model.d.mts +12 -0
  64. package/dist/models/selection.model.mjs +1 -0
  65. package/dist/models/sort.model.d.mts +19 -0
  66. package/dist/models/sort.model.mjs +5 -0
  67. package/dist/models/style.model.d.mts +29 -0
  68. package/dist/models/style.model.mjs +29 -0
  69. package/dist/models/tabela.model.d.mts +46 -0
  70. package/dist/models/tabela.model.mjs +1 -0
  71. package/dist/models/tabela.options.d.mts +14 -0
  72. package/dist/models/tabela.options.mjs +1 -0
  73. package/dist/tabela.d.mts +22 -0
  74. package/dist/{tabela.full.js → tabela.full.mjs} +1501 -803
  75. package/dist/tabela.mjs +126 -0
  76. package/package.json +2 -4
  77. package/src/components/column.component.ts +4 -4
  78. package/src/components/group.component.ts +6 -2
  79. package/src/components/row.component.ts +5 -5
  80. package/src/helpers/misc.helpers.ts +13 -1
  81. package/src/managers/column.manager.ts +9 -9
  82. package/src/managers/data.manager.ts +139 -53
  83. package/src/managers/event.manager.ts +52 -6
  84. package/src/managers/filter.manager.ts +36 -20
  85. package/src/managers/group.manager.ts +43 -10
  86. package/src/managers/render.manager.ts +30 -17
  87. package/src/managers/sort.manager.ts +81 -52
  88. package/src/managers/style.manager.ts +33 -0
  89. package/src/models/column.model.ts +2 -2
  90. package/src/models/data.model.ts +6 -6
  91. package/src/models/dom.model.ts +0 -2
  92. package/src/models/event.model.ts +168 -0
  93. package/src/models/filter.model.ts +2 -2
  94. package/src/models/group.model.ts +9 -0
  95. package/src/models/render.model.ts +6 -0
  96. package/src/models/sort.model.ts +7 -5
  97. package/src/tabela.ts +6 -2
  98. package/dist/components/body.component.js +0 -23
  99. package/dist/components/column.component.js +0 -41
  100. package/dist/components/group.component.js +0 -28
  101. package/dist/components/header.component.js +0 -22
  102. package/dist/components/row.component.js +0 -48
  103. package/dist/helpers/dom.helpers.js +0 -38
  104. package/dist/helpers/misc.helpers.js +0 -7
  105. package/dist/helpers/style.helper.js +0 -6
  106. package/dist/managers/data.manager.js +0 -181
  107. package/dist/managers/event.manager.js +0 -53
  108. package/dist/managers/filter.manager.js +0 -98
  109. package/dist/managers/group.manager.js +0 -46
  110. package/dist/managers/navigation.manager.js +0 -73
  111. package/dist/managers/render.manager.js +0 -135
  112. package/dist/managers/row.manager.js +0 -38
  113. package/dist/managers/sort.manager.js +0 -122
  114. package/dist/models/body.model.js +0 -0
  115. package/dist/models/column.model.js +0 -0
  116. package/dist/models/data.model.js +0 -0
  117. package/dist/models/filter.model.js +0 -0
  118. package/dist/models/footer.model.js +0 -0
  119. package/dist/models/group.model.js +0 -0
  120. package/dist/models/header.model.js +0 -0
  121. package/dist/models/render.model.js +0 -0
  122. package/dist/models/selection.model.js +0 -0
  123. package/dist/models/sort.model.js +0 -0
  124. package/dist/models/tabela.model.js +0 -0
  125. package/dist/models/tabela.options.js +0 -0
  126. package/dist/tabela.js +0 -105
@@ -0,0 +1,256 @@
1
+ import { EVENT_DATA_ADD, EVENT_DATA_CLEAR, EVENT_DATA_REMOVE, EVENT_DATA_SYNCHRONIZE, EVENT_DATA_UPDATE, EVENT_GROUP_ADD, EVENT_GROUP_REMOVE, EVENT_GROUP_UPDATE } from "../models/event.model.mjs";
2
+ import { GroupComponent, updateGroup } from "../components/group.component.mjs";
3
+ import { getGroup, isGroupKey } from "../helpers/misc.helpers.mjs";
4
+ import { SORT_ASCENDING } from "../models/sort.model.mjs";
5
+ import { sortWithGroups } from "./sort.manager.mjs";
6
+ import { chunk, select, sort } from "@oscarpalmer/atoms/array";
7
+ import { toMap } from "@oscarpalmer/atoms/array/to-map";
8
+ import { toRecord } from "@oscarpalmer/atoms/array/to-record";
9
+ import { isPlainObject } from "@oscarpalmer/atoms/is";
10
+ import { delay } from "@oscarpalmer/atoms/promise/delay";
11
+ import { getValue } from "@oscarpalmer/atoms/value/handle";
12
+ //#region src/managers/data.manager.ts
13
+ var DataManager = class {
14
+ handlers = {
15
+ add: (data) => this.add(data, true),
16
+ clear: () => this.clear(),
17
+ get: (active) => this.get(active),
18
+ remove: (items) => this.remove(items, true),
19
+ synchronize: (data, remove) => this.synchronize(data, remove === true),
20
+ update: (data) => this.update(data, true)
21
+ };
22
+ state;
23
+ get keys() {
24
+ return this.state.keys.active ?? this.state.keys.original;
25
+ }
26
+ get size() {
27
+ return this.keys.length;
28
+ }
29
+ constructor(state) {
30
+ this.state = {
31
+ ...state,
32
+ keys: { original: [] },
33
+ values: {
34
+ array: [],
35
+ mapped: /* @__PURE__ */ new Map()
36
+ }
37
+ };
38
+ }
39
+ async add(data, render) {
40
+ const { state } = this;
41
+ const addedData = [];
42
+ const updatedData = [];
43
+ const addedGroups = [];
44
+ const updatedGroups = [];
45
+ let groupColumn;
46
+ let { length } = data;
47
+ for (let index = 0; index < length; index += 1) {
48
+ const item = data[index];
49
+ const key = getValue(item, state.key);
50
+ if (state.values.mapped.has(key)) {
51
+ updatedData.push(item);
52
+ continue;
53
+ }
54
+ addedData.push(item);
55
+ state.values.array.push(item);
56
+ state.values.mapped.set(key, item);
57
+ if (!state.managers.group.enabled) continue;
58
+ const groupValue = getValue(item, state.managers.group.key);
59
+ let group = state.managers.group.getForValue(groupValue);
60
+ if (group == null) {
61
+ groupColumn ??= state.managers.column.get(state.managers.group.key);
62
+ group = new GroupComponent(`${groupColumn?.options.label ?? state.managers.group.key}: ${groupValue}`, groupValue);
63
+ state.values.array.push(group.key);
64
+ state.managers.group.add(group, false);
65
+ addedGroups.push(group);
66
+ } else if (!addedGroups.includes(group) && !updatedGroups.includes(group)) updatedGroups.push(group);
67
+ if (!group.expanded) state.managers.group.collapsed.add(key);
68
+ group.total += 1;
69
+ }
70
+ length = addedGroups.length;
71
+ if (length > 0) {
72
+ state.managers.event.emit(EVENT_GROUP_ADD, addedGroups.map(getGroup));
73
+ for (let index = 0; index < length; index += 1) updateGroup(state, addedGroups[index], false);
74
+ }
75
+ length = updatedGroups.length;
76
+ if (length > 0) {
77
+ for (let index = 0; index < length; index += 1) updateGroup(state, updatedGroups[index], false);
78
+ state.managers.event.emit(EVENT_GROUP_UPDATE, updatedGroups.map(getGroup));
79
+ }
80
+ await this.update(updatedData, addedData.length === 0);
81
+ if (addedData.length === 0) return;
82
+ state.managers.event.emit(EVENT_DATA_ADD, addedData);
83
+ if (render) this.render();
84
+ }
85
+ async clear() {
86
+ if (this.state.values.array.length > 0) return this.removeItems([], true, true).then(() => void 0);
87
+ }
88
+ destroy() {
89
+ const { state } = this;
90
+ state.values.mapped.clear();
91
+ state.keys.active = void 0;
92
+ state.keys.original.length = 0;
93
+ state.values.array.length = 0;
94
+ this.handlers = void 0;
95
+ this.state = void 0;
96
+ }
97
+ get(active) {
98
+ const { state } = this;
99
+ return (active ?? false) && state.keys.active != null ? select(state.keys.active, (key) => !isGroupKey(key), (key) => state.values.mapped.get(key)) : state.values.array.filter((item) => !isGroupKey(item));
100
+ }
101
+ getIndex(item) {
102
+ return this.keys.indexOf(item);
103
+ }
104
+ async remove(items, render) {
105
+ const { state } = this;
106
+ const keys = items.map((value) => isPlainObject(value) ? getValue(value, state.key) : value).filter((key) => !isGroupKey(key));
107
+ const { length } = keys;
108
+ return length === 0 ? render ? void 0 : [] : this.removeItems(keys, false, render);
109
+ }
110
+ async removeItems(keys, clear, render) {
111
+ const { state } = this;
112
+ if (clear) {
113
+ state.keys.active = void 0;
114
+ state.keys.original = [];
115
+ state.values.array = [];
116
+ state.values.mapped.clear();
117
+ state.managers.row.clear();
118
+ if (state.managers.group.enabled) state.managers.group.clear();
119
+ state.managers.event.emit(EVENT_DATA_CLEAR);
120
+ this.render();
121
+ return render ? void 0 : [];
122
+ }
123
+ const removedGroups = [];
124
+ const updatedGroups = [];
125
+ const removedData = [];
126
+ const chunked = chunk(keys);
127
+ const chunkedLength = chunked.length;
128
+ for (let chunkedIndex = 0; chunkedIndex < chunkedLength; chunkedIndex += 1) {
129
+ const chunk = chunked[chunkedIndex];
130
+ const chunkLength = chunk.length;
131
+ for (let keyIndex = 0; keyIndex < chunkLength; keyIndex += 1) {
132
+ const key = chunk[keyIndex];
133
+ const dataIndex = state.keys.original.indexOf(key);
134
+ let dataValue;
135
+ [dataValue] = state.values.array.splice(dataIndex, 1);
136
+ removedData.push(dataValue);
137
+ state.keys.original.splice(dataIndex, 1);
138
+ state.managers.row.remove(key);
139
+ state.values.mapped.delete(key);
140
+ if (!state.managers.group.enabled || isGroupKey(key)) continue;
141
+ state.managers.group.collapsed.delete(key);
142
+ const groupValue = getValue(dataValue, state.managers.group.key);
143
+ const group = state.managers.group.getForValue(groupValue);
144
+ if (group == null) continue;
145
+ group.total -= 1;
146
+ if (group.total > 0) {
147
+ updatedGroups.push(group);
148
+ continue;
149
+ }
150
+ let groupIndex = updatedGroups.indexOf(group);
151
+ if (groupIndex > -1) updatedGroups.splice(groupIndex, 1);
152
+ groupIndex = state.values.array.indexOf(group.key);
153
+ if (groupIndex > -1) {
154
+ state.keys.original.splice(groupIndex, 1);
155
+ state.values.array.splice(groupIndex, 1);
156
+ }
157
+ removedGroups.push(group);
158
+ state.managers.group.remove(group, false);
159
+ if (keys.length >= 1e4) await delay(25);
160
+ }
161
+ }
162
+ let { length } = updatedGroups;
163
+ if (length > 0) {
164
+ for (let index = 0; index < length; index += 1) updateGroup(state, updatedGroups[index], false);
165
+ state.managers.event.emit(EVENT_GROUP_UPDATE, updatedGroups.map(getGroup));
166
+ }
167
+ length = removedGroups.length;
168
+ if (length > 0) state.managers.event.emit(EVENT_GROUP_REMOVE, removedGroups.map(getGroup));
169
+ state.managers.event.emit(EVENT_DATA_REMOVE, removedData);
170
+ if (render) this.render();
171
+ return render ? void 0 : removedData;
172
+ }
173
+ render() {
174
+ const { state } = this;
175
+ if (state.managers.group.enabled) sortWithGroups(state, state.values.array, [{
176
+ direction: SORT_ASCENDING,
177
+ key: state.key
178
+ }]);
179
+ else sort(state.values.array, [{
180
+ direction: SORT_ASCENDING,
181
+ key: state.key
182
+ }]);
183
+ state.keys.active = void 0;
184
+ state.keys.original = state.values.array.map((item) => typeof item === "string" ? item : getValue(item, state.key));
185
+ state.values.mapped = toMap(state.values.array.filter((item) => !isGroupKey(item)), (item) => getValue(item, state.key));
186
+ if (Object.keys(state.managers.filter.items).length > 0) state.managers.filter.filter();
187
+ else if (state.managers.sort.items.length > 0) state.managers.sort.sort();
188
+ else state.managers.render.update(true, true);
189
+ }
190
+ set(data) {
191
+ const { state } = this;
192
+ const array = data.slice();
193
+ if (state.managers.group.enabled) {
194
+ const column = state.managers.column.get(state.managers.group.key);
195
+ const grouped = toRecord.arrays(data, state.managers.group.key);
196
+ const entries = Object.entries(grouped);
197
+ const { length } = entries;
198
+ const groups = [];
199
+ for (let index = 0; index < length; index += 1) {
200
+ const [value, items] = entries[index];
201
+ const group = new GroupComponent(`${column?.options.label ?? state.managers.group.key}: ${value}`, value);
202
+ group.total = items.length;
203
+ groups.push(group);
204
+ array.push(group.key);
205
+ }
206
+ state.managers.group.set(groups);
207
+ }
208
+ state.values.array = array;
209
+ this.render();
210
+ }
211
+ async synchronize(data, remove) {
212
+ const { state } = this;
213
+ const added = [];
214
+ const updated = [];
215
+ const keys = /* @__PURE__ */ new Set([]);
216
+ const { length } = data;
217
+ for (let index = 0; index < length; index += 1) {
218
+ const object = data[index];
219
+ const key = getValue(object, state.key);
220
+ if (state.values.mapped.has(key)) updated.push(object);
221
+ else added.push(object);
222
+ keys.add(key);
223
+ }
224
+ if (keys.size === 0) return;
225
+ let removed = [];
226
+ if (remove) {
227
+ const toRemove = state.keys.original.filter((key) => !isGroupKey(key) && !keys.has(key));
228
+ if (toRemove.length > 0) removed = await this.remove(toRemove, false);
229
+ }
230
+ await this.update(updated, added.length === 0);
231
+ await this.add(added, false);
232
+ state.managers.event.emit(EVENT_DATA_SYNCHRONIZE, {
233
+ added,
234
+ removed,
235
+ updated
236
+ });
237
+ if (added.length > 0 || remove) this.render();
238
+ }
239
+ async update(data, render) {
240
+ const { state } = this;
241
+ const { length } = data;
242
+ const updated = [];
243
+ for (let index = 0; index < length; index += 1) {
244
+ const item = data[index];
245
+ const key = getValue(item, state.key);
246
+ const existing = state.keys.original.indexOf(key);
247
+ if (existing === -1) continue;
248
+ Object.assign(state.values.array[existing], item);
249
+ updated.push(state.values.array[existing]);
250
+ if (render && state.managers.render.visible.keys.has(key)) state.managers.row.update(key);
251
+ }
252
+ if (updated.length > 0) state.managers.event.emit(EVENT_DATA_UPDATE, updated);
253
+ }
254
+ };
255
+ //#endregion
256
+ export { DataManager };
@@ -0,0 +1,18 @@
1
+ import { EventMap, EventName, Events, TabelaEvents } from "../models/event.model.mjs";
2
+ import { State } from "../models/tabela.model.mjs";
3
+ import { GenericCallback } from "@oscarpalmer/atoms/models";
4
+
5
+ //#region src/managers/event.manager.d.ts
6
+ declare class EventManager {
7
+ state: State;
8
+ events: Events;
9
+ handlers: TabelaEvents;
10
+ constructor(state: State);
11
+ emit<Name extends EventName>(name: Name, ...parameters: Parameters<EventMap[Name]>): void;
12
+ destroy(): void;
13
+ onSort(event: MouseEvent, target: HTMLElement): void;
14
+ subscribe(name: string, callback: GenericCallback): void;
15
+ unsubscribe(name: string, callback: GenericCallback): void;
16
+ }
17
+ //#endregion
18
+ export { EventManager };
@@ -0,0 +1,79 @@
1
+ import { ATTRIBUTE_DATA_EVENT, ATTRIBUTE_DATA_KEY, ATTRIBUTE_DATA_SORT_DIRECTION } from "../models/dom.model.mjs";
2
+ import { CSS_TABLE } from "../models/style.model.mjs";
3
+ import { EVENT_GROUP, EVENT_HEADING } from "../models/event.model.mjs";
4
+ import { isEvent } from "../helpers/misc.helpers.mjs";
5
+ import { on } from "@oscarpalmer/toretto/event";
6
+ import { findAncestor } from "@oscarpalmer/toretto/find";
7
+ //#region src/managers/event.manager.ts
8
+ var EventManager = class {
9
+ events = {};
10
+ handlers = {
11
+ subscribe: (name, callback) => this.subscribe(name, callback),
12
+ unsubscribe: (name, callback) => this.unsubscribe(name, callback)
13
+ };
14
+ constructor(state) {
15
+ this.state = state;
16
+ mapped.set(state.element, this);
17
+ }
18
+ emit(name, ...parameters) {
19
+ if (this.events[name] == null) return;
20
+ const handlers = [...this.events[name]];
21
+ const { length } = handlers;
22
+ for (let index = 0; index < length; index += 1) handlers[index](...parameters);
23
+ }
24
+ destroy() {
25
+ mapped.delete(this.state.element);
26
+ this.state = void 0;
27
+ }
28
+ onSort(event, target) {
29
+ const direction = target.getAttribute(ATTRIBUTE_DATA_SORT_DIRECTION);
30
+ const key = target.getAttribute(ATTRIBUTE_DATA_KEY);
31
+ if (key != null) this.state.managers.sort.toggle(event, key, direction);
32
+ }
33
+ subscribe(name, callback) {
34
+ if (!isEvent(name) || typeof callback !== "function") return;
35
+ this.events[name] ??= /* @__PURE__ */ new Set();
36
+ this.events[name].add(callback);
37
+ }
38
+ unsubscribe(name, callback) {
39
+ if (isEvent(name) && typeof callback === "function") this.events[name]?.delete(callback);
40
+ }
41
+ };
42
+ function onClick(event) {
43
+ const target = findAncestor(event, eventAttribute);
44
+ const table = findAncestor(event, tableClassName);
45
+ if (!(target instanceof HTMLElement) || !(table instanceof HTMLElement)) return;
46
+ const manager = mapped.get(table);
47
+ if (manager == null) return;
48
+ switch (target?.getAttribute(ATTRIBUTE_DATA_EVENT)) {
49
+ case EVENT_GROUP:
50
+ manager.state.managers.group.handle(target);
51
+ break;
52
+ case EVENT_HEADING:
53
+ manager.onSort(event, target);
54
+ break;
55
+ case "row":
56
+ manager.state.managers.selection.handle(event, target);
57
+ break;
58
+ default: break;
59
+ }
60
+ }
61
+ function onKeydown(event) {
62
+ const target = findAncestor(event, eventAttribute);
63
+ const table = findAncestor(event, tableClassName);
64
+ if (!(target instanceof HTMLElement) || !(table instanceof HTMLElement)) return;
65
+ const manager = mapped.get(table);
66
+ if (manager == null) return;
67
+ if (event.key === " ") {
68
+ event.preventDefault();
69
+ return;
70
+ }
71
+ manager.state.managers.navigation.handle(event);
72
+ }
73
+ const eventAttribute = `[${ATTRIBUTE_DATA_EVENT}]`;
74
+ const mapped = /* @__PURE__ */ new WeakMap();
75
+ const tableClassName = `.${CSS_TABLE}`;
76
+ on(document, "click", onClick);
77
+ on(document, "keydown", onKeydown, { passive: false });
78
+ //#endregion
79
+ export { EventManager };
@@ -0,0 +1,18 @@
1
+ import { TabelaFilter, TabelaFilterItem } from "../models/filter.model.mjs";
2
+ import { State } from "../models/tabela.model.mjs";
3
+
4
+ //#region src/managers/filter.manager.d.ts
5
+ declare class FilterManager {
6
+ state: State;
7
+ handlers: TabelaFilter;
8
+ items: Record<string, TabelaFilterItem[]>;
9
+ constructor(state: State);
10
+ add(item: TabelaFilterItem): void;
11
+ clear(): void;
12
+ destroy(): void;
13
+ filter(): void;
14
+ remove(value: string | TabelaFilterItem): void;
15
+ set(items: TabelaFilterItem[]): void;
16
+ }
17
+ //#endregion
18
+ export { FilterManager };
@@ -0,0 +1,115 @@
1
+ import { isGroupKey } from "../helpers/misc.helpers.mjs";
2
+ import { FILTER_CONTAINS, FILTER_ENDS_WITH, FILTER_EQUALS, FILTER_GREATER_THAN, FILTER_GREATER_THAN_OR_EQUAL, FILTER_LESS_THAN, FILTER_LESS_THAN_OR_EQUAL, FILTER_NOT_CONTAINS, FILTER_NOT_EQUALS, FILTER_STARTS_WITH } from "../models/filter.model.mjs";
3
+ import { getString } from "@oscarpalmer/atoms/string";
4
+ import { getNumber } from "@oscarpalmer/atoms/number";
5
+ import { endsWith, includes, startsWith } from "@oscarpalmer/atoms/string/match";
6
+ import { equal } from "@oscarpalmer/atoms/value/equal";
7
+ //#region src/managers/filter.manager.ts
8
+ var FilterManager = class {
9
+ handlers = {
10
+ add: (item) => this.add(item),
11
+ clear: () => this.clear(),
12
+ remove: (value) => this.remove(value),
13
+ set: (items) => this.set(items)
14
+ };
15
+ items = {};
16
+ constructor(state) {
17
+ this.state = state;
18
+ }
19
+ add(item) {
20
+ const { items, state } = this;
21
+ if (items[item.key] == null) items[item.key] = [];
22
+ else if (items[item.key].findIndex((existing) => equal(existing, item)) > -1) return;
23
+ items[item.key].push(item);
24
+ state.managers.event.emit("filter:add", [item]);
25
+ this.filter();
26
+ }
27
+ clear() {
28
+ if (Object.keys(this.items).length === 0) return;
29
+ this.items = {};
30
+ this.state.managers.event.emit("filter:clear");
31
+ this.filter();
32
+ }
33
+ destroy() {
34
+ this.handlers = void 0;
35
+ this.items = void 0;
36
+ this.state = void 0;
37
+ }
38
+ filter() {
39
+ const { state } = this;
40
+ const filtered = [];
41
+ const filters = Object.entries(this.items);
42
+ const itemsLength = state.managers.data.state.keys.original.length;
43
+ rowLoop: for (let itemIndex = 0; itemIndex < itemsLength; itemIndex += 1) {
44
+ const item = state.managers.data.state.keys.original[itemIndex];
45
+ if (isGroupKey(item)) {
46
+ filtered.push(item);
47
+ continue;
48
+ }
49
+ const row = state.managers.data.state.values.mapped.get(item);
50
+ if (row == null) continue;
51
+ filterLoop: for (let filterIndex = 0; filterIndex < filters.length; filterIndex += 1) {
52
+ const [key, items] = filters[filterIndex];
53
+ const value = row[key];
54
+ for (let itemIndex = 0; itemIndex < items.length; itemIndex += 1) {
55
+ const filter = items[itemIndex];
56
+ if (comparators[filter.comparison](value, filter.value)) continue filterLoop;
57
+ }
58
+ continue rowLoop;
59
+ }
60
+ filtered.push(item);
61
+ }
62
+ state.managers.data.state.keys.active = filtered;
63
+ if (state.managers.sort.items.length > 0) state.managers.sort.sort();
64
+ else state.managers.render.update(true, true);
65
+ }
66
+ remove(value) {
67
+ const removed = [];
68
+ if (typeof value === "string") {
69
+ if (this.items[value] == null) return;
70
+ const keyed = {};
71
+ const keys = Object.keys(this.items);
72
+ const { length } = keys;
73
+ for (let index = 0; index < length; index += 1) {
74
+ const key = keys[index];
75
+ if (key === value) removed.push(...this.items[key]);
76
+ else keyed[key] = this.items[key];
77
+ }
78
+ this.items = keyed;
79
+ } else {
80
+ const { key } = value;
81
+ if (this.items[key] == null) return;
82
+ const index = this.items[key].findIndex((item) => equal(item, value));
83
+ if (index === -1) return;
84
+ removed.push(this.items[key][index]);
85
+ }
86
+ this.state.managers.event.emit("filter:remove", removed);
87
+ this.filter();
88
+ }
89
+ set(items) {
90
+ const keyed = {};
91
+ const { length } = items;
92
+ for (let index = 0; index < length; index += 1) {
93
+ const item = items[index];
94
+ keyed[item.key] ??= [];
95
+ keyed[item.key].push(item);
96
+ }
97
+ this.items = keyed;
98
+ this.filter();
99
+ }
100
+ };
101
+ const comparators = {
102
+ [FILTER_CONTAINS]: (row, filter) => includes(getString(row), getString(filter), true),
103
+ [FILTER_ENDS_WITH]: (row, filter) => endsWith(getString(row), getString(filter), true),
104
+ [FILTER_EQUALS]: (row, filter) => equalizer(row, filter),
105
+ [FILTER_GREATER_THAN]: (row, filter) => getNumber(row) > getNumber(filter),
106
+ [FILTER_GREATER_THAN_OR_EQUAL]: (row, filter) => getNumber(row) >= getNumber(filter),
107
+ [FILTER_LESS_THAN]: (row, filter) => getNumber(row) < getNumber(filter),
108
+ [FILTER_LESS_THAN_OR_EQUAL]: (row, filter) => getNumber(row) <= getNumber(filter),
109
+ [FILTER_NOT_CONTAINS]: (row, filter) => !includes(getString(row), getString(filter), true),
110
+ [FILTER_NOT_EQUALS]: (row, filter) => !equalizer(row, filter),
111
+ [FILTER_STARTS_WITH]: (row, filter) => startsWith(getString(row), getString(filter), true)
112
+ };
113
+ const equalizer = equal.initialize({ ignoreCase: true });
114
+ //#endregion
115
+ export { FilterManager };
@@ -0,0 +1,27 @@
1
+ import { TabelaGroupHandlers } from "../models/group.model.mjs";
2
+ import { GroupComponent } from "../components/group.component.mjs";
3
+ import { State } from "../models/tabela.model.mjs";
4
+ import { Key } from "@oscarpalmer/atoms/models";
5
+
6
+ //#region src/managers/group.manager.d.ts
7
+ declare class GroupManager {
8
+ state: State;
9
+ collapsed: Set<Key>;
10
+ enabled: boolean;
11
+ key: string;
12
+ handlers: TabelaGroupHandlers;
13
+ items: GroupComponent[];
14
+ mapped: Map<string, GroupComponent>;
15
+ order: Record<never, number>;
16
+ constructor(state: State);
17
+ add(group: GroupComponent, emit: boolean): void;
18
+ clear(): void;
19
+ destroy(): void;
20
+ getForKey(key: string): GroupComponent | undefined;
21
+ getForValue(value: unknown): GroupComponent | undefined;
22
+ handle(button: HTMLElement): void;
23
+ remove(group: GroupComponent, update: boolean): void;
24
+ set(items: GroupComponent[]): void;
25
+ }
26
+ //#endregion
27
+ export { GroupManager };
@@ -0,0 +1,93 @@
1
+ import { EVENT_GROUP_ADD, EVENT_GROUP_CLEAR, EVENT_GROUP_REMOVE, EVENT_GROUP_TOGGLE } from "../models/event.model.mjs";
2
+ import { removeGroup } from "../components/group.component.mjs";
3
+ import { getGroup } from "../helpers/misc.helpers.mjs";
4
+ import { sort } from "@oscarpalmer/atoms/array";
5
+ import { toMap } from "@oscarpalmer/atoms/array/to-map";
6
+ import { toRecord } from "@oscarpalmer/atoms/array/to-record";
7
+ import { isNullableOrWhitespace } from "@oscarpalmer/atoms/is";
8
+ import { getString } from "@oscarpalmer/atoms/string";
9
+ import { compare } from "@oscarpalmer/atoms/value/compare";
10
+ //#region src/managers/group.manager.ts
11
+ var GroupManager = class {
12
+ collapsed = /* @__PURE__ */ new Set();
13
+ enabled = false;
14
+ key;
15
+ handlers = { set: (group) => {
16
+ if (group === this.key) return;
17
+ this.enabled = !isNullableOrWhitespace(group);
18
+ this.key = group ?? "";
19
+ this.state.managers.data.set(this.state.managers.data.get());
20
+ } };
21
+ items = [];
22
+ mapped = /* @__PURE__ */ new Map();
23
+ order = {};
24
+ constructor(state) {
25
+ this.state = state;
26
+ if (isNullableOrWhitespace(state.options.grouping)) return;
27
+ this.enabled = true;
28
+ this.key = state.options.grouping;
29
+ }
30
+ add(group, emit) {
31
+ this.set([...this.items, group]);
32
+ if (emit) this.state.managers.event.emit(EVENT_GROUP_ADD, [getGroup(group)]);
33
+ }
34
+ clear() {
35
+ if (this.items.length === 0) return;
36
+ const groups = this.items.splice(0);
37
+ const { length } = groups;
38
+ for (let index = 0; index < length; index += 1) this.remove(groups[index], false);
39
+ this.collapsed.clear();
40
+ this.set([]);
41
+ this.state.managers.event.emit(EVENT_GROUP_CLEAR);
42
+ }
43
+ destroy() {
44
+ const groups = this.items.splice(0);
45
+ const { length } = groups;
46
+ for (let index = 0; index < length; index += 1) removeGroup(groups[index]);
47
+ this.collapsed.clear();
48
+ this.handlers = void 0;
49
+ this.state = void 0;
50
+ }
51
+ getForKey(key) {
52
+ return this.mapped.get(key);
53
+ }
54
+ getForValue(value) {
55
+ const asString = getString(value);
56
+ return this.items.find((item) => item.value.stringified === asString);
57
+ }
58
+ handle(button) {
59
+ const key = button.dataset.key?.replace(`${this.state.prefix}_`, "");
60
+ const group = this.getForKey(key ?? "");
61
+ if (group == null) return;
62
+ const { collapsed, items, state } = this;
63
+ group.expanded = !group.expanded;
64
+ const index = items.indexOf(group);
65
+ let first = state.managers.data.state.keys.original.indexOf(group.key) + 1;
66
+ const last = items[index + 1] == null ? state.managers.data.state.keys.original.length - 1 : state.managers.data.state.keys.original.indexOf(items[index + 1].key) - 1;
67
+ for (; first <= last; first += 1) {
68
+ const key = state.managers.data.state.keys.original[first];
69
+ if (group.expanded) collapsed.delete(key);
70
+ else collapsed.add(key);
71
+ }
72
+ state.managers.event.emit(EVENT_GROUP_TOGGLE, {
73
+ collapsed: group.expanded ? [] : [getGroup(group)],
74
+ expanded: group.expanded ? [getGroup(group)] : []
75
+ });
76
+ if (Object.keys(state.managers.filter.items).length > 0) state.managers.filter.filter();
77
+ else if (state.managers.sort.items.length > 0) state.managers.sort.sort();
78
+ else state.managers.render.update(true, true);
79
+ }
80
+ remove(group, update) {
81
+ removeGroup(group);
82
+ if (!update) return;
83
+ this.set(this.items.filter((item) => item !== group));
84
+ this.state.managers.event.emit(EVENT_GROUP_REMOVE, [getGroup(group)]);
85
+ }
86
+ set(items) {
87
+ this.items = sort(items, (first, second) => compare(first.label, second.label));
88
+ this.mapped = toMap(items, (group) => group.key);
89
+ this.order = toRecord(items, (group) => group.value.stringified, (_, index) => index);
90
+ }
91
+ };
92
+ //#endregion
93
+ export { GroupManager };
@@ -0,0 +1,15 @@
1
+ import { State } from "../models/tabela.model.mjs";
2
+ import { Key } from "@oscarpalmer/atoms/models";
3
+
4
+ //#region src/managers/navigation.manager.d.ts
5
+ declare class NavigationManager {
6
+ state: State;
7
+ active: Key | undefined;
8
+ constructor(state: State);
9
+ destroy(): void;
10
+ handle(event: KeyboardEvent): void;
11
+ setActive(item: Key | undefined, scroll?: boolean): void;
12
+ }
13
+ declare const attributeDataActiveTrue = "[data-active=\"true\"]";
14
+ //#endregion
15
+ export { NavigationManager, attributeDataActiveTrue };