@shwfed/config 2.9.7 → 2.9.9
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/mcp.mjs +1054 -855
- package/dist/module.json +1 -1
- package/dist/preview/assets/{FieldGroup.vue_vue_type_script_setup_true_lang-tkU7rYrs.js → FieldGroup.vue_vue_type_script_setup_true_lang-CdbT3cSj.js} +1 -1
- package/dist/preview/assets/{badge-C55P2V8D.js → badge-DL-wtgr8.js} +1 -1
- package/dist/preview/assets/{config-DeaHg7ps.js → config-80OJWswM.js} +1 -1
- package/dist/preview/assets/{config-D0j4njOQ.js → config-B8F7X1oF.js} +1 -1
- package/dist/preview/assets/{config-rL7m78ZC.js → config-B9BcmOZt.js} +1 -1
- package/dist/preview/assets/{config-Bc2N2jlD.js → config-C-Ta4ALL.js} +1 -1
- package/dist/preview/assets/{config-DqibnZH4.js → config-C8R7tsmC.js} +1 -1
- package/dist/preview/assets/{config-CnxzerC5.js → config-CoObmLL2.js} +1 -1
- package/dist/preview/assets/{config-Bu1S_DR5.js → config-DBQ-1J66.js} +1 -1
- package/dist/preview/assets/{config-CH2QpakU.js → config-DVk8b1Qf.js} +1 -1
- package/dist/preview/assets/{config-DzKcQKJj.js → config-DjsQoLiy.js} +1 -1
- package/dist/preview/assets/{config-j1oKH3Ci.js → config-RmdB0dwp.js} +1 -1
- package/dist/preview/assets/{config-B3-xqMew.js → config-h_hDvpHt.js} +1 -1
- package/dist/preview/assets/{definition.vue_vue_type_script_setup_true_lang-G748uLwi.js → definition.vue_vue_type_script_setup_true_lang-SX94Z692.js} +1 -1
- package/dist/preview/assets/index-BIwwDhfa.js +1 -0
- package/dist/preview/assets/index-C1h9lV52.css +1 -0
- package/dist/preview/assets/index-CsN0336H.js +717 -0
- package/dist/preview/assets/{index-dIh1Jn4U.js → index-Df0XE7Lz.js} +1 -1
- package/dist/preview/assets/{item-BCWcrKaL.js → item-B9XcOWjy.js} +1 -1
- package/dist/preview/assets/{runtime-CBg0VVCJ.js → runtime-BBsXfAZm.js} +1 -1
- package/dist/preview/assets/{runtime-D3LGPlv3.js → runtime-BHlUDfbv.js} +1 -1
- package/dist/preview/assets/{runtime-BTFesnrJ.js → runtime-BrwIgXY3.js} +1 -1
- package/dist/preview/assets/{runtime-zoq6YaMz.js → runtime-C--WPQ3o.js} +1 -1
- package/dist/preview/assets/{runtime-BsqCaddm.js → runtime-C0yBdMlV.js} +1 -1
- package/dist/preview/assets/{runtime-C-KLJ71q.js → runtime-C6uebSDU.js} +1 -1
- package/dist/preview/assets/{runtime-DZiqhnCm.js → runtime-DU0iHs9-.js} +1 -1
- package/dist/preview/assets/{runtime-bRCsEM7S.js → runtime-Dqa4phvv.js} +1 -1
- package/dist/preview/assets/{runtime-C5-cN3M1.js → runtime-Dr-MmEyE.js} +1 -1
- package/dist/preview/assets/{runtime-DO8ov3J6.js → runtime-v_nJoD5I.js} +1 -1
- package/dist/preview/index.html +2 -2
- package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json/schema.d.ts +1 -1
- package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json/schema.js +2 -2
- package/dist/runtime/components/actions/buttons/2026-06-08/com.shwfed.actions.button.http.request.json.batch/schema.d.ts +1 -1
- package/dist/runtime/components/actions/buttons/2026-06-08/com.shwfed.actions.button.http.request.json.batch/schema.js +1 -1
- package/dist/runtime/components/block-layout-editor/index.vue +98 -3
- package/dist/runtime/components/config/footer.vue +22 -20
- package/dist/runtime/components/config/use-editor.js +5 -9
- package/dist/runtime/components/config/utils/validation-error.d.ts +1 -0
- package/dist/runtime/components/config/utils/validation-error.js +34 -0
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.d.vue.ts +4 -4
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.vue.d.ts +4 -4
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.d.vue.ts +6 -6
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.vue.d.ts +6 -6
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/config.d.vue.ts +2 -2
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/config.vue.d.ts +2 -2
- package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.monthrange/config.d.vue.ts +4 -4
- package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.monthrange/config.vue.d.ts +4 -4
- package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/config.d.vue.ts +155 -0
- package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/config.vue +918 -0
- package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/config.vue.d.ts +155 -0
- package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/runtime.d.vue.ts +8 -0
- package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/runtime.vue +482 -0
- package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/runtime.vue.d.ts +8 -0
- package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/schema.d.ts +126 -0
- package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/schema.js +178 -0
- package/dist/runtime/components/table/columns/2026-04-14/com.shwfed.table.column.markdown/runtime.vue +1 -1
- package/dist/runtime/components/ui/date-picker/DatePickerInput.d.vue.ts +1 -1
- package/dist/runtime/components/ui/date-picker/DatePickerInput.vue.d.ts +1 -1
- package/dist/runtime/components/ui/date-picker/DatePickerTimeInput.d.vue.ts +1 -1
- package/dist/runtime/components/ui/date-picker/DatePickerTimeInput.vue.d.ts +1 -1
- package/dist/runtime/components/ui/date-range-picker/DateRangePickerInput.d.vue.ts +1 -1
- package/dist/runtime/components/ui/date-range-picker/DateRangePickerInput.vue.d.ts +1 -1
- package/dist/runtime/components/ui/date-range-picker/DateRangePickerTimeInput.d.vue.ts +2 -2
- package/dist/runtime/components/ui/date-range-picker/DateRangePickerTimeInput.vue.d.ts +2 -2
- package/dist/runtime/vendor/cel-js/CLAUDE.md +1 -1
- package/dist/runtime/vendor/cel-js/PROMPT.md +2 -2
- package/dist/runtime/vendor/cel-js/lib/http-builder.js +13 -3
- package/package.json +1 -1
- package/dist/preview/assets/index-C16exop7.js +0 -717
- package/dist/preview/assets/index-CSm6dB4o.js +0 -1
- package/dist/preview/assets/index-vPcvbp7e.css +0 -1
package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/config.vue.d.ts
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { type Value } from './schema.js';
|
|
2
|
+
type __VLS_ModelProps = {
|
|
3
|
+
modelValue: Value;
|
|
4
|
+
};
|
|
5
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
6
|
+
"update:modelValue": (value: {
|
|
7
|
+
readonly label?: readonly [{
|
|
8
|
+
readonly locale: "zh";
|
|
9
|
+
readonly message: string;
|
|
10
|
+
}, ...{
|
|
11
|
+
readonly locale: "en" | "ja" | "ko";
|
|
12
|
+
readonly message: string;
|
|
13
|
+
}[]] | undefined;
|
|
14
|
+
readonly disabled?: string | undefined;
|
|
15
|
+
readonly type: "com.shwfed.form.field.upload";
|
|
16
|
+
readonly id: string;
|
|
17
|
+
readonly hidden?: string | undefined;
|
|
18
|
+
readonly tooltip?: readonly [{
|
|
19
|
+
readonly locale: "zh";
|
|
20
|
+
readonly message: string;
|
|
21
|
+
}, ...{
|
|
22
|
+
readonly locale: "en" | "ja" | "ko";
|
|
23
|
+
readonly message: string;
|
|
24
|
+
}[]] | undefined;
|
|
25
|
+
readonly multiple?: boolean | undefined;
|
|
26
|
+
readonly description?: readonly [{
|
|
27
|
+
readonly locale: "zh";
|
|
28
|
+
readonly message: string;
|
|
29
|
+
}, ...{
|
|
30
|
+
readonly locale: "en" | "ja" | "ko";
|
|
31
|
+
readonly message: string;
|
|
32
|
+
}[]] | undefined;
|
|
33
|
+
readonly required?: string | undefined;
|
|
34
|
+
readonly displayName?: string | undefined;
|
|
35
|
+
readonly compatibilityDate: "2026-06-09";
|
|
36
|
+
readonly orientation?: "vertical" | "floating" | undefined;
|
|
37
|
+
readonly placeholder?: readonly [{
|
|
38
|
+
readonly locale: "zh";
|
|
39
|
+
readonly message: string;
|
|
40
|
+
}, ...{
|
|
41
|
+
readonly locale: "en" | "ja" | "ko";
|
|
42
|
+
readonly message: string;
|
|
43
|
+
}[]] | undefined;
|
|
44
|
+
readonly readonly?: string | undefined;
|
|
45
|
+
readonly binding?: string | undefined;
|
|
46
|
+
readonly validations?: readonly {
|
|
47
|
+
readonly message: readonly [{
|
|
48
|
+
readonly locale: "zh";
|
|
49
|
+
readonly message: string;
|
|
50
|
+
}, ...{
|
|
51
|
+
readonly locale: "en" | "ja" | "ko";
|
|
52
|
+
readonly message: string;
|
|
53
|
+
}[]];
|
|
54
|
+
readonly warning?: boolean | undefined;
|
|
55
|
+
readonly when: string;
|
|
56
|
+
}[] | undefined;
|
|
57
|
+
readonly accept?: readonly string[] | undefined;
|
|
58
|
+
readonly maxFileSize?: number | undefined;
|
|
59
|
+
readonly maxTotalSize?: number | undefined;
|
|
60
|
+
readonly maxFiles?: number | undefined;
|
|
61
|
+
readonly upload?: {
|
|
62
|
+
readonly handle: string;
|
|
63
|
+
readonly request: string;
|
|
64
|
+
readonly filename?: string | undefined;
|
|
65
|
+
} | undefined;
|
|
66
|
+
readonly templates?: readonly {
|
|
67
|
+
readonly label?: readonly [{
|
|
68
|
+
readonly locale: "zh";
|
|
69
|
+
readonly message: string;
|
|
70
|
+
}, ...{
|
|
71
|
+
readonly locale: "en" | "ja" | "ko";
|
|
72
|
+
readonly message: string;
|
|
73
|
+
}[]] | undefined;
|
|
74
|
+
readonly icon?: string | undefined;
|
|
75
|
+
readonly download?: string | undefined;
|
|
76
|
+
readonly request: string;
|
|
77
|
+
}[] | undefined;
|
|
78
|
+
}) => any;
|
|
79
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
|
|
80
|
+
"onUpdate:modelValue"?: ((value: {
|
|
81
|
+
readonly label?: readonly [{
|
|
82
|
+
readonly locale: "zh";
|
|
83
|
+
readonly message: string;
|
|
84
|
+
}, ...{
|
|
85
|
+
readonly locale: "en" | "ja" | "ko";
|
|
86
|
+
readonly message: string;
|
|
87
|
+
}[]] | undefined;
|
|
88
|
+
readonly disabled?: string | undefined;
|
|
89
|
+
readonly type: "com.shwfed.form.field.upload";
|
|
90
|
+
readonly id: string;
|
|
91
|
+
readonly hidden?: string | undefined;
|
|
92
|
+
readonly tooltip?: readonly [{
|
|
93
|
+
readonly locale: "zh";
|
|
94
|
+
readonly message: string;
|
|
95
|
+
}, ...{
|
|
96
|
+
readonly locale: "en" | "ja" | "ko";
|
|
97
|
+
readonly message: string;
|
|
98
|
+
}[]] | undefined;
|
|
99
|
+
readonly multiple?: boolean | undefined;
|
|
100
|
+
readonly description?: readonly [{
|
|
101
|
+
readonly locale: "zh";
|
|
102
|
+
readonly message: string;
|
|
103
|
+
}, ...{
|
|
104
|
+
readonly locale: "en" | "ja" | "ko";
|
|
105
|
+
readonly message: string;
|
|
106
|
+
}[]] | undefined;
|
|
107
|
+
readonly required?: string | undefined;
|
|
108
|
+
readonly displayName?: string | undefined;
|
|
109
|
+
readonly compatibilityDate: "2026-06-09";
|
|
110
|
+
readonly orientation?: "vertical" | "floating" | undefined;
|
|
111
|
+
readonly placeholder?: readonly [{
|
|
112
|
+
readonly locale: "zh";
|
|
113
|
+
readonly message: string;
|
|
114
|
+
}, ...{
|
|
115
|
+
readonly locale: "en" | "ja" | "ko";
|
|
116
|
+
readonly message: string;
|
|
117
|
+
}[]] | undefined;
|
|
118
|
+
readonly readonly?: string | undefined;
|
|
119
|
+
readonly binding?: string | undefined;
|
|
120
|
+
readonly validations?: readonly {
|
|
121
|
+
readonly message: readonly [{
|
|
122
|
+
readonly locale: "zh";
|
|
123
|
+
readonly message: string;
|
|
124
|
+
}, ...{
|
|
125
|
+
readonly locale: "en" | "ja" | "ko";
|
|
126
|
+
readonly message: string;
|
|
127
|
+
}[]];
|
|
128
|
+
readonly warning?: boolean | undefined;
|
|
129
|
+
readonly when: string;
|
|
130
|
+
}[] | undefined;
|
|
131
|
+
readonly accept?: readonly string[] | undefined;
|
|
132
|
+
readonly maxFileSize?: number | undefined;
|
|
133
|
+
readonly maxTotalSize?: number | undefined;
|
|
134
|
+
readonly maxFiles?: number | undefined;
|
|
135
|
+
readonly upload?: {
|
|
136
|
+
readonly handle: string;
|
|
137
|
+
readonly request: string;
|
|
138
|
+
readonly filename?: string | undefined;
|
|
139
|
+
} | undefined;
|
|
140
|
+
readonly templates?: readonly {
|
|
141
|
+
readonly label?: readonly [{
|
|
142
|
+
readonly locale: "zh";
|
|
143
|
+
readonly message: string;
|
|
144
|
+
}, ...{
|
|
145
|
+
readonly locale: "en" | "ja" | "ko";
|
|
146
|
+
readonly message: string;
|
|
147
|
+
}[]] | undefined;
|
|
148
|
+
readonly icon?: string | undefined;
|
|
149
|
+
readonly download?: string | undefined;
|
|
150
|
+
readonly request: string;
|
|
151
|
+
}[] | undefined;
|
|
152
|
+
}) => any) | undefined;
|
|
153
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
154
|
+
declare const _default: typeof __VLS_export;
|
|
155
|
+
export default _default;
|
package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/runtime.d.vue.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Value } from './schema.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
fieldId: string;
|
|
4
|
+
config: Value;
|
|
5
|
+
};
|
|
6
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
7
|
+
declare const _default: typeof __VLS_export;
|
|
8
|
+
export default _default;
|
package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/runtime.vue
ADDED
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { Icon } from "@iconify/vue";
|
|
3
|
+
import { Effect } from "effect";
|
|
4
|
+
import { Fetch } from "fx-fetch";
|
|
5
|
+
import { computed, ref } from "vue";
|
|
6
|
+
import { useI18n } from "vue-i18n";
|
|
7
|
+
import { toast } from "vue-sonner";
|
|
8
|
+
import { cel as _rawCel } from "../../../../../utils/cel";
|
|
9
|
+
import { celBindings, injectCELContext } from "../../../../../utils/cel-context";
|
|
10
|
+
import { getLocalizedText } from "../../../../../share/locale";
|
|
11
|
+
import { Button } from "../../../../ui/button";
|
|
12
|
+
import { Field, FieldLabel, FieldMessages } from "../../../../ui/field";
|
|
13
|
+
import { Markdown } from "../../../../ui/markdown";
|
|
14
|
+
import { DEFAULT_FIELD_ORIENTATION } from "../../../utils/common";
|
|
15
|
+
import { useFieldValidation } from "../../../utils/validation";
|
|
16
|
+
import { useFormReadonly } from "../../../utils/readonly";
|
|
17
|
+
import { useFormState } from "../../../utils/state";
|
|
18
|
+
const ICONS = {
|
|
19
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "vscode-icons:file-type-excel",
|
|
20
|
+
"application/vnd.ms-excel": "vscode-icons:file-type-excel",
|
|
21
|
+
"application/vnd.openxmlformats-officedocument.presentationml.presentation": "vscode-icons:file-type-powerpoint",
|
|
22
|
+
"application/vnd.ms-powerpoint": "vscode-icons:file-type-powerpoint",
|
|
23
|
+
"application/zip": "vscode-icons:file-type-zip",
|
|
24
|
+
"application/x-zip-compressed": "vscode-icons:file-type-zip",
|
|
25
|
+
"application/vnd.rar": "vscode-icons:file-type-zip",
|
|
26
|
+
"application/x-rar-compressed": "vscode-icons:file-type-zip",
|
|
27
|
+
"application/pdf": "vscode-icons:file-type-pdf2",
|
|
28
|
+
"application/ofd": "vscode-icons:file-type-ofd",
|
|
29
|
+
"application/xml": "vscode-icons:file-type-xml",
|
|
30
|
+
"image/png": "vscode-icons:file-type-image",
|
|
31
|
+
"image/jpg": "vscode-icons:file-type-image",
|
|
32
|
+
"image/jpeg": "vscode-icons:file-type-image",
|
|
33
|
+
"application/msword": "vscode-icons:file-type-word",
|
|
34
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "vscode-icons:file-type-word"
|
|
35
|
+
};
|
|
36
|
+
const SHORT_NAMES = {
|
|
37
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "XLSX",
|
|
38
|
+
"application/vnd.ms-excel": "XLS",
|
|
39
|
+
"application/vnd.openxmlformats-officedocument.presentationml.presentation": "PPTX",
|
|
40
|
+
"application/vnd.ms-powerpoint": "PPT",
|
|
41
|
+
"application/zip": "ZIP",
|
|
42
|
+
"application/x-zip-compressed": "ZIP",
|
|
43
|
+
"application/vnd.rar": "RAR",
|
|
44
|
+
"application/x-rar-compressed": "RAR",
|
|
45
|
+
"application/pdf": "PDF",
|
|
46
|
+
"application/ofd": "OFD",
|
|
47
|
+
"application/xml": "XML",
|
|
48
|
+
"image/png": "PNG",
|
|
49
|
+
"image/jpg": "JPG",
|
|
50
|
+
"image/jpeg": "JPEG",
|
|
51
|
+
"application/msword": "DOC",
|
|
52
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "DOCX"
|
|
53
|
+
};
|
|
54
|
+
defineOptions({ name: "ShwfedUploadFieldRuntime" });
|
|
55
|
+
const props = defineProps({
|
|
56
|
+
fieldId: { type: String, required: true },
|
|
57
|
+
config: { type: null, required: true }
|
|
58
|
+
});
|
|
59
|
+
const { locale, t } = useI18n({
|
|
60
|
+
inheritLocale: true,
|
|
61
|
+
messages: {
|
|
62
|
+
zh: {
|
|
63
|
+
"upload-add-file": "\u6DFB\u52A0\u6587\u4EF6",
|
|
64
|
+
"upload-accept-hint": "\u4EC5\u63A5\u53D7 {types}",
|
|
65
|
+
"upload-rejected-mime": "\u300C{name}\u300D\u7C7B\u578B\u4E0D\u88AB\u5141\u8BB8",
|
|
66
|
+
"upload-rejected-size": "\u300C{name}\u300D\u8D85\u51FA\u5355\u6587\u4EF6\u5927\u5C0F\u9650\u5236",
|
|
67
|
+
"upload-rejected-total": "\u300C{name}\u300D\u52A0\u5165\u540E\u5C06\u8D85\u51FA\u603B\u5927\u5C0F\u9650\u5236",
|
|
68
|
+
"upload-rejected-count": "\u5DF2\u8FBE\u5230\u6587\u4EF6\u6570\u91CF\u4E0A\u9650\uFF0C\u300C{name}\u300D\u672A\u6DFB\u52A0",
|
|
69
|
+
"upload-uploading": "\u4E0A\u4F20\u4E2D\u2026",
|
|
70
|
+
"upload-failed": "\u6587\u4EF6\u4E0A\u4F20\u5931\u8D25"
|
|
71
|
+
},
|
|
72
|
+
en: {
|
|
73
|
+
"upload-add-file": "Add file",
|
|
74
|
+
"upload-accept-hint": "Only {types} are accepted",
|
|
75
|
+
"upload-rejected-mime": "{name} is not an allowed file type",
|
|
76
|
+
"upload-rejected-size": "{name} exceeds the maximum file size",
|
|
77
|
+
"upload-rejected-total": "{name} would exceed the total size limit",
|
|
78
|
+
"upload-rejected-count": "File count limit reached; {name} was not added",
|
|
79
|
+
"upload-uploading": "Uploading\u2026",
|
|
80
|
+
"upload-failed": "File upload failed"
|
|
81
|
+
},
|
|
82
|
+
ja: {
|
|
83
|
+
"upload-add-file": "\u30D5\u30A1\u30A4\u30EB\u3092\u8FFD\u52A0",
|
|
84
|
+
"upload-accept-hint": "{types} \u306E\u307F\u53D7\u3051\u4ED8\u3051\u307E\u3059",
|
|
85
|
+
"upload-rejected-mime": "\u300C{name}\u300D\u306F\u8A31\u53EF\u3055\u308C\u305F\u30D5\u30A1\u30A4\u30EB\u5F62\u5F0F\u3067\u306F\u3042\u308A\u307E\u305B\u3093",
|
|
86
|
+
"upload-rejected-size": "\u300C{name}\u300D\u306F\u30D5\u30A1\u30A4\u30EB\u30B5\u30A4\u30BA\u306E\u4E0A\u9650\u3092\u8D85\u3048\u3066\u3044\u307E\u3059",
|
|
87
|
+
"upload-rejected-total": "\u300C{name}\u300D\u3092\u8FFD\u52A0\u3059\u308B\u3068\u5408\u8A08\u30B5\u30A4\u30BA\u306E\u4E0A\u9650\u3092\u8D85\u3048\u307E\u3059",
|
|
88
|
+
"upload-rejected-count": "\u30D5\u30A1\u30A4\u30EB\u6570\u306E\u4E0A\u9650\u306B\u9054\u3057\u305F\u305F\u3081\u300C{name}\u300D\u306F\u8FFD\u52A0\u3055\u308C\u307E\u305B\u3093",
|
|
89
|
+
"upload-uploading": "\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u4E2D\u2026",
|
|
90
|
+
"upload-failed": "\u30D5\u30A1\u30A4\u30EB\u306E\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u306B\u5931\u6557\u3057\u307E\u3057\u305F"
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
const { state, getAt, setAt } = useFormState();
|
|
95
|
+
const inherited = injectCELContext();
|
|
96
|
+
const $cel = (expression, context) => _rawCel(expression, { ...celBindings(inherited), ...context });
|
|
97
|
+
const labelText = computed(
|
|
98
|
+
() => props.config.label ? getLocalizedText(props.config.label, locale.value) : void 0
|
|
99
|
+
);
|
|
100
|
+
const descriptionText = computed(
|
|
101
|
+
() => props.config.description ? getLocalizedText(props.config.description, locale.value) : void 0
|
|
102
|
+
);
|
|
103
|
+
const tooltipText = computed(
|
|
104
|
+
() => props.config.tooltip ? getLocalizedText(props.config.tooltip, locale.value) : void 0
|
|
105
|
+
);
|
|
106
|
+
function evalBool(expression, label) {
|
|
107
|
+
if (!expression) return false;
|
|
108
|
+
try {
|
|
109
|
+
return Effect.runSync($cel(expression, { form: state.value ?? {} }));
|
|
110
|
+
} catch (err) {
|
|
111
|
+
console.error(`[shwfed-form] failed to evaluate ${label} for ${props.fieldId}:`, err);
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const isDisabled = computed(() => evalBool(props.config.disabled, "disabled"));
|
|
116
|
+
const formReadonly = useFormReadonly();
|
|
117
|
+
const isReadonly = computed(
|
|
118
|
+
() => props.config.readonly != null ? evalBool(props.config.readonly, "readonly") : formReadonly.value
|
|
119
|
+
);
|
|
120
|
+
const { isRequired, errors, warnings, visible } = useFieldValidation({
|
|
121
|
+
fieldId: () => props.fieldId,
|
|
122
|
+
config: () => props.config,
|
|
123
|
+
$cel,
|
|
124
|
+
locale: () => locale.value
|
|
125
|
+
});
|
|
126
|
+
const uncontrolled = ref([]);
|
|
127
|
+
const entries = computed({
|
|
128
|
+
get: () => {
|
|
129
|
+
const path = props.config.binding;
|
|
130
|
+
const raw = path == null ? uncontrolled.value : getAt(path);
|
|
131
|
+
return Array.isArray(raw) ? raw : [];
|
|
132
|
+
},
|
|
133
|
+
set: (next) => {
|
|
134
|
+
const path = props.config.binding;
|
|
135
|
+
if (path == null) {
|
|
136
|
+
uncontrolled.value = next;
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
setAt(path, next.length === 0 ? null : next);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
const immediate = computed(() => props.config.upload != null);
|
|
143
|
+
const uploading = ref(false);
|
|
144
|
+
function entryName(entry) {
|
|
145
|
+
if (entry instanceof File) return entry.name;
|
|
146
|
+
const expr = props.config.upload?.filename;
|
|
147
|
+
if (expr) {
|
|
148
|
+
try {
|
|
149
|
+
const name = Effect.runSync($cel(expr, { form: state.value ?? {}, file: entry }));
|
|
150
|
+
if (typeof name === "string" && name.length > 0) return name;
|
|
151
|
+
} catch (err) {
|
|
152
|
+
console.error(`[shwfed-form] failed to evaluate upload filename for ${props.fieldId}:`, err);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (entry != null && typeof entry === "object") {
|
|
156
|
+
const rec = entry;
|
|
157
|
+
if (typeof rec.filename === "string") return rec.filename;
|
|
158
|
+
if (typeof rec.name === "string") return rec.name;
|
|
159
|
+
}
|
|
160
|
+
return "(\u6587\u4EF6)";
|
|
161
|
+
}
|
|
162
|
+
function entryIcon(entry) {
|
|
163
|
+
if (entry instanceof File) return ICONS[entry.type] ?? "fluent:document-20-regular";
|
|
164
|
+
return "fluent:document-20-regular";
|
|
165
|
+
}
|
|
166
|
+
const inputRef = ref();
|
|
167
|
+
const acceptAttr = computed(() => {
|
|
168
|
+
const list = props.config.accept;
|
|
169
|
+
return list && list.length > 0 ? list.join(",") : void 0;
|
|
170
|
+
});
|
|
171
|
+
const acceptHint = computed(() => {
|
|
172
|
+
const list = props.config.accept;
|
|
173
|
+
if (!list || list.length === 0) return void 0;
|
|
174
|
+
return Array.from(new Set(list.map((m) => SHORT_NAMES[m] ?? m))).join("\u3001");
|
|
175
|
+
});
|
|
176
|
+
const isFull = computed(
|
|
177
|
+
() => props.config.maxFiles !== void 0 && entries.value.length >= props.config.maxFiles
|
|
178
|
+
);
|
|
179
|
+
const canAdd = computed(() => !isDisabled.value && !isReadonly.value && !isFull.value && !uploading.value);
|
|
180
|
+
function isMimeAllowed(file) {
|
|
181
|
+
const list = props.config.accept;
|
|
182
|
+
if (!list || list.length === 0) return true;
|
|
183
|
+
return list.includes(file.type);
|
|
184
|
+
}
|
|
185
|
+
function partition(incoming) {
|
|
186
|
+
const accepted = [];
|
|
187
|
+
const rejected = [];
|
|
188
|
+
let runningTotal = entries.value.reduce((acc, f) => acc + (f instanceof File ? f.size : 0), 0);
|
|
189
|
+
let count = entries.value.length;
|
|
190
|
+
for (const file of incoming) {
|
|
191
|
+
if (!isMimeAllowed(file)) {
|
|
192
|
+
rejected.push({ file, reason: "mime" });
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (props.config.maxFileSize !== void 0 && file.size > props.config.maxFileSize) {
|
|
196
|
+
rejected.push({ file, reason: "size" });
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
if (props.config.maxFiles !== void 0 && count >= props.config.maxFiles) {
|
|
200
|
+
rejected.push({ file, reason: "count" });
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
if (props.config.maxTotalSize !== void 0 && runningTotal + file.size > props.config.maxTotalSize) {
|
|
204
|
+
rejected.push({ file, reason: "total" });
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
accepted.push(file);
|
|
208
|
+
runningTotal += file.size;
|
|
209
|
+
count += 1;
|
|
210
|
+
}
|
|
211
|
+
return { accepted, rejected };
|
|
212
|
+
}
|
|
213
|
+
async function uploadFiles(accepted) {
|
|
214
|
+
const upload = props.config.upload;
|
|
215
|
+
if (!upload) return [];
|
|
216
|
+
const program = Effect.gen(function* () {
|
|
217
|
+
const builder = yield* $cel(upload.request, {
|
|
218
|
+
form: state.value ?? {},
|
|
219
|
+
files: accepted
|
|
220
|
+
});
|
|
221
|
+
const json = yield* builder.json();
|
|
222
|
+
return yield* $cel(upload.handle, { form: state.value ?? {}, json });
|
|
223
|
+
});
|
|
224
|
+
try {
|
|
225
|
+
const items = await Effect.runPromise(Effect.provide(program, Fetch.layer));
|
|
226
|
+
if (!Array.isArray(items)) {
|
|
227
|
+
console.error(`[shwfed-form] upload handle for ${props.fieldId} did not return a list`);
|
|
228
|
+
toast.error(t("upload-failed"));
|
|
229
|
+
return [];
|
|
230
|
+
}
|
|
231
|
+
return items;
|
|
232
|
+
} catch (err) {
|
|
233
|
+
console.error(`[shwfed-form] failed to upload files for ${props.fieldId}:`, err);
|
|
234
|
+
toast.error(t("upload-failed"));
|
|
235
|
+
return [];
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
async function ingest(list) {
|
|
239
|
+
if (!list || list.length === 0) return;
|
|
240
|
+
const multi = props.config.multiple ?? false;
|
|
241
|
+
const incoming = multi ? Array.from(list) : Array.from(list).slice(0, 1);
|
|
242
|
+
const { accepted, rejected } = partition(incoming);
|
|
243
|
+
for (const r of rejected) {
|
|
244
|
+
toast.error(t(`upload-rejected-${r.reason}`, { name: r.file.name }));
|
|
245
|
+
}
|
|
246
|
+
if (inputRef.value) inputRef.value.value = "";
|
|
247
|
+
if (accepted.length === 0) return;
|
|
248
|
+
if (!immediate.value) {
|
|
249
|
+
entries.value = multi ? [...entries.value, ...accepted] : accepted;
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
uploading.value = true;
|
|
253
|
+
try {
|
|
254
|
+
const items = await uploadFiles(accepted);
|
|
255
|
+
if (items.length > 0) {
|
|
256
|
+
entries.value = multi ? [...entries.value, ...items] : items;
|
|
257
|
+
}
|
|
258
|
+
} finally {
|
|
259
|
+
uploading.value = false;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
function onPickerChange(event) {
|
|
263
|
+
void ingest(event.target.files);
|
|
264
|
+
}
|
|
265
|
+
function onAddClick() {
|
|
266
|
+
if (!canAdd.value) return;
|
|
267
|
+
inputRef.value?.click();
|
|
268
|
+
}
|
|
269
|
+
function onKeydown(event) {
|
|
270
|
+
if (!canAdd.value) return;
|
|
271
|
+
if (event.key === "Enter" || event.key === " ") {
|
|
272
|
+
event.preventDefault();
|
|
273
|
+
inputRef.value?.click();
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
function onDelete(index) {
|
|
277
|
+
if (isDisabled.value || isReadonly.value || uploading.value) return;
|
|
278
|
+
const next = [...entries.value];
|
|
279
|
+
next.splice(index, 1);
|
|
280
|
+
entries.value = next;
|
|
281
|
+
}
|
|
282
|
+
const templates = computed(() => props.config.templates ?? []);
|
|
283
|
+
function templateIcon(template) {
|
|
284
|
+
return template.icon ?? "fluent:arrow-download-20-regular";
|
|
285
|
+
}
|
|
286
|
+
function templateLabelText(template) {
|
|
287
|
+
return (template.label ? getLocalizedText(template.label, locale.value) : void 0) ?? "\u4E0B\u8F7D\u6A21\u677F";
|
|
288
|
+
}
|
|
289
|
+
async function onDownloadTemplate(template) {
|
|
290
|
+
const ctx = { form: state.value ?? {} };
|
|
291
|
+
const program = Effect.gen(function* () {
|
|
292
|
+
const requestBuilder = yield* $cel(template.request, ctx);
|
|
293
|
+
if (!template.download) {
|
|
294
|
+
return yield* requestBuilder.file();
|
|
295
|
+
}
|
|
296
|
+
const json = yield* requestBuilder.json();
|
|
297
|
+
const downloadBuilder = yield* $cel(template.download, { ...ctx, json });
|
|
298
|
+
return yield* downloadBuilder.file();
|
|
299
|
+
});
|
|
300
|
+
try {
|
|
301
|
+
const file = await Effect.runPromise(Effect.provide(program, Fetch.layer));
|
|
302
|
+
if (!(file instanceof File)) {
|
|
303
|
+
console.error(`[shwfed-form] template request for ${props.fieldId} did not produce a File`);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
const url = URL.createObjectURL(file);
|
|
307
|
+
const a = document.createElement("a");
|
|
308
|
+
a.href = url;
|
|
309
|
+
a.download = file.name;
|
|
310
|
+
document.body.appendChild(a);
|
|
311
|
+
a.click();
|
|
312
|
+
a.remove();
|
|
313
|
+
URL.revokeObjectURL(url);
|
|
314
|
+
} catch (err) {
|
|
315
|
+
console.error(`[shwfed-form] failed to download template for ${props.fieldId}:`, err);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
</script>
|
|
319
|
+
|
|
320
|
+
<template>
|
|
321
|
+
<Field
|
|
322
|
+
:orientation="config.orientation ?? DEFAULT_FIELD_ORIENTATION"
|
|
323
|
+
:data-disabled="isDisabled || void 0"
|
|
324
|
+
>
|
|
325
|
+
<FieldLabel
|
|
326
|
+
v-if="labelText"
|
|
327
|
+
:for="fieldId"
|
|
328
|
+
class="text-xs text-zinc-500"
|
|
329
|
+
>
|
|
330
|
+
<template
|
|
331
|
+
v-if="tooltipText"
|
|
332
|
+
#tooltip
|
|
333
|
+
>
|
|
334
|
+
<Markdown
|
|
335
|
+
:source="tooltipText"
|
|
336
|
+
class="prose prose-xs prose-zinc"
|
|
337
|
+
/>
|
|
338
|
+
</template>
|
|
339
|
+
{{ labelText }}<span
|
|
340
|
+
v-if="isRequired"
|
|
341
|
+
aria-hidden="true"
|
|
342
|
+
class="text-red-600"
|
|
343
|
+
> *</span>
|
|
344
|
+
</FieldLabel>
|
|
345
|
+
|
|
346
|
+
<div
|
|
347
|
+
:id="fieldId"
|
|
348
|
+
class="flex flex-col gap-2"
|
|
349
|
+
:data-disabled="isDisabled || void 0"
|
|
350
|
+
:data-readonly="isReadonly || void 0"
|
|
351
|
+
>
|
|
352
|
+
<div
|
|
353
|
+
v-if="entries.length === 0"
|
|
354
|
+
role="button"
|
|
355
|
+
:tabindex="canAdd ? 0 : -1"
|
|
356
|
+
data-slot="upload-zone"
|
|
357
|
+
:data-disabled="isDisabled || void 0"
|
|
358
|
+
:data-readonly="isReadonly || void 0"
|
|
359
|
+
:aria-disabled="isDisabled || void 0"
|
|
360
|
+
class="flex min-h-40 w-full flex-col gap-3 rounded border-2 border-dashed border-zinc-200 bg-zinc-50 p-4 outline-none transition-colors duration-180 ease-out focus-visible:border-(--primary) data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-60"
|
|
361
|
+
:class="[
|
|
362
|
+
canAdd && 'cursor-pointer hover:border-zinc-400 hover:bg-zinc-100',
|
|
363
|
+
isReadonly && 'cursor-default'
|
|
364
|
+
]"
|
|
365
|
+
@click="onAddClick"
|
|
366
|
+
@keydown="onKeydown"
|
|
367
|
+
>
|
|
368
|
+
<div class="flex flex-1 flex-col items-center justify-center gap-2">
|
|
369
|
+
<Icon
|
|
370
|
+
:icon="uploading ? 'fluent:spinner-ios-20-regular' : 'fluent:cloud-arrow-up-20-regular'"
|
|
371
|
+
class="size-8 text-zinc-400"
|
|
372
|
+
:class="uploading && 'animate-spin'"
|
|
373
|
+
/>
|
|
374
|
+
<p
|
|
375
|
+
v-if="uploading"
|
|
376
|
+
class="text-xs text-zinc-500"
|
|
377
|
+
>
|
|
378
|
+
{{ t("upload-uploading") }}
|
|
379
|
+
</p>
|
|
380
|
+
<Markdown
|
|
381
|
+
v-if="descriptionText"
|
|
382
|
+
:source="descriptionText"
|
|
383
|
+
block
|
|
384
|
+
class="prose prose-sm prose-zinc max-w-none text-center text-zinc-500"
|
|
385
|
+
/>
|
|
386
|
+
<p
|
|
387
|
+
v-if="acceptHint"
|
|
388
|
+
class="text-xs text-zinc-500"
|
|
389
|
+
>
|
|
390
|
+
{{ t("upload-accept-hint", { types: acceptHint }) }}
|
|
391
|
+
</p>
|
|
392
|
+
</div>
|
|
393
|
+
</div>
|
|
394
|
+
|
|
395
|
+
<div
|
|
396
|
+
v-else
|
|
397
|
+
class="flex w-full flex-col gap-2"
|
|
398
|
+
>
|
|
399
|
+
<ul
|
|
400
|
+
data-slot="upload-zone-list"
|
|
401
|
+
class="flex flex-col gap-1"
|
|
402
|
+
>
|
|
403
|
+
<li
|
|
404
|
+
v-for="(entry, index) in entries"
|
|
405
|
+
:key="`${entryName(entry)}-${index}`"
|
|
406
|
+
data-slot="upload-zone-item"
|
|
407
|
+
class="flex items-center justify-between gap-2 rounded px-2 py-1.5 text-sm leading-snug transition-[background-color] duration-180 ease-out hover:bg-zinc-50"
|
|
408
|
+
>
|
|
409
|
+
<span class="flex min-w-0 items-center gap-2">
|
|
410
|
+
<Icon
|
|
411
|
+
:icon="entryIcon(entry)"
|
|
412
|
+
class="size-4 shrink-0"
|
|
413
|
+
/>
|
|
414
|
+
<span class="truncate text-zinc-700">{{ entryName(entry) }}</span>
|
|
415
|
+
</span>
|
|
416
|
+
<Button
|
|
417
|
+
v-if="!isDisabled && !isReadonly"
|
|
418
|
+
type="button"
|
|
419
|
+
variant="ghost"
|
|
420
|
+
size="sm"
|
|
421
|
+
data-slot="upload-zone-delete"
|
|
422
|
+
class="size-6 p-0 text-zinc-500 hover:bg-red-50 hover:text-red-600"
|
|
423
|
+
:disabled="uploading"
|
|
424
|
+
:aria-label="`\u5220\u9664\uFF1A${entryName(entry)}`"
|
|
425
|
+
@click="onDelete(index)"
|
|
426
|
+
>
|
|
427
|
+
<Icon icon="fluent:delete-20-regular" />
|
|
428
|
+
</Button>
|
|
429
|
+
</li>
|
|
430
|
+
</ul>
|
|
431
|
+
|
|
432
|
+
<Button
|
|
433
|
+
v-if="canAdd"
|
|
434
|
+
type="button"
|
|
435
|
+
variant="default"
|
|
436
|
+
data-slot="upload-zone-add"
|
|
437
|
+
class="w-full shrink-0"
|
|
438
|
+
@click="onAddClick"
|
|
439
|
+
>
|
|
440
|
+
<Icon
|
|
441
|
+
:icon="uploading ? 'fluent:spinner-ios-20-regular' : 'fluent:add-20-regular'"
|
|
442
|
+
:class="uploading && 'animate-spin'"
|
|
443
|
+
/>
|
|
444
|
+
{{ uploading ? t("upload-uploading") : t("upload-add-file") }}
|
|
445
|
+
</Button>
|
|
446
|
+
</div>
|
|
447
|
+
|
|
448
|
+
<input
|
|
449
|
+
ref="inputRef"
|
|
450
|
+
type="file"
|
|
451
|
+
class="hidden"
|
|
452
|
+
:accept="acceptAttr"
|
|
453
|
+
:multiple="config.multiple"
|
|
454
|
+
:disabled="isDisabled || isReadonly"
|
|
455
|
+
@change="onPickerChange"
|
|
456
|
+
>
|
|
457
|
+
|
|
458
|
+
<div
|
|
459
|
+
v-if="templates.length > 0 && !isReadonly"
|
|
460
|
+
class="flex flex-wrap justify-end gap-1"
|
|
461
|
+
>
|
|
462
|
+
<Button
|
|
463
|
+
v-for="(template, index) in templates"
|
|
464
|
+
:key="index"
|
|
465
|
+
type="button"
|
|
466
|
+
variant="link"
|
|
467
|
+
size="sm"
|
|
468
|
+
data-slot="upload-zone-template"
|
|
469
|
+
@click="onDownloadTemplate(template)"
|
|
470
|
+
>
|
|
471
|
+
<Icon :icon="templateIcon(template)" />
|
|
472
|
+
{{ templateLabelText(template) }}
|
|
473
|
+
</Button>
|
|
474
|
+
</div>
|
|
475
|
+
</div>
|
|
476
|
+
<FieldMessages
|
|
477
|
+
v-if="visible"
|
|
478
|
+
:errors="errors"
|
|
479
|
+
:warnings="warnings"
|
|
480
|
+
/>
|
|
481
|
+
</Field>
|
|
482
|
+
</template>
|
package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/runtime.vue.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Value } from './schema.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
fieldId: string;
|
|
4
|
+
config: Value;
|
|
5
|
+
};
|
|
6
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
7
|
+
declare const _default: typeof __VLS_export;
|
|
8
|
+
export default _default;
|