@rasamjs/connectors 0.0.0-stage → 0.2.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 (46) hide show
  1. package/API.md +143 -0
  2. package/CHANGELOG.md +40 -0
  3. package/LICENSE +21 -0
  4. package/README.md +54 -2
  5. package/RELEASING.md +27 -0
  6. package/dist/connectors.d.ts +38 -0
  7. package/dist/connectors.d.ts.map +1 -0
  8. package/dist/connectors.js +291 -0
  9. package/dist/connectors.js.map +1 -0
  10. package/dist/editor.d.ts +56 -0
  11. package/dist/editor.d.ts.map +1 -0
  12. package/dist/editor.js +67 -0
  13. package/dist/editor.js.map +1 -0
  14. package/dist/index.d.ts +5 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +4 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/metadata.d.ts +12 -0
  19. package/dist/metadata.d.ts.map +1 -0
  20. package/dist/metadata.js +72 -0
  21. package/dist/metadata.js.map +1 -0
  22. package/dist/routing.d.ts +14 -0
  23. package/dist/routing.d.ts.map +1 -0
  24. package/dist/routing.js +130 -0
  25. package/dist/routing.js.map +1 -0
  26. package/dist/tool-surface.d.ts +21 -0
  27. package/dist/tool-surface.d.ts.map +1 -0
  28. package/dist/tool-surface.js +98 -0
  29. package/dist/tool-surface.js.map +1 -0
  30. package/dist/tool.d.ts +47 -0
  31. package/dist/tool.d.ts.map +1 -0
  32. package/dist/tool.js +326 -0
  33. package/dist/tool.js.map +1 -0
  34. package/dist/types.d.ts +43 -0
  35. package/dist/types.d.ts.map +1 -0
  36. package/dist/types.js +2 -0
  37. package/dist/types.js.map +1 -0
  38. package/package.json +64 -6
  39. package/src/connectors.ts +324 -0
  40. package/src/editor.ts +105 -0
  41. package/src/index.ts +14 -0
  42. package/src/metadata.ts +88 -0
  43. package/src/routing.ts +153 -0
  44. package/src/tool-surface.ts +96 -0
  45. package/src/tool.ts +367 -0
  46. package/src/types.ts +38 -0
package/API.md ADDED
@@ -0,0 +1,143 @@
1
+ # Connectors API
2
+
3
+ The root exports `Connectors`, `isConnector`, `connectorPort`, `routeConnector` and
4
+ connector option/state/geometry types. Optional `./tool` exports `ConnectorTool` and
5
+ `ConnectorToolOptions`. Only core is imported at runtime. Imports are document-free.
6
+
7
+ ## Model and history
8
+
9
+ `new Connectors(drawing)` attaches one service to an owning SVG root. Existing saved
10
+ connectors are validated without rewriting their stored geometry. No history recorder
11
+ is created; supply your own if needed.
12
+
13
+ `create(options)` returns an ordinary `Path` in one labelled core change group:
14
+
15
+ - `start`, `end`: `{ target, anchor? }`, `{ target, port }` or `{ point: { x, y } }`.
16
+ Free points use drawing units. Targets are transformable shapes/groups/viewports in the same drawing,
17
+ excluding the root, connectors and groups containing connectors.
18
+ - `anchor`: `auto` (default), `top`, `right`, `bottom`, `left`, or `{ x, y }` normalized
19
+ between 0 and 1 within the target's local geometric bounds. `{ x: 1, y: 0.5 }` is
20
+ right-center and follows resizing. Sides rotate with the target. Auto intersects the
21
+ ray toward the other endpoint with the local bounds rectangle.
22
+ - `port`: the name of one of the target's ports, read structurally from its
23
+ `portDefinitions` (core's `PortDefinition`), such as a component's `ports()`. The end
24
+ sits exactly on the port and leaves along the port's side, transformed with the
25
+ target; a port without a side has no lead. An unknown port rejects the edit.
26
+ - `routing`: `straight` (default) or `elbow`. Elbows use orthogonal drawing-space
27
+ segments with 16-unit outward leads. They do not avoid obstacles; close/opposing
28
+ anchors can produce backtracking. Curved routing and connector labels are deferred.
29
+ - `arrows`: `end` (default), `both`, or `none`. SVG markers use `auto-start-reverse`
30
+ orientation and `context-stroke` fill, following the connector's stroke.
31
+ - `stroke`: nonempty SVG paint, default `#334155`; `strokeWidth`: finite nonnegative
32
+ number, default 2. Edit subsequent appearance through ordinary path APIs.
33
+
34
+ `nodes` is a frozen snapshot of current paths in document order. `links(target, port?)`
35
+ lists the connectors with an end on `target`, or only on its port named `port`, in
36
+ the same order. `read(path)` returns `{ path, start, end, routing }`. `update(path, { start?, end?, routing? })` changes a
37
+ connection in one labelled edit. `remove(path)` detaches it reversibly in one edit;
38
+ its marker resources remain available. Undoing creation also removes newly created
39
+ endpoint IDs and markers. Undo/redo retain path and endpoint identities.
40
+
41
+ Routes update synchronously through core `deriveChanges()`, before the mover's final
42
+ change snapshot. Shape/parent moves, resizing, rotation and reparenting join the same
43
+ operation/group, including ordinary setters, transformer gestures and transactions.
44
+ Getter-only operations do not route. Replay and rollback restore saved path data
45
+ without recomputing it. Camera changes with source `viewport` do not route.
46
+
47
+ Only the connectors a change reaches are routed: those inside a changed subtree and
48
+ those attached to a changed node, its descendants or its ancestors. Attachments are
49
+ found through core's typed-reference index (`context.defs.consumersOf(target)`), so a
50
+ move costs about the same with 10 or 1,000 connectors in the drawing. `links()` uses the
51
+ same index. `bun run bench` measures 500 parts with 10 and 1,000 links
52
+ (`reports/benchmark.json`; `--revision=<commit>` measures older connector sources).
53
+
54
+ Geometry uses fill bounds, excluding strokes and clipping. Curved/irregular targets
55
+ use their bounds rectangle for automatic anchors. Empty/unavailable geometry or an
56
+ unmappable automatic anchor/path rejects creation/update. When a target leaves the
57
+ drawing (removal, Delete, Cut, or removing a parent) or its port disappears (for
58
+ example after a prop change), that end becomes a loose point where the path ends now,
59
+ in the same operation and undo step, and the target is no longer referenced. Undo
60
+ restores the attachment. Existing paths retain their last geometry while targets are
61
+ unmappable.
62
+ A connector cannot be placed inside its own endpoint target, which would make routing
63
+ cyclic. Failed connector commands cancel partial edits. Caller setters follow core's
64
+ failure semantics; use a history transaction for rollback when dependent writes fail.
65
+ The service discovers imported/cloned paths at operation boundaries without registration.
66
+
67
+ `isDestroyed` reports disposal. `destroy()` is idempotent and stops derivation without
68
+ removing document paths. `onDispose(callback)` returns an unsubscribe function.
69
+ Drawing disposal destroys the service and its tools. Recreate for a replacement drawing.
70
+
71
+ ## Persistence
72
+
73
+ Versioned routing, anchors, ports and free points live in `data-rasam-connector`
74
+ (version 1). A port end is saved as `{ "port": "b" }`; readers without port support
75
+ treat it as an automatic anchor on the same target. Attached
76
+ targets use typed href fragments in the reserved `data-rasam-connector-start` and
77
+ `data-rasam-connector-end` attributes. Core recognizes them during clone, export/import
78
+ and ID remapping. Markers use normal typed URL references. No custom catalog is needed.
79
+
80
+ Cloning a whole group rebinds copied connectors to copied endpoints. Cloning a path
81
+ alone shares its external endpoints/markers by default. Targets are links, not
82
+ resources: exporting, copying or duplicating a connector never copies the shapes it
83
+ joins into defs. Importing or pasting one whose target was left out turns that end into
84
+ a loose point where it was, and ends whose targets were copied along rebind to the
85
+ copies. A whole drawing retains visible shapes and attachments. Permanently destroying
86
+ a target that a connector still references is refused, as for any referenced node;
87
+ editor deletion uses reversible removal, which loosens those ends first. Connectors
88
+ 0.2.0 requires core 0.3.0 or a compatible newer 0.3.x release. Earlier connector
89
+ versions do not provide the named-port or partial-copy behavior above.
90
+
91
+ ## Geometry helpers
92
+
93
+ `connectorPort(endpoint, toward)` returns `{ point, direction }` in drawing units or
94
+ null for unavailable geometry. Direction is the dominant orthogonal outward axis,
95
+ or zero for a free endpoint. `routeConnector({ start, end, routing })` returns route
96
+ points without editing the drawing.
97
+
98
+ ## Connector tool
99
+
100
+ `new ConnectorTool(connectors, options = {})` creates a disabled overlay outside the
101
+ managed SVG. Set `enabled = true` to draw primary-pointer drags. Options accept the
102
+ same routing/arrows/stroke/strokeWidth settings, plus:
103
+
104
+ - `selectable(target)`: filter hover targets, for example with layer lock rules.
105
+ - `onCreate(path)`: select the committed node or switch tools after creation.
106
+ - `onGesture(active)`: suspend camera input during a drag; false on completion/cancel.
107
+ - `onError(error)`: receives pointer/callback errors; otherwise errors propagate.
108
+ - `onExit()`: runs after Escape exits an idle enabled tool.
109
+
110
+ Hover shows four side hints, five overlay pixels in radius at every zoom. A target with
111
+ ports, such as a component, shows its ports instead (`data-connector-port`). Press or
112
+ release within twelve client pixels of a hint to choose it, a side anchor or a
113
+ `{ target, port }` end; the chosen hint is filled (`data-connector-active`). Other
114
+ body presses use auto anchors. Hit testing never reports groups, so a hit that
115
+ `selectable` rejects, such as a component's rendered child, resolves to its nearest
116
+ accepted ancestor. Empty-space
117
+ presses/releases use free points. Previews never edit the document. Release creates one
118
+ labelled edit; coincident endpoints create nothing. The tool stays enabled so the app
119
+ can choose keep-tool behavior.
120
+
121
+ Escape cancels an active drag; another Escape exits the tool. Blur, pointer cancellation,
122
+ lost capture, disabling, endpoint removal, service destruction and drawing destruction
123
+ release captures/previews. Editable controls and dialogs retain their keys. `update()`
124
+ refreshes the overlay and returns the tool. `isDestroyed` reports disposal. `destroy()`
125
+ is idempotent and releases listeners, frames, observers and DOM. Disable the tool when
126
+ switching other application modes.
127
+
128
+ ## Editor integration entry
129
+
130
+ `@rasamjs/connectors/editor` exports `connectorEditing(options?)`, a structural extension
131
+ factory. Its value is the current `Connectors` service. It registers
132
+ `connector-straight` (C) and `connector-elbow` (Shift+C), or the `tools` you pass:
133
+ `ConnectorEditingTool` entries `{ id, label, key, routing?, arrows?, hint? }`, for
134
+ example `{ id: 'wire', label: 'Wire', key: 'W', routing: 'elbow', arrows: 'none' }`.
135
+ Each tool has a matching command ID and active-tool metadata, current selection/layer
136
+ restrictions, paint, keep-tool and camera/capture cleanup. Escape cancels a drag first
137
+ and exits an idle tool; document replacement, editing/dialog actions, tool changes and
138
+ disposal interrupt sessions. Read-only camera commands retain an idle connector mode.
139
+
140
+ `ConnectorTool.paint` reads an immutable `{ stroke, strokeWidth }` snapshot and
141
+ accepts a validated replacement. Updates repaint an active preview and apply to
142
+ the committed path. The adapter forwards editor paint changes through this API.
143
+ The adapter imports only connector modules and core, with no editor peer.
package/CHANGELOG.md ADDED
@@ -0,0 +1,40 @@
1
+ # Changelog
2
+
3
+ ## Unreleased
4
+
5
+ ## 0.2.0 — 2026-11-07
6
+
7
+ - Ignore disposed derived children when finding affected links during component
8
+ hydration, so copying and pasting rendered components keeps its undo step.
9
+ - Attach ends to named ports with `{ target, port }`, read structurally from
10
+ `portDefinitions` such as a component's `ports()`. Port ends sit exactly on the port,
11
+ lead out along its side and save as `{ "port": "b" }` in version 1 metadata.
12
+ - When a target leaves the drawing or its port disappears, that end becomes a loose
13
+ point where it was, in the same undo step; undo reattaches it. Deleted targets are no
14
+ longer saved as hidden dependencies in `<defs>`.
15
+ - Copying or pasting a connector without its targets pastes loose ends instead of
16
+ hidden copies of the targets.
17
+ - Add `links(target, port?)`.
18
+ - Route only the connectors a change reaches, found through core's reference index:
19
+ with 500 parts, moving one part 100 times takes 20 ms with 1,000 links (1,726 ms
20
+ before) and 15 ms with 10 links. Creating 1,000 links takes 1.1 s instead of 11.2 s.
21
+ Add `bun run bench`.
22
+ - The tool shows a target's ports instead of its side hints, snaps to the nearest one
23
+ within twelve client pixels, fills the chosen hint, and resolves a rejected hit (such
24
+ as a component's rendered child) to its nearest accepted ancestor.
25
+ - `connectorEditing({ tools })` registers custom tools, such as a Wire tool with elbow
26
+ routing and no arrows, in place of Connector and Elbow connector.
27
+ - TypeScript: `ConnectorEndpoint` has a third, port variant. Narrow with
28
+ `'anchor' in endpoint` before reading `anchor`.
29
+
30
+ ## 0.1.0 — 2026-11-06
31
+
32
+ - Add `./editor` connector integration with registered tool metadata, live paint,
33
+ keep-tool and scoped camera/input cleanup. Add `ConnectorTool.paint` for preview updates.
34
+
35
+ - Add attached straight/elbow paths, automatic/side/normalized-point anchors, free
36
+ endpoints, marker arrows and saved typed references.
37
+ - Derive routing inside the mover's original operation/group; undo/redo restore stored
38
+ geometry. Support transformed parents, resizing, reparenting and cloned connections.
39
+ - Add optional `./tool` with hover anchors, previews, capture, cancellation and cleanup.
40
+ - Include API, documentation, size/isolation and packed-consumer checks.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 rasam contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,55 @@
1
- # Temporary Holding Version
1
+ # @rasamjs/connectors
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The optional [editor adapter](API.md#editor-integration-entry) packages connector
4
+ services and registered straight/elbow tools, including live paint and input cleanup.
5
+
6
+ Attached straight and elbow lines and marker arrows for rasam SVG drawings. Core is
7
+ the only runtime peer. Version 0.2.0 requires `@rasamjs/core@^0.3.0` for named ports,
8
+ loose-end persistence and indexed routing. Source manifests stay private between releases.
9
+
10
+ ```sh
11
+ npm install @rasamjs/core@^0.3.0 @rasamjs/connectors@^0.2.0
12
+ ```
13
+
14
+ ```ts
15
+ import { SVG } from '@rasamjs/core';
16
+ import { Connectors } from '@rasamjs/connectors';
17
+ import { ConnectorTool } from '@rasamjs/connectors/tool';
18
+
19
+ const drawing = SVG(host, { width: 700, height: 500 });
20
+ const a = drawing.rect({ x: 40, y: 40, width: 80, height: 50 });
21
+ const b = drawing.rect({ x: 300, y: 180, width: 80, height: 50 });
22
+ const connectors = new Connectors(drawing);
23
+ const path = connectors.create({
24
+ start: { target: a, anchor: 'right' },
25
+ end: { target: b, anchor: 'auto' },
26
+ routing: 'elbow',
27
+ });
28
+ const tool = new ConnectorTool(connectors, { routing: 'straight' });
29
+ tool.enabled = true;
30
+ ```
31
+
32
+ Ends can also attach to a component's named ports, `{ target: chip, port: 'p3' }`, and
33
+ `connectors.links(chip)` lists the connectors on it. Deleting a target keeps its
34
+ connectors, with a loose end where it was.
35
+
36
+ Moving or resizing an endpoint, or its parent, updates the connector inside the same
37
+ model operation and change group. History records one undo step for a move and all
38
+ its attached lines. Replay restores stored geometry without routing again.
39
+
40
+ The optional tool previews on an overlay, shows side anchors on hover, and writes
41
+ one connector on release. Escape, pointer cancellation and blur discard the preview.
42
+ The playground exposes Connector (`C`) and Elbow connector (`Shift+C`) tools.
43
+
44
+ Attachments are typed references on ordinary paths, so saved SVG, clones, imports,
45
+ clipboard and history retain them. No custom element registration is needed.
46
+ Both entries can be imported without a document. See [API.md](./API.md) for anchor
47
+ coordinates, lifecycle, routing limits and persistence behavior.
48
+
49
+ ```sh
50
+ bun run --cwd packages/connectors test
51
+ bun run --cwd packages/connectors test:browser
52
+ bun run --cwd packages/connectors typecheck
53
+ bun run --cwd packages/connectors build
54
+ bun run --cwd packages/connectors bench
55
+ ```
package/RELEASING.md ADDED
@@ -0,0 +1,27 @@
1
+ # Releasing connectors
2
+
3
+ The source manifest stays private between releases. Version 0.2.0 is paired with
4
+ core 0.3.0 and adds named ports, loose ends, partial-copy remapping and indexed routing.
5
+ The owner authorized release preparation, publication and pushing on 2026-11-07.
6
+ Existing approved size caps stay unchanged.
7
+
8
+ Run scoped format, typecheck, unit, build, API, docs, browser, consumer and size checks.
9
+ Run `api:update` only after reviewing the API diff. The root's 5 KiB gzip and optional
10
+ tool's 4 KiB budgets keep core external and UI code isolated from the model entry.
11
+
12
+ The separately requested `release:check` uses the shared workspace gate and records
13
+ source hashes/readiness. Build core first: connectors need its current derivation and
14
+ reserved-reference APIs. The consumer check packs only core and connectors, validates
15
+ all three entries, declarations, maps, document-free imports and absence of dependencies.
16
+
17
+ Phase 13 adds `@rasamjs/connectors/editor`, a structural service/tool adapter at
18
+ 5,781/8,192 B gzip. It keeps the existing core-only peer graph; editor is not a
19
+ runtime dependency or peer. Root/tool caps remain unchanged. The tool accepts live
20
+ paint updates, and editor/playground matrices cover registered shortcuts, metadata,
21
+ keep-tool, captures and camera cleanup. Scoped checks pass 18 unit tests and 12
22
+ three-engine browser cases, typecheck/build, formatting, API/docs, size/isolation
23
+ and the packed consumer. The full release gate, new benchmarks and native-device
24
+ checks were not run.
25
+
26
+ Before separately authorized publication, follow the workspace/core release procedure
27
+ and validate the matching core version. No npm publication is performed here.
@@ -0,0 +1,38 @@
1
+ import { Path } from '@rasamjs/core';
2
+ import type { Svg } from '@rasamjs/core';
3
+ import type { ConnectorOptions, ConnectorState, ConnectorTarget } from './types.js';
4
+ export declare class Connectors {
5
+ readonly drawing: Svg;
6
+ private disposed;
7
+ private readonly cleanups;
8
+ private readonly disposals;
9
+ constructor(drawing: Svg);
10
+ get isDestroyed(): boolean;
11
+ onDispose(listener: () => void): () => void;
12
+ get nodes(): readonly Path[];
13
+ read(path: Path): ConnectorState;
14
+ /** Connectors with an end on `target`, or only on its port named `port`. */
15
+ links(target: ConnectorTarget, port?: string): readonly Path[];
16
+ create(options: ConnectorOptions): Path;
17
+ update(path: Path, patch: Partial<Pick<ConnectorOptions, 'start' | 'end' | 'routing'>>): void;
18
+ remove(path: Path): void;
19
+ destroy(): void;
20
+ private assertLive;
21
+ private assertPath;
22
+ private validate;
23
+ private validateEndpoint;
24
+ /** An end whose target left the drawing, or whose port is gone, stays where it is. */
25
+ private loosen;
26
+ /** Connectors in this drawing with an end on `target`, from core's reference index. */
27
+ private attached;
28
+ /**
29
+ * Connectors to route after a change: those inside a changed subtree, and those attached
30
+ * to a changed node, its descendants or its ancestors, since parents move, resize or
31
+ * reparent targets and a descendant changes a group's bounds. The work follows the
32
+ * size of the change, not the number of connectors.
33
+ */
34
+ private affected;
35
+ private route;
36
+ private edit;
37
+ }
38
+ //# sourceMappingURL=connectors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connectors.d.ts","sourceRoot":"","sources":["../src/connectors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,KAAK,EAAE,GAAG,EAAW,MAAM,eAAe,CAAC;AAoBlD,OAAO,KAAK,EAEV,gBAAgB,EAChB,cAAc,EACd,eAAe,EAChB,MAAM,YAAY,CAAC;AAkBpB,qBAAa,UAAU;IAIT,QAAQ,CAAC,OAAO,EAAE,GAAG;IAHjC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsB;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyB;IACnD,YAAqB,OAAO,EAAE,GAAG,EAyBhC;IACD,IAAI,WAAW,IAAI,OAAO,CAEzB;IACD,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAO1C;IACD,IAAI,KAAK,IAAI,SAAS,IAAI,EAAE,CAG3B;IACD,IAAI,CAAC,IAAI,EAAE,IAAI,GAAG,cAAc,CAG/B;IACD,4EAA4E;IAC5E,KAAK,CAAC,MAAM,EAAE,eAAe,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,IAAI,EAAE,CAiB7D;IACD,MAAM,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAgCtC;IACD,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,OAAO,GAAG,KAAK,GAAG,SAAS,CAAC,CAAC,GAAG,IAAI,CAS5F;IACD,MAAM,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAGvB;IACD,OAAO,IAAI,IAAI,CAcd;IACD,OAAO,CAAC,UAAU;IAGlB,OAAO,CAAC,UAAU;IAUlB,OAAO,CAAC,QAAQ;IAmBhB,OAAO,CAAC,gBAAgB;IA2BxB,sFAAsF;IACtF,OAAO,CAAC,MAAM;IAgBd,uFAAuF;IACvF,OAAO,CAAC,QAAQ;IAYhB;;;;;OAKG;IACH,OAAO,CAAC,QAAQ;IAehB,OAAO,CAAC,KAAK;IAuBb,OAAO,CAAC,IAAI;CAgBb"}
@@ -0,0 +1,291 @@
1
+ import { Path } from '@rasamjs/core';
2
+ import { Guards } from '@rasamjs/core/advanced';
3
+ import { beginChangeGroup, deriveChanges } from '@rasamjs/core/changes';
4
+ import { endpointAttribute, isConnector, pathEnd, readConnector, unbound, writeConnector, } from './metadata.js';
5
+ import { connectorPort, endpointCenter, findPort, pathData, routeConnector, validateAnchor, validatePoint, } from './routing.js';
6
+ const owners = new WeakMap();
7
+ const drawableTags = new Set([
8
+ 'rect',
9
+ 'circle',
10
+ 'ellipse',
11
+ 'line',
12
+ 'polyline',
13
+ 'polygon',
14
+ 'path',
15
+ 'text',
16
+ 'image',
17
+ 'foreignObject',
18
+ 'use',
19
+ 'g',
20
+ 'svg',
21
+ ]);
22
+ export class Connectors {
23
+ drawing;
24
+ disposed = false;
25
+ cleanups = [];
26
+ disposals = new Set();
27
+ constructor(drawing) {
28
+ this.drawing = drawing;
29
+ if (!Guards.isTransformable(drawing) ||
30
+ drawing.isDestroyed ||
31
+ drawing !== drawing.context.root ||
32
+ drawing.el.localName !== 'svg')
33
+ throw new TypeError('Connectors needs a live SVG drawing root');
34
+ if (owners.has(drawing))
35
+ throw new Error('Connectors is already attached to this drawing');
36
+ // Validate saved attachments without changing stored routing during attachment or replay.
37
+ this.nodes.forEach(readConnector);
38
+ owners.set(drawing, this);
39
+ this.cleanups.push(deriveChanges(drawing, (event) => {
40
+ if (event.source === 'viewport')
41
+ return;
42
+ for (const path of this.affected(event.nodes)) {
43
+ let state = readConnector(path);
44
+ const loose = this.loosen(state);
45
+ if (loose !== state || unbound.has(state.start) || unbound.has(state.end))
46
+ writeConnector(path, (state = loose));
47
+ this.route(state);
48
+ }
49
+ }), drawing.onDispose(() => this.destroy()));
50
+ }
51
+ get isDestroyed() {
52
+ return this.disposed;
53
+ }
54
+ onDispose(listener) {
55
+ this.assertLive();
56
+ if (typeof listener !== 'function')
57
+ throw new TypeError('Disposal listener must be a function');
58
+ this.disposals.add(listener);
59
+ return () => {
60
+ this.disposals.delete(listener);
61
+ };
62
+ }
63
+ get nodes() {
64
+ this.assertLive();
65
+ return Object.freeze(this.drawing.descendants().filter(isConnector));
66
+ }
67
+ read(path) {
68
+ this.assertPath(path);
69
+ return readConnector(path);
70
+ }
71
+ /** Connectors with an end on `target`, or only on its port named `port`. */
72
+ links(target, port) {
73
+ this.assertLive();
74
+ if (port !== undefined && (typeof port !== 'string' || !port))
75
+ throw new TypeError('Port names must be non-empty strings');
76
+ return Object.freeze(this.attached(target)
77
+ .filter((path) => {
78
+ const { start, end } = readConnector(path);
79
+ return [start, end].some((endpoint) => 'target' in endpoint &&
80
+ endpoint.target === target &&
81
+ (port === undefined || ('port' in endpoint && endpoint.port === port)));
82
+ })
83
+ .sort((a, b) => (a.el.compareDocumentPosition(b.el) & 4 ? -1 : 1)));
84
+ }
85
+ create(options) {
86
+ this.assertLive();
87
+ this.validate(options);
88
+ return this.edit('Create connector', () => {
89
+ const path = this.drawing.path({
90
+ d: '',
91
+ fill: 'none',
92
+ stroke: options.stroke ?? '#334155',
93
+ 'stroke-width': options.strokeWidth ?? 2,
94
+ });
95
+ writeConnector(path, {
96
+ start: options.start,
97
+ end: options.end,
98
+ routing: options.routing ?? 'straight',
99
+ });
100
+ if ((options.arrows ?? 'end') !== 'none') {
101
+ const marker = this.drawing.createMarker({
102
+ viewBox: '0 0 10 10',
103
+ markerWidth: 6,
104
+ markerHeight: 6,
105
+ refX: 9,
106
+ refY: 5,
107
+ orient: 'auto-start-reverse',
108
+ });
109
+ marker.path({ d: 'M0 0 L10 5 L0 10 Z', fill: 'context-stroke', stroke: 'none' });
110
+ path.marker('end', marker);
111
+ if (options.arrows === 'both')
112
+ path.marker('start', marker);
113
+ }
114
+ if (!this.route(readConnector(path)))
115
+ throw new Error('Connector needs available bounds and invertible transforms');
116
+ return path;
117
+ });
118
+ }
119
+ update(path, patch) {
120
+ this.assertPath(path);
121
+ const state = { ...readConnector(path), ...patch };
122
+ this.validate(state);
123
+ this.edit('Edit connector', () => {
124
+ writeConnector(path, state);
125
+ if (!this.route(state))
126
+ throw new Error('Connector needs available bounds and invertible transforms');
127
+ });
128
+ }
129
+ remove(path) {
130
+ this.assertPath(path);
131
+ this.edit('Delete connector', () => path.remove());
132
+ }
133
+ destroy() {
134
+ if (this.disposed)
135
+ return;
136
+ this.disposed = true;
137
+ owners.delete(this.drawing);
138
+ const failures = [];
139
+ for (const stop of [...this.cleanups.splice(0).reverse(), ...this.disposals]) {
140
+ try {
141
+ stop();
142
+ }
143
+ catch (error) {
144
+ failures.push(error);
145
+ }
146
+ }
147
+ this.disposals.clear();
148
+ if (failures.length)
149
+ throw new AggregateError(failures, 'Connector cleanup failed');
150
+ }
151
+ assertLive() {
152
+ if (this.disposed)
153
+ throw new Error('Connectors is destroyed');
154
+ }
155
+ assertPath(path) {
156
+ this.assertLive();
157
+ if (!isConnector(path) ||
158
+ path.isDestroyed ||
159
+ path.context !== this.drawing.context ||
160
+ !this.drawing.el.contains(path.el))
161
+ throw new TypeError('Expected a connector in this drawing');
162
+ }
163
+ validate(options) {
164
+ if (!options || typeof options !== 'object')
165
+ throw new TypeError('Connector options must be an object');
166
+ for (const endpoint of [options.start, options.end])
167
+ this.validateEndpoint(endpoint);
168
+ if (options.routing !== undefined && !['straight', 'elbow'].includes(options.routing))
169
+ throw new TypeError('Unknown connector routing');
170
+ if (options.arrows !== undefined && !['none', 'end', 'both'].includes(options.arrows))
171
+ throw new TypeError('Unknown connector arrows');
172
+ if (options.stroke !== undefined &&
173
+ (typeof options.stroke !== 'string' || !options.stroke.trim()))
174
+ throw new TypeError('Connector stroke must be nonempty');
175
+ if (options.strokeWidth !== undefined &&
176
+ (!Number.isFinite(options.strokeWidth) || options.strokeWidth < 0))
177
+ throw new TypeError('Connector stroke width must be nonnegative');
178
+ }
179
+ validateEndpoint(endpoint) {
180
+ if (!endpoint || typeof endpoint !== 'object' || 'target' in endpoint === 'point' in endpoint)
181
+ throw new TypeError('Endpoint needs either a target or a point');
182
+ if ('point' in endpoint) {
183
+ validatePoint(endpoint.point);
184
+ return;
185
+ }
186
+ const target = endpoint.target;
187
+ if (!Guards.isTransformable(target) ||
188
+ target.isDestroyed ||
189
+ target === this.drawing ||
190
+ target.context !== this.drawing.context ||
191
+ !this.drawing.el.contains(target.el) ||
192
+ target.descendants().some(isConnector))
193
+ throw new TypeError('Endpoint target must be a drawable shape without connectors in this drawing');
194
+ for (let node = target; node && node !== this.drawing; node = node.parent)
195
+ if (!drawableTags.has(node.el.localName))
196
+ throw new TypeError('Connector targets cannot be inside definitions');
197
+ if (!('port' in endpoint))
198
+ return validateAnchor(endpoint.anchor ?? 'auto');
199
+ if ('anchor' in endpoint)
200
+ throw new TypeError('Endpoint needs either a port or an anchor');
201
+ if (typeof endpoint.port !== 'string' || !findPort(target, endpoint.port))
202
+ throw new TypeError(`Unknown connector port: ${String(endpoint.port)}`);
203
+ }
204
+ /** An end whose target left the drawing, or whose port is gone, stays where it is. */
205
+ loosen(state) {
206
+ const loose = (end) => {
207
+ const endpoint = state[end];
208
+ if ('point' in endpoint)
209
+ return endpoint;
210
+ const { target } = endpoint;
211
+ const gone = target.isDestroyed ||
212
+ !this.drawing.el.contains(target.el) ||
213
+ ('port' in endpoint && !findPort(target, endpoint.port));
214
+ const point = gone && pathEnd(state.path, end);
215
+ return point ? { point } : endpoint;
216
+ };
217
+ const start = loose('start'), end = loose('end');
218
+ return start === state.start && end === state.end ? state : { ...state, start, end };
219
+ }
220
+ /** Connectors in this drawing with an end on `target`, from core's reference index. */
221
+ attached(target) {
222
+ return this.drawing.context.defs
223
+ .consumersOf(target)
224
+ .filter((node) => isConnector(node) &&
225
+ this.drawing.el.contains(node.el) &&
226
+ ['start', 'end'].some((end) => node.references.get(endpointAttribute(end)) === target));
227
+ }
228
+ /**
229
+ * Connectors to route after a change: those inside a changed subtree, and those attached
230
+ * to a changed node, its descendants or its ancestors, since parents move, resize or
231
+ * reparent targets and a descendant changes a group's bounds. The work follows the
232
+ * size of the change, not the number of connectors.
233
+ */
234
+ affected(changed) {
235
+ const paths = new Set(), seen = new Set();
236
+ const visit = (node) => {
237
+ if (node.isDestroyed || seen.has(node))
238
+ return;
239
+ seen.add(node);
240
+ if (isConnector(node) && this.drawing.el.contains(node.el))
241
+ paths.add(node);
242
+ for (const path of this.attached(node))
243
+ paths.add(path);
244
+ };
245
+ for (const node of changed) {
246
+ node.descendants().forEach(visit);
247
+ for (let parent = node.parent; parent; parent = parent.parent)
248
+ visit(parent);
249
+ }
250
+ return paths;
251
+ }
252
+ route(state) {
253
+ const { path, start, end } = state;
254
+ for (const endpoint of [start, end])
255
+ if ('target' in endpoint) {
256
+ if (endpoint.target.isDestroyed || !this.drawing.el.contains(endpoint.target.el))
257
+ return false;
258
+ if (endpoint.target.el.contains(path.el))
259
+ throw new TypeError('A connector cannot be inside its endpoint target');
260
+ }
261
+ const a = endpointCenter(start), b = endpointCenter(end);
262
+ const from = a && b ? connectorPort(start, b) : null;
263
+ const to = a && b ? connectorPort(end, a) : null;
264
+ const inverse = path.worldMatrix().inverse();
265
+ if (!from || !to || !inverse)
266
+ return false;
267
+ const d = pathData(routeConnector({ start: from, end: to, routing: state.routing }).map((point) => inverse.apply(point)));
268
+ if (path.getAttributeValue('d') !== d)
269
+ path.attrs({ d });
270
+ return true;
271
+ }
272
+ edit(label, run) {
273
+ const group = beginChangeGroup(this.drawing, { source: 'connectors', label });
274
+ let result;
275
+ try {
276
+ result = group.run(run);
277
+ }
278
+ catch (error) {
279
+ try {
280
+ group.cancel();
281
+ }
282
+ catch (cleanup) {
283
+ throw new AggregateError([error, cleanup], 'Connector edit and rollback failed');
284
+ }
285
+ throw error;
286
+ }
287
+ group.end();
288
+ return result;
289
+ }
290
+ }
291
+ //# sourceMappingURL=connectors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connectors.js","sourceRoot":"","sources":["../src/connectors.ts"],"names":[],"mappings":"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"}