Read-only pan and zoom graph canvas for typed, positioned graph documents.
Install @wyrd-company/react or the Flutter package and use it directly —
your DESIGN.md does the styling.
catalog/contracts/graph-viewer.ymlsource of truth · verbatim
$schema: https://thewyrdingway.dev/schemas/component-contract.schema.ymlcontractVersion: 0.1.0identity:name: GraphViewertag: wyrd-graph-viewerpackage: wyrd.component.graph-viewertitle: Graph Viewersummary: Read-only pan and zoom graph canvas for typed, positioned graph documents.relationships:related-to: - graph-components - canvas-flutter-viewerclassification:category: canvascomposition: collectioninteractive: truetarget-strategy:react: requiredflutter: requiredsurface:properties: []slots: - name: rendererkeyed: truekey-domain: node-typerequired: truecardinality: exactly-oneaccepts: - componentsummary: One renderer per node-type key; unknown keys fall back to a built-in generic node.events: - name: node-selectpayload:node-id:kind: stringbubbles: truecomposed: truecancelable: falsesummary: Emitted when the selected node changes. - name: node-activatepayload:node-id:kind: stringbubbles: truecomposed: truecancelable: falsesummary: Emitted when the host should drill into or expand a node.states: - name: defaultsource: platformsummary: Graph is visible and pannable. - name: selectedsource: propertysummary: One node is selected.parts: - name: fieldsummary: Pannable graph field. - name: nodesummary: Repeated rendered node. - name: edgesummary: Drawn graph edge. - name: edge-labelsummary: Optional edge label pill.tokens:field:background: color.backgroundpadding: 240pxgrid:color: color.disabledstroke-width: 1pxstep: 80pxedge:color: color.on-surface-variantstroke-width: 1.6pxarrow-radius: 3.5pxedge-label:background: color.surfaceforeground: color.on-surfacetext: typography.label-mdpadding-x: spacing.xspadding-y: spacing.xsradius: rounded.fullmax-width: 240pxnode:background: color.surfaceforeground: color.on-surfacemuted-foreground: color.on-surface-variantselected-background: color.secondaryborder-color: color.outlineselected-border-color: color.primaryborder-width: 1pxselected-border-width: 2pxshadow: shadow.mdradius: rounded.mdpadding: spacing.mdvertical-gap: spacing.smcompound-state:width: 214pxmin-height: 84pxtitle-text: typography.label-mdbody-text: typography.body-mdstate:width: 184pxmin-height: 72pxtitle-text: typography.label-mdbody-text: typography.body-mdevent:width: 150pxmin-height: 60pxtitle-text: typography.label-mdbody-text: typography.body-mdmessages: []obligations:accessibility:role: applicationname: Host-provided accessible graph label.keyboard: []semantics: - Exposes mounted interactive nodes as tappable/selectable elements. - Preserves read-only graph semantics; structural editing is not available.behavior:model: statelessinteractions: - Pan and zoom move the viewport without mutating the graph document. - Tap selects a node. - Compound nodes activate on tap. - Leaf nodes with an activation affordance activate on double tap.hostEffects: - Dispatch node-select. - Dispatch node-activate.conditions: - rtl - density-compact - text-expansionsdui:status: blockedserializableProperties: []serializableSlots: []eventBindings: []notes: Graph documents are serializable through the graph contract; renderer registries are modeled as keyed component slots and are not serializable as SDUI data.examples: - name: menu-statechartstate: defaultproperties:graph:nodes: - id: menu.closedtype: stateposition:x: 40y: 60data:label: closeddescription: Initial leaf. OPEN enters open. - id: event.opentype: eventposition:x: 300y: 20interactive: falsedata:label: OPENdescription: "guard: disabled == false" - id: event.closetype: eventposition:x: 300y: 160interactive: falsedata:label: CLOSE / ESCAPEdescription: Dismissal returns closed. - id: menu.opentype: stateposition:x: 520y: 60data:label: opendescription: CLOSE and ESCAPE return closed.edges: - id: menu.closed:outgoing->event.open:incomingtype: transitionfrom:node: menu.closedport: outgoingto:node: event.openport: incomingdata:label: OPEN - id: event.open:outgoing->menu.open:incomingtype: transitionfrom:node: event.openport: outgoingto:node: menu.openport: incoming - id: menu.open:outgoing->event.close:incomingtype: transitionfrom:node: menu.openport: outgoingto:node: event.closeport: incomingdata:label: CLOSE - id: event.close:outgoing->menu.closed:incomingtype: transitionfrom:node: event.closeport: outgoingto:node: menu.closedport: incomingnode-types: - type: statelabel: Behavior statesize:width: 184minHeight: 72ports: - name: incominglabel: Incoming transitionsdirection: inputside: left - name: outgoinglabel: Outgoing transitionsdirection: outputside: right - type: eventlabel: Transition eventsize:width: 150minHeight: 60ports: - name: incominglabel: Incoming transitionsdirection: inputside: left - name: outgoinglabel: Outgoing transitionsdirection: outputside: rightslots:renderer: state | event
01
Examples
Generated from the contract's examples block.
Previews are the published @wyrd-company/react component, themed by the
brand's role tokens — flip the site's light/dark toggle and they follow.
menu-statechartstate: default
Usage
React example unavailableThe generated documentation data does not publish verified React source for this example.
Flutter example unavailableThe generated documentation data does not publish verified Flutter source for this example.
One renderer per node-type key; unknown keys fall back to a built-in generic node.
Event
Payload
Summary
node-select
node-id
Emitted when the selected node changes.
node-activate
node-id
Emitted when the host should drill into or expand a node.
03
Tokens
The contract's token bindings. Open the shared contextual sidebar from any example;
primary swatches reflect the color you pick there. Error swatches show the active
preset's values; editing any knob switches to custom and resets error to TWW · Ink.
Binding
Token
field.background
color.background
field.padding
240px
grid.color
color.disabled
grid.stroke-width
1px
grid.step
80px
edge.color
color.on-surface-variant
edge.stroke-width
1.6px
edge.arrow-radius
3.5px
edge-label.background
color.surface
edge-label.foreground
color.on-surface
edge-label.text
typography.label-md
edge-label.padding-x
spacing.xs
edge-label.padding-y
spacing.xs
edge-label.radius
rounded.full
edge-label.max-width
240px
node.background
color.surface
node.foreground
color.on-surface
node.muted-foreground
color.on-surface-variant
node.selected-background
color.secondary
node.border-color
color.outline
node.selected-border-color
color.primary
node.border-width
1px
node.selected-border-width
2px
node.shadow
shadow.md
node.radius
rounded.md
node.padding
spacing.md
node.vertical-gap
spacing.sm
compound-state.width
214px
compound-state.min-height
84px
compound-state.title-text
typography.label-md
compound-state.body-text
typography.body-md
state.width
184px
state.min-height
72px
state.title-text
typography.label-md
state.body-text
typography.body-md
event.width
150px
event.min-height
60px
event.title-text
typography.label-md
event.body-text
typography.body-md
04
States
State
Source
Summary
default
platform
Graph is visible and pannable.
selected
property
One node is selected.
05
Accessibility
From the contract's accessibility obligations. Role application; Host-provided accessible graph label.
Exposes mounted interactive nodes as tappable/selectable elements.
Preserves read-only graph semantics; structural editing is not available.
Status: blocked. Graph documents are serializable through the graph contract; renderer registries are modeled as keyed component slots and are not serializable as SDUI data.