@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.
- package/dist/module.json +1 -1
- package/dist/runtime/components/fields.d.vue.ts +78 -4
- package/dist/runtime/components/fields.vue +1 -0
- package/dist/runtime/components/fields.vue.d.ts +78 -4
- package/dist/runtime/components/ui/field/index.d.ts +1 -1
- package/dist/runtime/components/ui/field/index.js +6 -0
- package/dist/runtime/components/ui/fields/Fields.d.vue.ts +154 -6
- package/dist/runtime/components/ui/fields/Fields.vue +267 -12
- package/dist/runtime/components/ui/fields/Fields.vue.d.ts +154 -6
- package/dist/runtime/components/ui/fields/schema.d.ts +287 -0
- package/dist/runtime/components/ui/fields/schema.js +35 -7
- package/dist/runtime/components/ui/fields-configurator/FieldsConfiguratorDialog.d.vue.ts +76 -2
- package/dist/runtime/components/ui/fields-configurator/FieldsConfiguratorDialog.vue +320 -5
- package/dist/runtime/components/ui/fields-configurator/FieldsConfiguratorDialog.vue.d.ts +76 -2
- package/package.json +2 -1
|
@@ -57,6 +57,9 @@ function cloneConfig(config2) {
|
|
|
57
57
|
if (config2.orientation) {
|
|
58
58
|
nextConfig.orientation = config2.orientation;
|
|
59
59
|
}
|
|
60
|
+
if (config2.bordered) {
|
|
61
|
+
nextConfig.bordered = config2.bordered;
|
|
62
|
+
}
|
|
60
63
|
if (config2.style) {
|
|
61
64
|
nextConfig.style = config2.style;
|
|
62
65
|
}
|
|
@@ -65,6 +68,12 @@ function cloneConfig(config2) {
|
|
|
65
68
|
function getConfigOrientation(config2) {
|
|
66
69
|
return config2.orientation ?? "horizontal";
|
|
67
70
|
}
|
|
71
|
+
function usesContentsOrientation(config2) {
|
|
72
|
+
return getConfigOrientation(config2) === "contents";
|
|
73
|
+
}
|
|
74
|
+
function isConfigBordered(config2) {
|
|
75
|
+
return usesContentsOrientation(config2) && config2.bordered === true;
|
|
76
|
+
}
|
|
68
77
|
function tryEvaluateExpression(source, context) {
|
|
69
78
|
try {
|
|
70
79
|
return {
|
|
@@ -100,11 +109,11 @@ function getConfigStyle(config2) {
|
|
|
100
109
|
}
|
|
101
110
|
return style;
|
|
102
111
|
}
|
|
103
|
-
function
|
|
104
|
-
if (!
|
|
112
|
+
function getFieldPartStyle(styleExpression) {
|
|
113
|
+
if (!styleExpression) {
|
|
105
114
|
return {};
|
|
106
115
|
}
|
|
107
|
-
const style = evaluateExpression(
|
|
116
|
+
const style = evaluateExpression(styleExpression, void 0, {});
|
|
108
117
|
const normalizedStyle = {};
|
|
109
118
|
if (!style || typeof style !== "object" || Array.isArray(style)) {
|
|
110
119
|
return normalizedStyle;
|
|
@@ -116,6 +125,27 @@ function getFieldStyle(field) {
|
|
|
116
125
|
}
|
|
117
126
|
return normalizedStyle;
|
|
118
127
|
}
|
|
128
|
+
function getFieldStyle(field) {
|
|
129
|
+
return getFieldPartStyle(field.style);
|
|
130
|
+
}
|
|
131
|
+
function getFieldContainerStyle(field, config2) {
|
|
132
|
+
if (!isPassiveField(field) && usesContentsOrientation(config2)) {
|
|
133
|
+
return {};
|
|
134
|
+
}
|
|
135
|
+
return getFieldStyle(field);
|
|
136
|
+
}
|
|
137
|
+
function getFieldLabelStyle(field, config2) {
|
|
138
|
+
if (!usesContentsOrientation(config2)) {
|
|
139
|
+
return {};
|
|
140
|
+
}
|
|
141
|
+
return getFieldPartStyle(field.labelStyle);
|
|
142
|
+
}
|
|
143
|
+
function getFieldContentStyle(field, config2) {
|
|
144
|
+
if (!usesContentsOrientation(config2)) {
|
|
145
|
+
return {};
|
|
146
|
+
}
|
|
147
|
+
return getFieldPartStyle(field.contentStyle);
|
|
148
|
+
}
|
|
119
149
|
function isPassiveField(field) {
|
|
120
150
|
return field.type === "slot" || field.type === "empty";
|
|
121
151
|
}
|
|
@@ -158,6 +188,115 @@ function initializeFieldValues(config2) {
|
|
|
158
188
|
);
|
|
159
189
|
}
|
|
160
190
|
}
|
|
191
|
+
const MIME_LABELS = {
|
|
192
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "Excel",
|
|
193
|
+
"application/vnd.ms-excel": "Excel",
|
|
194
|
+
"application/x-zip-compressed": "ZIP",
|
|
195
|
+
"application/zip": "ZIP",
|
|
196
|
+
"application/pdf": "PDF",
|
|
197
|
+
"application/ofd": "OFD",
|
|
198
|
+
"application/xml": "XML",
|
|
199
|
+
"image/png": "\u56FE\u7247",
|
|
200
|
+
"image/jpg": "\u56FE\u7247",
|
|
201
|
+
"image/jpeg": "\u56FE\u7247",
|
|
202
|
+
"application/msword": "Word",
|
|
203
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "Word"
|
|
204
|
+
};
|
|
205
|
+
const FILE_EXTENSION_ICONS = {
|
|
206
|
+
xlsx: "vscode-icons:file-type-excel",
|
|
207
|
+
xls: "vscode-icons:file-type-excel",
|
|
208
|
+
csv: "vscode-icons:file-type-excel",
|
|
209
|
+
pdf: "vscode-icons:file-type-pdf2",
|
|
210
|
+
doc: "vscode-icons:file-type-word",
|
|
211
|
+
docx: "vscode-icons:file-type-word",
|
|
212
|
+
ppt: "vscode-icons:file-type-powerpoint",
|
|
213
|
+
pptx: "vscode-icons:file-type-powerpoint",
|
|
214
|
+
png: "vscode-icons:file-type-image",
|
|
215
|
+
jpg: "vscode-icons:file-type-image",
|
|
216
|
+
jpeg: "vscode-icons:file-type-image",
|
|
217
|
+
gif: "vscode-icons:file-type-image",
|
|
218
|
+
webp: "vscode-icons:file-type-image",
|
|
219
|
+
svg: "vscode-icons:file-type-svg",
|
|
220
|
+
txt: "vscode-icons:file-type-text",
|
|
221
|
+
json: "vscode-icons:file-type-json",
|
|
222
|
+
zip: "vscode-icons:file-type-zip"
|
|
223
|
+
};
|
|
224
|
+
function getFileIcon(filename) {
|
|
225
|
+
const ext = filename.split(".").pop()?.toLowerCase() ?? "";
|
|
226
|
+
return FILE_EXTENSION_ICONS[ext] ?? "vscode-icons:default-file";
|
|
227
|
+
}
|
|
228
|
+
function getUploadAcceptString(field) {
|
|
229
|
+
if (!field.accept || field.accept.length === 0) {
|
|
230
|
+
return void 0;
|
|
231
|
+
}
|
|
232
|
+
return field.accept.join(",");
|
|
233
|
+
}
|
|
234
|
+
function getUploadDescription(field) {
|
|
235
|
+
if (!field.accept || field.accept.length === 0) {
|
|
236
|
+
return "";
|
|
237
|
+
}
|
|
238
|
+
const uniqueLabels = [...new Set(field.accept.map((mime) => MIME_LABELS[mime] ?? mime))];
|
|
239
|
+
return t("upload-accept-description", { formats: uniqueLabels.join(` ${t("upload-accept-or")} `) });
|
|
240
|
+
}
|
|
241
|
+
function getUploadMaxCount(field) {
|
|
242
|
+
if (!field.maxCount) {
|
|
243
|
+
return Infinity;
|
|
244
|
+
}
|
|
245
|
+
const result = evaluateExpression(field.maxCount, { form: modelValue.value }, Infinity);
|
|
246
|
+
if (typeof result === "bigint") {
|
|
247
|
+
return Number(result);
|
|
248
|
+
}
|
|
249
|
+
return result;
|
|
250
|
+
}
|
|
251
|
+
function getUploadFiles(field) {
|
|
252
|
+
const raw = getProperty(modelValue.value, field.path);
|
|
253
|
+
if (!Array.isArray(raw)) {
|
|
254
|
+
return [];
|
|
255
|
+
}
|
|
256
|
+
return raw.filter((item) => item instanceof File);
|
|
257
|
+
}
|
|
258
|
+
function handleUploadInputChange(field, event) {
|
|
259
|
+
const target = event.target;
|
|
260
|
+
if (!(target instanceof HTMLInputElement)) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
handleUploadFiles(field, target.files);
|
|
264
|
+
target.value = "";
|
|
265
|
+
}
|
|
266
|
+
function handleUploadFiles(field, fileList) {
|
|
267
|
+
if (!fileList || fileList.length === 0) {
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
const existing = getUploadFiles(field);
|
|
271
|
+
const maxCount = getUploadMaxCount(field);
|
|
272
|
+
const remaining = maxCount === Infinity ? fileList.length : Math.max(0, maxCount - existing.length);
|
|
273
|
+
const incoming = Array.from(fileList).slice(0, remaining);
|
|
274
|
+
const next = [...existing, ...incoming];
|
|
275
|
+
if (next.length === 0) {
|
|
276
|
+
deleteProperty(modelValue.value, field.path);
|
|
277
|
+
} else {
|
|
278
|
+
setProperty(modelValue.value, field.path, next);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
function removeUploadFile(field, index) {
|
|
282
|
+
const files = getUploadFiles(field);
|
|
283
|
+
const next = files.filter((_, i) => i !== index);
|
|
284
|
+
if (next.length === 0) {
|
|
285
|
+
deleteProperty(modelValue.value, field.path);
|
|
286
|
+
} else {
|
|
287
|
+
setProperty(modelValue.value, field.path, next);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
function handleUploadDrop(field, event) {
|
|
291
|
+
event.preventDefault();
|
|
292
|
+
if (isFieldDisabled(field)) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
handleUploadFiles(field, event.dataTransfer?.files ?? null);
|
|
296
|
+
}
|
|
297
|
+
function handleUploadDragOver(event) {
|
|
298
|
+
event.preventDefault();
|
|
299
|
+
}
|
|
161
300
|
function stringifySelectValue(value) {
|
|
162
301
|
try {
|
|
163
302
|
return JSON.stringify(value);
|
|
@@ -437,6 +576,7 @@ export {
|
|
|
437
576
|
SlotFieldC,
|
|
438
577
|
SUPPORTED_COMPATIBILITY_DATES,
|
|
439
578
|
StringFieldC,
|
|
579
|
+
UploadFieldC,
|
|
440
580
|
ValidationRuleC,
|
|
441
581
|
createFieldsConfig,
|
|
442
582
|
validationC
|
|
@@ -447,7 +587,8 @@ export {
|
|
|
447
587
|
<div
|
|
448
588
|
:class="[
|
|
449
589
|
'relative p-1 -m-1 border border-dashed',
|
|
450
|
-
isCheating ? 'border-(--primary)/20 rounded hover:border-(--primary)/40 transition-colors duration-150 group cursor-pointer' : 'border-transparent'
|
|
590
|
+
isCheating ? 'border-(--primary)/20 rounded hover:border-(--primary)/40 transition-colors duration-150 group cursor-pointer' : 'border-transparent',
|
|
591
|
+
isConfigBordered(displayConfig) ? '!p-0 !m-0 border-solid border-zinc-200' : ''
|
|
451
592
|
]"
|
|
452
593
|
:style="getConfigStyle(displayConfig)"
|
|
453
594
|
>
|
|
@@ -479,8 +620,20 @@ export {
|
|
|
479
620
|
v-for="field in displayConfig.fields"
|
|
480
621
|
:key="field.id"
|
|
481
622
|
>
|
|
623
|
+
<div
|
|
624
|
+
v-if="field.type === 'slot' && isConfigBordered(displayConfig)"
|
|
625
|
+
:class="'border-b border-r border-zinc-200'"
|
|
626
|
+
:style="getFieldStyle(field)"
|
|
627
|
+
>
|
|
628
|
+
<slot
|
|
629
|
+
:name="field.id"
|
|
630
|
+
:form="slotForm"
|
|
631
|
+
:style="{}"
|
|
632
|
+
:valid="valid"
|
|
633
|
+
/>
|
|
634
|
+
</div>
|
|
482
635
|
<slot
|
|
483
|
-
v-if="field.type === 'slot'"
|
|
636
|
+
v-else-if="field.type === 'slot'"
|
|
484
637
|
:name="field.id"
|
|
485
638
|
:form="slotForm"
|
|
486
639
|
:style="getFieldStyle(field)"
|
|
@@ -488,16 +641,100 @@ export {
|
|
|
488
641
|
/>
|
|
489
642
|
<div
|
|
490
643
|
v-else-if="field.type === 'empty'"
|
|
644
|
+
:class="isConfigBordered(displayConfig) ? 'border-b border-r border-zinc-200' : void 0"
|
|
491
645
|
:style="getFieldStyle(field)"
|
|
492
646
|
/>
|
|
647
|
+
<div
|
|
648
|
+
v-else-if="field.type === 'upload' && !isFieldHidden(field)"
|
|
649
|
+
:data-disabled="isFieldDisabled(field) ? 'true' : void 0"
|
|
650
|
+
:style="getFieldContainerStyle(field, displayConfig)"
|
|
651
|
+
class="flex flex-col gap-2 p-2"
|
|
652
|
+
>
|
|
653
|
+
<p class="text-sm font-medium text-zinc-700">
|
|
654
|
+
<span class="inline-flex items-start gap-0.5">
|
|
655
|
+
<span>{{ getFieldLabel(field) }}</span>
|
|
656
|
+
<sup
|
|
657
|
+
v-if="isFieldRequired(field)"
|
|
658
|
+
class="text-red-500 leading-none"
|
|
659
|
+
>*</sup>
|
|
660
|
+
</span>
|
|
661
|
+
</p>
|
|
662
|
+
<label
|
|
663
|
+
v-if="getUploadFiles(field).length < getUploadMaxCount(field)"
|
|
664
|
+
:class="[
|
|
665
|
+
'flex cursor-pointer flex-col items-center justify-center gap-3 rounded-lg border-2 border-dashed px-4 py-8 transition-colors',
|
|
666
|
+
isFieldDisabled(field) ? 'cursor-not-allowed border-zinc-200 opacity-50' : 'border-zinc-300 hover:border-zinc-400 hover:bg-zinc-50'
|
|
667
|
+
]"
|
|
668
|
+
@drop="handleUploadDrop(field, $event)"
|
|
669
|
+
@dragover="handleUploadDragOver"
|
|
670
|
+
>
|
|
671
|
+
<Icon
|
|
672
|
+
:icon="field.icon ?? 'fluent:cloud-arrow-up-20-regular'"
|
|
673
|
+
class="text-4xl text-zinc-400"
|
|
674
|
+
/>
|
|
675
|
+
<p
|
|
676
|
+
v-if="field.description"
|
|
677
|
+
class="text-sm text-zinc-600"
|
|
678
|
+
v-html="$md.inline`${getLocalizedText(field.description, locale) ?? ''}`()"
|
|
679
|
+
/>
|
|
680
|
+
<p
|
|
681
|
+
v-else
|
|
682
|
+
class="text-sm text-zinc-600"
|
|
683
|
+
>
|
|
684
|
+
{{ t("upload-click-or-drag") }}
|
|
685
|
+
</p>
|
|
686
|
+
<p class="text-xs text-zinc-400">
|
|
687
|
+
{{ getUploadDescription(field) || t("upload-accept-all") }}
|
|
688
|
+
</p>
|
|
689
|
+
<input
|
|
690
|
+
type="file"
|
|
691
|
+
class="sr-only"
|
|
692
|
+
:accept="getUploadAcceptString(field)"
|
|
693
|
+
:disabled="isFieldDisabled(field)"
|
|
694
|
+
:multiple="getUploadMaxCount(field) !== 1"
|
|
695
|
+
@change="handleUploadInputChange(field, $event)"
|
|
696
|
+
>
|
|
697
|
+
</label>
|
|
698
|
+
<ul
|
|
699
|
+
v-if="getUploadFiles(field).length > 0"
|
|
700
|
+
class="flex flex-col gap-1"
|
|
701
|
+
>
|
|
702
|
+
<li
|
|
703
|
+
v-for="(file, fileIndex) in getUploadFiles(field)"
|
|
704
|
+
:key="`${field.id}:${fileIndex}:${file.name}`"
|
|
705
|
+
class="flex items-center gap-2 rounded-md border border-zinc-200 px-3 py-2"
|
|
706
|
+
>
|
|
707
|
+
<Icon
|
|
708
|
+
:icon="getFileIcon(file.name)"
|
|
709
|
+
class="shrink-0 text-lg"
|
|
710
|
+
/>
|
|
711
|
+
<span class="flex-1 truncate text-sm text-zinc-700">{{ file.name }}</span>
|
|
712
|
+
<button
|
|
713
|
+
type="button"
|
|
714
|
+
class="shrink-0 text-zinc-300 transition-colors hover:text-red-500"
|
|
715
|
+
:disabled="isFieldDisabled(field)"
|
|
716
|
+
@click="removeUploadFile(field, fileIndex)"
|
|
717
|
+
>
|
|
718
|
+
<Icon
|
|
719
|
+
icon="fluent:delete-20-regular"
|
|
720
|
+
class="text-lg"
|
|
721
|
+
/>
|
|
722
|
+
</button>
|
|
723
|
+
</li>
|
|
724
|
+
</ul>
|
|
725
|
+
</div>
|
|
493
726
|
<Field
|
|
494
727
|
v-else-if="!isFieldHidden(field)"
|
|
495
728
|
:data-disabled="isFieldDisabled(field) ? 'true' : void 0"
|
|
496
729
|
:data-invalid="isFieldInvalid(field) ? 'true' : void 0"
|
|
497
730
|
:orientation="getConfigOrientation(displayConfig)"
|
|
498
|
-
:style="
|
|
731
|
+
:style="getFieldContainerStyle(field, displayConfig)"
|
|
499
732
|
>
|
|
500
|
-
<FieldLabel
|
|
733
|
+
<FieldLabel
|
|
734
|
+
:for="['string', 'textarea', 'number', 'select'].includes(field.type) ? `${id}:${field.path}` : void 0"
|
|
735
|
+
:class="isConfigBordered(displayConfig) ? 'border-b border-r border-zinc-200' : void 0"
|
|
736
|
+
:style="getFieldLabelStyle(field, displayConfig)"
|
|
737
|
+
>
|
|
501
738
|
<span class="inline-flex items-start gap-0.5">
|
|
502
739
|
<span>{{ getFieldLabel(field) }}</span>
|
|
503
740
|
<sup
|
|
@@ -509,7 +746,10 @@ export {
|
|
|
509
746
|
<span class="font-mono">{{ field.path }}</span>
|
|
510
747
|
</span>
|
|
511
748
|
</FieldLabel>
|
|
512
|
-
<FieldContent
|
|
749
|
+
<FieldContent
|
|
750
|
+
:class="isConfigBordered(displayConfig) ? 'border-b border-r border-zinc-200 p-2' : void 0"
|
|
751
|
+
:style="getFieldContentStyle(field, displayConfig)"
|
|
752
|
+
>
|
|
513
753
|
<Popover
|
|
514
754
|
v-if="field.type === 'calendar'"
|
|
515
755
|
@update:open="(open) => handleCalendarOpenChange(field, open)"
|
|
@@ -809,7 +1049,10 @@ export {
|
|
|
809
1049
|
</InputGroup>
|
|
810
1050
|
</template>
|
|
811
1051
|
|
|
812
|
-
<FieldError
|
|
1052
|
+
<FieldError
|
|
1053
|
+
v-if="isFieldInvalid(field)"
|
|
1054
|
+
:class="usesContentsOrientation(displayConfig) ? 'static pt-1' : void 0"
|
|
1055
|
+
>
|
|
813
1056
|
<span v-html="renderValidationMessage(field)" />
|
|
814
1057
|
</FieldError>
|
|
815
1058
|
</FieldContent>
|
|
@@ -826,19 +1069,31 @@ export {
|
|
|
826
1069
|
"clear": "清空",
|
|
827
1070
|
"select-empty": "无搜索结果",
|
|
828
1071
|
"select-search-placeholder": "搜索…",
|
|
829
|
-
"select-placeholder": "选择…"
|
|
1072
|
+
"select-placeholder": "选择…",
|
|
1073
|
+
"upload-click-or-drag": "点击或拖拽文件到此处上传",
|
|
1074
|
+
"upload-accept-description": "仅接受 {formats} 格式文件",
|
|
1075
|
+
"upload-accept-or": "或",
|
|
1076
|
+
"upload-accept-all": "接受所有格式文件"
|
|
830
1077
|
},
|
|
831
1078
|
"ja": {
|
|
832
1079
|
"clear": "クリア",
|
|
833
1080
|
"select-empty": "結果はありません",
|
|
834
1081
|
"select-search-placeholder": "検索…",
|
|
835
|
-
"select-placeholder": "選択…"
|
|
1082
|
+
"select-placeholder": "選択…",
|
|
1083
|
+
"upload-click-or-drag": "クリックまたはファイルをここにドラッグしてアップロード",
|
|
1084
|
+
"upload-accept-description": "{formats} 形式のファイルのみ受け付けます",
|
|
1085
|
+
"upload-accept-or": "または",
|
|
1086
|
+
"upload-accept-all": "すべての形式を受け付けます"
|
|
836
1087
|
},
|
|
837
1088
|
"en": {
|
|
838
1089
|
"clear": "Clear",
|
|
839
1090
|
"select-empty": "No results",
|
|
840
1091
|
"select-search-placeholder": "Search…",
|
|
841
|
-
"select-placeholder": "Select…"
|
|
1092
|
+
"select-placeholder": "Select…",
|
|
1093
|
+
"upload-click-or-drag": "Click or drag files here to upload",
|
|
1094
|
+
"upload-accept-description": "Only {formats} format files accepted",
|
|
1095
|
+
"upload-accept-or": "or",
|
|
1096
|
+
"upload-accept-all": "All formats accepted"
|
|
842
1097
|
}
|
|
843
1098
|
}
|
|
844
1099
|
</i18n>
|