@shwfed/nuxt 0.7.9 → 0.7.11

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.
Files changed (108) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/runtime/components/app.d.vue.ts +7 -56
  3. package/dist/runtime/components/app.vue +17 -404
  4. package/dist/runtime/components/app.vue.d.ts +7 -56
  5. package/dist/runtime/components/fields.d.vue.ts +154 -132
  6. package/dist/runtime/components/fields.vue +30 -295
  7. package/dist/runtime/components/fields.vue.d.ts +154 -132
  8. package/dist/runtime/components/table.d.vue.ts +129 -59
  9. package/dist/runtime/components/table.vue +51 -617
  10. package/dist/runtime/components/table.vue.d.ts +129 -59
  11. package/dist/runtime/components/ui/app/App.d.vue.ts +86 -0
  12. package/dist/runtime/components/ui/app/App.vue +414 -0
  13. package/dist/runtime/components/ui/app/App.vue.d.ts +86 -0
  14. package/dist/runtime/components/ui/checkbox/Checkbox.vue +6 -2
  15. package/dist/runtime/components/ui/dropdown-menu/DropdownMenuItem.vue +1 -1
  16. package/dist/runtime/components/ui/expression-editor/ExpressionEditor.d.vue.ts +30 -0
  17. package/dist/runtime/components/ui/expression-editor/ExpressionEditor.vue +87 -0
  18. package/dist/runtime/components/ui/expression-editor/ExpressionEditor.vue.d.ts +30 -0
  19. package/dist/runtime/components/ui/expression-editor/index.d.ts +1 -0
  20. package/dist/runtime/components/ui/expression-editor/index.js +1 -0
  21. package/dist/runtime/components/ui/field/FieldContent.vue +1 -1
  22. package/dist/runtime/components/ui/field/FieldError.vue +2 -2
  23. package/dist/runtime/components/ui/field/FieldLabel.vue +1 -1
  24. package/dist/runtime/components/ui/fields/Fields.d.vue.ts +376 -0
  25. package/dist/runtime/components/ui/fields/Fields.vue +441 -0
  26. package/dist/runtime/components/ui/fields/Fields.vue.d.ts +376 -0
  27. package/dist/runtime/components/ui/fields-configurator/FieldsConfiguratorDialog.d.vue.ts +163 -0
  28. package/dist/runtime/components/ui/fields-configurator/FieldsConfiguratorDialog.vue +363 -0
  29. package/dist/runtime/components/ui/fields-configurator/FieldsConfiguratorDialog.vue.d.ts +163 -0
  30. package/dist/runtime/components/ui/icon-picker/IconPicker.d.vue.ts +15 -0
  31. package/dist/runtime/components/ui/icon-picker/IconPicker.vue +178 -0
  32. package/dist/runtime/components/ui/icon-picker/IconPicker.vue.d.ts +15 -0
  33. package/dist/runtime/components/ui/icon-picker/index.d.ts +1 -0
  34. package/dist/runtime/components/ui/icon-picker/index.js +1 -0
  35. package/dist/runtime/components/ui/input/Input.d.vue.ts +1 -0
  36. package/dist/runtime/components/ui/input/Input.vue +2 -0
  37. package/dist/runtime/components/ui/input/Input.vue.d.ts +1 -0
  38. package/dist/runtime/components/ui/input-group/InputGroupAddon.vue +4 -1
  39. package/dist/runtime/components/ui/input-group/InputGroupCombobox.d.vue.ts +8 -3
  40. package/dist/runtime/components/ui/input-group/InputGroupCombobox.vue +8 -3
  41. package/dist/runtime/components/ui/input-group/InputGroupCombobox.vue.d.ts +8 -3
  42. package/dist/runtime/components/ui/input-group/InputGroupComboboxInput.d.vue.ts +8 -1
  43. package/dist/runtime/components/ui/input-group/InputGroupComboboxInput.vue +11 -2
  44. package/dist/runtime/components/ui/input-group/InputGroupComboboxInput.vue.d.ts +8 -1
  45. package/dist/runtime/components/ui/input-group/InputGroupInput.vue +1 -1
  46. package/dist/runtime/components/ui/input-group/InputGroupNumberField.d.vue.ts +5 -2
  47. package/dist/runtime/components/ui/input-group/InputGroupNumberField.vue +10 -4
  48. package/dist/runtime/components/ui/input-group/InputGroupNumberField.vue.d.ts +5 -2
  49. package/dist/runtime/components/ui/input-group/InputGroupTextarea.vue +1 -1
  50. package/dist/runtime/components/ui/input-group/index.js +1 -1
  51. package/dist/runtime/components/ui/locale/Locale.d.vue.ts +20 -0
  52. package/dist/runtime/components/ui/locale/Locale.vue +291 -0
  53. package/dist/runtime/components/ui/locale/Locale.vue.d.ts +20 -0
  54. package/dist/runtime/components/ui/locale/index.d.ts +1 -0
  55. package/dist/runtime/components/ui/locale/index.js +1 -0
  56. package/dist/runtime/components/ui/native-select/NativeSelect.d.vue.ts +2 -2
  57. package/dist/runtime/components/ui/native-select/NativeSelect.vue +1 -1
  58. package/dist/runtime/components/ui/native-select/NativeSelect.vue.d.ts +2 -2
  59. package/dist/runtime/components/ui/native-select/NativeSelectOption.d.vue.ts +1 -0
  60. package/dist/runtime/components/ui/native-select/NativeSelectOption.vue +4 -1
  61. package/dist/runtime/components/ui/native-select/NativeSelectOption.vue.d.ts +1 -0
  62. package/dist/runtime/components/ui/number-field/NumberFieldInput.vue +1 -1
  63. package/dist/runtime/components/ui/switch/Switch.vue +2 -2
  64. package/dist/runtime/components/ui/table/Table.d.vue.ts +147 -0
  65. package/dist/runtime/components/ui/table/Table.vue +952 -0
  66. package/dist/runtime/components/ui/table/Table.vue.d.ts +147 -0
  67. package/dist/runtime/components/ui/table/schema.d.ts +151 -0
  68. package/dist/runtime/components/ui/table/schema.js +142 -0
  69. package/dist/runtime/components/ui/table-configurator/TableConfiguratorDialog.d.vue.ts +128 -0
  70. package/dist/runtime/components/ui/table-configurator/TableConfiguratorDialog.vue +2719 -0
  71. package/dist/runtime/components/ui/table-configurator/TableConfiguratorDialog.vue.d.ts +128 -0
  72. package/dist/runtime/components/ui/table-configurator/menu.d.ts +37 -0
  73. package/dist/runtime/components/ui/table-configurator/menu.js +227 -0
  74. package/dist/runtime/components/ui/tabs/Tabs.d.vue.ts +24 -0
  75. package/dist/runtime/components/ui/tabs/Tabs.vue +30 -0
  76. package/dist/runtime/components/ui/tabs/Tabs.vue.d.ts +24 -0
  77. package/dist/runtime/components/ui/tabs/TabsContent.d.vue.ts +18 -0
  78. package/dist/runtime/components/ui/tabs/TabsContent.vue +23 -0
  79. package/dist/runtime/components/ui/tabs/TabsContent.vue.d.ts +18 -0
  80. package/dist/runtime/components/ui/tabs/TabsList.d.vue.ts +18 -0
  81. package/dist/runtime/components/ui/tabs/TabsList.vue +25 -0
  82. package/dist/runtime/components/ui/tabs/TabsList.vue.d.ts +18 -0
  83. package/dist/runtime/components/ui/tabs/TabsTrigger.d.vue.ts +18 -0
  84. package/dist/runtime/components/ui/tabs/TabsTrigger.vue +27 -0
  85. package/dist/runtime/components/ui/tabs/TabsTrigger.vue.d.ts +18 -0
  86. package/dist/runtime/components/ui/tabs/index.d.ts +4 -0
  87. package/dist/runtime/components/ui/tabs/index.js +4 -0
  88. package/dist/runtime/components/ui/textarea/Textarea.d.vue.ts +1 -0
  89. package/dist/runtime/components/ui/textarea/Textarea.vue +4 -2
  90. package/dist/runtime/components/ui/textarea/Textarea.vue.d.ts +1 -0
  91. package/dist/runtime/components/ui/toggle/Toggle.d.vue.ts +34 -0
  92. package/dist/runtime/components/ui/toggle/Toggle.vue +32 -0
  93. package/dist/runtime/components/ui/toggle/Toggle.vue.d.ts +34 -0
  94. package/dist/runtime/components/ui/toggle/index.d.ts +7 -0
  95. package/dist/runtime/components/ui/toggle/index.js +22 -0
  96. package/dist/runtime/composables/useTableRenderers.d.ts +2 -1
  97. package/dist/runtime/composables/useTableRenderers.js +2 -1
  98. package/dist/runtime/plugins/toast/index.d.ts +2 -2
  99. package/dist/runtime/style.css +1 -1
  100. package/dist/runtime/table-renderers/builtins.js +328 -137
  101. package/dist/runtime/table-renderers/registry.d.ts +2 -1
  102. package/dist/runtime/table-renderers/registry.js +3 -0
  103. package/dist/runtime/utils/coders.d.ts +29 -2
  104. package/dist/runtime/utils/coders.js +40 -2
  105. package/package.json +8 -6
  106. /package/dist/runtime/components/{logo.d.vue.ts → ui/logo/Logo.d.vue.ts} +0 -0
  107. /package/dist/runtime/components/{logo.vue → ui/logo/Logo.vue} +0 -0
  108. /package/dist/runtime/components/{logo.vue.d.ts → ui/logo/Logo.vue.d.ts} +0 -0
@@ -0,0 +1,952 @@
1
+ <script setup>
2
+ import { useNuxtApp } from "#app";
3
+ import { useCheating } from "#imports";
4
+ import { Icon } from "@iconify/vue";
5
+ import {
6
+ FlexRender,
7
+ getCoreRowModel,
8
+ getExpandedRowModel,
9
+ getPaginationRowModel,
10
+ getSortedRowModel,
11
+ useVueTable
12
+ } from "@tanstack/vue-table";
13
+ import { useVirtualizer } from "@tanstack/vue-virtual";
14
+ import { computedAsync } from "@vueuse/core";
15
+ import { getProperty } from "dot-prop";
16
+ import { Effect } from "effect";
17
+ import { Pagination } from "reka-ui/namespaced";
18
+ import { computed, ref, watch } from "vue";
19
+ import { useI18n } from "vue-i18n";
20
+ import { useTableRenderers } from "../../../composables/useTableRenderers";
21
+ import { getLocalizedText } from "../../../utils/coders";
22
+ import {
23
+ normalizePaginationPageSizes,
24
+ resolvePaginationPageSize,
25
+ TableConfigC
26
+ } from "./schema";
27
+ import { Button } from "../button";
28
+ import { NativeSelect, NativeSelectOption } from "../native-select";
29
+ import { NumberField, NumberFieldInput } from "../number-field";
30
+ import { Skeleton } from "../skeleton";
31
+ import TableConfiguratorDialog from "../table-configurator/TableConfiguratorDialog.vue";
32
+ import { Tooltip, TooltipContent, TooltipTrigger } from "../tooltip";
33
+ const props = defineProps({
34
+ config: { type: null, required: true },
35
+ data: { type: Array, required: true },
36
+ rowCount: { type: Number, required: false }
37
+ });
38
+ const emit = defineEmits(["update:config"]);
39
+ const resolvedConfig = computedAsync(async () => TableConfigC.parse(await props.config.pipe(Effect.runPromise)));
40
+ const currentConfig = ref();
41
+ const { t, locale } = useI18n();
42
+ const slots = defineSlots();
43
+ const { $dsl } = useNuxtApp();
44
+ const isCheating = useCheating();
45
+ const { resolveTableRenderer } = useTableRenderers();
46
+ const containerRef = ref(null);
47
+ const appliedInitialStateKey = ref("");
48
+ watch(resolvedConfig, (config) => {
49
+ if (config !== void 0) {
50
+ currentConfig.value = config;
51
+ }
52
+ }, { immediate: true });
53
+ function genColumnId(column) {
54
+ if (typeof column.accessor === "string") {
55
+ return column.accessor;
56
+ } else if (column.accessor) {
57
+ return column.accessor.read;
58
+ } else if (column.id) {
59
+ return column.id;
60
+ }
61
+ return crypto.randomUUID();
62
+ }
63
+ function getColumnTitle(column) {
64
+ return getLocalizedText(column.title, locale.value) ?? genColumnId(column);
65
+ }
66
+ function getColumnTooltip(column) {
67
+ return getLocalizedText(column.tooltip, locale.value);
68
+ }
69
+ function translate(column) {
70
+ if (Array.isArray(column.columns) && column.columns.length > 0) {
71
+ return {
72
+ id: column.id ?? genColumnId(column),
73
+ header: getColumnTitle(column),
74
+ columns: column.columns?.map((column2) => translate(column2)) ?? [],
75
+ enableSorting: column.enableSorting ?? false,
76
+ enableMultiSort: column.enableMultiSorting,
77
+ enablePinning: column.enablePinning,
78
+ size: column.size,
79
+ meta: {
80
+ tooltip: getColumnTooltip(column),
81
+ grow: column.grow ?? false,
82
+ accessor: column.accessor
83
+ }
84
+ };
85
+ }
86
+ const renderer = resolveTableRenderer(typeof column.renderer === "string" ? column.renderer : column.renderer?.id ? column.renderer.id : "table.renderer.text");
87
+ const options = renderer.parseOptions(column.renderer && typeof column.renderer === "object" && "props" in column.renderer ? column.renderer.props : null);
88
+ return {
89
+ id: column.id ?? genColumnId(column),
90
+ header: (ctx) => renderer.header?.({ ctx, options }) ?? getColumnTitle(column),
91
+ cell: (ctx) => {
92
+ const slot = slots[ctx.column.id];
93
+ if (slot) {
94
+ return slot({ cell: ctx });
95
+ }
96
+ return renderer.cell({ ctx, options });
97
+ },
98
+ accessorFn: (row, index) => {
99
+ const key = column.accessor;
100
+ if (typeof key === "string") {
101
+ return getProperty(row, key);
102
+ } else if (key !== void 0) {
103
+ try {
104
+ return $dsl.evaluate`${key.read}`({
105
+ row,
106
+ index: BigInt(index)
107
+ });
108
+ } catch (e) {
109
+ console.error(e);
110
+ return void 0;
111
+ }
112
+ }
113
+ return void 0;
114
+ },
115
+ enableSorting: column.enableSorting ?? false,
116
+ enableMultiSort: column.enableMultiSorting,
117
+ enablePinning: column.enablePinning,
118
+ size: column.size,
119
+ columns: column.columns?.map((column2) => translate(column2)) ?? [],
120
+ meta: {
121
+ tooltip: getColumnTooltip(column),
122
+ grow: column.grow ?? false,
123
+ accessor: column.accessor
124
+ },
125
+ ...renderer.columnDefOverrides
126
+ };
127
+ }
128
+ const columns = computed(() => currentConfig.value?.columns.map((column) => translate(column)) ?? []);
129
+ const data = computed(() => props.data);
130
+ const isManualPagination = computed(() => props.rowCount !== void 0);
131
+ const totalItems = computed(() => props.rowCount ?? data.value.length);
132
+ const paginationLeft = computed(() => currentConfig.value?.paginationLeft ?? "");
133
+ const paginationRight = computed(() => currentConfig.value?.paginationRight ?? "");
134
+ const resolvedPaginationPageSizes = computed(() => normalizePaginationPageSizes(currentConfig.value?.paginationPageSizes));
135
+ const isConfiguratorOpen = ref(false);
136
+ function handleConfiguratorConfirm(nextConfig) {
137
+ currentConfig.value = nextConfig;
138
+ emit("update:config", nextConfig);
139
+ }
140
+ function handlePaginationPageSizeChange(value) {
141
+ const nextPageSize = Number(value);
142
+ if (!Number.isInteger(nextPageSize) || nextPageSize <= 0) {
143
+ return;
144
+ }
145
+ tableApi.setPageSize(nextPageSize);
146
+ }
147
+ function syncPaginationPageSize() {
148
+ const nextPageSize = resolvePaginationPageSize(
149
+ tableApi.getState().pagination.pageSize,
150
+ resolvedPaginationPageSizes.value
151
+ );
152
+ if (nextPageSize === void 0 || nextPageSize === tableApi.getState().pagination.pageSize) {
153
+ return;
154
+ }
155
+ tableApi.setPageSize(nextPageSize);
156
+ }
157
+ function getRowId(originalRow, index, parent) {
158
+ const expression = currentConfig.value?.getRowId;
159
+ if (!expression) {
160
+ return parent ? `${parent.index}.${index}` : `${index}`;
161
+ }
162
+ try {
163
+ const key = $dsl.evaluate`${expression}`(
164
+ {
165
+ row: originalRow,
166
+ index,
167
+ parent: parent ? {
168
+ id: parent.id,
169
+ index: BigInt(parent.index),
170
+ original: parent.original
171
+ } : null
172
+ }
173
+ );
174
+ if (typeof key === "string") {
175
+ return key;
176
+ }
177
+ } catch (e) {
178
+ console.error(e);
179
+ }
180
+ return parent ? `${parent.index}.${index}` : `${index}`;
181
+ }
182
+ function getSubRows(row, index) {
183
+ const expression = currentConfig.value?.getSubRows;
184
+ if (!expression) {
185
+ return void 0;
186
+ }
187
+ try {
188
+ const value = $dsl.evaluate`${expression}`({
189
+ row,
190
+ index
191
+ });
192
+ return Array.isArray(value) ? value : void 0;
193
+ } catch (e) {
194
+ console.error(e);
195
+ return void 0;
196
+ }
197
+ }
198
+ function enableRowSelection(row) {
199
+ const expression = currentConfig.value?.enableRowSelection;
200
+ if (!expression) {
201
+ return true;
202
+ }
203
+ try {
204
+ return Boolean($dsl.evaluate`${expression}`({
205
+ row: row.original,
206
+ index: BigInt(row.index),
207
+ id: row.id
208
+ }));
209
+ } catch (e) {
210
+ console.error(e);
211
+ return true;
212
+ }
213
+ }
214
+ function enableMultiRowSelection(row) {
215
+ const expression = currentConfig.value?.enableMultiRowSelection;
216
+ if (!expression) {
217
+ return true;
218
+ }
219
+ try {
220
+ return Boolean($dsl.evaluate`${expression}`({
221
+ row: row.original,
222
+ index: BigInt(row.index),
223
+ id: row.id
224
+ }));
225
+ } catch (e) {
226
+ console.error(e);
227
+ return true;
228
+ }
229
+ }
230
+ const columnResizeMode = "onChange";
231
+ const baseTableOptions = {
232
+ get columns() {
233
+ return columns.value;
234
+ },
235
+ data,
236
+ getCoreRowModel: getCoreRowModel(),
237
+ getExpandedRowModel: getExpandedRowModel(),
238
+ getPaginationRowModel: getPaginationRowModel(),
239
+ getSortedRowModel: getSortedRowModel(),
240
+ get manualPagination() {
241
+ return isManualPagination.value;
242
+ },
243
+ get rowCount() {
244
+ return props.rowCount;
245
+ },
246
+ get getRowId() {
247
+ return currentConfig.value?.getRowId ? getRowId : void 0;
248
+ },
249
+ getSubRows,
250
+ enableRowSelection,
251
+ get enableMultiRowSelection() {
252
+ return currentConfig.value?.enableMultiRowSelection ? enableMultiRowSelection : void 0;
253
+ },
254
+ columnResizeMode
255
+ };
256
+ function getConfigOption(property) {
257
+ const configOptions = currentConfig.value?.props;
258
+ if (!configOptions) {
259
+ return void 0;
260
+ }
261
+ return Reflect.get(configOptions, property);
262
+ }
263
+ const tableOptions = new Proxy(baseTableOptions, {
264
+ get(target, property, receiver) {
265
+ const baseValue = Reflect.get(target, property, receiver);
266
+ if (baseValue !== void 0) {
267
+ return baseValue;
268
+ }
269
+ return getConfigOption(property);
270
+ },
271
+ has(target, property) {
272
+ const configOptions = currentConfig.value?.props;
273
+ return Reflect.has(target, property) || (configOptions ? Reflect.has(configOptions, property) : false);
274
+ },
275
+ ownKeys(target) {
276
+ const keys = [...Reflect.ownKeys(target)];
277
+ const configOptions = currentConfig.value?.props;
278
+ if (configOptions) {
279
+ keys.push(...Reflect.ownKeys(configOptions));
280
+ }
281
+ return Array.from(new Set(keys));
282
+ },
283
+ getOwnPropertyDescriptor(target, property) {
284
+ const configOptions = currentConfig.value?.props;
285
+ if (!Reflect.has(target, property) && !(configOptions && Reflect.has(configOptions, property))) {
286
+ return void 0;
287
+ }
288
+ return {
289
+ configurable: true,
290
+ enumerable: true,
291
+ get() {
292
+ const baseValue = Reflect.get(target, property);
293
+ if (baseValue !== void 0) {
294
+ return baseValue;
295
+ }
296
+ return getConfigOption(property);
297
+ }
298
+ };
299
+ }
300
+ });
301
+ const tableApi = useVueTable(tableOptions);
302
+ watch(currentConfig, (config) => {
303
+ if (!config) {
304
+ return;
305
+ }
306
+ const initialState = config.props?.initialState;
307
+ const nextInitialStateKey = initialState ? JSON.stringify(initialState) : "";
308
+ if (appliedInitialStateKey.value === nextInitialStateKey || !initialState) {
309
+ appliedInitialStateKey.value = nextInitialStateKey;
310
+ syncPaginationPageSize();
311
+ return;
312
+ }
313
+ tableApi.initialState = mergeInitialState(tableApi.initialState, initialState);
314
+ tableApi.reset();
315
+ appliedInitialStateKey.value = nextInitialStateKey;
316
+ syncPaginationPageSize();
317
+ }, { immediate: true });
318
+ defineExpose(tableApi);
319
+ const rowVirtualizer = useVirtualizer(
320
+ computed(() => ({
321
+ count: tableApi.getRowModel().rows.length,
322
+ estimateSize: () => 35,
323
+ getScrollElement: () => containerRef.value,
324
+ overscan: 30
325
+ }))
326
+ );
327
+ const rowTotalSize = computed(() => rowVirtualizer.value.getTotalSize());
328
+ const rowWindow = computed(() => rowVirtualizer.value.getVirtualItems());
329
+ function measureRow(el) {
330
+ if (!el || !(el instanceof Element))
331
+ return;
332
+ rowVirtualizer.value.measureElement(el);
333
+ }
334
+ const rows = computed(() => tableApi.getRowModel().rows);
335
+ const maxPage = computed(() => Math.max(tableApi.getPageCount(), 1));
336
+ function isStyleRecord(x) {
337
+ return typeof x === "object" && x !== null && !Array.isArray(x);
338
+ }
339
+ function getCellStyles(ctx) {
340
+ const expression = currentConfig.value?.cellStyles;
341
+ if (!expression)
342
+ return {};
343
+ try {
344
+ const result = $dsl.evaluate`${expression}`({
345
+ row: ctx.row.original,
346
+ index: BigInt(ctx.row.index),
347
+ id: ctx.column.id,
348
+ selected: ctx.row.getIsSelected(),
349
+ pinned: ctx.column.getIsPinned()
350
+ });
351
+ return isStyleRecord(result) ? result : {};
352
+ } catch (e) {
353
+ console.error(e);
354
+ return {};
355
+ }
356
+ }
357
+ function shouldHaveRightBorder(column) {
358
+ switch (column.getIsPinned()) {
359
+ case "left":
360
+ return true;
361
+ case "right":
362
+ return false;
363
+ case false:
364
+ return !column.getIsLastColumn("center");
365
+ }
366
+ }
367
+ function shouldHaveLeftBorder(column) {
368
+ switch (column.getIsPinned()) {
369
+ case "left":
370
+ return false;
371
+ case "right":
372
+ return true;
373
+ case false:
374
+ return false;
375
+ }
376
+ }
377
+ function pinnedStyle(column) {
378
+ const pinned = column.getIsPinned();
379
+ if (!pinned)
380
+ return {};
381
+ const style = {
382
+ [pinned]: pinned === "left" ? `${column.getStart("left")}px` : `${column.getAfter("right")}px`
383
+ };
384
+ if (column.getIsLastColumn("left"))
385
+ style.boxShadow = "5px 5px 5px #00000005";
386
+ if (column.getIsFirstColumn("right"))
387
+ style.boxShadow = "-5px 5px 5px #00000005";
388
+ return style;
389
+ }
390
+ function shouldShowResizeHandle(column) {
391
+ const lastVisibleLeafColumn = tableApi.getVisibleLeafColumns().at(-1);
392
+ if (!lastVisibleLeafColumn) {
393
+ return false;
394
+ }
395
+ const lastLeafColumn = column.getLeafColumns().at(-1);
396
+ return lastLeafColumn?.id !== lastVisibleLeafColumn.id;
397
+ }
398
+ const SORT_ICONS = {
399
+ unsorted: "fluent:arrow-sort-16-regular",
400
+ asc: "fluent:arrow-sort-up-16-regular",
401
+ desc: "fluent:arrow-sort-down-16-regular"
402
+ };
403
+ function getSortIcon(column) {
404
+ const sortDir = column.getIsSorted();
405
+ const iconKey = sortDir === false ? "unsorted" : sortDir;
406
+ return SORT_ICONS[iconKey];
407
+ }
408
+ function cloneItems(items) {
409
+ return items ? [...items] : void 0;
410
+ }
411
+ function isNullableNumber(value) {
412
+ return typeof value === "number" || value === null;
413
+ }
414
+ function normalizeExpandedState(expanded, current) {
415
+ if (expanded === void 0) {
416
+ return current;
417
+ }
418
+ if (expanded === true) {
419
+ return true;
420
+ }
421
+ if (expanded === false) {
422
+ return {};
423
+ }
424
+ return expanded;
425
+ }
426
+ function mergeColumnSizingInfo(current, next) {
427
+ if (!next) {
428
+ return current;
429
+ }
430
+ const merged = {
431
+ ...current
432
+ };
433
+ if (Array.isArray(next.columnSizingStart)) {
434
+ merged.columnSizingStart = next.columnSizingStart;
435
+ }
436
+ if (isNullableNumber(next.deltaOffset)) {
437
+ merged.deltaOffset = next.deltaOffset;
438
+ }
439
+ if (isNullableNumber(next.deltaPercentage)) {
440
+ merged.deltaPercentage = next.deltaPercentage;
441
+ }
442
+ if (next.isResizingColumn === false || typeof next.isResizingColumn === "string") {
443
+ merged.isResizingColumn = next.isResizingColumn;
444
+ }
445
+ if (isNullableNumber(next.startOffset)) {
446
+ merged.startOffset = next.startOffset;
447
+ }
448
+ if (isNullableNumber(next.startSize)) {
449
+ merged.startSize = next.startSize;
450
+ }
451
+ return merged;
452
+ }
453
+ function mergeInitialState(current, initialState) {
454
+ return {
455
+ ...current,
456
+ columnVisibility: initialState.columnVisibility ?? current.columnVisibility,
457
+ columnOrder: cloneItems(initialState.columnOrder) ?? current.columnOrder,
458
+ columnPinning: initialState.columnPinning ? {
459
+ ...current.columnPinning,
460
+ ...initialState.columnPinning,
461
+ left: cloneItems(initialState.columnPinning.left) ?? current.columnPinning.left,
462
+ right: cloneItems(initialState.columnPinning.right) ?? current.columnPinning.right
463
+ } : current.columnPinning,
464
+ rowPinning: initialState.rowPinning ? {
465
+ ...current.rowPinning,
466
+ ...initialState.rowPinning,
467
+ top: cloneItems(initialState.rowPinning.top) ?? current.rowPinning.top,
468
+ bottom: cloneItems(initialState.rowPinning.bottom) ?? current.rowPinning.bottom
469
+ } : current.rowPinning,
470
+ columnFilters: cloneItems(initialState.columnFilters) ?? current.columnFilters,
471
+ globalFilter: initialState.globalFilter ?? current.globalFilter,
472
+ sorting: cloneItems(initialState.sorting) ?? current.sorting,
473
+ expanded: normalizeExpandedState(initialState.expanded, current.expanded),
474
+ grouping: cloneItems(initialState.grouping) ?? current.grouping,
475
+ columnSizing: initialState.columnSizing ?? current.columnSizing,
476
+ columnSizingInfo: mergeColumnSizingInfo(current.columnSizingInfo, initialState.columnSizingInfo),
477
+ pagination: initialState.pagination ? { ...current.pagination, ...initialState.pagination } : current.pagination,
478
+ rowSelection: initialState.rowSelection ?? current.rowSelection
479
+ };
480
+ }
481
+ function getSortLabel(column) {
482
+ const direction = column.getIsSorted();
483
+ if (direction === "asc") {
484
+ return t("table-sort-asc");
485
+ }
486
+ if (direction === "desc") {
487
+ return t("table-sort-desc");
488
+ }
489
+ return t("table-sort-unsorted");
490
+ }
491
+ function getColumnTooltipLabel(column) {
492
+ return t("table-column-tooltip", { column: column.id });
493
+ }
494
+ function getAccessorTooltipLabel(column) {
495
+ return t("table-column-accessor", { column: column.id });
496
+ }
497
+ </script>
498
+
499
+ <script>
500
+ export { AccessorC, ColumnC, RenderC, TableConfigC } from "./schema";
501
+ </script>
502
+
503
+ <template>
504
+ <div
505
+ class="relative flex h-full flex-col"
506
+ >
507
+ <Button
508
+ v-if="isCheating"
509
+ data-slot="table-configurator-trigger"
510
+ variant="ghost"
511
+ size="sm"
512
+ :aria-label="t('table-open-configurator')"
513
+ :title="t('table-open-configurator')"
514
+ type="button"
515
+ class="absolute right-3 top-3 z-20 bg-white/90 shadow-xs backdrop-blur-sm hover:bg-white"
516
+ @click="isConfiguratorOpen = true"
517
+ >
518
+ <Icon icon="fluent:settings-20-regular" />
519
+ </Button>
520
+
521
+ <TableConfiguratorDialog
522
+ v-if="currentConfig"
523
+ v-model:open="isConfiguratorOpen"
524
+ :config="currentConfig"
525
+ @confirm="handleConfiguratorConfirm"
526
+ />
527
+
528
+ <div
529
+ class="relative flex min-h-0 flex-1 flex-col"
530
+ >
531
+ <Skeleton
532
+ v-if="currentConfig === void 0"
533
+ class="absolute inset-0 z-10 w-full h-full"
534
+ />
535
+
536
+ <div
537
+ :class="[
538
+ 'flex min-h-0 flex-1 flex-col',
539
+ currentConfig === void 0 && 'opacity-0'
540
+ ]"
541
+ >
542
+ <div
543
+ ref="containerRef"
544
+ class="overflow-scroll overscroll-none flex-1 border border-zinc-200 rounded relative"
545
+ >
546
+ <div :style="{ height: `${rowTotalSize}px` }">
547
+ <table class="grid">
548
+ <thead class="grid sticky top-0 z-10 select-none">
549
+ <tr
550
+ v-for="group in tableApi.getHeaderGroups()"
551
+ :key="group.id"
552
+ class="flex w-full border-b border-zinc-200"
553
+ >
554
+ <th
555
+ v-for="header in group.headers"
556
+ :key="header.id"
557
+ :colspan="header.colSpan"
558
+ :class="[
559
+ header.column.columnDef.meta?.grow && 'flex-1',
560
+ 'flex items-center gap-2 border-zinc-300 py-2 text-zinc-600',
561
+ 'text-xs flex items-center justify-center relative',
562
+ 'bg-[color-mix(in_srgb,var(--primary)_10%,white)] group',
563
+ header.column.getIsPinned() && 'sticky z-15',
564
+ shouldHaveRightBorder(header.column) && 'border-r',
565
+ shouldHaveLeftBorder(header.column) && 'border-l'
566
+ ]"
567
+ :style="{
568
+ width: `${header.getSize()}px`,
569
+ ...pinnedStyle(header.column)
570
+ }"
571
+ >
572
+ <FlexRender
573
+ v-if="!header.isPlaceholder"
574
+ :render="header.column.columnDef.header"
575
+ :props="header.getContext()"
576
+ />
577
+
578
+ <Tooltip
579
+ v-if="!header.isPlaceholder && header.column.columnDef.meta?.tooltip"
580
+ :delay-duration="180"
581
+ >
582
+ <TooltipTrigger as-child>
583
+ <button
584
+ type="button"
585
+ data-slot="table-column-tooltip-trigger"
586
+ :aria-label="getColumnTooltipLabel(header.column)"
587
+ class="inline-flex items-center justify-center text-zinc-500"
588
+ >
589
+ <Icon
590
+ icon="fluent:info-20-regular"
591
+ />
592
+ </button>
593
+ </TooltipTrigger>
594
+ <TooltipContent
595
+ align="center"
596
+ side="top"
597
+ >
598
+ <span v-html="$md.inline`${header.column.columnDef.meta?.tooltip}`()" />
599
+ </TooltipContent>
600
+ </Tooltip>
601
+
602
+ <Tooltip
603
+ v-if="!header.isPlaceholder && isCheating && header.column.columnDef.meta?.accessor"
604
+ :delay-duration="180"
605
+ >
606
+ <TooltipTrigger as-child>
607
+ <button
608
+ type="button"
609
+ data-slot="table-column-accessor-trigger"
610
+ :aria-label="getAccessorTooltipLabel(header.column)"
611
+ class="inline-flex items-center justify-center text-zinc-500"
612
+ >
613
+ <Icon
614
+ icon="fluent:code-20-regular"
615
+ />
616
+ </button>
617
+ </TooltipTrigger>
618
+ <TooltipContent
619
+ align="center"
620
+ side="top"
621
+ >
622
+ <template v-if="typeof header.column.columnDef.meta?.accessor === 'string'">
623
+ <span class="font-mono">{{ header.column.columnDef.meta?.accessor }}</span>
624
+ </template>
625
+ <template v-else>
626
+ <span class="font-mono">{{ JSON.stringify(header.column.columnDef.meta?.accessor) }}</span>
627
+ </template>
628
+ </TooltipContent>
629
+ </Tooltip>
630
+
631
+ <Tooltip
632
+ v-if="!header.isPlaceholder && header.column.getCanSort()"
633
+ :delay-duration="800"
634
+ >
635
+ <TooltipTrigger as-child>
636
+ <Button
637
+ variant="ghost"
638
+ size="xs"
639
+ :class="[
640
+ 'absolute hover:bg-transparent right-1 top-1/2 -translate-y-1/2 transform-3d transition-opacity duration-180',
641
+ !header.column.getIsSorted() ? 'opacity-30 hover:opacity-60' : 'text-(--primary)/80 hover:text-(--primary)'
642
+ ]"
643
+ as-child
644
+ >
645
+ <button
646
+ type="button"
647
+ :aria-label="getSortLabel(header.column)"
648
+ @click="header.column.getToggleSortingHandler()?.($event)"
649
+ >
650
+ <Icon :icon="getSortIcon(header.column)" />
651
+ </button>
652
+ </Button>
653
+ </TooltipTrigger>
654
+ <TooltipContent>
655
+ {{ getSortLabel(header.column) }}
656
+ </TooltipContent>
657
+ </Tooltip>
658
+
659
+ <div
660
+ v-if="!header.isPlaceholder && header.column.getCanResize() && shouldShowResizeHandle(header.column)"
661
+ :class="[
662
+ 'group',
663
+ 'absolute',
664
+ 'top-0',
665
+ 'bottom-0',
666
+ 'right-0',
667
+ 'px-2',
668
+ 'translate-x-2',
669
+ 'z-5',
670
+ 'opacity-0',
671
+ 'duration-150',
672
+ 'transition-opacity',
673
+ 'ease-out',
674
+ 'hover:opacity-100',
675
+ 'cursor-col-resize'
676
+ ]"
677
+ @mousedown="header.getResizeHandler()($event)"
678
+ >
679
+ <div :class="['w-2pt', 'h-full', 'translate-x-1pt', 'transform-3d', 'bg-[color-mix(in_srgb,var(--primary)_80%,white)]']" />
680
+ </div>
681
+ </th>
682
+ </tr>
683
+ </thead>
684
+
685
+ <tbody
686
+ class="grid relative"
687
+ :style="{ height: `${rowTotalSize}px` }"
688
+ >
689
+ <tr
690
+ v-for="r in rowWindow"
691
+ :key="rows[r.index]?.id ?? r.index"
692
+ :ref="measureRow"
693
+ class="flex absolute w-full not-last:border-b border-zinc-300"
694
+ :data-index="rows[r.index]?.index"
695
+ :style="{ transform: `translate3d(0, ${r.start}px, 0)` }"
696
+ >
697
+ <td
698
+ v-for="cell in rows[r.index]?.getVisibleCells() ?? []"
699
+ :key="cell.id"
700
+ :class="[
701
+ 'border-zinc-300',
702
+ cell.column.columnDef.meta?.grow && 'flex-1',
703
+ cell.column.getIsPinned() && 'sticky z-15',
704
+ shouldHaveRightBorder(cell.column) && 'border-r',
705
+ shouldHaveLeftBorder(cell.column) && 'border-l'
706
+ ]"
707
+ :style="{
708
+ width: `${cell.column.getSize()}px`,
709
+ ...pinnedStyle(cell.column),
710
+ ...getCellStyles(cell.getContext())
711
+ }"
712
+ >
713
+ <FlexRender
714
+ :render="cell.column.columnDef.cell"
715
+ :props="cell.getContext()"
716
+ />
717
+ </td>
718
+ </tr>
719
+ </tbody>
720
+
721
+ <tfoot class="hidden has-data-footer:grid sticky bottom-0 z-10 select-none border-t border-zinc-200">
722
+ <tr
723
+ v-for="group in tableApi.getFooterGroups()"
724
+ :key="group.id"
725
+ class="flex w-full border-zinc-200"
726
+ >
727
+ <th
728
+ v-for="header in group.headers"
729
+ :key="header.id"
730
+ :colSpan="header.colSpan"
731
+ :class="[
732
+ header.column.columnDef.meta?.grow && 'flex-1',
733
+ 'flex items-center gap-2 border-zinc-300 text-zinc-600 p-0',
734
+ 'text-xs flex items-center justify-center relative',
735
+ 'bg-[color-mix(in_srgb,var(--primary)_10%,white)] group',
736
+ header.column.getIsPinned() && 'sticky z-15',
737
+ shouldHaveRightBorder(header.column) && 'border-r',
738
+ shouldHaveLeftBorder(header.column) && 'border-l'
739
+ ]"
740
+ :style="{
741
+ width: `${header.getSize()}px`,
742
+ ...pinnedStyle(header.column)
743
+ }"
744
+ >
745
+ <FlexRender
746
+ v-if="!header.isPlaceholder"
747
+ :render="header.column.columnDef.footer"
748
+ :props="header.getContext()"
749
+ />
750
+ </th>
751
+ </tr>
752
+ </tfoot>
753
+ </table>
754
+ </div>
755
+ </div>
756
+
757
+ <div class="flex items-center justify-between w-full py-2 gap-2 text-sm text-zinc-600">
758
+ <div
759
+ :class="[
760
+ 'relative p-1 flex-1 prose prose-zinc text-xs'
761
+ ]"
762
+ >
763
+ <span
764
+ v-html="$md.inline`${paginationLeft}`({
765
+ selected: tableApi.getSelectedRowModel().rows.map((row) => row.original)
766
+ })"
767
+ />
768
+ &nbsp;
769
+ </div>
770
+ <div class="flex items-center gap-4">
771
+ <i18n-t
772
+ keypath="total"
773
+ tag="span"
774
+ class="text-xs"
775
+ >
776
+ <template #count>
777
+ <strong>{{ totalItems }}</strong>
778
+ </template>
779
+ </i18n-t>
780
+ <label
781
+ v-if="resolvedPaginationPageSizes"
782
+ data-slot="table-pagination-page-size"
783
+ class="flex items-center gap-2 text-xs text-zinc-500"
784
+ >
785
+ <NativeSelect
786
+ data-slot="table-pagination-page-size-select"
787
+ :model-value="tableApi.getState().pagination.pageSize"
788
+ :aria-label="t('pagination-page-size')"
789
+ class="h-7 min-w-20 rounded-sm px-2 py-1 pr-7 text-xs text-zinc-600"
790
+ @update:model-value="handlePaginationPageSizeChange"
791
+ >
792
+ <NativeSelectOption
793
+ v-for="pageSize in resolvedPaginationPageSizes"
794
+ :key="pageSize"
795
+ :value="pageSize"
796
+ >
797
+ {{ pageSize }}
798
+ </NativeSelectOption>
799
+ </NativeSelect>
800
+ </label>
801
+ <Pagination.Root
802
+ show-edges
803
+ :total="totalItems"
804
+ :items-per-page="tableApi.getState().pagination.pageSize"
805
+ :page="tableApi.getState().pagination.pageIndex + 1"
806
+ @update:page="(page2) => tableApi.setPageIndex(page2 - 1)"
807
+ >
808
+ <Pagination.List
809
+ v-slot="{ items }"
810
+ class="flex items-center gap-1"
811
+ >
812
+ <Pagination.First
813
+ :class="[
814
+ 'w-7 h-7 flex items-center justify-center bg-transparent hover:bg-zinc-100 transition disabled:opacity-50 rounded text-zinc-600',
815
+ 'data-disabled:opacity-50 data-disabled:cursor-not-allowed cursor-pointer'
816
+ ]"
817
+ >
818
+ <Icon
819
+ icon="radix-icons:double-arrow-left"
820
+ class="w-4 h-4"
821
+ />
822
+ </Pagination.First>
823
+ <Pagination.Prev
824
+ :class="[
825
+ 'w-7 h-7 flex items-center justify-center bg-transparent hover:bg-zinc-100 transition disabled:opacity-50 rounded text-zinc-600',
826
+ 'data-disabled:opacity-50 data-disabled:cursor-not-allowed cursor-pointer'
827
+ ]"
828
+ >
829
+ <Icon
830
+ icon="radix-icons:chevron-left"
831
+ class="w-4 h-4"
832
+ />
833
+ </Pagination.Prev>
834
+
835
+ <template
836
+ v-for="(page, index) in items"
837
+ :key="page.type === 'page' ? `${page.type}-${page.value}` : `${page.type}-${index}`"
838
+ >
839
+ <Pagination.ListItem
840
+ v-if="page.type === 'page'"
841
+ :class="[
842
+ 'w-7 h-7 flex items-center justify-center rounded text-xs bg-transparent',
843
+ 'data-selected:text-(--primary) hover:bg-zinc-100 transition cursor-pointer'
844
+ ]"
845
+ :value="page.value"
846
+ >
847
+ {{ page.value }}
848
+ </Pagination.ListItem>
849
+ <Pagination.Ellipsis
850
+ v-else
851
+ class="w-7 h-7 flex items-center justify-center text-zinc-400"
852
+ >
853
+ &#8230;
854
+ </Pagination.Ellipsis>
855
+ </template>
856
+
857
+ <Pagination.Next
858
+ :class="[
859
+ 'w-7 h-7 flex items-center justify-center bg-transparent hover:bg-zinc-100 transition disabled:opacity-50 rounded text-zinc-600',
860
+ 'data-disabled:opacity-50 data-disabled:cursor-not-allowed cursor-pointer'
861
+ ]"
862
+ >
863
+ <Icon
864
+ icon="radix-icons:chevron-right"
865
+ class="w-4 h-4"
866
+ />
867
+ </Pagination.Next>
868
+ <Pagination.Last
869
+ :class="[
870
+ 'w-7 h-7 flex items-center justify-center bg-transparent hover:bg-zinc-100 transition disabled:opacity-50 rounded text-zinc-600',
871
+ 'data-disabled:opacity-50 data-disabled:cursor-not-allowed cursor-pointer'
872
+ ]"
873
+ >
874
+ <Icon
875
+ icon="radix-icons:double-arrow-right"
876
+ class="w-4 h-4"
877
+ />
878
+ </Pagination.Last>
879
+ </Pagination.List>
880
+ </Pagination.Root>
881
+ <i18n-t
882
+ keypath="goto"
883
+ tag="div"
884
+ class="text-xs flex items-center gap-2"
885
+ >
886
+ <template #page>
887
+ <NumberField
888
+ :model-value="tableApi.getState().pagination.pageIndex + 1"
889
+ :min="1"
890
+ :max="maxPage"
891
+ @update:model-value="(value) => tableApi.setPageIndex(value - 1)"
892
+ >
893
+ <NumberFieldInput class="h-6 w-16 text-xs" />
894
+ </NumberField>
895
+ </template>
896
+ </i18n-t>
897
+ </div>
898
+ <div
899
+ :class="[
900
+ 'relative p-1 flex-1 prose prose-zinc text-xs text-right'
901
+ ]"
902
+ >
903
+ <span
904
+ v-html="$md.inline`${paginationRight}`({
905
+ selected: tableApi.getSelectedRowModel().rows.map((row) => row.original)
906
+ })"
907
+ />
908
+ &nbsp;
909
+ </div>
910
+ </div>
911
+ </div>
912
+ </div>
913
+ </div>
914
+ </template>
915
+
916
+ <i18n lang="json">
917
+ {
918
+ "zh": {
919
+ "total": "共 {count} 条",
920
+ "pagination-page-size": "每页条数",
921
+ "goto": "前往 {page} 页",
922
+ "table-open-configurator": "打开表格配置",
923
+ "table-column-tooltip": "查看列提示:{column}",
924
+ "table-column-accessor": "查看列取值器:{column}",
925
+ "table-sort-asc": "升序",
926
+ "table-sort-desc": "降序",
927
+ "table-sort-unsorted": "未排序"
928
+ },
929
+ "ja": {
930
+ "total": "合計 {count} 件",
931
+ "pagination-page-size": "1ページあたりの件数",
932
+ "goto": "ページ {page} に移動",
933
+ "table-open-configurator": "テーブル設定を開く",
934
+ "table-column-tooltip": "列ツールチップを表示: {column}",
935
+ "table-column-accessor": "列アクセサを表示: {column}",
936
+ "table-sort-asc": "昇順",
937
+ "table-sort-desc": "降順",
938
+ "table-sort-unsorted": "未排序"
939
+ },
940
+ "en": {
941
+ "total": "Total {count} items",
942
+ "pagination-page-size": "Page size",
943
+ "goto": "Go to page {page}",
944
+ "table-open-configurator": "Open table configurator",
945
+ "table-column-tooltip": "Show column tooltip: {column}",
946
+ "table-column-accessor": "Show column accessor: {column}",
947
+ "table-sort-asc": "Ascending",
948
+ "table-sort-desc": "Descending",
949
+ "table-sort-unsorted": "Unsorted"
950
+ }
951
+ }
952
+ </i18n>