# @grafloria/qwik

Qwik bindings for Grafloria Diagrams and Grafloria Dashboards — an MIT diagram and dashboard engine: routing, auto-layout, undo, collaboration and dashboard layouts, server-rendered and resumable in Qwik.

## Install

```bash
npm install @grafloria/qwik @grafloria/engine @grafloria/renderer @builder.io/qwik @grafloria/element
```

It expects these alongside it:

- `@grafloria/engine` ^0.3.0
- `@grafloria/renderer` ^0.4.18
- `@builder.io/qwik` ^1.5.0
- `@grafloria/element` ^0.4.3

## Functions

### `useGrafloria`

The live `DiagramInstance` signal. Falls back to a component-local signal
when there is no `<GrafloriaProvider>` above, so the hook is always safe to
call — it simply never fills in without a provider or a sibling flow.

```ts
function useGrafloria(): GrafloriaStore
```

### `useOnSelectionChangeQrl`

Fire a QRL on every selection change; teardown is automatic.

The handler is a QRL rather than a plain function because Qwik has to be
able to serialize the subscription and load the handler lazily — that is
the whole point of the `$` suffix, and it is why this reads
`useOnSelectionChange$(...)` at the call site.

```ts
function useOnSelectionChangeQrl(handler: QRL<(change: SelectionChange) => void>): void
```

### `useSelection`

The current selection as reactive state (for an inspector panel).

```ts
function useSelection(): Signal<SelectionChange>
```

### `useViewport`

The live camera (zoom + world origin) as reactive state.

```ts
function useViewport(): Signal<{ zoom: number; x: number; y: number }>
```

## Constants

### `GRAFLORIA_STORE`

```ts
const GRAFLORIA_STORE: any
```

### `GrafloriaCommentPanel`

```ts
const GrafloriaCommentPanel: any
```

**Props**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `store` | `NoSerialize<CommentStore>` |  | The live comment store. Must be `noSerialize()`d. |
| `options?` | `CommentPanelOptions` |  |  |
| `onSelect$?` | `QRL<(threadId: string) => void>` |  |  |
| `class?` | `string` |  |  |

**Events**

- `onSelect$`

### `GrafloriaDashboard`

```ts
const GrafloriaDashboard: any
```

**Props**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `views?` | `DashboardViewSpec[]` |  |  |
| `widgets?` | `DashboardWidgetSpec[]` |  |  |
| `options?` | `Partial<DashboardOptions>` |  |  |
| `activeView?` | `string` |  | The visible view. |
| `layout?` | `"split" \| "grid"` |  | LIVE SWITCHES — the toolbar toggles as props: applied at mount (over |
| `sizing?` | `"fit" \| "grow"` |  |  |
| `static?` | `boolean` |  | Static board: the viewer's mode — no drag, no resize, no handles. |
| `widgetTypes?` | `WidgetTypes` |  | Qwik components for widget kinds, keyed by `kind`. |
| `onReady$?` | `QRL<(handle: DashboardHandle) => void>` |  |  |
| `onLayoutChange$?` | `QRL<(change: { viewId: string; widgets: DashboardWidgetSpec[]; }) => void>` |  |  |
| `class?` | `string` |  |  |
| `style?` | `Record<string, string \| number>` |  |  |

**Events**

- `onReady$`
- `onLayoutChange$`

### `GrafloriaDiagram`

```ts
const GrafloriaDiagram: any
```

**Props**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `spec` | `RenderSpec` |  | Any kit spec — erDiagram(...), umlDiagram(...), dashboard(...), or DSL text. |
| `options?` | `RenderOptions` |  |  |
| `onReady$?` | `QRL<(instance: DiagramInstance) => void>` |  | Fires once the kit has rendered, with the live instance. |
| `class?` | `string` |  |  |
| `style?` | `Record<string, string \| number>` |  |  |

**Events**

- `onReady$` — Fires once the kit has rendered, with the live instance.

### `GrafloriaFlow`

```ts
const GrafloriaFlow: any
```

**Props**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `nodes?` | `NodeSpec[]` |  |  |
| `edges?` | `EdgeSpec[]` |  |  |
| `groups?` | `(GroupModel \| GroupSpec)[]` |  | Controlled groups — zones around some nodes (a spec's `groups`, or the live |
| `defaultNodes?` | `NodeSpec[]` |  |  |
| `defaultEdges?` | `EdgeSpec[]` |  |  |
| `defaultGroups?` | `(GroupModel \| GroupSpec)[]` |  |  |
| `onInit$?` | `QRL<(instance: DiagramInstance) => void>` |  |  |
| `onNodesChange$?` | `QRL<(nodes: NodeSpec[]) => void>` |  |  |
| `onEdgesChange$?` | `QRL<(edges: EdgeSpec[]) => void>` |  |  |
| `onSelectionChange$?` | `QRL<(change: SelectionChange) => void>` |  |  |
| `onConnect$?` | `QRL<(change: { link: LinkModel; }) => void>` |  |  |
| `onNodeClick$?` | `QRL<(change: { node: NodeModel; world: { x: number; y: number; }; }) => void>` |  |  |
| `onEdgeClick$?` | `QRL<(change: { edge: LinkModel; world: { x: number; y: number; }; }) => void>` |  |  |
| `onLayoutDone$?` | `QRL<(result: unknown) => void>` |  |  |
| `onCollabReady$?` | `QRL<(session: SyncAdapter) => void>` |  |  |
| `nodeTypes?` | `NodeTypes` |  | Custom node components, keyed by node `type`. |
| `theme?` | `Theme` |  |  |
| `fitView?` | `boolean` |  |  |
| `enablePan?` | `boolean` |  |  |
| `enableZoom?` | `boolean` |  |  |
| `zoomSensitivity?` | `number` |  |  |
| `dragThreshold?` | `number` |  |  |
| `readonly?` | `boolean` |  |  |
| `minZoom?` | `number` |  |  |
| `maxZoom?` | `number` |  |  |
| `ssr?` | `{ html: string; snapshot: HydrationSnapshot; }` |  | The `renderToStaticSVG()` result. Renders server-side; the visible task |
| `layout?` | `string \| GrafloriaLayoutRequest` |  | Declarative auto-layout — any engine registry name ('elk', 'dagre', |
| `plugins?` | `boolean \| CanvasPluginOptions` |  | Canvas plugins — `true` mounts minimap + zoom/fit controls + background |
| `collab?` | `NoSerialize<GrafloriaCollabOptions>` |  | Real-time collaboration: a transport + actor id. The flow joins a CRDT |
| `comments?` | `any` |  | Anchored comment threads — `true` creates a store, or pass a shared |
| `commentsViewer?` | `string` |  | Viewer id for a `comments: true`-created store. |
| `rendererConfig?` | `Record<string, unknown>` |  | Renderer config passthrough (parallelLinks, parallelSpacing, jump styles, …). |
| `interaction?` | `Record<string, unknown>` |  | Interaction config passthrough (portVisibility, enableHelperLines, …). |
| `tokenBridge?` | `unknown` |  | Design-token bridge — adopt the app's shadcn / MUI / Tailwind CSS variables. |
| `highlighterConfig?` | `boolean \| Partial<HighlighterConfig>` |  | The outline layer: outlines around the hovered node, the selected node, |
| `highlightConnected?` | `boolean \| HighlightConnectedOptions` |  | Bring the selected nodes' lines forward and fade the rest: `true`, or |
| `class?` | `string` |  |  |
| `style?` | `Record<string, string \| number>` |  |  |

**Events**

- `onInit$`
- `onNodesChange$`
- `onEdgesChange$`
- `onSelectionChange$`
- `onConnect$`
- `onNodeClick$`
- `onEdgeClick$`
- `onLayoutDone$`
- `onCollabReady$`

### `GrafloriaProvider`

Makes the nearest `<GrafloriaFlow>`'s instance reachable by SIBLINGS —
toolbars, inspectors, minimaps — through the hooks below.

```ts
const GrafloriaProvider: any
```

### `useOnSelectionChange$`

```ts
const useOnSelectionChange$: any
```

## Interfaces

### `GrafloriaCollabOptions`

The uniform collab contract every Grafloria wrapper shares.

```ts
interface GrafloriaCollabOptions
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `transport` | `SyncTransport` |  | The transport (BroadcastChannelTransport, WebSocketTransport, …). |
| `actor` | `string` |  |  |
| `presence?` | `boolean \| BindPresenceOptions` |  | Live cursors + remote selection outlines. `true` for defaults. |

### `GrafloriaCommentPanelProps`

```ts
interface GrafloriaCommentPanelProps
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `store` | `NoSerialize<CommentStore>` |  | The live comment store. Must be `noSerialize()`d. |
| `options?` | `CommentPanelOptions` |  |  |
| `onSelect$?` | `QRL<(threadId: string \| null) => void>` |  |  |
| `class?` | `string` |  |  |

### `GrafloriaDashboardProps`

```ts
interface GrafloriaDashboardProps
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `views?` | `DashboardViewSpec[]` |  |  |
| `widgets?` | `DashboardWidgetSpec[]` |  |  |
| `options?` | `Partial<DashboardOptions>` |  |  |
| `activeView?` | `string` |  | The visible view. |
| `layout?` | `'grid' \| 'split'` |  | LIVE SWITCHES — the toolbar toggles as props: applied at mount (over `options`) and, when they change, through the handle (`setLayout` / `setSizing` / `setStatic`), never by remounting. 'split' is the splitter tree; 'grid' the cell grid. |
| `sizing?` | `'fit' \| 'grow'` |  |  |
| `static?` | `boolean` |  | Static board: the viewer's mode — no drag, no resize, no handles. |
| `widgetTypes?` | `WidgetTypes` |  | Qwik components for widget kinds, keyed by `kind`. |
| `onReady$?` | `QRL<(handle: DashboardHandle) => void>` |  |  |
| `onLayoutChange$?` | `QRL< (change: { viewId: string; widgets: DashboardWidgetSpec[] }) => void >` |  |  |
| `class?` | `string` |  |  |
| `style?` | `Record<string, string \| number>` |  |  |

### `GrafloriaDiagramProps`

```ts
interface GrafloriaDiagramProps
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `spec` | `RenderSpec` |  | Any kit spec — erDiagram(...), umlDiagram(...), dashboard(...), or DSL text. |
| `options?` | `RenderOptions` |  |  |
| `onReady$?` | `QRL<(instance: DiagramInstance) => void>` |  | Fires once the kit has rendered, with the live instance. |
| `class?` | `string` |  |  |
| `style?` | `Record<string, string \| number>` |  |  |

### `GrafloriaFlowProps`

```ts
interface GrafloriaFlowProps
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `nodes?` | `NodeSpec[]` |  |  |
| `edges?` | `EdgeSpec[]` |  |  |
| `groups?` | `Array<GroupSpec \| GroupModel>` |  | Controlled groups — zones around some nodes (a spec's `groups`, or the live GroupModels of a loaded document). Reconciled like `nodes`. |
| `defaultNodes?` | `NodeSpec[]` |  |  |
| `defaultEdges?` | `EdgeSpec[]` |  |  |
| `defaultGroups?` | `Array<GroupSpec \| GroupModel>` |  |  |
| `onInit$?` | `QRL<(instance: DiagramInstance) => void>` |  |  |
| `onNodesChange$?` | `QRL<(nodes: NodeSpec[]) => void>` |  |  |
| `onEdgesChange$?` | `QRL<(edges: EdgeSpec[]) => void>` |  |  |
| `onSelectionChange$?` | `QRL<(change: SelectionChange) => void>` |  |  |
| `onConnect$?` | `QRL<(change: { link: LinkModel }) => void>` |  |  |
| `onNodeClick$?` | `QRL<(change: { node: NodeModel; world: { x: number; y: number } }) => void>` |  |  |
| `onEdgeClick$?` | `QRL<(change: { edge: LinkModel; world: { x: number; y: number } }) => void>` |  |  |
| `onLayoutDone$?` | `QRL<(result: unknown) => void>` |  |  |
| `onCollabReady$?` | `QRL<(session: SyncAdapter) => void>` |  |  |
| `nodeTypes?` | `NodeTypes` |  | Custom node components, keyed by node `type`. |
| `theme?` | `Theme` |  |  |
| `fitView?` | `boolean` |  |  |
| `enablePan?` | `boolean` |  |  |
| `enableZoom?` | `boolean` |  |  |
| `zoomSensitivity?` | `number` |  |  |
| `dragThreshold?` | `number` |  |  |
| `readonly?` | `boolean` |  |  |
| `minZoom?` | `number` |  |  |
| `maxZoom?` | `number` |  |  |
| `ssr?` | `{ html: string; snapshot: HydrationSnapshot }` |  | The `renderToStaticSVG()` result. Renders server-side; the visible task adopts the markup instead of rebuilding it, so there is no flash and no re-layout. Put `ssr.css` in your document head. |
| `layout?` | `string \| GrafloriaLayoutRequest` |  | Declarative auto-layout — any engine registry name ('elk', 'dagre', 'force', 'tree', 'grid', 'auto', …) or `{ name, options }`. Re-runs when the prop VALUE changes, never when node data changes. |
| `plugins?` | `boolean \| CanvasPluginOptions` |  | Canvas plugins — `true` mounts minimap + zoom/fit controls + background grid with defaults; an object picks and configures them. |
| `collab?` | `NoSerialize<GrafloriaCollabOptions>` |  | Real-time collaboration: a transport + actor id. The flow joins a CRDT sync session on mount and leaves on unmount. Fixed for the life of the instance. `collab.transport` must be `noSerialize()`d. |
| `comments?` | `boolean \| NoSerialize<CommentStore>` |  | Anchored comment threads — `true` creates a store, or pass a shared `CommentStore` (which must be `noSerialize()`d). |
| `commentsViewer?` | `string` |  | Viewer id for a `comments: true`-created store. |
| `rendererConfig?` | `Record<string, unknown>` |  | Renderer config passthrough (parallelLinks, parallelSpacing, jump styles, …). |
| `interaction?` | `Record<string, unknown>` |  | Interaction config passthrough (portVisibility, enableHelperLines, …). |
| `tokenBridge?` | `unknown` |  | Design-token bridge — adopt the app's shadcn / MUI / Tailwind CSS variables. |
| `highlighterConfig?` | `boolean \| Partial<HighlighterConfig>` |  | The outline layer: outlines around the hovered node, the selected node, nodes with a validation issue, and valid connection targets. `true` turns every kind on; an object turns kinds on or off one by one. Off when unset. Follows the prop by VALUE. |
| `highlightConnected?` | `boolean \| HighlightConnectedOptions` |  | Bring the selected nodes' lines forward and fade the rest: `true`, or options (depth, stroke, outgoing, dimOpacity). Off when unset. Follows the prop by VALUE. |
| `class?` | `string` |  |  |
| `style?` | `Record<string, string \| number>` |  |  |

### `GrafloriaLayoutRequest`

```ts
interface GrafloriaLayoutRequest
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `name` | `string` |  |  |
| `options?` | `Record<string, unknown>` |  |  |

### `NodeProps`

Props a custom node component receives.

```ts
interface NodeProps<TData = Record<string, unknown>>
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `id` | `string` |  |  |
| `data` | `TData` |  |  |
| `selected` | `boolean` |  |  |
| `node` | `NodeModel` |  | The live engine model — the escape hatch. |

### `SelectionChange`

```ts
interface SelectionChange
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `nodes` | `NodeModel[]` |  |  |
| `edges` | `LinkModel[]` |  |  |

### `WidgetProps`

Props a custom widget component receives.

```ts
interface WidgetProps<TData = Record<string, unknown>>
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `widget` | `DashboardWidgetSpec` |  |  |
| `data` | `TData` |  |  |

## Types

### `GrafloriaStore`

The live instance, or `undefined` until a `<GrafloriaFlow>` mounts. Always
`noSerialize`d — see the note at the top of this file.

```ts
type GrafloriaStore = Signal<NoSerialize<DiagramInstance> | undefined>;
```

### `NodeTypes`

`nodeTypes` maps a node's `type` to the Qwik component that renders it.

Declaring a type here IS the opt-in: specs whose `type` has an entry are
flagged `custom` automatically, the same rule the Vue and Angular wrappers
use. An explicit `custom` on the spec always wins.

```ts
type NodeTypes = Record<string, Component<NodeProps<never>>>;
```

### `WidgetTypes`

```ts
type WidgetTypes = Record<string, Component<WidgetProps<never>>>;
```

## Also exported from here

These names are documented with the package that defines them, and can be imported from this one too.

- From [@grafloria/renderer](https://atloria.dev/p/grafloria-h7YM7amryF/developer/grafloria-renderer-overview): `DARK_THEME`, `DiagramInstance`, `EdgeSpec`, `GroupSpec`, `HighlightConnectedOptions`, `HydrationSnapshot`, `LIGHT_THEME`, `NodeSpec`, `renderToStaticSVG`, `StaticRenderOptions`, `StaticRenderResult`, `Theme`
