orcasvn-react-diagrams 0.2.2 → 0.2.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.
Files changed (83) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/README.md +15 -3
  3. package/dist/cjs/examples.js +2616 -291
  4. package/dist/cjs/index.js +1186 -153
  5. package/dist/cjs/types/api/createDiagramEditor.d.ts +19 -1
  6. package/dist/cjs/types/api/index.d.ts +1 -1
  7. package/dist/cjs/types/api/types.d.ts +41 -0
  8. package/dist/cjs/types/displaybox/DisplayBoxControls.d.ts +5 -1
  9. package/dist/cjs/types/displaybox/demos/AsymmetricPortMultiAnchorDemoTab.d.ts +3 -0
  10. package/dist/cjs/types/displaybox/demos/LayoutLabelReservedSpaceDemoTab.d.ts +3 -0
  11. package/dist/cjs/types/displaybox/demos/VertexControlLinkSessionDemoTab.d.ts +3 -0
  12. package/dist/cjs/types/displaybox/demos/asymmetricPortMultiAnchorDemo.d.ts +31 -0
  13. package/dist/cjs/types/displaybox/demos/labelStyleDemo.d.ts +2 -0
  14. package/dist/cjs/types/displaybox/demos/layoutLabelReservedSpaceDemo.d.ts +11 -0
  15. package/dist/cjs/types/displaybox/demos/portPositionLimitsDemo.d.ts +2 -0
  16. package/dist/cjs/types/displaybox/demos/vertexControlLinkSessionDemo.d.ts +12 -0
  17. package/dist/cjs/types/displaybox/useDemoControls.d.ts +4 -0
  18. package/dist/cjs/types/engine/AutoLayoutService.d.ts +2 -0
  19. package/dist/cjs/types/engine/DiagramEngine.d.ts +11 -0
  20. package/dist/cjs/types/engine/LinkRoutingService.d.ts +9 -1
  21. package/dist/cjs/types/models/PortModel.d.ts +5 -0
  22. package/dist/cjs/types/renderer/RenderTypes.d.ts +3 -1
  23. package/dist/cjs/types/renderer/konva/KonvaInteraction.d.ts +14 -0
  24. package/dist/cjs/types/renderer/konva/KonvaNodeFactory.d.ts +12 -0
  25. package/dist/cjs/types/renderer/konva/KonvaRenderer.d.ts +2 -1
  26. package/dist/cjs/types/shapes/BuiltInShapes.d.ts +3 -1
  27. package/dist/cjs/types/strategies/ObstacleRouter.d.ts +2 -0
  28. package/dist/cjs/types/utils/__tests__/portGeometry.test.d.ts +1 -0
  29. package/dist/cjs/types/utils/portGeometry.d.ts +44 -0
  30. package/dist/esm/examples.js +2617 -292
  31. package/dist/esm/examples.js.map +1 -1
  32. package/dist/esm/index.js +1186 -153
  33. package/dist/esm/index.js.map +1 -1
  34. package/dist/esm/types/api/createDiagramEditor.d.ts +19 -1
  35. package/dist/esm/types/api/index.d.ts +1 -1
  36. package/dist/esm/types/api/types.d.ts +41 -0
  37. package/dist/esm/types/displaybox/DisplayBoxControls.d.ts +5 -1
  38. package/dist/esm/types/displaybox/demos/AsymmetricPortMultiAnchorDemoTab.d.ts +3 -0
  39. package/dist/esm/types/displaybox/demos/LayoutLabelReservedSpaceDemoTab.d.ts +3 -0
  40. package/dist/esm/types/displaybox/demos/VertexControlLinkSessionDemoTab.d.ts +3 -0
  41. package/dist/esm/types/displaybox/demos/asymmetricPortMultiAnchorDemo.d.ts +31 -0
  42. package/dist/esm/types/displaybox/demos/labelStyleDemo.d.ts +2 -0
  43. package/dist/esm/types/displaybox/demos/layoutLabelReservedSpaceDemo.d.ts +11 -0
  44. package/dist/esm/types/displaybox/demos/portPositionLimitsDemo.d.ts +2 -0
  45. package/dist/esm/types/displaybox/demos/vertexControlLinkSessionDemo.d.ts +12 -0
  46. package/dist/esm/types/displaybox/useDemoControls.d.ts +4 -0
  47. package/dist/esm/types/engine/AutoLayoutService.d.ts +2 -0
  48. package/dist/esm/types/engine/DiagramEngine.d.ts +11 -0
  49. package/dist/esm/types/engine/LinkRoutingService.d.ts +9 -1
  50. package/dist/esm/types/models/PortModel.d.ts +5 -0
  51. package/dist/esm/types/renderer/RenderTypes.d.ts +3 -1
  52. package/dist/esm/types/renderer/konva/KonvaInteraction.d.ts +14 -0
  53. package/dist/esm/types/renderer/konva/KonvaNodeFactory.d.ts +12 -0
  54. package/dist/esm/types/renderer/konva/KonvaRenderer.d.ts +2 -1
  55. package/dist/esm/types/shapes/BuiltInShapes.d.ts +3 -1
  56. package/dist/esm/types/strategies/ObstacleRouter.d.ts +2 -0
  57. package/dist/esm/types/utils/__tests__/portGeometry.test.d.ts +1 -0
  58. package/dist/esm/types/utils/portGeometry.d.ts +44 -0
  59. package/dist/examples.d.ts +59 -0
  60. package/dist/index.d.ts +67 -1
  61. package/package.json +2 -1
  62. package/src/displaybox/demos/AsymmetricPortMultiAnchorDemoTab.tsx +269 -0
  63. package/src/displaybox/demos/AutoLayoutDemoTab.tsx +113 -11
  64. package/src/displaybox/demos/DeletionEventsDemoTab.tsx +6 -1
  65. package/src/displaybox/demos/EngineEventsDemoTab.tsx +5 -0
  66. package/src/displaybox/demos/EventHandlersDemoTab.tsx +5 -0
  67. package/src/displaybox/demos/ExternalDragDropDemoTab.tsx +5 -0
  68. package/src/displaybox/demos/LayoutLabelReservedSpaceDemoTab.tsx +291 -0
  69. package/src/displaybox/demos/LinkCancelDemoTab.tsx +5 -0
  70. package/src/displaybox/demos/ObstacleRoutingDemoTab.tsx +11 -10
  71. package/src/displaybox/demos/ShapeHoverControlsDemoTab.tsx +6 -1
  72. package/src/displaybox/demos/SimpleDemo.tsx +5 -0
  73. package/src/displaybox/demos/SvgPathDemoTab.tsx +5 -0
  74. package/src/displaybox/demos/TextLayoutDemoTab.tsx +6 -1
  75. package/src/displaybox/demos/VertexControlLinkSessionDemoTab.tsx +302 -0
  76. package/src/displaybox/demos/asymmetricPortMultiAnchorDemo.ts +357 -0
  77. package/src/displaybox/demos/autoLayoutDemo.ts +23 -5
  78. package/src/displaybox/demos/index.tsx +110 -80
  79. package/src/displaybox/demos/labelStyleDemo.ts +101 -0
  80. package/src/displaybox/demos/layoutLabelReservedSpaceDemo.ts +121 -0
  81. package/src/displaybox/demos/obstacleRoutingDemo.ts +212 -176
  82. package/src/displaybox/demos/portPositionLimitsDemo.ts +211 -0
  83. package/src/displaybox/demos/vertexControlLinkSessionDemo.ts +145 -0
@@ -1,4 +1,4 @@
1
- import { DiagramEngineHandle, DiagramState, ElementShapeHoverControlActivationEvent, ElementShapeHoverControlInteractionEvent, ElementShapeHoverControls, EngineChangeEvent, EngineSelectionEvent } from './types';
1
+ import { DiagramEngineHandle, Point, DiagramState, ElementShapeHoverControlActivationEvent, ElementShapeHoverControlInteractionEvent, ElementShapeHoverControls, EngineChangeEvent, EngineSelectionEvent } from './types';
2
2
  import { type BuiltInShapeKind } from '../shapes';
3
3
  export type SimpleShape = {
4
4
  id: string;
@@ -19,7 +19,25 @@ export type DiagramEditorConfig = {
19
19
  onChange?: (event: EngineChangeEvent) => void;
20
20
  onSelection?: (event: EngineSelectionEvent) => void;
21
21
  };
22
+ export type DiagramImageExportOptions = {
23
+ mimeType?: string;
24
+ quality?: number;
25
+ pixelRatio?: number;
26
+ x?: number;
27
+ y?: number;
28
+ width?: number;
29
+ height?: number;
30
+ fitToContent?: boolean | {
31
+ padding?: number;
32
+ };
33
+ };
22
34
  export type DiagramEditorHandle = DiagramEngineHandle & {
35
+ startLinkFromPort: (sourcePortId: string, pointer?: Point) => void;
36
+ updateLinkPreview: (pointer: Point) => void;
37
+ completeLinkToPort: (targetPortId: string) => void;
38
+ completeLinkToElement: (targetElementId: string, pointer: Point) => void;
39
+ cancelLink: () => void;
40
+ exportImage: (options?: DiagramImageExportOptions) => string;
23
41
  resize: (width: number, height: number) => void;
24
42
  setElementShapeHoverControls: (controls?: ElementShapeHoverControls) => void;
25
43
  destroy: () => void;
@@ -1,4 +1,4 @@
1
1
  export * from './types';
2
2
  export { createDiagramEngine } from '../engine/DiagramEngine';
3
3
  export { createDiagramEditor } from './createDiagramEditor';
4
- export type { DiagramEditorConfig, DiagramEditorHandle, SimpleShape } from './createDiagramEditor';
4
+ export type { DiagramEditorConfig, DiagramEditorHandle, DiagramImageExportOptions, SimpleShape, } from './createDiagramEditor';
@@ -22,6 +22,7 @@ export type DiagramContainer = {
22
22
  export type MoveConstraint = 'free' | 'inside' | 'border';
23
23
  export type BorderSide = 'left' | 'right' | 'top' | 'bottom';
24
24
  export type HostAnchorPreset = 'vertices' | 'cardinal';
25
+ export type PortLinkAttachMode = 'external' | 'internal';
25
26
  export type PortAnchor = {
26
27
  id: string;
27
28
  position: Point;
@@ -29,10 +30,32 @@ export type PortAnchor = {
29
30
  normal?: Point;
30
31
  meta?: Record<string, unknown>;
31
32
  };
33
+ export type PortBorderTransformContext = {
34
+ side: BorderSide;
35
+ normal: Point;
36
+ hostRect: Rect;
37
+ attachMode: PortLinkAttachMode;
38
+ effectiveLinkAttachPoint: Point;
39
+ placementPoint: Point;
40
+ rotationPivot: Point;
41
+ portSize?: Size;
42
+ };
43
+ export type PortBorderTransformResult = {
44
+ rotation?: number;
45
+ offset?: Point;
46
+ };
32
47
  export type PortAnchorConstraint = {
33
48
  preset: HostAnchorPreset;
34
49
  fallback?: 'nearest';
35
50
  };
51
+ export type PositionAxisLimit = {
52
+ min?: number;
53
+ max?: number;
54
+ };
55
+ export type PortPositionLimits = {
56
+ x?: PositionAxisLimit;
57
+ y?: PositionAxisLimit;
58
+ };
36
59
  export type ResolvePortAnchorsOptions = {
37
60
  preset: HostAnchorPreset;
38
61
  };
@@ -143,6 +166,7 @@ export type ElementShapeHoverControlActivationEvent = {
143
166
  export type ElementPortMovementPolicy = {
144
167
  moveMode: MoveConstraint | 'anchors';
145
168
  anchorConstraint?: PortAnchorConstraint;
169
+ positionLimits?: PortPositionLimits;
146
170
  };
147
171
  export type LinkRoutingMode = 'auto' | 'manual';
148
172
  export type AnchorReference = 'top-left' | 'center';
@@ -153,6 +177,15 @@ export type ElementLayoutMode = 'manual' | 'horizontal' | 'vertical';
153
177
  export type ElementLayoutAlign = 'start' | 'center' | 'end';
154
178
  export type ElementLayoutChildFitMainAxis = 'none' | 'distribute';
155
179
  export type ElementLayoutChildFitCrossAxis = 'none' | 'stretch';
180
+ export type ElementLayoutLabelReservedSpaceMode = 'none' | 'fixed' | 'flexible';
181
+ export type ElementLayoutLabelReservedSpacePlacement = 'top';
182
+ export type ElementLayoutLabelReservedSpace = {
183
+ mode?: ElementLayoutLabelReservedSpaceMode;
184
+ placement?: ElementLayoutLabelReservedSpacePlacement;
185
+ size?: number;
186
+ minSize?: number;
187
+ maxSize?: number;
188
+ };
156
189
  export type TextLayoutBoundsMode = 'owner-width' | 'owner-box' | 'fixed';
157
190
  export type TextLayoutWrapMode = 'none' | 'word' | 'char';
158
191
  export type TextLayoutOverflowMode = 'clip' | 'ellipsis-end' | 'ellipsis-middle' | 'ellipsis-start';
@@ -168,6 +201,7 @@ export type ElementLayout = {
168
201
  childFitCrossAxis?: ElementLayoutChildFitCrossAxis;
169
202
  childFitMinSize?: Partial<Size>;
170
203
  childFitMaxSize?: Partial<Size>;
204
+ labelReservedSpace?: ElementLayoutLabelReservedSpace;
171
205
  };
172
206
  export type TextLayout = {
173
207
  boundsMode?: TextLayoutBoundsMode;
@@ -222,6 +256,11 @@ export type PortData = {
222
256
  moveMode?: MoveConstraint;
223
257
  anchorCenter?: boolean;
224
258
  orientToHostBorder?: boolean;
259
+ placementPoint?: Point;
260
+ linkAttachPoint?: Point;
261
+ externalLinkAttachPoint?: Point;
262
+ internalLinkAttachPoint?: Point;
263
+ rotationPivot?: Point;
225
264
  currentAnchorId?: string;
226
265
  };
227
266
  export type ShapeDrawContext = {
@@ -441,7 +480,9 @@ export type DiagramEngineHandle = {
441
480
  svgSize?: Size;
442
481
  projectToBorder?: (point: Point, rect: Rect) => Point;
443
482
  resolveBorderSide?: (point: Point, rect: Rect) => BorderSide;
483
+ resolveBorderNormal?: (point: Point, rect: Rect) => Point;
444
484
  resolvePortAnchors?: (rect: Rect, options: ResolvePortAnchorsOptions) => PortAnchor[];
485
+ resolvePortBorderTransform?: (context: PortBorderTransformContext) => PortBorderTransformResult | undefined;
445
486
  resolveHoverGeometry?: (rect: Rect) => ShapeHoverGeometry | undefined;
446
487
  resolveEllipseMidPoints?: (rect: Rect) => ShapeEllipseMidPointTarget[] | undefined;
447
488
  }) => void;
@@ -13,6 +13,10 @@ type ControlsProps = {
13
13
  onManualRender: () => void;
14
14
  onToggleLinkRouting: () => void;
15
15
  onAction: (action: DemoAction) => void;
16
+ onExportImage?: () => void;
17
+ onClearExportPreview?: () => void;
18
+ exportPreviewDataUrl?: string | null;
19
+ exportError?: string | null;
16
20
  };
17
- declare const DisplayBoxControls: ({ actions, snapEnabled, selectedLinkRouting, canToggleLinkRouting, onReload, onZoomIn, onZoomOut, onResetViewport, onToggleSnap, onManualRender, onToggleLinkRouting, onAction, }: ControlsProps) => React.JSX.Element;
21
+ declare const DisplayBoxControls: ({ actions, snapEnabled, selectedLinkRouting, canToggleLinkRouting, onReload, onZoomIn, onZoomOut, onResetViewport, onToggleSnap, onManualRender, onToggleLinkRouting, onAction, onExportImage, onClearExportPreview, exportPreviewDataUrl, exportError, }: ControlsProps) => React.JSX.Element;
18
22
  export default DisplayBoxControls;
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ declare const AsymmetricPortMultiAnchorDemo: () => React.JSX.Element;
3
+ export default AsymmetricPortMultiAnchorDemo;
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ declare const LayoutLabelReservedSpaceDemo: () => React.JSX.Element;
3
+ export default LayoutLabelReservedSpaceDemo;
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ declare const VertexControlLinkSessionDemo: () => React.JSX.Element;
3
+ export default VertexControlLinkSessionDemo;
@@ -0,0 +1,31 @@
1
+ import type { DiagramState, Point } from '../../api';
2
+ import type { DemoConfig } from '../types';
3
+ export declare const asymmetricPortMultiAnchorDemoId = "asymmetric-port-multi-anchor";
4
+ export declare const asymmetricPortDefaultVariantId = "classic";
5
+ export type AsymmetricPortShapeVariant = {
6
+ id: string;
7
+ label: string;
8
+ description: string;
9
+ shapeId: string;
10
+ svgPath: string;
11
+ svgSize: {
12
+ width: number;
13
+ height: number;
14
+ };
15
+ placementPoint: Point;
16
+ externalLinkAttachPoint: Point;
17
+ internalLinkAttachPoint: Point;
18
+ rotationPivot: Point;
19
+ };
20
+ export declare const asymmetricPortShapeVariants: AsymmetricPortShapeVariant[];
21
+ export declare const resolveAsymmetricPortShapeVariant: (variantId?: string) => AsymmetricPortShapeVariant;
22
+ export declare const asymmetricPortMultiAnchorShapeId: string;
23
+ export declare const asymmetricPortMultiAnchorShapeSvgPath: string;
24
+ export declare const asymmetricPortMultiAnchorShapeSize: {
25
+ width: number;
26
+ height: number;
27
+ };
28
+ export declare const multiAnchorHostId = "multi-anchor-host";
29
+ export declare const multiAnchorExternalPortId = "multi-anchor-port-external";
30
+ export declare const createAsymmetricPortMultiAnchorState: (showLegacyComparison?: boolean, variantId?: string) => DiagramState;
31
+ export declare const asymmetricPortMultiAnchorDemoConfig: DemoConfig;
@@ -0,0 +1,2 @@
1
+ import type { DemoConfig } from '../types';
2
+ export declare const labelStyleDemoConfig: DemoConfig;
@@ -0,0 +1,11 @@
1
+ import type { DemoConfig } from '../types';
2
+ export declare const layoutReservedDemoIds: {
3
+ readonly parent: "layout-lane-parent";
4
+ readonly childA: "layout-lane-child-a";
5
+ readonly childB: "layout-lane-child-b";
6
+ readonly nestedParent: "layout-lane-nested-parent";
7
+ readonly nestedChildA: "layout-lane-nested-child-a";
8
+ readonly nestedChildB: "layout-lane-nested-child-b";
9
+ readonly parentLabel: "layout-lane-parent-label";
10
+ };
11
+ export declare const layoutLabelReservedSpaceDemoConfig: DemoConfig;
@@ -0,0 +1,2 @@
1
+ import type { DemoConfig } from '../types';
2
+ export declare const portPositionLimitsDemoConfig: DemoConfig;
@@ -0,0 +1,12 @@
1
+ import type { DemoConfig } from '../types';
2
+ export declare const vertexSessionDemoIds: {
3
+ readonly source: "vertex-session-source";
4
+ readonly portTarget: "vertex-session-port-target";
5
+ readonly elementTarget: "vertex-session-element-target";
6
+ readonly nativeSource: "vertex-session-native-source";
7
+ readonly nativeTarget: "vertex-session-native-target";
8
+ readonly existingTargetPort: "vertex-session-existing-target-port";
9
+ readonly nativeSourcePort: "vertex-session-native-source-port";
10
+ readonly nativeTargetPort: "vertex-session-native-target-port";
11
+ };
12
+ export declare const vertexControlLinkSessionDemoConfig: DemoConfig;
@@ -13,6 +13,8 @@ type UseDemoControlsArgs = {
13
13
  declare const useDemoControls: ({ demo, editorRef, diagramState, selection, snapEnabled, setSnapEnabled, actionHelpers, }: UseDemoControlsArgs) => {
14
14
  selectedLinkRouting: import("../api").LinkRoutingMode;
15
15
  canToggleLinkRouting: boolean;
16
+ exportPreviewDataUrl: string | null;
17
+ exportError: string | null;
16
18
  handleAction: (action: DemoAction) => void;
17
19
  handleReload: () => void;
18
20
  handleZoomIn: () => void;
@@ -21,6 +23,8 @@ declare const useDemoControls: ({ demo, editorRef, diagramState, selection, snap
21
23
  handleToggleSnap: () => void;
22
24
  handleManualRender: () => void;
23
25
  handleToggleLinkRouting: () => void;
26
+ handleExportImage: () => void;
27
+ handleClearExportPreview: () => void;
24
28
  snapEnabled: boolean;
25
29
  };
26
30
  export default useDemoControls;
@@ -19,6 +19,8 @@ export default class AutoLayoutService {
19
19
  applyLayoutCascade(startParentId: string | null): AutoLayoutResult;
20
20
  applyAllLayouts(): AutoLayoutResult;
21
21
  private resolveLayoutPadding;
22
+ private resolveLabelReservedTopLane;
23
+ private resolveFlexibleLabelLaneFromText;
22
24
  private clampLayoutSize;
23
25
  private distributeLayoutSizes;
24
26
  }
@@ -78,6 +78,10 @@ export default class DiagramEngine {
78
78
  height: number;
79
79
  };
80
80
  getPortWorldPosition(id: string): Point | null;
81
+ getPortLinkWorldPosition(id: string, options?: {
82
+ oppositePortId?: string;
83
+ attachMode?: 'external' | 'internal';
84
+ }): Point | null;
81
85
  getTextWorldPosition(id: string): Point | null;
82
86
  getPortElementId(portId: string): string | null;
83
87
  deleteSelection(): void;
@@ -111,22 +115,29 @@ export default class DiagramEngine {
111
115
  private collectResizedElementSizes;
112
116
  private resolveBorderPortResizeProjection;
113
117
  private resolveConstrainedPortRelativePosition;
118
+ private applyPortPositionLimits;
119
+ private resolveBorderPositionWithLimits;
120
+ private isPointWithinPositionLimits;
121
+ private filterAnchorsByPositionLimits;
114
122
  private resolveEffectivePortMoveMode;
115
123
  private resolvePortAnchorsForElement;
116
124
  private resolveNearestPortAnchor;
117
125
  private findNearestPortAnchor;
118
126
  private resolveAnchoredPortResizeProjection;
119
127
  private resolveTextPresentation;
128
+ private resolveAllTextPresentationPatches;
120
129
  private emitSelection;
121
130
  private applyLayoutForParent;
122
131
  private applyLayoutCascade;
123
132
  private applyAllLayouts;
133
+ private hasFlexibleLabelReservedSpace;
124
134
  private updateLinksForPorts;
125
135
  private collectElementPortIds;
126
136
  private computeAutoRoute;
127
137
  private constrainPortToHostBorder;
128
138
  private projectPointToHostBorder;
129
139
  private routeLinksWithEmptyPoints;
140
+ private normalizePortsForHostPolicies;
130
141
  private computeRemovalDiff;
131
142
  private emitEntityDeletionEvents;
132
143
  }
@@ -1,4 +1,4 @@
1
- import { DiagramPatch, LinkData, Point } from '../api/types';
1
+ import { DiagramPatch, LinkData, Point, PortLinkAttachMode } from '../api/types';
2
2
  import DiagramModel from '../models/DiagramModel';
3
3
  import { ShapeRegistry } from '../renderer/RenderTypes';
4
4
  import { RouterStrategy } from '../strategies/RouterStrategy';
@@ -18,8 +18,13 @@ export default class LinkRoutingService {
18
18
  setRouter(router: RouterStrategy): void;
19
19
  updateLinksForPorts(portIds: string[]): DiagramPatch[];
20
20
  routeLinksWithEmptyPoints(): DiagramPatch[];
21
+ getPortLinkWorldPosition(portId: string, options?: {
22
+ oppositePortId?: string;
23
+ attachMode?: PortLinkAttachMode;
24
+ }): Point | null;
21
25
  computeAutoRoute(link: LinkData, source: Point, target: Point): Point[];
22
26
  private resolveLinkPointsForUpdate;
27
+ private resolveLinkEndpoints;
23
28
  private updateManualRoute;
24
29
  private buildRouteContext;
25
30
  private resolveEndpointGeometry;
@@ -27,6 +32,9 @@ export default class LinkRoutingService {
27
32
  private resolveElementShape;
28
33
  private isPointOnProjectedBorder;
29
34
  private getElementRect;
35
+ private resolveHostForPort;
36
+ private resolveAttachModeForPorts;
37
+ private isAncestorOf;
30
38
  private getAncestorChain;
31
39
  private getAncestorExclusions;
32
40
  private resolveRouteBounds;
@@ -10,6 +10,11 @@ export default class PortModel {
10
10
  moveMode?: MoveConstraint;
11
11
  anchorCenter?: boolean;
12
12
  orientToHostBorder: boolean;
13
+ placementPoint?: Point;
14
+ linkAttachPoint?: Point;
15
+ externalLinkAttachPoint?: Point;
16
+ internalLinkAttachPoint?: Point;
17
+ rotationPivot?: Point;
13
18
  currentAnchorId?: string;
14
19
  constructor(data: PortData);
15
20
  setPosition(position: Point): void;
@@ -1,4 +1,4 @@
1
- import { ElementData, Point, PortAnchor, PortData, Rect, ResolvePortAnchorsOptions, ShapeEllipseMidPointTarget, ShapeDrawContext, ShapeHoverGeometry } from '../api/types';
1
+ import { ElementData, Point, PortBorderTransformContext, PortBorderTransformResult, PortAnchor, PortData, Rect, ResolvePortAnchorsOptions, ShapeEllipseMidPointTarget, ShapeDrawContext, ShapeHoverGeometry } from '../api/types';
2
2
  import { BorderSide } from '../utils/borderGeometry';
3
3
  export type ShapeNodeSizeUpdateContext = {
4
4
  size: {
@@ -38,7 +38,9 @@ export type ShapeDefinition = {
38
38
  };
39
39
  projectToBorder?: (point: Point, rect: Rect) => Point;
40
40
  resolveBorderSide?: (point: Point, rect: Rect) => BorderSide;
41
+ resolveBorderNormal?: (point: Point, rect: Rect) => Point;
41
42
  resolvePortAnchors?: (rect: Rect, options: ResolvePortAnchorsOptions) => PortAnchor[];
43
+ resolvePortBorderTransform?: (context: PortBorderTransformContext) => PortBorderTransformResult | undefined;
42
44
  resolveHoverGeometry?: (rect: Rect) => ShapeHoverGeometry | undefined;
43
45
  resolveEllipseMidPoints?: (rect: Rect) => ShapeEllipseMidPointTarget[] | undefined;
44
46
  };
@@ -56,6 +56,7 @@ export default class KonvaInteraction {
56
56
  private onShapeHoverControlInteracted?;
57
57
  private onShapeHoverControlActivated?;
58
58
  private linkDragContext;
59
+ private programmaticLinkSession;
59
60
  private bound;
60
61
  private handlers;
61
62
  private windowHandlers;
@@ -70,9 +71,16 @@ export default class KonvaInteraction {
70
71
  private textEditor;
71
72
  private readonly dragThreshold;
72
73
  private readonly panSpeed;
74
+ private readonly occupiedVertexTolerance;
75
+ private emittingElementLinkEnded;
73
76
  private panKey;
74
77
  constructor(engine: DiagramEngine, config?: InteractionConfig);
75
78
  setShapeHoverControls(controls?: ElementShapeHoverControls): void;
79
+ startLinkFromPort(sourcePortId: string, pointer?: Point): void;
80
+ updateLinkPreview(pointer: Point): void;
81
+ completeLinkToPort(targetPortId: string): void;
82
+ completeLinkToElement(targetElementId: string, pointer: Point): void;
83
+ cancelLink(): void;
76
84
  private buildPointerInfo;
77
85
  bind(stage?: KonvaStageLike): void;
78
86
  dispose(): void;
@@ -102,6 +110,7 @@ export default class KonvaInteraction {
102
110
  private resolveTargetHoverCandidate;
103
111
  private resolveElementHoverCandidate;
104
112
  private resolveEligibleTargetIndices;
113
+ private resolveOccupiedVertexIndices;
105
114
  private resolveEligibleEllipseMidPoints;
106
115
  private resolveRotatedHoverGeometry;
107
116
  private resolveRotatedEllipseMidPoints;
@@ -122,7 +131,12 @@ export default class KonvaInteraction {
122
131
  private projectPointOnSegment;
123
132
  private applyMarqueeSelection;
124
133
  private applyPortConstraints;
134
+ private resolveLinkPreviewSource;
135
+ private resolveActiveLinkSession;
136
+ private finishLinkDragSession;
137
+ private emitElementLinkEndedSafely;
125
138
  private tryCreateLinkToPort;
139
+ private tryCreateLinkToElement;
126
140
  private createPortForLink;
127
141
  private createPlaceholderPort;
128
142
  private getElementById;
@@ -36,6 +36,17 @@ export default class KonvaNodeFactory {
36
36
  createPortNode(model: PortData): KonvaNodeLike;
37
37
  createLinkNode(model: LinkData): KonvaNodeLike;
38
38
  createTextNode(model: TextData): KonvaNodeLike;
39
+ createTextBackgroundNode(config: {
40
+ id: string;
41
+ x: number;
42
+ y: number;
43
+ width: number;
44
+ height: number;
45
+ fill: string;
46
+ stroke?: string;
47
+ strokeWidth?: number;
48
+ cornerRadius?: number | [number, number, number, number];
49
+ }): KonvaNodeLike;
39
50
  createHandleNode(config: {
40
51
  id: string;
41
52
  x: number;
@@ -79,5 +90,6 @@ export default class KonvaNodeFactory {
79
90
  }): KonvaNodeLike;
80
91
  private createDrawNode;
81
92
  private createSvgPathNode;
93
+ private resolveShapeRotation;
82
94
  private applyShapeBehaviorAttrs;
83
95
  }
@@ -61,6 +61,7 @@ export default class KonvaRenderer implements Renderer {
61
61
  private portNodes;
62
62
  private linkNodes;
63
63
  private textNodes;
64
+ private textBackgroundNodes;
64
65
  private selectedIds;
65
66
  private overlayLayer;
66
67
  private tempLinkNode;
@@ -118,9 +119,9 @@ export default class KonvaRenderer implements Renderer {
118
119
  private syncPorts;
119
120
  private syncLinks;
120
121
  private syncTexts;
122
+ private resolveTextBackgroundMeta;
121
123
  private updatePosition;
122
124
  private applyPortOrientation;
123
- private resolvePortBorderRotation;
124
125
  private resolveHostElement;
125
126
  private getNodeAttr;
126
127
  private updateSize;
@@ -1,4 +1,4 @@
1
- import { Point, PortAnchor, Rect, ResolvePortAnchorsOptions, ShapeEllipseMidPointTarget, ShapeHoverGeometry } from '../api/types';
1
+ import { Point, PortBorderTransformContext, PortBorderTransformResult, PortAnchor, Rect, ResolvePortAnchorsOptions, ShapeEllipseMidPointTarget, ShapeHoverGeometry } from '../api/types';
2
2
  import { ShapeNodeSizeUpdater, ShapeResizeNormalizeContext } from '../renderer/RenderTypes';
3
3
  import { BorderSide } from '../utils/borderGeometry';
4
4
  export type BuiltInShapeKind = 'rect' | 'circle' | 'ellipse' | 'diamond' | 'triangle' | 'pentagon' | 'hexagon';
@@ -46,7 +46,9 @@ export declare abstract class BuiltInShape {
46
46
  abstract createNode(context: ShapeCreateContext): unknown;
47
47
  projectToBorder(point: Point, rect: Rect): Point;
48
48
  resolveBorderSide(point: Point, rect: Rect): BorderSide;
49
+ resolveBorderNormal(point: Point, rect: Rect): Point;
49
50
  resolvePortAnchors(_rect: Rect, _options: ResolvePortAnchorsOptions): PortAnchor[];
51
+ resolvePortBorderTransform(_context: PortBorderTransformContext): PortBorderTransformResult | undefined;
50
52
  resolveHoverGeometry(_rect: Rect): ShapeHoverGeometry | undefined;
51
53
  resolveEllipseMidPoints(_rect: Rect): ShapeEllipseMidPointTarget[] | undefined;
52
54
  protected resolveShapeName(isPort: boolean): string;
@@ -16,6 +16,8 @@ export default class ObstacleRouter implements RouterStrategy {
16
16
  private pointsWithinBounds;
17
17
  private isPathClear;
18
18
  private computeStubEndpoint;
19
+ private computeAvailableStubLength;
20
+ private rectsEqual;
19
21
  private getNormal;
20
22
  private distanceToBounds;
21
23
  private distanceToObstacles;
@@ -0,0 +1,44 @@
1
+ import { BorderSide, Point, PortData, PortLinkAttachMode } from '../api/types';
2
+ import { ShapeRegistry } from '../renderer/RenderTypes';
3
+ type HostElementLike = {
4
+ id: string;
5
+ position: Point;
6
+ size: {
7
+ width: number;
8
+ height: number;
9
+ };
10
+ shapeId: string;
11
+ };
12
+ export type PortGeometryPoints = {
13
+ placementPoint: Point;
14
+ sharedLinkAttachPoint: Point;
15
+ effectiveLinkAttachPoint: Point;
16
+ rotationPivot: Point;
17
+ };
18
+ export type PortOrientationContext = {
19
+ localRotation: number;
20
+ rotation: number;
21
+ offset: Point;
22
+ nodeAnchorPoint: Point;
23
+ side?: BorderSide;
24
+ normal?: Point;
25
+ };
26
+ export declare const borderSideToNormal: (side: BorderSide) => Point;
27
+ export declare const resolvePortGeometryPoints: (port: Pick<PortData, 'placementPoint' | 'linkAttachPoint' | 'externalLinkAttachPoint' | 'internalLinkAttachPoint' | 'rotationPivot'>, attachMode: PortLinkAttachMode) => PortGeometryPoints;
28
+ export declare const resolvePortOrientationContext: (options: {
29
+ port: Pick<PortData, 'shapeId' | 'style' | 'moveMode' | 'orientToHostBorder' | 'anchorCenter' | 'placementPoint' | 'linkAttachPoint' | 'externalLinkAttachPoint' | 'internalLinkAttachPoint' | 'rotationPivot' | 'size'>;
30
+ worldPlacement: Point;
31
+ host: HostElementLike | null;
32
+ shapeRegistry: ShapeRegistry;
33
+ attachMode: PortLinkAttachMode;
34
+ }) => PortOrientationContext;
35
+ export declare const resolvePortWorldTransform: (options: {
36
+ port: Pick<PortData, 'placementPoint' | 'linkAttachPoint' | 'externalLinkAttachPoint' | 'internalLinkAttachPoint' | 'rotationPivot'>;
37
+ worldPlacement: Point;
38
+ attachMode: PortLinkAttachMode;
39
+ orientation: Pick<PortOrientationContext, 'localRotation' | 'rotation' | 'offset' | 'nodeAnchorPoint'>;
40
+ }) => {
41
+ nodePosition: Point;
42
+ linkAttachWorld: Point;
43
+ };
44
+ export {};
@@ -24,6 +24,7 @@ type DiagramContainer = {
24
24
  type MoveConstraint = 'free' | 'inside' | 'border';
25
25
  type BorderSide = 'left' | 'right' | 'top' | 'bottom';
26
26
  type HostAnchorPreset = 'vertices' | 'cardinal';
27
+ type PortLinkAttachMode = 'external' | 'internal';
27
28
  type PortAnchor = {
28
29
  id: string;
29
30
  position: Point;
@@ -31,10 +32,32 @@ type PortAnchor = {
31
32
  normal?: Point;
32
33
  meta?: Record<string, unknown>;
33
34
  };
35
+ type PortBorderTransformContext = {
36
+ side: BorderSide;
37
+ normal: Point;
38
+ hostRect: Rect;
39
+ attachMode: PortLinkAttachMode;
40
+ effectiveLinkAttachPoint: Point;
41
+ placementPoint: Point;
42
+ rotationPivot: Point;
43
+ portSize?: Size;
44
+ };
45
+ type PortBorderTransformResult = {
46
+ rotation?: number;
47
+ offset?: Point;
48
+ };
34
49
  type PortAnchorConstraint = {
35
50
  preset: HostAnchorPreset;
36
51
  fallback?: 'nearest';
37
52
  };
53
+ type PositionAxisLimit = {
54
+ min?: number;
55
+ max?: number;
56
+ };
57
+ type PortPositionLimits = {
58
+ x?: PositionAxisLimit;
59
+ y?: PositionAxisLimit;
60
+ };
38
61
  type ResolvePortAnchorsOptions = {
39
62
  preset: HostAnchorPreset;
40
63
  };
@@ -116,6 +139,7 @@ type ElementShapeHoverControls = {
116
139
  type ElementPortMovementPolicy = {
117
140
  moveMode: MoveConstraint | 'anchors';
118
141
  anchorConstraint?: PortAnchorConstraint;
142
+ positionLimits?: PortPositionLimits;
119
143
  };
120
144
  type LinkRoutingMode = 'auto' | 'manual';
121
145
  type AnchorReference = 'top-left' | 'center';
@@ -126,6 +150,15 @@ type ElementLayoutMode = 'manual' | 'horizontal' | 'vertical';
126
150
  type ElementLayoutAlign = 'start' | 'center' | 'end';
127
151
  type ElementLayoutChildFitMainAxis = 'none' | 'distribute';
128
152
  type ElementLayoutChildFitCrossAxis = 'none' | 'stretch';
153
+ type ElementLayoutLabelReservedSpaceMode = 'none' | 'fixed' | 'flexible';
154
+ type ElementLayoutLabelReservedSpacePlacement = 'top';
155
+ type ElementLayoutLabelReservedSpace = {
156
+ mode?: ElementLayoutLabelReservedSpaceMode;
157
+ placement?: ElementLayoutLabelReservedSpacePlacement;
158
+ size?: number;
159
+ minSize?: number;
160
+ maxSize?: number;
161
+ };
129
162
  type TextLayoutBoundsMode = 'owner-width' | 'owner-box' | 'fixed';
130
163
  type TextLayoutWrapMode = 'none' | 'word' | 'char';
131
164
  type TextLayoutOverflowMode = 'clip' | 'ellipsis-end' | 'ellipsis-middle' | 'ellipsis-start';
@@ -141,6 +174,7 @@ type ElementLayout = {
141
174
  childFitCrossAxis?: ElementLayoutChildFitCrossAxis;
142
175
  childFitMinSize?: Partial<Size>;
143
176
  childFitMaxSize?: Partial<Size>;
177
+ labelReservedSpace?: ElementLayoutLabelReservedSpace;
144
178
  };
145
179
  type TextLayout = {
146
180
  boundsMode?: TextLayoutBoundsMode;
@@ -195,6 +229,11 @@ type PortData = {
195
229
  moveMode?: MoveConstraint;
196
230
  anchorCenter?: boolean;
197
231
  orientToHostBorder?: boolean;
232
+ placementPoint?: Point;
233
+ linkAttachPoint?: Point;
234
+ externalLinkAttachPoint?: Point;
235
+ internalLinkAttachPoint?: Point;
236
+ rotationPivot?: Point;
198
237
  currentAnchorId?: string;
199
238
  };
200
239
  type ShapeDrawContext = {
@@ -414,7 +453,9 @@ type DiagramEngineHandle = {
414
453
  svgSize?: Size;
415
454
  projectToBorder?: (point: Point, rect: Rect) => Point;
416
455
  resolveBorderSide?: (point: Point, rect: Rect) => BorderSide;
456
+ resolveBorderNormal?: (point: Point, rect: Rect) => Point;
417
457
  resolvePortAnchors?: (rect: Rect, options: ResolvePortAnchorsOptions) => PortAnchor[];
458
+ resolvePortBorderTransform?: (context: PortBorderTransformContext) => PortBorderTransformResult | undefined;
418
459
  resolveHoverGeometry?: (rect: Rect) => ShapeHoverGeometry | undefined;
419
460
  resolveEllipseMidPoints?: (rect: Rect) => ShapeEllipseMidPointTarget[] | undefined;
420
461
  }) => void;
@@ -450,7 +491,25 @@ type SimpleShape = {
450
491
  kind: BuiltInShapeKind;
451
492
  style?: Record<string, unknown>;
452
493
  };
494
+ type DiagramImageExportOptions = {
495
+ mimeType?: string;
496
+ quality?: number;
497
+ pixelRatio?: number;
498
+ x?: number;
499
+ y?: number;
500
+ width?: number;
501
+ height?: number;
502
+ fitToContent?: boolean | {
503
+ padding?: number;
504
+ };
505
+ };
453
506
  type DiagramEditorHandle = DiagramEngineHandle & {
507
+ startLinkFromPort: (sourcePortId: string, pointer?: Point) => void;
508
+ updateLinkPreview: (pointer: Point) => void;
509
+ completeLinkToPort: (targetPortId: string) => void;
510
+ completeLinkToElement: (targetElementId: string, pointer: Point) => void;
511
+ cancelLink: () => void;
512
+ exportImage: (options?: DiagramImageExportOptions) => string;
454
513
  resize: (width: number, height: number) => void;
455
514
  setElementShapeHoverControls: (controls?: ElementShapeHoverControls) => void;
456
515
  destroy: () => void;