orcasvn-react-diagrams 0.2.12 → 0.2.13

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 (35) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +15 -11
  3. package/ai/api-contract.json +47 -0
  4. package/ai/invariants.json +6 -2
  5. package/ai/manifest.json +1 -1
  6. package/dist/cjs/examples.js +427 -48
  7. package/dist/cjs/index.js +226 -36
  8. package/dist/cjs/types/api/createDiagramEditor.d.ts +2 -1
  9. package/dist/cjs/types/api/types.d.ts +50 -0
  10. package/dist/cjs/types/displaybox/demos/deletionEventsDemo.d.ts +2 -0
  11. package/dist/cjs/types/displaybox/demos/focusElementDemo.d.ts +4 -0
  12. package/dist/cjs/types/engine/DiagramEngine.d.ts +9 -0
  13. package/dist/esm/examples.js +427 -48
  14. package/dist/esm/examples.js.map +1 -1
  15. package/dist/esm/index.js +226 -36
  16. package/dist/esm/index.js.map +1 -1
  17. package/dist/esm/types/api/createDiagramEditor.d.ts +2 -1
  18. package/dist/esm/types/api/types.d.ts +50 -0
  19. package/dist/esm/types/displaybox/demos/deletionEventsDemo.d.ts +2 -0
  20. package/dist/esm/types/displaybox/demos/focusElementDemo.d.ts +4 -0
  21. package/dist/esm/types/engine/DiagramEngine.d.ts +9 -0
  22. package/dist/examples.d.ts +51 -0
  23. package/dist/index.d.ts +52 -1
  24. package/docs/API_CONTRACT.md +48 -1
  25. package/docs/ARCHITECTURE.md +9 -7
  26. package/docs/CAPABILITIES.md +3 -0
  27. package/docs/COMMANDS_EVENTS.md +15 -6
  28. package/docs/DOCUMENTATION_WORKFLOW.md +3 -1
  29. package/docs/INTEGRATION_PLAYBOOK.md +4 -0
  30. package/docs/PORTING_CHECKLIST.md +4 -1
  31. package/package.json +1 -1
  32. package/src/displaybox/demos/DeletionEventsDemoTab.tsx +167 -9
  33. package/src/displaybox/demos/deletionEventsDemo.ts +2 -2
  34. package/src/displaybox/demos/focusElementDemo.ts +91 -0
  35. package/src/displaybox/demos/index.tsx +2 -0
package/dist/esm/index.js CHANGED
@@ -4135,8 +4135,15 @@ var DiagramEngine = /** @class */ (function () {
4135
4135
  var _this = this;
4136
4136
  var _a;
4137
4137
  var existing = this.model.getElement(id);
4138
- var parentId = (_a = existing === null || existing === void 0 ? void 0 : existing.parentId) !== null && _a !== void 0 ? _a : null;
4138
+ if (!existing)
4139
+ return;
4140
+ var parentId = (_a = existing.parentId) !== null && _a !== void 0 ? _a : null;
4139
4141
  var before = this.model.toState();
4142
+ var root = { entity: 'element', id: id };
4143
+ var plannedRemoval = this.planRemoval(before, root);
4144
+ if (!plannedRemoval || this.emitDeletionLifecycleEvents(plannedRemoval.removed, root, 'direct')) {
4145
+ return;
4146
+ }
4140
4147
  this.commandQueue.run(createRemoveElementCommand(id), this.model);
4141
4148
  var removal = this.computeRemovalDiff(before);
4142
4149
  var allPatches = this.mutationPipeline.run({
@@ -4144,9 +4151,6 @@ var DiagramEngine = /** @class */ (function () {
4144
4151
  layoutSteps: [function () { return _this.applyLayoutCascade(parentId); }],
4145
4152
  });
4146
4153
  this.emitChange(allPatches);
4147
- if (existing) {
4148
- this.events.emit('elementDeleted', { elementId: id });
4149
- }
4150
4154
  this.emitEntityDeletionEvents(removal.removed);
4151
4155
  };
4152
4156
  DiagramEngine.prototype.addPortToElement = function (elementId, port) {
@@ -4227,7 +4231,14 @@ var DiagramEngine = /** @class */ (function () {
4227
4231
  }
4228
4232
  };
4229
4233
  DiagramEngine.prototype.removePort = function (id) {
4234
+ if (!this.model.getPort(id))
4235
+ return;
4230
4236
  var before = this.model.toState();
4237
+ var root = { entity: 'port', id: id };
4238
+ var plannedRemoval = this.planRemoval(before, root);
4239
+ if (!plannedRemoval || this.emitDeletionLifecycleEvents(plannedRemoval.removed, root, 'direct')) {
4240
+ return;
4241
+ }
4231
4242
  this.commandQueue.run(createRemovePortCommand(id), this.model);
4232
4243
  var removal = this.computeRemovalDiff(before);
4233
4244
  this.emitChange(removal.patches);
@@ -4321,7 +4332,14 @@ var DiagramEngine = /** @class */ (function () {
4321
4332
  }
4322
4333
  };
4323
4334
  DiagramEngine.prototype.removeLink = function (id) {
4335
+ if (!this.model.getLink(id))
4336
+ return;
4324
4337
  var before = this.model.toState();
4338
+ var root = { entity: 'link', id: id };
4339
+ var plannedRemoval = this.planRemoval(before, root);
4340
+ if (!plannedRemoval || this.emitDeletionLifecycleEvents(plannedRemoval.removed, root, 'direct')) {
4341
+ return;
4342
+ }
4325
4343
  this.commandQueue.run(createRemoveLinkCommand(id), this.model);
4326
4344
  var removal = this.computeRemovalDiff(before);
4327
4345
  this.emitChange(removal.patches);
@@ -4406,7 +4424,14 @@ var DiagramEngine = /** @class */ (function () {
4406
4424
  this.emitChange(patches);
4407
4425
  };
4408
4426
  DiagramEngine.prototype.removeText = function (id) {
4427
+ if (!this.model.getText(id))
4428
+ return;
4409
4429
  var before = this.model.toState();
4430
+ var root = { entity: 'text', id: id };
4431
+ var plannedRemoval = this.planRemoval(before, root);
4432
+ if (!plannedRemoval || this.emitDeletionLifecycleEvents(plannedRemoval.removed, root, 'direct')) {
4433
+ return;
4434
+ }
4410
4435
  this.commandQueue.run(createRemoveTextCommand(id), this.model);
4411
4436
  var removal = this.computeRemovalDiff(before);
4412
4437
  this.emitChange(removal.patches);
@@ -4601,40 +4626,22 @@ var DiagramEngine = /** @class */ (function () {
4601
4626
  if (selected.length === 0)
4602
4627
  return;
4603
4628
  var before = this.model.toState();
4604
- var elementIds = [];
4605
- selected.forEach(function (id) {
4606
- if (_this.model.getElement(id))
4607
- elementIds.push(id);
4608
- else if (_this.model.getPort(id))
4609
- ;
4610
- else if (_this.model.getLink(id))
4611
- ;
4612
- else if (_this.model.getText(id))
4613
- ;
4614
- });
4615
4629
  selected.forEach(function (id) {
4616
- if (_this.model.getElement(id)) {
4617
- _this.commandQueue.run(createRemoveElementCommand(id), _this.model);
4630
+ var root = _this.resolveDeletionRoot(id);
4631
+ if (!root)
4618
4632
  return;
4619
- }
4620
- if (_this.model.getPort(id)) {
4621
- _this.commandQueue.run(createRemovePortCommand(id), _this.model);
4622
- return;
4623
- }
4624
- if (_this.model.getLink(id)) {
4625
- _this.commandQueue.run(createRemoveLinkCommand(id), _this.model);
4633
+ var currentState = _this.model.toState();
4634
+ var plannedRemoval = _this.planRemoval(currentState, root);
4635
+ if (!plannedRemoval || _this.emitDeletionLifecycleEvents(plannedRemoval.removed, root, 'selection')) {
4626
4636
  return;
4627
4637
  }
4628
- if (_this.model.getText(id)) {
4629
- _this.commandQueue.run(createRemoveTextCommand(id), _this.model);
4630
- }
4638
+ _this.applyRemovalCommand(root);
4631
4639
  });
4632
4640
  var removal = this.computeRemovalDiff(before);
4641
+ if (removal.patches.length === 0)
4642
+ return;
4633
4643
  this.emitChange(removal.patches);
4634
4644
  this.emitEntityDeletionEvents(removal.removed);
4635
- elementIds.forEach(function (elementId) { return _this.events.emit('elementDeleted', { elementId: elementId }); });
4636
- this.selection.clear();
4637
- this.emitSelection();
4638
4645
  };
4639
4646
  DiagramEngine.prototype.setViewport = function (pan, zoom) {
4640
4647
  var hasPanChange = this.viewport.pan.x !== pan.x || this.viewport.pan.y !== pan.y;
@@ -4687,6 +4694,9 @@ var DiagramEngine = /** @class */ (function () {
4687
4694
  DiagramEngine.prototype.emitElementClick = function (elementId, pointer, isMulti) {
4688
4695
  this.events.emit('elementClick', { elementId: elementId, pointer: pointer, isMulti: isMulti });
4689
4696
  };
4697
+ DiagramEngine.prototype.emitElementDoubleClick = function (elementId, pointer, isMulti) {
4698
+ this.events.emit('elementDoubleClick', { elementId: elementId, pointer: pointer, isMulti: isMulti });
4699
+ };
4690
4700
  DiagramEngine.prototype.emitElementLinkStarted = function (event) {
4691
4701
  this.events.emit('elementLinkStarted', event);
4692
4702
  };
@@ -5330,8 +5340,8 @@ var DiagramEngine = /** @class */ (function () {
5330
5340
  });
5331
5341
  return { patches: normalizedPatches, movedPortIds: Array.from(movedPortIds) };
5332
5342
  };
5333
- DiagramEngine.prototype.computeRemovalDiff = function (before) {
5334
- var after = this.model.toState();
5343
+ DiagramEngine.prototype.computeRemovalDiff = function (before, after) {
5344
+ if (after === void 0) { after = this.model.toState(); }
5335
5345
  var removedPatches = [];
5336
5346
  var beforeElements = new Set(before.elements.map(function (element) { return element.id; }));
5337
5347
  var beforePorts = new Set(before.ports.map(function (port) { return port.id; }));
@@ -5341,9 +5351,13 @@ var DiagramEngine = /** @class */ (function () {
5341
5351
  var afterPorts = new Set(after.ports.map(function (port) { return port.id; }));
5342
5352
  var afterLinks = new Set(after.links.map(function (link) { return link.id; }));
5343
5353
  var afterTexts = new Set(after.texts.map(function (text) { return text.id; }));
5354
+ var removedElements = [];
5344
5355
  beforeElements.forEach(function (id) {
5345
5356
  if (!afterElements.has(id))
5346
5357
  removedPatches.push(patchRemove('element', id));
5358
+ var removedElement = before.elements.find(function (element) { return element.id === id; });
5359
+ if (!afterElements.has(id) && removedElement)
5360
+ removedElements.push(removedElement);
5347
5361
  });
5348
5362
  var removedPorts = [];
5349
5363
  beforePorts.forEach(function (id) {
@@ -5374,11 +5388,144 @@ var DiagramEngine = /** @class */ (function () {
5374
5388
  });
5375
5389
  return {
5376
5390
  patches: removedPatches,
5377
- removed: { ports: removedPorts, links: removedLinks, texts: removedTexts },
5391
+ removed: { elements: removedElements, ports: removedPorts, links: removedLinks, texts: removedTexts },
5378
5392
  };
5379
5393
  };
5394
+ DiagramEngine.prototype.resolveDeletionRoot = function (id) {
5395
+ if (this.model.getElement(id))
5396
+ return { entity: 'element', id: id };
5397
+ if (this.model.getPort(id))
5398
+ return { entity: 'port', id: id };
5399
+ if (this.model.getLink(id))
5400
+ return { entity: 'link', id: id };
5401
+ if (this.model.getText(id))
5402
+ return { entity: 'text', id: id };
5403
+ return null;
5404
+ };
5405
+ DiagramEngine.prototype.applyRemovalCommand = function (root) {
5406
+ if (root.entity === 'element') {
5407
+ this.commandQueue.run(createRemoveElementCommand(root.id), this.model);
5408
+ return;
5409
+ }
5410
+ if (root.entity === 'port') {
5411
+ this.commandQueue.run(createRemovePortCommand(root.id), this.model);
5412
+ return;
5413
+ }
5414
+ if (root.entity === 'link') {
5415
+ this.commandQueue.run(createRemoveLinkCommand(root.id), this.model);
5416
+ return;
5417
+ }
5418
+ this.commandQueue.run(createRemoveTextCommand(root.id), this.model);
5419
+ };
5420
+ DiagramEngine.prototype.planRemoval = function (before, root) {
5421
+ var tempModel = new DiagramModel();
5422
+ tempModel.load(before);
5423
+ if (root.entity === 'element') {
5424
+ tempModel.removeElement(root.id);
5425
+ }
5426
+ else if (root.entity === 'port') {
5427
+ tempModel.removePort(root.id);
5428
+ }
5429
+ else if (root.entity === 'link') {
5430
+ tempModel.removeLink(root.id);
5431
+ }
5432
+ else {
5433
+ tempModel.removeText(root.id);
5434
+ }
5435
+ return this.computeRemovalDiff(before, tempModel.toState());
5436
+ };
5437
+ DiagramEngine.prototype.emitDeletionLifecycleEvents = function (removed, root, rootTrigger) {
5438
+ for (var _i = 0, _a = removed.elements; _i < _a.length; _i++) {
5439
+ var element = _a[_i];
5440
+ var trigger = root.entity === 'element' && element.id === root.id ? rootTrigger : 'cascade';
5441
+ if (this.emitElementDeleting({
5442
+ elementId: element.id,
5443
+ trigger: trigger,
5444
+ root: root,
5445
+ })) {
5446
+ return true;
5447
+ }
5448
+ }
5449
+ for (var _b = 0, _c = removed.ports; _b < _c.length; _b++) {
5450
+ var port = _c[_b];
5451
+ var trigger = root.entity === 'port' && port.id === root.id ? rootTrigger : 'cascade';
5452
+ if (this.emitPortDeleting({
5453
+ portId: port.id,
5454
+ elementId: port.elementId,
5455
+ trigger: trigger,
5456
+ root: root,
5457
+ })) {
5458
+ return true;
5459
+ }
5460
+ }
5461
+ for (var _d = 0, _e = removed.links; _d < _e.length; _d++) {
5462
+ var link = _e[_d];
5463
+ var trigger = root.entity === 'link' && link.id === root.id ? rootTrigger : 'cascade';
5464
+ if (this.emitLinkDeleting({
5465
+ linkId: link.id,
5466
+ sourcePortId: link.sourcePortId,
5467
+ targetPortId: link.targetPortId,
5468
+ trigger: trigger,
5469
+ root: root,
5470
+ })) {
5471
+ return true;
5472
+ }
5473
+ }
5474
+ for (var _f = 0, _g = removed.texts; _f < _g.length; _f++) {
5475
+ var text = _g[_f];
5476
+ var trigger = root.entity === 'text' && text.id === root.id ? rootTrigger : 'cascade';
5477
+ if (this.emitTextDeleting({
5478
+ textId: text.id,
5479
+ ownerId: text.ownerId,
5480
+ trigger: trigger,
5481
+ root: root,
5482
+ })) {
5483
+ return true;
5484
+ }
5485
+ }
5486
+ return false;
5487
+ };
5488
+ DiagramEngine.prototype.emitElementDeleting = function (event) {
5489
+ var cancelled = false;
5490
+ var payload = __assign(__assign({}, event), { cancelled: false, cancel: function () {
5491
+ cancelled = true;
5492
+ payload.cancelled = true;
5493
+ } });
5494
+ this.events.emit('elementDeleting', payload);
5495
+ return cancelled || payload.cancelled;
5496
+ };
5497
+ DiagramEngine.prototype.emitPortDeleting = function (event) {
5498
+ var cancelled = false;
5499
+ var payload = __assign(__assign({}, event), { cancelled: false, cancel: function () {
5500
+ cancelled = true;
5501
+ payload.cancelled = true;
5502
+ } });
5503
+ this.events.emit('portDeleting', payload);
5504
+ return cancelled || payload.cancelled;
5505
+ };
5506
+ DiagramEngine.prototype.emitLinkDeleting = function (event) {
5507
+ var cancelled = false;
5508
+ var payload = __assign(__assign({}, event), { cancelled: false, cancel: function () {
5509
+ cancelled = true;
5510
+ payload.cancelled = true;
5511
+ } });
5512
+ this.events.emit('linkDeleting', payload);
5513
+ return cancelled || payload.cancelled;
5514
+ };
5515
+ DiagramEngine.prototype.emitTextDeleting = function (event) {
5516
+ var cancelled = false;
5517
+ var payload = __assign(__assign({}, event), { cancelled: false, cancel: function () {
5518
+ cancelled = true;
5519
+ payload.cancelled = true;
5520
+ } });
5521
+ this.events.emit('textDeleting', payload);
5522
+ return cancelled || payload.cancelled;
5523
+ };
5380
5524
  DiagramEngine.prototype.emitEntityDeletionEvents = function (removed) {
5381
5525
  var _this = this;
5526
+ removed.elements.forEach(function (element) {
5527
+ _this.events.emit('elementDeleted', { elementId: element.id });
5528
+ });
5382
5529
  removed.ports.forEach(function (port) {
5383
5530
  _this.events.emit('portDeleted', { portId: port.id, elementId: port.elementId });
5384
5531
  });
@@ -7263,15 +7410,29 @@ var KonvaInteraction = /** @class */ (function () {
7263
7410
  this.stage.on(upEvents, pointerUp);
7264
7411
  this.handlers.push([upEvents, pointerUp]);
7265
7412
  var doubleClick = function () {
7413
+ var args = [];
7414
+ for (var _i = 0; _i < arguments.length; _i++) {
7415
+ args[_i] = arguments[_i];
7416
+ }
7417
+ var event = args[0];
7418
+ var nativeEvent = event === null || event === void 0 ? void 0 : event.evt;
7266
7419
  var point = _this.getPointerPosition();
7267
7420
  if (!point)
7268
7421
  return;
7269
7422
  var hit = _this.resolveHit(point);
7270
- if (!hit || hit.type !== 'text')
7423
+ if (!hit)
7271
7424
  return;
7272
- if (!_this.isTextEditable(hit.id))
7425
+ if (hit.type === 'text') {
7426
+ if (!_this.isTextEditable(hit.id))
7427
+ return;
7428
+ _this.startTextEdit(hit.id);
7429
+ return;
7430
+ }
7431
+ if (hit.type !== 'element')
7273
7432
  return;
7274
- _this.startTextEdit(hit.id);
7433
+ var isMulti = Boolean(nativeEvent && (nativeEvent.ctrlKey || nativeEvent.metaKey || nativeEvent.shiftKey));
7434
+ var pointerInfo = _this.buildPointerInfo(point, nativeEvent);
7435
+ _this.engine.emitElementDoubleClick(hit.id, pointerInfo, isMulti);
7275
7436
  };
7276
7437
  this.stage.on('dblclick dbltap', doubleClick);
7277
7438
  this.handlers.push(['dblclick dbltap', doubleClick]);
@@ -9789,6 +9950,29 @@ var resolveViewportFitTransform = function (state, viewportSize, options) {
9789
9950
  };
9790
9951
  return { pan: pan, zoom: zoom };
9791
9952
  };
9953
+ var resolveFocusElementTransform = function (state, elementId, viewportSize, currentZoom, options) {
9954
+ var elementsById = new Map(state.elements.map(function (element) { return [element.id, element]; }));
9955
+ var element = elementsById.get(elementId);
9956
+ if (!element)
9957
+ return null;
9958
+ var position = resolveElementWorldPositionInState(elementId, elementsById);
9959
+ if (!position)
9960
+ return null;
9961
+ var safeWidth = Math.max(1, viewportSize.width);
9962
+ var safeHeight = Math.max(1, viewportSize.height);
9963
+ var requestedZoom = options === null || options === void 0 ? void 0 : options.zoom;
9964
+ var zoom = typeof requestedZoom === 'number' && Number.isFinite(requestedZoom)
9965
+ ? clamp(requestedZoom, DEFAULT_VIEWPORT_FIT_MIN_ZOOM, DEFAULT_VIEWPORT_FIT_MAX_ZOOM)
9966
+ : currentZoom;
9967
+ var safeZoom = zoom === 0 ? 1 : zoom;
9968
+ var centerX = position.x + element.size.width / 2;
9969
+ var centerY = position.y + element.size.height / 2;
9970
+ var pan = {
9971
+ x: safeWidth / 2 - centerX * safeZoom,
9972
+ y: safeHeight / 2 - centerY * safeZoom,
9973
+ };
9974
+ return { pan: pan, zoom: zoom };
9975
+ };
9792
9976
  var resolveFitToContentPadding = function (fitToContent) {
9793
9977
  if (typeof fitToContent === 'object' && typeof fitToContent.padding === 'number') {
9794
9978
  return Math.max(0, fitToContent.padding);
@@ -10023,6 +10207,12 @@ var createDiagramEditor = function (config) {
10023
10207
  return;
10024
10208
  engine.setViewport(transform.pan, transform.zoom);
10025
10209
  },
10210
+ focusElement: function (elementId, options) {
10211
+ var transform = resolveFocusElementTransform(engine.getState(), elementId, { width: stageWidth, height: stageHeight }, engine.getViewport().zoom, options);
10212
+ if (!transform)
10213
+ return;
10214
+ engine.setViewport(transform.pan, transform.zoom);
10215
+ },
10026
10216
  exportImage: function (options) {
10027
10217
  engine.render();
10028
10218
  if (typeof stage.toDataURL !== 'function') {