@oscarpalmer/tabela 0.13.0 → 0.14.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.mjs → body.component.js} +3 -6
- package/dist/components/{column.component.mjs → column.component.js} +5 -8
- package/dist/components/{footer.component.mjs → footer.component.js} +4 -7
- package/dist/components/group.component.js +28 -0
- package/dist/components/{header.component.mjs → header.component.js} +3 -6
- package/dist/components/{row.component.mjs → row.component.js} +7 -11
- package/dist/helpers/{dom.helpers.mjs → dom.helpers.js} +9 -13
- package/dist/helpers/{misc.helpers.mjs → misc.helpers.js} +1 -3
- package/dist/helpers/style.helper.js +6 -0
- package/dist/{index.mjs → index.js} +1 -3
- package/dist/managers/{column.manager.mjs → column.manager.js} +1 -6
- package/dist/managers/data.manager.js +181 -0
- package/dist/managers/{event.manager.mjs → event.manager.js} +8 -9
- package/dist/managers/{filter.manager.mjs → filter.manager.js} +14 -23
- package/dist/managers/group.manager.js +46 -0
- package/dist/managers/{navigation.manager.mjs → navigation.manager.js} +24 -27
- package/dist/managers/{render.manager.mjs → render.manager.js} +26 -35
- package/dist/managers/{row.manager.mjs → row.manager.js} +11 -18
- package/dist/managers/{selection.manager.mjs → selection.manager.js} +28 -32
- package/dist/managers/{sort.manager.mjs → sort.manager.js} +9 -12
- 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.full.mjs → tabela.full.js} +860 -1049
- package/dist/tabela.js +105 -0
- package/package.json +1 -1
- package/src/components/body.component.ts +10 -7
- package/src/components/column.component.ts +19 -15
- package/src/components/footer.component.ts +7 -10
- package/src/components/group.component.ts +34 -12
- package/src/components/header.component.ts +6 -5
- package/src/components/row.component.ts +27 -19
- package/src/helpers/dom.helpers.ts +18 -22
- package/src/helpers/misc.helpers.ts +5 -0
- package/src/managers/data.manager.ts +80 -77
- package/src/managers/event.manager.ts +21 -10
- package/src/managers/filter.manager.ts +34 -21
- package/src/managers/group.manager.ts +18 -9
- package/src/managers/navigation.manager.ts +46 -49
- package/src/managers/render.manager.ts +34 -21
- package/src/managers/row.manager.ts +1 -1
- package/src/managers/selection.manager.ts +37 -35
- package/src/managers/sort.manager.ts +47 -34
- package/src/managers/style.manager.ts +40 -25
- package/src/models/column.model.ts +2 -6
- package/src/models/data.model.ts +7 -8
- package/src/models/dom.model.ts +33 -0
- package/src/models/event.model.ts +7 -0
- package/src/models/filter.model.ts +20 -0
- package/src/models/group.model.ts +4 -0
- package/src/models/sort.model.ts +4 -0
- package/src/models/style.model.ts +32 -20
- package/src/models/tabela.model.ts +1 -0
- package/src/tabela.ts +20 -22
- package/dist/body.component-_VDOpJhV.d.mts +0 -10
- package/dist/body.model-2iwsovAV.d.mts +0 -7
- package/dist/column.component-Bx46r3JI.d.mts +0 -16
- package/dist/column.model-D-aw4EU4.d.mts +0 -16
- package/dist/components/body.component.d.mts +0 -2
- package/dist/components/column.component.d.mts +0 -2
- package/dist/components/footer.component.d.mts +0 -2
- package/dist/components/group.component.d.mts +0 -2
- package/dist/components/group.component.mjs +0 -51
- package/dist/components/header.component.d.mts +0 -2
- package/dist/components/row.component.d.mts +0 -2
- package/dist/filter.model-7ukJrtil.d.mts +0 -16
- package/dist/footer.component-Curiab8j.d.mts +0 -12
- package/dist/footer.model-DhqoS6ds.d.mts +0 -8
- package/dist/group.component-Cq1YYbfJ.d.mts +0 -285
- package/dist/group.model-BsKFwHbt.d.mts +0 -10
- package/dist/header.component-BjjlpZIg.d.mts +0 -12
- package/dist/header.model-DN_KzUCV.d.mts +0 -7
- package/dist/helpers/dom.helpers.d.mts +0 -12
- package/dist/helpers/misc.helpers.d.mts +0 -6
- package/dist/helpers/style.helper.d.mts +0 -6
- package/dist/helpers/style.helper.mjs +0 -8
- package/dist/index.d.mts +0 -7
- package/dist/managers/column.manager.d.mts +0 -2
- package/dist/managers/data.manager.d.mts +0 -2
- package/dist/managers/data.manager.mjs +0 -222
- package/dist/managers/event.manager.d.mts +0 -2
- package/dist/managers/filter.manager.d.mts +0 -2
- package/dist/managers/group.manager.d.mts +0 -2
- package/dist/managers/group.manager.mjs +0 -73
- package/dist/managers/navigation.manager.d.mts +0 -2
- package/dist/managers/render.manager.d.mts +0 -2
- package/dist/managers/row.manager.d.mts +0 -2
- package/dist/managers/selection.manager.d.mts +0 -2
- package/dist/managers/sort.manager.d.mts +0 -2
- package/dist/managers/style.manager.d.mts +0 -2
- package/dist/managers/style.manager.mjs +0 -149
- package/dist/models/body.model.d.mts +0 -2
- package/dist/models/body.model.mjs +0 -1
- package/dist/models/column.model.d.mts +0 -2
- package/dist/models/column.model.mjs +0 -1
- package/dist/models/data.model.d.mts +0 -2
- package/dist/models/data.model.mjs +0 -1
- package/dist/models/filter.model.d.mts +0 -2
- package/dist/models/filter.model.mjs +0 -1
- package/dist/models/footer.model.d.mts +0 -2
- package/dist/models/footer.model.mjs +0 -1
- package/dist/models/group.model.d.mts +0 -2
- package/dist/models/group.model.mjs +0 -1
- package/dist/models/header.model.d.mts +0 -2
- package/dist/models/header.model.mjs +0 -1
- package/dist/models/render.model.d.mts +0 -2
- package/dist/models/render.model.mjs +0 -1
- package/dist/models/selection.model.d.mts +0 -2
- package/dist/models/selection.model.mjs +0 -1
- package/dist/models/sort.model.d.mts +0 -2
- package/dist/models/sort.model.mjs +0 -1
- package/dist/models/style.model.d.mts +0 -23
- package/dist/models/style.model.mjs +0 -23
- package/dist/models/tabela.model.d.mts +0 -2
- package/dist/models/tabela.model.mjs +0 -1
- package/dist/models/tabela.options.d.mts +0 -2
- package/dist/models/tabela.options.mjs +0 -1
- package/dist/selection.model-rwQe9fco.d.mts +0 -12
- package/dist/sort.model-CauImaLu.d.mts +0 -15
- package/dist/tabela.d.mts +0 -21
- package/dist/tabela.mjs +0 -126
- package/dist/tabela.options-RkZvfptB.d.mts +0 -14
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {isNullableOrWhitespace} from '@oscarpalmer/atoms/is';
|
|
2
|
+
import type {Key} from '@oscarpalmer/atoms/models';
|
|
2
3
|
import {clamp} from '@oscarpalmer/atoms/number';
|
|
3
|
-
import {getKey} from '../helpers/misc.helpers';
|
|
4
|
-
import
|
|
4
|
+
import {getKey, isGroupKey} from '../helpers/misc.helpers';
|
|
5
|
+
import {ARIA_ACTIVEDESCENDANT, ATTRIBUTE_DATA_ACTIVE} from '../models/dom.model';
|
|
5
6
|
import type {State} from '../models/tabela.model';
|
|
6
|
-
import {GroupComponent} from '../components/group.component';
|
|
7
7
|
|
|
8
8
|
export class NavigationManager {
|
|
9
|
-
active:
|
|
9
|
+
active: Key | undefined;
|
|
10
10
|
|
|
11
11
|
constructor(public state: State) {}
|
|
12
12
|
|
|
@@ -21,41 +21,43 @@ export class NavigationManager {
|
|
|
21
21
|
|
|
22
22
|
event.preventDefault();
|
|
23
23
|
|
|
24
|
-
const {components,
|
|
24
|
+
const {components, managers} = this.state;
|
|
25
25
|
|
|
26
|
-
const activeDescendant = components.body.elements.group.getAttribute(
|
|
26
|
+
const activeDescendant = components.body.elements.group.getAttribute(ARIA_ACTIVEDESCENDANT);
|
|
27
27
|
|
|
28
|
-
const {
|
|
29
|
-
const {length} =
|
|
28
|
+
const {keys} = managers.data;
|
|
29
|
+
const {length} = keys;
|
|
30
30
|
|
|
31
31
|
let next: number;
|
|
32
32
|
|
|
33
33
|
if (isNullableOrWhitespace(activeDescendant)) {
|
|
34
34
|
next = getDefaultIndex(event.key, length);
|
|
35
35
|
} else {
|
|
36
|
-
next = getIndex(this.state, event, activeDescendant
|
|
36
|
+
next = getIndex(this.state, event, activeDescendant)!;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
if (next != null) {
|
|
40
|
-
this.setActive(
|
|
40
|
+
this.setActive(keys.at(next));
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
setActive(item:
|
|
45
|
-
const {components,
|
|
44
|
+
setActive(item: Key | undefined, scroll?: boolean): void {
|
|
45
|
+
const {components, managers, options, prefix} = this.state;
|
|
46
46
|
|
|
47
47
|
this.active = item;
|
|
48
48
|
|
|
49
|
-
const active = components.body.elements.group.querySelectorAll(
|
|
49
|
+
const active = components.body.elements.group.querySelectorAll(attributeDataActiveTrue);
|
|
50
50
|
|
|
51
51
|
for (const item of active) {
|
|
52
|
-
item.setAttribute(
|
|
52
|
+
item.setAttribute(ATTRIBUTE_DATA_ACTIVE, 'false');
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
const component =
|
|
55
|
+
const component = isGroupKey(item)
|
|
56
|
+
? managers.group.getForKey(item as string)
|
|
57
|
+
: managers.row.get(item!, false);
|
|
56
58
|
|
|
57
59
|
if (component != null) {
|
|
58
|
-
component.element?.setAttribute(
|
|
60
|
+
component.element?.setAttribute(ATTRIBUTE_DATA_ACTIVE, 'true');
|
|
59
61
|
|
|
60
62
|
if (scroll ?? true) {
|
|
61
63
|
if (component.element == null) {
|
|
@@ -72,8 +74,8 @@ export class NavigationManager {
|
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
components.body.elements.group.setAttribute(
|
|
75
|
-
|
|
76
|
-
component == null ? '' :
|
|
77
|
+
ARIA_ACTIVEDESCENDANT,
|
|
78
|
+
component == null ? '' : `${prefix}${component.key}`,
|
|
77
79
|
);
|
|
78
80
|
}
|
|
79
81
|
}
|
|
@@ -83,10 +85,10 @@ function getDefaultIndex(key: string, max: number): number {
|
|
|
83
85
|
case negativeDefaultKeys.has(key):
|
|
84
86
|
return -1;
|
|
85
87
|
|
|
86
|
-
case key ===
|
|
88
|
+
case key === KEY_PAGE_DOWN:
|
|
87
89
|
return Math.min(9, max - 1);
|
|
88
90
|
|
|
89
|
-
case key ===
|
|
91
|
+
case key === KEY_PAGE_UP:
|
|
90
92
|
return max < 10 ? 0 : max - 10;
|
|
91
93
|
|
|
92
94
|
default:
|
|
@@ -94,54 +96,49 @@ function getDefaultIndex(key: string, max: number): number {
|
|
|
94
96
|
}
|
|
95
97
|
}
|
|
96
98
|
|
|
97
|
-
function getIndex(
|
|
98
|
-
state
|
|
99
|
-
event: KeyboardEvent,
|
|
100
|
-
active: string,
|
|
101
|
-
id: number,
|
|
102
|
-
): number | undefined {
|
|
103
|
-
const key = getKey(active.replace(`tabela_${id}_`, ''));
|
|
99
|
+
function getIndex(state: State, event: KeyboardEvent, active: string): number | undefined {
|
|
100
|
+
const key = getKey(active.replace(state.prefix, ''));
|
|
104
101
|
|
|
105
102
|
if (key == null) {
|
|
106
103
|
return;
|
|
107
104
|
}
|
|
108
105
|
|
|
109
106
|
if (absoluteKeys.has(event.key)) {
|
|
110
|
-
return event.key ===
|
|
107
|
+
return event.key === KEY_HOME ? 0 : state.managers.data.size - 1;
|
|
111
108
|
}
|
|
112
109
|
|
|
113
110
|
const index = state.managers.data.getIndex(key);
|
|
114
111
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
return clamp(index + offset, 0, state.managers.data.size - 1, true);
|
|
112
|
+
return clamp(index + (offset[event.key] ?? 0), 0, state.managers.data.size - 1, true);
|
|
118
113
|
}
|
|
119
114
|
|
|
120
|
-
|
|
121
|
-
switch (key) {
|
|
122
|
-
case 'ArrowDown':
|
|
123
|
-
return 1;
|
|
115
|
+
const KEY_ARROW_DOWN = 'ArrowDown';
|
|
124
116
|
|
|
125
|
-
|
|
126
|
-
return -1;
|
|
117
|
+
const KEY_ARROW_UP = 'ArrowUp';
|
|
127
118
|
|
|
128
|
-
|
|
129
|
-
return 10;
|
|
119
|
+
const KEY_END = 'End';
|
|
130
120
|
|
|
131
|
-
|
|
132
|
-
return -10;
|
|
121
|
+
const KEY_HOME = 'Home';
|
|
133
122
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
123
|
+
const KEY_PAGE_DOWN = 'PageDown';
|
|
124
|
+
|
|
125
|
+
const KEY_PAGE_UP = 'PageUp';
|
|
126
|
+
|
|
127
|
+
const absoluteKeys = new Set([KEY_END, KEY_HOME]);
|
|
128
|
+
|
|
129
|
+
const arrowKeys = new Set([KEY_ARROW_DOWN, KEY_ARROW_UP]);
|
|
138
130
|
|
|
139
|
-
const
|
|
131
|
+
export const attributeDataActiveTrue = `[${ATTRIBUTE_DATA_ACTIVE}="true"]`;
|
|
140
132
|
|
|
141
|
-
const
|
|
133
|
+
const negativeDefaultKeys = new Set([KEY_ARROW_UP, KEY_END]);
|
|
142
134
|
|
|
143
|
-
const
|
|
135
|
+
const offset: Record<string, number> = {
|
|
136
|
+
[KEY_ARROW_DOWN]: 1,
|
|
137
|
+
[KEY_ARROW_UP]: -1,
|
|
138
|
+
[KEY_PAGE_DOWN]: 10,
|
|
139
|
+
[KEY_PAGE_UP]: -10,
|
|
140
|
+
};
|
|
144
141
|
|
|
145
|
-
const pageKeys = new Set([
|
|
142
|
+
const pageKeys = new Set([KEY_PAGE_DOWN, KEY_PAGE_UP]);
|
|
146
143
|
|
|
147
144
|
const allKeys = new Set([...absoluteKeys, ...arrowKeys, ...pageKeys]);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import type {Key} from '@oscarpalmer/atoms/models';
|
|
1
2
|
import {on} from '@oscarpalmer/toretto/event';
|
|
2
3
|
import type {RemovableEventListener} from '@oscarpalmer/toretto/models';
|
|
3
|
-
import {
|
|
4
|
+
import {renderGroup} from '../components/group.component';
|
|
4
5
|
import {removeRow, renderRow} from '../components/row.component';
|
|
5
|
-
import
|
|
6
|
+
import {isGroupKey} from '../helpers/misc.helpers';
|
|
6
7
|
import type {RenderElementPool, RenderRange, RenderState} from '../models/render.model';
|
|
7
8
|
import type {State} from '../models/tabela.model';
|
|
8
9
|
|
|
@@ -10,10 +11,10 @@ function getRange(state: State, down: boolean): RenderRange {
|
|
|
10
11
|
const {element, managers, options} = state;
|
|
11
12
|
const {clientHeight, scrollTop} = element;
|
|
12
13
|
|
|
13
|
-
const {
|
|
14
|
+
const {keys} = managers.data;
|
|
14
15
|
|
|
15
16
|
const firstIndex = Math.floor(scrollTop / options.rowHeight);
|
|
16
|
-
const lastIndex =
|
|
17
|
+
const lastIndex = keys.length - managers.group.collapsed.size - 1;
|
|
17
18
|
|
|
18
19
|
const last = Math.min(lastIndex, Math.ceil((scrollTop + clientHeight) / options.rowHeight) - 1);
|
|
19
20
|
|
|
@@ -57,7 +58,7 @@ export class RenderManager {
|
|
|
57
58
|
|
|
58
59
|
state: RenderState;
|
|
59
60
|
|
|
60
|
-
visible = new Map<number,
|
|
61
|
+
visible = new Map<number, Key>();
|
|
61
62
|
|
|
62
63
|
constructor(state: State) {
|
|
63
64
|
this.listener = on(state.element, 'scroll', onScroll.bind(this));
|
|
@@ -108,7 +109,7 @@ export class RenderManager {
|
|
|
108
109
|
}
|
|
109
110
|
|
|
110
111
|
for (const [, key] of visible) {
|
|
111
|
-
if (key
|
|
112
|
+
if (isGroupKey(key)) {
|
|
112
113
|
continue;
|
|
113
114
|
}
|
|
114
115
|
|
|
@@ -153,11 +154,11 @@ export class RenderManager {
|
|
|
153
154
|
let remove = rerender ?? false;
|
|
154
155
|
|
|
155
156
|
for (const [index, key] of visible) {
|
|
156
|
-
if (key
|
|
157
|
+
if (isGroupKey(key)) {
|
|
157
158
|
if (remove || !indices.has(index)) {
|
|
158
159
|
visible.delete(index);
|
|
159
160
|
|
|
160
|
-
key
|
|
161
|
+
state.managers.group.getForKey(key as string)?.element?.remove();
|
|
161
162
|
}
|
|
162
163
|
|
|
163
164
|
continue;
|
|
@@ -176,7 +177,7 @@ export class RenderManager {
|
|
|
176
177
|
|
|
177
178
|
const fragment = this.getFragment();
|
|
178
179
|
|
|
179
|
-
const {
|
|
180
|
+
const {keys} = managers.data;
|
|
180
181
|
|
|
181
182
|
let count = 0;
|
|
182
183
|
let offset = 0;
|
|
@@ -186,31 +187,37 @@ export class RenderManager {
|
|
|
186
187
|
continue;
|
|
187
188
|
}
|
|
188
189
|
|
|
189
|
-
const
|
|
190
|
+
const key = keys[index];
|
|
191
|
+
|
|
192
|
+
if (isGroupKey(key)) {
|
|
193
|
+
const group = managers.group.getForKey(key as string);
|
|
194
|
+
|
|
195
|
+
if (group == null) {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
190
198
|
|
|
191
|
-
if (item instanceof GroupComponent) {
|
|
192
199
|
count += 1;
|
|
193
200
|
|
|
194
|
-
renderGroup(state,
|
|
201
|
+
renderGroup(state, group);
|
|
195
202
|
|
|
196
|
-
visible.set(index,
|
|
203
|
+
visible.set(index, group.key);
|
|
197
204
|
|
|
198
|
-
if (
|
|
199
|
-
|
|
205
|
+
if (group.element != null) {
|
|
206
|
+
group.element.style.transform = `translateY(${(index - offset) * options.rowHeight}px)`;
|
|
200
207
|
|
|
201
|
-
fragment.append(
|
|
208
|
+
fragment.append(group.element);
|
|
202
209
|
}
|
|
203
210
|
|
|
204
211
|
continue;
|
|
205
212
|
}
|
|
206
213
|
|
|
207
|
-
const row = managers.row.get(
|
|
214
|
+
const row = managers.row.get(key, true);
|
|
208
215
|
|
|
209
216
|
if (row == null) {
|
|
210
217
|
continue;
|
|
211
218
|
}
|
|
212
219
|
|
|
213
|
-
if (managers.group.collapsed.has(
|
|
220
|
+
if (managers.group.collapsed.has(key)) {
|
|
214
221
|
offset += 1;
|
|
215
222
|
|
|
216
223
|
continue;
|
|
@@ -220,7 +227,7 @@ export class RenderManager {
|
|
|
220
227
|
|
|
221
228
|
renderRow(state, row);
|
|
222
229
|
|
|
223
|
-
visible.set(index,
|
|
230
|
+
visible.set(index, key);
|
|
224
231
|
|
|
225
232
|
if (row.element != null) {
|
|
226
233
|
row.element.style.transform = `translateY(${(index - offset) * options.rowHeight}px)`;
|
|
@@ -229,8 +236,14 @@ export class RenderManager {
|
|
|
229
236
|
}
|
|
230
237
|
}
|
|
231
238
|
|
|
232
|
-
if (count
|
|
233
|
-
|
|
239
|
+
if (count === 0) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (down) {
|
|
244
|
+
components.body.elements.group.append(fragment);
|
|
245
|
+
} else {
|
|
246
|
+
components.body.elements.group.prepend(fragment);
|
|
234
247
|
}
|
|
235
248
|
}
|
|
236
249
|
}
|
|
@@ -4,26 +4,22 @@ import {setAttribute} from '@oscarpalmer/toretto/attribute';
|
|
|
4
4
|
import {getPosition, on} from '@oscarpalmer/toretto/event';
|
|
5
5
|
import {findAncestor} from '@oscarpalmer/toretto/find';
|
|
6
6
|
import type {EventPosition} from '@oscarpalmer/toretto/models';
|
|
7
|
-
import {GroupComponent} from '../components/group.component';
|
|
8
7
|
import {createElement} from '../helpers/dom.helpers';
|
|
9
|
-
import {getKey} from '../helpers/misc.helpers';
|
|
8
|
+
import {getKey, isGroupKey} from '../helpers/misc.helpers';
|
|
10
9
|
import {preventSelection} from '../helpers/style.helper';
|
|
10
|
+
import {ARIA_SELECTED, ATTRIBUTE_DATA_KEY, ELEMENT_DIV} from '../models/dom.model';
|
|
11
11
|
import type {TabelaSelection} from '../models/selection.model';
|
|
12
|
-
import {
|
|
13
|
-
CSS_TABELA_ROW_BODY,
|
|
14
|
-
CSS_TABELA_ROW_SELECTED,
|
|
15
|
-
CSS_TABELA_SELECTION,
|
|
16
|
-
} from '../models/style.model';
|
|
12
|
+
import {CSS_ROW_BODY, CSS_ROW_SELECTED, CSS_SELECTION, CSS_TABLE} from '../models/style.model';
|
|
17
13
|
import type {State} from '../models/tabela.model';
|
|
18
14
|
|
|
19
15
|
export class SelectionManager {
|
|
20
|
-
handlers =
|
|
16
|
+
handlers: TabelaSelection = {
|
|
21
17
|
add: keys => this.add(keys),
|
|
22
18
|
clear: () => this.clear(),
|
|
23
19
|
remove: keys => this.remove(keys),
|
|
24
20
|
set: keys => this.set(keys),
|
|
25
21
|
toggle: () => this.toggle(),
|
|
26
|
-
}
|
|
22
|
+
};
|
|
27
23
|
|
|
28
24
|
items = new Set<Key>();
|
|
29
25
|
|
|
@@ -75,7 +71,7 @@ export class SelectionManager {
|
|
|
75
71
|
}
|
|
76
72
|
|
|
77
73
|
handle(event: MouseEvent, target: HTMLElement): void {
|
|
78
|
-
const key = getKey(target.getAttribute(
|
|
74
|
+
const key = getKey(target.getAttribute(ATTRIBUTE_DATA_KEY));
|
|
79
75
|
|
|
80
76
|
if (key == null) {
|
|
81
77
|
return;
|
|
@@ -115,14 +111,19 @@ export class SelectionManager {
|
|
|
115
111
|
|
|
116
112
|
const keyed = isKey(from) && isKey(to);
|
|
117
113
|
|
|
118
|
-
const fromKey = keyed
|
|
119
|
-
|
|
114
|
+
const fromKey = keyed
|
|
115
|
+
? (from as Key)
|
|
116
|
+
: getKey((from as HTMLElement).getAttribute(ATTRIBUTE_DATA_KEY))!;
|
|
117
|
+
|
|
118
|
+
const toKey = keyed
|
|
119
|
+
? (to as Key)
|
|
120
|
+
: getKey((to as HTMLElement).getAttribute(ATTRIBUTE_DATA_KEY))!;
|
|
120
121
|
|
|
121
122
|
if (fromKey === toKey) {
|
|
122
123
|
return;
|
|
123
124
|
}
|
|
124
125
|
|
|
125
|
-
const {
|
|
126
|
+
const {keys} = state.managers.data;
|
|
126
127
|
|
|
127
128
|
const fromIndex = state.managers.data.getIndex(fromKey);
|
|
128
129
|
const toIndex = state.managers.data.getIndex(toKey);
|
|
@@ -136,10 +137,10 @@ export class SelectionManager {
|
|
|
136
137
|
const selected: Key[] = [];
|
|
137
138
|
|
|
138
139
|
for (let index = start; index <= end; index += 1) {
|
|
139
|
-
const
|
|
140
|
+
const key = keys[index];
|
|
140
141
|
|
|
141
|
-
if (!(
|
|
142
|
-
selected.push(
|
|
142
|
+
if (!isGroupKey(key)) {
|
|
143
|
+
selected.push(key);
|
|
143
144
|
}
|
|
144
145
|
}
|
|
145
146
|
|
|
@@ -189,12 +190,12 @@ export class SelectionManager {
|
|
|
189
190
|
|
|
190
191
|
toggle(): void {
|
|
191
192
|
const {items, state} = this;
|
|
192
|
-
const
|
|
193
|
+
const {keys} = state.managers.data;
|
|
193
194
|
|
|
194
|
-
if (items.size ===
|
|
195
|
+
if (items.size === keys.length - state.managers.group.items.length) {
|
|
195
196
|
this.clear();
|
|
196
197
|
} else {
|
|
197
|
-
this.set(
|
|
198
|
+
this.set(keys.filter(key => !isGroupKey(key)));
|
|
198
199
|
}
|
|
199
200
|
}
|
|
200
201
|
|
|
@@ -217,33 +218,28 @@ export class SelectionManager {
|
|
|
217
218
|
continue;
|
|
218
219
|
}
|
|
219
220
|
|
|
220
|
-
setAttribute(element,
|
|
221
|
+
setAttribute(element, ARIA_SELECTED, String(!removed));
|
|
221
222
|
|
|
222
223
|
if (removed) {
|
|
223
|
-
element.classList.remove(
|
|
224
|
+
element.classList.remove(CSS_ROW_SELECTED);
|
|
224
225
|
} else {
|
|
225
|
-
element.classList.add(
|
|
226
|
+
element.classList.add(CSS_ROW_SELECTED);
|
|
226
227
|
}
|
|
227
228
|
}
|
|
228
229
|
}
|
|
229
230
|
}
|
|
230
231
|
|
|
231
232
|
function getPlaceholder(): HTMLElement {
|
|
232
|
-
placeholder ??= createElement(
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
className: CSS_TABELA_SELECTION,
|
|
236
|
-
},
|
|
237
|
-
{},
|
|
238
|
-
{},
|
|
239
|
-
);
|
|
233
|
+
placeholder ??= createElement(ELEMENT_DIV, {
|
|
234
|
+
className: CSS_SELECTION,
|
|
235
|
+
});
|
|
240
236
|
|
|
241
237
|
return placeholder;
|
|
242
238
|
}
|
|
243
239
|
|
|
244
240
|
function onMouseDown(event: MouseEvent): void {
|
|
245
241
|
if (shifted) {
|
|
246
|
-
const row = findAncestor(event.target as HTMLElement, `.${
|
|
242
|
+
const row = findAncestor(event.target as HTMLElement, `.${CSS_ROW_BODY}`);
|
|
247
243
|
|
|
248
244
|
if (!(row instanceof HTMLElement)) {
|
|
249
245
|
return;
|
|
@@ -298,13 +294,13 @@ function onMouseUp(event: MouseEvent): void {
|
|
|
298
294
|
|
|
299
295
|
getPlaceholder().remove();
|
|
300
296
|
|
|
301
|
-
const row = findAncestor(event.target as HTMLElement,
|
|
297
|
+
const row = findAncestor(event.target as HTMLElement, bodyRowSelector);
|
|
302
298
|
|
|
303
299
|
if (row instanceof HTMLElement) {
|
|
304
300
|
endElement = row;
|
|
305
301
|
|
|
306
|
-
const endTable = findAncestor(endElement,
|
|
307
|
-
const startTable = findAncestor(startElement,
|
|
302
|
+
const endTable = findAncestor(endElement, tableSelector);
|
|
303
|
+
const startTable = findAncestor(startElement, tableSelector);
|
|
308
304
|
|
|
309
305
|
if (startTable != null && startTable === endTable) {
|
|
310
306
|
mapped.get(startTable)?.range(startElement, endElement);
|
|
@@ -317,7 +313,7 @@ function onMouseUp(event: MouseEvent): void {
|
|
|
317
313
|
}
|
|
318
314
|
|
|
319
315
|
function onShift(event: KeyboardEvent, value: boolean): void {
|
|
320
|
-
if (event.key ===
|
|
316
|
+
if (event.key === KEY_SHIFT) {
|
|
321
317
|
shifted = value;
|
|
322
318
|
}
|
|
323
319
|
}
|
|
@@ -330,8 +326,14 @@ function onShiftUp(event: KeyboardEvent): void {
|
|
|
330
326
|
onShift(event, false);
|
|
331
327
|
}
|
|
332
328
|
|
|
329
|
+
const KEY_SHIFT = 'Shift';
|
|
330
|
+
|
|
333
331
|
const mapped = new WeakMap<Element, SelectionManager>();
|
|
334
332
|
|
|
333
|
+
const bodyRowSelector = `.${CSS_ROW_BODY}`;
|
|
334
|
+
|
|
335
|
+
const tableSelector = `.${CSS_TABLE}`;
|
|
336
|
+
|
|
335
337
|
let shifted = false;
|
|
336
338
|
|
|
337
339
|
let endElement: HTMLElement | undefined;
|
|
@@ -3,19 +3,30 @@ import type {Key, PlainObject} from '@oscarpalmer/atoms/models';
|
|
|
3
3
|
import {compare} from '@oscarpalmer/atoms/value/compare';
|
|
4
4
|
import {getValue} from '@oscarpalmer/atoms/value/handle';
|
|
5
5
|
import {setAttribute, setAttributes} from '@oscarpalmer/toretto/attribute';
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
import {
|
|
7
|
+
ARIA_SORT,
|
|
8
|
+
ATTRIBUTE_DATA_SORT_DIRECTION,
|
|
9
|
+
ATTRIBUTE_DATA_SORT_POSITION,
|
|
10
|
+
} from '../models/dom.model';
|
|
11
|
+
import {
|
|
12
|
+
SORT_ASCENDING,
|
|
13
|
+
SORT_DESCENDING,
|
|
14
|
+
type TabelaSort,
|
|
15
|
+
type TabelaSortDirection,
|
|
16
|
+
type TabelaSortItem,
|
|
17
|
+
} from '../models/sort.model';
|
|
9
18
|
import type {State} from '../models/tabela.model';
|
|
19
|
+
import type {DataValue} from '../models/data.model';
|
|
20
|
+
import {isGroupKey} from '../helpers/misc.helpers';
|
|
10
21
|
|
|
11
22
|
export class SortManager {
|
|
12
|
-
handlers =
|
|
23
|
+
handlers: TabelaSort = {
|
|
13
24
|
add: (field, direction) => this.add(field, direction),
|
|
14
25
|
flip: field => this.flip(field),
|
|
15
26
|
clear: () => this.clear(),
|
|
16
27
|
remove: field => this.remove(field),
|
|
17
28
|
set: items => this.set(items),
|
|
18
|
-
}
|
|
29
|
+
};
|
|
19
30
|
|
|
20
31
|
items: PlainObject[] = [];
|
|
21
32
|
|
|
@@ -30,7 +41,7 @@ export class SortManager {
|
|
|
30
41
|
|
|
31
42
|
this.items.push({
|
|
32
43
|
key: field,
|
|
33
|
-
direction: direction ??
|
|
44
|
+
direction: direction ?? SORT_ASCENDING,
|
|
34
45
|
});
|
|
35
46
|
|
|
36
47
|
this.sort();
|
|
@@ -40,7 +51,7 @@ export class SortManager {
|
|
|
40
51
|
if (event.ctrlKey || event.metaKey) {
|
|
41
52
|
this.add(field);
|
|
42
53
|
} else {
|
|
43
|
-
this.set([{field, direction:
|
|
54
|
+
this.set([{field, direction: SORT_ASCENDING}]);
|
|
44
55
|
}
|
|
45
56
|
}
|
|
46
57
|
|
|
@@ -65,7 +76,7 @@ export class SortManager {
|
|
|
65
76
|
return;
|
|
66
77
|
}
|
|
67
78
|
|
|
68
|
-
item.direction = item.direction ===
|
|
79
|
+
item.direction = item.direction === SORT_ASCENDING ? SORT_DESCENDING : SORT_ASCENDING;
|
|
69
80
|
|
|
70
81
|
this.sort();
|
|
71
82
|
}
|
|
@@ -110,19 +121,19 @@ export class SortManager {
|
|
|
110
121
|
const sorterItem = items[sorterIndex];
|
|
111
122
|
|
|
112
123
|
setAttributes(column.elements.wrapper, {
|
|
113
|
-
|
|
114
|
-
sorterItem == null ?
|
|
115
|
-
|
|
124
|
+
[ARIA_SORT]:
|
|
125
|
+
sorterItem == null ? SORT_NONE : items.length > 1 ? SORT_OTHER : sorterItem.direction,
|
|
126
|
+
[ATTRIBUTE_DATA_SORT_DIRECTION]: sorterItem == null ? undefined : sorterItem.direction,
|
|
116
127
|
});
|
|
117
128
|
|
|
118
129
|
setAttribute(
|
|
119
130
|
column.elements.sorter,
|
|
120
|
-
|
|
131
|
+
ATTRIBUTE_DATA_SORT_POSITION,
|
|
121
132
|
sorterIndex > -1 && items.length > 1 ? sorterIndex + 1 : undefined,
|
|
122
133
|
);
|
|
123
134
|
}
|
|
124
135
|
|
|
125
|
-
state.managers.data.state.
|
|
136
|
+
state.managers.data.state.keys.active =
|
|
126
137
|
items.length === 0 ? undefined : getSortedItems(state, items);
|
|
127
138
|
|
|
128
139
|
state.managers.render.update(true, true);
|
|
@@ -130,11 +141,11 @@ export class SortManager {
|
|
|
130
141
|
|
|
131
142
|
toggle(event: MouseEvent, field: string, direction?: string | null): void {
|
|
132
143
|
switch (direction) {
|
|
133
|
-
case
|
|
144
|
+
case SORT_ASCENDING:
|
|
134
145
|
this.flip(field);
|
|
135
146
|
return;
|
|
136
147
|
|
|
137
|
-
case
|
|
148
|
+
case SORT_DESCENDING:
|
|
138
149
|
this.removeOrClear(event, field);
|
|
139
150
|
return;
|
|
140
151
|
|
|
@@ -145,11 +156,11 @@ export class SortManager {
|
|
|
145
156
|
}
|
|
146
157
|
}
|
|
147
158
|
|
|
148
|
-
function getSortedItems(state: State, sorters: PlainObject[]):
|
|
159
|
+
function getSortedItems(state: State, sorters: PlainObject[]): Key[] {
|
|
149
160
|
const data =
|
|
150
|
-
state.managers.data.state.
|
|
151
|
-
key
|
|
152
|
-
) ?? state.managers.data.state.values.array
|
|
161
|
+
(state.managers.data.state.keys.active?.map(key =>
|
|
162
|
+
isGroupKey(key) ? key : state.managers.data.state.values.mapped.get(key)!,
|
|
163
|
+
) as DataValue[]) ?? state.managers.data.state.values.array;
|
|
153
164
|
|
|
154
165
|
if (!state.managers.group.enabled) {
|
|
155
166
|
return sort(data as PlainObject[], sorters as never).map(
|
|
@@ -158,27 +169,28 @@ function getSortedItems(state: State, sorters: PlainObject[]): DataItem[] {
|
|
|
158
169
|
}
|
|
159
170
|
|
|
160
171
|
return sortWithGroups(state, data, sorters).map(item =>
|
|
161
|
-
item
|
|
172
|
+
typeof item === 'string' ? item : (getValue(item, state.key) as Key),
|
|
162
173
|
);
|
|
163
174
|
}
|
|
164
175
|
|
|
165
176
|
export function sortWithGroups(
|
|
166
177
|
state: State,
|
|
167
|
-
data:
|
|
178
|
+
data: DataValue[],
|
|
168
179
|
sorters: PlainObject[],
|
|
169
|
-
):
|
|
180
|
+
): DataValue[] {
|
|
170
181
|
const {length} = sorters;
|
|
171
182
|
|
|
172
183
|
return data.sort((first, second) => {
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
? first.value.stringified
|
|
176
|
-
: getValue(first, state.managers.group.field);
|
|
184
|
+
const firstIsGroup = typeof first === 'string';
|
|
185
|
+
const secondIsGroup = typeof second === 'string';
|
|
177
186
|
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
187
|
+
const firstValue = firstIsGroup
|
|
188
|
+
? state.managers.group.getForKey(first)?.value.stringified
|
|
189
|
+
: getValue(first, state.managers.group.field);
|
|
190
|
+
|
|
191
|
+
const secondValue = secondIsGroup
|
|
192
|
+
? state.managers.group.getForKey(second)?.value.stringified
|
|
193
|
+
: getValue(second, state.managers.group.field);
|
|
182
194
|
|
|
183
195
|
const firstOrder = state.managers.group.order[firstValue as never];
|
|
184
196
|
const secondOrder = state.managers.group.order[secondValue as never];
|
|
@@ -189,9 +201,6 @@ export function sortWithGroups(
|
|
|
189
201
|
return groupComparison;
|
|
190
202
|
}
|
|
191
203
|
|
|
192
|
-
const firstIsGroup = first instanceof GroupComponent;
|
|
193
|
-
const secondIsGroup = second instanceof GroupComponent;
|
|
194
|
-
|
|
195
204
|
if (firstIsGroup || secondIsGroup) {
|
|
196
205
|
return firstIsGroup && secondIsGroup ? 0 : firstIsGroup ? -1 : 1;
|
|
197
206
|
}
|
|
@@ -205,10 +214,14 @@ export function sortWithGroups(
|
|
|
205
214
|
);
|
|
206
215
|
|
|
207
216
|
if (comparison !== 0) {
|
|
208
|
-
return comparison * (sorter.direction ===
|
|
217
|
+
return comparison * (sorter.direction === SORT_ASCENDING ? 1 : -1);
|
|
209
218
|
}
|
|
210
219
|
}
|
|
211
220
|
|
|
212
221
|
return 0;
|
|
213
222
|
});
|
|
214
223
|
}
|
|
224
|
+
|
|
225
|
+
const SORT_NONE = 'none';
|
|
226
|
+
|
|
227
|
+
const SORT_OTHER = 'other';
|