@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.
Files changed (182) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +10 -2
  3. package/dist/builder/canvas.js +695 -0
  4. package/dist/builder/canvas.js.map +1 -0
  5. package/dist/builder/completion.js +49 -0
  6. package/dist/builder/completion.js.map +1 -0
  7. package/dist/builder/condition-editor.js +6 -0
  8. package/dist/builder/condition-editor.js.map +1 -0
  9. package/dist/builder/condition-editor.vue_vue_type_script_setup_true_lang.js +410 -0
  10. package/dist/builder/condition-editor.vue_vue_type_script_setup_true_lang.js.map +1 -0
  11. package/dist/builder/condition.js +159 -0
  12. package/dist/builder/condition.js.map +1 -0
  13. package/dist/builder/context.js +477 -0
  14. package/dist/builder/context.js.map +1 -0
  15. package/dist/builder/core/commands.js +373 -0
  16. package/dist/builder/core/commands.js.map +1 -0
  17. package/dist/builder/core/history.js +76 -0
  18. package/dist/builder/core/history.js.map +1 -0
  19. package/dist/builder/core/transaction.js +298 -0
  20. package/dist/builder/core/transaction.js.map +1 -0
  21. package/dist/builder/drag.js +466 -0
  22. package/dist/builder/drag.js.map +1 -0
  23. package/dist/builder/expression-box.js +19 -0
  24. package/dist/builder/expression-box.js.map +1 -0
  25. package/dist/builder/expression-input.js +6 -0
  26. package/dist/builder/expression-input.js.map +1 -0
  27. package/dist/builder/expression-input.vue_vue_type_script_setup_true_lang.js +117 -0
  28. package/dist/builder/expression-input.vue_vue_type_script_setup_true_lang.js.map +1 -0
  29. package/dist/builder/extension.js +47 -0
  30. package/dist/builder/extension.js.map +1 -0
  31. package/dist/builder/form-builder.js +6 -0
  32. package/dist/builder/form-builder.js.map +1 -0
  33. package/dist/builder/form-builder.vue_vue_type_script_setup_true_lang.js +450 -0
  34. package/dist/builder/form-builder.vue_vue_type_script_setup_true_lang.js.map +1 -0
  35. package/dist/builder/index.js +22 -0
  36. package/dist/builder/index.js.map +1 -0
  37. package/dist/builder/inspector.js +6 -0
  38. package/dist/builder/inspector.js.map +1 -0
  39. package/dist/builder/inspector.vue_vue_type_script_setup_true_lang.js +442 -0
  40. package/dist/builder/inspector.vue_vue_type_script_setup_true_lang.js.map +1 -0
  41. package/dist/builder/json-dialog.js +6 -0
  42. package/dist/builder/json-dialog.js.map +1 -0
  43. package/dist/builder/json-dialog.vue_vue_type_script_setup_true_lang.js +281 -0
  44. package/dist/builder/json-dialog.vue_vue_type_script_setup_true_lang.js.map +1 -0
  45. package/dist/builder/locale.js +1271 -0
  46. package/dist/builder/locale.js.map +1 -0
  47. package/dist/builder/logic-fields.js +18 -0
  48. package/dist/builder/logic-fields.js.map +1 -0
  49. package/dist/builder/logic.js +332 -0
  50. package/dist/builder/logic.js.map +1 -0
  51. package/dist/builder/menu.js +92 -0
  52. package/dist/builder/menu.js.map +1 -0
  53. package/dist/builder/outline-row.js +6 -0
  54. package/dist/builder/outline-row.js.map +1 -0
  55. package/dist/builder/outline-row.vue_vue_type_script_setup_true_lang.js +88 -0
  56. package/dist/builder/outline-row.vue_vue_type_script_setup_true_lang.js.map +1 -0
  57. package/dist/builder/outline.js +6 -0
  58. package/dist/builder/outline.js.map +1 -0
  59. package/dist/builder/outline.vue_vue_type_script_setup_true_lang.js +111 -0
  60. package/dist/builder/outline.vue_vue_type_script_setup_true_lang.js.map +1 -0
  61. package/dist/builder/palette.js +6 -0
  62. package/dist/builder/palette.js.map +1 -0
  63. package/dist/builder/palette.vue_vue_type_script_setup_true_lang.js +96 -0
  64. package/dist/builder/palette.vue_vue_type_script_setup_true_lang.js.map +1 -0
  65. package/dist/builder/preview.js +6 -0
  66. package/dist/builder/preview.js.map +1 -0
  67. package/dist/builder/preview.vue_vue_type_script_setup_true_lang.js +111 -0
  68. package/dist/builder/preview.vue_vue_type_script_setup_true_lang.js.map +1 -0
  69. package/dist/builder/settings-binding.js +57 -0
  70. package/dist/builder/settings-binding.js.map +1 -0
  71. package/dist/builder/settings.js +487 -0
  72. package/dist/builder/settings.js.map +1 -0
  73. package/dist/builder/span-field.js +104 -0
  74. package/dist/builder/span-field.js.map +1 -0
  75. package/dist/code/expression-input.js +6 -0
  76. package/dist/code/expression-input.js.map +1 -0
  77. package/dist/code/expression-input.vue_vue_type_script_setup_true_lang.js +88 -0
  78. package/dist/code/expression-input.vue_vue_type_script_setup_true_lang.js.map +1 -0
  79. package/dist/code/extension.js +202 -0
  80. package/dist/code/extension.js.map +1 -0
  81. package/dist/code/index.js +19 -0
  82. package/dist/code/index.js.map +1 -0
  83. package/dist/code/language.js +43 -0
  84. package/dist/code/language.js.map +1 -0
  85. package/dist/collaboration/index.js +382 -0
  86. package/dist/collaboration/index.js.map +1 -0
  87. package/dist/collaboration/order.js +88 -0
  88. package/dist/collaboration/order.js.map +1 -0
  89. package/dist/core/check.js +314 -0
  90. package/dist/core/check.js.map +1 -0
  91. package/dist/core/document.js +112 -0
  92. package/dist/core/document.js.map +1 -0
  93. package/dist/core/expression.js +854 -0
  94. package/dist/core/expression.js.map +1 -0
  95. package/dist/core/formulas.js +242 -0
  96. package/dist/core/formulas.js.map +1 -0
  97. package/dist/core/rules.js +83 -0
  98. package/dist/core/rules.js.map +1 -0
  99. package/dist/core/values.js +80 -0
  100. package/dist/core/values.js.map +1 -0
  101. package/dist/fields/builtin.js +167 -0
  102. package/dist/fields/builtin.js.map +1 -0
  103. package/dist/fields/components.js +155 -0
  104. package/dist/fields/components.js.map +1 -0
  105. package/dist/fields/define.js +44 -0
  106. package/dist/fields/define.js.map +1 -0
  107. package/dist/fields/format.js +125 -0
  108. package/dist/fields/format.js.map +1 -0
  109. package/dist/fields/options.js +54 -0
  110. package/dist/fields/options.js.map +1 -0
  111. package/dist/index.js +20 -0
  112. package/dist/locale.js +161 -0
  113. package/dist/locale.js.map +1 -0
  114. package/dist/renderer/containers.js +430 -0
  115. package/dist/renderer/containers.js.map +1 -0
  116. package/dist/renderer/context.js +21 -0
  117. package/dist/renderer/context.js.map +1 -0
  118. package/dist/renderer/form-renderer.js +6 -0
  119. package/dist/renderer/form-renderer.js.map +1 -0
  120. package/dist/renderer/form-renderer.vue_vue_type_script_setup_true_lang.js +272 -0
  121. package/dist/renderer/form-renderer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  122. package/dist/renderer/index.js +19 -0
  123. package/dist/renderer/index.js.map +1 -0
  124. package/dist/renderer/node-view.js +385 -0
  125. package/dist/renderer/node-view.js.map +1 -0
  126. package/dist/style.css +1 -0
  127. package/dist/style.d.ts +1 -0
  128. package/dist/style.js +27 -0
  129. package/dist/types/builder/canvas.d.ts +5 -0
  130. package/dist/types/builder/completion.d.ts +35 -0
  131. package/dist/types/builder/condition-editor.vue.d.ts +17 -0
  132. package/dist/types/builder/condition.d.ts +37 -0
  133. package/dist/types/builder/context.d.ts +149 -0
  134. package/dist/types/builder/core/commands.d.ts +74 -0
  135. package/dist/types/builder/core/history.d.ts +23 -0
  136. package/dist/types/builder/core/transaction.d.ts +108 -0
  137. package/dist/types/builder/drag.d.ts +52 -0
  138. package/dist/types/builder/expression-box.d.ts +8 -0
  139. package/dist/types/builder/expression-input.vue.d.ts +29 -0
  140. package/dist/types/builder/extension.d.ts +149 -0
  141. package/dist/types/builder/form-builder.vue.d.ts +24 -0
  142. package/dist/types/builder/index.d.ts +76 -0
  143. package/dist/types/builder/inspector.vue.d.ts +3 -0
  144. package/dist/types/builder/json-dialog.vue.d.ts +10 -0
  145. package/dist/types/builder/locale.d.ts +195 -0
  146. package/dist/types/builder/logic-fields.d.ts +2 -0
  147. package/dist/types/builder/logic.d.ts +57 -0
  148. package/dist/types/builder/menu.d.ts +23 -0
  149. package/dist/types/builder/outline-row.vue.d.ts +19 -0
  150. package/dist/types/builder/outline.vue.d.ts +3 -0
  151. package/dist/types/builder/palette.vue.d.ts +3 -0
  152. package/dist/types/builder/preview.vue.d.ts +3 -0
  153. package/dist/types/builder/settings-binding.d.ts +23 -0
  154. package/dist/types/builder/settings.d.ts +49 -0
  155. package/dist/types/builder/span-field.d.ts +4 -0
  156. package/dist/types/builder/types.d.ts +59 -0
  157. package/dist/types/code/expression-input.vue.d.ts +23 -0
  158. package/dist/types/code/extension.d.ts +45 -0
  159. package/dist/types/code/index.d.ts +12 -0
  160. package/dist/types/code/language.d.ts +6 -0
  161. package/dist/types/collaboration/index.d.ts +64 -0
  162. package/dist/types/collaboration/order.d.ts +20 -0
  163. package/dist/types/core/check.d.ts +68 -0
  164. package/dist/types/core/document.d.ts +36 -0
  165. package/dist/types/core/expression.d.ts +175 -0
  166. package/dist/types/core/formulas.d.ts +44 -0
  167. package/dist/types/core/rules.d.ts +23 -0
  168. package/dist/types/core/types.d.ts +211 -0
  169. package/dist/types/core/values.d.ts +22 -0
  170. package/dist/types/fields/builtin.d.ts +9 -0
  171. package/dist/types/fields/components.d.ts +177 -0
  172. package/dist/types/fields/define.d.ts +93 -0
  173. package/dist/types/fields/format.d.ts +76 -0
  174. package/dist/types/fields/options.d.ts +11 -0
  175. package/dist/types/index.d.ts +3 -0
  176. package/dist/types/locale.d.ts +45 -0
  177. package/dist/types/renderer/containers.d.ts +20 -0
  178. package/dist/types/renderer/context.d.ts +186 -0
  179. package/dist/types/renderer/form-renderer.vue.d.ts +25 -0
  180. package/dist/types/renderer/index.d.ts +81 -0
  181. package/dist/types/renderer/node-view.d.ts +56 -0
  182. package/package.json +88 -4
@@ -0,0 +1,477 @@
1
+ import { isContainer, isPage } from "../core/document.js";
2
+ import { formatMessage } from "../locale.js";
3
+ import { FormBuilderTransaction, formNodePlaces } from "./core/transaction.js";
4
+ import { FormBuilderHistory } from "./core/history.js";
5
+ import { createNode, duplicateNodes, insertPlace, moveNodes, moveNodesTo, namesIn, removeNodes, replaceDocument, scopeOf, topmost, wrapNodes } from "./core/commands.js";
6
+ import { labelOf, nodeTitle } from "./settings.js";
7
+ import { matchesHotkey } from "dou-ui";
8
+ import { computed, inject, nextTick, shallowReactive, shallowRef, toRaw, watch } from "vue";
9
+ // src/builder/context.ts
10
+ var builderKey = Symbol("DouFormBuilder");
11
+ /** Inside a builder: its document, selection and commands. */
12
+ function useFormBuilder() {
13
+ const state = inject(builderKey, void 0);
14
+ if (!state) throw new Error("[@dou-ui/form-builder] useFormBuilder() must be called inside <DouFormBuilder>");
15
+ return state;
16
+ }
17
+ function useBuilderState() {
18
+ const state = inject(builderKey, void 0);
19
+ if (!state) throw new Error("[@dou-ui/form-builder] the parts of a form builder must be placed inside <DouFormBuilder>");
20
+ return state;
21
+ }
22
+ var same = (a, b) => a.length === b.length && a.every((id, index) => id === b[index]);
23
+ function createBuilderState(options) {
24
+ const doc = shallowRef(toRaw(options.document()));
25
+ const selection = shallowRef(options.selection() ?? []);
26
+ const history = new FormBuilderHistory();
27
+ /** Bumped whenever the history changes, so `canUndo` and `canRedo` stay current. */
28
+ const travelled = shallowRef(0);
29
+ const live = shallowRef("");
30
+ const inspector = shallowRef(null);
31
+ const canvas = shallowRef(null);
32
+ const dragger = shallowRef(null);
33
+ const openMenu = shallowRef(null);
34
+ watch(options.document, (next) => {
35
+ const raw = toRaw(next);
36
+ if (raw === doc.value) return;
37
+ doc.value = raw;
38
+ history.clear();
39
+ travelled.value++;
40
+ setSelection(selection.value);
41
+ });
42
+ watch(options.selection, (next) => {
43
+ if (next && !same(next, selection.value)) setSelection(next, false);
44
+ });
45
+ function setSelection(ids, emit = true) {
46
+ const map = formNodePlaces(doc.value);
47
+ const seen = /* @__PURE__ */ new Set();
48
+ const next = ids.filter((id) => map.has(id) && !seen.has(id) && seen.add(id));
49
+ if (same(next, selection.value)) return;
50
+ selection.value = next;
51
+ if (emit) options.emitSelection(next.slice());
52
+ }
53
+ const opened = shallowReactive(/* @__PURE__ */ new Map());
54
+ watch([selection, doc], ([ids, document]) => {
55
+ const map = formNodePlaces(document);
56
+ for (const id of ids) {
57
+ let place = map.get(id);
58
+ while (place) {
59
+ const parent = place.parent;
60
+ if (parent && isPage(place.node) && opened.get(parent.id) !== place.node.id) opened.set(parent.id, place.node.id);
61
+ place = parent ? map.get(parent.id) : void 0;
62
+ }
63
+ }
64
+ }, { immediate: true });
65
+ function shownPage(container) {
66
+ const pages = container.children;
67
+ const id = opened.get(container.id);
68
+ return pages.find((page) => page.id === id) ?? pages[0];
69
+ }
70
+ const selected = computed(() => new Set(selection.value));
71
+ const focused = computed(() => {
72
+ const last = selection.value[selection.value.length - 1];
73
+ return last ? formNodePlaces(doc.value).get(last)?.node : void 0;
74
+ });
75
+ function announce(text) {
76
+ live.value = "";
77
+ nextTick(() => live.value = text);
78
+ }
79
+ function transaction() {
80
+ return new FormBuilderTransaction(doc.value);
81
+ }
82
+ /** An extension's history, used instead of the builder's own. */
83
+ let customFor;
84
+ let custom = null;
85
+ function customHistory() {
86
+ const make = options.extensions().history;
87
+ if (make !== customFor) {
88
+ customFor = make;
89
+ custom = make ? make(self) : null;
90
+ }
91
+ return custom;
92
+ }
93
+ function dispatch(tr, dispatchOptions = {}) {
94
+ if (tr.before !== doc.value) throw new Error("[@dou-ui/form-builder] the transaction was made on another version of the form");
95
+ const before = selection.value.slice();
96
+ if (tr.changed) for (const hook of options.extensions().transactions) hook(tr, self);
97
+ if (tr.changed) {
98
+ doc.value = tr.doc;
99
+ options.emitDocument(tr.doc, tr);
100
+ }
101
+ setSelection(dispatchOptions.selection ?? selection.value);
102
+ if (tr.changed) {
103
+ if (!customHistory()) history.record(tr, before, selection.value.slice());
104
+ travelled.value++;
105
+ }
106
+ if (dispatchOptions.announce) announce(dispatchOptions.announce);
107
+ }
108
+ function select(ids, mode = "replace") {
109
+ const list = ids === null ? [] : typeof ids === "string" ? [ids] : ids;
110
+ if (mode === "replace") return setSelection(list);
111
+ const current = selection.value;
112
+ if (mode === "toggle") {
113
+ const off = new Set(list.filter((id) => current.includes(id)));
114
+ return setSelection([...current.filter((id) => !off.has(id)), ...list.filter((id) => !off.has(id))]);
115
+ }
116
+ setSelection([...current.filter((id) => !list.includes(id)), ...list]);
117
+ }
118
+ const tapToggles = shallowRef(false);
119
+ /** Where a Shift range starts: the node of the last press without Shift. */
120
+ let anchor;
121
+ function pick(id, event, view) {
122
+ if (event.metaKey || event.ctrlKey || tapToggles.value) {
123
+ anchor = id;
124
+ return select(id, "toggle");
125
+ }
126
+ const from = anchor && selection.value.includes(anchor) ? anchor : void 0;
127
+ if (event.shiftKey && from) {
128
+ const order = view.order();
129
+ const a = order.indexOf(from);
130
+ const b = order.indexOf(id);
131
+ if (a >= 0 && b >= 0) {
132
+ const range = [];
133
+ const dir = a <= b ? 1 : -1;
134
+ for (let at = a; at !== b + dir; at += dir) range.push(order[at]);
135
+ return setSelection(range);
136
+ }
137
+ }
138
+ anchor = id;
139
+ select(id, "replace");
140
+ }
141
+ const context = () => ({
142
+ fields: options.fields(),
143
+ messages: options.messages()
144
+ });
145
+ const target = (ids) => ids ?? selection.value;
146
+ const locked = () => options.readonly();
147
+ function add(type, place) {
148
+ if (locked()) return void 0;
149
+ const document = doc.value;
150
+ const where = place ?? insertPlace(document, selection.value, type, shownPage);
151
+ const node = createNode(type, {
152
+ ...context(),
153
+ taken: namesIn(document, scopeOf(document, where.parent))
154
+ });
155
+ const tr = transaction().insert(node, where.parent, where.index);
156
+ tr.setMeta("origin", "insert");
157
+ const label = labelOf(type, options.fields().get(type), options.messages());
158
+ dispatch(tr, {
159
+ selection: [node.id],
160
+ announce: formatMessage(options.messages().announce.inserted, { label })
161
+ });
162
+ return node.id;
163
+ }
164
+ function remove(ids) {
165
+ if (locked()) return;
166
+ const tr = transaction();
167
+ const { removed, next } = removeNodes(tr, target(ids));
168
+ if (!removed) return;
169
+ dispatch(tr, {
170
+ selection: next ? [next] : [],
171
+ announce: formatMessage(options.messages().announce.removed, { count: removed })
172
+ });
173
+ }
174
+ function duplicate(ids) {
175
+ if (locked()) return;
176
+ const tr = transaction();
177
+ const copies = duplicateNodes(tr, target(ids));
178
+ if (!copies.length) return;
179
+ dispatch(tr, {
180
+ selection: copies,
181
+ announce: formatMessage(options.messages().announce.duplicated, { count: copies.length })
182
+ });
183
+ }
184
+ function moveBy(delta, ids) {
185
+ if (locked()) return;
186
+ const tr = transaction();
187
+ if (!moveNodes(tr, target(ids), delta)) return;
188
+ const last = target(ids)[target(ids).length - 1];
189
+ const place = last ? formNodePlaces(tr.doc).get(last) : void 0;
190
+ dispatch(tr, { announce: place ? formatMessage(options.messages().announce.moved, { index: place.index + 1 }) : void 0 });
191
+ }
192
+ function moveTo(place, ids) {
193
+ if (locked()) return;
194
+ const tr = transaction();
195
+ const moving = target(ids);
196
+ if (!moveNodesTo(tr, moving, place.parent, place.index)) return;
197
+ tr.setMeta("origin", "drag");
198
+ const map = formNodePlaces(tr.doc);
199
+ const moved = topmost(tr.doc, moving);
200
+ const first = map.get(moved[0] ?? "");
201
+ const messages = options.messages();
202
+ const where = first?.parent ? nodeTitle(first.parent, options.fields(), messages) : messages.drag.top;
203
+ dispatch(tr, {
204
+ selection: [...moving],
205
+ announce: first ? formatMessage(moved.length > 1 ? messages.announce.movedManyTo : messages.announce.movedTo, {
206
+ where,
207
+ index: first.index + 1,
208
+ count: moved.length
209
+ }) : void 0
210
+ });
211
+ }
212
+ function replace(next) {
213
+ if (locked()) return;
214
+ const tr = transaction();
215
+ replaceDocument(tr, toRaw(next));
216
+ tr.setMeta("origin", "replace");
217
+ dispatch(tr, {
218
+ selection: [],
219
+ announce: options.messages().announce.replaced
220
+ });
221
+ }
222
+ function wrap(ids) {
223
+ if (locked()) return;
224
+ const tr = transaction();
225
+ const section = wrapNodes(tr, target(ids), context());
226
+ if (!section) return;
227
+ dispatch(tr, {
228
+ selection: [section],
229
+ announce: options.messages().announce.wrapped
230
+ });
231
+ }
232
+ function addPage(id) {
233
+ if (locked()) return;
234
+ const map = formNodePlaces(doc.value);
235
+ let place = map.get(id ?? selection.value[selection.value.length - 1] ?? "");
236
+ while (place && place.node.type !== "tabs" && place.node.type !== "steps") place = place.parent ? map.get(place.parent.id) : void 0;
237
+ if (!place) return;
238
+ const container = place.node;
239
+ const messages = options.messages();
240
+ const text = container.type === "steps" ? messages.created.step : messages.created.page;
241
+ const page = createNode("page", {
242
+ ...context(),
243
+ taken: /* @__PURE__ */ new Set()
244
+ });
245
+ page.title = formatMessage(text, { index: container.children.length + 1 });
246
+ dispatch(transaction().insert(page, container.id, container.children.length), {
247
+ selection: [page.id],
248
+ announce: formatMessage(messages.announce.inserted, { label: page.title })
249
+ });
250
+ }
251
+ function parentOf(id) {
252
+ if (!id) return void 0;
253
+ return formNodePlaces(doc.value).get(id)?.parent ?? void 0;
254
+ }
255
+ function selectParent() {
256
+ const last = selection.value[selection.value.length - 1];
257
+ const parent = parentOf(last);
258
+ setSelection(parent ? [parent.id] : []);
259
+ }
260
+ function travel(direction) {
261
+ if (locked()) return;
262
+ const handler = customHistory();
263
+ if (handler) {
264
+ if (!handler[direction]()) return;
265
+ travelled.value++;
266
+ announce(options.messages().announce[direction === "undo" ? "undone" : "redone"]);
267
+ return;
268
+ }
269
+ const result = direction === "undo" ? history.undo(doc.value) : history.redo(doc.value);
270
+ if (!result) return;
271
+ doc.value = result.tr.doc;
272
+ options.emitDocument(result.tr.doc, result.tr);
273
+ setSelection(result.selection);
274
+ travelled.value++;
275
+ announce(options.messages().announce[direction === "undo" ? "undone" : "redone"]);
276
+ }
277
+ function focusInspector() {
278
+ (inspector.value?.querySelector("input:not([disabled]), textarea:not([disabled]), button:not([disabled]), [tabindex=\"0\"]"))?.focus();
279
+ }
280
+ /** The keys of the canvas and the outline, as hotkeys. */
281
+ const keys = [
282
+ [
283
+ "mod+z",
284
+ () => travel("undo"),
285
+ true
286
+ ],
287
+ [
288
+ "mod+shift+z",
289
+ () => travel("redo"),
290
+ true
291
+ ],
292
+ [
293
+ "mod+y",
294
+ () => travel("redo"),
295
+ true
296
+ ],
297
+ [
298
+ "mod+d",
299
+ () => duplicate(),
300
+ true
301
+ ],
302
+ [
303
+ "mod+g",
304
+ () => wrap(),
305
+ true
306
+ ],
307
+ [
308
+ "delete",
309
+ () => remove(),
310
+ true
311
+ ],
312
+ [
313
+ "backspace",
314
+ () => remove(),
315
+ true
316
+ ],
317
+ [
318
+ "mod+arrowup",
319
+ () => moveBy(-1),
320
+ true
321
+ ],
322
+ [
323
+ "mod+arrowdown",
324
+ () => moveBy(1),
325
+ true
326
+ ],
327
+ ["arrowup", (view) => step(view, -1, false)],
328
+ ["arrowdown", (view) => step(view, 1, false)],
329
+ ["shift+arrowup", (view) => step(view, -1, true)],
330
+ ["shift+arrowdown", (view) => step(view, 1, true)],
331
+ ["home", (view) => jump(view, 0)],
332
+ ["end", (view) => jump(view, -1)],
333
+ ["arrowright", (view) => inward(view)],
334
+ ["arrowleft", (view) => outward(view)],
335
+ ["enter", () => focusInspector()],
336
+ ["escape", () => selectParent()]
337
+ ];
338
+ function step(view, delta, extend) {
339
+ const order = view.order();
340
+ if (!order.length) return;
341
+ const last = selection.value[selection.value.length - 1];
342
+ const at = last ? order.indexOf(last) : -1;
343
+ const next = at < 0 ? order[delta > 0 ? 0 : order.length - 1] : order[Math.min(Math.max(at + delta, 0), order.length - 1)];
344
+ if (!extend) return setSelection([next]);
345
+ if (selection.value[selection.value.length - 2] === next) return setSelection(selection.value.slice(0, -1));
346
+ select(next, "extend");
347
+ }
348
+ function jump(view, at) {
349
+ const order = view.order();
350
+ const id = at === 0 ? order[0] : order[order.length - 1];
351
+ if (id) setSelection([id]);
352
+ }
353
+ function inward(view) {
354
+ const last = selection.value[selection.value.length - 1];
355
+ if (!last || view.expand?.(last)) return;
356
+ const node = formNodePlaces(doc.value).get(last)?.node;
357
+ if (!node || !isContainer(node)) return;
358
+ const first = node.children[0];
359
+ if (!first) return;
360
+ if (view.order().includes(first.id)) setSelection([first.id]);
361
+ }
362
+ function outward(view) {
363
+ const last = selection.value[selection.value.length - 1];
364
+ if (!last || view.collapse?.(last)) return;
365
+ const parent = parentOf(last);
366
+ if (parent) setSelection([parent.id]);
367
+ }
368
+ function keydown(event, view) {
369
+ if (event.isComposing) return;
370
+ if (dragger.value?.carrying) {
371
+ if (dragger.value.keydown(event)) event.preventDefault();
372
+ return;
373
+ }
374
+ if (event.key === " " && !event.repeat && !locked() && dragger.value?.pickUp()) {
375
+ event.preventDefault();
376
+ return;
377
+ }
378
+ for (const keymap of options.extensions().keymaps) for (const [hotkey, handler] of Object.entries(keymap(self))) {
379
+ if (!matchesHotkey(event, hotkey) || handler(event) === false) continue;
380
+ event.preventDefault();
381
+ return;
382
+ }
383
+ for (const [hotkey, run, edits] of keys) {
384
+ if (!matchesHotkey(event, hotkey) || edits && locked()) continue;
385
+ event.preventDefault();
386
+ run(view, event);
387
+ return;
388
+ }
389
+ }
390
+ const self = {
391
+ get document() {
392
+ return doc.value;
393
+ },
394
+ get selection() {
395
+ return selection.value;
396
+ },
397
+ get fields() {
398
+ return options.fields();
399
+ },
400
+ get messages() {
401
+ return options.messages();
402
+ },
403
+ get canUndo() {
404
+ travelled.value;
405
+ return !locked() && (customHistory()?.canUndo() ?? history.canUndo);
406
+ },
407
+ get canRedo() {
408
+ travelled.value;
409
+ return !locked() && (customHistory()?.canRedo() ?? history.canRedo);
410
+ },
411
+ get readonly() {
412
+ return locked();
413
+ },
414
+ get mode() {
415
+ return options.mode();
416
+ },
417
+ setMode: (mode) => {
418
+ if (mode !== options.mode()) options.emitMode(mode);
419
+ },
420
+ transaction,
421
+ dispatch,
422
+ select,
423
+ add,
424
+ remove,
425
+ duplicate,
426
+ moveBy,
427
+ moveTo,
428
+ replace,
429
+ wrap,
430
+ addPage,
431
+ selectParent,
432
+ undo: () => travel("undo"),
433
+ redo: () => travel("redo"),
434
+ shownPage,
435
+ domId: (id, view) => `${options.uid}-${view === "canvas" ? "n" : "o"}-${id}`,
436
+ announce,
437
+ live,
438
+ keydown,
439
+ focusInspector,
440
+ inspector,
441
+ canvas,
442
+ dragger,
443
+ openMenu,
444
+ tapToggles,
445
+ pick,
446
+ selected,
447
+ focused,
448
+ functionNames: computed(() => Object.keys(options.functions() ?? {})),
449
+ functions: options.functions,
450
+ sources: options.sources,
451
+ validators: options.validators,
452
+ extensions: options.extensions
453
+ };
454
+ return self;
455
+ }
456
+ /** Every node in the order the canvas lists them: only the shown page of tabs and steps is open. */
457
+ function canvasOrder(state) {
458
+ const order = [];
459
+ const visit = (nodes) => {
460
+ for (const node of nodes) {
461
+ order.push(node.id);
462
+ if (node.type === "tabs" || node.type === "steps") {
463
+ const container = node;
464
+ const shown = state.shownPage(container);
465
+ for (const page of container.children) {
466
+ order.push(page.id);
467
+ if (page === shown) visit(page.children);
468
+ }
469
+ } else if (isContainer(node)) visit(node.children);
470
+ }
471
+ };
472
+ visit(state.document.nodes);
473
+ return order;
474
+ }
475
+ export { builderKey, canvasOrder, createBuilderState, useBuilderState, useFormBuilder };
476
+
477
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","names":[],"sources":["../../src/builder/context.ts"],"sourcesContent":["import { computed, inject, nextTick, shallowReactive, shallowRef, toRaw, watch } from 'vue'\nimport type { ComputedRef, InjectionKey, Ref } from 'vue'\nimport { matchesHotkey } from 'dou-ui'\nimport { isContainer, isPage } from '../core/document'\nimport type {\n FormContainerNode,\n FormDocument,\n FormNode,\n FormPageNode,\n FormValidator,\n} from '../core/types'\nimport type { FormFunction } from '../core/expression'\nimport type { FormFieldType } from '../fields/define'\nimport type { FormOptionsLoader } from '../renderer/context'\nimport type { FormBuilderHistoryHandler, ResolvedFormBuilderExtensions } from './extension'\nimport { formatMessage } from '../locale'\nimport type { FormBuilderMessages } from './locale'\nimport { FormBuilderHistory } from './core/history'\nimport { FormBuilderTransaction, formNodePlaces } from './core/transaction'\nimport {\n createNode,\n duplicateNodes,\n insertPlace,\n moveNodes,\n moveNodesTo,\n namesIn,\n topmost,\n removeNodes,\n replaceDocument,\n scopeOf,\n wrapNodes,\n} from './core/commands'\nimport type { FormBuilderInsertPlace } from './core/commands'\nimport { labelOf, nodeTitle } from './settings'\nimport type { DragController } from './drag'\n\n/** What the builder shows: the canvas to edit on, or the form to fill in as people will. */\nexport type FormBuilderMode = 'design' | 'preview'\n\n/** How a click changes the selection: replace it, add or take away the node, or extend it. */\nexport type FormBuilderSelectMode = 'replace' | 'toggle' | 'extend'\n\nexport interface FormBuilderDispatchOptions {\n /** The selection after the change. Defaults to the current one, without nodes that are gone. */\n selection?: readonly string[]\n /** Read out to screen readers once the change is made. */\n announce?: string\n}\n\n/**\n * What the builder and its parts share, from `useFormBuilder()` inside a\n * builder, e.g. in a panel of your own or a field type's component.\n */\nexport interface FormBuilderContext {\n /** The document as it is now. */\n readonly document: FormDocument\n /** The ids of the selected nodes, the last one selected last. */\n readonly selection: readonly string[]\n /** Every field type, built-in and given. */\n readonly fields: ReadonlyMap<string, FormFieldType>\n readonly messages: FormBuilderMessages\n readonly canUndo: boolean\n readonly canRedo: boolean\n /**\n * Whether the builder only shows the form: nodes can be selected and\n * their settings read, but the commands below change nothing. A\n * transaction handed to `dispatch` still applies.\n */\n readonly readonly: boolean\n readonly mode: FormBuilderMode\n /** Show the canvas or the preview. */\n setMode: (mode: FormBuilderMode) => void\n /** A transaction on the document as it is now, to `dispatch`. */\n transaction: () => FormBuilderTransaction\n /** Make the changes of a transaction, as one undo step (or part of one, by `meta.group`). */\n dispatch: (tr: FormBuilderTransaction, options?: FormBuilderDispatchOptions) => void\n /** Select nodes; `null` or `[]` selects the form itself. */\n select: (ids: string | readonly string[] | null, mode?: FormBuilderSelectMode) => void\n /**\n * Add a new node of a type (a field type or `section`, `tabs`, `steps`,\n * `list`) and select it. It goes into the selected container, else\n * after the selected node, else at the end, unless `place` says where.\n * Returns its id.\n */\n add: (type: string, place?: FormBuilderInsertPlace) => string | undefined\n /** Delete nodes, the selected ones by default. */\n remove: (ids?: readonly string[]) => void\n /** Put a copy of each node after it, the selected ones by default, and select the copies. */\n duplicate: (ids?: readonly string[]) => void\n /** Move nodes, the selected ones by default, one place up (`-1`) or down (`1`). */\n moveBy: (delta: -1 | 1, ids?: readonly string[]) => void\n /**\n * Move nodes, the selected ones by default, into a container (`null`:\n * the top) to start at `index` of its children as they are now.\n */\n moveTo: (place: FormBuilderInsertPlace, ids?: readonly string[]) => void\n /** Replace the whole form with another, e.g. one imported as JSON, as one undo step. */\n replace: (document: FormDocument) => void\n /** Put nodes of one container into a new section, the selected ones by default. */\n wrap: (ids?: readonly string[]) => void\n /** Add a page to tabs or steps (the selected ones, or the ones around the selection). */\n addPage: (id?: string) => void\n /** Select the container around the last selected node, or the form. */\n selectParent: () => void\n undo: () => void\n redo: () => void\n /** The page of tabs or steps the canvas shows. */\n shownPage: (container: FormContainerNode) => FormPageNode | undefined\n}\n\n/** What the builder's own parts read besides the public context. */\nexport interface BuilderState extends FormBuilderContext {\n /** The id of a node's element on the canvas or in the outline. */\n domId: (id: string, view: 'canvas' | 'outline') => string\n announce: (text: string) => void\n live: Ref<string>\n /** Keys pressed on the canvas or the outline; `order` is the nodes as they are listed there. */\n keydown: (event: KeyboardEvent, view: BuilderView) => void\n /** Ask the inspector to focus its first setting. */\n focusInspector: () => void\n inspector: Ref<HTMLElement | null>\n /** The canvas's focusable tree, to take focus back. */\n canvas: Ref<HTMLElement | null>\n /** Taps add to the selection or take from it, for touch screens without Shift or ⌘. */\n tapToggles: Ref<boolean>\n /**\n * A press on a node in a view: Shift selects the range from the last\n * plain press, ⌘ / Ctrl (or `tapToggles`) adds or removes, else replaces.\n */\n pick: (id: string, event: MouseEvent, view: BuilderView) => void\n /** Drags on the canvas, set by the canvas once it is mounted. */\n dragger: Ref<DragController | null>\n /** Opens the menu of the selected nodes at a point of the viewport, set by the canvas. */\n openMenu: Ref<((x: number, y: number) => void) | null>\n /** The names of the functions given to the builder, for checks and completions. */\n functionNames: ComputedRef<string[]>\n /** The functions given to the builder, for the preview. */\n functions: () => Record<string, FormFunction> | undefined\n sources: () => Record<string, FormOptionsLoader> | undefined\n /** The validators given to the builder, for the preview and the rules editor. */\n validators: () => Record<string, FormValidator> | undefined\n extensions: () => ResolvedFormBuilderExtensions\n /** The selection, as a set, for views checking many nodes. */\n selected: ComputedRef<ReadonlySet<string>>\n /** The node the inspector and the action bar are for: the last selected one. */\n focused: ComputedRef<FormNode | undefined>\n}\n\n/** A list of nodes as a view shows them, for the arrow keys. */\nexport interface BuilderView {\n name: 'canvas' | 'outline'\n /** The nodes in the order they are listed. */\n order: () => string[]\n /** `ArrowRight` on a node: return `true` when the view handled it, e.g. by expanding it. */\n expand?: (id: string) => boolean\n collapse?: (id: string) => boolean\n}\n\nexport const builderKey: InjectionKey<BuilderState> = Symbol('DouFormBuilder')\n\n/** Inside a builder: its document, selection and commands. */\nexport function useFormBuilder(): FormBuilderContext {\n const state = inject(builderKey, undefined)\n if (!state)\n throw new Error(\n '[@dou-ui/form-builder] useFormBuilder() must be called inside <DouFormBuilder>',\n )\n return state\n}\n\nexport function useBuilderState(): BuilderState {\n const state = inject(builderKey, undefined)\n if (!state)\n throw new Error(\n '[@dou-ui/form-builder] the parts of a form builder must be placed inside <DouFormBuilder>',\n )\n return state\n}\n\nexport interface CreateBuilderOptions {\n uid: string\n document: () => FormDocument\n selection: () => readonly string[] | undefined\n fields: () => Map<string, FormFieldType>\n messages: () => FormBuilderMessages\n emitDocument: (document: FormDocument, tr: FormBuilderTransaction) => void\n emitSelection: (ids: string[]) => void\n mode: () => FormBuilderMode\n emitMode: (mode: FormBuilderMode) => void\n functions: () => Record<string, FormFunction> | undefined\n sources: () => Record<string, FormOptionsLoader> | undefined\n validators: () => Record<string, FormValidator> | undefined\n readonly: () => boolean\n extensions: () => ResolvedFormBuilderExtensions\n}\n\nconst same = (a: readonly string[], b: readonly string[]) =>\n a.length === b.length && a.every((id, index) => id === b[index])\n\nexport function createBuilderState(options: CreateBuilderOptions): BuilderState {\n const doc = shallowRef<FormDocument>(toRaw(options.document()))\n const selection = shallowRef<readonly string[]>(options.selection() ?? [])\n const history = new FormBuilderHistory()\n /** Bumped whenever the history changes, so `canUndo` and `canRedo` stay current. */\n const travelled = shallowRef(0)\n const live = shallowRef('')\n const inspector = shallowRef<HTMLElement | null>(null)\n const canvas = shallowRef<HTMLElement | null>(null)\n const dragger = shallowRef<DragController | null>(null)\n const openMenu = shallowRef<((x: number, y: number) => void) | null>(null)\n\n // A document from outside, e.g. one loaded or reset by the page, starts a new history.\n watch(options.document, (next) => {\n const raw = toRaw(next)\n if (raw === doc.value) return\n doc.value = raw\n history.clear()\n travelled.value++\n setSelection(selection.value)\n })\n watch(options.selection, (next) => {\n if (next && !same(next, selection.value)) setSelection(next, false)\n })\n\n function setSelection(ids: readonly string[], emit = true) {\n const map = formNodePlaces(doc.value)\n const seen = new Set<string>()\n const next = ids.filter((id) => map.has(id) && !seen.has(id) && seen.add(id))\n if (same(next, selection.value)) return\n selection.value = next\n if (emit) options.emitSelection(next.slice())\n }\n\n // The page each tabs and steps shows: the one holding the selection, else the last one opened.\n const opened = shallowReactive(new Map<string, string>())\n watch(\n [selection, doc],\n ([ids, document]) => {\n const map = formNodePlaces(document)\n for (const id of ids) {\n let place = map.get(id)\n while (place) {\n const parent = place.parent\n if (parent && isPage(place.node) && opened.get(parent.id) !== place.node.id)\n opened.set(parent.id, place.node.id)\n place = parent ? map.get(parent.id) : undefined\n }\n }\n },\n { immediate: true },\n )\n function shownPage(container: FormContainerNode) {\n const pages = container.children as FormNode[]\n const id = opened.get(container.id)\n return (pages.find((page) => page.id === id) ?? pages[0]) as FormPageNode | undefined\n }\n\n const selected = computed(() => new Set(selection.value))\n const focused = computed(() => {\n const last = selection.value[selection.value.length - 1]\n return last ? formNodePlaces(doc.value).get(last)?.node : undefined\n })\n\n function announce(text: string) {\n live.value = ''\n void nextTick(() => (live.value = text))\n }\n\n function transaction() {\n return new FormBuilderTransaction(doc.value)\n }\n\n /** An extension's history, used instead of the builder's own. */\n let customFor: unknown\n let custom: FormBuilderHistoryHandler | null = null\n function customHistory() {\n const make = options.extensions().history\n if (make !== customFor) {\n customFor = make\n custom = make ? make(self) : null\n }\n return custom\n }\n\n function dispatch(tr: FormBuilderTransaction, dispatchOptions: FormBuilderDispatchOptions = {}) {\n if (tr.before !== doc.value)\n throw new Error(\n '[@dou-ui/form-builder] the transaction was made on another version of the form',\n )\n const before = selection.value.slice()\n if (tr.changed) for (const hook of options.extensions().transactions) hook(tr, self)\n if (tr.changed) {\n doc.value = tr.doc\n options.emitDocument(tr.doc, tr)\n }\n setSelection(dispatchOptions.selection ?? selection.value)\n if (tr.changed) {\n if (!customHistory()) history.record(tr, before, selection.value.slice())\n travelled.value++\n }\n if (dispatchOptions.announce) announce(dispatchOptions.announce)\n }\n\n function select(ids: string | readonly string[] | null, mode: FormBuilderSelectMode = 'replace') {\n const list = ids === null ? [] : typeof ids === 'string' ? [ids] : ids\n if (mode === 'replace') return setSelection(list)\n const current = selection.value\n if (mode === 'toggle') {\n const off = new Set(list.filter((id) => current.includes(id)))\n return setSelection([\n ...current.filter((id) => !off.has(id)),\n ...list.filter((id) => !off.has(id)),\n ])\n }\n setSelection([...current.filter((id) => !list.includes(id)), ...list])\n }\n\n const tapToggles = shallowRef(false)\n /** Where a Shift range starts: the node of the last press without Shift. */\n let anchor: string | undefined\n function pick(id: string, event: MouseEvent, view: BuilderView) {\n if (event.metaKey || event.ctrlKey || tapToggles.value) {\n anchor = id\n return select(id, 'toggle')\n }\n const from = anchor && selection.value.includes(anchor) ? anchor : undefined\n if (event.shiftKey && from) {\n const order = view.order()\n const a = order.indexOf(from)\n const b = order.indexOf(id)\n if (a >= 0 && b >= 0) {\n // From the start of the range to the pressed node, which goes last for the inspector.\n const range: string[] = []\n const dir = a <= b ? 1 : -1\n for (let at = a; at !== b + dir; at += dir) range.push(order[at]!)\n return setSelection(range)\n }\n }\n anchor = id\n select(id, 'replace')\n }\n\n const context = () => ({ fields: options.fields(), messages: options.messages() })\n const target = (ids?: readonly string[]) => ids ?? selection.value\n\n const locked = () => options.readonly()\n\n function add(type: string, place?: FormBuilderInsertPlace) {\n if (locked()) return undefined\n const document = doc.value\n const where = place ?? insertPlace(document, selection.value, type, shownPage)\n const node = createNode(type, {\n ...context(),\n taken: namesIn(document, scopeOf(document, where.parent)),\n })\n const tr = transaction().insert(node, where.parent, where.index)\n tr.setMeta('origin', 'insert')\n const label = labelOf(type, options.fields().get(type), options.messages())\n dispatch(tr, {\n selection: [node.id],\n announce: formatMessage(options.messages().announce.inserted, { label }),\n })\n return node.id\n }\n\n function remove(ids?: readonly string[]) {\n if (locked()) return\n const tr = transaction()\n const { removed, next } = removeNodes(tr, target(ids))\n if (!removed) return\n dispatch(tr, {\n selection: next ? [next] : [],\n announce: formatMessage(options.messages().announce.removed, { count: removed }),\n })\n }\n\n function duplicate(ids?: readonly string[]) {\n if (locked()) return\n const tr = transaction()\n const copies = duplicateNodes(tr, target(ids))\n if (!copies.length) return\n dispatch(tr, {\n selection: copies,\n announce: formatMessage(options.messages().announce.duplicated, { count: copies.length }),\n })\n }\n\n function moveBy(delta: -1 | 1, ids?: readonly string[]) {\n if (locked()) return\n const tr = transaction()\n if (!moveNodes(tr, target(ids), delta)) return\n const last = target(ids)[target(ids).length - 1]\n const place = last ? formNodePlaces(tr.doc).get(last) : undefined\n dispatch(tr, {\n announce: place\n ? formatMessage(options.messages().announce.moved, { index: place.index + 1 })\n : undefined,\n })\n }\n\n function moveTo(place: FormBuilderInsertPlace, ids?: readonly string[]) {\n if (locked()) return\n const tr = transaction()\n const moving = target(ids)\n if (!moveNodesTo(tr, moving, place.parent, place.index)) return\n tr.setMeta('origin', 'drag')\n const map = formNodePlaces(tr.doc)\n const moved = topmost(tr.doc, moving)\n const first = map.get(moved[0] ?? '')\n const messages = options.messages()\n const where = first?.parent\n ? nodeTitle(first.parent, options.fields(), messages)\n : messages.drag.top\n dispatch(tr, {\n selection: [...moving],\n announce: first\n ? formatMessage(\n moved.length > 1 ? messages.announce.movedManyTo : messages.announce.movedTo,\n {\n where,\n index: first.index + 1,\n count: moved.length,\n },\n )\n : undefined,\n })\n }\n\n function replace(next: FormDocument) {\n if (locked()) return\n const tr = transaction()\n replaceDocument(tr, toRaw(next))\n tr.setMeta('origin', 'replace')\n dispatch(tr, { selection: [], announce: options.messages().announce.replaced })\n }\n\n function wrap(ids?: readonly string[]) {\n if (locked()) return\n const tr = transaction()\n const section = wrapNodes(tr, target(ids), context())\n if (!section) return\n dispatch(tr, { selection: [section], announce: options.messages().announce.wrapped })\n }\n\n function addPage(id?: string) {\n if (locked()) return\n const map = formNodePlaces(doc.value)\n let place = map.get(id ?? selection.value[selection.value.length - 1] ?? '')\n while (place && place.node.type !== 'tabs' && place.node.type !== 'steps')\n place = place.parent ? map.get(place.parent.id) : undefined\n if (!place) return\n const container = place.node as FormContainerNode\n const messages = options.messages()\n const text = container.type === 'steps' ? messages.created.step : messages.created.page\n const page = createNode('page', { ...context(), taken: new Set() }) as FormPageNode\n page.title = formatMessage(text, { index: container.children.length + 1 })\n const tr = transaction().insert(page, container.id, container.children.length)\n dispatch(tr, {\n selection: [page.id],\n announce: formatMessage(messages.announce.inserted, { label: page.title }),\n })\n }\n\n function parentOf(id: string | undefined) {\n if (!id) return undefined\n return formNodePlaces(doc.value).get(id)?.parent ?? undefined\n }\n\n function selectParent() {\n const last = selection.value[selection.value.length - 1]\n const parent = parentOf(last)\n setSelection(parent ? [parent.id] : [])\n }\n\n function travel(direction: 'undo' | 'redo') {\n if (locked()) return\n const handler = customHistory()\n if (handler) {\n if (!handler[direction]()) return\n travelled.value++\n announce(options.messages().announce[direction === 'undo' ? 'undone' : 'redone'])\n return\n }\n const result = direction === 'undo' ? history.undo(doc.value) : history.redo(doc.value)\n if (!result) return\n doc.value = result.tr.doc\n options.emitDocument(result.tr.doc, result.tr)\n setSelection(result.selection)\n travelled.value++\n announce(options.messages().announce[direction === 'undo' ? 'undone' : 'redone'])\n }\n\n function focusInspector() {\n const root = inspector.value\n const first = root?.querySelector<HTMLElement>(\n 'input:not([disabled]), textarea:not([disabled]), button:not([disabled]), [tabindex=\"0\"]',\n )\n first?.focus()\n }\n\n /** The keys of the canvas and the outline, as hotkeys. */\n const keys: [\n hotkey: string,\n run: (view: BuilderView, event: KeyboardEvent) => void,\n /** Changes the form, so a read-only builder lets the key through. */\n edits?: boolean,\n ][] = [\n ['mod+z', () => travel('undo'), true],\n ['mod+shift+z', () => travel('redo'), true],\n ['mod+y', () => travel('redo'), true],\n ['mod+d', () => duplicate(), true],\n ['mod+g', () => wrap(), true],\n ['delete', () => remove(), true],\n ['backspace', () => remove(), true],\n ['mod+arrowup', () => moveBy(-1), true],\n ['mod+arrowdown', () => moveBy(1), true],\n ['arrowup', (view) => step(view, -1, false)],\n ['arrowdown', (view) => step(view, 1, false)],\n ['shift+arrowup', (view) => step(view, -1, true)],\n ['shift+arrowdown', (view) => step(view, 1, true)],\n ['home', (view) => jump(view, 0)],\n ['end', (view) => jump(view, -1)],\n ['arrowright', (view) => inward(view)],\n ['arrowleft', (view) => outward(view)],\n ['enter', () => focusInspector()],\n ['escape', () => selectParent()],\n ]\n\n function step(view: BuilderView, delta: -1 | 1, extend: boolean) {\n const order = view.order()\n if (!order.length) return\n const last = selection.value[selection.value.length - 1]\n const at = last ? order.indexOf(last) : -1\n const next =\n at < 0\n ? order[delta > 0 ? 0 : order.length - 1]!\n : order[Math.min(Math.max(at + delta, 0), order.length - 1)]!\n if (!extend) return setSelection([next])\n // Shift + arrows grow the selection, or shrink it when going back over it.\n const before = selection.value[selection.value.length - 2]\n if (before === next) return setSelection(selection.value.slice(0, -1))\n select(next, 'extend')\n }\n\n function jump(view: BuilderView, at: 0 | -1) {\n const order = view.order()\n const id = at === 0 ? order[0] : order[order.length - 1]\n if (id) setSelection([id])\n }\n\n function inward(view: BuilderView) {\n const last = selection.value[selection.value.length - 1]\n if (!last || view.expand?.(last)) return\n const node = formNodePlaces(doc.value).get(last)?.node\n if (!node || !isContainer(node)) return\n const first = node.children[0]\n if (!first) return\n const order = view.order()\n if (order.includes(first.id)) setSelection([first.id])\n }\n\n function outward(view: BuilderView) {\n const last = selection.value[selection.value.length - 1]\n if (!last || view.collapse?.(last)) return\n const parent = parentOf(last)\n if (parent) setSelection([parent.id])\n }\n\n function keydown(event: KeyboardEvent, view: BuilderView) {\n if (event.isComposing) return\n // While nodes are picked up, the keys choose where they go.\n if (dragger.value?.carrying) {\n if (dragger.value.keydown(event)) event.preventDefault()\n return\n }\n if (event.key === ' ' && !event.repeat && !locked() && dragger.value?.pickUp()) {\n event.preventDefault()\n return\n }\n for (const keymap of options.extensions().keymaps)\n for (const [hotkey, handler] of Object.entries(keymap(self))) {\n if (!matchesHotkey(event, hotkey) || handler(event) === false) continue\n event.preventDefault()\n return\n }\n for (const [hotkey, run, edits] of keys) {\n if (!matchesHotkey(event, hotkey) || (edits && locked())) continue\n event.preventDefault()\n run(view, event)\n return\n }\n }\n\n const functionNames = computed(() => Object.keys(options.functions() ?? {}))\n\n const self: BuilderState = {\n get document() {\n return doc.value\n },\n get selection() {\n return selection.value\n },\n get fields() {\n return options.fields()\n },\n get messages() {\n return options.messages()\n },\n get canUndo() {\n void travelled.value\n return !locked() && (customHistory()?.canUndo() ?? history.canUndo)\n },\n get canRedo() {\n void travelled.value\n return !locked() && (customHistory()?.canRedo() ?? history.canRedo)\n },\n get readonly() {\n return locked()\n },\n get mode() {\n return options.mode()\n },\n setMode: (mode) => {\n if (mode !== options.mode()) options.emitMode(mode)\n },\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: () => travel('undo'),\n redo: () => travel('redo'),\n shownPage,\n domId: (id, view) => `${options.uid}-${view === 'canvas' ? 'n' : 'o'}-${id}`,\n announce,\n live,\n keydown,\n focusInspector,\n inspector,\n canvas,\n dragger,\n openMenu,\n tapToggles,\n pick,\n selected,\n focused,\n functionNames,\n functions: options.functions,\n sources: options.sources,\n validators: options.validators,\n extensions: options.extensions,\n }\n return self\n}\n\n/** Every node in the order the canvas lists them: only the shown page of tabs and steps is open. */\nexport function canvasOrder(state: BuilderState): string[] {\n const order: string[] = []\n const visit = (nodes: readonly FormNode[]) => {\n for (const node of nodes) {\n order.push(node.id)\n if (node.type === 'tabs' || node.type === 'steps') {\n const container = node as FormContainerNode\n const shown = state.shownPage(container)\n for (const page of container.children) {\n order.push(page.id)\n if (page === shown) visit((page as FormPageNode).children)\n }\n } else if (isContainer(node)) visit(node.children)\n }\n }\n visit(state.document.nodes)\n return order\n}\n"],"mappings":"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"}