@floegence/floe-webapp-core 0.35.58 → 0.36.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 (55) hide show
  1. package/dist/components/deck/DeckCell.js +47 -50
  2. package/dist/components/deck/DeckContextMenu.d.ts +22 -0
  3. package/dist/components/deck/DeckContextMenu.js +73 -0
  4. package/dist/components/deck/DeckGrid.js +147 -104
  5. package/dist/components/deck/DeckTopBar.js +74 -96
  6. package/dist/components/deck/WidgetFrame.d.ts +7 -1
  7. package/dist/components/deck/WidgetFrame.js +60 -52
  8. package/dist/components/deck/index.d.ts +1 -0
  9. package/dist/components/ui/InfiniteCanvas.d.ts +2 -0
  10. package/dist/components/ui/InfiniteCanvas.js +43 -37
  11. package/dist/components/workbench/WorkbenchCanvas.d.ts +28 -0
  12. package/dist/components/workbench/WorkbenchCanvas.js +79 -0
  13. package/dist/components/workbench/WorkbenchContextMenu.d.ts +24 -0
  14. package/dist/components/workbench/WorkbenchContextMenu.js +44 -0
  15. package/dist/components/workbench/WorkbenchFilterBar.d.ts +16 -0
  16. package/dist/components/workbench/WorkbenchFilterBar.js +266 -0
  17. package/dist/components/workbench/WorkbenchHud.d.ts +6 -0
  18. package/dist/components/workbench/WorkbenchHud.js +17 -0
  19. package/dist/components/workbench/WorkbenchLockButton.d.ts +6 -0
  20. package/dist/components/workbench/WorkbenchLockButton.js +49 -0
  21. package/dist/components/workbench/WorkbenchOverlay.d.ts +18 -0
  22. package/dist/components/workbench/WorkbenchOverlay.js +107 -0
  23. package/dist/components/workbench/WorkbenchSurface.d.ts +21 -0
  24. package/dist/components/workbench/WorkbenchSurface.js +183 -0
  25. package/dist/components/workbench/WorkbenchWidget.d.ts +25 -0
  26. package/dist/components/workbench/WorkbenchWidget.js +183 -0
  27. package/dist/components/workbench/index.d.ts +7 -0
  28. package/dist/components/workbench/types.d.ts +39 -0
  29. package/dist/components/workbench/types.js +25 -0
  30. package/dist/components/workbench/useWorkbenchModel.d.ts +70 -0
  31. package/dist/components/workbench/useWorkbenchModel.js +259 -0
  32. package/dist/components/workbench/widgets/CodeEditorWidget.d.ts +1 -0
  33. package/dist/components/workbench/widgets/CodeEditorWidget.js +144 -0
  34. package/dist/components/workbench/widgets/FileBrowserWidget.d.ts +1 -0
  35. package/dist/components/workbench/widgets/FileBrowserWidget.js +142 -0
  36. package/dist/components/workbench/widgets/LogViewerWidget.d.ts +1 -0
  37. package/dist/components/workbench/widgets/LogViewerWidget.js +86 -0
  38. package/dist/components/workbench/widgets/SystemMonitorWidget.d.ts +1 -0
  39. package/dist/components/workbench/widgets/SystemMonitorWidget.js +122 -0
  40. package/dist/components/workbench/widgets/TerminalWidget.d.ts +1 -0
  41. package/dist/components/workbench/widgets/TerminalWidget.js +70 -0
  42. package/dist/components/workbench/widgets/widgetRegistry.d.ts +13 -0
  43. package/dist/components/workbench/widgets/widgetRegistry.js +50 -0
  44. package/dist/components/workbench/workbenchHelpers.d.ts +22 -0
  45. package/dist/components/workbench/workbenchHelpers.js +176 -0
  46. package/dist/deck.js +14 -12
  47. package/dist/full.js +381 -379
  48. package/dist/hooks/useDeckDrag.js +15 -15
  49. package/dist/styles.css +1 -1
  50. package/dist/tailwind.css +1 -0
  51. package/dist/ui.css +4 -0
  52. package/dist/workbench.css +1220 -0
  53. package/dist/workbench.d.ts +1 -0
  54. package/dist/workbench.js +22 -0
  55. package/package.json +5 -1
@@ -1,103 +1,103 @@
1
- import { insert as n, createComponent as o, effect as g, className as h, Portal as N, setStyleProperty as _, memo as k, template as l, use as F, delegateEvents as I } from "solid-js/web";
2
- import { createSignal as C, createEffect as M, onCleanup as T, Show as d, For as K } from "solid-js";
3
- import { cn as p } from "../../utils/cn.js";
4
- import { useDeck as j } from "../../context/DeckContext.js";
5
- import { useResolvedFloeConfig as q } from "../../context/FloeConfigContext.js";
6
- import { useLayout as G } from "../../context/LayoutContext.js";
7
- import { useWidgetRegistry as H } from "../../context/WidgetRegistry.js";
8
- import { deferNonBlocking as P } from "../../utils/defer.js";
9
- import { LayoutSelector as J } from "./LayoutSelector.js";
10
- import { Plus as O, ChevronDown as Q, Copy as U, Check as V, Pencil as X } from "../icons/index.js";
11
- var Y = /* @__PURE__ */ l("<button><span>Add"), Z = /* @__PURE__ */ l('<div class="fixed inset-0 z-[9998]">'), ee = /* @__PURE__ */ l('<div class="px-3 py-4 text-xs text-muted-foreground text-center">No widgets available'), te = /* @__PURE__ */ l("<div><div class=p-1>"), re = /* @__PURE__ */ l('<button title="Duplicate &amp; edit"><span>Duplicate &amp; Edit'), oe = /* @__PURE__ */ l("<span>Done"), ne = /* @__PURE__ */ l("<button>"), ie = /* @__PURE__ */ l('<div><div class="w-px h-3.5 bg-border/40"></div><div class=flex-1>'), le = /* @__PURE__ */ l('<button class="w-full flex items-center gap-2 px-3 py-2 rounded hover:bg-muted transition-colors text-left cursor-pointer"><span class=text-xs>'), se = /* @__PURE__ */ l('<div class="w-4 h-4">'), ae = /* @__PURE__ */ l("<span>Edit");
12
- function be($) {
13
- const D = q(), s = j(), E = G(), w = H(), [v, m] = C(!1), [y, L] = C({
1
+ import { insert as i, createComponent as o, effect as h, className as x, Portal as W, setStyleProperty as _, template as l, use as B, delegateEvents as z } from "solid-js/web";
2
+ import { createSignal as k, createEffect as A, onCleanup as N, Show as p, For as F } from "solid-js";
3
+ import { cn as f } from "../../utils/cn.js";
4
+ import { useDeck as I } from "../../context/DeckContext.js";
5
+ import { useResolvedFloeConfig as T } from "../../context/FloeConfigContext.js";
6
+ import { useLayout as K } from "../../context/LayoutContext.js";
7
+ import { useWidgetRegistry as j } from "../../context/WidgetRegistry.js";
8
+ import { deferNonBlocking as C } from "../../utils/defer.js";
9
+ import { LayoutSelector as q } from "./LayoutSelector.js";
10
+ import { Plus as G, ChevronDown as H, Copy as J } from "../icons/index.js";
11
+ var O = /* @__PURE__ */ l("<button><span>Add"), Q = /* @__PURE__ */ l('<div class="fixed inset-0 z-[9998]">'), U = /* @__PURE__ */ l('<div class="px-3 py-4 text-xs text-muted-foreground text-center">No widgets available'), V = /* @__PURE__ */ l("<div><div class=p-1>"), X = /* @__PURE__ */ l('<button title="Duplicate &amp; edit"><span>Duplicate &amp; Edit'), Y = /* @__PURE__ */ l('<div><div class="w-px h-3.5 bg-border/40"></div><div class=flex-1>'), Z = /* @__PURE__ */ l('<button class="w-full flex items-center gap-2 px-3 py-2 rounded hover:bg-muted transition-colors text-left cursor-pointer"><span class=text-xs>'), ee = /* @__PURE__ */ l('<div class="w-4 h-4">');
12
+ function ue($) {
13
+ const P = T(), c = I();
14
+ K();
15
+ const b = j(), [m, g] = k(!1), [w, D] = k({
14
16
  top: 0,
15
17
  left: 0
16
18
  });
17
- let x;
18
- const S = () => E.isMobile(), b = () => (D.config.deck.presetsMode ?? "mutable") === "immutable" && !!s.activeLayout()?.isPreset, R = (r, i) => {
19
- r.stopPropagation(), r.preventDefault(), m(!1), P(() => s.addWidget(i));
20
- }, W = (r) => {
21
- if (r.stopPropagation(), r.preventDefault(), !v() && x) {
22
- const i = x.getBoundingClientRect();
23
- L({
24
- top: i.bottom + 4,
25
- left: i.left
19
+ let v;
20
+ const y = () => (P.config.deck.presetsMode ?? "mutable") === "immutable" && !!c.activeLayout()?.isPreset, E = (r, n) => {
21
+ r.stopPropagation(), r.preventDefault(), g(!1), C(() => c.addWidget(n));
22
+ }, L = (r) => {
23
+ if (r.stopPropagation(), r.preventDefault(), !m() && v) {
24
+ const n = v.getBoundingClientRect();
25
+ D({
26
+ top: n.bottom + 4,
27
+ left: n.left
26
28
  });
27
29
  }
28
- m((i) => !i);
29
- }, B = () => {
30
- m(!1);
30
+ g((n) => !n);
31
+ }, M = () => {
32
+ g(!1);
31
33
  };
32
- return M(() => {
33
- s.editMode() || m(!1);
34
- }), M(() => {
35
- if (!v() || typeof document > "u") return;
36
- const r = (i) => {
37
- i.key === "Escape" && m(!1);
34
+ return A(() => {
35
+ if (!m() || typeof document > "u") return;
36
+ const r = (n) => {
37
+ n.key === "Escape" && g(!1);
38
38
  };
39
- document.addEventListener("keydown", r), T(() => document.removeEventListener("keydown", r));
39
+ document.addEventListener("keydown", r), N(() => document.removeEventListener("keydown", r));
40
40
  }), (() => {
41
- var r = ie(), i = r.firstChild, z = i.nextSibling;
42
- return n(r, o(J, {}), i), n(r, o(d, {
41
+ var r = Y(), n = r.firstChild, S = n.nextSibling;
42
+ return i(r, o(q, {}), n), i(r, o(p, {
43
43
  get when() {
44
- return k(() => !!s.editMode())() && !b();
44
+ return !y();
45
45
  },
46
46
  get children() {
47
47
  return [(() => {
48
- var e = Y(), c = e.firstChild;
49
- e.$$click = W;
50
- var t = x;
51
- return typeof t == "function" ? F(t, e) : x = e, n(e, o(O, {
48
+ var e = O(), s = e.firstChild;
49
+ e.$$click = L;
50
+ var t = v;
51
+ return typeof t == "function" ? B(t, e) : v = e, i(e, o(G, {
52
52
  class: "w-2.5 h-2.5"
53
- }), c), n(e, o(Q, {
53
+ }), s), i(e, o(H, {
54
54
  get class() {
55
- return p("w-2.5 h-2.5 opacity-50 transition-transform", v() && "rotate-180");
55
+ return f("w-2.5 h-2.5 opacity-50 transition-transform", m() && "rotate-180");
56
56
  }
57
- }), null), g(() => h(e, p("flex items-center gap-1 px-1.5 h-5 rounded text-[10px]", "text-muted-foreground/70 hover:text-foreground hover:bg-muted/50", "transition-colors cursor-pointer"))), e;
58
- })(), o(d, {
57
+ }), null), h(() => x(e, f("flex items-center gap-1 px-1.5 h-5 rounded text-[10px]", "text-muted-foreground/70 hover:text-foreground hover:bg-muted/50", "transition-colors cursor-pointer"))), e;
58
+ })(), o(p, {
59
59
  get when() {
60
- return v();
60
+ return m();
61
61
  },
62
62
  get children() {
63
- return o(N, {
63
+ return o(W, {
64
64
  get children() {
65
65
  return [(() => {
66
- var e = Z();
67
- return e.$$click = B, e;
66
+ var e = Q();
67
+ return e.$$click = M, e;
68
68
  })(), (() => {
69
- var e = te(), c = e.firstChild;
70
- return n(c, o(K, {
69
+ var e = V(), s = e.firstChild;
70
+ return i(s, o(F, {
71
71
  get each() {
72
- return Array.from(w.widgets().values());
72
+ return Array.from(b.widgets().values());
73
73
  },
74
74
  children: (t) => (() => {
75
- var a = le(), f = a.firstChild;
76
- return a.$$click = (u) => R(u, t.type), n(a, o(d, {
75
+ var a = Z(), u = a.firstChild;
76
+ return a.$$click = (d) => E(d, t.type), i(a, o(p, {
77
77
  get when() {
78
78
  return t.icon;
79
79
  },
80
80
  get fallback() {
81
- return se();
81
+ return ee();
82
82
  },
83
- children: (u) => {
84
- const A = u();
85
- return o(A, {
83
+ children: (d) => {
84
+ const R = d();
85
+ return o(R, {
86
86
  class: "w-4 h-4 text-muted-foreground"
87
87
  });
88
88
  }
89
- }), f), n(f, () => t.name), a;
89
+ }), u), i(u, () => t.name), a;
90
90
  })()
91
- }), null), n(c, o(d, {
91
+ }), null), i(s, o(p, {
92
92
  get when() {
93
- return w.widgets().size === 0;
93
+ return b.widgets().size === 0;
94
94
  },
95
95
  get children() {
96
- return ee();
96
+ return U();
97
97
  }
98
- }), null), g((t) => {
99
- var a = p("fixed z-[9999]", "min-w-[180px] max-h-[300px] overflow-y-auto", "bg-popover border border-border rounded-md shadow-xl", "animate-in fade-in slide-in-from-top-1 duration-150"), f = `${y().top}px`, u = `${Math.max(8, y().left)}px`;
100
- return a !== t.e && h(e, t.e = a), f !== t.t && _(e, "top", t.t = f), u !== t.a && _(e, "left", t.a = u), t;
98
+ }), null), h((t) => {
99
+ var a = f("fixed z-[9999]", "min-w-[180px] max-h-[300px] overflow-y-auto", "bg-popover border border-border rounded-md shadow-xl", "animate-in fade-in slide-in-from-top-1 duration-150"), u = `${w().top}px`, d = `${Math.max(8, w().left)}px`;
100
+ return a !== t.e && x(e, t.e = a), u !== t.t && _(e, "top", t.t = u), d !== t.a && _(e, "left", t.a = d), t;
101
101
  }, {
102
102
  e: void 0,
103
103
  t: void 0,
@@ -109,47 +109,25 @@ function be($) {
109
109
  }
110
110
  })];
111
111
  }
112
- }), z), n(r, o(d, {
112
+ }), S), i(r, o(p, {
113
113
  get when() {
114
- return b();
114
+ return y();
115
115
  },
116
116
  get children() {
117
- var e = re(), c = e.firstChild;
117
+ var e = X(), s = e.firstChild;
118
118
  return e.$$click = () => {
119
- const t = s.activeLayout();
120
- t && P(() => {
121
- s.duplicateLayout(t.id, `${t.name} (Copy)`), s.setEditMode(!0);
119
+ const t = c.activeLayout();
120
+ t && C(() => {
121
+ c.duplicateLayout(t.id, `${t.name} (Copy)`), c.setEditMode(!0);
122
122
  });
123
- }, n(e, o(U, {
123
+ }, i(e, o(J, {
124
124
  class: "w-2.5 h-2.5"
125
- }), c), g(() => h(e, p("flex items-center gap-1 px-1.5 h-5 rounded text-[10px]", "text-muted-foreground/70 hover:text-foreground hover:bg-muted/50", "transition-colors cursor-pointer"))), e;
125
+ }), s), h(() => x(e, f("flex items-center gap-1 px-1.5 h-5 rounded text-[10px]", "text-muted-foreground/70 hover:text-foreground hover:bg-muted/50", "transition-colors cursor-pointer"))), e;
126
126
  }
127
- }), null), n(r, o(d, {
128
- get when() {
129
- return k(() => !S())() && !b();
130
- },
131
- get children() {
132
- var e = ne();
133
- return e.$$click = () => s.toggleEditMode(), n(e, o(d, {
134
- get when() {
135
- return s.editMode();
136
- },
137
- get fallback() {
138
- return [o(X, {
139
- class: "w-2.5 h-2.5"
140
- }), ae()];
141
- },
142
- get children() {
143
- return [o(V, {
144
- class: "w-2.5 h-2.5"
145
- }), oe()];
146
- }
147
- })), g(() => h(e, p("flex items-center gap-1 px-1.5 h-5 rounded text-[10px] transition-colors cursor-pointer", s.editMode() ? "bg-primary text-primary-foreground hover:bg-primary/90" : "text-muted-foreground/70 hover:text-foreground hover:bg-muted/50"))), e;
148
- }
149
- }), null), n(r, () => $.actions, null), g(() => h(r, p("deck-topbar flex items-center gap-1.5 h-7 px-2", "bg-gradient-to-b from-background to-background/95", "border-b border-border/30", $.class))), r;
127
+ }), null), i(r, () => $.actions, null), h(() => x(r, f("deck-topbar flex items-center gap-1.5 h-7 px-2", "bg-gradient-to-b from-background to-background/95", "border-b border-border/30", $.class))), r;
150
128
  })();
151
129
  }
152
- I(["click"]);
130
+ z(["click"]);
153
131
  export {
154
- be as DeckTopBar
132
+ ue as DeckTopBar
155
133
  };
@@ -9,6 +9,12 @@ export interface WidgetFrameProps {
9
9
  children: JSX.Element;
10
10
  }
11
11
  /**
12
- * Widget chrome with header, drag handle, and resize handles
12
+ * Widget chrome with header drag-handle and resize handles.
13
+ *
14
+ * The header is a persistent, always-on drag handle (notes-style): the grip
15
+ * icon + title region carries `data-widget-drag-handle`, so dragging the
16
+ * header moves the widget while the widget body stays fully interactive.
17
+ * The widget body never blocks pointer events — autosave on every commit
18
+ * means there's no "edit / done" toggle to gate interactions with.
13
19
  */
14
20
  export declare function WidgetFrame(props: WidgetFrameProps): JSX.Element;
@@ -1,109 +1,117 @@
1
- import { insert as r, createComponent as e, effect as h, className as v, template as c, delegateEvents as x } from "solid-js/web";
1
+ import { insert as i, createComponent as r, effect as x, className as b, setAttribute as $, template as a, delegateEvents as y } from "solid-js/web";
2
2
  import { Show as l } from "solid-js";
3
- import { cn as $ } from "../../utils/cn.js";
4
- import { useDeck as _ } from "../../context/DeckContext.js";
5
- import { GripVertical as b, X as k } from "../icons/index.js";
6
- import { WidgetResizeHandle as i } from "./WidgetResizeHandle.js";
7
- import { WidgetTypeSwitcher as C } from "./WidgetTypeSwitcher.js";
8
- var D = /* @__PURE__ */ c("<div class=text-muted-foreground/50>"), W = /* @__PURE__ */ c('<button class="p-0.5 rounded hover:bg-destructive/10 text-muted-foreground hover:text-destructive transition-colors cursor-pointer pointer-events-auto"title="Remove widget">'), y = /* @__PURE__ */ c('<div class="h-full flex flex-col"><div><span class="flex-1 text-xs font-medium text-foreground truncate"></span></div><div class="flex-1 min-h-0 overflow-auto">');
9
- function H(t) {
10
- const w = _(), o = () => w.editMode(), m = () => t.widget.title ?? t.widgetDef?.name ?? t.widget.type, a = (g) => {
11
- g.stopPropagation(), g.preventDefault(), w.removeWidget(t.widget.id);
3
+ import { cn as _ } from "../../utils/cn.js";
4
+ import { useDeck as D } from "../../context/DeckContext.js";
5
+ import { useLayout as k } from "../../context/LayoutContext.js";
6
+ import { GripVertical as C, X as W } from "../icons/index.js";
7
+ import { WidgetResizeHandle as d } from "./WidgetResizeHandle.js";
8
+ import { WidgetTypeSwitcher as R } from "./WidgetTypeSwitcher.js";
9
+ var S = /* @__PURE__ */ a('<div class="text-muted-foreground/50 pointer-events-none">'), z = /* @__PURE__ */ a('<div class="opacity-0 group-hover:opacity-100 transition-opacity">'), A = /* @__PURE__ */ a('<button class="opacity-0 group-hover:opacity-100 p-0.5 rounded hover:bg-destructive/10 text-muted-foreground hover:text-destructive transition-all cursor-pointer"title="Remove widget">'), E = /* @__PURE__ */ a('<div class="h-full flex flex-col"><div><span class="flex-1 text-xs font-medium text-foreground truncate"></span></div><div class="flex-1 min-h-0 overflow-auto">');
10
+ function T(e) {
11
+ const m = D(), s = k(), v = () => e.widget.title ?? e.widgetDef?.name ?? e.widget.type, g = () => !s.isMobile(), f = (o) => {
12
+ o.stopPropagation(), o.preventDefault(), m.removeWidget(e.widget.id);
12
13
  };
13
14
  return (() => {
14
- var g = y(), d = g.firstChild, u = d.firstChild, s = d.nextSibling;
15
- return r(d, e(l, {
15
+ var o = E(), n = o.firstChild, c = n.firstChild, h = n.nextSibling;
16
+ return i(n, r(l, {
16
17
  get when() {
17
- return o();
18
+ return g();
18
19
  },
19
20
  get children() {
20
- var n = D();
21
- return r(n, e(b, {
21
+ var t = S();
22
+ return i(t, r(C, {
22
23
  class: "w-3.5 h-3.5"
23
- })), n;
24
+ })), t;
24
25
  }
25
- }), u), r(d, e(l, {
26
+ }), c), i(n, r(l, {
26
27
  get when() {
27
- return t.widgetDef?.icon;
28
+ return e.widgetDef?.icon;
28
29
  },
29
- children: (n) => {
30
- const f = n();
31
- return e(f, {
30
+ children: (t) => {
31
+ const u = t();
32
+ return r(u, {
32
33
  class: "w-3.5 h-3.5 text-muted-foreground"
33
34
  });
34
35
  }
35
- }), u), r(u, m), r(d, e(l, {
36
+ }), c), i(c, v), i(n, r(l, {
36
37
  get when() {
37
- return o();
38
+ return g();
38
39
  },
39
40
  get children() {
40
- return e(C, {
41
+ var t = z();
42
+ return i(t, r(R, {
41
43
  get widget() {
42
- return t.widget;
44
+ return e.widget;
43
45
  }
44
- });
46
+ })), t;
45
47
  }
46
- }), null), r(d, e(l, {
48
+ }), null), i(n, r(l, {
47
49
  get when() {
48
- return o();
50
+ return g();
49
51
  },
50
52
  get children() {
51
- var n = W();
52
- return n.$$click = a, r(n, e(k, {
53
+ var t = A();
54
+ return t.$$click = f, i(t, r(W, {
53
55
  class: "w-3.5 h-3.5"
54
- })), n;
56
+ })), t;
55
57
  }
56
- }), null), r(s, () => t.children), r(g, e(l, {
58
+ }), null), i(h, () => e.children), i(o, r(l, {
57
59
  get when() {
58
- return o();
60
+ return g();
59
61
  },
60
62
  get children() {
61
- return [e(i, {
63
+ return [r(d, {
62
64
  get widget() {
63
- return t.widget;
65
+ return e.widget;
64
66
  },
65
67
  edge: "e"
66
- }), e(i, {
68
+ }), r(d, {
67
69
  get widget() {
68
- return t.widget;
70
+ return e.widget;
69
71
  },
70
72
  edge: "s"
71
- }), e(i, {
73
+ }), r(d, {
72
74
  get widget() {
73
- return t.widget;
75
+ return e.widget;
74
76
  },
75
77
  edge: "se"
76
- }), e(i, {
78
+ }), r(d, {
77
79
  get widget() {
78
- return t.widget;
80
+ return e.widget;
79
81
  },
80
82
  edge: "w"
81
- }), e(i, {
83
+ }), r(d, {
82
84
  get widget() {
83
- return t.widget;
85
+ return e.widget;
84
86
  },
85
87
  edge: "n"
86
- }), e(i, {
88
+ }), r(d, {
87
89
  get widget() {
88
- return t.widget;
90
+ return e.widget;
89
91
  },
90
92
  edge: "sw"
91
- }), e(i, {
93
+ }), r(d, {
92
94
  get widget() {
93
- return t.widget;
95
+ return e.widget;
94
96
  },
95
97
  edge: "ne"
96
- }), e(i, {
98
+ }), r(d, {
97
99
  get widget() {
98
- return t.widget;
100
+ return e.widget;
99
101
  },
100
102
  edge: "nw"
101
103
  })];
102
104
  }
103
- }), null), h(() => v(d, $("widget-header flex items-center gap-1 px-2 py-1.5 border-b border-border bg-muted/30", "select-none"))), g;
105
+ }), null), x((t) => {
106
+ var u = _("widget-header flex items-center gap-1 px-2 py-1.5 border-b border-border bg-muted/30", "select-none", g() && !e.isDragging && "cursor-move", e.isDragging && "cursor-grabbing"), w = g() ? e.widget.id : void 0;
107
+ return u !== t.e && b(n, t.e = u), w !== t.t && $(n, "data-widget-drag-handle", t.t = w), t;
108
+ }, {
109
+ e: void 0,
110
+ t: void 0
111
+ }), o;
104
112
  })();
105
113
  }
106
- x(["click"]);
114
+ y(["click"]);
107
115
  export {
108
- H as WidgetFrame
116
+ T as WidgetFrame
109
117
  };
@@ -7,3 +7,4 @@ export { WidgetTypeSwitcher, type WidgetTypeSwitcherProps } from './WidgetTypeSw
7
7
  export { LayoutSelector, type LayoutSelectorProps } from './LayoutSelector';
8
8
  export { DeckTopBar, type DeckTopBarProps } from './DeckTopBar';
9
9
  export { DropZonePreview, type DropZonePreviewProps } from './DropZonePreview';
10
+ export { DeckContextMenu, type DeckContextMenuItem, type DeckContextMenuProps, } from './DeckContextMenu';
@@ -25,5 +25,7 @@ export interface InfiniteCanvasProps {
25
25
  minScale?: number;
26
26
  maxScale?: number;
27
27
  wheelZoomSpeed?: number;
28
+ /** When true, wheel zoom and pan are suppressed. Widgets inside remain interactive. */
29
+ disablePanZoom?: boolean;
28
30
  }
29
31
  export declare function InfiniteCanvas(props: InfiniteCanvasProps): JSX.Element;
@@ -1,14 +1,14 @@
1
- import { insert as q, effect as G, className as I, setAttribute as J, setStyleProperty as K, template as Q, use as ee, delegateEvents as te } from "solid-js/web";
2
- import { createSignal as T, untrack as D, createEffect as L, onCleanup as y } from "solid-js";
1
+ import { insert as q, effect as G, className as T, setAttribute as J, setStyleProperty as K, template as Q, use as ee, delegateEvents as te } from "solid-js/web";
2
+ import { createSignal as D, untrack as L, createEffect as b, onCleanup as y } from "solid-js";
3
3
  import { cn as Y } from "../../utils/cn.js";
4
4
  import { isTypingElement as _ } from "../../utils/dom.js";
5
- import { startHotInteraction as b } from "../../utils/hotInteraction.js";
5
+ import { startHotInteraction as A } from "../../utils/hotInteraction.js";
6
6
  var ne = /* @__PURE__ */ Q('<div><div style="transform-origin:0 0">');
7
- const re = 1, ie = 0.45, oe = 2.2, ae = 14e-4, ce = '[data-floe-canvas-pan-surface="true"]', A = 3;
7
+ const re = 1, ie = 0.45, oe = 2.2, ae = 14e-4, ce = '[data-floe-canvas-pan-surface="true"]', M = 3;
8
8
  function le(n, a, d) {
9
9
  return Math.max(a, Math.min(d, n));
10
10
  }
11
- function M(n) {
11
+ function X(n) {
12
12
  return {
13
13
  x: Number.isFinite(n.x) ? n.x : 0,
14
14
  y: Number.isFinite(n.y) ? n.y : 0,
@@ -19,16 +19,16 @@ function se(n, a) {
19
19
  return n.deltaMode === 1 ? n.deltaY * 16 : n.deltaMode === 2 ? n.deltaY * (a?.clientHeight ?? window.innerHeight) : n.deltaY;
20
20
  }
21
21
  function we(n) {
22
- const [a, d] = T(D(() => M(n.viewport))), [p, S] = T(null);
22
+ const [a, d] = D(L(() => X(n.viewport))), [p, S] = D(null);
23
23
  let o, f, m = !1, l;
24
- const X = () => n.interactiveSelector ?? '[data-floe-canvas-interactive="true"]', F = () => n.panSurfaceSelector ?? ce, $ = () => n.minScale ?? ie, k = () => n.maxScale ?? oe, V = () => n.wheelZoomSpeed ?? ae, R = () => {
24
+ const F = () => n.interactiveSelector ?? '[data-floe-canvas-interactive="true"]', k = () => n.panSurfaceSelector ?? ce, $ = () => n.minScale ?? ie, V = () => n.maxScale ?? oe, R = () => n.wheelZoomSpeed ?? ae, N = () => {
25
25
  const e = p();
26
26
  return e ? e.startedFromPanSurface ? e.moved : !0 : !1;
27
- }, C = () => {
28
- f !== void 0 && (window.clearTimeout(f), f = void 0);
29
27
  }, v = () => {
28
+ f !== void 0 && (window.clearTimeout(f), f = void 0);
29
+ }, C = () => {
30
30
  m = !1, l !== void 0 && (window.clearTimeout(l), l = void 0);
31
- }, N = () => {
31
+ }, U = () => {
32
32
  if (typeof window > "u") {
33
33
  m = !1;
34
34
  return;
@@ -37,47 +37,49 @@ function we(n) {
37
37
  l = void 0, m = !1;
38
38
  }, 0);
39
39
  }, h = (e) => {
40
- D(() => n.onViewportChange?.(e));
41
- }, U = (e) => {
40
+ L(() => n.onViewportChange?.(e));
41
+ }, H = (e) => {
42
42
  if (typeof window > "u") {
43
43
  h(e);
44
44
  return;
45
45
  }
46
- C(), f = window.setTimeout(() => {
46
+ v(), f = window.setTimeout(() => {
47
47
  f = void 0, h(e);
48
48
  }, 90);
49
- }, E = (e) => e instanceof Element ? e.closest(X()) ? !0 : _(e) : !1, x = (e) => e instanceof Element ? e.closest(F()) !== null : !1, g = (e) => {
49
+ }, E = (e) => e instanceof Element ? e.closest(F()) ? !0 : _(e) : !1, P = (e) => e instanceof Element ? e.closest(k()) !== null : !1, g = (e) => {
50
50
  const t = p();
51
51
  if (!t || e !== void 0 && t.pointerId !== e) return;
52
52
  t.stopInteraction?.();
53
53
  const r = a();
54
- S(null), o && o.hasPointerCapture(t.pointerId) && o.releasePointerCapture(t.pointerId), t.startedFromPanSurface && t.moved && (m = !0, N()), h(r);
54
+ S(null), o && o.hasPointerCapture(t.pointerId) && o.releasePointerCapture(t.pointerId), t.startedFromPanSurface && t.moved && (m = !0, U()), h(r);
55
55
  };
56
- L(() => {
57
- p() || d(M(n.viewport));
58
- }), L(() => {
56
+ b(() => {
57
+ p() || d(X(n.viewport));
58
+ }), b(() => {
59
59
  const e = o;
60
60
  if (!e) return;
61
61
  const t = (r) => {
62
- !m || !x(r.target) || (v(), r.preventDefault(), r.stopPropagation());
62
+ !m || !P(r.target) || (C(), r.preventDefault(), r.stopPropagation());
63
63
  };
64
- e.addEventListener("click", t, !0), y(() => {
65
- e.removeEventListener("click", t, !0);
64
+ e.addEventListener("click", t, !0), e.addEventListener("wheel", x, {
65
+ passive: !1
66
+ }), y(() => {
67
+ e.removeEventListener("click", t, !0), e.removeEventListener("wheel", x);
66
68
  });
67
69
  }), y(() => {
68
- C(), g(), v();
70
+ v(), g(), C();
69
71
  });
70
- const H = (e) => {
71
- if (e.button !== 0 || _(e.target)) return;
72
- const t = x(e.target);
73
- E(e.target) && !t || (C(), v(), t || (e.preventDefault(), o?.setPointerCapture(e.pointerId)), S({
72
+ const Z = (e) => {
73
+ if (e.button !== 0 || _(e.target) || n.disablePanZoom) return;
74
+ const t = P(e.target);
75
+ E(e.target) && !t || (v(), C(), t || (e.preventDefault(), o?.setPointerCapture(e.pointerId)), S({
74
76
  pointerId: e.pointerId,
75
77
  startClientX: e.clientX,
76
78
  startClientY: e.clientY,
77
79
  startViewport: a(),
78
80
  moved: !1,
79
81
  startedFromPanSurface: t,
80
- stopInteraction: t ? void 0 : b({
82
+ stopInteraction: t ? void 0 : A({
81
83
  kind: "drag",
82
84
  cursor: "grabbing"
83
85
  })
@@ -86,7 +88,7 @@ function we(n) {
86
88
  const t = p();
87
89
  if (!t || t.pointerId !== e.pointerId) return;
88
90
  const r = e.clientX - t.startClientX, i = e.clientY - t.startClientY;
89
- if (!(t.moved || Math.abs(r) > A || Math.abs(i) > A)) return;
91
+ if (!(t.moved || Math.abs(r) > M || Math.abs(i) > M)) return;
90
92
  t.moved || (e.preventDefault(), o?.hasPointerCapture(e.pointerId) || o?.setPointerCapture(e.pointerId));
91
93
  const u = {
92
94
  ...t.startViewport,
@@ -96,27 +98,31 @@ function we(n) {
96
98
  t.moved || S({
97
99
  ...t,
98
100
  moved: !0,
99
- stopInteraction: t.stopInteraction ?? b({
101
+ stopInteraction: t.stopInteraction ?? A({
100
102
  kind: "drag",
101
103
  cursor: "grabbing"
102
104
  })
103
105
  }), d(u);
104
106
  }, W = (e) => {
105
107
  g(e.pointerId);
106
- }, Z = (e) => {
107
- g(e.pointerId);
108
108
  }, B = (e) => {
109
+ g(e.pointerId);
110
+ }, x = (e) => {
109
111
  const t = o?.getBoundingClientRect();
110
112
  if (!t) return;
113
+ if (n.disablePanZoom) {
114
+ e.preventDefault();
115
+ return;
116
+ }
111
117
  e.preventDefault();
112
- const r = a(), i = e.clientX - t.left, c = e.clientY - t.top, u = se(e, o), s = le(r.scale * Math.exp(-u * V()), $(), k());
118
+ const r = a(), i = e.clientX - t.left, c = e.clientY - t.top, u = se(e, o), s = le(r.scale * Math.exp(-u * R()), $(), V());
113
119
  if (Math.abs(s - r.scale) < 1e-4) return;
114
- const w = (i - r.x) / r.scale, j = (c - r.y) / r.scale, P = {
120
+ const w = (i - r.x) / r.scale, j = (c - r.y) / r.scale, I = {
115
121
  x: i - w * s,
116
122
  y: c - j * s,
117
123
  scale: s
118
124
  };
119
- d(P), U(P);
125
+ d(I), H(I);
120
126
  }, z = (e) => {
121
127
  if (E(e.target)) return;
122
128
  const t = o?.getBoundingClientRect();
@@ -134,11 +140,11 @@ function we(n) {
134
140
  };
135
141
  return (() => {
136
142
  var e = ne(), t = e.firstChild;
137
- e.$$contextmenu = z, e.addEventListener("wheel", B), e.addEventListener("pointercancel", Z), e.$$pointerup = W, e.$$pointermove = O, e.$$pointerdown = H;
143
+ e.$$contextmenu = z, e.addEventListener("pointercancel", B), e.$$pointerup = W, e.$$pointermove = O, e.$$pointerdown = Z;
138
144
  var r = o;
139
145
  return typeof r == "function" ? ee(r, e) : o = e, q(t, () => n.children), G((i) => {
140
- var c = Y("floe-infinite-canvas", R() && "is-panning", n.class), u = n.ariaLabel ?? "Infinite canvas", s = Y("floe-infinite-canvas__viewport", n.contentClass), w = `translate(${a().x}px, ${a().y}px) scale(${a().scale})`;
141
- return c !== i.e && I(e, i.e = c), u !== i.t && J(e, "aria-label", i.t = u), s !== i.a && I(t, i.a = s), w !== i.o && K(t, "transform", i.o = w), i;
146
+ var c = Y("floe-infinite-canvas", N() && "is-panning", n.disablePanZoom && "is-locked", n.class), u = n.ariaLabel ?? "Infinite canvas", s = Y("floe-infinite-canvas__viewport", n.contentClass), w = `translate(${a().x}px, ${a().y}px) scale(${a().scale})`;
147
+ return c !== i.e && T(e, i.e = c), u !== i.t && J(e, "aria-label", i.t = u), s !== i.a && T(t, i.a = s), w !== i.o && K(t, "transform", i.o = w), i;
142
148
  }, {
143
149
  e: void 0,
144
150
  t: void 0,
@@ -0,0 +1,28 @@
1
+ import { type InfiniteCanvasContextMenuEvent } from '../../ui';
2
+ import type { WorkbenchViewport, WorkbenchWidgetItem, WorkbenchWidgetType } from './types';
3
+ export interface WorkbenchCanvasProps {
4
+ widgets: readonly WorkbenchWidgetItem[];
5
+ viewport: WorkbenchViewport;
6
+ selectedWidgetId: string | null;
7
+ optimisticFrontWidgetId: string | null;
8
+ topZIndex: number;
9
+ locked: boolean;
10
+ filters: Record<WorkbenchWidgetType, boolean>;
11
+ setCanvasFrameRef: (el: HTMLDivElement | undefined) => void;
12
+ onViewportCommit: (viewport: WorkbenchViewport) => void;
13
+ onCanvasContextMenu: (event: InfiniteCanvasContextMenuEvent) => void;
14
+ onSelectWidget: (widgetId: string) => void;
15
+ onWidgetContextMenu: (event: MouseEvent, item: WorkbenchWidgetItem) => void;
16
+ onStartOptimisticFront: (widgetId: string) => void;
17
+ onCommitFront: (widgetId: string) => void;
18
+ onCommitMove: (widgetId: string, position: {
19
+ x: number;
20
+ y: number;
21
+ }) => void;
22
+ onCommitResize: (widgetId: string, size: {
23
+ width: number;
24
+ height: number;
25
+ }) => void;
26
+ onRequestDelete: (widgetId: string) => void;
27
+ }
28
+ export declare function WorkbenchCanvas(props: WorkbenchCanvasProps): import("solid-js").JSX.Element;