@bian-womp/spark-workbench 0.1.24 → 0.1.26
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/lib/cjs/index.cjs +34 -16
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/cjs/src/misc/DefaultContextMenu.d.ts.map +1 -1
- package/lib/cjs/src/misc/WorkbenchStudio.d.ts.map +1 -1
- package/lib/esm/index.js +34 -16
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/src/misc/DefaultContextMenu.d.ts.map +1 -1
- package/lib/esm/src/misc/WorkbenchStudio.d.ts.map +1 -1
- package/package.json +4 -4
package/lib/cjs/index.cjs
CHANGED
|
@@ -1756,8 +1756,13 @@ function DefaultContextMenu({ open, clientPos, onAdd, onClose, }) {
|
|
|
1756
1756
|
const { registry } = useWorkbenchContext();
|
|
1757
1757
|
const rf = ReactFlow.useReactFlow();
|
|
1758
1758
|
const ids = Array.from(registry.nodes.keys());
|
|
1759
|
+
const [query, setQuery] = React.useState("");
|
|
1760
|
+
const q = query.trim().toLowerCase();
|
|
1761
|
+
const filteredIds = q
|
|
1762
|
+
? ids.filter((id) => id.toLowerCase().includes(q))
|
|
1763
|
+
: ids;
|
|
1759
1764
|
const root = { __children: {} };
|
|
1760
|
-
for (const id of
|
|
1765
|
+
for (const id of filteredIds) {
|
|
1761
1766
|
const parts = id.split(".");
|
|
1762
1767
|
let node = root;
|
|
1763
1768
|
for (let i = 0; i < parts.length; i++) {
|
|
@@ -1768,7 +1773,7 @@ function DefaultContextMenu({ open, clientPos, onAdd, onClose, }) {
|
|
|
1768
1773
|
node.__self = id;
|
|
1769
1774
|
}
|
|
1770
1775
|
}
|
|
1771
|
-
const totalCount =
|
|
1776
|
+
const totalCount = filteredIds.length;
|
|
1772
1777
|
// Ref for focus/outside click handling
|
|
1773
1778
|
const ref = React.useRef(null);
|
|
1774
1779
|
// Close on outside click and on ESC
|
|
@@ -1792,10 +1797,12 @@ function DefaultContextMenu({ open, clientPos, onAdd, onClose, }) {
|
|
|
1792
1797
|
window.removeEventListener("keydown", onKey);
|
|
1793
1798
|
};
|
|
1794
1799
|
}, [open, onClose]);
|
|
1795
|
-
// Focus
|
|
1800
|
+
// Focus search input when menu opens
|
|
1801
|
+
const inputRef = React.useRef(null);
|
|
1796
1802
|
React.useEffect(() => {
|
|
1797
|
-
if (open)
|
|
1798
|
-
|
|
1803
|
+
if (open) {
|
|
1804
|
+
setTimeout(() => inputRef.current?.focus(), 0);
|
|
1805
|
+
}
|
|
1799
1806
|
}, [open]);
|
|
1800
1807
|
if (!open || !clientPos)
|
|
1801
1808
|
return null;
|
|
@@ -1816,14 +1823,19 @@ function DefaultContextMenu({ open, clientPos, onAdd, onClose, }) {
|
|
|
1816
1823
|
return (jsxRuntime.jsx("div", { children: entries.map(([key, child]) => {
|
|
1817
1824
|
const label = key;
|
|
1818
1825
|
const hasChildren = Object.keys(child.__children).length > 0;
|
|
1819
|
-
|
|
1820
|
-
|
|
1826
|
+
const idKey = [...path, key].join(".");
|
|
1827
|
+
if (!hasChildren) {
|
|
1828
|
+
// Leaf: render only the action button, no group header
|
|
1829
|
+
return child.__self ? (jsxRuntime.jsx("button", { onClick: () => handleClick(child.__self), className: "block w-full text-left px-3 py-1 hover:bg-gray-100 cursor-pointer", title: child.__self, children: label }, idKey)) : null;
|
|
1830
|
+
}
|
|
1831
|
+
// Group: show label, optional action for id at this level, and children
|
|
1832
|
+
return (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("div", { className: "px-2 py-1 text-[11px] uppercase tracking-wide text-gray-400", children: label }), child.__self && (jsxRuntime.jsx("button", { onClick: () => handleClick(child.__self), className: "block w-full text-left px-3 py-1 hover:bg-gray-100 cursor-pointer", title: child.__self, children: label })), jsxRuntime.jsx("div", { className: "pl-2 border-l border-gray-200 ml-2", children: renderTree(child, [...path, key]) })] }, idKey));
|
|
1821
1833
|
}) }));
|
|
1822
1834
|
};
|
|
1823
1835
|
return (jsxRuntime.jsxs("div", { ref: ref, tabIndex: -1, className: "fixed z-[1000] bg-white border border-gray-300 rounded-none shadow-lg p-1 min-w-[180px] text-sm text-gray-700", style: { left: x, top: y }, onClick: (e) => e.stopPropagation(), onMouseDown: (e) => e.stopPropagation(), onWheel: (e) => e.stopPropagation(), onContextMenu: (e) => {
|
|
1824
1836
|
e.preventDefault();
|
|
1825
1837
|
e.stopPropagation();
|
|
1826
|
-
}, children: [jsxRuntime.jsxs("div", { className: "px-2 py-1 font-semibold text-gray-700", children: ["Add Node ", jsxRuntime.jsxs("span", { className: "text-gray-500 font-normal", children: ["(", totalCount, ")"] })] }), jsxRuntime.jsx("div", { className: "max-h-60 overflow-auto", children: renderTree(root) })] }));
|
|
1838
|
+
}, children: [jsxRuntime.jsxs("div", { className: "px-2 py-1 font-semibold text-gray-700", children: ["Add Node", " ", jsxRuntime.jsxs("span", { className: "text-gray-500 font-normal", children: ["(", totalCount, ")"] })] }), jsxRuntime.jsx("div", { className: "px-2 pb-1", children: jsxRuntime.jsx("input", { ref: inputRef, type: "text", value: query, onChange: (e) => setQuery(e.target.value), placeholder: "Filter nodes...", className: "w-full border border-gray-300 px-2 py-1 text-sm outline-none focus:border-gray-400", onClick: (e) => e.stopPropagation(), onMouseDown: (e) => e.stopPropagation(), onWheel: (e) => e.stopPropagation() }) }), jsxRuntime.jsx("div", { className: "max-h-60 overflow-auto", children: totalCount > 0 ? (renderTree(root)) : (jsxRuntime.jsx("div", { className: "px-3 py-2 text-gray-400", children: "No matches" })) })] }));
|
|
1827
1839
|
}
|
|
1828
1840
|
|
|
1829
1841
|
function NodeContextMenu({ open, clientPos, nodeId, onClose, }) {
|
|
@@ -2113,7 +2125,9 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
|
|
|
2113
2125
|
const downloadGraph = React.useCallback(() => {
|
|
2114
2126
|
try {
|
|
2115
2127
|
const def = wb.export();
|
|
2116
|
-
const
|
|
2128
|
+
const inputs = runner.getInputs(def);
|
|
2129
|
+
const payload = { def, inputs };
|
|
2130
|
+
const pretty = JSON.stringify(payload, null, 2);
|
|
2117
2131
|
const blob = new Blob([pretty], { type: "application/json" });
|
|
2118
2132
|
const url = URL.createObjectURL(blob);
|
|
2119
2133
|
const a = document.createElement("a");
|
|
@@ -2130,7 +2144,7 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
|
|
|
2130
2144
|
catch (err) {
|
|
2131
2145
|
alert(String(err?.message ?? err));
|
|
2132
2146
|
}
|
|
2133
|
-
}, [wb]);
|
|
2147
|
+
}, [wb, runner]);
|
|
2134
2148
|
const hydrateFromBackend = React.useCallback(async (kind, base) => {
|
|
2135
2149
|
try {
|
|
2136
2150
|
const transport = kind === "remote-http"
|
|
@@ -2280,20 +2294,24 @@ function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, ex
|
|
|
2280
2294
|
value = Number.isFinite(n) ? n : 0;
|
|
2281
2295
|
break;
|
|
2282
2296
|
}
|
|
2297
|
+
case "base.float[]": {
|
|
2298
|
+
value = parseArray(String(raw), (x) => Number(x));
|
|
2299
|
+
break;
|
|
2300
|
+
}
|
|
2283
2301
|
case "base.bool": {
|
|
2284
2302
|
value = raw === "true" || raw === "1" ? true : false;
|
|
2285
2303
|
break;
|
|
2286
2304
|
}
|
|
2287
|
-
case "base.
|
|
2288
|
-
value = String(raw);
|
|
2305
|
+
case "base.bool[]": {
|
|
2306
|
+
value = parseArray(String(raw), (x) => /^(true|1)$/i.test(x));
|
|
2289
2307
|
break;
|
|
2290
2308
|
}
|
|
2291
|
-
case "base.
|
|
2292
|
-
value =
|
|
2309
|
+
case "base.string": {
|
|
2310
|
+
value = String(raw);
|
|
2293
2311
|
break;
|
|
2294
2312
|
}
|
|
2295
|
-
case "base.
|
|
2296
|
-
value = parseArray(String(raw), (x) =>
|
|
2313
|
+
case "base.string[]": {
|
|
2314
|
+
value = parseArray(String(raw), (x) => String(x));
|
|
2297
2315
|
break;
|
|
2298
2316
|
}
|
|
2299
2317
|
case "base.vec3": {
|