@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.
- package/dist/components/body.component.d.mts +11 -0
- package/dist/components/body.component.mjs +28 -0
- package/dist/components/column.component.d.mts +16 -0
- package/dist/components/column.component.mjs +46 -0
- package/dist/components/footer.component.d.mts +13 -0
- package/dist/components/{footer.component.js → footer.component.mjs} +9 -6
- package/dist/components/group.component.d.mts +20 -0
- package/dist/components/group.component.mjs +57 -0
- package/dist/components/header.component.d.mts +13 -0
- package/dist/components/header.component.mjs +25 -0
- package/dist/components/row.component.d.mts +15 -0
- package/dist/components/row.component.mjs +56 -0
- package/dist/helpers/dom.helpers.d.mts +12 -0
- package/dist/helpers/dom.helpers.mjs +43 -0
- package/dist/helpers/misc.helpers.d.mts +12 -0
- package/dist/helpers/misc.helpers.mjs +20 -0
- package/dist/helpers/style.helper.d.mts +6 -0
- package/dist/helpers/style.helper.mjs +8 -0
- package/dist/index.d.mts +7 -0
- package/dist/{index.js → index.mjs} +3 -1
- package/dist/managers/column.manager.d.mts +17 -0
- package/dist/managers/{column.manager.js → column.manager.mjs} +11 -6
- package/dist/managers/data.manager.d.mts +27 -0
- package/dist/managers/data.manager.mjs +256 -0
- package/dist/managers/event.manager.d.mts +18 -0
- package/dist/managers/event.manager.mjs +79 -0
- package/dist/managers/filter.manager.d.mts +18 -0
- package/dist/managers/filter.manager.mjs +115 -0
- package/dist/managers/group.manager.d.mts +27 -0
- package/dist/managers/group.manager.mjs +93 -0
- package/dist/managers/navigation.manager.d.mts +15 -0
- package/dist/managers/navigation.manager.mjs +80 -0
- package/dist/managers/render.manager.d.mts +19 -0
- package/dist/managers/render.manager.mjs +157 -0
- package/dist/managers/row.manager.d.mts +19 -0
- package/dist/managers/row.manager.mjs +45 -0
- package/dist/managers/selection.manager.d.mts +23 -0
- package/dist/managers/{selection.manager.js → selection.manager.mjs} +38 -31
- package/dist/managers/sort.manager.d.mts +23 -0
- package/dist/managers/sort.manager.mjs +147 -0
- package/dist/managers/style.manager.d.mts +9 -0
- package/dist/managers/style.manager.mjs +181 -0
- package/dist/models/body.model.d.mts +7 -0
- package/dist/models/body.model.mjs +1 -0
- package/dist/models/column.model.d.mts +13 -0
- package/dist/models/column.model.mjs +1 -0
- package/dist/models/data.model.d.mts +28 -0
- package/dist/models/data.model.mjs +1 -0
- package/dist/models/dom.model.d.mts +19 -0
- package/dist/models/dom.model.mjs +19 -0
- package/dist/models/event.model.d.mts +99 -0
- package/dist/models/event.model.mjs +53 -0
- package/dist/models/filter.model.d.mts +26 -0
- package/dist/models/filter.model.mjs +13 -0
- package/dist/models/footer.model.d.mts +8 -0
- package/dist/models/footer.model.mjs +1 -0
- package/dist/models/group.model.d.mts +19 -0
- package/dist/models/group.model.mjs +5 -0
- package/dist/models/header.model.d.mts +7 -0
- package/dist/models/header.model.mjs +1 -0
- package/dist/models/render.model.d.mts +22 -0
- package/dist/models/render.model.mjs +1 -0
- package/dist/models/selection.model.d.mts +12 -0
- package/dist/models/selection.model.mjs +1 -0
- package/dist/models/sort.model.d.mts +19 -0
- package/dist/models/sort.model.mjs +5 -0
- package/dist/models/style.model.d.mts +29 -0
- package/dist/models/style.model.mjs +29 -0
- package/dist/models/tabela.model.d.mts +46 -0
- package/dist/models/tabela.model.mjs +1 -0
- package/dist/models/tabela.options.d.mts +14 -0
- package/dist/models/tabela.options.mjs +1 -0
- package/dist/tabela.d.mts +22 -0
- package/dist/{tabela.full.js → tabela.full.mjs} +1501 -803
- package/dist/tabela.mjs +126 -0
- package/package.json +2 -4
- package/src/components/column.component.ts +4 -4
- package/src/components/group.component.ts +6 -2
- package/src/components/row.component.ts +5 -5
- package/src/helpers/misc.helpers.ts +13 -1
- package/src/managers/column.manager.ts +9 -9
- package/src/managers/data.manager.ts +139 -53
- package/src/managers/event.manager.ts +52 -6
- package/src/managers/filter.manager.ts +36 -20
- package/src/managers/group.manager.ts +43 -10
- package/src/managers/render.manager.ts +30 -17
- package/src/managers/sort.manager.ts +81 -52
- package/src/managers/style.manager.ts +33 -0
- package/src/models/column.model.ts +2 -2
- package/src/models/data.model.ts +6 -6
- package/src/models/dom.model.ts +0 -2
- package/src/models/event.model.ts +168 -0
- package/src/models/filter.model.ts +2 -2
- package/src/models/group.model.ts +9 -0
- package/src/models/render.model.ts +6 -0
- package/src/models/sort.model.ts +7 -5
- package/src/tabela.ts +6 -2
- package/dist/components/body.component.js +0 -23
- package/dist/components/column.component.js +0 -41
- package/dist/components/group.component.js +0 -28
- package/dist/components/header.component.js +0 -22
- package/dist/components/row.component.js +0 -48
- package/dist/helpers/dom.helpers.js +0 -38
- package/dist/helpers/misc.helpers.js +0 -7
- package/dist/helpers/style.helper.js +0 -6
- package/dist/managers/data.manager.js +0 -181
- package/dist/managers/event.manager.js +0 -53
- package/dist/managers/filter.manager.js +0 -98
- package/dist/managers/group.manager.js +0 -46
- package/dist/managers/navigation.manager.js +0 -73
- package/dist/managers/render.manager.js +0 -135
- package/dist/managers/row.manager.js +0 -38
- package/dist/managers/sort.manager.js +0 -122
- package/dist/models/body.model.js +0 -0
- package/dist/models/column.model.js +0 -0
- package/dist/models/data.model.js +0 -0
- package/dist/models/filter.model.js +0 -0
- package/dist/models/footer.model.js +0 -0
- package/dist/models/group.model.js +0 -0
- package/dist/models/header.model.js +0 -0
- package/dist/models/render.model.js +0 -0
- package/dist/models/selection.model.js +0 -0
- package/dist/models/sort.model.js +0 -0
- package/dist/models/tabela.model.js +0 -0
- package/dist/models/tabela.options.js +0 -0
- package/dist/tabela.js +0 -105
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { ARIA_ACTIVEDESCENDANT, ATTRIBUTE_DATA_ACTIVE } from "../models/dom.model.mjs";
|
|
2
|
+
import { getKey, isGroupKey } from "../helpers/misc.helpers.mjs";
|
|
3
|
+
import { isNullableOrWhitespace } from "@oscarpalmer/atoms/is";
|
|
4
|
+
import { clamp } from "@oscarpalmer/atoms/number";
|
|
5
|
+
//#region src/managers/navigation.manager.ts
|
|
6
|
+
var NavigationManager = class {
|
|
7
|
+
active;
|
|
8
|
+
constructor(state) {
|
|
9
|
+
this.state = state;
|
|
10
|
+
}
|
|
11
|
+
destroy() {
|
|
12
|
+
this.state = void 0;
|
|
13
|
+
}
|
|
14
|
+
handle(event) {
|
|
15
|
+
if (!allKeys.has(event.key)) return;
|
|
16
|
+
event.preventDefault();
|
|
17
|
+
const { components, managers } = this.state;
|
|
18
|
+
const activeDescendant = components.body.elements.group.getAttribute(ARIA_ACTIVEDESCENDANT);
|
|
19
|
+
const { keys } = managers.data;
|
|
20
|
+
const { length } = keys;
|
|
21
|
+
let next;
|
|
22
|
+
if (isNullableOrWhitespace(activeDescendant)) next = getDefaultIndex(event.key, length);
|
|
23
|
+
else next = getIndex(this.state, event, activeDescendant);
|
|
24
|
+
if (next != null) this.setActive(keys.at(next));
|
|
25
|
+
}
|
|
26
|
+
setActive(item, scroll) {
|
|
27
|
+
const { components, managers, options, prefix } = this.state;
|
|
28
|
+
this.active = item;
|
|
29
|
+
const active = components.body.elements.group.querySelectorAll(attributeDataActiveTrue);
|
|
30
|
+
for (const item of active) item.setAttribute(ATTRIBUTE_DATA_ACTIVE, "false");
|
|
31
|
+
const component = isGroupKey(item) ? managers.group.getForKey(item) : managers.row.get(item, false);
|
|
32
|
+
if (component != null) {
|
|
33
|
+
component.element?.setAttribute(ATTRIBUTE_DATA_ACTIVE, "true");
|
|
34
|
+
if (scroll ?? true) if (component.element == null) components.body.elements.group.scrollTo({
|
|
35
|
+
top: managers.data.getIndex(item) * options.rowHeight,
|
|
36
|
+
behavior: "smooth"
|
|
37
|
+
});
|
|
38
|
+
else component.element.scrollIntoView({ block: "nearest" });
|
|
39
|
+
}
|
|
40
|
+
components.body.elements.group.setAttribute(ARIA_ACTIVEDESCENDANT, component == null ? "" : `${prefix}${component.key}`);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
function getDefaultIndex(key, max) {
|
|
44
|
+
switch (true) {
|
|
45
|
+
case negativeDefaultKeys.has(key): return -1;
|
|
46
|
+
case key === KEY_PAGE_DOWN: return Math.min(9, max - 1);
|
|
47
|
+
case key === KEY_PAGE_UP: return max < 10 ? 0 : max - 10;
|
|
48
|
+
default: return 0;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function getIndex(state, event, active) {
|
|
52
|
+
const key = getKey(active.replace(state.prefix, ""));
|
|
53
|
+
if (key == null) return;
|
|
54
|
+
if (absoluteKeys.has(event.key)) return event.key === KEY_HOME ? 0 : state.managers.data.size - 1;
|
|
55
|
+
return clamp(state.managers.data.getIndex(key) + (offset[event.key] ?? 0), 0, state.managers.data.size - 1, true);
|
|
56
|
+
}
|
|
57
|
+
const KEY_ARROW_DOWN = "ArrowDown";
|
|
58
|
+
const KEY_ARROW_UP = "ArrowUp";
|
|
59
|
+
const KEY_END = "End";
|
|
60
|
+
const KEY_HOME = "Home";
|
|
61
|
+
const KEY_PAGE_DOWN = "PageDown";
|
|
62
|
+
const KEY_PAGE_UP = "PageUp";
|
|
63
|
+
const absoluteKeys = new Set([KEY_END, KEY_HOME]);
|
|
64
|
+
const arrowKeys = new Set([KEY_ARROW_DOWN, KEY_ARROW_UP]);
|
|
65
|
+
const attributeDataActiveTrue = `[${ATTRIBUTE_DATA_ACTIVE}="true"]`;
|
|
66
|
+
const negativeDefaultKeys = new Set([KEY_ARROW_UP, KEY_END]);
|
|
67
|
+
const offset = {
|
|
68
|
+
[KEY_ARROW_DOWN]: 1,
|
|
69
|
+
[KEY_ARROW_UP]: -1,
|
|
70
|
+
[KEY_PAGE_DOWN]: 10,
|
|
71
|
+
[KEY_PAGE_UP]: -10
|
|
72
|
+
};
|
|
73
|
+
const pageKeys = new Set([KEY_PAGE_DOWN, KEY_PAGE_UP]);
|
|
74
|
+
const allKeys = new Set([
|
|
75
|
+
...absoluteKeys,
|
|
76
|
+
...arrowKeys,
|
|
77
|
+
...pageKeys
|
|
78
|
+
]);
|
|
79
|
+
//#endregion
|
|
80
|
+
export { NavigationManager, attributeDataActiveTrue };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { RenderElementPool, RenderState, RenderVisible } from "../models/render.model.mjs";
|
|
2
|
+
import { State } from "../models/tabela.model.mjs";
|
|
3
|
+
import { RemovableEventListener } from "@oscarpalmer/toretto/models";
|
|
4
|
+
|
|
5
|
+
//#region src/managers/render.manager.d.ts
|
|
6
|
+
declare class RenderManager {
|
|
7
|
+
fragment: DocumentFragment;
|
|
8
|
+
listener: RemovableEventListener;
|
|
9
|
+
pool: RenderElementPool;
|
|
10
|
+
state: RenderState;
|
|
11
|
+
visible: RenderVisible;
|
|
12
|
+
constructor(state: State);
|
|
13
|
+
destroy(): void;
|
|
14
|
+
removeCells(keys: string[]): void;
|
|
15
|
+
getFragment(): DocumentFragment;
|
|
16
|
+
update(down: boolean, rerender?: boolean): void;
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { RenderManager };
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { renderGroup } from "../components/group.component.mjs";
|
|
2
|
+
import { isGroupKey } from "../helpers/misc.helpers.mjs";
|
|
3
|
+
import { removeRow, renderRow } from "../components/row.component.mjs";
|
|
4
|
+
import { on } from "@oscarpalmer/toretto/event";
|
|
5
|
+
//#region src/managers/render.manager.ts
|
|
6
|
+
function getRange(state, down) {
|
|
7
|
+
const { element, managers, options } = state;
|
|
8
|
+
const { clientHeight, scrollTop } = element;
|
|
9
|
+
const { keys } = managers.data;
|
|
10
|
+
const firstIndex = Math.floor(scrollTop / options.rowHeight);
|
|
11
|
+
const lastIndex = keys.length - managers.group.collapsed.size - 1;
|
|
12
|
+
const last = Math.min(lastIndex, Math.ceil((scrollTop + clientHeight) / options.rowHeight) - 1);
|
|
13
|
+
const visible = clientHeight / options.rowHeight;
|
|
14
|
+
const before = Math.ceil(visible) * (down ? 1 : 2);
|
|
15
|
+
const after = Math.ceil(visible) * (down ? 2 : 1);
|
|
16
|
+
const start = Math.max(0, firstIndex - before);
|
|
17
|
+
return {
|
|
18
|
+
end: Math.min(lastIndex, last + after),
|
|
19
|
+
start
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function onScroll() {
|
|
23
|
+
const { state } = this;
|
|
24
|
+
if (!state.active) {
|
|
25
|
+
requestAnimationFrame(() => {
|
|
26
|
+
const top = state.element.scrollTop;
|
|
27
|
+
this.update(top > state.top);
|
|
28
|
+
state.active = false;
|
|
29
|
+
state.top = top;
|
|
30
|
+
});
|
|
31
|
+
state.active = true;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
var RenderManager = class {
|
|
35
|
+
fragment;
|
|
36
|
+
listener;
|
|
37
|
+
pool = {
|
|
38
|
+
cells: {},
|
|
39
|
+
rows: []
|
|
40
|
+
};
|
|
41
|
+
state;
|
|
42
|
+
visible = {
|
|
43
|
+
indiced: /* @__PURE__ */ new Map(),
|
|
44
|
+
keys: /* @__PURE__ */ new Set()
|
|
45
|
+
};
|
|
46
|
+
constructor(state) {
|
|
47
|
+
this.listener = on(state.element, "scroll", onScroll.bind(this));
|
|
48
|
+
this.state = {
|
|
49
|
+
...state,
|
|
50
|
+
active: false,
|
|
51
|
+
top: 0
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
destroy() {
|
|
55
|
+
const { listener, pool, visible } = this;
|
|
56
|
+
listener();
|
|
57
|
+
visible.indiced.clear();
|
|
58
|
+
visible.keys.clear();
|
|
59
|
+
const cells = Object.values(pool.cells).flat();
|
|
60
|
+
let { length } = cells;
|
|
61
|
+
for (let index = 0; index < length; index += 1) cells[index].remove();
|
|
62
|
+
length = pool.rows.length;
|
|
63
|
+
for (let index = 0; index < length; index += 1) pool.rows[index].remove();
|
|
64
|
+
pool.cells = {};
|
|
65
|
+
pool.rows = [];
|
|
66
|
+
this.fragment = void 0;
|
|
67
|
+
this.listener = void 0;
|
|
68
|
+
this.pool = void 0;
|
|
69
|
+
this.state = void 0;
|
|
70
|
+
this.visible = void 0;
|
|
71
|
+
}
|
|
72
|
+
removeCells(keys) {
|
|
73
|
+
const { pool, state, visible } = this;
|
|
74
|
+
const { length } = keys;
|
|
75
|
+
for (let index = 0; index < length; index += 1) delete pool.cells[keys[index]];
|
|
76
|
+
for (const [, key] of visible.indiced) {
|
|
77
|
+
if (isGroupKey(key)) continue;
|
|
78
|
+
const row = state.managers.row.get(key, false);
|
|
79
|
+
if (row == null || row.element == null) continue;
|
|
80
|
+
for (let index = 0; index < length; index += 1) {
|
|
81
|
+
row.cells[keys[index]].innerHTML = "";
|
|
82
|
+
row.cells[keys[index]].remove();
|
|
83
|
+
delete row.cells[keys[index]];
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
getFragment() {
|
|
88
|
+
this.fragment ??= document.createDocumentFragment();
|
|
89
|
+
this.fragment.replaceChildren();
|
|
90
|
+
return this.fragment;
|
|
91
|
+
}
|
|
92
|
+
update(down, rerender) {
|
|
93
|
+
const { state, pool, visible } = this;
|
|
94
|
+
const { components, managers, options } = state;
|
|
95
|
+
components.body.elements.faker.style.height = `${(managers.data.size - managers.group.collapsed.size) * options.rowHeight}px`;
|
|
96
|
+
const indices = /* @__PURE__ */ new Set();
|
|
97
|
+
const range = getRange(state, down);
|
|
98
|
+
for (let index = range.start; index <= range.end; index += 1) indices.add(index);
|
|
99
|
+
let remove = rerender ?? false;
|
|
100
|
+
for (const [index, key] of visible.indiced) {
|
|
101
|
+
if (isGroupKey(key)) {
|
|
102
|
+
if (remove || !indices.has(index)) {
|
|
103
|
+
visible.indiced.delete(index);
|
|
104
|
+
visible.keys.delete(key);
|
|
105
|
+
state.managers.group.getForKey(key)?.element?.remove();
|
|
106
|
+
}
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const row = managers.row.get(key, false);
|
|
110
|
+
if (remove || row == null || !indices.has(index) || managers.group.collapsed.has(key)) {
|
|
111
|
+
visible.indiced.delete(index);
|
|
112
|
+
visible.keys.delete(key);
|
|
113
|
+
if (row != null) removeRow(pool, row);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
const fragment = this.getFragment();
|
|
117
|
+
const { keys } = managers.data;
|
|
118
|
+
let count = 0;
|
|
119
|
+
let offset = 0;
|
|
120
|
+
for (let index = range.start; index <= range.end + offset; index += 1) {
|
|
121
|
+
if (visible.indiced.has(index)) continue;
|
|
122
|
+
const key = keys[index];
|
|
123
|
+
if (isGroupKey(key)) {
|
|
124
|
+
const group = managers.group.getForKey(key);
|
|
125
|
+
if (group == null) continue;
|
|
126
|
+
count += 1;
|
|
127
|
+
renderGroup(state, group);
|
|
128
|
+
visible.indiced.set(index, group.key);
|
|
129
|
+
visible.keys.add(group.key);
|
|
130
|
+
if (group.element != null) {
|
|
131
|
+
group.element.style.transform = `translateY(${(index - offset) * options.rowHeight}px)`;
|
|
132
|
+
fragment.append(group.element);
|
|
133
|
+
}
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const row = managers.row.get(key, true);
|
|
137
|
+
if (row == null) continue;
|
|
138
|
+
if (managers.group.collapsed.has(key)) {
|
|
139
|
+
offset += 1;
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
count += 1;
|
|
143
|
+
renderRow(state, row);
|
|
144
|
+
visible.indiced.set(index, key);
|
|
145
|
+
visible.keys.add(key);
|
|
146
|
+
if (row.element != null) {
|
|
147
|
+
row.element.style.transform = `translateY(${(index - offset) * options.rowHeight}px)`;
|
|
148
|
+
fragment.append(row.element);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (count === 0) return;
|
|
152
|
+
if (down) components.body.elements.group.append(fragment);
|
|
153
|
+
else components.body.elements.group.prepend(fragment);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
//#endregion
|
|
157
|
+
export { RenderManager };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { RowComponent } from "../components/row.component.mjs";
|
|
2
|
+
import { State } from "../models/tabela.model.mjs";
|
|
3
|
+
import { Key } from "@oscarpalmer/atoms/models";
|
|
4
|
+
|
|
5
|
+
//#region src/managers/row.manager.d.ts
|
|
6
|
+
declare class RowManager {
|
|
7
|
+
state: State;
|
|
8
|
+
components: Map<Key, RowComponent>;
|
|
9
|
+
constructor(state: State);
|
|
10
|
+
clear(): void;
|
|
11
|
+
destroy(): void;
|
|
12
|
+
get(key: Key, create: boolean): RowComponent | undefined;
|
|
13
|
+
has(key: Key): boolean;
|
|
14
|
+
remove(key: Key): void;
|
|
15
|
+
removeRow(row: RowComponent): void;
|
|
16
|
+
update(key: Key): void;
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { RowManager };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { RowComponent, removeRow, renderRow } from "../components/row.component.mjs";
|
|
2
|
+
//#region src/managers/row.manager.ts
|
|
3
|
+
var RowManager = class {
|
|
4
|
+
components = /* @__PURE__ */ new Map();
|
|
5
|
+
constructor(state) {
|
|
6
|
+
this.state = state;
|
|
7
|
+
}
|
|
8
|
+
clear() {
|
|
9
|
+
const { components } = this;
|
|
10
|
+
const rows = [...components.values()];
|
|
11
|
+
const { length } = rows;
|
|
12
|
+
for (let index = 0; index < length; index += 1) this.removeRow(rows[index]);
|
|
13
|
+
components.clear();
|
|
14
|
+
}
|
|
15
|
+
destroy() {
|
|
16
|
+
this.clear();
|
|
17
|
+
this.components = void 0;
|
|
18
|
+
this.state = void 0;
|
|
19
|
+
}
|
|
20
|
+
get(key, create) {
|
|
21
|
+
let row = this.components.get(key);
|
|
22
|
+
if (row == null && create) {
|
|
23
|
+
row = new RowComponent(key);
|
|
24
|
+
this.components.set(key, row);
|
|
25
|
+
}
|
|
26
|
+
return row;
|
|
27
|
+
}
|
|
28
|
+
has(key) {
|
|
29
|
+
return this.components.has(key);
|
|
30
|
+
}
|
|
31
|
+
remove(key) {
|
|
32
|
+
const row = this.components.get(key);
|
|
33
|
+
if (row != null) this.removeRow(row);
|
|
34
|
+
}
|
|
35
|
+
removeRow(row) {
|
|
36
|
+
if (row.element != null) removeRow(this.state.managers.render.pool, row);
|
|
37
|
+
this.components.delete(row.key);
|
|
38
|
+
}
|
|
39
|
+
update(key) {
|
|
40
|
+
const row = this.components.get(key);
|
|
41
|
+
if (row?.element != null) renderRow(this.state, row);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
//#endregion
|
|
45
|
+
export { RowManager };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { TabelaSelection } from "../models/selection.model.mjs";
|
|
2
|
+
import { State } from "../models/tabela.model.mjs";
|
|
3
|
+
import { Key } from "@oscarpalmer/atoms/models";
|
|
4
|
+
|
|
5
|
+
//#region src/managers/selection.manager.d.ts
|
|
6
|
+
declare class SelectionManager {
|
|
7
|
+
state: State;
|
|
8
|
+
handlers: TabelaSelection;
|
|
9
|
+
items: Set<Key>;
|
|
10
|
+
last: Key | undefined;
|
|
11
|
+
constructor(state: State);
|
|
12
|
+
add(keys: Key[]): void;
|
|
13
|
+
clear(): void;
|
|
14
|
+
destroy(): void;
|
|
15
|
+
handle(event: MouseEvent, target: HTMLElement): void;
|
|
16
|
+
range(from: Key | HTMLElement, to: Key | HTMLElement): void;
|
|
17
|
+
remove(keys: Key[]): void;
|
|
18
|
+
set(keys: Key[]): void;
|
|
19
|
+
toggle(): void;
|
|
20
|
+
update(removed: Key[]): void;
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
export { SelectionManager };
|
|
@@ -1,19 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { ARIA_SELECTED, ATTRIBUTE_DATA_KEY } from "../models/dom.model.mjs";
|
|
2
|
+
import { CSS_ROW_BODY, CSS_ROW_SELECTED, CSS_SELECTION, CSS_TABLE } from "../models/style.model.mjs";
|
|
3
|
+
import { createElement } from "../helpers/dom.helpers.mjs";
|
|
4
|
+
import { getKey, isGroupKey } from "../helpers/misc.helpers.mjs";
|
|
5
|
+
import { preventSelection } from "../helpers/style.helper.mjs";
|
|
5
6
|
import { setAttribute } from "@oscarpalmer/toretto/attribute";
|
|
6
7
|
import { isKey } from "@oscarpalmer/atoms/is";
|
|
7
8
|
import { getPosition, on } from "@oscarpalmer/toretto/event";
|
|
8
9
|
import { findAncestor } from "@oscarpalmer/toretto/find";
|
|
10
|
+
//#region src/managers/selection.manager.ts
|
|
9
11
|
var SelectionManager = class {
|
|
10
|
-
handlers =
|
|
12
|
+
handlers = {
|
|
11
13
|
add: (keys) => this.add(keys),
|
|
12
14
|
clear: () => this.clear(),
|
|
13
15
|
remove: (keys) => this.remove(keys),
|
|
14
16
|
set: (keys) => this.set(keys),
|
|
15
17
|
toggle: () => this.toggle()
|
|
16
|
-
}
|
|
18
|
+
};
|
|
17
19
|
items = /* @__PURE__ */ new Set();
|
|
18
20
|
last;
|
|
19
21
|
constructor(state) {
|
|
@@ -46,7 +48,7 @@ var SelectionManager = class {
|
|
|
46
48
|
this.state = void 0;
|
|
47
49
|
}
|
|
48
50
|
handle(event, target) {
|
|
49
|
-
const key = getKey(target.getAttribute(
|
|
51
|
+
const key = getKey(target.getAttribute(ATTRIBUTE_DATA_KEY));
|
|
50
52
|
if (key == null) return;
|
|
51
53
|
const { items } = this;
|
|
52
54
|
if (event.shiftKey) {
|
|
@@ -66,8 +68,8 @@ var SelectionManager = class {
|
|
|
66
68
|
range(from, to) {
|
|
67
69
|
const { state } = this;
|
|
68
70
|
const keyed = isKey(from) && isKey(to);
|
|
69
|
-
const fromKey = keyed ? from : getKey(from.getAttribute(
|
|
70
|
-
const toKey = keyed ? to : getKey(to.getAttribute(
|
|
71
|
+
const fromKey = keyed ? from : getKey(from.getAttribute(ATTRIBUTE_DATA_KEY));
|
|
72
|
+
const toKey = keyed ? to : getKey(to.getAttribute(ATTRIBUTE_DATA_KEY));
|
|
71
73
|
if (fromKey === toKey) return;
|
|
72
74
|
const { keys } = state.managers.data;
|
|
73
75
|
const fromIndex = state.managers.data.getIndex(fromKey);
|
|
@@ -77,7 +79,7 @@ var SelectionManager = class {
|
|
|
77
79
|
const selected = [];
|
|
78
80
|
for (let index = start; index <= end; index += 1) {
|
|
79
81
|
const key = keys[index];
|
|
80
|
-
if (!(key
|
|
82
|
+
if (!isGroupKey(key)) selected.push(key);
|
|
81
83
|
}
|
|
82
84
|
if (keyed) this.add(selected);
|
|
83
85
|
else this.set(selected);
|
|
@@ -105,9 +107,10 @@ var SelectionManager = class {
|
|
|
105
107
|
const { items, state } = this;
|
|
106
108
|
const { keys } = state.managers.data;
|
|
107
109
|
if (items.size === keys.length - state.managers.group.items.length) this.clear();
|
|
108
|
-
else this.set(keys.filter((key) => !(key
|
|
110
|
+
else this.set(keys.filter((key) => !isGroupKey(key)));
|
|
109
111
|
}
|
|
110
112
|
update(removed) {
|
|
113
|
+
const { state } = this;
|
|
111
114
|
const items = [...removed.map((key) => ({
|
|
112
115
|
key,
|
|
113
116
|
removed: true
|
|
@@ -115,28 +118,28 @@ var SelectionManager = class {
|
|
|
115
118
|
key,
|
|
116
119
|
removed: false
|
|
117
120
|
}))];
|
|
118
|
-
|
|
121
|
+
let { length } = items;
|
|
119
122
|
for (let index = 0; index < length; index += 1) {
|
|
120
123
|
const { key, removed } = items[index];
|
|
121
|
-
const
|
|
122
|
-
if (
|
|
123
|
-
setAttribute(
|
|
124
|
-
if (removed)
|
|
125
|
-
else
|
|
124
|
+
const element = state.managers.row.get(key, false)?.element;
|
|
125
|
+
if (element == null) continue;
|
|
126
|
+
setAttribute(element, ARIA_SELECTED, String(!removed));
|
|
127
|
+
if (removed) element.classList.remove(CSS_ROW_SELECTED);
|
|
128
|
+
else element.classList.add(CSS_ROW_SELECTED);
|
|
126
129
|
}
|
|
127
130
|
}
|
|
128
131
|
};
|
|
129
132
|
function getPlaceholder() {
|
|
130
|
-
placeholder ??= createElement("div", { className:
|
|
133
|
+
placeholder ??= createElement("div", { className: CSS_SELECTION });
|
|
131
134
|
return placeholder;
|
|
132
135
|
}
|
|
133
136
|
function onMouseDown(event) {
|
|
134
137
|
if (shifted) {
|
|
135
|
-
const row = findAncestor(event.target,
|
|
138
|
+
const row = findAncestor(event.target, `.${CSS_ROW_BODY}`);
|
|
136
139
|
if (!(row instanceof HTMLElement)) return;
|
|
137
140
|
startElement = row;
|
|
138
141
|
startPosition = getPosition(event);
|
|
139
|
-
|
|
142
|
+
preventSelection.set();
|
|
140
143
|
}
|
|
141
144
|
}
|
|
142
145
|
function onMouseMove(event) {
|
|
@@ -157,14 +160,14 @@ function onMouseUp(event) {
|
|
|
157
160
|
if (startElement == null) return;
|
|
158
161
|
if (!event.shiftKey) {
|
|
159
162
|
shifted = false;
|
|
160
|
-
|
|
163
|
+
preventSelection.remove();
|
|
161
164
|
}
|
|
162
165
|
getPlaceholder().remove();
|
|
163
|
-
const row = findAncestor(event.target,
|
|
166
|
+
const row = findAncestor(event.target, bodyRowSelector);
|
|
164
167
|
if (row instanceof HTMLElement) {
|
|
165
168
|
endElement = row;
|
|
166
|
-
const endTable = findAncestor(endElement,
|
|
167
|
-
const startTable = findAncestor(startElement,
|
|
169
|
+
const endTable = findAncestor(endElement, tableSelector);
|
|
170
|
+
const startTable = findAncestor(startElement, tableSelector);
|
|
168
171
|
if (startTable != null && startTable === endTable) mapped.get(startTable)?.range(startElement, endElement);
|
|
169
172
|
}
|
|
170
173
|
endElement = void 0;
|
|
@@ -172,7 +175,7 @@ function onMouseUp(event) {
|
|
|
172
175
|
startPosition = void 0;
|
|
173
176
|
}
|
|
174
177
|
function onShift(event, value) {
|
|
175
|
-
if (event.key ===
|
|
178
|
+
if (event.key === KEY_SHIFT) shifted = value;
|
|
176
179
|
}
|
|
177
180
|
function onShiftDown(event) {
|
|
178
181
|
onShift(event, true);
|
|
@@ -180,15 +183,19 @@ function onShiftDown(event) {
|
|
|
180
183
|
function onShiftUp(event) {
|
|
181
184
|
onShift(event, false);
|
|
182
185
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
186
|
+
const KEY_SHIFT = "Shift";
|
|
187
|
+
const mapped = /* @__PURE__ */ new WeakMap();
|
|
188
|
+
const bodyRowSelector = `.${CSS_ROW_BODY}`;
|
|
189
|
+
const tableSelector = `.${CSS_TABLE}`;
|
|
190
|
+
let shifted = false;
|
|
191
|
+
let endElement;
|
|
192
|
+
let placeholder;
|
|
193
|
+
let startPosition;
|
|
194
|
+
let startElement;
|
|
189
195
|
on(document, "keydown", onShiftDown);
|
|
190
196
|
on(document, "keyup", onShiftUp);
|
|
191
197
|
on(document, "mousedown", onMouseDown);
|
|
192
198
|
on(document, "mousemove", onMouseMove);
|
|
193
199
|
on(document, "mouseup", onMouseUp);
|
|
200
|
+
//#endregion
|
|
194
201
|
export { SelectionManager };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { DataValue } from "../models/data.model.mjs";
|
|
2
|
+
import { TabelaSort, TabelaSortDirection, TabelaSortItem } from "../models/sort.model.mjs";
|
|
3
|
+
import { State } from "../models/tabela.model.mjs";
|
|
4
|
+
|
|
5
|
+
//#region src/managers/sort.manager.d.ts
|
|
6
|
+
declare class SortManager {
|
|
7
|
+
state: State;
|
|
8
|
+
handlers: TabelaSort;
|
|
9
|
+
items: TabelaSortItem[];
|
|
10
|
+
constructor(state: State);
|
|
11
|
+
add(key: string, direction?: TabelaSortDirection): void;
|
|
12
|
+
addOrSet(event: MouseEvent, key: string): void;
|
|
13
|
+
clear(): void;
|
|
14
|
+
destroy(): void;
|
|
15
|
+
flip(key: string): void;
|
|
16
|
+
remove(key: string): void;
|
|
17
|
+
set(items: TabelaSortItem[], set: boolean): void;
|
|
18
|
+
sort(): void;
|
|
19
|
+
toggle(event: MouseEvent, key: string, direction?: string | null): void;
|
|
20
|
+
}
|
|
21
|
+
declare function sortWithGroups(state: State, data: DataValue[], sorters: TabelaSortItem[]): DataValue[];
|
|
22
|
+
//#endregion
|
|
23
|
+
export { SortManager, sortWithGroups };
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { ARIA_SORT, ATTRIBUTE_DATA_SORT_DIRECTION, ATTRIBUTE_DATA_SORT_POSITION } from "../models/dom.model.mjs";
|
|
2
|
+
import { EVENT_DATA_SORTED, EVENT_SORT_ADD, EVENT_SORT_CLEAR, EVENT_SORT_FLIP, EVENT_SORT_REMOVE, EVENT_SORT_SET } from "../models/event.model.mjs";
|
|
3
|
+
import { isGroupKey } from "../helpers/misc.helpers.mjs";
|
|
4
|
+
import { SORT_ASCENDING, SORT_DESCENDING } from "../models/sort.model.mjs";
|
|
5
|
+
import { setAttribute, setAttributes } from "@oscarpalmer/toretto/attribute";
|
|
6
|
+
import { sort } from "@oscarpalmer/atoms/array";
|
|
7
|
+
import { getValue } from "@oscarpalmer/atoms/value/handle";
|
|
8
|
+
import { compare } from "@oscarpalmer/atoms/value/compare";
|
|
9
|
+
//#region src/managers/sort.manager.ts
|
|
10
|
+
var SortManager = class {
|
|
11
|
+
handlers = {
|
|
12
|
+
add: (field, direction) => this.add(field, direction),
|
|
13
|
+
flip: (field) => this.flip(field),
|
|
14
|
+
clear: () => this.clear(),
|
|
15
|
+
remove: (field) => this.remove(field),
|
|
16
|
+
set: (items) => this.set(items, true)
|
|
17
|
+
};
|
|
18
|
+
items = [];
|
|
19
|
+
constructor(state) {
|
|
20
|
+
this.state = state;
|
|
21
|
+
}
|
|
22
|
+
add(key, direction) {
|
|
23
|
+
if (this.items.findIndex((item) => item.key === key) > -1) return;
|
|
24
|
+
this.items.push({
|
|
25
|
+
key,
|
|
26
|
+
direction: direction ?? "ascending"
|
|
27
|
+
});
|
|
28
|
+
this.state.managers.event.emit(EVENT_SORT_ADD, [{
|
|
29
|
+
key,
|
|
30
|
+
direction: direction ?? "ascending"
|
|
31
|
+
}]);
|
|
32
|
+
this.sort();
|
|
33
|
+
}
|
|
34
|
+
addOrSet(event, key) {
|
|
35
|
+
if (event.ctrlKey || event.metaKey) this.add(key);
|
|
36
|
+
else this.set([{
|
|
37
|
+
key,
|
|
38
|
+
direction: SORT_ASCENDING
|
|
39
|
+
}], false);
|
|
40
|
+
}
|
|
41
|
+
clear() {
|
|
42
|
+
if (this.items.length === 0) return;
|
|
43
|
+
this.items.length = 0;
|
|
44
|
+
this.state.managers.event.emit(EVENT_SORT_CLEAR);
|
|
45
|
+
this.sort();
|
|
46
|
+
}
|
|
47
|
+
destroy() {
|
|
48
|
+
this.handlers = void 0;
|
|
49
|
+
this.items = void 0;
|
|
50
|
+
this.state = void 0;
|
|
51
|
+
}
|
|
52
|
+
flip(key) {
|
|
53
|
+
const item = this.items.find((item) => item.key === key);
|
|
54
|
+
if (item == null) return;
|
|
55
|
+
item.direction = item.direction === "ascending" ? SORT_DESCENDING : SORT_ASCENDING;
|
|
56
|
+
this.state.managers.event.emit(EVENT_SORT_FLIP, [{
|
|
57
|
+
key,
|
|
58
|
+
direction: item.direction
|
|
59
|
+
}]);
|
|
60
|
+
this.sort();
|
|
61
|
+
}
|
|
62
|
+
remove(key) {
|
|
63
|
+
const index = this.items.findIndex((item) => item.key === key);
|
|
64
|
+
if (index === -1) return;
|
|
65
|
+
const spliced = this.items.splice(index, 1);
|
|
66
|
+
this.state.managers.event.emit(EVENT_SORT_REMOVE, spliced);
|
|
67
|
+
if (this.items.length === 0) this.state.managers.event.emit(EVENT_SORT_CLEAR);
|
|
68
|
+
this.sort();
|
|
69
|
+
}
|
|
70
|
+
set(items, set) {
|
|
71
|
+
const removed = this.items.splice(0, this.items.length, ...items.map((item) => ({
|
|
72
|
+
key: item.key,
|
|
73
|
+
direction: item.direction
|
|
74
|
+
})));
|
|
75
|
+
if (set) this.state.managers.event.emit(EVENT_SORT_SET, {
|
|
76
|
+
removed,
|
|
77
|
+
added: items.map((item) => ({
|
|
78
|
+
key: item.key,
|
|
79
|
+
direction: item.direction
|
|
80
|
+
}))
|
|
81
|
+
});
|
|
82
|
+
else this.state.managers.event.emit(EVENT_SORT_ADD, items.map((item) => ({
|
|
83
|
+
key: item.key,
|
|
84
|
+
direction: item.direction
|
|
85
|
+
})));
|
|
86
|
+
this.sort();
|
|
87
|
+
}
|
|
88
|
+
sort() {
|
|
89
|
+
const { items, state } = this;
|
|
90
|
+
const { length } = state.managers.column.items;
|
|
91
|
+
for (let index = 0; index < length; index += 1) {
|
|
92
|
+
const column = state.managers.column.items[index];
|
|
93
|
+
const sorterIndex = items.findIndex((item) => item.key === column.options.key);
|
|
94
|
+
const sorterItem = items[sorterIndex];
|
|
95
|
+
setAttributes(column.elements.wrapper, {
|
|
96
|
+
[ARIA_SORT]: sorterItem == null ? SORT_NONE : items.length > 1 ? SORT_OTHER : sorterItem.direction,
|
|
97
|
+
[ATTRIBUTE_DATA_SORT_DIRECTION]: sorterItem == null ? void 0 : sorterItem.direction
|
|
98
|
+
});
|
|
99
|
+
setAttribute(column.elements.sorter, ATTRIBUTE_DATA_SORT_POSITION, sorterIndex > -1 && items.length > 1 ? sorterIndex + 1 : void 0);
|
|
100
|
+
}
|
|
101
|
+
state.managers.data.state.keys.active = items.length === 0 ? void 0 : getSortedItems(state, items);
|
|
102
|
+
state.managers.event.emit(EVENT_DATA_SORTED, state.managers.data.get(true));
|
|
103
|
+
state.managers.render.update(true, true);
|
|
104
|
+
}
|
|
105
|
+
toggle(event, key, direction) {
|
|
106
|
+
switch (direction) {
|
|
107
|
+
case SORT_ASCENDING:
|
|
108
|
+
this.flip(key);
|
|
109
|
+
return;
|
|
110
|
+
case SORT_DESCENDING:
|
|
111
|
+
this.remove(key);
|
|
112
|
+
return;
|
|
113
|
+
default:
|
|
114
|
+
this.addOrSet(event, key);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
function getSortedItems(state, sorters) {
|
|
120
|
+
const data = state.managers.data.state.keys.active?.map((key) => isGroupKey(key) ? key : state.managers.data.state.values.mapped.get(key)) ?? state.managers.data.state.values.array;
|
|
121
|
+
if (!state.managers.group.enabled) return sort(data, sorters).map((item) => getValue(item, state.key));
|
|
122
|
+
return sortWithGroups(state, data, sorters).map((item) => isGroupKey(item) ? item : getValue(item, state.key));
|
|
123
|
+
}
|
|
124
|
+
function sortWithGroups(state, data, sorters) {
|
|
125
|
+
const { length } = sorters;
|
|
126
|
+
return data.sort((first, second) => {
|
|
127
|
+
const firstIsGroup = isGroupKey(first);
|
|
128
|
+
const secondIsGroup = isGroupKey(second);
|
|
129
|
+
const firstValue = firstIsGroup ? state.managers.group.getForKey(first).value.stringified : getValue(first, state.managers.group.key);
|
|
130
|
+
const secondValue = secondIsGroup ? state.managers.group.getForKey(second).value.stringified : getValue(second, state.managers.group.key);
|
|
131
|
+
const firstOrder = state.managers.group.order[firstValue];
|
|
132
|
+
const secondOrder = state.managers.group.order[secondValue];
|
|
133
|
+
const groupComparison = compare(firstOrder, secondOrder);
|
|
134
|
+
if (groupComparison !== 0) return groupComparison;
|
|
135
|
+
if (firstIsGroup || secondIsGroup) return firstIsGroup && secondIsGroup ? 0 : firstIsGroup ? -1 : 1;
|
|
136
|
+
for (let index = 0; index < length; index += 1) {
|
|
137
|
+
const sorter = sorters[index];
|
|
138
|
+
const comparison = compare(getValue(first, sorter.key), getValue(second, sorter.key));
|
|
139
|
+
if (comparison !== 0) return comparison * (sorter.direction === "ascending" ? 1 : -1);
|
|
140
|
+
}
|
|
141
|
+
return 0;
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
const SORT_NONE = "none";
|
|
145
|
+
const SORT_OTHER = "other";
|
|
146
|
+
//#endregion
|
|
147
|
+
export { SortManager, sortWithGroups };
|