@serhiitupilow/nuxt-table 0.1.7 → 1.0.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/module.json
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
computed,
|
|
4
|
+
getCurrentInstance,
|
|
5
|
+
onBeforeUpdate,
|
|
6
|
+
shallowRef,
|
|
7
|
+
toRef
|
|
8
|
+
} from "vue";
|
|
3
9
|
import { useNuxtTable } from "../composables/useNuxtTable";
|
|
4
10
|
const props = defineProps({
|
|
5
11
|
columns: { type: Array, required: true },
|
|
@@ -15,13 +21,17 @@ const props = defineProps({
|
|
|
15
21
|
});
|
|
16
22
|
const emit = defineEmits(["columnOrderChange", "manualSortChange", "manualFilterChange"]);
|
|
17
23
|
const instance = getCurrentInstance();
|
|
24
|
+
const vnodeProps = shallowRef(
|
|
25
|
+
instance?.vnode.props ?? null
|
|
26
|
+
);
|
|
27
|
+
onBeforeUpdate(() => {
|
|
28
|
+
vnodeProps.value = instance?.vnode.props ?? null;
|
|
29
|
+
});
|
|
18
30
|
const hasManualSortChangeListener = computed(() => {
|
|
19
|
-
|
|
20
|
-
return Boolean(vnodeProps?.onManualSortChange);
|
|
31
|
+
return Boolean(vnodeProps.value?.onManualSortChange);
|
|
21
32
|
});
|
|
22
33
|
const hasManualFilterChangeListener = computed(() => {
|
|
23
|
-
|
|
24
|
-
return Boolean(vnodeProps?.onManualFilterChange);
|
|
34
|
+
return Boolean(vnodeProps.value?.onManualFilterChange);
|
|
25
35
|
});
|
|
26
36
|
const defaultClassNames = {
|
|
27
37
|
root: "nuxt-table",
|
|
@@ -80,15 +90,17 @@ const {
|
|
|
80
90
|
storageKey: toRef(props, "storageKey"),
|
|
81
91
|
rowKey: toRef(props, "rowKey"),
|
|
82
92
|
enableColumnDnd: toRef(props, "enableColumnDnd"),
|
|
93
|
+
isManualSortMode: hasManualSortChangeListener,
|
|
94
|
+
isManualFilterMode: hasManualFilterChangeListener,
|
|
83
95
|
onColumnOrderChange: (payload) => {
|
|
84
96
|
emit("columnOrderChange", payload);
|
|
85
97
|
},
|
|
86
|
-
onManualSortChange:
|
|
98
|
+
onManualSortChange: (payload) => {
|
|
87
99
|
emit("manualSortChange", payload);
|
|
88
|
-
}
|
|
89
|
-
onManualFilterChange:
|
|
100
|
+
},
|
|
101
|
+
onManualFilterChange: (payload) => {
|
|
90
102
|
emit("manualFilterChange", payload);
|
|
91
|
-
}
|
|
103
|
+
}
|
|
92
104
|
});
|
|
93
105
|
const displayedColumns = computed(() => {
|
|
94
106
|
if (!props.enabledColumns) {
|
|
@@ -97,6 +109,12 @@ const displayedColumns = computed(() => {
|
|
|
97
109
|
const enabledKeySet = new Set(props.enabledColumns);
|
|
98
110
|
return orderedColumns.value.filter((column) => enabledKeySet.has(column.key));
|
|
99
111
|
});
|
|
112
|
+
const keyedRows = computed(() => {
|
|
113
|
+
return sortedRows.value.map((row, rowIndex) => ({
|
|
114
|
+
row,
|
|
115
|
+
key: resolveRowKey(row, rowIndex)
|
|
116
|
+
}));
|
|
117
|
+
});
|
|
100
118
|
</script>
|
|
101
119
|
|
|
102
120
|
<template>
|
|
@@ -131,22 +149,22 @@ const displayedColumns = computed(() => {
|
|
|
131
149
|
</thead>
|
|
132
150
|
<tbody :class="mergedClassNames.tableBody">
|
|
133
151
|
<tr
|
|
134
|
-
v-for="
|
|
135
|
-
:key="
|
|
152
|
+
v-for="rowEntry in keyedRows"
|
|
153
|
+
:key="rowEntry.key"
|
|
136
154
|
:class="mergedClassNames.bodyRow"
|
|
137
155
|
>
|
|
138
156
|
<NuxtTableBodyCell
|
|
139
157
|
v-for="column in displayedColumns"
|
|
140
|
-
:key="`${
|
|
141
|
-
:row="row"
|
|
142
|
-
:row-key="
|
|
158
|
+
:key="`${rowEntry.key}-${column.key}`"
|
|
159
|
+
:row="rowEntry.row"
|
|
160
|
+
:row-key="rowEntry.key"
|
|
143
161
|
:column="column"
|
|
144
|
-
:value="resolveDisplayValue(row, column)"
|
|
162
|
+
:value="resolveDisplayValue(rowEntry.row, column)"
|
|
145
163
|
:column-style="getColumnStyle(column.key)"
|
|
146
164
|
:class-names="mergedClassNames"
|
|
147
165
|
/>
|
|
148
166
|
</tr>
|
|
149
|
-
<tr v-if="
|
|
167
|
+
<tr v-if="keyedRows.length === 0">
|
|
150
168
|
<td
|
|
151
169
|
:colspan="Math.max(displayedColumns.length, 1)"
|
|
152
170
|
:class="mergedClassNames.emptyCell"
|
|
@@ -17,13 +17,7 @@ export declare function useNuxtTable(options: UseNuxtTableOptions): {
|
|
|
17
17
|
onHeaderDragLeave: (columnKey: string) => void;
|
|
18
18
|
onHeaderDrop: (targetColumnKey: string) => Promise<void>;
|
|
19
19
|
onHeaderDragEnd: () => void;
|
|
20
|
-
getColumnStyle: (columnKey: string) =>
|
|
21
|
-
width?: undefined;
|
|
22
|
-
minWidth?: undefined;
|
|
23
|
-
} | {
|
|
24
|
-
width: string;
|
|
25
|
-
minWidth: string;
|
|
26
|
-
};
|
|
20
|
+
getColumnStyle: (columnKey: string) => Record<string, string>;
|
|
27
21
|
startColumnResize: (event: MouseEvent, columnKey: string) => void;
|
|
28
22
|
setHeaderElement: (columnKey: string, element: Element | ComponentPublicInstance | null) => void;
|
|
29
23
|
resolveDisplayValue: (row: TableRow, column: NuxtTableColumn) => any;
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
watch
|
|
8
8
|
} from "vue";
|
|
9
9
|
const MIN_COLUMN_WIDTH = 140;
|
|
10
|
+
const EMPTY_STYLE = {};
|
|
10
11
|
export function useNuxtTable(options) {
|
|
11
12
|
const columnOrder = ref([]);
|
|
12
13
|
const enabledColumnKeys = ref([]);
|
|
@@ -19,11 +20,20 @@ export function useNuxtTable(options) {
|
|
|
19
20
|
const hasLoadedPersistence = ref(false);
|
|
20
21
|
const headerElements = ref({});
|
|
21
22
|
const columnWidths = ref({});
|
|
23
|
+
const resolverPathCache = /* @__PURE__ */ new Map();
|
|
22
24
|
const activeResize = ref(null);
|
|
23
|
-
const isManualSortMode = computed(() =>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
const isManualSortMode = computed(() => {
|
|
26
|
+
if (options.isManualSortMode) {
|
|
27
|
+
return options.isManualSortMode.value;
|
|
28
|
+
}
|
|
29
|
+
return Boolean(options.onManualSortChange);
|
|
30
|
+
});
|
|
31
|
+
const isManualFilterMode = computed(() => {
|
|
32
|
+
if (options.isManualFilterMode) {
|
|
33
|
+
return options.isManualFilterMode.value;
|
|
34
|
+
}
|
|
35
|
+
return Boolean(options.onManualFilterChange);
|
|
36
|
+
});
|
|
27
37
|
const availableColumnKeys = computed(
|
|
28
38
|
() => options.columns.value.map((column) => column.key)
|
|
29
39
|
);
|
|
@@ -34,30 +44,60 @@ export function useNuxtTable(options) {
|
|
|
34
44
|
return columnOrder.value.map((columnKey) => columnsByKey.value.get(columnKey)).filter((column) => Boolean(column));
|
|
35
45
|
});
|
|
36
46
|
const visibleColumns = computed(() => {
|
|
47
|
+
const enabledKeySet = new Set(enabledColumnKeys.value);
|
|
37
48
|
return orderedColumns.value.filter(
|
|
38
|
-
(column) =>
|
|
49
|
+
(column) => enabledKeySet.has(column.key)
|
|
39
50
|
);
|
|
40
51
|
});
|
|
52
|
+
const activeTextFilters = computed(() => {
|
|
53
|
+
if (isManualFilterMode.value) {
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
const nextFilters = [];
|
|
57
|
+
for (const column of orderedColumns.value) {
|
|
58
|
+
const filterValue = filters.value[column.key];
|
|
59
|
+
if (!isFilterActive(filterValue)) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
nextFilters.push({
|
|
63
|
+
key: column.key,
|
|
64
|
+
resolver: column.filterKey ?? column.key,
|
|
65
|
+
filterText: String(filterValue ?? "").toLowerCase()
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return nextFilters;
|
|
69
|
+
});
|
|
41
70
|
const filteredRows = computed(() => {
|
|
71
|
+
if (isManualFilterMode.value) {
|
|
72
|
+
return options.rows.value;
|
|
73
|
+
}
|
|
74
|
+
const activeFilters = activeTextFilters.value;
|
|
75
|
+
if (activeFilters.length === 0) {
|
|
76
|
+
return options.rows.value;
|
|
77
|
+
}
|
|
42
78
|
return options.rows.value.filter((row) => {
|
|
43
|
-
return
|
|
44
|
-
const
|
|
45
|
-
if (!isFilterActive(filterValue)) {
|
|
46
|
-
return true;
|
|
47
|
-
}
|
|
48
|
-
if (isManualFilterMode.value) {
|
|
49
|
-
return true;
|
|
50
|
-
}
|
|
51
|
-
const candidate = resolveColumnValue(
|
|
52
|
-
row,
|
|
53
|
-
column.filterKey ?? column.key
|
|
54
|
-
);
|
|
79
|
+
return activeFilters.every(({ resolver, filterText }) => {
|
|
80
|
+
const candidate = resolveColumnValue(row, resolver);
|
|
55
81
|
const candidateText = String(candidate ?? "").toLowerCase();
|
|
56
|
-
const filterText = String(filterValue ?? "").toLowerCase();
|
|
57
82
|
return candidateText.includes(filterText);
|
|
58
83
|
});
|
|
59
84
|
});
|
|
60
85
|
});
|
|
86
|
+
const columnStylesByKey = computed(() => {
|
|
87
|
+
const styles = {};
|
|
88
|
+
for (const [columnKey, width] of Object.entries(columnWidths.value)) {
|
|
89
|
+
if (!width) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const safeWidth = Math.max(MIN_COLUMN_WIDTH, width);
|
|
93
|
+
const widthPx = `${safeWidth}px`;
|
|
94
|
+
styles[columnKey] = {
|
|
95
|
+
width: widthPx,
|
|
96
|
+
minWidth: widthPx
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return styles;
|
|
100
|
+
});
|
|
61
101
|
const sortedRows = computed(() => {
|
|
62
102
|
if (!sortState.value) {
|
|
63
103
|
return filteredRows.value;
|
|
@@ -83,13 +123,9 @@ export function useNuxtTable(options) {
|
|
|
83
123
|
loadPersistedState();
|
|
84
124
|
hasLoadedPersistence.value = true;
|
|
85
125
|
});
|
|
86
|
-
watch(
|
|
87
|
-
()
|
|
88
|
-
|
|
89
|
-
initializeColumnState();
|
|
90
|
-
},
|
|
91
|
-
{ deep: true }
|
|
92
|
-
);
|
|
126
|
+
watch(availableColumnKeys, () => {
|
|
127
|
+
initializeColumnState();
|
|
128
|
+
});
|
|
93
129
|
watch(
|
|
94
130
|
[columnOrder, enabledColumnKeys, columnWidths],
|
|
95
131
|
() => {
|
|
@@ -123,7 +159,8 @@ export function useNuxtTable(options) {
|
|
|
123
159
|
const keptKeys = columnOrder.value.filter(
|
|
124
160
|
(key) => currentKeySet.has(key)
|
|
125
161
|
);
|
|
126
|
-
const
|
|
162
|
+
const keptKeySet = new Set(keptKeys);
|
|
163
|
+
const newKeys = currentKeys.filter((key) => !keptKeySet.has(key));
|
|
127
164
|
columnOrder.value = [...keptKeys, ...newKeys];
|
|
128
165
|
}
|
|
129
166
|
if (!enabledColumnKeys.value.length) {
|
|
@@ -133,8 +170,9 @@ export function useNuxtTable(options) {
|
|
|
133
170
|
const keptEnabledKeys = enabledColumnKeys.value.filter(
|
|
134
171
|
(key) => currentKeySet.has(key)
|
|
135
172
|
);
|
|
173
|
+
const keptEnabledKeySet = new Set(keptEnabledKeys);
|
|
136
174
|
const missingEnabledKeys = currentKeys.filter(
|
|
137
|
-
(key) => !
|
|
175
|
+
(key) => !keptEnabledKeySet.has(key)
|
|
138
176
|
);
|
|
139
177
|
enabledColumnKeys.value = [...keptEnabledKeys, ...missingEnabledKeys];
|
|
140
178
|
}
|
|
@@ -157,17 +195,19 @@ export function useNuxtTable(options) {
|
|
|
157
195
|
return;
|
|
158
196
|
}
|
|
159
197
|
try {
|
|
198
|
+
const availableKeySet = new Set(availableColumnKeys.value);
|
|
160
199
|
const persistedOrder = localStorage.getItem(buildStorageKey("order"));
|
|
161
200
|
if (persistedOrder) {
|
|
162
201
|
const parsedOrder = JSON.parse(persistedOrder);
|
|
163
202
|
if (Array.isArray(parsedOrder)) {
|
|
164
203
|
const validPersistedOrder = parsedOrder.filter(
|
|
165
204
|
(key) => {
|
|
166
|
-
return typeof key === "string" &&
|
|
205
|
+
return typeof key === "string" && availableKeySet.has(key);
|
|
167
206
|
}
|
|
168
207
|
);
|
|
208
|
+
const validPersistedOrderSet = new Set(validPersistedOrder);
|
|
169
209
|
const missingKeys = availableColumnKeys.value.filter(
|
|
170
|
-
(key) => !
|
|
210
|
+
(key) => !validPersistedOrderSet.has(key)
|
|
171
211
|
);
|
|
172
212
|
columnOrder.value = [...validPersistedOrder, ...missingKeys];
|
|
173
213
|
}
|
|
@@ -180,7 +220,7 @@ export function useNuxtTable(options) {
|
|
|
180
220
|
if (Array.isArray(parsedEnabledColumns)) {
|
|
181
221
|
enabledColumnKeys.value = parsedEnabledColumns.filter(
|
|
182
222
|
(key) => {
|
|
183
|
-
return typeof key === "string" &&
|
|
223
|
+
return typeof key === "string" && availableKeySet.has(key);
|
|
184
224
|
}
|
|
185
225
|
);
|
|
186
226
|
}
|
|
@@ -273,7 +313,8 @@ export function useNuxtTable(options) {
|
|
|
273
313
|
});
|
|
274
314
|
}
|
|
275
315
|
function toggleColumn(columnKey) {
|
|
276
|
-
|
|
316
|
+
const enabledKeySet = new Set(enabledColumnKeys.value);
|
|
317
|
+
if (enabledKeySet.has(columnKey)) {
|
|
277
318
|
if (enabledColumnKeys.value.length === 1) {
|
|
278
319
|
return;
|
|
279
320
|
}
|
|
@@ -349,15 +390,7 @@ export function useNuxtTable(options) {
|
|
|
349
390
|
dragOverColumnKey.value = null;
|
|
350
391
|
}
|
|
351
392
|
function getColumnStyle(columnKey) {
|
|
352
|
-
|
|
353
|
-
if (!width) {
|
|
354
|
-
return {};
|
|
355
|
-
}
|
|
356
|
-
const safeWidth = Math.max(MIN_COLUMN_WIDTH, width);
|
|
357
|
-
return {
|
|
358
|
-
width: `${safeWidth}px`,
|
|
359
|
-
minWidth: `${safeWidth}px`
|
|
360
|
-
};
|
|
393
|
+
return columnStylesByKey.value[columnKey] ?? EMPTY_STYLE;
|
|
361
394
|
}
|
|
362
395
|
function startColumnResize(event, columnKey) {
|
|
363
396
|
if (!import.meta.client) {
|
|
@@ -381,10 +414,7 @@ export function useNuxtTable(options) {
|
|
|
381
414
|
MIN_COLUMN_WIDTH,
|
|
382
415
|
Math.round(activeResize.value.startWidth + delta)
|
|
383
416
|
);
|
|
384
|
-
columnWidths.value =
|
|
385
|
-
...columnWidths.value,
|
|
386
|
-
[activeResize.value.columnKey]: nextWidth
|
|
387
|
-
};
|
|
417
|
+
columnWidths.value[activeResize.value.columnKey] = nextWidth;
|
|
388
418
|
}
|
|
389
419
|
function onColumnResizeEnd() {
|
|
390
420
|
stopResizing();
|
|
@@ -453,7 +483,11 @@ export function useNuxtTable(options) {
|
|
|
453
483
|
if (typeof resolver === "function") {
|
|
454
484
|
return resolver(row);
|
|
455
485
|
}
|
|
456
|
-
const
|
|
486
|
+
const cachedPath = resolverPathCache.get(resolver);
|
|
487
|
+
const pathParts = cachedPath ?? resolver.split(".");
|
|
488
|
+
if (!cachedPath) {
|
|
489
|
+
resolverPathCache.set(resolver, pathParts);
|
|
490
|
+
}
|
|
457
491
|
let currentValue = row;
|
|
458
492
|
for (const pathPart of pathParts) {
|
|
459
493
|
if (currentValue == null) {
|
|
@@ -68,6 +68,8 @@ export interface UseNuxtTableOptions {
|
|
|
68
68
|
storageKey: Ref<string>;
|
|
69
69
|
rowKey: Ref<string | ((row: TableRow, index: number) => string | number)>;
|
|
70
70
|
enableColumnDnd: Ref<boolean>;
|
|
71
|
+
isManualSortMode?: Ref<boolean>;
|
|
72
|
+
isManualFilterMode?: Ref<boolean>;
|
|
71
73
|
onColumnOrderChange?: (payload: NuxtTableColumnOrderChange) => void;
|
|
72
74
|
onManualSortChange?: (payload: NuxtTableManualSortChange) => void;
|
|
73
75
|
onManualFilterChange?: (payload: NuxtTableManualFilterChange) => void;
|
package/package.json
CHANGED