@unpunnyfuns/conduit 0.1.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.
- package/LICENSE +25 -0
- package/README.md +202 -0
- package/dist/assert.d.ts +6 -0
- package/dist/assert.d.ts.map +1 -0
- package/dist/assert.js +8 -0
- package/dist/assert.js.map +1 -0
- package/dist/cn.d.ts +3 -0
- package/dist/cn.d.ts.map +1 -0
- package/dist/cn.js +3 -0
- package/dist/cn.js.map +1 -0
- package/dist/components/Badge.d.ts +6 -0
- package/dist/components/Badge.d.ts.map +1 -0
- package/dist/components/Badge.js +11 -0
- package/dist/components/Badge.js.map +1 -0
- package/dist/components/Card.d.ts +20 -0
- package/dist/components/Card.d.ts.map +1 -0
- package/dist/components/Card.js +24 -0
- package/dist/components/Card.js.map +1 -0
- package/dist/components/Diagram.d.ts +37 -0
- package/dist/components/Diagram.d.ts.map +1 -0
- package/dist/components/Diagram.js +92 -0
- package/dist/components/Diagram.js.map +1 -0
- package/dist/components/EdgeLayer.d.ts +23 -0
- package/dist/components/EdgeLayer.d.ts.map +1 -0
- package/dist/components/EdgeLayer.js +85 -0
- package/dist/components/EdgeLayer.js.map +1 -0
- package/dist/components/Lane.d.ts +11 -0
- package/dist/components/Lane.d.ts.map +1 -0
- package/dist/components/Lane.js +6 -0
- package/dist/components/Lane.js.map +1 -0
- package/dist/components/icons.d.ts +7 -0
- package/dist/components/icons.d.ts.map +1 -0
- package/dist/components/icons.js +47 -0
- package/dist/components/icons.js.map +1 -0
- package/dist/components/pulse.d.ts +15 -0
- package/dist/components/pulse.d.ts.map +1 -0
- package/dist/components/pulse.js +10 -0
- package/dist/components/pulse.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/layout/architecture.d.ts +60 -0
- package/dist/layout/architecture.d.ts.map +1 -0
- package/dist/layout/architecture.js +88 -0
- package/dist/layout/architecture.js.map +1 -0
- package/dist/layout/bounds.d.ts +25 -0
- package/dist/layout/bounds.d.ts.map +1 -0
- package/dist/layout/bounds.js +32 -0
- package/dist/layout/bounds.js.map +1 -0
- package/dist/layout/congestion.d.ts +18 -0
- package/dist/layout/congestion.d.ts.map +1 -0
- package/dist/layout/congestion.js +49 -0
- package/dist/layout/congestion.js.map +1 -0
- package/dist/layout/design.d.ts +98 -0
- package/dist/layout/design.d.ts.map +1 -0
- package/dist/layout/design.js +92 -0
- package/dist/layout/design.js.map +1 -0
- package/dist/layout/edges.d.ts +53 -0
- package/dist/layout/edges.d.ts.map +1 -0
- package/dist/layout/edges.js +848 -0
- package/dist/layout/edges.js.map +1 -0
- package/dist/layout/errors.d.ts +6 -0
- package/dist/layout/errors.d.ts.map +1 -0
- package/dist/layout/errors.js +9 -0
- package/dist/layout/errors.js.map +1 -0
- package/dist/layout/frame.d.ts +35 -0
- package/dist/layout/frame.d.ts.map +1 -0
- package/dist/layout/frame.js +63 -0
- package/dist/layout/frame.js.map +1 -0
- package/dist/layout/geometry.d.ts +23 -0
- package/dist/layout/geometry.d.ts.map +1 -0
- package/dist/layout/geometry.js +22 -0
- package/dist/layout/geometry.js.map +1 -0
- package/dist/layout/labels.d.ts +12 -0
- package/dist/layout/labels.d.ts.map +1 -0
- package/dist/layout/labels.js +153 -0
- package/dist/layout/labels.js.map +1 -0
- package/dist/layout/lanes.d.ts +5 -0
- package/dist/layout/lanes.d.ts.map +1 -0
- package/dist/layout/lanes.js +13 -0
- package/dist/layout/lanes.js.map +1 -0
- package/dist/layout/layout.d.ts +42 -0
- package/dist/layout/layout.d.ts.map +1 -0
- package/dist/layout/layout.js +94 -0
- package/dist/layout/layout.js.map +1 -0
- package/dist/layout/rank.d.ts +14 -0
- package/dist/layout/rank.d.ts.map +1 -0
- package/dist/layout/rank.js +78 -0
- package/dist/layout/rank.js.map +1 -0
- package/dist/layout/scope.d.ts +20 -0
- package/dist/layout/scope.d.ts.map +1 -0
- package/dist/layout/scope.js +52 -0
- package/dist/layout/scope.js.map +1 -0
- package/dist/layout/seating.d.ts +27 -0
- package/dist/layout/seating.d.ts.map +1 -0
- package/dist/layout/seating.js +135 -0
- package/dist/layout/seating.js.map +1 -0
- package/dist/layout/text.d.ts +12 -0
- package/dist/layout/text.d.ts.map +1 -0
- package/dist/layout/text.js +148 -0
- package/dist/layout/text.js.map +1 -0
- package/dist/layout/trace.d.ts +8 -0
- package/dist/layout/trace.d.ts.map +1 -0
- package/dist/layout/trace.js +51 -0
- package/dist/layout/trace.js.map +1 -0
- package/dist/layout.d.ts +9 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +6 -0
- package/dist/layout.js.map +1 -0
- package/dist/schema/document.d.ts +239 -0
- package/dist/schema/document.d.ts.map +1 -0
- package/dist/schema/document.js +83 -0
- package/dist/schema/document.js.map +1 -0
- package/dist/schema/errors.d.ts +20 -0
- package/dist/schema/errors.d.ts.map +1 -0
- package/dist/schema/errors.js +12 -0
- package/dist/schema/errors.js.map +1 -0
- package/dist/schema/integrity.d.ts +8 -0
- package/dist/schema/integrity.d.ts.map +1 -0
- package/dist/schema/integrity.js +63 -0
- package/dist/schema/integrity.js.map +1 -0
- package/dist/schema/parse.d.ts +6 -0
- package/dist/schema/parse.d.ts.map +1 -0
- package/dist/schema/parse.js +53 -0
- package/dist/schema/parse.js.map +1 -0
- package/dist/schema/primitives.d.ts +58 -0
- package/dist/schema/primitives.d.ts.map +1 -0
- package/dist/schema/primitives.js +44 -0
- package/dist/schema/primitives.js.map +1 -0
- package/dist/theme.css +63 -0
- package/package.json +83 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Coldtea AI
|
|
4
|
+
Copyright (c) 2026 unpunnyfuns
|
|
5
|
+
|
|
6
|
+
Portions of this software are derived from pr-lens
|
|
7
|
+
(https://github.com/coldteadotai/pr-lens), licensed under the MIT License.
|
|
8
|
+
|
|
9
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
10
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
11
|
+
in the Software without restriction, including without limitation the rights
|
|
12
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
13
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
14
|
+
furnished to do so, subject to the following conditions:
|
|
15
|
+
|
|
16
|
+
The above copyright notice and this permission notice shall be included in all
|
|
17
|
+
copies or substantial portions of the Software.
|
|
18
|
+
|
|
19
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
20
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
21
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
22
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
23
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
24
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
25
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# @unpunnyfuns/conduit
|
|
2
|
+
|
|
3
|
+
Lane-based architecture diagrams for React, with live content in every card.
|
|
4
|
+
|
|
5
|
+
A port of [pr-lens](https://github.com/coldteadotai/pr-lens)'s layout engine
|
|
6
|
+
with a React + Tailwind v4 renderer. Hand-author a document — lanes, nodes,
|
|
7
|
+
edges — and get a deterministic diagram whose cards can host any React
|
|
8
|
+
content, such as a chart.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @unpunnyfuns/conduit
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Peers: `react ^19`, `react-dom ^19`, `tailwindcss ^4`.
|
|
17
|
+
|
|
18
|
+
In your Tailwind CSS entry:
|
|
19
|
+
|
|
20
|
+
```css
|
|
21
|
+
@import "tailwindcss";
|
|
22
|
+
@import "@unpunnyfuns/conduit/theme.css";
|
|
23
|
+
@source "../node_modules/@unpunnyfuns/conduit";
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The `@source` line is required: the components use Tailwind utilities and
|
|
27
|
+
Tailwind only emits the classes it can see.
|
|
28
|
+
|
|
29
|
+
## Structure
|
|
30
|
+
|
|
31
|
+
| Path | Contents |
|
|
32
|
+
| -------------------------------- | --------------------------------------------------------------------------------------- |
|
|
33
|
+
| `@unpunnyfuns/conduit` | `Diagram`, `Card`, `LaneBand`, `EdgeLayer`, `Badge`, `KindIcon`, `parseDocument`, types |
|
|
34
|
+
| `@unpunnyfuns/conduit/layout` | `layout()` — the pure engine, no React |
|
|
35
|
+
| `@unpunnyfuns/conduit/theme.css` | `--color-conduit-*` tokens with light and `.dark` values |
|
|
36
|
+
|
|
37
|
+
## Usage
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import { Diagram, parseDocument } from "@unpunnyfuns/conduit";
|
|
41
|
+
|
|
42
|
+
const doc = parseDocument({
|
|
43
|
+
version: 1,
|
|
44
|
+
title: "Data ingress",
|
|
45
|
+
lanes: [
|
|
46
|
+
{ id: "sources", label: "External sources", order: 0 },
|
|
47
|
+
{ id: "ingest", label: "Ingestion", order: 1 },
|
|
48
|
+
],
|
|
49
|
+
nodes: [
|
|
50
|
+
{ id: "partner-api", label: "Partner API", kind: "external", lane: "sources", row: 0 },
|
|
51
|
+
{ id: "kafka", label: "Kafka ingest", kind: "queue", lane: "ingest", row: 0, size: "chart" },
|
|
52
|
+
],
|
|
53
|
+
edges: [{ id: "api-to-kafka", from: "partner-api", to: "kafka", kind: "http", animated: true }],
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export const Ingress = () => (
|
|
57
|
+
<Diagram doc={doc} onNodeClick={(id) => console.log(id)}>
|
|
58
|
+
{(node) => (node.size === "chart" ? <Throughput source={node.id} /> : null)}
|
|
59
|
+
</Diagram>
|
|
60
|
+
);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Document
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
type ConduitDocumentInput = {
|
|
67
|
+
version: 1;
|
|
68
|
+
title: string;
|
|
69
|
+
summary?: string;
|
|
70
|
+
direction?: "right" | "down";
|
|
71
|
+
lanes: { id; label; subtitle?; order?; status?; summary? }[];
|
|
72
|
+
nodes: {
|
|
73
|
+
id;
|
|
74
|
+
label;
|
|
75
|
+
kind: NodeKind;
|
|
76
|
+
lane;
|
|
77
|
+
row?: number;
|
|
78
|
+
size?: "compact" | "chart" | number;
|
|
79
|
+
status?: Status;
|
|
80
|
+
badges?: { label; tone? }[];
|
|
81
|
+
group?;
|
|
82
|
+
subtitle?;
|
|
83
|
+
summary?;
|
|
84
|
+
}[];
|
|
85
|
+
edges?: {
|
|
86
|
+
id;
|
|
87
|
+
from;
|
|
88
|
+
to;
|
|
89
|
+
kind: EdgeKind;
|
|
90
|
+
label?;
|
|
91
|
+
emphasis?: "normal" | "hero" | "muted";
|
|
92
|
+
animated?;
|
|
93
|
+
status?;
|
|
94
|
+
summary?;
|
|
95
|
+
}[];
|
|
96
|
+
views?: {
|
|
97
|
+
id;
|
|
98
|
+
title;
|
|
99
|
+
summary?;
|
|
100
|
+
scope?: { kind: "all" } | { kind: "selection"; lanes?; nodes?; edges? };
|
|
101
|
+
children?;
|
|
102
|
+
}[];
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
type Status = "neutral" | "positive" | "caution" | "critical";
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Two nodes with the same `row` in one lane sit side by side; a third throws
|
|
109
|
+
`ROW_OVERFULL`. Status affects colour only. Omit `row` to derive it from
|
|
110
|
+
edges. `size: "chart"` reserves a body slot; a number is a height in
|
|
111
|
+
pixels.
|
|
112
|
+
|
|
113
|
+
`direction: "down"` draws lanes as horizontal bands with cards flowing left
|
|
114
|
+
to right; `row` then means column. Default `"right"`.
|
|
115
|
+
|
|
116
|
+
### `Diagram` props
|
|
117
|
+
|
|
118
|
+
| Prop | Type | Notes |
|
|
119
|
+
| ---------------------------- | ------------------------------------------------------ | --------------------------------------------------------------------------------- |
|
|
120
|
+
| `doc` | `ConduitDocument` | from `parseDocument` |
|
|
121
|
+
| `view` | `string` | id of a view to draw |
|
|
122
|
+
| `selected` | `string[]` | ids to keep lit; everything else dims |
|
|
123
|
+
| `highlight` | `"neighbours" \| "upstream" \| "downstream" \| "both"` | what a selection lights; traced edges draw at hero weight; default `"neighbours"` |
|
|
124
|
+
| `onNodeClick`, `onEdgeClick` | `(id) => void` | cards become buttons when set |
|
|
125
|
+
| `cardHeights` | `{ compact?; withSubtitle?; chart? }` | defaults 52 / 62 / 140 |
|
|
126
|
+
| `className` | `string` | applied to the scroll viewport |
|
|
127
|
+
| `fit` | `boolean` | scale the canvas down to fit; default `false` |
|
|
128
|
+
| `children` | `(node) => ReactNode` | body slot of every card that has one |
|
|
129
|
+
| `edgeState` | `Record<string, EdgeState>` | live overlay by edge id; never relayouts |
|
|
130
|
+
|
|
131
|
+
The root is a scroll viewport; size it with `className`. With `fit` the
|
|
132
|
+
canvas scales down to the viewport width (never up).
|
|
133
|
+
|
|
134
|
+
`layout()` runs during render and throws `ConduitLayoutError`
|
|
135
|
+
(`UNKNOWN_VIEW`, `ROW_OVERFULL`, `NOTHING_TO_RENDER`) for a document it
|
|
136
|
+
cannot draw; wrap `Diagram` in an error boundary if documents are
|
|
137
|
+
user-supplied.
|
|
138
|
+
|
|
139
|
+
### Live state
|
|
140
|
+
|
|
141
|
+
`edgeState` flips a hop between live, idle, done, stale and down without
|
|
142
|
+
touching the document or triggering a relayout. Per edge, with
|
|
143
|
+
`state = edgeState[edge.id]`:
|
|
144
|
+
|
|
145
|
+
| `state.level` | pulses | tone | stroke |
|
|
146
|
+
| ------------- | ------------------------------------------------------------- | ---------- | -------------------------------- |
|
|
147
|
+
| absent | document `animated` | document | as today |
|
|
148
|
+
| `live` | pulses on; period from `rate` when given, else the edge's own | document | as today |
|
|
149
|
+
| `idle` | off | document | as today |
|
|
150
|
+
| `done` | off | `positive` | as today |
|
|
151
|
+
| `stale` | off | `caution` | as today |
|
|
152
|
+
| `down` | off | `critical` | dashed (`stroke-dasharray: 5 4`) |
|
|
153
|
+
|
|
154
|
+
State tone replaces the document's `status` tone while set — a `critical`
|
|
155
|
+
edge marked `stale` shows caution until the state clears.
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
import { Diagram, type EdgeState } from "@unpunnyfuns/conduit";
|
|
159
|
+
|
|
160
|
+
const edgeState: Record<string, EdgeState> = { "kafka-to-validator": { level: "down" } };
|
|
161
|
+
<Diagram doc={doc} edgeState={edgeState} />;
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Layout without React
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
import { layout } from "@unpunnyfuns/conduit/layout";
|
|
168
|
+
|
|
169
|
+
const { width, height, nodes, edges, atlas } = layout(doc, { view: "storage" });
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Same document, same geometry, every time.
|
|
173
|
+
|
|
174
|
+
To trace from a selection:
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
import { traceFrom } from "@unpunnyfuns/conduit/layout";
|
|
178
|
+
|
|
179
|
+
const traced = traceFrom(doc.edges, ["warehouse"], "upstream");
|
|
180
|
+
const litNodeIds = [...traced.nodes];
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
`traceFrom` walks whatever edge list you give it — pass `doc.edges` for the whole
|
|
184
|
+
document, or the `edges` from a `layout()` call to match a view's scope, which is
|
|
185
|
+
what `Diagram` does.
|
|
186
|
+
|
|
187
|
+
## Development
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
npm test
|
|
191
|
+
npm run example
|
|
192
|
+
npm run build
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
`npm test` runs the engine tests in Node and the component tests in
|
|
196
|
+
Chromium; `npm run example` starts the Vite playground.
|
|
197
|
+
|
|
198
|
+
Developing requires Node ≥ 22.12 (Vitest 5); the published package runs on Node ≥ 20.11.
|
|
199
|
+
|
|
200
|
+
## License
|
|
201
|
+
|
|
202
|
+
MIT. Layout engine derived from pr-lens, © Coldtea AI.
|
package/dist/assert.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ends a switch over a closed set. Adding a variant then fails to compile at
|
|
3
|
+
* every consumer instead of silently falling through at runtime.
|
|
4
|
+
*/
|
|
5
|
+
export declare const assertNever: (value: never, message?: string) => never;
|
|
6
|
+
//# sourceMappingURL=assert.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assert.d.ts","sourceRoot":"","sources":["../src/assert.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,WAAW,UAAW,KAAK,uBAAkC,KAEzE,CAAC"}
|
package/dist/assert.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ends a switch over a closed set. Adding a variant then fails to compile at
|
|
3
|
+
* every consumer instead of silently falling through at runtime.
|
|
4
|
+
*/
|
|
5
|
+
export const assertNever = (value, message = "Unhandled variant") => {
|
|
6
|
+
throw new Error(`${message}: ${JSON.stringify(value)}`);
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=assert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assert.js","sourceRoot":"","sources":["../src/assert.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAY,EAAE,OAAO,GAAG,mBAAmB,EAAS,EAAE;IAChF,MAAM,IAAI,KAAK,CAAC,GAAG,OAAO,KAAK,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAC1D,CAAC,CAAC"}
|
package/dist/cn.d.ts
ADDED
package/dist/cn.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cn.d.ts","sourceRoot":"","sources":["../src/cn.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,eAAO,MAAM,EAAE,aAAc,SAAS,CAAC,MAAM,GAAG,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,KAAG,MACiB,CAAC"}
|
package/dist/cn.js
ADDED
package/dist/cn.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cn.js","sourceRoot":"","sources":["../src/cn.ts"],"names":[],"mappings":"AAAA,+CAA+C;AAC/C,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,KAAqD,EAAU,EAAE,CACrF,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Badge.d.ts","sourceRoot":"","sources":["../../src/components/Badge.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAWtD,eAAO,MAAM,KAAK,oBAAqB;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,gCAUrE,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../cn.js";
|
|
3
|
+
import { BADGE_HEIGHT } from "../layout/design.js";
|
|
4
|
+
const TONE = {
|
|
5
|
+
neutral: "bg-conduit-chip border-conduit-card-border text-conduit-muted",
|
|
6
|
+
positive: "bg-conduit-positive-fill border-conduit-positive-border text-conduit-positive-text",
|
|
7
|
+
caution: "bg-conduit-caution-fill border-conduit-caution-border text-conduit-caution-text",
|
|
8
|
+
critical: "bg-conduit-critical-fill border-conduit-critical-border text-conduit-critical-text",
|
|
9
|
+
};
|
|
10
|
+
export const Badge = ({ label, tone }) => (_jsx("span", { className: cn("inline-flex items-center rounded-full border px-[9px] text-[8.5px] font-bold uppercase leading-none tracking-[0.06em] whitespace-nowrap", TONE[tone]), style: { height: BADGE_HEIGHT }, children: label }));
|
|
11
|
+
//# sourceMappingURL=Badge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Badge.js","sourceRoot":"","sources":["../../src/components/Badge.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,MAAM,IAAI,GAA2B;IACnC,OAAO,EAAE,+DAA+D;IACxE,QAAQ,EAAE,oFAAoF;IAC9F,OAAO,EAAE,iFAAiF;IAC1F,QAAQ,EAAE,oFAAoF;CAC/F,CAAC;AAEF,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,EAAE,KAAK,EAAE,IAAI,EAAmC,EAAE,EAAE,CAAC,CACzE,eACE,SAAS,EAAE,EAAE,CACX,yIAAyI,EACzI,IAAI,CAAC,IAAI,CAAC,CACX,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,YAE9B,KAAK,GACD,CACR,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import type { ConduitNode } from "../schema/document.js";
|
|
3
|
+
import type { Box } from "../layout/geometry.js";
|
|
4
|
+
export type CardProps = {
|
|
5
|
+
id?: string;
|
|
6
|
+
node: ConduitNode;
|
|
7
|
+
box: Box;
|
|
8
|
+
/** Height of the title block the layout reserved; the body slot gets the rest. */
|
|
9
|
+
headerHeight: number;
|
|
10
|
+
dimmed?: boolean;
|
|
11
|
+
selected?: boolean;
|
|
12
|
+
onClick?: () => void;
|
|
13
|
+
children?: ReactNode;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* One card. Absolutely positioned from its layout box so that a chart
|
|
17
|
+
* mounting in the body changes nothing around it.
|
|
18
|
+
*/
|
|
19
|
+
export declare const Card: ({ id, node, box, headerHeight, dimmed, selected, onClick, children, }: CardProps) => import("react").JSX.Element;
|
|
20
|
+
//# sourceMappingURL=Card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Card.d.ts","sourceRoot":"","sources":["../../src/components/Card.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGzD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AAcjD,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,WAAW,CAAC;IAClB,GAAG,EAAE,GAAG,CAAC;IACT,kFAAkF;IAClF,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,IAAI,0EASd,SAAS,gCAuDX,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../cn.js";
|
|
3
|
+
import { Badge } from "./Badge.js";
|
|
4
|
+
import { KindIcon } from "./icons.js";
|
|
5
|
+
const BORDER = {
|
|
6
|
+
neutral: "border-conduit-card-border",
|
|
7
|
+
positive: "border-conduit-positive-border",
|
|
8
|
+
caution: "border-conduit-caution-border",
|
|
9
|
+
critical: "border-conduit-critical-border",
|
|
10
|
+
};
|
|
11
|
+
/** Below this width a card's title steps down a size, as upstream did. */
|
|
12
|
+
const SMALL_TITLE_BELOW = 200;
|
|
13
|
+
/**
|
|
14
|
+
* One card. Absolutely positioned from its layout box so that a chart
|
|
15
|
+
* mounting in the body changes nothing around it.
|
|
16
|
+
*/
|
|
17
|
+
export const Card = ({ id, node, box, headerHeight, dimmed = false, selected = false, onClick, children, }) => {
|
|
18
|
+
const hasBody = box.height > headerHeight;
|
|
19
|
+
const label = node.subtitle === undefined ? node.label : `${node.label}, ${node.subtitle}`;
|
|
20
|
+
const className = cn("absolute flex flex-col rounded-[10px] border bg-conduit-card text-left shadow-[0_1px_2px_var(--color-conduit-shadow)] transition-opacity", BORDER[node.status], dimmed && "opacity-45", selected && "ring-2 ring-conduit-fg/40");
|
|
21
|
+
const style = { left: box.x, top: box.y, width: box.width, height: box.height };
|
|
22
|
+
return (_jsxs("div", { role: "group", "aria-label": label, "data-conduit-node": id, className: className, style: style, children: [onClick !== undefined && (_jsx("button", { type: "button", "aria-label": label, onClick: onClick, className: "absolute inset-x-0 top-0 cursor-pointer rounded-[10px] bg-transparent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-conduit-fg/40", style: { height: headerHeight } })), node.badges.length > 0 && (_jsx("div", { className: "absolute -top-2 right-[7px] flex gap-1.5", children: node.badges.map((badge) => (_jsx(Badge, { label: badge.label, tone: badge.tone }, badge.label))) })), _jsxs("div", { className: "flex shrink-0 items-center gap-[10px] px-[14px]", style: { height: headerHeight }, children: [_jsx("span", { className: "flex size-[26px] shrink-0 items-center justify-center rounded-[7px] bg-conduit-chip", children: _jsx(KindIcon, { kind: node.kind }) }), _jsxs("span", { className: "flex min-w-0 flex-col", children: [_jsx("span", { className: cn("truncate font-semibold text-conduit-fg", box.width >= SMALL_TITLE_BELOW ? "text-[13px]" : "text-[11.5px]"), children: node.label }), node.subtitle !== undefined && (_jsx("span", { className: "truncate font-mono text-[9.5px] text-conduit-muted", children: node.subtitle }))] })] }), hasBody && _jsx("div", { className: "min-h-0 flex-1 px-[14px] pb-[12px]", children: children })] }));
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=Card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Card.js","sourceRoot":"","sources":["../../src/components/Card.tsx"],"names":[],"mappings":";AAGA,OAAO,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AAE9B,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,MAAM,MAAM,GAA2B;IACrC,OAAO,EAAE,4BAA4B;IACrC,QAAQ,EAAE,gCAAgC;IAC1C,OAAO,EAAE,+BAA+B;IACxC,QAAQ,EAAE,gCAAgC;CAC3C,CAAC;AAEF,0EAA0E;AAC1E,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAc9B;;;GAGG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,EACnB,EAAE,EACF,IAAI,EACJ,GAAG,EACH,YAAY,EACZ,MAAM,GAAG,KAAK,EACd,QAAQ,GAAG,KAAK,EAChB,OAAO,EACP,QAAQ,GACE,EAAE,EAAE;IACd,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,GAAG,YAAY,CAAC;IAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,QAAQ,EAAE,CAAC;IAC3F,MAAM,SAAS,GAAG,EAAE,CAClB,0IAA0I,EAC1I,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EACnB,MAAM,IAAI,YAAY,EACtB,QAAQ,IAAI,2BAA2B,CACxC,CAAC;IACF,MAAM,KAAK,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC;IAEhF,OAAO,CACL,eAAK,IAAI,EAAC,OAAO,gBAAa,KAAK,uBAAqB,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,aAC3F,OAAO,KAAK,SAAS,IAAI,CACxB,iBACE,IAAI,EAAC,QAAQ,gBACD,KAAK,EACjB,OAAO,EAAE,OAAO,EAChB,SAAS,EAAC,wJAAwJ,EAClK,KAAK,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,GAC/B,CACH,EACA,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,CACzB,cAAK,SAAS,EAAC,0CAA0C,YACtD,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAC1B,KAAC,KAAK,IAAmB,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,IAAjD,KAAK,CAAC,KAAK,CAA0C,CAClE,CAAC,GACE,CACP,EACD,eACE,SAAS,EAAC,iDAAiD,EAC3D,KAAK,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,aAE/B,eAAM,SAAS,EAAC,qFAAqF,YACnG,KAAC,QAAQ,IAAC,IAAI,EAAE,IAAI,CAAC,IAAI,GAAI,GACxB,EACP,gBAAM,SAAS,EAAC,uBAAuB,aACrC,eACE,SAAS,EAAE,EAAE,CACX,wCAAwC,EACxC,GAAG,CAAC,KAAK,IAAI,iBAAiB,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,eAAe,CACjE,YAEA,IAAI,CAAC,KAAK,GACN,EACN,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,CAC9B,eAAM,SAAS,EAAC,oDAAoD,YACjE,IAAI,CAAC,QAAQ,GACT,CACR,IACI,IACH,EACL,OAAO,IAAI,cAAK,SAAS,EAAC,oCAAoC,YAAE,QAAQ,GAAO,IAC5E,CACP,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { ConduitDocument, ConduitNode } from "../schema/document.js";
|
|
3
|
+
import { type CardHeights } from "../layout/design.js";
|
|
4
|
+
import { type Highlight } from "../layout/trace.js";
|
|
5
|
+
import type { EdgeState } from "./pulse.js";
|
|
6
|
+
export type DiagramProps = {
|
|
7
|
+
doc: ConduitDocument;
|
|
8
|
+
/** Id of a view to draw. Omitted draws the whole document. */
|
|
9
|
+
view?: string;
|
|
10
|
+
/** Ids of lanes, nodes or edges to keep lit; everything else dims. */
|
|
11
|
+
selected?: readonly string[];
|
|
12
|
+
/** What a selection lights: neighbours (default), everything upstream, downstream, or both. */
|
|
13
|
+
highlight?: Highlight;
|
|
14
|
+
onNodeClick?: (id: string) => void;
|
|
15
|
+
onEdgeClick?: (id: string) => void;
|
|
16
|
+
cardHeights?: Partial<CardHeights>;
|
|
17
|
+
/** Applied to the scroll viewport; size it with `h-[…]` / `max-h-[…]` etc. */
|
|
18
|
+
className?: string;
|
|
19
|
+
/** Scales the canvas down to the viewport's width. Never scales up. */
|
|
20
|
+
fit?: boolean;
|
|
21
|
+
/** Fills the body slot of every card that has one. */
|
|
22
|
+
children?: (node: ConduitNode) => ReactNode;
|
|
23
|
+
/** Live overlay by edge id; changes never relayout. */
|
|
24
|
+
edgeState?: Readonly<Record<string, EdgeState>>;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* The diagram: lanes underneath, one svg of edges, cards on top. Layout is
|
|
28
|
+
* pure and memoised on its inputs, so a chart re-rendering inside a card
|
|
29
|
+
* never triggers a relayout.
|
|
30
|
+
*
|
|
31
|
+
* The root (`role="figure"`) is a scroll viewport; the fixed-size drawing
|
|
32
|
+
* itself is `[data-conduit-canvas]` inside it, scaled down to the viewport's
|
|
33
|
+
* width when `fit` is set. Atlas coordinates from `layout()` are relative to
|
|
34
|
+
* the canvas, not the viewport.
|
|
35
|
+
*/
|
|
36
|
+
export declare const Diagram: ({ doc, view, selected, highlight, onNodeClick, onEdgeClick, cardHeights, className, fit, children, edgeState, }: DiagramProps) => import("react").JSX.Element;
|
|
37
|
+
//# sourceMappingURL=Diagram.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Diagram.d.ts","sourceRoot":"","sources":["../../src/components/Diagram.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAwC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAC7E,OAAO,KAAK,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAE1E,OAAO,EAAwB,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAE7E,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAI/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,eAAe,CAAC;IACrB,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,+FAA+F;IAC/F,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,WAAW,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IACnC,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,sDAAsD;IACtD,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,SAAS,CAAC;IAC5C,uDAAuD;IACvD,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;CACjD,CAAC;AAKF;;;;;;;;;GASG;AACH,eAAO,MAAM,OAAO,oHAYjB,YAAY,gCA0Jd,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
import { cn } from "../cn.js";
|
|
4
|
+
import { DEFAULT_CARD_HEIGHTS } from "../layout/design.js";
|
|
5
|
+
import { layout } from "../layout/layout.js";
|
|
6
|
+
import { traceFrom } from "../layout/trace.js";
|
|
7
|
+
import { Card } from "./Card.js";
|
|
8
|
+
import { EdgeLayer } from "./EdgeLayer.js";
|
|
9
|
+
import { LaneBand } from "./Lane.js";
|
|
10
|
+
const headerHeightOf = (node, heights) => node.subtitle === undefined ? heights.compact : heights.withSubtitle;
|
|
11
|
+
/**
|
|
12
|
+
* The diagram: lanes underneath, one svg of edges, cards on top. Layout is
|
|
13
|
+
* pure and memoised on its inputs, so a chart re-rendering inside a card
|
|
14
|
+
* never triggers a relayout.
|
|
15
|
+
*
|
|
16
|
+
* The root (`role="figure"`) is a scroll viewport; the fixed-size drawing
|
|
17
|
+
* itself is `[data-conduit-canvas]` inside it, scaled down to the viewport's
|
|
18
|
+
* width when `fit` is set. Atlas coordinates from `layout()` are relative to
|
|
19
|
+
* the canvas, not the viewport.
|
|
20
|
+
*/
|
|
21
|
+
export const Diagram = ({ doc, view, selected, highlight = "neighbours", onNodeClick, onEdgeClick, cardHeights, className, fit = false, children, edgeState, }) => {
|
|
22
|
+
// Deps are the scalars, not `cardHeights` itself: a caller passing a fresh
|
|
23
|
+
// object literal every render must not defeat the memo below it.
|
|
24
|
+
const compactHeight = cardHeights?.compact;
|
|
25
|
+
const withSubtitleHeight = cardHeights?.withSubtitle;
|
|
26
|
+
const chartHeight = cardHeights?.chart;
|
|
27
|
+
const heights = useMemo(() => ({
|
|
28
|
+
compact: compactHeight ?? DEFAULT_CARD_HEIGHTS.compact,
|
|
29
|
+
withSubtitle: withSubtitleHeight ?? DEFAULT_CARD_HEIGHTS.withSubtitle,
|
|
30
|
+
chart: chartHeight ?? DEFAULT_CARD_HEIGHTS.chart,
|
|
31
|
+
}), [compactHeight, withSubtitleHeight, chartHeight]);
|
|
32
|
+
const { laid, nodeLabel } = useMemo(() => {
|
|
33
|
+
const drawn = layout(doc, { view, cardHeights: heights });
|
|
34
|
+
const labels = new Map(drawn.nodes.map(({ node }) => [node.id, node.label]));
|
|
35
|
+
return { laid: drawn, nodeLabel: labels };
|
|
36
|
+
}, [doc, view, heights]);
|
|
37
|
+
const viewportRef = useRef(null);
|
|
38
|
+
const [viewportWidth, setViewportWidth] = useState(0);
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
if (!fit)
|
|
41
|
+
return;
|
|
42
|
+
const node = viewportRef.current;
|
|
43
|
+
if (node === null || typeof ResizeObserver === "undefined")
|
|
44
|
+
return;
|
|
45
|
+
const update = () => setViewportWidth(node.clientWidth);
|
|
46
|
+
update();
|
|
47
|
+
const observer = new ResizeObserver(update);
|
|
48
|
+
observer.observe(node);
|
|
49
|
+
return () => observer.disconnect();
|
|
50
|
+
}, [fit]);
|
|
51
|
+
const scale = fit && viewportWidth > 0 ? Math.min(1, viewportWidth / laid.width) : 1;
|
|
52
|
+
const lit = useMemo(() => {
|
|
53
|
+
if (selected === undefined || selected.length === 0)
|
|
54
|
+
return undefined;
|
|
55
|
+
const trace = traceFrom(laid.edges.map(({ edge }) => edge), selected, highlight);
|
|
56
|
+
const ids = new Set(selected);
|
|
57
|
+
const nodes = new Set(laid.nodes.filter(({ node }) => trace.nodes.has(node.id)).map(({ node }) => node.id));
|
|
58
|
+
const edges = new Set(laid.edges.filter(({ edge }) => trace.edges.has(edge.id)).map(({ edge }) => edge.id));
|
|
59
|
+
const lanesWithLitNode = new Set();
|
|
60
|
+
for (const { node } of laid.nodes)
|
|
61
|
+
if (nodes.has(node.id))
|
|
62
|
+
lanesWithLitNode.add(node.lane);
|
|
63
|
+
const lanes = new Set(laid.lanes
|
|
64
|
+
.filter(({ lane }) => ids.has(lane.id) || lanesWithLitNode.has(lane.id))
|
|
65
|
+
.map(({ lane }) => lane.id));
|
|
66
|
+
return { nodes, edges, lanes };
|
|
67
|
+
}, [selected, highlight, laid]);
|
|
68
|
+
const emphasised = lit === undefined || highlight === "neighbours" ? undefined : lit.edges;
|
|
69
|
+
const dimmedEdges = useMemo(() => new Set(lit === undefined
|
|
70
|
+
? []
|
|
71
|
+
: laid.edges.filter(({ edge }) => !lit.edges.has(edge.id)).map(({ edge }) => edge.id)), [lit, laid]);
|
|
72
|
+
return (_jsx("div", { role: "figure", "aria-label": doc.title, ref: viewportRef, className: cn("relative max-w-full overflow-auto", className), children: _jsxs("div", { "data-conduit-canvas": true, className: "relative rounded-xl bg-conduit-bg bg-[radial-gradient(var(--color-conduit-dot)_1px,transparent_1px)] bg-[size:18px_18px] text-conduit-fg", style: {
|
|
73
|
+
width: laid.width,
|
|
74
|
+
height: laid.height,
|
|
75
|
+
...(scale < 1
|
|
76
|
+
? {
|
|
77
|
+
transform: `scale(${scale})`,
|
|
78
|
+
transformOrigin: "top left",
|
|
79
|
+
marginRight: -(laid.width * (1 - scale)),
|
|
80
|
+
marginBottom: -(laid.height * (1 - scale)),
|
|
81
|
+
}
|
|
82
|
+
: {}),
|
|
83
|
+
}, children: [laid.lanes.map(({ lane, box }) => (_jsx(LaneBand, { id: lane.id, lane: lane, box: box, dimmed: lit !== undefined && !lit.lanes.has(lane.id) }, lane.id))), _jsx(EdgeLayer, { width: laid.width, height: laid.height, edges: laid.edges, dimmedIds: dimmedEdges, emphasisedIds: emphasised, onEdgeClick: onEdgeClick, edgeState: edgeState }), laid.nodes.map(({ node, box }) => {
|
|
84
|
+
const headerHeight = headerHeightOf(node, heights);
|
|
85
|
+
const hasBody = box.height > headerHeight;
|
|
86
|
+
return (_jsx(Card, { id: node.id, node: node, box: box, headerHeight: headerHeight, dimmed: lit !== undefined && !lit.nodes.has(node.id), selected: selected?.includes(node.id) ?? false, onClick: onNodeClick === undefined ? undefined : () => onNodeClick(node.id), children: hasBody ? children?.(node) : null }, node.id));
|
|
87
|
+
}), _jsx("ul", { className: "sr-only", children: laid.edges.map(({ edge }) => {
|
|
88
|
+
const text = `${nodeLabel.get(edge.from) ?? edge.from} → ${nodeLabel.get(edge.to) ?? edge.to}, ${edge.kind}`;
|
|
89
|
+
return (_jsx("li", { children: onEdgeClick === undefined ? (text) : (_jsx("button", { type: "button", onClick: () => onEdgeClick(edge.id), children: text })) }, edge.id));
|
|
90
|
+
}) })] }) }));
|
|
91
|
+
};
|
|
92
|
+
//# sourceMappingURL=Diagram.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Diagram.js","sourceRoot":"","sources":["../../src/components/Diagram.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAkB,MAAM,OAAO,CAAC;AAE7E,OAAO,EAAE,EAAE,EAAE,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,oBAAoB,EAAoB,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAkB,MAAM,oBAAoB,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAwBrC,MAAM,cAAc,GAAG,CAAC,IAAiB,EAAE,OAAoB,EAAU,EAAE,CACzE,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;AAEvE;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,EACtB,GAAG,EACH,IAAI,EACJ,QAAQ,EACR,SAAS,GAAG,YAAY,EACxB,WAAW,EACX,WAAW,EACX,WAAW,EACX,SAAS,EACT,GAAG,GAAG,KAAK,EACX,QAAQ,EACR,SAAS,GACI,EAAE,EAAE;IACjB,2EAA2E;IAC3E,iEAAiE;IACjE,MAAM,aAAa,GAAG,WAAW,EAAE,OAAO,CAAC;IAC3C,MAAM,kBAAkB,GAAG,WAAW,EAAE,YAAY,CAAC;IACrD,MAAM,WAAW,GAAG,WAAW,EAAE,KAAK,CAAC;IACvC,MAAM,OAAO,GAAG,OAAO,CACrB,GAAG,EAAE,CAAC,CAAC;QACL,OAAO,EAAE,aAAa,IAAI,oBAAoB,CAAC,OAAO;QACtD,YAAY,EAAE,kBAAkB,IAAI,oBAAoB,CAAC,YAAY;QACrE,KAAK,EAAE,WAAW,IAAI,oBAAoB,CAAC,KAAK;KACjD,CAAC,EACF,CAAC,aAAa,EAAE,kBAAkB,EAAE,WAAW,CAAC,CACjD,CAAC;IAEF,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE;QACvC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC;QAC1D,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC7E,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;IAC5C,CAAC,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IAEzB,MAAM,WAAW,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IACjD,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAEtD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,MAAM,IAAI,GAAG,WAAW,CAAC,OAAO,CAAC;QACjC,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,cAAc,KAAK,WAAW;YAAE,OAAO;QACnE,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACxD,MAAM,EAAE,CAAC;QACT,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC;QAC5C,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACvB,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;IACrC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAEV,MAAM,KAAK,GAAG,GAAG,IAAI,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAErF,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE;QACvB,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;QACtE,MAAM,KAAK,GAAG,SAAS,CACrB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,EAClC,QAAQ,EACR,SAAS,CACV,CAAC;QACF,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC9B,MAAM,KAAK,GAAG,IAAI,GAAG,CACnB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CACrF,CAAC;QACF,MAAM,KAAK,GAAG,IAAI,GAAG,CACnB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CACrF,CAAC;QACF,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAU,CAAC;QAC3C,KAAK,MAAM,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,KAAK;YAAE,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBAAE,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3F,MAAM,KAAK,GAAG,IAAI,GAAG,CACnB,IAAI,CAAC,KAAK;aACP,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;aACvE,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAC9B,CAAC;QACF,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IACjC,CAAC,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAEhC,MAAM,UAAU,GAAG,GAAG,KAAK,SAAS,IAAI,SAAS,KAAK,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;IAE3F,MAAM,WAAW,GAAG,OAAO,CACzB,GAAG,EAAE,CACH,IAAI,GAAG,CACL,GAAG,KAAK,SAAS;QACf,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CACxF,EACH,CAAC,GAAG,EAAE,IAAI,CAAC,CACZ,CAAC;IAEF,OAAO,CACL,cACE,IAAI,EAAC,QAAQ,gBACD,GAAG,CAAC,KAAK,EACrB,GAAG,EAAE,WAAW,EAChB,SAAS,EAAE,EAAE,CAAC,mCAAmC,EAAE,SAAS,CAAC,YAE7D,4CAEE,SAAS,EAAC,0IAA0I,EACpJ,KAAK,EAAE;gBACL,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,GAAG,CAAC,KAAK,GAAG,CAAC;oBACX,CAAC,CAAC;wBACE,SAAS,EAAE,SAAS,KAAK,GAAG;wBAC5B,eAAe,EAAE,UAAU;wBAC3B,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;wBACxC,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;qBAC3C;oBACH,CAAC,CAAC,EAAE,CAAC;aACR,aAEA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CACjC,KAAC,QAAQ,IAEP,EAAE,EAAE,IAAI,CAAC,EAAE,EACX,IAAI,EAAE,IAAI,EACV,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,GAAG,KAAK,SAAS,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAJ/C,IAAI,CAAC,EAAE,CAKZ,CACH,CAAC,EAEF,KAAC,SAAS,IACR,KAAK,EAAE,IAAI,CAAC,KAAK,EACjB,MAAM,EAAE,IAAI,CAAC,MAAM,EACnB,KAAK,EAAE,IAAI,CAAC,KAAK,EACjB,SAAS,EAAE,WAAW,EACtB,aAAa,EAAE,UAAU,EACzB,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE,SAAS,GACpB,EAED,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE;oBAChC,MAAM,YAAY,GAAG,cAAc,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;oBACnD,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,GAAG,YAAY,CAAC;oBAC1C,OAAO,CACL,KAAC,IAAI,IAEH,EAAE,EAAE,IAAI,CAAC,EAAE,EACX,IAAI,EAAE,IAAI,EACV,GAAG,EAAE,GAAG,EACR,YAAY,EAAE,YAAY,EAC1B,MAAM,EAAE,GAAG,KAAK,SAAS,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,EACpD,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,EAC9C,OAAO,EAAE,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,YAE1E,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,IAT7B,IAAI,CAAC,EAAE,CAUP,CACR,CAAC;gBACJ,CAAC,CAAC,EAEF,aAAI,SAAS,EAAC,SAAS,YACpB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE;wBAC3B,MAAM,IAAI,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,MAAM,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;wBAC7G,OAAO,CACL,uBACG,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,CAC3B,IAAI,CACL,CAAC,CAAC,CAAC,CACF,iBAAQ,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,YACtD,IAAI,GACE,CACV,IAPM,IAAI,CAAC,EAAE,CAQX,CACN,CAAC;oBACJ,CAAC,CAAC,GACC,IACD,GACF,CACP,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { PlacedEdge } from "../layout/layout.js";
|
|
2
|
+
import { type EdgeState } from "./pulse.js";
|
|
3
|
+
export type EdgeLayerProps = {
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
edges: readonly PlacedEdge[];
|
|
7
|
+
dimmedIds: ReadonlySet<string>;
|
|
8
|
+
/**
|
|
9
|
+
* Edges drawn at hero weight without changing their pulses, e.g. a traced path.
|
|
10
|
+
* An edge the document marks `muted` stays muted.
|
|
11
|
+
*/
|
|
12
|
+
emphasisedIds?: ReadonlySet<string>;
|
|
13
|
+
onEdgeClick?: (id: string) => void;
|
|
14
|
+
/** Live overlay by edge id. Absent ids follow the document; see the mapping in the README. */
|
|
15
|
+
edgeState?: Readonly<Record<string, EdgeState>>;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Every edge of the diagram in one svg under the cards. Lines pass behind
|
|
19
|
+
* cards; pills are opaque so they read wherever they land, and are drawn
|
|
20
|
+
* last so they pass in front of everything in this layer.
|
|
21
|
+
*/
|
|
22
|
+
export declare const EdgeLayer: ({ width, height, edges, dimmedIds, emphasisedIds, onEdgeClick, edgeState, }: EdgeLayerProps) => import("react").JSX.Element;
|
|
23
|
+
//# sourceMappingURL=EdgeLayer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EdgeLayer.d.ts","sourceRoot":"","sources":["../../src/components/EdgeLayer.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAoC,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AA+G9E,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,SAAS,UAAU,EAAE,CAAC;IAC7B,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC/B;;;OAGG;IACH,aAAa,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACpC,WAAW,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,8FAA8F;IAC9F,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;CACjD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,SAAS,gFAQnB,cAAc,gCAgGhB,CAAC"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useId } from "react";
|
|
3
|
+
import { cn } from "../cn.js";
|
|
4
|
+
import { HERO_PULSE_COUNT, HERO_PULSE_DURATION, PILL_TEXT_SIZE, PULSE_DURATION, } from "../layout/design.js";
|
|
5
|
+
import { coord } from "../layout/geometry.js";
|
|
6
|
+
import { pulseDurationFor } from "./pulse.js";
|
|
7
|
+
import { STATUSES } from "../schema/primitives.js";
|
|
8
|
+
const STROKE = {
|
|
9
|
+
neutral: "stroke-conduit-edge",
|
|
10
|
+
positive: "stroke-conduit-positive",
|
|
11
|
+
caution: "stroke-conduit-caution",
|
|
12
|
+
critical: "stroke-conduit-critical",
|
|
13
|
+
};
|
|
14
|
+
const FILL = {
|
|
15
|
+
neutral: "fill-conduit-edge",
|
|
16
|
+
positive: "fill-conduit-positive",
|
|
17
|
+
caution: "fill-conduit-caution",
|
|
18
|
+
critical: "fill-conduit-critical",
|
|
19
|
+
};
|
|
20
|
+
const PILL_TEXT = {
|
|
21
|
+
neutral: "fill-conduit-muted",
|
|
22
|
+
positive: "fill-conduit-positive-text",
|
|
23
|
+
caution: "fill-conduit-caution-text",
|
|
24
|
+
critical: "fill-conduit-critical-text",
|
|
25
|
+
};
|
|
26
|
+
const PULSE_RADIUS = 2.6;
|
|
27
|
+
const TRAIN_RADIUS = 3;
|
|
28
|
+
const toneFor = (level, base) => {
|
|
29
|
+
switch (level) {
|
|
30
|
+
case "down":
|
|
31
|
+
return "critical";
|
|
32
|
+
case "stale":
|
|
33
|
+
return "caution";
|
|
34
|
+
case "done":
|
|
35
|
+
return "positive";
|
|
36
|
+
default:
|
|
37
|
+
return base;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* The travelling pulse: the mark that says a connection carries traffic
|
|
42
|
+
* rather than merely existing. A dot running behind the drawing's clock says
|
|
43
|
+
* so with a negative `begin`, so it is never seen waiting at the origin.
|
|
44
|
+
*/
|
|
45
|
+
const Pulses = ({ id, path, tone, hero, duration, }) => {
|
|
46
|
+
const count = hero ? HERO_PULSE_COUNT : 1;
|
|
47
|
+
return (_jsx("g", { "data-pulse": id, className: "motion-reduce:hidden", children: Array.from({ length: count }, (_, index) => {
|
|
48
|
+
const behind = ((duration / count) * index) % duration;
|
|
49
|
+
return (_jsx("circle", { r: hero ? TRAIN_RADIUS : PULSE_RADIUS, className: FILL[tone], children: _jsx("animateMotion", { dur: `${coord(duration)}s`, begin: behind === 0 ? undefined : `${coord(behind - duration)}s`, repeatCount: "indefinite", path: path }) }, index));
|
|
50
|
+
}) }));
|
|
51
|
+
};
|
|
52
|
+
const Pill = ({ text, box, tone, }) => (_jsxs("g", { children: [_jsx("rect", { className: "fill-conduit-pill stroke-conduit-pill-border stroke-[1]", x: box.x, y: box.y, width: box.width, height: box.height, rx: box.height / 2 }), _jsx("text", { className: cn("font-semibold", PILL_TEXT[tone]), style: { fontSize: PILL_TEXT_SIZE }, x: box.x + box.width / 2, y: box.y + box.height / 2 + 3.5, textAnchor: "middle", children: text })] }));
|
|
53
|
+
const EMPTY = new Set();
|
|
54
|
+
const NO_STATE = {};
|
|
55
|
+
/**
|
|
56
|
+
* Every edge of the diagram in one svg under the cards. Lines pass behind
|
|
57
|
+
* cards; pills are opaque so they read wherever they land, and are drawn
|
|
58
|
+
* last so they pass in front of everything in this layer.
|
|
59
|
+
*/
|
|
60
|
+
export const EdgeLayer = ({ width, height, edges, dimmedIds, emphasisedIds = EMPTY, onEdgeClick, edgeState = NO_STATE, }) => {
|
|
61
|
+
const uid = useId().replace(/:/g, "");
|
|
62
|
+
const marker = (tone) => `${uid}-mk-${tone}`;
|
|
63
|
+
return (_jsxs("svg", { className: "pointer-events-none absolute inset-0 overflow-visible", width: width, height: height, viewBox: `0 0 ${width} ${height}`, "aria-hidden": "true", children: [_jsx("defs", { children: STATUSES.map((tone) => (_jsx("marker", { id: marker(tone), viewBox: "0 0 10 10", refX: 8, refY: 5, markerWidth: 6.5, markerHeight: 6.5, orient: "auto-start-reverse", children: _jsx("path", { d: "M0,0 L10,5 L0,10 z", className: FILL[tone] }) }, tone))) }), edges.map(({ edge, path, tone }) => {
|
|
64
|
+
const state = edgeState[edge.id];
|
|
65
|
+
const level = state?.level;
|
|
66
|
+
const liveTone = toneFor(level, tone);
|
|
67
|
+
const pulsing = level === undefined ? edge.animated : level === "live";
|
|
68
|
+
const heroPulses = edge.emphasis === "hero";
|
|
69
|
+
const duration = level === "live" && state?.rate !== undefined
|
|
70
|
+
? pulseDurationFor(state.rate)
|
|
71
|
+
: heroPulses
|
|
72
|
+
? HERO_PULSE_DURATION
|
|
73
|
+
: PULSE_DURATION;
|
|
74
|
+
const hero = heroPulses || (emphasisedIds.has(edge.id) && edge.emphasis !== "muted");
|
|
75
|
+
const dimmed = dimmedIds.has(edge.id) || edge.emphasis === "muted";
|
|
76
|
+
return (_jsxs("g", { "data-edge-group": edge.id, "data-edge-state": level, className: cn("transition-opacity", dimmed && "opacity-45"), children: [hero && (_jsx("path", { d: path, className: cn("fill-none stroke-[7] opacity-[0.14]", STROKE[liveTone]) })), _jsx("path", { "data-edge": edge.id, d: path, className: cn("fill-none", STROKE[liveTone], hero ? "stroke-[2.25]" : "stroke-[1.5]", level === "down" && "[stroke-dasharray:5_4]"), markerEnd: `url(#${marker(liveTone)})` }), pulsing && (_jsx(Pulses, { id: edge.id, path: path, tone: liveTone, hero: heroPulses, duration: duration })), onEdgeClick !== undefined && (_jsx("path", { "data-edge-hit": edge.id, d: path, className: "pointer-events-auto cursor-pointer fill-none stroke-transparent stroke-[12]", onClick: () => onEdgeClick(edge.id) }))] }, edge.id));
|
|
77
|
+
}), edges.map(({ edge, label, tone }) => {
|
|
78
|
+
if (label === undefined)
|
|
79
|
+
return null;
|
|
80
|
+
const level = edgeState[edge.id]?.level;
|
|
81
|
+
const liveTone = toneFor(level, tone);
|
|
82
|
+
return _jsx(Pill, { text: label.text, box: label.box, tone: liveTone }, `${edge.id}-label`);
|
|
83
|
+
})] }));
|
|
84
|
+
};
|
|
85
|
+
//# sourceMappingURL=EdgeLayer.js.map
|