@workflow-vue/ui 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.css ADDED
@@ -0,0 +1 @@
1
+ [data-v-5d9eb27b] .vue-flow__node-resizer{z-index:100}.vue-flow{position:relative;width:100%;height:100%;overflow:hidden;z-index:0;direction:ltr}.vue-flow__container{position:absolute;height:100%;width:100%;left:0;top:0}.vue-flow__pane{z-index:1}.vue-flow__pane.draggable{cursor:grab}.vue-flow__pane.selection{cursor:pointer}.vue-flow__pane.dragging{cursor:grabbing}.vue-flow__transformationpane{transform-origin:0 0;z-index:2;pointer-events:none}.vue-flow__viewport{z-index:4;overflow:clip}.vue-flow__selection{z-index:6}.vue-flow__edge-labels{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.vue-flow__nodesselection-rect:focus,.vue-flow__nodesselection-rect:focus-visible{outline:none}.vue-flow .vue-flow__edges{pointer-events:none;overflow:visible}.vue-flow__edge-path,.vue-flow__connection-path{stroke:#b1b1b7;stroke-width:1;fill:none}.vue-flow__edge{pointer-events:visibleStroke;cursor:pointer}.vue-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.vue-flow__edge.animated path.vue-flow__edge-interaction{stroke-dasharray:none;animation:none}.vue-flow__edge.inactive{pointer-events:none}.vue-flow__edge.selected,.vue-flow__edge:focus,.vue-flow__edge:focus-visible{outline:none}.vue-flow__edge.selected .vue-flow__edge-path,.vue-flow__edge:focus .vue-flow__edge-path,.vue-flow__edge:focus-visible .vue-flow__edge-path{stroke:#555}.vue-flow__edge-textwrapper{pointer-events:all}.vue-flow__edge-textbg{fill:#fff}.vue-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.vue-flow__connection{pointer-events:none}.vue-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.vue-flow__connectionline{z-index:1001}.vue-flow__nodes{pointer-events:none;transform-origin:0 0}.vue-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default}.vue-flow__node.draggable{cursor:grab;pointer-events:all}.vue-flow__node.draggable.dragging{cursor:grabbing}.vue-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.vue-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.vue-flow__nodesselection-rect.dragging{cursor:grabbing}.vue-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px}.vue-flow__handle.connectable{pointer-events:all;cursor:crosshair}.vue-flow__handle-bottom{left:50%;bottom:0;transform:translate(-50%,50%)}.vue-flow__handle-top{left:50%;top:0;transform:translate(-50%,-50%)}.vue-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.vue-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.vue-flow__edgeupdater{cursor:move;pointer-events:all}.vue-flow__panel{position:absolute;z-index:5;margin:15px}.vue-flow__panel.top{top:0}.vue-flow__panel.bottom{bottom:0}.vue-flow__panel.left{left:0}.vue-flow__panel.right{right:0}.vue-flow__panel.center{left:50%;transform:translate(-50%)}@keyframes dashdraw{0%{stroke-dashoffset:10}}.vue-flow__controls{box-shadow:0 0 2px 1px #00000014}.vue-flow__controls-button{background:#fefefe;border:none;border-bottom:1px solid #eee;box-sizing:content-box;display:flex;justify-content:center;align-items:center;width:16px;height:16px;cursor:pointer;-webkit-user-select:none;user-select:none;padding:5px}.vue-flow__controls-button svg{width:100%;max-width:12px;max-height:12px}.vue-flow__controls-button:hover{background:#f4f4f4}.vue-flow__controls-button:disabled{pointer-events:none}.vue-flow__controls-button:disabled svg{fill-opacity:.4}.vue-flow__minimap{background-color:#fff}.vue-flow__minimap.pannable{cursor:grab}.vue-flow__minimap.dragging{cursor:grabbing}.vue-flow__minimap-mask.pannable{cursor:grab}.vue-flow__selection{background:#3b82f61a;border:2px dashed rgb(59,130,246)}
package/dist/index.js ADDED
@@ -0,0 +1,444 @@
1
+ import { watch as ee, computed as _, toValue as T, unref as c, defineComponent as z, createElementBlock as N, openBlock as g, normalizeClass as P, createVNode as w, createElementVNode as o, createCommentVNode as H, toDisplayString as D, createSlots as te, withCtx as B, normalizeProps as W, guardReactiveProps as M, renderList as F, createBlock as K, resolveDynamicComponent as q, Fragment as oe, createTextVNode as X } from "vue";
2
+ import { Handle as V, Position as j, useVueFlow as ne, VueFlow as se, SelectionMode as ie } from "@vue-flow/core";
3
+ import { Background as re } from "@vue-flow/background";
4
+ import { Controls as de } from "@vue-flow/controls";
5
+ import { MiniMap as le } from "@vue-flow/minimap";
6
+ import { useFlowStore as O, registry as A } from "@workflow-vue/core";
7
+ import { NodeResizer as ae } from "@vue-flow/node-resizer";
8
+ const ce = typeof window < "u" && typeof document < "u";
9
+ typeof WorkerGlobalScope < "u" && globalThis instanceof WorkerGlobalScope;
10
+ const ue = Object.prototype.toString, pe = (t) => ue.call(t) === "[object Object]";
11
+ function R(t) {
12
+ return Array.isArray(t) ? t : [t];
13
+ }
14
+ function fe(t, e, n) {
15
+ return ee(t, e, {
16
+ ...n,
17
+ immediate: !0
18
+ });
19
+ }
20
+ const J = ce ? window : void 0;
21
+ function ge(t) {
22
+ var e;
23
+ const n = T(t);
24
+ return (e = n?.$el) !== null && e !== void 0 ? e : n;
25
+ }
26
+ function ye(...t) {
27
+ const e = (i, l, d, f) => (i.addEventListener(l, d, f), () => i.removeEventListener(l, d, f)), n = _(() => {
28
+ const i = R(T(t[0])).filter((l) => l != null);
29
+ return i.every((l) => typeof l != "string") ? i : void 0;
30
+ });
31
+ return fe(() => {
32
+ var i, l;
33
+ return [
34
+ (i = (l = n.value) === null || l === void 0 ? void 0 : l.map((d) => ge(d))) !== null && i !== void 0 ? i : [J].filter((d) => d != null),
35
+ R(T(n.value ? t[1] : t[0])),
36
+ R(c(n.value ? t[2] : t[1])),
37
+ T(n.value ? t[3] : t[2])
38
+ ];
39
+ }, ([i, l, d, f], y, r) => {
40
+ if (!i?.length || !l?.length || !d?.length) return;
41
+ const v = pe(f) ? { ...f } : f, C = i.flatMap(($) => l.flatMap((G) => d.map((s) => e($, G, s, v))));
42
+ r(() => {
43
+ C.forEach(($) => $());
44
+ });
45
+ }, { flush: "post" });
46
+ }
47
+ function me(t) {
48
+ return typeof t == "function" ? t : typeof t == "string" ? (e) => e.key === t : Array.isArray(t) ? (e) => t.includes(e.key) : () => !0;
49
+ }
50
+ function L(...t) {
51
+ let e, n, i = {};
52
+ t.length === 3 ? (e = t[0], n = t[1], i = t[2]) : t.length === 2 ? typeof t[1] == "object" ? (e = !0, n = t[0], i = t[1]) : (e = t[0], n = t[1]) : (e = !0, n = t[0]);
53
+ const { target: l = J, eventName: d = "keydown", passive: f = !1, dedupe: y = !1 } = i, r = me(e);
54
+ return ye(l, d, (C) => {
55
+ C.repeat && T(y) || r(C) && n(C);
56
+ }, f);
57
+ }
58
+ const ve = { class: "absolute -top-6 left-0 flex items-center gap-2" }, xe = { class: "text-xs font-medium text-blue-900 opacity-60 group-hover:opacity-100 transition-opacity" }, be = {
59
+ key: 0,
60
+ class: "absolute inset-0 border-2 border-dashed border-blue-400 rounded-2xl pointer-events-none animate-pulse"
61
+ }, Y = "#3b82f6", he = /* @__PURE__ */ z({
62
+ __name: "GroupNode",
63
+ props: {
64
+ id: {},
65
+ data: {},
66
+ selected: { type: Boolean }
67
+ },
68
+ setup(t) {
69
+ const e = t, n = O(), i = _(() => n.hoveredNodeId === e.id);
70
+ return (l, d) => (g(), N("div", {
71
+ class: P(["w-full h-full rounded-2xl transition-all duration-300 relative group", [
72
+ "bg-blue-50/30 border-2",
73
+ t.selected ? "border-blue-500 ring-4 ring-blue-500/10" : "border-blue-200/50",
74
+ i.value ? "bg-blue-100/40 border-blue-400" : ""
75
+ ]])
76
+ }, [
77
+ w(c(ae), {
78
+ "is-visible": t.selected,
79
+ "min-width": 150,
80
+ "min-height": 100,
81
+ "line-style": { borderColor: Y, borderWidth: "2px" },
82
+ "handle-style": {
83
+ width: "12px",
84
+ height: "12px",
85
+ backgroundColor: "white",
86
+ border: `2px solid ${Y}`,
87
+ borderRadius: "4px"
88
+ }
89
+ }, null, 8, ["is-visible", "line-style", "handle-style"]),
90
+ o("div", ve, [
91
+ d[0] || (d[0] = o("div", { class: "px-2 py-0.5 bg-blue-500 rounded text-[10px] font-bold text-white uppercase tracking-wider shadow-sm" }, " Group ", -1)),
92
+ o("div", xe, D(t.data.title), 1)
93
+ ]),
94
+ i.value ? (g(), N("div", be)) : H("", !0),
95
+ w(c(V), {
96
+ type: "target",
97
+ position: c(j).Left,
98
+ class: "!opacity-0"
99
+ }, null, 8, ["position"]),
100
+ w(c(V), {
101
+ type: "source",
102
+ position: c(j).Right,
103
+ class: "!opacity-0"
104
+ }, null, 8, ["position"])
105
+ ], 2));
106
+ }
107
+ }), Ne = (t, e) => {
108
+ const n = t.__vccOpts || t;
109
+ for (const [i, l] of e)
110
+ n[i] = l;
111
+ return n;
112
+ }, we = /* @__PURE__ */ Ne(he, [["__scopeId", "data-v-5d9eb27b"]]), Fe = /* @__PURE__ */ z({
113
+ __name: "CanvasView",
114
+ setup(t) {
115
+ const e = O(), {
116
+ onConnect: n,
117
+ onNodeDrag: i,
118
+ onNodeDragStop: l,
119
+ findNode: d,
120
+ getIntersectingNodes: f,
121
+ screenToFlowCoordinate: y
122
+ } = ne();
123
+ n((s) => {
124
+ e.onConnect(s);
125
+ });
126
+ const r = (s) => {
127
+ s.preventDefault(), s.dataTransfer && (s.dataTransfer.dropEffect = "move");
128
+ const u = y({
129
+ x: s.clientX,
130
+ y: s.clientY
131
+ }), p = e.nodes.filter((h) => h.type === "group").find((h) => {
132
+ const m = d(h.id);
133
+ if (!m) return !1;
134
+ const k = m.computedPosition?.x ?? m.position.x, I = m.computedPosition?.y ?? m.position.y, S = m.dimensions?.width ?? m.width ?? 200, x = m.dimensions?.height ?? m.height ?? 150;
135
+ return u.x >= k && u.x <= k + S && u.y >= I && u.y <= I + x;
136
+ });
137
+ p ? e.setHoveredNode(p.id) : e.setHoveredNode(null);
138
+ }, v = (s) => {
139
+ e.setHoveredNode(null);
140
+ const u = s.dataTransfer?.getData("application/vueflow");
141
+ if (!u) return;
142
+ const a = y({
143
+ x: s.clientX,
144
+ y: s.clientY
145
+ }), p = e.nodes.filter((x) => x.type === "group");
146
+ let h, m = a;
147
+ const k = p.find((x) => {
148
+ const b = d(x.id);
149
+ if (!b) return !1;
150
+ const E = b.computedPosition?.x ?? b.position.x, U = b.computedPosition?.y ?? b.position.y, Q = b.dimensions?.width ?? b.width ?? 200, Z = b.dimensions?.height ?? b.height ?? 150;
151
+ return a.x >= E && a.x <= E + Q && a.y >= U && a.y <= U + Z;
152
+ });
153
+ if (k) {
154
+ const x = d(k.id);
155
+ if (x) {
156
+ h = k.id;
157
+ const b = x.computedPosition?.x ?? x.position.x, E = x.computedPosition?.y ?? x.position.y;
158
+ m = {
159
+ x: a.x - b,
160
+ y: a.y - E
161
+ };
162
+ }
163
+ }
164
+ const I = {
165
+ parentNode: h,
166
+ expandParent: !!h,
167
+ // If creating a group, give it initial size so it's not tiny
168
+ ...u === "group" ? { width: 300, height: 200 } : {}
169
+ }, S = {
170
+ id: crypto.randomUUID(),
171
+ type: u,
172
+ position: m,
173
+ data: {
174
+ title: `New ${u.charAt(0).toUpperCase() + u.slice(1)}`,
175
+ config: {}
176
+ },
177
+ ...I
178
+ // Spread options into node object if needed locally, but we pass to store
179
+ };
180
+ e.addNode(S.type, S.position, S.data, I);
181
+ };
182
+ i(({ node: s }) => {
183
+ const a = f(s).find((p) => p.type === "group");
184
+ a ? e.setHoveredNode(a.id) : e.setHoveredNode(null);
185
+ }), l(({ node: s }) => {
186
+ e.setHoveredNode(null);
187
+ const a = f(s).find((p) => p.type === "group");
188
+ if (a) {
189
+ if (s.parentNode !== a.id) {
190
+ const p = d(a.id);
191
+ if (p) {
192
+ const h = {
193
+ x: s.position.x - p.position.x,
194
+ y: s.position.y - p.position.y
195
+ };
196
+ e.updateNode(s.id, {
197
+ parentNode: a.id,
198
+ position: h,
199
+ expandParent: !0
200
+ });
201
+ }
202
+ }
203
+ } else if (s.parentNode) {
204
+ const p = { ...s.computedPosition };
205
+ e.updateNode(s.id, {
206
+ parentNode: void 0,
207
+ position: p
208
+ });
209
+ }
210
+ });
211
+ function C() {
212
+ }
213
+ function $({ node: s }) {
214
+ e.selectNode(s.id);
215
+ }
216
+ function G() {
217
+ e.selectNode(null);
218
+ }
219
+ return L(["c", "C"], (s) => {
220
+ (s.ctrlKey || s.metaKey) && !s.shiftKey && !s.altKey && (s.preventDefault(), e.copySelectedNodes());
221
+ }), L(["v", "V"], (s) => {
222
+ (s.ctrlKey || s.metaKey) && !s.shiftKey && !s.altKey && (s.preventDefault(), e.pasteNodes());
223
+ }), L(["Delete", "Backspace"], () => {
224
+ e.nodes.filter((u) => u.selected).forEach((u) => {
225
+ e.removeNode(u.id);
226
+ });
227
+ }), (s, u) => (g(), N("div", {
228
+ class: "h-full w-full",
229
+ onDrop: v,
230
+ onDragover: r
231
+ }, [
232
+ w(c(se), {
233
+ nodes: c(e).nodes,
234
+ "onUpdate:nodes": u[0] || (u[0] = (a) => c(e).nodes = a),
235
+ edges: c(e).edges,
236
+ "onUpdate:edges": u[1] || (u[1] = (a) => c(e).edges = a),
237
+ "default-viewport": { zoom: 1 },
238
+ "min-zoom": 0.2,
239
+ "max-zoom": 4,
240
+ "selection-mode": c(ie).Partial,
241
+ onPaneReady: C,
242
+ onNodeClick: $,
243
+ onPaneClick: G
244
+ }, te({
245
+ "node-group": B((a) => [
246
+ w(we, W(M(a)), null, 16)
247
+ ]),
248
+ default: B(() => [
249
+ w(c(re), {
250
+ "pattern-color": "#aaa",
251
+ gap: 16
252
+ }),
253
+ w(c(de)),
254
+ w(c(le))
255
+ ]),
256
+ _: 2
257
+ }, [
258
+ F(c(A).getAllDefinitions(), (a) => ({
259
+ name: `node-${a.type}`,
260
+ fn: B((p) => [
261
+ (g(), K(q(a.component), W(M(p)), null, 16))
262
+ ])
263
+ }))
264
+ ]), 1032, ["nodes", "edges", "selection-mode"])
265
+ ], 32));
266
+ }
267
+ }), Ce = { class: "w-64 bg-white border-r border-gray-200 flex flex-col z-10" }, _e = { class: "flex-1 overflow-y-auto p-3 space-y-2" }, ke = ["onDragstart"], Pe = { class: "text-sm font-medium text-gray-700" }, De = { class: "text-[10px] text-gray-400" }, qe = /* @__PURE__ */ z({
268
+ __name: "NodePalette",
269
+ setup(t) {
270
+ const e = _(() => A.getAllDefinitions()), n = (i, l) => {
271
+ i.dataTransfer && (i.dataTransfer.setData("application/vueflow", l), i.dataTransfer.effectAllowed = "move");
272
+ };
273
+ return (i, l) => (g(), N("aside", Ce, [
274
+ l[0] || (l[0] = o("div", { class: "p-4 border-b border-gray-100" }, [
275
+ o("h2", { class: "font-medium text-gray-900" }, "Components"),
276
+ o("p", { class: "text-xs text-gray-500 mt-1" }, "Drag nodes to the canvas")
277
+ ], -1)),
278
+ o("div", _e, [
279
+ (g(!0), N(oe, null, F(e.value, (d) => (g(), N("div", {
280
+ key: d.type,
281
+ class: "group flex items-center gap-3 p-2 rounded-lg border border-transparent hover:border-gray-200 hover:bg-gray-50 cursor-grab active:cursor-grabbing transition",
282
+ draggable: "true",
283
+ onDragstart: (f) => n(f, d.type)
284
+ }, [
285
+ o("div", {
286
+ class: P([
287
+ d.color,
288
+ "w-8 h-8 rounded-lg flex items-center justify-center text-white shrink-0",
289
+ d.type === "group" ? "text-gray-600" : ""
290
+ // Special handling for group text color
291
+ ])
292
+ }, [
293
+ o("div", {
294
+ class: P([d.icon, "text-lg"])
295
+ }, null, 2)
296
+ ], 2),
297
+ o("div", null, [
298
+ o("div", Pe, D(d.label), 1),
299
+ o("div", De, D(d.description), 1)
300
+ ])
301
+ ], 40, ke))), 128))
302
+ ])
303
+ ]));
304
+ }
305
+ }), $e = {
306
+ key: 0,
307
+ class: "w-80 bg-white border-l border-gray-200 flex flex-col z-20 shadow-lg transition-transform"
308
+ }, Ie = { class: "p-4 border-b border-gray-100 flex items-center justify-between bg-gray-50/50" }, Se = { class: "text-xs text-gray-500 mt-0.5 font-mono text-opacity-80" }, Te = { class: "flex-1 overflow-y-auto p-4 space-y-6" }, ze = { class: "space-y-4" }, Ee = ["value"], He = ["value"], Ke = { class: "space-y-4" }, Ve = {
309
+ key: 1,
310
+ class: "text-center py-8 text-gray-400"
311
+ }, je = { class: "p-4 border-t border-gray-200 bg-gray-50 flex gap-2" }, Je = /* @__PURE__ */ z({
312
+ __name: "InspectorPanel",
313
+ setup(t) {
314
+ const e = O(), n = _(() => e.nodes.find((y) => y.id === e.selectedNodeId)), i = _(() => !!n.value), l = (y, r) => {
315
+ if (e.selectedNodeId && n.value) {
316
+ const v = n.value.data.config || {};
317
+ e.updateNodeData(e.selectedNodeId, {
318
+ config: { ...v, [y]: r }
319
+ });
320
+ }
321
+ }, d = (y, r) => {
322
+ e.selectedNodeId && e.updateNodeData(e.selectedNodeId, { [y]: r });
323
+ }, f = () => {
324
+ e.selectNode(null);
325
+ };
326
+ return (y, r) => i.value ? (g(), N("aside", $e, [
327
+ o("div", Ie, [
328
+ o("div", null, [
329
+ r[3] || (r[3] = o("h2", { class: "font-semibold text-gray-900 leading-tight" }, "Configuration", -1)),
330
+ o("p", Se, D(n.value?.type) + " node ", 1)
331
+ ]),
332
+ o("button", {
333
+ onClick: f,
334
+ class: "icon-btn"
335
+ }, [...r[4] || (r[4] = [
336
+ o("div", { class: "i-ph-x text-lg" }, null, -1)
337
+ ])])
338
+ ]),
339
+ o("div", Te, [
340
+ o("div", ze, [
341
+ o("div", null, [
342
+ r[5] || (r[5] = o("label", { class: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-1.5 align-middle" }, [
343
+ o("span", { class: "i-ph-tag mr-1 inline-block" }),
344
+ X(" Node Name ")
345
+ ], -1)),
346
+ o("input", {
347
+ value: n.value?.data.title,
348
+ onInput: r[0] || (r[0] = (v) => d("title", v.target.value)),
349
+ type: "text",
350
+ class: "w-full px-3 py-2 bg-gray-50 border border-gray-200 rounded-lg focus:bg-white focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary text-sm transition"
351
+ }, null, 40, Ee)
352
+ ]),
353
+ o("div", null, [
354
+ r[6] || (r[6] = o("label", { class: "block text-xs font-semibold text-gray-500 uppercase tracking-wider mb-1.5" }, "Description", -1)),
355
+ o("textarea", {
356
+ value: n.value?.data.description,
357
+ onInput: r[1] || (r[1] = (v) => d("description", v.target.value)),
358
+ rows: "2",
359
+ class: "w-full px-3 py-2 bg-gray-50 border border-gray-200 rounded-lg focus:bg-white focus:outline-none focus:ring-2 focus:ring-primary/20 focus:border-primary text-sm transition resize-none"
360
+ }, null, 40, He)
361
+ ])
362
+ ]),
363
+ r[9] || (r[9] = o("div", { class: "h-px bg-gray-100 my-2" }, null, -1)),
364
+ o("div", Ke, [
365
+ r[8] || (r[8] = o("div", { class: "flex items-center gap-2 mb-2" }, [
366
+ o("div", { class: "i-ph-sliders-horizontal text-gray-400" }),
367
+ o("h3", { class: "text-xs font-semibold text-gray-900 uppercase tracking-wider" }, "Parameters")
368
+ ], -1)),
369
+ n.value && c(A).getConfigComponent(n.value.type) ? (g(), K(q(c(A).getConfigComponent(n.value.type)), {
370
+ key: 0,
371
+ data: n.value.data,
372
+ "node-id": n.value.id,
373
+ onUpdate: l
374
+ }, null, 40, ["data", "node-id"])) : (g(), N("div", Ve, [...r[7] || (r[7] = [
375
+ o("div", { class: "i-ph-sliders text-4xl mx-auto mb-2 opacity-20" }, null, -1),
376
+ o("p", { class: "text-sm" }, "No specific configuration for this node type.", -1)
377
+ ])]))
378
+ ])
379
+ ]),
380
+ o("div", je, [
381
+ o("button", {
382
+ onClick: r[2] || (r[2] = (v) => c(e).removeNode(n.value.id)),
383
+ class: "flex-1 px-4 py-2 rounded-lg border border-red-200 text-red-600 bg-white hover:bg-red-50 hover:border-red-300 transition text-sm font-medium flex items-center justify-center gap-2"
384
+ }, [...r[10] || (r[10] = [
385
+ o("div", { class: "i-ph-trash" }, null, -1),
386
+ X(" Delete ", -1)
387
+ ])]),
388
+ r[11] || (r[11] = o("button", {
389
+ class: "px-4 py-2 rounded-lg border border-gray-200 text-gray-600 bg-white hover:bg-gray-100 transition text-sm font-medium",
390
+ title: "Duplicate"
391
+ }, [
392
+ o("div", { class: "i-ph-copy" })
393
+ ], -1))
394
+ ])
395
+ ])) : H("", !0);
396
+ }
397
+ }), Ae = { class: "p-3 flex items-start gap-3 border-gray-100" }, Ge = { class: "flex-1 min-w-0" }, Be = { class: "font-medium text-sm text-gray-900 truncate" }, Re = { class: "text-xs text-gray-500 truncate mt-0.5" }, Qe = /* @__PURE__ */ z({
398
+ __name: "NodeCard",
399
+ props: {
400
+ id: {},
401
+ data: {},
402
+ selected: { type: Boolean }
403
+ },
404
+ setup(t) {
405
+ const e = t, n = _(() => e.data.icon || "i-ph-cube"), i = _(() => e.data.color || "bg-blue-600");
406
+ return (l, d) => (g(), N("div", {
407
+ class: P(["w-64 bg-white rounded-xl shadow-sm border transition-all duration-200", [
408
+ t.selected ? "border-primary shadow-md ring-2 ring-primary/20" : "border-gray-200 hover:border-gray-300"
409
+ ]])
410
+ }, [
411
+ o("div", Ae, [
412
+ o("div", {
413
+ class: P(["w-8 h-8 rounded-lg flex items-center justify-center shrink-0 text-white", i.value])
414
+ }, [
415
+ o("div", {
416
+ class: P([n.value, "text-lg"])
417
+ }, null, 2)
418
+ ], 2),
419
+ o("div", Ge, [
420
+ o("h3", Be, D(t.data.title), 1),
421
+ o("p", Re, D(t.data.description || "No description"), 1)
422
+ ])
423
+ ]),
424
+ t.data.isStart ? H("", !0) : (g(), K(c(V), {
425
+ key: 0,
426
+ type: "target",
427
+ position: c(j).Left,
428
+ class: "!-ml-1.5"
429
+ }, null, 8, ["position"])),
430
+ t.data.isEnd ? H("", !0) : (g(), K(c(V), {
431
+ key: 1,
432
+ type: "source",
433
+ position: c(j).Right,
434
+ class: "!-mr-1.5"
435
+ }, null, 8, ["position"]))
436
+ ], 2));
437
+ }
438
+ });
439
+ export {
440
+ Fe as CanvasView,
441
+ Je as InspectorPanel,
442
+ Qe as NodeCard,
443
+ qe as NodePalette
444
+ };
@@ -0,0 +1,2 @@
1
+ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, HTMLDivElement>;
2
+ export default _default;
@@ -0,0 +1,2 @@
1
+ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, any>;
2
+ export default _default;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
1
+ type __VLS_Props = {
2
+ id: string;
3
+ data: {
4
+ title: string;
5
+ description?: string;
6
+ icon?: string;
7
+ color?: string;
8
+ [key: string]: any;
9
+ };
10
+ selected?: boolean;
11
+ };
12
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
13
+ export default _default;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ declare const _default: import('vue').DefineComponent<{}, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, true, {}, HTMLElement>;
2
+ export default _default;
@@ -0,0 +1,8 @@
1
+ import { NodeData } from '../../../../core/src/index.ts';
2
+ type __VLS_Props = {
3
+ id: string;
4
+ data: NodeData;
5
+ selected?: boolean;
6
+ };
7
+ declare const _default: import('vue').DefineComponent<__VLS_Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
8
+ export default _default;
@@ -0,0 +1,5 @@
1
+ export { default as CanvasView } from './components/CanvasView.vue';
2
+ export { default as NodePalette } from './components/NodePalette.vue';
3
+ export { default as InspectorPanel } from './components/InspectorPanel.vue';
4
+ export { default as NodeCard } from './components/NodeCard.vue';
5
+ export * from './components/nodes/GroupNode.vue';
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@workflow-vue/ui",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "scripts": {
12
+ "build": "vite build",
13
+ "dev": "vite"
14
+ },
15
+ "dependencies": {
16
+ "@vue-flow/background": "^1.3.2",
17
+ "@vue-flow/controls": "^1.1.3",
18
+ "@vue-flow/core": "^1.48.0",
19
+ "@vue-flow/minimap": "^1.5.4",
20
+ "@vue-flow/node-resizer": "^1.5.0",
21
+ "@workflow-vue/core": "workspace:*",
22
+ "vue": "^3.5.24"
23
+ },
24
+ "devDependencies": {
25
+ "@vitejs/plugin-vue": "^6.0.1",
26
+ "@vue/tsconfig": "^0.8.1",
27
+ "typescript": "~5.9.3",
28
+ "unocss": "^66.5.10",
29
+ "vite": "^7.2.4",
30
+ "vite-plugin-dts": "^4.5.3"
31
+ }
32
+ }