@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
@@ -1,27 +1,30 @@
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 } = this;
4
+ function getRange(state, down) {
5
+ const { components, managers, options } = state;
5
6
  const { clientHeight, scrollTop } = components.body.elements.group;
6
- const first = Math.floor(scrollTop / managers.row.height);
7
- const last = Math.min((managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length) - 1, Math.ceil((scrollTop + clientHeight) / managers.row.height) - 1);
8
- const before = Math.ceil(clientHeight / managers.row.height) * (down ? 1 : 2);
9
- const after = Math.ceil(clientHeight / managers.row.height) * (down ? 2 : 1);
7
+ const { keys } = managers.data;
8
+ const first = Math.floor(scrollTop / options.rowHeight);
9
+ const last = Math.min(keys.length - managers.group.collapsed.size - 1, Math.ceil((scrollTop + clientHeight) / options.rowHeight) - 1);
10
+ const before = Math.ceil(clientHeight / options.rowHeight) * (down ? 1 : 2);
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
  }
16
18
  function onScroll() {
17
- if (!this.state.active) {
19
+ const { state } = this;
20
+ if (!state.active) {
18
21
  requestAnimationFrame(() => {
19
- const top = this.components.body.elements.group.scrollTop;
20
- this.update(top > this.state.top);
21
- this.state.active = false;
22
- this.state.top = top;
22
+ const top = state.components.body.elements.group.scrollTop;
23
+ this.update(top > state.top);
24
+ state.active = false;
25
+ state.top = top;
23
26
  });
24
- this.state.active = true;
27
+ state.active = true;
25
28
  }
26
29
  }
27
30
  var RenderManager = class {
@@ -31,15 +34,15 @@ var RenderManager = class {
31
34
  cells: {},
32
35
  rows: []
33
36
  };
34
- state = {
35
- active: false,
36
- top: 0
37
- };
37
+ state;
38
38
  visible = /* @__PURE__ */ new Map();
39
- constructor(managers, components) {
40
- this.managers = managers;
41
- this.components = components;
42
- this.listener = on(components.body.elements.group, "scroll", onScroll.bind(this));
39
+ constructor(state) {
40
+ this.listener = on(state.components.body.elements.group, "scroll", onScroll.bind(this));
41
+ this.state = {
42
+ ...state,
43
+ active: false,
44
+ top: 0
45
+ };
43
46
  }
44
47
  destroy() {
45
48
  const { listener, pool, visible } = this;
@@ -47,15 +50,19 @@ var RenderManager = class {
47
50
  visible.clear();
48
51
  pool.cells = {};
49
52
  pool.rows = [];
53
+ this.fragment = void 0;
50
54
  this.listener = void 0;
55
+ this.pool = void 0;
56
+ this.state = void 0;
51
57
  this.visible = void 0;
52
58
  }
53
59
  removeCells(fields) {
54
- const { managers, pool, visible } = this;
60
+ const { pool, state, visible } = this;
55
61
  const { length } = fields;
56
62
  for (let index = 0; index < length; index += 1) delete pool.cells[fields[index]];
57
63
  for (const [, key] of visible) {
58
- const row = managers.row.get(key);
64
+ if (key instanceof GroupComponent) continue;
65
+ const row = state.managers.row.get(key);
59
66
  if (row == null || row.element == null) continue;
60
67
  for (let index = 0; index < length; index += 1) {
61
68
  row.cells[fields[index]].innerHTML = "";
@@ -70,32 +77,55 @@ var RenderManager = class {
70
77
  return this.fragment;
71
78
  }
72
79
  update(down, rerender) {
73
- const { components, managers, pool, visible } = this;
74
- components.body.elements.faker.style.height = `${managers.data.size * managers.row.height}px`;
80
+ const { state, pool, visible } = this;
81
+ const { components, managers, options } = state;
82
+ components.body.elements.faker.style.height = `${(managers.data.size - managers.group.collapsed.size) * options.rowHeight}px`;
75
83
  const indices = /* @__PURE__ */ new Set();
76
- const range = getRange.call(this, down);
84
+ const range = getRange(state, down);
77
85
  for (let index = range.start; index <= range.end; index += 1) indices.add(index);
78
86
  let remove = rerender ?? false;
79
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
+ }
80
95
  const row = managers.row.get(key);
81
- if (remove || row == null || !indices.has(index)) {
96
+ if (remove || row == null || !indices.has(index) || managers.group.collapsed.has(key)) {
82
97
  visible.delete(index);
83
98
  if (row != null) removeRow(pool, row);
84
99
  }
85
100
  }
86
101
  const fragment = this.getFragment();
87
- const keys = managers.data.values.keys.active ?? managers.data.values.keys.original;
102
+ const { keys } = managers.data;
88
103
  let count = 0;
89
- 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) {
90
106
  if (visible.has(index)) continue;
91
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
+ }
92
118
  const row = managers.row.get(key);
93
119
  if (row == null) continue;
120
+ if (managers.group.collapsed.has(key)) {
121
+ offset += 1;
122
+ continue;
123
+ }
94
124
  count += 1;
95
- renderRow(managers, row);
125
+ renderRow(state, row);
96
126
  visible.set(index, key);
97
127
  if (row.element != null) {
98
- row.element.style.transform = `translateY(${index * managers.row.height}px)`;
128
+ row.element.style.transform = `translateY(${(index - offset) * options.rowHeight}px)`;
99
129
  fragment.append(row.element);
100
130
  }
101
131
  }
@@ -1,16 +1,16 @@
1
1
  import { RowComponent, removeRow, renderRow } from "../components/row.component.js";
2
2
  var RowManager = class {
3
3
  components = /* @__PURE__ */ new Map();
4
- height;
5
- constructor(managers, rowHeight) {
6
- this.managers = managers;
7
- this.height = rowHeight;
4
+ constructor(state) {
5
+ this.state = state;
8
6
  }
9
7
  destroy() {
10
8
  const components = [...this.components.values()];
11
9
  const { length } = components;
12
- for (let index = 0; index < length; index += 1) removeRow(this.managers.render.pool, components[index]);
10
+ for (let index = 0; index < length; index += 1) removeRow(this.state.managers.render.pool, components[index]);
13
11
  this.components.clear();
12
+ this.components = void 0;
13
+ this.state = void 0;
14
14
  }
15
15
  get(key) {
16
16
  let row = this.components.get(key);
@@ -26,13 +26,13 @@ var RowManager = class {
26
26
  remove(key) {
27
27
  const row = this.components.get(key);
28
28
  if (row != null) {
29
- removeRow(this.managers.render.pool, row);
29
+ removeRow(this.state.managers.render.pool, row);
30
30
  this.components.delete(key);
31
31
  }
32
32
  }
33
33
  update(key) {
34
34
  const row = this.components.get(key);
35
- if (row != null) renderRow(this.managers, row);
35
+ if (row != null) renderRow(this.state, row);
36
36
  }
37
37
  };
38
38
  export { RowManager };
@@ -1,23 +1,36 @@
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();
16
18
  last;
17
- constructor(element, managers) {
18
- this.element = element;
19
- this.managers = managers;
20
- mapped.set(element, this);
19
+ constructor(state) {
20
+ this.state = state;
21
+ mapped.set(state.element, this);
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([]);
21
34
  }
22
35
  clear() {
23
36
  if (this.items.size === 0) return;
@@ -25,70 +38,60 @@ var SelectionManager = class {
25
38
  this.items.clear();
26
39
  this.update(removed);
27
40
  }
28
- deselect(keys) {
29
- const { length } = keys;
30
- const removed = [];
31
- for (let index = 0; index < length; index += 1) {
32
- const key = keys[index];
33
- if (this.items.delete(key)) removed.push(key);
34
- }
35
- if (removed.length > 0) this.update(removed);
36
- }
37
41
  destroy() {
38
- mapped.delete(this.element);
42
+ mapped.delete(this.state.element);
39
43
  this.handlers = void 0;
40
- this.element = void 0;
41
44
  this.items = void 0;
45
+ this.last = void 0;
46
+ this.state = void 0;
42
47
  }
43
48
  handle(event, target) {
44
49
  const key = getKey(target.getAttribute("data-key"));
45
50
  if (key == null) return;
46
51
  const { items } = this;
47
52
  if (event.shiftKey) {
48
- if (this.last == null) {
49
- this.last = key;
50
- return;
51
- }
52
- this.range(this.last, key);
53
- this.last = key;
53
+ if (this.last == null) this.state.managers.navigation.setActive(key, false);
54
+ else this.range(this.last, key);
54
55
  return;
55
56
  }
56
57
  this.last = key;
58
+ this.state.managers.navigation.setActive(key, false);
57
59
  if (event.ctrlKey || event.metaKey) {
58
- if (items.has(key)) this.deselect([key]);
59
- else this.select([key]);
60
+ if (items.has(key)) this.remove([key]);
61
+ else this.add([key]);
60
62
  return;
61
63
  }
62
- if (items.has(key)) if (items.size === 1) this.clear();
63
- else this.set([key]);
64
- else this.set([key]);
64
+ this.set([key]);
65
65
  }
66
66
  range(from, to) {
67
+ const { state } = this;
67
68
  const keyed = isKey(from) && isKey(to);
68
69
  const fromKey = keyed ? from : getKey(from.getAttribute("data-key"));
69
70
  const toKey = keyed ? to : getKey(to.getAttribute("data-key"));
70
71
  if (fromKey === toKey) return;
71
- const keys = this.managers.data.values.keys.active ?? this.managers.data.values.keys.original;
72
- const fromIndex = keys.indexOf(fromKey);
73
- const toIndex = keys.indexOf(toKey);
72
+ const { keys } = state.managers.data;
73
+ const fromIndex = state.managers.data.getIndex(fromKey);
74
+ const toIndex = state.managers.data.getIndex(toKey);
74
75
  if (fromIndex === -1 || toIndex === -1) return;
75
76
  const [start, end] = fromIndex < toIndex ? [fromIndex, toIndex] : [toIndex, fromIndex];
76
77
  const selected = [];
77
- for (let index = start; index <= end; index += 1) selected.push(keys[index]);
78
- 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);
79
83
  else this.set(selected);
84
+ this.last = toKey;
85
+ this.state.managers.navigation.setActive(toKey, false);
80
86
  }
81
- select(keys) {
87
+ remove(keys) {
82
88
  const { length } = keys;
83
- let update = false;
89
+ const removed = [];
84
90
  for (let index = 0; index < length; index += 1) {
85
91
  const key = keys[index];
86
- if (!this.items.has(key)) {
87
- this.items.add(key);
88
- update = true;
89
- }
92
+ if (this.items.delete(key)) removed.push(key);
90
93
  }
91
- if (update) this.update([]);
94
+ if (removed.length > 0) this.update(removed);
92
95
  }
93
96
  set(keys) {
94
97
  const { items } = this;
@@ -99,10 +102,10 @@ var SelectionManager = class {
99
102
  this.update(removed);
100
103
  }
101
104
  toggle() {
102
- const { items, managers } = this;
103
- const all = managers.data.values.keys.active ?? managers.data.values.keys.original;
104
- if (items.size === all.length) this.clear();
105
- else this.select(all);
105
+ const { items, state } = this;
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)));
106
109
  }
107
110
  update(removed) {
108
111
  const items = [...removed.map((key) => ({
@@ -115,7 +118,7 @@ var SelectionManager = class {
115
118
  const { length } = items;
116
119
  for (let index = 0; index < length; index += 1) {
117
120
  const { key, removed } = items[index];
118
- const row = this.managers.row.get(key);
121
+ const row = this.state.managers.row.get(key);
119
122
  if (row == null || row.element == null) continue;
120
123
  setAttribute(row.element, "aria-selected", String(!removed));
121
124
  if (removed) row.element.classList.remove("tabela__row--selected");
@@ -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),
@@ -9,8 +11,8 @@ var SortManager = class {
9
11
  set: (items) => this.set(items)
10
12
  });
11
13
  items = [];
12
- constructor(managers) {
13
- this.managers = managers;
14
+ constructor(state) {
15
+ this.state = state;
14
16
  }
15
17
  add(field, direction) {
16
18
  if (this.items.findIndex((item) => item.key === field) > -1) return;
@@ -35,7 +37,8 @@ var SortManager = class {
35
37
  }
36
38
  destroy() {
37
39
  this.handlers = void 0;
38
- this.items.length = 0;
40
+ this.items = void 0;
41
+ this.state = void 0;
39
42
  }
40
43
  flip(field) {
41
44
  const item = this.items.find((item) => item.key === field);
@@ -62,10 +65,10 @@ var SortManager = class {
62
65
  this.sort();
63
66
  }
64
67
  sort() {
65
- const { items, managers } = this;
66
- const { length } = managers.column.items;
68
+ const { items, state } = this;
69
+ const { length } = state.managers.column.items;
67
70
  for (let index = 0; index < length; index += 1) {
68
- const column = managers.column.items[index];
71
+ const column = state.managers.column.items[index];
69
72
  const sorterIndex = items.findIndex((item) => item.key === column.options.field);
70
73
  const sorterItem = items[sorterIndex];
71
74
  setAttributes(column.elements.wrapper, {
@@ -74,8 +77,8 @@ var SortManager = class {
74
77
  });
75
78
  setAttribute(column.elements.sorter, "data-sort-position", sorterIndex > -1 && items.length > 1 ? sorterIndex + 1 : void 0);
76
79
  }
77
- managers.data.values.keys.active = items.length === 0 ? void 0 : sort(managers.data.values.keys.active?.map((key) => managers.data.values.objects.mapped.get(key)) ?? managers.data.values.objects.array, items).map((row) => row[managers.data.field]);
78
- managers.render.update(true, true);
80
+ state.managers.data.values.keys.active = items.length === 0 ? void 0 : getSortedKeys(state, items);
81
+ state.managers.render.update(true, true);
79
82
  }
80
83
  toggle(event, field, direction) {
81
84
  switch (direction) {
@@ -91,4 +94,29 @@ var SortManager = class {
91
94
  }
92
95
  }
93
96
  };
94
- 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