@oscarpalmer/tabela 0.8.0 → 0.10.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 (55) hide show
  1. package/dist/components/body.component.js +2 -15
  2. package/dist/components/footer.component.js +3 -3
  3. package/dist/components/header.component.js +2 -2
  4. package/dist/components/row.component.js +13 -4
  5. package/dist/helpers/dom.helpers.js +5 -10
  6. package/dist/helpers/misc.helpers.js +7 -0
  7. package/dist/helpers/style.helper.js +6 -0
  8. package/dist/managers/column.manager.js +7 -2
  9. package/dist/managers/data.manager.js +6 -4
  10. package/dist/managers/event.manager.js +6 -2
  11. package/dist/managers/filter.manager.js +92 -0
  12. package/dist/managers/{virtualization.manager.js → render.manager.js} +28 -22
  13. package/dist/managers/row.manager.js +9 -2
  14. package/dist/managers/selection.manager.js +191 -0
  15. package/dist/managers/sort.manager.js +17 -6
  16. package/dist/models/render.model.js +0 -0
  17. package/dist/tabela.full.js +1253 -105
  18. package/dist/tabela.js +19 -6
  19. package/package.json +1 -1
  20. package/src/components/body.component.ts +4 -21
  21. package/src/components/footer.component.ts +3 -3
  22. package/src/components/header.component.ts +2 -2
  23. package/src/components/row.component.ts +22 -7
  24. package/src/helpers/dom.helpers.ts +3 -10
  25. package/src/helpers/misc.helpers.ts +15 -0
  26. package/src/helpers/style.helper.ts +6 -0
  27. package/src/managers/column.manager.ts +9 -1
  28. package/src/managers/data.manager.ts +9 -5
  29. package/src/managers/event.manager.ts +10 -3
  30. package/src/managers/filter.manager.ts +154 -0
  31. package/src/managers/{virtualization.manager.ts → render.manager.ts} +36 -31
  32. package/src/managers/row.manager.ts +16 -2
  33. package/src/managers/selection.manager.ts +338 -0
  34. package/src/managers/sort.manager.ts +35 -16
  35. package/src/models/filter.model.ts +17 -0
  36. package/src/models/{virtualization.model.ts → render.model.ts} +3 -3
  37. package/src/models/sort.model.ts +1 -1
  38. package/src/models/tabela.model.ts +22 -2
  39. package/src/tabela.ts +28 -6
  40. package/types/components/row.component.d.ts +2 -2
  41. package/types/helpers/dom.helpers.d.ts +1 -1
  42. package/types/helpers/misc.helpers.d.ts +2 -0
  43. package/types/helpers/style.helper.d.ts +1 -0
  44. package/types/managers/data.manager.d.ts +1 -1
  45. package/types/managers/event.manager.d.ts +1 -1
  46. package/types/managers/filter.manager.d.ts +19 -0
  47. package/types/managers/{virtualization.manager.d.ts → render.manager.d.ts} +6 -6
  48. package/types/managers/selection.manager.d.ts +19 -0
  49. package/types/managers/sort.manager.d.ts +5 -2
  50. package/types/models/filter.model.d.ts +6 -0
  51. package/types/models/{virtualization.model.d.ts → render.model.d.ts} +3 -3
  52. package/types/models/sort.model.d.ts +1 -1
  53. package/types/models/tabela.model.d.ts +20 -2
  54. package/types/tabela.d.ts +3 -1
  55. /package/dist/models/{virtualization.model.js → filter.model.js} +0 -0
@@ -1,14 +1,6 @@
1
1
  import { createElement, createRowGroup } from "../helpers/dom.helpers.js";
2
- import { setStyles } from "@oscarpalmer/toretto/style";
3
2
  function createFaker() {
4
- return createElement("div", {}, {}, {
5
- height: "0",
6
- inset: "0 auto auto 0",
7
- opacity: "0",
8
- pointerEvents: "none",
9
- position: "absolute",
10
- width: "1px"
11
- });
3
+ return createElement("div", { className: "tabela__faker" }, {}, {});
12
4
  }
13
5
  var BodyComponent = class {
14
6
  elements = {
@@ -18,13 +10,8 @@ var BodyComponent = class {
18
10
  constructor() {
19
11
  const group = createRowGroup(false);
20
12
  this.elements.group = group;
21
- group.className += " tabela__rowgroup-body";
13
+ group.className += " tabela__rowgroup--body";
22
14
  group.tabIndex = 0;
23
- setStyles(group, {
24
- height: "100%",
25
- overflow: "auto",
26
- position: "relative"
27
- });
28
15
  group.append(this.elements.faker);
29
16
  }
30
17
  destroy() {
@@ -8,8 +8,8 @@ var FooterComponent = class {
8
8
  row,
9
9
  cells: []
10
10
  };
11
- group.className += " tabela__rowgroup-footer";
12
- row.className += " tabela__row-footer";
11
+ group.className += " tabela__rowgroup--footer";
12
+ row.className += " tabela__row--footer";
13
13
  }
14
14
  destroy() {
15
15
  this.elements.cells.length = 0;
@@ -23,7 +23,7 @@ var FooterComponent = class {
23
23
  elements.row.innerHTML = "";
24
24
  for (let index = 0; index < length; index += 1) {
25
25
  const cell = createCell(columns[index].options.width ?? 4, false);
26
- cell.className += " tabela__cell-footer";
26
+ cell.className += " tabela__cell--footer";
27
27
  cell.innerHTML = "&nbsp;";
28
28
  elements.cells.push(cell);
29
29
  elements.row.append(cell);
@@ -7,8 +7,8 @@ var HeaderComponent = class {
7
7
  group,
8
8
  row
9
9
  };
10
- group.className += " tabela__rowgroup-header";
11
- row.className += " tabela__row-header";
10
+ group.className += " tabela__rowgroup--header";
11
+ row.className += " tabela__row--header";
12
12
  }
13
13
  destroy() {
14
14
  this.elements.group = void 0;
@@ -1,4 +1,5 @@
1
1
  import { createCell, createRow } from "../helpers/dom.helpers.js";
2
+ import { setAttributes } from "@oscarpalmer/toretto/attribute";
2
3
  function removeRow(pool, row) {
3
4
  if (row.element != null) {
4
5
  row.element.innerHTML = "";
@@ -9,18 +10,26 @@ function removeRow(pool, row) {
9
10
  row.cells = {};
10
11
  }
11
12
  function renderRow(managers, row) {
12
- const element = row.element ?? managers.virtualization.pool.rows.shift() ?? createRow();
13
+ const element = row.element ?? managers.render.pool.rows.shift() ?? createRow();
13
14
  row.element = element;
14
- element.dataset.key = String(row.key);
15
15
  element.innerHTML = "";
16
+ const selected = managers.selection.items.has(row.key);
17
+ setAttributes(element, {
18
+ "aria-selected": String(selected),
19
+ "data-event": "row",
20
+ "data-key": String(row.key)
21
+ });
22
+ element.classList.add("tabela__row--body");
23
+ if (selected) element.classList.add("tabela__row--selected");
24
+ else element.classList.remove("tabela__row--selected");
16
25
  const columns = managers.column.items;
17
26
  const { length } = columns;
18
27
  const data = managers.data.values.objects.mapped.get(row.key);
19
28
  if (data == null) return;
20
29
  for (let index = 0; index < length; index += 1) {
21
30
  const { options } = columns[index];
22
- managers.virtualization.pool.cells[options.field] ??= [];
23
- const cell = managers.virtualization.pool.cells[columns[index].options.field].shift() ?? createCell(options.width);
31
+ managers.render.pool.cells[options.field] ??= [];
32
+ const cell = managers.render.pool.cells[columns[index].options.field].shift() ?? createCell(options.width);
24
33
  cell.textContent = String(data[options.field]);
25
34
  row.cells[options.field] = cell;
26
35
  element.append(cell);
@@ -1,11 +1,11 @@
1
- import { setStyles } from "@oscarpalmer/toretto/style";
2
1
  import { setAttributes } from "@oscarpalmer/toretto/attribute";
2
+ import { setStyles } from "@oscarpalmer/toretto/style";
3
3
  function createCell(width, body) {
4
4
  const cell = createElement("div", {
5
5
  className: "tabela__cell",
6
6
  role: "cell"
7
7
  }, {}, { width: `${width}px` });
8
- if (body ?? true) cell.classList.add("tabela__cell-body");
8
+ if (body ?? true) cell.classList.add("tabela__cell--body");
9
9
  return cell;
10
10
  }
11
11
  function createElement(tagName, properties, attributes, style) {
@@ -22,22 +22,17 @@ function createRowGroup(withRow) {
22
22
  role: "rowgroup"
23
23
  }, {}, {});
24
24
  if (!(withRow ?? true)) return group;
25
- const row = createRow(false);
25
+ const row = createRow();
26
26
  group.append(row);
27
27
  return {
28
28
  group,
29
29
  row
30
30
  };
31
31
  }
32
- function createRow(withStyle) {
33
- const row = createElement("div", {
32
+ function createRow() {
33
+ return createElement("div", {
34
34
  className: "tabela__row",
35
35
  role: "row"
36
36
  }, {}, {});
37
- if (withStyle ?? true) setStyles(row, {
38
- inset: "0 auto auto 0",
39
- position: "absolute"
40
- });
41
- return row;
42
37
  }
43
38
  export { createCell, createElement, createRow, createRowGroup };
@@ -0,0 +1,7 @@
1
+ function getKey(value) {
2
+ if (typeof value === "number") return value;
3
+ if (typeof value !== "string") return;
4
+ return integerExpression.test(value) ? Number.parseInt(value, 10) : value;
5
+ }
6
+ var integerExpression = /^\d+$/;
7
+ export { getKey };
@@ -0,0 +1,6 @@
1
+ import { toggleStyles } from "@oscarpalmer/toretto/style";
2
+ const dragStyling = toggleStyles(document.body, {
3
+ userSelect: "none",
4
+ webkitUserSelect: "none"
5
+ });
6
+ export { dragStyling };
@@ -7,6 +7,8 @@ var ColumnManager = class {
7
7
  this.set(columns);
8
8
  }
9
9
  destroy() {
10
+ const { length } = this.items;
11
+ for (let index = 0; index < length; index += 1) this.items[index].destroy();
10
12
  this.items.length = 0;
11
13
  }
12
14
  remove(value) {
@@ -16,11 +18,14 @@ var ColumnManager = class {
16
18
  if (length === 0) return;
17
19
  for (let fieldIndex = 0; fieldIndex < length; fieldIndex += 1) {
18
20
  const itemIndex = items.findIndex((component) => component.options.field === fields[fieldIndex]);
19
- if (itemIndex > -1) items.splice(itemIndex, 1);
21
+ if (itemIndex > -1) {
22
+ items[itemIndex].destroy();
23
+ items.splice(itemIndex, 1);
24
+ }
20
25
  }
21
26
  components.header.update(items);
22
27
  components.footer.update(items);
23
- managers.virtualization.removeCells(fields);
28
+ managers.render.removeCells(fields);
24
29
  }
25
30
  set(columns) {
26
31
  const { components, items } = this;
@@ -1,4 +1,4 @@
1
- import { sort } from "@oscarpalmer/atoms/array";
1
+ import { push, sort } from "@oscarpalmer/atoms/array";
2
2
  import { toMap } from "@oscarpalmer/atoms/array/to-map";
3
3
  import { isPlainObject } from "@oscarpalmer/atoms/is";
4
4
  var DataManager = class {
@@ -27,7 +27,7 @@ var DataManager = class {
27
27
  }
28
28
  async add(data, render) {
29
29
  const { field, values } = this;
30
- values.objects.array.push(...data);
30
+ push(values.objects.array, data);
31
31
  values.objects.mapped = toMap(values.objects.array, field);
32
32
  if (render) this.render();
33
33
  }
@@ -40,6 +40,7 @@ var DataManager = class {
40
40
  values.keys.active = void 0;
41
41
  values.keys.original.length = 0;
42
42
  values.objects.array.length = 0;
43
+ this.handlers = void 0;
43
44
  }
44
45
  get(active) {
45
46
  const { values } = this;
@@ -63,8 +64,9 @@ var DataManager = class {
63
64
  render() {
64
65
  const { field, managers, values } = this;
65
66
  values.keys.original = sort(values.objects.array.map((item) => item[field]));
66
- if (managers.sort.items.length > 0) managers.sort.sort();
67
- else managers.virtualization.update(true);
67
+ if (Object.keys(managers.filter.items).length > 0) managers.filter.filter();
68
+ else if (managers.sort.items.length > 0) managers.sort.sort();
69
+ else managers.render.update(true);
68
70
  }
69
71
  set(data) {
70
72
  const { field, values } = this;
@@ -2,9 +2,9 @@ import { on } from "@oscarpalmer/toretto/event";
2
2
  import { findAncestor } from "@oscarpalmer/toretto";
3
3
  var EventManager = class {
4
4
  listener;
5
- constructor(managers, element) {
5
+ constructor(element, managers) {
6
6
  this.managers = managers;
7
- on(element, "click", (event) => {
7
+ this.listener = on(element, "click", (event) => {
8
8
  this.onClick(event);
9
9
  }, { passive: false });
10
10
  }
@@ -18,6 +18,10 @@ var EventManager = class {
18
18
  case "heading":
19
19
  this.onSort(event, target);
20
20
  break;
21
+ case "row":
22
+ this.managers.selection.handle(event, target);
23
+ break;
24
+ default: break;
21
25
  }
22
26
  }
23
27
  onSort(event, target) {
@@ -0,0 +1,92 @@
1
+ import { getNumber } from "@oscarpalmer/atoms/number";
2
+ import { getString } from "@oscarpalmer/atoms/string";
3
+ import { endsWith, includes, startsWith } from "@oscarpalmer/atoms/string/match";
4
+ import { equal } from "@oscarpalmer/atoms/value/equal";
5
+ var FilterManager = class {
6
+ handlers = Object.freeze({
7
+ add: (item) => this.add(item),
8
+ clear: () => this.clear(),
9
+ remove: (value) => this.remove(value),
10
+ set: (items) => this.set(items)
11
+ });
12
+ items = {};
13
+ constructor(managers) {
14
+ this.managers = managers;
15
+ }
16
+ add(item) {
17
+ if (this.items[item.field] == null) this.items[item.field] = [];
18
+ else if (this.items[item.field].findIndex((existing) => equal(existing, item)) !== -1) return;
19
+ this.items[item.field].push(item);
20
+ this.filter();
21
+ }
22
+ clear() {
23
+ if (Object.keys(this.items).length > 0) {
24
+ this.items = {};
25
+ this.filter();
26
+ }
27
+ }
28
+ destroy() {
29
+ this.handlers = void 0;
30
+ this.items = {};
31
+ }
32
+ filter() {
33
+ const { managers } = this;
34
+ const filtered = [];
35
+ const filters = Object.entries(this.items);
36
+ const keysLength = managers.data.values.keys.original.length;
37
+ rowLoop: for (let keyIndex = 0; keyIndex < keysLength; keyIndex += 1) {
38
+ const key = managers.data.values.keys.original[keyIndex];
39
+ const row = managers.data.values.objects.mapped.get(key);
40
+ if (row == null) continue;
41
+ filterLoop: for (let filterIndex = 0; filterIndex < filters.length; filterIndex += 1) {
42
+ const [field, items] = filters[filterIndex];
43
+ const value = row[field];
44
+ for (let itemIndex = 0; itemIndex < items.length; itemIndex += 1) {
45
+ const filter = items[itemIndex];
46
+ if (comparators[filter.comparison](value, filter.value)) continue filterLoop;
47
+ }
48
+ continue rowLoop;
49
+ }
50
+ filtered.push(key);
51
+ }
52
+ managers.data.values.keys.active = filtered;
53
+ if (managers.sort.items.length > 0) managers.sort.sort();
54
+ else managers.render.update(true, true);
55
+ }
56
+ remove(value) {
57
+ if (typeof value === "string") {
58
+ if (this.items[value] == null) return;
59
+ this.items = {};
60
+ } else {
61
+ const { field } = value;
62
+ if (this.items[field] == null) return;
63
+ if (this.items[field].findIndex((item) => equal(item, value)) === -1) return;
64
+ }
65
+ this.filter();
66
+ }
67
+ set(items) {
68
+ const keyed = {};
69
+ const { length } = items;
70
+ for (let index = 0; index < length; index += 1) {
71
+ const item = items[index];
72
+ keyed[item.field] ??= [];
73
+ keyed[item.field].push(item);
74
+ }
75
+ this.items = keyed;
76
+ this.filter();
77
+ }
78
+ };
79
+ var comparators = {
80
+ contains: (row, filter) => includes(getString(row), getString(filter), true),
81
+ "ends-with": (row, filter) => endsWith(getString(row), getString(filter), true),
82
+ equals: (row, filter) => equalizer(row, filter),
83
+ "greater-than": (row, filter) => getNumber(row) > getNumber(filter),
84
+ "greater-than-or-equal": (row, filter) => getNumber(row) >= getNumber(filter),
85
+ "less-than": (row, filter) => getNumber(row) < getNumber(filter),
86
+ "less-than-or-equal": (row, filter) => getNumber(row) <= getNumber(filter),
87
+ "not-contains": (row, filter) => !includes(getString(row), getString(filter), true),
88
+ "not-equals": (row, filter) => !equalizer(row, filter),
89
+ "starts-with": (row, filter) => startsWith(getString(row), getString(filter), true)
90
+ };
91
+ var equalizer = equal.initialize({ ignoreCase: true });
92
+ export { FilterManager };
@@ -4,12 +4,12 @@ function getRange(down) {
4
4
  const { components, managers } = this;
5
5
  const { clientHeight, scrollTop } = components.body.elements.group;
6
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);
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
8
  const before = Math.ceil(clientHeight / managers.row.height) * (down ? 1 : 2);
9
9
  const after = Math.ceil(clientHeight / managers.row.height) * (down ? 2 : 1);
10
10
  const start = Math.max(0, first - before);
11
11
  return {
12
- end: Math.min(managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length - 1, last + after),
12
+ end: Math.min((managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length) - 1, last + after),
13
13
  start
14
14
  };
15
15
  }
@@ -24,7 +24,7 @@ function onScroll() {
24
24
  this.state.active = true;
25
25
  }
26
26
  }
27
- var VirtualizationManager = class {
27
+ var RenderManager = class {
28
28
  fragment;
29
29
  listener;
30
30
  pool = {
@@ -42,21 +42,26 @@ var VirtualizationManager = class {
42
42
  this.listener = on(components.body.elements.group, "scroll", onScroll.bind(this));
43
43
  }
44
44
  destroy() {
45
- this.listener();
46
- for (const [index, row] of this.visible) {
47
- removeRow(this.pool, row);
48
- this.visible.delete(index);
49
- }
50
- this.pool.cells = {};
51
- this.pool.rows = [];
45
+ const { listener, pool, visible } = this;
46
+ listener();
47
+ visible.clear();
48
+ pool.cells = {};
49
+ pool.rows = [];
50
+ this.listener = void 0;
51
+ this.visible = void 0;
52
52
  }
53
53
  removeCells(fields) {
54
+ const { managers, pool, visible } = this;
54
55
  const { length } = fields;
55
- for (let index = 0; index < length; index += 1) delete this.pool.cells[fields[index]];
56
- for (const [, row] of this.visible) for (let index = 0; index < length; index += 1) {
57
- row.cells[fields[index]].innerHTML = "";
58
- row.cells[fields[index]].remove();
59
- delete row.cells[fields[index]];
56
+ for (let index = 0; index < length; index += 1) delete pool.cells[fields[index]];
57
+ for (const [, key] of visible) {
58
+ const row = managers.row.get(key);
59
+ if (row == null || row.element == null) continue;
60
+ for (let index = 0; index < length; index += 1) {
61
+ row.cells[fields[index]].innerHTML = "";
62
+ row.cells[fields[index]].remove();
63
+ delete row.cells[fields[index]];
64
+ }
60
65
  }
61
66
  }
62
67
  getFragment() {
@@ -71,11 +76,11 @@ var VirtualizationManager = class {
71
76
  const range = getRange.call(this, down);
72
77
  for (let index = range.start; index <= range.end; index += 1) indices.add(index);
73
78
  let remove = rerender ?? false;
74
- for (const [index, row] of visible) {
75
- if (!managers.row.has(row.key) || !indices.has(index)) remove = true;
76
- if (remove) {
79
+ for (const [index, key] of visible) {
80
+ const row = managers.row.get(key);
81
+ if (remove || row == null || !indices.has(index)) {
77
82
  visible.delete(index);
78
- removeRow(pool, row);
83
+ if (row != null) removeRow(pool, row);
79
84
  }
80
85
  }
81
86
  const fragment = this.getFragment();
@@ -83,11 +88,12 @@ var VirtualizationManager = class {
83
88
  let count = 0;
84
89
  for (let index = range.start; index <= range.end; index += 1) {
85
90
  if (visible.has(index)) continue;
86
- const row = managers.row.get(keys[index]);
91
+ const key = keys[index];
92
+ const row = managers.row.get(key);
87
93
  if (row == null) continue;
88
94
  count += 1;
89
95
  renderRow(managers, row);
90
- visible.set(index, row);
96
+ visible.set(index, key);
91
97
  if (row.element != null) {
92
98
  row.element.style.transform = `translateY(${index * managers.row.height}px)`;
93
99
  fragment.append(row.element);
@@ -96,4 +102,4 @@ var VirtualizationManager = class {
96
102
  if (count > 0) components.body.elements.group[down ? "append" : "prepend"](fragment);
97
103
  }
98
104
  };
99
- export { VirtualizationManager };
105
+ export { RenderManager };
@@ -1,4 +1,4 @@
1
- import { RowComponent, renderRow } from "../components/row.component.js";
1
+ import { RowComponent, removeRow, renderRow } from "../components/row.component.js";
2
2
  var RowManager = class {
3
3
  components = /* @__PURE__ */ new Map();
4
4
  height;
@@ -7,6 +7,9 @@ var RowManager = class {
7
7
  this.height = rowHeight;
8
8
  }
9
9
  destroy() {
10
+ const components = [...this.components.values()];
11
+ const { length } = components;
12
+ for (let index = 0; index < length; index += 1) removeRow(this.managers.render.pool, components[index]);
10
13
  this.components.clear();
11
14
  }
12
15
  get(key) {
@@ -21,7 +24,11 @@ var RowManager = class {
21
24
  return this.components.has(key);
22
25
  }
23
26
  remove(key) {
24
- this.components.delete(key);
27
+ const row = this.components.get(key);
28
+ if (row != null) {
29
+ removeRow(this.managers.render.pool, row);
30
+ this.components.delete(key);
31
+ }
25
32
  }
26
33
  update(key) {
27
34
  const row = this.components.get(key);
@@ -0,0 +1,191 @@
1
+ import { createElement } from "../helpers/dom.helpers.js";
2
+ import { getKey } from "../helpers/misc.helpers.js";
3
+ import { dragStyling } from "../helpers/style.helper.js";
4
+ import { setAttribute } from "@oscarpalmer/toretto/attribute";
5
+ import { isKey } from "@oscarpalmer/atoms/is";
6
+ import { getPosition, on } from "@oscarpalmer/toretto/event";
7
+ import { findAncestor } from "@oscarpalmer/toretto";
8
+ var SelectionManager = class {
9
+ handlers = Object.freeze({
10
+ clear: () => this.clear(),
11
+ deselect: (keys) => this.deselect(keys),
12
+ select: (keys) => this.select(keys),
13
+ toggle: () => this.toggle()
14
+ });
15
+ items = /* @__PURE__ */ new Set();
16
+ last;
17
+ constructor(element, managers) {
18
+ this.element = element;
19
+ this.managers = managers;
20
+ mapped.set(element, this);
21
+ }
22
+ clear() {
23
+ if (this.items.size === 0) return;
24
+ const removed = [...this.items];
25
+ this.items.clear();
26
+ this.update(removed);
27
+ }
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
+ destroy() {
38
+ mapped.delete(this.element);
39
+ this.handlers = void 0;
40
+ this.element = void 0;
41
+ this.items = void 0;
42
+ }
43
+ handle(event, target) {
44
+ const key = getKey(target.getAttribute("data-key"));
45
+ if (key == null) return;
46
+ const { items } = this;
47
+ 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;
54
+ return;
55
+ }
56
+ this.last = key;
57
+ if (event.ctrlKey || event.metaKey) {
58
+ if (items.has(key)) this.deselect([key]);
59
+ else this.select([key]);
60
+ return;
61
+ }
62
+ if (items.has(key)) if (items.size === 1) this.clear();
63
+ else this.set([key]);
64
+ else this.set([key]);
65
+ }
66
+ range(from, to) {
67
+ const keyed = isKey(from) && isKey(to);
68
+ const fromKey = keyed ? from : getKey(from.getAttribute("data-key"));
69
+ const toKey = keyed ? to : getKey(to.getAttribute("data-key"));
70
+ 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);
74
+ if (fromIndex === -1 || toIndex === -1) return;
75
+ const [start, end] = fromIndex < toIndex ? [fromIndex, toIndex] : [toIndex, fromIndex];
76
+ const selected = [];
77
+ for (let index = start; index <= end; index += 1) selected.push(keys[index]);
78
+ if (keyed) this.select(selected);
79
+ else this.set(selected);
80
+ }
81
+ select(keys) {
82
+ const { length } = keys;
83
+ let update = false;
84
+ for (let index = 0; index < length; index += 1) {
85
+ const key = keys[index];
86
+ if (!this.items.has(key)) {
87
+ this.items.add(key);
88
+ update = true;
89
+ }
90
+ }
91
+ if (update) this.update([]);
92
+ }
93
+ set(keys) {
94
+ const { items } = this;
95
+ const removed = [...items].filter((key) => !keys.includes(key));
96
+ const added = keys.filter((key) => !items.has(key));
97
+ if (removed.length === 0 && added.length === 0) return;
98
+ this.items = new Set(keys);
99
+ this.update(removed);
100
+ }
101
+ 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);
106
+ }
107
+ update(removed) {
108
+ const items = [...removed.map((key) => ({
109
+ key,
110
+ removed: true
111
+ })), ...[...this.items].map((key) => ({
112
+ key,
113
+ removed: false
114
+ }))];
115
+ const { length } = items;
116
+ for (let index = 0; index < length; index += 1) {
117
+ const { key, removed } = items[index];
118
+ const row = this.managers.row.get(key);
119
+ if (row == null || row.element == null) continue;
120
+ setAttribute(row.element, "aria-selected", String(!removed));
121
+ if (removed) row.element.classList.remove("tabela__row--selected");
122
+ else row.element.classList.add("tabela__row--selected");
123
+ }
124
+ }
125
+ };
126
+ function getPlaceholder() {
127
+ placeholder ??= createElement("div", { className: "tabela__selection--placeholder" }, {}, {});
128
+ return placeholder;
129
+ }
130
+ function onMouseDown(event) {
131
+ if (shifted) {
132
+ const row = findAncestor(event.target, ".tabela__row--body");
133
+ if (!(row instanceof HTMLElement)) return;
134
+ startElement = row;
135
+ startPosition = getPosition(event);
136
+ dragStyling.set();
137
+ }
138
+ }
139
+ function onMouseMove(event) {
140
+ if (startElement == null) return;
141
+ const currentPosition = getPosition(event);
142
+ if (currentPosition == null || startPosition == null) return;
143
+ const element = getPlaceholder();
144
+ if (element.parentElement == null) document.body.append(element);
145
+ const { x: cX, y: cY } = currentPosition;
146
+ const { x: sX, y: sY } = startPosition;
147
+ const top = Math.min(cY, sY);
148
+ const left = Math.min(cX, sX);
149
+ const width = Math.abs(cX - sX);
150
+ const height = Math.abs(cY - sY);
151
+ element.style.inset = `${top}px ${window.innerWidth - left - width}px ${window.innerHeight - top - height}px ${left}px`;
152
+ }
153
+ function onMouseUp(event) {
154
+ if (startElement == null) return;
155
+ if (!event.shiftKey) {
156
+ shifted = false;
157
+ dragStyling.remove();
158
+ }
159
+ getPlaceholder().remove();
160
+ const row = findAncestor(event.target, ".tabela__row--body");
161
+ if (row instanceof HTMLElement) {
162
+ endElement = row;
163
+ const endTable = findAncestor(endElement, ".tabela");
164
+ const startTable = findAncestor(startElement, ".tabela");
165
+ if (startTable != null && startTable === endTable) mapped.get(startTable)?.range(startElement, endElement);
166
+ }
167
+ endElement = void 0;
168
+ startElement = void 0;
169
+ startPosition = void 0;
170
+ }
171
+ function onShift(event, value) {
172
+ if (event.key === "Shift") shifted = value;
173
+ }
174
+ function onShiftDown(event) {
175
+ onShift(event, true);
176
+ }
177
+ function onShiftUp(event) {
178
+ onShift(event, false);
179
+ }
180
+ var mapped = /* @__PURE__ */ new WeakMap();
181
+ var shifted = false;
182
+ var endElement;
183
+ var placeholder;
184
+ var startPosition;
185
+ var startElement;
186
+ on(document, "keydown", onShiftDown);
187
+ on(document, "keyup", onShiftUp);
188
+ on(document, "mousedown", onMouseDown);
189
+ on(document, "mousemove", onMouseMove);
190
+ on(document, "mouseup", onMouseUp);
191
+ export { SelectionManager };