# Stencil Kit

Import these from `@grafloria/element`.

## Functions

### `bindShapeDataPanel`

Bind a shape-data panel into `host`. It follows the diagram's selection:
nodes, edges and multi-selections each get their own sections; nothing
selected shows the empty message.

```ts
function bindShapeDataPanel(
  api: ShapeDataPanelApi,
  host: HTMLElement,
  options: ShapeDataPanelOptions = {}
): ShapeDataPanelHandle
```

### `bindStencilPalette`

Build a stencil palette in `palette` that drops masters onto `canvas`.

```ts
function bindStencilPalette(
  api: StencilPaletteApi,
  hosts: { palette: HTMLElement; canvas: HTMLElement },
  options: StencilPaletteOptions = {}
): StencilPaletteHandle
```

**Parameters**

- `api`: the diagram instance (engine + model + viewport)
- `hosts`: `palette`: where the list renders · `canvas`: the drop target (the element the diagram is mounted in)

### `ensureStencilKitStyles`

Inject the palette stylesheet once per document.

```ts
function ensureStencilKitStyles(doc: Document = document): void
```

## Interfaces

### `ShapeDataPanelApi`

```ts
interface ShapeDataPanelApi
```

**Members**

- `getEngine(): any`
- `getModel(): any`
- `on(event: string, handler: (payload: any) => void): () => void`

### `ShapeDataPanelHandle`

```ts
interface ShapeDataPanelHandle
```

**Members**

- `refresh(): void` — Re-read the selection and rebuild the fields.
- `destroy(): void`

### `ShapeDataPanelOptions`

```ts
interface ShapeDataPanelOptions
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `title?` | `string` |  | Heading above the fields (default "Shape data"). |
| `emptyText?` | `string` |  | Shown when nothing (or more than one thing) is selected. |
| `onEdit?` | `(info: { nodeId: string; key: string; value: unknown }) => void` |  | Called after an edit commits. |

### `StencilPaletteApi`

The bits of a diagram instance the palette needs (kept structural so any
host — element, React, Vue — satisfies it without importing a class).

```ts
interface StencilPaletteApi
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `viewport` | `{ clientToWorld(x: number, y: number, rect: { left: number; top: number; width: number; height: number }): { x: number; y: number } }` |  |  |

**Members**

- `getEngine(): any`
- `getModel(): any`

### `StencilPaletteHandle`

```ts
interface StencilPaletteHandle
```

**Members**

- `setSearch(query: string): void` — Filter the list programmatically (same as typing in the search box).
- `place(masterId: string, world: { x: number; y: number }): Promise<string | null>` — Place a master at a WORLD point without dragging (keyboard / test path).
- `destroy(): void` — Remove listeners and the palette DOM.

### `StencilPaletteOptions`

```ts
interface StencilPaletteOptions
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `stencils?` | `Stencil[]` |  | Sections to show (default: every built-in stencil). |
| `search?` | `boolean` |  | Show the search box (default true). |
| `collapsed?` | `string[]` |  | Stencil ids to render collapsed initially (default: all but the first). |
| `data?` | `(master: NodeTemplate) => Record<string, unknown>` |  | Data merged into every placed master (e.g. a default label). |
| `onPlace?` | `(info: { master: NodeTemplate; nodeId: string; x: number; y: number }) => void` |  | Called after a master is placed on the canvas. |
| `notationTheme?` | `Record<string, { fill?: string; stroke?: string }>` |  | Restyle the shapes per stencil WITHOUT editing any master — the seam that makes stencil colour a host/theme decision instead of baked template data. Keyed by stencil id (`flowchart`, `bpmn`, `uml`, `erd`); each entry overrides the master's own `fill` / `stroke`. Pass `'theme'` for a value to take it from the live theme instead of a literal. |
| `htmlLayer?` | `boolean` |  | Opt a placed master INTO `useHTMLLayer`. Only set this when the host really runs an HTML layer that paints `node.data._html` — with the plain SVG renderer the flag makes the node render as an empty group. |
