@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,2719 @@
1
+ <script setup>
2
+ import { useNuxtApp } from "#app";
3
+ import { useSortable } from "@vueuse/integrations/useSortable";
4
+ import { Icon } from "@iconify/vue";
5
+ import z from "zod";
6
+ import { computed, nextTick, ref, watch } from "vue";
7
+ import { useI18n } from "vue-i18n";
8
+ import { useTableRenderers } from "../../../composables/useTableRenderers";
9
+ import { dotPropC, expressionC, getLocalizedText, hasVisibleLocaleValue } from "../../../utils/coders";
10
+ import { cn } from "../../../utils/cn";
11
+ import ExpressionEditor from "../expression-editor/ExpressionEditor.vue";
12
+ import { Button } from "../button";
13
+ import { Checkbox } from "../checkbox";
14
+ import {
15
+ Dialog,
16
+ DialogContent,
17
+ DialogDescription,
18
+ DialogFooter,
19
+ DialogHeader,
20
+ DialogTitle
21
+ } from "../dialog";
22
+ import { Input } from "../input";
23
+ import { InputGroup, InputGroupAddon, InputGroupNumberField } from "../input-group";
24
+ import Locale from "../locale/Locale.vue";
25
+ import { NativeSelect, NativeSelectOption } from "../native-select";
26
+ import { NumberField, NumberFieldInput } from "../number-field";
27
+ import { Switch } from "../switch";
28
+ import { Textarea } from "../textarea";
29
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from "../tabs";
30
+ import { Toggle } from "../toggle";
31
+ import {
32
+ getColumnTechnicalKey,
33
+ normalizePaginationPageSizes,
34
+ resolvePaginationPageSize,
35
+ TableConfigC,
36
+ TableConfigCellStylesC,
37
+ TableConfigEnableMultiRowSelectionC,
38
+ TableConfigEnableRowSelectionC,
39
+ TableConfigGetRowIdC,
40
+ TableConfigGetSubRowsC
41
+ } from "../table/schema";
42
+ import {
43
+ buildTableConfiguratorColumnTree,
44
+ createTableConfiguratorDraftColumnNode,
45
+ flattenTableConfiguratorColumnTree,
46
+ getTableConfiguratorColumnAncestorItemIds,
47
+ getTableConfiguratorColumnDescendantItemIds,
48
+ getTableConfiguratorColumnNode,
49
+ insertTableConfiguratorRootColumnNode,
50
+ materializeTableConfiguratorColumnTree,
51
+ moveTableConfiguratorColumnNodeAfterItem,
52
+ moveTableConfiguratorColumnNodeToParent,
53
+ moveTableConfiguratorColumnSibling,
54
+ removeTableConfiguratorColumnSubtree,
55
+ updateTableConfiguratorColumnNode
56
+ } from "./menu";
57
+ const GENERATED_COLUMN_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
58
+ const TableConfiguratorColumnAccessorReadC = expressionC(/.+/, { row: "dyn", index: "int" });
59
+ const TableConfiguratorColumnAccessorWriteC = z.string().trim().refine((value) => value.length > 0, { error: "\u5199\u5165\u8868\u8FBE\u5F0F\u4E0D\u80FD\u4E3A\u7A7A" });
60
+ const TOOLTIP_EXPRESSION_EXAMPLE = "{{ expression }}";
61
+ const props = defineProps({
62
+ config: { type: Object, required: true }
63
+ });
64
+ const emit = defineEmits(["confirm"]);
65
+ const open = defineModel("open", { type: Boolean, ...{
66
+ default: false
67
+ } });
68
+ const { $toast } = useNuxtApp();
69
+ const { t, locale } = useI18n();
70
+ const { getTableRenderer, listTableRenderers, resolveTableRenderer } = useTableRenderers();
71
+ const search = ref("");
72
+ const childSearch = ref("");
73
+ const selectedItemId = ref("general");
74
+ const draftBaseConfig = ref({ columns: [] });
75
+ const draftColumnTree = ref(buildTableConfiguratorColumnTree([]));
76
+ const draftGetRowId = ref();
77
+ const draftGetSubRows = ref();
78
+ const draftEnableRowSelection = ref();
79
+ const draftEnableMultiRowSelection = ref();
80
+ const draftCellStyles = ref();
81
+ const draftPaginationLeft = ref();
82
+ const draftPaginationRight = ref();
83
+ const draftPageSize = ref();
84
+ const draftPaginationPageSizes = ref([]);
85
+ const leftPinnedSortableListRef = ref(null);
86
+ const leftPinnedSortableItemIds = ref([]);
87
+ const centerSortableListRef = ref(null);
88
+ const centerSortableItemIds = ref([]);
89
+ const rightPinnedSortableListRef = ref(null);
90
+ const rightPinnedSortableItemIds = ref([]);
91
+ const leftPinnedRootItemIds = ref([]);
92
+ const centerRootItemIds = ref([]);
93
+ const rightPinnedRootItemIds = ref([]);
94
+ const paginationPageSizesSortableListRef = ref(null);
95
+ const paginationPageSizesSortableItemIds = ref([]);
96
+ const selectedChildSortableListRef = ref(null);
97
+ const selectedChildSortableItemIds = ref([]);
98
+ const getRowIdEditor = ref(null);
99
+ const getSubRowsEditor = ref(null);
100
+ const enableRowSelectionEditor = ref(null);
101
+ const enableMultiRowSelectionEditor = ref(null);
102
+ const cellStylesEditor = ref(null);
103
+ const accessorPathEditor = ref(null);
104
+ const accessorReadEditor = ref(null);
105
+ const accessorWriteEditor = ref(null);
106
+ const selectedRendererConfigRef = ref(null);
107
+ const selectedColumnAccessorMode = ref("path");
108
+ const generalItem = computed(() => ({
109
+ id: "general",
110
+ label: t("general")
111
+ }));
112
+ const normalizedSearch = computed(() => search.value.trim().toLocaleLowerCase());
113
+ const normalizedChildSearch = computed(() => childSearch.value.trim().toLocaleLowerCase());
114
+ const selectedColumnNode = computed(() => {
115
+ if (selectedItemId.value === "general") {
116
+ return void 0;
117
+ }
118
+ return getTableConfiguratorColumnNode(draftColumnTree.value, selectedItemId.value);
119
+ });
120
+ const selectedColumn = computed(() => selectedColumnNode.value?.column);
121
+ const selectedColumnTechnicalKey = computed(() => selectedColumn.value ? getColumnTechnicalKey(selectedColumn.value) : void 0);
122
+ const selectedColumnAncestorItemIds = computed(() => {
123
+ const node = selectedColumnNode.value;
124
+ if (!node) {
125
+ return [];
126
+ }
127
+ return getTableConfiguratorColumnAncestorItemIds(draftColumnTree.value, node.itemId);
128
+ });
129
+ const selectedColumnDescendantItemIds = computed(() => {
130
+ const node = selectedColumnNode.value;
131
+ if (!node) {
132
+ return [];
133
+ }
134
+ return getTableConfiguratorColumnDescendantItemIds(draftColumnTree.value, node.itemId);
135
+ });
136
+ function looksLikeGeneratedColumnId(value) {
137
+ if (!value) {
138
+ return false;
139
+ }
140
+ return GENERATED_COLUMN_ID_RE.test(value);
141
+ }
142
+ function getColumnSearchMeta(column, hasChildren) {
143
+ if (typeof column.accessor === "string") {
144
+ return column.accessor;
145
+ }
146
+ if (column.accessor) {
147
+ return column.accessor.read;
148
+ }
149
+ if (column.id && (hasChildren || !looksLikeGeneratedColumnId(column.id))) {
150
+ return column.id;
151
+ }
152
+ return void 0;
153
+ }
154
+ function createListItem(itemId, depth) {
155
+ const node = getTableConfiguratorColumnNode(draftColumnTree.value, itemId);
156
+ if (!node) {
157
+ return void 0;
158
+ }
159
+ const hasChildren = node.childItemIds.length > 0;
160
+ const searchMeta = getColumnSearchMeta(node.column, hasChildren);
161
+ return {
162
+ itemId,
163
+ label: getLocalizedText(node.column.title, locale.value) ?? searchMeta ?? t("untitled-column"),
164
+ searchMeta,
165
+ depth,
166
+ hasChildren,
167
+ column: node.column
168
+ };
169
+ }
170
+ const columnListItems = computed(() => flattenTableConfiguratorColumnTree(draftColumnTree.value).flatMap((item) => {
171
+ const listItem = createListItem(item.itemId, item.depth);
172
+ return listItem ? [listItem] : [];
173
+ }));
174
+ const filteredColumnItems = computed(() => {
175
+ if (!normalizedSearch.value) {
176
+ return columnListItems.value;
177
+ }
178
+ return columnListItems.value.filter((item) => matchesSearch(item, normalizedSearch.value));
179
+ });
180
+ const selectedColumnItem = computed(() => columnListItems.value.find((item) => item.itemId === selectedItemId.value));
181
+ const selectedItemLabel = computed(() => selectedColumnItem.value?.label ?? generalItem.value.label);
182
+ const selectedColumnLocaleValue = computed(() => {
183
+ const node = selectedColumnNode.value;
184
+ if (!node) {
185
+ return void 0;
186
+ }
187
+ if (node.column.title) {
188
+ return node.column.title;
189
+ }
190
+ const fallbackLabel = getColumnSearchMeta(node.column, node.childItemIds.length > 0);
191
+ if (!fallbackLabel) {
192
+ return void 0;
193
+ }
194
+ return [
195
+ {
196
+ locale: "zh",
197
+ message: fallbackLabel
198
+ }
199
+ ];
200
+ });
201
+ const selectedColumnTooltipValue = computed(() => {
202
+ const node = selectedColumnNode.value;
203
+ if (!node) {
204
+ return void 0;
205
+ }
206
+ return node.column.tooltip;
207
+ });
208
+ const selectedColumnHasChildren = computed(() => (selectedColumnNode.value?.childItemIds.length ?? 0) > 0);
209
+ const rendererOptions = computed(() => listTableRenderers().map((renderer) => ({
210
+ id: renderer.id,
211
+ label: getTableConfiguratorRendererLabel(renderer.id)
212
+ })));
213
+ function getTableConfiguratorRendererLabel(rendererId) {
214
+ const segments = rendererId.split(".");
215
+ const leaf = segments.at(-1) ?? rendererId;
216
+ if (locale.value.startsWith("ja")) {
217
+ const labels2 = {
218
+ text: "\u30C6\u30AD\u30B9\u30C8",
219
+ selection: "\u9078\u629E",
220
+ expand: "\u5C55\u958B",
221
+ money: "\u91D1\u984D",
222
+ date: "\u65E5\u4ED8",
223
+ markdown: "Markdown"
224
+ };
225
+ const label2 = labels2[leaf];
226
+ if (label2) {
227
+ return label2;
228
+ }
229
+ }
230
+ if (locale.value.startsWith("en")) {
231
+ const labels2 = {
232
+ text: "Text",
233
+ selection: "Selection",
234
+ expand: "Expand",
235
+ money: "Money",
236
+ date: "Date",
237
+ markdown: "Markdown"
238
+ };
239
+ const label2 = labels2[leaf];
240
+ if (label2) {
241
+ return label2;
242
+ }
243
+ }
244
+ const labels = {
245
+ text: "\u6587\u672C",
246
+ selection: "\u9009\u62E9",
247
+ expand: "\u5C55\u5F00",
248
+ money: "\u91D1\u989D",
249
+ date: "\u65E5\u671F",
250
+ markdown: "Markdown"
251
+ };
252
+ const label = labels[leaf];
253
+ if (label) {
254
+ return label;
255
+ }
256
+ return `${leaf.slice(0, 1).toLocaleUpperCase()}${leaf.slice(1)}`;
257
+ }
258
+ function getColumnRendererId(column) {
259
+ if (!column) {
260
+ return "table.renderer.text";
261
+ }
262
+ if (typeof column.renderer === "string") {
263
+ return column.renderer;
264
+ }
265
+ return column.renderer?.id ?? "table.renderer.text";
266
+ }
267
+ function getColumnRendererProps(column) {
268
+ if (!column || !column.renderer || typeof column.renderer === "string") {
269
+ return void 0;
270
+ }
271
+ return column.renderer.props;
272
+ }
273
+ const selectedColumnRendererId = computed(() => getColumnRendererId(selectedColumn.value));
274
+ const selectedColumnRendererModel = computed({
275
+ get() {
276
+ return selectedColumnRendererId.value;
277
+ },
278
+ set(value) {
279
+ updateSelectedColumnRendererId(value);
280
+ }
281
+ });
282
+ const selectedColumnRenderer = computed(() => resolveTableRenderer(selectedColumnRendererId.value));
283
+ const selectedColumnRendererConfigComponent = computed(() => selectedColumnRenderer.value.config);
284
+ const selectedColumnRendererOptions = computed(() => {
285
+ const renderer = selectedColumnRenderer.value;
286
+ try {
287
+ return renderer.parseOptions(getColumnRendererProps(selectedColumn.value));
288
+ } catch (e) {
289
+ console.error(e);
290
+ return renderer.parseOptions(void 0);
291
+ }
292
+ });
293
+ function isDotPropPath(value) {
294
+ if (!value) {
295
+ return false;
296
+ }
297
+ return dotPropC.safeParse(value).success;
298
+ }
299
+ async function copySelectedColumnId() {
300
+ if (!selectedColumnTechnicalKey.value) {
301
+ return;
302
+ }
303
+ try {
304
+ await navigator.clipboard.writeText(selectedColumnTechnicalKey.value);
305
+ } catch (e) {
306
+ console.error(e);
307
+ }
308
+ }
309
+ function getColumnAccessorPath(column) {
310
+ if (!column) {
311
+ return void 0;
312
+ }
313
+ if (typeof column.accessor === "string") {
314
+ return column.accessor;
315
+ }
316
+ if (!column.accessor) {
317
+ return void 0;
318
+ }
319
+ if (isDotPropPath(column.accessor.write)) {
320
+ return column.accessor.write;
321
+ }
322
+ const read = column.accessor.read;
323
+ if (!read.startsWith("row")) {
324
+ return void 0;
325
+ }
326
+ const path = read.slice(3);
327
+ const normalizedPath = path.startsWith(".") ? path.slice(1) : path;
328
+ return isDotPropPath(normalizedPath) ? normalizedPath : void 0;
329
+ }
330
+ function createAccessorReadFromPath(path) {
331
+ if (!path) {
332
+ return "";
333
+ }
334
+ return path.startsWith("[") ? `row${path}` : `row.${path}`;
335
+ }
336
+ function getColumnAccessorExpression(column) {
337
+ if (column?.accessor && typeof column.accessor !== "string") {
338
+ return column.accessor;
339
+ }
340
+ const path = getColumnAccessorPath(column);
341
+ return {
342
+ read: createAccessorReadFromPath(path),
343
+ write: path ?? ""
344
+ };
345
+ }
346
+ function getColumnAccessorMode(column) {
347
+ if (column?.accessor && typeof column.accessor !== "string") {
348
+ return "expression";
349
+ }
350
+ return "path";
351
+ }
352
+ const selectedColumnAccessorPath = computed(() => getColumnAccessorPath(selectedColumn.value));
353
+ const selectedColumnAccessorExpression = computed(() => getColumnAccessorExpression(selectedColumn.value));
354
+ function normalizeOptionalText(value) {
355
+ if (value === void 0 || value.trim().length === 0) {
356
+ return void 0;
357
+ }
358
+ return value;
359
+ }
360
+ function normalizeOptionalNumber(value) {
361
+ if (typeof value === "number") {
362
+ return Number.isFinite(value) ? value : void 0;
363
+ }
364
+ if (value === void 0 || value.trim().length === 0) {
365
+ return void 0;
366
+ }
367
+ const normalized = Number(value);
368
+ return Number.isFinite(normalized) ? normalized : void 0;
369
+ }
370
+ function getInitialPageSize(config) {
371
+ return config.props?.initialState?.pagination?.pageSize;
372
+ }
373
+ function getInitialPaginationPageSizes(config) {
374
+ return normalizePaginationPageSizes(config.paginationPageSizes) ?? [];
375
+ }
376
+ function createPaginationPageSizeItem(value = void 0) {
377
+ return {
378
+ itemId: crypto.randomUUID(),
379
+ value
380
+ };
381
+ }
382
+ function createPaginationPageSizeItems(values) {
383
+ return (normalizePaginationPageSizes(values) ?? []).map((value) => createPaginationPageSizeItem(value));
384
+ }
385
+ function isRendererConfigExposed(value) {
386
+ if (typeof value !== "object" || value === null) {
387
+ return false;
388
+ }
389
+ const clearValidation = Reflect.get(value, "clearValidation");
390
+ const validate = Reflect.get(value, "validate");
391
+ return typeof clearValidation === "function" && typeof validate === "function";
392
+ }
393
+ function areRendererOptionsDefault(rendererId, props2) {
394
+ const renderer = resolveTableRenderer(rendererId);
395
+ const normalizedProps = renderer.parseOptions(props2);
396
+ const defaultProps = renderer.parseOptions(void 0);
397
+ return JSON.stringify(normalizedProps) === JSON.stringify(defaultProps);
398
+ }
399
+ function buildColumnRenderer(rendererId, props2) {
400
+ const renderer = resolveTableRenderer(rendererId);
401
+ const normalizedProps = renderer.parseOptions(props2);
402
+ if (areRendererOptionsDefault(rendererId, normalizedProps)) {
403
+ return rendererId;
404
+ }
405
+ return {
406
+ id: renderer.id,
407
+ props: normalizedProps
408
+ };
409
+ }
410
+ function getLeafColumnTechnicalKeys(itemId) {
411
+ const node = getTableConfiguratorColumnNode(draftColumnTree.value, itemId);
412
+ if (!node) {
413
+ return void 0;
414
+ }
415
+ if (node.childItemIds.length === 0) {
416
+ const technicalKey = getColumnTechnicalKey(node.column);
417
+ return technicalKey ? [technicalKey] : void 0;
418
+ }
419
+ const leafColumnIds = [];
420
+ for (const childItemId of node.childItemIds) {
421
+ const childLeafColumnIds = getLeafColumnTechnicalKeys(childItemId);
422
+ if (!childLeafColumnIds?.length) {
423
+ return void 0;
424
+ }
425
+ leafColumnIds.push(...childLeafColumnIds);
426
+ }
427
+ return leafColumnIds;
428
+ }
429
+ function createRootInitialStateItem(itemId) {
430
+ const listItem = createListItem(itemId, 0);
431
+ if (!listItem) {
432
+ return void 0;
433
+ }
434
+ const leafColumnIds = getLeafColumnTechnicalKeys(itemId) ?? [];
435
+ return {
436
+ itemId,
437
+ label: listItem.label,
438
+ leafColumnIds,
439
+ canManage: leafColumnIds.length > 0
440
+ };
441
+ }
442
+ const rootInitialStateItems = computed(() => draftColumnTree.value.rootItemIds.flatMap((itemId) => {
443
+ const listItem = createRootInitialStateItem(itemId);
444
+ return listItem ? [listItem] : [];
445
+ }));
446
+ function resolveRootInitialStateItems(itemIds) {
447
+ return itemIds.flatMap((itemId) => {
448
+ const item = rootInitialStateItems.value.find((candidate) => candidate.itemId === itemId);
449
+ return item ? [item] : [];
450
+ });
451
+ }
452
+ const leftPinnedInitialStateItems = computed(() => resolveRootInitialStateItems(leftPinnedRootItemIds.value));
453
+ const centerInitialStateItems = computed(() => resolveRootInitialStateItems(centerRootItemIds.value));
454
+ const rightPinnedInitialStateItems = computed(() => resolveRootInitialStateItems(rightPinnedRootItemIds.value));
455
+ const selectedChildItems = computed(() => {
456
+ const node = selectedColumnNode.value;
457
+ if (!node) {
458
+ return [];
459
+ }
460
+ return node.childItemIds.flatMap((itemId) => {
461
+ const listItem = createListItem(itemId, 0);
462
+ return listItem ? [listItem] : [];
463
+ });
464
+ });
465
+ const childCandidateItems = computed(() => {
466
+ const node = selectedColumnNode.value;
467
+ if (!node) {
468
+ return [];
469
+ }
470
+ const excludedItemIds = /* @__PURE__ */ new Set([
471
+ node.itemId,
472
+ ...selectedColumnAncestorItemIds.value,
473
+ ...selectedColumnDescendantItemIds.value
474
+ ]);
475
+ return columnListItems.value.filter((item) => !excludedItemIds.has(item.itemId));
476
+ });
477
+ const filteredChildCandidateItems = computed(() => {
478
+ if (!normalizedChildSearch.value) {
479
+ return childCandidateItems.value;
480
+ }
481
+ return childCandidateItems.value.filter((item) => matchesSearch(item, normalizedChildSearch.value));
482
+ });
483
+ function matchesSearch(item, normalizedValue) {
484
+ const haystack = [item.label, item.searchMeta].filter((value) => value).join(" ").toLocaleLowerCase();
485
+ return haystack.includes(normalizedValue);
486
+ }
487
+ function reorderItemIds(itemIds, oldIndex, newIndex) {
488
+ if (oldIndex < 0 || newIndex < 0 || oldIndex >= itemIds.length || newIndex >= itemIds.length) {
489
+ return itemIds.slice();
490
+ }
491
+ const nextItemIds = itemIds.slice();
492
+ const movedItemId = nextItemIds[oldIndex];
493
+ if (!movedItemId) {
494
+ return itemIds.slice();
495
+ }
496
+ nextItemIds.splice(oldIndex, 1);
497
+ nextItemIds.splice(newIndex, 0, movedItemId);
498
+ return nextItemIds;
499
+ }
500
+ function areItemIdsEqual(left, right) {
501
+ if (left.length !== right.length) {
502
+ return false;
503
+ }
504
+ return left.every((itemId, index) => itemId === right[index]);
505
+ }
506
+ function syncDraftColumnTreeRootOrder() {
507
+ const existingRootItemIds = draftColumnTree.value.rootItemIds;
508
+ const nextRootItemIds = [
509
+ ...leftPinnedRootItemIds.value,
510
+ ...centerRootItemIds.value,
511
+ ...rightPinnedRootItemIds.value
512
+ ].filter((itemId, index, itemIds) => existingRootItemIds.includes(itemId) && itemIds.indexOf(itemId) === index);
513
+ for (const itemId of existingRootItemIds) {
514
+ if (!nextRootItemIds.includes(itemId)) {
515
+ nextRootItemIds.push(itemId);
516
+ }
517
+ }
518
+ if (areItemIdsEqual(existingRootItemIds, nextRootItemIds)) {
519
+ return;
520
+ }
521
+ draftColumnTree.value = {
522
+ ...draftColumnTree.value,
523
+ rootItemIds: nextRootItemIds
524
+ };
525
+ }
526
+ function initializeInitialStateGroups(config) {
527
+ const leafColumnIdToRootItemId = /* @__PURE__ */ new Map();
528
+ for (const item of rootInitialStateItems.value) {
529
+ if (!item.canManage) {
530
+ continue;
531
+ }
532
+ for (const leafColumnId of item.leafColumnIds) {
533
+ if (!leafColumnIdToRootItemId.has(leafColumnId)) {
534
+ leafColumnIdToRootItemId.set(leafColumnId, item.itemId);
535
+ }
536
+ }
537
+ }
538
+ const initialState = config.props?.initialState;
539
+ const leftItemIds = [];
540
+ const rightItemIds = [];
541
+ const centerItemIds = [];
542
+ for (const leafColumnId of initialState?.columnPinning?.left ?? []) {
543
+ const itemId = leafColumnIdToRootItemId.get(leafColumnId);
544
+ if (!itemId || leftItemIds.includes(itemId)) {
545
+ continue;
546
+ }
547
+ leftItemIds.push(itemId);
548
+ }
549
+ for (const leafColumnId of initialState?.columnPinning?.right ?? []) {
550
+ const itemId = leafColumnIdToRootItemId.get(leafColumnId);
551
+ if (!itemId || leftItemIds.includes(itemId) || rightItemIds.includes(itemId)) {
552
+ continue;
553
+ }
554
+ rightItemIds.push(itemId);
555
+ }
556
+ for (const leafColumnId of initialState?.columnOrder ?? []) {
557
+ const itemId = leafColumnIdToRootItemId.get(leafColumnId);
558
+ if (!itemId || leftItemIds.includes(itemId) || rightItemIds.includes(itemId) || centerItemIds.includes(itemId)) {
559
+ continue;
560
+ }
561
+ centerItemIds.push(itemId);
562
+ }
563
+ for (const item of rootInitialStateItems.value) {
564
+ if (leftItemIds.includes(item.itemId) || rightItemIds.includes(item.itemId) || centerItemIds.includes(item.itemId)) {
565
+ continue;
566
+ }
567
+ centerItemIds.push(item.itemId);
568
+ }
569
+ leftPinnedRootItemIds.value = leftItemIds;
570
+ centerRootItemIds.value = centerItemIds;
571
+ rightPinnedRootItemIds.value = rightItemIds;
572
+ }
573
+ function resetDraftState(config) {
574
+ const nextPaginationPageSizes = getInitialPaginationPageSizes(config);
575
+ draftBaseConfig.value = config;
576
+ draftColumnTree.value = buildTableConfiguratorColumnTree(config.columns);
577
+ draftGetRowId.value = config.getRowId;
578
+ draftGetSubRows.value = config.getSubRows;
579
+ draftEnableRowSelection.value = config.enableRowSelection;
580
+ draftEnableMultiRowSelection.value = config.enableMultiRowSelection;
581
+ draftCellStyles.value = config.cellStyles;
582
+ draftPaginationLeft.value = config.paginationLeft;
583
+ draftPaginationRight.value = config.paginationRight;
584
+ draftPageSize.value = resolvePaginationPageSize(getInitialPageSize(config), nextPaginationPageSizes);
585
+ draftPaginationPageSizes.value = createPaginationPageSizeItems(nextPaginationPageSizes);
586
+ initializeInitialStateGroups(config);
587
+ syncDraftColumnTreeRootOrder();
588
+ childSearch.value = "";
589
+ selectedItemId.value = "general";
590
+ clearExpressionValidation();
591
+ }
592
+ watch(() => props.config, (config) => {
593
+ if (!open.value) {
594
+ resetDraftState(config);
595
+ }
596
+ }, { immediate: true });
597
+ const leftPinnedSortable = useSortable(leftPinnedSortableListRef, leftPinnedSortableItemIds);
598
+ const centerSortable = useSortable(centerSortableListRef, centerSortableItemIds);
599
+ const rightPinnedSortable = useSortable(rightPinnedSortableListRef, rightPinnedSortableItemIds);
600
+ const paginationPageSizesSortable = useSortable(paginationPageSizesSortableListRef, paginationPageSizesSortableItemIds);
601
+ const childSortable = useSortable(selectedChildSortableListRef, selectedChildSortableItemIds);
602
+ function syncSortableItemIds() {
603
+ leftPinnedSortableItemIds.value = leftPinnedRootItemIds.value.slice();
604
+ centerSortableItemIds.value = centerRootItemIds.value.slice();
605
+ rightPinnedSortableItemIds.value = rightPinnedRootItemIds.value.slice();
606
+ paginationPageSizesSortableItemIds.value = draftPaginationPageSizes.value.map((item) => item.itemId);
607
+ selectedChildSortableItemIds.value = selectedColumnNode.value?.childItemIds.slice() ?? [];
608
+ }
609
+ function normalizeInitialStateGroups() {
610
+ const rootItemIdSet = new Set(rootInitialStateItems.value.map((item) => item.itemId));
611
+ const manageableRootItemIdSet = new Set(
612
+ rootInitialStateItems.value.filter((item) => item.canManage).map((item) => item.itemId)
613
+ );
614
+ const leftItemIds = [];
615
+ const centerItemIds = [];
616
+ const rightItemIds = [];
617
+ for (const itemId of leftPinnedRootItemIds.value) {
618
+ if (!rootItemIdSet.has(itemId) || !manageableRootItemIdSet.has(itemId) || leftItemIds.includes(itemId)) {
619
+ continue;
620
+ }
621
+ leftItemIds.push(itemId);
622
+ }
623
+ for (const itemId of centerRootItemIds.value) {
624
+ if (!rootItemIdSet.has(itemId) || leftItemIds.includes(itemId) || centerItemIds.includes(itemId)) {
625
+ continue;
626
+ }
627
+ centerItemIds.push(itemId);
628
+ }
629
+ for (const itemId of rightPinnedRootItemIds.value) {
630
+ if (!rootItemIdSet.has(itemId) || !manageableRootItemIdSet.has(itemId) || leftItemIds.includes(itemId) || centerItemIds.includes(itemId) || rightItemIds.includes(itemId)) {
631
+ continue;
632
+ }
633
+ rightItemIds.push(itemId);
634
+ }
635
+ for (const item of rootInitialStateItems.value) {
636
+ if (leftItemIds.includes(item.itemId) || centerItemIds.includes(item.itemId) || rightItemIds.includes(item.itemId)) {
637
+ continue;
638
+ }
639
+ centerItemIds.push(item.itemId);
640
+ }
641
+ leftPinnedRootItemIds.value = leftItemIds;
642
+ centerRootItemIds.value = centerItemIds;
643
+ rightPinnedRootItemIds.value = rightItemIds;
644
+ }
645
+ function handleLeftPinnedSortableUpdate(event) {
646
+ const oldIndex = event.oldIndex;
647
+ const newIndex = event.newIndex;
648
+ if (selectedItemId.value !== "general" || oldIndex === void 0 || newIndex === void 0 || oldIndex === newIndex) {
649
+ return;
650
+ }
651
+ leftPinnedRootItemIds.value = reorderItemIds(
652
+ leftPinnedRootItemIds.value,
653
+ oldIndex,
654
+ newIndex
655
+ );
656
+ }
657
+ function handleCenterSortableUpdate(event) {
658
+ const oldIndex = event.oldIndex;
659
+ const newIndex = event.newIndex;
660
+ if (selectedItemId.value !== "general" || oldIndex === void 0 || newIndex === void 0 || oldIndex === newIndex) {
661
+ return;
662
+ }
663
+ centerRootItemIds.value = reorderItemIds(
664
+ centerRootItemIds.value,
665
+ oldIndex,
666
+ newIndex
667
+ );
668
+ }
669
+ function handleRightPinnedSortableUpdate(event) {
670
+ const oldIndex = event.oldIndex;
671
+ const newIndex = event.newIndex;
672
+ if (selectedItemId.value !== "general" || oldIndex === void 0 || newIndex === void 0 || oldIndex === newIndex) {
673
+ return;
674
+ }
675
+ rightPinnedRootItemIds.value = reorderItemIds(
676
+ rightPinnedRootItemIds.value,
677
+ oldIndex,
678
+ newIndex
679
+ );
680
+ }
681
+ function handlePaginationPageSizesSortableUpdate(event) {
682
+ const oldIndex = event.oldIndex;
683
+ const newIndex = event.newIndex;
684
+ if (selectedItemId.value !== "general" || oldIndex === void 0 || newIndex === void 0 || oldIndex === newIndex) {
685
+ return;
686
+ }
687
+ const nextItemIds = reorderItemIds(
688
+ draftPaginationPageSizes.value.map((item) => item.itemId),
689
+ oldIndex,
690
+ newIndex
691
+ );
692
+ const itemMap = new Map(draftPaginationPageSizes.value.map((item) => [item.itemId, item]));
693
+ draftPaginationPageSizes.value = nextItemIds.flatMap((itemId) => {
694
+ const item = itemMap.get(itemId);
695
+ return item ? [item] : [];
696
+ });
697
+ }
698
+ function handleChildSortableUpdate(event) {
699
+ const oldIndex = event.oldIndex;
700
+ const newIndex = event.newIndex;
701
+ const node = selectedColumnNode.value;
702
+ if (!node || oldIndex === void 0 || newIndex === void 0 || oldIndex === newIndex) {
703
+ return;
704
+ }
705
+ draftColumnTree.value = moveTableConfiguratorColumnSibling(
706
+ draftColumnTree.value,
707
+ node.itemId,
708
+ oldIndex,
709
+ newIndex
710
+ );
711
+ }
712
+ function configureLeftPinnedSortable() {
713
+ leftPinnedSortable.option("animation", 150);
714
+ leftPinnedSortable.option("handle", '[data-slot="table-configurator-initial-state-left-drag-handle"]');
715
+ leftPinnedSortable.option("onUpdate", handleLeftPinnedSortableUpdate);
716
+ }
717
+ function configureCenterSortable() {
718
+ centerSortable.option("animation", 150);
719
+ centerSortable.option("handle", '[data-slot="table-configurator-initial-state-center-drag-handle"]');
720
+ centerSortable.option("onUpdate", handleCenterSortableUpdate);
721
+ }
722
+ function configureRightPinnedSortable() {
723
+ rightPinnedSortable.option("animation", 150);
724
+ rightPinnedSortable.option("handle", '[data-slot="table-configurator-initial-state-right-drag-handle"]');
725
+ rightPinnedSortable.option("onUpdate", handleRightPinnedSortableUpdate);
726
+ }
727
+ function configurePaginationPageSizesSortable() {
728
+ paginationPageSizesSortable.option("animation", 150);
729
+ paginationPageSizesSortable.option("handle", '[data-slot="table-configurator-pagination-page-size-drag-handle"]');
730
+ paginationPageSizesSortable.option("onUpdate", handlePaginationPageSizesSortableUpdate);
731
+ }
732
+ function configureChildSortable() {
733
+ childSortable.option("animation", 150);
734
+ childSortable.option("handle", '[data-slot="table-configurator-child-drag-handle"]');
735
+ childSortable.option("onUpdate", handleChildSortableUpdate);
736
+ }
737
+ async function refreshSortable() {
738
+ leftPinnedSortable.stop();
739
+ centerSortable.stop();
740
+ rightPinnedSortable.stop();
741
+ paginationPageSizesSortable.stop();
742
+ childSortable.stop();
743
+ if (!open.value) {
744
+ return;
745
+ }
746
+ await nextTick();
747
+ if (selectedItemId.value === "general") {
748
+ leftPinnedSortable.start();
749
+ centerSortable.start();
750
+ rightPinnedSortable.start();
751
+ paginationPageSizesSortable.start();
752
+ configureLeftPinnedSortable();
753
+ configureCenterSortable();
754
+ configureRightPinnedSortable();
755
+ configurePaginationPageSizesSortable();
756
+ return;
757
+ }
758
+ if (selectedColumnNode.value) {
759
+ childSortable.start();
760
+ configureChildSortable();
761
+ }
762
+ }
763
+ watch(rootInitialStateItems, () => {
764
+ normalizeInitialStateGroups();
765
+ }, { immediate: true });
766
+ watch([leftPinnedRootItemIds, centerRootItemIds, rightPinnedRootItemIds], () => {
767
+ syncDraftColumnTreeRootOrder();
768
+ }, { immediate: true });
769
+ watch([draftColumnTree, draftPaginationPageSizes, selectedItemId, leftPinnedRootItemIds, centerRootItemIds, rightPinnedRootItemIds], () => {
770
+ syncSortableItemIds();
771
+ }, { immediate: true });
772
+ watch(() => draftPaginationPageSizes.value.length, async () => {
773
+ if (!open.value || selectedItemId.value !== "general") {
774
+ return;
775
+ }
776
+ await refreshSortable();
777
+ });
778
+ watch(open, async (value) => {
779
+ if (value) {
780
+ resetDraftState(props.config);
781
+ await refreshSortable();
782
+ return;
783
+ }
784
+ leftPinnedSortable.stop();
785
+ centerSortable.stop();
786
+ rightPinnedSortable.stop();
787
+ paginationPageSizesSortable.stop();
788
+ childSortable.stop();
789
+ childSearch.value = "";
790
+ search.value = "";
791
+ }, { immediate: true });
792
+ watch(selectedItemId, async () => {
793
+ childSearch.value = "";
794
+ clearAccessorValidation();
795
+ clearRendererValidation();
796
+ selectedColumnAccessorMode.value = getColumnAccessorMode(selectedColumn.value);
797
+ if (!open.value) {
798
+ return;
799
+ }
800
+ await refreshSortable();
801
+ });
802
+ watch(selectedColumnAccessorMode, (value, oldValue) => {
803
+ if (value === oldValue) {
804
+ return;
805
+ }
806
+ updateSelectedColumnAccessorMode(value);
807
+ });
808
+ watch(columnListItems, (items) => {
809
+ if (selectedItemId.value === "general") {
810
+ return;
811
+ }
812
+ if (!items.some((item) => item.itemId === selectedItemId.value)) {
813
+ selectedItemId.value = "general";
814
+ }
815
+ }, { immediate: true });
816
+ watch(filteredColumnItems, (items) => {
817
+ if (!normalizedSearch.value || selectedItemId.value === "general") {
818
+ return;
819
+ }
820
+ if (items.some((item) => item.itemId === selectedItemId.value)) {
821
+ return;
822
+ }
823
+ selectedItemId.value = items[0]?.itemId ?? "general";
824
+ }, { immediate: true });
825
+ watch(selectedColumnRendererId, () => {
826
+ clearRendererValidation();
827
+ });
828
+ function normalizeColumn(column) {
829
+ const title = hasVisibleLocaleValue(column.title) ? column.title : void 0;
830
+ const tooltip = hasVisibleLocaleValue(column.tooltip) ? column.tooltip : void 0;
831
+ const normalizedChildren = column.columns?.map(normalizeColumn);
832
+ const shouldDropGeneratedId = looksLikeGeneratedColumnId(column.id) && normalizedChildren === void 0 && column.accessor !== void 0;
833
+ return {
834
+ ...column,
835
+ id: shouldDropGeneratedId ? void 0 : column.id,
836
+ title,
837
+ tooltip,
838
+ columns: normalizedChildren?.length ? normalizedChildren : void 0
839
+ };
840
+ }
841
+ function discardChanges() {
842
+ resetDraftState(props.config);
843
+ childSearch.value = "";
844
+ search.value = "";
845
+ open.value = false;
846
+ }
847
+ function handleOpenChange(value) {
848
+ if (value) {
849
+ open.value = true;
850
+ return;
851
+ }
852
+ discardChanges();
853
+ }
854
+ function selectGeneral() {
855
+ selectedItemId.value = "general";
856
+ }
857
+ function selectItem(itemId) {
858
+ selectedItemId.value = itemId;
859
+ }
860
+ function moveRootItemToGroup(itemId, group) {
861
+ const nextLeftItemIds = leftPinnedRootItemIds.value.filter((currentItemId) => currentItemId !== itemId);
862
+ const nextCenterItemIds = centerRootItemIds.value.filter((currentItemId) => currentItemId !== itemId);
863
+ const nextRightItemIds = rightPinnedRootItemIds.value.filter((currentItemId) => currentItemId !== itemId);
864
+ if (group === "left") {
865
+ nextLeftItemIds.push(itemId);
866
+ } else if (group === "center") {
867
+ nextCenterItemIds.push(itemId);
868
+ } else {
869
+ nextRightItemIds.push(itemId);
870
+ }
871
+ leftPinnedRootItemIds.value = nextLeftItemIds;
872
+ centerRootItemIds.value = nextCenterItemIds;
873
+ rightPinnedRootItemIds.value = nextRightItemIds;
874
+ }
875
+ function addColumn() {
876
+ const nextNode = createTableConfiguratorDraftColumnNode({
877
+ id: crypto.randomUUID()
878
+ });
879
+ draftColumnTree.value = insertTableConfiguratorRootColumnNode(draftColumnTree.value, nextNode);
880
+ selectedItemId.value = nextNode.itemId;
881
+ }
882
+ function deleteColumn(itemId) {
883
+ const flattenedItems = flattenTableConfiguratorColumnTree(draftColumnTree.value);
884
+ const deleteIndex = flattenedItems.findIndex((item) => item.itemId === itemId);
885
+ if (deleteIndex < 0) {
886
+ return;
887
+ }
888
+ const removedItemIds = [itemId, ...getTableConfiguratorColumnDescendantItemIds(draftColumnTree.value, itemId)];
889
+ const nextTree = removeTableConfiguratorColumnSubtree(draftColumnTree.value, itemId);
890
+ draftColumnTree.value = nextTree;
891
+ if (!removedItemIds.includes(selectedItemId.value)) {
892
+ return;
893
+ }
894
+ const nextFlattenedItems = flattenTableConfiguratorColumnTree(nextTree);
895
+ const nextSelectedItem = nextFlattenedItems[deleteIndex] ?? nextFlattenedItems[deleteIndex - 1];
896
+ selectedItemId.value = nextSelectedItem?.itemId ?? "general";
897
+ }
898
+ function updateSelectedColumnTitle(value) {
899
+ const node = selectedColumnNode.value;
900
+ if (!node) {
901
+ return;
902
+ }
903
+ draftColumnTree.value = updateTableConfiguratorColumnNode(
904
+ draftColumnTree.value,
905
+ node.itemId,
906
+ (column) => ({
907
+ ...column,
908
+ title: value
909
+ })
910
+ );
911
+ }
912
+ function updateSelectedColumnTooltip(value) {
913
+ const node = selectedColumnNode.value;
914
+ if (!node) {
915
+ return;
916
+ }
917
+ draftColumnTree.value = updateTableConfiguratorColumnNode(
918
+ draftColumnTree.value,
919
+ node.itemId,
920
+ (column) => ({
921
+ ...column,
922
+ tooltip: value
923
+ })
924
+ );
925
+ }
926
+ function updateSelectedColumnAccessor(accessor) {
927
+ const node = selectedColumnNode.value;
928
+ if (!node) {
929
+ return;
930
+ }
931
+ draftColumnTree.value = updateTableConfiguratorColumnNode(
932
+ draftColumnTree.value,
933
+ node.itemId,
934
+ (column) => ({
935
+ ...column,
936
+ accessor
937
+ })
938
+ );
939
+ }
940
+ function updateSelectedColumnSize(value) {
941
+ const node = selectedColumnNode.value;
942
+ if (!node) {
943
+ return;
944
+ }
945
+ draftColumnTree.value = updateTableConfiguratorColumnNode(
946
+ draftColumnTree.value,
947
+ node.itemId,
948
+ (column) => ({
949
+ ...column,
950
+ size: normalizeOptionalNumber(value)
951
+ })
952
+ );
953
+ }
954
+ function updateSelectedColumnGrow(value) {
955
+ const node = selectedColumnNode.value;
956
+ if (!node) {
957
+ return;
958
+ }
959
+ draftColumnTree.value = updateTableConfiguratorColumnNode(
960
+ draftColumnTree.value,
961
+ node.itemId,
962
+ (column) => ({
963
+ ...column,
964
+ grow: value === true
965
+ })
966
+ );
967
+ }
968
+ function updateSelectedColumnEnableSorting(value) {
969
+ const node = selectedColumnNode.value;
970
+ if (!node) {
971
+ return;
972
+ }
973
+ draftColumnTree.value = updateTableConfiguratorColumnNode(
974
+ draftColumnTree.value,
975
+ node.itemId,
976
+ (column) => ({
977
+ ...column,
978
+ enableSorting: value === true
979
+ })
980
+ );
981
+ }
982
+ function updateSelectedColumnAccessorPath(value) {
983
+ updateSelectedColumnAccessor(value);
984
+ }
985
+ function updateSelectedColumnAccessorRead(value) {
986
+ const currentAccessor = selectedColumnAccessorExpression.value;
987
+ const nextRead = value ?? "";
988
+ const nextWrite = currentAccessor.write;
989
+ if (nextRead.length === 0 && nextWrite.length === 0) {
990
+ updateSelectedColumnAccessor(void 0);
991
+ return;
992
+ }
993
+ updateSelectedColumnAccessor({
994
+ read: nextRead,
995
+ write: nextWrite
996
+ });
997
+ }
998
+ function updateSelectedColumnAccessorWrite(value) {
999
+ const currentAccessor = selectedColumnAccessorExpression.value;
1000
+ const nextRead = currentAccessor.read;
1001
+ const nextWrite = value ?? "";
1002
+ if (nextRead.length === 0 && nextWrite.length === 0) {
1003
+ updateSelectedColumnAccessor(void 0);
1004
+ return;
1005
+ }
1006
+ updateSelectedColumnAccessor({
1007
+ read: nextRead,
1008
+ write: nextWrite
1009
+ });
1010
+ }
1011
+ function updateSelectedColumnAccessorMode(value) {
1012
+ const column = selectedColumn.value;
1013
+ if (!column) {
1014
+ return;
1015
+ }
1016
+ if (value === "path") {
1017
+ updateSelectedColumnAccessor(getColumnAccessorPath(column));
1018
+ clearAccessorValidation();
1019
+ return;
1020
+ }
1021
+ const accessor = getColumnAccessorExpression(column);
1022
+ updateSelectedColumnAccessor({
1023
+ read: accessor.read,
1024
+ write: accessor.write
1025
+ });
1026
+ clearAccessorValidation();
1027
+ }
1028
+ function updateSelectedColumnRendererId(value) {
1029
+ const node = selectedColumnNode.value;
1030
+ if (!node || typeof value !== "string") {
1031
+ return;
1032
+ }
1033
+ draftColumnTree.value = updateTableConfiguratorColumnNode(
1034
+ draftColumnTree.value,
1035
+ node.itemId,
1036
+ (column) => ({
1037
+ ...column,
1038
+ renderer: buildColumnRenderer(value, void 0)
1039
+ })
1040
+ );
1041
+ }
1042
+ function updateSelectedColumnRendererProps(value) {
1043
+ const node = selectedColumnNode.value;
1044
+ if (!node) {
1045
+ return;
1046
+ }
1047
+ draftColumnTree.value = updateTableConfiguratorColumnNode(
1048
+ draftColumnTree.value,
1049
+ node.itemId,
1050
+ (column) => ({
1051
+ ...column,
1052
+ renderer: buildColumnRenderer(selectedColumnRendererId.value, value)
1053
+ })
1054
+ );
1055
+ }
1056
+ function toggleChildSelection(itemId, value) {
1057
+ const node = selectedColumnNode.value;
1058
+ if (!node || value !== true) {
1059
+ return;
1060
+ }
1061
+ draftColumnTree.value = moveTableConfiguratorColumnNodeToParent(
1062
+ draftColumnTree.value,
1063
+ itemId,
1064
+ node.itemId
1065
+ );
1066
+ }
1067
+ function removeSelectedChild(itemId) {
1068
+ const node = selectedColumnNode.value;
1069
+ if (!node) {
1070
+ return;
1071
+ }
1072
+ draftColumnTree.value = moveTableConfiguratorColumnNodeAfterItem(
1073
+ draftColumnTree.value,
1074
+ itemId,
1075
+ node.itemId
1076
+ );
1077
+ }
1078
+ function clearExpressionValidation() {
1079
+ getRowIdEditor.value?.clearValidation();
1080
+ getSubRowsEditor.value?.clearValidation();
1081
+ enableRowSelectionEditor.value?.clearValidation();
1082
+ enableMultiRowSelectionEditor.value?.clearValidation();
1083
+ cellStylesEditor.value?.clearValidation();
1084
+ clearAccessorValidation();
1085
+ clearRendererValidation();
1086
+ }
1087
+ function clearAccessorValidation() {
1088
+ accessorPathEditor.value?.clearValidation();
1089
+ accessorReadEditor.value?.clearValidation();
1090
+ accessorWriteEditor.value?.clearValidation();
1091
+ }
1092
+ function clearRendererValidation() {
1093
+ if (isRendererConfigExposed(selectedRendererConfigRef.value)) {
1094
+ selectedRendererConfigRef.value.clearValidation();
1095
+ }
1096
+ }
1097
+ function validateExpressionEditors() {
1098
+ let isValid = true;
1099
+ if (getRowIdEditor.value && !getRowIdEditor.value.validate()) {
1100
+ isValid = false;
1101
+ }
1102
+ if (getSubRowsEditor.value && !getSubRowsEditor.value.validate()) {
1103
+ isValid = false;
1104
+ }
1105
+ if (enableRowSelectionEditor.value && !enableRowSelectionEditor.value.validate()) {
1106
+ isValid = false;
1107
+ }
1108
+ if (enableMultiRowSelectionEditor.value && !enableMultiRowSelectionEditor.value.validate()) {
1109
+ isValid = false;
1110
+ }
1111
+ if (cellStylesEditor.value && !cellStylesEditor.value.validate()) {
1112
+ isValid = false;
1113
+ }
1114
+ if (selectedColumn.value && selectedColumnAccessorMode.value === "path" && selectedColumnAccessorPath.value !== void 0 && accessorPathEditor.value && !accessorPathEditor.value.validate()) {
1115
+ isValid = false;
1116
+ }
1117
+ if (selectedColumn.value && selectedColumnAccessorMode.value === "expression") {
1118
+ const accessor = selectedColumn.value.accessor;
1119
+ if (!accessor || typeof accessor === "string") {
1120
+ return validateRendererConfig(isValid);
1121
+ }
1122
+ if (accessorReadEditor.value && !accessorReadEditor.value.validate()) {
1123
+ isValid = false;
1124
+ }
1125
+ if (accessorWriteEditor.value && !accessorWriteEditor.value.validate()) {
1126
+ isValid = false;
1127
+ }
1128
+ }
1129
+ return validateRendererConfig(isValid);
1130
+ }
1131
+ function validateRendererConfig(currentIsValid) {
1132
+ if (!selectedColumn.value || selectedColumnHasChildren.value) {
1133
+ return currentIsValid;
1134
+ }
1135
+ if (isRendererConfigExposed(selectedRendererConfigRef.value) && !selectedRendererConfigRef.value.validate()) {
1136
+ return false;
1137
+ }
1138
+ return currentIsValid;
1139
+ }
1140
+ function buildInitialStateLeafColumnIds(itemIds) {
1141
+ const leafColumnIds = [];
1142
+ for (const itemId of itemIds) {
1143
+ const item = rootInitialStateItems.value.find((candidate) => candidate.itemId === itemId);
1144
+ if (!item?.canManage) {
1145
+ continue;
1146
+ }
1147
+ leafColumnIds.push(...item.leafColumnIds);
1148
+ }
1149
+ return leafColumnIds;
1150
+ }
1151
+ function updateDraftPaginationLeft(value) {
1152
+ draftPaginationLeft.value = normalizeOptionalText(String(value));
1153
+ }
1154
+ function updateDraftPaginationRight(value) {
1155
+ draftPaginationRight.value = normalizeOptionalText(String(value));
1156
+ }
1157
+ function updateDraftPageSize(value) {
1158
+ draftPageSize.value = normalizeOptionalNumber(value);
1159
+ }
1160
+ function updateDraftPaginationPageSizeOption(itemId, value) {
1161
+ const normalizedValue = normalizeOptionalNumber(value);
1162
+ draftPaginationPageSizes.value = draftPaginationPageSizes.value.map((item) => item.itemId === itemId ? {
1163
+ ...item,
1164
+ value: normalizedValue
1165
+ } : item);
1166
+ }
1167
+ function addDraftPaginationPageSizeOption() {
1168
+ draftPaginationPageSizes.value = [
1169
+ ...draftPaginationPageSizes.value,
1170
+ createPaginationPageSizeItem()
1171
+ ];
1172
+ }
1173
+ function removeDraftPaginationPageSizeOption(itemId) {
1174
+ draftPaginationPageSizes.value = draftPaginationPageSizes.value.filter((item) => item.itemId !== itemId);
1175
+ }
1176
+ function buildNextPaginationPageSizes() {
1177
+ return normalizePaginationPageSizes(draftPaginationPageSizes.value.flatMap((item) => {
1178
+ if (item.value === void 0) {
1179
+ return [];
1180
+ }
1181
+ return [item.value];
1182
+ }));
1183
+ }
1184
+ function buildNextPaginationState() {
1185
+ const currentPagination = draftBaseConfig.value.props?.initialState?.pagination;
1186
+ const nextPaginationPageSizes = buildNextPaginationPageSizes();
1187
+ const nextPageSize = resolvePaginationPageSize(draftPageSize.value, nextPaginationPageSizes);
1188
+ if (!currentPagination && nextPageSize === void 0) {
1189
+ return void 0;
1190
+ }
1191
+ return {
1192
+ ...currentPagination,
1193
+ pageSize: nextPageSize
1194
+ };
1195
+ }
1196
+ function buildDraftConfig() {
1197
+ return TableConfigC.safeParse({
1198
+ ...draftBaseConfig.value,
1199
+ getRowId: draftGetRowId.value,
1200
+ getSubRows: draftGetSubRows.value,
1201
+ enableRowSelection: draftEnableRowSelection.value,
1202
+ enableMultiRowSelection: draftEnableMultiRowSelection.value,
1203
+ cellStyles: draftCellStyles.value,
1204
+ paginationLeft: normalizeOptionalText(draftPaginationLeft.value),
1205
+ paginationRight: normalizeOptionalText(draftPaginationRight.value),
1206
+ paginationPageSizes: buildNextPaginationPageSizes(),
1207
+ columns: materializeTableConfiguratorColumnTree(draftColumnTree.value).map(normalizeColumn),
1208
+ props: {
1209
+ ...draftBaseConfig.value.props,
1210
+ initialState: {
1211
+ ...draftBaseConfig.value.props?.initialState,
1212
+ columnPinning: {
1213
+ ...draftBaseConfig.value.props?.initialState?.columnPinning,
1214
+ left: buildInitialStateLeafColumnIds(leftPinnedRootItemIds.value),
1215
+ right: buildInitialStateLeafColumnIds(rightPinnedRootItemIds.value)
1216
+ },
1217
+ columnOrder: buildInitialStateLeafColumnIds(centerRootItemIds.value),
1218
+ pagination: buildNextPaginationState()
1219
+ }
1220
+ }
1221
+ });
1222
+ }
1223
+ function showImportError(message) {
1224
+ $toast.error(message);
1225
+ }
1226
+ function showCopyError(message) {
1227
+ $toast.error(message);
1228
+ }
1229
+ function showImportErrorWithCopyAction(message, onClick) {
1230
+ $toast.error(message, {
1231
+ action: {
1232
+ label: t("copy-paste-error"),
1233
+ onClick
1234
+ }
1235
+ });
1236
+ }
1237
+ function getValidDraftConfig(errorMessage) {
1238
+ if (!validateExpressionEditors()) {
1239
+ showCopyError(errorMessage);
1240
+ return void 0;
1241
+ }
1242
+ const result = buildDraftConfig();
1243
+ if (!result.success) {
1244
+ showCopyError(errorMessage);
1245
+ return void 0;
1246
+ }
1247
+ return result.data;
1248
+ }
1249
+ function buildTableConfigJsonSchema() {
1250
+ return z.toJSONSchema(TableConfigC, {
1251
+ io: "input",
1252
+ unrepresentable: "any"
1253
+ });
1254
+ }
1255
+ function collectUsedRendererIds(columns) {
1256
+ const rendererIds = [];
1257
+ for (const column of columns) {
1258
+ if (Array.isArray(column.columns) && column.columns.length > 0) {
1259
+ for (const rendererId2 of collectUsedRendererIds(column.columns)) {
1260
+ if (!rendererIds.includes(rendererId2)) {
1261
+ rendererIds.push(rendererId2);
1262
+ }
1263
+ }
1264
+ continue;
1265
+ }
1266
+ const rendererId = getColumnRendererId(column);
1267
+ if (!rendererIds.includes(rendererId)) {
1268
+ rendererIds.push(rendererId);
1269
+ }
1270
+ }
1271
+ return rendererIds;
1272
+ }
1273
+ function buildRendererSchemaMarkdown(config) {
1274
+ const rendererIds = collectUsedRendererIds(config.columns);
1275
+ if (rendererIds.length === 0) {
1276
+ return "\u5F53\u524D\u8349\u7A3F\u4E2D\u6CA1\u6709\u53F6\u5B50\u5217\u6E32\u67D3\u5668\u3002";
1277
+ }
1278
+ return rendererIds.map((rendererId) => {
1279
+ const renderer = getTableRenderer(rendererId);
1280
+ if (!renderer) {
1281
+ return [
1282
+ `### ${rendererId}`,
1283
+ "\u672A\u627E\u5230\u8BE5\u6E32\u67D3\u5668\u7684 options schema\u3002"
1284
+ ].join("\n");
1285
+ }
1286
+ return [
1287
+ `### ${rendererId}`,
1288
+ "```json",
1289
+ JSON.stringify(z.toJSONSchema(renderer.optionsSchema, {
1290
+ io: "input",
1291
+ unrepresentable: "any"
1292
+ }), null, 2),
1293
+ "```"
1294
+ ].join("\n");
1295
+ }).join("\n\n");
1296
+ }
1297
+ function buildDslGuideMarkdown() {
1298
+ return [
1299
+ "## DSL / CEL \u7F16\u5199\u8BF4\u660E",
1300
+ "\u672C\u914D\u7F6E\u4E2D\u7684 DSL \u662F CEL \u8868\u8FBE\u5F0F\uFF1B\u8868\u8FBE\u5F0F\u5B57\u6BB5\u5FC5\u987B\u586B\u5199\u5B57\u7B26\u4E32\uFF0C\u4E0D\u8981\u751F\u6210 JavaScript\u3001TypeScript\u3001\u7BAD\u5934\u51FD\u6570\u6216\u4F2A\u4EE3\u7801\u3002",
1301
+ "",
1302
+ "### 1. \u57FA\u7840\u8BED\u6CD5",
1303
+ '- \u5B57\u9762\u91CF\uFF1A`"text"`\u3001`123`\u3001`123.45`\u3001`true`\u3001`false`\u3001`null`\u3002',
1304
+ '- \u5217\u8868 / \u5BF9\u8C61\uFF1A`[1, 2, 3]`\u3001`{"a": 1, "b": 2}`\u3002',
1305
+ '- \u8BBF\u95EE\uFF1A`.`\u3001`[]`\uFF0C\u4F8B\u5982 `row.id`\u3001`row["id"]`\u3001`row.items[0]`\u3002',
1306
+ '- \u53EF\u9009\u8BBF\u95EE\uFF1A`.?`\u3001`[?]`\uFF0C\u4F8B\u5982 `row.?children`\u3001`row[?"name"]`\u3002',
1307
+ "- \u903B\u8F91\u4E0E\u6761\u4EF6\uFF1A`&&`\u3001`||`\u3001`!`\u3001`condition ? a : b`\u3002",
1308
+ "- \u6BD4\u8F83\uFF1A`==`\u3001`!=`\u3001`<`\u3001`<=`\u3001`>`\u3001`>=`\u3001`in`\u3002",
1309
+ "- \u7B97\u672F\uFF1A`+`\u3001`-`\u3001`*`\u3001`/`\u3001`%`\u3002",
1310
+ '- \u65B9\u6CD5\u8C03\u7528\uFF1A`value.method(args)`\uFF0C\u4F8B\u5982 `now.format("yyyy-MM-dd")`\u3001`row.?children.orValue([])`\u3002',
1311
+ "- `accessor` \u4E3A\u5B57\u7B26\u4E32\u65F6\u4E0D\u662F CEL\uFF0C\u800C\u662F dot-prop \u8DEF\u5F84\uFF0C\u4F8B\u5982 `id`\u3001`foo.bar`\u3001`foo[0].bar`\u3002",
1312
+ "",
1313
+ "### 2. \u5168\u5C40\u53D8\u91CF\u4E0E\u5E38\u91CF",
1314
+ "- `now: Date` \u5F53\u524D\u65F6\u95F4\u3002",
1315
+ "- `today: Date` \u4E0E `now` \u7C7B\u4F3C\uFF0C\u4FDD\u7559\u7528\u4E8E\u517C\u5BB9\u65E7\u914D\u7F6E\u3002",
1316
+ "- `location: URL` \u5F53\u524D\u9875\u9762 URL\u3002",
1317
+ "- `token: string` \u5F53\u524D sessionStorage \u4E2D\u7684 token\uFF0C\u7F3A\u5931\u65F6\u4E3A\u7A7A\u5B57\u7B26\u4E32\u3002",
1318
+ "- `locale: string` \u5F53\u524D\u6D4F\u89C8\u5668\u8BED\u8A00\u3002",
1319
+ "- `git: map<string, string>` \u6765\u81EA\u8FD0\u884C\u65F6\u914D\u7F6E\u7684 git \u5E38\u91CF\u3002",
1320
+ "- `ci: map<string, dyn>` \u6765\u81EA\u8FD0\u884C\u65F6\u914D\u7F6E\u7684 CI \u5E38\u91CF\uFF0C\u5176\u4E2D `ci.build` \u4F1A\u88AB\u8F6C\u6210 `int`\u3002",
1321
+ "- \u8FD8\u4F1A\u6DF7\u5165\u5BBF\u4E3B\u5E94\u7528\u901A\u8FC7 `props.dsl` \u6CE8\u5165\u7684\u5168\u5C40\u52A8\u6001\u4E0A\u4E0B\u6587\uFF1B\u8FD9\u4E9B\u952E\u5B58\u5728\u65F6\u53EF\u76F4\u63A5\u8BBF\u95EE\uFF0C\u4F46\u540D\u79F0\u548C\u7C7B\u578B\u4E0D\u56FA\u5B9A\uFF0C\u5E94\u4EE5\u5F53\u524D\u914D\u7F6E\u548C\u4E1A\u52A1\u4E0A\u4E0B\u6587\u4E3A\u51C6\u3002",
1322
+ "",
1323
+ "### 3. \u8868\u683C\u914D\u7F6E\u5B57\u6BB5\u91CC\u7684\u5C40\u90E8\u53D8\u91CF",
1324
+ "- `accessor.read`: `row: dyn`\u3001`index: int`\u3002",
1325
+ "- `getRowId`: `row: dyn`\u3001`index: int`\u3001`parent: dyn`\uFF1B\u5FC5\u987B\u8FD4\u56DE `string`\u3002",
1326
+ "- `getSubRows`: `row: dyn`\u3001`index: int`\uFF1B\u901A\u5E38\u8FD4\u56DE `list<dyn>`\u3002",
1327
+ "- `enableRowSelection`: `row: dyn`\u3001`index: int`\u3001`id: string`\uFF1B\u5FC5\u987B\u8FD4\u56DE `bool`\u3002",
1328
+ "- `enableMultiRowSelection`: `row: dyn`\u3001`index: int`\u3001`id: string`\uFF1B\u5FC5\u987B\u8FD4\u56DE `bool`\u3002",
1329
+ "- `cellStyles`: `row: dyn`\u3001`index: int`\u3001`id: string`\u3001`selected: bool`\u3001`pinned: dyn`\uFF1B\u5FC5\u987B\u8FD4\u56DE `map`\u3002",
1330
+ "- `table.renderer.text.props.copyExpression`: `row: dyn`\u3001`index: int`\u3002",
1331
+ "",
1332
+ "### 4. \u53EF\u7528\u7C7B\u578B\u4E0E\u6269\u5C55\u80FD\u529B",
1333
+ "- `URL` \u7C7B\u578B\uFF1A\u53EF\u8C03\u7528 `location.searchParams()`\uFF0C\u8FD4\u56DE `URLSearchParams`\u3002",
1334
+ "- `URLSearchParams` \u7C7B\u578B\uFF1A\u53EF\u8C03\u7528 `searchParams({...})` \u521B\u5EFA\uFF0C`URLSearchParams.get(string)` \u8FD4\u56DE `optional<string>`\u3002",
1335
+ "- `Date` \u7C7B\u578B\uFF1A\u7531 `date(string)` \u521B\u5EFA\uFF0C\u4E5F\u53EF\u76F4\u63A5\u4F7F\u7528 `now` / `today`\u3002",
1336
+ "- `Date` \u652F\u6301\u6BD4\u8F83\uFF1A`<`\u3001`<=`\u3001`>`\u3001`>=`\u3001`==`\u3002",
1337
+ "- `Date.startOf(string)` / `Date.endOf(string)`\uFF1A`unit` \u652F\u6301 `day` / `week` / `month` / `year`\u3002",
1338
+ "- `Date.offset(int, string)`\uFF1A`unit` \u652F\u6301 `day|days|week|weeks|month|months|year|years`\u3002",
1339
+ "- `Date.set(string, int)`\uFF1A`unit` \u652F\u6301 `day` / `month` / `year`\uFF0C\u5176\u4E2D `month` \u4F20\u5165\u81EA\u7136\u6708 1-12\u3002",
1340
+ '- `Date.format(string)`\uFF1A\u4F7F\u7528 `date-fns` \u683C\u5F0F\u5316\u5B57\u7B26\u4E32\uFF0C\u4F8B\u5982 `now.format("yyyy-MM-dd")`\u3002',
1341
+ "- `list<double>.sum()` / `list<int>.sum()`\uFF1A\u5BF9\u6570\u5B57\u5217\u8868\u6C42\u548C\uFF0C\u8FD4\u56DE `double`\u3002",
1342
+ "- `double.toLocaleString(dyn)` / `int.toLocaleString(dyn)`\uFF1A\u6309\u5F53\u524D\u8BED\u8A00\u683C\u5F0F\u5316\u6570\u5B57\u3002",
1343
+ "- `double.encodeSimplifiedChineseUppercase()` / `int.encodeSimplifiedChineseUppercase()`\uFF1A\u8F6C\u4E2D\u6587\u5927\u5199\u91D1\u989D/\u6570\u5B57\u3002",
1344
+ "- `parseJSON(string): dyn`\uFF1A\u628A JSON \u5B57\u7B26\u4E32\u89E3\u6790\u6210\u5BF9\u8C61\u6216\u5217\u8868\u3002",
1345
+ "- `string.slice(int)` / `string.slice(int, int)`\uFF1A\u5B57\u7B26\u4E32\u5207\u7247\u3002",
1346
+ "- `session(string): optional<string>`\uFF1A\u4ECE `sessionStorage` \u8BFB\u53D6\u503C\u3002",
1347
+ "- `local(string): optional<string>`\uFF1A\u4ECE `localStorage` \u8BFB\u53D6\u503C\u3002",
1348
+ "",
1349
+ "### 5. Optional / \u7A7A\u503C\u8BED\u4E49",
1350
+ "- \u53EF\u9009\u8BBF\u95EE .? \u548C [?] \u4F1A\u8FD4\u56DE `Optional`\uFF0C\u800C\u4E0D\u662F\u76F4\u63A5\u8FD4\u56DE\u666E\u901A\u503C\u3002",
1351
+ "- `Optional.hasValue()` \u5224\u65AD\u662F\u5426\u5B58\u5728\u503C\u3002",
1352
+ "- `Optional.value()` \u53D6\u503C\uFF1B\u5728\u7A7A\u503C\u65F6\u4F1A\u629B\u9519\uFF0C\u4E00\u822C\u4E0D\u5EFA\u8BAE\u76F4\u63A5\u4F7F\u7528\u3002",
1353
+ "- `Optional.or(optional)` \u5728\u7A7A\u503C\u65F6\u4F7F\u7528\u53E6\u4E00\u4E2A Optional\u3002",
1354
+ "- `Optional.orValue(defaultValue)` \u5728\u7A7A\u503C\u65F6\u8FD4\u56DE\u9ED8\u8BA4\u503C\uFF0C\u6700\u5E38\u7528\u3002\u793A\u4F8B\uFF1A`row.?children.orValue([])`\u3002",
1355
+ "",
1356
+ "### 6. \u7F16\u5199\u8981\u6C42",
1357
+ "- \u751F\u6210\u8868\u8FBE\u5F0F\u65F6\u8981\u4E25\u683C\u9075\u5B88\u5B57\u6BB5\u8FD4\u56DE\u7C7B\u578B\uFF0C\u4E0D\u8981\u6DF7\u7528\u5B57\u7B26\u4E32\u3001\u5E03\u5C14\u503C\u3001\u6570\u7EC4\u548C\u5BF9\u8C61\u3002",
1358
+ "- \u5982\u679C\u5B57\u6BB5 schema \u6216\u5C40\u90E8\u53D8\u91CF\u6CA1\u6709\u58F0\u660E\u67D0\u4E2A\u53D8\u91CF\uFF0C\u5C31\u4E0D\u8981\u81C6\u9020\u65B0\u7684\u53D8\u91CF\u540D\u3002",
1359
+ "- \u4F18\u5148\u590D\u7528\u5F53\u524D\u914D\u7F6E\u4E2D\u5DF2\u7ECF\u51FA\u73B0\u8FC7\u7684\u5B57\u6BB5\u8DEF\u5F84\u3001\u8868\u8FBE\u5F0F\u6A21\u5F0F\u548C\u8FD4\u56DE\u7ED3\u6784\u3002"
1360
+ ].join("\n");
1361
+ }
1362
+ function buildMarkdownNotes() {
1363
+ return [
1364
+ "## \u6CE8\u610F\u4E8B\u9879",
1365
+ "- \u8BF7\u4F18\u5148\u4F9D\u636E schema \u4E2D\u7684 `description` \u7F16\u5199\u914D\u7F6E\uFF0C\u63CF\u8FF0\u8D8A\u8BE6\u7EC6\u8D8A\u91CD\u8981\uFF0C\u4E0D\u8981\u5FFD\u7565\u5B57\u6BB5\u8BF4\u660E\u3002",
1366
+ "- \u53EA\u5141\u8BB8\u4FEE\u6539\u73B0\u6709\u5217\u7684\u914D\u7F6E\uFF1B\u7981\u6B62\u65B0\u589E\u9876\u7EA7\u5217\u3001\u7981\u6B62\u65B0\u589E\u5B50\u5217\u3001\u7981\u6B62\u5220\u9664\u540E\u91CD\u5EFA\u5217\u3002",
1367
+ "- \u7981\u6B62\u751F\u6210\u65B0\u7684\u5217 ID\uFF0C\u4E5F\u4E0D\u8981\u4E3A\u7F3A\u5931 ID \u7684\u65B0\u5217\u8865 ID\uFF1B\u5982\u679C\u7528\u6237\u9700\u8981\u65B0\u589E\u5217\uFF0C\u5FC5\u987B\u5728\u754C\u9762\u4E2D\u624B\u52A8\u5B8C\u6210\u3002",
1368
+ "- \u4FEE\u6539\u5217\u914D\u7F6E\u65F6\u5C3D\u91CF\u4FDD\u7559\u73B0\u6709\u5217\u987A\u5E8F\u3001\u5C42\u7EA7\u7ED3\u6784\u3001`id`\u3001`accessor` \u548C renderer \u8BED\u4E49\uFF0C\u9664\u975E\u7528\u6237\u660E\u786E\u8981\u6C42\u53D8\u66F4\u3002",
1369
+ "- \u5982\u679C\u9700\u6C42\u8D85\u51FA schema \u80FD\u8868\u8FBE\u7684\u8303\u56F4\uFF0C\u5E94\u8BE5\u76F4\u63A5\u8BF4\u660E\u9650\u5236\uFF0C\u800C\u4E0D\u662F\u53D1\u660E schema \u4E2D\u4E0D\u5B58\u5728\u7684\u65B0\u5B57\u6BB5\u3002"
1370
+ ].join("\n");
1371
+ }
1372
+ function buildAiPromptHeaderMarkdown() {
1373
+ return [
1374
+ "# \u8868\u683C\u914D\u7F6E AI \u4E0A\u4E0B\u6587",
1375
+ "\u4F60\u662F\u4E00\u4E2A\u5E2E\u52A9\u7528\u6237\u914D\u7F6E\u8868\u683C\u7EC4\u4EF6\u7684 AI \u52A9\u624B\uFF0C\u8D1F\u8D23\u6839\u636E\u5F53\u524D\u914D\u7F6E\u3001schema \u548C DSL \u89C4\u5219\u56DE\u7B54\u7528\u6237\u95EE\u9898\u3002",
1376
+ "\u4F60\u7684\u76EE\u6807\u662F\u89E3\u91CA\u73B0\u6709\u914D\u7F6E\u3001\u5E2E\u52A9\u7528\u6237\u4FEE\u6539\u73B0\u6709\u914D\u7F6E\uFF0C\u5E76\u5728\u7EA6\u675F\u8303\u56F4\u5185\u751F\u6210\u53EF\u7528\u7684\u914D\u7F6E\u7247\u6BB5\u3002",
1377
+ "\u5982\u679C\u4F60\u4E0D\u786E\u5B9A\u67D0\u4E2A\u5B57\u6BB5\u3001\u53D8\u91CF\u3001\u7C7B\u578B\u3001\u8FD0\u884C\u65F6\u4E0A\u4E0B\u6587\u6216\u4E1A\u52A1\u542B\u4E49\uFF0C\u5FC5\u987B\u660E\u786E\u8BF4\u660E\u4E0D\u786E\u5B9A\u70B9\uFF0C\u5E76\u8981\u6C42\u7528\u6237\u8865\u5145\u4FE1\u606F\uFF1B\u4E0D\u8981\u731C\u6D4B\uFF0C\u4E0D\u8981\u53D1\u660E schema \u4E2D\u4E0D\u5B58\u5728\u7684\u5B57\u6BB5\u3001\u53D8\u91CF\u3001\u51FD\u6570\u6216\u80FD\u529B\u3002",
1378
+ "\u53EA\u6709\u5F53\u7528\u6237\u660E\u786E\u8981\u6C42\u201C\u751F\u6210\u914D\u7F6E\u201D\u201C\u8F93\u51FA\u914D\u7F6E\u201D\u201C\u76F4\u63A5\u7ED9\u6211\u914D\u7F6E\u201D\u201C\u8FD4\u56DE\u53EF\u7C98\u8D34\u914D\u7F6E\u201D\u8FD9\u7C7B\u7ED3\u679C\u65F6\uFF0C\u624D\u8FD4\u56DE\u5B8C\u6574\u914D\u7F6E\u6216\u914D\u7F6E\u7247\u6BB5\uFF1B\u5176\u4ED6\u60C5\u51B5\u4E0B\u4F18\u5148\u89E3\u91CA\u601D\u8DEF\u3001\u6307\u51FA\u4FEE\u6539\u70B9\u548C\u539F\u56E0\u3002",
1379
+ "\u5F53\u6211\u8BF4\u201C\u751F\u6210\u914D\u7F6E\u201D\u65F6\uFF0C\u6211\u4F1A\u628A\u914D\u7F6E\u4EE5 Markdown code block \u7684\u5F62\u5F0F\u53D1\u7ED9\u4F60\uFF1B\u4F60\u8FD4\u56DE\u7684\u914D\u7F6E\u4E5F\u5E94\u8BE5\u653E\u5728 Markdown code block \u4E2D\uFF0C\u8FD9\u6837\u6211\u53EF\u4EE5\u76F4\u63A5\u7C98\u8D34\u5230\u9875\u9762\u914D\u7F6E\u91CC\u3002"
1380
+ ].join("\n");
1381
+ }
1382
+ function buildMarkdownCopyContent(config) {
1383
+ return [
1384
+ buildAiPromptHeaderMarkdown(),
1385
+ "",
1386
+ "## \u5F53\u524D\u914D\u7F6E",
1387
+ "```json",
1388
+ JSON.stringify(config, null, 2),
1389
+ "```",
1390
+ "",
1391
+ buildDslGuideMarkdown(),
1392
+ "",
1393
+ buildMarkdownNotes(),
1394
+ "",
1395
+ "## TableConfig JSON Schema",
1396
+ "```json",
1397
+ JSON.stringify(buildTableConfigJsonSchema(), null, 2),
1398
+ "```",
1399
+ "",
1400
+ "## \u5F53\u524D\u4F7F\u7528\u7684 Renderer Options Schema",
1401
+ buildRendererSchemaMarkdown(config)
1402
+ ].join("\n");
1403
+ }
1404
+ function formatIssuePath(path) {
1405
+ if (path.length === 0) {
1406
+ return "(root)";
1407
+ }
1408
+ return path.map((segment) => {
1409
+ if (typeof segment === "number") {
1410
+ return `${segment}`;
1411
+ }
1412
+ if (typeof segment === "string") {
1413
+ return segment;
1414
+ }
1415
+ return String(segment);
1416
+ }).join(".");
1417
+ }
1418
+ function formatIssueExtraFields(issue) {
1419
+ const lines = [];
1420
+ const entries = Object.entries(issue);
1421
+ for (const [key, value] of entries) {
1422
+ if (key === "code" || key === "message" || key === "path") {
1423
+ continue;
1424
+ }
1425
+ lines.push(` - ${key}: ${JSON.stringify(value)}`);
1426
+ }
1427
+ return lines;
1428
+ }
1429
+ function buildPasteConfigErrorDetails(source, error) {
1430
+ if (error instanceof SyntaxError) {
1431
+ return [
1432
+ "## \u7C98\u8D34\u5931\u8D25\u539F\u56E0",
1433
+ "- \u7C7B\u578B\uFF1AJSON \u89E3\u6790\u5931\u8D25",
1434
+ `- message: ${error.message}`,
1435
+ "",
1436
+ "## \u539F\u59CB\u7C98\u8D34\u5185\u5BB9",
1437
+ "```text",
1438
+ source,
1439
+ "```"
1440
+ ].join("\n");
1441
+ }
1442
+ const issueLines = error.issues.flatMap((issue, index) => {
1443
+ return [
1444
+ `### Issue ${index + 1}`,
1445
+ `- path: ${formatIssuePath(issue.path)}`,
1446
+ `- code: ${issue.code}`,
1447
+ `- message: ${issue.message}`,
1448
+ ...formatIssueExtraFields(issue)
1449
+ ];
1450
+ });
1451
+ return [
1452
+ "## \u7C98\u8D34\u5931\u8D25\u539F\u56E0",
1453
+ "- \u7C7B\u578B\uFF1ASchema \u6821\u9A8C\u5931\u8D25",
1454
+ "",
1455
+ "## \u539F\u59CB\u7C98\u8D34\u5185\u5BB9",
1456
+ "```json",
1457
+ source,
1458
+ "```",
1459
+ "",
1460
+ "## Schema \u62A5\u9519",
1461
+ ...issueLines
1462
+ ].join("\n");
1463
+ }
1464
+ function buildPasteConfigErrorMarkdown(source, error) {
1465
+ return [
1466
+ buildAiPromptHeaderMarkdown(),
1467
+ "",
1468
+ "## \u5F53\u524D\u4EFB\u52A1",
1469
+ "\u7528\u6237\u628A\u4E00\u6BB5\u914D\u7F6E\u7C98\u8D34\u56DE\u8868\u683C\u914D\u7F6E\u5668\u65F6\u5931\u8D25\u4E86\u3002\u8BF7\u57FA\u4E8E\u4E0B\u9762\u7684\u539F\u59CB\u5185\u5BB9\u548C\u62A5\u9519\u4FEE\u590D\u5F53\u524D\u914D\u7F6E\u3002",
1470
+ "\u4F60\u53EA\u80FD\u4FEE\u590D\u5F53\u524D\u914D\u7F6E\uFF0C\u4E0D\u80FD\u65B0\u589E\u5217\u3001\u4E0D\u80FD\u65B0\u589E\u5B50\u5217\u3001\u4E0D\u80FD\u5220\u9664\u540E\u91CD\u5EFA\u5217\u3001\u4E0D\u80FD\u751F\u6210\u65B0\u7684\u5217 ID\u3002",
1471
+ "\u5982\u679C\u67D0\u4E2A\u5217\u7F3A\u5C11 ID\uFF0C\u4E0D\u8981\u66FF\u7528\u6237\u8865\u4E00\u4E2A\u65B0 ID\uFF1B\u8FD9\u7C7B\u64CD\u4F5C\u5FC5\u987B\u5728\u754C\u9762\u4E2D\u5B8C\u6210\u3002",
1472
+ "\u8BF7\u4F18\u5148\u4FEE\u590D\u6700\u5C0F\u5FC5\u8981\u8303\u56F4\uFF0C\u53EA\u4FEE\u6539\u5BFC\u81F4\u62A5\u9519\u7684\u90E8\u5206\u3002",
1473
+ "\u53EA\u6709\u5F53\u7528\u6237\u660E\u786E\u8981\u6C42\u8F93\u51FA\u914D\u7F6E\u65F6\uFF0C\u624D\u8FD4\u56DE\u5B8C\u6574\u914D\u7F6E\uFF1B\u5982\u679C\u8FD4\u56DE\u914D\u7F6E\uFF0C\u5FC5\u987B\u653E\u5728 Markdown code block \u4E2D\u3002",
1474
+ "",
1475
+ buildPasteConfigErrorDetails(source, error),
1476
+ "",
1477
+ buildMarkdownNotes()
1478
+ ].join("\n");
1479
+ }
1480
+ async function writeClipboardText(value, errorMessage) {
1481
+ try {
1482
+ await navigator.clipboard.writeText(value);
1483
+ } catch {
1484
+ showCopyError(errorMessage);
1485
+ }
1486
+ }
1487
+ async function copyPasteConfigError(source, error) {
1488
+ await writeClipboardText(buildPasteConfigErrorMarkdown(source, error), t("copy-paste-error-failed"));
1489
+ }
1490
+ async function pasteConfigFromClipboard() {
1491
+ let source = "";
1492
+ try {
1493
+ source = await navigator.clipboard.readText();
1494
+ } catch {
1495
+ showImportError(t("paste-config-read-failed"));
1496
+ return;
1497
+ }
1498
+ let parsedValue;
1499
+ try {
1500
+ parsedValue = JSON.parse(source);
1501
+ } catch (error) {
1502
+ if (error instanceof SyntaxError) {
1503
+ showImportErrorWithCopyAction(
1504
+ t("paste-config-invalid-json"),
1505
+ async () => copyPasteConfigError(source, error)
1506
+ );
1507
+ return;
1508
+ }
1509
+ showImportError(t("paste-config-invalid-json"));
1510
+ return;
1511
+ }
1512
+ const result = TableConfigC.safeParse(parsedValue);
1513
+ if (!result.success) {
1514
+ showImportErrorWithCopyAction(
1515
+ t("paste-config-invalid-schema"),
1516
+ async () => copyPasteConfigError(source, result.error)
1517
+ );
1518
+ return;
1519
+ }
1520
+ resetDraftState(result.data);
1521
+ await nextTick();
1522
+ await refreshSortable();
1523
+ }
1524
+ async function copyConfig() {
1525
+ const config = getValidDraftConfig(t("copy-config-failed"));
1526
+ if (!config) {
1527
+ return;
1528
+ }
1529
+ await writeClipboardText(JSON.stringify(config, null, 2), t("copy-config-failed"));
1530
+ }
1531
+ async function copyMarkdown() {
1532
+ const config = getValidDraftConfig(t("copy-markdown-failed"));
1533
+ if (!config) {
1534
+ return;
1535
+ }
1536
+ await writeClipboardText(buildMarkdownCopyContent(config), t("copy-markdown-failed"));
1537
+ }
1538
+ function confirmChanges() {
1539
+ if (!validateExpressionEditors()) {
1540
+ return;
1541
+ }
1542
+ const result = buildDraftConfig();
1543
+ if (!result.success) {
1544
+ return;
1545
+ }
1546
+ emit("confirm", result.data);
1547
+ search.value = "";
1548
+ open.value = false;
1549
+ }
1550
+ </script>
1551
+
1552
+ <template>
1553
+ <Dialog
1554
+ :open="open"
1555
+ @update:open="handleOpenChange"
1556
+ >
1557
+ <DialogContent
1558
+ class="flex h-[min(42rem,calc(100vh-4rem))] w-[calc(100%-2rem)] max-h-[calc(100vh-4rem)] max-w-[calc(100%-2rem)] flex-col overflow-hidden p-0 sm:w-[80vw] sm:max-w-[80vw]"
1559
+ :show-close-button="true"
1560
+ @pointer-down-outside="(event) => event.preventDefault()"
1561
+ >
1562
+ <DialogHeader class="gap-1 border-b border-zinc-200 px-6 py-5">
1563
+ <div class="flex items-center gap-3">
1564
+ <DialogTitle class="text-xl font-semibold text-zinc-800">
1565
+ {{ t("configure-table") }}
1566
+ </DialogTitle>
1567
+ <Button
1568
+ type="button"
1569
+ variant="ghost"
1570
+ size="sm"
1571
+ data-slot="table-configurator-paste"
1572
+ class="shrink-0"
1573
+ @click="pasteConfigFromClipboard"
1574
+ >
1575
+ <Icon icon="fluent:clipboard-paste-20-regular" />
1576
+ {{ t("paste-config") }}
1577
+ </Button>
1578
+ </div>
1579
+ <DialogDescription class="text-sm text-zinc-500">
1580
+ {{ t("configure-table-description") }}
1581
+ </DialogDescription>
1582
+ </DialogHeader>
1583
+
1584
+ <div class="grid min-h-0 flex-1 grid-cols-[19rem_minmax(0,1fr)]">
1585
+ <section class="flex min-h-0 flex-col border-r border-zinc-200 px-4 py-4">
1586
+ <Input
1587
+ v-model="search"
1588
+ data-slot="table-configurator-search"
1589
+ :placeholder="t('search-columns')"
1590
+ />
1591
+
1592
+ <Button
1593
+ type="button"
1594
+ data-slot="table-configurator-add"
1595
+ class="mt-3 w-full justify-center"
1596
+ @click="addColumn"
1597
+ >
1598
+ <Icon icon="fluent:add-20-regular" />
1599
+ {{ t("add-column") }}
1600
+ </Button>
1601
+
1602
+ <div class="mt-4 flex min-h-0 flex-1 flex-col overflow-hidden">
1603
+ <div class="flex min-h-0 flex-1 flex-col gap-1 overflow-y-auto pr-1">
1604
+ <button
1605
+ type="button"
1606
+ data-slot="table-configurator-item"
1607
+ data-item-id="general"
1608
+ :data-selected="selectedItemId === 'general' ? 'true' : 'false'"
1609
+ :class="cn(
1610
+ 'flex w-full items-center rounded-md border p-1 text-left transition-colors',
1611
+ selectedItemId === 'general' ? 'border-(--primary)/25 bg-[color-mix(in_srgb,var(--primary)_10%,white)]' : 'border-transparent hover:border-zinc-200 hover:bg-zinc-50'
1612
+ )"
1613
+ @click="selectGeneral"
1614
+ >
1615
+ <span class="truncate px-2 py-2 text-sm font-medium text-zinc-800">{{ generalItem.label }}</span>
1616
+ </button>
1617
+
1618
+ <div
1619
+ data-slot="table-configurator-column-list"
1620
+ class="flex flex-col gap-1"
1621
+ >
1622
+ <div
1623
+ v-for="item in filteredColumnItems"
1624
+ :key="item.itemId"
1625
+ data-slot="table-configurator-item"
1626
+ :data-item-id="item.itemId"
1627
+ :data-selected="selectedItemId === item.itemId ? 'true' : 'false'"
1628
+ :class="cn(
1629
+ 'flex w-full items-center gap-2 rounded-md border p-1 transition-colors',
1630
+ selectedItemId === item.itemId ? 'border-(--primary)/25 bg-[color-mix(in_srgb,var(--primary)_10%,white)]' : 'border-transparent hover:border-zinc-200 hover:bg-zinc-50'
1631
+ )"
1632
+ @click="selectItem(item.itemId)"
1633
+ >
1634
+ <button
1635
+ type="button"
1636
+ class="min-w-0 flex-1 px-2 py-2 text-left"
1637
+ >
1638
+ <span class="block truncate text-sm font-medium text-zinc-800">{{ item.label }}</span>
1639
+ </button>
1640
+
1641
+ <button
1642
+ type="button"
1643
+ data-slot="table-configurator-delete"
1644
+ class="flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-sm text-zinc-400 transition-colors hover:bg-red-50 hover:text-red-600"
1645
+ :aria-label="t('delete-column', { column: item.label })"
1646
+ @click.stop="deleteColumn(item.itemId)"
1647
+ >
1648
+ <Icon icon="fluent:delete-20-regular" />
1649
+ </button>
1650
+ </div>
1651
+ </div>
1652
+
1653
+ <p
1654
+ v-if="normalizedSearch && filteredColumnItems.length === 0"
1655
+ data-slot="table-configurator-empty"
1656
+ class="px-1 pt-2 text-xs text-zinc-400"
1657
+ >
1658
+ {{ t("no-matches") }}
1659
+ </p>
1660
+ </div>
1661
+ </div>
1662
+ </section>
1663
+
1664
+ <section class="flex min-h-0 flex-col overflow-y-auto px-6 py-6">
1665
+ <div class="flex items-center gap-2">
1666
+ <h3
1667
+ data-slot="table-configurator-detail-title"
1668
+ class="text-lg font-semibold text-zinc-800"
1669
+ >
1670
+ {{ selectedItemLabel }}
1671
+ </h3>
1672
+ <Button
1673
+ v-if="selectedColumnTechnicalKey"
1674
+ type="button"
1675
+ variant="ghost"
1676
+ size="sm"
1677
+ data-slot="table-configurator-copy-id"
1678
+ class="size-7 p-0 text-zinc-400 hover:text-zinc-700"
1679
+ :aria-label="t('copy-column-id', { column: selectedItemLabel })"
1680
+ :title="selectedColumnTechnicalKey"
1681
+ @click="copySelectedColumnId"
1682
+ >
1683
+ <Icon icon="fluent:copy-20-regular" />
1684
+ </Button>
1685
+ </div>
1686
+ <p
1687
+ v-if="selectedItemId === 'general'"
1688
+ data-slot="table-configurator-detail-description"
1689
+ class="mt-2 text-sm text-zinc-500"
1690
+ >
1691
+ {{ t("general-placeholder") }}
1692
+ </p>
1693
+
1694
+ <div
1695
+ v-if="selectedItemId === 'general'"
1696
+ data-slot="table-configurator-general-fields"
1697
+ class="mt-6 flex flex-col gap-4"
1698
+ >
1699
+ <ExpressionEditor
1700
+ ref="getRowIdEditor"
1701
+ v-model="draftGetRowId"
1702
+ data-field-key="getRowId"
1703
+ :label="t('get-row-id')"
1704
+ :description="t('get-row-id-description')"
1705
+ :placeholder="t('expression-placeholder')"
1706
+ :schema="TableConfigGetRowIdC"
1707
+ />
1708
+
1709
+ <ExpressionEditor
1710
+ ref="getSubRowsEditor"
1711
+ v-model="draftGetSubRows"
1712
+ data-field-key="getSubRows"
1713
+ :label="t('get-sub-rows')"
1714
+ :description="t('get-sub-rows-description')"
1715
+ :placeholder="t('expression-placeholder')"
1716
+ :schema="TableConfigGetSubRowsC"
1717
+ />
1718
+
1719
+ <ExpressionEditor
1720
+ ref="enableRowSelectionEditor"
1721
+ v-model="draftEnableRowSelection"
1722
+ data-field-key="enableRowSelection"
1723
+ :label="t('enable-row-selection')"
1724
+ :description="t('enable-row-selection-description')"
1725
+ :placeholder="t('expression-placeholder')"
1726
+ :schema="TableConfigEnableRowSelectionC"
1727
+ />
1728
+
1729
+ <ExpressionEditor
1730
+ ref="enableMultiRowSelectionEditor"
1731
+ v-model="draftEnableMultiRowSelection"
1732
+ data-field-key="enableMultiRowSelection"
1733
+ :label="t('enable-multi-row-selection')"
1734
+ :description="t('enable-multi-row-selection-description')"
1735
+ :placeholder="t('expression-placeholder')"
1736
+ :schema="TableConfigEnableMultiRowSelectionC"
1737
+ />
1738
+
1739
+ <ExpressionEditor
1740
+ ref="cellStylesEditor"
1741
+ v-model="draftCellStyles"
1742
+ data-field-key="cellStyles"
1743
+ :label="t('cell-styles')"
1744
+ :description="t('cell-styles-description')"
1745
+ :placeholder="t('expression-placeholder')"
1746
+ :schema="TableConfigCellStylesC"
1747
+ />
1748
+
1749
+ <section
1750
+ data-slot="table-configurator-pagination"
1751
+ class="rounded-lg border border-zinc-200 p-4"
1752
+ >
1753
+ <h4 class="text-sm font-semibold text-zinc-800">
1754
+ {{ t("pagination") }}
1755
+ </h4>
1756
+
1757
+ <div class="mt-3 flex flex-col gap-4">
1758
+ <label
1759
+ data-field-key="paginationLeft"
1760
+ class="flex flex-col gap-1"
1761
+ >
1762
+ <span class="text-xs font-medium text-zinc-500">{{ t("pagination-left") }}</span>
1763
+ <Textarea
1764
+ class="min-h-20"
1765
+ :model-value="draftPaginationLeft ?? ''"
1766
+ :placeholder="t('pagination-left-placeholder')"
1767
+ @update:model-value="updateDraftPaginationLeft"
1768
+ />
1769
+ </label>
1770
+
1771
+ <label
1772
+ data-field-key="paginationRight"
1773
+ class="flex flex-col gap-1"
1774
+ >
1775
+ <span class="text-xs font-medium text-zinc-500">{{ t("pagination-right") }}</span>
1776
+ <Textarea
1777
+ class="min-h-20"
1778
+ :model-value="draftPaginationRight ?? ''"
1779
+ :placeholder="t('pagination-right-placeholder')"
1780
+ @update:model-value="updateDraftPaginationRight"
1781
+ />
1782
+ </label>
1783
+
1784
+ <label
1785
+ data-field-key="pageSize"
1786
+ class="flex flex-col gap-1"
1787
+ >
1788
+ <span class="text-xs font-medium text-zinc-500">{{ t("pagination-page-size") }}</span>
1789
+ <NumberField
1790
+ :model-value="draftPageSize"
1791
+ :min="1"
1792
+ @update:model-value="updateDraftPageSize"
1793
+ >
1794
+ <NumberFieldInput class="w-full text-left" />
1795
+ </NumberField>
1796
+ </label>
1797
+
1798
+ <div
1799
+ data-field-key="paginationPageSizes"
1800
+ class="flex flex-col gap-3"
1801
+ >
1802
+ <div class="flex items-center justify-between gap-3">
1803
+ <span class="text-xs font-medium text-zinc-500">{{ t("pagination-page-size-options") }}</span>
1804
+ <Button
1805
+ type="button"
1806
+ variant="ghost"
1807
+ size="sm"
1808
+ data-slot="table-configurator-pagination-page-size-add"
1809
+ class="h-7 px-2 text-xs"
1810
+ @click="addDraftPaginationPageSizeOption"
1811
+ >
1812
+ <Icon icon="fluent:add-20-regular" />
1813
+ {{ t("add-pagination-page-size") }}
1814
+ </Button>
1815
+ </div>
1816
+
1817
+ <div
1818
+ v-if="draftPaginationPageSizes.length > 0"
1819
+ ref="paginationPageSizesSortableListRef"
1820
+ data-slot="table-configurator-pagination-page-size-list"
1821
+ class="flex flex-col gap-2"
1822
+ >
1823
+ <InputGroup
1824
+ v-for="item in draftPaginationPageSizes"
1825
+ :key="item.itemId"
1826
+ :data-item-id="item.itemId"
1827
+ data-slot="table-configurator-pagination-page-size-item"
1828
+ class="overflow-hidden"
1829
+ >
1830
+ <InputGroupNumberField
1831
+ class="flex-1"
1832
+ :model-value="item.value"
1833
+ :min="1"
1834
+ @update:model-value="(value) => updateDraftPaginationPageSizeOption(item.itemId, value)"
1835
+ />
1836
+
1837
+ <InputGroupAddon class="w-12 shrink-0 self-stretch border-r border-zinc-200 px-0 py-0">
1838
+ <div
1839
+ data-slot="table-configurator-pagination-page-size-drag-handle"
1840
+ :title="t('drag-pagination-page-size')"
1841
+ class="flex h-full w-full cursor-grab items-center justify-center text-zinc-400 transition-colors hover:bg-zinc-50 hover:text-zinc-700 active:cursor-grabbing"
1842
+ >
1843
+ <Icon icon="fluent:re-order-dots-vertical-20-regular" />
1844
+ </div>
1845
+ </InputGroupAddon>
1846
+
1847
+ <InputGroupAddon
1848
+ align="inline-end"
1849
+ class="w-12 shrink-0 self-stretch border-l border-zinc-200 px-0 py-0 mr-0"
1850
+ >
1851
+ <button
1852
+ type="button"
1853
+ data-slot="table-configurator-pagination-page-size-remove"
1854
+ class="flex h-full w-full items-center justify-center bg-transparent text-red-600 transition-colors hover:bg-red-50 hover:text-red-700"
1855
+ :aria-label="t('remove-pagination-page-size')"
1856
+ @click="removeDraftPaginationPageSizeOption(item.itemId)"
1857
+ >
1858
+ <Icon icon="fluent:delete-20-regular" />
1859
+ </button>
1860
+ </InputGroupAddon>
1861
+ </InputGroup>
1862
+ </div>
1863
+
1864
+ <p
1865
+ v-else
1866
+ data-slot="table-configurator-pagination-page-size-empty"
1867
+ class="text-xs text-zinc-400"
1868
+ >
1869
+ {{ t("no-pagination-page-sizes") }}
1870
+ </p>
1871
+ </div>
1872
+ </div>
1873
+ </section>
1874
+
1875
+ <section
1876
+ data-slot="table-configurator-initial-state"
1877
+ class="rounded-lg border border-zinc-200 p-4"
1878
+ >
1879
+ <h4 class="text-sm font-semibold text-zinc-800">
1880
+ {{ t("initial-state") }}
1881
+ </h4>
1882
+
1883
+ <div class="mt-3 flex flex-col gap-4">
1884
+ <section
1885
+ data-slot="table-configurator-initial-state-left"
1886
+ class="rounded-md border border-zinc-200/80 p-3"
1887
+ >
1888
+ <p class="text-xs font-medium text-zinc-500">
1889
+ {{ t("pinned-left-group") }}
1890
+ </p>
1891
+
1892
+ <div
1893
+ v-if="leftPinnedInitialStateItems.length > 0"
1894
+ ref="leftPinnedSortableListRef"
1895
+ class="mt-3 flex flex-col gap-1"
1896
+ >
1897
+ <div
1898
+ v-for="item in leftPinnedInitialStateItems"
1899
+ :key="item.itemId"
1900
+ data-slot="table-configurator-initial-state-left-item"
1901
+ class="flex items-center gap-2 rounded-md border border-transparent p-1"
1902
+ >
1903
+ <button
1904
+ type="button"
1905
+ data-slot="table-configurator-initial-state-left-drag-handle"
1906
+ class="flex size-8 shrink-0 cursor-grab items-center justify-center rounded-sm text-zinc-400 active:cursor-grabbing"
1907
+ :aria-label="t('drag-left-column', { column: item.label })"
1908
+ >
1909
+ <Icon icon="fluent:re-order-dots-vertical-20-regular" />
1910
+ </button>
1911
+
1912
+ <span class="min-w-0 flex-1 truncate px-1 text-sm font-medium text-zinc-800">{{ item.label }}</span>
1913
+
1914
+ <button
1915
+ v-if="item.canManage"
1916
+ type="button"
1917
+ data-slot="table-configurator-unpin-from-left"
1918
+ class="flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-sm text-zinc-400 transition-colors hover:bg-zinc-100 hover:text-zinc-700"
1919
+ :aria-label="t('unpin-left-column', { column: item.label })"
1920
+ @click="moveRootItemToGroup(item.itemId, 'center')"
1921
+ >
1922
+ <Icon icon="fluent:padding-right-20-regular" />
1923
+ </button>
1924
+ </div>
1925
+ </div>
1926
+
1927
+ <p
1928
+ v-else
1929
+ data-slot="table-configurator-initial-state-left-empty"
1930
+ class="mt-3 text-xs text-zinc-400"
1931
+ >
1932
+ {{ t("no-pinned-left-columns") }}
1933
+ </p>
1934
+ </section>
1935
+
1936
+ <section
1937
+ data-slot="table-configurator-initial-state-center"
1938
+ class="rounded-md border border-zinc-200/80 p-3"
1939
+ >
1940
+ <p class="text-xs font-medium text-zinc-500">
1941
+ {{ t("pinned-center-group") }}
1942
+ </p>
1943
+
1944
+ <div
1945
+ v-if="centerInitialStateItems.length > 0"
1946
+ ref="centerSortableListRef"
1947
+ class="mt-3 flex flex-col gap-1"
1948
+ >
1949
+ <div
1950
+ v-for="item in centerInitialStateItems"
1951
+ :key="item.itemId"
1952
+ data-slot="table-configurator-initial-state-center-item"
1953
+ class="flex items-center gap-2 rounded-md border border-transparent p-1"
1954
+ >
1955
+ <button
1956
+ type="button"
1957
+ data-slot="table-configurator-initial-state-center-drag-handle"
1958
+ class="flex size-8 shrink-0 cursor-grab items-center justify-center rounded-sm text-zinc-400 active:cursor-grabbing"
1959
+ :aria-label="t('drag-center-column', { column: item.label })"
1960
+ >
1961
+ <Icon icon="fluent:re-order-dots-vertical-20-regular" />
1962
+ </button>
1963
+
1964
+ <span class="min-w-0 flex-1 truncate px-1 text-sm font-medium text-zinc-800">{{ item.label }}</span>
1965
+
1966
+ <div
1967
+ v-if="item.canManage"
1968
+ class="flex items-center gap-1"
1969
+ >
1970
+ <button
1971
+ type="button"
1972
+ data-slot="table-configurator-pin-left"
1973
+ class="flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-sm text-zinc-400 transition-colors hover:bg-zinc-100 hover:text-zinc-700"
1974
+ :aria-label="t('pin-left-column', { column: item.label })"
1975
+ @click="moveRootItemToGroup(item.itemId, 'left')"
1976
+ >
1977
+ <Icon icon="fluent:padding-left-20-regular" />
1978
+ </button>
1979
+
1980
+ <button
1981
+ type="button"
1982
+ data-slot="table-configurator-pin-right"
1983
+ class="flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-sm text-zinc-400 transition-colors hover:bg-zinc-100 hover:text-zinc-700"
1984
+ :aria-label="t('pin-right-column', { column: item.label })"
1985
+ @click="moveRootItemToGroup(item.itemId, 'right')"
1986
+ >
1987
+ <Icon icon="fluent:padding-right-20-regular" />
1988
+ </button>
1989
+ </div>
1990
+ </div>
1991
+ </div>
1992
+
1993
+ <p
1994
+ v-else
1995
+ data-slot="table-configurator-initial-state-center-empty"
1996
+ class="mt-3 text-xs text-zinc-400"
1997
+ >
1998
+ {{ t("no-pinned-center-columns") }}
1999
+ </p>
2000
+ </section>
2001
+
2002
+ <section
2003
+ data-slot="table-configurator-initial-state-right"
2004
+ class="rounded-md border border-zinc-200/80 p-3"
2005
+ >
2006
+ <p class="text-xs font-medium text-zinc-500">
2007
+ {{ t("pinned-right-group") }}
2008
+ </p>
2009
+
2010
+ <div
2011
+ v-if="rightPinnedInitialStateItems.length > 0"
2012
+ ref="rightPinnedSortableListRef"
2013
+ class="mt-3 flex flex-col gap-1"
2014
+ >
2015
+ <div
2016
+ v-for="item in rightPinnedInitialStateItems"
2017
+ :key="item.itemId"
2018
+ data-slot="table-configurator-initial-state-right-item"
2019
+ class="flex items-center gap-2 rounded-md border border-transparent p-1"
2020
+ >
2021
+ <button
2022
+ type="button"
2023
+ data-slot="table-configurator-initial-state-right-drag-handle"
2024
+ class="flex size-8 shrink-0 cursor-grab items-center justify-center rounded-sm text-zinc-400 active:cursor-grabbing"
2025
+ :aria-label="t('drag-right-column', { column: item.label })"
2026
+ >
2027
+ <Icon icon="fluent:re-order-dots-vertical-20-regular" />
2028
+ </button>
2029
+
2030
+ <span class="min-w-0 flex-1 truncate px-1 text-sm font-medium text-zinc-800">{{ item.label }}</span>
2031
+
2032
+ <button
2033
+ v-if="item.canManage"
2034
+ type="button"
2035
+ data-slot="table-configurator-unpin-from-right"
2036
+ class="flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-sm text-zinc-400 transition-colors hover:bg-zinc-100 hover:text-zinc-700"
2037
+ :aria-label="t('unpin-right-column', { column: item.label })"
2038
+ @click="moveRootItemToGroup(item.itemId, 'center')"
2039
+ >
2040
+ <Icon icon="fluent:padding-left-20-regular" />
2041
+ </button>
2042
+ </div>
2043
+ </div>
2044
+
2045
+ <p
2046
+ v-else
2047
+ data-slot="table-configurator-initial-state-right-empty"
2048
+ class="mt-3 text-xs text-zinc-400"
2049
+ >
2050
+ {{ t("no-pinned-right-columns") }}
2051
+ </p>
2052
+ </section>
2053
+ </div>
2054
+ </section>
2055
+ </div>
2056
+
2057
+ <div
2058
+ v-else-if="selectedColumn"
2059
+ class="mt-6 flex flex-col gap-6"
2060
+ >
2061
+ <section
2062
+ data-slot="table-configurator-column-main"
2063
+ class="flex flex-col gap-6"
2064
+ >
2065
+ <h4 class="text-sm font-semibold text-zinc-800">
2066
+ {{ t("column-main") }}
2067
+ </h4>
2068
+
2069
+ <div
2070
+ data-slot="table-configurator-locale-field"
2071
+ class="flex flex-col gap-2"
2072
+ >
2073
+ <p class="text-xs font-medium text-zinc-500">
2074
+ {{ t("column-title") }}
2075
+ </p>
2076
+
2077
+ <Locale
2078
+ data-slot="table-configurator-locale"
2079
+ :model-value="selectedColumnLocaleValue"
2080
+ @update:model-value="updateSelectedColumnTitle"
2081
+ />
2082
+ </div>
2083
+
2084
+ <div
2085
+ data-slot="table-configurator-column-options"
2086
+ class="flex flex-col gap-3"
2087
+ >
2088
+ <label
2089
+ data-field-key="columnSize"
2090
+ class="flex flex-col gap-1"
2091
+ >
2092
+ <span class="text-xs font-medium text-zinc-500">{{ t("column-size") }}</span>
2093
+ <InputGroup class="overflow-hidden">
2094
+ <InputGroupNumberField
2095
+ class="flex-1"
2096
+ :model-value="selectedColumn.size"
2097
+ :min="1"
2098
+ @update:model-value="updateSelectedColumnSize"
2099
+ />
2100
+
2101
+ <div class="flex h-full items-stretch border-l border-zinc-200">
2102
+ <Toggle
2103
+ data-field-key="columnGrow"
2104
+ class="h-full rounded-none border-0 px-3 text-xs shadow-none"
2105
+ :model-value="selectedColumn.grow ?? false"
2106
+ @update:model-value="updateSelectedColumnGrow"
2107
+ >
2108
+ <Icon icon="fluent:arrow-fit-20-regular" />
2109
+ {{ t("column-grow") }}
2110
+ </Toggle>
2111
+ </div>
2112
+ </InputGroup>
2113
+ </label>
2114
+
2115
+ <label
2116
+ data-field-key="columnEnableSorting"
2117
+ class="flex items-center justify-between gap-3 py-1"
2118
+ >
2119
+ <div class="flex flex-col gap-1">
2120
+ <span class="text-sm font-medium text-zinc-800">{{ t("column-enable-sorting") }}</span>
2121
+ <span class="text-xs text-zinc-500">{{ t("column-enable-sorting-description") }}</span>
2122
+ </div>
2123
+ <Switch
2124
+ :model-value="selectedColumn.enableSorting ?? false"
2125
+ @update:model-value="updateSelectedColumnEnableSorting"
2126
+ />
2127
+ </label>
2128
+ </div>
2129
+
2130
+ <div
2131
+ data-slot="table-configurator-accessor"
2132
+ class="flex flex-col gap-3"
2133
+ >
2134
+ <p class="text-xs font-medium text-zinc-500">
2135
+ {{ t("accessor") }}
2136
+ </p>
2137
+
2138
+ <Tabs
2139
+ v-model="selectedColumnAccessorMode"
2140
+ data-slot="table-configurator-accessor-tabs"
2141
+ class="gap-4"
2142
+ >
2143
+ <TabsList>
2144
+ <TabsTrigger value="path">
2145
+ {{ t("accessor-path-tab") }}
2146
+ </TabsTrigger>
2147
+ <TabsTrigger value="expression">
2148
+ {{ t("accessor-expression-tab") }}
2149
+ </TabsTrigger>
2150
+ </TabsList>
2151
+
2152
+ <TabsContent
2153
+ value="path"
2154
+ class="flex flex-col gap-4"
2155
+ >
2156
+ <ExpressionEditor
2157
+ ref="accessorPathEditor"
2158
+ data-field-key="accessorPath"
2159
+ :model-value="selectedColumnAccessorPath"
2160
+ :label="t('accessor-path')"
2161
+ :description="t('accessor-path-description')"
2162
+ :placeholder="t('accessor-path-placeholder')"
2163
+ :schema="dotPropC"
2164
+ @update:model-value="updateSelectedColumnAccessorPath"
2165
+ />
2166
+ </TabsContent>
2167
+
2168
+ <TabsContent
2169
+ value="expression"
2170
+ class="flex flex-col gap-4"
2171
+ >
2172
+ <ExpressionEditor
2173
+ ref="accessorReadEditor"
2174
+ data-field-key="accessorRead"
2175
+ :model-value="selectedColumnAccessorExpression.read"
2176
+ :label="t('accessor-read')"
2177
+ :description="t('accessor-read-description')"
2178
+ :placeholder="t('accessor-read-placeholder')"
2179
+ :schema="TableConfiguratorColumnAccessorReadC"
2180
+ @update:model-value="updateSelectedColumnAccessorRead"
2181
+ />
2182
+
2183
+ <ExpressionEditor
2184
+ ref="accessorWriteEditor"
2185
+ data-field-key="accessorWrite"
2186
+ :model-value="selectedColumnAccessorExpression.write"
2187
+ :label="t('accessor-write')"
2188
+ :description="t('accessor-write-description')"
2189
+ :placeholder="t('accessor-write-placeholder')"
2190
+ :schema="TableConfiguratorColumnAccessorWriteC"
2191
+ @update:model-value="updateSelectedColumnAccessorWrite"
2192
+ />
2193
+ </TabsContent>
2194
+ </Tabs>
2195
+ </div>
2196
+
2197
+ <div
2198
+ v-if="!selectedColumnHasChildren"
2199
+ data-slot="table-configurator-renderer"
2200
+ class="flex flex-col gap-3"
2201
+ >
2202
+ <div class="flex items-center justify-between gap-3">
2203
+ <p class="text-xs font-medium text-zinc-500">
2204
+ {{ t("renderer") }}
2205
+ </p>
2206
+
2207
+ <label
2208
+ data-field-key="rendererId"
2209
+ class="min-w-32 max-w-40"
2210
+ >
2211
+ <NativeSelect
2212
+ v-model="selectedColumnRendererModel"
2213
+ class="w-full"
2214
+ >
2215
+ <NativeSelectOption
2216
+ v-for="item in rendererOptions"
2217
+ :key="item.id"
2218
+ :value="item.id"
2219
+ >
2220
+ {{ item.label }}
2221
+ </NativeSelectOption>
2222
+ </NativeSelect>
2223
+ </label>
2224
+ </div>
2225
+
2226
+ <component
2227
+ :is="selectedColumnRendererConfigComponent"
2228
+ v-if="selectedColumnRendererConfigComponent"
2229
+ ref="selectedRendererConfigRef"
2230
+ data-slot="table-configurator-renderer-config"
2231
+ :model-value="selectedColumnRendererOptions"
2232
+ @update:model-value="updateSelectedColumnRendererProps"
2233
+ />
2234
+ </div>
2235
+
2236
+ <div
2237
+ data-slot="table-configurator-tooltip"
2238
+ class="flex flex-col gap-3"
2239
+ >
2240
+ <div class="flex flex-col gap-1">
2241
+ <p class="text-xs font-medium text-zinc-500">
2242
+ {{ t("tooltip") }}
2243
+ </p>
2244
+
2245
+ <p class="text-sm text-zinc-500">
2246
+ {{ t("tooltip-description", { expression: TOOLTIP_EXPRESSION_EXAMPLE }) }}
2247
+ </p>
2248
+ </div>
2249
+
2250
+ <Locale
2251
+ data-slot="table-configurator-tooltip-locale"
2252
+ :model-value="selectedColumnTooltipValue"
2253
+ :multiline="true"
2254
+ @update:model-value="updateSelectedColumnTooltip"
2255
+ />
2256
+ </div>
2257
+ </section>
2258
+
2259
+ <section
2260
+ data-slot="table-configurator-children"
2261
+ class="flex flex-col gap-3"
2262
+ >
2263
+ <h4 class="text-sm font-semibold text-zinc-800">
2264
+ {{ t("child-columns") }}
2265
+ </h4>
2266
+
2267
+ <div
2268
+ data-slot="table-configurator-selected-children"
2269
+ >
2270
+ <p class="text-xs font-medium text-zinc-500">
2271
+ {{ t("selected-children") }}
2272
+ </p>
2273
+
2274
+ <div
2275
+ v-if="selectedChildItems.length > 0"
2276
+ ref="selectedChildSortableListRef"
2277
+ class="mt-2 flex flex-col gap-1"
2278
+ >
2279
+ <div
2280
+ v-for="item in selectedChildItems"
2281
+ :key="item.itemId"
2282
+ data-slot="table-configurator-child-item"
2283
+ class="flex items-center gap-2 rounded-md border border-transparent p-1"
2284
+ >
2285
+ <button
2286
+ type="button"
2287
+ data-slot="table-configurator-child-drag-handle"
2288
+ class="flex size-8 shrink-0 cursor-grab items-center justify-center rounded-sm text-zinc-400 active:cursor-grabbing"
2289
+ :aria-label="t('drag-child-column', { column: item.label })"
2290
+ >
2291
+ <Icon icon="fluent:re-order-dots-vertical-20-regular" />
2292
+ </button>
2293
+
2294
+ <span class="min-w-0 flex-1 truncate px-1 text-sm font-medium text-zinc-800">{{ item.label }}</span>
2295
+
2296
+ <button
2297
+ type="button"
2298
+ data-slot="table-configurator-child-remove"
2299
+ class="flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-sm text-zinc-400 transition-colors hover:bg-red-50 hover:text-red-600"
2300
+ :aria-label="t('remove-child-column', { column: item.label })"
2301
+ @click="removeSelectedChild(item.itemId)"
2302
+ >
2303
+ <Icon icon="fluent:dismiss-20-regular" />
2304
+ </button>
2305
+ </div>
2306
+ </div>
2307
+
2308
+ <p
2309
+ v-else
2310
+ data-slot="table-configurator-child-empty"
2311
+ class="mt-2 text-xs text-zinc-400"
2312
+ >
2313
+ {{ t("no-selected-children") }}
2314
+ </p>
2315
+ </div>
2316
+
2317
+ <div
2318
+ data-slot="table-configurator-child-candidates"
2319
+ class="border-t border-zinc-200 pt-3"
2320
+ >
2321
+ <p class="text-xs font-medium text-zinc-500">
2322
+ {{ t("available-columns") }}
2323
+ </p>
2324
+
2325
+ <Input
2326
+ v-model="childSearch"
2327
+ data-slot="table-configurator-child-search"
2328
+ class="mt-2"
2329
+ :placeholder="t('search-child-columns')"
2330
+ />
2331
+
2332
+ <div
2333
+ v-if="filteredChildCandidateItems.length > 0"
2334
+ class="mt-3 flex flex-col gap-1"
2335
+ >
2336
+ <label
2337
+ v-for="item in filteredChildCandidateItems"
2338
+ :key="item.itemId"
2339
+ data-slot="table-configurator-child-candidate"
2340
+ class="flex items-center gap-3 rounded-md border border-transparent p-1 text-sm text-zinc-700"
2341
+ >
2342
+ <Checkbox
2343
+ :model-value="false"
2344
+ @update:model-value="(value) => toggleChildSelection(item.itemId, value)"
2345
+ />
2346
+ <span class="min-w-0 truncate font-medium text-zinc-800">{{ item.label }}</span>
2347
+ </label>
2348
+ </div>
2349
+
2350
+ <p
2351
+ v-else-if="normalizedChildSearch"
2352
+ data-slot="table-configurator-candidate-empty"
2353
+ class="mt-3 text-xs text-zinc-400"
2354
+ >
2355
+ {{ t("no-child-matches") }}
2356
+ </p>
2357
+
2358
+ <p
2359
+ v-else
2360
+ data-slot="table-configurator-candidate-empty"
2361
+ class="mt-3 text-xs text-zinc-400"
2362
+ >
2363
+ {{ t("no-available-columns") }}
2364
+ </p>
2365
+ </div>
2366
+ </section>
2367
+ </div>
2368
+ </section>
2369
+ </div>
2370
+
2371
+ <DialogFooter class="border-t border-zinc-200 px-6 py-4 sm:justify-between">
2372
+ <div
2373
+ data-slot="table-configurator-copy-actions"
2374
+ class="flex items-center gap-2"
2375
+ >
2376
+ <Button
2377
+ type="button"
2378
+ data-slot="table-configurator-copy-markdown"
2379
+ variant="ghost"
2380
+ @click="copyMarkdown"
2381
+ >
2382
+ <Icon icon="simple-icons:markdown" />
2383
+ {{ t("copy-markdown") }}
2384
+ </Button>
2385
+ <Button
2386
+ type="button"
2387
+ data-slot="table-configurator-copy-config"
2388
+ variant="ghost"
2389
+ @click="copyConfig"
2390
+ >
2391
+ <Icon icon="fluent:copy-20-regular" />
2392
+ {{ t("copy-config") }}
2393
+ </Button>
2394
+ </div>
2395
+ <div class="flex items-center gap-2">
2396
+ <Button
2397
+ type="button"
2398
+ data-slot="table-configurator-cancel"
2399
+ variant="default"
2400
+ @click="discardChanges"
2401
+ >
2402
+ <Icon icon="fluent:dismiss-20-regular" />
2403
+ {{ t("cancel") }}
2404
+ </Button>
2405
+ <Button
2406
+ type="button"
2407
+ data-slot="table-configurator-confirm"
2408
+ variant="primary"
2409
+ @click="confirmChanges"
2410
+ >
2411
+ <Icon icon="fluent:checkmark-20-regular" />
2412
+ {{ t("confirm") }}
2413
+ </Button>
2414
+ </div>
2415
+ </DialogFooter>
2416
+ </DialogContent>
2417
+ </Dialog>
2418
+ </template>
2419
+
2420
+ <i18n lang="json">
2421
+ {
2422
+ "zh": {
2423
+ "configure-table": "配置表格",
2424
+ "configure-table-description": "在这里浏览表格和列配置项。",
2425
+ "paste-config": "粘贴配置",
2426
+ "paste-config-invalid-json": "粘贴失败,剪贴板不是有效的 JSON。",
2427
+ "paste-config-invalid-schema": "粘贴失败,配置格式无效。",
2428
+ "paste-config-read-failed": "读取剪贴板失败,请检查剪贴板权限。",
2429
+ "copy-paste-error": "复制错误",
2430
+ "copy-paste-error-failed": "复制错误详情失败,请检查剪贴板权限。",
2431
+ "copy-markdown": "复制为 Markdown",
2432
+ "copy-markdown-failed": "复制 Markdown 失败,请先修正当前配置中的错误。",
2433
+ "copy-config": "仅复制配置",
2434
+ "copy-config-failed": "复制配置失败,请先修正当前配置中的错误。",
2435
+ "search-columns": "搜索列名称……",
2436
+ "general": "通用",
2437
+ "no-matches": "没有匹配的列。",
2438
+ "general-placeholder": "配置当前表格的通用 CEL 表达式。",
2439
+ "expression-placeholder": "输入 CEL 表达式",
2440
+ "accessor": "取值配置",
2441
+ "accessor-path-tab": "路径",
2442
+ "accessor-expression-tab": "表达式",
2443
+ "accessor-path": "路径",
2444
+ "accessor-path-description": "使用 dot-prop 路径从 row 读取值,如 foo.bar 或 foo[0].bar。",
2445
+ "accessor-path-placeholder": "输入 dot-prop 路径",
2446
+ "accessor-read": "读取表达式",
2447
+ "accessor-read-description": "返回列值的 CEL 表达式,可使用 row、index 变量。",
2448
+ "accessor-read-placeholder": "输入读取用 CEL 表达式",
2449
+ "accessor-write": "写入表达式",
2450
+ "accessor-write-description": "保存列值时使用的表达式。",
2451
+ "accessor-write-placeholder": "输入写入表达式",
2452
+ "tooltip": "提示",
2453
+ "tooltip-description": "列提示支持 Markdown 编辑,并支持在 {expression} 中求值。",
2454
+ "get-row-id": "行 ID",
2455
+ "get-row-id-description": "返回 string 的 CEL 表达式,可使用 row、index、parent 变量。",
2456
+ "get-sub-rows": "子行",
2457
+ "get-sub-rows-description": "返回子行数据的 CEL 表达式,可使用 row、index 变量。",
2458
+ "enable-row-selection": "启用行选择",
2459
+ "enable-row-selection-description": "返回 bool 的 CEL 表达式,可使用 row、index、id 变量。",
2460
+ "enable-multi-row-selection": "启用多选",
2461
+ "enable-multi-row-selection-description": "返回 bool 的 CEL 表达式,可使用 row、index、id 变量。",
2462
+ "cell-styles": "单元格样式",
2463
+ "cell-styles-description": "返回样式对象的 CEL 表达式,可使用 row、index、id、selected、pinned 变量。",
2464
+ "pagination": "分页",
2465
+ "pagination-left": "左侧文案",
2466
+ "pagination-left-placeholder": "输入分页左侧 Markdown",
2467
+ "pagination-right": "右侧文案",
2468
+ "pagination-right-placeholder": "输入分页右侧 Markdown",
2469
+ "pagination-page-size": "每页条数",
2470
+ "pagination-page-size-options": "每页条数选项",
2471
+ "add-pagination-page-size": "新增选项",
2472
+ "drag-pagination-page-size": "拖拽调整每页条数选项顺序",
2473
+ "remove-pagination-page-size": "删除每页条数选项",
2474
+ "no-pagination-page-sizes": "暂未配置每页条数选项。",
2475
+ "initial-state": "初始状态",
2476
+ "column-options": "列配置",
2477
+ "column-main": "基本",
2478
+ "column-title": "标题",
2479
+ "column-size": "列宽",
2480
+ "column-grow": "自适应增长",
2481
+ "column-grow-description": "启用后该列会占据剩余空间。",
2482
+ "column-enable-sorting": "启用排序",
2483
+ "column-enable-sorting-description": "启用后表头会显示排序操作。",
2484
+ "renderer": "渲染器",
2485
+ "renderer-type": "渲染器类型",
2486
+ "renderer-name-text": "文本",
2487
+ "renderer-name-selection": "选择",
2488
+ "renderer-name-expand": "展开",
2489
+ "renderer-name-money": "金额",
2490
+ "renderer-name-date": "日期",
2491
+ "renderer-name-markdown": "Markdown",
2492
+ "pinned-left-group": "左侧组",
2493
+ "pinned-center-group": "中间组",
2494
+ "pinned-right-group": "右侧组",
2495
+ "child-columns": "子列",
2496
+ "selected-children": "已选子列",
2497
+ "available-columns": "可选列",
2498
+ "search-child-columns": "搜索可选列……",
2499
+ "no-child-matches": "没有匹配的可选列。",
2500
+ "no-pinned-left-columns": "左侧组暂无列。",
2501
+ "no-pinned-center-columns": "中间组暂无列。",
2502
+ "no-pinned-right-columns": "右侧组暂无列。",
2503
+ "no-selected-children": "当前列还没有子列。",
2504
+ "no-available-columns": "没有可添加的列。",
2505
+ "add-column": "新增列",
2506
+ "drag-left-column": "拖拽调整左侧组顺序:{column}",
2507
+ "drag-center-column": "拖拽调整中间组顺序:{column}",
2508
+ "drag-right-column": "拖拽调整右侧组顺序:{column}",
2509
+ "pin-left-column": "固定到左侧组:{column}",
2510
+ "pin-right-column": "固定到右侧组:{column}",
2511
+ "unpin-left-column": "从左侧组释放到中间组:{column}",
2512
+ "unpin-right-column": "从右侧组释放到中间组:{column}",
2513
+ "drag-child-column": "拖拽调整子列顺序:{column}",
2514
+ "delete-column": "删除列:{column}",
2515
+ "remove-child-column": "移出子列:{column}",
2516
+ "copy-column-id": "复制列 ID:{column}",
2517
+ "untitled-column": "未命名列",
2518
+ "cancel": "取消",
2519
+ "confirm": "确认"
2520
+ },
2521
+ "ja": {
2522
+ "configure-table": "テーブルを設定",
2523
+ "configure-table-description": "ここではテーブルと列の設定項目を確認できます。",
2524
+ "paste-config": "設定を貼り付け",
2525
+ "paste-config-invalid-json": "貼り付けに失敗しました。クリップボードの内容が有効な JSON ではありません。",
2526
+ "paste-config-invalid-schema": "貼り付けに失敗しました。設定形式が無効です。",
2527
+ "paste-config-read-failed": "クリップボードの読み取りに失敗しました。権限を確認してください。",
2528
+ "copy-paste-error": "エラーをコピー",
2529
+ "copy-paste-error-failed": "エラー詳細のコピーに失敗しました。クリップボード権限を確認してください。",
2530
+ "copy-markdown": "Markdown としてコピー",
2531
+ "copy-markdown-failed": "Markdown のコピーに失敗しました。現在の設定エラーを先に修正してください。",
2532
+ "copy-config": "設定のみコピー",
2533
+ "copy-config-failed": "設定のコピーに失敗しました。現在の設定エラーを先に修正してください。",
2534
+ "search-columns": "列名を検索…",
2535
+ "general": "共通",
2536
+ "no-matches": "一致する列がありません。",
2537
+ "general-placeholder": "このテーブルの共通 CEL 式を設定します。",
2538
+ "expression-placeholder": "CEL 式を入力",
2539
+ "accessor": "アクセサ",
2540
+ "accessor-path-tab": "パス",
2541
+ "accessor-expression-tab": "式",
2542
+ "accessor-path": "パス",
2543
+ "accessor-path-description": "foo.bar や foo[0].bar のような dot-prop パスで row から値を読み取ります。",
2544
+ "accessor-path-placeholder": "dot-prop パスを入力",
2545
+ "accessor-read": "読み取り式",
2546
+ "accessor-read-description": "列値を返す CEL 式です。row、index を利用できます。",
2547
+ "accessor-read-placeholder": "読み取り用 CEL 式を入力",
2548
+ "accessor-write": "書き込み式",
2549
+ "accessor-write-description": "列値を書き戻すときに使う式です。",
2550
+ "accessor-write-placeholder": "書き込み式を入力",
2551
+ "tooltip": "ツールチップ",
2552
+ "tooltip-description": "列ツールチップは Markdown で編集でき、{expression} も利用できます。",
2553
+ "get-row-id": "行 ID",
2554
+ "get-row-id-description": "string を返す CEL 式です。row、index、parent を利用できます。",
2555
+ "get-sub-rows": "子行",
2556
+ "get-sub-rows-description": "子行データを返す CEL 式です。row、index を利用できます。",
2557
+ "enable-row-selection": "行選択を有効化",
2558
+ "enable-row-selection-description": "bool を返す CEL 式です。row、index、id を利用できます。",
2559
+ "enable-multi-row-selection": "複数選択を有効化",
2560
+ "enable-multi-row-selection-description": "bool を返す CEL 式です。row、index、id を利用できます。",
2561
+ "cell-styles": "セルスタイル",
2562
+ "cell-styles-description": "スタイルオブジェクトを返す CEL 式です。row、index、id、selected、pinned を利用できます。",
2563
+ "pagination": "ページネーション",
2564
+ "pagination-left": "左側テキスト",
2565
+ "pagination-left-placeholder": "左側の Markdown を入力",
2566
+ "pagination-right": "右側テキスト",
2567
+ "pagination-right-placeholder": "右側の Markdown を入力",
2568
+ "pagination-page-size": "1ページあたりの件数",
2569
+ "pagination-page-size-options": "1ページあたりの件数候補",
2570
+ "add-pagination-page-size": "候補を追加",
2571
+ "drag-pagination-page-size": "ドラッグして1ページあたりの件数候補の順序を変更",
2572
+ "remove-pagination-page-size": "1ページあたりの件数候補を削除",
2573
+ "no-pagination-page-sizes": "1ページあたりの件数候補はまだありません。",
2574
+ "initial-state": "初期状態",
2575
+ "column-options": "列設定",
2576
+ "column-main": "基本",
2577
+ "column-title": "タイトル",
2578
+ "column-size": "列幅",
2579
+ "column-grow": "可変幅",
2580
+ "column-grow-description": "有効にすると余白を埋めるように広がります。",
2581
+ "column-enable-sorting": "ソートを有効化",
2582
+ "column-enable-sorting-description": "有効にするとヘッダーにソート操作を表示します。",
2583
+ "renderer": "レンダラー",
2584
+ "renderer-type": "レンダラー種別",
2585
+ "renderer-name-text": "テキスト",
2586
+ "renderer-name-selection": "選択",
2587
+ "renderer-name-expand": "展開",
2588
+ "renderer-name-money": "金額",
2589
+ "renderer-name-date": "日付",
2590
+ "renderer-name-markdown": "Markdown",
2591
+ "pinned-left-group": "左側グループ",
2592
+ "pinned-center-group": "中央グループ",
2593
+ "pinned-right-group": "右側グループ",
2594
+ "child-columns": "子列",
2595
+ "selected-children": "選択済みの子列",
2596
+ "available-columns": "追加可能な列",
2597
+ "search-child-columns": "追加可能な列を検索…",
2598
+ "no-child-matches": "一致する追加可能な列がありません。",
2599
+ "no-pinned-left-columns": "左側グループに列がありません。",
2600
+ "no-pinned-center-columns": "中央グループに列がありません。",
2601
+ "no-pinned-right-columns": "右側グループに列がありません。",
2602
+ "no-selected-children": "この列にはまだ子列がありません。",
2603
+ "no-available-columns": "追加できる列がありません。",
2604
+ "add-column": "列を追加",
2605
+ "drag-left-column": "{column} の左側グループ順をドラッグで変更",
2606
+ "drag-center-column": "{column} の中央グループ順をドラッグで変更",
2607
+ "drag-right-column": "{column} の右側グループ順をドラッグで変更",
2608
+ "pin-left-column": "{column} を左側グループに固定",
2609
+ "pin-right-column": "{column} を右側グループに固定",
2610
+ "unpin-left-column": "{column} を左側グループから中央グループに戻す",
2611
+ "unpin-right-column": "{column} を右側グループから中央グループに戻す",
2612
+ "drag-child-column": "{column} の子列順をドラッグで変更",
2613
+ "delete-column": "{column} を削除",
2614
+ "remove-child-column": "{column} を子列から外す",
2615
+ "copy-column-id": "{column} の列 ID をコピー",
2616
+ "untitled-column": "未設定の列",
2617
+ "cancel": "キャンセル",
2618
+ "confirm": "確認"
2619
+ },
2620
+ "en": {
2621
+ "configure-table": "Configure Table",
2622
+ "configure-table-description": "Browse the table and column settings here.",
2623
+ "paste-config": "Paste Config",
2624
+ "paste-config-invalid-json": "Paste failed because the clipboard does not contain valid JSON.",
2625
+ "paste-config-invalid-schema": "Paste failed because the config shape is invalid.",
2626
+ "paste-config-read-failed": "Failed to read from the clipboard. Check clipboard permissions.",
2627
+ "copy-paste-error": "Copy Error",
2628
+ "copy-paste-error-failed": "Failed to copy the error details. Check clipboard permissions.",
2629
+ "copy-markdown": "Copy as Markdown",
2630
+ "copy-markdown-failed": "Failed to copy Markdown. Fix the current config errors first.",
2631
+ "copy-config": "Copy Config Only",
2632
+ "copy-config-failed": "Failed to copy the config. Fix the current config errors first.",
2633
+ "search-columns": "Search columns…",
2634
+ "general": "General",
2635
+ "no-matches": "No matching columns.",
2636
+ "general-placeholder": "Configure the shared CEL expressions for this table.",
2637
+ "expression-placeholder": "Enter a CEL expression",
2638
+ "accessor": "Accessor",
2639
+ "accessor-path-tab": "Path",
2640
+ "accessor-expression-tab": "Expression",
2641
+ "accessor-path": "Path",
2642
+ "accessor-path-description": "Read from row with a dot-prop path such as foo.bar or foo[0].bar.",
2643
+ "accessor-path-placeholder": "Enter a dot-prop path",
2644
+ "accessor-read": "Read expression",
2645
+ "accessor-read-description": "CEL expression that returns the column value. Variables: row, index.",
2646
+ "accessor-read-placeholder": "Enter a read CEL expression",
2647
+ "accessor-write": "Write expression",
2648
+ "accessor-write-description": "Expression used when writing the column value back.",
2649
+ "accessor-write-placeholder": "Enter a write expression",
2650
+ "tooltip": "Tooltip",
2651
+ "tooltip-description": "Column tooltips support Markdown and can evaluate {expression}.",
2652
+ "get-row-id": "Row ID",
2653
+ "get-row-id-description": "CEL expression that returns a string. Variables: row, index, parent.",
2654
+ "get-sub-rows": "Sub rows",
2655
+ "get-sub-rows-description": "CEL expression that returns sub-row data. Variables: row, index.",
2656
+ "enable-row-selection": "Enable row selection",
2657
+ "enable-row-selection-description": "CEL expression that returns a bool. Variables: row, index, id.",
2658
+ "enable-multi-row-selection": "Enable multi row selection",
2659
+ "enable-multi-row-selection-description": "CEL expression that returns a bool. Variables: row, index, id.",
2660
+ "cell-styles": "Cell styles",
2661
+ "cell-styles-description": "CEL expression that returns a style map. Variables: row, index, id, selected, pinned.",
2662
+ "pagination": "Pagination",
2663
+ "pagination-left": "Left content",
2664
+ "pagination-left-placeholder": "Enter left pagination markdown",
2665
+ "pagination-right": "Right content",
2666
+ "pagination-right-placeholder": "Enter right pagination markdown",
2667
+ "pagination-page-size": "Page size",
2668
+ "pagination-page-size-options": "Page size options",
2669
+ "add-pagination-page-size": "Add option",
2670
+ "drag-pagination-page-size": "Drag to reorder page size options",
2671
+ "remove-pagination-page-size": "Remove page size option",
2672
+ "no-pagination-page-sizes": "No page size options configured.",
2673
+ "initial-state": "Initial State",
2674
+ "column-options": "Column options",
2675
+ "column-main": "Basics",
2676
+ "column-title": "Title",
2677
+ "column-size": "Column size",
2678
+ "column-grow": "Grow",
2679
+ "column-grow-description": "Allow this column to fill remaining horizontal space.",
2680
+ "column-enable-sorting": "Enable sorting",
2681
+ "column-enable-sorting-description": "Show sorting controls in the header.",
2682
+ "renderer": "Renderer",
2683
+ "renderer-type": "Renderer type",
2684
+ "renderer-name-text": "Text",
2685
+ "renderer-name-selection": "Selection",
2686
+ "renderer-name-expand": "Expand",
2687
+ "renderer-name-money": "Money",
2688
+ "renderer-name-date": "Date",
2689
+ "renderer-name-markdown": "Markdown",
2690
+ "pinned-left-group": "Left group",
2691
+ "pinned-center-group": "Center group",
2692
+ "pinned-right-group": "Right group",
2693
+ "child-columns": "Child columns",
2694
+ "selected-children": "Selected child columns",
2695
+ "available-columns": "Available columns",
2696
+ "search-child-columns": "Search available columns…",
2697
+ "no-child-matches": "No matching available columns.",
2698
+ "no-pinned-left-columns": "No columns in the left group.",
2699
+ "no-pinned-center-columns": "No columns in the center group.",
2700
+ "no-pinned-right-columns": "No columns in the right group.",
2701
+ "no-selected-children": "This column has no child columns yet.",
2702
+ "no-available-columns": "No columns can be added here.",
2703
+ "add-column": "Add column",
2704
+ "drag-left-column": "Drag to reorder left group column {column}",
2705
+ "drag-center-column": "Drag to reorder center group column {column}",
2706
+ "drag-right-column": "Drag to reorder right group column {column}",
2707
+ "pin-left-column": "Pin {column} to the left group",
2708
+ "pin-right-column": "Pin {column} to the right group",
2709
+ "unpin-left-column": "Move {column} from the left group to the center group",
2710
+ "unpin-right-column": "Move {column} from the right group to the center group",
2711
+ "drag-child-column": "Drag to reorder child column {column}",
2712
+ "delete-column": "Delete {column}",
2713
+ "remove-child-column": "Remove child column {column}",
2714
+ "untitled-column": "Untitled column",
2715
+ "cancel": "Cancel",
2716
+ "confirm": "Confirm"
2717
+ }
2718
+ }
2719
+ </i18n>