@tumaet/apollon 4.8.0 → 4.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +45 -20
  2. package/dist/assets/style.css +1 -1
  3. package/dist/exportStyles-Co-WBqTa.js +5 -0
  4. package/dist/external/LICENSE-InterFont +92 -0
  5. package/dist/external/exportFonts-DxO9jrR1.js +19 -0
  6. package/dist/external/exportStyles-Co-WBqTa.js +5 -0
  7. package/dist/external/index.js +22191 -0
  8. package/dist/index.d.ts +131 -3
  9. package/dist/index.js +19744 -19098
  10. package/dist/internals.d.ts +29 -0
  11. package/dist/internals.js +7 -6
  12. package/dist/react/apollon-editor.d.ts +56 -3
  13. package/dist/react/components/CustomControls.d.ts +7 -0
  14. package/dist/react/components/popovers/PopoverManager.d.ts +1 -1
  15. package/dist/react/components/popovers/activityDiagram/ActivitySwimlaneEditPopover.d.ts +2 -0
  16. package/dist/react/components/popovers/activityDiagram/index.d.ts +1 -0
  17. package/dist/react/components/react/ApollonControl.d.ts +18 -0
  18. package/dist/react/components/svgs/nodes/InterfaceLabel.d.ts +26 -0
  19. package/dist/react/components/svgs/nodes/activityDiagram/ActivitySwimlaneSVG.d.ts +9 -0
  20. package/dist/react/components/svgs/nodes/activityDiagram/index.d.ts +1 -0
  21. package/dist/react/components/svgs/nodes/componentDiagram/ComponentInterfaceNodeSVG.d.ts +2 -0
  22. package/dist/react/components/svgs/nodes/deploymentDiagram/DeploymentInterfaceSVG.d.ts +2 -0
  23. package/dist/react/constants.d.ts +18 -0
  24. package/dist/react/edges/labelTypes/EdgeIncludeExtendLabel.d.ts +1 -4
  25. package/dist/react/edges/labelTypes/EdgeMiddleLabels.d.ts +7 -4
  26. package/dist/react/edges/labelTypes/EdgeMultipleLabels.d.ts +2 -3
  27. package/dist/react/edges/labelTypes/messageLayout.d.ts +51 -0
  28. package/dist/react/exportStyles-yVX7Dykt.js +6 -0
  29. package/dist/react/hooks/index.d.ts +0 -1
  30. package/dist/react/hooks/useStepPathEdge.d.ts +11 -0
  31. package/dist/react/index.d.ts +1 -0
  32. package/dist/react/nodes/activityDiagram/ActivitySwimlane.d.ts +3 -0
  33. package/dist/react/nodes/activityDiagram/index.d.ts +1 -0
  34. package/dist/react/nodes/types.d.ts +2 -1
  35. package/dist/react/overlay/OverlayLayer.d.ts +8 -0
  36. package/dist/react/overlay/RegionMount.d.ts +10 -0
  37. package/dist/react/overlay/overlayStore.d.ts +20 -0
  38. package/dist/react/overlay/types.d.ts +48 -0
  39. package/dist/react/react.d.ts +1 -0
  40. package/dist/react/react.js +13264 -18536
  41. package/dist/react/store/context.d.ts +3 -0
  42. package/dist/react/types/nodes/NodeProps.d.ts +24 -0
  43. package/dist/react/utils/geometry/edgeLabelLayout.d.ts +123 -0
  44. package/dist/react/utils/geometry/interfaceLabelLayout.d.ts +44 -0
  45. package/dist/react/utils/index.d.ts +1 -0
  46. package/dist/react/utils/paletteLayout.d.ts +23 -19
  47. package/dist/react/utils/swimlaneUtils.d.ts +58 -0
  48. package/dist/yjsSync-BCNFF_EI.js +45418 -0
  49. package/package.json +19 -8
  50. package/schema/uml-model-4.schema.json +1 -0
  51. package/dist/exportStyles-Wcc8N8Xj.js +0 -5
  52. package/dist/react/exportStyles-CH2hautV.js +0 -6
  53. package/dist/react/hooks/useMessagePositioning.d.ts +0 -30
  54. package/dist/yjsSync-CqmgRwRE.js +0 -51038
@@ -24,6 +24,21 @@ declare function ActivityMergeNode({ id, width, height, data, parentId, }: NodeP
24
24
 
25
25
  declare function ActivityObjectNode({ id, width, height, data, parentId, }: NodeProps<Node_2<DefaultNodeProps>>): JSX.Element | null;
26
26
 
27
+ declare function ActivitySwimlane({ id, width, height, data, parentId, }: NodeProps<Node_2<ActivitySwimlaneProps>>): JSX.Element | null;
28
+
29
+ /**
30
+ * Activity-partition (swimlane) container. Lanes are equal divisions along the
31
+ * primary axis (columns when vertical, rows when horizontal). Elements dropped
32
+ * into the swimlane become its children and move with it; which lane an element
33
+ * belongs to is expressed by where the modeller places it, matching the UML
34
+ * activity-partition notation where partition membership is positional rather
35
+ * than stored per element.
36
+ */
37
+ declare type ActivitySwimlaneProps = DefaultNodeProps & {
38
+ orientation: "vertical" | "horizontal";
39
+ lanes: SwimlaneLane[];
40
+ };
41
+
27
42
  declare type ApollonEdge = {
28
43
  id: string;
29
44
  source: string;
@@ -360,6 +375,7 @@ declare const diagramNodeTypes: {
360
375
  activityMergeNode: typeof ActivityMergeNode;
361
376
  activityForkNode: typeof ActivityForkNode;
362
377
  activityForkNodeHorizontal: typeof ActivityForkNodeHorizontal;
378
+ activitySwimlane: typeof ActivitySwimlane;
363
379
  useCase: typeof UseCase;
364
380
  useCaseActor: typeof UseCaseActor;
365
381
  useCaseSystem: typeof UseCaseSystem;
@@ -641,6 +657,19 @@ declare type SfcTransitionBranchNodeProps = DefaultNodeProps & {
641
657
  showHint?: boolean;
642
658
  };
643
659
 
660
+ /** A single partition (lane) inside an activity swimlane. */
661
+ declare type SwimlaneLane = {
662
+ id: string;
663
+ name: string;
664
+ /**
665
+ * Lane's extent along the swimlane's primary axis, in absolute flow px. The
666
+ * last lane is elastic (fills the remainder), so resizing the swimlane only
667
+ * changes the last lane. Optional: lanes without it divide the space equally,
668
+ * so existing saved swimlanes render as equal lanes until a separator moves.
669
+ */
670
+ size?: number;
671
+ };
672
+
644
673
  declare function SyntaxTreeNonterminal({ id, width, height, data, parentId, }: NodeProps<Node_2<DefaultNodeProps>>): JSX.Element | null;
645
674
 
646
675
  declare function SyntaxTreeTerminal({ id, width, height, data, parentId, }: NodeProps<Node_2<DefaultNodeProps>>): JSX.Element | null;
package/dist/internals.js CHANGED
@@ -1,6 +1,7 @@
1
- import { U as n, aB as r } from "./yjsSync-CqmgRwRE.js";
2
- import { a8 as m, aR as g, aS as p, aT as u, aU as S, aV as T, aW as b, bl as l, bm as F, bn as v } from "./yjsSync-CqmgRwRE.js";
3
- function d(t = new n()) {
1
+ import { aD as r } from "./yjsSync-BCNFF_EI.js";
2
+ import { a8 as m, aT as p, aU as g, aV as u, aW as S, aX as T, aY as b, bo as l, bp as F, bq as Y } from "./yjsSync-BCNFF_EI.js";
3
+ import * as n from "yjs";
4
+ function d(t = new n.Doc()) {
4
5
  const e = () => {
5
6
  }, a = {
6
7
  getState: () => ({
@@ -33,8 +34,8 @@ function d(t = new n()) {
33
34
  export {
34
35
  m as MessageType,
35
36
  r as YjsSync,
36
- g as convertV2ToV4,
37
- p as convertV3EdgeTypeToV4,
37
+ p as convertV2ToV4,
38
+ g as convertV3EdgeTypeToV4,
38
39
  u as convertV3HandleToV4,
39
40
  S as convertV3MessagesToV4,
40
41
  T as convertV3NodeTypeToV4,
@@ -42,5 +43,5 @@ export {
42
43
  d as createHeadlessSync,
43
44
  l as isV2Format,
44
45
  F as isV3Format,
45
- v as isV4Format
46
+ Y as isV4Format
46
47
  };
@@ -1,5 +1,6 @@
1
1
  import { Node, Edge } from '@xyflow/react';
2
2
  import { UMLDiagramType } from './types';
3
+ import { OverlayControlInput, OverlayRegion, OverlaySide } from './overlay/types';
3
4
  import { SendBroadcastMessage } from './sync/yjsSync';
4
5
  import * as Apollon from "./typings";
5
6
  export declare class ApollonEditor {
@@ -11,8 +12,8 @@ export declare class ApollonEditor {
11
12
  private readonly metadataStore;
12
13
  private readonly popoverStore;
13
14
  private readonly assessmentSelectionStore;
14
- private readonly alignmentGuidesStore;
15
- private readonly edgeGeometryStore;
15
+ private readonly overlayStore;
16
+ private readonly hostRegionEls;
16
17
  private subscribers;
17
18
  constructor(element: HTMLElement, options?: Apollon.ApollonOptions);
18
19
  private setReactFlowInstance;
@@ -31,10 +32,62 @@ export declare class ApollonEditor {
31
32
  x: number;
32
33
  y: number;
33
34
  }): import('@xyflow/react').XYPosition | null;
35
+ /**
36
+ * Zoom/pan so the whole diagram fits, capped at `maxZoom: 1.0`. Retries up to
37
+ * 10 animation frames until every node is measured.
38
+ * @param options.padding - Scalar fraction (default `0.15`), or per-side px
39
+ * that adds to a 16px gutter. A per-side object forces the inset-aware path.
40
+ * @param options.duration - Animation duration in ms (default `200`).
41
+ * @param options.respectInsets - Pad the fit by reserved overlay insets
42
+ * (header, rails, …). Default `true`.
43
+ */
34
44
  fitView(options?: {
35
- padding?: number;
45
+ padding?: number | Partial<Record<OverlaySide, number>>;
36
46
  duration?: number;
47
+ /** Pad the fit by the reserved overlay insets (header, rails, …). */
48
+ respectInsets?: boolean;
37
49
  }): void;
50
+ /**
51
+ * Register a floating control, returning a disposer. Re-using an id replaces
52
+ * (idempotent / StrictMode-safe). Pick a façade: a React host →
53
+ * `<ApollonControl>`; a non-React host (or one that needs its own React
54
+ * root/context) → `getRegionElement` + `createPortal`; a one-off imperative
55
+ * widget → `addControl`.
56
+ * @param control - id, target region, a `render` thunk, and optional layout
57
+ * options ({@link OverlayControlInput}).
58
+ * @returns A disposer that unregisters this control; safe to call twice.
59
+ * @throws If `id` is empty or `region` is not a known region — mistakes fail
60
+ * loudly at the edge, not silently in the renderer.
61
+ */
62
+ addControl(control: OverlayControlInput): () => void;
63
+ /**
64
+ * Patch a registered control's options/renderer (a no-op if absent).
65
+ * @param id - The control's immutable id (an `id` in `patch` is ignored).
66
+ * @param patch - Partial options/renderer merged over the existing control.
67
+ */
68
+ updateControl(id: string, patch: Partial<OverlayControlInput>): void;
69
+ /**
70
+ * @param id - A control id.
71
+ * @returns `true` if a control with this id is currently registered.
72
+ */
73
+ hasControl(id: string): boolean;
74
+ /**
75
+ * A stable DOM node anchored in `region`, for hosts that render their own
76
+ * React into it (via `createPortal`) to keep host context. Auto-measured, so
77
+ * the diagram makes room for whatever the host mounts. Lifetime = the editor;
78
+ * `releaseRegionElement` unregisters it. Reserved id: `apollon:host:<region>`.
79
+ * @param region - The region to anchor the node in.
80
+ * @returns The same node for the lifetime of one acquire; `releaseRegionElement`
81
+ * drops it and the next call returns a fresh node.
82
+ * @throws If `region` is not a known region.
83
+ */
84
+ getRegionElement(region: OverlayRegion): HTMLElement;
85
+ /**
86
+ * Release a region acquired via {@link getRegionElement} (unregister + drop
87
+ * the cached node); a later `getRegionElement(region)` creates a fresh node.
88
+ * @param region - The region whose host node to release.
89
+ */
90
+ releaseRegionElement(region: OverlayRegion): void;
38
91
  set diagramType(type: UMLDiagramType);
39
92
  destroy(): void;
40
93
  /** Renders a model to SVG via a hidden, off-screen mount. */
@@ -1 +1,8 @@
1
+ /**
2
+ * Bottom-left control cluster. Every button shares one idiom
3
+ * (`apollon-chrome-iconbtn`): borderless on the glass pane, state shown as a
4
+ * surface-layer fill. Reads left→right as view (zoom-out/in, fit, a clickable
5
+ * %-reset) then, past a hairline, history (undo/redo). React Flow renders its
6
+ * built-in zoom/fit buttons first; our children follow.
7
+ */
1
8
  export declare const CustomControls: () => import("react").JSX.Element;
@@ -1,4 +1,4 @@
1
- type NodePopoverType = "class" | "objectName" | "communicationObjectName" | "default" | "Component" | "ComponentSubsystem" | "FlowchartTerminal" | "FlowchartProcess" | "FlowchartDecision" | "FlowchartInputOutput" | "FlowchartFunctionCall" | "DeploymentComponent" | "DeploymentNode" | "SyntaxTreeNonterminal" | "SyntaxTreeTerminal" | "PetriNetPlace" | "BPMNTask" | "BPMNStartEvent" | "BPMNIntermediateEvent" | "BPMNEndEvent" | "BPMNGateway" | "BPMNSubprocess" | "BPMNTransaction" | "BPMNCallActivity" | "BPMNAnnotation" | "BPMNDataObject" | "BPMNDataStore" | "BPMNPool" | "BPMNGroup" | "ReachabilityGraphMarking" | "Sfc" | "SfcActionTable";
1
+ type NodePopoverType = "class" | "objectName" | "communicationObjectName" | "default" | "Component" | "ComponentSubsystem" | "FlowchartTerminal" | "FlowchartProcess" | "FlowchartDecision" | "FlowchartInputOutput" | "FlowchartFunctionCall" | "DeploymentComponent" | "DeploymentNode" | "SyntaxTreeNonterminal" | "SyntaxTreeTerminal" | "PetriNetPlace" | "BPMNTask" | "BPMNStartEvent" | "BPMNIntermediateEvent" | "BPMNEndEvent" | "BPMNGateway" | "BPMNSubprocess" | "BPMNTransaction" | "BPMNCallActivity" | "BPMNAnnotation" | "BPMNDataObject" | "BPMNDataStore" | "BPMNPool" | "BPMNGroup" | "ReachabilityGraphMarking" | "Sfc" | "SfcActionTable" | "ActivitySwimlane";
2
2
  type EdgePopoverType = "ClassAggregation" | "ClassInheritance" | "ClassRealization" | "ClassComposition" | "ClassBidirectional" | "ClassUnidirectional" | "ClassDependency" | "ActivityControlFlow" | "ObjectLink" | "CommunicationLink" | "UseCaseAssociation" | "UseCaseInclude" | "UseCaseExtend" | "UseCaseGeneralization" | "ComponentDependency" | "ComponentProvidedInterface" | "ComponentRequiredInterface" | "ComponentRequiredThreeQuarterInterface" | "ComponentRequiredQuarterInterface" | "BPMNSequenceFlow" | "BPMNMessageFlow" | "BPMNAssociationFlow" | "BPMNDataAssociationFlow" | "DeploymentAssociation" | "DeploymentDependency" | "DeploymentProvidedInterface" | "DeploymentRequiredInterface" | "DeploymentRequiredThreeQuarterInterface" | "DeploymentRequiredQuarterInterface" | "FlowChartFlowline" | "SyntaxTreeLink" | "SfcDiagramEdge" | "ReachabilityGraphArc" | "PetriNetArc";
3
3
  type PopoverType = NodePopoverType | EdgePopoverType;
4
4
  interface PopoverManagerProps {
@@ -0,0 +1,2 @@
1
+ import { PopoverProps } from '../types';
2
+ export declare const ActivitySwimlaneEditPopover: React.FC<PopoverProps>;
@@ -0,0 +1 @@
1
+ export { ActivitySwimlaneEditPopover } from './ActivitySwimlaneEditPopover';
@@ -0,0 +1,18 @@
1
+ import { ReactNode } from 'react';
2
+ import { OverlayControlOptions } from '../../overlay/types';
3
+ /** Props for {@link ApollonControl}: every {@link OverlayControlOptions} field
4
+ * (id, region, inset, order, …) plus the children to render in-canvas. */
5
+ export type ApollonControlProps = OverlayControlOptions & {
6
+ /** Portaled into the control's host node inside the chosen region. Children
7
+ * changes never re-register the control; only real option changes do. */
8
+ children: ReactNode;
9
+ };
10
+ /**
11
+ * Declarative façade over `editor.addControl`. Registers a control that renders
12
+ * a stable host node into the chosen region, and portals `children` into that
13
+ * node — so children render INSIDE the canvas while React owns their
14
+ * reconciliation. Children changes therefore never touch the overlay store; only
15
+ * real option changes (region/inset/order/…) push an update. Returns null in the
16
+ * host tree.
17
+ */
18
+ export declare function ApollonControl({ children, ...options }: ApollonControlProps): ReactNode;
@@ -0,0 +1,26 @@
1
+ import { FC } from 'react';
2
+ import { InterfaceLabelSide } from '../../../utils/geometry/interfaceLabelLayout';
3
+ interface Props {
4
+ name?: string | null;
5
+ /** Interface circle bounds (always square — INTERFACE.SIZE). */
6
+ width: number;
7
+ height: number;
8
+ fill?: string;
9
+ /** Which side of the circle the name sits on. Defaults to "bottom"; the node
10
+ * component flips it away from sides a connecting edge attaches to (including
11
+ * a diagonal corner when every side is taken). */
12
+ side?: InterfaceLabelSide;
13
+ }
14
+ /**
15
+ * The provided/required interface name. Sits centered below the ball/socket by
16
+ * default; the node component moves it to whichever side — or, when all four
17
+ * sides have an edge, whichever diagonal corner — is clear of connecting edges.
18
+ * The name is rendered as real multi-line text (honouring line breaks) and is
19
+ * never auto-wrapped.
20
+ *
21
+ * Renders as SVG <text>/<tspan> in the node's overflow:visible region. The
22
+ * PNG/PDF/SVG export pipeline captures it via its node-text bbox scan
23
+ * (utils/exportUtils.ts), so it exports correctly without enlarging the viewBox.
24
+ */
25
+ export declare const InterfaceLabel: FC<Props>;
26
+ export {};
@@ -0,0 +1,9 @@
1
+ import { SVGComponentProps } from '../../../../types/SVG';
2
+ import { ActivitySwimlaneProps } from '../../../../types';
3
+ /** Thickness of the band that holds the lane name labels. */
4
+ export declare const SWIMLANE_HEADER_SIZE = 30;
5
+ interface ActivitySwimlaneSVGProps extends SVGComponentProps {
6
+ data: ActivitySwimlaneProps;
7
+ }
8
+ export declare const ActivitySwimlaneSVG: React.FC<ActivitySwimlaneSVGProps>;
9
+ export {};
@@ -6,3 +6,4 @@ export * from './ActivityObjectNodeSVG';
6
6
  export * from './ActivityMergeNodeSVG';
7
7
  export * from './ActivityForkNodeSVG';
8
8
  export * from './ActivityForkNodeHorizontalSVG';
9
+ export * from './ActivitySwimlaneSVG';
@@ -1,7 +1,9 @@
1
1
  import { SVGComponentProps } from '../../../../types/SVG';
2
2
  import { DefaultNodeProps } from '../../../../types';
3
+ import { InterfaceLabelSide } from '../../../../utils/geometry/interfaceLabelLayout';
3
4
  interface Props extends SVGComponentProps {
4
5
  data: DefaultNodeProps;
6
+ labelSide?: InterfaceLabelSide;
5
7
  }
6
8
  export declare const ComponentInterfaceNodeSVG: React.FC<Props>;
7
9
  export {};
@@ -1,7 +1,9 @@
1
1
  import { SVGComponentProps } from '../../../../types/SVG';
2
2
  import { DefaultNodeProps } from '../../../../types';
3
+ import { InterfaceLabelSide } from '../../../../utils/geometry/interfaceLabelLayout';
3
4
  interface Props extends SVGComponentProps {
4
5
  data: DefaultNodeProps;
6
+ labelSide?: InterfaceLabelSide;
5
7
  }
6
8
  export declare const DeploymentInterfaceSVG: React.FC<Props>;
7
9
  export {};
@@ -107,6 +107,19 @@ export declare const EDGES: Readonly<{
107
107
  * U-turn is never a deliberate edit, so this stays at the visual-merge
108
108
  * threshold rather than the per-step threshold. */
109
109
  readonly ORTHOGONAL_ARM_OVERLAP_PX: 10;
110
+ /** Perpendicular gap (flow px) between an edge's mid-segment line and the
111
+ * near edge of its relationship/stereotype label. The label sits this far
112
+ * off the line on whichever side is clearer. */
113
+ readonly LABEL_GAP: 14;
114
+ /** Nominal label line height (flow px) used as the across-text depth of the
115
+ * candidate box when scoring which side a label sits on. Constant by
116
+ * construction — placement never measures the rendered text (mirrors the
117
+ * messageLayout.ts invariant). */
118
+ readonly LABEL_LINE_HEIGHT: 14;
119
+ /** Nominal half-width (flow px) of a label along its text axis, used only to
120
+ * build the candidate box for side scoring. Coarse on purpose: we choose a
121
+ * side, not a pixel-perfect fit. */
122
+ readonly LABEL_NOMINAL_HALF_EXTENT: 40;
110
123
  }>;
111
124
  export declare const ZINDEX: Readonly<{
112
125
  readonly BASE: 0;
@@ -235,6 +248,11 @@ export type DropElementConfig = {
235
248
  readonly type: DiagramNodeType;
236
249
  readonly width: number;
237
250
  readonly height: number;
251
+ /** Size of the node when dropped on the canvas, if it should differ from the
252
+ * sidebar preview size (`width`/`height`). Lets a large element preview small
253
+ * in the palette without shrinking the rest of the picker. */
254
+ readonly dropWidth?: number;
255
+ readonly dropHeight?: number;
238
256
  readonly defaultData?: Record<string, unknown>;
239
257
  readonly svg: React.FC<any>;
240
258
  readonly marginTop?: number;
@@ -1,13 +1,10 @@
1
1
  import { IPoint } from '../Connection';
2
2
  interface EdgeIncludeExtendLabelsProps {
3
- label?: string | null;
4
- pathMiddlePosition: IPoint;
5
3
  sourcePoint?: IPoint;
6
4
  targetPoint?: IPoint;
7
- isUseCasePath?: boolean;
8
5
  showRelationshipLabels?: boolean;
9
6
  relationshipType?: "include" | "extend";
10
7
  textColor?: string;
11
8
  }
12
- export declare const EdgeIncludeExtendLabel: ({ sourcePoint, targetPoint, showRelationshipLabels, relationshipType, textColor, }: EdgeIncludeExtendLabelsProps) => import("react").JSX.Element;
9
+ export declare const EdgeIncludeExtendLabel: ({ sourcePoint, targetPoint, showRelationshipLabels, relationshipType, textColor, }: EdgeIncludeExtendLabelsProps) => import("react").JSX.Element | null;
13
10
  export {};
@@ -1,15 +1,18 @@
1
1
  import { IPoint } from '../Connection';
2
+ import { Rect } from '../../utils/geometry/edgeLabelLayout';
2
3
  interface EdgeMiddleLabelsProps {
3
4
  label?: string | null;
4
- pathMiddlePosition: IPoint;
5
- isMiddlePathHorizontal: boolean;
5
+ /** The edge's full rendered polyline (orthogonal edges). */
6
+ activePoints?: IPoint[];
6
7
  sourcePoint?: IPoint;
7
8
  targetPoint?: IPoint;
9
+ /** Every node the edge routes near, so the label avoids all of them. */
10
+ nodeRects?: Rect[];
11
+ neighborGeometry?: IPoint[][];
8
12
  showRelationshipLabels?: boolean;
9
13
  isUseCasePath?: boolean;
10
14
  isPetriNet?: boolean;
11
- avoidToolbarOverlap?: boolean;
12
15
  textColor: string;
13
16
  }
14
- export declare const EdgeMiddleLabels: ({ label, pathMiddlePosition, isMiddlePathHorizontal, sourcePoint, targetPoint, showRelationshipLabels, isUseCasePath, isPetriNet, avoidToolbarOverlap, textColor, }: EdgeMiddleLabelsProps) => import("react").JSX.Element | null;
17
+ export declare const EdgeMiddleLabels: ({ label, activePoints, sourcePoint, targetPoint, nodeRects, neighborGeometry, showRelationshipLabels, isUseCasePath, isPetriNet, textColor, }: EdgeMiddleLabelsProps) => import("react").JSX.Element | null;
15
18
  export {};
@@ -7,9 +7,8 @@ interface EdgeMultipleLabelsProps {
7
7
  isReconnecting?: boolean;
8
8
  sourcePosition: IPoint;
9
9
  targetPosition: IPoint;
10
- edgePoints?: IPoint[];
11
- isHorizontalEdge?: boolean;
10
+ isHorizontalEdge: boolean;
12
11
  textColor: string;
13
12
  }
14
- export declare const EdgeMultipleLabels: ({ messages, pathMiddlePosition, showRelationshipLabels, isReconnecting, sourcePosition, targetPosition, edgePoints, isHorizontalEdge, textColor, }: EdgeMultipleLabelsProps) => import("react").JSX.Element | null;
13
+ export declare const EdgeMultipleLabels: ({ messages, pathMiddlePosition, showRelationshipLabels, isReconnecting, sourcePosition, targetPosition, isHorizontalEdge, textColor, }: EdgeMultipleLabelsProps) => import("react").JSX.Element | null;
15
14
  export {};
@@ -0,0 +1,51 @@
1
+ import { MessageData } from '../EdgeProps';
2
+ import { IPoint } from '../Connection';
3
+ /**
4
+ * Geometry for communication-edge message labels, relative to the middle-segment
5
+ * midpoint (position-independent, hence unit-testable on its own).
6
+ *
7
+ * Invariant: a group's SIDE is fixed by the segment orientation; flow direction
8
+ * is encoded ONLY by the arrow rotation, never by the side. Gaps are constant by
9
+ * construction — nothing measures text width.
10
+ */
11
+ export interface MessageHostSegment {
12
+ /** Rounded midpoint of the chosen arm (flow space). */
13
+ point: IPoint;
14
+ /** Orientation of the chosen arm. */
15
+ isHorizontal: boolean;
16
+ /** The arm's endpoints in source->target order (for arrow direction). */
17
+ start: IPoint;
18
+ end: IPoint;
19
+ }
20
+ /**
21
+ * The arm of a (possibly stepped) communication edge that should HOST the
22
+ * message stack. The naive mid-segment can land on a tiny jog between two long
23
+ * arms — classifying a dominantly-vertical edge as "horizontal" so the labels
24
+ * centre on the jog and straddle BOTH neighbouring arms. Instead we host on the
25
+ * LONGEST arm (tie-broken toward the edge's middle), so the stack sits beside a
26
+ * long straight run: it never crosses the line and, in vertical mode, all
27
+ * same-direction messages share a leading edge. Pure geometry — identical in the
28
+ * editor and in headless export.
29
+ */
30
+ export declare const getMessageHostSegment: (renderPoints: IPoint[], fallbackSource: IPoint, fallbackTarget: IPoint) => MessageHostSegment;
31
+ export type LabelTextAnchor = "start" | "middle" | "end";
32
+ export declare const ARROW_SIZE = 16;
33
+ export declare const ARROW_TEXT_GAP = 4;
34
+ export declare const LINE_GAP = 8;
35
+ export declare const STACK_SPACING = 22;
36
+ export interface MessageGroupLayout {
37
+ messages: MessageData[];
38
+ arrowRotation: number;
39
+ textAnchor: LabelTextAnchor;
40
+ /** Top-left of the arrow icon for the first message, relative to the segment midpoint. */
41
+ arrowOrigin: IPoint;
42
+ /** Text anchor point for the first message, relative to the segment midpoint. */
43
+ textOrigin: IPoint;
44
+ /** Offset added per stacked message (multiplied by the message index). */
45
+ stackStep: IPoint;
46
+ }
47
+ export interface MessageLayout {
48
+ forward: MessageGroupLayout;
49
+ backward: MessageGroupLayout;
50
+ }
51
+ export declare const computeMessageLayout: (messages: MessageData[], sourcePosition: IPoint, targetPosition: IPoint, isHorizontalEdge: boolean) => MessageLayout;
@@ -0,0 +1,6 @@
1
+ "use client";
2
+ const o = ".react-flow{direction:ltr;--xy-edge-stroke-default: #b1b1b7;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #555;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(255, 255, 255, .5);--xy-minimap-background-color-default: #fff;--xy-minimap-mask-background-color-default: rgba(240, 240, 240, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #e2e2e2;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: transparent;--xy-background-pattern-dots-color-default: #91919a;--xy-background-pattern-lines-color-default: #eee;--xy-background-pattern-cross-color-default: #e2e2e2;background-color:var(--xy-background-color, var(--xy-background-color-default));--xy-node-border-default: 1px solid #bbb;--xy-node-border-selected-default: 1px solid #555;--xy-handle-background-color-default: #333;--xy-selection-background-color-default: rgba(150, 150, 180, .1);--xy-selection-border-default: 1px dotted rgba(155, 155, 155, .8);--xy-resize-background-color-default: #3367d9}.react-flow.dark{--xy-edge-stroke-default: #3e3e3e;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #727272;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(150, 150, 150, .25);--xy-minimap-background-color-default: #141414;--xy-minimap-mask-background-color-default: rgba(60, 60, 60, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #2b2b2b;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: #141414;--xy-background-pattern-dots-color-default: #777;--xy-background-pattern-lines-color-default: #777;--xy-background-pattern-cross-color-default: #777;--xy-node-color-default: #f8f8f8}.react-flow__background{background-color:var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));pointer-events:none;z-index:-1}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1}.react-flow__pane.draggable{cursor:grab}.react-flow__pane.dragging{cursor:grabbing}.react-flow__pane.selection{cursor:pointer}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow__edge-path{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default));stroke-width:var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));fill:none}.react-flow__connection-path{stroke:var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));stroke-width:var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));fill:none}.react-flow .react-flow__edges{position:absolute}.react-flow .react-flow__edges svg{overflow:visible;position:absolute;pointer-events:none}.react-flow__edge{pointer-events:visibleStroke}.react-flow__edge.selectable{cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge.selectable:focus .react-flow__edge-path,.react-flow__edge.selectable:focus-visible .react-flow__edge-path{stroke:var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default))}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__arrowhead polyline{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__arrowhead polyline.arrowclosed{fill:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}svg.react-flow__connectionline{z-index:1001;overflow:visible;position:absolute}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default}.react-flow__node.selectable{cursor:pointer}.react-flow__node.draggable{cursor:grab;pointer-events:all}.react-flow__node.draggable.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;background-color:var(--xy-handle-background-color, var(--xy-handle-background-color-default))}.react-flow__handle.connectingfrom{pointer-events:all}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:0;transform:translate(-50%,50%)}.react-flow__handle-top{top:0;left:50%;transform:translate(-50%,-50%)}.react-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.react-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__pane.selection .react-flow__panel{pointer-events:none}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.top.center,.react-flow__panel.bottom.center{left:50%;transform:translate(-15px) translate(-50%)}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.left.center,.react-flow__panel.right.center{top:50%;transform:translateY(-15px) translateY(-50%)}.react-flow__attribution{font-size:10px;background:var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;left:0;top:0}.react-flow__viewport-portal{position:absolute;width:100%;height:100%;left:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__minimap{background:var( --xy-minimap-background-color-props, var(--xy-minimap-background-color, var(--xy-minimap-background-color-default)) )}.react-flow__minimap-svg{display:block}.react-flow__minimap-mask{fill:var( --xy-minimap-mask-background-color-props, var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default)) );stroke:var( --xy-minimap-mask-stroke-color-props, var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default)) );stroke-width:var( --xy-minimap-mask-stroke-width-props, var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default)) )}.react-flow__minimap-node{fill:var( --xy-minimap-node-background-color-props, var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default)) );stroke:var( --xy-minimap-node-stroke-color-props, var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default)) );stroke-width:var( --xy-minimap-node-stroke-width-props, var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default)) )}.react-flow__background-pattern.dots{fill:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default)) )}.react-flow__background-pattern.lines{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default)) )}.react-flow__background-pattern.cross{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default)) )}.react-flow__controls{display:flex;flex-direction:column}.react-flow__controls.horizontal{flex-direction:row}.react-flow__controls-button{display:flex;justify-content:center;align-items:center;height:26px;width:26px;padding:4px}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px;fill:currentColor}.react-flow__node-input,.react-flow__node-default,.react-flow__node-output,.react-flow__node-group{border:var(--xy-node-border, var(--xy-node-border-default));color:var(--xy-node-color, var(--xy-node-color-default))}.react-flow__node-input.selected,.react-flow__node-input:focus,.react-flow__node-input:focus-visible,.react-flow__node-default.selected,.react-flow__node-default:focus,.react-flow__node-default:focus-visible,.react-flow__node-output.selected,.react-flow__node-output:focus,.react-flow__node-output:focus-visible,.react-flow__node-group.selected,.react-flow__node-group:focus,.react-flow__node-group:focus-visible{outline:none;border:var(--xy-node-border-selected, var(--xy-node-border-selected-default))}.react-flow__nodesselection-rect,.react-flow__selection{background:var(--xy-selection-background-color, var(--xy-selection-background-color-default));border:var(--xy-selection-border, var(--xy-selection-border-default))}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:5px;height:5px;border:1px solid #fff;border-radius:1px;background-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));translate:-50% -50%}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}", e = ':root{--safe-area-inset-top: env(safe-area-inset-top, 0px);--safe-area-inset-right: env(safe-area-inset-right, 0px);--safe-area-inset-bottom: env(safe-area-inset-bottom, 0px);--safe-area-inset-left: env(safe-area-inset-left, 0px)}:root{--apollon-chrome-surface: var(--apollon-background, #fff);--apollon-chrome-surface-hover: color-mix( in srgb, var(--apollon-primary-contrast, #000) 8%, var(--apollon-background, #fff) );--apollon-chrome-surface-active: color-mix( in srgb, var(--apollon-primary-contrast, #000) 14%, var(--apollon-background, #fff) );--apollon-chrome-border: color-mix( in srgb, var(--apollon-primary-contrast, #000) 12%, var(--apollon-background, #fff) );--apollon-chrome-border-strong: color-mix( in srgb, var(--apollon-primary-contrast, #000) 28%, var(--apollon-background, #fff) );--apollon-chrome-text: var(--apollon-primary-contrast, #212529);--apollon-chrome-text-muted: color-mix( in srgb, var(--apollon-primary-contrast, #000) 58%, var(--apollon-background, #fff) );--apollon-chrome-accent: var(--apollon-primary, #3e8acc);--apollon-chrome-accent-contrast: #fff;--apollon-chrome-radius-sm: 6px;--apollon-chrome-radius-md: 8px;--apollon-chrome-radius-lg: 12px;--apollon-chrome-edge: 10px;--apollon-chrome-gap: 8px;--apollon-chrome-btn: 32px;--apollon-chrome-pad: 6px;--apollon-chrome-hit: 44px;--apollon-chrome-edge-safe-left: max( var(--apollon-chrome-edge), var(--safe-area-inset-left, 0px) );--apollon-chrome-edge-safe-right: max( var(--apollon-chrome-edge), var(--safe-area-inset-right, 0px) );--apollon-chrome-edge-safe-bottom: max( var(--apollon-chrome-edge), var(--safe-area-inset-bottom, 0px) );--apollon-chrome-island-h: calc( var(--apollon-chrome-btn) + 2 * var(--apollon-chrome-pad) + 2px );--apollon-chrome-shadow-docked: 0 1px 2px rgb(15 23 42 / 8%);--apollon-chrome-shadow-floating: 0 0 1px 0 rgb(15 23 42 / 20%), 0 2px 8px 0 rgb(15 23 42 / 12%);--apollon-chrome-inset-hairline: 0 0 0 0 transparent;--apollon-chrome-glass: color-mix( in srgb, var(--apollon-background, #fff) 80%, transparent );--apollon-chrome-glass-solid: color-mix( in srgb, var(--apollon-background, #fff) 92%, transparent );--apollon-chrome-glass-blur: saturate(180%) blur(20px);--apollon-chrome-duration-hover: .12s;--apollon-chrome-duration-enter: .22s;--apollon-chrome-ease-standard: cubic-bezier(.2, 0, 0, 1);--apollon-chrome-ease-decelerate: cubic-bezier(.05, .7, .1, 1)}:root[data-theme=dark],.apollon-editor[data-theme=dark]{--apollon-chrome-shadow-docked: 0 1px 2px rgb(0 0 0 / 40%);--apollon-chrome-shadow-floating: 0 2px 12px 0 rgb(0 0 0 / 50%);--apollon-chrome-inset-hairline: inset 0 0 0 1px rgb(255 255 255 / 8%)}@media(pointer:coarse){:root{--apollon-chrome-pad: 4px}}.react-flow{--panel-background: var(--apollon-background, #fff);--panel-shadow: 0 0 4px 0 var(--apollon-background-variant, #f8f9fa);--text: var(--apollon-primary-contrast, #000);--xy-edge-stroke: var(--apollon-primary-contrast, #000);--xy-edge-stroke-width: 2px;--xy-controls-button-background-color: var(--apollon-background, #fff);--xy-controls-button-border-color: transparent}.apollon-editor{background-color:var(--apollon-background, #fff);color:var(--apollon-primary-contrast, #000);isolation:isolate;--apollon-z-chrome: 10005}.apollon-overlay-panel,.apollon-overlay-band{z-index:var(--apollon-z-chrome)}.apollon-canvas{position:relative;flex:1;min-width:0;height:100%;overflow:hidden}.apollon-collaboration-presence-bar{position:absolute;top:calc(10px + var(--apollon-inset-top, 0px));right:calc(10px + var(--apollon-inset-right, 0px));display:flex;align-items:center;z-index:10002;pointer-events:auto}.apollon-collaboration-presence-bar [role=button]:focus-visible{outline:2px solid var(--apollon-primary, #3e8acc);outline-offset:2px}.apollon-collaboration-follower-badge{position:absolute;bottom:-4px;left:-4px;min-width:14px;height:14px;padding:0 3px;box-sizing:border-box;display:flex;align-items:center;justify-content:center;border-radius:10px;border:2px solid;background-color:var(--apollon-background, #fff);color:var(--apollon-primary-contrast, #000);font-size:8px;font-weight:700}.apollon-collaboration-follow-frame{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;z-index:10001}.apollon-collaboration-follow-banner{position:absolute;top:16px;left:50%;transform:translate(-50%);display:flex;align-items:center;gap:8px;max-width:min(calc(100% - 32px),420px);padding:6px 6px 6px 14px;border-radius:999px;border:1px solid;background-color:var(--apollon-background, #fff);color:var(--apollon-primary-contrast, #000);box-shadow:0 2px 12px color-mix(in srgb,var(--apollon-primary-contrast, #000) 22%,transparent);font-size:13px;font-weight:500;white-space:nowrap;z-index:10004;pointer-events:auto;animation:apollon-collaboration-follow-banner-in .16s ease-out}@keyframes apollon-collaboration-follow-banner-in{0%{opacity:0;transform:translate(-50%,-8px)}to{opacity:1;transform:translate(-50%)}}@media(prefers-reduced-motion:reduce){.apollon-collaboration-follow-banner{animation:none}}.apollon-collaboration-follow-banner-dot{width:10px;height:10px;border-radius:50%;flex-shrink:0}.apollon-collaboration-follow-banner-text{overflow:hidden;text-overflow:ellipsis}.apollon-collaboration-follow-banner-stop{flex-shrink:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;border:none;cursor:pointer;border-radius:999px;padding:3px 12px;font:inherit;font-weight:600;background-color:var(--apollon-primary-contrast, #000);color:var(--apollon-background, #fff)}.apollon-collaboration-follow-banner-stop:hover{opacity:.85}.apollon-collaboration-follow-banner-stop:focus-visible{outline:2px solid var(--apollon-primary, #3e8acc);outline-offset:2px}.apollon-collaboration-cursors{position:absolute;top:0;right:0;bottom:0;left:0;overflow:hidden;pointer-events:none;z-index:10003}.apollon-collaboration-cursor{position:absolute}.apollon-collaboration-cursor-label{margin-top:4px;padding:2px 6px;font-size:12px;border-radius:6px;color:#fff;white-space:nowrap}.react-flow__node.apollon-collaboration-highlighted{box-shadow:0 0 0 4px var(--apollon-collaboration-highlight-color),0 0 16px 3px var(--apollon-collaboration-highlight-color)!important;border-color:var(--apollon-collaboration-highlight-color)!important}.react-flow__edge.apollon-collaboration-highlighted path{stroke:var(--apollon-collaboration-highlight-color)!important;stroke-width:4.5px!important;filter:drop-shadow(0 0 4px var(--apollon-collaboration-highlight-color))}.apollon-palette{box-sizing:border-box;position:absolute;top:calc(var(--safe-area-inset-top, 0px) + var(--apollon-chrome-gap) + var( --apollon-inset-top, calc(var(--apollon-chrome-edge) + var(--apollon-chrome-island-h)) ));left:calc(var(--apollon-chrome-edge-safe-left) + var(--apollon-inset-left, 0px));z-index:10000;max-height:calc(100% - var(--safe-area-inset-top, 0px) - var(--apollon-chrome-gap) - var( --apollon-inset-top, calc(var(--apollon-chrome-edge) + var(--apollon-chrome-island-h)) ) - var(--apollon-chrome-edge-safe-bottom) - var(--apollon-chrome-island-h) - var(--apollon-chrome-gap) - var(--apollon-inset-bottom, 0px));display:flex;flex-direction:column;gap:var(--apollon-chrome-gap);align-items:center;padding:var(--apollon-chrome-pad);overflow-y:auto;overscroll-behavior:contain;background:var(--apollon-chrome-glass);backdrop-filter:var(--apollon-chrome-glass-blur);-webkit-backdrop-filter:var(--apollon-chrome-glass-blur);color:var(--apollon-chrome-text);border:1px solid var(--apollon-chrome-border);border-radius:var(--apollon-chrome-radius-lg);box-shadow:var(--apollon-chrome-shadow-floating),var(--apollon-chrome-inset-hairline)}.apollon-palette__entries{display:grid;justify-content:center}.apollon-palette__entry{display:flex;align-items:center;justify-content:center;cursor:grab;border-radius:var(--apollon-chrome-radius-sm);transition:background-color .12s ease}.apollon-palette__entry:hover{background:var(--apollon-chrome-surface-hover)}.apollon-palette__entry:active{cursor:grabbing}.apollon-palette__view-switch{width:100%;display:flex;flex-direction:column;gap:4px}.apollon-palette__view-button{border-radius:var(--apollon-chrome-radius-md);border:1px solid var(--apollon-chrome-border-strong);background:transparent;color:var(--apollon-chrome-text);padding:6px 8px;cursor:pointer;font-weight:600;white-space:nowrap;font-size:12px}.apollon-palette__view-button:hover{background:var(--apollon-chrome-surface-hover)}.apollon-palette__view-button--active,.apollon-palette__view-button--active:hover{background:var(--apollon-chrome-accent);color:var(--apollon-chrome-accent-contrast);border-color:var(--apollon-chrome-accent)}.apollon-palette__hint{box-sizing:border-box;width:100%;max-width:160px;padding:4px;font-size:11px;line-height:1.4}.react-flow__panel.top.left,.react-flow__panel.top.right{margin-top:calc(var(--apollon-chrome-edge) + var(--safe-area-inset-top, 0px))}.react-flow__panel.bottom.left,.react-flow__panel.bottom.right{margin-bottom:var(--apollon-chrome-edge-safe-bottom)}.react-flow__panel.top.left,.react-flow__panel.bottom.left{margin-left:var(--apollon-chrome-edge-safe-left)}.react-flow__panel.top.right,.react-flow__panel.bottom.right{margin-right:var(--apollon-chrome-edge-safe-right)}.apollon-chrome-header-row{display:flex;align-items:flex-start;gap:var(--apollon-chrome-gap);width:100%;box-sizing:border-box;padding-top:var(--apollon-chrome-edge);padding-left:var(--apollon-chrome-edge-safe-left);padding-right:var(--apollon-chrome-edge-safe-right);pointer-events:none}.apollon-chrome-header-row>:not(.apollon-chrome-header-spacer){flex-shrink:0}.apollon-chrome-header-spacer{display:flex;flex:1 1 auto;min-width:0;justify-content:flex-start}@media(max-width:950px)and (max-height:500px){:root{--apollon-chrome-island-h: 36px;--apollon-chrome-pad: 2px}.apollon-collaboration-presence-bar{right:var(--apollon-chrome-edge-safe-right)}}.apollon-chrome-iconbtn{box-sizing:border-box;position:relative;display:inline-flex;align-items:center;justify-content:center;width:var(--apollon-chrome-btn);height:var(--apollon-chrome-btn);padding:0;border:0;border-radius:var(--apollon-chrome-radius-sm);background:transparent;color:var(--apollon-chrome-text);cursor:pointer;transition:background-color var(--apollon-chrome-duration-hover) var(--apollon-chrome-ease-standard)}.apollon-chrome-iconbtn>svg{fill:currentColor}.apollon-chrome-iconbtn:before{content:"";position:absolute;inset:calc((var(--apollon-chrome-btn) - var(--apollon-chrome-hit)) / 2)}.apollon-chrome-iconbtn:disabled{opacity:.4;cursor:not-allowed}.apollon-chrome-iconbtn:focus-visible{outline:none;box-shadow:0 0 0 2px color-mix(in srgb,var(--apollon-chrome-accent) 45%,transparent)}.apollon-chrome-iconbtn:hover:not(:disabled){background:var(--apollon-chrome-surface-hover)}.apollon-chrome-iconbtn:active:not(:disabled){background:var(--apollon-chrome-surface-active)}.apollon-chrome-iconbtn--readout{width:auto;min-width:48px;padding:0 8px;font-size:13px;font-weight:600;font-variant-numeric:tabular-nums}.react-flow__minimap.apollon-minimap{padding:0;overflow:hidden;border-radius:var(--apollon-chrome-radius-lg)}.react-flow__minimap.apollon-minimap .react-flow__minimap-svg{display:block;border-radius:inherit}.apollon-chrome-cluster-divider{align-self:stretch;width:1px;margin:4px 2px;background:var(--apollon-chrome-border)}.react-flow__controls-button{position:relative;width:var(--apollon-chrome-btn);height:var(--apollon-chrome-btn);padding:0;border:0;border-radius:var(--apollon-chrome-radius-sm);background:transparent;color:var(--apollon-chrome-text);transition:background-color var(--apollon-chrome-duration-hover) var(--apollon-chrome-ease-standard)}.react-flow__controls-button:before{content:"";position:absolute;inset:calc((var(--apollon-chrome-btn) - var(--apollon-chrome-hit)) / 2)}.react-flow__controls-button:hover{background:var(--apollon-chrome-surface-hover)}.react-flow__controls-button>svg{max-width:18px;max-height:18px;fill:currentColor}.apollon-glass,.react-flow__panel,.react-flow__node-toolbar{background-color:var(--apollon-chrome-glass);backdrop-filter:var(--apollon-chrome-glass-blur);-webkit-backdrop-filter:var(--apollon-chrome-glass-blur);border:1px solid var(--apollon-chrome-border);box-shadow:var(--apollon-chrome-shadow-floating),var(--apollon-chrome-inset-hairline);border-radius:var(--apollon-chrome-radius-lg)}.react-flow__panel,.react-flow__node-toolbar{padding:var(--apollon-chrome-pad)}.apollon-history-panel{background-color:var(--apollon-chrome-glass-solid)}.apollon-overlay-band,.apollon-overlay-panel{background-color:transparent;backdrop-filter:none;-webkit-backdrop-filter:none;border:0;box-shadow:none;border-radius:0;padding:0}.apollon-overlay-panel{margin:var(--apollon-chrome-edge)}@keyframes apollon-island-in{0%{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:translateY(0)}}.apollon-chrome-island{animation:apollon-island-in var(--apollon-chrome-duration-enter) var(--apollon-chrome-ease-decelerate) both}.apollon-chrome-title-island:focus-within{border-color:var(--apollon-chrome-accent);box-shadow:0 0 0 2px color-mix(in srgb,var(--apollon-chrome-accent) 35%,transparent),var(--apollon-chrome-shadow-floating)}@media(prefers-reduced-motion:reduce){.apollon-chrome-island{animation:none}}@media(prefers-reduced-transparency:reduce){.apollon-glass,.react-flow__panel,.react-flow__node-toolbar,.apollon-palette{background-color:var(--apollon-chrome-surface);backdrop-filter:none;-webkit-backdrop-filter:none}}@media(prefers-contrast:more){.apollon-glass,.react-flow__panel,.react-flow__node-toolbar,.apollon-palette{border-color:var(--apollon-chrome-border-strong)}}.react-flow svg{display:block}.react-flow__node-toolbar{display:flex;gap:8px}.react-flow__handle{opacity:0;background-color:transparent}.react-flow__handle.apollon-arc-handle:before{content:"";position:absolute;background-color:var(--apollon-primary, #3e8acc);opacity:.4;box-sizing:border-box;pointer-events:all;cursor:crosshair;--arc-long: calc(28px * var(--arc-scale, 1));--arc-short: calc(14px * var(--arc-scale, 1));--arc-radius: calc(14px * var(--arc-scale, 1))}.react-flow__handle.apollon-arc-handle--top:before{width:var(--arc-long);height:var(--arc-short);left:50%;top:50%;transform:translate(-50%,-100%);border-radius:var(--arc-radius) var(--arc-radius) 0 0}.react-flow__handle.apollon-arc-handle--right:before{width:var(--arc-short);height:var(--arc-long);left:50%;top:50%;transform:translateY(-50%);border-radius:0 var(--arc-radius) var(--arc-radius) 0}.react-flow__handle.apollon-arc-handle--bottom:before{width:var(--arc-long);height:var(--arc-short);left:50%;top:50%;transform:translate(-50%);border-radius:0 0 var(--arc-radius) var(--arc-radius)}.react-flow__handle.apollon-arc-handle--left:before{width:var(--arc-short);height:var(--arc-long);left:50%;top:50%;transform:translate(-100%,-50%);border-radius:var(--arc-radius) 0 0 var(--arc-radius)}.react-flow__resize-control line{z-index:9}.react-flow__resize-control.handle{z-index:20}.react-flow__resize-control{opacity:0;pointer-events:none;transition:opacity .12s ease}.react-flow__node:hover .react-flow__resize-control,.react-flow__node.selected .react-flow__resize-control{opacity:1;pointer-events:all}.react-flow__node:hover .react-flow__handle,.react-flow__node.selected .react-flow__handle{opacity:1;background-color:transparent;pointer-events:all;cursor:crosshair}.apollon-editor--connection-guidance .react-flow__handle.apollon-arc-handle:before{opacity:0;pointer-events:none}.apollon-editor--connection-guidance .react-flow__node:has(.apollon-connection-guidance-source),.apollon-editor--connection-guidance .react-flow__node:has(.react-flow__handle.connectionindicator.connectingto){z-index:10001!important}.apollon-editor--connection-guidance .react-flow__handle.connectionindicator{opacity:1!important;width:10px!important;height:10px!important;border-radius:999px;border:2px solid var(--apollon-primary, #3e8acc);background-color:var(--apollon-background, #fff);box-sizing:border-box}.apollon-editor--connection-guidance .react-flow__handle.connectionindicator.connectingfrom,.apollon-editor--connection-guidance .react-flow__handle.apollon-connection-guidance-source{opacity:0!important;pointer-events:none!important;border-color:transparent!important;background-color:transparent!important}.apollon-editor--connection-guidance .react-flow__handle.connectionindicator.valid{background-color:var(--apollon-primary, #3e8acc)!important}.edge-bend-handle{opacity:0;stroke:none;fill:color-mix(in srgb,var(--apollon-primary, #3e8acc) 34%,var(--apollon-background, #fff));transition:fill .12s ease,opacity .12s ease;vector-effect:non-scaling-stroke}.edge-endpoint-handle{fill:transparent;stroke:transparent;stroke-width:0;cursor:move;vector-effect:non-scaling-stroke}.edge-endpoint-handle--disabled{cursor:default}.react-flow__edge:hover .edge-bend-handle,.react-flow__edge.selected .edge-bend-handle{opacity:1;fill:var(--apollon-primary, #3e8acc)}.react-flow__edge:hover .edge-bend-handle:hover,.react-flow__edge.selected .edge-bend-handle:hover{fill:color-mix(in srgb,var(--apollon-primary, #3e8acc) 70%,#000)}.react-flow__edge:hover .edge-overlay,.react-flow__edge:hover .edge-marker-highlight{opacity:0}.react-flow__edge.selected .edge-overlay{opacity:0;pointer-events:none}.react-flow__edge.selected .edge-marker-highlight{opacity:0}.react-flow__edge:hover .react-flow__edge-path,.react-flow__edge:hover [data-inline-marker]{stroke:color-mix(in srgb,var(--apollon-primary, #3e8acc) 70%,#000)!important}.react-flow__edge:hover [data-inline-marker-filled=true]{fill:color-mix(in srgb,var(--apollon-primary, #3e8acc) 70%,#000)!important}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge.selected [data-inline-marker]{stroke:var(--apollon-primary, #3e8acc)!important}.react-flow__edge.selected [data-inline-marker-filled=true]{fill:var(--apollon-primary, #3e8acc)!important}.react-flow__node:hover,.react-flow__node.selected{opacity:.9;box-shadow:0 0 0 2px var(--apollon-primary, #3e8acc);border-radius:4px}.apollon-interactive-selection{--apollon-interactive-selection-color: var( --apollon-interactive-selection, #f39c12 )}.apollon-interactive-selection--selected [stroke]:not([stroke=none]){stroke:var(--apollon-interactive-selection-color)}.apollon-interactive-selection--selected .react-flow__edge-path{stroke-width:3px}.apollon-interactive-selection--selected .edge-overlay,.apollon-interactive-selection--selected .edge-marker-highlight{opacity:.45;stroke:var(--apollon-interactive-selection-color);stroke-width:15px}.react-flow__edges{z-index:9999}.react-flow__node{z-index:9998}svg.react-flow__connectionline{z-index:10000}.react-flow__connection-path{stroke:var(--xy-edge-stroke);stroke-width:var(--xy-edge-stroke-width);opacity:.5}.react-flow__minimap-mask{fill:var(--apollon-chrome-text-muted);opacity:.15}.prevent-select{-webkit-user-select:none;-ms-user-select:none;user-select:none}.horizontally-not-resizable .react-flow__resize-control.top.line:hover,.horizontally-not-resizable .react-flow__resize-control.bottom.line:hover,.vertically-not-resizable .react-flow__resize-control.right.line:hover,.vertically-not-resizable .react-flow__resize-control.left.line:hover{cursor:grab}.apollon-editor .MuiSelect-select,.apollon-editor .MuiFormLabel-root{color:var(--apollon-primary-contrast, #000)!important}.apollon-editor .MuiOutlinedInput-notchedOutline{border-color:var(--apollon-primary-contrast, #000)!important}.apollon-editor .MuiSvgIcon-root{color:var(--apollon-primary-contrast, #000)!important}.scroll-overlay{position:absolute;top:0;left:0;right:0;bottom:0;background-color:var(--apollon-grid, rgba(36, 39, 36, .1));-webkit-backdrop-filter:blur(.5px);backdrop-filter:blur(.5px);z-index:10;cursor:not-allowed;animation:fadeIn .2s ease-in-out;display:flex;align-items:center;justify-content:center;pointer-events:auto}.scroll-overlay-hint{position:absolute;bottom:40px;left:50%;transform:translate(-50%);z-index:11}.scroll-overlay-hint-content{background-color:var(--apollon-background, #fff);border:2px solid var(--apollon-primary, #3e8acc);border-radius:8px;padding:16px 24px;box-shadow:0 4px 12px var(--apollon-grid, rgba(36, 39, 36, .1));display:flex;align-items:center;justify-content:center}.scroll-overlay-hint-text{margin:0;color:var(--apollon-primary, #3e8acc);font-weight:600;font-size:14px;text-align:center}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}', r = `${o}
3
+ ${e}`;
4
+ export {
5
+ r as EXPORT_LAYOUT_CSS
6
+ };
@@ -14,6 +14,5 @@ export * from './useDragOver';
14
14
  export * from './useHandleFinder';
15
15
  export * from './useStepPathEdge';
16
16
  export * from './useStraightPathEdge';
17
- export * from './useMessagePositioning';
18
17
  export * from './useAssessmentSelection';
19
18
  export * from './usePaneClicked';
@@ -1,6 +1,7 @@
1
1
  import { Position } from '@xyflow/react';
2
2
  import { IPoint } from '../edges/Connection';
3
3
  import { BendHandle } from '../utils/geometry/bendHandles';
4
+ import { Rect } from '../utils/geometry/edgeLabelLayout';
4
5
  interface UseStepPathEdgeProps {
5
6
  id: string;
6
7
  type: string;
@@ -27,6 +28,16 @@ export interface StepPathEdgeData {
27
28
  isMiddlePathHorizontal: boolean;
28
29
  sourcePoint: IPoint;
29
30
  targetPoint: IPoint;
31
+ /** Bounds (flow space) of every node the edge routes near, so label placement
32
+ * keeps the label off any node's body, not just the source/target. */
33
+ nodeRects: Rect[];
34
+ /** Mid-segment endpoints in source->target order — the LOCAL flow direction
35
+ * at the middle (used for communication-message arrow direction). */
36
+ midSegmentStart: IPoint;
37
+ midSegmentEnd: IPoint;
38
+ /** Nearby other-edge polylines, so a middle label can break a side tie toward
39
+ * where fewer edges cross. */
40
+ neighborGeometry: IPoint[][];
30
41
  }
31
42
  export declare const useStepPathEdge: ({ id, type, source, target, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, data, allowMidpointDragging, enableStraightPath, }: UseStepPathEdgeProps) => {
32
43
  pathRef: import('react').RefObject<SVGPathElement | null>;
@@ -1,5 +1,6 @@
1
1
  export * from './typings';
2
2
  export { ApollonEditor } from './apollon-editor';
3
+ export type { OverlayRegion, OverlaySide, InsetContribution, OverlayControlOptions, OverlayControlInput, } from './overlay/types';
3
4
  export { getAssessmentNameForArtemis, getEdgeAssessmentDataById, getNodeAssessmentDataByNodeElementId, type AssessmentViewData, } from './utils/helpers';
4
5
  export { importDiagram } from './utils/versionConverter';
5
6
  export { collabColorFromName, randomCollabName } from './utils/collaboration';
@@ -0,0 +1,3 @@
1
+ import { NodeProps, Node } from '@xyflow/react';
2
+ import { ActivitySwimlaneProps } from '../../types';
3
+ export declare function ActivitySwimlane({ id, width, height, data, parentId, }: NodeProps<Node<ActivitySwimlaneProps>>): import("react").JSX.Element | null;
@@ -6,3 +6,4 @@ export * from './ActivityObjectNode';
6
6
  export * from './ActivityMergeNode';
7
7
  export * from './ActivityForkNode';
8
8
  export * from './ActivityForkNodeHorizontal';
9
+ export * from './ActivitySwimlane';
@@ -3,7 +3,7 @@ import { ObjectName } from './objectDiagram';
3
3
  import { CommunicationObjectName } from './communicationDiagram';
4
4
  import { TitleAndDesctiption } from './TitleAndDescriptionNode';
5
5
  import { default as Package } from './classDiagram/Package';
6
- import { Activity, ActivityInitialNode, ActivityFinalNode, ActivityActionNode, ActivityObjectNode, ActivityMergeNode, ActivityForkNode, ActivityForkNodeHorizontal } from './activityDiagram';
6
+ import { Activity, ActivityInitialNode, ActivityFinalNode, ActivityActionNode, ActivityObjectNode, ActivityMergeNode, ActivityForkNode, ActivityForkNodeHorizontal, ActivitySwimlane } from './activityDiagram';
7
7
  import { UseCase, UseCaseActor, UseCaseSystem } from './useCaseDiagram';
8
8
  import { Component, ComponentInterface, ComponentSubsystem } from './componentDiagram';
9
9
  import { DeploymentNode, DeploymentComponent, DeploymentArtifact, DeploymentInterface } from './deploymentDiagram';
@@ -29,6 +29,7 @@ export declare const diagramNodeTypes: {
29
29
  activityMergeNode: typeof ActivityMergeNode;
30
30
  activityForkNode: typeof ActivityForkNode;
31
31
  activityForkNodeHorizontal: typeof ActivityForkNodeHorizontal;
32
+ activitySwimlane: typeof ActivitySwimlane;
32
33
  useCase: typeof UseCase;
33
34
  useCaseActor: typeof UseCaseActor;
34
35
  useCaseSystem: typeof UseCaseSystem;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The single in-canvas host layer. Renders every registered overlay control into
3
+ * its region (React Flow `<Panel>` for the six corners, library-owned bands for
4
+ * header/rails, `<ViewportPortal>` for on-canvas) and measures auto-inset
5
+ * controls with one shared ResizeObserver (the store derives the content-inset
6
+ * rect from those measurements — it is the single inset authority).
7
+ */
8
+ export declare function OverlayLayer(): import("react").JSX.Element;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Mounts a host-owned DOM node (returned by `editor.getRegionElement`) into an
3
+ * overlay region. The node's lifetime is the editor instance, not this React
4
+ * subtree, so a host `createPortal` target stays valid across re-renders. The
5
+ * host renders into the node from its OWN React root, keeping host context
6
+ * (theme tokens, router) — see ApollonEditor.getRegionElement.
7
+ */
8
+ export declare function RegionMount({ el }: {
9
+ el: HTMLElement;
10
+ }): import("react").JSX.Element;
@@ -0,0 +1,20 @@
1
+ import { StoreApi, UseBoundStore } from 'zustand';
2
+ import { Insets, OverlayControl, OverlaySide } from './types';
3
+ /**
4
+ * Content-inset rect: per side, the largest reservation among visible controls
5
+ * touching that side. `max` (not sum) avoids double-counting nested/stacked
6
+ * chrome. Controls hidden with `visible: false` reserve nothing. Recomputed on
7
+ * every mutation so the rect is reliable without a render.
8
+ */
9
+ export declare function computeInsets(controls: OverlayControl[], measured: Record<string, Partial<Record<OverlaySide, number>>>): Insets;
10
+ export type OverlayStore = {
11
+ controls: Record<string, OverlayControl>;
12
+ /** Measured rects per control id (written by the shared ResizeObserver). */
13
+ measured: Record<string, Partial<Record<OverlaySide, number>>>;
14
+ /** Derived content-inset rect — recomputed on every registry mutation. */
15
+ insets: Insets;
16
+ register: (control: OverlayControl) => void;
17
+ unregister: (id: string) => void;
18
+ setMeasured: (id: string, rect: Partial<Record<OverlaySide, number>>) => void;
19
+ };
20
+ export declare const createOverlayStore: () => UseBoundStore<StoreApi<OverlayStore>>;