@dou-ui/flow 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 (173) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +10 -2
  3. package/dist/collaboration/index.js +360 -0
  4. package/dist/collaboration/index.js.map +1 -0
  5. package/dist/collaboration/peers.js +76 -0
  6. package/dist/collaboration/peers.js.map +1 -0
  7. package/dist/components/default-node.js +6 -0
  8. package/dist/components/default-node.js.map +1 -0
  9. package/dist/components/default-node.vue_vue_type_script_setup_true_lang.js +87 -0
  10. package/dist/components/default-node.vue_vue_type_script_setup_true_lang.js.map +1 -0
  11. package/dist/components/default-node2.js +116 -0
  12. package/dist/components/default-node2.js.map +1 -0
  13. package/dist/components/flow-controls.js +6 -0
  14. package/dist/components/flow-controls.js.map +1 -0
  15. package/dist/components/flow-controls.vue_vue_type_script_setup_true_lang.js +148 -0
  16. package/dist/components/flow-controls.vue_vue_type_script_setup_true_lang.js.map +1 -0
  17. package/dist/components/flow-menu.js +6 -0
  18. package/dist/components/flow-menu.js.map +1 -0
  19. package/dist/components/flow-menu.vue_vue_type_script_setup_true_lang.js +52 -0
  20. package/dist/components/flow-menu.vue_vue_type_script_setup_true_lang.js.map +1 -0
  21. package/dist/components/flow-minimap.js +6 -0
  22. package/dist/components/flow-minimap.js.map +1 -0
  23. package/dist/components/flow-minimap.vue_vue_type_script_setup_true_lang.js +238 -0
  24. package/dist/components/flow-minimap.vue_vue_type_script_setup_true_lang.js.map +1 -0
  25. package/dist/components/flow-port.js +6 -0
  26. package/dist/components/flow-port.js.map +1 -0
  27. package/dist/components/flow-port.vue_vue_type_script_setup_true_lang.js +57 -0
  28. package/dist/components/flow-port.vue_vue_type_script_setup_true_lang.js.map +1 -0
  29. package/dist/components/flow-quick-add.js +6 -0
  30. package/dist/components/flow-quick-add.js.map +1 -0
  31. package/dist/components/flow-quick-add.vue_vue_type_script_setup_true_lang.js +126 -0
  32. package/dist/components/flow-quick-add.vue_vue_type_script_setup_true_lang.js.map +1 -0
  33. package/dist/components/flow-toolbar.js +6 -0
  34. package/dist/components/flow-toolbar.js.map +1 -0
  35. package/dist/components/flow-toolbar.vue_vue_type_script_setup_true_lang.js +161 -0
  36. package/dist/components/flow-toolbar.vue_vue_type_script_setup_true_lang.js.map +1 -0
  37. package/dist/components/group-node.js +6 -0
  38. package/dist/components/group-node.js.map +1 -0
  39. package/dist/components/group-node.vue_vue_type_script_setup_true_lang.js +84 -0
  40. package/dist/components/group-node.vue_vue_type_script_setup_true_lang.js.map +1 -0
  41. package/dist/components/group-node2.js +42 -0
  42. package/dist/components/group-node2.js.map +1 -0
  43. package/dist/components/node-view.js +6 -0
  44. package/dist/components/node-view.js.map +1 -0
  45. package/dist/components/node-view.vue_vue_type_script_setup_true_lang.js +179 -0
  46. package/dist/components/node-view.vue_vue_type_script_setup_true_lang.js.map +1 -0
  47. package/dist/context.js +13 -0
  48. package/dist/context.js.map +1 -0
  49. package/dist/core/clipboard.js +37 -0
  50. package/dist/core/clipboard.js.map +1 -0
  51. package/dist/core/connect.js +74 -0
  52. package/dist/core/connect.js.map +1 -0
  53. package/dist/core/edge-types.js +240 -0
  54. package/dist/core/edge-types.js.map +1 -0
  55. package/dist/core/extension.js +63 -0
  56. package/dist/core/extension.js.map +1 -0
  57. package/dist/core/geometry.js +232 -0
  58. package/dist/core/geometry.js.map +1 -0
  59. package/dist/core/groups.js +76 -0
  60. package/dist/core/groups.js.map +1 -0
  61. package/dist/core/history.js +79 -0
  62. package/dist/core/history.js.map +1 -0
  63. package/dist/core/model.js +21 -0
  64. package/dist/core/model.js.map +1 -0
  65. package/dist/core/node-types.js +32 -0
  66. package/dist/core/node-types.js.map +1 -0
  67. package/dist/core/order.js +42 -0
  68. package/dist/core/order.js.map +1 -0
  69. package/dist/core/transaction.js +288 -0
  70. package/dist/core/transaction.js.map +1 -0
  71. package/dist/document.js +220 -0
  72. package/dist/document.js.map +1 -0
  73. package/dist/export/color.js +38 -0
  74. package/dist/export/color.js.map +1 -0
  75. package/dist/export/context.js +223 -0
  76. package/dist/export/context.js.map +1 -0
  77. package/dist/export/draw.js +249 -0
  78. package/dist/export/draw.js.map +1 -0
  79. package/dist/flow-editor.js +6 -0
  80. package/dist/flow-editor.js.map +1 -0
  81. package/dist/flow-editor.vue_vue_type_script_setup_true_lang.js +3721 -0
  82. package/dist/flow-editor.vue_vue_type_script_setup_true_lang.js.map +1 -0
  83. package/dist/index.js +31 -0
  84. package/dist/index.js.map +1 -0
  85. package/dist/kit.js +234 -0
  86. package/dist/kit.js.map +1 -0
  87. package/dist/layers.js +150 -0
  88. package/dist/layers.js.map +1 -0
  89. package/dist/locale.js +426 -0
  90. package/dist/locale.js.map +1 -0
  91. package/dist/style.css +1 -0
  92. package/dist/style.d.ts +1 -0
  93. package/dist/style.js +8 -0
  94. package/dist/types/collaboration/index.d.ts +42 -0
  95. package/dist/types/collaboration/peers.d.ts +27 -0
  96. package/dist/types/components/default-node.d.ts +18 -0
  97. package/dist/types/components/default-node.vue.d.ts +6 -0
  98. package/dist/types/components/flow-controls.vue.d.ts +8 -0
  99. package/dist/types/components/flow-menu.vue.d.ts +29 -0
  100. package/dist/types/components/flow-minimap.vue.d.ts +8 -0
  101. package/dist/types/components/flow-port.vue.d.ts +9 -0
  102. package/dist/types/components/flow-quick-add.vue.d.ts +31 -0
  103. package/dist/types/components/flow-toolbar.vue.d.ts +25 -0
  104. package/dist/types/components/group-node.d.ts +13 -0
  105. package/dist/types/components/group-node.vue.d.ts +6 -0
  106. package/dist/types/components/node-view.vue.d.ts +28 -0
  107. package/dist/types/context.d.ts +362 -0
  108. package/dist/types/core/clipboard.d.ts +9 -0
  109. package/dist/types/core/connect.d.ts +63 -0
  110. package/dist/types/core/edge-types.d.ts +50 -0
  111. package/dist/types/core/extension.d.ts +141 -0
  112. package/dist/types/core/geometry.d.ts +63 -0
  113. package/dist/types/core/groups.d.ts +23 -0
  114. package/dist/types/core/history.d.ts +24 -0
  115. package/dist/types/core/menu.d.ts +40 -0
  116. package/dist/types/core/model.d.ts +87 -0
  117. package/dist/types/core/node-types.d.ts +103 -0
  118. package/dist/types/core/order.d.ts +7 -0
  119. package/dist/types/core/transaction.d.ts +97 -0
  120. package/dist/types/document.d.ts +57 -0
  121. package/dist/types/export/color.d.ts +7 -0
  122. package/dist/types/export/context.d.ts +90 -0
  123. package/dist/types/export/draw.d.ts +72 -0
  124. package/dist/types/flow-editor.vue.d.ts +63 -0
  125. package/dist/types/index.d.ts +202 -0
  126. package/dist/types/kit.d.ts +22 -0
  127. package/dist/types/layers.d.ts +24 -0
  128. package/dist/types/locale.d.ts +172 -0
  129. package/dist/types/whiteboard/board-draft.vue.d.ts +3 -0
  130. package/dist/types/whiteboard/board-node.vue.d.ts +19 -0
  131. package/dist/types/whiteboard/connector.d.ts +12 -0
  132. package/dist/types/whiteboard/draw.d.ts +5 -0
  133. package/dist/types/whiteboard/image.d.ts +27 -0
  134. package/dist/types/whiteboard/index.d.ts +6 -0
  135. package/dist/types/whiteboard/ink.d.ts +30 -0
  136. package/dist/types/whiteboard/kit.d.ts +36 -0
  137. package/dist/types/whiteboard/model.d.ts +79 -0
  138. package/dist/types/whiteboard/pen.d.ts +7 -0
  139. package/dist/types/whiteboard/state.d.ts +37 -0
  140. package/dist/types/whiteboard/transform.d.ts +67 -0
  141. package/dist/types/whiteboard/whiteboard-toolbar.vue.d.ts +3 -0
  142. package/dist/whiteboard/board-draft.js +6 -0
  143. package/dist/whiteboard/board-draft.js.map +1 -0
  144. package/dist/whiteboard/board-draft.vue_vue_type_script_setup_true_lang.js +58 -0
  145. package/dist/whiteboard/board-draft.vue_vue_type_script_setup_true_lang.js.map +1 -0
  146. package/dist/whiteboard/board-node.js +6 -0
  147. package/dist/whiteboard/board-node.js.map +1 -0
  148. package/dist/whiteboard/board-node.vue_vue_type_script_setup_true_lang.js +332 -0
  149. package/dist/whiteboard/board-node.vue_vue_type_script_setup_true_lang.js.map +1 -0
  150. package/dist/whiteboard/connector.js +180 -0
  151. package/dist/whiteboard/connector.js.map +1 -0
  152. package/dist/whiteboard/draw.js +68 -0
  153. package/dist/whiteboard/draw.js.map +1 -0
  154. package/dist/whiteboard/image.js +104 -0
  155. package/dist/whiteboard/image.js.map +1 -0
  156. package/dist/whiteboard/index.js +5 -0
  157. package/dist/whiteboard/ink.js +168 -0
  158. package/dist/whiteboard/ink.js.map +1 -0
  159. package/dist/whiteboard/kit.js +406 -0
  160. package/dist/whiteboard/kit.js.map +1 -0
  161. package/dist/whiteboard/model.js +52 -0
  162. package/dist/whiteboard/model.js.map +1 -0
  163. package/dist/whiteboard/pen.js +88 -0
  164. package/dist/whiteboard/pen.js.map +1 -0
  165. package/dist/whiteboard/state.js +26 -0
  166. package/dist/whiteboard/state.js.map +1 -0
  167. package/dist/whiteboard/transform.js +256 -0
  168. package/dist/whiteboard/transform.js.map +1 -0
  169. package/dist/whiteboard/whiteboard-toolbar.js +6 -0
  170. package/dist/whiteboard/whiteboard-toolbar.js.map +1 -0
  171. package/dist/whiteboard/whiteboard-toolbar.vue_vue_type_script_setup_true_lang.js +171 -0
  172. package/dist/whiteboard/whiteboard-toolbar.vue_vue_type_script_setup_true_lang.js.map +1 -0
  173. package/package.json +74 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"default-node.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_createElementVNode","_createBlock","FlowPortView","_createCommentVNode","_resolveDynamicComponent","_toDisplayString","_normalizeClass","_unref","_Fragment","_renderList","_createVNode","_createTextVNode"],"sources":["../../src/components/default-node.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport { portSide, type NodeViewProps } from '../core/node-types'\nimport { useFlowEditor } from '../context'\nimport type { DefaultNodeData } from './default-node'\nimport FlowPortView from './flow-port.vue'\n\nconst props = defineProps<NodeViewProps<DefaultNodeData>>()\nconst { messages } = useFlowEditor()\n\n// Ports on the top or bottom are placed by the editor.\nconst inputs = computed(() =>\n props.ports.filter((p) => p.kind === 'input' && portSide(p) === 'left'),\n)\nconst outputs = computed(() =>\n props.ports.filter((p) => p.kind === 'output' && portSide(p) === 'right'),\n)\n// A single unnamed input and output sit on the title row.\nconst inline = computed(\n () =>\n inputs.value.length <= 1 &&\n outputs.value.length <= 1 &&\n [...inputs.value, ...outputs.value].every((p) => !p.label),\n)\nconst rows = computed(() => {\n if (inline.value) return []\n const count = Math.max(inputs.value.length, outputs.value.length)\n return Array.from({ length: count }, (_, i) => ({\n input: inputs.value[i],\n output: outputs.value[i],\n }))\n})\n</script>\n\n<template>\n <div class=\"dou-flow-default-node\">\n <div class=\"dou-flow-default-node__head\">\n <FlowPortView v-if=\"inline && inputs[0]\" :id=\"inputs[0].id\" />\n <span v-if=\"data.icon\" class=\"dou-flow-default-node__icon\">\n <component :is=\"data.icon\" />\n </span>\n <span class=\"dou-flow-default-node__title\">{{ data.label }}</span>\n <span\n v-if=\"data.status\"\n class=\"dou-flow-default-node__status\"\n :class=\"`is-${data.status}`\"\n role=\"img\"\n :aria-label=\"messages.status[data.status]\"\n />\n <FlowPortView v-if=\"inline && outputs[0]\" :id=\"outputs[0].id\" />\n </div>\n <p v-if=\"data.description\" class=\"dou-flow-default-node__description\">\n {{ data.description }}\n </p>\n <div v-if=\"rows.length\" class=\"dou-flow-default-node__ports\">\n <div v-for=\"(row, i) in rows\" :key=\"i\" class=\"dou-flow-default-node__row\">\n <span v-if=\"row.input\" class=\"dou-flow-default-node__port is-input\">\n <FlowPortView :id=\"row.input.id\" />\n {{ row.input.label ?? messages.input }}\n </span>\n <span v-if=\"row.output\" class=\"dou-flow-default-node__port is-output\">\n {{ row.output.label ?? messages.output }}\n <FlowPortView :id=\"row.output.id\" />\n </span>\n </div>\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAOA,MAAM,QAAQ;EACd,MAAM,EAAE,aAAa,cAAc;EAGnC,MAAM,SAAS,eACb,MAAM,MAAM,QAAQ,MAAM,EAAE,SAAS,WAAW,SAAS,CAAC,MAAM,MAAM,CACxE;EACA,MAAM,UAAU,eACd,MAAM,MAAM,QAAQ,MAAM,EAAE,SAAS,YAAY,SAAS,CAAC,MAAM,OAAO,CAC1E;EAEA,MAAM,SAAS,eAEX,OAAO,MAAM,UAAU,KACvB,QAAQ,MAAM,UAAU,KACxB,CAAC,GAAG,OAAO,OAAO,GAAG,QAAQ,KAAK,CAAC,CAAC,OAAO,MAAM,CAAC,EAAE,KAAK,CAC7D;EACA,MAAM,OAAO,eAAe;GAC1B,IAAI,OAAO,OAAO,OAAO,CAAC;GAC1B,MAAM,QAAQ,KAAK,IAAI,OAAO,MAAM,QAAQ,QAAQ,MAAM,MAAM;GAChE,OAAO,MAAM,KAAK,EAAE,QAAQ,MAAM,IAAI,GAAG,OAAO;IAC9C,OAAO,OAAO,MAAM;IACpB,QAAQ,QAAQ,MAAM;GACxB,EAAE;EACJ,CAAC;;GAIC,OAAAA,UAAA,GAAAC,mBA+BM,OA/BN,YA+BM;IA9BJC,mBAcM,OAdN,YAcM;KAbgB,OAAA,SAAU,OAAA,MAAM,MAApCF,UAAA,GAAAG,YAA8DC,mBAAA;;MAApB,IAAI,OAAA,MAAM,EAAA,CAAI;;KAC5C,QAAA,KAAK,QAAjBJ,UAAA,GAAAC,mBAEO,QAFP,YAEO,EADLD,UAAA,GAAAG,YAA6BG,wBAAb,QAAA,KAAK,IAAI,CAAA,E;KAE3BJ,mBAAkE,QAAlE,YAAkEK,gBAApB,QAAA,KAAK,KAAK,GAAA,CAAA;KAEhD,QAAA,KAAK,UADbP,UAAA,GAAAC,mBAME,QAAA;;MAJA,OAAKO,eAAA,CAAC,iCAA+B,MACvB,QAAA,KAAK,QAAM,CAAA;MACzB,MAAK;MACJ,cAAYC,MAAA,QAAA,CAAQ,CAAC,OAAO,QAAA,KAAK;;KAEhB,OAAA,SAAU,QAAA,MAAO,MAArCT,UAAA,GAAAG,YAAgEC,mBAAA;;MAArB,IAAI,QAAA,MAAO,EAAA,CAAI;;;IAEnD,QAAA,KAAK,eAAdJ,UAAA,GAAAC,mBAEI,KAFJ,YAEIM,gBADC,QAAA,KAAK,WAAW,GAAA,CAAA,K;IAEV,KAAA,MAAK,UAAhBP,UAAA,GAAAC,mBAWM,OAXN,YAWM,EAVJD,UAAA,IAAA,GAAAC,mBASMS,UAAA,MAAAC,WATkB,KAAA,QAAX,KAAK,MAAC;KAAnB,OAAAX,UAAA,GAAAC,mBASM,OAAA;MATyB,KAAK;MAAG,OAAM;K,IAC/B,IAAI,SAAhBD,UAAA,GAAAC,mBAGO,QAHP,YAGO,CAFLW,YAAmCR,mBAAA,EAApB,IAAI,IAAI,MAAM,G,qBAAMS,gBAAA,MACnCN,gBAAG,IAAI,MAAM,SAASE,MAAA,QAAA,CAAQ,CAAC,KAAK,GAAA,CAAA,C,oCAE1B,IAAI,UAAhBT,UAAA,GAAAC,mBAGO,QAHP,YAGO,CAFFY,gBAAAN,gBAAA,IAAI,OAAO,SAASE,MAAA,QAAA,CAAQ,CAAC,MAAM,IAAG,KACzC,CAAA,GAAAG,YAAoCR,mBAAA,EAArB,IAAI,IAAI,OAAO,G"}
@@ -0,0 +1,116 @@
1
+ import { defineNodeType } from "../core/node-types.js";
2
+ import default_node_default from "./default-node.js";
3
+ import { drawCard } from "../export/draw.js";
4
+ // src/components/default-node.ts
5
+ var px = (value, fallback) => Number.parseFloat(value) || fallback;
6
+ /**
7
+ * A titled card: an optional icon, a status dot and a description, then a
8
+ * row per port, inputs on the left and outputs on the right. A single
9
+ * unnamed input and output sit on the title row.
10
+ */
11
+ var defaultNode = defineNodeType({
12
+ type: "default",
13
+ component: default_node_default,
14
+ ports: (node) => [...(node.data?.inputs ?? []).map((port) => ({
15
+ ...port,
16
+ kind: "input"
17
+ })), ...(node.data?.outputs ?? []).map((port) => ({
18
+ ...port,
19
+ kind: "output"
20
+ }))],
21
+ defaults: () => ({ label: "" }),
22
+ draw(node, draw) {
23
+ const data = node.data ?? {};
24
+ const t = draw.messages;
25
+ const parts = [drawCard(draw)];
26
+ const headHeight = px(draw.style("dou-flow-default-node__head").minHeight, 44);
27
+ const inputs = data.inputs ?? [];
28
+ const outputs = data.outputs ?? [];
29
+ const inline = inputs.length <= 1 && outputs.length <= 1 && ![...inputs, ...outputs].some((p) => p.label);
30
+ let left = 12;
31
+ let right = draw.width - 12;
32
+ if (data.icon) {
33
+ const box = draw.style("dou-flow-default-node__icon");
34
+ const y = (headHeight - 24) / 2;
35
+ parts.push(`<rect x="${left}" y="${y}" width="24" height="24" rx="${px(box.borderTopLeftRadius, 6)}" fill="${draw.color(box.backgroundColor)}"/>`, draw.icon(data.icon, {
36
+ x: left + 4,
37
+ y: y + 4,
38
+ width: 16,
39
+ height: 16
40
+ }, draw.color(box.color)));
41
+ left += 32;
42
+ }
43
+ if (data.status) {
44
+ const dot = draw.style(`dou-flow-default-node__status is-${data.status}`);
45
+ parts.push(`<circle cx="${right - 4}" cy="${headHeight / 2}" r="4" fill="${draw.color(dot.backgroundColor)}"/>`);
46
+ right -= 16;
47
+ }
48
+ const title = draw.style("dou-flow-default-node__title");
49
+ parts.push(draw.text(data.label ?? "", {
50
+ x: left,
51
+ y: 0,
52
+ width: Math.max(0, right - left),
53
+ height: headHeight
54
+ }, {
55
+ weight: title.fontWeight,
56
+ valign: "middle",
57
+ nowrap: true,
58
+ lineHeight: headHeight
59
+ }));
60
+ let y = headHeight;
61
+ if (data.description) {
62
+ const text = draw.style("dou-flow-default-node__description");
63
+ const lineHeight = px(text.lineHeight, 20);
64
+ const width = draw.width - 24;
65
+ const lines = draw.text(data.description, {
66
+ x: 12,
67
+ y: y - 4,
68
+ width,
69
+ height: 1e6
70
+ }, {
71
+ size: px(text.fontSize, 12),
72
+ lineHeight,
73
+ color: draw.color(text.color)
74
+ });
75
+ parts.push(lines);
76
+ y += (lines.match(/<tspan/g)?.length ?? 1) * lineHeight + 12 - 4;
77
+ }
78
+ if (!inline) {
79
+ const rows = draw.style("dou-flow-default-node__ports");
80
+ const row = draw.style("dou-flow-default-node__row");
81
+ parts.push(`<rect x="1" y="${y}" width="${draw.width - 2}" height="1" fill="${draw.color(rows.borderTopColor)}"/>`);
82
+ y += 1 + px(rows.paddingTop, 3);
83
+ const height = px(row.height, 28);
84
+ const size = px(row.fontSize, 12);
85
+ const color = draw.color(row.color);
86
+ const half = (draw.width - 24) / 2;
87
+ for (let i = 0; i < Math.max(inputs.length, outputs.length); i++) {
88
+ const input = inputs[i];
89
+ const output = outputs[i];
90
+ const box = (x) => ({
91
+ x,
92
+ y: y + i * height,
93
+ width: half - 4,
94
+ height
95
+ });
96
+ const options = {
97
+ size,
98
+ color,
99
+ valign: "middle",
100
+ nowrap: true,
101
+ lineHeight: height
102
+ };
103
+ if (input) parts.push(draw.text(input.label ?? t.input, box(12), options));
104
+ if (output) parts.push(draw.text(output.label ?? t.output, box(draw.width / 2 + 4), {
105
+ ...options,
106
+ align: "end"
107
+ }));
108
+ }
109
+ }
110
+ for (const id of draw.ports.keys()) parts.push(draw.port(id));
111
+ return parts.join("");
112
+ }
113
+ });
114
+ export { defaultNode };
115
+
116
+ //# sourceMappingURL=default-node2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"default-node2.js","names":["DefaultNode"],"sources":["../../src/components/default-node.ts"],"sourcesContent":["import { defineNodeType } from '../core/node-types'\nimport { drawCard } from '../export/draw'\nimport type { Component } from 'vue'\nimport type { FlowPortSpec } from '../core/model'\nimport DefaultNode from './default-node.vue'\n\nconst px = (value: string, fallback: number) => Number.parseFloat(value) || fallback\n\nexport interface DefaultNodeData {\n [key: string]: unknown\n /** The title. */\n label?: string\n description?: string\n icon?: Component\n status?: 'wait' | 'process' | 'finish' | 'error'\n inputs?: Omit<FlowPortSpec, 'kind'>[]\n outputs?: Omit<FlowPortSpec, 'kind'>[]\n}\n\n/**\n * A titled card: an optional icon, a status dot and a description, then a\n * row per port, inputs on the left and outputs on the right. A single\n * unnamed input and output sit on the title row.\n */\nexport const defaultNode = defineNodeType<DefaultNodeData>({\n type: 'default',\n component: DefaultNode,\n ports: (node) => [\n ...(node.data?.inputs ?? []).map((port) => ({ ...port, kind: 'input' as const })),\n ...(node.data?.outputs ?? []).map((port) => ({ ...port, kind: 'output' as const })),\n ],\n defaults: () => ({ label: '' }),\n draw(node, draw) {\n const data = node.data ?? {}\n const t = draw.messages\n const parts = [drawCard(draw)]\n const head = draw.style('dou-flow-default-node__head')\n const headHeight = px(head.minHeight, 44)\n const inputs = data.inputs ?? []\n const outputs = data.outputs ?? []\n const inline =\n inputs.length <= 1 && outputs.length <= 1 && ![...inputs, ...outputs].some((p) => p.label)\n let left = 12\n let right = draw.width - 12\n if (data.icon) {\n const box = draw.style('dou-flow-default-node__icon')\n const y = (headHeight - 24) / 2\n parts.push(\n `<rect x=\"${left}\" y=\"${y}\" width=\"24\" height=\"24\" rx=\"${px(box.borderTopLeftRadius, 6)}\" fill=\"${draw.color(box.backgroundColor)}\"/>`,\n draw.icon(\n data.icon,\n { x: left + 4, y: y + 4, width: 16, height: 16 },\n draw.color(box.color),\n ),\n )\n left += 32\n }\n if (data.status) {\n const dot = draw.style(`dou-flow-default-node__status is-${data.status}`)\n parts.push(\n `<circle cx=\"${right - 4}\" cy=\"${headHeight / 2}\" r=\"4\" fill=\"${draw.color(dot.backgroundColor)}\"/>`,\n )\n right -= 16\n }\n const title = draw.style('dou-flow-default-node__title')\n parts.push(\n draw.text(\n data.label ?? '',\n { x: left, y: 0, width: Math.max(0, right - left), height: headHeight },\n { weight: title.fontWeight, valign: 'middle', nowrap: true, lineHeight: headHeight },\n ),\n )\n let y = headHeight\n if (data.description) {\n const text = draw.style('dou-flow-default-node__description')\n const lineHeight = px(text.lineHeight, 20)\n const width = draw.width - 24\n const lines = draw.text(\n data.description,\n { x: 12, y: y - 4, width, height: 1e6 },\n {\n size: px(text.fontSize, 12),\n lineHeight,\n color: draw.color(text.color),\n },\n )\n parts.push(lines)\n y += (lines.match(/<tspan/g)?.length ?? 1) * lineHeight + 12 - 4\n }\n if (!inline) {\n const rows = draw.style('dou-flow-default-node__ports')\n const row = draw.style('dou-flow-default-node__row')\n parts.push(\n `<rect x=\"1\" y=\"${y}\" width=\"${draw.width - 2}\" height=\"1\" fill=\"${draw.color(rows.borderTopColor)}\"/>`,\n )\n y += 1 + px(rows.paddingTop, 3)\n const height = px(row.height, 28)\n const size = px(row.fontSize, 12)\n const color = draw.color(row.color)\n const half = (draw.width - 24) / 2\n for (let i = 0; i < Math.max(inputs.length, outputs.length); i++) {\n const input = inputs[i]\n const output = outputs[i]\n const box = (x: number) => ({ x, y: y + i * height, width: half - 4, height })\n const options = { size, color, valign: 'middle' as const, nowrap: true, lineHeight: height }\n if (input) parts.push(draw.text(input.label ?? t.input, box(12), options))\n if (output)\n parts.push(\n draw.text(output.label ?? t.output, box(draw.width / 2 + 4), {\n ...options,\n align: 'end',\n }),\n )\n }\n }\n for (const id of draw.ports.keys()) parts.push(draw.port(id))\n return parts.join('')\n },\n})\n"],"mappings":";;;;AAMA,IAAM,MAAM,OAAe,aAAqB,OAAO,WAAW,KAAK,KAAK;;;;;;AAkB5E,IAAa,cAAc,eAAgC;CACzD,MAAM;CACN,WAAWA;CACX,QAAQ,SAAS,CACf,IAAI,KAAK,MAAM,UAAU,CAAC,EAAA,CAAG,KAAK,UAAU;EAAE,GAAG;EAAM,MAAM;CAAiB,EAAE,GAChF,IAAI,KAAK,MAAM,WAAW,CAAC,EAAA,CAAG,KAAK,UAAU;EAAE,GAAG;EAAM,MAAM;CAAkB,EAAE,CACpF;CACA,iBAAiB,EAAE,OAAO,GAAG;CAC7B,KAAK,MAAM,MAAM;EACf,MAAM,OAAO,KAAK,QAAQ,CAAC;EAC3B,MAAM,IAAI,KAAK;EACf,MAAM,QAAQ,CAAC,SAAS,IAAI,CAAC;EAE7B,MAAM,aAAa,GADN,KAAK,MAAM,6BACF,CAAA,CAAK,WAAW,EAAE;EACxC,MAAM,SAAS,KAAK,UAAU,CAAC;EAC/B,MAAM,UAAU,KAAK,WAAW,CAAC;EACjC,MAAM,SACJ,OAAO,UAAU,KAAK,QAAQ,UAAU,KAAK,CAAC,CAAC,GAAG,QAAQ,GAAG,OAAO,CAAC,CAAC,MAAM,MAAM,EAAE,KAAK;EAC3F,IAAI,OAAO;EACX,IAAI,QAAQ,KAAK,QAAQ;EACzB,IAAI,KAAK,MAAM;GACb,MAAM,MAAM,KAAK,MAAM,6BAA6B;GACpD,MAAM,KAAK,aAAa,MAAM;GAC9B,MAAM,KACJ,YAAY,KAAK,OAAO,EAAE,+BAA+B,GAAG,IAAI,qBAAqB,CAAC,EAAE,UAAU,KAAK,MAAM,IAAI,eAAe,EAAE,MAClI,KAAK,KACH,KAAK,MACL;IAAE,GAAG,OAAO;IAAG,GAAG,IAAI;IAAG,OAAO;IAAI,QAAQ;GAAG,GAC/C,KAAK,MAAM,IAAI,KAAK,CACtB,CACF;GACA,QAAQ;EACV;EACA,IAAI,KAAK,QAAQ;GACf,MAAM,MAAM,KAAK,MAAM,oCAAoC,KAAK,QAAQ;GACxE,MAAM,KACJ,eAAe,QAAQ,EAAE,QAAQ,aAAa,EAAE,gBAAgB,KAAK,MAAM,IAAI,eAAe,EAAE,IAClG;GACA,SAAS;EACX;EACA,MAAM,QAAQ,KAAK,MAAM,8BAA8B;EACvD,MAAM,KACJ,KAAK,KACH,KAAK,SAAS,IACd;GAAE,GAAG;GAAM,GAAG;GAAG,OAAO,KAAK,IAAI,GAAG,QAAQ,IAAI;GAAG,QAAQ;EAAW,GACtE;GAAE,QAAQ,MAAM;GAAY,QAAQ;GAAU,QAAQ;GAAM,YAAY;EAAW,CACrF,CACF;EACA,IAAI,IAAI;EACR,IAAI,KAAK,aAAa;GACpB,MAAM,OAAO,KAAK,MAAM,oCAAoC;GAC5D,MAAM,aAAa,GAAG,KAAK,YAAY,EAAE;GACzC,MAAM,QAAQ,KAAK,QAAQ;GAC3B,MAAM,QAAQ,KAAK,KACjB,KAAK,aACL;IAAE,GAAG;IAAI,GAAG,IAAI;IAAG;IAAO,QAAQ;GAAI,GACtC;IACE,MAAM,GAAG,KAAK,UAAU,EAAE;IAC1B;IACA,OAAO,KAAK,MAAM,KAAK,KAAK;GAC9B,CACF;GACA,MAAM,KAAK,KAAK;GAChB,MAAM,MAAM,MAAM,SAAS,CAAC,EAAE,UAAU,KAAK,aAAa,KAAK;EACjE;EACA,IAAI,CAAC,QAAQ;GACX,MAAM,OAAO,KAAK,MAAM,8BAA8B;GACtD,MAAM,MAAM,KAAK,MAAM,4BAA4B;GACnD,MAAM,KACJ,kBAAkB,EAAE,WAAW,KAAK,QAAQ,EAAE,qBAAqB,KAAK,MAAM,KAAK,cAAc,EAAE,IACrG;GACA,KAAK,IAAI,GAAG,KAAK,YAAY,CAAC;GAC9B,MAAM,SAAS,GAAG,IAAI,QAAQ,EAAE;GAChC,MAAM,OAAO,GAAG,IAAI,UAAU,EAAE;GAChC,MAAM,QAAQ,KAAK,MAAM,IAAI,KAAK;GAClC,MAAM,QAAQ,KAAK,QAAQ,MAAM;GACjC,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,IAAI,OAAO,QAAQ,QAAQ,MAAM,GAAG,KAAK;IAChE,MAAM,QAAQ,OAAO;IACrB,MAAM,SAAS,QAAQ;IACvB,MAAM,OAAO,OAAe;KAAE;KAAG,GAAG,IAAI,IAAI;KAAQ,OAAO,OAAO;KAAG;IAAO;IAC5E,MAAM,UAAU;KAAE;KAAM;KAAO,QAAQ;KAAmB,QAAQ;KAAM,YAAY;IAAO;IAC3F,IAAI,OAAO,MAAM,KAAK,KAAK,KAAK,MAAM,SAAS,EAAE,OAAO,IAAI,EAAE,GAAG,OAAO,CAAC;IACzE,IAAI,QACF,MAAM,KACJ,KAAK,KAAK,OAAO,SAAS,EAAE,QAAQ,IAAI,KAAK,QAAQ,IAAI,CAAC,GAAG;KAC3D,GAAG;KACH,OAAO;IACT,CAAC,CACH;GACJ;EACF;EACA,KAAK,MAAM,MAAM,KAAK,MAAM,KAAK,GAAG,MAAM,KAAK,KAAK,KAAK,EAAE,CAAC;EAC5D,OAAO,MAAM,KAAK,EAAE;CACtB;AACF,CAAC"}
@@ -0,0 +1,6 @@
1
+ import flow_controls_vue_vue_type_script_setup_true_lang_default from "./flow-controls.vue_vue_type_script_setup_true_lang.js";
2
+ // src/components/flow-controls.vue
3
+ var flow_controls_default = flow_controls_vue_vue_type_script_setup_true_lang_default;
4
+ export { flow_controls_default as default };
5
+
6
+ //# sourceMappingURL=flow-controls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow-controls.js","names":["_sfc_main"],"sources":["../../src/components/flow-controls.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n FocusIcon,\n HierarchyHorizontalIcon,\n RedoIcon,\n UndoIcon,\n ZoomInIcon,\n ZoomOutIcon,\n} from '@dou-ui/icons'\nimport { DouTooltip } from 'dou-ui'\nimport { computed } from 'vue'\nimport { useFlowEditor, type FlowControlsProps } from '../context'\nimport { format } from '../locale'\n\ndefineOptions({ name: 'DouFlowControls' })\n\nconst props = withDefaults(defineProps<FlowControlsProps>(), {\n placement: 'bottom-left',\n history: true,\n tidy: true,\n})\n\nconst flow = useFlowEditor()\nconst { messages } = flow\nconst zoom = computed(() => flow.viewport.value.zoom)\nconst percent = computed(() => Math.round(zoom.value * 100))\nconst showHistory = computed(() => props.history && !flow.readonly.value)\n/** Tips open away from the edge the controls sit on. */\nconst tipPlacement = computed(() => (props.placement.startsWith('top') ? 'bottom' : 'top'))\n</script>\n\n<template>\n <div\n class=\"dou-flow-controls\"\n data-flow-overlay\n :class=\"`is-${placement}`\"\n role=\"toolbar\"\n :aria-label=\"messages.controls\"\n >\n <template v-if=\"showHistory\">\n <DouTooltip :content=\"messages.undo\" shortcut=\"mod+z\" :placement=\"tipPlacement\">\n <button\n type=\"button\"\n class=\"dou-flow-controls__button\"\n :disabled=\"!flow.canUndo.value\"\n :aria-label=\"messages.undo\"\n @click=\"flow.undo()\"\n >\n <UndoIcon />\n </button>\n </DouTooltip>\n <DouTooltip :content=\"messages.redo\" shortcut=\"mod+shift+z\" :placement=\"tipPlacement\">\n <button\n type=\"button\"\n class=\"dou-flow-controls__button\"\n :disabled=\"!flow.canRedo.value\"\n :aria-label=\"messages.redo\"\n @click=\"flow.redo()\"\n >\n <RedoIcon />\n </button>\n </DouTooltip>\n <span class=\"dou-flow-controls__divider\" />\n </template>\n <DouTooltip :content=\"messages.zoomOut\" shortcut=\"mod+-\" :placement=\"tipPlacement\">\n <button\n type=\"button\"\n class=\"dou-flow-controls__button\"\n :disabled=\"zoom <= flow.minZoom.value\"\n :aria-label=\"messages.zoomOut\"\n @click=\"flow.zoomOut()\"\n >\n <ZoomOutIcon />\n </button>\n </DouTooltip>\n <DouTooltip :content=\"messages.zoomReset\" shortcut=\"mod+0\" :placement=\"tipPlacement\">\n <button\n type=\"button\"\n class=\"dou-flow-controls__button dou-flow-controls__zoom\"\n :aria-label=\"format(messages.zoomLevel, { value: percent })\"\n @click=\"flow.zoomTo(1)\"\n >\n {{ percent }}%\n </button>\n </DouTooltip>\n <DouTooltip :content=\"messages.zoomIn\" shortcut=\"mod+=\" :placement=\"tipPlacement\">\n <button\n type=\"button\"\n class=\"dou-flow-controls__button\"\n :disabled=\"zoom >= flow.maxZoom.value\"\n :aria-label=\"messages.zoomIn\"\n @click=\"flow.zoomIn()\"\n >\n <ZoomInIcon />\n </button>\n </DouTooltip>\n <DouTooltip :content=\"messages.fit\" :placement=\"tipPlacement\">\n <button\n type=\"button\"\n class=\"dou-flow-controls__button\"\n :aria-label=\"messages.fit\"\n @click=\"flow.fit()\"\n >\n <FocusIcon />\n </button>\n </DouTooltip>\n <DouTooltip\n v-if=\"tidy && !flow.readonly.value\"\n :content=\"messages.tidy\"\n :placement=\"tipPlacement\"\n >\n <button\n type=\"button\"\n class=\"dou-flow-controls__button\"\n :aria-label=\"messages.tidy\"\n @click=\"flow.tidy()\"\n >\n <HierarchyHorizontalIcon />\n </button>\n </DouTooltip>\n </div>\n</template>\n"],"mappings":""}
@@ -0,0 +1,148 @@
1
+ import { useFlowEditor } from "../context.js";
2
+ import { format } from "../locale.js";
3
+ import { DouTooltip } from "dou-ui";
4
+ import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, normalizeClass, openBlock, toDisplayString, unref, withCtx } from "vue";
5
+ import { FocusIcon, HierarchyHorizontalIcon, RedoIcon, UndoIcon, ZoomInIcon, ZoomOutIcon } from "@dou-ui/icons";
6
+ // src/components/flow-controls.vue?vue&type=script&setup=true&lang.ts
7
+ var _hoisted_1 = ["aria-label"];
8
+ var _hoisted_2 = ["disabled", "aria-label"];
9
+ var _hoisted_3 = ["disabled", "aria-label"];
10
+ var _hoisted_4 = ["disabled", "aria-label"];
11
+ var _hoisted_5 = ["aria-label"];
12
+ var _hoisted_6 = ["disabled", "aria-label"];
13
+ var _hoisted_7 = ["aria-label"];
14
+ var _hoisted_8 = ["aria-label"];
15
+ var flow_controls_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
16
+ name: "DouFlowControls",
17
+ __name: "flow-controls",
18
+ props: {
19
+ placement: { default: "bottom-left" },
20
+ history: {
21
+ type: Boolean,
22
+ default: true
23
+ },
24
+ tidy: {
25
+ type: Boolean,
26
+ default: true
27
+ }
28
+ },
29
+ setup(__props) {
30
+ const props = __props;
31
+ const flow = useFlowEditor();
32
+ const { messages } = flow;
33
+ const zoom = computed(() => flow.viewport.value.zoom);
34
+ const percent = computed(() => Math.round(zoom.value * 100));
35
+ const showHistory = computed(() => props.history && !flow.readonly.value);
36
+ /** Tips open away from the edge the controls sit on. */
37
+ const tipPlacement = computed(() => props.placement.startsWith("top") ? "bottom" : "top");
38
+ return (_ctx, _cache) => {
39
+ return openBlock(), createElementBlock("div", {
40
+ class: normalizeClass(["dou-flow-controls", `is-${__props.placement}`]),
41
+ "data-flow-overlay": "",
42
+ role: "toolbar",
43
+ "aria-label": unref(messages).controls
44
+ }, [
45
+ showHistory.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
46
+ createVNode(unref(DouTooltip), {
47
+ content: unref(messages).undo,
48
+ shortcut: "mod+z",
49
+ placement: tipPlacement.value
50
+ }, {
51
+ default: withCtx(() => [createElementVNode("button", {
52
+ type: "button",
53
+ class: "dou-flow-controls__button",
54
+ disabled: !unref(flow).canUndo.value,
55
+ "aria-label": unref(messages).undo,
56
+ onClick: _cache[0] || (_cache[0] = ($event) => unref(flow).undo())
57
+ }, [createVNode(unref(UndoIcon))], 8, _hoisted_2)]),
58
+ _: 1
59
+ }, 8, ["content", "placement"]),
60
+ createVNode(unref(DouTooltip), {
61
+ content: unref(messages).redo,
62
+ shortcut: "mod+shift+z",
63
+ placement: tipPlacement.value
64
+ }, {
65
+ default: withCtx(() => [createElementVNode("button", {
66
+ type: "button",
67
+ class: "dou-flow-controls__button",
68
+ disabled: !unref(flow).canRedo.value,
69
+ "aria-label": unref(messages).redo,
70
+ onClick: _cache[1] || (_cache[1] = ($event) => unref(flow).redo())
71
+ }, [createVNode(unref(RedoIcon))], 8, _hoisted_3)]),
72
+ _: 1
73
+ }, 8, ["content", "placement"]),
74
+ _cache[7] || (_cache[7] = createElementVNode("span", { class: "dou-flow-controls__divider" }, null, -1))
75
+ ], 64)) : createCommentVNode("", true),
76
+ createVNode(unref(DouTooltip), {
77
+ content: unref(messages).zoomOut,
78
+ shortcut: "mod+-",
79
+ placement: tipPlacement.value
80
+ }, {
81
+ default: withCtx(() => [createElementVNode("button", {
82
+ type: "button",
83
+ class: "dou-flow-controls__button",
84
+ disabled: zoom.value <= unref(flow).minZoom.value,
85
+ "aria-label": unref(messages).zoomOut,
86
+ onClick: _cache[2] || (_cache[2] = ($event) => unref(flow).zoomOut())
87
+ }, [createVNode(unref(ZoomOutIcon))], 8, _hoisted_4)]),
88
+ _: 1
89
+ }, 8, ["content", "placement"]),
90
+ createVNode(unref(DouTooltip), {
91
+ content: unref(messages).zoomReset,
92
+ shortcut: "mod+0",
93
+ placement: tipPlacement.value
94
+ }, {
95
+ default: withCtx(() => [createElementVNode("button", {
96
+ type: "button",
97
+ class: "dou-flow-controls__button dou-flow-controls__zoom",
98
+ "aria-label": unref(format)(unref(messages).zoomLevel, { value: percent.value }),
99
+ onClick: _cache[3] || (_cache[3] = ($event) => unref(flow).zoomTo(1))
100
+ }, toDisplayString(percent.value) + "% ", 9, _hoisted_5)]),
101
+ _: 1
102
+ }, 8, ["content", "placement"]),
103
+ createVNode(unref(DouTooltip), {
104
+ content: unref(messages).zoomIn,
105
+ shortcut: "mod+=",
106
+ placement: tipPlacement.value
107
+ }, {
108
+ default: withCtx(() => [createElementVNode("button", {
109
+ type: "button",
110
+ class: "dou-flow-controls__button",
111
+ disabled: zoom.value >= unref(flow).maxZoom.value,
112
+ "aria-label": unref(messages).zoomIn,
113
+ onClick: _cache[4] || (_cache[4] = ($event) => unref(flow).zoomIn())
114
+ }, [createVNode(unref(ZoomInIcon))], 8, _hoisted_6)]),
115
+ _: 1
116
+ }, 8, ["content", "placement"]),
117
+ createVNode(unref(DouTooltip), {
118
+ content: unref(messages).fit,
119
+ placement: tipPlacement.value
120
+ }, {
121
+ default: withCtx(() => [createElementVNode("button", {
122
+ type: "button",
123
+ class: "dou-flow-controls__button",
124
+ "aria-label": unref(messages).fit,
125
+ onClick: _cache[5] || (_cache[5] = ($event) => unref(flow).fit())
126
+ }, [createVNode(unref(FocusIcon))], 8, _hoisted_7)]),
127
+ _: 1
128
+ }, 8, ["content", "placement"]),
129
+ __props.tidy && !unref(flow).readonly.value ? (openBlock(), createBlock(unref(DouTooltip), {
130
+ key: 1,
131
+ content: unref(messages).tidy,
132
+ placement: tipPlacement.value
133
+ }, {
134
+ default: withCtx(() => [createElementVNode("button", {
135
+ type: "button",
136
+ class: "dou-flow-controls__button",
137
+ "aria-label": unref(messages).tidy,
138
+ onClick: _cache[6] || (_cache[6] = ($event) => unref(flow).tidy())
139
+ }, [createVNode(unref(HierarchyHorizontalIcon))], 8, _hoisted_8)]),
140
+ _: 1
141
+ }, 8, ["content", "placement"])) : createCommentVNode("", true)
142
+ ], 10, _hoisted_1);
143
+ };
144
+ }
145
+ });
146
+ export { flow_controls_vue_vue_type_script_setup_true_lang_default as default };
147
+
148
+ //# sourceMappingURL=flow-controls.vue_vue_type_script_setup_true_lang.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow-controls.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_normalizeClass","_unref","_Fragment","_createVNode","_withCtx","_createElementVNode","_createCommentVNode","_toDisplayString","_createBlock"],"sources":["../../src/components/flow-controls.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport {\n FocusIcon,\n HierarchyHorizontalIcon,\n RedoIcon,\n UndoIcon,\n ZoomInIcon,\n ZoomOutIcon,\n} from '@dou-ui/icons'\nimport { DouTooltip } from 'dou-ui'\nimport { computed } from 'vue'\nimport { useFlowEditor, type FlowControlsProps } from '../context'\nimport { format } from '../locale'\n\ndefineOptions({ name: 'DouFlowControls' })\n\nconst props = withDefaults(defineProps<FlowControlsProps>(), {\n placement: 'bottom-left',\n history: true,\n tidy: true,\n})\n\nconst flow = useFlowEditor()\nconst { messages } = flow\nconst zoom = computed(() => flow.viewport.value.zoom)\nconst percent = computed(() => Math.round(zoom.value * 100))\nconst showHistory = computed(() => props.history && !flow.readonly.value)\n/** Tips open away from the edge the controls sit on. */\nconst tipPlacement = computed(() => (props.placement.startsWith('top') ? 'bottom' : 'top'))\n</script>\n\n<template>\n <div\n class=\"dou-flow-controls\"\n data-flow-overlay\n :class=\"`is-${placement}`\"\n role=\"toolbar\"\n :aria-label=\"messages.controls\"\n >\n <template v-if=\"showHistory\">\n <DouTooltip :content=\"messages.undo\" shortcut=\"mod+z\" :placement=\"tipPlacement\">\n <button\n type=\"button\"\n class=\"dou-flow-controls__button\"\n :disabled=\"!flow.canUndo.value\"\n :aria-label=\"messages.undo\"\n @click=\"flow.undo()\"\n >\n <UndoIcon />\n </button>\n </DouTooltip>\n <DouTooltip :content=\"messages.redo\" shortcut=\"mod+shift+z\" :placement=\"tipPlacement\">\n <button\n type=\"button\"\n class=\"dou-flow-controls__button\"\n :disabled=\"!flow.canRedo.value\"\n :aria-label=\"messages.redo\"\n @click=\"flow.redo()\"\n >\n <RedoIcon />\n </button>\n </DouTooltip>\n <span class=\"dou-flow-controls__divider\" />\n </template>\n <DouTooltip :content=\"messages.zoomOut\" shortcut=\"mod+-\" :placement=\"tipPlacement\">\n <button\n type=\"button\"\n class=\"dou-flow-controls__button\"\n :disabled=\"zoom <= flow.minZoom.value\"\n :aria-label=\"messages.zoomOut\"\n @click=\"flow.zoomOut()\"\n >\n <ZoomOutIcon />\n </button>\n </DouTooltip>\n <DouTooltip :content=\"messages.zoomReset\" shortcut=\"mod+0\" :placement=\"tipPlacement\">\n <button\n type=\"button\"\n class=\"dou-flow-controls__button dou-flow-controls__zoom\"\n :aria-label=\"format(messages.zoomLevel, { value: percent })\"\n @click=\"flow.zoomTo(1)\"\n >\n {{ percent }}%\n </button>\n </DouTooltip>\n <DouTooltip :content=\"messages.zoomIn\" shortcut=\"mod+=\" :placement=\"tipPlacement\">\n <button\n type=\"button\"\n class=\"dou-flow-controls__button\"\n :disabled=\"zoom >= flow.maxZoom.value\"\n :aria-label=\"messages.zoomIn\"\n @click=\"flow.zoomIn()\"\n >\n <ZoomInIcon />\n </button>\n </DouTooltip>\n <DouTooltip :content=\"messages.fit\" :placement=\"tipPlacement\">\n <button\n type=\"button\"\n class=\"dou-flow-controls__button\"\n :aria-label=\"messages.fit\"\n @click=\"flow.fit()\"\n >\n <FocusIcon />\n </button>\n </DouTooltip>\n <DouTooltip\n v-if=\"tidy && !flow.readonly.value\"\n :content=\"messages.tidy\"\n :placement=\"tipPlacement\"\n >\n <button\n type=\"button\"\n class=\"dou-flow-controls__button\"\n :aria-label=\"messages.tidy\"\n @click=\"flow.tidy()\"\n >\n <HierarchyHorizontalIcon />\n </button>\n </DouTooltip>\n </div>\n</template>\n"],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import flow_menu_vue_vue_type_script_setup_true_lang_default from "./flow-menu.vue_vue_type_script_setup_true_lang.js";
2
+ // src/components/flow-menu.vue
3
+ var flow_menu_default = flow_menu_vue_vue_type_script_setup_true_lang_default;
4
+ export { flow_menu_default as default };
5
+
6
+ //# sourceMappingURL=flow-menu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow-menu.js","names":["_sfc_main"],"sources":["../../src/components/flow-menu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ContextMenuItem } from 'dou-ui'\nimport { DouContextMenu } from 'dou-ui'\nimport { nextTick, useTemplateRef } from 'vue'\n\ndefineProps<{ items: ContextMenuItem[] }>()\nconst open = defineModel<boolean>('open', { default: false })\n\nconst menu = useTemplateRef<InstanceType<typeof DouContextMenu>>('menu')\n\ndefineExpose({\n /**\n * `box` makes (x, y) the top left of a box the menu opens beside, e.g. the\n * button that opened it; `focusChecked` puts focus on the option in use,\n * for a menu opened from the keyboard.\n */\n open(\n x: number,\n y: number,\n {\n box,\n focusChecked = false,\n }: { box?: { width: number; height: number }; focusChecked?: boolean } = {},\n ) {\n menu.value?.open(x, y, box)\n if (!focusChecked) return\n // after the menu has focused itself\n void nextTick(() =>\n nextTick(() => {\n const panel = document.activeElement\n const item =\n panel?.querySelector<HTMLElement>('[aria-checked=\"true\"]') ??\n panel?.querySelector<HTMLElement>('[role^=\"menuitem\"]:not([aria-disabled=\"true\"])')\n item?.focus({ preventScroll: true })\n }),\n )\n },\n close: () => menu.value?.close(),\n})\n</script>\n\n<template>\n <!-- The editor opens the menu itself; the empty anchor only gives it a place in the page. -->\n <DouContextMenu ref=\"menu\" v-model:open=\"open\" :items=\"items\">\n <span class=\"dou-flow-editor__menu-anchor\" aria-hidden=\"true\" />\n </DouContextMenu>\n</template>\n"],"mappings":""}
@@ -0,0 +1,52 @@
1
+ import { DouContextMenu } from "dou-ui";
2
+ import { createBlock, createElementVNode, defineComponent, mergeModels, nextTick, openBlock, unref, useModel, useTemplateRef, withCtx } from "vue";
3
+ // src/components/flow-menu.vue?vue&type=script&setup=true&lang.ts
4
+ var flow_menu_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
5
+ __name: "flow-menu",
6
+ props: /*@__PURE__*/ mergeModels({ items: {} }, {
7
+ "open": {
8
+ type: Boolean,
9
+ default: false
10
+ },
11
+ "openModifiers": {}
12
+ }),
13
+ emits: ["update:open"],
14
+ setup(__props, { expose: __expose }) {
15
+ const open = useModel(__props, "open");
16
+ const menu = useTemplateRef("menu");
17
+ __expose({
18
+ /**
19
+ * `box` makes (x, y) the top left of a box the menu opens beside, e.g. the
20
+ * button that opened it; `focusChecked` puts focus on the option in use,
21
+ * for a menu opened from the keyboard.
22
+ */
23
+ open(x, y, { box, focusChecked = false } = {}) {
24
+ menu.value?.open(x, y, box);
25
+ if (!focusChecked) return;
26
+ nextTick(() => nextTick(() => {
27
+ const panel = document.activeElement;
28
+ (panel?.querySelector("[aria-checked=\"true\"]") ?? panel?.querySelector("[role^=\"menuitem\"]:not([aria-disabled=\"true\"])"))?.focus({ preventScroll: true });
29
+ }));
30
+ },
31
+ close: () => menu.value?.close()
32
+ });
33
+ return (_ctx, _cache) => {
34
+ return openBlock(), createBlock(unref(DouContextMenu), {
35
+ ref_key: "menu",
36
+ ref: menu,
37
+ open: open.value,
38
+ "onUpdate:open": _cache[0] || (_cache[0] = ($event) => open.value = $event),
39
+ items: __props.items
40
+ }, {
41
+ default: withCtx(() => [..._cache[1] || (_cache[1] = [createElementVNode("span", {
42
+ class: "dou-flow-editor__menu-anchor",
43
+ "aria-hidden": "true"
44
+ }, null, -1)])]),
45
+ _: 1
46
+ }, 8, ["open", "items"]);
47
+ };
48
+ }
49
+ });
50
+ export { flow_menu_vue_vue_type_script_setup_true_lang_default as default };
51
+
52
+ //# sourceMappingURL=flow-menu.vue_vue_type_script_setup_true_lang.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow-menu.vue_vue_type_script_setup_true_lang.js","names":["_useModel","_openBlock","_createBlock","_unref","_withCtx","_createElementVNode"],"sources":["../../src/components/flow-menu.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport type { ContextMenuItem } from 'dou-ui'\nimport { DouContextMenu } from 'dou-ui'\nimport { nextTick, useTemplateRef } from 'vue'\n\ndefineProps<{ items: ContextMenuItem[] }>()\nconst open = defineModel<boolean>('open', { default: false })\n\nconst menu = useTemplateRef<InstanceType<typeof DouContextMenu>>('menu')\n\ndefineExpose({\n /**\n * `box` makes (x, y) the top left of a box the menu opens beside, e.g. the\n * button that opened it; `focusChecked` puts focus on the option in use,\n * for a menu opened from the keyboard.\n */\n open(\n x: number,\n y: number,\n {\n box,\n focusChecked = false,\n }: { box?: { width: number; height: number }; focusChecked?: boolean } = {},\n ) {\n menu.value?.open(x, y, box)\n if (!focusChecked) return\n // after the menu has focused itself\n void nextTick(() =>\n nextTick(() => {\n const panel = document.activeElement\n const item =\n panel?.querySelector<HTMLElement>('[aria-checked=\"true\"]') ??\n panel?.querySelector<HTMLElement>('[role^=\"menuitem\"]:not([aria-disabled=\"true\"])')\n item?.focus({ preventScroll: true })\n }),\n )\n },\n close: () => menu.value?.close(),\n})\n</script>\n\n<template>\n <!-- The editor opens the menu itself; the empty anchor only gives it a place in the page. -->\n <DouContextMenu ref=\"menu\" v-model:open=\"open\" :items=\"items\">\n <span class=\"dou-flow-editor__menu-anchor\" aria-hidden=\"true\" />\n </DouContextMenu>\n</template>\n"],"mappings":";;;;;;;;;;;;;;EAMA,MAAM,OAAOA,SAAoB,SAAC,MAA0B;EAE5D,MAAM,OAAO,eAAoD,MAAM;EAEvE,SAAa;;;;;;GAMX,KACE,GACA,GACA,EACE,KACA,eAAe,UACwD,CAAC,GAC1E;IACA,KAAK,OAAO,KAAK,GAAG,GAAG,GAAG;IAC1B,IAAI,CAAC,cAAc;IAEnB,eACE,eAAe;KACb,MAAM,QAAQ,SAAS;KAIvB,CAFE,OAAO,cAA2B,yBAAuB,KACzD,OAAO,cAA2B,oDAAgD,EAAA,EAC9E,MAAM,EAAE,eAAe,KAAK,CAAC;IACrC,CAAC,CACH;GACF;GACA,aAAa,KAAK,OAAO,MAAM;EACjC,CAAC;;GAKC,OAAAC,UAAA,GAAAC,YAEiBC,MAAA,cAAA,GAAA;IAFG,SAAA;IAAJ,KAAI;IAAe,MAAM,KAAA;IAAA,iBAAA,OAAA,OAAA,OAAA,MAAA,WAAA,KAAI,QAAA;IAAG,OAAO,QAAA;;IACrD,SAAAC,cAAgE,CAAA,GAAA,OAAA,OAAA,OAAA,KAAA,CAAhEC,mBAAgE,QAAA;KAA1D,OAAM;KAA+B,eAAY"}
@@ -0,0 +1,6 @@
1
+ import flow_minimap_vue_vue_type_script_setup_true_lang_default from "./flow-minimap.vue_vue_type_script_setup_true_lang.js";
2
+ // src/components/flow-minimap.vue
3
+ var flow_minimap_default = flow_minimap_vue_vue_type_script_setup_true_lang_default;
4
+ export { flow_minimap_default as default };
5
+
6
+ //# sourceMappingURL=flow-minimap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flow-minimap.js","names":["_sfc_main"],"sources":["../../src/components/flow-minimap.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport { useFlowEditor, type FlowMinimapProps } from '../context'\nimport { boundsOf } from '../core/geometry'\nimport type { Point, Rect } from '../core/model'\n\ndefineOptions({ name: 'DouFlowMinimap' })\n\nconst props = withDefaults(defineProps<FlowMinimapProps>(), {\n placement: 'bottom-right',\n width: 200,\n height: 136,\n})\n\nconst flow = useFlowEditor()\nconst { messages } = flow\n\n/** The part of the canvas on screen, in canvas coordinates. */\nconst visible = computed<Rect>(() => {\n const { x, y, zoom } = flow.viewport.value\n const { width, height } = flow.size.value\n return { x: -x / zoom, y: -y / zoom, width: width / zoom, height: height / zoom }\n})\n\nconst rects = computed(() =>\n flow.doc.value.nodes.flatMap((node) => {\n const rect = flow.getNodeRect(node.id)\n return rect ? [{ id: node.id, rect, selected: flow.selectedNodes.value.has(node.id) }] : []\n }),\n)\n\n/** What the map shows: every node and the view, with some room around. */\nconst fitted = computed<Rect>(() => {\n const all = boundsOf([...rects.value.map((r) => r.rect), visible.value])!\n const pad = Math.max(all.width, all.height) * 0.05\n return {\n x: all.x - pad,\n y: all.y - pad,\n width: all.width + pad * 2,\n height: all.height + pad * 2,\n }\n})\n\n/**\n * Held still while the view is dragged: a map that grew to take in the view\n * as it went would slide away under the pointer, sending the view further\n * each time.\n */\nconst held = ref<Rect | null>(null)\nconst world = computed(() => held.value ?? fitted.value)\n\n/** Canvas units per map pixel; the map keeps the canvas's proportions. */\nconst scale = computed(() =>\n Math.max(world.value.width / props.width, world.value.height / props.height, 1e-6),\n)\nconst viewBox = computed(() => {\n const w = props.width * scale.value\n const h = props.height * scale.value\n const { x, y, width, height } = world.value\n return `${x - (w - width) / 2} ${y - (h - height) / 2} ${w} ${h}`\n})\n\n/** Everything outside the view, shaded: the map's box with the view cut out. */\nconst shade = computed(() => {\n const [x, y, w, h] = viewBox.value.split(' ').map(Number) as [number, number, number, number]\n const v = visible.value\n return `M${x} ${y}h${w}v${h}h${-w}Z M${v.x} ${v.y}v${v.height}h${v.width}v${-v.height}Z`\n})\n\nconst svg = ref<SVGSVGElement>()\nconst dragging = ref(false)\n\n/** How far along a side `at` is, from 0 to 1, staying on it when past its ends. */\nconst along = (at: number, start: number, length: number) =>\n length ? Math.min(1, Math.max(0, (at - start) / length)) : 0.5\n\n/** The point of the map under the pointer; past its edges, the nearest point on them. */\nfunction toWorld(event: PointerEvent): Point {\n const box = svg.value!.getBoundingClientRect()\n const [x, y, w, h] = viewBox.value.split(' ').map(Number) as [number, number, number, number]\n return {\n x: x + along(event.clientX, box.left, box.width) * w,\n y: y + along(event.clientY, box.top, box.height) * h,\n }\n}\n\n/** Centres the view on a point of the map, as far as the nodes allow. */\nfunction moveTo(event: PointerEvent) {\n const p = toWorld(event)\n const { zoom } = flow.viewport.value\n const { width, height } = flow.size.value\n flow.setViewport({ x: width / 2 - p.x * zoom, y: height / 2 - p.y * zoom, zoom })\n}\n\nfunction onPointerDown(event: PointerEvent) {\n if (event.button !== 0) return\n event.stopPropagation()\n dragging.value = true\n // The map as it is now: the press lands where it was seen.\n held.value = fitted.value\n try {\n svg.value!.setPointerCapture(event.pointerId)\n } catch {\n // Synthetic events have no pointer to capture.\n }\n moveTo(event)\n}\n\nfunction onPointerMove(event: PointerEvent) {\n if (dragging.value) moveTo(event)\n}\n\nfunction onPointerUp() {\n dragging.value = false\n held.value = null\n}\n\nconst el = ref<HTMLElement>()\n/** How far the map moves away from its edge to clear the other panels there, in px. */\nconst lift = ref(0)\nconst LIFT_GAP = 8\n\n/**\n * On a narrow editor the map would cover a panel in the same corner row,\n * e.g. the controls: then it sits above (or below) them instead.\n */\nfunction place() {\n const self = el.value\n const root = flow.root.value\n if (!self || !root) return\n const upper = props.placement.startsWith('top')\n const box = self.getBoundingClientRect()\n // where the map is without the lift\n const top = box.top + (upper ? -lift.value : lift.value)\n const bottom = top + box.height\n let next = 0\n for (const panel of root.querySelectorAll('.dou-flow-editor__panels > *')) {\n if (panel === self || panel.classList.contains('dou-flow-minimap')) continue\n const rect = panel.getBoundingClientRect()\n if (!rect.width || !rect.height) continue\n if (rect.right <= box.left || rect.left >= box.right) continue\n if (rect.bottom <= top || rect.top >= bottom) continue\n next = Math.max(next, upper ? rect.bottom - top + LIFT_GAP : bottom - rect.top + LIFT_GAP)\n }\n lift.value = next\n}\n\n// Panels come, go and change size after the map is shown (controls put in\n// later, undo hidden when made read-only…): place it again each time.\nlet resizes: ResizeObserver | undefined\nlet changes: MutationObserver | undefined\nfunction watchPanels() {\n const panels = el.value?.parentElement\n if (!panels) return\n resizes?.disconnect()\n if (typeof ResizeObserver !== 'undefined') {\n resizes = new ResizeObserver(() => place())\n for (const panel of panels.children) if (panel !== el.value) resizes.observe(panel)\n }\n place()\n}\n\nonMounted(() => {\n nextTick(watchPanels)\n const panels = el.value?.parentElement\n if (panels && typeof MutationObserver !== 'undefined') {\n changes = new MutationObserver(watchPanels)\n changes.observe(panels, { childList: true })\n }\n})\nonBeforeUnmount(() => {\n resizes?.disconnect()\n changes?.disconnect()\n})\nwatch(\n () => [flow.size.value.width, flow.size.value.height, props.width, props.height, props.placement],\n () => nextTick(place),\n)\n</script>\n\n<template>\n <div\n ref=\"el\"\n class=\"dou-flow-minimap\"\n data-flow-overlay\n :style=\"lift ? { translate: `0 ${placement.startsWith('top') ? lift : -lift}px` } : undefined\"\n :class=\"[`is-${placement}`, { 'is-dragging': dragging }]\"\n role=\"img\"\n :aria-label=\"messages.minimap\"\n >\n <svg\n ref=\"svg\"\n :width=\"width\"\n :height=\"height\"\n :viewBox=\"viewBox\"\n preserveAspectRatio=\"xMidYMid meet\"\n aria-hidden=\"true\"\n @pointerdown=\"onPointerDown\"\n @pointermove=\"onPointerMove\"\n @pointerup=\"onPointerUp\"\n @pointercancel=\"onPointerUp\"\n >\n <rect\n v-for=\"item in rects\"\n :key=\"item.id\"\n class=\"dou-flow-minimap__node\"\n :class=\"{ 'is-selected': item.selected }\"\n :x=\"item.rect.x\"\n :y=\"item.rect.y\"\n :width=\"item.rect.width\"\n :height=\"item.rect.height\"\n :rx=\"2 * scale\"\n />\n <path class=\"dou-flow-minimap__shade\" :d=\"shade\" fill-rule=\"evenodd\" />\n <rect\n class=\"dou-flow-minimap__view\"\n :x=\"visible.x\"\n :y=\"visible.y\"\n :width=\"visible.width\"\n :height=\"visible.height\"\n />\n </svg>\n </div>\n</template>\n"],"mappings":""}