@shwfed/config 3.0.14 → 3.0.15
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/module.mjs +20 -1
- package/dist/runtime/components/actions/ai-l1.md +1 -1
- package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json/config.d.vue.ts +2 -2
- package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json/config.vue.d.ts +2 -2
- package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json.confirm/config.d.vue.ts +2 -2
- package/dist/runtime/components/actions/buttons/2026-04-18/com.shwfed.actions.button.http.request.json.confirm/config.vue.d.ts +2 -2
- package/dist/runtime/components/actions/buttons/2026-05-15/com.shwfed.actions.button.event.dispatch/prompt.md +1 -1
- package/dist/runtime/components/actions/buttons/2026-05-21/com.shwfed.actions.button.http.download/schema.d.ts +1 -1
- package/dist/runtime/components/actions/buttons/2026-05-21/com.shwfed.actions.button.http.download/schema.js +2 -2
- package/dist/runtime/components/actions/buttons/2026-06-08/com.shwfed.actions.button.http.request.json.batch/config.d.vue.ts +2 -2
- package/dist/runtime/components/actions/buttons/2026-06-08/com.shwfed.actions.button.http.request.json.batch/config.vue.d.ts +2 -2
- package/dist/runtime/components/actions/buttons/2026-06-25/com.shwfed.actions.button.state.write/config.d.vue.ts +8 -8
- package/dist/runtime/components/actions/buttons/2026-06-25/com.shwfed.actions.button.state.write/config.vue.d.ts +8 -8
- package/dist/runtime/components/actions/buttons/2026-07-13/com.shwfed.actions.button.state.write/prompt.md +1 -1
- package/dist/runtime/components/actions/buttons/2026-07-13/com.shwfed.actions.button.state.write/runtime.vue +1 -1
- package/dist/runtime/components/actions/buttons/2026-07-13/com.shwfed.actions.button.state.write/schema.d.ts +2 -4
- package/dist/runtime/components/actions/buttons/2026-07-13/com.shwfed.actions.button.state.write/schema.js +1 -1
- package/dist/runtime/components/actions/components/trigger-row-scope.vue +6 -3
- package/dist/runtime/components/actions/utils/steps.d.ts +1 -1
- package/dist/runtime/components/config/blocks/2026-06-17/com.shwfed.block.tree.single/config.d.vue.ts +18 -18
- package/dist/runtime/components/config/blocks/2026-06-17/com.shwfed.block.tree.single/config.vue.d.ts +18 -18
- package/dist/runtime/components/config/blocks/2026-06-17/com.shwfed.block.tree.single/runtime.d.vue.ts +18 -18
- package/dist/runtime/components/config/blocks/2026-06-17/com.shwfed.block.tree.single/runtime.vue.d.ts +18 -18
- package/dist/runtime/components/config/index.d.vue.ts +2 -2
- package/dist/runtime/components/config/index.vue.d.ts +2 -2
- package/dist/runtime/components/config/schema.js +2 -2
- package/dist/runtime/components/form/fields/2026-04-22/com.shwfed.form.field.text/config.d.vue.ts +22 -22
- package/dist/runtime/components/form/fields/2026-04-22/com.shwfed.form.field.text/config.vue.d.ts +22 -22
- package/dist/runtime/components/form/fields/2026-04-24/com.shwfed.form.field.combobox.single/config.d.vue.ts +16 -16
- package/dist/runtime/components/form/fields/2026-04-24/com.shwfed.form.field.combobox.single/config.vue.d.ts +16 -16
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.d.vue.ts +6 -6
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.vue.d.ts +6 -6
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.d.vue.ts +8 -8
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.vue.d.ts +8 -8
- 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-04-28/com.shwfed.form.field.number/config.d.vue.ts +22 -22
- package/dist/runtime/components/form/fields/2026-04-28/com.shwfed.form.field.number/config.vue.d.ts +22 -22
- package/dist/runtime/components/form/fields/2026-05-13/com.shwfed.form.field.combobox.single.remote/config.d.vue.ts +16 -16
- package/dist/runtime/components/form/fields/2026-05-13/com.shwfed.form.field.combobox.single.remote/config.vue.d.ts +16 -16
- package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/config.d.vue.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/config.vue.d.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.monthrange/config.d.vue.ts +6 -6
- package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.monthrange/config.vue.d.ts +6 -6
- package/dist/runtime/components/form/fields/2026-05-25/com.shwfed.form.field.combobox.multi/config.d.vue.ts +16 -16
- package/dist/runtime/components/form/fields/2026-05-25/com.shwfed.form.field.combobox.multi/config.vue.d.ts +16 -16
- package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.multi/config.d.vue.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.multi/config.vue.d.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.single/config.d.vue.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.single/config.vue.d.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.multi/config.d.vue.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.multi/config.vue.d.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.single/config.d.vue.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.single/config.vue.d.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/config.d.vue.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/config.vue.d.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/config.d.vue.ts +26 -26
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/config.vue.d.ts +26 -26
- package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/prompt.md +1 -1
- package/dist/runtime/components/form/fields/2026-07-18/com.shwfed.form.field.richtext/RichTextEditor.d.vue.ts +33 -0
- package/dist/runtime/components/form/fields/2026-07-18/com.shwfed.form.field.richtext/RichTextEditor.vue +269 -0
- package/dist/runtime/components/form/fields/2026-07-18/com.shwfed.form.field.richtext/RichTextEditor.vue.d.ts +33 -0
- package/dist/runtime/components/form/fields/2026-07-18/com.shwfed.form.field.richtext/config.d.vue.ts +107 -0
- package/dist/runtime/components/form/fields/2026-07-18/com.shwfed.form.field.richtext/config.vue +370 -0
- package/dist/runtime/components/form/fields/2026-07-18/com.shwfed.form.field.richtext/config.vue.d.ts +107 -0
- package/dist/runtime/components/form/fields/2026-07-18/com.shwfed.form.field.richtext/extensions.d.ts +27 -0
- package/dist/runtime/components/form/fields/2026-07-18/com.shwfed.form.field.richtext/extensions.js +83 -0
- package/dist/runtime/components/form/fields/2026-07-18/com.shwfed.form.field.richtext/features.d.ts +21 -0
- package/dist/runtime/components/form/fields/2026-07-18/com.shwfed.form.field.richtext/features.js +16 -0
- package/dist/runtime/components/form/fields/2026-07-18/com.shwfed.form.field.richtext/indent.d.ts +26 -0
- package/dist/runtime/components/form/fields/2026-07-18/com.shwfed.form.field.richtext/indent.js +64 -0
- package/dist/runtime/components/form/fields/2026-07-18/com.shwfed.form.field.richtext/prompt.md +33 -0
- package/dist/runtime/components/form/fields/2026-07-18/com.shwfed.form.field.richtext/runtime.d.vue.ts +8 -0
- package/dist/runtime/components/form/fields/2026-07-18/com.shwfed.form.field.richtext/runtime.vue +121 -0
- package/dist/runtime/components/form/fields/2026-07-18/com.shwfed.form.field.richtext/runtime.vue.d.ts +8 -0
- package/dist/runtime/components/form/fields/2026-07-18/com.shwfed.form.field.richtext/schema.d.ts +133 -0
- package/dist/runtime/components/form/fields/2026-07-18/com.shwfed.form.field.richtext/schema.js +65 -0
- package/dist/runtime/components/operations/2026-06-11/com.shwfed.operation.http.request.json/runtime.js +16 -4
- package/dist/runtime/components/operations/2026-06-11/com.shwfed.operation.http.request.json/schema.js +10 -3
- package/dist/runtime/components/operations/2026-06-15/com.shwfed.operation.http.download/schema.js +2 -2
- package/dist/runtime/components/operations/2026-06-15/com.shwfed.operation.navigation/schema.js +1 -1
- package/dist/runtime/components/operations/utils/resolve.d.ts +1 -1
- package/dist/runtime/components/operations/utils/step-vars.d.ts +16 -4
- package/dist/runtime/components/operations/utils/step-vars.js +14 -1
- package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-remote/config.d.vue.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-remote/config.vue.d.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-static/config.d.vue.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-static/config.vue.d.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-remote/config.d.vue.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-remote/config.vue.d.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-static/config.d.vue.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-static/config.vue.d.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-multi.remote/config.d.vue.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-multi.remote/config.vue.d.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-single.remote/config.d.vue.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-single.remote/config.vue.d.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-multi/config.d.vue.ts +10 -10
- package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-multi/config.vue.d.ts +10 -10
- package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-single/config.d.vue.ts +10 -10
- package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-single/config.vue.d.ts +10 -10
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/config.d.vue.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/config.vue.d.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/config.d.vue.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/config.vue.d.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/config.d.vue.ts +10 -10
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/config.vue.d.ts +10 -10
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/config.d.vue.ts +10 -10
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/config.vue.d.ts +10 -10
- package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.combobox-multi/config.d.vue.ts +2 -2
- package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.combobox-multi/config.vue.d.ts +2 -2
- package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.combobox-single/config.d.vue.ts +2 -2
- package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.combobox-single/config.vue.d.ts +2 -2
- package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.tree-combobox-multi/config.d.vue.ts +10 -10
- package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.tree-combobox-multi/config.vue.d.ts +10 -10
- package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.tree-combobox-single/config.d.vue.ts +10 -10
- package/dist/runtime/components/table/columns/2026-06-14/com.shwfed.table.column.tree-combobox-single/config.vue.d.ts +10 -10
- package/dist/runtime/components/table/columns/2026-07-16/com.shwfed.table.column.upload/prompt.md +1 -1
- package/dist/runtime/components/ui/calendar/Calendar.d.vue.ts +8 -4
- package/dist/runtime/components/ui/calendar/Calendar.vue +39 -10
- package/dist/runtime/components/ui/calendar/Calendar.vue.d.ts +8 -4
- package/dist/runtime/components/ui/date-picker/DatePicker.vue +3 -1
- package/dist/runtime/components/ui/date-picker/DatePickerDatePanel.vue +6 -0
- package/dist/runtime/components/ui/date-picker/DatePickerDateTimePanel.vue +6 -0
- package/dist/runtime/components/ui/date-picker/DatePickerInput.d.vue.ts +1 -1
- package/dist/runtime/components/ui/date-picker/DatePickerInput.vue +7 -9
- 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/DateRangePicker.vue +10 -7
- package/dist/runtime/components/ui/date-range-picker/DateRangePickerInput.d.vue.ts +3 -5
- package/dist/runtime/components/ui/date-range-picker/DateRangePickerInput.vue +28 -26
- package/dist/runtime/components/ui/date-range-picker/DateRangePickerInput.vue.d.ts +3 -5
- 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/components/ui/expression-editor/picker-entries.js +1 -1
- package/dist/runtime/components/ui/expression-editor/step-chip-extension.js +1 -1
- package/dist/runtime/components/ui/expression-editor/step-refs.js +1 -1
- package/dist/runtime/components/ui/range-calendar/RangeCalendar.d.vue.ts +5 -5
- package/dist/runtime/components/ui/range-calendar/RangeCalendar.vue +22 -5
- package/dist/runtime/components/ui/range-calendar/RangeCalendar.vue.d.ts +5 -5
- package/dist/runtime/components/ui/range-calendar/RangeCalendarNextButton.vue +0 -1
- package/dist/runtime/components/ui/range-calendar/RangeCalendarPrevButton.vue +0 -1
- package/dist/runtime/share/event-bus.d.ts +16 -0
- package/dist/runtime/share/event-bus.js +18 -13
- package/dist/runtime/share/idempotency-key.d.ts +18 -0
- package/dist/runtime/share/idempotency-key.js +9 -0
- package/dist/runtime/utils/cel-context.d.ts +3 -2
- package/dist/runtime/utils/cel-context.js +1 -0
- package/package.json +8 -1
package/dist/runtime/components/form/fields/2026-07-18/com.shwfed.form.field.richtext/indent.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Extension } from "@tiptap/core";
|
|
2
|
+
export const Indent = Extension.create({
|
|
3
|
+
name: "indent",
|
|
4
|
+
// Load-bearing. Extensions are sorted by priority descending and their keymap
|
|
5
|
+
// plugins run in that order, with ProseMirror stopping at the first handler
|
|
6
|
+
// that returns true. `ListItem` and the table extension both bind Tab at the
|
|
7
|
+
// default priority of 100; sitting at 50 puts this keymap last, so nesting a
|
|
8
|
+
// list item and moving between table cells keep first refusal and Tab only
|
|
9
|
+
// reaches paragraph indentation when neither applies.
|
|
10
|
+
priority: 50,
|
|
11
|
+
addOptions() {
|
|
12
|
+
return { types: ["paragraph"], step: 2, maxLevel: 8 };
|
|
13
|
+
},
|
|
14
|
+
addGlobalAttributes() {
|
|
15
|
+
return [{
|
|
16
|
+
types: this.options.types,
|
|
17
|
+
attributes: {
|
|
18
|
+
indent: {
|
|
19
|
+
default: 0,
|
|
20
|
+
keepOnSplit: true,
|
|
21
|
+
parseHTML: (element) => {
|
|
22
|
+
const raw = element.style.marginInlineStart || element.style.marginLeft;
|
|
23
|
+
if (!raw) return 0;
|
|
24
|
+
const em = Number.parseFloat(raw);
|
|
25
|
+
return Number.isFinite(em) ? Math.round(em / this.options.step) : 0;
|
|
26
|
+
},
|
|
27
|
+
renderHTML: (attributes) => {
|
|
28
|
+
const level = Number(attributes.indent) || 0;
|
|
29
|
+
if (level <= 0) return {};
|
|
30
|
+
return { style: `margin-inline-start: ${level * this.options.step}em` };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}];
|
|
35
|
+
},
|
|
36
|
+
addCommands() {
|
|
37
|
+
const clamp = (n) => Math.min(Math.max(n, 0), this.options.maxLevel);
|
|
38
|
+
const apply = (next) => ({ state, tr, dispatch }) => {
|
|
39
|
+
const { from, to } = state.selection;
|
|
40
|
+
let changed = false;
|
|
41
|
+
state.doc.nodesBetween(from, to, (node, pos) => {
|
|
42
|
+
if (!this.options.types.includes(node.type.name)) return;
|
|
43
|
+
const current = Number(node.attrs.indent) || 0;
|
|
44
|
+
const level = clamp(next(current));
|
|
45
|
+
if (level === current) return;
|
|
46
|
+
tr.setNodeMarkup(pos, void 0, { ...node.attrs, indent: level });
|
|
47
|
+
changed = true;
|
|
48
|
+
});
|
|
49
|
+
if (!changed) return false;
|
|
50
|
+
if (dispatch) dispatch(tr);
|
|
51
|
+
return true;
|
|
52
|
+
};
|
|
53
|
+
return {
|
|
54
|
+
indent: () => apply((current) => current + 1),
|
|
55
|
+
outdent: () => apply((current) => current - 1)
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
addKeyboardShortcuts() {
|
|
59
|
+
return {
|
|
60
|
+
"Tab": () => this.editor.commands.indent(),
|
|
61
|
+
"Shift-Tab": () => this.editor.commands.outdent()
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
});
|
package/dist/runtime/components/form/fields/2026-07-18/com.shwfed.form.field.richtext/prompt.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
**何时用我**:需要用户输入**带简单排版的正文**(公告、说明、条款……),且这段内容要以 HTML 存取。只要纯文本(哪怕多行)就用 `textarea`,不要用我。
|
|
2
|
+
|
|
3
|
+
**配置配方**
|
|
4
|
+
|
|
5
|
+
- `binding`:写入表单状态的 dot-prop 路径(如 `article.body`)。写入的值是 **HTML 字符串**。
|
|
6
|
+
- `placeholder`:正文为空时的占位文本(纯文本 Locale)。
|
|
7
|
+
- 其余 `label` / `tooltip` / `required` / `hidden` / `disabled` / `readonly` / `validations` / `derived` 与其它输入字段一致。
|
|
8
|
+
|
|
9
|
+
**功能清单**(两个数组,**都是必填**)
|
|
10
|
+
|
|
11
|
+
- `inline`:行内样式,取值 `bold` / `italic` / `underline` / `strike`。
|
|
12
|
+
- `block`:块级功能,取值 `bulletList` / `orderedList`。
|
|
13
|
+
|
|
14
|
+
新建时用 `defaults()` 的种子——两个数组全开。只有用户明确要求裁剪("不要斜体")时才删元素,**不要自作主张删**。数组元素顺序固定按上面的顺序写。
|
|
15
|
+
|
|
16
|
+
不要编造别的开关。**左/中/右对齐和增减缩进是常驻功能,不在这两个数组里**,也没有对应配置项。
|
|
17
|
+
|
|
18
|
+
**能力边界**:加粗、斜体、下划线、删除线、无序列表、有序列表、左中右对齐、缩进/减少缩进。
|
|
19
|
+
|
|
20
|
+
**没有链接,也没有表格**——这两项已被移除,交互设计需要重新考虑。用户要求这两个功能时,直接说明当前不支持,**不要编造 `link` / `table` 配置项**,也不要建议用别的字段拼凑。
|
|
21
|
+
|
|
22
|
+
其余不支持的还有:标题、图片、代码块、引用、任务列表。
|
|
23
|
+
|
|
24
|
+
**坑**
|
|
25
|
+
|
|
26
|
+
- 正文为空时写入的是 `null`,不是 `''`,也不是 `<p></p>`。`required` 与自定义校验按 `null` 判空即可。
|
|
27
|
+
- 值是 HTML 而非 Markdown。要在别处展示它,直接渲染 HTML;不要套 `markdown` 字段或 `Markdown` 组件。**编辑器不解析 Markdown**:用户敲 `**x**`、`- `、`# ` 不会自动变格式,别向用户承诺这个行为。
|
|
28
|
+
- 载入的 HTML 只保留上面列出的能力,**其余标签会被拍平**:`<a>` 退化成纯文本、`<table>` 只剩单元格文字、`<h1>` 变普通段落。文字不会丢,结构会丢。从别处迁移内容进来前先确认这一点。
|
|
29
|
+
- 从数组里删掉一项只是收回"写"的入口(按钮不渲染、快捷键解绑),**不会清洗存量内容**——已有的加粗照常显示和保存。所以删元素不能用来做数据清理。
|
|
30
|
+
- 缩进落在 HTML 里是 `<p style="margin-inline-start: Nem">`,对齐是 `<p style="text-align: …">`;未对齐/未缩进的段落不带 `style`。如果后端会过滤内联样式,这两项会丢。
|
|
31
|
+
- 校验规则里对正文做长度判断会连 HTML 标签一起算进去——需要按可见字数校验时先向用户确认口径,不要想当然。
|
|
32
|
+
- `derived` 的表达式返回的同样是 HTML 字符串。
|
|
33
|
+
- 这是块级字段,`h.grow` 为真、高度跟随内容;布局里给它留足空间(默认 12×8)。
|
|
@@ -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-07-18/com.shwfed.form.field.richtext/runtime.vue
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { Effect } from "effect";
|
|
3
|
+
import { computed } from "vue";
|
|
4
|
+
import { useI18n } from "vue-i18n";
|
|
5
|
+
import { cel as _rawCel } from "../../../../../utils/cel";
|
|
6
|
+
import { celBindings, injectCELContext } from "../../../../../utils/cel-context";
|
|
7
|
+
import { getLocalizedText } from "../../../../../share/locale";
|
|
8
|
+
import { interpolateMarkdown } from "../../../../table/utils/runtime";
|
|
9
|
+
import { Field, FieldLabel, FieldMessages } from "../../../../ui/field";
|
|
10
|
+
import { Markdown } from "../../../../ui/markdown";
|
|
11
|
+
import { useFieldValue } from "../../../utils/field-value";
|
|
12
|
+
import { useFieldValidation } from "../../../utils/validation";
|
|
13
|
+
import { useFormReadonly } from "../../../utils/readonly";
|
|
14
|
+
import { useFormScope } from "../../../utils/state";
|
|
15
|
+
import RichTextEditor from "./RichTextEditor.vue";
|
|
16
|
+
import { featureSignature, resolveFeatures } from "./features";
|
|
17
|
+
defineOptions({ name: "ShwfedRichTextFieldRuntime" });
|
|
18
|
+
const props = defineProps({
|
|
19
|
+
fieldId: { type: String, required: true },
|
|
20
|
+
config: { type: null, required: true }
|
|
21
|
+
});
|
|
22
|
+
const { locale } = useI18n();
|
|
23
|
+
const formScope = useFormScope();
|
|
24
|
+
const inherited = injectCELContext();
|
|
25
|
+
const $cel = (expression, context) => _rawCel(expression, { ...celBindings(inherited), ...context });
|
|
26
|
+
const labelText = computed(() => getLocalizedText(props.config.label, locale.value));
|
|
27
|
+
const placeholderText = computed(
|
|
28
|
+
() => props.config.placeholder ? getLocalizedText(props.config.placeholder, locale.value) : void 0
|
|
29
|
+
);
|
|
30
|
+
const tooltipText = computed(() => {
|
|
31
|
+
const raw = props.config.tooltip ? getLocalizedText(props.config.tooltip, locale.value) : void 0;
|
|
32
|
+
return raw ? interpolateMarkdown(raw, $cel, { form: formScope.state.value ?? {} }) : void 0;
|
|
33
|
+
});
|
|
34
|
+
function evalBool(expression, label) {
|
|
35
|
+
if (!expression) return false;
|
|
36
|
+
try {
|
|
37
|
+
return Effect.runSync($cel(expression, { form: formScope.state.value ?? {} }));
|
|
38
|
+
} catch (err) {
|
|
39
|
+
console.error(`[shwfed-form] failed to evaluate ${label} for ${props.fieldId}:`, err);
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const isDisabled = computed(() => evalBool(props.config.disabled, "disabled"));
|
|
44
|
+
const formReadonly = useFormReadonly();
|
|
45
|
+
const isReadonly = computed(
|
|
46
|
+
() => props.config.readonly != null ? evalBool(props.config.readonly, "readonly") : formReadonly.value
|
|
47
|
+
);
|
|
48
|
+
const effectiveReadonly = computed(() => isReadonly.value || props.config.derived?.mode === "formula");
|
|
49
|
+
const { draft, commit } = useFieldValue({
|
|
50
|
+
binding: () => props.config.binding,
|
|
51
|
+
fromState: (raw) => raw == null ? "" : String(raw),
|
|
52
|
+
toState: (next) => next.length === 0 ? null : next
|
|
53
|
+
});
|
|
54
|
+
const features = computed(() => resolveFeatures(props.config));
|
|
55
|
+
const featureKey = computed(() => featureSignature(features.value));
|
|
56
|
+
const { isRequired, errors, warnings, visible } = useFieldValidation({
|
|
57
|
+
fieldId: () => props.fieldId,
|
|
58
|
+
config: () => props.config,
|
|
59
|
+
$cel,
|
|
60
|
+
locale: () => locale.value
|
|
61
|
+
});
|
|
62
|
+
</script>
|
|
63
|
+
|
|
64
|
+
<template>
|
|
65
|
+
<Field
|
|
66
|
+
orientation="vertical"
|
|
67
|
+
:data-disabled="isDisabled || void 0"
|
|
68
|
+
>
|
|
69
|
+
<FieldLabel
|
|
70
|
+
v-if="labelText"
|
|
71
|
+
:for="fieldId"
|
|
72
|
+
class="text-xs text-zinc-500"
|
|
73
|
+
>
|
|
74
|
+
<template
|
|
75
|
+
v-if="tooltipText"
|
|
76
|
+
#tooltip
|
|
77
|
+
>
|
|
78
|
+
<Markdown
|
|
79
|
+
:source="tooltipText"
|
|
80
|
+
class="prose prose-xs prose-zinc"
|
|
81
|
+
/>
|
|
82
|
+
</template>
|
|
83
|
+
{{ labelText }}<span
|
|
84
|
+
v-if="isRequired"
|
|
85
|
+
aria-hidden="true"
|
|
86
|
+
class="text-red-600"
|
|
87
|
+
> *</span>
|
|
88
|
+
</FieldLabel>
|
|
89
|
+
<div
|
|
90
|
+
v-if="effectiveReadonly"
|
|
91
|
+
data-slot="field-value"
|
|
92
|
+
data-value="true"
|
|
93
|
+
class="min-h-9 py-1.5 text-sm"
|
|
94
|
+
>
|
|
95
|
+
<div
|
|
96
|
+
v-if="draft"
|
|
97
|
+
class="prose prose-sm prose-zinc max-w-none"
|
|
98
|
+
v-html="draft"
|
|
99
|
+
/>
|
|
100
|
+
<span
|
|
101
|
+
v-else
|
|
102
|
+
class="font-mono text-zinc-300 select-none"
|
|
103
|
+
>-</span>
|
|
104
|
+
</div>
|
|
105
|
+
<RichTextEditor
|
|
106
|
+
v-else
|
|
107
|
+
:id="fieldId"
|
|
108
|
+
:key="featureKey"
|
|
109
|
+
v-model="draft"
|
|
110
|
+
:features="features"
|
|
111
|
+
:placeholder="placeholderText"
|
|
112
|
+
:editable="!isDisabled"
|
|
113
|
+
@blur="commit"
|
|
114
|
+
/>
|
|
115
|
+
<FieldMessages
|
|
116
|
+
v-if="visible"
|
|
117
|
+
:errors="errors"
|
|
118
|
+
:warnings="warnings"
|
|
119
|
+
/>
|
|
120
|
+
</Field>
|
|
121
|
+
</template>
|
|
@@ -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-07-18/com.shwfed.form.field.richtext/schema.d.ts
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { Schema } from 'effect';
|
|
2
|
+
import type { Environment } from '../../../../../vendor/cel-js/lib/index.js';
|
|
3
|
+
export declare const type: "com.shwfed.form.field.richtext";
|
|
4
|
+
export declare const compatibilityDate: "2026-07-18";
|
|
5
|
+
export declare const metadata: {
|
|
6
|
+
readonly name: "富文本";
|
|
7
|
+
readonly icon: "fluent:text-edit-style-20-regular";
|
|
8
|
+
readonly description: "所见即所得的富文本输入,读写 HTML 字符串;行内样式与列表可逐项开关";
|
|
9
|
+
readonly w: {
|
|
10
|
+
readonly initial: 12;
|
|
11
|
+
readonly min: 6;
|
|
12
|
+
readonly max: number;
|
|
13
|
+
};
|
|
14
|
+
readonly h: {
|
|
15
|
+
readonly initial: 8;
|
|
16
|
+
readonly min: 4;
|
|
17
|
+
readonly max: number;
|
|
18
|
+
readonly grow: true;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* What the toolbar may offer, split the way the editor actually works on it:
|
|
23
|
+
* `inline` decorates a text range, `block` restructures the document.
|
|
24
|
+
*
|
|
25
|
+
* Unchecking one withdraws the *means of authoring* it — the button is not
|
|
26
|
+
* rendered and the keyboard shortcut is unbound — but the mark or node stays
|
|
27
|
+
* registered on the schema. Dropping the extension outright would make
|
|
28
|
+
* ProseMirror discard the tag while parsing existing content, so merely
|
|
29
|
+
* opening a record authored before the box was unchecked would silently strip
|
|
30
|
+
* it and the next save would persist the loss.
|
|
31
|
+
*
|
|
32
|
+
* Alignment and indentation are in neither list: they are always-on toolbar
|
|
33
|
+
* furniture, not capabilities to negotiate.
|
|
34
|
+
*/
|
|
35
|
+
export declare const INLINE_FEATURES: readonly ["bold", "italic", "underline", "strike"];
|
|
36
|
+
export declare const BLOCK_FEATURES: readonly ["bulletList", "orderedList"];
|
|
37
|
+
export type InlineFeature = typeof INLINE_FEATURES[number];
|
|
38
|
+
export type BlockFeature = typeof BLOCK_FEATURES[number];
|
|
39
|
+
export declare function schema(configure: (env: Environment) => void): Schema.Struct<{
|
|
40
|
+
label: Schema.optional<Schema.suspend<readonly [{
|
|
41
|
+
readonly locale: "zh";
|
|
42
|
+
readonly message: string;
|
|
43
|
+
}, ...{
|
|
44
|
+
readonly locale: "en" | "ja" | "ko";
|
|
45
|
+
readonly message: string;
|
|
46
|
+
}[]], string | readonly [{
|
|
47
|
+
readonly locale: "zh";
|
|
48
|
+
readonly message: string;
|
|
49
|
+
}, ...{
|
|
50
|
+
readonly locale: "en" | "ja" | "ko";
|
|
51
|
+
readonly message: string;
|
|
52
|
+
}[]], never>>;
|
|
53
|
+
placeholder: Schema.optional<Schema.suspend<readonly [{
|
|
54
|
+
readonly locale: "zh";
|
|
55
|
+
readonly message: string;
|
|
56
|
+
}, ...{
|
|
57
|
+
readonly locale: "en" | "ja" | "ko";
|
|
58
|
+
readonly message: string;
|
|
59
|
+
}[]], string | readonly [{
|
|
60
|
+
readonly locale: "zh";
|
|
61
|
+
readonly message: string;
|
|
62
|
+
}, ...{
|
|
63
|
+
readonly locale: "en" | "ja" | "ko";
|
|
64
|
+
readonly message: string;
|
|
65
|
+
}[]], never>>;
|
|
66
|
+
tooltip: Schema.optional<Schema.refine<readonly [{
|
|
67
|
+
readonly locale: "zh";
|
|
68
|
+
readonly message: string;
|
|
69
|
+
}, ...{
|
|
70
|
+
readonly locale: "en" | "ja" | "ko";
|
|
71
|
+
readonly message: string;
|
|
72
|
+
}[]], Schema.suspend<readonly [{
|
|
73
|
+
readonly locale: "zh";
|
|
74
|
+
readonly message: string;
|
|
75
|
+
}, ...{
|
|
76
|
+
readonly locale: "en" | "ja" | "ko";
|
|
77
|
+
readonly message: string;
|
|
78
|
+
}[]], string | readonly [{
|
|
79
|
+
readonly locale: "zh";
|
|
80
|
+
readonly message: string;
|
|
81
|
+
}, ...{
|
|
82
|
+
readonly locale: "en" | "ja" | "ko";
|
|
83
|
+
readonly message: string;
|
|
84
|
+
}[]], never>>>;
|
|
85
|
+
binding: Schema.optional<Schema.refine<string, typeof Schema.String>>;
|
|
86
|
+
inline: Schema.Array$<Schema.Literal<["bold", "italic", "underline", "strike"]>>;
|
|
87
|
+
block: Schema.Array$<Schema.Literal<["bulletList", "orderedList"]>>;
|
|
88
|
+
disabled: Schema.optional<Schema.Schema<string, string, never>>;
|
|
89
|
+
readonly: Schema.optional<Schema.Schema<string, string, never>>;
|
|
90
|
+
derived: Schema.optional<Schema.Struct<{
|
|
91
|
+
mode: Schema.Literal<["formula", "prefill"]>;
|
|
92
|
+
expression: Schema.Schema<string, string, never>;
|
|
93
|
+
}>>;
|
|
94
|
+
id: Schema.refine<string, typeof Schema.String>;
|
|
95
|
+
displayName: Schema.optional<Schema.SchemaClass<string, string, never>>;
|
|
96
|
+
hidden: Schema.optional<Schema.Schema<string, string, never>>;
|
|
97
|
+
required: Schema.optional<Schema.Schema<string, string, never>>;
|
|
98
|
+
validations: Schema.optional<Schema.Array$<Schema.Struct<{
|
|
99
|
+
when: Schema.Schema<string, string, never>;
|
|
100
|
+
warning: Schema.optional<Schema.SchemaClass<boolean, boolean, never>>;
|
|
101
|
+
message: Schema.refine<readonly [{
|
|
102
|
+
readonly locale: "zh";
|
|
103
|
+
readonly message: string;
|
|
104
|
+
}, ...{
|
|
105
|
+
readonly locale: "en" | "ja" | "ko";
|
|
106
|
+
readonly message: string;
|
|
107
|
+
}[]], Schema.suspend<readonly [{
|
|
108
|
+
readonly locale: "zh";
|
|
109
|
+
readonly message: string;
|
|
110
|
+
}, ...{
|
|
111
|
+
readonly locale: "en" | "ja" | "ko";
|
|
112
|
+
readonly message: string;
|
|
113
|
+
}[]], string | readonly [{
|
|
114
|
+
readonly locale: "zh";
|
|
115
|
+
readonly message: string;
|
|
116
|
+
}, ...{
|
|
117
|
+
readonly locale: "en" | "ja" | "ko";
|
|
118
|
+
readonly message: string;
|
|
119
|
+
}[]], never>>;
|
|
120
|
+
}>>>;
|
|
121
|
+
type: Schema.Literal<["com.shwfed.form.field.richtext"]>;
|
|
122
|
+
compatibilityDate: Schema.Literal<["2026-07-18"]>;
|
|
123
|
+
}>;
|
|
124
|
+
export type Value = Schema.Schema.Type<ReturnType<typeof schema>>;
|
|
125
|
+
/**
|
|
126
|
+
* Creation-time seed. Required because `inline` and `block` are required
|
|
127
|
+
* fields beyond identity — without this the picker would mint a bare
|
|
128
|
+
* `{ id, type, compatibilityDate }` that fails its own schema.
|
|
129
|
+
*
|
|
130
|
+
* Everything starts enabled: a new editor should be fully capable, and the
|
|
131
|
+
* author narrows it down rather than opting in one feature at a time.
|
|
132
|
+
*/
|
|
133
|
+
export declare function defaults(): Partial<Value>;
|
package/dist/runtime/components/form/fields/2026-07-18/com.shwfed.form.field.richtext/schema.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
import { LocaleMarkdown, Expression } from "../../../../../share/expression.js";
|
|
3
|
+
import { Locale } from "../../../../../share/locale.js";
|
|
4
|
+
import { commonFieldFields, derivedField } from "../../../utils/common.js";
|
|
5
|
+
export const type = "com.shwfed.form.field.richtext";
|
|
6
|
+
export const compatibilityDate = "2026-07-18";
|
|
7
|
+
export const metadata = {
|
|
8
|
+
name: "\u5BCC\u6587\u672C",
|
|
9
|
+
icon: "fluent:text-edit-style-20-regular",
|
|
10
|
+
description: "\u6240\u89C1\u5373\u6240\u5F97\u7684\u5BCC\u6587\u672C\u8F93\u5165\uFF0C\u8BFB\u5199 HTML \u5B57\u7B26\u4E32\uFF1B\u884C\u5185\u6837\u5F0F\u4E0E\u5217\u8868\u53EF\u9010\u9879\u5F00\u5173",
|
|
11
|
+
w: { initial: 12, min: 6, max: Infinity },
|
|
12
|
+
h: { initial: 8, min: 4, max: Infinity, grow: true }
|
|
13
|
+
};
|
|
14
|
+
export const INLINE_FEATURES = ["bold", "italic", "underline", "strike"];
|
|
15
|
+
export const BLOCK_FEATURES = ["bulletList", "orderedList"];
|
|
16
|
+
export function schema(configure) {
|
|
17
|
+
const CelBool = Expression({ configure, resultType: "bool" });
|
|
18
|
+
return Schema.Struct({
|
|
19
|
+
type: Schema.Literal(type),
|
|
20
|
+
compatibilityDate: Schema.Literal(compatibilityDate),
|
|
21
|
+
...commonFieldFields(configure),
|
|
22
|
+
label: Schema.optional(Locale.annotations({
|
|
23
|
+
title: "\u6807\u7B7E",
|
|
24
|
+
description: "\u5B57\u6BB5\u524D\u5C55\u793A\u7684\u6587\u672C\uFF1B\u7559\u7A7A\u5219\u4E0D\u6E32\u67D3\u6807\u7B7E"
|
|
25
|
+
})),
|
|
26
|
+
placeholder: Schema.optional(Locale.annotations({
|
|
27
|
+
title: "\u5360\u4F4D\u7B26",
|
|
28
|
+
description: "\u6B63\u6587\u4E3A\u7A7A\u65F6\u5C55\u793A\u7684\u5360\u4F4D\u6587\u672C"
|
|
29
|
+
})),
|
|
30
|
+
tooltip: Schema.optional(LocaleMarkdown({ configure }).annotations({
|
|
31
|
+
title: "\u63D0\u793A",
|
|
32
|
+
description: "\u9F20\u6807\u60AC\u505C\u5728\u6807\u7B7E\u4E0A\u65F6\u5C55\u793A\u7684\u8BF4\u660E"
|
|
33
|
+
})),
|
|
34
|
+
binding: Schema.optional(Schema.String.pipe(Schema.minLength(1)).annotations({
|
|
35
|
+
title: "\u7ED1\u5B9A\u8DEF\u5F84",
|
|
36
|
+
description: "\u5199\u5165\u8868\u5355\u72B6\u6001\u7684 `dot-prop` \u8DEF\u5F84\uFF0C\u4F8B\u5982 `article.body`\uFF1B\u5199\u5165\u7684\u503C\u662F HTML \u5B57\u7B26\u4E32\uFF0C\u6B63\u6587\u4E3A\u7A7A\u65F6\u5199\u5165 `null`\u3002\u7559\u7A7A\u5219\u4E3A\u975E\u53D7\u63A7\u5B57\u6BB5\uFF0C\u4E0D\u5199\u5165\u8868\u5355\u72B6\u6001"
|
|
37
|
+
})),
|
|
38
|
+
inline: Schema.Array(Schema.Literal(...INLINE_FEATURES)).annotations({
|
|
39
|
+
title: "\u884C\u5185\u6837\u5F0F",
|
|
40
|
+
description: "\u5DE5\u5177\u680F\u5F00\u653E\u7684\u884C\u5185\u6837\u5F0F\uFF1A\u52A0\u7C97\u3001\u659C\u4F53\u3001\u4E0B\u5212\u7EBF\u3001\u5220\u9664\u7EBF\u3002\u53D6\u6D88\u52FE\u9009\u53EA\u662F\u6536\u56DE\u300C\u5199\u300D\u7684\u5165\u53E3\u2014\u2014\u6309\u94AE\u4E0D\u518D\u6E32\u67D3\u3001\u5FEB\u6377\u952E\u4E00\u5E76\u89E3\u7ED1\u2014\u2014\u5B58\u91CF\u5185\u5BB9\u91CC\u5DF2\u6709\u7684\u6837\u5F0F\u4ECD\u7136\u7167\u5E38\u89E3\u6790\u4E0E\u4FDD\u5B58\uFF0C\u4E0D\u4F1A\u88AB\u6E05\u6D17\u6389"
|
|
41
|
+
}),
|
|
42
|
+
block: Schema.Array(Schema.Literal(...BLOCK_FEATURES)).annotations({
|
|
43
|
+
title: "\u5757\u7EA7\u529F\u80FD",
|
|
44
|
+
description: "\u5DE5\u5177\u680F\u5F00\u653E\u7684\u5757\u7EA7\u529F\u80FD\uFF1A\u65E0\u5E8F\u5217\u8868\u3001\u6709\u5E8F\u5217\u8868\u3002\u5DE6\u53F3\u5BF9\u9F50\u4E0E\u7F29\u8FDB\u662F\u5E38\u9A7B\u529F\u80FD\uFF0C\u4E0D\u5728\u6B64\u5217"
|
|
45
|
+
}),
|
|
46
|
+
disabled: Schema.optional(CelBool.annotations({
|
|
47
|
+
title: "\u7981\u7528\u6761\u4EF6",
|
|
48
|
+
description: "\u8FD4\u56DE `true` \u65F6\u7F16\u8F91\u5668\u4ECD\u7136\u6E32\u67D3\u4F46\u4E0D\u53EF\u7F16\u8F91\uFF0C\u5DE5\u5177\u680F\u4E00\u5E76\u7981\u7528"
|
|
49
|
+
})),
|
|
50
|
+
readonly: Schema.optional(CelBool.annotations({
|
|
51
|
+
title: "\u53EA\u8BFB\u6761\u4EF6",
|
|
52
|
+
description: "\u8FD4\u56DE `true` \u65F6\u9690\u85CF\u5DE5\u5177\u680F\uFF0C\u4EC5\u6E32\u67D3\u6B63\u6587 HTML"
|
|
53
|
+
})),
|
|
54
|
+
derived: derivedField(configure, "string")
|
|
55
|
+
}).annotations({
|
|
56
|
+
title: "RichTextField",
|
|
57
|
+
description: "\u5BCC\u6587\u672C\u8F93\u5165\uFF0C\u503C\u4E3A HTML \u5B57\u7B26\u4E32"
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
export function defaults() {
|
|
61
|
+
return {
|
|
62
|
+
inline: [...INLINE_FEATURES],
|
|
63
|
+
block: [...BLOCK_FEATURES]
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -2,6 +2,7 @@ import { Effect, Either, Option } from "effect";
|
|
|
2
2
|
import { Fetch } from "fx-fetch";
|
|
3
3
|
import { toast } from "vue-sonner";
|
|
4
4
|
import { asRequest } from "../../../../share/request.js";
|
|
5
|
+
import { IDEMPOTENCY_KEY_HEADER, mintIdempotencyKey } from "../../../../share/idempotency-key.js";
|
|
5
6
|
import { getLocalizedText } from "../../../../share/locale.js";
|
|
6
7
|
import { interpolateMarkdown } from "../../../../share/interpolate.js";
|
|
7
8
|
class HttpRequestHalted {
|
|
@@ -11,24 +12,35 @@ class HttpRequestHalted {
|
|
|
11
12
|
_tag = "HttpRequestHalted";
|
|
12
13
|
}
|
|
13
14
|
const TOAST_STYLES = /* @__PURE__ */ new Set(["success", "error", "warning", "info"]);
|
|
15
|
+
const KEYLESS_METHODS = /* @__PURE__ */ new Set(["GET", "HEAD", "OPTIONS", "TRACE"]);
|
|
16
|
+
function applyIdempotencyKey(request, key) {
|
|
17
|
+
const { method, headers } = request.describe();
|
|
18
|
+
if (KEYLESS_METHODS.has(method.toUpperCase())) return;
|
|
19
|
+
const target = IDEMPOTENCY_KEY_HEADER.toLowerCase();
|
|
20
|
+
if (headers.some(([name]) => name.toLowerCase() === target)) return;
|
|
21
|
+
request.header(IDEMPOTENCY_KEY_HEADER, key);
|
|
22
|
+
}
|
|
14
23
|
export const handler = (params, ctx) => {
|
|
15
24
|
const { expression, resultExpression, titleExpression, description } = params ?? {};
|
|
16
25
|
if (!expression || expression.trim().length === 0) return Effect.void;
|
|
17
26
|
const program = Effect.gen(function* () {
|
|
18
27
|
const steps = ctx.step?.outputs() ?? {};
|
|
19
|
-
const
|
|
28
|
+
const idempotencyKey = ctx.step?.idempotencyKey() ?? mintIdempotencyKey();
|
|
29
|
+
const scope = { steps, idempotencyKey };
|
|
30
|
+
const evaluated = yield* ctx.cel(expression, scope);
|
|
20
31
|
const request = asRequest(evaluated);
|
|
21
32
|
if (Option.isNone(request)) return;
|
|
33
|
+
applyIdempotencyKey(request.value, idempotencyKey);
|
|
22
34
|
const outcome = yield* Effect.either(request.value.json());
|
|
23
35
|
const json = Either.isRight(outcome) ? outcome.right : null;
|
|
24
36
|
if (Either.isRight(outcome)) ctx.step?.publish(json);
|
|
25
|
-
const result = Either.isLeft(outcome) ? "error" : resultExpression === void 0 ? "success" : yield* ctx.cel(resultExpression, {
|
|
37
|
+
const result = Either.isLeft(outcome) ? "error" : resultExpression === void 0 ? "success" : yield* ctx.cel(resultExpression, { ...scope, json });
|
|
26
38
|
const kind = TOAST_STYLES.has(result) ? result : "success";
|
|
27
39
|
if (titleExpression !== void 0) {
|
|
28
|
-
const title = yield* ctx.cel(titleExpression, { json, result
|
|
40
|
+
const title = yield* ctx.cel(titleExpression, { ...scope, json, result });
|
|
29
41
|
if (title.length > 0) {
|
|
30
42
|
const raw = getLocalizedText(description, ctx.locale()) ?? "";
|
|
31
|
-
const body = raw.length === 0 ? void 0 : interpolateMarkdown(raw, ctx.cel, { json, result
|
|
43
|
+
const body = raw.length === 0 ? void 0 : interpolateMarkdown(raw, ctx.cel, { ...scope, json, result });
|
|
32
44
|
toast[kind](title, body === void 0 ? void 0 : { description: body });
|
|
33
45
|
}
|
|
34
46
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Schema } from "effect";
|
|
2
2
|
import { Expression, LocaleMarkdown } from "../../../../share/expression.js";
|
|
3
3
|
import { md } from "../../../../share/markdown.js";
|
|
4
|
-
import { registerStepsVariableIfAbsent } from "../../utils/step-vars.js";
|
|
4
|
+
import { registerIdempotencyKeyVariableIfAbsent, registerStepsVariableIfAbsent } from "../../utils/step-vars.js";
|
|
5
5
|
export const type = "com.shwfed.operation.http.request.json";
|
|
6
6
|
export const compatibilityDate = "2026-06-11";
|
|
7
7
|
export const metadata = {
|
|
@@ -9,13 +9,14 @@ export const metadata = {
|
|
|
9
9
|
icon: "fluent:cloud-arrow-up-20-regular",
|
|
10
10
|
description: "\u53D1\u9001\u4E00\u4E2A HTTP \u8BF7\u6C42\uFF1B\u5176\u89E3\u6790\u540E\u7684\u54CD\u5E94\u4F53\u4F5C\u4E3A\u94FE\u6B65\u8F93\u51FA\uFF0C\u540E\u7EED\u6B65\u9AA4\u53EF\u7528 steps \u5F15\u7528",
|
|
11
11
|
// This op publishes its parsed response as a chain-step output, so later
|
|
12
|
-
// trigger rows can reference it via `steps[
|
|
12
|
+
// trigger rows can reference it via `steps["<row-id>"]`.
|
|
13
13
|
output: "HTTP \u54CD\u5E94\uFF08\u89E3\u6790\u540E\u7684 JSON\uFF09"
|
|
14
14
|
};
|
|
15
15
|
export function schema(configure) {
|
|
16
16
|
const withSteps = (env) => {
|
|
17
17
|
configure(env);
|
|
18
18
|
registerStepsVariableIfAbsent(env);
|
|
19
|
+
registerIdempotencyKeyVariableIfAbsent(env);
|
|
19
20
|
};
|
|
20
21
|
const CelHttpRequest = Expression({ configure: withSteps, resultType: "HttpRequest" });
|
|
21
22
|
const withJson = (env) => {
|
|
@@ -70,10 +71,16 @@ export function schema(configure) {
|
|
|
70
71
|
description: md`
|
|
71
72
|
发起一次 HTTP 请求(响应解析为 JSON)。请求失败(网络错误 / 非 2xx / 响应不可解析)
|
|
72
73
|
或「执行结果」为 \`error\` 时中止本次触发链。在触发列表中串联多个本操作即可按顺序
|
|
73
|
-
调用多个接口——前一个失败后,后续操作不再执行。后面的步骤可经 \`steps[
|
|
74
|
+
调用多个接口——前一个失败后,后续操作不再执行。后面的步骤可经 \`steps["<步骤标识>"]\`
|
|
74
75
|
引用前面步骤的响应。
|
|
75
76
|
|
|
76
77
|
toast 完全由「提示标题」「提示内容」决定(含失败场景);不配置标题、或标题求值为空字符串则静默。
|
|
78
|
+
|
|
79
|
+
写请求(\`POST\` / \`PUT\` / \`PATCH\` / \`DELETE\`)自动附带 \`Idempotency-Key\`
|
|
80
|
+
请求头——值是本步在本次运行中的幂等键,同一次运行内固定、重新触发则改变,
|
|
81
|
+
服务端可据此识别重发、避免重复落库。\`GET\` 不带(本就幂等,且会平白触发
|
|
82
|
+
跨域预检)。需要把它放进**请求体**的接口,用 \`idempotencyKey\` 变量自行拼进
|
|
83
|
+
「请求」表达式即可——与请求头取到的是同一个值。
|
|
77
84
|
`
|
|
78
85
|
});
|
|
79
86
|
}
|
package/dist/runtime/components/operations/2026-06-15/com.shwfed.operation.http.download/schema.js
CHANGED
|
@@ -40,7 +40,7 @@ export function schema(configure) {
|
|
|
40
40
|
title: "\u8BF7\u6C42",
|
|
41
41
|
description: md`
|
|
42
42
|
构造一个请求,其响应将被取回并保存为文件。
|
|
43
|
-
可经 \`steps[
|
|
43
|
+
可经 \`steps["<步骤标识>"]\` 引用前序步骤的输出——把先前
|
|
44
44
|
\`发送请求\` 行取得的凭据用于构造真正的下载请求。
|
|
45
45
|
`
|
|
46
46
|
}),
|
|
@@ -76,7 +76,7 @@ export function schema(configure) {
|
|
|
76
76
|
发起一次 HTTP 请求:若响应是二进制(非 JSON)则保存为本地文件;若响应是 JSON,
|
|
77
77
|
则视为后端返回的状态信封,经「执行结果」裁定成败而**不**保存。下载失败(网络错误 / 非 2xx)
|
|
78
78
|
或「执行结果」为 \`error\` 会中止本次触发链——其后排队的操作不再执行。把本操作接在一个
|
|
79
|
-
\`发送请求\` 行之后、并经 \`steps[
|
|
79
|
+
\`发送请求\` 行之后、并经 \`steps["<步骤标识>"]\` 引用其响应,即可实现
|
|
80
80
|
“先取凭据再下载”的两步式。toast 完全由「提示标题」「提示内容」决定(含失败场景);
|
|
81
81
|
不配置标题、或标题求值为空字符串则静默。
|
|
82
82
|
`
|
package/dist/runtime/components/operations/2026-06-15/com.shwfed.operation.navigation/schema.js
CHANGED
|
@@ -29,7 +29,7 @@ export function schema(configure) {
|
|
|
29
29
|
}).annotations({
|
|
30
30
|
title: "NavigationOperation",
|
|
31
31
|
description: md`
|
|
32
|
-
按所选方式打开一个链接。链接表达式可经 \`steps[
|
|
32
|
+
按所选方式打开一个链接。链接表达式可经 \`steps["<步骤标识>"]\` 引用前序步骤的输出,
|
|
33
33
|
因此可由先前请求的响应拼接目标地址。导航失败不中止本次触发链。
|
|
34
34
|
`
|
|
35
35
|
});
|
|
@@ -35,7 +35,7 @@ export type OperationMetadata = Readonly<{
|
|
|
35
35
|
description?: string;
|
|
36
36
|
/**
|
|
37
37
|
* Present iff this operation publishes a chain-step output (`ctx.step.publish`)
|
|
38
|
-
* for later trigger rows to read via `steps[
|
|
38
|
+
* for later trigger rows to read via `steps["<row-id>"]` — the value is the
|
|
39
39
|
* designer-facing label of what gets published (e.g. 'HTTP 响应'). The trigger
|
|
40
40
|
* editor reads it to decide which rows to offer as step references, so a
|
|
41
41
|
* non-publishing op never advertises a reference that resolves to nothing.
|
|
@@ -6,12 +6,10 @@ import { type CELVar } from '../../../utils/cel-context.js';
|
|
|
6
6
|
* an op schema may be embedded under a host whose `configure` already
|
|
7
7
|
* advertises it, and double registration throws.
|
|
8
8
|
*
|
|
9
|
-
* `dyn` (not `map<string, dyn>`) so `steps[
|
|
9
|
+
* `dyn` (not `map<string, dyn>`) so `steps["<id>"].data.code` type-checks the
|
|
10
10
|
* same way `form.foo.bar` does — what a step publishes is backend-defined and
|
|
11
11
|
* unknowable at design time. Keyed by trigger-row uuid; the picker renders
|
|
12
|
-
* each key as its「第 N 步」position
|
|
13
|
-
* a step that published nothing evaluates to `undefined` instead of throwing
|
|
14
|
-
* `No such key`.
|
|
12
|
+
* each key as its「第 N 步」position.
|
|
15
13
|
*/
|
|
16
14
|
export declare function registerStepsVariableIfAbsent(env: Environment): void;
|
|
17
15
|
/**
|
|
@@ -22,3 +20,17 @@ export declare function registerStepsVariableIfAbsent(env: Environment): void;
|
|
|
22
20
|
* context channel at all — the op handler passes it as an evaluation extra.
|
|
23
21
|
*/
|
|
24
22
|
export declare function stepsCelVar(): CELVar;
|
|
23
|
+
/**
|
|
24
|
+
* Register the `idempotencyKey` variable on `env`, skipping it when already
|
|
25
|
+
* declared — idempotent for the same reason as the `steps` variant.
|
|
26
|
+
*
|
|
27
|
+
* `string` (not `dyn`): unlike `steps`, the shape is ours and fully known, so
|
|
28
|
+
* a typo like `idempotencyKey.value` should fail the editor's inline check
|
|
29
|
+
* rather than defer to runtime.
|
|
30
|
+
*/
|
|
31
|
+
export declare function registerIdempotencyKeyVariableIfAbsent(env: Environment): void;
|
|
32
|
+
/**
|
|
33
|
+
* The design-time CELVar cell for `idempotencyKey`. The value shown in the
|
|
34
|
+
* picker is a placeholder — the real key does not exist until the chain runs.
|
|
35
|
+
*/
|
|
36
|
+
export declare function idempotencyKeyCelVar(): CELVar;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { STEPS_VAR } from "../../../utils/cel-context.js";
|
|
1
|
+
import { IDEMPOTENCY_KEY_VAR, STEPS_VAR } from "../../../utils/cel-context.js";
|
|
2
2
|
const STEPS_VAR_META = {
|
|
3
3
|
label: "\u524D\u5E8F\u6B65\u9AA4",
|
|
4
4
|
description: "\u672C\u6B21\u89E6\u53D1\u94FE\u4E2D\u524D\u5E8F\u6B65\u9AA4\u53D1\u5E03\u7684\u8F93\u51FA\uFF08\u6309\u6B65\u9AA4\u6807\u8BC6\uFF09"
|
|
@@ -10,3 +10,16 @@ export function registerStepsVariableIfAbsent(env) {
|
|
|
10
10
|
export function stepsCelVar() {
|
|
11
11
|
return { type: "dyn", ...STEPS_VAR_META, value: void 0 };
|
|
12
12
|
}
|
|
13
|
+
const IDEMPOTENCY_KEY_VAR_META = {
|
|
14
|
+
label: "\u5E42\u7B49\u952E",
|
|
15
|
+
description: "\u672C\u6B65\u5728\u672C\u6B21\u8FD0\u884C\u4E2D\u7684\u5E42\u7B49\u952E\uFF08UUID\uFF09\uFF1B\u540C\u4E00\u6B21\u8FD0\u884C\u5185\u56FA\u5B9A\uFF0C\u91CD\u65B0\u89E6\u53D1\u5373\u6539\u53D8"
|
|
16
|
+
};
|
|
17
|
+
export function registerIdempotencyKeyVariableIfAbsent(env) {
|
|
18
|
+
const declared = new Set(env.getDefinitions().variables.map((v) => v.name));
|
|
19
|
+
if (!declared.has(IDEMPOTENCY_KEY_VAR)) {
|
|
20
|
+
env.registerVariable(IDEMPOTENCY_KEY_VAR, "string", IDEMPOTENCY_KEY_VAR_META);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function idempotencyKeyCelVar() {
|
|
24
|
+
return { type: "string", ...IDEMPOTENCY_KEY_VAR_META, value: "" };
|
|
25
|
+
}
|
|
@@ -53,9 +53,9 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
|
|
|
53
53
|
readonly locale: "en" | "ja" | "ko";
|
|
54
54
|
readonly message: string;
|
|
55
55
|
}[]];
|
|
56
|
-
readonly successMessage?: string | undefined;
|
|
57
56
|
readonly accessor?: string | undefined;
|
|
58
57
|
readonly sortKey?: string | undefined;
|
|
58
|
+
readonly successMessage?: string | undefined;
|
|
59
59
|
}) => any;
|
|
60
60
|
}, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
|
|
61
61
|
"onUpdate:modelValue"?: ((value: {
|
|
@@ -108,9 +108,9 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
|
|
|
108
108
|
readonly locale: "en" | "ja" | "ko";
|
|
109
109
|
readonly message: string;
|
|
110
110
|
}[]];
|
|
111
|
-
readonly successMessage?: string | undefined;
|
|
112
111
|
readonly accessor?: string | undefined;
|
|
113
112
|
readonly sortKey?: string | undefined;
|
|
113
|
+
readonly successMessage?: string | undefined;
|
|
114
114
|
}) => any) | undefined;
|
|
115
115
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
116
116
|
declare const _default: typeof __VLS_export;
|