@oscarpalmer/tabela 0.10.0 → 0.11.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.js +1 -0
- package/dist/components/row.component.js +11 -8
- package/dist/managers/column.manager.js +9 -8
- package/dist/managers/data.manager.js +26 -22
- package/dist/managers/event.manager.js +39 -23
- package/dist/managers/filter.manager.js +11 -10
- package/dist/managers/navigation.manager.js +73 -0
- package/dist/managers/render.manager.js +30 -25
- package/dist/managers/row.manager.js +7 -7
- package/dist/managers/selection.manager.js +19 -21
- package/dist/managers/sort.manager.js +9 -8
- package/dist/tabela.full.js +535 -410
- package/dist/tabela.js +27 -9
- package/package.json +1 -1
- package/src/components/body.component.ts +2 -0
- package/src/components/row.component.ts +14 -9
- package/src/managers/column.manager.ts +11 -13
- package/src/managers/data.manager.ts +31 -27
- package/src/managers/event.manager.ts +65 -42
- package/src/managers/filter.manager.ts +12 -11
- package/src/managers/navigation.manager.ts +145 -0
- package/src/managers/render.manager.ts +34 -28
- package/src/managers/row.manager.ts +9 -14
- package/src/managers/selection.manager.ts +24 -30
- package/src/managers/sort.manager.ts +14 -14
- package/src/models/render.model.ts +3 -1
- package/src/models/tabela.model.ts +12 -0
- package/src/tabela.ts +34 -9
- package/types/components/row.component.d.ts +2 -2
- package/types/managers/column.manager.d.ts +4 -5
- package/types/managers/data.manager.d.ts +5 -6
- package/types/managers/event.manager.d.ts +3 -6
- package/types/managers/filter.manager.d.ts +3 -3
- package/types/managers/navigation.manager.d.ts +10 -0
- package/types/managers/render.manager.d.ts +4 -6
- package/types/managers/row.manager.d.ts +4 -5
- package/types/managers/selection.manager.d.ts +3 -4
- package/types/managers/sort.manager.d.ts +4 -4
- package/types/models/render.model.d.ts +2 -1
- package/types/models/tabela.model.d.ts +11 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import {isNullableOrWhitespace} from '@oscarpalmer/atoms/is';
|
|
2
|
+
import type {Key} from '@oscarpalmer/atoms/models';
|
|
3
|
+
import {clamp} from '@oscarpalmer/atoms/number';
|
|
4
|
+
import {getKey} from '../helpers/misc.helpers';
|
|
5
|
+
import type {TabelaState} from '../models/tabela.model';
|
|
6
|
+
|
|
7
|
+
export class NavigationManager {
|
|
8
|
+
active: Key | undefined;
|
|
9
|
+
|
|
10
|
+
constructor(public state: TabelaState) {}
|
|
11
|
+
|
|
12
|
+
destroy(): void {
|
|
13
|
+
this.state = undefined as never;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
handle(event: KeyboardEvent): void {
|
|
17
|
+
if (!allKeys.has(event.key)) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
event.preventDefault();
|
|
22
|
+
|
|
23
|
+
const {components, id, managers} = this.state;
|
|
24
|
+
|
|
25
|
+
const activeDescendant = components.body.elements.group.getAttribute('aria-activedescendant');
|
|
26
|
+
|
|
27
|
+
const keys = managers.data.values.keys.active ?? managers.data.values.keys.original;
|
|
28
|
+
const {length} = keys;
|
|
29
|
+
|
|
30
|
+
let next: number;
|
|
31
|
+
|
|
32
|
+
if (isNullableOrWhitespace(activeDescendant)) {
|
|
33
|
+
next = getDefaultIndex(event.key, length);
|
|
34
|
+
} else {
|
|
35
|
+
next = getIndex(event, activeDescendant, id, keys)!;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (next != null) {
|
|
39
|
+
this.setActive(keys.at(next)!);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
setActive(key: Key | undefined, scroll?: boolean): void {
|
|
44
|
+
const {components, managers, options} = this.state;
|
|
45
|
+
|
|
46
|
+
this.active = key;
|
|
47
|
+
|
|
48
|
+
const active = components.body.elements.group.querySelectorAll('[data-active="true"]');
|
|
49
|
+
|
|
50
|
+
for (const item of active) {
|
|
51
|
+
item.setAttribute('data-active', 'false');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const row = managers.row.get(key!);
|
|
55
|
+
|
|
56
|
+
if (row != null) {
|
|
57
|
+
row.element?.setAttribute('data-active', 'true');
|
|
58
|
+
|
|
59
|
+
if (scroll ?? true) {
|
|
60
|
+
if (row.element == null) {
|
|
61
|
+
components.body.elements.group.scrollTo({
|
|
62
|
+
top: managers.data.getIndex(key!) * options.rowHeight,
|
|
63
|
+
behavior: 'smooth',
|
|
64
|
+
});
|
|
65
|
+
} else {
|
|
66
|
+
row.element.scrollIntoView({
|
|
67
|
+
block: 'nearest',
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
components.body.elements.group.setAttribute(
|
|
74
|
+
'aria-activedescendant',
|
|
75
|
+
row == null ? '' : `tabela_${this.state.id}_row_${key}`,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function getDefaultIndex(key: string, max: number): number {
|
|
81
|
+
switch (true) {
|
|
82
|
+
case negativeDefaultKeys.has(key):
|
|
83
|
+
return -1;
|
|
84
|
+
|
|
85
|
+
case key === 'PageDown':
|
|
86
|
+
return Math.min(9, max - 1);
|
|
87
|
+
|
|
88
|
+
case key === 'PageUp':
|
|
89
|
+
return max < 10 ? 0 : max - 10;
|
|
90
|
+
|
|
91
|
+
default:
|
|
92
|
+
return 0;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function getIndex(
|
|
97
|
+
event: KeyboardEvent,
|
|
98
|
+
active: string,
|
|
99
|
+
id: number,
|
|
100
|
+
keys: Key[],
|
|
101
|
+
): number | undefined {
|
|
102
|
+
const key = getKey(active.replace(`tabela_${id}_row_`, ''));
|
|
103
|
+
|
|
104
|
+
if (key == null) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (absoluteKeys.has(event.key)) {
|
|
109
|
+
return event.key === 'Home' ? 0 : keys.length - 1;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const index = keys.indexOf(key);
|
|
113
|
+
const offset = getOffset(event.key);
|
|
114
|
+
|
|
115
|
+
return clamp(index + offset, 0, keys.length - 1, true);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function getOffset(key: string): number {
|
|
119
|
+
switch (key) {
|
|
120
|
+
case 'ArrowDown':
|
|
121
|
+
return 1;
|
|
122
|
+
|
|
123
|
+
case 'ArrowUp':
|
|
124
|
+
return -1;
|
|
125
|
+
|
|
126
|
+
case 'PageDown':
|
|
127
|
+
return 10;
|
|
128
|
+
|
|
129
|
+
case 'PageUp':
|
|
130
|
+
return -10;
|
|
131
|
+
|
|
132
|
+
default:
|
|
133
|
+
return 0;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const absoluteKeys = new Set(['End', 'Home']);
|
|
138
|
+
|
|
139
|
+
const arrowKeys = new Set(['ArrowDown', 'ArrowUp']);
|
|
140
|
+
|
|
141
|
+
const negativeDefaultKeys = new Set(['ArrowUp', 'End']);
|
|
142
|
+
|
|
143
|
+
const pageKeys = new Set(['PageDown', 'PageUp']);
|
|
144
|
+
|
|
145
|
+
const allKeys = new Set([...absoluteKeys, ...arrowKeys, ...pageKeys]);
|
|
@@ -3,21 +3,21 @@ import {on} from '@oscarpalmer/toretto/event';
|
|
|
3
3
|
import type {RemovableEventListener} from '@oscarpalmer/toretto/models';
|
|
4
4
|
import {removeRow, renderRow} from '../components/row.component';
|
|
5
5
|
import type {RenderElementPool, RenderRange, RenderState} from '../models/render.model';
|
|
6
|
-
import type {
|
|
6
|
+
import type {TabelaState} from '../models/tabela.model';
|
|
7
7
|
|
|
8
8
|
function getRange(this: RenderManager, down: boolean): RenderRange {
|
|
9
|
-
const {components, managers} = this;
|
|
9
|
+
const {components, managers, options} = this.state;
|
|
10
10
|
const {clientHeight, scrollTop} = components.body.elements.group;
|
|
11
11
|
|
|
12
|
-
const first = Math.floor(scrollTop /
|
|
12
|
+
const first = Math.floor(scrollTop / options.rowHeight);
|
|
13
13
|
|
|
14
14
|
const last = Math.min(
|
|
15
15
|
(managers.data.values.keys.active?.length ?? managers.data.values.keys.original.length) - 1,
|
|
16
|
-
Math.ceil((scrollTop + clientHeight) /
|
|
16
|
+
Math.ceil((scrollTop + clientHeight) / options.rowHeight) - 1,
|
|
17
17
|
);
|
|
18
18
|
|
|
19
|
-
const before = Math.ceil(clientHeight /
|
|
20
|
-
const after = Math.ceil(clientHeight /
|
|
19
|
+
const before = Math.ceil(clientHeight / options.rowHeight) * (down ? 1 : 2);
|
|
20
|
+
const after = Math.ceil(clientHeight / options.rowHeight) * (down ? 2 : 1);
|
|
21
21
|
|
|
22
22
|
const start = Math.max(0, first - before);
|
|
23
23
|
|
|
@@ -30,17 +30,19 @@ function getRange(this: RenderManager, down: boolean): RenderRange {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
function onScroll(this: RenderManager): void {
|
|
33
|
-
|
|
33
|
+
const {state} = this;
|
|
34
|
+
|
|
35
|
+
if (!state.active) {
|
|
34
36
|
requestAnimationFrame(() => {
|
|
35
|
-
const top =
|
|
37
|
+
const top = state.components.body.elements.group.scrollTop;
|
|
36
38
|
|
|
37
|
-
this.update(top >
|
|
39
|
+
this.update(top > state.top);
|
|
38
40
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
state.active = false;
|
|
42
|
+
state.top = top;
|
|
41
43
|
});
|
|
42
44
|
|
|
43
|
-
|
|
45
|
+
state.active = true;
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
48
|
|
|
@@ -49,23 +51,23 @@ export class RenderManager {
|
|
|
49
51
|
|
|
50
52
|
listener: RemovableEventListener;
|
|
51
53
|
|
|
52
|
-
|
|
54
|
+
pool: RenderElementPool = {
|
|
53
55
|
cells: {},
|
|
54
56
|
rows: [],
|
|
55
57
|
};
|
|
56
58
|
|
|
57
|
-
|
|
58
|
-
active: false,
|
|
59
|
-
top: 0,
|
|
60
|
-
};
|
|
59
|
+
state: RenderState;
|
|
61
60
|
|
|
62
61
|
visible = new Map<number, Key>();
|
|
63
62
|
|
|
64
|
-
constructor(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
63
|
+
constructor(state: TabelaState) {
|
|
64
|
+
this.listener = on(state.components.body.elements.group, 'scroll', onScroll.bind(this));
|
|
65
|
+
|
|
66
|
+
this.state = {
|
|
67
|
+
...state,
|
|
68
|
+
active: false,
|
|
69
|
+
top: 0,
|
|
70
|
+
};
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
destroy(): void {
|
|
@@ -77,12 +79,15 @@ export class RenderManager {
|
|
|
77
79
|
pool.cells = {};
|
|
78
80
|
pool.rows = [];
|
|
79
81
|
|
|
82
|
+
this.fragment = undefined as never;
|
|
80
83
|
this.listener = undefined as never;
|
|
84
|
+
this.pool = undefined as never;
|
|
85
|
+
this.state = undefined as never;
|
|
81
86
|
this.visible = undefined as never;
|
|
82
87
|
}
|
|
83
88
|
|
|
84
89
|
removeCells(fields: string[]): void {
|
|
85
|
-
const {
|
|
90
|
+
const {pool, state, visible} = this;
|
|
86
91
|
const {length} = fields;
|
|
87
92
|
|
|
88
93
|
for (let index = 0; index < length; index += 1) {
|
|
@@ -90,7 +95,7 @@ export class RenderManager {
|
|
|
90
95
|
}
|
|
91
96
|
|
|
92
97
|
for (const [, key] of visible) {
|
|
93
|
-
const row = managers.row.get(key);
|
|
98
|
+
const row = state.managers.row.get(key);
|
|
94
99
|
|
|
95
100
|
if (row == null || row.element == null) {
|
|
96
101
|
continue;
|
|
@@ -115,9 +120,10 @@ export class RenderManager {
|
|
|
115
120
|
}
|
|
116
121
|
|
|
117
122
|
update(down: boolean, rerender?: boolean): void {
|
|
118
|
-
const {
|
|
123
|
+
const {state, pool, visible} = this;
|
|
124
|
+
const {components, managers, options} = state;
|
|
119
125
|
|
|
120
|
-
components.body.elements.faker.style.height = `${managers.data.size *
|
|
126
|
+
components.body.elements.faker.style.height = `${managers.data.size * options.rowHeight}px`;
|
|
121
127
|
|
|
122
128
|
const indices = new Set<number>();
|
|
123
129
|
const range = getRange.call(this, down);
|
|
@@ -160,12 +166,12 @@ export class RenderManager {
|
|
|
160
166
|
|
|
161
167
|
count += 1;
|
|
162
168
|
|
|
163
|
-
renderRow(
|
|
169
|
+
renderRow(state, row);
|
|
164
170
|
|
|
165
171
|
visible.set(index, key);
|
|
166
172
|
|
|
167
173
|
if (row.element != null) {
|
|
168
|
-
row.element.style.transform = `translateY(${index *
|
|
174
|
+
row.element.style.transform = `translateY(${index * options.rowHeight}px)`;
|
|
169
175
|
|
|
170
176
|
fragment.append(row.element);
|
|
171
177
|
}
|
|
@@ -1,29 +1,24 @@
|
|
|
1
1
|
import type {Key} from '@oscarpalmer/atoms/models';
|
|
2
2
|
import {removeRow, renderRow, RowComponent} from '../components/row.component';
|
|
3
|
-
import type {
|
|
3
|
+
import type {TabelaState} from '../models/tabela.model';
|
|
4
4
|
|
|
5
5
|
export class RowManager {
|
|
6
|
-
|
|
6
|
+
components = new Map<Key, RowComponent>();
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
constructor(
|
|
11
|
-
readonly managers: TabelaManagers,
|
|
12
|
-
rowHeight: number,
|
|
13
|
-
) {
|
|
14
|
-
this.height = rowHeight;
|
|
15
|
-
}
|
|
8
|
+
constructor(public state: TabelaState) {}
|
|
16
9
|
|
|
17
10
|
destroy(): void {
|
|
18
11
|
const components = [...this.components.values()];
|
|
19
|
-
|
|
20
12
|
const {length} = components;
|
|
21
13
|
|
|
22
14
|
for (let index = 0; index < length; index += 1) {
|
|
23
|
-
removeRow(this.managers.render.pool, components[index]);
|
|
15
|
+
removeRow(this.state.managers.render.pool, components[index]);
|
|
24
16
|
}
|
|
25
17
|
|
|
26
18
|
this.components.clear();
|
|
19
|
+
|
|
20
|
+
this.components = undefined as never;
|
|
21
|
+
this.state = undefined as never;
|
|
27
22
|
}
|
|
28
23
|
|
|
29
24
|
get(key: Key): RowComponent | undefined {
|
|
@@ -46,7 +41,7 @@ export class RowManager {
|
|
|
46
41
|
const row = this.components.get(key);
|
|
47
42
|
|
|
48
43
|
if (row != null) {
|
|
49
|
-
removeRow(this.managers.render.pool, row);
|
|
44
|
+
removeRow(this.state.managers.render.pool, row);
|
|
50
45
|
|
|
51
46
|
this.components.delete(key);
|
|
52
47
|
}
|
|
@@ -56,7 +51,7 @@ export class RowManager {
|
|
|
56
51
|
const row = this.components.get(key);
|
|
57
52
|
|
|
58
53
|
if (row != null) {
|
|
59
|
-
renderRow(this.
|
|
54
|
+
renderRow(this.state, row);
|
|
60
55
|
}
|
|
61
56
|
}
|
|
62
57
|
}
|
|
@@ -6,7 +6,7 @@ import {getPosition, on} from '@oscarpalmer/toretto/event';
|
|
|
6
6
|
import {createElement} from '../helpers/dom.helpers';
|
|
7
7
|
import {getKey} from '../helpers/misc.helpers';
|
|
8
8
|
import {dragStyling} from '../helpers/style.helper';
|
|
9
|
-
import type {
|
|
9
|
+
import type {TabelaSelection, TabelaState} from '../models/tabela.model';
|
|
10
10
|
|
|
11
11
|
export class SelectionManager {
|
|
12
12
|
handlers = Object.freeze({
|
|
@@ -20,11 +20,8 @@ export class SelectionManager {
|
|
|
20
20
|
|
|
21
21
|
last: Key | undefined;
|
|
22
22
|
|
|
23
|
-
constructor(
|
|
24
|
-
|
|
25
|
-
readonly managers: TabelaManagers,
|
|
26
|
-
) {
|
|
27
|
-
mapped.set(element, this);
|
|
23
|
+
constructor(public state: TabelaState) {
|
|
24
|
+
mapped.set(state.element, this);
|
|
28
25
|
}
|
|
29
26
|
|
|
30
27
|
clear(): void {
|
|
@@ -58,11 +55,12 @@ export class SelectionManager {
|
|
|
58
55
|
}
|
|
59
56
|
|
|
60
57
|
destroy(): void {
|
|
61
|
-
mapped.delete(this.element);
|
|
58
|
+
mapped.delete(this.state.element);
|
|
62
59
|
|
|
63
60
|
this.handlers = undefined as never;
|
|
64
|
-
this.element = undefined as never;
|
|
65
61
|
this.items = undefined as never;
|
|
62
|
+
this.last = undefined;
|
|
63
|
+
this.state = undefined as never;
|
|
66
64
|
}
|
|
67
65
|
|
|
68
66
|
handle(event: MouseEvent, target: HTMLElement): void {
|
|
@@ -76,20 +74,18 @@ export class SelectionManager {
|
|
|
76
74
|
|
|
77
75
|
if (event.shiftKey) {
|
|
78
76
|
if (this.last == null) {
|
|
79
|
-
this.
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
this.state.managers.navigation.setActive(key, false);
|
|
78
|
+
} else {
|
|
79
|
+
this.range(this.last, key);
|
|
82
80
|
}
|
|
83
81
|
|
|
84
|
-
this.range(this.last, key);
|
|
85
|
-
|
|
86
|
-
this.last = key;
|
|
87
|
-
|
|
88
82
|
return;
|
|
89
83
|
}
|
|
90
84
|
|
|
91
85
|
this.last = key;
|
|
92
86
|
|
|
87
|
+
this.state.managers.navigation.setActive(key, false);
|
|
88
|
+
|
|
93
89
|
if (event.ctrlKey || event.metaKey) {
|
|
94
90
|
if (items.has(key)) {
|
|
95
91
|
this.deselect([key]);
|
|
@@ -100,18 +96,12 @@ export class SelectionManager {
|
|
|
100
96
|
return;
|
|
101
97
|
}
|
|
102
98
|
|
|
103
|
-
|
|
104
|
-
if (items.size === 1) {
|
|
105
|
-
this.clear();
|
|
106
|
-
} else {
|
|
107
|
-
this.set([key]);
|
|
108
|
-
}
|
|
109
|
-
} else {
|
|
110
|
-
this.set([key]);
|
|
111
|
-
}
|
|
99
|
+
this.set([key]);
|
|
112
100
|
}
|
|
113
101
|
|
|
114
102
|
range(from: Key | HTMLElement, to: Key | HTMLElement): void {
|
|
103
|
+
const {state} = this;
|
|
104
|
+
|
|
115
105
|
const keyed = isKey(from) && isKey(to);
|
|
116
106
|
|
|
117
107
|
const fromKey = keyed ? (from as Key) : getKey((from as HTMLElement).getAttribute('data-key'))!;
|
|
@@ -121,10 +111,10 @@ export class SelectionManager {
|
|
|
121
111
|
return;
|
|
122
112
|
}
|
|
123
113
|
|
|
124
|
-
const keys =
|
|
114
|
+
const keys = state.managers.data.values.keys.active ?? state.managers.data.values.keys.original;
|
|
125
115
|
|
|
126
|
-
const fromIndex =
|
|
127
|
-
const toIndex =
|
|
116
|
+
const fromIndex = state.managers.data.getIndex(fromKey);
|
|
117
|
+
const toIndex = state.managers.data.getIndex(toKey);
|
|
128
118
|
|
|
129
119
|
if (fromIndex === -1 || toIndex === -1) {
|
|
130
120
|
return;
|
|
@@ -143,6 +133,10 @@ export class SelectionManager {
|
|
|
143
133
|
} else {
|
|
144
134
|
this.set(selected);
|
|
145
135
|
}
|
|
136
|
+
|
|
137
|
+
this.last = toKey;
|
|
138
|
+
|
|
139
|
+
this.state.managers.navigation.setActive(toKey, false);
|
|
146
140
|
}
|
|
147
141
|
|
|
148
142
|
select(keys: Key[]): void {
|
|
@@ -181,9 +175,9 @@ export class SelectionManager {
|
|
|
181
175
|
}
|
|
182
176
|
|
|
183
177
|
toggle(): void {
|
|
184
|
-
const {items,
|
|
178
|
+
const {items, state} = this;
|
|
185
179
|
|
|
186
|
-
const all = managers.data.values.keys.active ?? managers.data.values.keys.original;
|
|
180
|
+
const all = state.managers.data.values.keys.active ?? state.managers.data.values.keys.original;
|
|
187
181
|
|
|
188
182
|
if (items.size === all.length) {
|
|
189
183
|
this.clear();
|
|
@@ -203,7 +197,7 @@ export class SelectionManager {
|
|
|
203
197
|
for (let index = 0; index < length; index += 1) {
|
|
204
198
|
const {key, removed} = items[index];
|
|
205
199
|
|
|
206
|
-
const row = this.managers.row.get(key);
|
|
200
|
+
const row = this.state.managers.row.get(key);
|
|
207
201
|
|
|
208
202
|
if (row == null || row.element == null) {
|
|
209
203
|
continue;
|
|
@@ -2,7 +2,7 @@ import {sort, type ArrayKeySorter} from '@oscarpalmer/atoms/array';
|
|
|
2
2
|
import type {Key, PlainObject} from '@oscarpalmer/atoms/models';
|
|
3
3
|
import {setAttribute, setAttributes} from '@oscarpalmer/toretto/attribute';
|
|
4
4
|
import type {SortDirection, SortItem} from '../models/sort.model';
|
|
5
|
-
import type {
|
|
5
|
+
import type {TabelaSort, TabelaState} from '../models/tabela.model';
|
|
6
6
|
|
|
7
7
|
export class SortManager {
|
|
8
8
|
handlers = Object.freeze({
|
|
@@ -13,9 +13,9 @@ export class SortManager {
|
|
|
13
13
|
set: items => this.set(items),
|
|
14
14
|
} satisfies TabelaSort);
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
items: ArrayKeySorter<PlainObject>[] = [];
|
|
17
17
|
|
|
18
|
-
constructor(
|
|
18
|
+
constructor(public state: TabelaState) {}
|
|
19
19
|
|
|
20
20
|
add(field: string, direction?: SortDirection): void {
|
|
21
21
|
const index = this.items.findIndex(item => item.key === field);
|
|
@@ -50,7 +50,8 @@ export class SortManager {
|
|
|
50
50
|
|
|
51
51
|
destroy(): void {
|
|
52
52
|
this.handlers = undefined as never;
|
|
53
|
-
this.items
|
|
53
|
+
this.items = undefined as never;
|
|
54
|
+
this.state = undefined as never;
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
flip(field: string): void {
|
|
@@ -94,12 +95,12 @@ export class SortManager {
|
|
|
94
95
|
}
|
|
95
96
|
|
|
96
97
|
sort(): void {
|
|
97
|
-
const {items,
|
|
98
|
+
const {items, state} = this;
|
|
98
99
|
|
|
99
|
-
const {length} = managers.column.items;
|
|
100
|
+
const {length} = state.managers.column.items;
|
|
100
101
|
|
|
101
102
|
for (let index = 0; index < length; index += 1) {
|
|
102
|
-
const column = managers.column.items[index];
|
|
103
|
+
const column = state.managers.column.items[index];
|
|
103
104
|
|
|
104
105
|
const sorterIndex = items.findIndex(item => item.key === column.options.field);
|
|
105
106
|
const sorterItem = items[sorterIndex];
|
|
@@ -117,18 +118,17 @@ export class SortManager {
|
|
|
117
118
|
);
|
|
118
119
|
}
|
|
119
120
|
|
|
120
|
-
managers.data.values.keys.active =
|
|
121
|
+
state.managers.data.values.keys.active =
|
|
121
122
|
items.length === 0
|
|
122
123
|
? undefined
|
|
123
124
|
: (sort(
|
|
124
|
-
managers.data.values.keys.active?.map(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
managers.data.values.objects.array,
|
|
125
|
+
state.managers.data.values.keys.active?.map(
|
|
126
|
+
key => state.managers.data.values.objects.mapped.get(key)!,
|
|
127
|
+
) ?? state.managers.data.values.objects.array,
|
|
128
128
|
items,
|
|
129
|
-
).map(row => row[
|
|
129
|
+
).map(row => row[state.key]) as Key[]);
|
|
130
130
|
|
|
131
|
-
managers.render.update(true, true);
|
|
131
|
+
state.managers.render.update(true, true);
|
|
132
132
|
}
|
|
133
133
|
|
|
134
134
|
toggle(event: MouseEvent, field: string, direction?: string | null): void {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type {TabelaState} from './tabela.model';
|
|
2
|
+
|
|
1
3
|
export type RenderElementPool = {
|
|
2
4
|
cells: Record<string, HTMLDivElement[]>;
|
|
3
5
|
rows: HTMLDivElement[];
|
|
@@ -11,4 +13,4 @@ export type RenderRange = {
|
|
|
11
13
|
export type RenderState = {
|
|
12
14
|
active: boolean;
|
|
13
15
|
top: number;
|
|
14
|
-
};
|
|
16
|
+
} & TabelaState;
|
|
@@ -6,12 +6,14 @@ import type {ColumnManager} from '../managers/column.manager';
|
|
|
6
6
|
import type {DataManager} from '../managers/data.manager';
|
|
7
7
|
import type {EventManager} from '../managers/event.manager';
|
|
8
8
|
import type {FilterManager} from '../managers/filter.manager';
|
|
9
|
+
import type {NavigationManager} from '../managers/navigation.manager';
|
|
9
10
|
import type {RenderManager} from '../managers/render.manager';
|
|
10
11
|
import type {RowManager} from '../managers/row.manager';
|
|
11
12
|
import type {SelectionManager} from '../managers/selection.manager';
|
|
12
13
|
import type {SortManager} from '../managers/sort.manager';
|
|
13
14
|
import type {FilterItem} from './filter.model';
|
|
14
15
|
import type {SortDirection, SortItem} from './sort.model';
|
|
16
|
+
import type {TabelaOptions} from './tabela.options';
|
|
15
17
|
|
|
16
18
|
export type TabelaComponents = {
|
|
17
19
|
body: BodyComponent;
|
|
@@ -42,6 +44,7 @@ export type TabelaManagers = {
|
|
|
42
44
|
data: DataManager;
|
|
43
45
|
event: EventManager;
|
|
44
46
|
filter: FilterManager;
|
|
47
|
+
navigation: NavigationManager;
|
|
45
48
|
row: RowManager;
|
|
46
49
|
selection: SelectionManager;
|
|
47
50
|
sort: SortManager;
|
|
@@ -62,3 +65,12 @@ export type TabelaSort = {
|
|
|
62
65
|
remove(field: string): void;
|
|
63
66
|
set(items: SortItem[]): void;
|
|
64
67
|
};
|
|
68
|
+
|
|
69
|
+
export type TabelaState = {
|
|
70
|
+
readonly components: TabelaComponents;
|
|
71
|
+
readonly element: HTMLElement;
|
|
72
|
+
readonly id: number;
|
|
73
|
+
readonly key: string;
|
|
74
|
+
readonly managers: TabelaManagers;
|
|
75
|
+
readonly options: TabelaOptions;
|
|
76
|
+
};
|
package/src/tabela.ts
CHANGED
|
@@ -5,10 +5,11 @@ import {ColumnManager} from './managers/column.manager';
|
|
|
5
5
|
import {DataManager} from './managers/data.manager';
|
|
6
6
|
import {EventManager} from './managers/event.manager';
|
|
7
7
|
import {FilterManager} from './managers/filter.manager';
|
|
8
|
+
import {NavigationManager} from './managers/navigation.manager';
|
|
9
|
+
import {RenderManager} from './managers/render.manager';
|
|
8
10
|
import {RowManager} from './managers/row.manager';
|
|
9
11
|
import {SelectionManager} from './managers/selection.manager';
|
|
10
12
|
import {SortManager} from './managers/sort.manager';
|
|
11
|
-
import {RenderManager} from './managers/render.manager';
|
|
12
13
|
import type {
|
|
13
14
|
TabelaComponents,
|
|
14
15
|
TabelaData,
|
|
@@ -16,6 +17,7 @@ import type {
|
|
|
16
17
|
TabelaManagers,
|
|
17
18
|
TabelaSelection,
|
|
18
19
|
TabelaSort,
|
|
20
|
+
TabelaState,
|
|
19
21
|
} from './models/tabela.model';
|
|
20
22
|
import type {TabelaOptions} from './models/tabela.options';
|
|
21
23
|
|
|
@@ -28,6 +30,8 @@ export class Tabela {
|
|
|
28
30
|
|
|
29
31
|
#element: HTMLElement;
|
|
30
32
|
|
|
33
|
+
#id = getId();
|
|
34
|
+
|
|
31
35
|
readonly #key: string;
|
|
32
36
|
|
|
33
37
|
readonly #managers: TabelaManagers = {
|
|
@@ -35,6 +39,7 @@ export class Tabela {
|
|
|
35
39
|
data: undefined as never,
|
|
36
40
|
event: undefined as never,
|
|
37
41
|
filter: undefined as never,
|
|
42
|
+
navigation: undefined as never,
|
|
38
43
|
render: undefined as never,
|
|
39
44
|
row: undefined as never,
|
|
40
45
|
selection: undefined as never,
|
|
@@ -69,14 +74,24 @@ export class Tabela {
|
|
|
69
74
|
this.#components.body = new BodyComponent();
|
|
70
75
|
this.#components.footer = new FooterComponent();
|
|
71
76
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
const state: TabelaState = {
|
|
78
|
+
element,
|
|
79
|
+
options,
|
|
80
|
+
components: this.#components,
|
|
81
|
+
id: this.#id,
|
|
82
|
+
key: this.#key,
|
|
83
|
+
managers: this.#managers,
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
this.#managers.column = new ColumnManager(state);
|
|
87
|
+
this.#managers.data = new DataManager(state);
|
|
88
|
+
this.#managers.event = new EventManager(state);
|
|
89
|
+
this.#managers.filter = new FilterManager(state);
|
|
90
|
+
this.#managers.navigation = new NavigationManager(state);
|
|
91
|
+
this.#managers.render = new RenderManager(state);
|
|
92
|
+
this.#managers.row = new RowManager(state);
|
|
93
|
+
this.#managers.selection = new SelectionManager(state);
|
|
94
|
+
this.#managers.sort = new SortManager(state);
|
|
80
95
|
|
|
81
96
|
element.append(
|
|
82
97
|
this.#components.header.elements.group,
|
|
@@ -105,8 +120,10 @@ export class Tabela {
|
|
|
105
120
|
managers.data.destroy();
|
|
106
121
|
managers.event.destroy();
|
|
107
122
|
managers.filter.destroy();
|
|
123
|
+
// managers.navigation.destroy();
|
|
108
124
|
managers.render.destroy();
|
|
109
125
|
managers.row.destroy();
|
|
126
|
+
managers.selection.destroy();
|
|
110
127
|
managers.sort.destroy();
|
|
111
128
|
|
|
112
129
|
element.innerHTML = '';
|
|
@@ -119,3 +136,11 @@ export class Tabela {
|
|
|
119
136
|
this.#element = undefined as never;
|
|
120
137
|
}
|
|
121
138
|
}
|
|
139
|
+
|
|
140
|
+
function getId(): number {
|
|
141
|
+
id += 1;
|
|
142
|
+
|
|
143
|
+
return id;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
let id = 0;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { Key } from '@oscarpalmer/atoms/models';
|
|
2
2
|
import type { RenderElementPool } from '../models/render.model';
|
|
3
|
-
import type {
|
|
3
|
+
import type { TabelaState } from '../models/tabela.model';
|
|
4
4
|
export declare function removeRow(pool: RenderElementPool, row: RowComponent): void;
|
|
5
|
-
export declare function renderRow(
|
|
5
|
+
export declare function renderRow(state: TabelaState, row: RowComponent): void;
|
|
6
6
|
export declare class RowComponent {
|
|
7
7
|
readonly key: Key;
|
|
8
8
|
cells: Record<string, HTMLDivElement>;
|