# Flowstage UI components

Six dependency-free components for AI interfaces. The examples use local data and timers. They do not access a model, read documents, change settings, or run external tasks.

## Install

Download `lib/components.js` and `lib/components.css`. Both files include all six components. They need no build step, package manager, network request, or framework and can run from `file://`.

```html
<link rel="stylesheet" href="components.css">
<div id="demo"></div>
<script src="components.js"></script>
<script>
  const component = FlowstageUI.mount(document.querySelector('#demo'), {
    type: 'thinking-trace'
  });
</script>
```

The container controls width. The component controls its natural height. All selectors use the `fsui-` prefix and are scoped to `.fsui`. The stylesheet does not require Flowstage's site stylesheet.

## Public API

`FlowstageUI.mount(container, options)` takes a DOM element and a configuration object. It replaces that element's children. Mounting into the same container again destroys the previous instance first. An unknown type or missing element throws `TypeError`.

Every instance provides:

- `getState()` — a detached JSON snapshot; changing it does not change the component.
- `reset()` — restore the initial state and stop pending timers.
- `destroy()` — remove the component, listeners, and timers. This is idempotent. Other mutating methods do nothing after destruction.

`options.onChange(state)` receives a detached state snapshot after interactions. The container also dispatches a bubbling `flowstage:change` CustomEvent with `{ type, state }` in `event.detail`. No event is emitted for the initial render or destruction. `getState()` still returns the final snapshot after destruction.

All text configuration is inserted as text, not interpreted as HTML. The only SVG paths are built-in icons. Host applications are responsible for validating their own data and enforcing real permissions. Do not use the approval card's client-side state as an authorization boundary.

## Types and configuration

Every type accepts `title`, `subtitle`, and `onChange`. Omitted options use the documented example data in `FlowstageUI.getComponent(type).config`. Array options replace the default arrays. Identifiers should be unique strings.

| Type | Configuration | Additional instance methods |
| --- | --- | --- |
| `thinking-trace` | `steps: [{ title, detail, meta, status }]`. Status: `complete`, `running`, `queued`, or `error`. | `toggle(index)`, `expandAll()`, `collapseAll()` |
| `streaming-response` | `text`, `interval` in milliseconds between words (default 55, minimum 15). Starts complete. | `replay()`, `pause()`, `resume()` |
| `approval-card` | `action`, `description`, `facts: [{ label, value }]`, `options: [{ id, label, detail }]`. First scope is selected initially. | `select(scopeId)`, `approve()`, `reject()` |
| `task-list` | `tasks: [{ id, title, detail, status }]`, `duration` in milliseconds per local step (default 850, minimum 150). Initial status is `complete`, `error`, or `queued`. | `run()`, `retry(id)`, `pause()` |
| `context-sources` | `sources: [{ id, title, kind, meta, excerpt }]`, `selected: [id]`. Unknown initial selections are ignored. | `select(id, selected?)`, `selectAll()`, `clear()` |
| `prompt-composer` | `placeholder`, `suggestions: [text]`, `maxLength` (default 2000), `responseText`, `duration` (default 700, minimum 100), `onSubmit(prompt)`. | `setValue(text)`, `submit()`, `cancel()` |

`thinking-trace` is an authored summary of task steps, not a model's private reasoning transcript. Step states are configured at mount time. To replace the steps, remount with a new configuration.

`task-list.run()` simulates all unfinished tasks in order, including failed tasks. `retry(id)` validates a failed task, queues it, then continues the unfinished workflow. Pause stops the timer and requeues the active task; continuing restarts that step. Reset restores the supplied initial task states, including the deliberate example failure.

`prompt-composer.onSubmit` receives the trimmed prompt as a notification. Its return value is ignored. The component then displays the supplied local `responseText`; it does not automatically render an API response. Use the submitted value to integrate the component with host application behavior. Cancel stops the local example reply and preserves the prompt. Enter submits, Shift+Enter adds a line, and IME composition is respected.

## Example: explicit approval

```js
const approval = FlowstageUI.mount(document.querySelector('#approval'), {
  type: 'approval-card',
  title: 'Review the proposed change',
  action: 'Change the project view',
  description: 'Set Overview as the default view.',
  facts: [{ label: 'Project', value: 'Website refresh' }],
  options: [{ id: 'once', label: 'This change only', detail: 'Ask again next time.' }],
  onChange(state) {
    if (state.status === 'approved') {
      console.log('Decision received:', state.scope);
      // The host application checks permissions and performs any real action.
    }
  }
});
```

## Theming

Override tokens directly on `.fsui`, or on a more specific selector such as `#demo .fsui`:

```css
#demo .fsui {
  --fsui-bg: #14161c;
  --fsui-panel: #1b1e27;
  --fsui-border: #343946;
  --fsui-text: #f1f2f6;
  --fsui-muted: #a5adbc;
  --fsui-accent: #b9a2ff;
  --fsui-success: #91d7b1;
  --fsui-blue: #9bbcf9;
  --fsui-radius: 12px;
  --fsui-font: Inter, 'Segoe UI', system-ui, sans-serif;
}
```

Some secondary surfaces and semantic fills use fixed colors intended for the dark palette. This release provides a dark theme; a complete light theme requires reviewing those surface colors as well as the tokens.

## Accessibility and motion

Components use native buttons, radio inputs, checkboxes, a progress element, and a labeled textarea. Focus indicators remain visible. Trace disclosures set `aria-expanded` and `aria-controls`. Status regions announce decisions and meaningful progress. Streaming words are not individually announced. A replay with `prefers-reduced-motion: reduce` reveals the whole response immediately. Task simulation keeps its completion timing but has no decorative animation.

The gallery's Preview, Code, and Details tabs support Left/Right arrows, Home, and End. Search has a visible placeholder and an accessible label. Press `/` outside a text input to focus it. Category filters expose `aria-pressed`. Deep links such as `components/#approval-card` reveal their target even when a filter was active.

## Metadata for tools and agents

Load `lib/components.js` and read `window.FlowstageComponents`, an array of six entries. `FlowstageUI.getComponent(id)` returns a detached copy of one entry. Each entry contains:

- `id`, `type`, `name`, `category`, `description`, `version`, and `order`.
- `anatomy`, `states`, `accessibility`, `use`, and public `methods`.
- `files` and CSS `tokens`.
- Complete working `config` and a copyable JavaScript `snippet`.

The gallery also downloads this metadata as JSON. There is no fetch dependency: metadata lives in the JavaScript bundle so it remains available in a local file.

## Reference and license

Original implementation by Flowstage. [Beautiful UI](https://www.beautifului.dev/) is a design reference for visual hierarchy and interaction clarity; no source code, assets, or copy were imported. MIT, consistent with the Flowstage library.
