@oscarpalmer/tabela 0.13.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 +10 -1
- package/dist/components/body.component.mjs +8 -6
- package/dist/components/column.component.d.mts +15 -1
- package/dist/components/column.component.mjs +12 -10
- package/dist/components/footer.component.d.mts +12 -1
- package/dist/components/footer.component.mjs +6 -6
- package/dist/components/group.component.d.mts +19 -1
- package/dist/components/group.component.mjs +17 -11
- package/dist/components/header.component.d.mts +12 -1
- package/dist/components/header.component.mjs +5 -5
- package/dist/components/row.component.d.mts +14 -1
- package/dist/components/row.component.mjs +21 -17
- package/dist/helpers/dom.helpers.d.mts +3 -3
- package/dist/helpers/dom.helpers.mjs +12 -11
- package/dist/helpers/misc.helpers.d.mts +7 -1
- package/dist/helpers/misc.helpers.mjs +12 -1
- package/dist/index.d.mts +1 -1
- package/dist/managers/column.manager.d.mts +16 -1
- package/dist/managers/column.manager.mjs +7 -7
- package/dist/managers/data.manager.d.mts +26 -1
- package/dist/managers/data.manager.mjs +122 -88
- package/dist/managers/event.manager.d.mts +17 -1
- package/dist/managers/event.manager.mjs +35 -10
- package/dist/managers/filter.manager.d.mts +17 -1
- package/dist/managers/filter.manager.mjs +43 -35
- package/dist/managers/group.manager.d.mts +26 -1
- package/dist/managers/group.manager.mjs +36 -16
- package/dist/managers/navigation.manager.d.mts +15 -2
- package/dist/managers/navigation.manager.mjs +38 -34
- package/dist/managers/render.manager.d.mts +18 -1
- package/dist/managers/render.manager.mjs +44 -31
- package/dist/managers/row.manager.d.mts +18 -1
- package/dist/managers/row.manager.mjs +1 -1
- package/dist/managers/selection.manager.d.mts +22 -1
- package/dist/managers/selection.manager.mjs +26 -23
- package/dist/managers/sort.manager.d.mts +22 -1
- package/dist/managers/sort.manager.mjs +71 -49
- package/dist/managers/style.manager.d.mts +8 -1
- package/dist/managers/style.manager.mjs +57 -25
- package/dist/models/body.model.d.mts +6 -1
- package/dist/models/column.model.d.mts +13 -2
- package/dist/models/data.model.d.mts +28 -2
- 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 -2
- package/dist/models/filter.model.mjs +13 -1
- package/dist/models/footer.model.d.mts +7 -1
- package/dist/models/group.model.d.mts +19 -2
- package/dist/models/group.model.mjs +5 -1
- package/dist/models/header.model.d.mts +6 -1
- package/dist/models/render.model.d.mts +22 -2
- package/dist/models/selection.model.d.mts +11 -1
- package/dist/models/sort.model.d.mts +19 -2
- package/dist/models/sort.model.mjs +5 -1
- package/dist/models/style.model.d.mts +27 -21
- package/dist/models/style.model.mjs +27 -21
- package/dist/models/tabela.model.d.mts +45 -1
- package/dist/models/tabela.options.d.mts +13 -1
- package/dist/tabela.d.mts +9 -8
- package/dist/tabela.full.mjs +1083 -574
- package/dist/tabela.mjs +19 -19
- package/package.json +2 -4
- package/src/components/body.component.ts +10 -7
- package/src/components/column.component.ts +20 -16
- package/src/components/footer.component.ts +7 -10
- package/src/components/group.component.ts +39 -13
- 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 +17 -0
- package/src/managers/column.manager.ts +9 -9
- package/src/managers/data.manager.ts +196 -107
- package/src/managers/event.manager.ts +69 -12
- package/src/managers/filter.manager.ts +70 -41
- package/src/managers/group.manager.ts +60 -18
- package/src/managers/navigation.manager.ts +46 -49
- package/src/managers/render.manager.ts +60 -34
- package/src/managers/row.manager.ts +1 -1
- package/src/managers/selection.manager.ts +37 -35
- package/src/managers/sort.manager.ts +114 -72
- package/src/managers/style.manager.ts +73 -25
- package/src/models/column.model.ts +4 -8
- package/src/models/data.model.ts +13 -14
- package/src/models/dom.model.ts +31 -0
- package/src/models/event.model.ts +175 -0
- package/src/models/filter.model.ts +22 -2
- package/src/models/group.model.ts +13 -0
- package/src/models/render.model.ts +6 -0
- package/src/models/sort.model.ts +11 -5
- package/src/models/style.model.ts +32 -20
- package/src/models/tabela.model.ts +1 -0
- package/src/tabela.ts +26 -24
- 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/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/selection.model-rwQe9fco.d.mts +0 -12
- package/dist/sort.model-CauImaLu.d.mts +0 -15
- package/dist/tabela.options-RkZvfptB.d.mts +0 -14
|
@@ -1,46 +1,67 @@
|
|
|
1
|
+
import type {Key} from '@oscarpalmer/atoms/models';
|
|
1
2
|
import {getNumber} from '@oscarpalmer/atoms/number';
|
|
2
3
|
import {getString} from '@oscarpalmer/atoms/string';
|
|
3
4
|
import {endsWith, includes, startsWith} from '@oscarpalmer/atoms/string/match';
|
|
4
5
|
import {equal} from '@oscarpalmer/atoms/value/equal';
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
|
|
6
|
+
import {isGroupKey} from '../helpers/misc.helpers';
|
|
7
|
+
import {
|
|
8
|
+
FILTER_CONTAINS,
|
|
9
|
+
FILTER_ENDS_WITH,
|
|
10
|
+
FILTER_EQUALS,
|
|
11
|
+
FILTER_GREATER_THAN,
|
|
12
|
+
FILTER_GREATER_THAN_OR_EQUAL,
|
|
13
|
+
FILTER_LESS_THAN,
|
|
14
|
+
FILTER_LESS_THAN_OR_EQUAL,
|
|
15
|
+
FILTER_NOT_CONTAINS,
|
|
16
|
+
FILTER_NOT_EQUALS,
|
|
17
|
+
FILTER_STARTS_WITH,
|
|
18
|
+
type TabelaFilter,
|
|
19
|
+
type TabelaFilterItem,
|
|
20
|
+
} from '../models/filter.model';
|
|
8
21
|
import type {State} from '../models/tabela.model';
|
|
9
22
|
|
|
10
23
|
export class FilterManager {
|
|
11
|
-
handlers =
|
|
24
|
+
handlers: TabelaFilter = {
|
|
12
25
|
add: item => this.add(item),
|
|
13
26
|
clear: () => this.clear(),
|
|
14
27
|
remove: value => this.remove(value),
|
|
15
28
|
set: items => this.set(items),
|
|
16
|
-
}
|
|
29
|
+
};
|
|
17
30
|
|
|
18
31
|
items: Record<string, TabelaFilterItem[]> = {};
|
|
19
32
|
|
|
20
33
|
constructor(public state: State) {}
|
|
21
34
|
|
|
22
35
|
add(item: TabelaFilterItem): void {
|
|
23
|
-
|
|
24
|
-
|
|
36
|
+
const {items, state} = this;
|
|
37
|
+
|
|
38
|
+
if (items[item.key] == null) {
|
|
39
|
+
items[item.key] = [];
|
|
25
40
|
} else {
|
|
26
|
-
const index =
|
|
41
|
+
const index = items[item.key].findIndex(existing => equal(existing, item));
|
|
27
42
|
|
|
28
43
|
if (index > -1) {
|
|
29
44
|
return;
|
|
30
45
|
}
|
|
31
46
|
}
|
|
32
47
|
|
|
33
|
-
|
|
48
|
+
items[item.key].push(item);
|
|
49
|
+
|
|
50
|
+
state.managers.event.emit('filter:add', [item]);
|
|
34
51
|
|
|
35
52
|
this.filter();
|
|
36
53
|
}
|
|
37
54
|
|
|
38
55
|
clear(): void {
|
|
39
|
-
if (Object.keys(this.items).length
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
this.filter();
|
|
56
|
+
if (Object.keys(this.items).length === 0) {
|
|
57
|
+
return;
|
|
43
58
|
}
|
|
59
|
+
|
|
60
|
+
this.items = {};
|
|
61
|
+
|
|
62
|
+
this.state.managers.event.emit('filter:clear');
|
|
63
|
+
|
|
64
|
+
this.filter();
|
|
44
65
|
}
|
|
45
66
|
|
|
46
67
|
destroy(): void {
|
|
@@ -52,15 +73,15 @@ export class FilterManager {
|
|
|
52
73
|
filter(): void {
|
|
53
74
|
const {state} = this;
|
|
54
75
|
|
|
55
|
-
const filtered:
|
|
76
|
+
const filtered: Key[] = [];
|
|
56
77
|
const filters = Object.entries(this.items);
|
|
57
78
|
|
|
58
|
-
const itemsLength = state.managers.data.state.
|
|
79
|
+
const itemsLength = state.managers.data.state.keys.original.length;
|
|
59
80
|
|
|
60
81
|
rowLoop: for (let itemIndex = 0; itemIndex < itemsLength; itemIndex += 1) {
|
|
61
|
-
const item = state.managers.data.state.
|
|
82
|
+
const item = state.managers.data.state.keys.original[itemIndex];
|
|
62
83
|
|
|
63
|
-
if (item
|
|
84
|
+
if (isGroupKey(item)) {
|
|
64
85
|
filtered.push(item);
|
|
65
86
|
|
|
66
87
|
continue;
|
|
@@ -73,9 +94,9 @@ export class FilterManager {
|
|
|
73
94
|
}
|
|
74
95
|
|
|
75
96
|
filterLoop: for (let filterIndex = 0; filterIndex < filters.length; filterIndex += 1) {
|
|
76
|
-
const [
|
|
97
|
+
const [key, items] = filters[filterIndex];
|
|
77
98
|
|
|
78
|
-
const value = row[
|
|
99
|
+
const value = row[key];
|
|
79
100
|
|
|
80
101
|
for (let itemIndex = 0; itemIndex < items.length; itemIndex += 1) {
|
|
81
102
|
const filter = items[itemIndex];
|
|
@@ -91,7 +112,7 @@ export class FilterManager {
|
|
|
91
112
|
filtered.push(item);
|
|
92
113
|
}
|
|
93
114
|
|
|
94
|
-
state.managers.data.state.
|
|
115
|
+
state.managers.data.state.keys.active = filtered;
|
|
95
116
|
|
|
96
117
|
if (state.managers.sort.items.length > 0) {
|
|
97
118
|
state.managers.sort.sort();
|
|
@@ -101,6 +122,8 @@ export class FilterManager {
|
|
|
101
122
|
}
|
|
102
123
|
|
|
103
124
|
remove(value: string | TabelaFilterItem): void {
|
|
125
|
+
const removed: TabelaFilterItem[] = [];
|
|
126
|
+
|
|
104
127
|
if (typeof value === 'string') {
|
|
105
128
|
if (this.items[value] == null) {
|
|
106
129
|
return;
|
|
@@ -108,32 +131,38 @@ export class FilterManager {
|
|
|
108
131
|
|
|
109
132
|
const keyed: Record<string, TabelaFilterItem[]> = {};
|
|
110
133
|
|
|
111
|
-
const
|
|
112
|
-
const {length} =
|
|
134
|
+
const keys = Object.keys(this.items);
|
|
135
|
+
const {length} = keys;
|
|
113
136
|
|
|
114
137
|
for (let index = 0; index < length; index += 1) {
|
|
115
|
-
const
|
|
138
|
+
const key = keys[index];
|
|
116
139
|
|
|
117
|
-
if (
|
|
118
|
-
|
|
140
|
+
if (key === value) {
|
|
141
|
+
removed.push(...this.items[key]);
|
|
142
|
+
} else {
|
|
143
|
+
keyed[key] = this.items[key];
|
|
119
144
|
}
|
|
120
145
|
}
|
|
121
146
|
|
|
122
147
|
this.items = keyed;
|
|
123
148
|
} else {
|
|
124
|
-
const {
|
|
149
|
+
const {key} = value;
|
|
125
150
|
|
|
126
|
-
if (this.items[
|
|
151
|
+
if (this.items[key] == null) {
|
|
127
152
|
return;
|
|
128
153
|
}
|
|
129
154
|
|
|
130
|
-
const index = this.items[
|
|
155
|
+
const index = this.items[key].findIndex(item => equal(item, value));
|
|
131
156
|
|
|
132
157
|
if (index === -1) {
|
|
133
158
|
return;
|
|
134
159
|
}
|
|
160
|
+
|
|
161
|
+
removed.push(this.items[key][index]);
|
|
135
162
|
}
|
|
136
163
|
|
|
164
|
+
this.state.managers.event.emit('filter:remove', removed);
|
|
165
|
+
|
|
137
166
|
this.filter();
|
|
138
167
|
}
|
|
139
168
|
|
|
@@ -145,9 +174,9 @@ export class FilterManager {
|
|
|
145
174
|
for (let index = 0; index < length; index += 1) {
|
|
146
175
|
const item = items[index];
|
|
147
176
|
|
|
148
|
-
keyed[item.
|
|
177
|
+
keyed[item.key] ??= [];
|
|
149
178
|
|
|
150
|
-
keyed[item.
|
|
179
|
+
keyed[item.key].push(item);
|
|
151
180
|
}
|
|
152
181
|
|
|
153
182
|
this.items = keyed;
|
|
@@ -156,17 +185,17 @@ export class FilterManager {
|
|
|
156
185
|
}
|
|
157
186
|
}
|
|
158
187
|
|
|
159
|
-
const comparators: Record<
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
188
|
+
const comparators: Record<string, (row: unknown, filter: unknown) => boolean> = {
|
|
189
|
+
[FILTER_CONTAINS]: (row, filter) => includes(getString(row), getString(filter), true),
|
|
190
|
+
[FILTER_ENDS_WITH]: (row, filter) => endsWith(getString(row), getString(filter), true),
|
|
191
|
+
[FILTER_EQUALS]: (row, filter) => equalizer(row, filter),
|
|
192
|
+
[FILTER_GREATER_THAN]: (row, filter) => getNumber(row) > getNumber(filter),
|
|
193
|
+
[FILTER_GREATER_THAN_OR_EQUAL]: (row, filter) => getNumber(row) >= getNumber(filter),
|
|
194
|
+
[FILTER_LESS_THAN]: (row, filter) => getNumber(row) < getNumber(filter),
|
|
195
|
+
[FILTER_LESS_THAN_OR_EQUAL]: (row, filter) => getNumber(row) <= getNumber(filter),
|
|
196
|
+
[FILTER_NOT_CONTAINS]: (row, filter) => !includes(getString(row), getString(filter), true),
|
|
197
|
+
[FILTER_NOT_EQUALS]: (row, filter) => !equalizer(row, filter),
|
|
198
|
+
[FILTER_STARTS_WITH]: (row, filter) => startsWith(getString(row), getString(filter), true),
|
|
170
199
|
};
|
|
171
200
|
|
|
172
201
|
const equalizer = equal.initialize({
|
|
@@ -1,34 +1,45 @@
|
|
|
1
1
|
import {sort} from '@oscarpalmer/atoms/array';
|
|
2
|
+
import {toMap} from '@oscarpalmer/atoms/array/to-map';
|
|
2
3
|
import {toRecord} from '@oscarpalmer/atoms/array/to-record';
|
|
3
4
|
import {isNullableOrWhitespace} from '@oscarpalmer/atoms/is';
|
|
4
5
|
import type {Key, Simplify} from '@oscarpalmer/atoms/models';
|
|
5
6
|
import {getString} from '@oscarpalmer/atoms/string';
|
|
6
7
|
import {removeGroup, type GroupComponent} from '../components/group.component';
|
|
7
|
-
import
|
|
8
|
+
import {
|
|
9
|
+
EVENT_GROUP_ADD,
|
|
10
|
+
EVENT_GROUP_CLEAR,
|
|
11
|
+
EVENT_GROUP_REMOVE,
|
|
12
|
+
EVENT_GROUP_TOGGLE,
|
|
13
|
+
} from '../models/event.model';
|
|
14
|
+
import type {TabelaGroupHandlers, TabelaGroupToggle} from '../models/group.model';
|
|
8
15
|
import type {State} from '../models/tabela.model';
|
|
16
|
+
import {compare} from '@oscarpalmer/atoms/value/compare';
|
|
17
|
+
import {getGroup} from '../helpers/misc.helpers';
|
|
9
18
|
|
|
10
19
|
export class GroupManager {
|
|
11
20
|
collapsed = new Set<Key>();
|
|
12
21
|
|
|
13
22
|
enabled = false;
|
|
14
23
|
|
|
15
|
-
|
|
24
|
+
key!: string;
|
|
16
25
|
|
|
17
|
-
handlers =
|
|
26
|
+
handlers: TabelaGroupHandlers = {
|
|
18
27
|
set: (group?: string) => {
|
|
19
|
-
if (group === this.
|
|
28
|
+
if (group === this.key) {
|
|
20
29
|
return;
|
|
21
30
|
}
|
|
22
31
|
|
|
23
32
|
this.enabled = !isNullableOrWhitespace(group);
|
|
24
|
-
this.
|
|
33
|
+
this.key = group ?? '';
|
|
25
34
|
|
|
26
35
|
this.state.managers.data.set(this.state.managers.data.get());
|
|
27
36
|
},
|
|
28
|
-
}
|
|
37
|
+
};
|
|
29
38
|
|
|
30
39
|
items: GroupComponent[] = [];
|
|
31
40
|
|
|
41
|
+
mapped = new Map<string, GroupComponent>();
|
|
42
|
+
|
|
32
43
|
order: Record<never, number> = {};
|
|
33
44
|
|
|
34
45
|
constructor(public state: State) {
|
|
@@ -37,20 +48,34 @@ export class GroupManager {
|
|
|
37
48
|
}
|
|
38
49
|
|
|
39
50
|
this.enabled = true;
|
|
40
|
-
this.
|
|
51
|
+
this.key = state.options.grouping;
|
|
41
52
|
}
|
|
42
53
|
|
|
43
|
-
add(group: GroupComponent): void {
|
|
54
|
+
add(group: GroupComponent, emit: boolean): void {
|
|
44
55
|
this.set([...this.items, group]);
|
|
56
|
+
|
|
57
|
+
if (emit) {
|
|
58
|
+
this.state.managers.event.emit(EVENT_GROUP_ADD, [getGroup(group)]);
|
|
59
|
+
}
|
|
45
60
|
}
|
|
46
61
|
|
|
47
62
|
clear(): void {
|
|
63
|
+
if (this.items.length === 0) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
48
67
|
const groups = this.items.splice(0);
|
|
49
68
|
const {length} = groups;
|
|
50
69
|
|
|
51
70
|
for (let index = 0; index < length; index += 1) {
|
|
52
|
-
this.remove(groups[index]);
|
|
71
|
+
this.remove(groups[index], false);
|
|
53
72
|
}
|
|
73
|
+
|
|
74
|
+
this.collapsed.clear();
|
|
75
|
+
|
|
76
|
+
this.set([]);
|
|
77
|
+
|
|
78
|
+
this.state.managers.event.emit(EVENT_GROUP_CLEAR);
|
|
54
79
|
}
|
|
55
80
|
|
|
56
81
|
destroy(): void {
|
|
@@ -67,15 +92,19 @@ export class GroupManager {
|
|
|
67
92
|
this.state = undefined as never;
|
|
68
93
|
}
|
|
69
94
|
|
|
70
|
-
|
|
95
|
+
getForKey(key: string): GroupComponent | undefined {
|
|
96
|
+
return this.mapped.get(key);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
getForValue(value: unknown): GroupComponent | undefined {
|
|
71
100
|
const asString = getString(value);
|
|
72
101
|
|
|
73
102
|
return this.items.find(item => item.value.stringified === asString);
|
|
74
103
|
}
|
|
75
104
|
|
|
76
105
|
handle(button: HTMLElement): void {
|
|
77
|
-
const
|
|
78
|
-
const group = this.
|
|
106
|
+
const key = button.dataset.key?.replace(`${this.state.prefix}_`, '');
|
|
107
|
+
const group = this.getForKey(key ?? '');
|
|
79
108
|
|
|
80
109
|
if (group == null) {
|
|
81
110
|
return;
|
|
@@ -87,15 +116,15 @@ export class GroupManager {
|
|
|
87
116
|
|
|
88
117
|
const index = items.indexOf(group);
|
|
89
118
|
|
|
90
|
-
let first = state.managers.data.state.
|
|
119
|
+
let first = state.managers.data.state.keys.original.indexOf(group.key) + 1;
|
|
91
120
|
|
|
92
121
|
const last =
|
|
93
122
|
items[index + 1] == null
|
|
94
|
-
? state.managers.data.state.
|
|
95
|
-
: state.managers.data.state.
|
|
123
|
+
? state.managers.data.state.keys.original.length - 1
|
|
124
|
+
: state.managers.data.state.keys.original.indexOf(items[index + 1].key) - 1;
|
|
96
125
|
|
|
97
126
|
for (; first <= last; first += 1) {
|
|
98
|
-
const key = state.managers.data.state.
|
|
127
|
+
const key = state.managers.data.state.keys.original[first] as Key;
|
|
99
128
|
|
|
100
129
|
if (group.expanded) {
|
|
101
130
|
collapsed.delete(key);
|
|
@@ -104,6 +133,11 @@ export class GroupManager {
|
|
|
104
133
|
}
|
|
105
134
|
}
|
|
106
135
|
|
|
136
|
+
state.managers.event.emit(EVENT_GROUP_TOGGLE, {
|
|
137
|
+
collapsed: group.expanded ? [] : [getGroup(group)],
|
|
138
|
+
expanded: group.expanded ? [getGroup(group)] : [],
|
|
139
|
+
});
|
|
140
|
+
|
|
107
141
|
if (Object.keys(state.managers.filter.items).length > 0) {
|
|
108
142
|
state.managers.filter.filter();
|
|
109
143
|
} else if (state.managers.sort.items.length > 0) {
|
|
@@ -113,14 +147,22 @@ export class GroupManager {
|
|
|
113
147
|
}
|
|
114
148
|
}
|
|
115
149
|
|
|
116
|
-
remove(group: GroupComponent): void {
|
|
150
|
+
remove(group: GroupComponent, update: boolean): void {
|
|
117
151
|
removeGroup(group);
|
|
118
152
|
|
|
153
|
+
if (!update) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
119
157
|
this.set(this.items.filter(item => item !== group));
|
|
158
|
+
|
|
159
|
+
this.state.managers.event.emit(EVENT_GROUP_REMOVE, [getGroup(group)]);
|
|
120
160
|
}
|
|
121
161
|
|
|
122
162
|
set(items: GroupComponent[]) {
|
|
123
|
-
this.items = sort(items,
|
|
163
|
+
this.items = sort(items, (first, second) => compare(first.label, second.label));
|
|
164
|
+
|
|
165
|
+
this.mapped = toMap(items, group => group.key);
|
|
124
166
|
|
|
125
167
|
this.order = toRecord(
|
|
126
168
|
items as Simplify<GroupComponent>[],
|
|
@@ -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]);
|