orcasvn-react-diagrams 0.2.4 → 0.2.6

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 (75) hide show
  1. package/CHANGELOG.md +42 -4
  2. package/README.md +15 -32
  3. package/ai/api-contract.json +88 -3
  4. package/ai/manifest.json +1 -1
  5. package/dist/cjs/examples.js +6519 -4423
  6. package/dist/cjs/index.js +1513 -120
  7. package/dist/cjs/types/api/createDiagramEditor.d.ts +4 -1
  8. package/dist/cjs/types/api/types.d.ts +43 -1
  9. package/dist/cjs/types/displaybox/demos/LinkColorPoolDemoTab.d.ts +3 -0
  10. package/dist/cjs/types/displaybox/demos/OffsetAnchorAvoidanceDemoTab.d.ts +3 -0
  11. package/dist/cjs/types/displaybox/demos/SimpleDemo.d.ts +4 -1
  12. package/dist/cjs/types/displaybox/demos/ZoomToFitElementsDemoTab.d.ts +3 -0
  13. package/dist/cjs/types/displaybox/demos/linkColorPoolDemo.d.ts +2 -0
  14. package/dist/cjs/types/displaybox/demos/offsetAnchorAvoidanceDemo.d.ts +4 -0
  15. package/dist/cjs/types/displaybox/demos/textDemo.d.ts +3 -0
  16. package/dist/cjs/types/displaybox/demos/zoomToFitElementsDemo.d.ts +4 -0
  17. package/dist/cjs/types/displaybox/types.d.ts +3 -1
  18. package/dist/cjs/types/displaybox/useDemoEditor.d.ts +4 -2
  19. package/dist/cjs/types/engine/AutoLayoutService.d.ts +59 -2
  20. package/dist/cjs/types/engine/DiagramEngine.d.ts +20 -1
  21. package/dist/cjs/types/engine/LinkRoutingService.d.ts +9 -0
  22. package/dist/cjs/types/models/TextModel.d.ts +1 -0
  23. package/dist/cjs/types/renderer/konva/KonvaInteraction.d.ts +6 -0
  24. package/dist/cjs/types/strategies/ObstacleRouter.d.ts +2 -0
  25. package/dist/cjs/types/strategies/RouterStrategy.d.ts +10 -0
  26. package/dist/esm/examples.js +6519 -4423
  27. package/dist/esm/examples.js.map +1 -1
  28. package/dist/esm/index.js +1513 -120
  29. package/dist/esm/index.js.map +1 -1
  30. package/dist/esm/types/api/createDiagramEditor.d.ts +4 -1
  31. package/dist/esm/types/api/types.d.ts +43 -1
  32. package/dist/esm/types/displaybox/demos/LinkColorPoolDemoTab.d.ts +3 -0
  33. package/dist/esm/types/displaybox/demos/OffsetAnchorAvoidanceDemoTab.d.ts +3 -0
  34. package/dist/esm/types/displaybox/demos/SimpleDemo.d.ts +4 -1
  35. package/dist/esm/types/displaybox/demos/ZoomToFitElementsDemoTab.d.ts +3 -0
  36. package/dist/esm/types/displaybox/demos/linkColorPoolDemo.d.ts +2 -0
  37. package/dist/esm/types/displaybox/demos/offsetAnchorAvoidanceDemo.d.ts +4 -0
  38. package/dist/esm/types/displaybox/demos/textDemo.d.ts +3 -0
  39. package/dist/esm/types/displaybox/demos/zoomToFitElementsDemo.d.ts +4 -0
  40. package/dist/esm/types/displaybox/types.d.ts +3 -1
  41. package/dist/esm/types/displaybox/useDemoEditor.d.ts +4 -2
  42. package/dist/esm/types/engine/AutoLayoutService.d.ts +59 -2
  43. package/dist/esm/types/engine/DiagramEngine.d.ts +20 -1
  44. package/dist/esm/types/engine/LinkRoutingService.d.ts +9 -0
  45. package/dist/esm/types/models/TextModel.d.ts +1 -0
  46. package/dist/esm/types/renderer/konva/KonvaInteraction.d.ts +6 -0
  47. package/dist/esm/types/strategies/ObstacleRouter.d.ts +2 -0
  48. package/dist/esm/types/strategies/RouterStrategy.d.ts +10 -0
  49. package/dist/examples.d.ts +56 -1
  50. package/dist/index.d.ts +60 -2
  51. package/docs/API_CONTRACT.md +73 -3
  52. package/docs/CAPABILITIES.md +8 -0
  53. package/docs/COMMANDS_EVENTS.md +8 -0
  54. package/docs/DOCUMENTATION_WORKFLOW.md +4 -1
  55. package/docs/INTEGRATION_PLAYBOOK.md +3 -0
  56. package/docs/STATE_INVARIANTS.md +4 -0
  57. package/package.json +1 -1
  58. package/src/displaybox/demos/AutoLayoutDemoTab.tsx +515 -381
  59. package/src/displaybox/demos/EngineEventsDemoTab.tsx +12 -11
  60. package/src/displaybox/demos/LinkColorPoolDemoTab.tsx +49 -0
  61. package/src/displaybox/demos/ObstacleRoutingDemoTab.tsx +52 -31
  62. package/src/displaybox/demos/OffsetAnchorAvoidanceDemoTab.tsx +30 -0
  63. package/src/displaybox/demos/SimpleDemo.tsx +18 -13
  64. package/src/displaybox/demos/TextLayoutDemoTab.tsx +18 -1
  65. package/src/displaybox/demos/ZoomToFitElementsDemoTab.tsx +29 -0
  66. package/src/displaybox/demos/autoLayoutDemo.ts +62 -26
  67. package/src/displaybox/demos/index.tsx +81 -57
  68. package/src/displaybox/demos/linkColorPoolDemo.ts +122 -0
  69. package/src/displaybox/demos/obstacleRoutingDemo.ts +77 -1
  70. package/src/displaybox/demos/offsetAnchorAvoidanceDemo.ts +211 -0
  71. package/src/displaybox/demos/routingDemo.ts +5 -5
  72. package/src/displaybox/demos/shared.ts +17 -12
  73. package/src/displaybox/demos/textDemo.ts +6 -2
  74. package/src/displaybox/demos/zoomToFitElementsDemo.ts +83 -0
  75. package/src/displaybox/types.ts +10 -8
package/dist/index.d.ts CHANGED
@@ -19,7 +19,16 @@ type ClientRectLike = {
19
19
  type DiagramContainer = {
20
20
  getBoundingClientRect: () => ClientRectLike;
21
21
  };
22
+ type ViewportFitOptions = {
23
+ padding?: number;
24
+ minZoom?: number;
25
+ maxZoom?: number;
26
+ };
22
27
  type MoveConstraint = 'free' | 'inside' | 'border';
28
+ type TextInteractionPolicy = {
29
+ movable?: boolean;
30
+ editable?: boolean;
31
+ };
23
32
  type BorderSide$1 = 'left' | 'right' | 'top' | 'bottom';
24
33
  type HostAnchorPreset = 'vertices' | 'cardinal';
25
34
  type PortLinkAttachMode = 'external' | 'internal';
@@ -173,10 +182,21 @@ type AnchorReference = 'top-left' | 'center';
173
182
  type RerouteLinksOptions = {
174
183
  includeManual?: boolean;
175
184
  };
176
- type ElementLayoutMode = 'manual' | 'horizontal' | 'vertical';
185
+ type LinkRouteRefreshMode = 'mutation-only' | 'redraw-two-endpoint-change';
186
+ type LinkRouteRefreshPolicy = {
187
+ mode?: LinkRouteRefreshMode;
188
+ includeManual?: boolean;
189
+ };
190
+ type LinkColorPoolPolicy = {
191
+ enabled?: boolean;
192
+ colors?: string[];
193
+ };
194
+ type ElementLayoutMode = 'manual' | 'horizontal' | 'vertical' | 'grid';
177
195
  type ElementLayoutAlign = 'start' | 'center' | 'end';
178
196
  type ElementLayoutChildFitMainAxis = 'none' | 'distribute';
179
197
  type ElementLayoutChildFitCrossAxis = 'none' | 'stretch';
198
+ type ElementLayoutAutoResizeMode = 'grow' | 'grow-shrink';
199
+ type ElementLayoutGridRowTemplate = number;
180
200
  type ElementLayoutLabelReservedSpaceMode = 'none' | 'fixed' | 'flexible';
181
201
  type ElementLayoutLabelReservedSpacePlacement = 'top';
182
202
  type ElementLayoutLabelReservedSpace = {
@@ -197,8 +217,15 @@ type ElementLayout = {
197
217
  };
198
218
  gap?: number;
199
219
  align?: ElementLayoutAlign;
220
+ autoResize?: ElementLayoutAutoResizeMode;
221
+ gridTemplate?: ElementLayoutGridRowTemplate[];
222
+ gridChildWidthResizeEnabled?: boolean;
200
223
  childFitMainAxis?: ElementLayoutChildFitMainAxis;
201
224
  childFitCrossAxis?: ElementLayoutChildFitCrossAxis;
225
+ childMinWidth?: number;
226
+ childMaxWidth?: number;
227
+ childMinHeight?: number;
228
+ childMaxHeight?: number;
202
229
  childFitMinSize?: Partial<Size>;
203
230
  childFitMaxSize?: Partial<Size>;
204
231
  labelReservedSpace?: ElementLayoutLabelReservedSpace;
@@ -283,6 +310,7 @@ type TextData = {
283
310
  size?: Size;
284
311
  style?: Record<string, unknown>;
285
312
  ownerId?: string | null;
313
+ interaction?: TextInteractionPolicy;
286
314
  layout?: TextLayout;
287
315
  displayContent?: string;
288
316
  displayOffset?: Point;
@@ -356,6 +384,19 @@ type ElementResizedEvent = {
356
384
  oldSize: Size;
357
385
  newSize: Size;
358
386
  };
387
+ type GridLayoutChangedReason = 'child-resize-split' | 'child-resize-redistribute';
388
+ type GridRowSnapshot = {
389
+ childIds: string[];
390
+ };
391
+ type GridLayoutChangedEvent = {
392
+ parentId: string;
393
+ triggerChildId: string;
394
+ reason: GridLayoutChangedReason;
395
+ beforeRows: GridRowSnapshot[];
396
+ afterRows: GridRowSnapshot[];
397
+ beforeGridTemplate?: ElementLayoutGridRowTemplate[];
398
+ afterGridTemplate: ElementLayoutGridRowTemplate[];
399
+ };
359
400
  type ElementDeletedEvent = {
360
401
  elementId: string;
361
402
  };
@@ -424,6 +465,7 @@ type EngineEventMap = {
424
465
  elementDragged: ElementDropEvent;
425
466
  elementMoved: ElementMovedEvent;
426
467
  elementResized: ElementResizedEvent;
468
+ gridLayoutChanged: GridLayoutChangedEvent;
427
469
  elementDeleted: ElementDeletedEvent;
428
470
  portDeleted: PortDeletedEvent;
429
471
  linkDeleted: LinkDeletedEvent;
@@ -568,6 +610,7 @@ declare class TextModel {
568
610
  size?: Size;
569
611
  style?: Record<string, unknown>;
570
612
  ownerId?: string | null;
613
+ interaction?: TextData['interaction'];
571
614
  layout?: TextData['layout'];
572
615
  displayContent?: string;
573
616
  displayOffset?: Point;
@@ -646,6 +689,15 @@ type RouteEndpoint = {
646
689
  rect?: Rect;
647
690
  onEdgeSide?: 'left' | 'right' | 'top' | 'bottom';
648
691
  };
692
+ type CommonAncestorCorridorHint = {
693
+ ancestorId: string;
694
+ bounds: Rect;
695
+ sourceBranchId: string;
696
+ targetBranchId: string;
697
+ sourceBranchRect: Rect;
698
+ targetBranchRect: Rect;
699
+ axis: 'horizontal' | 'vertical';
700
+ };
649
701
  type RouteContext = {
650
702
  linkId: string;
651
703
  sourcePortId: string;
@@ -654,6 +706,7 @@ type RouteContext = {
654
706
  bounds?: Rect;
655
707
  sourceEndpoint?: RouteEndpoint;
656
708
  targetEndpoint?: RouteEndpoint;
709
+ commonAncestorCorridor?: CommonAncestorCorridorHint;
657
710
  };
658
711
  interface RouterStrategy {
659
712
  route(source: Point, target: Point, context?: RouteContext): Point[];
@@ -727,6 +780,8 @@ type DiagramEngineConfig = {
727
780
  snapper?: SnapStrategy;
728
781
  shapeRegistry?: ShapeRegistry;
729
782
  textMeasurer?: TextMeasurer;
783
+ linkRouteRefreshPolicy?: LinkRouteRefreshPolicy;
784
+ linkColorPoolPolicy?: LinkColorPoolPolicy;
730
785
  };
731
786
  declare const createDiagramEngine: (config: DiagramEngineConfig) => DiagramEngineHandle;
732
787
 
@@ -750,6 +805,8 @@ type DiagramEditorConfig = {
750
805
  onElementShapeHoverControlActivated?: (event: ElementShapeHoverControlActivationEvent) => void;
751
806
  onChange?: (event: EngineChangeEvent) => void;
752
807
  onSelection?: (event: EngineSelectionEvent) => void;
808
+ linkRouteRefreshPolicy?: LinkRouteRefreshPolicy;
809
+ linkColorPoolPolicy?: LinkColorPoolPolicy;
753
810
  };
754
811
  type DiagramImageExportOptions = {
755
812
  mimeType?: string;
@@ -769,6 +826,7 @@ type DiagramEditorHandle = DiagramEngineHandle & {
769
826
  completeLinkToPort: (targetPortId: string) => void;
770
827
  completeLinkToElement: (targetElementId: string, pointer: Point) => void;
771
828
  cancelLink: () => void;
829
+ zoomToFitElements: (options?: ViewportFitOptions) => void;
772
830
  exportImage: (options?: DiagramImageExportOptions) => string;
773
831
  resize: (width: number, height: number) => void;
774
832
  setElementShapeHoverControls: (controls?: ElementShapeHoverControls) => void;
@@ -776,4 +834,4 @@ type DiagramEditorHandle = DiagramEngineHandle & {
776
834
  };
777
835
  declare const createDiagramEditor: (config: DiagramEditorConfig) => DiagramEditorHandle;
778
836
 
779
- export { type AnchorReference, type BorderSide$1 as BorderSide, type ClientRectLike, type DiagramContainer, type DiagramEditorConfig, type DiagramEditorHandle, type DiagramEngineHandle, type DiagramImageExportOptions, type DiagramPatch, type DiagramState, type EdgeHoverControl, type ElementData, type ElementDeletedEvent, type ElementDropEvent, type ElementLayout, type ElementLayoutAlign, type ElementLayoutChildFitCrossAxis, type ElementLayoutChildFitMainAxis, type ElementLayoutLabelReservedSpace, type ElementLayoutLabelReservedSpaceMode, type ElementLayoutLabelReservedSpacePlacement, type ElementLayoutMode, type ElementLinkConnectingEvent, type ElementLinkEndedEvent, type ElementLinkStartedEvent, type ElementMovedEvent, type ElementPointerEvent, type ElementPortMovementPolicy, type ElementResizedEvent, type ElementSelectedEvent, type ElementShapeControlDragEvent, type ElementShapeControlEventType, type ElementShapeHoverControlActivationEvent, type ElementShapeHoverControlInteractionEvent, type ElementShapeHoverControls, EllipseMidPoint, type EngineChangeEvent, type EngineConfigEvent, type EngineEventMap, type EnginePointerInfo, type EngineSelectionEvent, type HostAnchorPreset, type HoverControlIcon, type LinkData, type LinkDeletedEvent, type LinkRoutingMode, type MoveConstraint, type OverlayShapeConfig, type OverlayShapeHandle, type PaperClickEvent, type Point, type PortAnchor, type PortAnchorConstraint, type PortBorderTransformContext, type PortBorderTransformResult, type PortData, type PortDeletedEvent, type PortLinkAttachMode, type PortMouseEvent, type PortMovedEvent, type PortPositionLimits, type PortSelectedEvent, type PositionAxisLimit, type Rect, type RerouteLinksOptions, type ResolvePortAnchorsOptions, type ShapeControlDefinition, type ShapeControlTargetKind, type ShapeControlVisibilityTrigger, type ShapeDrawContext, type ShapeEdgeTarget, type ShapeEllipseMidPointTarget, type ShapeHoverGeometry, type ShapeVertexTarget, type SimpleShape, type Size, type TextData, type TextDeletedEvent, type TextLayout, type TextLayoutBoundsMode, type TextLayoutOverflowMode, type TextLayoutWrapMode, type TextSelectedEvent, type TextUpdatedEvent, type VertexHoverControl, createDiagramEditor, createDiagramEngine };
837
+ export { type AnchorReference, type BorderSide$1 as BorderSide, type ClientRectLike, type DiagramContainer, type DiagramEditorConfig, type DiagramEditorHandle, type DiagramEngineHandle, type DiagramImageExportOptions, type DiagramPatch, type DiagramState, type EdgeHoverControl, type ElementData, type ElementDeletedEvent, type ElementDropEvent, type ElementLayout, type ElementLayoutAlign, type ElementLayoutAutoResizeMode, type ElementLayoutChildFitCrossAxis, type ElementLayoutChildFitMainAxis, type ElementLayoutGridRowTemplate, type ElementLayoutLabelReservedSpace, type ElementLayoutLabelReservedSpaceMode, type ElementLayoutLabelReservedSpacePlacement, type ElementLayoutMode, type ElementLinkConnectingEvent, type ElementLinkEndedEvent, type ElementLinkStartedEvent, type ElementMovedEvent, type ElementPointerEvent, type ElementPortMovementPolicy, type ElementResizedEvent, type ElementSelectedEvent, type ElementShapeControlDragEvent, type ElementShapeControlEventType, type ElementShapeHoverControlActivationEvent, type ElementShapeHoverControlInteractionEvent, type ElementShapeHoverControls, EllipseMidPoint, type EngineChangeEvent, type EngineConfigEvent, type EngineEventMap, type EnginePointerInfo, type EngineSelectionEvent, type GridLayoutChangedEvent, type GridLayoutChangedReason, type GridRowSnapshot, type HostAnchorPreset, type HoverControlIcon, type LinkColorPoolPolicy, type LinkData, type LinkDeletedEvent, type LinkRouteRefreshMode, type LinkRouteRefreshPolicy, type LinkRoutingMode, type MoveConstraint, type OverlayShapeConfig, type OverlayShapeHandle, type PaperClickEvent, type Point, type PortAnchor, type PortAnchorConstraint, type PortBorderTransformContext, type PortBorderTransformResult, type PortData, type PortDeletedEvent, type PortLinkAttachMode, type PortMouseEvent, type PortMovedEvent, type PortPositionLimits, type PortSelectedEvent, type PositionAxisLimit, type Rect, type RerouteLinksOptions, type ResolvePortAnchorsOptions, type ShapeControlDefinition, type ShapeControlTargetKind, type ShapeControlVisibilityTrigger, type ShapeDrawContext, type ShapeEdgeTarget, type ShapeEllipseMidPointTarget, type ShapeHoverGeometry, type ShapeVertexTarget, type SimpleShape, type Size, type TextData, type TextDeletedEvent, type TextInteractionPolicy, type TextLayout, type TextLayoutBoundsMode, type TextLayoutOverflowMode, type TextLayoutWrapMode, type TextSelectedEvent, type TextUpdatedEvent, type VertexHoverControl, type ViewportFitOptions, createDiagramEditor, createDiagramEngine };
@@ -28,6 +28,8 @@ Primary definitions:
28
28
  - `onElementShapeHoverControlActivated?: (event: ElementShapeHoverControlActivationEvent) => void` (deprecated callback contract)
29
29
  - `onChange?: (event: EngineChangeEvent) => void`
30
30
  - `onSelection?: (event: EngineSelectionEvent) => void`
31
+ - `linkRouteRefreshPolicy?: LinkRouteRefreshPolicy`
32
+ - `linkColorPoolPolicy?: LinkColorPoolPolicy`
31
33
 
32
34
  ## Engine Config (`DiagramEngineConfig`)
33
35
 
@@ -40,6 +42,8 @@ Primary definitions:
40
42
  - `snapper?: SnapStrategy`
41
43
  - `shapeRegistry?: ShapeRegistry`
42
44
  - `textMeasurer?: TextMeasurer`
45
+ - `linkRouteRefreshPolicy?: LinkRouteRefreshPolicy`
46
+ - `linkColorPoolPolicy?: LinkColorPoolPolicy`
43
47
 
44
48
  Defaults:
45
49
  - `scheduler`: `RenderScheduler`
@@ -65,17 +69,41 @@ Defaults:
65
69
  - `parentId`: `null`
66
70
 
67
71
  ### `ElementLayout`
68
- - Required: `mode: 'manual' | 'horizontal' | 'vertical'`
72
+ - Required: `mode: 'manual' | 'horizontal' | 'vertical' | 'grid'`
69
73
  - Optional: `padding?: number | { x: number; y: number }`, `gap?: number`, `align?: 'start' | 'center' | 'end'`
74
+ - Optional: `autoResize?: 'grow' | 'grow-shrink'` (default: `'grow'`)
75
+ - Optional grid controls: `gridTemplate?: number[]`
76
+ - Optional grid interaction policy: `gridChildWidthResizeEnabled?: boolean` (default: `false`)
70
77
  - Optional fit controls: `childFitMainAxis?: 'none' | 'distribute'`, `childFitCrossAxis?: 'none' | 'stretch'`, `childFitMinSize?: Partial<Size>`, `childFitMaxSize?: Partial<Size>`
78
+ - Optional child size aliases: `childMinWidth?: number`, `childMaxWidth?: number`, `childMinHeight?: number`, `childMaxHeight?: number`
79
+ - Optional label reservation: `labelReservedSpace?: ElementLayoutLabelReservedSpace`
71
80
  - Layout defaults when `mode !== 'manual'`:
72
81
  - `padding`: `12` (or `{ x: 12, y: 12 }`)
73
82
  - `gap`: `12`
74
83
  - `align`: `'center'`
75
84
 
85
+ ### `ViewportFitOptions`
86
+ - Optional `padding?: number` (default: `24`)
87
+ - Optional `minZoom?: number` (default: `0.2`)
88
+ - Optional `maxZoom?: number` (default: `3`)
89
+ - Normalization rules:
90
+ - negative padding is clamped to `0`
91
+ - non-finite values fall back to defaults
92
+ - `minZoom`/`maxZoom` are clamped to positive values and normalized into ascending order
93
+
94
+ ### `TextInteractionPolicy`
95
+ - Optional `movable?: boolean` (default behavior: `true`)
96
+ - Optional `editable?: boolean` (default behavior: `true`)
97
+ - Semantics:
98
+ - `movable: false` suppresses built-in pointer drag for that text label
99
+ - `editable: false` suppresses built-in double-click/tap editing for that text label
100
+ - omitted fields preserve existing built-in behavior
101
+ - programmatic `moveTextTo(...)` and `updateText(...)` remain allowed
102
+
76
103
  ### `ElementPortMovementPolicy`
77
104
  - `moveMode: 'free' | 'inside' | 'border' | 'anchors'`
78
105
  - Optional `anchorConstraint?: PortAnchorConstraint`
106
+ - Optional `positionLimits?: PortPositionLimits`
79
107
 
80
108
  ### `PortAnchorConstraint`
81
109
  - `preset: 'vertices' | 'cardinal'`
@@ -83,7 +111,7 @@ Defaults:
83
111
 
84
112
  ### `PortData`
85
113
  - Required: `id`, `elementId`, `position`
86
- - Optional: `shapeId`, `size`, `style`, `textIds`, `moveMode`, `anchorCenter`, `orientToHostBorder`, `currentAnchorId`
114
+ - Optional: `shapeId`, `size`, `style`, `textIds`, `moveMode`, `anchorCenter`, `orientToHostBorder`, `placementPoint`, `linkAttachPoint`, `externalLinkAttachPoint`, `internalLinkAttachPoint`, `rotationPivot`, `currentAnchorId`
87
115
  - Defaults at runtime/model:
88
116
  - `textIds`: `[]`
89
117
  - `anchorCenter`: `true`
@@ -96,9 +124,29 @@ Defaults:
96
124
  - `routing`: `'auto'`
97
125
  - `textIds`: `[]`
98
126
 
127
+ ### `LinkRouteRefreshPolicy`
128
+ - Optional `mode?: 'mutation-only' | 'redraw-two-endpoint-change'` (default: `'mutation-only'`)
129
+ - Optional `includeManual?: boolean` (default: `false`)
130
+ - Applies to editor/engine configuration and controls redraw-cycle link refresh behavior.
131
+
132
+ ### `LinkColorPoolPolicy`
133
+ - Optional `enabled?: boolean` (default: `false`)
134
+ - Optional `colors?: string[]`
135
+ - When enabled:
136
+ - link creation assigns `style.stroke` from the active pool if no explicit non-empty stroke is already provided
137
+ - empty/whitespace custom entries are ignored
138
+ - if resulting custom pool is empty, built-in 20-color pool is used
139
+
140
+ ### `GridLayoutChangedEvent`
141
+ - Required: `parentId`, `triggerChildId`, `reason`, `beforeRows`, `afterRows`, `afterGridTemplate`
142
+ - Optional: `beforeGridTemplate`
143
+ - `reason`: `'child-resize-split' | 'child-resize-redistribute'`
144
+ - `beforeRows` / `afterRows`: arrays of `{ childIds: string[] }` snapshots describing derived row membership before and after the topology change
145
+ - Emitted only when enabled grid-child width resizing causes a real row-topology change
146
+
99
147
  ### `TextData`
100
148
  - Required: `id`, `content`, `position`
101
- - Optional: `size`, `style`, `ownerId`, `layout`, `displayContent`, `displayOffset`, `displayClipSize`
149
+ - Optional: `size`, `style`, `ownerId`, `layout`, `interaction`, `displayContent`, `displayOffset`, `displayClipSize`
102
150
  - Defaults at runtime/model:
103
151
  - `ownerId`: `null`
104
152
  - `displayContent`: mirrors `content` at creation
@@ -139,10 +187,24 @@ Defaults:
139
187
  - Rendering: `registerShape`, `render`
140
188
 
141
189
  ### Editor Only (`DiagramEditorHandle`)
190
+ - `startLinkFromPort(sourcePortId, pointer?)`
191
+ - `updateLinkPreview(pointer)`
192
+ - `completeLinkToPort(targetPortId)`
193
+ - `completeLinkToElement(targetElementId, pointer)`
194
+ - `cancelLink()`
195
+ - `zoomToFitElements(options?)`
196
+ - `exportImage(options?)`
142
197
  - `resize(width, height)`
143
198
  - `setElementShapeHoverControls(controls?)`
144
199
  - `destroy()`
145
200
 
201
+ ### `exportImage` Options (`DiagramImageExportOptions`)
202
+ - Optional: `mimeType?: string`
203
+ - Optional: `quality?: number`
204
+ - Optional: `pixelRatio?: number`
205
+ - Optional crop rectangle: `x?: number`, `y?: number`, `width?: number`, `height?: number`
206
+ - Optional `fitToContent?: boolean | { padding?: number }`
207
+
146
208
  ### `registerShape` Definition Contract
147
209
  - Required: `id`
148
210
  - Optional behavior hooks:
@@ -173,6 +235,7 @@ Defaults:
173
235
  - `elementDragged: ElementDropEvent`
174
236
  - `elementMoved: ElementMovedEvent`
175
237
  - `elementResized: ElementResizedEvent`
238
+ - `gridLayoutChanged: GridLayoutChangedEvent`
176
239
  - `elementDeleted: ElementDeletedEvent`
177
240
  - `portDeleted: PortDeletedEvent`
178
241
  - `linkDeleted: LinkDeletedEvent`
@@ -188,9 +251,16 @@ Defaults:
188
251
 
189
252
  - Missing IDs in most mutators are no-op (non-throwing).
190
253
  - `setViewport` emits a `change` patch with `entity: 'viewport'` and skips immediate render scheduling.
254
+ - `zoomToFitElements` computes bounds from `elements[]` only, ignores ports/links/texts for fit expansion, and no-ops when no elements exist.
255
+ - `zoomToFitElements` applies its result through `setViewport`, so hosts observe the standard viewport patch/change path.
191
256
  - `clientToWorld` uses: `world = (client - containerRect - pan) / zoom`, with zoom fallback to `1` when zoom is `0`.
192
257
  - `rerouteLinks(ids)` skips manual links unless `options.includeManual === true`.
258
+ - `linkRouteRefreshPolicy.mode` defaults to `'mutation-only'`; `'redraw-two-endpoint-change'` enables redraw-cycle reroute checks for links whose two endpoints changed.
193
259
  - `updateLinkPoints` always marks the link as manual routing.
260
+ - `linkColorPoolPolicy` is opt-in and applies only to newly created links; explicitly provided non-empty `style.stroke` values are preserved.
261
+ - `gridLayoutChanged` is additive and does not replace standard `change` / `elementResized` flows.
262
+ - `TextData.interaction.movable = false` blocks built-in drag only; selection still works and programmatic movement remains allowed.
263
+ - `TextData.interaction.editable = false` blocks built-in textarea editing only; selection still works and programmatic text updates remain allowed.
194
264
  - Text layout/overflow resolution updates `displayContent` and emits `textUpdated` when `updateText` is called.
195
265
  - Deletion mutators emit cascading `portDeleted`/`linkDeleted`/`textDeleted` for removed dependent entities.
196
266
 
@@ -6,11 +6,19 @@
6
6
  - CRUD for elements, ports, links, and texts.
7
7
  - Nested elements with world/local coordinate resolution.
8
8
  - Link routing modes: `auto` and `manual`.
9
+ - Optional redraw-cycle reroute policy for two-endpoint-change detection.
10
+ - Hierarchy-aware cross-parent corridor preference for auto link routing.
9
11
  - Manual bend editing while preserving interior bends during endpoint moves.
10
12
  - Selection, marquee selection, and viewport pan/zoom.
13
+ - Host-callable viewport fitting through `zoomToFitElements(options?)`.
11
14
  - Shape registration by canvas draw, custom node factory, or SVG path metadata.
12
15
  - Shape-aware host border projection and anchor-constrained port placement.
16
+ - Auto-layout modes: `manual`, `horizontal`, `vertical`, and `grid` with template rows/columns.
17
+ - Auto-layout parent resize policy (`grow` / `grow-shrink`) and child size constraints.
18
+ - Optional grid-child width topology editing with `gridLayoutChanged` host events.
13
19
  - Element shape hover controls with edge/vertex/midpoint targets and interaction callbacks.
20
+ - Optional random link color assignment from configurable pools during link creation.
21
+ - Per-text interaction policy for suppressing built-in text drag and/or built-in text editing.
14
22
  - Overlay shapes for external drag ghosting and previews.
15
23
  - Event-driven host integration (`change`, `selection`, pointer/link lifecycle events).
16
24
 
@@ -6,6 +6,7 @@
6
6
  - Engine mutators route through command factories in `src/engine/EngineCommands.ts`.
7
7
  - Each command applies model mutation and returns one or more patches.
8
8
  - `emitChange` publishes `{ patches, state }` on `change`.
9
+ - Editor helpers such as `zoomToFitElements(options?)` compose existing engine commands rather than introducing a separate patch type.
9
10
 
10
11
  ## Patch Entities
11
12
  - `element`
@@ -20,6 +21,10 @@
20
21
  - `add/move/resize/remove element`
21
22
  - Always `change`
22
23
  - Plus `elementMoved`, `elementResized`, or `elementDeleted` when applicable
24
+ - `resize element` with enabled grid-child width topology editing
25
+ - Standard `change`
26
+ - Standard `elementResized` when size changes
27
+ - Plus `gridLayoutChanged` when row occupancy actually splits or redistributes
23
28
  - `add/move/remove port`
24
29
  - Always `change`
25
30
  - Plus `portMoved` on effective movement
@@ -35,6 +40,9 @@
35
40
  - `selection` plus derived selected entity events
36
41
  - `setViewport`
37
42
  - `change` with viewport patch (`render: false`)
43
+ - `zoomToFitElements`
44
+ - delegates to `setViewport` when at least one element exists
45
+ - emits the same viewport `change` patch path
38
46
  - `setRouting/setSnapping/registerShape`
39
47
  - `config` events
40
48
 
@@ -59,7 +59,7 @@ When resuming later:
59
59
  5. Re-run packaging verification.
60
60
 
61
61
  ## 6. Current Status
62
- - Last updated: 2026-04-25
62
+ - Last updated: 2026-05-14
63
63
  - Last completed step: 10
64
64
  - Next step: 7 (optional additional fixture coverage for deeper nested/manual-route scenarios)
65
65
  - Owner: Codex (with repository maintainers)
@@ -82,3 +82,6 @@ When resuming later:
82
82
  - 2026-02-26: Added cross-page navigation and section-level links across core docs for human and AI readability.
83
83
  - 2026-04-25: Completed release-doc pass for `v0.2.2` including `v0.2.1` scope consolidation; refreshed API/event contracts in `docs/*` and `ai/*`.
84
84
  - 2026-04-25: Ran release validations: `npm run typecheck`, `npm test -- --watchAll=false`, `npm run build`, `npm run rollup-build-lib`, and `npm pack --dry-run`.
85
+ - 2026-05-10: Completed release-doc pass for `v0.2.5`; refreshed release highlights, API contract updates (`linkRouteRefreshPolicy`, `linkColorPoolPolicy`, grid auto-layout fields), and machine-readable contract metadata.
86
+ - 2026-05-10: Ran release validations: `npm run typecheck`, `npm test -- --watchAll=false`, `npm run build`, `npm run rollup-build-lib`, and `npm pack --dry-run`.
87
+ - 2026-05-14: Completed release-doc pass for `v0.2.6`; refreshed release highlights, API contract updates (`zoomToFitElements`, `ViewportFitOptions`, `gridChildWidthResizeEnabled`, `gridLayoutChanged`, `TextInteractionPolicy`), and machine-readable contract metadata.
@@ -12,9 +12,12 @@ Embed this library into another diagram host while preserving deterministic stat
12
12
  - `selection` for host inspector panels
13
13
  - link/pointer events for UI workflows
14
14
  - deletion/text lifecycle events when host needs side-effects (`portDeleted`, `linkDeleted`, `textDeleted`, `textUpdated`)
15
+ - `gridLayoutChanged` when the host needs to observe resize-driven grid row topology edits
15
16
  3. Convert external pointer drops with `clientToWorld`.
16
17
  4. Use `createOverlayShape` during host drag previews.
17
18
  5. For shape controls, pass `elementShapeHoverControls` and handle `onElementShapeHoverControlInteraction`.
19
+ 6. Use `zoomToFitElements(options?)` when the host needs library-owned fit-to-elements navigation instead of recomputing viewport math externally.
20
+ 7. Set `TextData.interaction` when some labels must remain read-only or fixed in place while still using library selection behavior.
18
21
 
19
22
  ## Path B: Engine-Only Adapter
20
23
  1. Implement `Renderer`:
@@ -39,6 +39,9 @@
39
39
  - `ownerId` can reference element, port, or link.
40
40
  - Owned text position is stored owner-relative.
41
41
  - Text with missing owner behaves as standalone world-position text.
42
+ - Text interaction policy is persisted separately from style/layout metadata.
43
+ - `interaction.movable = false` suppresses built-in drag without blocking selection or programmatic movement.
44
+ - `interaction.editable = false` suppresses built-in editing without blocking selection or programmatic content updates.
42
45
  - Size is measured on add/update when using engine text measurer.
43
46
  - Text layout can compute derived `displayContent`, `displayOffset`, and `displayClipSize`.
44
47
 
@@ -47,6 +50,7 @@
47
50
  - `selection`
48
51
  - plus derived `elementSelected`/`portSelected`/`textSelected`
49
52
  - `setViewport` emits `change` with `entity=viewport` and does not force render directly.
53
+ - `zoomToFitElements` derives viewport fit from `elements[]` bounds only and applies the result through `setViewport`.
50
54
 
51
55
  ## Failure Modes
52
56
  - Non-existent target IDs: operation is no-op.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orcasvn-react-diagrams",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "dependencies": {
5
5
  "eventemitter3": "^5.0.1",
6
6
  "flatten-js": "^0.6.9",