@shwfed/nuxt 0.11.49 → 0.11.51

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 (30) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/runtime/components/button.d.vue.ts +8 -0
  3. package/dist/runtime/components/button.vue.d.ts +8 -0
  4. package/dist/runtime/components/fields.d.vue.ts +850 -6
  5. package/dist/runtime/components/fields.vue +0 -2
  6. package/dist/runtime/components/fields.vue.d.ts +850 -6
  7. package/dist/runtime/components/ui/button-configurator/ButtonConfiguratorDialog.d.vue.ts +8 -0
  8. package/dist/runtime/components/ui/button-configurator/ButtonConfiguratorDialog.vue +137 -0
  9. package/dist/runtime/components/ui/button-configurator/ButtonConfiguratorDialog.vue.d.ts +8 -0
  10. package/dist/runtime/components/ui/button-configurator/menu.d.ts +2 -0
  11. package/dist/runtime/components/ui/button-configurator/menu.js +14 -0
  12. package/dist/runtime/components/ui/buttons/Buttons.d.vue.ts +8 -0
  13. package/dist/runtime/components/ui/buttons/Buttons.vue +42 -14
  14. package/dist/runtime/components/ui/buttons/Buttons.vue.d.ts +8 -0
  15. package/dist/runtime/components/ui/buttons/schema.d.ts +30 -0
  16. package/dist/runtime/components/ui/buttons/schema.js +5 -0
  17. package/dist/runtime/components/ui/fields/Fields.d.vue.ts +1698 -10
  18. package/dist/runtime/components/ui/fields/Fields.vue +627 -162
  19. package/dist/runtime/components/ui/fields/Fields.vue.d.ts +1698 -10
  20. package/dist/runtime/components/ui/fields/schema.d.ts +5625 -153
  21. package/dist/runtime/components/ui/fields/schema.js +83 -80
  22. package/dist/runtime/components/ui/fields-configurator/FieldsConfiguratorDialog.d.vue.ts +849 -5
  23. package/dist/runtime/components/ui/fields-configurator/FieldsConfiguratorDialog.vue +224 -618
  24. package/dist/runtime/components/ui/fields-configurator/FieldsConfiguratorDialog.vue.d.ts +849 -5
  25. package/package.json +1 -1
  26. package/dist/runtime/components/ui/fields/FieldsBody.d.vue.ts +0 -17
  27. package/dist/runtime/components/ui/fields/FieldsBody.vue +0 -720
  28. package/dist/runtime/components/ui/fields/FieldsBody.vue.d.ts +0 -17
  29. package/dist/runtime/components/ui/fields/render-context.d.ts +0 -120
  30. package/dist/runtime/components/ui/fields/render-context.js +0 -0
@@ -1,720 +0,0 @@
1
- <script setup>
2
- import { useNuxtApp } from "#app";
3
- import { getLocalTimeZone } from "@internationalized/date";
4
- import { Icon } from "@iconify/vue";
5
- import { format } from "date-fns";
6
- import { deleteProperty, getProperty, hasProperty, setProperty } from "dot-prop";
7
- import { useI18n } from "vue-i18n";
8
- import { RadioGroupIndicator, RadioGroupItem, RadioGroupRoot } from "reka-ui";
9
- import { getLocalizedText } from "../../../utils/coders";
10
- import { Calendar } from "../calendar";
11
- import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "../command";
12
- import { Field as UiField, FieldContent, FieldError, FieldLabel, FieldSet } from "../field";
13
- import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupNumberField, InputGroupTextarea } from "../input-group";
14
- import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from "../popover";
15
- import { Tooltip, TooltipContent, TooltipTrigger } from "../tooltip";
16
- defineOptions({
17
- name: "FieldsBody"
18
- });
19
- defineProps({
20
- body: { type: Object, required: true },
21
- renderer: { type: Object, required: true },
22
- applyStyle: { type: Boolean, required: false }
23
- });
24
- const slots = defineSlots();
25
- const { $md } = useNuxtApp();
26
- const { t, locale } = useI18n();
27
- function getContainerBody(field) {
28
- return {
29
- orientation: field.bodyOrientation,
30
- bordered: field.bodyBordered,
31
- style: field.bodyStyle,
32
- fields: field.fields,
33
- groups: []
34
- };
35
- }
36
- function requireSlotProps(slotProps) {
37
- if (!slotProps) {
38
- throw new TypeError("missing slot props");
39
- }
40
- return slotProps;
41
- }
42
- function hasVisibleTitle(field) {
43
- return "title" in field && Array.isArray(field.title) && field.title.length > 0;
44
- }
45
- </script>
46
-
47
- <template>
48
- <div
49
- data-slot="fields-body"
50
- :style="applyStyle ? renderer.getBodyStyle(body) : void 0"
51
- >
52
- <component
53
- :is="entry.group ? FieldSet : 'div'"
54
- v-for="entry in renderer.getBodyEntries(body)"
55
- :key="entry.key"
56
- :data-slot="entry.group ? 'fields-group' : 'fields-root-entry'"
57
- :data-group-id="entry.group?.id"
58
- :class="entry.group ? [
59
- renderer.isBodyBordered(body) ? 'overflow-hidden border border-zinc-200 [[data-slot=fields-group]+&]:border-t-0 [&>[data-slot=field]:last-child>[data-slot=field-label]]:border-b-0 [&>[data-slot=field]:last-child>[data-slot=field-content]]:border-r-0 [&>[data-slot=field]:last-child>[data-slot=field-content]]:border-b-0 [&>div:last-child]:border-r-0 [&>div:last-child]:border-b-0' : ''
60
- ] : void 0"
61
- :style="entry.group ? renderer.getGroupStyle(entry.group, body) : { display: 'contents' }"
62
- >
63
- <template
64
- v-for="field in entry.group ? entry.group.fields : entry.field ? [entry.field] : []"
65
- :key="field.id"
66
- >
67
- <div
68
- v-if="field.type === 'slot' && !hasVisibleTitle(field) && !renderer.isFieldHidden(field) && renderer.isBodyBordered(body)"
69
- class="border-b border-r border-zinc-200"
70
- :style="renderer.getFieldStyle(field)"
71
- >
72
- <slot
73
- :name="field.id"
74
- :form="renderer.slotForm"
75
- :style="{}"
76
- :valid="renderer.valid"
77
- />
78
- </div>
79
- <slot
80
- v-else-if="field.type === 'slot' && !hasVisibleTitle(field) && !renderer.isFieldHidden(field)"
81
- :name="field.id"
82
- :form="renderer.slotForm"
83
- :style="renderer.getFieldStyle(field)"
84
- :valid="renderer.valid"
85
- />
86
- <div
87
- v-else-if="field.type === 'empty'"
88
- :class="renderer.isBodyBordered(body) ? 'border-b border-r border-zinc-200' : void 0"
89
- :style="renderer.getFieldStyle(field)"
90
- />
91
- <UiField
92
- v-else-if="field.type === 'markdown' && !renderer.isFieldHidden(field)"
93
- :orientation="renderer.getBodyOrientation(body)"
94
- :style="renderer.getFieldContainerStyle(field, body)"
95
- >
96
- <FieldLabel
97
- v-if="!renderer.isFieldLabelHidden(field)"
98
- :class="renderer.isBodyBordered(body) ? 'border-b border-r border-zinc-200' : void 0"
99
- :style="renderer.getFieldLabelStyle(field, body)"
100
- >
101
- <span>{{ renderer.getDisplayFieldLabel(field) }}</span>
102
- </FieldLabel>
103
- <FieldContent
104
- :class="renderer.isBodyBordered(body) ? 'border-b border-r border-zinc-200 p-2 items-center justify-center text-center' : void 0"
105
- :style="renderer.getFieldContentStyle(field, body)"
106
- >
107
- <div
108
- class="text-center"
109
- data-slot="fields-markdown"
110
- v-html="renderer.renderMarkdownField(field)"
111
- />
112
- </FieldContent>
113
- </UiField>
114
- <UiField
115
- v-else-if="field.type === 'markdown-body' && !renderer.isFieldHidden(field)"
116
- :orientation="renderer.getBodyOrientation(body)"
117
- :style="renderer.getFieldContainerStyle(field, body)"
118
- >
119
- <FieldContent
120
- :class="renderer.isBodyBordered(body) ? 'border-b border-r border-zinc-200 p-2' : void 0"
121
- :style="renderer.getMarkdownBodyContentStyle(field, body)"
122
- >
123
- <div
124
- data-slot="fields-markdown-body"
125
- v-html="renderer.renderMarkdownBodyField(field)"
126
- />
127
- </FieldContent>
128
- </UiField>
129
- <UiField
130
- v-else-if="field.type === 'slot' && hasVisibleTitle(field) && !renderer.isFieldHidden(field)"
131
- :orientation="renderer.getBodyOrientation(body)"
132
- :style="renderer.getFieldContainerStyle(field, body)"
133
- >
134
- <FieldLabel
135
- v-if="!renderer.isFieldLabelHidden(field)"
136
- :class="renderer.isBodyBordered(body) ? 'border-b border-r border-zinc-200' : void 0"
137
- :style="renderer.getFieldLabelStyle(field, body)"
138
- >
139
- <span class="inline-flex items-start gap-0.5">
140
- <span>{{ renderer.getDisplayFieldLabel(field) }}</span>
141
- <sup
142
- v-if="renderer.isFieldRequired(field)"
143
- class="text-red-500 leading-none"
144
- >*</sup>
145
- </span>
146
- </FieldLabel>
147
- <FieldContent
148
- :class="renderer.isBodyBordered(body) ? 'border-b border-r border-zinc-200 p-2' : void 0"
149
- :style="renderer.getFieldContentStyle(field, body)"
150
- >
151
- <slot
152
- :name="field.id"
153
- :form="renderer.slotForm"
154
- :style="renderer.getFieldStyle(field)"
155
- :valid="renderer.valid"
156
- />
157
- </FieldContent>
158
- </UiField>
159
- <UiField
160
- v-else-if="field.type === 'container' && !renderer.isFieldHidden(field)"
161
- :orientation="renderer.getBodyOrientation(body)"
162
- >
163
- <FieldLabel
164
- v-if="!renderer.isFieldLabelHidden(field)"
165
- :class="renderer.isBodyBordered(body) ? 'border-b border-r border-zinc-200' : void 0"
166
- :style="renderer.getFieldLabelStyle(field, body)"
167
- >
168
- <span class="inline-flex items-start gap-0.5">
169
- <span>{{ renderer.getDisplayFieldLabel(field) }}</span>
170
- <sup
171
- v-if="renderer.isFieldRequired(field)"
172
- class="text-red-500 leading-none"
173
- >*</sup>
174
- </span>
175
- </FieldLabel>
176
- <FieldContent
177
- :class="renderer.isBodyBordered(body) ? 'border-b border-r border-zinc-200 p-2' : void 0"
178
- :style="renderer.getFieldContentStyle(field, body)"
179
- >
180
- <FieldsBody
181
- :body="getContainerBody(field)"
182
- :renderer="renderer"
183
- :apply-style="true"
184
- >
185
- <template
186
- v-for="(_, slotName) in slots"
187
- #[slotName]="slotProps"
188
- >
189
- <slot
190
- :name="slotName"
191
- v-bind="requireSlotProps(slotProps)"
192
- />
193
- </template>
194
- </FieldsBody>
195
- </FieldContent>
196
- </UiField>
197
- <UiField
198
- v-else-if="field.type === 'upload' && !renderer.isFieldHidden(field)"
199
- :data-disabled="renderer.isFieldDisabled(field) ? 'true' : void 0"
200
- :data-invalid="renderer.isFieldInvalid(field) ? 'true' : void 0"
201
- :orientation="renderer.getBodyOrientation(body)"
202
- :style="renderer.getFieldContainerStyle(field, body)"
203
- >
204
- <FieldLabel
205
- v-if="!renderer.isFieldLabelHidden(field)"
206
- :class="renderer.isBodyBordered(body) ? 'border-b border-r border-zinc-200' : void 0"
207
- :style="renderer.getFieldLabelStyle(field, body)"
208
- >
209
- <span class="inline-flex items-start gap-0.5">
210
- <span>{{ renderer.getFieldLabel(field) }}</span>
211
- <sup
212
- v-if="renderer.isFieldRequired(field)"
213
- class="text-red-500 leading-none"
214
- >*</sup>
215
- </span>
216
- <span v-if="renderer.isCheating">
217
- <span class="font-mono">{{ field.path }}</span>
218
- </span>
219
- </FieldLabel>
220
- <FieldContent
221
- :class="renderer.isBodyBordered(body) ? 'border-b border-r border-zinc-200 p-2' : void 0"
222
- :style="renderer.getFieldContentStyle(field, body)"
223
- >
224
- <div
225
- :data-disabled="renderer.isFieldDisabled(field) ? 'true' : void 0"
226
- class="flex flex-col gap-2"
227
- >
228
- <label
229
- v-if="renderer.getUploadFiles(field).length < renderer.getUploadMaxCount(field)"
230
- :class="[
231
- 'flex cursor-pointer flex-col items-center justify-center gap-3 rounded-lg border-2 border-dashed px-4 py-8 transition-colors',
232
- renderer.isFieldDisabled(field) ? 'cursor-not-allowed border-zinc-200 opacity-50' : 'border-zinc-300 hover:border-zinc-400 hover:bg-zinc-50'
233
- ]"
234
- @drop="renderer.handleUploadDrop(field, $event)"
235
- @dragover="renderer.handleUploadDragOver"
236
- >
237
- <Icon
238
- :icon="field.icon ?? 'fluent:cloud-arrow-up-20-regular'"
239
- class="text-4xl text-zinc-400"
240
- />
241
- <button
242
- v-if="field.template"
243
- type="button"
244
- class="inline-flex items-center gap-1.5 rounded-md border border-zinc-300 bg-white px-3 py-1.5 text-sm text-zinc-600 transition-colors hover:border-[--el-color-primary] hover:text-[--el-color-primary] disabled:opacity-50"
245
- :disabled="renderer.templateDownloading[field.id]"
246
- @click.prevent.stop="renderer.handleTemplateDownload(field)"
247
- >
248
- <Icon
249
- :icon="renderer.templateDownloading[field.id] ? 'svg-spinners:ring-resize' : renderer.getUploadTemplateIcon(field)"
250
- class="text-base"
251
- />
252
- {{ getLocalizedText(field.templateName, locale) ?? t("upload-download-template") }}
253
- </button>
254
- <p
255
- v-if="field.description"
256
- class="text-sm text-zinc-600"
257
- v-html="$md.inline`${getLocalizedText(field.description, locale) ?? ''}`()"
258
- />
259
- <p
260
- v-else
261
- class="text-sm text-zinc-600"
262
- >
263
- {{ t("upload-click-or-drag") }}
264
- </p>
265
- <p class="text-xs text-zinc-400">
266
- {{ renderer.getUploadDescription(field) || t("upload-accept-all") }}
267
- </p>
268
- <input
269
- type="file"
270
- class="sr-only"
271
- :accept="renderer.getUploadAcceptString(field)"
272
- :disabled="renderer.isFieldDisabled(field)"
273
- :multiple="renderer.getUploadMaxCount(field) !== 1"
274
- @change="renderer.handleUploadInputChange(field, $event)"
275
- >
276
- </label>
277
- <ul
278
- v-if="renderer.getUploadFiles(field).length > 0"
279
- class="flex flex-col gap-1"
280
- >
281
- <li
282
- v-for="(file, fileIndex) in renderer.getUploadFiles(field)"
283
- :key="`${field.id}:${fileIndex}:${file.name}`"
284
- class="flex items-center gap-2 rounded-md border border-zinc-200 px-3 py-2"
285
- >
286
- <Icon
287
- :icon="renderer.getFileIcon(file.name)"
288
- class="shrink-0 text-lg"
289
- />
290
- <span class="flex-1 truncate text-sm text-zinc-700">{{ file.name }}</span>
291
- <button
292
- type="button"
293
- class="shrink-0 text-zinc-300 transition-colors hover:text-red-500"
294
- :disabled="renderer.isFieldDisabled(field)"
295
- @click="renderer.removeUploadFile(field, fileIndex)"
296
- >
297
- <Icon
298
- icon="fluent:delete-20-regular"
299
- class="text-lg"
300
- />
301
- </button>
302
- </li>
303
- </ul>
304
- </div>
305
- <FieldError
306
- v-if="renderer.isFieldInvalid(field)"
307
- :class="renderer.getBodyOrientation(body) === 'contents' ? 'static pt-1' : void 0"
308
- >
309
- <span v-html="renderer.renderValidationMessage(field)" />
310
- </FieldError>
311
- </FieldContent>
312
- </UiField>
313
- <UiField
314
- v-else-if="renderer.isInteractiveField(field) && !renderer.isFieldHidden(field)"
315
- :data-disabled="renderer.isFieldDisabled(field) ? 'true' : void 0"
316
- :data-invalid="renderer.isFieldInvalid(field) ? 'true' : void 0"
317
- :orientation="renderer.getBodyOrientation(body)"
318
- :style="renderer.getFieldContainerStyle(field, body)"
319
- >
320
- <FieldLabel
321
- v-if="!renderer.isFieldLabelHidden(field)"
322
- :for="['string', 'textarea', 'number', 'select'].includes(field.type) ? `${renderer.id}:${field.path}` : void 0"
323
- :class="renderer.isBodyBordered(body) ? 'border-b border-r border-zinc-200' : void 0"
324
- :style="renderer.getFieldLabelStyle(field, body)"
325
- >
326
- <span class="inline-flex items-start gap-0.5">
327
- <span>{{ renderer.getFieldLabel(field) }}</span>
328
- <sup
329
- v-if="renderer.isFieldRequired(field)"
330
- class="text-red-500 leading-none"
331
- >*</sup>
332
- </span>
333
- <span v-if="renderer.isCheating">
334
- <span class="font-mono">{{ field.path }}</span>
335
- </span>
336
- </FieldLabel>
337
- <FieldContent
338
- :class="renderer.isBodyBordered(body) ? 'border-b border-r border-zinc-200 p-2' : void 0"
339
- :style="renderer.getFieldContentStyle(field, body)"
340
- >
341
- <Popover
342
- v-if="field.type === 'calendar'"
343
- @update:open="(open) => renderer.handleCalendarOpenChange(field, open)"
344
- >
345
- <PopoverAnchor as-child>
346
- <InputGroup :data-disabled="renderer.isFieldDisabled(field) ? 'true' : void 0">
347
- <PopoverTrigger as-child>
348
- <InputGroupInput
349
- :model-value="renderer.displayCalendarValue(getProperty(renderer.modelValue, field.path), field.display, field.value)"
350
- class="text-left"
351
- :disabled="renderer.isFieldDisabled(field)"
352
- :aria-invalid="renderer.isFieldInvalid(field) ? 'true' : void 0"
353
- readonly
354
- @blur="renderer.handleCalendarBlur(field)"
355
- />
356
- </PopoverTrigger>
357
- <InputGroupAddon v-if="field.icon">
358
- <Icon
359
- :icon="field.icon"
360
- />
361
- </InputGroupAddon>
362
- <InputGroupAddon
363
- v-if="hasProperty(renderer.modelValue, field.path)"
364
- align="inline-end"
365
- :class="renderer.getBodyOrientation(body) === 'floating' ? 'group-data-[disabled=true]/input-group:hidden' : void 0"
366
- >
367
- <Tooltip :delay-duration="800">
368
- <TooltipTrigger>
369
- <InputGroupButton as-child>
370
- <button
371
- type="button"
372
- class="text-zinc-300 hover:text-zinc-500 transition-colors"
373
- :disabled="renderer.isFieldDisabled(field)"
374
- @click="deleteProperty(renderer.modelValue, field.path)"
375
- >
376
- <Icon
377
- icon="fluent:dismiss-20-regular"
378
- />
379
- </button>
380
- </InputGroupButton>
381
- </TooltipTrigger>
382
- <TooltipContent>
383
- {{ t("clear") }}
384
- </TooltipContent>
385
- </Tooltip>
386
- </InputGroupAddon>
387
- </InputGroup>
388
- </PopoverAnchor>
389
- <PopoverContent class="w-72">
390
- <Calendar
391
- :locale="locale"
392
- :layout="field.mode"
393
- :model-value="renderer.toCalendarDateValue(getProperty(renderer.modelValue, field.path), field.value)"
394
- :disabled="renderer.isFieldDisabled(field)"
395
- :is-date-disabled="field.disableDate ? (date) => renderer.isCalendarDateDisabled(field, date) : void 0"
396
- @update:model-value="(value) => {
397
- if (value === void 0) {
398
- deleteProperty(renderer.modelValue, field.path);
399
- } else {
400
- setProperty(renderer.modelValue, field.path, format(value.toDate(getLocalTimeZone()), field.value));
401
- }
402
- }"
403
- />
404
- </PopoverContent>
405
- </Popover>
406
- <template v-else>
407
- <template v-if="field.type === 'select'">
408
- <Popover
409
- v-for="selectState in [renderer.getSelectFieldState(field)]"
410
- :key="`${field.id}:select:${selectState.selectedKey ?? 'empty'}`"
411
- :open="renderer.selectOpen[field.path] === true"
412
- @update:open="(open) => renderer.handleSelectOpenChange(field, open)"
413
- >
414
- <PopoverAnchor as-child>
415
- <InputGroup :data-disabled="renderer.isFieldDisabled(field) ? 'true' : void 0">
416
- <PopoverTrigger as-child>
417
- <InputGroupInput
418
- :id="`${renderer.id}:${field.path}`"
419
- :model-value="renderer.getSelectDisplayValue(selectState, selectState.selectedKey)"
420
- :disabled="renderer.isFieldDisabled(field)"
421
- :aria-invalid="renderer.isFieldInvalid(field) ? 'true' : void 0"
422
- :placeholder="t('select-placeholder')"
423
- class="text-left"
424
- readonly
425
- @blur="renderer.handleSelectBlur(field)"
426
- />
427
- </PopoverTrigger>
428
- <InputGroupAddon v-if="field.icon">
429
- <Icon
430
- :icon="field.icon"
431
- />
432
- </InputGroupAddon>
433
- <InputGroupAddon
434
- v-if="hasProperty(renderer.modelValue, field.path)"
435
- align="inline-end"
436
- :class="renderer.getBodyOrientation(body) === 'floating' ? 'group-data-[disabled=true]/input-group:hidden' : void 0"
437
- >
438
- <Tooltip :delay-duration="800">
439
- <TooltipTrigger>
440
- <InputGroupButton as-child>
441
- <button
442
- type="button"
443
- class="text-zinc-300 hover:text-zinc-500 transition-colors"
444
- :disabled="renderer.isFieldDisabled(field)"
445
- @click="renderer.clearSelectField(field)"
446
- >
447
- <Icon
448
- icon="fluent:dismiss-20-regular"
449
- />
450
- </button>
451
- </InputGroupButton>
452
- </TooltipTrigger>
453
- <TooltipContent>
454
- {{ t("clear") }}
455
- </TooltipContent>
456
- </Tooltip>
457
- </InputGroupAddon>
458
- </InputGroup>
459
- </PopoverAnchor>
460
-
461
- <PopoverContent
462
- class="p-0"
463
- :style="{ width: 'var(--reka-popover-trigger-width)' }"
464
- >
465
- <Command
466
- :model-value="selectState.selectedKey"
467
- :disabled="renderer.isFieldDisabled(field)"
468
- selection-behavior="toggle"
469
- @update:model-value="(value) => renderer.handleSelectCommandValueChange(field, selectState, value)"
470
- >
471
- <CommandInput :placeholder="t('select-search-placeholder')" />
472
- <CommandList>
473
- <CommandEmpty as-child>
474
- <section class="h-32 flex flex-col text-lg items-center justify-center gap-2 select-none">
475
- <Icon
476
- icon="fluent:app-recent-20-regular"
477
- class="text-zinc-400 text-2xl!"
478
- />
479
- <p class="text-zinc-500">
480
- {{ t("select-empty") }}
481
- </p>
482
- </section>
483
- </CommandEmpty>
484
- <CommandGroup>
485
- <CommandItem
486
- v-for="option in selectState.options"
487
- :key="option.key"
488
- data-slot="select-option"
489
- :value="option.key"
490
- class="data-highlighted:bg-zinc-50 data-highlighted:text-zinc-700 data-[state=checked]:bg-zinc-100 data-[state=checked]:text-zinc-700 transition cursor-pointer relative flex items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none"
491
- >
492
- {{ option.label }}
493
- </CommandItem>
494
- </CommandGroup>
495
- </CommandList>
496
- </Command>
497
- </PopoverContent>
498
- </Popover>
499
- </template>
500
-
501
- <template v-else-if="field.type === 'radio'">
502
- <RadioGroupRoot
503
- v-for="radioState in [renderer.getSelectFieldState(field)]"
504
- :key="`${field.id}:radio:${radioState.selectedKey ?? 'empty'}`"
505
- :model-value="radioState.selectedKey"
506
- :disabled="renderer.isFieldDisabled(field)"
507
- :aria-invalid="renderer.isFieldInvalid(field) ? 'true' : void 0"
508
- class="flex flex-wrap gap-x-4 gap-y-1.5"
509
- @update:model-value="(value) => renderer.handleSelectValueChange(field, radioState, value)"
510
- @focusout="renderer.validateField(field)"
511
- >
512
- <label
513
- v-for="option in radioState.options"
514
- :key="option.key"
515
- class="flex items-center gap-1.5 text-sm cursor-pointer data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50"
516
- :data-disabled="renderer.isFieldDisabled(field) ? 'true' : void 0"
517
- >
518
- <RadioGroupItem
519
- :value="option.key"
520
- data-slot="radio-group-item"
521
- class="size-4 rounded-full border border-zinc-300 data-[state=checked]:border-(--primary) data-[state=checked]:bg-(--primary) focus:outline-none focus-visible:ring-1 focus-visible:ring-(--primary) focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 transition-colors"
522
- >
523
- <RadioGroupIndicator class="flex items-center justify-center">
524
- <span class="size-1.5 rounded-full bg-white" />
525
- </RadioGroupIndicator>
526
- </RadioGroupItem>
527
- {{ option.label }}
528
- </label>
529
- </RadioGroupRoot>
530
- </template>
531
-
532
- <InputGroup
533
- v-else
534
- :data-disabled="renderer.isFieldDisabled(field) ? 'true' : void 0"
535
- :class="field.type === 'textarea' ? 'h-auto flex-col items-stretch' : void 0"
536
- >
537
- <div
538
- v-if="field.type === 'textarea'"
539
- class="flex min-w-0 w-full items-center"
540
- >
541
- <InputGroupTextarea
542
- :id="`${renderer.id}:${field.path}`"
543
- :model-value="getProperty(renderer.modelValue, field.path)"
544
- :maxlength="renderer.getFieldMaxLength(field)"
545
- :disabled="renderer.isFieldDisabled(field)"
546
- :aria-invalid="renderer.isFieldInvalid(field) ? 'true' : void 0"
547
- @update:model-value="(value) => {
548
- if (!value && !field.discardEmptyString) {
549
- deleteProperty(renderer.modelValue, field.path);
550
- } else {
551
- setProperty(renderer.modelValue, field.path, value);
552
- }
553
- }"
554
- @blur="renderer.validateField(field)"
555
- />
556
- <InputGroupAddon v-if="field.icon">
557
- <Icon
558
- :icon="field.icon"
559
- />
560
- </InputGroupAddon>
561
- </div>
562
- <InputGroupInput
563
- v-if="field.type === 'string'"
564
- :id="`${renderer.id}:${field.path}`"
565
- :treat-empty-as-different-state-from-null="!!field.discardEmptyString"
566
- :model-value="getProperty(renderer.modelValue, field.path)"
567
- :maxlength="renderer.getFieldMaxLength(field)"
568
- :disabled="renderer.isFieldDisabled(field)"
569
- :aria-invalid="renderer.isFieldInvalid(field) ? 'true' : void 0"
570
- @update:model-value="(value) => {
571
- if (!value && !field.discardEmptyString) {
572
- deleteProperty(renderer.modelValue, field.path);
573
- } else {
574
- setProperty(renderer.modelValue, field.path, value);
575
- }
576
- }"
577
- @blur="renderer.validateField(field)"
578
- />
579
- <InputGroupNumberField
580
- v-if="field.type === 'number'"
581
- :id="`${renderer.id}:${field.path}`"
582
- :model-value="getProperty(renderer.modelValue, field.path) ?? null"
583
- :min="renderer.getNumberFieldMin(field)"
584
- :max="renderer.getNumberFieldMax(field)"
585
- :step="renderer.getNumberFieldStep(field)"
586
- :disabled="renderer.isFieldDisabled(field)"
587
- :invalid="renderer.isFieldInvalid(field)"
588
- @update:model-value="(value) => {
589
- if (!value && value !== 0) {
590
- deleteProperty(renderer.modelValue, field.path);
591
- } else {
592
- setProperty(renderer.modelValue, field.path, value);
593
- }
594
- }"
595
- @blur="renderer.validateField(field)"
596
- />
597
- <InputGroupAddon v-if="field.type !== 'textarea' && field.icon">
598
- <Icon
599
- :icon="field.icon"
600
- />
601
- </InputGroupAddon>
602
- <InputGroupAddon
603
- v-if="field.type !== 'textarea' && hasProperty(renderer.modelValue, field.path)"
604
- align="inline-end"
605
- :class="renderer.getBodyOrientation(body) === 'floating' ? 'group-data-[disabled=true]/input-group:hidden' : void 0"
606
- >
607
- <Tooltip :delay-duration="800">
608
- <TooltipTrigger>
609
- <InputGroupButton as-child>
610
- <button
611
- type="button"
612
- class="text-zinc-300 hover:text-zinc-500 transition-colors"
613
- :disabled="renderer.isFieldDisabled(field)"
614
- @click="deleteProperty(renderer.modelValue, field.path)"
615
- >
616
- <Icon
617
- icon="fluent:dismiss-20-regular"
618
- />
619
- </button>
620
- </InputGroupButton>
621
- </TooltipTrigger>
622
- <TooltipContent>
623
- {{ t("clear") }}
624
- </TooltipContent>
625
- </Tooltip>
626
- </InputGroupAddon>
627
- <InputGroupAddon
628
- v-if="field.type === 'string' && field.maxLength && getProperty(renderer.modelValue, field.path)"
629
- align="inline-end"
630
- >
631
- <span class="text-xs text-zinc-400 font-mono">
632
- <span class="inline-block text-right">{{ String(getProperty(renderer.modelValue, field.path) ?? "").length }}</span>/{{ field.maxLength }}
633
- </span>
634
- </InputGroupAddon>
635
- <InputGroupAddon
636
- v-if="field.type === 'textarea' && (hasProperty(renderer.modelValue, field.path) || field.maxLength && getProperty(renderer.modelValue, field.path))"
637
- align="block-end"
638
- >
639
- <Tooltip
640
- v-if="hasProperty(renderer.modelValue, field.path)"
641
- :delay-duration="800"
642
- >
643
- <TooltipTrigger>
644
- <InputGroupButton as-child>
645
- <button
646
- type="button"
647
- class="text-zinc-300 hover:text-zinc-500 transition-colors"
648
- :disabled="renderer.isFieldDisabled(field)"
649
- @click="deleteProperty(renderer.modelValue, field.path)"
650
- >
651
- <Icon
652
- icon="fluent:dismiss-20-regular"
653
- />
654
- </button>
655
- </InputGroupButton>
656
- </TooltipTrigger>
657
- <TooltipContent>
658
- {{ t("clear") }}
659
- </TooltipContent>
660
- </Tooltip>
661
- <span
662
- v-if="field.maxLength && getProperty(renderer.modelValue, field.path)"
663
- class="text-xs text-zinc-400 font-mono"
664
- >
665
- <span class="inline-block text-right">{{ String(getProperty(renderer.modelValue, field.path) ?? "").length }}</span>/{{ field.maxLength }}
666
- </span>
667
- </InputGroupAddon>
668
- </InputGroup>
669
- </template>
670
-
671
- <FieldError
672
- v-if="renderer.isFieldInvalid(field)"
673
- :class="renderer.getBodyOrientation(body) === 'contents' ? 'static pt-1' : void 0"
674
- >
675
- <span v-html="renderer.renderValidationMessage(field)" />
676
- </FieldError>
677
- </FieldContent>
678
- </UiField>
679
- </template>
680
- </component>
681
- </div>
682
- </template>
683
-
684
- <i18n lang="json">
685
- {
686
- "zh": {
687
- "clear": "清空",
688
- "select-empty": "无搜索结果",
689
- "select-search-placeholder": "搜索…",
690
- "select-placeholder": "选择…",
691
- "upload-click-or-drag": "点击或拖拽文件到此处上传",
692
- "upload-accept-description": "仅接受 {formats} 格式文件",
693
- "upload-accept-or": "或",
694
- "upload-accept-all": "接受所有格式文件",
695
- "upload-download-template": "下载模板"
696
- },
697
- "ja": {
698
- "clear": "クリア",
699
- "select-empty": "検索結果がありません",
700
- "select-search-placeholder": "検索…",
701
- "select-placeholder": "選択…",
702
- "upload-click-or-drag": "クリックまたはドラッグしてアップロード",
703
- "upload-accept-description": "{formats} 形式のみアップロードできます",
704
- "upload-accept-or": "または",
705
- "upload-accept-all": "すべての形式を受け付けます",
706
- "upload-download-template": "テンプレートをダウンロード"
707
- },
708
- "en": {
709
- "clear": "Clear",
710
- "select-empty": "No search results",
711
- "select-search-placeholder": "Search…",
712
- "select-placeholder": "Select…",
713
- "upload-click-or-drag": "Click or drag files here to upload",
714
- "upload-accept-description": "Only {formats} files are accepted",
715
- "upload-accept-or": "or",
716
- "upload-accept-all": "All file formats are accepted",
717
- "upload-download-template": "Download template"
718
- }
719
- }
720
- </i18n>