# @net-advantage/nabs-ui-graph

Canvas-based graph board control for the Nabs UI library.

## Features

- Pan and wheel zoom canvas interactions
- Node creation and drag-move
- Edge creation between selected nodes
- Node and edge labels
- Collapsible toolbox rail
- Pluggable toolbox architecture with toolset definitions

## Install

This package is part of the Nabs monorepo and is consumed as a workspace package.

## Basic Usage

```tsx
import { Graph } from "@net-advantage/nabs-ui-graph";
import "@net-advantage/nabs-ui-graph/style.css";

export function Example() {
  return <Graph toolboxLabel="Tools" />;
}
```

## Graph API

### Graph props

- `toolboxLabel?: string`
  - Accessible label for the toolbox toolbar.
- `toolset?: "simple" | "agentic-workflow"`
  - Selects one of the built-in toolsets. Defaults to `"simple"`.
- `toolsets?: GraphToolsetDefinition[]`
  - Optional custom toolsets. If provided, this overrides `toolset`.
- `ToolboxComponent?: ComponentType<GraphToolboxProps>`
  - Optional custom toolbox renderer. Defaults to `SimpleGraphToolset`.
- `onShapeAdd?: (shape: GraphShape) => void`
  - Called when a node is created.
- `onShapeMove?: (shape: GraphShape) => void`
  - Called when a node is moved.

### Exported types

- `GraphShape`
- `GraphNodeType`
- `GraphToolDefinition`
- `GraphToolsetDefinition`
- `GraphToolboxProps`

## Pluggable Toolsets

Toolsets are independent groups of tools. Each toolset can keep its own active tool state.

```tsx
import { Graph, type GraphToolsetDefinition } from "@net-advantage/nabs-ui-graph";

const customToolsets: GraphToolsetDefinition[] = [
  {
    id: "simple-graph-toolset",
    label: "Simple Graph Toolset",
    tools: [
      { id: "square", label: "Square", kind: "node", nodeType: "square" },
      { id: "circle", label: "Circle", kind: "node", nodeType: "circle" },
      { id: "edge", label: "Edge", kind: "edge" },
    ],
  },
];

export function Example() {
  return <Graph toolsets={customToolsets} />;
}
```

## Built-in Toolset Selection

```tsx
import { Graph } from "@net-advantage/nabs-ui-graph";

export function Example() {
  return <Graph toolset="agentic-workflow" toolboxLabel="Workflow Tools" />;
}
```

`agentic-workflow` includes:

- `Initiative` node (rectangle)
- `Scenario` node (parallelogram)
- `Lifecycle` node (circle)
- `Context` node (document)
- `Connector` tool for straight, labeled links

Connection rules currently enforced in this built-in toolset:

- `Initiative -> Scenario` uses label `ResultIn`
- `Initiative -> Initiative` uses label `Extend` (single parent and no cycles)
- `Scenario -> Lifecycle` uses label `Use` (one lifecycle target per scenario)
- `Context -> Lifecycle` uses label `UsedBy`
- Unsupported links are blocked
- Node labels are rendered inside nodes with wrapping/truncation up to four lines

## Custom Toolbox Component

You can fully replace toolbox rendering while keeping the graph canvas behavior.

```tsx
import {
  Graph,
  type GraphToolboxProps,
} from "@net-advantage/nabs-ui-graph";

function MyToolbox(props: GraphToolboxProps) {
  const {
    toolboxLabel,
    toolsets,
    isCollapsed,
    onToggleCollapse,
    onToolClick,
    onToolDoubleClick,
    activeToolIdsBySet,
    isEdgeToolEnabled,
    edgeHint,
  } = props;

  return (
    <div role="toolbar" aria-label={toolboxLabel}>
      <button type="button" onClick={onToggleCollapse}>
        {isCollapsed ? "Expand" : "Collapse"}
      </button>

      {!isCollapsed &&
        toolsets.map((set) => (
          <section key={set.id}>
            {set.label && <h4>{set.label}</h4>}
            {set.tools.map((tool) => {
              const active = activeToolIdsBySet[set.id] === tool.id;
              const disabled = tool.kind === "edge" && !isEdgeToolEnabled;
              return (
                <button
                  key={tool.id}
                  type="button"
                  disabled={disabled}
                  aria-pressed={active}
                  title={tool.kind === "edge" ? edgeHint : tool.label}
                  onClick={() => onToolClick(tool, set.id)}
                  onDoubleClick={() => onToolDoubleClick(tool, set.id)}
                >
                  {tool.label}
                </button>
              );
            })}
          </section>
        ))}
    </div>
  );
}

export function Example() {
  return <Graph ToolboxComponent={MyToolbox} />;
}
```

## Built-in Sample Toolset

The package also exports a sample toolbox renderer and its toolset config:

- `SimpleGraphToolset`
- `simpleGraphToolset`
- `simpleGraphToolsets`

It also exports the agentic workflow toolset definitions:

- `agenticWorkflowToolset`
- `agenticWorkflowToolsets`

These live under the package toolsets folder and are intended as a reference implementation for custom toolboxes.
