@bian-womp/spark-workbench 0.1.23 → 0.1.25

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 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 ids) {
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 = ids.length;
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 for keyboard accessibility
1800
+ // Focus search input when menu opens
1801
+ const inputRef = React.useRef(null);
1796
1802
  React.useEffect(() => {
1797
- if (open)
1798
- ref.current?.focus();
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
- !!child.__self && !hasChildren;
1820
- 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: child.__self.split(".").slice(-1)[0] })), hasChildren && (jsxRuntime.jsx("div", { className: "pl-2 border-l border-gray-200 ml-2", children: renderTree(child, [...path, key]) }))] }, [...path, key].join(".")));
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, }) {