@oscarpalmer/tabela 0.11.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 (64) hide show
  1. package/dist/components/column.component.js +4 -4
  2. package/dist/components/group.component.js +28 -0
  3. package/dist/helpers/dom.helpers.js +1 -1
  4. package/dist/managers/data.manager.js +76 -15
  5. package/dist/managers/event.manager.js +3 -0
  6. package/dist/managers/filter.manager.js +5 -0
  7. package/dist/managers/group.manager.js +46 -0
  8. package/dist/managers/navigation.manager.js +1 -1
  9. package/dist/managers/render.manager.js +35 -10
  10. package/dist/managers/selection.manager.js +32 -27
  11. package/dist/managers/sort.manager.js +29 -2
  12. package/dist/models/group.model.js +0 -0
  13. package/dist/models/selection.model.js +0 -0
  14. package/dist/tabela.full.js +364 -398
  15. package/dist/tabela.js +4 -1
  16. package/package.json +1 -1
  17. package/src/components/column.component.ts +6 -6
  18. package/src/components/group.component.ts +43 -0
  19. package/src/components/row.component.ts +2 -2
  20. package/src/helpers/dom.helpers.ts +3 -1
  21. package/src/managers/column.manager.ts +4 -4
  22. package/src/managers/data.manager.ts +155 -21
  23. package/src/managers/event.manager.ts +7 -3
  24. package/src/managers/filter.manager.ts +19 -11
  25. package/src/managers/group.manager.ts +79 -0
  26. package/src/managers/navigation.manager.ts +6 -5
  27. package/src/managers/render.manager.ts +55 -17
  28. package/src/managers/row.manager.ts +2 -2
  29. package/src/managers/selection.manager.ts +48 -41
  30. package/src/managers/sort.manager.ts +76 -13
  31. package/src/models/column.model.ts +2 -2
  32. package/src/models/data.model.ts +14 -3
  33. package/src/models/filter.model.ts +11 -3
  34. package/src/models/group.model.ts +4 -0
  35. package/src/models/render.model.ts +2 -2
  36. package/src/models/selection.model.ts +9 -0
  37. package/src/models/sort.model.ts +11 -3
  38. package/src/models/tabela.model.ts +7 -41
  39. package/src/models/tabela.options.ts +3 -2
  40. package/src/tabela.ts +11 -12
  41. package/types/components/column.component.d.ts +3 -3
  42. package/types/components/group.component.d.ts +14 -0
  43. package/types/components/row.component.d.ts +2 -2
  44. package/types/helpers/style.helper.d.ts +1 -1
  45. package/types/managers/column.manager.d.ts +5 -5
  46. package/types/managers/data.manager.d.ts +5 -3
  47. package/types/managers/event.manager.d.ts +3 -3
  48. package/types/managers/filter.manager.d.ts +11 -11
  49. package/types/managers/group.manager.d.ts +17 -0
  50. package/types/managers/navigation.manager.d.ts +3 -3
  51. package/types/managers/render.manager.d.ts +4 -3
  52. package/types/managers/row.manager.d.ts +3 -3
  53. package/types/managers/selection.manager.d.ts +12 -6
  54. package/types/managers/sort.manager.d.ts +10 -8
  55. package/types/models/column.model.d.ts +2 -2
  56. package/types/models/data.model.d.ts +13 -3
  57. package/types/models/filter.model.d.ts +10 -3
  58. package/types/models/group.model.d.ts +4 -0
  59. package/types/models/render.model.d.ts +2 -2
  60. package/types/models/selection.model.d.ts +8 -0
  61. package/types/models/sort.model.d.ts +10 -3
  62. package/types/models/tabela.model.d.ts +7 -37
  63. package/types/models/tabela.options.d.ts +3 -2
  64. package/types/tabela.d.ts +4 -1
@@ -2,13 +2,13 @@ import { createElement } from "../helpers/dom.helpers.js";
2
2
  var ColumnComponent = class {
3
3
  elements;
4
4
  options;
5
- constructor(options) {
6
- const width = Number.parseInt(getComputedStyle(document.body).fontSize, 10) * (options.width ?? options.title.length * 1.5);
5
+ constructor(column) {
6
+ const width = Number.parseInt(getComputedStyle(document.body).fontSize, 10) * (column.width ?? column.title.length * 1.5);
7
7
  this.options = {
8
- ...options,
8
+ ...column,
9
9
  width
10
10
  };
11
- this.elements = createHeading(options.field, options.title, width);
11
+ this.elements = createHeading(this.options.field, this.options.title, width);
12
12
  }
13
13
  destroy() {
14
14
  this.elements.content.remove();
@@ -0,0 +1,28 @@
1
+ import { createElement } from "../helpers/dom.helpers.js";
2
+ var GroupComponent = class {
3
+ element;
4
+ expanded = true;
5
+ filtered = 0;
6
+ selected = 0;
7
+ total = 0;
8
+ constructor(key, label, value) {
9
+ this.key = key;
10
+ this.label = label;
11
+ this.value = value;
12
+ }
13
+ };
14
+ function renderGroup(state, component) {
15
+ component.element ??= createElement("div", {
16
+ className: "tabela__row tabela__row--group",
17
+ innerHTML: `<div class="tabela__cell tabela__cell--group" role="cell">
18
+ <button class="tabela__button tabela__button--group" data-event="group" data-key="${component.key}" type="button">
19
+ <span aria-hidden="true"></span>
20
+ <span>Open/close</span>
21
+ </button>
22
+ <p>${component.label}</p>
23
+ </div>`,
24
+ role: "row"
25
+ }, {}, { height: `${state.options.rowHeight}px` });
26
+ }
27
+ function updateGroup(state, component) {}
28
+ export { GroupComponent, renderGroup, updateGroup };
@@ -33,6 +33,6 @@ function createRow() {
33
33
  return createElement("div", {
34
34
  className: "tabela__row",
35
35
  role: "row"
36
- }, {}, {});
36
+ }, {}, { height: "32px" });
37
37
  }
38
38
  export { createCell, createElement, createRow, createRowGroup };
@@ -1,5 +1,8 @@
1
- import { push, sort } from "@oscarpalmer/atoms/array";
1
+ import { GroupComponent } from "../components/group.component.js";
2
+ import { sortWithGroups } from "./sort.manager.js";
3
+ import { select, sort } from "@oscarpalmer/atoms/array";
2
4
  import { toMap } from "@oscarpalmer/atoms/array/to-map";
5
+ import { toRecord } from "@oscarpalmer/atoms/array/to-record";
3
6
  import { isPlainObject } from "@oscarpalmer/atoms/is";
4
7
  var DataManager = class {
5
8
  handlers = Object.freeze({
@@ -17,17 +20,41 @@ var DataManager = class {
17
20
  array: []
18
21
  }
19
22
  };
23
+ get keys() {
24
+ return this.values.keys.active ?? this.values.keys.original;
25
+ }
20
26
  get size() {
21
- return this.values.keys.active?.length ?? this.values.keys.original.length;
27
+ return this.keys.length;
22
28
  }
23
29
  constructor(state) {
24
30
  this.state = state;
25
31
  }
26
32
  async add(data, render) {
27
33
  const { state, values } = this;
28
- push(values.objects.array, data);
29
- values.objects.mapped = toMap(values.objects.array, state.key);
30
- if (render) this.render();
34
+ const { length } = data;
35
+ const updates = [];
36
+ for (let index = 0; index < length; index += 1) {
37
+ const item = data[index];
38
+ const key = item[state.key];
39
+ if (values.objects.mapped.has(key)) {
40
+ updates.push(item);
41
+ continue;
42
+ }
43
+ values.objects.array.push(item);
44
+ values.objects.mapped.set(key, item);
45
+ if (!state.managers.group.enabled) continue;
46
+ const groupKey = item[state.managers.group.field];
47
+ let group = state.managers.group.get(groupKey);
48
+ if (group == null) {
49
+ group = new GroupComponent(String(groupKey), String(groupKey), groupKey);
50
+ values.objects.array.push(group);
51
+ state.managers.group.add(group);
52
+ }
53
+ if (!group.expanded) state.managers.group.collapsed.add(key);
54
+ group.total += 1;
55
+ }
56
+ if (updates.length > 0) this.update(updates);
57
+ else if (render) this.render();
31
58
  }
32
59
  clear() {
33
60
  if (this.values.objects.array.length > 0) this.set([]);
@@ -44,11 +71,10 @@ var DataManager = class {
44
71
  }
45
72
  get(active) {
46
73
  const { values } = this;
47
- return active ?? false ? values.keys.active?.map((key) => values.objects.mapped.get(key)) ?? [] : values.objects.array;
74
+ return active ?? false ? select(values.keys.active ?? [], (key) => !(key instanceof GroupComponent), (key) => values.objects.mapped.get(key)) : values.objects.array.filter((item) => !(item instanceof GroupComponent));
48
75
  }
49
76
  getIndex(key) {
50
- const { values } = this;
51
- return (values.keys.active ?? values.keys.original).indexOf(key);
77
+ return this.keys.indexOf(key);
52
78
  }
53
79
  async remove(items, render) {
54
80
  const { state, values } = this;
@@ -58,24 +84,59 @@ var DataManager = class {
58
84
  for (let keyIndex = 0; keyIndex < length; keyIndex += 1) {
59
85
  const key = keys[keyIndex];
60
86
  values.objects.mapped.delete(key);
61
- const arrayIndex = values.objects.array.findIndex((object) => object[state.key] === key);
62
- if (arrayIndex > -1) values.objects.array.splice(arrayIndex, 1);
87
+ const arrayIndex = values.objects.array.findIndex((item) => !(item instanceof GroupComponent) && item[state.key] === key);
88
+ let item;
89
+ if (arrayIndex > -1) [item] = values.objects.array.splice(arrayIndex, 1);
63
90
  values.keys.original.splice(values.keys.original.indexOf(key), 1);
64
91
  state.managers.row.remove(key);
92
+ if (!state.managers.group.enabled || item == null) continue;
93
+ state.managers.group.collapsed.delete(key);
94
+ const groupKey = item[state.managers.group.field];
95
+ const group = state.managers.group.get(groupKey);
96
+ if (group == null) continue;
97
+ group.total -= 1;
98
+ if (group.total > 0) continue;
99
+ const groupIndex = values.objects.array.findIndex((item) => item instanceof GroupComponent && item.value === groupKey);
100
+ if (groupIndex > -1) values.objects.array.splice(groupIndex, 1);
101
+ state.managers.group.remove(group);
65
102
  }
66
103
  if (render) this.render();
67
104
  }
68
105
  render() {
69
106
  const { state, values } = this;
70
- values.keys.original = sort(values.objects.array.map((item) => item[state.key]));
107
+ if (state.managers.group.enabled) sortWithGroups(state, values.objects.array, [{
108
+ direction: "ascending",
109
+ key: state.key
110
+ }]);
111
+ else sort(values.objects.array, [{
112
+ direction: "ascending",
113
+ key: state.key
114
+ }]);
115
+ values.keys.original = values.objects.array.map((item) => item instanceof GroupComponent ? item : item[state.key]);
116
+ values.objects.mapped = toMap(values.objects.array.filter((item) => !(item instanceof GroupComponent)), (item) => item[state.key]);
71
117
  if (Object.keys(state.managers.filter.items).length > 0) state.managers.filter.filter();
72
118
  else if (state.managers.sort.items.length > 0) state.managers.sort.sort();
73
- else state.managers.render.update(true);
119
+ else state.managers.render.update(true, true);
74
120
  }
75
121
  set(data) {
76
122
  const { state, values } = this;
77
- values.objects.mapped = toMap(data, state.key);
78
- values.objects.array = data;
123
+ const array = data.slice();
124
+ if (state.managers.group.enabled) {
125
+ const grouped = toRecord.arrays(data, state.managers.group.field);
126
+ const entries = Object.entries(grouped);
127
+ const { length } = entries;
128
+ const groups = [];
129
+ for (let index = 0; index < length; index += 1) {
130
+ const [value, items] = entries[index];
131
+ const key = String(value);
132
+ const group = new GroupComponent(key, key, value);
133
+ group.total = items.length;
134
+ groups.push(group);
135
+ array.push(group);
136
+ }
137
+ state.managers.group.set(groups);
138
+ }
139
+ values.objects.array = array;
79
140
  this.render();
80
141
  }
81
142
  async synchronize(data, remove) {
@@ -93,7 +154,7 @@ var DataManager = class {
93
154
  }
94
155
  if (keys.size === 0) return;
95
156
  if (remove ?? false) {
96
- const toRemove = values.keys.original.filter((key) => !keys.has(key));
157
+ const toRemove = values.keys.original.filter((key) => !(key instanceof GroupComponent) && !keys.has(key));
97
158
  if (toRemove.length > 0) await this.remove(toRemove, false);
98
159
  }
99
160
  await this.update(updated);
@@ -22,6 +22,9 @@ function onClick(event) {
22
22
  const manager = mapped.get(table);
23
23
  if (manager == null) return;
24
24
  switch (target?.getAttribute("data-event")) {
25
+ case "group":
26
+ manager.state.managers.group.handle(target);
27
+ break;
25
28
  case "heading":
26
29
  manager.onSort(event, target);
27
30
  break;
@@ -1,3 +1,4 @@
1
+ import { GroupComponent } from "../components/group.component.js";
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";
@@ -37,6 +38,10 @@ var FilterManager = class {
37
38
  const keysLength = state.managers.data.values.keys.original.length;
38
39
  rowLoop: for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
39
40
  const key = state.managers.data.values.keys.original[keyIndex];
41
+ if (key instanceof GroupComponent) {
42
+ filtered.push(key);
43
+ continue;
44
+ }
40
45
  const row = state.managers.data.values.objects.mapped.get(key);
41
46
  if (row == null) continue;
42
47
  filterLoop: for (let filterIndex = 0; filterIndex < filters.length; filterIndex += 1) {
@@ -0,0 +1,46 @@
1
+ import { sort } from "@oscarpalmer/atoms/array";
2
+ import { toRecord } from "@oscarpalmer/atoms/array/to-record";
3
+ import { isNullableOrWhitespace } from "@oscarpalmer/atoms/is";
4
+ var GroupManager = class {
5
+ collapsed = /* @__PURE__ */ new Set();
6
+ enabled = false;
7
+ field;
8
+ items = [];
9
+ order = {};
10
+ constructor(state) {
11
+ this.state = state;
12
+ if (isNullableOrWhitespace(state.options.grouping)) return;
13
+ this.enabled = true;
14
+ this.field = state.options.grouping;
15
+ }
16
+ add(group) {
17
+ this.set([...this.items, group]);
18
+ }
19
+ get(value) {
20
+ return this.items.find((item) => item.value === value);
21
+ }
22
+ handle(button) {
23
+ const key = button.dataset.key;
24
+ const group = this.get(key);
25
+ if (group == null) return;
26
+ const { collapsed, items, state } = this;
27
+ group.expanded = !group.expanded;
28
+ const index = items.indexOf(group);
29
+ let first = state.managers.data.values.keys.original.indexOf(items[index]) + 1;
30
+ const last = items[index + 1] == null ? state.managers.data.keys.length - 1 : state.managers.data.values.keys.original.indexOf(items[index + 1]) - 1;
31
+ for (; first <= last; first += 1) {
32
+ const key = state.managers.data.values.keys.original[first];
33
+ if (group.expanded) collapsed.delete(key);
34
+ else collapsed.add(key);
35
+ }
36
+ state.managers.render.update(true, true);
37
+ }
38
+ remove(group) {
39
+ this.set(this.items.filter((item) => item !== group));
40
+ }
41
+ set(items) {
42
+ this.items = sort(items, (item) => item.label);
43
+ this.order = toRecord(items, "value", (_, index) => index);
44
+ }
45
+ };
46
+ export { GroupManager };
@@ -14,7 +14,7 @@ var NavigationManager = class {
14
14
  event.preventDefault();
15
15
  const { components, id, managers } = this.state;
16
16
  const activeDescendant = components.body.elements.group.getAttribute("aria-activedescendant");
17
- const keys = managers.data.values.keys.active ?? managers.data.values.keys.original;
17
+ const { keys } = managers.data;
18
18
  const { length } = keys;
19
19
  let next;
20
20
  if (isNullableOrWhitespace(activeDescendant)) next = getDefaultIndex(event.key, length);
@@ -1,15 +1,17 @@
1
+ import { GroupComponent, renderGroup } from "../components/group.component.js";
1
2
  import { removeRow, renderRow } from "../components/row.component.js";
2
3
  import { on } from "@oscarpalmer/toretto/event";
3
- function getRange(down) {
4
- const { components, managers, options } = this.state;
4
+ function getRange(state, down) {
5
+ const { components, managers, options } = state;
5
6
  const { clientHeight, scrollTop } = components.body.elements.group;
7
+ const { keys } = managers.data;
6
8
  const first = Math.floor(scrollTop / options.rowHeight);
7
- const last = Math.min((managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length) - 1, Math.ceil((scrollTop + clientHeight) / options.rowHeight) - 1);
9
+ const last = Math.min(keys.length - managers.group.collapsed.size - 1, Math.ceil((scrollTop + clientHeight) / options.rowHeight) - 1);
8
10
  const before = Math.ceil(clientHeight / options.rowHeight) * (down ? 1 : 2);
9
11
  const after = Math.ceil(clientHeight / options.rowHeight) * (down ? 2 : 1);
10
12
  const start = Math.max(0, first - before);
11
13
  return {
12
- end: Math.min((managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length) - 1, last + after),
14
+ end: Math.min(keys.length - managers.group.collapsed.size - 1, last + after),
13
15
  start
14
16
  };
15
17
  }
@@ -59,6 +61,7 @@ var RenderManager = class {
59
61
  const { length } = fields;
60
62
  for (let index = 0; index < length; index += 1) delete pool.cells[fields[index]];
61
63
  for (const [, key] of visible) {
64
+ if (key instanceof GroupComponent) continue;
62
65
  const row = state.managers.row.get(key);
63
66
  if (row == null || row.element == null) continue;
64
67
  for (let index = 0; index < length; index += 1) {
@@ -76,31 +79,53 @@ var RenderManager = class {
76
79
  update(down, rerender) {
77
80
  const { state, pool, visible } = this;
78
81
  const { components, managers, options } = state;
79
- components.body.elements.faker.style.height = `${managers.data.size * options.rowHeight}px`;
82
+ components.body.elements.faker.style.height = `${(managers.data.size - managers.group.collapsed.size) * options.rowHeight}px`;
80
83
  const indices = /* @__PURE__ */ new Set();
81
- const range = getRange.call(this, down);
84
+ const range = getRange(state, down);
82
85
  for (let index = range.start; index <= range.end; index += 1) indices.add(index);
83
86
  let remove = rerender ?? false;
84
87
  for (const [index, key] of visible) {
88
+ if (key instanceof GroupComponent) {
89
+ if (remove || !indices.has(index)) {
90
+ visible.delete(index);
91
+ key.element?.remove();
92
+ }
93
+ continue;
94
+ }
85
95
  const row = managers.row.get(key);
86
- if (remove || row == null || !indices.has(index)) {
96
+ if (remove || row == null || !indices.has(index) || managers.group.collapsed.has(key)) {
87
97
  visible.delete(index);
88
98
  if (row != null) removeRow(pool, row);
89
99
  }
90
100
  }
91
101
  const fragment = this.getFragment();
92
- const keys = managers.data.values.keys.active ?? managers.data.values.keys.original;
102
+ const { keys } = managers.data;
93
103
  let count = 0;
94
- for (let index = range.start; index <= range.end; index += 1) {
104
+ let offset = 0;
105
+ for (let index = range.start; index <= range.end + offset; index += 1) {
95
106
  if (visible.has(index)) continue;
96
107
  const key = keys[index];
108
+ if (key instanceof GroupComponent) {
109
+ count += 1;
110
+ renderGroup(state, key);
111
+ visible.set(index, key);
112
+ if (key.element != null) {
113
+ key.element.style.transform = `translateY(${(index - offset) * options.rowHeight}px)`;
114
+ fragment.append(key.element);
115
+ }
116
+ continue;
117
+ }
97
118
  const row = managers.row.get(key);
98
119
  if (row == null) continue;
120
+ if (managers.group.collapsed.has(key)) {
121
+ offset += 1;
122
+ continue;
123
+ }
99
124
  count += 1;
100
125
  renderRow(state, row);
101
126
  visible.set(index, key);
102
127
  if (row.element != null) {
103
- row.element.style.transform = `translateY(${index * options.rowHeight}px)`;
128
+ row.element.style.transform = `translateY(${(index - offset) * options.rowHeight}px)`;
104
129
  fragment.append(row.element);
105
130
  }
106
131
  }
@@ -1,15 +1,17 @@
1
1
  import { createElement } from "../helpers/dom.helpers.js";
2
+ import { GroupComponent } from "../components/group.component.js";
2
3
  import { getKey } from "../helpers/misc.helpers.js";
3
4
  import { dragStyling } from "../helpers/style.helper.js";
4
5
  import { setAttribute } from "@oscarpalmer/toretto/attribute";
5
6
  import { isKey } from "@oscarpalmer/atoms/is";
6
7
  import { getPosition, on } from "@oscarpalmer/toretto/event";
7
- import { findAncestor } from "@oscarpalmer/toretto";
8
+ import { findAncestor } from "@oscarpalmer/toretto/find";
8
9
  var SelectionManager = class {
9
10
  handlers = Object.freeze({
11
+ add: (keys) => this.add(keys),
10
12
  clear: () => this.clear(),
11
- deselect: (keys) => this.deselect(keys),
12
- select: (keys) => this.select(keys),
13
+ remove: (keys) => this.remove(keys),
14
+ set: (keys) => this.set(keys),
13
15
  toggle: () => this.toggle()
14
16
  });
15
17
  items = /* @__PURE__ */ new Set();
@@ -18,21 +20,24 @@ var SelectionManager = class {
18
20
  this.state = state;
19
21
  mapped.set(state.element, this);
20
22
  }
23
+ add(keys) {
24
+ const { length } = keys;
25
+ let update = false;
26
+ for (let index = 0; index < length; index += 1) {
27
+ const key = keys[index];
28
+ if (!this.items.has(key)) {
29
+ this.items.add(key);
30
+ update = true;
31
+ }
32
+ }
33
+ if (update) this.update([]);
34
+ }
21
35
  clear() {
22
36
  if (this.items.size === 0) return;
23
37
  const removed = [...this.items];
24
38
  this.items.clear();
25
39
  this.update(removed);
26
40
  }
27
- deselect(keys) {
28
- const { length } = keys;
29
- const removed = [];
30
- for (let index = 0; index < length; index += 1) {
31
- const key = keys[index];
32
- if (this.items.delete(key)) removed.push(key);
33
- }
34
- if (removed.length > 0) this.update(removed);
35
- }
36
41
  destroy() {
37
42
  mapped.delete(this.state.element);
38
43
  this.handlers = void 0;
@@ -52,8 +57,8 @@ var SelectionManager = class {
52
57
  this.last = key;
53
58
  this.state.managers.navigation.setActive(key, false);
54
59
  if (event.ctrlKey || event.metaKey) {
55
- if (items.has(key)) this.deselect([key]);
56
- else this.select([key]);
60
+ if (items.has(key)) this.remove([key]);
61
+ else this.add([key]);
57
62
  return;
58
63
  }
59
64
  this.set([key]);
@@ -64,29 +69,29 @@ var SelectionManager = class {
64
69
  const fromKey = keyed ? from : getKey(from.getAttribute("data-key"));
65
70
  const toKey = keyed ? to : getKey(to.getAttribute("data-key"));
66
71
  if (fromKey === toKey) return;
67
- const keys = state.managers.data.values.keys.active ?? state.managers.data.values.keys.original;
72
+ const { keys } = state.managers.data;
68
73
  const fromIndex = state.managers.data.getIndex(fromKey);
69
74
  const toIndex = state.managers.data.getIndex(toKey);
70
75
  if (fromIndex === -1 || toIndex === -1) return;
71
76
  const [start, end] = fromIndex < toIndex ? [fromIndex, toIndex] : [toIndex, fromIndex];
72
77
  const selected = [];
73
- for (let index = start; index <= end; index += 1) selected.push(keys[index]);
74
- if (keyed) this.select(selected);
78
+ for (let index = start; index <= end; index += 1) {
79
+ const key = keys[index];
80
+ if (!(key instanceof GroupComponent)) selected.push(key);
81
+ }
82
+ if (keyed) this.add(selected);
75
83
  else this.set(selected);
76
84
  this.last = toKey;
77
85
  this.state.managers.navigation.setActive(toKey, false);
78
86
  }
79
- select(keys) {
87
+ remove(keys) {
80
88
  const { length } = keys;
81
- let update = false;
89
+ const removed = [];
82
90
  for (let index = 0; index < length; index += 1) {
83
91
  const key = keys[index];
84
- if (!this.items.has(key)) {
85
- this.items.add(key);
86
- update = true;
87
- }
92
+ if (this.items.delete(key)) removed.push(key);
88
93
  }
89
- if (update) this.update([]);
94
+ if (removed.length > 0) this.update(removed);
90
95
  }
91
96
  set(keys) {
92
97
  const { items } = this;
@@ -98,9 +103,9 @@ var SelectionManager = class {
98
103
  }
99
104
  toggle() {
100
105
  const { items, state } = this;
101
- const all = state.managers.data.values.keys.active ?? state.managers.data.values.keys.original;
102
- if (items.size === all.length) this.clear();
103
- else this.select(all);
106
+ const { keys } = state.managers.data;
107
+ if (items.size === keys.length - state.managers.group.items.length) this.clear();
108
+ else this.set(keys.filter((key) => !(key instanceof GroupComponent)));
104
109
  }
105
110
  update(removed) {
106
111
  const items = [...removed.map((key) => ({
@@ -1,5 +1,7 @@
1
+ import { GroupComponent } from "../components/group.component.js";
1
2
  import { setAttribute, setAttributes } from "@oscarpalmer/toretto/attribute";
2
3
  import { sort } from "@oscarpalmer/atoms/array";
4
+ import { compare } from "@oscarpalmer/atoms/value/compare";
3
5
  var SortManager = class {
4
6
  handlers = Object.freeze({
5
7
  add: (field, direction) => this.add(field, direction),
@@ -75,7 +77,7 @@ var SortManager = class {
75
77
  });
76
78
  setAttribute(column.elements.sorter, "data-sort-position", sorterIndex > -1 && items.length > 1 ? sorterIndex + 1 : void 0);
77
79
  }
78
- state.managers.data.values.keys.active = items.length === 0 ? void 0 : sort(state.managers.data.values.keys.active?.map((key) => state.managers.data.values.objects.mapped.get(key)) ?? state.managers.data.values.objects.array, items).map((row) => row[state.key]);
80
+ state.managers.data.values.keys.active = items.length === 0 ? void 0 : getSortedKeys(state, items);
79
81
  state.managers.render.update(true, true);
80
82
  }
81
83
  toggle(event, field, direction) {
@@ -92,4 +94,29 @@ var SortManager = class {
92
94
  }
93
95
  }
94
96
  };
95
- export { SortManager };
97
+ function getSortedKeys(state, sorters) {
98
+ const data = state.managers.data.values.keys.active?.map((key) => key instanceof GroupComponent ? key : state.managers.data.values.objects.mapped.get(key)) ?? state.managers.data.values.objects.array.slice();
99
+ if (!state.managers.group.enabled) return sort(data, sorters).map((item) => item[state.key]);
100
+ return sortWithGroups(state, data, sorters).map((item) => item instanceof GroupComponent ? item : item[state.key]);
101
+ }
102
+ function sortWithGroups(state, data, sorters) {
103
+ const { length } = sorters;
104
+ return data.sort((first, second) => {
105
+ const firstValue = first instanceof GroupComponent ? first.value : first[state.managers.group.field];
106
+ const secondValue = second instanceof GroupComponent ? second.value : second[state.managers.group.field];
107
+ const firstOrder = state.managers.group.order[firstValue];
108
+ const secondOrder = state.managers.group.order[secondValue];
109
+ const groupComparison = compare(firstOrder, secondOrder);
110
+ if (groupComparison !== 0) return groupComparison;
111
+ const firstIsGroup = first instanceof GroupComponent;
112
+ const secondIsGroup = second instanceof GroupComponent;
113
+ if (firstIsGroup || secondIsGroup) return firstIsGroup && secondIsGroup ? 0 : firstIsGroup ? -1 : 1;
114
+ for (let index = 0; index < length; index += 1) {
115
+ const sorter = sorters[index];
116
+ const comparison = compare(first[sorter.key], second[sorter.key]);
117
+ if (comparison !== 0) return comparison * (sorter.direction === "ascending" ? 1 : -1);
118
+ }
119
+ return 0;
120
+ });
121
+ }
122
+ export { SortManager, sortWithGroups };
File without changes
File without changes