@shwfed/nuxt 0.11.31 → 0.11.32

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.
@@ -15,7 +15,8 @@ import {
15
15
  SelectFieldC,
16
16
  SlotFieldC,
17
17
  StringFieldC,
18
- TextareaFieldC
18
+ TextareaFieldC,
19
+ UploadFieldC
19
20
  } from "../fields/schema";
20
21
  import { cn } from "../../../utils/cn";
21
22
  import { Button } from "../button";
@@ -29,6 +30,7 @@ import {
29
30
  } from "../dialog";
30
31
  import {
31
32
  DropdownMenu,
33
+ DropdownMenuCheckboxItem,
32
34
  DropdownMenuContent,
33
35
  DropdownMenuItem,
34
36
  DropdownMenuTrigger
@@ -48,6 +50,7 @@ const open = defineModel("open", { type: Boolean, ...{
48
50
  const { $toast } = useNuxtApp();
49
51
  const { t } = useI18n();
50
52
  const draftOrientation = ref("horizontal");
53
+ const draftBordered = ref(false);
51
54
  const draftStyle = ref();
52
55
  const search = ref("");
53
56
  const selectedItemId = ref("general");
@@ -61,6 +64,7 @@ const fieldTypeOptions = computed(() => [
61
64
  { type: "number", label: t("field-type-number") },
62
65
  { type: "select", label: t("field-type-select") },
63
66
  { type: "calendar", label: t("field-type-calendar") },
67
+ { type: "upload", label: t("field-type-upload") },
64
68
  { type: "empty", label: t("field-type-empty") },
65
69
  { type: "slot", label: t("field-type-slot") }
66
70
  ]);
@@ -70,6 +74,7 @@ const generalItem = computed(() => ({
70
74
  }));
71
75
  const normalizedSearch = computed(() => search.value.trim().toLocaleLowerCase());
72
76
  const selectedField = computed(() => draftFields.value.find((field) => field.draftId === selectedItemId.value));
77
+ const usesContentsOrientation = computed(() => draftOrientation.value === "contents");
73
78
  const selectedFieldValidationRules = computed(() => {
74
79
  const field = selectedField.value?.field;
75
80
  if (!field || field.type === "slot" || field.type === "empty") {
@@ -96,7 +101,7 @@ function cloneFields(fields) {
96
101
  return fields.map(createDraftField);
97
102
  }
98
103
  function normalizeOrientation(value) {
99
- if (value === "vertical" || value === "floating") {
104
+ if (value === "vertical" || value === "floating" || value === "contents") {
100
105
  return value;
101
106
  }
102
107
  return "horizontal";
@@ -220,6 +225,8 @@ function normalizeField(field) {
220
225
  required: field.required ? true : void 0,
221
226
  icon: normalizeOptionalString(field.icon ?? ""),
222
227
  style: normalizeOptionalString(field.style ?? ""),
228
+ labelStyle: normalizeOptionalString(field.labelStyle ?? ""),
229
+ contentStyle: normalizeOptionalString(field.contentStyle ?? ""),
223
230
  initialValue: normalizeOptionalString(field.initialValue ?? ""),
224
231
  maxLength: normalizeOptionalString(field.maxLength ?? ""),
225
232
  hidden: normalizeOptionalString(field.hidden ?? ""),
@@ -234,6 +241,8 @@ function normalizeField(field) {
234
241
  required: field.required ? true : void 0,
235
242
  icon: normalizeOptionalString(field.icon ?? ""),
236
243
  style: normalizeOptionalString(field.style ?? ""),
244
+ labelStyle: normalizeOptionalString(field.labelStyle ?? ""),
245
+ contentStyle: normalizeOptionalString(field.contentStyle ?? ""),
237
246
  initialValue: normalizeOptionalString(field.initialValue ?? ""),
238
247
  min: normalizeOptionalString(field.min ?? ""),
239
248
  max: normalizeOptionalString(field.max ?? ""),
@@ -249,6 +258,8 @@ function normalizeField(field) {
249
258
  required: field.required ? true : void 0,
250
259
  icon: normalizeOptionalString(field.icon ?? ""),
251
260
  style: normalizeOptionalString(field.style ?? ""),
261
+ labelStyle: normalizeOptionalString(field.labelStyle ?? ""),
262
+ contentStyle: normalizeOptionalString(field.contentStyle ?? ""),
252
263
  options: field.options.trim(),
253
264
  label: field.label.trim(),
254
265
  value: field.value.trim(),
@@ -265,6 +276,8 @@ function normalizeField(field) {
265
276
  required: field.required ? true : void 0,
266
277
  icon: normalizeOptionalString(field.icon ?? ""),
267
278
  style: normalizeOptionalString(field.style ?? ""),
279
+ labelStyle: normalizeOptionalString(field.labelStyle ?? ""),
280
+ contentStyle: normalizeOptionalString(field.contentStyle ?? ""),
268
281
  display: normalizeOptionalString(field.display ?? ""),
269
282
  value: field.value.trim(),
270
283
  initialValue: normalizeOptionalString(field.initialValue ?? ""),
@@ -273,6 +286,24 @@ function normalizeField(field) {
273
286
  disabled: normalizeOptionalString(field.disabled ?? ""),
274
287
  validation: normalizeValidationRules(field.validation)
275
288
  };
289
+ case "upload": {
290
+ const normalizedAccept = (field.accept ?? []).filter((mime) => mime.trim().length > 0);
291
+ return {
292
+ ...field,
293
+ path: field.path.trim(),
294
+ required: field.required ? true : void 0,
295
+ icon: normalizeOptionalString(field.icon ?? ""),
296
+ style: normalizeOptionalString(field.style ?? ""),
297
+ labelStyle: normalizeOptionalString(field.labelStyle ?? ""),
298
+ contentStyle: normalizeOptionalString(field.contentStyle ?? ""),
299
+ accept: normalizedAccept.length > 0 ? normalizedAccept : void 0,
300
+ maxCount: normalizeOptionalString(field.maxCount ?? ""),
301
+ initialValue: normalizeOptionalString(field.initialValue ?? ""),
302
+ hidden: normalizeOptionalString(field.hidden ?? ""),
303
+ disabled: normalizeOptionalString(field.disabled ?? ""),
304
+ validation: normalizeValidationRules(field.validation)
305
+ };
306
+ }
276
307
  case "slot":
277
308
  return {
278
309
  ...field,
@@ -324,6 +355,13 @@ function createField(type) {
324
355
  mode: "date",
325
356
  value: "yyyy-MM-dd"
326
357
  };
358
+ case "upload":
359
+ return {
360
+ id,
361
+ type,
362
+ path: "",
363
+ title
364
+ };
327
365
  case "empty":
328
366
  return {
329
367
  id,
@@ -341,6 +379,7 @@ function resetDraftConfig() {
341
379
  }
342
380
  function applyDraftConfig(config) {
343
381
  draftOrientation.value = config.orientation ?? "horizontal";
382
+ draftBordered.value = config.bordered ?? false;
344
383
  draftStyle.value = normalizeOptionalString(config.style ?? "");
345
384
  search.value = "";
346
385
  draftFields.value = cloneFields(config.fields);
@@ -448,6 +487,9 @@ function selectItem(itemId) {
448
487
  function updateDraftOrientation(value) {
449
488
  draftOrientation.value = normalizeOrientation(value);
450
489
  }
490
+ function updateDraftBordered(value) {
491
+ draftBordered.value = value;
492
+ }
451
493
  function updateDraftStyle(value) {
452
494
  clearError(getGeneralErrorKey("style"));
453
495
  draftStyle.value = normalizeOptionalString(String(value));
@@ -532,6 +574,28 @@ function updateSelectedFieldStyle(value) {
532
574
  style: normalizeOptionalString(String(value))
533
575
  }));
534
576
  }
577
+ function updateSelectedFieldLabelStyle(value) {
578
+ const selected = selectedField.value;
579
+ if (!selected || isPassiveField(selected.field)) {
580
+ return;
581
+ }
582
+ clearFieldError(selected.draftId, "labelStyle");
583
+ updateDraftField(selected.draftId, (field) => isPassiveField(field) ? field : {
584
+ ...field,
585
+ labelStyle: normalizeOptionalString(String(value))
586
+ });
587
+ }
588
+ function updateSelectedFieldContentStyle(value) {
589
+ const selected = selectedField.value;
590
+ if (!selected || isPassiveField(selected.field)) {
591
+ return;
592
+ }
593
+ clearFieldError(selected.draftId, "contentStyle");
594
+ updateDraftField(selected.draftId, (field) => isPassiveField(field) ? field : {
595
+ ...field,
596
+ contentStyle: normalizeOptionalString(String(value))
597
+ });
598
+ }
535
599
  function updateSelectedFieldHidden(value) {
536
600
  const selected = selectedField.value;
537
601
  if (!selected) {
@@ -791,6 +855,70 @@ function updateSelectedCalendarDisableDate(value) {
791
855
  };
792
856
  });
793
857
  }
858
+ const UPLOAD_MIME_OPTIONS = [
859
+ { mime: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", label: "Excel (.xlsx)", icon: "vscode-icons:file-type-excel" },
860
+ { mime: "application/vnd.ms-excel", label: "Excel (.xls)", icon: "vscode-icons:file-type-excel" },
861
+ { mime: "application/x-zip-compressed", label: "ZIP", icon: "vscode-icons:file-type-zip" },
862
+ { mime: "application/zip", label: "ZIP (.zip)", icon: "vscode-icons:file-type-zip" },
863
+ { mime: "application/pdf", label: "PDF", icon: "vscode-icons:file-type-pdf2" },
864
+ { mime: "application/ofd", label: "OFD", icon: "vscode-icons:file-type-ofd" },
865
+ { mime: "application/xml", label: "XML", icon: "vscode-icons:file-type-xml" },
866
+ { mime: "image/png", label: "PNG", icon: "vscode-icons:file-type-image" },
867
+ { mime: "image/jpg", label: "JPG", icon: "vscode-icons:file-type-image" },
868
+ { mime: "image/jpeg", label: "JPEG", icon: "vscode-icons:file-type-image" },
869
+ { mime: "application/msword", label: "Word (.doc)", icon: "vscode-icons:file-type-word" },
870
+ { mime: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", label: "Word (.docx)", icon: "vscode-icons:file-type-word" }
871
+ ];
872
+ function toggleSelectedUploadAccept(mime) {
873
+ const selected = selectedField.value;
874
+ if (!selected || selected.field.type !== "upload") {
875
+ return;
876
+ }
877
+ clearFieldError(selected.draftId, "accept");
878
+ updateDraftField(selected.draftId, (field) => {
879
+ if (field.type !== "upload") {
880
+ return field;
881
+ }
882
+ const current = field.accept ?? [];
883
+ const next = current.includes(mime) ? current.filter((m) => m !== mime) : [...current, mime];
884
+ return {
885
+ ...field,
886
+ accept: next.length > 0 ? next : void 0
887
+ };
888
+ });
889
+ }
890
+ function updateSelectedUploadDescription(value) {
891
+ const selected = selectedField.value;
892
+ if (!selected || selected.field.type !== "upload") {
893
+ return;
894
+ }
895
+ clearFieldError(selected.draftId, "description");
896
+ updateDraftField(selected.draftId, (field) => {
897
+ if (field.type !== "upload") {
898
+ return field;
899
+ }
900
+ return {
901
+ ...field,
902
+ description: value
903
+ };
904
+ });
905
+ }
906
+ function updateSelectedUploadMaxCount(value) {
907
+ const selected = selectedField.value;
908
+ if (!selected || selected.field.type !== "upload") {
909
+ return;
910
+ }
911
+ clearFieldError(selected.draftId, "maxCount");
912
+ updateDraftField(selected.draftId, (field) => {
913
+ if (field.type !== "upload") {
914
+ return field;
915
+ }
916
+ return {
917
+ ...field,
918
+ maxCount: normalizeOptionalString(String(value))
919
+ };
920
+ });
921
+ }
794
922
  function addValidationRule() {
795
923
  const selected = selectedField.value;
796
924
  if (!selected || isPassiveField(selected.field)) {
@@ -933,6 +1061,10 @@ function getSchemaIssues(field) {
933
1061
  const result = CalendarFieldC.safeParse(field);
934
1062
  return result.success ? [] : result.error.issues;
935
1063
  }
1064
+ case "upload": {
1065
+ const result = UploadFieldC.safeParse(field);
1066
+ return result.success ? [] : result.error.issues;
1067
+ }
936
1068
  case "slot": {
937
1069
  const result = SlotFieldC.safeParse(field);
938
1070
  return result.success ? [] : result.error.issues;
@@ -1040,6 +1172,9 @@ function buildDraftConfig() {
1040
1172
  if (draftOrientation.value !== "horizontal") {
1041
1173
  nextBody.orientation = draftOrientation.value;
1042
1174
  }
1175
+ if (draftBordered.value && draftOrientation.value === "contents") {
1176
+ nextBody.bordered = true;
1177
+ }
1043
1178
  if (generalStyleResult.data) {
1044
1179
  nextBody.style = generalStyleResult.data;
1045
1180
  }
@@ -1102,7 +1237,7 @@ function buildDslGuideMarkdown() {
1102
1237
  '- \u65B9\u6CD5\u8C03\u7528\uFF1A`value.method(args)`\uFF0C\u4F8B\u5982 `now.format("yyyy-MM-dd")`\u3002',
1103
1238
  "",
1104
1239
  "### 2. \u5E38\u89C1\u5B57\u6BB5\u4E0E\u7528\u9014",
1105
- '- `style` \u76F8\u5173\u5B57\u6BB5\u9700\u8981\u8FD4\u56DE style map\uFF0C\u4F8B\u5982 `{"display": "grid"}`\u3002',
1240
+ '- `style`\u3001`labelStyle`\u3001`contentStyle` \u76F8\u5173\u5B57\u6BB5\u9700\u8981\u8FD4\u56DE style map\uFF0C\u4F8B\u5982 `{"display": "grid"}`\u3002',
1106
1241
  "- `initialValue` \u9700\u8981\u8FD4\u56DE\u5BF9\u5E94\u5B57\u6BB5\u6700\u7EC8\u5199\u5165 `path` \u7684\u503C\u3002",
1107
1242
  "- `hidden` / `disabled` / `disableDate` \u9700\u8981\u8FD4\u56DE `bool`\u3002",
1108
1243
  "- `validation[].expression` \u9700\u8981\u8FD4\u56DE `bool`\uFF1B\u8FD4\u56DE `false` \u65F6\u5C55\u793A\u5BF9\u5E94\u6D88\u606F\u3002",
@@ -1112,7 +1247,8 @@ function buildDslGuideMarkdown() {
1112
1247
  "- \u4EE3\u7801\u91CC\u5E94\u5148\u751F\u6210\u5E76\u4F7F\u7528 UUID\uFF0C\u518D\u628A\u540C\u4E00\u4E2A `id` \u7C98\u8D34\u56DE\u5B57\u6BB5\u914D\u7F6E\u3002",
1113
1248
  "- \u6240\u6709\u5B57\u6BB5\u90FD\u5FC5\u987B\u5305\u542B\u552F\u4E00\u4E14\u5408\u6CD5\u7684 UUID `id`\u3002",
1114
1249
  "- \u53EA\u6709\u975E `slot` / `empty` \u5B57\u6BB5\u53EF\u4EE5\u914D\u7F6E `path`\uFF0C\u5E76\u53C2\u4E0E\u8868\u5355\u503C\u8BFB\u5199\u3002",
1115
- "- `slot` \u548C `empty` \u5B57\u6BB5\u90FD\u4E0D\u4F1A\u7ED1\u5B9A\u6A21\u578B\u503C\uFF0C\u53EA\u5141\u8BB8 `id`\u3001`type` \u548C\u53EF\u9009\u7684 `style`\u3002"
1250
+ "- `slot` \u548C `empty` \u5B57\u6BB5\u90FD\u4E0D\u4F1A\u7ED1\u5B9A\u6A21\u578B\u503C\uFF0C\u53EA\u5141\u8BB8 `id`\u3001`type` \u548C\u53EF\u9009\u7684 `style`\u3002",
1251
+ "- \u666E\u901A\u5B57\u6BB5\u53EF\u989D\u5916\u4F7F\u7528 `labelStyle` \u4E0E `contentStyle`\uFF0C\u7528\u4E8E contents \u5E03\u5C40\u6A21\u5F0F\u4E0B\u5206\u522B\u63A7\u5236\u6807\u7B7E\u4E0E\u5185\u5BB9\u5355\u5143\u683C\u3002"
1116
1252
  ].join("\n");
1117
1253
  }
1118
1254
  function buildMarkdownNotes() {
@@ -1121,6 +1257,7 @@ function buildMarkdownNotes() {
1121
1257
  "- \u5148\u5728\u4EE3\u7801\u91CC\u751F\u6210\u5E76\u4F7F\u7528 UUID\uFF0C\u518D\u628A\u540C\u4E00\u4E2A `id` \u7C98\u8D34\u5230\u5B57\u6BB5\u914D\u7F6E\u4E2D\u3002",
1122
1258
  "- \u6240\u6709\u5B57\u6BB5 `id` \u90FD\u5FC5\u987B\u552F\u4E00\u4E14\u7B26\u5408 UUID \u683C\u5F0F\u3002",
1123
1259
  "- `slot` \u4E0E `empty` \u5B57\u6BB5\u53EA\u80FD\u4F7F\u7528 `id`\u3001`type` \u548C\u53EF\u9009\u7684 `style`\u3002",
1260
+ "- \u666E\u901A\u5B57\u6BB5\u5728 contents \u5E03\u5C40\u6A21\u5F0F\u4E0B\u53EF\u989D\u5916\u4F7F\u7528 `labelStyle` \u4E0E `contentStyle`\u3002",
1124
1261
  "- \u975E `slot` / `empty` \u5B57\u6BB5\u7684 `path` \u5FC5\u987B\u552F\u4E00\u4E14\u4E0D\u80FD\u4E3A\u7A7A\u3002",
1125
1262
  "- \u8868\u8FBE\u5F0F\u5B57\u6BB5\u5FC5\u987B\u4E25\u683C\u9075\u5B88 schema \u7EA6\u675F\uFF1B\u5982\u679C schema \u4E0D\u652F\u6301\uFF0C\u5C31\u76F4\u63A5\u8BF4\u660E\u9650\u5236\u3002"
1126
1263
  ].join("\n");
@@ -1504,9 +1641,27 @@ function confirmChanges() {
1504
1641
  <NativeSelectOption value="floating">
1505
1642
  {{ t("fields-orientation-floating") }}
1506
1643
  </NativeSelectOption>
1644
+ <NativeSelectOption value="contents">
1645
+ {{ t("fields-orientation-contents") }}
1646
+ </NativeSelectOption>
1507
1647
  </NativeSelect>
1508
1648
  </label>
1509
1649
 
1650
+ <label
1651
+ v-if="usesContentsOrientation"
1652
+ data-slot="fields-configurator-general-bordered-section"
1653
+ class="flex items-center justify-between gap-2"
1654
+ >
1655
+ <span class="text-xs font-medium text-zinc-500">
1656
+ {{ t("fields-bordered") }}
1657
+ </span>
1658
+ <Switch
1659
+ data-slot="fields-configurator-general-bordered-switch"
1660
+ :model-value="draftBordered"
1661
+ @update:model-value="updateDraftBordered"
1662
+ />
1663
+ </label>
1664
+
1510
1665
  <label
1511
1666
  data-slot="fields-configurator-general-style-section"
1512
1667
  class="flex flex-col gap-2 md:col-span-2"
@@ -1661,7 +1816,10 @@ function confirmChanges() {
1661
1816
  />
1662
1817
  </label>
1663
1818
 
1664
- <label class="flex flex-col gap-2">
1819
+ <label
1820
+ v-if="!usesContentsOrientation"
1821
+ class="flex flex-col gap-2"
1822
+ >
1665
1823
  <span class="text-xs font-medium text-zinc-500">
1666
1824
  {{ t("field-style") }}
1667
1825
  </span>
@@ -1681,6 +1839,52 @@ function confirmChanges() {
1681
1839
  </p>
1682
1840
  </label>
1683
1841
 
1842
+ <label
1843
+ v-else
1844
+ class="flex flex-col gap-2"
1845
+ >
1846
+ <span class="text-xs font-medium text-zinc-500">
1847
+ {{ t("field-label-style") }}
1848
+ </span>
1849
+ <Textarea
1850
+ data-slot="fields-configurator-field-label-style-input"
1851
+ :model-value="selectedField.field.labelStyle ?? ''"
1852
+ :aria-invalid="validationErrors[getFieldErrorKey(selectedField.draftId, 'labelStyle')] ? 'true' : void 0"
1853
+ :placeholder="t('field-style-placeholder')"
1854
+ class="min-h-20 font-mono text-sm"
1855
+ @update:model-value="updateSelectedFieldLabelStyle"
1856
+ />
1857
+ <p
1858
+ v-if="validationErrors[getFieldErrorKey(selectedField.draftId, 'labelStyle')]"
1859
+ class="text-xs text-red-500"
1860
+ >
1861
+ {{ validationErrors[getFieldErrorKey(selectedField.draftId, "labelStyle")] }}
1862
+ </p>
1863
+ </label>
1864
+
1865
+ <label
1866
+ v-if="usesContentsOrientation"
1867
+ class="flex flex-col gap-2"
1868
+ >
1869
+ <span class="text-xs font-medium text-zinc-500">
1870
+ {{ t("field-content-style") }}
1871
+ </span>
1872
+ <Textarea
1873
+ data-slot="fields-configurator-field-content-style-input"
1874
+ :model-value="selectedField.field.contentStyle ?? ''"
1875
+ :aria-invalid="validationErrors[getFieldErrorKey(selectedField.draftId, 'contentStyle')] ? 'true' : void 0"
1876
+ :placeholder="t('field-style-placeholder')"
1877
+ class="min-h-20 font-mono text-sm"
1878
+ @update:model-value="updateSelectedFieldContentStyle"
1879
+ />
1880
+ <p
1881
+ v-if="validationErrors[getFieldErrorKey(selectedField.draftId, 'contentStyle')]"
1882
+ class="text-xs text-red-500"
1883
+ >
1884
+ {{ validationErrors[getFieldErrorKey(selectedField.draftId, "contentStyle")] }}
1885
+ </p>
1886
+ </label>
1887
+
1684
1888
  <label class="flex flex-col gap-2">
1685
1889
  <span class="text-xs font-medium text-zinc-500">
1686
1890
  {{ t("field-hidden") }}
@@ -2010,6 +2214,84 @@ function confirmChanges() {
2010
2214
  </label>
2011
2215
  </section>
2012
2216
 
2217
+ <section
2218
+ v-if="selectedField.field.type === 'upload'"
2219
+ data-slot="fields-configurator-upload-options"
2220
+ class="grid gap-4 md:grid-cols-2"
2221
+ >
2222
+ <div class="flex flex-col gap-2">
2223
+ <span class="text-xs font-medium text-zinc-500">
2224
+ {{ t("field-upload-accept") }}
2225
+ </span>
2226
+ <DropdownMenu>
2227
+ <DropdownMenuTrigger
2228
+ data-slot="fields-configurator-field-upload-accept-trigger"
2229
+ :aria-invalid="validationErrors[getFieldErrorKey(selectedField.draftId, 'accept')] ? 'true' : void 0"
2230
+ class="flex h-9 w-full items-center justify-between rounded-md border border-zinc-200 bg-white px-3 text-sm text-zinc-700 hover:bg-zinc-50 aria-invalid:border-red-400"
2231
+ >
2232
+ <span class="truncate">
2233
+ {{ (selectedField.field.accept ?? []).length > 0 ? (selectedField.field.accept ?? []).length + " " + t("field-upload-accept-selected") : t("field-upload-accept-placeholder") }}
2234
+ </span>
2235
+ <Icon
2236
+ icon="fluent:chevron-down-20-regular"
2237
+ class="shrink-0 text-zinc-400"
2238
+ />
2239
+ </DropdownMenuTrigger>
2240
+ <DropdownMenuContent class="w-72">
2241
+ <DropdownMenuCheckboxItem
2242
+ v-for="option in UPLOAD_MIME_OPTIONS"
2243
+ :key="option.mime"
2244
+ :model-value="(selectedField.field.accept ?? []).includes(option.mime)"
2245
+ @update:model-value="toggleSelectedUploadAccept(option.mime)"
2246
+ >
2247
+ <Icon
2248
+ :icon="option.icon"
2249
+ class="text-base"
2250
+ />
2251
+ {{ option.label }}
2252
+ </DropdownMenuCheckboxItem>
2253
+ </DropdownMenuContent>
2254
+ </DropdownMenu>
2255
+ <p
2256
+ v-if="validationErrors[getFieldErrorKey(selectedField.draftId, 'accept')]"
2257
+ class="text-xs text-red-500"
2258
+ >
2259
+ {{ validationErrors[getFieldErrorKey(selectedField.draftId, "accept")] }}
2260
+ </p>
2261
+ </div>
2262
+
2263
+ <div class="flex flex-col gap-2 md:col-span-2">
2264
+ <span class="text-xs font-medium text-zinc-500">
2265
+ {{ t("field-upload-description") }}
2266
+ </span>
2267
+ <Locale
2268
+ data-slot="fields-configurator-field-upload-description-locale"
2269
+ :model-value="selectedField.field.description"
2270
+ @update:model-value="updateSelectedUploadDescription"
2271
+ />
2272
+ </div>
2273
+
2274
+ <label class="flex flex-col gap-2">
2275
+ <span class="text-xs font-medium text-zinc-500">
2276
+ {{ t("field-upload-max-count") }}
2277
+ </span>
2278
+ <Textarea
2279
+ data-slot="fields-configurator-field-upload-max-count-input"
2280
+ :model-value="selectedField.field.maxCount ?? ''"
2281
+ :aria-invalid="validationErrors[getFieldErrorKey(selectedField.draftId, 'maxCount')] ? 'true' : void 0"
2282
+ :placeholder="t('field-upload-max-count-placeholder')"
2283
+ class="min-h-20 font-mono text-sm"
2284
+ @update:model-value="updateSelectedUploadMaxCount"
2285
+ />
2286
+ <p
2287
+ v-if="validationErrors[getFieldErrorKey(selectedField.draftId, 'maxCount')]"
2288
+ class="text-xs text-red-500"
2289
+ >
2290
+ {{ validationErrors[getFieldErrorKey(selectedField.draftId, "maxCount")] }}
2291
+ </p>
2292
+ </label>
2293
+ </section>
2294
+
2013
2295
  <section
2014
2296
  v-if="!isPassiveField(selectedField.field)"
2015
2297
  data-slot="fields-configurator-validation"
@@ -2207,6 +2489,8 @@ function confirmChanges() {
2207
2489
  "fields-orientation-horizontal": "水平",
2208
2490
  "fields-orientation-vertical": "垂直",
2209
2491
  "fields-orientation-floating": "浮动标签",
2492
+ "fields-orientation-contents": "内容透传",
2493
+ "fields-bordered": "表格式边框",
2210
2494
  "paste-config": "粘贴配置",
2211
2495
  "paste-config-invalid-json": "粘贴失败,剪贴板不是有效的 JSON。",
2212
2496
  "paste-config-invalid-schema": "粘贴失败,配置格式无效。",
@@ -2225,6 +2509,7 @@ function confirmChanges() {
2225
2509
  "field-type-number": "数字",
2226
2510
  "field-type-select": "选择",
2227
2511
  "field-type-calendar": "日期",
2512
+ "field-type-upload": "上传",
2228
2513
  "field-type-empty": "空白",
2229
2514
  "field-type-slot": "插槽",
2230
2515
  "field-id": "字段 ID",
@@ -2244,6 +2529,8 @@ function confirmChanges() {
2244
2529
  "field-icon": "图标",
2245
2530
  "field-icon-placeholder": "例如 fluent:person-20-regular",
2246
2531
  "field-style": "样式表达式",
2532
+ "field-label-style": "标签样式表达式",
2533
+ "field-content-style": "内容样式表达式",
2247
2534
  "field-style-placeholder": "例如 width: 100%",
2248
2535
  "field-hidden": "隐藏条件",
2249
2536
  "field-hidden-placeholder": "返回 true 时隐藏字段",
@@ -2280,6 +2567,12 @@ function confirmChanges() {
2280
2567
  "calendar-value-required": "日期存储格式不能为空",
2281
2568
  "field-disable-date": "禁用日期条件",
2282
2569
  "field-disable-date-placeholder": "返回 true 时禁用该日期",
2570
+ "field-upload-accept": "接受文件类型",
2571
+ "field-upload-accept-placeholder": "未选择",
2572
+ "field-upload-accept-selected": "种格式",
2573
+ "field-upload-description": "上传提示文本",
2574
+ "field-upload-max-count": "最大文件数量",
2575
+ "field-upload-max-count-placeholder": "例如 5",
2283
2576
  "field-validation": "校验规则",
2284
2577
  "field-validation-description": "字段失焦时按顺序执行,命中第一个失败规则后停止。",
2285
2578
  "add-validation-rule": "新增规则",
@@ -2312,6 +2605,8 @@ function confirmChanges() {
2312
2605
  "fields-orientation-horizontal": "横並び",
2313
2606
  "fields-orientation-vertical": "縦並び",
2314
2607
  "fields-orientation-floating": "フローティングラベル",
2608
+ "fields-orientation-contents": "コンテンツ透過",
2609
+ "fields-bordered": "テーブルボーダー",
2315
2610
  "paste-config": "設定を貼り付け",
2316
2611
  "paste-config-invalid-json": "貼り付けに失敗しました。クリップボードの内容が有効な JSON ではありません。",
2317
2612
  "paste-config-invalid-schema": "貼り付けに失敗しました。設定形式が無効です。",
@@ -2330,6 +2625,7 @@ function confirmChanges() {
2330
2625
  "field-type-number": "数値",
2331
2626
  "field-type-select": "選択",
2332
2627
  "field-type-calendar": "日付",
2628
+ "field-type-upload": "アップロード",
2333
2629
  "field-type-empty": "空白",
2334
2630
  "field-type-slot": "スロット",
2335
2631
  "field-id": "フィールド ID",
@@ -2349,6 +2645,8 @@ function confirmChanges() {
2349
2645
  "field-icon": "アイコン",
2350
2646
  "field-icon-placeholder": "例: fluent:person-20-regular",
2351
2647
  "field-style": "スタイル式",
2648
+ "field-label-style": "ラベルスタイル式",
2649
+ "field-content-style": "コンテンツスタイル式",
2352
2650
  "field-style-placeholder": "例: width: 100%",
2353
2651
  "field-hidden": "非表示条件",
2354
2652
  "field-hidden-placeholder": "true を返すと非表示になります",
@@ -2385,6 +2683,12 @@ function confirmChanges() {
2385
2683
  "calendar-value-required": "日付の保存形式は必須です",
2386
2684
  "field-disable-date": "無効日条件",
2387
2685
  "field-disable-date-placeholder": "true を返す日付を無効化します",
2686
+ "field-upload-accept": "受け入れファイル形式",
2687
+ "field-upload-accept-placeholder": "未選択",
2688
+ "field-upload-accept-selected": "種類選択済",
2689
+ "field-upload-description": "アップロード説明文",
2690
+ "field-upload-max-count": "最大ファイル数",
2691
+ "field-upload-max-count-placeholder": "例: 5",
2388
2692
  "field-validation": "検証ルール",
2389
2693
  "field-validation-description": "フォーカスを外したときに順番に評価し、最初の失敗で停止します。",
2390
2694
  "add-validation-rule": "ルールを追加",
@@ -2417,6 +2721,8 @@ function confirmChanges() {
2417
2721
  "fields-orientation-horizontal": "Horizontal",
2418
2722
  "fields-orientation-vertical": "Vertical",
2419
2723
  "fields-orientation-floating": "Floating label",
2724
+ "fields-orientation-contents": "Contents passthrough",
2725
+ "fields-bordered": "Table borders",
2420
2726
  "paste-config": "Paste Config",
2421
2727
  "paste-config-invalid-json": "Paste failed because the clipboard does not contain valid JSON.",
2422
2728
  "paste-config-invalid-schema": "Paste failed because the config shape is invalid.",
@@ -2435,6 +2741,7 @@ function confirmChanges() {
2435
2741
  "field-type-number": "Number",
2436
2742
  "field-type-select": "Select",
2437
2743
  "field-type-calendar": "Date",
2744
+ "field-type-upload": "Upload",
2438
2745
  "field-type-empty": "Empty",
2439
2746
  "field-type-slot": "Slot",
2440
2747
  "field-id": "Field ID",
@@ -2454,6 +2761,8 @@ function confirmChanges() {
2454
2761
  "field-icon": "Icon",
2455
2762
  "field-icon-placeholder": "For example fluent:person-20-regular",
2456
2763
  "field-style": "Style expression",
2764
+ "field-label-style": "Label style expression",
2765
+ "field-content-style": "Content style expression",
2457
2766
  "field-style-placeholder": "For example width: 100%",
2458
2767
  "field-hidden": "Hidden expression",
2459
2768
  "field-hidden-placeholder": "Return true to hide the field",
@@ -2490,6 +2799,12 @@ function confirmChanges() {
2490
2799
  "calendar-value-required": "Storage format is required",
2491
2800
  "field-disable-date": "Disabled date expression",
2492
2801
  "field-disable-date-placeholder": "Return true to disable the date",
2802
+ "field-upload-accept": "Accepted file types",
2803
+ "field-upload-accept-placeholder": "None selected",
2804
+ "field-upload-accept-selected": "selected",
2805
+ "field-upload-description": "Upload description",
2806
+ "field-upload-max-count": "Max file count",
2807
+ "field-upload-max-count-placeholder": "For example 5",
2493
2808
  "field-validation": "Validation rules",
2494
2809
  "field-validation-description": "Rules run on blur in order and stop at the first failure.",
2495
2810
  "add-validation-rule": "Add rule",