@rokkit/graph 1.7.0 → 1.8.1

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 (120) hide show
  1. package/README.md +67 -1
  2. package/dist/Graph.svelte +234 -259
  3. package/dist/Graph.svelte.d.ts +1 -1
  4. package/dist/GraphLegend.svelte +81 -10
  5. package/dist/GraphLegend.svelte.d.ts +15 -0
  6. package/dist/GraphState.svelte.d.ts +168 -51
  7. package/dist/GraphState.svelte.js +406 -305
  8. package/dist/actions/canvas.d.ts +18 -0
  9. package/dist/actions/canvas.js +59 -0
  10. package/dist/actions/choices.d.ts +12 -0
  11. package/dist/actions/choices.js +23 -0
  12. package/dist/actions/interactions.d.ts +20 -0
  13. package/dist/actions/interactions.js +57 -0
  14. package/dist/actions/listen.d.ts +2 -0
  15. package/dist/actions/listen.js +10 -0
  16. package/dist/canvas/frame.d.ts +41 -0
  17. package/dist/canvas/frame.js +34 -0
  18. package/dist/controls/BundleControl.svelte +11 -10
  19. package/dist/controls/BundleControl.svelte.d.ts +0 -7
  20. package/dist/controls/DensityControl.svelte +17 -9
  21. package/dist/controls/DensityControl.svelte.d.ts +0 -8
  22. package/dist/controls/DepthControl.svelte +11 -4
  23. package/dist/controls/DepthControl.svelte.d.ts +0 -9
  24. package/dist/controls/DrillBar.svelte +63 -0
  25. package/dist/controls/DrillBar.svelte.d.ts +9 -0
  26. package/dist/controls/EdgeStyleControl.svelte +10 -10
  27. package/dist/controls/EdgeStyleControl.svelte.d.ts +0 -6
  28. package/dist/controls/HiddenControl.svelte +27 -0
  29. package/dist/controls/HiddenControl.svelte.d.ts +7 -0
  30. package/dist/controls/MeasureControl.svelte +39 -0
  31. package/dist/controls/MeasureControl.svelte.d.ts +12 -0
  32. package/dist/controls/ToggleControl.svelte +33 -0
  33. package/dist/controls/ToggleControl.svelte.d.ts +13 -0
  34. package/dist/controls/ViolationsControl.svelte +27 -0
  35. package/dist/controls/ViolationsControl.svelte.d.ts +7 -0
  36. package/dist/controls/ZoomControl.svelte +21 -18
  37. package/dist/controls/zoom.d.ts +3 -0
  38. package/dist/controls/zoom.js +6 -0
  39. package/dist/diagrams/ArcDiagram.svelte +116 -0
  40. package/dist/diagrams/ArcDiagram.svelte.d.ts +31 -0
  41. package/dist/diagrams/CallTree.svelte +17 -5
  42. package/dist/diagrams/CallTree.svelte.d.ts +5 -1
  43. package/dist/diagrams/DependencyDiagram.svelte +18 -6
  44. package/dist/diagrams/DependencyDiagram.svelte.d.ts +5 -1
  45. package/dist/diagrams/DependencyMatrix.svelte +156 -0
  46. package/dist/diagrams/DependencyMatrix.svelte.d.ts +34 -0
  47. package/dist/diagrams/ErDiagram.svelte +18 -6
  48. package/dist/diagrams/ErDiagram.svelte.d.ts +5 -1
  49. package/dist/diagrams/LayersDiagram.svelte +124 -0
  50. package/dist/diagrams/LayersDiagram.svelte.d.ts +30 -0
  51. package/dist/diagrams/Neighborhood.svelte +26 -6
  52. package/dist/diagrams/Neighborhood.svelte.d.ts +11 -1
  53. package/dist/diagrams/PolymetricTree.svelte +116 -0
  54. package/dist/diagrams/PolymetricTree.svelte.d.ts +28 -0
  55. package/dist/diagrams/StructureDiagram.svelte +38 -8
  56. package/dist/diagrams/StructureDiagram.svelte.d.ts +9 -1
  57. package/dist/diagrams/Sunburst.svelte +44 -8
  58. package/dist/diagrams/Sunburst.svelte.d.ts +12 -2
  59. package/dist/diagrams/Treemap.svelte +44 -8
  60. package/dist/diagrams/Treemap.svelte.d.ts +12 -2
  61. package/dist/index.d.ts +13 -3
  62. package/dist/index.js +11 -2
  63. package/dist/layout/arcs.d.ts +6 -0
  64. package/dist/layout/arcs.js +141 -0
  65. package/dist/layout/cards.js +9 -2
  66. package/dist/layout/edges.d.ts +13 -1
  67. package/dist/layout/edges.js +35 -0
  68. package/dist/layout/extent.d.ts +17 -0
  69. package/dist/layout/extent.js +27 -0
  70. package/dist/layout/flow.js +3 -1
  71. package/dist/layout/index.d.ts +4 -1
  72. package/dist/layout/index.js +17 -2
  73. package/dist/layout/layers.d.ts +6 -0
  74. package/dist/layout/layers.js +180 -0
  75. package/dist/layout/matrix.d.ts +50 -0
  76. package/dist/layout/matrix.js +110 -0
  77. package/dist/layout/neighborhood.js +16 -7
  78. package/dist/layout/options.d.ts +1 -1
  79. package/dist/layout/options.js +16 -3
  80. package/dist/layout/percentile.d.ts +8 -0
  81. package/dist/layout/percentile.js +13 -0
  82. package/dist/layout/polymetric.d.ts +3 -0
  83. package/dist/layout/polymetric.js +221 -0
  84. package/dist/layout/radial.js +3 -1
  85. package/dist/layout/structure.js +7 -1
  86. package/dist/layout/sunburst.js +11 -4
  87. package/dist/layout/types.d.ts +83 -0
  88. package/dist/layout/world.js +11 -4
  89. package/dist/messages.d.ts +14 -0
  90. package/dist/messages.js +17 -0
  91. package/dist/model/condense.d.ts +8 -0
  92. package/dist/model/condense.js +114 -0
  93. package/dist/model/entities.d.ts +12 -0
  94. package/dist/model/entities.js +12 -0
  95. package/dist/model/normalize.d.ts +2 -6
  96. package/dist/model/normalize.js +83 -5
  97. package/dist/model/relationships.d.ts +30 -0
  98. package/dist/model/relationships.js +51 -0
  99. package/dist/model/share.d.ts +9 -0
  100. package/dist/model/share.js +43 -0
  101. package/dist/model/tree.d.ts +7 -1
  102. package/dist/model/tree.js +11 -4
  103. package/dist/preset.d.ts +18 -0
  104. package/dist/preset.js +34 -3
  105. package/dist/schema/EntitiesView.svelte +8 -6
  106. package/dist/schema/EntityView.svelte +13 -10
  107. package/dist/state/GraphConfig.svelte.d.ts +124 -0
  108. package/dist/state/GraphConfig.svelte.js +253 -0
  109. package/dist/state/GraphDrill.svelte.d.ts +52 -0
  110. package/dist/state/GraphDrill.svelte.js +115 -0
  111. package/dist/state/GraphGroups.svelte.d.ts +35 -0
  112. package/dist/state/GraphGroups.svelte.js +73 -0
  113. package/dist/state/GraphSelection.svelte.d.ts +53 -0
  114. package/dist/state/GraphSelection.svelte.js +94 -0
  115. package/dist/state/intents.d.ts +33 -0
  116. package/dist/state/intents.js +30 -0
  117. package/dist/state/text.d.ts +28 -0
  118. package/dist/state/text.js +56 -0
  119. package/dist/types.d.ts +92 -1
  120. package/package.json +5 -4
@@ -14,6 +14,9 @@
14
14
  */
15
15
  import type { GraphState } from './GraphState.svelte.js'
16
16
  import { DEFAULT_ICONS } from './icons.js'
17
+ import { choices } from './actions/choices.js'
18
+ import { say } from './messages.js'
19
+ import { readable } from './state/text.js'
17
20
 
18
21
  type Section = 'kind' | 'relation' | 'group'
19
22
 
@@ -25,6 +28,21 @@
25
28
  relations?: boolean
26
29
  /** Group names present, each with its ramp colour. */
27
30
  groups?: boolean
31
+ /**
32
+ * Which measure each channel of a polymetric view carries (#168) — three encodings at
33
+ * once are unreadable without a key.
34
+ */
35
+ channels?: boolean
36
+ /**
37
+ * The two sides of an arc diagram, left then right (#169) — which relation is which is
38
+ * not something a reader can guess from the arcs. `true` names them from the data
39
+ * (`GraphState.sideNames`); a pair names them yourself.
40
+ */
41
+ sides?: boolean | [string, string]
42
+ /** A key for the hidden-coupling stroke (#169). */
43
+ hidden?: boolean
44
+ /** What the shade means in a containment view (#164): the measure, on its ramp. */
45
+ shade?: boolean
28
46
  icons?: Record<string, string>
29
47
  /**
30
48
  * Fires with the entry a reader activated. Given one, entries become real buttons;
@@ -38,15 +56,29 @@
38
56
  kinds = false,
39
57
  relations = false,
40
58
  groups = false,
59
+ channels = false,
60
+ sides = undefined,
61
+ hidden = false,
62
+ shade = false,
41
63
  icons: userIcons,
42
64
  onpick
43
65
  }: Props = $props()
44
66
 
45
67
  const icons = $derived<Record<string, string>>({ ...DEFAULT_ICONS, ...userIcons })
46
- const shown = $derived(kinds || relations || groups)
68
+ const channelRows = $derived(channels ? graph.channelRows : [])
69
+ const sideLabels = $derived(
70
+ sides === true ? [graph.sideNames.below, graph.sideNames.above] : sides || null
71
+ )
72
+ const shadeRow = $derived(shade ? graph.shadeLegend : null)
73
+ const shown = $derived(
74
+ kinds || relations || groups || channelRows.length > 0 || Boolean(sideLabels) || hidden || Boolean(shadeRow)
75
+ )
47
76
 
48
- /** Underscores are the WIRE format (dbd sends `materialized_view`), not something to read. */
49
- const readable = (value: string) => value.replace(/_/g, ' ')
77
+ /** A pick names its section and value in one choice; split at the first colon. */
78
+ function pick(choice: string) {
79
+ const at = choice.indexOf(':')
80
+ onpick?.(choice.slice(0, at) as Section, choice.slice(at + 1))
81
+ }
50
82
 
51
83
  /** `data-legend-kind` / `-relation` / `-group`, so CSS and tests can address a section. */
52
84
  const attrs = (section: Section, value: string) => ({ [`data-legend-${section}`]: value })
@@ -72,12 +104,7 @@
72
104
  a screen reader — and a click handler on a `<span>` is unreachable by keyboard. -->
73
105
  {#snippet row(section: Section, value: string)}
74
106
  {#if onpick}
75
- <button
76
- type="button"
77
- data-graph-legend-entry
78
- {...attrs(section, value)}
79
- onclick={() => onpick(section, value)}
80
- >
107
+ <button type="button" data-graph-legend-entry {...attrs(section, value)} data-graph-choice="{section}:{value}">
81
108
  {@render swatch(section, value)}
82
109
  <span data-legend-label>{readable(value)}</span>
83
110
  </button>
@@ -90,7 +117,7 @@
90
117
  {/snippet}
91
118
 
92
119
  {#if shown}
93
- <div data-graph-legend aria-label="Legend">
120
+ <div data-graph-legend aria-label={say('legend')} use:choices={{ onchoose: pick }}>
94
121
  {#if kinds}
95
122
  {#each graph.kindsPresent as kind (kind)}
96
123
  {@render row('kind', kind)}
@@ -108,5 +135,49 @@
108
135
  {@render row('group', group)}
109
136
  {/each}
110
137
  {/if}
138
+
139
+ {#if sideLabels}
140
+ <span data-graph-legend-entry data-legend-side="below">
141
+ <span data-legend-label>← {sideLabels[0]}</span>
142
+ </span>
143
+ <span data-graph-legend-entry data-legend-side="above">
144
+ <span data-legend-label>{sideLabels[1]} →</span>
145
+ </span>
146
+ {/if}
147
+
148
+ {#if hidden}
149
+ <span data-graph-legend-entry data-legend-hidden>
150
+ <svg data-legend-swatch data-edge-hidden aria-hidden="true">
151
+ <line x1="2" y1="7" x2="26" y2="7" />
152
+ </svg>
153
+ <span data-legend-label>{say('legendHidden')}</span>
154
+ </span>
155
+ {/if}
156
+
157
+ {#if shadeRow}
158
+ <!-- The swatch is the ramp itself, low to high: the colours on the canvas, not a sample. -->
159
+ <span data-graph-legend-entry data-legend-shade={shadeRow.measure}>
160
+ <span
161
+ data-legend-swatch
162
+ data-legend-shade-swatch
163
+ style:--shade-low={shadeRow.low}
164
+ style:--shade-high={shadeRow.high}
165
+ aria-hidden="true"
166
+ ></span>
167
+ <span data-legend-label>{say('shade')}</span>
168
+ <span data-legend-measure>{readable(shadeRow.measure)}</span>
169
+ <span data-legend-cap>{say('shadeScale')}</span>
170
+ </span>
171
+ {/if}
172
+
173
+ {#each channelRows as channel (channel.key)}
174
+ <!-- The cap is what the full extent of the channel stands for: past it, a box clamps. -->
175
+ <span data-graph-legend-entry data-legend-channel={channel.key}>
176
+ <span data-legend-swatch data-legend-channel-swatch={channel.key} aria-hidden="true"></span>
177
+ <span data-legend-label>{channel.label}</span>
178
+ <span data-legend-measure>{readable(channel.scale.measure)}</span>
179
+ <span data-legend-cap>{say('legendCap', { cap: channel.scale.cap })}</span>
180
+ </span>
181
+ {/each}
111
182
  </div>
112
183
  {/if}
@@ -21,6 +21,21 @@ type Props = {
21
21
  relations?: boolean;
22
22
  /** Group names present, each with its ramp colour. */
23
23
  groups?: boolean;
24
+ /**
25
+ * Which measure each channel of a polymetric view carries (#168) — three encodings at
26
+ * once are unreadable without a key.
27
+ */
28
+ channels?: boolean;
29
+ /**
30
+ * The two sides of an arc diagram, left then right (#169) — which relation is which is
31
+ * not something a reader can guess from the arcs. `true` names them from the data
32
+ * (`GraphState.sideNames`); a pair names them yourself.
33
+ */
34
+ sides?: boolean | [string, string];
35
+ /** A key for the hidden-coupling stroke (#169). */
36
+ hidden?: boolean;
37
+ /** What the shade means in a containment view (#164): the measure, on its ramp. */
38
+ shade?: boolean;
24
39
  icons?: Record<string, string>;
25
40
  /**
26
41
  * Fires with the entry a reader activated. Given one, entries become real buttons;
@@ -1,26 +1,18 @@
1
1
  import { SvelteSet } from 'svelte/reactivity';
2
2
  import type { GraphPreset } from './preset.js';
3
- import type { Arrange, Cards, Cluster, Column, Density, EdgeStyle, LayoutFn, NodeAxis, RoutedEdge, Size } from './layout/types.js';
3
+ import type { Arrange, Cards, Cluster, Column, Density, EdgeStyle, LayoutFn, NodeAxis, RoutedEdge, ShowEdges, Size, LayoutResult } from './layout/types.js';
4
4
  import type { GraphEdge, GraphFields, GraphModel, GraphNode } from './types.js';
5
- export type EntityRow = {
6
- id: string;
7
- label: string;
8
- group?: string;
9
- kind?: string;
10
- rowCount: number;
11
- refCount: number;
12
- note?: string;
13
- };
14
- export type Relationship = {
15
- direction: 'in' | 'out';
16
- id: string;
17
- label: string;
18
- group?: string;
19
- /** The canonical edge — always present. A relationship is a fact about the model. */
20
- edge: GraphEdge;
21
- /** Routed geometry, present only when the ACTIVE layout placed this edge. */
22
- routed?: RoutedEdge;
23
- };
5
+ import type { Relationship } from './model/relationships.js';
6
+ import type { EntityRow } from './model/entities.js';
7
+ import { GraphConfig } from './state/GraphConfig.svelte.js';
8
+ import { GraphSelection } from './state/GraphSelection.svelte.js';
9
+ import { GraphDrill } from './state/GraphDrill.svelte.js';
10
+ import { GraphGroups } from './state/GraphGroups.svelte.js';
11
+ import type { GroupAction } from './state/GraphGroups.svelte.js';
12
+ import type { Intent } from './state/intents.js';
13
+ import type { ChannelRow } from './state/text.js';
14
+ import type { Breadcrumb } from './state/GraphDrill.svelte.js';
15
+ export type { Relationship, EntityRow, Breadcrumb, GroupAction };
24
16
  export type GraphStateConfig = {
25
17
  nodes?: unknown[];
26
18
  edges?: unknown[];
@@ -66,9 +58,66 @@ export type GraphStateConfig = {
66
58
  mode?: 'light' | 'dark';
67
59
  label?: string;
68
60
  onselect?: (id: string | null) => void;
61
+ /**
62
+ * The reader drilled INTO a box: `path` is the new `focusPath`, `node` the declared node at
63
+ * it (null for a container nothing declared). Return a promise to show a pending state
64
+ * until the level's data arrives; a rejection restores the previous level. Distinct from
65
+ * `onselect` — drilling changes scope, it does not select.
66
+ */
67
+ ondrill?: (path: string[], node: GraphNode | null) => void | Promise<void>;
68
+ /** The reader drilled OUT; `path` is the new, shorter `focusPath`. Same promise contract. */
69
+ ondrillup?: (path: string[]) => void | Promise<void>;
70
+ /**
71
+ * Every internal change of `focusPath` — drill in, out, or a rollback after a failed load.
72
+ * For a component that owns a bindable `focusPath` prop, so its next `update()` agrees.
73
+ */
74
+ onfocuspath?: (path: string[]) => void;
75
+ /**
76
+ * The reader expanded a group (#166). With its members already in `nodes` they appear at
77
+ * once; a host that sends only the group can load them in answer.
78
+ */
79
+ onexpand?: (id: string, node: GraphNode) => void;
80
+ /** The reader collapsed a group back into one node. */
81
+ oncollapse?: (id: string, node: GraphNode) => void;
82
+ /**
83
+ * Every edge (the default), or only the ones the view is about: `violations` in `layers`
84
+ * (#167), `hidden` in `arcs` (#169).
85
+ */
86
+ showEdges?: ShowEdges;
87
+ /** `layers` only — band names by layer index. */
88
+ layerLabels?: string[];
89
+ /** `polymetric` only — the measures box width, height and shade encode (#168). */
90
+ widthBy?: string;
91
+ heightBy?: string;
92
+ colorBy?: string;
93
+ /** `arcs` only — the relation drawn on the right of the axis (#169). */
94
+ above?: string;
95
+ /** `world` / `sunburst` — the measure (a 0..1 share) each box is shaded by (#164). */
96
+ shadeBy?: string;
69
97
  };
98
+ /**
99
+ * The store. Turns raw `nodes`/`edges`/`fields` into the reactive shape the visuals
100
+ * render, and owns every transition.
101
+ *
102
+ * Components read from this and call its methods — they never compute. That is what
103
+ * lets the geometry, badge derivation and selection logic be covered exhaustively
104
+ * with no DOM, and lets the component specs assert only attributes.
105
+ *
106
+ * A composition: `config` (every input, `state/GraphConfig`) feeds the layout pipeline
107
+ * derived here; the selection and the view queries read both. `update()` FULLY re-applies
108
+ * config rather than merging deltas — so a prop reverting to undefined actually reverts;
109
+ * `apply()` merges.
110
+ */
70
111
  export declare class GraphState {
71
112
  #private;
113
+ /** Every input — see `CONFIG_FIELDS` for what each omitted key falls back to. */
114
+ readonly config: GraphConfig;
115
+ /** Which subtree is the canvas, and the host events for moving it (#165). */
116
+ readonly drill: GraphDrill;
117
+ /** What the reader picked and opened. */
118
+ readonly selection: GraphSelection;
119
+ /** Which groups are collapsed (#166). */
120
+ readonly groups: GraphGroups;
72
121
  constructor(config?: GraphStateConfig);
73
122
  /**
74
123
  * Fully re-applies config. Safe to call on every prop change.
@@ -88,27 +137,41 @@ export declare class GraphState {
88
137
  */
89
138
  apply(config: Partial<GraphStateConfig>): void;
90
139
  select(id: string): void;
140
+ /** Drop the selection and report `null` — see `GraphSelection.clear`. */
141
+ clear(): void;
142
+ /** Show one node's rows in full, whatever the density says — see `GraphSelection`. */
143
+ toggleExpanded(id: string): void;
144
+ isExpanded(id: string): boolean;
145
+ isGroup(id: string): boolean;
146
+ isCollapsed(id: string): boolean;
147
+ memberCount(id: string): number;
148
+ groupOf(id: string): string | null;
91
149
  /**
92
- * Drop the selection, and SAY SO.
93
- *
94
- * Found by dbd consuming the package: it owns `selected` in its route and branches on it
95
- * to show the entity panel, so a silent clear left that panel open over nothing. A
96
- * controlled consumer cannot observe an internal `#value` — the callback is the only
97
- * channel, which is why it carries `null` rather than being skipped.
98
- *
99
- * Guarded on an actual change, or a background click on an already-empty canvas
100
- * round-trips through the consumer's setter on every stray click.
150
+ * Expand or collapse a group. Collapsing one whose member is selected moves the selection to
151
+ * the group: the thing being looked at is now inside it, and a selection naming a hidden node
152
+ * would leave the entity panel empty for no visible reason.
101
153
  */
102
- clear(): void;
154
+ toggleGroup(id: string): boolean;
155
+ /** The selection's group action — what a drill bar offers. */
156
+ get groupAction(): GroupAction | null;
157
+ get drillPath(): string[];
158
+ get breadcrumbs(): Breadcrumb[];
159
+ /** A drill's handler returned a promise that has not settled. */
160
+ get pending(): boolean;
161
+ get drillError(): unknown;
162
+ canDrill(box: Cluster): boolean;
163
+ drillInto(box: Cluster): boolean;
164
+ drillOut(levels?: number): boolean;
165
+ drillTo(path: string[]): boolean;
103
166
  /**
104
- * Show one node's rows in full, whatever the density says.
105
- *
106
- * Per NODE rather than a global density change: a reader who clicks "+3 more" on one
107
- * card is asking about that card, and expanding all of them answers a question they did
108
- * not ask — on a large diagram it also relayouts everything under them.
167
+ * The selected box, when it can be opened — what a drill bar's "Open" acts on. The keyboard
168
+ * route into a leaf: Enter selects it, and this is the next step.
109
169
  */
110
- toggleExpanded(id: string): void;
111
- isExpanded(id: string): boolean;
170
+ /** The failed drill, worded for the reader; null when the last drill did not fail. */
171
+ get drillErrorText(): string | null;
172
+ get drillTarget(): Cluster | null;
173
+ /** Whether a drill bar has anything to show: a trail, a load, a failure, or a box to open. */
174
+ get showsDrillBar(): boolean;
112
175
  /**
113
176
  * The more-row's text, or null when the card is hiding nothing and needs no control.
114
177
  *
@@ -130,17 +193,24 @@ export declare class GraphState {
130
193
  * prop would render, click, and change nothing.
131
194
  */
132
195
  setDensity(density: Density): void;
196
+ /** Every edge or only the climbing ones — what `ViolationsControl` drives (#167). */
197
+ setShowEdges(value: ShowEdges): void;
198
+ get showEdges(): ShowEdges;
133
199
  nodeState(id: string): 'selected' | 'related' | 'dim' | null;
134
200
  edgeState(edge: RoutedEdge): 'highlight' | 'dim' | null;
135
201
  edgePath(edge: RoutedEdge): string;
136
202
  groupStyle(group: string | undefined): Record<string, string>;
137
203
  /**
138
- * The same style as a `style=` attribute string.
139
- *
140
- * A template cannot spread an object into `style`, so something has to serialise it.
141
- * Doing that inline put the same map/join in two places in `Graph.svelte` — a derivation
142
- * living in a component, which is the one thing this layer exists to prevent.
204
+ * A box's paint as a style attribute: the shade ramp's step for its share when shading
205
+ * (#164), else its group's colour. Custom properties, so a theme still has the last word.
143
206
  */
207
+ boxStyleAttr(cluster: Cluster): string;
208
+ /** What a legend says about the shade: the measure and the ramp's two ends, or null. */
209
+ get shadeLegend(): {
210
+ measure: string;
211
+ low: string;
212
+ high: string;
213
+ } | null;
144
214
  groupStyleAttr(group: string | undefined): string;
145
215
  get model(): GraphModel;
146
216
  /**
@@ -154,7 +224,16 @@ export declare class GraphState {
154
224
  get hasWedges(): boolean;
155
225
  get clusters(): Cluster[];
156
226
  get cards(): Cards;
227
+ /** Structural edges as the layout routed them, then any overlay edges on top. */
157
228
  get routedEdges(): RoutedEdge[];
229
+ /** Every overlay edge in the model, placed or not. */
230
+ get overlayEdges(): GraphEdge[];
231
+ /**
232
+ * An edge's weight as 0..1 of the heaviest weighted edge, for stroke width — or undefined
233
+ * for an edge with no weight, which draws at the theme's normal width. A layout's own
234
+ * per-set `strength` wins.
235
+ */
236
+ edgeWeight(edge: RoutedEdge): number | undefined;
158
237
  get size(): Size;
159
238
  /**
160
239
  * The true content extent, as distinct from `size`.
@@ -182,14 +261,6 @@ export declare class GraphState {
182
261
  get unplacedEdges(): GraphEdge[];
183
262
  get density(): Density;
184
263
  get arrange(): Arrange;
185
- /**
186
- * A cluster's unique render key.
187
- *
188
- * NOT the name: nesting puts a `table` box under `public` AND under `billing`, and keying
189
- * an `{#each}` by name alone is a duplicate key — Svelte throws `each_key_duplicate`, the
190
- * render aborts, and no inner box appears at all, which reads as nesting silently not
191
- * working rather than as an error.
192
- */
193
264
  /**
194
265
  * The SVG path for a wedge-shaped box, centred on the canvas.
195
266
  *
@@ -204,7 +275,53 @@ export declare class GraphState {
204
275
  * differ only in the element and its role, which is exactly the difference that matters.
205
276
  */
206
277
  boxAttrs(cluster: Cluster): Record<string, string | null | undefined>;
278
+ /** Whether a box takes the pointer and the keyboard: it has an intent. */
279
+ interactive(cluster: Cluster): boolean;
280
+ /** A box's visible caption: its name, and the layout's caption or its count. */
281
+ caption(cluster: Cluster): string;
282
+ /**
283
+ * A node card's hooks and intents: it selects on press, and folds or opens its group on open
284
+ * (#166). A card with nothing below its head — no rows shown, none to reveal, not a group —
285
+ * is marked head-only so the theme can drop the empty body.
286
+ */
287
+ cardAttrs(key: string): Record<string, string | undefined>;
288
+ /** What a card's head counts: a group, the members it stands for; anything else, its rows. */
289
+ cardCount(key: string): number;
290
+ /** The "more rows" control's hooks: it expands the card, and says when a filter emptied it. */
291
+ moreAttrs(key: string): Record<string, string | undefined>;
292
+ /**
293
+ * The box a `data-graph-key` names, if it is on the canvas: a container by its render key,
294
+ * a leaf by its node id — the one key a leaf carries for both its press and its open.
295
+ */
296
+ boxFor(key: string): Cluster | undefined;
297
+ /**
298
+ * Perform an intent read off the DOM (see `state/intents`). An unknown intent, or a key
299
+ * that names nothing, does nothing — the DOM is not a trusted source.
300
+ */
301
+ act(intent: Intent, key: string | null): void;
302
+ /**
303
+ * A cluster's unique render key.
304
+ *
305
+ * NOT the name: nesting puts a `table` box under `public` AND under `billing`, and keying
306
+ * an `{#each}` by name alone is a duplicate key — Svelte throws `each_key_duplicate`, the
307
+ * render aborts, and no inner box appears at all, which reads as nesting silently not
308
+ * working rather than as an error.
309
+ */
207
310
  clusterKey(cluster: Cluster): string;
311
+ /** `polymetric` — which measure is on which channel, and each one's cap; for the legend. */
312
+ get channels(): LayoutResult['channels'];
313
+ /** The polymetric legend's rows, labelled from the locale (#168). */
314
+ get channelRows(): ChannelRow[];
315
+ /** What each side of an arc diagram shows, named from the data or the locale (#169). */
316
+ get sideNames(): {
317
+ below: string;
318
+ above: string;
319
+ };
320
+ /**
321
+ * Every measure a channel could bind: the keys in the nodes' `measures`, plus `weight` and
322
+ * `degree`, which every node has an answer for. Sorted, so a picker does not reshuffle.
323
+ */
324
+ get measureKeys(): string[];
208
325
  get groupBy(): NodeAxis;
209
326
  /**
210
327
  * The node kinds actually present, sorted.
@@ -223,9 +340,9 @@ export declare class GraphState {
223
340
  get relationsPresent(): string[];
224
341
  /** The group names present, sorted. Same reasoning as `kindsPresent`. */
225
342
  get groupsPresent(): string[];
226
- /** Whether cards carry the group ramp themselves. See `GraphStateConfig.groupTint`. */
227
343
  /** `dot` or `card` — what the active layout draws a node as. */
228
344
  get nodeShape(): 'dot' | 'card';
345
+ /** Whether cards carry the group ramp themselves. See `GraphStateConfig.groupTint`. */
229
346
  get groupTint(): boolean;
230
347
  get nestBy(): NodeAxis | null;
231
348
  get sizeBy(): string;