@jmbarzee/force-graph 0.0.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.
@@ -0,0 +1,68 @@
1
+ import { AxisValue } from './axis';
2
+ import { Taxonomy } from './taxonomy';
3
+ /** The two themes every colour is declared in. */
4
+ export type Theme = 'light' | 'dark';
5
+ /** Both themes, in order. */
6
+ export declare const THEMES: readonly Theme[];
7
+ /** A fill and a border. */
8
+ export interface ColorPair {
9
+ /** Canvas fill colour. */
10
+ readonly fill: string;
11
+ /** Canvas border colour, a few stops darker than the fill. */
12
+ readonly border: string;
13
+ }
14
+ /** A value's colour in both themes — declared together, so no half can go missing. */
15
+ export interface ThemedColor {
16
+ readonly light: ColorPair;
17
+ readonly dark: ColorPair;
18
+ }
19
+ /** How an edge type is stroked: its colour per theme, base alpha, dash pattern and width. */
20
+ export interface EdgeStroke {
21
+ readonly color: {
22
+ readonly light: string;
23
+ readonly dark: string;
24
+ };
25
+ readonly alpha: number;
26
+ readonly dash: readonly number[];
27
+ readonly width: number;
28
+ }
29
+ /**
30
+ * The stem of a value's custom-property name: the value id in kebab case
31
+ * (`twoWords` → `two-words`). Derived, never stored.
32
+ */
33
+ export declare function cssSuffix(value: AxisValue): string;
34
+ /**
35
+ * The inline custom properties a pane carries for one theme: every style
36
+ * value's fill and border. Set on the pane's root, they are what tokens, chip
37
+ * tints and typed rows read, and they follow the resolved theme by being
38
+ * recomputed, not overridden.
39
+ */
40
+ export declare function schemeVars(taxonomy: Taxonomy, theme: Theme): Record<string, string>;
41
+ /**
42
+ * The red, green and blue of a scheme colour, or undefined. A scheme colour
43
+ * is hex of either length, `rgb()`/`rgba()` or `hsl()`/`hsla()` — a form
44
+ * every reader can parse without a browser, so the taxonomy can refuse
45
+ * anything else at construction (`isSchemeColor`) and no reader meets a
46
+ * colour it cannot read.
47
+ */
48
+ export declare function rgbOf(color: string): readonly [number, number, number] | undefined;
49
+ /** Whether a colour is one every reader parses: hex, `rgb()` or `hsl()`. */
50
+ export declare const isSchemeColor: (color: string) => boolean;
51
+ /**
52
+ * A colour at an alpha, as `rgba()`, for a canvas gradient or fill. A colour
53
+ * outside the scheme's forms becomes a neutral grey, said once per colour on
54
+ * the console — never a throw, because this runs inside the draw loop.
55
+ * Unreachable for a taxonomy's colours, which are refused at
56
+ * construction; it guards the library's own group palette and any caller
57
+ * that bypasses the taxonomy.
58
+ */
59
+ export declare function withAlpha(color: string, alpha: number): string;
60
+ /**
61
+ * A stylesheet for a host's own CSS: every style value's fill and border on
62
+ * `:root`, and the dark values that differ under `darkSelector` — by default
63
+ * `[data-theme="dark"]`, the attribute the pane carries on its own root; a
64
+ * host that marks its theme another way names its own selector. The pane
65
+ * does not read this — it carries `schemeVars` inline — so a host that
66
+ * styles nothing of its own by node value never needs it.
67
+ */
68
+ export declare function schemeStylesheet(taxonomy: Taxonomy, darkSelector?: string): string;
@@ -0,0 +1,227 @@
1
+ import { AxisId, AxisValue } from './axis';
2
+ import { EdgeStroke, ThemedColor } from './scheme';
3
+ /** A rest band on one layout axis: the range inside which a value feels no gravity. */
4
+ export interface Band {
5
+ min: number;
6
+ max: number;
7
+ }
8
+ /**
9
+ * How one value on the style axis is drawn, sized, and physically weighted,
10
+ * as a host declares it. Only the id, the label and the colour are required;
11
+ * the rest is derived from them and from the value's position in the
12
+ * declaration order (top of the hierarchy first):
13
+ *
14
+ * - `abbreviation`: the first two characters of the label.
15
+ * - `icon`: none.
16
+ * - `size.r`: 12; `size.iconSize`: nine tenths of the radius, rounded, at least 9.
17
+ * - `physics.charge`: −40 × r; `physics.coreRadius`: 4 × r.
18
+ * - `physics.band.y`: the value's slice of the stack, by position — the
19
+ * first value's band at the top of the canvas, the last at the bottom,
20
+ * neighbours overlapping a fifth; `physics.band.x`: 0 to 380.
21
+ * - `whenHidden`: `ascend`; `summaryKind`: `degree`.
22
+ *
23
+ * A field given overrides its default, field by field — a band's `x` may be
24
+ * declared and its `y` left to the stack.
25
+ */
26
+ export interface NodeStyle {
27
+ /** The value on the style axis this style is for. */
28
+ id: AxisValue;
29
+ /** Display name, e.g. "Service". */
30
+ label: string;
31
+ /**
32
+ * One or two characters for a control token: a control surface renders a
33
+ * token per value and has no room for a name.
34
+ */
35
+ abbreviation?: string;
36
+ /** Single glyph drawn inside the canvas node. */
37
+ icon?: string;
38
+ /** Fill and border in both themes; the canvas reads `color[theme]`. */
39
+ color: ThemedColor;
40
+ size?: {
41
+ /** Circle radius in world units. Hit-test radius = r + 4. */
42
+ r?: number;
43
+ /** Font size for the icon glyph (px). */
44
+ iconSize?: number;
45
+ };
46
+ physics?: {
47
+ /**
48
+ * Repulsion charge. Negative = repulsion. The starting point for the
49
+ * value the user tunes at runtime via the control panel.
50
+ */
51
+ charge?: number;
52
+ /**
53
+ * Core radius (charge softening, as a length). A pair of nodes softens
54
+ * its charge by the squared average of the two endpoints' effective core
55
+ * radii (`coreRadiusMultiplier × coreRadius`), added to d². Larger =
56
+ * gentler, wider plateau.
57
+ */
58
+ coreRadius?: number;
59
+ /**
60
+ * Rest bands, one per layout axis, inside which this value feels no
61
+ * gravity. `y` is the hierarchy (negative = top of canvas); `x` bounds
62
+ * the horizontal spread. The simulation seeds nodes inside their bands on
63
+ * creation, so the structure is visible before the first tick — which
64
+ * also makes this the seeding function, not only the gravity target.
65
+ */
66
+ band?: {
67
+ x?: Band;
68
+ y?: Band;
69
+ };
70
+ };
71
+ /**
72
+ * What a dependency edge touching a HIDDEN node of this value does:
73
+ * `ascend` re-points the endpoint to the node's nearest visible ancestor;
74
+ * `splice` follows the node's own dependency edges through to the far
75
+ * side, so caller → hidden → callee draws as caller → callee.
76
+ */
77
+ whenHidden?: 'ascend' | 'splice';
78
+ /**
79
+ * The glanceable summary for a node of this value: the children it contains,
80
+ * counted per style value and named by that value's abbreviation
81
+ * (`2 Sv · 1 Pd`); its dependency degree (`→3 ←2`); or nothing.
82
+ */
83
+ summaryKind?: 'children' | 'degree' | 'none';
84
+ }
85
+ /**
86
+ * A node style with every default filled in — what `Taxonomy.styleOf` answers.
87
+ *
88
+ * Reached through `Taxonomy.nodeStyleOf`, never by key lookup from the
89
+ * engine — a miss has to resolve to the fallback rather than throw, because
90
+ * the resolution happens per node per frame inside the draw loop where an
91
+ * exception stops the canvas repainting for good.
92
+ */
93
+ export interface ResolvedNodeStyle {
94
+ id: AxisValue;
95
+ label: string;
96
+ abbreviation: string;
97
+ /** Empty when the style declares none: nothing is drawn. */
98
+ icon: string;
99
+ color: ThemedColor;
100
+ size: {
101
+ r: number;
102
+ iconSize: number;
103
+ };
104
+ physics: {
105
+ charge: number;
106
+ coreRadius: number;
107
+ band: {
108
+ x: Band;
109
+ y: Band;
110
+ };
111
+ };
112
+ whenHidden: 'ascend' | 'splice';
113
+ summaryKind: 'children' | 'degree' | 'none';
114
+ }
115
+ /**
116
+ * Stable id for one edge type.
117
+ *
118
+ * A string, not a union, and that is the library's whole position on edge
119
+ * vocabulary: it is the override key in the spring tuning and the hover-link
120
+ * key across the spring map, curves, and canvas, so it has to be something a
121
+ * host can extend. A host narrows it to its own union.
122
+ */
123
+ export type EdgeTypeId = string;
124
+ /** One spring: stiffness (k) and rest length. */
125
+ export interface SpringPhysics {
126
+ strength: number;
127
+ distance: number;
128
+ }
129
+ /**
130
+ * One kind of edge, as a host declares it: which values it runs between and
131
+ * which relation it expresses, optionally which values the edge itself must
132
+ * carry (`match`), and — optionally — how it is stroked, its spring and its
133
+ * hover text. An edge is classified as the declared type of its relation
134
+ * that runs between its endpoints' values, in either orientation, and whose
135
+ * `match` (if any) its own values satisfy; a satisfied `match` beats a type
136
+ * without one, the declared orientation beats the reverse, and declaration
137
+ * order settles the rest — unless the taxonomy's `classifyEdge` says
138
+ * otherwise. A label left out is the id; a stroke left out is the neutral
139
+ * stroke (the containment stroke for a containment type), field by field; a
140
+ * spring left out is the middling spring; a tooltip left out is the label.
141
+ */
142
+ export interface EdgeType {
143
+ /** Stable id — also the override key in the spring tuning. */
144
+ id: EdgeTypeId;
145
+ /** Short control-panel label. Default: the id. */
146
+ label?: string;
147
+ /**
148
+ * The endpoint values on the style axis this type runs between — one
149
+ * value or several at each end: the type runs between every source value
150
+ * and every target value, in either orientation. Read off the edge's
151
+ * original endpoint nodes when an edge is classified; the first of each
152
+ * is the split-colour token's two halves. Values, not types: the engine
153
+ * resolves an edge's type from where its nodes sit.
154
+ */
155
+ sourceValue: AxisValue | readonly AxisValue[];
156
+ targetValue: AxisValue | readonly AxisValue[];
157
+ /** Which relation an edge of this type expresses; an edge is classified only as a type of its own relation. */
158
+ relation: 'containment' | 'dependency';
159
+ /**
160
+ * Values the edge itself must carry on the host's edge axes to be this
161
+ * type — how two types on one pair are told apart (a call and a signal
162
+ * between the same two values, by the edge's `dispatch`). An edge lacking
163
+ * one of these values is not this type. Absent, the pair alone decides,
164
+ * and this type is the fallback for a pair other types `match` on.
165
+ */
166
+ match?: Readonly<Record<AxisId, AxisValue>>;
167
+ /** Declared stiffness / rest length — what the type resolves to until tuned. */
168
+ physics?: SpringPhysics;
169
+ /** How the canvas strokes an edge of this type, in both themes; any field left out is its relation's default stroke's (`NEUTRAL_STROKE`, or `CONTAINMENT_STROKE` for a containment type). */
170
+ style?: Partial<EdgeStroke>;
171
+ /** The hover text for the type. Default: the label. */
172
+ tooltip?: string;
173
+ }
174
+ /** An edge type with its defaults filled in — what `Taxonomy.edgeTypes` carries. */
175
+ export interface ResolvedEdgeType extends EdgeType {
176
+ label: string;
177
+ /** The first declared source value — one half of the split-colour token. */
178
+ sourceValue: AxisValue;
179
+ /** The first declared target value — the other half. */
180
+ targetValue: AxisValue;
181
+ /** Every (source, target) pair the type runs between: each source value with each target value, in declaration order. */
182
+ pairs: readonly (readonly [AxisValue, AxisValue])[];
183
+ physics: SpringPhysics;
184
+ style: EdgeStroke;
185
+ tooltip: string;
186
+ }
187
+ /** The stroke a dependency type starts from, and the stroke of a dependency edge no type claims: a quiet, solid grey. */
188
+ export declare const NEUTRAL_STROKE: EdgeStroke;
189
+ /** The stroke a containment type starts from, and the stroke of a containment edge no type claims: the same grey, faint and dashed. */
190
+ export declare const CONTAINMENT_STROKE: EdgeStroke;
191
+ /** The values declared at one end of an edge type, as a list. */
192
+ export declare function endpointValues(declared: AxisValue | readonly AxisValue[]): readonly AxisValue[];
193
+ /** Every (source, target) pair a type runs between: each source value with each target value, in declaration order. */
194
+ export declare function edgePairs(type: Pick<EdgeType, 'sourceValue' | 'targetValue'>): readonly (readonly [AxisValue, AxisValue])[];
195
+ /**
196
+ * The frame the default rest bands are laid in, in world units: the
197
+ * hierarchy axis runs from `top` (the first declared value) to `bottom` (the
198
+ * last), and every value spreads across `x`. A host that declares a band of
199
+ * its own writes it in these units.
200
+ */
201
+ export declare const BAND_FRAME: {
202
+ readonly top: -300;
203
+ readonly bottom: 400;
204
+ readonly x: Band;
205
+ };
206
+ /** The spring a type starts from when it declares none. */
207
+ export declare const MIDDLING_SPRING: SpringPhysics;
208
+ /**
209
+ * The rest band on the hierarchy axis for the value at position `i` of `n`:
210
+ * centres spread evenly down the stack, each band wide enough to overlap its
211
+ * neighbours by a fifth, so the structure reads as tiers without a gap a node
212
+ * could never rest in. One value alone takes the whole stack.
213
+ */
214
+ export declare function stackBand(i: number, n: number): Band;
215
+ /**
216
+ * A declared style with every default filled in, given its position in the
217
+ * declaration order. Pure: the same inputs give the same object, so the
218
+ * taxonomy resolves each value once and hands out that one object.
219
+ */
220
+ export declare function resolveNodeStyle(style: NodeStyle, i: number, n: number): ResolvedNodeStyle;
221
+ /**
222
+ * A declared edge type with its defaults filled in: the id as label, the
223
+ * first declared value at each end beside every pair, the middling spring,
224
+ * its relation's stroke field by field, the label as tooltip. The taxonomy
225
+ * has refused an end that names no value before this runs.
226
+ */
227
+ export declare function resolveEdgeType(type: EdgeType): ResolvedEdgeType;
@@ -0,0 +1,207 @@
1
+ import { ReactNode } from 'react';
2
+ import { AxisDescriptor, AxisId, AxisValues, AxisValue, ResolvedAxisDescriptor } from './axis';
3
+ import { GraphEdge, GraphNode } from './model';
4
+ import { EdgeType, EdgeTypeId, NodeStyle, ResolvedEdgeType, ResolvedNodeStyle } from './shapes';
5
+ import { ResolvedScalarAxis, ScalarAxis } from './scalar';
6
+ import { EdgeStroke } from './scheme';
7
+ /** A highlight: the node ids lit and the edge ids lit. Edges absent means "every visible edge between lit nodes". */
8
+ export interface Highlight {
9
+ readonly nodes: ReadonlySet<string>;
10
+ readonly edges?: ReadonlySet<string>;
11
+ }
12
+ /** What a highlight rule may read: the visible graph, and a lookup for any node. */
13
+ export interface HighlightGraph {
14
+ readonly visibleNodes: readonly GraphNode[];
15
+ readonly visibleEdges: readonly GraphEdge[];
16
+ readonly visibleIds: ReadonlySet<string>;
17
+ getNode(id: string): GraphNode | undefined;
18
+ }
19
+ /** Which way a highlight walks from its node: what it depends on, or what depends on it. */
20
+ export type HighlightDirection = 'downstream' | 'upstream';
21
+ /** The minimum a consumer needs of a node in order to resolve its style. */
22
+ export type StyleSubject = {
23
+ values: AxisValues;
24
+ };
25
+ /** What the hover box shows under a node's name: one line, or several — text or a host's own elements. */
26
+ export type ContextLine = ReactNode | readonly ReactNode[];
27
+ /**
28
+ * The built taxonomy: what the view resolves every style, edge type, axis
29
+ * policy and host hook through. Built once by `createTaxonomy`; derive a
30
+ * variant from the spec, never by spreading this object.
31
+ *
32
+ * What a host reads: `filterAxes`, `axisFor` and `valueOn` to filter its own
33
+ * records the way the view does; `styleOf`, `styleValues` and `colorVar` for
34
+ * chrome of its own in the scheme's colours; `edgeTypes` for a legend;
35
+ * `searchText` to match as the view matches. The rest is the engine's
36
+ * interface — resolution for the draw loop — and a host has no call to read
37
+ * it.
38
+ */
39
+ export interface Taxonomy {
40
+ /**
41
+ * The axis this taxonomy resolves style on.
42
+ *
43
+ * One axis, named once. Every other feature elects its own — the physics reads
44
+ * its axis off the force params, filters read theirs off the filter — and no
45
+ * feature composes two.
46
+ *
47
+ * A method, not a field, and that is a correctness property rather than a
48
+ * style choice: a container derived by spreading (`{ ...taxonomy,
49
+ * styleAxis: 'other' }`) would rewrite a field and leave the closures
50
+ * answering on the old axis — an object that disagrees with itself, the
51
+ * draw loop reading one half and the physics the other. With one source
52
+ * there is nothing to override out of step.
53
+ */
54
+ styleAxis(): AxisId;
55
+ /** The style axis's display name, for a control that names axes. */
56
+ styleLabel(): string;
57
+ /**
58
+ * The axes a filter may operate on, with their per-axis policies,
59
+ * every default filled in. Host-declared, like the entries: which axes
60
+ * exist is a domain fact. The engine reads only the policies and never
61
+ * enumerates the ids.
62
+ */
63
+ readonly filterAxes: readonly ResolvedAxisDescriptor[];
64
+ /** One axis's policies, or undefined if the host does not declare it. */
65
+ axisFor(axis: AxisId): ResolvedAxisDescriptor | undefined;
66
+ /**
67
+ * The value a subject presents on one axis — read off its values, for
68
+ * every axis alike. An axis that is a projection of another is materialized
69
+ * by the host when it builds the node, so nothing here knows which axes are
70
+ * derived.
71
+ */
72
+ valueOn(subject: StyleSubject, axis: AxisId): AxisValue | undefined;
73
+ /** Every style value, in declaration order (top of the hierarchy first). */
74
+ readonly styleValues: readonly AxisValue[];
75
+ /** Every edge type, in control-panel order, its defaults filled in. */
76
+ readonly edgeTypes: readonly ResolvedEdgeType[];
77
+ /** Every computed scalar a layout axis may key on, its words filled in: the built-ins, then the host's. */
78
+ readonly scalars: readonly ResolvedScalarAxis[];
79
+ /** How the canvas strokes an edge of this type; the neutral stroke, said once, for an id the taxonomy does not declare. */
80
+ edgeStrokeFor(id: EdgeTypeId): EdgeStroke;
81
+ /**
82
+ * The custom property a value's fill is published under (`-border` for its
83
+ * border): `--gv-node-` and the value id in kebab case, or a numbered name
84
+ * when the id kebab-cases to nothing or to another value's name. The one
85
+ * way to learn the name; a host's CSS reads it through `schemeVars` or
86
+ * `schemeStylesheet`.
87
+ */
88
+ colorVar(value: AxisValue): string;
89
+ /** The hover box's context line(s) for a node — the host's, or its parent's name. */
90
+ contextLine(node: GraphNode, parent: GraphNode | undefined): ContextLine;
91
+ /** What the search control matches against for a node — the host's text, or the name. */
92
+ searchText(node: GraphNode): string;
93
+ /** The highlight for an active node — the host's refinement of the library's transitive walk in the given direction. */
94
+ highlight(active: GraphNode, base: Highlight, graph: HighlightGraph, direction: HighlightDirection): Highlight;
95
+ /**
96
+ * Style, size, physics and summary metadata for a value. Never throws — a
97
+ * value the taxonomy does not declare, and an ABSENT value, both resolve to
98
+ * the fallback.
99
+ */
100
+ styleOf(value: AxisValue | undefined): ResolvedNodeStyle;
101
+ /** Where a node sits on the style axis, or undefined if it sits nowhere. */
102
+ styleValueOf(subject: StyleSubject): AxisValue | undefined;
103
+ /**
104
+ * Short label for a value — one or two characters. Control surfaces render a
105
+ * token per value and have no room for a full name. A value the taxonomy
106
+ * does not declare abbreviates to its own first two characters.
107
+ */
108
+ abbreviationFor(value: AxisValue): string;
109
+ /** The same as `styleOf`, addressed by a node. The hot-path entry point. */
110
+ nodeStyleOf(subject: StyleSubject): ResolvedNodeStyle;
111
+ /**
112
+ * Which declared edge type an edge is, given the style values of its two
113
+ * ORIGINAL endpoints: the declared type of the edge's relation that runs
114
+ * between those values in either orientation and whose `match` the edge's
115
+ * own values satisfy (a satisfied `match` over none, the declared
116
+ * orientation over the reverse, then declaration order), handed to the
117
+ * spec's `classifyEdge`, which may keep it, replace it, or supply one where
118
+ * there is none; undefined when neither names one. Classified once, on
119
+ * the original endpoints; the type is carried through graduation, so a
120
+ * re-pointed edge keeps its stroke and its spring.
121
+ */
122
+ edgeTypeOf(edge: GraphEdge, src: AxisValue | undefined, tgt: AxisValue | undefined): EdgeTypeId | undefined;
123
+ /** Which of two graduated edges on one visible pair survives: the host's choice, or the one kept so far. */
124
+ collapse(kept: GraphEdge, candidate: GraphEdge): GraphEdge;
125
+ }
126
+ /**
127
+ * What a host declares in order to build an `Taxonomy`: the style axis and
128
+ * its values, the edge types and the rule that classifies an edge, the filter
129
+ * axes. Everything with a sensible default is optional.
130
+ */
131
+ export interface TaxonomySpec {
132
+ /** The axis every node's style is read on. */
133
+ styleAxis: AxisId;
134
+ /** The style axis's display name. Absent, the axis id. */
135
+ styleLabel?: string;
136
+ /**
137
+ * The style values, top of the hierarchy first. The order places each
138
+ * value's rest band down the stack when it declares none, and orders the
139
+ * control surfaces and the hover box's child counts.
140
+ */
141
+ styles: readonly NodeStyle[];
142
+ /**
143
+ * Drawn for a value the taxonomy does not declare, and for a node with no
144
+ * value on the style axis. Absent, a grey disc with a question mark that
145
+ * rests anywhere in the stack.
146
+ */
147
+ fallbackStyle?: Omit<NodeStyle, 'id'>;
148
+ /** The edge types, in control-panel order. Absent, none: every edge draws untyped in its relation's stroke, and `validateGraph` says so. */
149
+ edgeTypes?: readonly EdgeType[];
150
+ /**
151
+ * The host's say in classifying an edge, given the style values of its
152
+ * original endpoints and `declared` — the type the declarations answer (by
153
+ * relation, endpoint pair, `match` and orientation), or undefined: an id
154
+ * to use, or undefined to keep the declared answer. For the exceptions the
155
+ * declarations cannot express — a type that also runs between pairs it
156
+ * does not declare, say: `(edge, src, tgt, declared) => declared ?? …`.
157
+ * Required only when two declared types on one pair share an orientation
158
+ * and a `match`.
159
+ */
160
+ classifyEdge?: (edge: GraphEdge, src: AxisValue | undefined, tgt: AxisValue | undefined, declared: EdgeTypeId | undefined) => EdgeTypeId | undefined;
161
+ /** The axes the filter bar offers. Absent, the style axis alone, as an allow-list. */
162
+ filterAxes?: readonly AxisDescriptor[];
163
+ /**
164
+ * Computed scalars this host adds to the built-ins: each reads node
165
+ * metadata — its own payload included — and the graph's structure, and
166
+ * answers a number per node, which the frame maps onto [0, 1] the way the
167
+ * scalar's `normalize` says. Absent, the built-ins alone.
168
+ */
169
+ scalars?: readonly ScalarAxis[];
170
+ /**
171
+ * The hover box's context under the name: what a host wants said there —
172
+ * addressing metadata from its own payload, a parent by another name, an
173
+ * origin — as one line or several. Absent, the line is the parent's name.
174
+ */
175
+ contextLine?: (node: GraphNode, parent: GraphNode | undefined) => ContextLine;
176
+ /**
177
+ * What the search control matches a node on, case-insensitively: a code
178
+ * from the payload beside the name, say. Absent, the name.
179
+ */
180
+ searchText?: (node: GraphNode) => string;
181
+ /**
182
+ * The highlight for an active node: given the library's transitive walk
183
+ * from it in `direction`, the host may widen it (members it relates by
184
+ * metadata) or replace it. Absent, the walk is the highlight.
185
+ */
186
+ highlight?: (active: GraphNode, base: Highlight, graph: HighlightGraph, direction: HighlightDirection) => Highlight;
187
+ /**
188
+ * When two dependency edges each lose an end to a hidden node and come to
189
+ * run between the same two visible nodes, which of the two originals the
190
+ * drawn edge stands for. Both arguments are the host's own edges, so
191
+ * a host whose edges carry routing metadata may prefer the one that does.
192
+ * Absent, the one met first in the host's edge order is kept. Two edges
193
+ * whose ends are both visible are never collapsed.
194
+ */
195
+ collapse?: (kept: GraphEdge, candidate: GraphEdge) => GraphEdge;
196
+ }
197
+ /**
198
+ * Build the container, refusing an incoherent spec: a value declared twice, an
199
+ * edge type declared twice, running between values nobody declared or naming
200
+ * no value at an end, a filter axis declared twice, a colour no reader can
201
+ * parse, a band whose ends cross, a policy outside its vocabulary, a scalar
202
+ * id already taken. Every problem is named at once, by its path in the spec.
203
+ * To derive a variant, build one from a spec (`createTaxonomy({ ...spec, … })`);
204
+ * spreading the built object copies closures that still read the original's
205
+ * fields.
206
+ */
207
+ export declare function createTaxonomy(spec: TaxonomySpec): Taxonomy;
@@ -0,0 +1,47 @@
1
+ import { Graph } from './model';
2
+ import { Taxonomy } from './taxonomy';
3
+ /**
4
+ * The defects `validateGraph` names. Errors: a node or edge id used twice,
5
+ * an edge whose endpoint is not in the graph, an unknown relation, a type
6
+ * whose relation is not the edge's, a rule that threw, a parent not in the
7
+ * graph. Warnings: an edge no type claims, a style value the taxonomy does
8
+ * not declare, containment edges that contradict `parentId`, derived
9
+ * containment edges no type claims (`containment-untyped`, from
10
+ * `derivedContainmentDiagnostics`).
11
+ */
12
+ export type GraphDiagnosticCode = 'edge-id-duplicate' | 'edge-endpoint-missing' | 'edge-relation-unknown' | 'edge-type-rule-threw' | 'edge-type-unclassified' | 'edge-type-relation-mismatch' | 'parent-missing' | 'containment-parent-mismatch' | 'node-value-undeclared' | 'node-id-duplicate' | 'containment-untyped';
13
+ /** One defect in a host's graph, as data: its severity, its code, a message, and the node or edge it names. */
14
+ export interface GraphDiagnostic {
15
+ /** An error names something the view cannot draw as given; a warning, something it draws but the host should know. */
16
+ severity: 'error' | 'warning';
17
+ code: GraphDiagnosticCode;
18
+ message: string;
19
+ nodeId?: string;
20
+ edgeId?: string;
21
+ }
22
+ /**
23
+ * Every defect in a host's graph, as data: errors for what the view cannot
24
+ * draw as given (a duplicated node id, a dangling endpoint, an unknown
25
+ * relation, a type whose relation is not the edge's, a parent not in the
26
+ * graph) and warnings for what it draws but the host should know (an
27
+ * unclassified edge, an undeclared style value, containment edges that
28
+ * contradict `parentId`). Pure; the same graph and taxonomy give the same
29
+ * list, in graph order.
30
+ */
31
+ export declare function validateGraph(graph: Graph, taxonomy: Taxonomy): GraphDiagnostic[];
32
+ /**
33
+ * The graph with every node and edge an error names removed and every parent
34
+ * an error names cleared — what the view draws when the host's graph has
35
+ * defects. A duplicated id keeps its first node and its first edge. The
36
+ * host's objects are not mutated; a graph with no errors is returned as is.
37
+ */
38
+ export declare function dropInvalid(graph: Graph, diagnostics: readonly GraphDiagnostic[]): Graph;
39
+ /**
40
+ * The one warning the drawn graph adds to the host's: the containment edges
41
+ * the view derived from `parentId` that no declared containment type claims
42
+ * (a dependency type the host's rule answers does not count). They draw in
43
+ * the containment stroke and pull nothing while push and pull key on the
44
+ * style axis; a host that wants them typed declares a containment type
45
+ * between the child's value and the parent's.
46
+ */
47
+ export declare function derivedContainmentDiagnostics(drawn: Graph, host: Graph, taxonomy: Taxonomy): GraphDiagnostic[];
@@ -0,0 +1,35 @@
1
+ export { FilterBar } from './components/FilterBar';
2
+ export type { FilterBarChrome, FilterBarProps } from './components/FilterBar';
3
+ export { GraphView } from './components/GraphView';
4
+ export type { GraphViewChrome, GraphViewHandle, GraphViewProps, GroupsControl, NodeAction, Position, SearchState } from './components/GraphView';
5
+ export { GroupLegend } from './components/GroupLegend';
6
+ export type { GroupLegendProps } from './components/GroupLegend';
7
+ export { useLinkedViews } from './components/graph-view/useLinkedViews';
8
+ export type { LinkedViewProps, LinkedViewState, LinkedViews, LinkedViewsOptions } from './components/graph-view/useLinkedViews';
9
+ export type { FocusRequest } from './components/graph-view/focus';
10
+ export { useFocusRequest } from './components/graph-view/useFocusRequest';
11
+ export type { RecentlyChanged } from './components/graph-view/useRecentlyChanged';
12
+ export { TaxonomyContext, useTaxonomy } from './components/graph-view/useTaxonomy';
13
+ export { themeChoiceOf, useHostTheme } from './components/graph-view/useTheme';
14
+ export type { ThemeChoice } from './components/graph-view/useTheme';
15
+ export { reconcileFilter } from './filter/reconcile';
16
+ export type { ReconcileInput } from './filter/reconcile';
17
+ export { toggleGroup, toggleValue } from './filter/toggle';
18
+ export { initialFilter, filterFromJSON, filterStatesEqual, filterToJSON, hiddenMatchesOf, locksFromJSON, locksToJSON, matchesFocus, passesSelection, reseedFilter, lockedFor, selectionFor, withLock, withSelection } from './filter/types';
19
+ export type { FilterState, FocusTarget, HiddenMatches, HiddenMatchesInput, AxisLocks, PassesSelectionInput, ReconcileResult, AxisSelection, ViewTransition } from './filter/types';
20
+ export { countsOn, valuesOn } from './graph/axis';
21
+ export type { AxisDescriptor, AxisId, AxisNamer, AxisValues, AxisValue, FilterChip, Relation, ResolvedAxisDescriptor } from './graph/axis';
22
+ export type { ActiveGroup, NodeGroup } from './graph/groups';
23
+ export { copyGroups, isContainment, nodesById, payloadNumber, payloadString } from './graph/model';
24
+ export type { Graph, GraphEdge, GraphNode, ReadableGraph } from './graph/model';
25
+ export { createTaxonomy } from './graph/taxonomy';
26
+ export type { ContextLine, Highlight, HighlightDirection, HighlightGraph, StyleSubject, Taxonomy, TaxonomySpec } from './graph/taxonomy';
27
+ export { schemeStylesheet, schemeVars } from './graph/scheme';
28
+ export type { ColorPair, EdgeStroke, Theme, ThemedColor } from './graph/scheme';
29
+ export type { ResolvedScalarAxis, ScalarAxis } from './graph/scalar';
30
+ export { layoutFromJSON, layoutToJSON } from './graph/layout';
31
+ export type { LayoutJSON, LayoutState, LayoutTuningJSON } from './graph/layout';
32
+ export { validateGraph } from './graph/validate';
33
+ export type { GraphDiagnostic, GraphDiagnosticCode } from './graph/validate';
34
+ export { BAND_FRAME, CONTAINMENT_STROKE, NEUTRAL_STROKE } from './graph/shapes';
35
+ export type { Band, EdgeType, EdgeTypeId, NodeStyle, ResolvedEdgeType, ResolvedNodeStyle, SpringPhysics } from './graph/shapes';