@particle-academy/fancy-flow 0.20.0 → 0.21.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.
package/dist/index.cjs CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  var ReactExports = require('react');
4
4
  var jsxRuntime = require('react/jsx-runtime');
5
- require('react-dom');
5
+ var reactDom = require('react-dom');
6
6
 
7
7
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
8
 
@@ -1388,9 +1388,9 @@ function creator_default(name) {
1388
1388
  // node_modules/d3-selection/src/selector.js
1389
1389
  function none() {
1390
1390
  }
1391
- function selector_default(selector) {
1392
- return selector == null ? none : function() {
1393
- return this.querySelector(selector);
1391
+ function selector_default(selector2) {
1392
+ return selector2 == null ? none : function() {
1393
+ return this.querySelector(selector2);
1394
1394
  };
1395
1395
  }
1396
1396
 
@@ -1417,9 +1417,9 @@ function array(x) {
1417
1417
  function empty() {
1418
1418
  return [];
1419
1419
  }
1420
- function selectorAll_default(selector) {
1421
- return selector == null ? empty : function() {
1422
- return this.querySelectorAll(selector);
1420
+ function selectorAll_default(selector2) {
1421
+ return selector2 == null ? empty : function() {
1422
+ return this.querySelectorAll(selector2);
1423
1423
  };
1424
1424
  }
1425
1425
 
@@ -1444,14 +1444,14 @@ function selectAll_default(select) {
1444
1444
  }
1445
1445
 
1446
1446
  // node_modules/d3-selection/src/matcher.js
1447
- function matcher_default(selector) {
1447
+ function matcher_default(selector2) {
1448
1448
  return function() {
1449
- return this.matches(selector);
1449
+ return this.matches(selector2);
1450
1450
  };
1451
1451
  }
1452
- function childMatcher(selector) {
1452
+ function childMatcher(selector2) {
1453
1453
  return function(node) {
1454
- return node.matches(selector);
1454
+ return node.matches(selector2);
1455
1455
  };
1456
1456
  }
1457
1457
 
@@ -1520,11 +1520,11 @@ EnterNode.prototype = {
1520
1520
  insertBefore: function(child, next) {
1521
1521
  return this._parent.insertBefore(child, next);
1522
1522
  },
1523
- querySelector: function(selector) {
1524
- return this._parent.querySelector(selector);
1523
+ querySelector: function(selector2) {
1524
+ return this._parent.querySelector(selector2);
1525
1525
  },
1526
- querySelectorAll: function(selector) {
1527
- return this._parent.querySelectorAll(selector);
1526
+ querySelectorAll: function(selector2) {
1527
+ return this._parent.querySelectorAll(selector2);
1528
1528
  }
1529
1529
  };
1530
1530
 
@@ -2135,8 +2135,8 @@ Selection.prototype = selection.prototype = {
2135
2135
  var selection_default = selection;
2136
2136
 
2137
2137
  // node_modules/d3-selection/src/select.js
2138
- function select_default2(selector) {
2139
- return typeof selector === "string" ? new Selection([[document.querySelector(selector)]], [document.documentElement]) : new Selection([[selector]], root);
2138
+ function select_default2(selector2) {
2139
+ return typeof selector2 === "string" ? new Selection([[document.querySelector(selector2)]], [document.documentElement]) : new Selection([[selector2]], root);
2140
2140
  }
2141
2141
 
2142
2142
  // node_modules/d3-selection/src/sourceEvent.js
@@ -5150,6 +5150,40 @@ function createMarkerIds(edges, { id: id2, defaultColor, defaultMarkerStart, def
5150
5150
  return markers;
5151
5151
  }, []).sort((a, b) => a.id.localeCompare(b.id));
5152
5152
  }
5153
+ function getNodeToolbarTransform(nodeRect, viewport, position, offset, align) {
5154
+ let alignmentOffset = 0.5;
5155
+ if (align === "start") {
5156
+ alignmentOffset = 0;
5157
+ } else if (align === "end") {
5158
+ alignmentOffset = 1;
5159
+ }
5160
+ let pos = [
5161
+ (nodeRect.x + nodeRect.width * alignmentOffset) * viewport.zoom + viewport.x,
5162
+ nodeRect.y * viewport.zoom + viewport.y - offset
5163
+ ];
5164
+ let shift = [-100 * alignmentOffset, -100];
5165
+ switch (position) {
5166
+ case Position.Right:
5167
+ pos = [
5168
+ (nodeRect.x + nodeRect.width) * viewport.zoom + viewport.x + offset,
5169
+ (nodeRect.y + nodeRect.height * alignmentOffset) * viewport.zoom + viewport.y
5170
+ ];
5171
+ shift = [0, -100 * alignmentOffset];
5172
+ break;
5173
+ case Position.Bottom:
5174
+ pos[1] = (nodeRect.y + nodeRect.height) * viewport.zoom + viewport.y + offset;
5175
+ shift[1] = 0;
5176
+ break;
5177
+ case Position.Left:
5178
+ pos = [
5179
+ nodeRect.x * viewport.zoom + viewport.x - offset,
5180
+ (nodeRect.y + nodeRect.height * alignmentOffset) * viewport.zoom + viewport.y
5181
+ ];
5182
+ shift = [-100, -100 * alignmentOffset];
5183
+ break;
5184
+ }
5185
+ return `translate(${pos[0]}px, ${pos[1]}px) translate(${shift[0]}%, ${shift[1]}%)`;
5186
+ }
5153
5187
  var SELECTED_NODE_Z = 1e3;
5154
5188
  var ROOT_PARENT_Z_INCREMENT = 10;
5155
5189
  var defaultOptions = {
@@ -5517,10 +5551,10 @@ function isParentSelected(node, nodeLookup) {
5517
5551
  }
5518
5552
  return isParentSelected(parentNode, nodeLookup);
5519
5553
  }
5520
- function hasSelector(target, selector, domNode) {
5554
+ function hasSelector(target, selector2, domNode) {
5521
5555
  let current = target;
5522
5556
  do {
5523
- if (current?.matches?.(selector))
5557
+ if (current?.matches?.(selector2))
5524
5558
  return true;
5525
5559
  if (current === domNode)
5526
5560
  return false;
@@ -6478,6 +6512,8 @@ var ResizeControlVariant;
6478
6512
  ResizeControlVariant2["Line"] = "line";
6479
6513
  ResizeControlVariant2["Handle"] = "handle";
6480
6514
  })(ResizeControlVariant || (ResizeControlVariant = {}));
6515
+ var XY_RESIZER_HANDLE_POSITIONS = ["top-left", "top-right", "bottom-left", "bottom-right"];
6516
+ var XY_RESIZER_LINE_POSITIONS = ["top", "right", "bottom", "left"];
6481
6517
  function getResizeDirection({ width, prevWidth, height, prevHeight, affectsX, affectsY }) {
6482
6518
  const deltaWidth = width - prevWidth;
6483
6519
  const deltaHeight = height - prevHeight;
@@ -6834,7 +6870,7 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
6834
6870
  destroy
6835
6871
  };
6836
6872
  }
6837
- function useSyncExternalStoreWithSelector(subscribe, getSnapshot, getServerSnapshot, selector, isEqual) {
6873
+ function useSyncExternalStoreWithSelector(subscribe, getSnapshot, getServerSnapshot, selector2, isEqual) {
6838
6874
  const instRef = ReactExports.useRef(null);
6839
6875
  let inst;
6840
6876
  if (instRef.current === null) {
@@ -6851,7 +6887,7 @@ function useSyncExternalStoreWithSelector(subscribe, getSnapshot, getServerSnaps
6851
6887
  if (!hasMemo) {
6852
6888
  hasMemo = true;
6853
6889
  memoizedSnapshot = nextSnapshot;
6854
- const nextSelection2 = selector(nextSnapshot);
6890
+ const nextSelection2 = selector2(nextSnapshot);
6855
6891
  if (isEqual !== void 0 && inst.hasValue) {
6856
6892
  const currentSelection = inst.value;
6857
6893
  if (isEqual(currentSelection, nextSelection2)) {
@@ -6867,7 +6903,7 @@ function useSyncExternalStoreWithSelector(subscribe, getSnapshot, getServerSnaps
6867
6903
  if (Object.is(prevSnapshot, nextSnapshot)) {
6868
6904
  return prevSelection;
6869
6905
  }
6870
- const nextSelection = selector(nextSnapshot);
6906
+ const nextSelection = selector2(nextSnapshot);
6871
6907
  if (isEqual !== void 0 && isEqual(prevSelection, nextSelection)) {
6872
6908
  memoizedSnapshot = nextSnapshot;
6873
6909
  return prevSelection;
@@ -6880,7 +6916,7 @@ function useSyncExternalStoreWithSelector(subscribe, getSnapshot, getServerSnaps
6880
6916
  const getSnapshotWithSelector = () => memoizedSelector(getSnapshot());
6881
6917
  const getServerSnapshotWithSelector = maybeGetServerSnapshot === null ? void 0 : () => memoizedSelector(maybeGetServerSnapshot());
6882
6918
  return [getSnapshotWithSelector, getServerSnapshotWithSelector];
6883
- }, [getSnapshot, getServerSnapshot, selector, isEqual]);
6919
+ }, [getSnapshot, getServerSnapshot, selector2, isEqual]);
6884
6920
  const value = ReactExports.useSyncExternalStore(subscribe, getSelection, getServerSelection);
6885
6921
  ReactExports.useEffect(() => {
6886
6922
  inst.hasValue = true;
@@ -6927,12 +6963,12 @@ var createStore = (createState) => createState ? createStoreImpl(createState) :
6927
6963
  var { useDebugValue: useDebugValue2 } = ReactExports__default.default;
6928
6964
  var { useSyncExternalStoreWithSelector: useSyncExternalStoreWithSelector2 } = use_sync_external_store_with_selector_default;
6929
6965
  var identity3 = (arg) => arg;
6930
- function useStoreWithEqualityFn(api, selector = identity3, equalityFn) {
6966
+ function useStoreWithEqualityFn(api, selector2 = identity3, equalityFn) {
6931
6967
  const slice = useSyncExternalStoreWithSelector2(
6932
6968
  api.subscribe,
6933
6969
  api.getState,
6934
6970
  api.getServerState || api.getInitialState,
6935
- selector,
6971
+ selector2,
6936
6972
  equalityFn
6937
6973
  );
6938
6974
  useDebugValue2(slice);
@@ -6940,7 +6976,7 @@ function useStoreWithEqualityFn(api, selector = identity3, equalityFn) {
6940
6976
  }
6941
6977
  var createWithEqualityFnImpl = (createState, defaultEqualityFn) => {
6942
6978
  const api = createStore(createState);
6943
- const useBoundStoreWithEqualityFn = (selector, equalityFn = defaultEqualityFn) => useStoreWithEqualityFn(api, selector, equalityFn);
6979
+ const useBoundStoreWithEqualityFn = (selector2, equalityFn = defaultEqualityFn) => useStoreWithEqualityFn(api, selector2, equalityFn);
6944
6980
  Object.assign(useBoundStoreWithEqualityFn, api);
6945
6981
  return useBoundStoreWithEqualityFn;
6946
6982
  };
@@ -6986,12 +7022,12 @@ function shallow$1(objA, objB) {
6986
7022
  var StoreContext = ReactExports.createContext(null);
6987
7023
  var Provider$1 = StoreContext.Provider;
6988
7024
  var zustandErrorMessage = errorMessages["error001"]("react");
6989
- function useStore(selector, equalityFn) {
7025
+ function useStore(selector2, equalityFn) {
6990
7026
  const store = ReactExports.useContext(StoreContext);
6991
7027
  if (store === null) {
6992
7028
  throw new Error(zustandErrorMessage);
6993
7029
  }
6994
- return useStoreWithEqualityFn(store, selector, equalityFn);
7030
+ return useStoreWithEqualityFn(store, selector2, equalityFn);
6995
7031
  }
6996
7032
  function useStoreApi() {
6997
7033
  const store = ReactExports.useContext(StoreContext);
@@ -10189,7 +10225,69 @@ function ResizeControl({ nodeId, position, variant = ResizeControlVariant.Handle
10189
10225
  ...color2 && { [isHandleControl ? "backgroundColor" : "borderColor"]: color2 }
10190
10226
  }, children: children2 });
10191
10227
  }
10192
- ReactExports.memo(ResizeControl);
10228
+ var NodeResizeControl = ReactExports.memo(ResizeControl);
10229
+ function NodeResizer({ nodeId, isVisible = true, handleClassName, handleStyle, lineClassName, lineStyle, color: color2, minWidth = 10, minHeight = 10, maxWidth = Number.MAX_VALUE, maxHeight = Number.MAX_VALUE, keepAspectRatio = false, autoScale = true, shouldResize, onResizeStart, onResize, onResizeEnd }) {
10230
+ if (!isVisible) {
10231
+ return null;
10232
+ }
10233
+ return jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [XY_RESIZER_LINE_POSITIONS.map((position) => jsxRuntime.jsx(NodeResizeControl, { className: lineClassName, style: lineStyle, nodeId, position, variant: ResizeControlVariant.Line, color: color2, minWidth, minHeight, maxWidth, maxHeight, onResizeStart, keepAspectRatio, autoScale, shouldResize, onResize, onResizeEnd }, position)), XY_RESIZER_HANDLE_POSITIONS.map((position) => jsxRuntime.jsx(NodeResizeControl, { className: handleClassName, style: handleStyle, nodeId, position, color: color2, minWidth, minHeight, maxWidth, maxHeight, onResizeStart, keepAspectRatio, autoScale, shouldResize, onResize, onResizeEnd }, position))] });
10234
+ }
10235
+ var selector = (state) => state.domNode?.querySelector(".react-flow__renderer");
10236
+ function NodeToolbarPortal({ children: children2 }) {
10237
+ const wrapperRef = useStore(selector);
10238
+ if (!wrapperRef) {
10239
+ return null;
10240
+ }
10241
+ return reactDom.createPortal(children2, wrapperRef);
10242
+ }
10243
+ var nodeEqualityFn = (a, b) => a?.internals.positionAbsolute.x !== b?.internals.positionAbsolute.x || a?.internals.positionAbsolute.y !== b?.internals.positionAbsolute.y || a?.measured.width !== b?.measured.width || a?.measured.height !== b?.measured.height || a?.selected !== b?.selected || a?.internals.z !== b?.internals.z;
10244
+ var nodesEqualityFn = (a, b) => {
10245
+ if (a.size !== b.size) {
10246
+ return false;
10247
+ }
10248
+ for (const [key, node] of a) {
10249
+ if (nodeEqualityFn(node, b.get(key))) {
10250
+ return false;
10251
+ }
10252
+ }
10253
+ return true;
10254
+ };
10255
+ var storeSelector = (state) => ({
10256
+ x: state.transform[0],
10257
+ y: state.transform[1],
10258
+ zoom: state.transform[2],
10259
+ selectedNodesCount: state.nodes.filter((node) => node.selected).length
10260
+ });
10261
+ function NodeToolbar({ nodeId, children: children2, className, style: style2, isVisible, position = Position.Top, offset = 10, align = "center", ...rest }) {
10262
+ const contextNodeId = useNodeId();
10263
+ const nodesSelector = ReactExports.useCallback((state) => {
10264
+ const nodeIds = Array.isArray(nodeId) ? nodeId : [nodeId || contextNodeId || ""];
10265
+ const internalNodes = nodeIds.reduce((res, id2) => {
10266
+ const node = state.nodeLookup.get(id2);
10267
+ if (node) {
10268
+ res.set(node.id, node);
10269
+ }
10270
+ return res;
10271
+ }, /* @__PURE__ */ new Map());
10272
+ return internalNodes;
10273
+ }, [nodeId, contextNodeId]);
10274
+ const nodes = useStore(nodesSelector, nodesEqualityFn);
10275
+ const { x, y, zoom, selectedNodesCount } = useStore(storeSelector, shallow$1);
10276
+ const isActive = typeof isVisible === "boolean" ? isVisible : nodes.size === 1 && nodes.values().next().value?.selected && selectedNodesCount === 1;
10277
+ if (!isActive || !nodes.size) {
10278
+ return null;
10279
+ }
10280
+ const nodeRect = getInternalNodesBounds(nodes);
10281
+ const nodesArray = Array.from(nodes.values());
10282
+ const zIndex = Math.max(...nodesArray.map((node) => node.internals.z + 1));
10283
+ const wrapperStyle2 = {
10284
+ position: "absolute",
10285
+ transform: getNodeToolbarTransform(nodeRect, { x, y, zoom }, position, offset, align),
10286
+ zIndex,
10287
+ ...style2
10288
+ };
10289
+ return jsxRuntime.jsx(NodeToolbarPortal, { children: jsxRuntime.jsx("div", { style: wrapperStyle2, className: cc(["react-flow__node-toolbar", className]), ...rest, "data-id": nodesArray.reduce((acc, node) => `${acc}${node.id} `, "").trim(), children: children2 }) });
10290
+ }
10193
10291
  function NodeShellInner({
10194
10292
  node,
10195
10293
  accent,
@@ -11247,6 +11345,7 @@ function toSchemaNode(n) {
11247
11345
  const data = n.data ?? {};
11248
11346
  const kindName = data.kind ?? n.type ?? "custom";
11249
11347
  const ports = resolveNodePorts(n, getNodeKind(kindName) ?? void 0);
11348
+ const node = n;
11250
11349
  return {
11251
11350
  id: n.id,
11252
11351
  kind: kindName,
@@ -11255,7 +11354,14 @@ function toSchemaNode(n) {
11255
11354
  description: data.description,
11256
11355
  config: data.config,
11257
11356
  inputs: ports.inputs,
11258
- outputs: ports.outputs
11357
+ outputs: ports.outputs,
11358
+ // Visual layout — only when explicitly set (never persist auto-`measured`
11359
+ // dimensions, which are derived, not authored).
11360
+ ...node.parentId ? { parentId: node.parentId } : {},
11361
+ ...node.extent ? { extent: node.extent } : {},
11362
+ ...typeof node.width === "number" ? { width: node.width } : {},
11363
+ ...typeof node.height === "number" ? { height: node.height } : {},
11364
+ ...node.style ? { style: node.style } : {}
11259
11365
  };
11260
11366
  }
11261
11367
  function toSchemaEdge(e) {
@@ -11268,9 +11374,13 @@ function toSchemaEdge(e) {
11268
11374
  label: typeof e.label === "string" ? e.label : void 0
11269
11375
  };
11270
11376
  }
11377
+ function migrateSchema(schema) {
11378
+ return schema;
11379
+ }
11271
11380
  function importWorkflow(schema, options = {}) {
11272
11381
  const issues = [];
11273
11382
  const lenient = options.lenient === true;
11383
+ schema = migrateSchema(schema);
11274
11384
  if (!schema || typeof schema !== "object") {
11275
11385
  return { ok: false, graph: { nodes: [], edges: [] }, issues: [{ level: "error", message: "Schema is not an object." }] };
11276
11386
  }
@@ -11304,6 +11414,12 @@ function importWorkflow(schema, options = {}) {
11304
11414
  id: n.id,
11305
11415
  type: kindId,
11306
11416
  position: { x: n.position?.x ?? 0, y: n.position?.y ?? 0 },
11417
+ // Rehydrate visual layout onto the node's top level (where xyflow reads it).
11418
+ ...n.parentId ? { parentId: n.parentId } : {},
11419
+ ...n.extent ? { extent: n.extent } : {},
11420
+ ...typeof n.width === "number" ? { width: n.width } : {},
11421
+ ...typeof n.height === "number" ? { height: n.height } : {},
11422
+ ...n.style ? { style: n.style } : {},
11307
11423
  data: {
11308
11424
  kind: kindId,
11309
11425
  label: n.label ?? kind?.label ?? n.kind,
@@ -11408,10 +11524,20 @@ function RegistryNodeInner(props) {
11408
11524
  "ff-node",
11409
11525
  `ff-node--status-${status}`,
11410
11526
  `ff-node--cat-${kind.category}`,
11411
- props.selected ? "ff-node--selected" : ""
11527
+ props.selected ? "ff-node--selected" : "",
11528
+ kind.resizable ? "ff-node--resizable" : ""
11412
11529
  ].filter(Boolean).join(" "),
11413
11530
  style: { borderColor: props.selected ? accent : void 0 },
11414
11531
  children: [
11532
+ kind.resizable && /* @__PURE__ */ jsxRuntime.jsx(
11533
+ NodeResizer,
11534
+ {
11535
+ isVisible: props.selected ?? false,
11536
+ color: accent,
11537
+ ...typeof kind.resizable === "object" ? kind.resizable : {}
11538
+ }
11539
+ ),
11540
+ kind.toolbar && /* @__PURE__ */ jsxRuntime.jsx(NodeToolbar, { isVisible: props.selected ?? false, children: kind.toolbar({ nodeId: props.id, config, selected: props.selected ?? false }) }),
11415
11541
  /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "ff-node__header", style: { background: accent }, children: [
11416
11542
  kind.icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ff-node__icon", "aria-hidden": true, children: kind.icon }),
11417
11543
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ff-node__tag", children: kind.label.toUpperCase() }),
@@ -12287,6 +12413,7 @@ exports.importWorkflow = importWorkflow;
12287
12413
  exports.isPause = isPause;
12288
12414
  exports.isRichInputEnabled = isRichInputEnabled;
12289
12415
  exports.listNodeKinds = listNodeKinds;
12416
+ exports.migrateSchema = migrateSchema;
12290
12417
  exports.onNodeKindsChanged = onNodeKindsChanged;
12291
12418
  exports.onRichInputAdapterChanged = onRichInputAdapterChanged;
12292
12419
  exports.paletteDropHandlers = paletteDropHandlers;