cisse-vue-ui 0.8.4 → 0.10.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/README.md +666 -4
- package/dist/{CheckboxGroup.vue_vue_type_script_setup_true_lang-B190Yija.js → CheckboxGroup.vue_vue_type_script_setup_true_lang-ZP02bMgY.js} +2 -2
- package/dist/{CheckboxGroup.vue_vue_type_script_setup_true_lang-B190Yija.js.map → CheckboxGroup.vue_vue_type_script_setup_true_lang-ZP02bMgY.js.map} +1 -1
- package/dist/{ConfirmDialog.vue_vue_type_script_setup_true_lang-DWs2V7xX.js → ConfirmDialog.vue_vue_type_script_setup_true_lang-C5KHLMvx.js} +37 -184
- package/dist/ConfirmDialog.vue_vue_type_script_setup_true_lang-C5KHLMvx.js.map +1 -0
- package/dist/{ConfirmDialog.vue_vue_type_script_setup_true_lang-BGUoa5fT.cjs → ConfirmDialog.vue_vue_type_script_setup_true_lang-CLfy0-Wb.cjs} +33 -180
- package/dist/ConfirmDialog.vue_vue_type_script_setup_true_lang-CLfy0-Wb.cjs.map +1 -0
- package/dist/{FilterTabs.vue_vue_type_script_setup_true_lang-BmJHgkBs.js → FilterTabs.vue_vue_type_script_setup_true_lang-CJnvcF8Z.js} +1568 -384
- package/dist/FilterTabs.vue_vue_type_script_setup_true_lang-CJnvcF8Z.js.map +1 -0
- package/dist/{FilterTabs.vue_vue_type_script_setup_true_lang-DYxh-wFx.cjs → FilterTabs.vue_vue_type_script_setup_true_lang-l8lJzwoY.cjs} +1564 -380
- package/dist/FilterTabs.vue_vue_type_script_setup_true_lang-l8lJzwoY.cjs.map +1 -0
- package/dist/ListSkeleton.vue_vue_type_script_setup_true_lang-BHopJ9RG.js +298 -0
- package/dist/ListSkeleton.vue_vue_type_script_setup_true_lang-BHopJ9RG.js.map +1 -0
- package/dist/ListSkeleton.vue_vue_type_script_setup_true_lang-Bo3HqgX0.cjs +297 -0
- package/dist/ListSkeleton.vue_vue_type_script_setup_true_lang-Bo3HqgX0.cjs.map +1 -0
- package/dist/components/core/Breadcrumb.stories.d.ts +5 -0
- package/dist/components/core/CardWrapper.stories.d.ts +32 -0
- package/dist/components/core/CardWrapper.vue.d.ts +129 -0
- package/dist/components/core/CollapsibleCard.vue.d.ts +1 -1
- package/dist/components/core/DataTable.stories.d.ts +38 -0
- package/dist/components/core/Dropdown.vue.d.ts +1 -1
- package/dist/components/core/Popover.vue.d.ts +2 -2
- package/dist/components/core/StatItem.stories.d.ts +25 -0
- package/dist/components/core/StatItem.test.d.ts +1 -0
- package/dist/components/core/StatItem.vue.d.ts +81 -0
- package/dist/components/core/Stats.stories.d.ts +24 -0
- package/dist/components/core/Stats.test.d.ts +1 -0
- package/dist/components/core/Stats.vue.d.ts +41 -0
- package/dist/components/core/Tooltip.stories.d.ts +3 -0
- package/dist/components/core/index.cjs +41 -22
- package/dist/components/core/index.cjs.map +1 -1
- package/dist/components/core/index.d.ts +10 -4
- package/dist/components/core/index.js +41 -22
- package/dist/components/core/table/DataTable.test.d.ts +1 -0
- package/dist/components/core/{TableComponent.vue.d.ts → table/DataTable.vue.d.ts} +60 -7
- package/dist/components/core/table/Table.stories.d.ts +27 -0
- package/dist/components/core/table/atoms/Caption.test.d.ts +1 -0
- package/dist/components/core/table/atoms/Caption.vue.d.ts +26 -0
- package/dist/components/core/table/atoms/Col.test.d.ts +1 -0
- package/dist/components/core/table/atoms/Col.vue.d.ts +8 -0
- package/dist/components/core/table/atoms/Colgroup.test.d.ts +1 -0
- package/dist/components/core/table/atoms/Colgroup.vue.d.ts +17 -0
- package/dist/components/core/table/atoms/Table.test.d.ts +1 -0
- package/dist/components/core/table/atoms/Table.vue.d.ts +46 -0
- package/dist/components/core/table/atoms/Tbody.test.d.ts +1 -0
- package/dist/components/core/table/atoms/Tbody.vue.d.ts +17 -0
- package/dist/components/core/table/atoms/Td.test.d.ts +1 -0
- package/dist/components/core/table/atoms/Td.vue.d.ts +43 -0
- package/dist/components/core/table/atoms/Tfoot.test.d.ts +1 -0
- package/dist/components/core/table/atoms/Tfoot.vue.d.ts +17 -0
- package/dist/components/core/table/atoms/Th.test.d.ts +1 -0
- package/dist/components/core/table/atoms/Th.vue.d.ts +64 -0
- package/dist/components/core/table/atoms/Thead.test.d.ts +1 -0
- package/dist/components/core/table/atoms/Thead.vue.d.ts +17 -0
- package/dist/components/core/table/atoms/Tr.test.d.ts +1 -0
- package/dist/components/core/table/atoms/Tr.vue.d.ts +35 -0
- package/dist/components/core/table/atoms/index.d.ts +10 -0
- package/dist/components/core/table/index.d.ts +3 -0
- package/dist/components/core/table/molecules/ExpandableRow.test.d.ts +1 -0
- package/dist/components/core/table/molecules/ExpandableRow.vue.d.ts +47 -0
- package/dist/components/core/table/molecules/TableFooter.test.d.ts +1 -0
- package/dist/components/core/table/molecules/TableFooter.vue.d.ts +21 -0
- package/dist/components/core/table/molecules/TableHeader.test.d.ts +1 -0
- package/dist/components/core/table/molecules/TableHeader.vue.d.ts +49 -0
- package/dist/components/core/table/molecules/TableRow.test.d.ts +1 -0
- package/dist/components/core/table/molecules/TableRow.vue.d.ts +59 -0
- package/dist/components/core/table/molecules/index.d.ts +4 -0
- package/dist/components/feedback/Progress.vue.d.ts +1 -1
- package/dist/components/feedback/TableSkeleton.vue.d.ts +1 -1
- package/dist/components/feedback/index.cjs +14 -14
- package/dist/components/feedback/index.js +14 -14
- package/dist/components/form/Combobox.vue.d.ts +1 -1
- package/dist/components/form/DatePicker.vue.d.ts +1 -1
- package/dist/components/form/FormSection.vue.d.ts +1 -1
- package/dist/components/form/IconPicker.stories.d.ts +19 -0
- package/dist/components/form/IconPicker.test.d.ts +1 -0
- package/dist/components/form/InputWrapper.stories.d.ts +0 -5
- package/dist/components/form/Rating.vue.d.ts +1 -1
- package/dist/components/form/SearchInput.vue.d.ts +1 -1
- package/dist/components/form/index.js +2 -2
- package/dist/components/index.cjs +55 -36
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +67 -48
- package/dist/composables/index.cjs +15 -8
- package/dist/composables/index.cjs.map +1 -1
- package/dist/composables/index.d.ts +7 -0
- package/dist/composables/index.js +12 -5
- package/dist/composables/useColumnResize.d.ts +38 -0
- package/dist/composables/useColumnResize.test.d.ts +1 -0
- package/dist/composables/useColumnVisibility.d.ts +44 -0
- package/dist/composables/useColumnVisibility.test.d.ts +1 -0
- package/dist/composables/useEditableCell.d.ts +51 -0
- package/dist/composables/useEditableCell.test.d.ts +1 -0
- package/dist/composables/usePagination.d.ts +44 -0
- package/dist/composables/usePagination.test.d.ts +1 -0
- package/dist/composables/usePinnedRows.d.ts +41 -0
- package/dist/composables/usePinnedRows.test.d.ts +1 -0
- package/dist/composables/useTableKeyboardNavigation.d.ts +52 -0
- package/dist/composables/useTableKeyboardNavigation.test.d.ts +1 -0
- package/dist/composables/useVirtualScroll.d.ts +32 -0
- package/dist/composables/useVirtualScroll.test.d.ts +1 -0
- package/dist/{index-SNefWfX0.js → index-BaWpldIJ.js} +3 -3
- package/dist/{index-SNefWfX0.js.map → index-BaWpldIJ.js.map} +1 -1
- package/dist/{index-LFQFhClN.cjs → index-CYXOfUOG.cjs} +56 -37
- package/dist/{index-LFQFhClN.cjs.map → index-CYXOfUOG.cjs.map} +1 -1
- package/dist/index-C_N7WRnM.js +116 -0
- package/dist/index-C_N7WRnM.js.map +1 -0
- package/dist/index.cjs +71 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +81 -55
- package/dist/style.css +1 -1
- package/dist/types/components.d.ts +1 -1
- package/dist/types/property.d.ts +8 -0
- package/dist/usePagination-BGwbICFC.js +135 -0
- package/dist/usePagination-BGwbICFC.js.map +1 -0
- package/dist/usePagination-gvvh1zqA.cjs +134 -0
- package/dist/usePagination-gvvh1zqA.cjs.map +1 -0
- package/dist/useVirtualScroll-BivP86fA.cjs +869 -0
- package/dist/useVirtualScroll-BivP86fA.cjs.map +1 -0
- package/dist/useVirtualScroll-YeZru2Eo.js +870 -0
- package/dist/useVirtualScroll-YeZru2Eo.js.map +1 -0
- package/package.json +1 -1
- package/dist/ConfirmDialog.vue_vue_type_script_setup_true_lang-BGUoa5fT.cjs.map +0 -1
- package/dist/ConfirmDialog.vue_vue_type_script_setup_true_lang-DWs2V7xX.js.map +0 -1
- package/dist/FilterTabs.vue_vue_type_script_setup_true_lang-BmJHgkBs.js.map +0 -1
- package/dist/FilterTabs.vue_vue_type_script_setup_true_lang-DYxh-wFx.cjs.map +0 -1
- package/dist/ListSkeleton.vue_vue_type_script_setup_true_lang-BwtEbaiT.js +0 -150
- package/dist/ListSkeleton.vue_vue_type_script_setup_true_lang-BwtEbaiT.js.map +0 -1
- package/dist/ListSkeleton.vue_vue_type_script_setup_true_lang-DtwwmfWr.cjs +0 -149
- package/dist/ListSkeleton.vue_vue_type_script_setup_true_lang-DtwwmfWr.cjs.map +0 -1
- package/dist/components/core/StatsCard.stories.d.ts +0 -15
- package/dist/components/core/StatsCard.vue.d.ts +0 -44
- package/dist/components/core/StatsGrid.stories.d.ts +0 -12
- package/dist/components/core/StatsGrid.vue.d.ts +0 -16
- package/dist/components/core/TableComponent.stories.d.ts +0 -16
- package/dist/index-CyL_6V7D.js +0 -97
- package/dist/index-CyL_6V7D.js.map +0 -1
- package/dist/useDarkMode-Cl5QWTlC.js +0 -53
- package/dist/useDarkMode-Cl5QWTlC.js.map +0 -1
- package/dist/useDarkMode-DLZcJEUQ.cjs +0 -52
- package/dist/useDarkMode-DLZcJEUQ.cjs.map +0 -1
- package/dist/useToast-Bk60GArg.cjs +0 -176
- package/dist/useToast-Bk60GArg.cjs.map +0 -1
- package/dist/useToast-ina5g3mj.js +0 -177
- package/dist/useToast-ina5g3mj.js.map +0 -1
- /package/dist/components/core/{StatsCard.test.d.ts → AccordionItem.test.d.ts} +0 -0
- /package/dist/components/core/{StatsGrid.test.d.ts → CardWrapper.test.d.ts} +0 -0
|
@@ -0,0 +1,870 @@
|
|
|
1
|
+
import { readonly, ref, computed, onMounted, onUnmounted, watch, shallowRef } from "vue";
|
|
2
|
+
var IDX = 256, HEX = [], SIZE = 256, BUFFER;
|
|
3
|
+
while (IDX--) HEX[IDX] = (IDX + 256).toString(16).substring(1);
|
|
4
|
+
function uid(len) {
|
|
5
|
+
var i = 0, tmp = 11;
|
|
6
|
+
if (!BUFFER || IDX + tmp > SIZE * 2) {
|
|
7
|
+
for (BUFFER = "", IDX = 0; i < SIZE; i++) {
|
|
8
|
+
BUFFER += HEX[Math.random() * 256 | 0];
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return BUFFER.substring(IDX, IDX++ + tmp);
|
|
12
|
+
}
|
|
13
|
+
const notifications = ref([]);
|
|
14
|
+
function useNotifications() {
|
|
15
|
+
const notify = (type, message, options = {}) => {
|
|
16
|
+
const id = uid();
|
|
17
|
+
const notification = {
|
|
18
|
+
id,
|
|
19
|
+
type,
|
|
20
|
+
message,
|
|
21
|
+
title: options.title ?? null,
|
|
22
|
+
duration: options.duration ?? 5e3
|
|
23
|
+
};
|
|
24
|
+
notifications.value.push(notification);
|
|
25
|
+
if (notification.duration && notification.duration > 0) {
|
|
26
|
+
setTimeout(() => remove(id), notification.duration);
|
|
27
|
+
}
|
|
28
|
+
return id;
|
|
29
|
+
};
|
|
30
|
+
const success = (message, options) => notify("success", message, options);
|
|
31
|
+
const warning = (message, options) => notify("warning", message, options);
|
|
32
|
+
const error = (message, options) => notify("error", message, options);
|
|
33
|
+
const info = (message, options) => notify("info", message, options);
|
|
34
|
+
const remove = (id) => {
|
|
35
|
+
notifications.value = notifications.value.filter((n) => n.id !== id);
|
|
36
|
+
};
|
|
37
|
+
const clear = () => {
|
|
38
|
+
notifications.value = [];
|
|
39
|
+
};
|
|
40
|
+
return {
|
|
41
|
+
notifications: readonly(notifications),
|
|
42
|
+
notify,
|
|
43
|
+
success,
|
|
44
|
+
warning,
|
|
45
|
+
error,
|
|
46
|
+
info,
|
|
47
|
+
remove,
|
|
48
|
+
clear
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function useExportCSV() {
|
|
52
|
+
const escapeCSV = (value) => {
|
|
53
|
+
if (value === null || value === void 0) return "";
|
|
54
|
+
const str = String(value);
|
|
55
|
+
if (str.includes(",") || str.includes('"') || str.includes("\n")) {
|
|
56
|
+
return `"${str.replace(/"/g, '""')}"`;
|
|
57
|
+
}
|
|
58
|
+
return str;
|
|
59
|
+
};
|
|
60
|
+
const exportToCSV = (data, columns, filename = "export.csv") => {
|
|
61
|
+
if (!data || data.length === 0) {
|
|
62
|
+
console.warn("No data to export");
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const headers = columns.map((col) => escapeCSV(col.label)).join(",");
|
|
66
|
+
const rows = data.map(
|
|
67
|
+
(item) => columns.map((col) => escapeCSV(item[col.key])).join(",")
|
|
68
|
+
);
|
|
69
|
+
const csv = [headers, ...rows].join("\n");
|
|
70
|
+
const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
|
|
71
|
+
const url = URL.createObjectURL(blob);
|
|
72
|
+
const link = document.createElement("a");
|
|
73
|
+
link.setAttribute("href", url);
|
|
74
|
+
link.setAttribute("download", filename);
|
|
75
|
+
link.style.visibility = "hidden";
|
|
76
|
+
document.body.appendChild(link);
|
|
77
|
+
link.click();
|
|
78
|
+
document.body.removeChild(link);
|
|
79
|
+
URL.revokeObjectURL(url);
|
|
80
|
+
};
|
|
81
|
+
return {
|
|
82
|
+
exportToCSV,
|
|
83
|
+
escapeCSV
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function useModal(options) {
|
|
87
|
+
const {
|
|
88
|
+
initialOpen = false,
|
|
89
|
+
initialData = null,
|
|
90
|
+
onOpen,
|
|
91
|
+
onClose
|
|
92
|
+
} = options ?? {};
|
|
93
|
+
const isOpen = ref(initialOpen);
|
|
94
|
+
const data = ref(initialData);
|
|
95
|
+
const open = (newData) => {
|
|
96
|
+
data.value = newData ?? null;
|
|
97
|
+
isOpen.value = true;
|
|
98
|
+
onOpen == null ? void 0 : onOpen(data.value);
|
|
99
|
+
};
|
|
100
|
+
const close = () => {
|
|
101
|
+
isOpen.value = false;
|
|
102
|
+
data.value = null;
|
|
103
|
+
onClose == null ? void 0 : onClose();
|
|
104
|
+
};
|
|
105
|
+
const toggle = () => {
|
|
106
|
+
if (isOpen.value) {
|
|
107
|
+
close();
|
|
108
|
+
} else {
|
|
109
|
+
open();
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
return {
|
|
113
|
+
isOpen,
|
|
114
|
+
data,
|
|
115
|
+
open,
|
|
116
|
+
close,
|
|
117
|
+
toggle
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function useModals(modals) {
|
|
121
|
+
return modals;
|
|
122
|
+
}
|
|
123
|
+
const toasts = ref([]);
|
|
124
|
+
let toastId = 0;
|
|
125
|
+
function useToast() {
|
|
126
|
+
const add = (options) => {
|
|
127
|
+
const id = `toast-${++toastId}`;
|
|
128
|
+
const toast = {
|
|
129
|
+
id,
|
|
130
|
+
message: options.message,
|
|
131
|
+
type: options.type || "info",
|
|
132
|
+
title: options.title,
|
|
133
|
+
duration: options.duration ?? 5e3
|
|
134
|
+
};
|
|
135
|
+
toasts.value.push(toast);
|
|
136
|
+
return id;
|
|
137
|
+
};
|
|
138
|
+
const remove = (id) => {
|
|
139
|
+
const index = toasts.value.findIndex((t) => t.id === id);
|
|
140
|
+
if (index > -1) {
|
|
141
|
+
toasts.value.splice(index, 1);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
const clear = () => {
|
|
145
|
+
toasts.value = [];
|
|
146
|
+
};
|
|
147
|
+
const success = (message, title) => {
|
|
148
|
+
return add({ message, title, type: "success" });
|
|
149
|
+
};
|
|
150
|
+
const error = (message, title) => {
|
|
151
|
+
return add({ message, title, type: "error" });
|
|
152
|
+
};
|
|
153
|
+
const warning = (message, title) => {
|
|
154
|
+
return add({ message, title, type: "warning" });
|
|
155
|
+
};
|
|
156
|
+
const info = (message, title) => {
|
|
157
|
+
return add({ message, title, type: "info" });
|
|
158
|
+
};
|
|
159
|
+
return {
|
|
160
|
+
toasts,
|
|
161
|
+
add,
|
|
162
|
+
remove,
|
|
163
|
+
clear,
|
|
164
|
+
success,
|
|
165
|
+
error,
|
|
166
|
+
warning,
|
|
167
|
+
info
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function useTableKeyboardNavigation(options) {
|
|
171
|
+
const {
|
|
172
|
+
tableRef,
|
|
173
|
+
rowCount,
|
|
174
|
+
colCount,
|
|
175
|
+
cellNavigation = false,
|
|
176
|
+
onRowActivate,
|
|
177
|
+
onCellActivate,
|
|
178
|
+
onFocusChange,
|
|
179
|
+
skipHeader = true,
|
|
180
|
+
wrap = true
|
|
181
|
+
} = options;
|
|
182
|
+
const focusedRow = ref(skipHeader ? 1 : 0);
|
|
183
|
+
const focusedCol = ref(0);
|
|
184
|
+
const isActive = ref(false);
|
|
185
|
+
const totalRows = computed(() => typeof rowCount === "number" ? rowCount : rowCount.value);
|
|
186
|
+
const totalCols = computed(() => typeof colCount === "number" ? colCount : colCount.value);
|
|
187
|
+
const startRow = computed(() => skipHeader ? 1 : 0);
|
|
188
|
+
const clampRow = (row) => {
|
|
189
|
+
if (wrap) {
|
|
190
|
+
if (row < startRow.value) return totalRows.value - 1;
|
|
191
|
+
if (row >= totalRows.value) return startRow.value;
|
|
192
|
+
return row;
|
|
193
|
+
}
|
|
194
|
+
return Math.max(startRow.value, Math.min(totalRows.value - 1, row));
|
|
195
|
+
};
|
|
196
|
+
const clampCol = (col) => {
|
|
197
|
+
if (wrap) {
|
|
198
|
+
if (col < 0) return totalCols.value - 1;
|
|
199
|
+
if (col >= totalCols.value) return 0;
|
|
200
|
+
return col;
|
|
201
|
+
}
|
|
202
|
+
return Math.max(0, Math.min(totalCols.value - 1, col));
|
|
203
|
+
};
|
|
204
|
+
const setFocusedRow = (index) => {
|
|
205
|
+
focusedRow.value = clampRow(index);
|
|
206
|
+
onFocusChange == null ? void 0 : onFocusChange(focusedRow.value, focusedCol.value);
|
|
207
|
+
};
|
|
208
|
+
const setFocusedCell = (row, col) => {
|
|
209
|
+
focusedRow.value = clampRow(row);
|
|
210
|
+
focusedCol.value = clampCol(col);
|
|
211
|
+
onFocusChange == null ? void 0 : onFocusChange(focusedRow.value, focusedCol.value);
|
|
212
|
+
};
|
|
213
|
+
const activate = () => {
|
|
214
|
+
isActive.value = true;
|
|
215
|
+
focusCurrentElement();
|
|
216
|
+
};
|
|
217
|
+
const deactivate = () => {
|
|
218
|
+
isActive.value = false;
|
|
219
|
+
};
|
|
220
|
+
const focusCurrentElement = () => {
|
|
221
|
+
if (!tableRef.value) return;
|
|
222
|
+
const selector = cellNavigation ? `tr:nth-child(${focusedRow.value + 1}) td:nth-child(${focusedCol.value + 1}), tr:nth-child(${focusedRow.value + 1}) th:nth-child(${focusedCol.value + 1})` : `tr:nth-child(${focusedRow.value + 1})`;
|
|
223
|
+
const element = tableRef.value.querySelector(selector);
|
|
224
|
+
element == null ? void 0 : element.focus();
|
|
225
|
+
};
|
|
226
|
+
const handleKeyDown = (event) => {
|
|
227
|
+
if (!isActive.value) return;
|
|
228
|
+
const { key, shiftKey, ctrlKey, metaKey } = event;
|
|
229
|
+
if (ctrlKey || metaKey) return;
|
|
230
|
+
let handled = false;
|
|
231
|
+
switch (key) {
|
|
232
|
+
case "ArrowDown":
|
|
233
|
+
setFocusedRow(focusedRow.value + 1);
|
|
234
|
+
handled = true;
|
|
235
|
+
break;
|
|
236
|
+
case "ArrowUp":
|
|
237
|
+
setFocusedRow(focusedRow.value - 1);
|
|
238
|
+
handled = true;
|
|
239
|
+
break;
|
|
240
|
+
case "ArrowRight":
|
|
241
|
+
if (cellNavigation) {
|
|
242
|
+
setFocusedCell(focusedRow.value, focusedCol.value + 1);
|
|
243
|
+
handled = true;
|
|
244
|
+
}
|
|
245
|
+
break;
|
|
246
|
+
case "ArrowLeft":
|
|
247
|
+
if (cellNavigation) {
|
|
248
|
+
setFocusedCell(focusedRow.value, focusedCol.value - 1);
|
|
249
|
+
handled = true;
|
|
250
|
+
}
|
|
251
|
+
break;
|
|
252
|
+
case "Home":
|
|
253
|
+
if (cellNavigation) {
|
|
254
|
+
setFocusedCell(shiftKey ? startRow.value : focusedRow.value, 0);
|
|
255
|
+
} else {
|
|
256
|
+
setFocusedRow(startRow.value);
|
|
257
|
+
}
|
|
258
|
+
handled = true;
|
|
259
|
+
break;
|
|
260
|
+
case "End":
|
|
261
|
+
if (cellNavigation) {
|
|
262
|
+
setFocusedCell(
|
|
263
|
+
shiftKey ? totalRows.value - 1 : focusedRow.value,
|
|
264
|
+
totalCols.value - 1
|
|
265
|
+
);
|
|
266
|
+
} else {
|
|
267
|
+
setFocusedRow(totalRows.value - 1);
|
|
268
|
+
}
|
|
269
|
+
handled = true;
|
|
270
|
+
break;
|
|
271
|
+
case "PageDown":
|
|
272
|
+
setFocusedRow(focusedRow.value + 10);
|
|
273
|
+
handled = true;
|
|
274
|
+
break;
|
|
275
|
+
case "PageUp":
|
|
276
|
+
setFocusedRow(focusedRow.value - 10);
|
|
277
|
+
handled = true;
|
|
278
|
+
break;
|
|
279
|
+
case "Enter":
|
|
280
|
+
case " ":
|
|
281
|
+
if (cellNavigation) {
|
|
282
|
+
onCellActivate == null ? void 0 : onCellActivate(focusedRow.value, focusedCol.value);
|
|
283
|
+
} else {
|
|
284
|
+
onRowActivate == null ? void 0 : onRowActivate(focusedRow.value);
|
|
285
|
+
}
|
|
286
|
+
handled = true;
|
|
287
|
+
break;
|
|
288
|
+
case "Escape":
|
|
289
|
+
deactivate();
|
|
290
|
+
handled = true;
|
|
291
|
+
break;
|
|
292
|
+
case "Tab":
|
|
293
|
+
deactivate();
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
if (handled) {
|
|
297
|
+
event.preventDefault();
|
|
298
|
+
event.stopPropagation();
|
|
299
|
+
focusCurrentElement();
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
const getRowProps = (rowIndex) => ({
|
|
303
|
+
tabIndex: focusedRow.value === rowIndex && isActive.value ? 0 : -1,
|
|
304
|
+
"aria-selected": focusedRow.value === rowIndex ? true : void 0,
|
|
305
|
+
onFocus: () => {
|
|
306
|
+
if (!isActive.value) {
|
|
307
|
+
isActive.value = true;
|
|
308
|
+
}
|
|
309
|
+
focusedRow.value = rowIndex;
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
const getCellProps = (rowIndex, colIndex) => ({
|
|
313
|
+
tabIndex: focusedRow.value === rowIndex && focusedCol.value === colIndex && isActive.value ? 0 : -1,
|
|
314
|
+
"aria-selected": focusedRow.value === rowIndex && focusedCol.value === colIndex ? true : void 0,
|
|
315
|
+
onFocus: () => {
|
|
316
|
+
if (!isActive.value) {
|
|
317
|
+
isActive.value = true;
|
|
318
|
+
}
|
|
319
|
+
focusedRow.value = rowIndex;
|
|
320
|
+
focusedCol.value = colIndex;
|
|
321
|
+
}
|
|
322
|
+
});
|
|
323
|
+
const handleTableFocus = () => {
|
|
324
|
+
if (!isActive.value) {
|
|
325
|
+
activate();
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
onMounted(() => {
|
|
329
|
+
var _a;
|
|
330
|
+
(_a = tableRef.value) == null ? void 0 : _a.addEventListener("focus", handleTableFocus, true);
|
|
331
|
+
});
|
|
332
|
+
onUnmounted(() => {
|
|
333
|
+
var _a;
|
|
334
|
+
(_a = tableRef.value) == null ? void 0 : _a.removeEventListener("focus", handleTableFocus, true);
|
|
335
|
+
});
|
|
336
|
+
return {
|
|
337
|
+
focusedRow,
|
|
338
|
+
focusedCol,
|
|
339
|
+
isActive,
|
|
340
|
+
setFocusedRow,
|
|
341
|
+
setFocusedCell,
|
|
342
|
+
activate,
|
|
343
|
+
deactivate,
|
|
344
|
+
getRowProps,
|
|
345
|
+
getCellProps,
|
|
346
|
+
handleKeyDown
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
function useColumnVisibility(options) {
|
|
350
|
+
const {
|
|
351
|
+
columns: columnsOption,
|
|
352
|
+
initialHidden = [],
|
|
353
|
+
persist = false,
|
|
354
|
+
storageKey = "table-column-visibility",
|
|
355
|
+
minVisible = 1
|
|
356
|
+
} = options;
|
|
357
|
+
const loadInitialState = () => {
|
|
358
|
+
if (persist && typeof window !== "undefined") {
|
|
359
|
+
try {
|
|
360
|
+
const stored = localStorage.getItem(storageKey);
|
|
361
|
+
if (stored) {
|
|
362
|
+
return new Set(JSON.parse(stored));
|
|
363
|
+
}
|
|
364
|
+
} catch {
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return new Set(initialHidden);
|
|
368
|
+
};
|
|
369
|
+
const hiddenColumns = ref(loadInitialState());
|
|
370
|
+
const saveState = () => {
|
|
371
|
+
if (persist && typeof window !== "undefined") {
|
|
372
|
+
try {
|
|
373
|
+
localStorage.setItem(storageKey, JSON.stringify([...hiddenColumns.value]));
|
|
374
|
+
} catch {
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
const rawColumns = computed(() => {
|
|
379
|
+
const cols = "value" in columnsOption ? columnsOption.value : columnsOption;
|
|
380
|
+
return cols;
|
|
381
|
+
});
|
|
382
|
+
const columns = computed(() => {
|
|
383
|
+
return rawColumns.value.map((col) => ({
|
|
384
|
+
...col,
|
|
385
|
+
hidden: hiddenColumns.value.has(col.name)
|
|
386
|
+
}));
|
|
387
|
+
});
|
|
388
|
+
const visibleColumns = computed(() => {
|
|
389
|
+
return columns.value.filter((col) => !col.hidden);
|
|
390
|
+
});
|
|
391
|
+
const isVisible = (columnName) => {
|
|
392
|
+
return !hiddenColumns.value.has(columnName);
|
|
393
|
+
};
|
|
394
|
+
const show = (columnName) => {
|
|
395
|
+
hiddenColumns.value.delete(columnName);
|
|
396
|
+
hiddenColumns.value = new Set(hiddenColumns.value);
|
|
397
|
+
saveState();
|
|
398
|
+
};
|
|
399
|
+
const hide = (columnName) => {
|
|
400
|
+
if (visibleColumns.value.length <= minVisible) {
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
hiddenColumns.value.add(columnName);
|
|
404
|
+
hiddenColumns.value = new Set(hiddenColumns.value);
|
|
405
|
+
saveState();
|
|
406
|
+
};
|
|
407
|
+
const toggle = (columnName) => {
|
|
408
|
+
if (isVisible(columnName)) {
|
|
409
|
+
hide(columnName);
|
|
410
|
+
} else {
|
|
411
|
+
show(columnName);
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
const showAll = () => {
|
|
415
|
+
hiddenColumns.value = /* @__PURE__ */ new Set();
|
|
416
|
+
saveState();
|
|
417
|
+
};
|
|
418
|
+
const hideAll = () => {
|
|
419
|
+
const columnsToKeep = rawColumns.value.slice(0, minVisible).map((c) => c.name);
|
|
420
|
+
const newHidden = new Set(
|
|
421
|
+
rawColumns.value.filter((c) => !columnsToKeep.includes(c.name)).map((c) => c.name)
|
|
422
|
+
);
|
|
423
|
+
hiddenColumns.value = newHidden;
|
|
424
|
+
saveState();
|
|
425
|
+
};
|
|
426
|
+
const reset = () => {
|
|
427
|
+
hiddenColumns.value = new Set(initialHidden);
|
|
428
|
+
saveState();
|
|
429
|
+
};
|
|
430
|
+
const setVisibility = (visibility) => {
|
|
431
|
+
const newHidden = /* @__PURE__ */ new Set();
|
|
432
|
+
let visibleCount = 0;
|
|
433
|
+
for (const col of rawColumns.value) {
|
|
434
|
+
const shouldBeVisible = visibility[col.name] ?? true;
|
|
435
|
+
if (shouldBeVisible) {
|
|
436
|
+
visibleCount++;
|
|
437
|
+
} else {
|
|
438
|
+
newHidden.add(col.name);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
if (visibleCount < minVisible) {
|
|
442
|
+
let added = 0;
|
|
443
|
+
for (const col of rawColumns.value) {
|
|
444
|
+
if (newHidden.has(col.name)) {
|
|
445
|
+
newHidden.delete(col.name);
|
|
446
|
+
added++;
|
|
447
|
+
if (visibleCount + added >= minVisible) break;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
hiddenColumns.value = newHidden;
|
|
452
|
+
saveState();
|
|
453
|
+
};
|
|
454
|
+
return {
|
|
455
|
+
columns,
|
|
456
|
+
visibleColumns,
|
|
457
|
+
hiddenColumns,
|
|
458
|
+
isVisible,
|
|
459
|
+
show,
|
|
460
|
+
hide,
|
|
461
|
+
toggle,
|
|
462
|
+
showAll,
|
|
463
|
+
hideAll,
|
|
464
|
+
reset,
|
|
465
|
+
setVisibility
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
function useColumnResize(options) {
|
|
469
|
+
const {
|
|
470
|
+
columns: columnsOption,
|
|
471
|
+
defaultMinWidth = 50,
|
|
472
|
+
defaultMaxWidth = 1e3,
|
|
473
|
+
storageKey,
|
|
474
|
+
persist = false
|
|
475
|
+
} = options;
|
|
476
|
+
const allColumns = computed(() => {
|
|
477
|
+
return "value" in columnsOption ? columnsOption.value : columnsOption;
|
|
478
|
+
});
|
|
479
|
+
const getInitialWidths = () => {
|
|
480
|
+
const map = /* @__PURE__ */ new Map();
|
|
481
|
+
allColumns.value.forEach((col) => {
|
|
482
|
+
map.set(col.name, col.width);
|
|
483
|
+
});
|
|
484
|
+
return map;
|
|
485
|
+
};
|
|
486
|
+
const loadFromStorage = () => {
|
|
487
|
+
if (!persist || !storageKey) return null;
|
|
488
|
+
try {
|
|
489
|
+
const stored = localStorage.getItem(storageKey);
|
|
490
|
+
if (stored) {
|
|
491
|
+
const parsed = JSON.parse(stored);
|
|
492
|
+
return new Map(Object.entries(parsed));
|
|
493
|
+
}
|
|
494
|
+
} catch {
|
|
495
|
+
}
|
|
496
|
+
return null;
|
|
497
|
+
};
|
|
498
|
+
const saveToStorage = () => {
|
|
499
|
+
if (!persist || !storageKey) return;
|
|
500
|
+
try {
|
|
501
|
+
const obj = Object.fromEntries(widths.value);
|
|
502
|
+
localStorage.setItem(storageKey, JSON.stringify(obj));
|
|
503
|
+
} catch {
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
const widths = ref(loadFromStorage() ?? getInitialWidths());
|
|
507
|
+
watch(
|
|
508
|
+
allColumns,
|
|
509
|
+
(newColumns) => {
|
|
510
|
+
const stored = loadFromStorage();
|
|
511
|
+
newColumns.forEach((col) => {
|
|
512
|
+
if (!widths.value.has(col.name)) {
|
|
513
|
+
widths.value.set(col.name, (stored == null ? void 0 : stored.get(col.name)) ?? col.width);
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
},
|
|
517
|
+
{ deep: true }
|
|
518
|
+
);
|
|
519
|
+
const resizingColumn = ref(null);
|
|
520
|
+
const startX = ref(0);
|
|
521
|
+
const startWidth = ref(0);
|
|
522
|
+
const isResizing = computed(() => resizingColumn.value !== null);
|
|
523
|
+
const columnWidths = computed(() => {
|
|
524
|
+
const result = {};
|
|
525
|
+
widths.value.forEach((width, name) => {
|
|
526
|
+
result[name] = width;
|
|
527
|
+
});
|
|
528
|
+
return result;
|
|
529
|
+
});
|
|
530
|
+
const getWidth = (name) => {
|
|
531
|
+
var _a;
|
|
532
|
+
return widths.value.get(name) ?? ((_a = allColumns.value.find((c) => c.name === name)) == null ? void 0 : _a.width) ?? 100;
|
|
533
|
+
};
|
|
534
|
+
const getColumnConfig = (name) => {
|
|
535
|
+
return allColumns.value.find((c) => c.name === name);
|
|
536
|
+
};
|
|
537
|
+
const setWidth = (name, width) => {
|
|
538
|
+
const config = getColumnConfig(name);
|
|
539
|
+
const minWidth = (config == null ? void 0 : config.minWidth) ?? defaultMinWidth;
|
|
540
|
+
const maxWidth = (config == null ? void 0 : config.maxWidth) ?? defaultMaxWidth;
|
|
541
|
+
const clampedWidth = Math.max(minWidth, Math.min(maxWidth, width));
|
|
542
|
+
const newWidths = new Map(widths.value);
|
|
543
|
+
newWidths.set(name, clampedWidth);
|
|
544
|
+
widths.value = newWidths;
|
|
545
|
+
saveToStorage();
|
|
546
|
+
};
|
|
547
|
+
const handleMouseMove = (event) => {
|
|
548
|
+
if (!resizingColumn.value) return;
|
|
549
|
+
const clientX = "touches" in event ? event.touches[0].clientX : event.clientX;
|
|
550
|
+
const deltaX = clientX - startX.value;
|
|
551
|
+
const newWidth = startWidth.value + deltaX;
|
|
552
|
+
setWidth(resizingColumn.value, newWidth);
|
|
553
|
+
};
|
|
554
|
+
const handleMouseUp = () => {
|
|
555
|
+
resizingColumn.value = null;
|
|
556
|
+
document.removeEventListener("mousemove", handleMouseMove);
|
|
557
|
+
document.removeEventListener("mouseup", handleMouseUp);
|
|
558
|
+
document.removeEventListener("touchmove", handleMouseMove);
|
|
559
|
+
document.removeEventListener("touchend", handleMouseUp);
|
|
560
|
+
document.body.style.cursor = "";
|
|
561
|
+
document.body.style.userSelect = "";
|
|
562
|
+
};
|
|
563
|
+
const startResize = (name, event) => {
|
|
564
|
+
event.preventDefault();
|
|
565
|
+
resizingColumn.value = name;
|
|
566
|
+
startX.value = "touches" in event ? event.touches[0].clientX : event.clientX;
|
|
567
|
+
startWidth.value = getWidth(name);
|
|
568
|
+
document.addEventListener("mousemove", handleMouseMove);
|
|
569
|
+
document.addEventListener("mouseup", handleMouseUp);
|
|
570
|
+
document.addEventListener("touchmove", handleMouseMove);
|
|
571
|
+
document.addEventListener("touchend", handleMouseUp);
|
|
572
|
+
document.body.style.cursor = "col-resize";
|
|
573
|
+
document.body.style.userSelect = "none";
|
|
574
|
+
};
|
|
575
|
+
const reset = () => {
|
|
576
|
+
widths.value = getInitialWidths();
|
|
577
|
+
saveToStorage();
|
|
578
|
+
};
|
|
579
|
+
const resetColumn = (name) => {
|
|
580
|
+
const config = getColumnConfig(name);
|
|
581
|
+
if (config) {
|
|
582
|
+
setWidth(name, config.width);
|
|
583
|
+
}
|
|
584
|
+
};
|
|
585
|
+
return {
|
|
586
|
+
columnWidths,
|
|
587
|
+
getWidth,
|
|
588
|
+
setWidth,
|
|
589
|
+
startResize,
|
|
590
|
+
isResizing,
|
|
591
|
+
resizingColumn,
|
|
592
|
+
reset,
|
|
593
|
+
resetColumn
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
function usePinnedRows(options = {}) {
|
|
597
|
+
const {
|
|
598
|
+
keyField = "id",
|
|
599
|
+
initialPinned = [],
|
|
600
|
+
maxPinnedTop = Infinity,
|
|
601
|
+
maxPinnedBottom = Infinity
|
|
602
|
+
} = options;
|
|
603
|
+
const getItemKey = (item) => {
|
|
604
|
+
const key = item[keyField];
|
|
605
|
+
return String(key ?? Math.random());
|
|
606
|
+
};
|
|
607
|
+
const pinnedMap = shallowRef(
|
|
608
|
+
new Map(initialPinned.map((p) => [getItemKey(p.item), p]))
|
|
609
|
+
);
|
|
610
|
+
const pinnedTop = computed(() => {
|
|
611
|
+
const items = [];
|
|
612
|
+
pinnedMap.value.forEach(({ item, position }) => {
|
|
613
|
+
if (position === "top") {
|
|
614
|
+
items.push(item);
|
|
615
|
+
}
|
|
616
|
+
});
|
|
617
|
+
return items;
|
|
618
|
+
});
|
|
619
|
+
const pinnedBottom = computed(() => {
|
|
620
|
+
const items = [];
|
|
621
|
+
pinnedMap.value.forEach(({ item, position }) => {
|
|
622
|
+
if (position === "bottom") {
|
|
623
|
+
items.push(item);
|
|
624
|
+
}
|
|
625
|
+
});
|
|
626
|
+
return items;
|
|
627
|
+
});
|
|
628
|
+
const pinnedKeys = computed(() => {
|
|
629
|
+
return new Set(pinnedMap.value.keys());
|
|
630
|
+
});
|
|
631
|
+
const isPinned = (item) => {
|
|
632
|
+
return pinnedMap.value.has(getItemKey(item));
|
|
633
|
+
};
|
|
634
|
+
const getPinPosition = (item) => {
|
|
635
|
+
const pinned = pinnedMap.value.get(getItemKey(item));
|
|
636
|
+
return (pinned == null ? void 0 : pinned.position) ?? null;
|
|
637
|
+
};
|
|
638
|
+
const pin = (item, position) => {
|
|
639
|
+
const currentCount = position === "top" ? pinnedTop.value.length : pinnedBottom.value.length;
|
|
640
|
+
const maxCount = position === "top" ? maxPinnedTop : maxPinnedBottom;
|
|
641
|
+
if (currentCount >= maxCount && getPinPosition(item) !== position) {
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
const key = getItemKey(item);
|
|
645
|
+
const newMap = new Map(pinnedMap.value);
|
|
646
|
+
newMap.set(key, { item, position });
|
|
647
|
+
pinnedMap.value = newMap;
|
|
648
|
+
};
|
|
649
|
+
const unpin = (item) => {
|
|
650
|
+
const key = getItemKey(item);
|
|
651
|
+
if (pinnedMap.value.has(key)) {
|
|
652
|
+
const newMap = new Map(pinnedMap.value);
|
|
653
|
+
newMap.delete(key);
|
|
654
|
+
pinnedMap.value = newMap;
|
|
655
|
+
}
|
|
656
|
+
};
|
|
657
|
+
const togglePin = (item, position = "top") => {
|
|
658
|
+
if (isPinned(item)) {
|
|
659
|
+
unpin(item);
|
|
660
|
+
} else {
|
|
661
|
+
pin(item, position);
|
|
662
|
+
}
|
|
663
|
+
};
|
|
664
|
+
const movePin = (item, newPosition) => {
|
|
665
|
+
if (isPinned(item)) {
|
|
666
|
+
pin(item, newPosition);
|
|
667
|
+
}
|
|
668
|
+
};
|
|
669
|
+
const clearAll = () => {
|
|
670
|
+
pinnedMap.value = /* @__PURE__ */ new Map();
|
|
671
|
+
};
|
|
672
|
+
const clear = (position) => {
|
|
673
|
+
const newMap = /* @__PURE__ */ new Map();
|
|
674
|
+
pinnedMap.value.forEach((pinned, key) => {
|
|
675
|
+
if (pinned.position !== position) {
|
|
676
|
+
newMap.set(key, pinned);
|
|
677
|
+
}
|
|
678
|
+
});
|
|
679
|
+
pinnedMap.value = newMap;
|
|
680
|
+
};
|
|
681
|
+
return {
|
|
682
|
+
pinnedTop,
|
|
683
|
+
pinnedBottom,
|
|
684
|
+
pinnedKeys,
|
|
685
|
+
isPinned,
|
|
686
|
+
getPinPosition,
|
|
687
|
+
pin,
|
|
688
|
+
unpin,
|
|
689
|
+
togglePin,
|
|
690
|
+
movePin,
|
|
691
|
+
clearAll,
|
|
692
|
+
clear
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
function useEditableCell(options = {}) {
|
|
696
|
+
const {
|
|
697
|
+
keyField = "id",
|
|
698
|
+
onSave,
|
|
699
|
+
onCancel,
|
|
700
|
+
validate
|
|
701
|
+
} = options;
|
|
702
|
+
const editingCell = ref(null);
|
|
703
|
+
const editValue = ref(null);
|
|
704
|
+
const error = ref(null);
|
|
705
|
+
const saving = ref(false);
|
|
706
|
+
const currentItem = ref(null);
|
|
707
|
+
const originalValue = ref(null);
|
|
708
|
+
const getItemKey = (item) => {
|
|
709
|
+
const key = item[keyField];
|
|
710
|
+
return String(key ?? Math.random());
|
|
711
|
+
};
|
|
712
|
+
const isEditing = (rowKey, field) => {
|
|
713
|
+
var _a, _b;
|
|
714
|
+
return ((_a = editingCell.value) == null ? void 0 : _a.rowKey) === rowKey && ((_b = editingCell.value) == null ? void 0 : _b.field) === field;
|
|
715
|
+
};
|
|
716
|
+
const startEdit = (item, field, currentValue) => {
|
|
717
|
+
if (editingCell.value) {
|
|
718
|
+
cancelEdit();
|
|
719
|
+
}
|
|
720
|
+
currentItem.value = item;
|
|
721
|
+
originalValue.value = currentValue;
|
|
722
|
+
editValue.value = currentValue;
|
|
723
|
+
error.value = null;
|
|
724
|
+
editingCell.value = {
|
|
725
|
+
rowKey: getItemKey(item),
|
|
726
|
+
field
|
|
727
|
+
};
|
|
728
|
+
};
|
|
729
|
+
const confirmEdit = async () => {
|
|
730
|
+
if (!editingCell.value || !currentItem.value) return;
|
|
731
|
+
const event = {
|
|
732
|
+
item: currentItem.value,
|
|
733
|
+
field: editingCell.value.field,
|
|
734
|
+
originalValue: originalValue.value,
|
|
735
|
+
newValue: editValue.value
|
|
736
|
+
};
|
|
737
|
+
if (validate) {
|
|
738
|
+
const validationError = validate(event);
|
|
739
|
+
if (validationError) {
|
|
740
|
+
error.value = validationError;
|
|
741
|
+
return;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
saving.value = true;
|
|
745
|
+
error.value = null;
|
|
746
|
+
try {
|
|
747
|
+
if (onSave) {
|
|
748
|
+
await onSave(event);
|
|
749
|
+
}
|
|
750
|
+
editingCell.value = null;
|
|
751
|
+
editValue.value = null;
|
|
752
|
+
currentItem.value = null;
|
|
753
|
+
originalValue.value = null;
|
|
754
|
+
} catch (e) {
|
|
755
|
+
error.value = e instanceof Error ? e.message : "Failed to save";
|
|
756
|
+
} finally {
|
|
757
|
+
saving.value = false;
|
|
758
|
+
}
|
|
759
|
+
};
|
|
760
|
+
const cancelEdit = () => {
|
|
761
|
+
if (editingCell.value && currentItem.value && onCancel) {
|
|
762
|
+
onCancel({
|
|
763
|
+
item: currentItem.value,
|
|
764
|
+
field: editingCell.value.field,
|
|
765
|
+
originalValue: originalValue.value
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
editingCell.value = null;
|
|
769
|
+
editValue.value = null;
|
|
770
|
+
error.value = null;
|
|
771
|
+
currentItem.value = null;
|
|
772
|
+
originalValue.value = null;
|
|
773
|
+
};
|
|
774
|
+
const updateValue = (value) => {
|
|
775
|
+
editValue.value = value;
|
|
776
|
+
error.value = null;
|
|
777
|
+
};
|
|
778
|
+
const editingItem = computed(() => currentItem.value);
|
|
779
|
+
return {
|
|
780
|
+
editingCell,
|
|
781
|
+
editValue,
|
|
782
|
+
error,
|
|
783
|
+
saving,
|
|
784
|
+
isEditing,
|
|
785
|
+
startEdit,
|
|
786
|
+
confirmEdit,
|
|
787
|
+
cancelEdit,
|
|
788
|
+
updateValue,
|
|
789
|
+
editingItem
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
function useVirtualScroll(options) {
|
|
793
|
+
const {
|
|
794
|
+
items: itemsOption,
|
|
795
|
+
rowHeight,
|
|
796
|
+
containerHeight,
|
|
797
|
+
overscan = 3
|
|
798
|
+
} = options;
|
|
799
|
+
const scrollTop = ref(0);
|
|
800
|
+
const containerRef = ref(null);
|
|
801
|
+
const allItems = computed(() => {
|
|
802
|
+
return "value" in itemsOption ? itemsOption.value : itemsOption;
|
|
803
|
+
});
|
|
804
|
+
const totalHeight = computed(() => {
|
|
805
|
+
return allItems.value.length * rowHeight;
|
|
806
|
+
});
|
|
807
|
+
const visibleCount = computed(() => {
|
|
808
|
+
return Math.ceil(containerHeight / rowHeight);
|
|
809
|
+
});
|
|
810
|
+
const startIndex = computed(() => {
|
|
811
|
+
const rawStart = Math.floor(scrollTop.value / rowHeight);
|
|
812
|
+
return Math.max(0, rawStart - overscan);
|
|
813
|
+
});
|
|
814
|
+
const endIndex = computed(() => {
|
|
815
|
+
const rawEnd = startIndex.value + visibleCount.value + overscan * 2;
|
|
816
|
+
return Math.min(allItems.value.length, rawEnd);
|
|
817
|
+
});
|
|
818
|
+
const visibleItems = computed(() => {
|
|
819
|
+
return allItems.value.slice(startIndex.value, endIndex.value);
|
|
820
|
+
});
|
|
821
|
+
const offsetY = computed(() => {
|
|
822
|
+
return startIndex.value * rowHeight;
|
|
823
|
+
});
|
|
824
|
+
const onScroll = (event) => {
|
|
825
|
+
const target = event.target;
|
|
826
|
+
scrollTop.value = target.scrollTop;
|
|
827
|
+
};
|
|
828
|
+
const scrollToIndex = (index) => {
|
|
829
|
+
const targetScroll = index * rowHeight;
|
|
830
|
+
if (containerRef.value) {
|
|
831
|
+
containerRef.value.scrollTop = targetScroll;
|
|
832
|
+
}
|
|
833
|
+
scrollTop.value = targetScroll;
|
|
834
|
+
};
|
|
835
|
+
onMounted(() => {
|
|
836
|
+
if (containerRef.value) {
|
|
837
|
+
containerRef.value.addEventListener("scroll", onScroll, { passive: true });
|
|
838
|
+
}
|
|
839
|
+
});
|
|
840
|
+
onUnmounted(() => {
|
|
841
|
+
if (containerRef.value) {
|
|
842
|
+
containerRef.value.removeEventListener("scroll", onScroll);
|
|
843
|
+
}
|
|
844
|
+
});
|
|
845
|
+
return {
|
|
846
|
+
visibleItems,
|
|
847
|
+
totalHeight,
|
|
848
|
+
offsetY,
|
|
849
|
+
startIndex,
|
|
850
|
+
endIndex,
|
|
851
|
+
scrollTop,
|
|
852
|
+
onScroll,
|
|
853
|
+
scrollToIndex,
|
|
854
|
+
containerRef
|
|
855
|
+
};
|
|
856
|
+
}
|
|
857
|
+
export {
|
|
858
|
+
useExportCSV as a,
|
|
859
|
+
useModal as b,
|
|
860
|
+
useModals as c,
|
|
861
|
+
useToast as d,
|
|
862
|
+
useTableKeyboardNavigation as e,
|
|
863
|
+
useColumnVisibility as f,
|
|
864
|
+
useColumnResize as g,
|
|
865
|
+
usePinnedRows as h,
|
|
866
|
+
useEditableCell as i,
|
|
867
|
+
useVirtualScroll as j,
|
|
868
|
+
useNotifications as u
|
|
869
|
+
};
|
|
870
|
+
//# sourceMappingURL=useVirtualScroll-YeZru2Eo.js.map
|