@oscarpalmer/tabela 0.12.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/tabela.full.js +146 -18
- package/package.json +45 -37
- package/src/components/body.component.ts +11 -7
- package/src/components/column.component.ts +23 -24
- package/src/components/footer.component.ts +7 -5
- package/src/components/group.component.ts +73 -9
- package/src/components/header.component.ts +6 -4
- package/src/components/row.component.ts +28 -18
- package/src/helpers/dom.helpers.ts +27 -29
- package/src/helpers/misc.helpers.ts +5 -0
- package/src/helpers/style.helper.ts +1 -1
- package/src/managers/column.manager.ts +4 -0
- package/src/managers/data.manager.ts +197 -124
- package/src/managers/event.manager.ts +27 -17
- package/src/managers/filter.manager.ts +49 -25
- package/src/managers/group.manager.ts +73 -12
- package/src/managers/navigation.manager.ts +48 -50
- package/src/managers/render.manager.ts +56 -29
- package/src/managers/row.manager.ts +22 -10
- package/src/managers/selection.manager.ts +40 -31
- package/src/managers/sort.manager.ts +58 -43
- package/src/managers/style.manager.ts +171 -0
- package/src/models/column.model.ts +2 -6
- package/src/models/data.model.ts +12 -10
- 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 +10 -2
- package/src/models/sort.model.ts +4 -0
- package/src/models/style.model.ts +51 -0
- package/src/models/tabela.model.ts +11 -8
- package/src/tabela.ts +67 -37
- package/types/components/body.component.d.ts +0 -6
- package/types/components/column.component.d.ts +0 -13
- package/types/components/footer.component.d.ts +0 -8
- package/types/components/group.component.d.ts +0 -14
- package/types/components/header.component.d.ts +0 -8
- package/types/components/row.component.d.ts +0 -11
- package/types/helpers/dom.helpers.d.ts +0 -10
- package/types/helpers/misc.helpers.d.ts +0 -2
- package/types/helpers/style.helper.d.ts +0 -1
- package/types/index.d.ts +0 -4
- package/types/managers/column.manager.d.ts +0 -12
- package/types/managers/data.manager.d.ts +0 -29
- package/types/managers/event.manager.d.ts +0 -7
- package/types/managers/filter.manager.d.ts +0 -19
- package/types/managers/group.manager.d.ts +0 -17
- package/types/managers/navigation.manager.d.ts +0 -10
- package/types/managers/render.manager.d.ts +0 -17
- package/types/managers/row.manager.d.ts +0 -13
- package/types/managers/selection.manager.d.ts +0 -24
- package/types/managers/sort.manager.d.ts +0 -28
- package/types/models/body.model.d.ts +0 -4
- package/types/models/column.model.d.ts +0 -13
- package/types/models/data.model.d.ts +0 -24
- package/types/models/filter.model.d.ts +0 -13
- package/types/models/footer.model.d.ts +0 -5
- package/types/models/group.model.d.ts +0 -4
- package/types/models/header.model.d.ts +0 -4
- package/types/models/render.model.d.ts +0 -13
- package/types/models/selection.model.d.ts +0 -8
- package/types/models/sort.model.d.ts +0 -12
- package/types/models/tabela.model.d.ts +0 -39
- package/types/models/tabela.options.d.ts +0 -10
- package/types/tabela.d.ts +0 -15
|
@@ -5,20 +5,21 @@ 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
7
|
import {createElement} from '../helpers/dom.helpers';
|
|
8
|
-
import {getKey} from '../helpers/misc.helpers';
|
|
9
|
-
import {
|
|
8
|
+
import {getKey, isGroupKey} from '../helpers/misc.helpers';
|
|
9
|
+
import {preventSelection} from '../helpers/style.helper';
|
|
10
|
+
import {ARIA_SELECTED, ATTRIBUTE_DATA_KEY, ELEMENT_DIV} from '../models/dom.model';
|
|
10
11
|
import type {TabelaSelection} from '../models/selection.model';
|
|
12
|
+
import {CSS_ROW_BODY, CSS_ROW_SELECTED, CSS_SELECTION, CSS_TABLE} from '../models/style.model';
|
|
11
13
|
import type {State} from '../models/tabela.model';
|
|
12
|
-
import {GroupComponent} from '../components/group.component';
|
|
13
14
|
|
|
14
15
|
export class SelectionManager {
|
|
15
|
-
handlers =
|
|
16
|
+
handlers: TabelaSelection = {
|
|
16
17
|
add: keys => this.add(keys),
|
|
17
18
|
clear: () => this.clear(),
|
|
18
19
|
remove: keys => this.remove(keys),
|
|
19
20
|
set: keys => this.set(keys),
|
|
20
21
|
toggle: () => this.toggle(),
|
|
21
|
-
}
|
|
22
|
+
};
|
|
22
23
|
|
|
23
24
|
items = new Set<Key>();
|
|
24
25
|
|
|
@@ -70,7 +71,7 @@ export class SelectionManager {
|
|
|
70
71
|
}
|
|
71
72
|
|
|
72
73
|
handle(event: MouseEvent, target: HTMLElement): void {
|
|
73
|
-
const key = getKey(target.getAttribute(
|
|
74
|
+
const key = getKey(target.getAttribute(ATTRIBUTE_DATA_KEY));
|
|
74
75
|
|
|
75
76
|
if (key == null) {
|
|
76
77
|
return;
|
|
@@ -110,8 +111,13 @@ export class SelectionManager {
|
|
|
110
111
|
|
|
111
112
|
const keyed = isKey(from) && isKey(to);
|
|
112
113
|
|
|
113
|
-
const fromKey = keyed
|
|
114
|
-
|
|
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))!;
|
|
115
121
|
|
|
116
122
|
if (fromKey === toKey) {
|
|
117
123
|
return;
|
|
@@ -133,7 +139,7 @@ export class SelectionManager {
|
|
|
133
139
|
for (let index = start; index <= end; index += 1) {
|
|
134
140
|
const key = keys[index];
|
|
135
141
|
|
|
136
|
-
if (!(key
|
|
142
|
+
if (!isGroupKey(key)) {
|
|
137
143
|
selected.push(key);
|
|
138
144
|
}
|
|
139
145
|
}
|
|
@@ -189,54 +195,51 @@ export class SelectionManager {
|
|
|
189
195
|
if (items.size === keys.length - state.managers.group.items.length) {
|
|
190
196
|
this.clear();
|
|
191
197
|
} else {
|
|
192
|
-
this.set(keys.filter(key => !(key
|
|
198
|
+
this.set(keys.filter(key => !isGroupKey(key)));
|
|
193
199
|
}
|
|
194
200
|
}
|
|
195
201
|
|
|
196
202
|
update(removed: Key[]): void {
|
|
203
|
+
const {state} = this;
|
|
204
|
+
|
|
197
205
|
const items = [
|
|
198
206
|
...removed.map(key => ({key, removed: true})),
|
|
199
207
|
...[...this.items].map(key => ({key, removed: false})),
|
|
200
208
|
];
|
|
201
209
|
|
|
202
|
-
|
|
210
|
+
let {length} = items;
|
|
203
211
|
|
|
204
212
|
for (let index = 0; index < length; index += 1) {
|
|
205
213
|
const {key, removed} = items[index];
|
|
206
214
|
|
|
207
|
-
const
|
|
215
|
+
const element = state.managers.row.get(key, false)?.element;
|
|
208
216
|
|
|
209
|
-
if (
|
|
217
|
+
if (element == null) {
|
|
210
218
|
continue;
|
|
211
219
|
}
|
|
212
220
|
|
|
213
|
-
setAttribute(
|
|
221
|
+
setAttribute(element, ARIA_SELECTED, String(!removed));
|
|
214
222
|
|
|
215
223
|
if (removed) {
|
|
216
|
-
|
|
224
|
+
element.classList.remove(CSS_ROW_SELECTED);
|
|
217
225
|
} else {
|
|
218
|
-
|
|
226
|
+
element.classList.add(CSS_ROW_SELECTED);
|
|
219
227
|
}
|
|
220
228
|
}
|
|
221
229
|
}
|
|
222
230
|
}
|
|
223
231
|
|
|
224
232
|
function getPlaceholder(): HTMLElement {
|
|
225
|
-
placeholder ??= createElement(
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
className: 'tabela__selection--placeholder',
|
|
229
|
-
},
|
|
230
|
-
{},
|
|
231
|
-
{},
|
|
232
|
-
);
|
|
233
|
+
placeholder ??= createElement(ELEMENT_DIV, {
|
|
234
|
+
className: CSS_SELECTION,
|
|
235
|
+
});
|
|
233
236
|
|
|
234
237
|
return placeholder;
|
|
235
238
|
}
|
|
236
239
|
|
|
237
240
|
function onMouseDown(event: MouseEvent): void {
|
|
238
241
|
if (shifted) {
|
|
239
|
-
const row = findAncestor(event.target as HTMLElement,
|
|
242
|
+
const row = findAncestor(event.target as HTMLElement, `.${CSS_ROW_BODY}`);
|
|
240
243
|
|
|
241
244
|
if (!(row instanceof HTMLElement)) {
|
|
242
245
|
return;
|
|
@@ -245,7 +248,7 @@ function onMouseDown(event: MouseEvent): void {
|
|
|
245
248
|
startElement = row;
|
|
246
249
|
startPosition = getPosition(event)!;
|
|
247
250
|
|
|
248
|
-
|
|
251
|
+
preventSelection.set();
|
|
249
252
|
}
|
|
250
253
|
}
|
|
251
254
|
|
|
@@ -286,18 +289,18 @@ function onMouseUp(event: MouseEvent): void {
|
|
|
286
289
|
if (!event.shiftKey) {
|
|
287
290
|
shifted = false;
|
|
288
291
|
|
|
289
|
-
|
|
292
|
+
preventSelection.remove();
|
|
290
293
|
}
|
|
291
294
|
|
|
292
295
|
getPlaceholder().remove();
|
|
293
296
|
|
|
294
|
-
const row = findAncestor(event.target as HTMLElement,
|
|
297
|
+
const row = findAncestor(event.target as HTMLElement, bodyRowSelector);
|
|
295
298
|
|
|
296
299
|
if (row instanceof HTMLElement) {
|
|
297
300
|
endElement = row;
|
|
298
301
|
|
|
299
|
-
const endTable = findAncestor(endElement,
|
|
300
|
-
const startTable = findAncestor(startElement,
|
|
302
|
+
const endTable = findAncestor(endElement, tableSelector);
|
|
303
|
+
const startTable = findAncestor(startElement, tableSelector);
|
|
301
304
|
|
|
302
305
|
if (startTable != null && startTable === endTable) {
|
|
303
306
|
mapped.get(startTable)?.range(startElement, endElement);
|
|
@@ -310,7 +313,7 @@ function onMouseUp(event: MouseEvent): void {
|
|
|
310
313
|
}
|
|
311
314
|
|
|
312
315
|
function onShift(event: KeyboardEvent, value: boolean): void {
|
|
313
|
-
if (event.key ===
|
|
316
|
+
if (event.key === KEY_SHIFT) {
|
|
314
317
|
shifted = value;
|
|
315
318
|
}
|
|
316
319
|
}
|
|
@@ -323,8 +326,14 @@ function onShiftUp(event: KeyboardEvent): void {
|
|
|
323
326
|
onShift(event, false);
|
|
324
327
|
}
|
|
325
328
|
|
|
329
|
+
const KEY_SHIFT = 'Shift';
|
|
330
|
+
|
|
326
331
|
const mapped = new WeakMap<Element, SelectionManager>();
|
|
327
332
|
|
|
333
|
+
const bodyRowSelector = `.${CSS_ROW_BODY}`;
|
|
334
|
+
|
|
335
|
+
const tableSelector = `.${CSS_TABLE}`;
|
|
336
|
+
|
|
328
337
|
let shifted = false;
|
|
329
338
|
|
|
330
339
|
let endElement: HTMLElement | undefined;
|
|
@@ -1,21 +1,34 @@
|
|
|
1
|
-
import {sort
|
|
1
|
+
import {sort} from '@oscarpalmer/atoms/array';
|
|
2
2
|
import type {Key, PlainObject} from '@oscarpalmer/atoms/models';
|
|
3
3
|
import {compare} from '@oscarpalmer/atoms/value/compare';
|
|
4
|
+
import {getValue} from '@oscarpalmer/atoms/value/handle';
|
|
4
5
|
import {setAttribute, setAttributes} from '@oscarpalmer/toretto/attribute';
|
|
5
|
-
import {
|
|
6
|
-
|
|
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';
|
|
7
18
|
import type {State} from '../models/tabela.model';
|
|
19
|
+
import type {DataValue} from '../models/data.model';
|
|
20
|
+
import {isGroupKey} from '../helpers/misc.helpers';
|
|
8
21
|
|
|
9
22
|
export class SortManager {
|
|
10
|
-
handlers =
|
|
23
|
+
handlers: TabelaSort = {
|
|
11
24
|
add: (field, direction) => this.add(field, direction),
|
|
12
25
|
flip: field => this.flip(field),
|
|
13
26
|
clear: () => this.clear(),
|
|
14
27
|
remove: field => this.remove(field),
|
|
15
28
|
set: items => this.set(items),
|
|
16
|
-
}
|
|
29
|
+
};
|
|
17
30
|
|
|
18
|
-
items:
|
|
31
|
+
items: PlainObject[] = [];
|
|
19
32
|
|
|
20
33
|
constructor(public state: State) {}
|
|
21
34
|
|
|
@@ -28,7 +41,7 @@ export class SortManager {
|
|
|
28
41
|
|
|
29
42
|
this.items.push({
|
|
30
43
|
key: field,
|
|
31
|
-
direction: direction ??
|
|
44
|
+
direction: direction ?? SORT_ASCENDING,
|
|
32
45
|
});
|
|
33
46
|
|
|
34
47
|
this.sort();
|
|
@@ -38,7 +51,7 @@ export class SortManager {
|
|
|
38
51
|
if (event.ctrlKey || event.metaKey) {
|
|
39
52
|
this.add(field);
|
|
40
53
|
} else {
|
|
41
|
-
this.set([{field, direction:
|
|
54
|
+
this.set([{field, direction: SORT_ASCENDING}]);
|
|
42
55
|
}
|
|
43
56
|
}
|
|
44
57
|
|
|
@@ -63,7 +76,7 @@ export class SortManager {
|
|
|
63
76
|
return;
|
|
64
77
|
}
|
|
65
78
|
|
|
66
|
-
item.direction = item.direction ===
|
|
79
|
+
item.direction = item.direction === SORT_ASCENDING ? SORT_DESCENDING : SORT_ASCENDING;
|
|
67
80
|
|
|
68
81
|
this.sort();
|
|
69
82
|
}
|
|
@@ -108,31 +121,31 @@ export class SortManager {
|
|
|
108
121
|
const sorterItem = items[sorterIndex];
|
|
109
122
|
|
|
110
123
|
setAttributes(column.elements.wrapper, {
|
|
111
|
-
|
|
112
|
-
sorterItem == null ?
|
|
113
|
-
|
|
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,
|
|
114
127
|
});
|
|
115
128
|
|
|
116
129
|
setAttribute(
|
|
117
130
|
column.elements.sorter,
|
|
118
|
-
|
|
131
|
+
ATTRIBUTE_DATA_SORT_POSITION,
|
|
119
132
|
sorterIndex > -1 && items.length > 1 ? sorterIndex + 1 : undefined,
|
|
120
133
|
);
|
|
121
134
|
}
|
|
122
135
|
|
|
123
|
-
state.managers.data.
|
|
124
|
-
items.length === 0 ? undefined :
|
|
136
|
+
state.managers.data.state.keys.active =
|
|
137
|
+
items.length === 0 ? undefined : getSortedItems(state, items);
|
|
125
138
|
|
|
126
139
|
state.managers.render.update(true, true);
|
|
127
140
|
}
|
|
128
141
|
|
|
129
142
|
toggle(event: MouseEvent, field: string, direction?: string | null): void {
|
|
130
143
|
switch (direction) {
|
|
131
|
-
case
|
|
144
|
+
case SORT_ASCENDING:
|
|
132
145
|
this.flip(field);
|
|
133
146
|
return;
|
|
134
147
|
|
|
135
|
-
case
|
|
148
|
+
case SORT_DESCENDING:
|
|
136
149
|
this.removeOrClear(event, field);
|
|
137
150
|
return;
|
|
138
151
|
|
|
@@ -143,43 +156,41 @@ export class SortManager {
|
|
|
143
156
|
}
|
|
144
157
|
}
|
|
145
158
|
|
|
146
|
-
function
|
|
147
|
-
state: State,
|
|
148
|
-
sorters: ArrayKeySorter<PlainObject>[],
|
|
149
|
-
): Array<GroupComponent | Key> {
|
|
159
|
+
function getSortedItems(state: State, sorters: PlainObject[]): Key[] {
|
|
150
160
|
const data =
|
|
151
|
-
state.managers.data.
|
|
152
|
-
key
|
|
153
|
-
) ?? state.managers.data.values.
|
|
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;
|
|
154
164
|
|
|
155
165
|
if (!state.managers.group.enabled) {
|
|
156
|
-
return sort(data as PlainObject[], sorters).map(
|
|
157
|
-
item => (item
|
|
166
|
+
return sort(data as PlainObject[], sorters as never).map(
|
|
167
|
+
item => getValue(item, state.key) as Key,
|
|
158
168
|
);
|
|
159
169
|
}
|
|
160
170
|
|
|
161
171
|
return sortWithGroups(state, data, sorters).map(item =>
|
|
162
|
-
item
|
|
172
|
+
typeof item === 'string' ? item : (getValue(item, state.key) as Key),
|
|
163
173
|
);
|
|
164
174
|
}
|
|
165
175
|
|
|
166
176
|
export function sortWithGroups(
|
|
167
177
|
state: State,
|
|
168
|
-
data:
|
|
169
|
-
sorters:
|
|
170
|
-
):
|
|
178
|
+
data: DataValue[],
|
|
179
|
+
sorters: PlainObject[],
|
|
180
|
+
): DataValue[] {
|
|
171
181
|
const {length} = sorters;
|
|
172
182
|
|
|
173
183
|
return data.sort((first, second) => {
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
184
|
+
const firstIsGroup = typeof first === 'string';
|
|
185
|
+
const secondIsGroup = typeof second === 'string';
|
|
186
|
+
|
|
187
|
+
const firstValue = firstIsGroup
|
|
188
|
+
? state.managers.group.getForKey(first)?.value.stringified
|
|
189
|
+
: getValue(first, state.managers.group.field);
|
|
178
190
|
|
|
179
|
-
const secondValue =
|
|
180
|
-
second
|
|
181
|
-
|
|
182
|
-
: (second as PlainObject)[state.managers.group.field];
|
|
191
|
+
const secondValue = secondIsGroup
|
|
192
|
+
? state.managers.group.getForKey(second)?.value.stringified
|
|
193
|
+
: getValue(second, state.managers.group.field);
|
|
183
194
|
|
|
184
195
|
const firstOrder = state.managers.group.order[firstValue as never];
|
|
185
196
|
const secondOrder = state.managers.group.order[secondValue as never];
|
|
@@ -190,9 +201,6 @@ export function sortWithGroups(
|
|
|
190
201
|
return groupComparison;
|
|
191
202
|
}
|
|
192
203
|
|
|
193
|
-
const firstIsGroup = first instanceof GroupComponent;
|
|
194
|
-
const secondIsGroup = second instanceof GroupComponent;
|
|
195
|
-
|
|
196
204
|
if (firstIsGroup || secondIsGroup) {
|
|
197
205
|
return firstIsGroup && secondIsGroup ? 0 : firstIsGroup ? -1 : 1;
|
|
198
206
|
}
|
|
@@ -200,13 +208,20 @@ export function sortWithGroups(
|
|
|
200
208
|
for (let index = 0; index < length; index += 1) {
|
|
201
209
|
const sorter = sorters[index];
|
|
202
210
|
|
|
203
|
-
const comparison = compare(
|
|
211
|
+
const comparison = compare(
|
|
212
|
+
getValue(first, (sorter as any).key),
|
|
213
|
+
getValue(second, (sorter as any).key),
|
|
214
|
+
);
|
|
204
215
|
|
|
205
216
|
if (comparison !== 0) {
|
|
206
|
-
return comparison * (sorter.direction ===
|
|
217
|
+
return comparison * (sorter.direction === SORT_ASCENDING ? 1 : -1);
|
|
207
218
|
}
|
|
208
219
|
}
|
|
209
220
|
|
|
210
221
|
return 0;
|
|
211
222
|
});
|
|
212
223
|
}
|
|
224
|
+
|
|
225
|
+
const SORT_NONE = 'none';
|
|
226
|
+
|
|
227
|
+
const SORT_OTHER = 'other';
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CSS_BUTTON,
|
|
3
|
+
CSS_CELL,
|
|
4
|
+
CSS_CELL_FOOTER,
|
|
5
|
+
CSS_CELL_GROUP,
|
|
6
|
+
CSS_HEADING,
|
|
7
|
+
CSS_ROW,
|
|
8
|
+
CSS_ROW_SELECTED,
|
|
9
|
+
CSS_ROWGROUP_BODY,
|
|
10
|
+
CSS_ROWGROUP_FOOTER,
|
|
11
|
+
CSS_ROWGROUP_HEADER,
|
|
12
|
+
CSS_SELECTION,
|
|
13
|
+
CSS_TABLE,
|
|
14
|
+
CSS_WRAPPER,
|
|
15
|
+
} from '../models/style.model';
|
|
16
|
+
import type {State} from '../models/tabela.model';
|
|
17
|
+
|
|
18
|
+
export class StyleManager {
|
|
19
|
+
constructor(readonly state: State) {
|
|
20
|
+
if (appended) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
appended = true;
|
|
25
|
+
|
|
26
|
+
const style = document.createElement('style');
|
|
27
|
+
|
|
28
|
+
style.textContent = styling;
|
|
29
|
+
|
|
30
|
+
document.head.appendChild(style);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const styling = //css
|
|
35
|
+
`/** Table */
|
|
36
|
+
|
|
37
|
+
:where(.${CSS_WRAPPER}) {
|
|
38
|
+
flex: 1;
|
|
39
|
+
position: relative;
|
|
40
|
+
background-color: var(--oui-absolute);
|
|
41
|
+
border: 1px solid grey;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
:where(.${CSS_TABLE}) {
|
|
45
|
+
min-height: 24em;
|
|
46
|
+
display: flex;
|
|
47
|
+
flex-flow: column nowrap;
|
|
48
|
+
flex: 1;
|
|
49
|
+
overflow: auto;
|
|
50
|
+
position: absolute;
|
|
51
|
+
inset: 0;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Row group */
|
|
55
|
+
|
|
56
|
+
:where(.${CSS_ROWGROUP_HEADER}),
|
|
57
|
+
:where(.${CSS_ROWGROUP_FOOTER}) {
|
|
58
|
+
background-color: white;
|
|
59
|
+
position: sticky;
|
|
60
|
+
left: 0;
|
|
61
|
+
z-index: 10;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
:where(.${CSS_ROWGROUP_HEADER}) {
|
|
65
|
+
top: 0;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
:where(.${CSS_ROWGROUP_FOOTER}) {
|
|
69
|
+
bottom: 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
:where(.${CSS_ROWGROUP_BODY}) {
|
|
73
|
+
display: flex;
|
|
74
|
+
flex-flow: column nowrap;
|
|
75
|
+
flex: 1;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
:where(.${CSS_ROWGROUP_BODY}:focus) {
|
|
79
|
+
outline: none;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
:where(.${CSS_WRAPPER}:has(.${CSS_ROWGROUP_BODY}:focus-visible)) {
|
|
83
|
+
outline: 2px solid var(--oui-blue-6);
|
|
84
|
+
outline-offset: 2px;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Row */
|
|
88
|
+
|
|
89
|
+
:where(.${CSS_ROW}) {
|
|
90
|
+
width: 100%;
|
|
91
|
+
display: flex;
|
|
92
|
+
flex-flow: row nowrap;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
:where(.${CSS_ROW}:last-child .${CSS_CELL}) {
|
|
96
|
+
border-bottom-width: 0;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
:where(.${CSS_ROW}--body),
|
|
100
|
+
:where(.${CSS_ROW}--group) {
|
|
101
|
+
flex: 1;
|
|
102
|
+
position: absolute;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
:where(.${CSS_ROW_SELECTED}) {
|
|
106
|
+
background-color: var(--oui-blue-1);
|
|
107
|
+
color: var(--oui-blue-9);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
:where(.${CSS_WRAPPER}:has(.${CSS_ROWGROUP_BODY}:focus-visible) .${CSS_ROW}[data-active="true"]) {
|
|
111
|
+
outline: 2px solid var(--oui-blue-6);
|
|
112
|
+
outline-offset: 2px;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Cells */
|
|
116
|
+
|
|
117
|
+
:where(.${CSS_CELL}),
|
|
118
|
+
:where(.${CSS_HEADING}) {
|
|
119
|
+
padding: 0.5em;
|
|
120
|
+
border-color: gray;
|
|
121
|
+
border-style: solid;
|
|
122
|
+
border-width: 0 1px 1px 0;
|
|
123
|
+
line-height: 1;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
:where(.${CSS_WRAPPER} .${CSS_CELL}:last-child),
|
|
127
|
+
:where(.${CSS_ROW} .${CSS_HEADING}:last-child) {
|
|
128
|
+
flex: 1;
|
|
129
|
+
border-right-width: 0;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
:where(.${CSS_CELL}) {
|
|
133
|
+
overflow: hidden;
|
|
134
|
+
text-overflow: ellipsis;
|
|
135
|
+
white-space: nowrap;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
:where(.${CSS_CELL_FOOTER}) {
|
|
139
|
+
border-top-width: 1px;
|
|
140
|
+
border-bottom-width: 0;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
:where(.${CSS_CELL_GROUP}) {
|
|
144
|
+
padding: 0;
|
|
145
|
+
display: flex;
|
|
146
|
+
flex-flow: row nowrap;
|
|
147
|
+
align-items: center;
|
|
148
|
+
gap: 0.5em;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
:where(.${CSS_CELL_GROUP} .${CSS_BUTTON}) {
|
|
152
|
+
margin: 0 0 0 .25rem;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** Misc. */
|
|
156
|
+
|
|
157
|
+
:where(.${CSS_BUTTON}) {
|
|
158
|
+
font-size: .75rem;
|
|
159
|
+
font-weight: bold;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
:where(.${CSS_SELECTION}) {
|
|
163
|
+
background-color: color-mix(in oklch, var(--oui-blue-6), transparent);
|
|
164
|
+
border: 1px solid var(--oui-blue-6);
|
|
165
|
+
border-radius: .25rem;
|
|
166
|
+
position: fixed;
|
|
167
|
+
z-index: 1000;
|
|
168
|
+
}
|
|
169
|
+
`.replace(/^\s+|\s+|\s+$/g, ' ');
|
|
170
|
+
|
|
171
|
+
let appended = false;
|
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
export type Column = {
|
|
2
2
|
field: string;
|
|
3
|
-
|
|
4
|
-
type: TabelaColumnType;
|
|
3
|
+
label: string;
|
|
5
4
|
width: number;
|
|
6
5
|
};
|
|
7
6
|
|
|
8
7
|
export type TabelaColumn = {
|
|
9
8
|
field: string;
|
|
10
|
-
|
|
11
|
-
type: TabelaColumnType;
|
|
9
|
+
label: string;
|
|
12
10
|
width?: number;
|
|
13
11
|
};
|
|
14
|
-
|
|
15
|
-
export type TabelaColumnType = 'boolean' | 'date' | 'date-time' | 'number' | 'string' | 'time';
|
package/src/models/data.model.ts
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import type {Key, PlainObject} from '@oscarpalmer/atoms/models';
|
|
2
|
-
import type {
|
|
2
|
+
import type {State} from './tabela.model';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
type DataKeys = {
|
|
5
|
+
active?: Key[];
|
|
6
|
+
original: Key[];
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
-
type
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
};
|
|
9
|
+
export type DataState = {
|
|
10
|
+
keys: DataKeys;
|
|
11
|
+
values: DataValues;
|
|
12
|
+
} & State;
|
|
13
|
+
|
|
14
|
+
export type DataValue = string | PlainObject;
|
|
13
15
|
|
|
14
|
-
type
|
|
15
|
-
array:
|
|
16
|
+
type DataValues = {
|
|
17
|
+
array: DataValue[];
|
|
16
18
|
mapped: Map<Key, PlainObject>;
|
|
17
19
|
};
|
|
18
20
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export const ARIA_ACTIVEDESCENDANT = 'aria-activedescendant';
|
|
2
|
+
|
|
3
|
+
export const ARIA_LABEL = 'aria-label';
|
|
4
|
+
|
|
5
|
+
export const ARIA_SELECTED = 'aria-selected';
|
|
6
|
+
|
|
7
|
+
export const ARIA_SORT = 'aria-sort';
|
|
8
|
+
|
|
9
|
+
export const ATTRIBUTE_DATA_ACTIVE = 'data-active';
|
|
10
|
+
|
|
11
|
+
export const ATTRIBUTE_DATA_EVENT = 'data-event';
|
|
12
|
+
|
|
13
|
+
export const ATTRIBUTE_DATA_FIELD = 'data-field';
|
|
14
|
+
|
|
15
|
+
export const ATTRIBUTE_DATA_KEY = 'data-key';
|
|
16
|
+
|
|
17
|
+
export const ATTRIBUTE_DATA_SORT_DIRECTION = 'data-sort-direction';
|
|
18
|
+
|
|
19
|
+
export const ATTRIBUTE_DATA_SORT_POSITION = 'data-sort-position';
|
|
20
|
+
|
|
21
|
+
export const ATTRIBUTE_ROLE = 'role';
|
|
22
|
+
|
|
23
|
+
export const ELEMENT_DIV = 'div';
|
|
24
|
+
|
|
25
|
+
export const ROLE_CELL = 'cell';
|
|
26
|
+
|
|
27
|
+
export const ROLE_COLUMNHEADER = 'columnheader';
|
|
28
|
+
|
|
29
|
+
export const ROLE_ROW = 'row';
|
|
30
|
+
|
|
31
|
+
export const ROLE_ROWGROUP = 'rowgroup';
|
|
32
|
+
|
|
33
|
+
export const ROLE_TABLE = 'table';
|
|
@@ -23,3 +23,23 @@ export type TabelaFilterItem = {
|
|
|
23
23
|
field: string;
|
|
24
24
|
value: unknown;
|
|
25
25
|
};
|
|
26
|
+
|
|
27
|
+
export const FILTER_CONTAINS: TabelaFilterComparison = 'contains';
|
|
28
|
+
|
|
29
|
+
export const FILTER_ENDS_WITH: TabelaFilterComparison = 'ends-with';
|
|
30
|
+
|
|
31
|
+
export const FILTER_EQUALS: TabelaFilterComparison = 'equals';
|
|
32
|
+
|
|
33
|
+
export const FILTER_GREATER_THAN: TabelaFilterComparison = 'greater-than';
|
|
34
|
+
|
|
35
|
+
export const FILTER_GREATER_THAN_OR_EQUAL: TabelaFilterComparison = 'greater-than-or-equal';
|
|
36
|
+
|
|
37
|
+
export const FILTER_LESS_THAN: TabelaFilterComparison = 'less-than';
|
|
38
|
+
|
|
39
|
+
export const FILTER_LESS_THAN_OR_EQUAL: TabelaFilterComparison = 'less-than-or-equal';
|
|
40
|
+
|
|
41
|
+
export const FILTER_NOT_CONTAINS: TabelaFilterComparison = 'not-contains';
|
|
42
|
+
|
|
43
|
+
export const FILTER_NOT_EQUALS: TabelaFilterComparison = 'not-equals';
|
|
44
|
+
|
|
45
|
+
export const FILTER_STARTS_WITH: TabelaFilterComparison = 'starts-with';
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
+
export type GroupValue = {
|
|
2
|
+
original: unknown;
|
|
3
|
+
stringified: string;
|
|
4
|
+
};
|
|
5
|
+
|
|
1
6
|
export type TabelaGroup = {
|
|
2
|
-
|
|
3
|
-
value: unknown;
|
|
7
|
+
set(group?: string): void;
|
|
4
8
|
};
|
|
9
|
+
|
|
10
|
+
export const GROUP_KEY_EXPRESSION = /^group:(.+)$/;
|
|
11
|
+
|
|
12
|
+
export const GROUP_KEY_PREFIX = 'group:';
|
package/src/models/sort.model.ts
CHANGED