@dou-ui/form-builder 0.0.0-stage → 0.1.0-alpha.0
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/LICENSE +21 -0
- package/README.md +10 -2
- package/dist/builder/canvas.js +695 -0
- package/dist/builder/canvas.js.map +1 -0
- package/dist/builder/completion.js +49 -0
- package/dist/builder/completion.js.map +1 -0
- package/dist/builder/condition-editor.js +6 -0
- package/dist/builder/condition-editor.js.map +1 -0
- package/dist/builder/condition-editor.vue_vue_type_script_setup_true_lang.js +410 -0
- package/dist/builder/condition-editor.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/builder/condition.js +159 -0
- package/dist/builder/condition.js.map +1 -0
- package/dist/builder/context.js +477 -0
- package/dist/builder/context.js.map +1 -0
- package/dist/builder/core/commands.js +373 -0
- package/dist/builder/core/commands.js.map +1 -0
- package/dist/builder/core/history.js +76 -0
- package/dist/builder/core/history.js.map +1 -0
- package/dist/builder/core/transaction.js +298 -0
- package/dist/builder/core/transaction.js.map +1 -0
- package/dist/builder/drag.js +466 -0
- package/dist/builder/drag.js.map +1 -0
- package/dist/builder/expression-box.js +19 -0
- package/dist/builder/expression-box.js.map +1 -0
- package/dist/builder/expression-input.js +6 -0
- package/dist/builder/expression-input.js.map +1 -0
- package/dist/builder/expression-input.vue_vue_type_script_setup_true_lang.js +117 -0
- package/dist/builder/expression-input.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/builder/extension.js +47 -0
- package/dist/builder/extension.js.map +1 -0
- package/dist/builder/form-builder.js +6 -0
- package/dist/builder/form-builder.js.map +1 -0
- package/dist/builder/form-builder.vue_vue_type_script_setup_true_lang.js +450 -0
- package/dist/builder/form-builder.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/builder/index.js +22 -0
- package/dist/builder/index.js.map +1 -0
- package/dist/builder/inspector.js +6 -0
- package/dist/builder/inspector.js.map +1 -0
- package/dist/builder/inspector.vue_vue_type_script_setup_true_lang.js +442 -0
- package/dist/builder/inspector.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/builder/json-dialog.js +6 -0
- package/dist/builder/json-dialog.js.map +1 -0
- package/dist/builder/json-dialog.vue_vue_type_script_setup_true_lang.js +281 -0
- package/dist/builder/json-dialog.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/builder/locale.js +1271 -0
- package/dist/builder/locale.js.map +1 -0
- package/dist/builder/logic-fields.js +18 -0
- package/dist/builder/logic-fields.js.map +1 -0
- package/dist/builder/logic.js +332 -0
- package/dist/builder/logic.js.map +1 -0
- package/dist/builder/menu.js +92 -0
- package/dist/builder/menu.js.map +1 -0
- package/dist/builder/outline-row.js +6 -0
- package/dist/builder/outline-row.js.map +1 -0
- package/dist/builder/outline-row.vue_vue_type_script_setup_true_lang.js +88 -0
- package/dist/builder/outline-row.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/builder/outline.js +6 -0
- package/dist/builder/outline.js.map +1 -0
- package/dist/builder/outline.vue_vue_type_script_setup_true_lang.js +111 -0
- package/dist/builder/outline.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/builder/palette.js +6 -0
- package/dist/builder/palette.js.map +1 -0
- package/dist/builder/palette.vue_vue_type_script_setup_true_lang.js +96 -0
- package/dist/builder/palette.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/builder/preview.js +6 -0
- package/dist/builder/preview.js.map +1 -0
- package/dist/builder/preview.vue_vue_type_script_setup_true_lang.js +111 -0
- package/dist/builder/preview.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/builder/settings-binding.js +57 -0
- package/dist/builder/settings-binding.js.map +1 -0
- package/dist/builder/settings.js +487 -0
- package/dist/builder/settings.js.map +1 -0
- package/dist/builder/span-field.js +104 -0
- package/dist/builder/span-field.js.map +1 -0
- package/dist/code/expression-input.js +6 -0
- package/dist/code/expression-input.js.map +1 -0
- package/dist/code/expression-input.vue_vue_type_script_setup_true_lang.js +88 -0
- package/dist/code/expression-input.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/code/extension.js +202 -0
- package/dist/code/extension.js.map +1 -0
- package/dist/code/index.js +19 -0
- package/dist/code/index.js.map +1 -0
- package/dist/code/language.js +43 -0
- package/dist/code/language.js.map +1 -0
- package/dist/collaboration/index.js +382 -0
- package/dist/collaboration/index.js.map +1 -0
- package/dist/collaboration/order.js +88 -0
- package/dist/collaboration/order.js.map +1 -0
- package/dist/core/check.js +314 -0
- package/dist/core/check.js.map +1 -0
- package/dist/core/document.js +112 -0
- package/dist/core/document.js.map +1 -0
- package/dist/core/expression.js +854 -0
- package/dist/core/expression.js.map +1 -0
- package/dist/core/formulas.js +242 -0
- package/dist/core/formulas.js.map +1 -0
- package/dist/core/rules.js +83 -0
- package/dist/core/rules.js.map +1 -0
- package/dist/core/values.js +80 -0
- package/dist/core/values.js.map +1 -0
- package/dist/fields/builtin.js +167 -0
- package/dist/fields/builtin.js.map +1 -0
- package/dist/fields/components.js +155 -0
- package/dist/fields/components.js.map +1 -0
- package/dist/fields/define.js +44 -0
- package/dist/fields/define.js.map +1 -0
- package/dist/fields/format.js +125 -0
- package/dist/fields/format.js.map +1 -0
- package/dist/fields/options.js +54 -0
- package/dist/fields/options.js.map +1 -0
- package/dist/index.js +20 -0
- package/dist/locale.js +161 -0
- package/dist/locale.js.map +1 -0
- package/dist/renderer/containers.js +430 -0
- package/dist/renderer/containers.js.map +1 -0
- package/dist/renderer/context.js +21 -0
- package/dist/renderer/context.js.map +1 -0
- package/dist/renderer/form-renderer.js +6 -0
- package/dist/renderer/form-renderer.js.map +1 -0
- package/dist/renderer/form-renderer.vue_vue_type_script_setup_true_lang.js +272 -0
- package/dist/renderer/form-renderer.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/renderer/index.js +19 -0
- package/dist/renderer/index.js.map +1 -0
- package/dist/renderer/node-view.js +385 -0
- package/dist/renderer/node-view.js.map +1 -0
- package/dist/style.css +1 -0
- package/dist/style.d.ts +1 -0
- package/dist/style.js +27 -0
- package/dist/types/builder/canvas.d.ts +5 -0
- package/dist/types/builder/completion.d.ts +35 -0
- package/dist/types/builder/condition-editor.vue.d.ts +17 -0
- package/dist/types/builder/condition.d.ts +37 -0
- package/dist/types/builder/context.d.ts +149 -0
- package/dist/types/builder/core/commands.d.ts +74 -0
- package/dist/types/builder/core/history.d.ts +23 -0
- package/dist/types/builder/core/transaction.d.ts +108 -0
- package/dist/types/builder/drag.d.ts +52 -0
- package/dist/types/builder/expression-box.d.ts +8 -0
- package/dist/types/builder/expression-input.vue.d.ts +29 -0
- package/dist/types/builder/extension.d.ts +149 -0
- package/dist/types/builder/form-builder.vue.d.ts +24 -0
- package/dist/types/builder/index.d.ts +76 -0
- package/dist/types/builder/inspector.vue.d.ts +3 -0
- package/dist/types/builder/json-dialog.vue.d.ts +10 -0
- package/dist/types/builder/locale.d.ts +195 -0
- package/dist/types/builder/logic-fields.d.ts +2 -0
- package/dist/types/builder/logic.d.ts +57 -0
- package/dist/types/builder/menu.d.ts +23 -0
- package/dist/types/builder/outline-row.vue.d.ts +19 -0
- package/dist/types/builder/outline.vue.d.ts +3 -0
- package/dist/types/builder/palette.vue.d.ts +3 -0
- package/dist/types/builder/preview.vue.d.ts +3 -0
- package/dist/types/builder/settings-binding.d.ts +23 -0
- package/dist/types/builder/settings.d.ts +49 -0
- package/dist/types/builder/span-field.d.ts +4 -0
- package/dist/types/builder/types.d.ts +59 -0
- package/dist/types/code/expression-input.vue.d.ts +23 -0
- package/dist/types/code/extension.d.ts +45 -0
- package/dist/types/code/index.d.ts +12 -0
- package/dist/types/code/language.d.ts +6 -0
- package/dist/types/collaboration/index.d.ts +64 -0
- package/dist/types/collaboration/order.d.ts +20 -0
- package/dist/types/core/check.d.ts +68 -0
- package/dist/types/core/document.d.ts +36 -0
- package/dist/types/core/expression.d.ts +175 -0
- package/dist/types/core/formulas.d.ts +44 -0
- package/dist/types/core/rules.d.ts +23 -0
- package/dist/types/core/types.d.ts +211 -0
- package/dist/types/core/values.d.ts +22 -0
- package/dist/types/fields/builtin.d.ts +9 -0
- package/dist/types/fields/components.d.ts +177 -0
- package/dist/types/fields/define.d.ts +93 -0
- package/dist/types/fields/format.d.ts +76 -0
- package/dist/types/fields/options.d.ts +11 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/locale.d.ts +45 -0
- package/dist/types/renderer/containers.d.ts +20 -0
- package/dist/types/renderer/context.d.ts +186 -0
- package/dist/types/renderer/form-renderer.vue.d.ts +25 -0
- package/dist/types/renderer/index.d.ts +81 -0
- package/dist/types/renderer/node-view.d.ts +56 -0
- package/package.json +88 -4
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
import { resolveFields } from "../fields/builtin.js";
|
|
2
|
+
import { builderKey, createBuilderState } from "./context.js";
|
|
3
|
+
import { resolveFormBuilderExtensions } from "./extension.js";
|
|
4
|
+
import json_dialog_default from "./json-dialog.js";
|
|
5
|
+
import preview_default from "./preview.js";
|
|
6
|
+
import { useFormBuilderMessages } from "./locale.js";
|
|
7
|
+
import { FormBuilderCanvas } from "./canvas.js";
|
|
8
|
+
import inspector_default from "./inspector.js";
|
|
9
|
+
import outline_default from "./outline.js";
|
|
10
|
+
import palette_default from "./palette.js";
|
|
11
|
+
import { DouDrawer, DouPopover, DouTabPanel, DouTabs, DouTooltip } from "dou-ui";
|
|
12
|
+
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, nextTick, normalizeClass, onBeforeUnmount, onMounted, openBlock, provide, ref, renderList, renderSlot, resolveDynamicComponent, shallowRef, toDisplayString, unref, useId, watch, withCtx } from "vue";
|
|
13
|
+
import { BracesIcon, EyeIcon, ListChecksIcon, PanelLeftIcon, RedoIcon, SlidersIcon, UndoIcon } from "@dou-ui/icons";
|
|
14
|
+
// src/builder/form-builder.vue?vue&type=script&setup=true&lang.ts
|
|
15
|
+
var _hoisted_1 = { class: "dou-form-builder__layout" };
|
|
16
|
+
var _hoisted_2 = ["aria-label"];
|
|
17
|
+
var _hoisted_3 = { class: "dou-form-builder__main" };
|
|
18
|
+
var _hoisted_4 = {
|
|
19
|
+
class: "dou-form-builder__toolbar",
|
|
20
|
+
role: "toolbar"
|
|
21
|
+
};
|
|
22
|
+
var _hoisted_5 = {
|
|
23
|
+
type: "button",
|
|
24
|
+
class: "dou-form-builder__tool dou-form-builder__side-toggle"
|
|
25
|
+
};
|
|
26
|
+
var _hoisted_6 = ["disabled", "aria-label"];
|
|
27
|
+
var _hoisted_7 = ["disabled", "aria-label"];
|
|
28
|
+
var _hoisted_8 = [
|
|
29
|
+
"disabled",
|
|
30
|
+
"aria-pressed",
|
|
31
|
+
"aria-label",
|
|
32
|
+
"onClick"
|
|
33
|
+
];
|
|
34
|
+
var _hoisted_9 = { key: 1 };
|
|
35
|
+
var _hoisted_10 = ["aria-pressed", "aria-label"];
|
|
36
|
+
var _hoisted_11 = ["aria-label"];
|
|
37
|
+
var _hoisted_12 = ["aria-label"];
|
|
38
|
+
var _hoisted_13 = ["aria-pressed"];
|
|
39
|
+
var _hoisted_14 = ["aria-label"];
|
|
40
|
+
var _hoisted_15 = {
|
|
41
|
+
class: "dou-form-builder__live",
|
|
42
|
+
"aria-live": "polite",
|
|
43
|
+
"aria-atomic": "true"
|
|
44
|
+
};
|
|
45
|
+
var form_builder_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
|
|
46
|
+
name: "DouFormBuilder",
|
|
47
|
+
__name: "form-builder",
|
|
48
|
+
props: {
|
|
49
|
+
modelValue: {},
|
|
50
|
+
selection: {},
|
|
51
|
+
fields: {},
|
|
52
|
+
mode: {},
|
|
53
|
+
functions: {},
|
|
54
|
+
sources: {},
|
|
55
|
+
validators: {},
|
|
56
|
+
readonly: {
|
|
57
|
+
type: Boolean,
|
|
58
|
+
default: false
|
|
59
|
+
},
|
|
60
|
+
extensions: {},
|
|
61
|
+
messages: {}
|
|
62
|
+
},
|
|
63
|
+
emits: [
|
|
64
|
+
"update:modelValue",
|
|
65
|
+
"update:selection",
|
|
66
|
+
"update:mode",
|
|
67
|
+
"change"
|
|
68
|
+
],
|
|
69
|
+
setup(__props, { expose: __expose, emit: __emit }) {
|
|
70
|
+
const FormBuilderCanvas$1 = FormBuilderCanvas;
|
|
71
|
+
const props = __props;
|
|
72
|
+
const emit = __emit;
|
|
73
|
+
const extensions = computed(() => resolveFormBuilderExtensions(props.extensions));
|
|
74
|
+
const fields = computed(() => resolveFields([...props.fields ?? [], ...extensions.value.fields]));
|
|
75
|
+
const messages = useFormBuilderMessages(() => props.messages);
|
|
76
|
+
const ownMode = ref("design");
|
|
77
|
+
const mode = computed(() => props.mode ?? ownMode.value);
|
|
78
|
+
const previewing = computed(() => mode.value === "preview");
|
|
79
|
+
const state = createBuilderState({
|
|
80
|
+
uid: `dou-form-builder-${useId()}`,
|
|
81
|
+
document: () => props.modelValue,
|
|
82
|
+
selection: () => props.selection,
|
|
83
|
+
fields: () => fields.value,
|
|
84
|
+
messages: () => messages.value,
|
|
85
|
+
emitDocument: (document, tr) => {
|
|
86
|
+
emit("update:modelValue", document);
|
|
87
|
+
emit("change", tr);
|
|
88
|
+
},
|
|
89
|
+
emitSelection: (ids) => emit("update:selection", ids),
|
|
90
|
+
mode: () => mode.value,
|
|
91
|
+
emitMode: (next) => {
|
|
92
|
+
ownMode.value = next;
|
|
93
|
+
emit("update:mode", next);
|
|
94
|
+
},
|
|
95
|
+
functions: () => props.functions,
|
|
96
|
+
sources: () => props.sources,
|
|
97
|
+
validators: () => props.validators,
|
|
98
|
+
readonly: () => props.readonly,
|
|
99
|
+
extensions: () => extensions.value
|
|
100
|
+
});
|
|
101
|
+
provide(builderKey, state);
|
|
102
|
+
const jsonOpen = ref(false);
|
|
103
|
+
const toolbarItems = computed(() => extensions.value.toolbars.flatMap((toolbar) => toolbar(state)));
|
|
104
|
+
const stops = [];
|
|
105
|
+
let mounted = false;
|
|
106
|
+
let setUp = false;
|
|
107
|
+
let setupTimes = [];
|
|
108
|
+
let setupWarned = false;
|
|
109
|
+
/** An extension made in the template is new on every render, and set up again each time. */
|
|
110
|
+
function warnRepeatedSetup() {
|
|
111
|
+
if (process.env.NODE_ENV === "production" || setupWarned) return;
|
|
112
|
+
const now = Date.now();
|
|
113
|
+
setupTimes = [...setupTimes.filter((time) => now - time < 1e3), now];
|
|
114
|
+
if (setupTimes.length < 4) return;
|
|
115
|
+
setupWarned = true;
|
|
116
|
+
console.warn("[@dou-ui/form-builder] the extensions keep being set up again, which also clears undo each time. Create them once in <script setup> instead of in the template.");
|
|
117
|
+
}
|
|
118
|
+
function teardownExtensions() {
|
|
119
|
+
for (const stop of stops.splice(0)) stop();
|
|
120
|
+
}
|
|
121
|
+
function setupExtensions() {
|
|
122
|
+
if (setUp) warnRepeatedSetup();
|
|
123
|
+
setUp = true;
|
|
124
|
+
teardownExtensions();
|
|
125
|
+
for (const setup of extensions.value.setups) {
|
|
126
|
+
const stop = setup(state);
|
|
127
|
+
if (typeof stop === "function") stops.push(stop);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
onMounted(() => {
|
|
131
|
+
mounted = true;
|
|
132
|
+
setupExtensions();
|
|
133
|
+
});
|
|
134
|
+
watch(() => [extensions.value.history, ...extensions.value.setups], (hooks, before) => {
|
|
135
|
+
if (mounted && (hooks.length !== before.length || hooks.some((hook, i) => hook !== before[i]))) setupExtensions();
|
|
136
|
+
});
|
|
137
|
+
onBeforeUnmount(teardownExtensions);
|
|
138
|
+
const side = ref("fields");
|
|
139
|
+
const sideLabel = computed(() => props.readonly ? messages.value.panels.outline : messages.value.panels.fields);
|
|
140
|
+
const sideTitle = computed(() => props.readonly ? messages.value.panels.outline : messages.value.panels.side);
|
|
141
|
+
const sideOpen = ref(false);
|
|
142
|
+
const root = shallowRef(null);
|
|
143
|
+
const compact = ref(false);
|
|
144
|
+
const settingsOpen = ref(false);
|
|
145
|
+
let observer;
|
|
146
|
+
onMounted(() => {
|
|
147
|
+
if (typeof ResizeObserver === "undefined" || !root.value) return;
|
|
148
|
+
observer = new ResizeObserver(([entry]) => {
|
|
149
|
+
compact.value = (entry?.contentRect.width ?? Infinity) < 560;
|
|
150
|
+
});
|
|
151
|
+
observer.observe(root.value);
|
|
152
|
+
});
|
|
153
|
+
onBeforeUnmount(() => observer?.disconnect());
|
|
154
|
+
watch(compact, (on) => {
|
|
155
|
+
if (!on) state.tapToggles.value = false;
|
|
156
|
+
});
|
|
157
|
+
function onCanvasClick(event) {
|
|
158
|
+
if (!compact.value || state.tapToggles.value || state.dragger.value?.swallowClick()) return;
|
|
159
|
+
if (!event.target.closest(".dou-form-builder__node") || event.target.closest(".dou-form-builder__actions")) return;
|
|
160
|
+
nextTick(() => {
|
|
161
|
+
if (state.focused.value) settingsOpen.value = true;
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
watch(() => state.selection, () => {
|
|
165
|
+
if (!sideOpen.value) return;
|
|
166
|
+
sideOpen.value = false;
|
|
167
|
+
nextTick(() => state.canvas.value?.focus({ preventScroll: true }));
|
|
168
|
+
});
|
|
169
|
+
const { transaction, dispatch, select, add, remove, duplicate, moveBy, moveTo, replace, wrap, addPage, selectParent, undo, redo, shownPage, setMode } = state;
|
|
170
|
+
__expose({
|
|
171
|
+
get document() {
|
|
172
|
+
return state.document;
|
|
173
|
+
},
|
|
174
|
+
get selection() {
|
|
175
|
+
return state.selection;
|
|
176
|
+
},
|
|
177
|
+
get fields() {
|
|
178
|
+
return state.fields;
|
|
179
|
+
},
|
|
180
|
+
get messages() {
|
|
181
|
+
return state.messages;
|
|
182
|
+
},
|
|
183
|
+
get canUndo() {
|
|
184
|
+
return state.canUndo;
|
|
185
|
+
},
|
|
186
|
+
get canRedo() {
|
|
187
|
+
return state.canRedo;
|
|
188
|
+
},
|
|
189
|
+
get readonly() {
|
|
190
|
+
return state.readonly;
|
|
191
|
+
},
|
|
192
|
+
get mode() {
|
|
193
|
+
return state.mode;
|
|
194
|
+
},
|
|
195
|
+
setMode,
|
|
196
|
+
transaction,
|
|
197
|
+
dispatch,
|
|
198
|
+
select,
|
|
199
|
+
add,
|
|
200
|
+
remove,
|
|
201
|
+
duplicate,
|
|
202
|
+
moveBy,
|
|
203
|
+
moveTo,
|
|
204
|
+
replace,
|
|
205
|
+
wrap,
|
|
206
|
+
addPage,
|
|
207
|
+
selectParent,
|
|
208
|
+
undo,
|
|
209
|
+
redo,
|
|
210
|
+
shownPage
|
|
211
|
+
});
|
|
212
|
+
return (_ctx, _cache) => {
|
|
213
|
+
return openBlock(), createElementBlock("div", {
|
|
214
|
+
ref_key: "root",
|
|
215
|
+
ref: root,
|
|
216
|
+
class: normalizeClass([
|
|
217
|
+
"dou-form-builder",
|
|
218
|
+
compact.value && "is-compact",
|
|
219
|
+
previewing.value && "is-previewing",
|
|
220
|
+
__props.readonly && "is-readonly"
|
|
221
|
+
])
|
|
222
|
+
}, [
|
|
223
|
+
renderSlot(_ctx.$slots, "default", {}, () => [createElementVNode("div", _hoisted_1, [
|
|
224
|
+
!previewing.value ? (openBlock(), createElementBlock("aside", {
|
|
225
|
+
key: 0,
|
|
226
|
+
class: "dou-form-builder__side",
|
|
227
|
+
"aria-label": sideTitle.value
|
|
228
|
+
}, [__props.readonly ? (openBlock(), createBlock(outline_default, { key: 0 })) : (openBlock(), createBlock(unref(DouTabs), {
|
|
229
|
+
key: 1,
|
|
230
|
+
modelValue: side.value,
|
|
231
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => side.value = $event),
|
|
232
|
+
size: "sm",
|
|
233
|
+
class: "dou-form-builder__side-tabs"
|
|
234
|
+
}, {
|
|
235
|
+
default: withCtx(() => [createVNode(unref(DouTabPanel), {
|
|
236
|
+
value: "fields",
|
|
237
|
+
label: unref(messages).panels.fields
|
|
238
|
+
}, {
|
|
239
|
+
default: withCtx(() => [createVNode(palette_default)]),
|
|
240
|
+
_: 1
|
|
241
|
+
}, 8, ["label"]), createVNode(unref(DouTabPanel), {
|
|
242
|
+
value: "outline",
|
|
243
|
+
label: unref(messages).panels.outline
|
|
244
|
+
}, {
|
|
245
|
+
default: withCtx(() => [createVNode(outline_default)]),
|
|
246
|
+
_: 1
|
|
247
|
+
}, 8, ["label"])]),
|
|
248
|
+
_: 1
|
|
249
|
+
}, 8, ["modelValue"]))], 8, _hoisted_2)) : createCommentVNode("", true),
|
|
250
|
+
createElementVNode("div", _hoisted_3, [createElementVNode("div", _hoisted_4, [
|
|
251
|
+
previewing.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [], 64)) : compact.value ? (openBlock(), createElementBlock("button", {
|
|
252
|
+
key: 1,
|
|
253
|
+
type: "button",
|
|
254
|
+
class: "dou-form-builder__tool dou-form-builder__side-toggle",
|
|
255
|
+
"aria-haspopup": "dialog",
|
|
256
|
+
onClick: _cache[1] || (_cache[1] = ($event) => sideOpen.value = true)
|
|
257
|
+
}, [createVNode(unref(PanelLeftIcon)), createElementVNode("span", null, toDisplayString(sideLabel.value), 1)])) : (openBlock(), createBlock(unref(DouPopover), {
|
|
258
|
+
key: 2,
|
|
259
|
+
open: sideOpen.value,
|
|
260
|
+
"onUpdate:open": _cache[3] || (_cache[3] = ($event) => sideOpen.value = $event),
|
|
261
|
+
placement: "bottom-start",
|
|
262
|
+
"aria-label": sideTitle.value,
|
|
263
|
+
class: "dou-form-builder__side-popover"
|
|
264
|
+
}, {
|
|
265
|
+
content: withCtx(() => [__props.readonly ? (openBlock(), createBlock(outline_default, { key: 0 })) : (openBlock(), createBlock(unref(DouTabs), {
|
|
266
|
+
key: 1,
|
|
267
|
+
modelValue: side.value,
|
|
268
|
+
"onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => side.value = $event),
|
|
269
|
+
size: "sm",
|
|
270
|
+
class: "dou-form-builder__side-tabs"
|
|
271
|
+
}, {
|
|
272
|
+
default: withCtx(() => [createVNode(unref(DouTabPanel), {
|
|
273
|
+
value: "fields",
|
|
274
|
+
label: unref(messages).panels.fields
|
|
275
|
+
}, {
|
|
276
|
+
default: withCtx(() => [createVNode(palette_default)]),
|
|
277
|
+
_: 1
|
|
278
|
+
}, 8, ["label"]), createVNode(unref(DouTabPanel), {
|
|
279
|
+
value: "outline",
|
|
280
|
+
label: unref(messages).panels.outline
|
|
281
|
+
}, {
|
|
282
|
+
default: withCtx(() => [createVNode(outline_default)]),
|
|
283
|
+
_: 1
|
|
284
|
+
}, 8, ["label"])]),
|
|
285
|
+
_: 1
|
|
286
|
+
}, 8, ["modelValue"]))]),
|
|
287
|
+
default: withCtx(() => [createElementVNode("button", _hoisted_5, [createVNode(unref(PanelLeftIcon)), createElementVNode("span", null, toDisplayString(sideLabel.value), 1)])]),
|
|
288
|
+
_: 1
|
|
289
|
+
}, 8, ["open", "aria-label"])),
|
|
290
|
+
!previewing.value && !__props.readonly ? (openBlock(), createElementBlock(Fragment, { key: 3 }, [createVNode(unref(DouTooltip), {
|
|
291
|
+
content: unref(messages).actions.undo,
|
|
292
|
+
shortcut: "mod+z",
|
|
293
|
+
placement: "bottom"
|
|
294
|
+
}, {
|
|
295
|
+
default: withCtx(() => [createElementVNode("button", {
|
|
296
|
+
type: "button",
|
|
297
|
+
class: "dou-form-builder__tool",
|
|
298
|
+
disabled: !unref(state).canUndo,
|
|
299
|
+
"aria-label": unref(messages).actions.undo,
|
|
300
|
+
onClick: _cache[4] || (_cache[4] = ($event) => unref(state).undo())
|
|
301
|
+
}, [createVNode(unref(UndoIcon))], 8, _hoisted_6)]),
|
|
302
|
+
_: 1
|
|
303
|
+
}, 8, ["content"]), createVNode(unref(DouTooltip), {
|
|
304
|
+
content: unref(messages).actions.redo,
|
|
305
|
+
shortcut: "mod+shift+z",
|
|
306
|
+
placement: "bottom"
|
|
307
|
+
}, {
|
|
308
|
+
default: withCtx(() => [createElementVNode("button", {
|
|
309
|
+
type: "button",
|
|
310
|
+
class: "dou-form-builder__tool",
|
|
311
|
+
disabled: !unref(state).canRedo,
|
|
312
|
+
"aria-label": unref(messages).actions.redo,
|
|
313
|
+
onClick: _cache[5] || (_cache[5] = ($event) => unref(state).redo())
|
|
314
|
+
}, [createVNode(unref(RedoIcon))], 8, _hoisted_7)]),
|
|
315
|
+
_: 1
|
|
316
|
+
}, 8, ["content"])], 64)) : createCommentVNode("", true),
|
|
317
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(toolbarItems.value, (item) => {
|
|
318
|
+
return openBlock(), createBlock(unref(DouTooltip), {
|
|
319
|
+
key: item.key,
|
|
320
|
+
content: item.label,
|
|
321
|
+
shortcut: item.shortcut,
|
|
322
|
+
disabled: !item.icon && !item.shortcut,
|
|
323
|
+
placement: "bottom"
|
|
324
|
+
}, {
|
|
325
|
+
default: withCtx(() => [createElementVNode("button", {
|
|
326
|
+
type: "button",
|
|
327
|
+
class: "dou-form-builder__tool",
|
|
328
|
+
disabled: item.disabled,
|
|
329
|
+
"aria-pressed": item.pressed,
|
|
330
|
+
"aria-label": item.icon ? item.label : void 0,
|
|
331
|
+
onClick: ($event) => item.run()
|
|
332
|
+
}, [item.icon ? (openBlock(), createBlock(resolveDynamicComponent(item.icon), { key: 0 })) : (openBlock(), createElementBlock("span", _hoisted_9, toDisplayString(item.label), 1))], 8, _hoisted_8)]),
|
|
333
|
+
_: 2
|
|
334
|
+
}, 1032, [
|
|
335
|
+
"content",
|
|
336
|
+
"shortcut",
|
|
337
|
+
"disabled"
|
|
338
|
+
]);
|
|
339
|
+
}), 128)),
|
|
340
|
+
renderSlot(_ctx.$slots, "toolbar"),
|
|
341
|
+
_cache[14] || (_cache[14] = createElementVNode("span", { class: "dou-form-builder__toolbar-spacer" }, null, -1)),
|
|
342
|
+
compact.value && !previewing.value ? (openBlock(), createElementBlock(Fragment, { key: 4 }, [createVNode(unref(DouTooltip), {
|
|
343
|
+
content: unref(messages).actions.selectMany,
|
|
344
|
+
placement: "bottom"
|
|
345
|
+
}, {
|
|
346
|
+
default: withCtx(() => [createElementVNode("button", {
|
|
347
|
+
type: "button",
|
|
348
|
+
class: "dou-form-builder__tool dou-form-builder__select-toggle",
|
|
349
|
+
"aria-pressed": unref(state).tapToggles.value,
|
|
350
|
+
"aria-label": unref(messages).actions.selectMany,
|
|
351
|
+
onClick: _cache[6] || (_cache[6] = ($event) => unref(state).tapToggles.value = !unref(state).tapToggles.value)
|
|
352
|
+
}, [createVNode(unref(ListChecksIcon))], 8, _hoisted_10)]),
|
|
353
|
+
_: 1
|
|
354
|
+
}, 8, ["content"]), createVNode(unref(DouTooltip), {
|
|
355
|
+
content: unref(messages).panels.settings,
|
|
356
|
+
placement: "bottom"
|
|
357
|
+
}, {
|
|
358
|
+
default: withCtx(() => [createElementVNode("button", {
|
|
359
|
+
type: "button",
|
|
360
|
+
class: "dou-form-builder__tool dou-form-builder__settings-toggle",
|
|
361
|
+
"aria-haspopup": "dialog",
|
|
362
|
+
"aria-label": unref(messages).panels.settings,
|
|
363
|
+
onClick: _cache[7] || (_cache[7] = ($event) => settingsOpen.value = true)
|
|
364
|
+
}, [createVNode(unref(SlidersIcon))], 8, _hoisted_11)]),
|
|
365
|
+
_: 1
|
|
366
|
+
}, 8, ["content"])], 64)) : createCommentVNode("", true),
|
|
367
|
+
createVNode(unref(DouTooltip), {
|
|
368
|
+
content: unref(messages).json.title,
|
|
369
|
+
placement: "bottom"
|
|
370
|
+
}, {
|
|
371
|
+
default: withCtx(() => [createElementVNode("button", {
|
|
372
|
+
type: "button",
|
|
373
|
+
class: "dou-form-builder__tool",
|
|
374
|
+
"aria-haspopup": "dialog",
|
|
375
|
+
"aria-label": unref(messages).json.title,
|
|
376
|
+
onClick: _cache[8] || (_cache[8] = ($event) => jsonOpen.value = true)
|
|
377
|
+
}, [createVNode(unref(BracesIcon))], 8, _hoisted_12)]),
|
|
378
|
+
_: 1
|
|
379
|
+
}, 8, ["content"]),
|
|
380
|
+
createElementVNode("button", {
|
|
381
|
+
type: "button",
|
|
382
|
+
class: "dou-form-builder__tool dou-form-builder__preview-toggle",
|
|
383
|
+
"aria-pressed": previewing.value,
|
|
384
|
+
onClick: _cache[9] || (_cache[9] = ($event) => unref(state).setMode(previewing.value ? "design" : "preview"))
|
|
385
|
+
}, [createVNode(unref(EyeIcon)), createElementVNode("span", null, toDisplayString(unref(messages).preview.toggle), 1)], 8, _hoisted_13)
|
|
386
|
+
]), previewing.value ? (openBlock(), createBlock(preview_default, { key: 0 })) : (openBlock(), createBlock(unref(FormBuilderCanvas$1), {
|
|
387
|
+
key: 1,
|
|
388
|
+
onClickCapture: onCanvasClick
|
|
389
|
+
}))]),
|
|
390
|
+
!compact.value && !previewing.value ? (openBlock(), createElementBlock("aside", {
|
|
391
|
+
key: 1,
|
|
392
|
+
class: "dou-form-builder__side dou-form-builder__side--end",
|
|
393
|
+
"aria-label": unref(messages).panels.settings
|
|
394
|
+
}, [createVNode(inspector_default)], 8, _hoisted_14)) : createCommentVNode("", true)
|
|
395
|
+
]), compact.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createVNode(unref(DouDrawer), {
|
|
396
|
+
open: sideOpen.value,
|
|
397
|
+
"onUpdate:open": _cache[11] || (_cache[11] = ($event) => sideOpen.value = $event),
|
|
398
|
+
placement: "bottom",
|
|
399
|
+
title: sideTitle.value,
|
|
400
|
+
"snap-points": ["50%", "90%"],
|
|
401
|
+
swipeable: "",
|
|
402
|
+
class: "dou-form-builder__drawer"
|
|
403
|
+
}, {
|
|
404
|
+
default: withCtx(() => [__props.readonly ? (openBlock(), createBlock(outline_default, { key: 0 })) : (openBlock(), createBlock(unref(DouTabs), {
|
|
405
|
+
key: 1,
|
|
406
|
+
modelValue: side.value,
|
|
407
|
+
"onUpdate:modelValue": _cache[10] || (_cache[10] = ($event) => side.value = $event),
|
|
408
|
+
size: "sm",
|
|
409
|
+
class: "dou-form-builder__side-tabs"
|
|
410
|
+
}, {
|
|
411
|
+
default: withCtx(() => [createVNode(unref(DouTabPanel), {
|
|
412
|
+
value: "fields",
|
|
413
|
+
label: unref(messages).panels.fields
|
|
414
|
+
}, {
|
|
415
|
+
default: withCtx(() => [createVNode(palette_default)]),
|
|
416
|
+
_: 1
|
|
417
|
+
}, 8, ["label"]), createVNode(unref(DouTabPanel), {
|
|
418
|
+
value: "outline",
|
|
419
|
+
label: unref(messages).panels.outline
|
|
420
|
+
}, {
|
|
421
|
+
default: withCtx(() => [createVNode(outline_default)]),
|
|
422
|
+
_: 1
|
|
423
|
+
}, 8, ["label"])]),
|
|
424
|
+
_: 1
|
|
425
|
+
}, 8, ["modelValue"]))]),
|
|
426
|
+
_: 1
|
|
427
|
+
}, 8, ["open", "title"]), createVNode(unref(DouDrawer), {
|
|
428
|
+
open: settingsOpen.value,
|
|
429
|
+
"onUpdate:open": _cache[12] || (_cache[12] = ($event) => settingsOpen.value = $event),
|
|
430
|
+
placement: "bottom",
|
|
431
|
+
title: unref(messages).panels.settings,
|
|
432
|
+
"snap-points": ["50%", "90%"],
|
|
433
|
+
swipeable: "",
|
|
434
|
+
class: "dou-form-builder__drawer"
|
|
435
|
+
}, {
|
|
436
|
+
default: withCtx(() => [createVNode(inspector_default)]),
|
|
437
|
+
_: 1
|
|
438
|
+
}, 8, ["open", "title"])], 64)) : createCommentVNode("", true)]),
|
|
439
|
+
createVNode(json_dialog_default, {
|
|
440
|
+
open: jsonOpen.value,
|
|
441
|
+
"onUpdate:open": _cache[13] || (_cache[13] = ($event) => jsonOpen.value = $event)
|
|
442
|
+
}, null, 8, ["open"]),
|
|
443
|
+
createElementVNode("div", _hoisted_15, toDisplayString(unref(state).live.value), 1)
|
|
444
|
+
], 2);
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
export { form_builder_vue_vue_type_script_setup_true_lang_default as default };
|
|
449
|
+
|
|
450
|
+
//# sourceMappingURL=form-builder.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form-builder.vue_vue_type_script_setup_true_lang.js","names":["FormBuilderCanvas","FormBuilderCanvasComponent","_openBlock","_createElementBlock","_normalizeClass","_renderSlot","_createElementVNode","_createBlock","FormBuilderOutline","_unref","_withCtx","_createVNode","FormBuilderPalette","_createCommentVNode","_Fragment","_toDisplayString","_renderList","_resolveDynamicComponent","FormBuilderPreview","FormBuilderInspector","FormBuilderJson"],"sources":["../../src/builder/form-builder.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n computed,\n nextTick,\n onBeforeUnmount,\n onMounted,\n provide,\n ref,\n shallowRef,\n useId,\n watch,\n} from 'vue'\nimport { DouDrawer, DouPopover, DouTabPanel, DouTabs, DouTooltip } from 'dou-ui'\nimport {\n BracesIcon,\n EyeIcon,\n ListChecksIcon,\n PanelLeftIcon,\n RedoIcon,\n SlidersIcon,\n UndoIcon,\n} from '@dou-ui/icons'\nimport { resolveFields } from '../fields/builtin'\nimport { createBuilderState, builderKey } from './context'\nimport type { FormBuilderMode } from './context'\nimport { resolveFormBuilderExtensions } from './extension'\nimport FormBuilderJson from './json-dialog.vue'\nimport FormBuilderPreview from './preview.vue'\nimport { useFormBuilderMessages } from './locale'\nimport { FormBuilderCanvas as FormBuilderCanvasComponent } from './canvas'\nimport type { HTMLAttributes } from 'vue'\nimport type { WithAttributes } from 'dou-ui'\nimport FormBuilderInspector from './inspector.vue'\nimport FormBuilderOutline from './outline.vue'\nimport FormBuilderPalette from './palette.vue'\nimport type {\n FormBuilderEmits,\n FormBuilderExpose,\n FormBuilderProps,\n FormBuilderSlots,\n} from './types'\n\n// 让模板里也能写这个组件转交的原生属性\nconst FormBuilderCanvas = FormBuilderCanvasComponent as WithAttributes<\n typeof FormBuilderCanvasComponent,\n HTMLAttributes\n>\n\ndefineOptions({ name: 'DouFormBuilder' })\n\nconst props = withDefaults(defineProps<FormBuilderProps>(), { readonly: false })\nconst emit = defineEmits<FormBuilderEmits>()\ndefineSlots<FormBuilderSlots>()\n\nconst extensions = computed(() => resolveFormBuilderExtensions(props.extensions))\nconst fields = computed(() => resolveFields([...(props.fields ?? []), ...extensions.value.fields]))\nconst messages = useFormBuilderMessages(() => props.messages)\n\n// The mode follows `v-model:mode` when it is bound, else the builder's own.\nconst ownMode = ref<FormBuilderMode>('design')\nconst mode = computed(() => props.mode ?? ownMode.value)\nconst previewing = computed(() => mode.value === 'preview')\n\nconst state = createBuilderState({\n uid: `dou-form-builder-${useId()}`,\n document: () => props.modelValue,\n selection: () => props.selection,\n fields: () => fields.value,\n messages: () => messages.value,\n emitDocument: (document, tr) => {\n emit('update:modelValue', document)\n emit('change', tr)\n },\n emitSelection: (ids) => emit('update:selection', ids),\n mode: () => mode.value,\n emitMode: (next) => {\n ownMode.value = next\n emit('update:mode', next)\n },\n functions: () => props.functions,\n sources: () => props.sources,\n validators: () => props.validators,\n readonly: () => props.readonly,\n extensions: () => extensions.value,\n})\nprovide(builderKey, state)\n\nconst jsonOpen = ref(false)\nconst toolbarItems = computed(() => extensions.value.toolbars.flatMap((toolbar) => toolbar(state)))\n\n// Extensions start once the builder is mounted, again when their hooks change, and stop when it goes.\nconst stops: (() => void)[] = []\nlet mounted = false\nlet setUp = false\nlet setupTimes: number[] = []\nlet setupWarned = false\n/** An extension made in the template is new on every render, and set up again each time. */\nfunction warnRepeatedSetup() {\n // the app's bundler replaces this, as for Vue's own warnings\n if (process.env.NODE_ENV === 'production' || setupWarned) return\n const now = Date.now()\n setupTimes = [...setupTimes.filter((time) => now - time < 1000), now]\n if (setupTimes.length < 4) return\n setupWarned = true\n console.warn(\n '[@dou-ui/form-builder] the extensions keep being set up again, which also clears undo each time. Create them once in <script setup> instead of in the template.',\n )\n}\nfunction teardownExtensions() {\n for (const stop of stops.splice(0)) stop()\n}\nfunction setupExtensions() {\n if (setUp) warnRepeatedSetup()\n setUp = true\n teardownExtensions()\n for (const setup of extensions.value.setups) {\n const stop = setup(state)\n if (typeof stop === 'function') stops.push(stop)\n }\n}\nonMounted(() => {\n mounted = true\n setupExtensions()\n})\n// A list written inline is new on every render; set up again only when the hooks change.\nwatch(\n () => [extensions.value.history, ...extensions.value.setups],\n (hooks, before) => {\n if (mounted && (hooks.length !== before.length || hooks.some((hook, i) => hook !== before[i])))\n setupExtensions()\n },\n)\nonBeforeUnmount(teardownExtensions)\n\nconst side = ref<'fields' | 'outline'>('fields')\n// A read-only builder has nothing to add, so its side panel is the outline alone.\nconst sideLabel = computed(() =>\n props.readonly ? messages.value.panels.outline : messages.value.panels.fields,\n)\nconst sideTitle = computed(() =>\n props.readonly ? messages.value.panels.outline : messages.value.panels.side,\n)\n// On narrow builders the fields and the outline open from the toolbar,\n// and close once a node is added or picked; focus moves to the canvas,\n// where the node now is.\nconst sideOpen = ref(false)\n\n// On phones (a builder narrower than 560px) the fields and the settings\n// are drawers from the bottom. The settings open at half height when a\n// node is picked, and can be pulled up.\nconst root = shallowRef<HTMLElement | null>(null)\nconst compact = ref(false)\nconst settingsOpen = ref(false)\nlet observer: ResizeObserver | undefined\nonMounted(() => {\n if (typeof ResizeObserver === 'undefined' || !root.value) return\n observer = new ResizeObserver(([entry]) => {\n compact.value = (entry?.contentRect.width ?? Infinity) < 560\n })\n observer.observe(root.value)\n})\nonBeforeUnmount(() => observer?.disconnect())\n// Picking several nodes by tapping is for phones only.\nwatch(compact, (on) => {\n if (!on) state.tapToggles.value = false\n})\n// A tap on a node (not a drag, and not a node just added) opens its settings.\nfunction onCanvasClick(event: MouseEvent) {\n if (!compact.value || state.tapToggles.value || state.dragger.value?.swallowClick()) return\n const node = (event.target as HTMLElement).closest('.dou-form-builder__node')\n if (!node || (event.target as HTMLElement).closest('.dou-form-builder__actions')) return\n void nextTick(() => {\n if (state.focused.value) settingsOpen.value = true\n })\n}\nwatch(\n () => state.selection,\n () => {\n if (!sideOpen.value) return\n sideOpen.value = false\n void nextTick(() => state.canvas.value?.focus({ preventScroll: true }))\n },\n)\n\nconst {\n transaction,\n dispatch,\n select,\n add,\n remove,\n duplicate,\n moveBy,\n moveTo,\n replace,\n wrap,\n addPage,\n selectParent,\n undo,\n redo,\n shownPage,\n setMode,\n} = state\ndefineExpose<FormBuilderExpose>({\n get document() {\n return state.document\n },\n get selection() {\n return state.selection\n },\n get fields() {\n return state.fields\n },\n get messages() {\n return state.messages\n },\n get canUndo() {\n return state.canUndo\n },\n get canRedo() {\n return state.canRedo\n },\n get readonly() {\n return state.readonly\n },\n get mode() {\n return state.mode\n },\n setMode,\n transaction,\n dispatch,\n select,\n add,\n remove,\n duplicate,\n moveBy,\n moveTo,\n replace,\n wrap,\n addPage,\n selectParent,\n undo,\n redo,\n shownPage,\n})\n</script>\n\n<template>\n <div\n ref=\"root\"\n :class=\"[\n 'dou-form-builder',\n compact && 'is-compact',\n previewing && 'is-previewing',\n readonly && 'is-readonly',\n ]\"\n >\n <slot>\n <div class=\"dou-form-builder__layout\">\n <aside v-if=\"!previewing\" class=\"dou-form-builder__side\" :aria-label=\"sideTitle\">\n <FormBuilderOutline v-if=\"readonly\" />\n <DouTabs v-else v-model=\"side\" size=\"sm\" class=\"dou-form-builder__side-tabs\">\n <DouTabPanel value=\"fields\" :label=\"messages.panels.fields\">\n <FormBuilderPalette />\n </DouTabPanel>\n <DouTabPanel value=\"outline\" :label=\"messages.panels.outline\">\n <FormBuilderOutline />\n </DouTabPanel>\n </DouTabs>\n </aside>\n <div class=\"dou-form-builder__main\">\n <div class=\"dou-form-builder__toolbar\" role=\"toolbar\">\n <template v-if=\"previewing\" />\n <button\n v-else-if=\"compact\"\n type=\"button\"\n class=\"dou-form-builder__tool dou-form-builder__side-toggle\"\n aria-haspopup=\"dialog\"\n @click=\"sideOpen = true\"\n >\n <PanelLeftIcon />\n <span>{{ sideLabel }}</span>\n </button>\n <DouPopover\n v-else\n v-model:open=\"sideOpen\"\n placement=\"bottom-start\"\n :aria-label=\"sideTitle\"\n class=\"dou-form-builder__side-popover\"\n >\n <button type=\"button\" class=\"dou-form-builder__tool dou-form-builder__side-toggle\">\n <PanelLeftIcon />\n <span>{{ sideLabel }}</span>\n </button>\n <template #content>\n <FormBuilderOutline v-if=\"readonly\" />\n <DouTabs v-else v-model=\"side\" size=\"sm\" class=\"dou-form-builder__side-tabs\">\n <DouTabPanel value=\"fields\" :label=\"messages.panels.fields\">\n <FormBuilderPalette />\n </DouTabPanel>\n <DouTabPanel value=\"outline\" :label=\"messages.panels.outline\">\n <FormBuilderOutline />\n </DouTabPanel>\n </DouTabs>\n </template>\n </DouPopover>\n <template v-if=\"!previewing && !readonly\">\n <DouTooltip :content=\"messages.actions.undo\" shortcut=\"mod+z\" placement=\"bottom\">\n <button\n type=\"button\"\n class=\"dou-form-builder__tool\"\n :disabled=\"!state.canUndo\"\n :aria-label=\"messages.actions.undo\"\n @click=\"state.undo()\"\n >\n <UndoIcon />\n </button>\n </DouTooltip>\n <DouTooltip\n :content=\"messages.actions.redo\"\n shortcut=\"mod+shift+z\"\n placement=\"bottom\"\n >\n <button\n type=\"button\"\n class=\"dou-form-builder__tool\"\n :disabled=\"!state.canRedo\"\n :aria-label=\"messages.actions.redo\"\n @click=\"state.redo()\"\n >\n <RedoIcon />\n </button>\n </DouTooltip>\n </template>\n <!-- A tool with its name on it needs a tip only for its key. -->\n <DouTooltip\n v-for=\"item in toolbarItems\"\n :key=\"item.key\"\n :content=\"item.label\"\n :shortcut=\"item.shortcut\"\n :disabled=\"!item.icon && !item.shortcut\"\n placement=\"bottom\"\n >\n <button\n type=\"button\"\n class=\"dou-form-builder__tool\"\n :disabled=\"item.disabled\"\n :aria-pressed=\"item.pressed\"\n :aria-label=\"item.icon ? item.label : undefined\"\n @click=\"item.run()\"\n >\n <component :is=\"item.icon\" v-if=\"item.icon\" />\n <span v-else>{{ item.label }}</span>\n </button>\n </DouTooltip>\n <slot name=\"toolbar\" />\n <span class=\"dou-form-builder__toolbar-spacer\" />\n <template v-if=\"compact && !previewing\">\n <DouTooltip :content=\"messages.actions.selectMany\" placement=\"bottom\">\n <button\n type=\"button\"\n class=\"dou-form-builder__tool dou-form-builder__select-toggle\"\n :aria-pressed=\"state.tapToggles.value\"\n :aria-label=\"messages.actions.selectMany\"\n @click=\"state.tapToggles.value = !state.tapToggles.value\"\n >\n <ListChecksIcon />\n </button>\n </DouTooltip>\n <DouTooltip :content=\"messages.panels.settings\" placement=\"bottom\">\n <button\n type=\"button\"\n class=\"dou-form-builder__tool dou-form-builder__settings-toggle\"\n aria-haspopup=\"dialog\"\n :aria-label=\"messages.panels.settings\"\n @click=\"settingsOpen = true\"\n >\n <SlidersIcon />\n </button>\n </DouTooltip>\n </template>\n <DouTooltip :content=\"messages.json.title\" placement=\"bottom\">\n <button\n type=\"button\"\n class=\"dou-form-builder__tool\"\n aria-haspopup=\"dialog\"\n :aria-label=\"messages.json.title\"\n @click=\"jsonOpen = true\"\n >\n <BracesIcon />\n </button>\n </DouTooltip>\n <button\n type=\"button\"\n class=\"dou-form-builder__tool dou-form-builder__preview-toggle\"\n :aria-pressed=\"previewing\"\n @click=\"state.setMode(previewing ? 'design' : 'preview')\"\n >\n <EyeIcon />\n <span>{{ messages.preview.toggle }}</span>\n </button>\n </div>\n <FormBuilderPreview v-if=\"previewing\" />\n <FormBuilderCanvas v-else @click.capture=\"onCanvasClick\" />\n </div>\n <aside\n v-if=\"!compact && !previewing\"\n class=\"dou-form-builder__side dou-form-builder__side--end\"\n :aria-label=\"messages.panels.settings\"\n >\n <FormBuilderInspector />\n </aside>\n </div>\n <template v-if=\"compact\">\n <DouDrawer\n v-model:open=\"sideOpen\"\n placement=\"bottom\"\n :title=\"sideTitle\"\n :snap-points=\"['50%', '90%']\"\n swipeable\n class=\"dou-form-builder__drawer\"\n >\n <FormBuilderOutline v-if=\"readonly\" />\n <DouTabs v-else v-model=\"side\" size=\"sm\" class=\"dou-form-builder__side-tabs\">\n <DouTabPanel value=\"fields\" :label=\"messages.panels.fields\">\n <FormBuilderPalette />\n </DouTabPanel>\n <DouTabPanel value=\"outline\" :label=\"messages.panels.outline\">\n <FormBuilderOutline />\n </DouTabPanel>\n </DouTabs>\n </DouDrawer>\n <DouDrawer\n v-model:open=\"settingsOpen\"\n placement=\"bottom\"\n :title=\"messages.panels.settings\"\n :snap-points=\"['50%', '90%']\"\n swipeable\n class=\"dou-form-builder__drawer\"\n >\n <FormBuilderInspector />\n </DouDrawer>\n </template>\n </slot>\n <FormBuilderJson v-model:open=\"jsonOpen\" />\n <div class=\"dou-form-builder__live\" aria-live=\"polite\" aria-atomic=\"true\">\n {{ state.live.value }}\n </div>\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { FormBuilderTransaction, applyFormSteps, canContainFormNode, compactFormSteps, formNodePlaces } from "./core/transaction.js";
|
|
2
|
+
import { FormBuilderHistory } from "./core/history.js";
|
|
3
|
+
import { useFormBuilder } from "./context.js";
|
|
4
|
+
import { defineFormBuilderExtension, resolveFormBuilderExtensions, resolveFormBuilderFields } from "./extension.js";
|
|
5
|
+
import preview_default from "./preview.js";
|
|
6
|
+
import { formBuilderLocales, useFormBuilderMessages } from "./locale.js";
|
|
7
|
+
import { FormBuilderCanvas } from "./canvas.js";
|
|
8
|
+
import inspector_default from "./inspector.js";
|
|
9
|
+
import outline_default from "./outline.js";
|
|
10
|
+
import palette_default from "./palette.js";
|
|
11
|
+
import form_builder_default from "./form-builder.js";
|
|
12
|
+
import { withInstall } from "dou-ui";
|
|
13
|
+
// src/builder/index.ts
|
|
14
|
+
var DouFormBuilder = withInstall(form_builder_default);
|
|
15
|
+
var DouFormBuilderPalette = withInstall(palette_default);
|
|
16
|
+
var DouFormBuilderInspector = withInstall(inspector_default);
|
|
17
|
+
var DouFormBuilderOutline = withInstall(outline_default);
|
|
18
|
+
var DouFormBuilderCanvas = withInstall(FormBuilderCanvas);
|
|
19
|
+
var DouFormBuilderPreview = withInstall(preview_default);
|
|
20
|
+
export { DouFormBuilder, DouFormBuilderCanvas, DouFormBuilderInspector, DouFormBuilderOutline, DouFormBuilderPalette, DouFormBuilderPreview, FormBuilderHistory, FormBuilderTransaction, applyFormSteps, canContainFormNode, compactFormSteps, defineFormBuilderExtension, formBuilderLocales, formNodePlaces, resolveFormBuilderExtensions, resolveFormBuilderFields, useFormBuilder, useFormBuilderMessages };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["FormBuilder","Palette","Inspector","Outline","Preview"],"sources":["../../src/builder/index.ts"],"sourcesContent":["import { withInstall } from 'dou-ui'\nimport FormBuilder from './form-builder.vue'\nimport Inspector from './inspector.vue'\nimport Outline from './outline.vue'\nimport Palette from './palette.vue'\nimport Preview from './preview.vue'\nimport { FormBuilderCanvas } from './canvas'\n\nexport const DouFormBuilder = withInstall(FormBuilder)\nexport const DouFormBuilderPalette = withInstall(Palette)\nexport const DouFormBuilderInspector = withInstall(Inspector)\nexport const DouFormBuilderOutline = withInstall(Outline)\nexport const DouFormBuilderCanvas = withInstall(FormBuilderCanvas)\nexport const DouFormBuilderPreview = withInstall(Preview)\n\nexport type {\n FormBuilderEmits,\n FormBuilderExpose,\n FormBuilderProps,\n FormBuilderSlots,\n} from './types'\nexport { useFormBuilder } from './context'\nexport type {\n FormBuilderContext,\n FormBuilderDispatchOptions,\n FormBuilderMode,\n FormBuilderSelectMode,\n} from './context'\nexport {\n defineFormBuilderExtension,\n resolveFormBuilderExtensions,\n resolveFormBuilderFields,\n} from './extension'\nexport type {\n FormBuilderExtension,\n FormBuilderExtensionContext,\n FormBuilderInspectorSection,\n FormBuilderKeyHandler,\n FormBuilderMenuItem,\n FormBuilderToolbarItem,\n ResolvedFormBuilderExtensions,\n} from './extension'\nexport {\n applyFormSteps,\n canContainFormNode,\n compactFormSteps,\n FormBuilderTransaction,\n formNodePlaces,\n} from './core/transaction'\nexport type {\n FormBuilderStep,\n FormBuilderTransactionMeta,\n FormDocumentPatch,\n FormNodePatch,\n FormNodePlace,\n} from './core/transaction'\nexport { FormBuilderHistory } from './core/history'\nexport type { FormBuilderInsertPlace } from './core/commands'\nexport { formBuilderLocales, useFormBuilderMessages } from './locale'\nexport type { FormBuilderMessages, FormBuilderMessagesOverride } from './locale'\n\nexport type FormBuilderInstance = InstanceType<typeof FormBuilder>\n\ndeclare module 'vue' {\n export interface GlobalComponents {\n DouFormBuilder: typeof DouFormBuilder\n DouFormBuilderPalette: typeof DouFormBuilderPalette\n DouFormBuilderInspector: typeof DouFormBuilderInspector\n DouFormBuilderOutline: typeof DouFormBuilderOutline\n DouFormBuilderCanvas: typeof DouFormBuilderCanvas\n DouFormBuilderPreview: typeof DouFormBuilderPreview\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAQA,IAAa,iBAAiB,YAAYA,oBAAW;AACrD,IAAa,wBAAwB,YAAYC,eAAO;AACxD,IAAa,0BAA0B,YAAYC,iBAAS;AAC5D,IAAa,wBAAwB,YAAYC,eAAO;AACxD,IAAa,uBAAuB,YAAY,iBAAiB;AACjE,IAAa,wBAAwB,YAAYC,eAAO"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import inspector_vue_vue_type_script_setup_true_lang_default from "./inspector.vue_vue_type_script_setup_true_lang.js";
|
|
2
|
+
// src/builder/inspector.vue
|
|
3
|
+
var inspector_default = inspector_vue_vue_type_script_setup_true_lang_default;
|
|
4
|
+
export { inspector_default as default };
|
|
5
|
+
|
|
6
|
+
//# sourceMappingURL=inspector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspector.js","names":["_sfc_main"],"sources":["../../src/builder/inspector.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, provide, useTemplateRef, watchEffect } from 'vue'\nimport { DouButton } from 'dou-ui'\nimport type { FormRules } from 'dou-ui'\nimport { CopyIcon, PlusIcon, SquareDashedIcon, TrashIcon } from '@dou-ui/icons'\nimport { isContainer, isField, isList } from '../core/document'\nimport type { FormFieldNode, FormNode, FormRuleSpec } from '../core/types'\nimport { builtinFields } from '../fields/builtin'\nimport { normalizeOptions } from '../fields/components'\nimport type { FormFieldType } from '../fields/define'\nimport { formatMessage } from '../locale'\nimport FormRenderer from '../renderer/form-renderer.vue'\nimport { controlsReadonlyKey } from '../renderer/context'\nimport { useBuilderState } from './context'\nimport type { FormBuilderTransaction } from './core/transaction'\nimport { scopeOf } from './core/commands'\nimport { formNodePlaces } from './core/transaction'\nimport {\n itemToRule,\n logicScope,\n sameLogicScope,\n logicSettings,\n ruleSettings,\n ruleToItem,\n} from './logic'\nimport type { LogicScope } from './logic'\nimport { conditionField, expressionField } from './logic-fields'\nimport {\n builtinSettings,\n documentSettings,\n iconOf,\n labelOf,\n nodeSettings,\n nodeTitle,\n settingsDocument,\n} from './settings'\nimport { useSettingsBinding } from './settings-binding'\nimport { spanField } from './span-field'\n\ndefineOptions({ name: 'DouFormBuilderInspector' })\n\nconst state = useBuilderState()\n// A read-only builder's settings can be read, not changed: the controls stay legible.\nprovide(controlsReadonlyKey, () => state.readonly)\nconst root = useTemplateRef<HTMLElement>('root')\nwatchEffect(() => (state.inspector.value = root.value))\nonBeforeUnmount(() => {\n if (state.inspector.value === root.value) state.inspector.value = null\n})\n\nconst messages = computed(() => state.messages)\nconst types = computed(() => state.fields as Map<string, FormFieldType>)\nconst builderFields = [spanField, expressionField, conditionField]\nconst extra = builderFields\nconst rendererFields = computed(() => [...types.value.values(), ...builderFields])\nconst inspectorFields = computed(\n () => new Map([...types.value, ...builderFields.map((type) => [type.type, type] as const)]),\n)\n\nconst count = computed(() => state.selection.length)\nconst node = computed(() => (count.value === 1 ? state.focused.value : undefined))\nconst place = computed(() =>\n node.value ? formNodePlaces(state.document).get(node.value.id) : undefined,\n)\nconst spec = computed(() =>\n node.value && isField(node.value) ? types.value.get(node.value.type) : undefined,\n)\n\n/** Columns of the grid a node sits on. */\nfunction gridColumns(id: string | undefined) {\n const document = state.document\n const own = Math.max(1, Math.round(document.columns ?? 12))\n if (!id) return own\n const map = formNodePlaces(document)\n let parent = map.get(id)?.parent\n while (parent) {\n if ('columns' in parent && parent.columns) return parent.columns\n if (parent.type === 'tabs' || parent.type === 'steps') {\n parent = map.get(parent.id)?.parent\n continue\n }\n parent = map.get(parent.id)?.parent\n }\n return own\n}\n\n// The settings forms change only with what they depend on, so typing in one keeps the others.\nfunction memo<T>(deps: () => unknown[], make: () => T) {\n let last: unknown[] | undefined\n let value: T\n return computed(() => {\n const next = deps()\n if (!last || next.length !== last.length || next.some((dep, index) => dep !== last![index])) {\n last = next\n value = make()\n }\n return value\n })\n}\n\nconst columns = computed(() => gridColumns(node.value?.id))\nconst inItem = computed(() => !!scopeOf(state.document, place.value?.parent?.id ?? null))\n\nconst nodeForm = memo(\n () => {\n const current = node.value\n const kind = current && (isField(current) ? 'field' : current.type)\n return [\n kind,\n current?.type,\n (current as FormFieldNode | undefined)?.props,\n columns.value,\n inItem.value,\n messages.value,\n spec.value,\n ]\n },\n () =>\n settingsDocument(\n node.value\n ? nodeSettings(node.value, {\n messages: messages.value,\n columns: columns.value,\n inItem: inItem.value,\n type: spec.value,\n })\n : [],\n ),\n)\n\nconst isBuiltin = (type: FormFieldType | undefined) => !!type && builtinFields.includes(type)\nconst typeForm = memo(\n () => [node.value?.type, spec.value, messages.value],\n () => {\n const type = spec.value\n const nodes =\n type?.settings ?? (isBuiltin(type) ? builtinSettings(type!.type, messages.value) : [])\n return settingsDocument(nodes)\n },\n)\nconst formForm = memo(\n () => [messages.value],\n () => settingsDocument(documentSettings(messages.value)),\n)\nconst spanForm = memo(\n () => [messages.value, state.document.columns],\n () =>\n settingsDocument(\n nodeSettings(\n { id: '', type: 'tabs', children: [] },\n {\n messages: messages.value,\n columns: Math.max(1, Math.round(state.document.columns ?? 12)),\n inItem: false,\n },\n ),\n ),\n)\n\n// What the node's logic can read; kept as one object while the fields it lists stay the same.\nlet lastScope: LogicScope | undefined\nconst logic = computed(() => {\n const next = logicScope(state.document, node.value?.id, types.value, messages.value)\n if (!lastScope || !sameLogicScope(lastScope, next)) lastScope = next\n return lastScope\n})\nconst holdsValue = computed(() => {\n const current = node.value\n if (!current) return false\n return isList(current) || (isField(current) && spec.value?.kind !== 'display')\n})\n\nconst logicForm = memo(\n () => [\n node.value?.type,\n (node.value as FormFieldNode | undefined)?.name,\n logic.value,\n spec.value,\n messages.value,\n ],\n () =>\n settingsDocument(\n node.value\n ? logicSettings(node.value, {\n messages: messages.value,\n scope: logic.value,\n type: spec.value,\n })\n : [],\n ),\n)\nconst validatorNames = computed(() => {\n const given = state.validators()\n return given ? Object.keys(given) : undefined\n})\nconst ruleForm = memo(\n () => [holdsValue.value, logic.value, messages.value, validatorNames.value?.join()],\n () =>\n settingsDocument(\n holdsValue.value\n ? ruleSettings({\n messages: messages.value,\n scope: logic.value,\n validators: validatorNames.value,\n })\n : [],\n ),\n)\n\n/** Make a change of the settings, unless the builder is read-only. */\nfunction commit(tr: FormBuilderTransaction) {\n if (!state.readonly) state.dispatch(tr)\n}\n\nfunction update(id: string, patch: Record<string, unknown>) {\n const tr = state.transaction().update(id, patch)\n tr.setMeta('group', `inspector:${id}:${Object.keys(patch).join(',')}`)\n tr.setMeta('origin', 'inspector')\n commit(tr)\n return formNodePlaces(state.document).get(id)?.node\n}\n\nconst nodeModel = useSettingsBinding({\n source: () => node.value as Record<string, unknown> | undefined,\n form: () => nodeForm.value,\n fields: () => inspectorFields.value,\n apply: (patch) =>\n node.value ? (update(node.value.id, patch) as unknown as Record<string, unknown>) : undefined,\n})\n\nconst logicModel = useSettingsBinding({\n source: () => node.value as Record<string, unknown> | undefined,\n form: () => logicForm.value,\n fields: () => inspectorFields.value,\n apply: (patch) =>\n node.value ? (update(node.value.id, patch) as unknown as Record<string, unknown>) : undefined,\n})\n\nconst ruleModel = useSettingsBinding({\n source: () => node.value as Record<string, unknown> | undefined,\n form: () => ruleForm.value,\n fields: () => inspectorFields.value,\n prepare: (data) => {\n const rules = (data.rules as FormRuleSpec[] | undefined) ?? []\n return { ...data, rules: rules.map(ruleToItem) }\n },\n apply: (patch) => {\n const current = node.value\n if (!current || !('rules' in patch)) return undefined\n const items = (patch.rules as Record<string, unknown>[] | undefined) ?? []\n const rules = items.map(itemToRule)\n return update(current.id, { rules: rules.length ? rules : undefined }) as unknown as\n Record<string, unknown> | undefined\n },\n})\n\n/** Parts of the inspector from extensions, for the node or the form. */\nconst sections = computed(() =>\n count.value > 1\n ? []\n : state.extensions().inspectors.flatMap((inspector) => inspector(state, node.value)),\n)\n\nconst typeModel = useSettingsBinding({\n source: () => (node.value as FormFieldNode | undefined)?.props,\n key: () => node.value?.id,\n form: () => typeForm.value,\n fields: () => inspectorFields.value,\n prepare: (props) => {\n // Options written as plain values show as rows of text and value.\n const prop = spec.value?.optionsProp\n const options = prop ? props[prop] : undefined\n if (prop && Array.isArray(options) && options.some((option) => typeof option !== 'object'))\n props[prop] = normalizeOptions(options).map(({ label, value }) => ({ label, value }))\n return props\n },\n apply: (patch) => {\n const current = node.value as FormFieldNode | undefined\n if (!current) return undefined\n const props: Record<string, unknown> = { ...current.props }\n for (const [key, value] of Object.entries(patch)) {\n if (value === undefined) delete props[key]\n else props[key] = value\n }\n const next = update(current.id, { props: Object.keys(props).length ? props : undefined })\n return (next as FormFieldNode | undefined)?.props\n },\n})\n\n// The document's own settings, as an object that changes only when one of them does.\nconst settingKeys = [\n 'layout',\n 'labelAlign',\n 'labelWidth',\n 'size',\n 'requiredMark',\n 'columns',\n] as const\nlet lastSettings: Record<string, unknown> = {}\nconst documentSettingsOf = computed(() => {\n const document = state.document as unknown as Record<string, unknown>\n if (settingKeys.every((key) => lastSettings[key] === document[key])) return lastSettings\n const next: Record<string, unknown> = {}\n for (const key of settingKeys) if (document[key] !== undefined) next[key] = document[key]\n return (lastSettings = next)\n})\n\nconst formModel = useSettingsBinding({\n source: () => documentSettingsOf.value,\n form: () => formForm.value,\n fields: () => inspectorFields.value,\n apply: (patch) => {\n const tr = state.transaction().updateDocument(patch)\n tr.setMeta('group', `inspector:document:${Object.keys(patch).join(',')}`)\n tr.setMeta('origin', 'inspector')\n commit(tr)\n return documentSettingsOf.value\n },\n})\n\nconst spanModel = useSettingsBinding({\n source: () =>\n count.value > 1 ? (state.focused.value as Record<string, unknown> | undefined) : undefined,\n key: () => state.selection.join(),\n form: () => spanForm.value,\n fields: () => inspectorFields.value,\n apply: (patch) => {\n const tr = state.transaction()\n for (const id of state.selection) tr.update(id, patch)\n tr.setMeta('group', `inspector:${state.selection.join()}:span`)\n commit(tr)\n return state.focused.value as Record<string, unknown> | undefined\n },\n})\n\n/** The other names of the scope the node's name is a key of. */\nfunction otherNames(current: FormNode) {\n const document = state.document\n const scope = scopeOf(document, formNodePlaces(document).get(current.id)?.parent?.id ?? null)\n const names = new Set<string>()\n const visit = (nodes: readonly FormNode[]) => {\n for (const each of nodes) {\n if (each.id !== current.id && 'name' in each && each.name) names.add(each.name)\n if (isContainer(each) && !isList(each)) visit(each.children)\n }\n }\n visit(scope ? scope.children : document.nodes)\n return names\n}\n\nconst nameRules = computed<FormRules>(() => ({\n name: [\n {\n validator: (value: unknown) => {\n const current = node.value\n if (!current) return true\n const name = typeof value === 'string' ? value.trim() : ''\n if (!name) return holdsValue.value ? messages.value.errors.name : true\n if (otherNames(current).has(name))\n return formatMessage(messages.value.errors.taken, { text: name })\n return true\n },\n trigger: 'change',\n },\n ],\n}))\n\nconst heading = computed(() => {\n if (count.value > 1)\n return {\n icon: SquareDashedIcon,\n title: formatMessage(messages.value.inspector.multiple, { count: count.value }),\n type: '',\n }\n const current = node.value\n if (!current) return { icon: undefined, title: messages.value.inspector.form, type: '' }\n const type = labelOf(current.type, types.value.get(current.type), messages.value)\n const title = nodeTitle(current, types.value, messages.value)\n return {\n icon: iconOf(current.type, types.value.get(current.type)),\n title,\n type: title === type ? '' : type,\n }\n})\n\nconst holdsPages = computed(() => node.value?.type === 'tabs' || node.value?.type === 'steps')\nconst canWrap = computed(() => {\n const map = formNodePlaces(state.document)\n const parents = new Set(state.selection.map((id) => map.get(id)?.parent?.id ?? null))\n return parents.size === 1 && !state.selection.some((id) => map.get(id)?.node.type === 'page')\n})\n</script>\n\n<template>\n <div ref=\"root\" class=\"dou-form-builder__inspector\">\n <div class=\"dou-form-builder__inspector-header\">\n <component :is=\"heading.icon\" v-if=\"heading.icon\" class=\"dou-form-builder__inspector-icon\" />\n <span class=\"dou-form-builder__inspector-title\">{{ heading.title }}</span>\n <span v-if=\"heading.type\" class=\"dou-form-builder__inspector-type\">{{ heading.type }}</span>\n </div>\n <div class=\"dou-form-builder__inspector-body\">\n <template v-if=\"count > 1\">\n <FormRenderer :form=\"spanForm\" :model=\"spanModel\" :fields=\"extra\" />\n <div v-if=\"!state.readonly\" class=\"dou-form-builder__inspector-actions\">\n <DouButton size=\"sm\" variant=\"outline\" @click=\"state.duplicate()\">\n <template #leading><CopyIcon /></template>\n {{ messages.actions.duplicate }}\n </DouButton>\n <DouButton size=\"sm\" variant=\"outline\" :disabled=\"!canWrap\" @click=\"state.wrap()\">\n <template #leading><SquareDashedIcon /></template>\n {{ messages.actions.wrap }}\n </DouButton>\n <DouButton size=\"sm\" variant=\"outline\" tone=\"danger\" @click=\"state.remove()\">\n <template #leading><TrashIcon /></template>\n {{ messages.actions.remove }}\n </DouButton>\n </div>\n </template>\n <template v-else-if=\"node\">\n <FormRenderer\n :key=\"node.id\"\n :form=\"nodeForm\"\n :model=\"nodeModel\"\n :fields=\"rendererFields\"\n :rules=\"nameRules\"\n />\n <DouButton\n v-if=\"holdsPages && !state.readonly\"\n class=\"dou-form-builder__inspector-add\"\n size=\"sm\"\n variant=\"outline\"\n @click=\"state.addPage(node.id)\"\n >\n <template #leading><PlusIcon /></template>\n {{ messages.actions.addPage }}\n </DouButton>\n <template v-if=\"typeForm.nodes.length\">\n <div class=\"dou-form-builder__inspector-section\">{{ messages.inspector.type }}</div>\n <FormRenderer\n :key=\"`${node.id}/props`\"\n :form=\"typeForm\"\n :model=\"typeModel\"\n :fields=\"rendererFields\"\n />\n </template>\n <template v-if=\"ruleForm.nodes.length\">\n <div class=\"dou-form-builder__inspector-section\">{{ messages.inspector.rules }}</div>\n <FormRenderer\n :key=\"`${node.id}/rules`\"\n :form=\"ruleForm\"\n :model=\"ruleModel\"\n :fields=\"rendererFields\"\n />\n </template>\n <div class=\"dou-form-builder__inspector-section\">{{ messages.inspector.logic }}</div>\n <FormRenderer\n :key=\"`${node.id}/logic`\"\n :form=\"logicForm\"\n :model=\"logicModel\"\n :fields=\"rendererFields\"\n />\n </template>\n <FormRenderer v-else :form=\"formForm\" :model=\"formModel\" :fields=\"extra\" />\n <template v-for=\"section in sections\" :key=\"section.key\">\n <div class=\"dou-form-builder__inspector-section\">{{ section.title }}</div>\n <component :is=\"section.component\" v-bind=\"section.props\" />\n </template>\n </div>\n </div>\n</template>\n"],"mappings":""}
|