# Functions

Import these from `@grafloria/element`.

## Functions

### `addColumnAt`

Append a column (immutably) — returns the new column array.

```ts
function addColumnAt(columns: ErColumn[], column: ErColumn, at = columns.length): ErColumn[]
```

### `assignTiers`

Tier every candidate score at once: the FIRST candidate holding the maximum
score is `top` when that maximum is >= 2 — exactly one gold row per drag.

```ts
function assignTiers(scores: number[]): MatchTier[]
```

### `bindCardEditing`

Wire the editing gestures onto a kit container. Idempotent per container
(a re-bind disposes the previous one), matching `bindRowInteractions`.

```ts
function bindCardEditing(api: EditApi): CardEditingHandle
```

### `bindJoinGuidance`

Bind live join guidance to a diagram instance. Listens to the engine's
connection lifecycle; while a drag is live, every kit-card row on every
other table wears its tier class (and the best one its "★ BEST" chip), and
the matching port glyphs glow via a generated stylesheet. Everything clears
when the drag ends, however it ends.

```ts
function bindJoinGuidance(api: JoinGuidanceApi, options: JoinGuidanceOptions = {}): JoinGuidanceHandle
```

### `ensureDiagramKitStyles`

Inject the kit stylesheet once. Safe to call repeatedly and in SSR.

```ts
function ensureDiagramKitStyles(doc: Document | undefined = typeof document !== 'undefined' ? document : undefined): void
```

### `ensureJoinGuidanceStyles`

Inject the guidance tint stylesheet once. Safe to call repeatedly / in SSR.

```ts
function ensureJoinGuidanceStyles(
  doc: Document | undefined = typeof document !== 'undefined' ? document : undefined
): void
```

### `erDiagram`

Build a render() spec for an ER diagram.

Entities become HTML table cards; relationships become orthogonal edges with
crow's-foot cardinality. A `TABLE.column` end pins the edge to that row via
an absolute-layout port (the FK→PK look). Two edges landing on the same
column are automatically spread apart.

```ts
function erDiagram(options: ErDiagramOptions): {
  nodes: Array<Record<string, unknown>>;
  edges: Array<Record<string, unknown>>;
  finalize: (api: unknown) => void;
}
```

### `erRowCenterY`

Node-local y of a row's centre (the +1 offsets past the card's top border).

```ts
function erRowCenterY(rowIndex: number): number
```

### `erTable`

Typed handle for a kit ER table. Throws for unknown ids / non-kit nodes.

```ts
function erTable(api: HandleApi, id: string): ErTable
```

### `erTables`

Every kit ER table in the diagram, as handles.

```ts
function erTables(api: HandleApi): ErTable[]
```

### `matchColumns`

Match old columns to new columns for port reconciliation. Returns a map from
OLD index → NEW index; an old index absent from the map is a REMOVED column
(its pinned ports and their edges are dropped).

Three passes, most-certain first, so a single edit is always read the way a
human means it:
  1. object identity — reorder / add / remove that preserved references;
  2. name — a retype (same name, new object) or a rebuilt array;
  3. positional remainder — the leftovers matched in order, which is exactly
     what a rename is (one old + one new in the same slot). Without pass 3 a
     rename reads as remove+add and the edge is severed.

```ts
function matchColumns(oldCols: ErColumn[], newCols: ErColumn[]): Map<number, number>
```

### `matchTier`

Per-score tier (rank-free half; `assignTiers` promotes the single best to `top`).

```ts
function matchTier(score: number): Exclude<MatchTier, 'top'>
```

### `removeColumnAt`

Remove the column at `index` — returns the new column array.

```ts
function removeColumnAt(columns: ErColumn[], index: number): ErColumn[]
```

### `renameColumnAt`

Rename the column at `index` — returns a new array with a NEW object there.

```ts
function renameColumnAt(columns: ErColumn[], index: number, name: string): ErColumn[]
```

### `rowIndexFromY`

Inverse of {@link erRowCenterY}: which column row a pinned port sits on.

```ts
function rowIndexFromY(y: number): number
```

### `scoreMatch`

Score a candidate join between two columns. Pure; the exact production
logic. Higher is better; 0 means "no reason to join these".

```ts
function scoreMatch(a: JoinEnd, b: JoinEnd): 0 | 1 | 2 | 3
```

### `singularize`

Naive English singular — enough for schema names (orders, categories, statuses).

```ts
function singularize(word: string): string
```

### `umlClass`

Typed handle for a kit UML class. Throws for unknown ids / non-kit nodes.

```ts
function umlClass(api: HandleApi, id: string): UmlClass
```

### `umlClasses`

Every kit UML class in the diagram, as handles.

```ts
function umlClasses(api: HandleApi): UmlClass[]
```

### `umlDiagram`

Build a render() spec for a UML class diagram. Call `spec.finalize(api)`
after render() — multiplicity chips are positioned labels, which only the
live model's `link.addLabel` can express.

```ts
function umlDiagram(options: UmlDiagramOptions): {
  nodes: Array<Record<string, unknown>>;
  edges: Array<Record<string, unknown>>;
  finalize: (api: unknown) => void;
}
```

### `updateClass`

Edit a rendered UML class in place. `delta` may change the name, stereotype,
abstract flag, attributes, methods, and width/height. One undoable step.

```ts
function updateClass(api: KitApi, classId: string, delta: UmlClassDelta): Promise<boolean>
```

### `updateEntity`

Edit a rendered ER table in place. `delta` may change the name, the column
list (add / remove / reorder / rename / retype), and the width/height. Field
ports and their edges are reconciled so the diagram stays correct, as ONE
undoable step.

```ts
function updateEntity(api: KitApi, entityId: string, delta: ErEntityDelta): Promise<boolean>
```

**Returns** whether the node existed and the edit was applied.
