@astronox/core 0.4.18 → 0.5.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/package.json
CHANGED
|
@@ -8,12 +8,15 @@ import {
|
|
|
8
8
|
hasTableProgressive,
|
|
9
9
|
setTableProgressiveFilters,
|
|
10
10
|
} from './tableProgressiveController';
|
|
11
|
+
import {
|
|
12
|
+
matchesFilterSelection,
|
|
13
|
+
normalizeFilterSelection,
|
|
14
|
+
type TableFilterValues,
|
|
15
|
+
} from './tableFilterSelection';
|
|
11
16
|
import { revealTableStart } from './tableViewport';
|
|
12
17
|
|
|
13
|
-
type FilterValues = Readonly<Record<string, readonly string[]>>;
|
|
14
|
-
|
|
15
18
|
type CachedFilterValues = {
|
|
16
|
-
values:
|
|
19
|
+
values: TableFilterValues;
|
|
17
20
|
normalizedSearch: readonly string[];
|
|
18
21
|
};
|
|
19
22
|
|
|
@@ -92,7 +95,7 @@ export function initTableFilters(root: HTMLElement): () => void {
|
|
|
92
95
|
.normalize('NFD')
|
|
93
96
|
.replace(/\p{Diacritic}/gu, '')
|
|
94
97
|
.toLocaleLowerCase(locale);
|
|
95
|
-
const selections = new Map<string, string>();
|
|
98
|
+
const selections = new Map<string, readonly string[]>();
|
|
96
99
|
const filterValuesCache = new WeakMap<HTMLElement, CachedFilterValues>();
|
|
97
100
|
const rows: HTMLElement[] = [];
|
|
98
101
|
let scheduledFrame: number | null = null;
|
|
@@ -118,7 +121,7 @@ export function initTableFilters(root: HTMLElement): () => void {
|
|
|
118
121
|
const applyFilters = (): void => {
|
|
119
122
|
const query = normalize(search?.value.trim() ?? '');
|
|
120
123
|
const activeSelections = [...selections.entries()].filter(
|
|
121
|
-
([,
|
|
124
|
+
([, values]) => values.length > 0,
|
|
122
125
|
);
|
|
123
126
|
const hasExternalFilter =
|
|
124
127
|
root.hasAttribute(externalFiltersAttribute) ||
|
|
@@ -144,8 +147,10 @@ export function initTableFilters(root: HTMLElement): () => void {
|
|
|
144
147
|
query.length === 0 ||
|
|
145
148
|
cached.normalizedSearch.some((value) => value.includes(query));
|
|
146
149
|
const matchesSelections = activeSelections.every(
|
|
147
|
-
([field,
|
|
148
|
-
|
|
150
|
+
([field, selectedValues]) => {
|
|
151
|
+
const rowValues = cached.values[field] ?? [];
|
|
152
|
+
return matchesFilterSelection(rowValues, selectedValues);
|
|
153
|
+
},
|
|
149
154
|
);
|
|
150
155
|
const visible =
|
|
151
156
|
matchesSearch &&
|
|
@@ -190,7 +195,9 @@ export function initTableFilters(root: HTMLElement): () => void {
|
|
|
190
195
|
|
|
191
196
|
const field = target.dataset.tableFilterField;
|
|
192
197
|
if (!field) return;
|
|
193
|
-
|
|
198
|
+
const values = normalizeFilterSelection(customEvent.detail.values);
|
|
199
|
+
if (values.length > 0) selections.set(field, values);
|
|
200
|
+
else selections.delete(field);
|
|
194
201
|
revealTableStart(table);
|
|
195
202
|
scheduleFilters();
|
|
196
203
|
};
|
|
@@ -215,8 +222,10 @@ export function initTableFilters(root: HTMLElement): () => void {
|
|
|
215
222
|
|
|
216
223
|
for (const field of fields) {
|
|
217
224
|
const fieldName = field.dataset.tableFilterField;
|
|
218
|
-
const
|
|
219
|
-
if (fieldName &&
|
|
225
|
+
const selectedValues = normalizeFilterSelection(getComboboxValues(field));
|
|
226
|
+
if (fieldName && selectedValues.length > 0) {
|
|
227
|
+
selections.set(fieldName, selectedValues);
|
|
228
|
+
}
|
|
220
229
|
}
|
|
221
230
|
registerRows(
|
|
222
231
|
Array.from(
|
|
@@ -248,12 +257,14 @@ export function initTableFilters(root: HTMLElement): () => void {
|
|
|
248
257
|
};
|
|
249
258
|
}
|
|
250
259
|
|
|
251
|
-
function parseFilterValues(value: string | undefined):
|
|
260
|
+
function parseFilterValues(value: string | undefined): TableFilterValues {
|
|
252
261
|
if (!value) return {};
|
|
253
262
|
|
|
254
263
|
try {
|
|
255
264
|
const parsed = JSON.parse(value);
|
|
256
|
-
return parsed && typeof parsed === 'object'
|
|
265
|
+
return parsed && typeof parsed === 'object'
|
|
266
|
+
? (parsed as TableFilterValues)
|
|
267
|
+
: {};
|
|
257
268
|
} catch {
|
|
258
269
|
return {};
|
|
259
270
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export type TableFilterValues = Readonly<Record<string, readonly string[]>>;
|
|
2
|
+
|
|
3
|
+
export function normalizeFilterSelection(
|
|
4
|
+
values: readonly string[],
|
|
5
|
+
): readonly string[] {
|
|
6
|
+
return [...new Set(values.filter((value) => value.length > 0))].sort();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function normalizeFilterSelections(
|
|
10
|
+
selections: TableFilterValues,
|
|
11
|
+
): TableFilterValues {
|
|
12
|
+
const normalized: Record<string, readonly string[]> = {};
|
|
13
|
+
|
|
14
|
+
for (const [field, values] of Object.entries(selections)) {
|
|
15
|
+
const selection = normalizeFilterSelection(values);
|
|
16
|
+
if (selection.length > 0) normalized[field] = selection;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return normalized;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function matchesFilterSelection(
|
|
23
|
+
values: readonly string[],
|
|
24
|
+
selection: readonly string[],
|
|
25
|
+
): boolean {
|
|
26
|
+
return selection.some((value) => values.includes(value));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function areFilterSelectionsEqual(
|
|
30
|
+
left: TableFilterValues,
|
|
31
|
+
right: TableFilterValues,
|
|
32
|
+
): boolean {
|
|
33
|
+
const leftEntries = Object.entries(left);
|
|
34
|
+
const rightEntries = Object.entries(right);
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
leftEntries.length === rightEntries.length &&
|
|
38
|
+
leftEntries.every(([field, values]) => {
|
|
39
|
+
const rightValues = right[field];
|
|
40
|
+
return (
|
|
41
|
+
rightValues !== undefined &&
|
|
42
|
+
values.length === rightValues.length &&
|
|
43
|
+
values.every((value, index) => value === rightValues[index])
|
|
44
|
+
);
|
|
45
|
+
})
|
|
46
|
+
);
|
|
47
|
+
}
|
|
@@ -3,6 +3,12 @@ import type {
|
|
|
3
3
|
TableProgressiveModel,
|
|
4
4
|
} from '../../display/contracts';
|
|
5
5
|
import { tableProgressiveBatchSize } from '../../display/tableProgressive';
|
|
6
|
+
import {
|
|
7
|
+
areFilterSelectionsEqual,
|
|
8
|
+
matchesFilterSelection,
|
|
9
|
+
normalizeFilterSelections,
|
|
10
|
+
type TableFilterValues,
|
|
11
|
+
} from './tableFilterSelection';
|
|
6
12
|
import { resolveTableScrollRoot, revealTableStart } from './tableViewport';
|
|
7
13
|
|
|
8
14
|
const initializedAttribute = 'data-table-progressive-initialized';
|
|
@@ -20,7 +26,7 @@ export type TableRowsAppendedDetail = {
|
|
|
20
26
|
|
|
21
27
|
export type TableProgressiveFilterState = {
|
|
22
28
|
search: string;
|
|
23
|
-
selections:
|
|
29
|
+
selections: TableFilterValues;
|
|
24
30
|
};
|
|
25
31
|
|
|
26
32
|
export type TableProgressiveSortState = {
|
|
@@ -250,9 +256,10 @@ export function initTableProgressive(root: HTMLElement): () => void {
|
|
|
250
256
|
) {
|
|
251
257
|
return false;
|
|
252
258
|
}
|
|
253
|
-
return selections.every(([field,
|
|
254
|
-
|
|
255
|
-
|
|
259
|
+
return selections.every(([field, selectedValues]) => {
|
|
260
|
+
const entryValues = entry.filters?.[field] ?? [];
|
|
261
|
+
return matchesFilterSelection(entryValues, selectedValues);
|
|
262
|
+
});
|
|
256
263
|
});
|
|
257
264
|
|
|
258
265
|
if (sortState) {
|
|
@@ -455,8 +462,9 @@ export function initTableProgressive(root: HTMLElement): () => void {
|
|
|
455
462
|
progressive: true,
|
|
456
463
|
refresh,
|
|
457
464
|
setFilters(state) {
|
|
458
|
-
|
|
459
|
-
filterState
|
|
465
|
+
const normalizedState = normalizeFilterState(state);
|
|
466
|
+
if (areFilterStatesEqual(filterState, normalizedState)) return;
|
|
467
|
+
filterState = normalizedState;
|
|
460
468
|
if (prepared) prepareWindow(0, 'refreshing');
|
|
461
469
|
},
|
|
462
470
|
setSort(state) {
|
|
@@ -656,15 +664,21 @@ function areFilterStatesEqual(
|
|
|
656
664
|
left: TableProgressiveFilterState,
|
|
657
665
|
right: TableProgressiveFilterState,
|
|
658
666
|
): boolean {
|
|
659
|
-
if (left.search !== right.search) return false;
|
|
660
|
-
const leftEntries = Object.entries(left.selections);
|
|
661
|
-
const rightEntries = Object.entries(right.selections);
|
|
662
667
|
return (
|
|
663
|
-
|
|
664
|
-
|
|
668
|
+
left.search === right.search &&
|
|
669
|
+
areFilterSelectionsEqual(left.selections, right.selections)
|
|
665
670
|
);
|
|
666
671
|
}
|
|
667
672
|
|
|
673
|
+
function normalizeFilterState(
|
|
674
|
+
state: TableProgressiveFilterState,
|
|
675
|
+
): TableProgressiveFilterState {
|
|
676
|
+
return {
|
|
677
|
+
search: state.search,
|
|
678
|
+
selections: normalizeFilterSelections(state.selections),
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
|
|
668
682
|
function areSortStatesEqual(
|
|
669
683
|
left: TableProgressiveSortState,
|
|
670
684
|
right: TableProgressiveSortState,
|