# Topology editor
> Editable site topology graph: traffic pixels on each link follow its measured rate, and devices or links open an inspector when selected.
- Element: `<ln-topology>`
- React: `import { LnTopology } from "@/components/lumesec/ln-topology"`
- Collection: Network (https://elements.lumesec.ai/components/network)
- Registry item: https://elements.lumesec.ai/r/ln-topology.json
- Page: https://elements.lumesec.ai/components/network/topology



Live preview: https://elements.lumesec.ai/view/ln-topology

```html
<ln-topology label="Innsbruck HQ" height="560"></ln-topology>
```

## Playground

Change a prop and the component updates. Props marked live animate to the new value; the others rebuild the element.

## Installation

```bash
npx shadcn@latest add @lumesec/ln-topology
```

First time with the @lumesec registry? Register it once, or install by URL:

```bash
npx shadcn@latest registry add @lumesec=https://elements.lumesec.ai/r/{name}.json
npx shadcn@latest add https://elements.lumesec.ai/r/ln-topology.json
```

## Usage

React:

```tsx
import { LnTopology } from "@/components/lumesec/ln-topology";

export function Example() {
  return (
    <LnTopology label="Innsbruck HQ" height={560} />
  );
}
```

HTML:

```html
<script type="module" src="https://elements.lumesec.ai/cdn/ln-topology.js"></script>

<ln-topology label="Innsbruck HQ" height="560"></ln-topology>
```

## Behaviour

The whole site as a graph. Device cards and links are plain interface. The pixels on each link are its traffic, downstream on one side and upstream on the other, released at a rate that follows the measured throughput. Select a device or a link to inspect it. In edit mode, drag from a card’s handle onto another card to connect them.

## API reference

### Attributes

| Attribute | React prop | Type     | Default        | Description                                                                                                                                     |
| --------- | ---------- | -------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `label`   | `label`    | `string` | `Innsbruck HQ` | Title shown in the toolbar. Read once when the element connects; later changes are ignored.                                                     |
| `height`  | `height`   | `number` | `560`          | Stage height in pixels. Read once when the element connects. When it is not set, stages narrower than 640px size their height to fit the graph. |

### Events

Events bubble and cross the shadow boundary unless the description says otherwise.

| Event     | React prop  | Detail                                                                                                       | Description                                                                                                                                                                                                         |
| --------- | ----------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `select`  | `onSelect`  | `{ device: string } \| { link: [string, string] }`                                                           | Fires when a device or a link is selected by pointer, keyboard or the inspector's connection list, and after a device or link is added. `link` holds the ids of both ends. Not fired when the selection is cleared. |
| `restart` | `onRestart` | `{ device: string }`                                                                                         | Fires when Restart is pressed in the inspector. The device shows Restarting for about 2.6 s.                                                                                                                        |
| `change`  | `onChange`  | `{ added: string } \| { removed: string } \| { linked: [string, string] } \| { unlinked: [string, string] }` | Fires when the graph changes: a device is added or removed, or a link is drawn or removed. Removing a device drops its links without separate `unlinked` events.                                                    |
| `move`    | `onMove`    | `{ device: string, x: number, y: number }`                                                                   | Fires when a pointer drag of a device card ends. `x` and `y` are rounded graph coordinates. Arrow-key moves do not fire it.                                                                                         |

### Methods

Call them on the element, for example through a React ref.

| Method                                                                   | Description                                                                                                                                           |
| ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fit(anim?: boolean)`                                                    | Scales and centres the view so every device fits. Animates unless `anim` is false or reduced motion is on. Same as the Fit to view button.            |
| `tidy()`                                                                 | Arranges the devices as a tree from the uplinks down, then fits the view. Same as the Tidy button.                                                    |
| `addDevice(type: "switch" \| "ap" \| "server" \| "camera" \| "storage")` | Adds a device near the centre of the view, selects it and fires `change` with `added`. The device shows Adopting for 2.4 s. Works with edit mode off. |

## Keyboard

| Keys                                         | Action                                                                                                                 |
| -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| Enter / Space                                | On a focused device card: select it and open the inspector.                                                            |
| ArrowLeft / ArrowRight / ArrowUp / ArrowDown | On a focused device card: move it 10 px, or 40 px with Shift.                                                          |
| Delete / Backspace                           | In edit mode: remove the focused device (internet uplinks excepted), or the selected link when no card has focus.      |
| + / =                                        | Zoom in, when focus is in the stage but not on a device card.                                                          |
| -                                            | Zoom out, when focus is in the stage but not on a device card.                                                         |
| 0                                            | Fit the graph to the view, when focus is in the stage but not on a device card.                                        |
| Escape                                       | In the stage: clear the selection and close the Add device menu. In the menu: close it and return focus to Add device. |
| ArrowDown / ArrowUp                          | In the Add device menu: move to the next or previous item, wrapping around.                                            |

## Accessibility

* The stage is a focusable `role="application"` region whose `aria-label` describes the keyboard controls.
* Each device card is a `role="button"` with `tabindex="0"` and an `aria-label` of name, status and IP address.
* Edit, Traffic and Rates are toggle buttons with `aria-pressed`. Add device has `aria-haspopup="menu"` and opens a `role="menu"` of `menuitem` buttons; the first item receives focus.
* The zoom buttons are labelled Zoom out, Zoom in and Fit to view.
* Selections are announced in a polite live region ("Selected …"). The inspector is `aria-live="polite"` and its rates refresh every second.
* Links are drawn on a canvas and can be selected with a pointer only. The canvas and the legend are `aria-hidden`.
* Closing the inspector returns focus to the stage.
* Reduced motion: traffic pixels are not drawn, fit, zoom and Tidy jump without animation, and the card and inspector entrance animations are switched off; centring on a device still eases.

## Theming

The element reads your shadcn theme tokens through its shadow root, so light and dark follow your theme. The accent comes from `--lumesec`. See [Theming](/docs/theming).

This component reads `--background`, `--border`, `--card`, `--destructive`, `--foreground`, `--input`, `--lumesec`, `--lumesec-info`, `--muted` and `--muted-foreground`.

To restyle only LumeSec elements, set the matching `--ui-*` overrides: `--ui-accent`, `--ui-border`, `--ui-border-strong`, `--ui-danger`, `--ui-faint`, `--ui-fg`, `--ui-fg2`, `--ui-info`, `--ui-mono`, `--ui-muted`, `--ui-page`, `--ui-surface` and `--ui-track`.

## Notes

* Shows built-in demo data for one site: the shared device set from the network engine (ids such as `gw`, `core`, `aiop1`) plus a Frankfurt DC site and three client groups. No attribute selects other data; link rates are simulated and update every second while the element is on screen.
* Edits (moved devices, new devices and links) exist only inside the element and are lost when it is recreated.
* Ctrl or ⌘ with the mouse wheel zooms between 30% and 220%, two pointers pinch-zoom, and dragging the background pans.
* The React wrapper's `ref` is typed as the element class, so its methods can be called once the element is connected.


