@flowgram.ai/free-layout-core 0.3.2 → 0.3.4

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/esm/index.js CHANGED
@@ -167,7 +167,7 @@ import { FlowNodeRenderData } from "@flowgram.ai/document";
167
167
  import { EntityData, SizeData } from "@flowgram.ai/core";
168
168
 
169
169
  // src/entities/workflow-port-entity.ts
170
- import { Rectangle as Rectangle3, Emitter } from "@flowgram.ai/utils";
170
+ import { Rectangle as Rectangle3, Emitter, Compare } from "@flowgram.ai/utils";
171
171
  import { FlowNodeTransformData } from "@flowgram.ai/document";
172
172
  import {
173
173
  Entity,
@@ -176,17 +176,18 @@ import {
176
176
  } from "@flowgram.ai/core";
177
177
  var PORT_SIZE = 24;
178
178
  var WorkflowPortEntity = class extends Entity {
179
- // relativePosition
180
179
  constructor(opts) {
181
180
  super(opts);
182
181
  this.portID = "";
183
- this._disabled = false;
184
182
  this._hasError = false;
185
183
  this._onErrorChangedEmitter = new Emitter();
186
184
  this.onErrorChanged = this._onErrorChangedEmitter.event;
187
185
  this.portID = opts.portID || "";
188
186
  this.portType = opts.type;
189
- this._disabled = opts.disabled ?? false;
187
+ this._disabled = opts.disabled;
188
+ this._offset = opts.offset;
189
+ this._location = opts.location;
190
+ this._size = opts.size;
190
191
  this.node = opts.node;
191
192
  this.updateTargetElement(opts.targetElement);
192
193
  this.toDispose.push(this.node.getData(TransformData3).onDataChange(() => this.fireChange()));
@@ -195,6 +196,9 @@ var WorkflowPortEntity = class extends Entity {
195
196
  static getPortEntityId(node, portType, portID = "") {
196
197
  return getPortEntityId(node, portType, portID);
197
198
  }
199
+ get position() {
200
+ return this._location;
201
+ }
198
202
  // 获取连线是否为错误态
199
203
  get hasError() {
200
204
  return this._hasError;
@@ -229,18 +233,47 @@ var WorkflowPortEntity = class extends Entity {
229
233
  clientY: pos.y
230
234
  });
231
235
  }
232
- if (this.portType === "input") {
233
- return bounds.leftCenter;
236
+ let point = { x: 0, y: 0 };
237
+ const offset = this._offset || { x: 0, y: 0 };
238
+ if (this._location) {
239
+ switch (this._location) {
240
+ case "left":
241
+ point = bounds.leftCenter;
242
+ break;
243
+ case "top":
244
+ point = bounds.topCenter;
245
+ break;
246
+ case "right":
247
+ point = bounds.rightCenter;
248
+ break;
249
+ case "bottom":
250
+ point = bounds.bottomCenter;
251
+ break;
252
+ }
253
+ } else {
254
+ if (this.portType === "input") {
255
+ point = bounds.leftCenter;
256
+ } else {
257
+ point = bounds.rightCenter;
258
+ }
234
259
  }
235
- return bounds.rightCenter;
260
+ return {
261
+ x: point.x + offset.x,
262
+ y: point.y + offset.y
263
+ };
236
264
  }
237
265
  /**
238
- * 点的区域
266
+ * 端口热区
239
267
  */
240
268
  get bounds() {
241
269
  const { point } = this;
242
- const halfSize = PORT_SIZE / 2;
243
- return new Rectangle3(point.x - halfSize, point.y - halfSize, PORT_SIZE, PORT_SIZE);
270
+ const size = this._size || { width: PORT_SIZE, height: PORT_SIZE };
271
+ return new Rectangle3(
272
+ point.x - size.width / 2,
273
+ point.y - size.height / 2,
274
+ size.width,
275
+ size.height
276
+ );
244
277
  }
245
278
  isHovered(x, y) {
246
279
  return this.bounds.contains(x, y);
@@ -307,6 +340,32 @@ var WorkflowPortEntity = class extends Entity {
307
340
  });
308
341
  return lines;
309
342
  }
343
+ update(data) {
344
+ let changed = false;
345
+ if (data.targetElement !== this.targetElement) {
346
+ this.targetElement = data.targetElement;
347
+ changed = true;
348
+ }
349
+ if (data.location !== this._location) {
350
+ this._location = data.location;
351
+ changed = true;
352
+ }
353
+ if (Compare.isChanged(data.offset, this._offset)) {
354
+ this._offset = data.offset;
355
+ changed = true;
356
+ }
357
+ if (Compare.isChanged(data.size, this._size)) {
358
+ this._size = data.size;
359
+ changed = true;
360
+ }
361
+ if (data.disabled !== this._disabled) {
362
+ this._disabled = data.disabled;
363
+ changed = true;
364
+ }
365
+ if (changed) {
366
+ this.fireChange();
367
+ }
368
+ }
310
369
  dispose() {
311
370
  this.lines.forEach((l) => l.dispose());
312
371
  super.dispose();
@@ -345,17 +404,26 @@ var WorkflowNodePortsData = class extends EntityData {
345
404
  return {};
346
405
  }
347
406
  /**
348
- * 更新静态的 ports 数据
407
+ * Update all ports data, includes static ports and dynamic ports
408
+ * @param ports
349
409
  */
350
- updateStaticPorts(ports) {
410
+ updateAllPorts(ports) {
351
411
  const meta = this.entity.getNodeMeta();
352
- this._staticPorts = ports;
412
+ if (ports) {
413
+ this._staticPorts = ports;
414
+ }
353
415
  if (meta.useDynamicPort) {
354
416
  this.updateDynamicPorts();
355
417
  } else {
356
418
  this.updatePorts(this._staticPorts);
357
419
  }
358
420
  }
421
+ /**
422
+ * @deprecated use `updateAllPorts` instead
423
+ */
424
+ updateStaticPorts(ports) {
425
+ this.updateAllPorts(ports);
426
+ }
359
427
  /**
360
428
  * 动态计算点位,通过 dom 的 data-port-key
361
429
  */
@@ -494,9 +562,7 @@ var WorkflowNodePortsData = class extends EntityData {
494
562
  */
495
563
  updatePortEntity(portInfo) {
496
564
  const portEntity = this.getOrCreatePortEntity(portInfo);
497
- if (portInfo.targetElement) {
498
- portEntity.updateTargetElement(portInfo.targetElement);
499
- }
565
+ portEntity.update(portInfo);
500
566
  return portEntity;
501
567
  }
502
568
  };
@@ -1561,6 +1627,14 @@ var WorkflowLinesManager = class {
1561
1627
  if (fromPort === toPort || fromPort.node === toPort.node || fromPort.portType !== "output" || toPort.portType !== "input" || toPort.disabled) {
1562
1628
  return false;
1563
1629
  }
1630
+ const fromCanAdd = fromPort.node.getNodeRegistry().canAddLine;
1631
+ const toCanAdd = toPort.node.getNodeRegistry().canAddLine;
1632
+ if (fromCanAdd && !fromCanAdd(fromPort, toPort, this, silent)) {
1633
+ return false;
1634
+ }
1635
+ if (toCanAdd && !toCanAdd(fromPort, toPort, this, silent)) {
1636
+ return false;
1637
+ }
1564
1638
  if (this.options.canAddLine) {
1565
1639
  return this.options.canAddLine(fromPort, toPort, this, silent);
1566
1640
  }
@@ -2147,10 +2221,13 @@ var WorkflowDocument = class extends FlowDocument {
2147
2221
  from: line.from.id,
2148
2222
  to: line.to.id
2149
2223
  }));
2150
- const startNodeId = allNode.find((node) => node.isStart).id;
2151
- const endNodeId = allNode.find((node) => node.isNodeEnd).id;
2224
+ const startNodeId = allNode.find((node) => node.isStart)?.id;
2225
+ const endNodeId = allNode.find((node) => node.isNodeEnd)?.id;
2152
2226
  const nodeInContainer = allNode.filter((node) => node.parent?.getNodeMeta().isContainer).map((node) => node.id);
2153
- const associatedCache = /* @__PURE__ */ new Set([endNodeId, ...nodeInContainer]);
2227
+ const associatedCache = new Set(nodeInContainer);
2228
+ if (endNodeId) {
2229
+ associatedCache.add(endNodeId);
2230
+ }
2154
2231
  const bfs = (nodeId) => {
2155
2232
  if (associatedCache.has(nodeId)) {
2156
2233
  return;
@@ -2164,7 +2241,9 @@ var WorkflowDocument = class extends FlowDocument {
2164
2241
  }, []);
2165
2242
  nextNodes.forEach(bfs);
2166
2243
  };
2167
- bfs(startNodeId);
2244
+ if (startNodeId) {
2245
+ bfs(startNodeId);
2246
+ }
2168
2247
  const associatedNodes = allNode.filter((node) => associatedCache.has(node.id));
2169
2248
  return associatedNodes;
2170
2249
  }
@@ -2286,6 +2365,11 @@ var WorkflowDocument = class extends FlowDocument {
2286
2365
  * 导出数据
2287
2366
  */
2288
2367
  toJSON() {
2368
+ if (this.disposed) {
2369
+ throw new Error(
2370
+ "The WorkflowDocument has been disposed and it is no longer possible to call toJSON."
2371
+ );
2372
+ }
2289
2373
  const rootJSON = this.toNodeJSON(this.root);
2290
2374
  const json = {
2291
2375
  nodes: rootJSON.blocks ?? [],