@neuronection/assistant-ui 0.52.0 → 0.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/README.md +4 -1
  3. package/dist/chat-branch-tree.d.ts +15 -2
  4. package/dist/chat-composer.d.ts +43 -3
  5. package/dist/chat-composer.js +1 -1
  6. package/dist/chat-core.d.ts +54 -4
  7. package/dist/chat-launcher.js +1 -1
  8. package/dist/chat-markdown.d.ts +8 -1
  9. package/dist/chat-markdown.js +1 -1
  10. package/dist/chat-message.d.ts +16 -1
  11. package/dist/chat-message.js +1 -1
  12. package/dist/chat-panel.js +1 -1
  13. package/dist/chat-pending.d.ts +25 -0
  14. package/dist/chat-pending.js +3 -0
  15. package/dist/chat-pending.js.map +1 -0
  16. package/dist/chat-reasoning.d.ts +10 -2
  17. package/dist/chat-reasoning.js +1 -1
  18. package/dist/chat-session-list.d.ts +7 -0
  19. package/dist/chat-session-list.js +1 -1
  20. package/dist/chat-suggestion-card.d.ts +19 -0
  21. package/dist/chat-suggestion-card.js +3 -0
  22. package/dist/chat-suggestion-card.js.map +1 -0
  23. package/dist/chat-tool-card.js +1 -1
  24. package/dist/chat-transcript.d.ts +81 -8
  25. package/dist/chat-transcript.js +1 -1
  26. package/dist/chat-turn-status.js +1 -1
  27. package/dist/chat-welcome.d.ts +23 -0
  28. package/dist/chat-welcome.js +3 -0
  29. package/dist/chat-welcome.js.map +1 -0
  30. package/dist/{chunk-PC3CE4W2.js → chunk-22MIIWC7.js} +45 -7
  31. package/dist/chunk-22MIIWC7.js.map +1 -0
  32. package/dist/{chunk-GDGKARRB.js → chunk-5C2OLUDR.js} +11 -2
  33. package/dist/chunk-5C2OLUDR.js.map +1 -0
  34. package/dist/{chunk-5BJ4VULP.js → chunk-EQPXM2R4.js} +23 -10
  35. package/dist/chunk-EQPXM2R4.js.map +1 -0
  36. package/dist/chunk-F4BTJQLK.js +43 -0
  37. package/dist/chunk-F4BTJQLK.js.map +1 -0
  38. package/dist/{chunk-TQDTFPM4.js → chunk-GIQZNEG5.js} +3 -3
  39. package/dist/chunk-GIQZNEG5.js.map +1 -0
  40. package/dist/{chunk-E3NZM4U7.js → chunk-GO4ILLS6.js} +17 -4
  41. package/dist/chunk-GO4ILLS6.js.map +1 -0
  42. package/dist/chunk-HXU6P5FD.js +479 -0
  43. package/dist/chunk-HXU6P5FD.js.map +1 -0
  44. package/dist/{chunk-MFM4W6ZO.js → chunk-I4R5BRC7.js} +3 -3
  45. package/dist/{chunk-MFM4W6ZO.js.map → chunk-I4R5BRC7.js.map} +1 -1
  46. package/dist/{chunk-5U45TQJE.js → chunk-I5H4KYEZ.js} +3 -3
  47. package/dist/{chunk-5U45TQJE.js.map → chunk-I5H4KYEZ.js.map} +1 -1
  48. package/dist/{chunk-S63SYV6O.js → chunk-INXQJM2K.js} +27 -6
  49. package/dist/chunk-INXQJM2K.js.map +1 -0
  50. package/dist/{chunk-HQ3X5SVR.js → chunk-KQLKITZL.js} +105 -16
  51. package/dist/chunk-KQLKITZL.js.map +1 -0
  52. package/dist/chunk-M4SYVPC4.js +3 -0
  53. package/dist/chunk-M4SYVPC4.js.map +1 -0
  54. package/dist/chunk-NOAKHVBJ.js +264 -0
  55. package/dist/chunk-NOAKHVBJ.js.map +1 -0
  56. package/dist/chunk-OOQO6VGO.js +33 -0
  57. package/dist/chunk-OOQO6VGO.js.map +1 -0
  58. package/dist/chunk-P3QUNCBR.js +366 -0
  59. package/dist/chunk-P3QUNCBR.js.map +1 -0
  60. package/dist/chunk-PABMR4RA.js +30 -0
  61. package/dist/chunk-PABMR4RA.js.map +1 -0
  62. package/dist/{chunk-SEZZVAGP.js → chunk-SR4IN564.js} +10 -3
  63. package/dist/chunk-SR4IN564.js.map +1 -0
  64. package/dist/index.d.ts +243 -36
  65. package/dist/index.js +40 -37
  66. package/dist/markdown-diff-view.js +1 -1
  67. package/dist/model-registry.js +1 -1
  68. package/dist/styles.css +1 -1
  69. package/dist/theme-scope.d.ts +1 -1
  70. package/dist/tokens.d.ts +1 -1
  71. package/dist/tokens.js +1 -1
  72. package/dist/{types-LhE1KFBf.d.ts → types-CxieoN2u.d.ts} +1 -1
  73. package/dist/types-pivJdPC8.d.ts +14 -0
  74. package/package.json +13 -1
  75. package/dist/chunk-5BJ4VULP.js.map +0 -1
  76. package/dist/chunk-C5JZCCU7.js +0 -220
  77. package/dist/chunk-C5JZCCU7.js.map +0 -1
  78. package/dist/chunk-E3NZM4U7.js.map +0 -1
  79. package/dist/chunk-GDGKARRB.js.map +0 -1
  80. package/dist/chunk-HQ3X5SVR.js.map +0 -1
  81. package/dist/chunk-PC3CE4W2.js.map +0 -1
  82. package/dist/chunk-S63SYV6O.js.map +0 -1
  83. package/dist/chunk-SEZZVAGP.js.map +0 -1
  84. package/dist/chunk-TQDTFPM4.js.map +0 -1
  85. package/dist/chunk-XOODPYJ3.js +0 -173
  86. package/dist/chunk-XOODPYJ3.js.map +0 -1
  87. package/dist/chunk-YQQZMWHL.js +0 -201
  88. package/dist/chunk-YQQZMWHL.js.map +0 -1
  89. package/dist/tree-4Hv9stjF.d.ts +0 -54
package/CHANGELOG.md CHANGED
@@ -1,5 +1,96 @@
1
1
  # @neuronection/assistant-ui
2
2
 
3
+ ## 0.53.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#78](https://github.com/neuronection/assistant-ui/pull/78) [`7fb0f6e`](https://github.com/neuronection/assistant-ui/commit/7fb0f6ea2cb2fdec737a68e4379b917bf20ea79a) Thanks [@constLiakos](https://github.com/constLiakos)! - **Message states (plan 100 S3):** `ChatMessage` state changes now animate instead of snapping.
8
+
9
+ - **Entrance:** every message bubble rises 4px + fades in on mount (`--as-duration-base`, mount-only — stream re-renders never restart it).
10
+ - **Copy feedback:** new `actions.copied` prop (controlled) plus an uncontrolled default — the copy action morphs into a success check for 1.5 s after each copy click, with the `aria-label` following ("Copy" → "Copied", new `labels.copied`, default "Copied").
11
+ - **Interrupted:** the "Stopped" chip slides in with a single amber pulse (`--as-warning`); **error** cards slide up into place.
12
+ - **Action row:** the hover/focus reveal is now owned by `tokens.css` (`data-as="chat-message-actions"`, opacity + 2px rise, `--as-duration-fast`, reduced-motion safe) instead of Tailwind `group-hover` classes — TW3 app CSS can never collide with it. Keyboard reachability is unchanged.
13
+ - **Edit mode:** `ChatMessageEditor` reveals with a slide-up and autofocuses its textarea (previously no focus on mount).
14
+ - **Variant switch:** content crossfades (`--as-duration-fast`) when `variants.index` changes on a branched message — automatic, no new props.
15
+
16
+ Consumers: nothing to wire for entrance/error/interrupted/variant animations; copy feedback works uncontrolled out of the box.
17
+
18
+ - [#78](https://github.com/neuronection/assistant-ui/pull/78) [`7fb0f6e`](https://github.com/neuronection/assistant-ui/commit/7fb0f6ea2cb2fdec737a68e4379b917bf20ea79a) Thanks [@constLiakos](https://github.com/constLiakos)! - **Surfaces (plan 100 S6):** the three surface hosts get their final motion pass, plus the chat welcome kit.
19
+
20
+ - **New `ChatWelcome`** (`@neuronection/assistant-ui/chat-welcome`) — the chat empty-state kit: a breathing `--as-ai` identity orb (default `Sparkles` icon, overridable node), greeting + subtitle, and a staggered suggestion container (children enter 40 ms apart). Densities `page | sidebar | bubble` via `data-variant`. Non-interactive by itself — suggestion controls are app markup. Intended as `ChatTranscript emptyState`.
21
+ - **`ChatLauncher`:** the panel now springs in from the launcher corner (`--as-ease-spring`, bottom transform-origin), the launcher icon ↔ close icon morph on toggle (never on first mount), and the unread badge pulses once on every value change.
22
+ - **`ChatDrawer`:** the slide-in re-curved onto the spring token (`--as-duration-spring` / `--as-ease-spring`).
23
+ - **`ChatPanel`:** the `banner` strip slides up in when it appears.
24
+ - **`as-anim-pulse-once` rework:** the one-shot attention pulse is now a box-shadow ripple (position-independent) instead of a `::after` overlay — safe on absolutely-positioned hosts like badges; visual behavior on existing consumers (interrupted chip) unchanged.
25
+
26
+ Everything is disabled under `prefers-reduced-motion: reduce` (motion contract test enforced).
27
+
28
+ - [#78](https://github.com/neuronection/assistant-ui/pull/78) [`7fb0f6e`](https://github.com/neuronection/assistant-ui/commit/7fb0f6ea2cb2fdec737a68e4379b917bf20ea79a) Thanks [@constLiakos](https://github.com/constLiakos)! - **In-chat search (plan 101 P2):** find anything in the conversation without leaving the transcript.
29
+
30
+ - **`ChatTranscript search`** prop (`{ query, onQueryChange }`): renders the new **`ChatSearchField`** above the log — a labelled query input with an `n/N` match readout and prev/next controls. Enter jumps to the next match, Shift+Enter to the previous, Escape clears. The active match scrolls into view with a one-shot flash (`data-search-flash`, reduced-motion safe).
31
+ - **`MarkdownSurface query`** prop: case-insensitive matches wrap in `<mark data-as="chat-search-match">` (warning-tinted) via a hand-rolled hast walker — no new dependency, zero cost when no query is set.
32
+ - Custom `renderItem` receives the active query as its fourth argument; transcript rows now carry `data-message-id` for anchor queries.
33
+ - `ChatSearchField` is exported from the `chat-transcript` module (and the root) for standalone composition; new transcript labels: `search`, `searchPlaceholder`, `previousMatch`, `nextMatch`, `clearSearch`, `matches`.
34
+
35
+ Jump-scrolling requires a non-virtualized transcript (documented); virtualized transcripts highlight visible rows only.
36
+
37
+ - [#78](https://github.com/neuronection/assistant-ui/pull/78) [`7fb0f6e`](https://github.com/neuronection/assistant-ui/commit/7fb0f6ea2cb2fdec737a68e4379b917bf20ea79a) Thanks [@constLiakos](https://github.com/constLiakos)! - **Motion foundation (plan 100 S1 / ADR-012):** a CSS-first motion system in `tokens.css` — `--as-duration-fast/base/slow/spring` (120/180/280/420ms) and `--as-ease-out/standard/spring` tokens, plus guarded utilities `.as-anim-message-in`, `.as-anim-slide-up`, `.as-anim-fade-swap`, `.as-anim-check-draw`, `.as-anim-pulse-once`, `.as-anim-shimmer`, `.as-anim-breathe` and the `.as-collapse` grid height-reveal (collapsed content leaves the a11y tree + tab order after the transition). Every animation/transition rule in `tokens.css` — including the pre-existing `as-anim-fade/modal/pop/drawer`, which were previously unguarded — is now disabled under `prefers-reduced-motion: reduce`, enforced by a static CSS contract test. Existing entrance timings re-tuned onto the tokens (±30ms, no behavior change). Apps can re-pace the whole family by remapping the tokens in `theme.css` — documented in `docs/theming.md` § Motion tokens. No runtime animation dependency was added (deliberate — see ADR-012).
38
+
39
+ - [#78](https://github.com/neuronection/assistant-ui/pull/78) [`7fb0f6e`](https://github.com/neuronection/assistant-ui/commit/7fb0f6ea2cb2fdec737a68e4379b917bf20ea79a) Thanks [@constLiakos](https://github.com/constLiakos)! - **Streaming choreography (plan 100 S2):** the live turn now reads as one continuous animation instead of abrupt swaps.
40
+
41
+ - **New `ChatPending`** (`@neuronection/assistant-ui/chat-pending`) — the first-token latency placeholder: a narrated phase row (`ChatTurnStatus`: dots + elapsed timer) over an assistant-aligned shimmer bubble tinted with the `--as-ai` accent. Render it as the transcript's `live` tail between send and the first delta (`label`, `startedAt`, `lines`, `children` props).
42
+ - **`MarkdownSurface`:** `streaming` now renders a pulsing `--as-ai` caret at the tail of the last block (static but visible under reduced motion) — the "still generating" signal after the pending handoff.
43
+ - **`ChatReasoning`:** `--as-ai` edge while streaming; expand/collapse animates through the `.as-collapse` height reveal; new `autoCollapse` prop (default `true`, uncontrolled mode only) folds the block when `streaming` turns true → false — a controlled `open` is never auto-collapsed, and a block that never streamed never folds.
44
+ - **`ChatToolCard`:** `--as-ai` edge while running; the running → done transition crossfades into a stroke-drawn check; args/result panes reveal through the animated collapse (collapsed panes are `visibility: hidden` — out of the a11y tree and tab order, so screen-reader behavior matches the old conditional render).
45
+ - **`ChatTurnStatus`:** phase-label changes crossfade (`--as-duration-fast`).
46
+
47
+ All effects are compositor-only, mount-keyed (stream re-renders never restart them), and disabled under `prefers-reduced-motion: reduce` with state staying legible. Consumers: compose `ChatPending` into the `live` tail per `docs/guides/chat-surfaces.md`; everything else is automatic on the next dependency bump.
48
+
49
+ - [#78](https://github.com/neuronection/assistant-ui/pull/78) [`7fb0f6e`](https://github.com/neuronection/assistant-ui/commit/7fb0f6ea2cb2fdec737a68e4379b917bf20ea79a) Thanks [@constLiakos](https://github.com/constLiakos)! - **Transcript modernization (plan 100 S5):** `ChatTranscript` + `ChatMessage` gain the modern layout option and navigation polish.
50
+
51
+ - **Flat design:** `design="flat"` on `ChatTranscript` (feeds the default renderer) or `ChatMessage` — assistant content renders as prose on the panel surface while the user keeps its bubble; `data-design` styling hook for apps. Default stays `bubbles` — opt-in, zero migration.
52
+ - **Consecutive-message grouping:** `groupConsecutive` tightens spacing between same-role runs and tags rows `data-group-pos` (`single | start | mid | end`, system rows always `single`); `renderItem` now receives the position as a third argument (render group-start avatars only).
53
+ - **Avatar slot:** optional `ChatMessage avatar` node — leading for assistants, trailing for users (`data-as="chat-message-avatar"`).
54
+ - **Unread jump pill:** assistant replies that land while the user is scrolled away are counted; the pill label reads "Scroll to latest — N new messages" (new `labels.newMessages`), shows a `9+` badge chip beyond nine, and resets on return-to-bottom or pill click. The pill slides up in instead of teleporting.
55
+ - **Depth + chrome:** top fade mask while scrolled into the thread (`data-fade-top`) and thin themed scrollbars (`--as-scrollbar-thumb`/`--as-scrollbar-track` tokens, progressive enhancement).
56
+ - **Fix:** the jump pill no longer positions with a translate utility (TW3 double-apply hazard) — margin-centering, identical geometry.
57
+
58
+ Consumers: everything is opt-in (`design`, `groupConsecutive`, `avatar`); the unread pill and scroll polish are automatic on the next dependency bump.
59
+
60
+ - [#78](https://github.com/neuronection/assistant-ui/pull/78) [`7fb0f6e`](https://github.com/neuronection/assistant-ui/commit/7fb0f6ea2cb2fdec737a68e4379b917bf20ea79a) Thanks [@constLiakos](https://github.com/constLiakos)! - **Composer intelligence (plan 101 P1):** `ChatComposer` gains the three interaction features modern chat inputs have.
61
+
62
+ - **Slash commands / @-mentions:** new `commands` prop — `{ trigger? ('/' default), items, maxItems?, onSelect }`. The palette opens while the caret touches a trigger-started word (caret-aware, works mid-sentence), fuzzy-filters via `searchScore`, and is fully keyboard-driven: ArrowUp/Down move, Enter/Tab select — never submitting while open — Escape dismisses. `onSelect(id, token)` receives the draft span (`start/end/query`) so the app performs the insertion. A11y: `role="listbox"`/`option` + `aria-controls`, `aria-autocomplete="list"`, `aria-activedescendant` on the textarea.
63
+ - **Escape to stop:** pressing Escape while a turn is in flight now fires `onStop` (after the palette-dismiss Escape, when both apply).
64
+ - **Prompt recall:** new `history` prop — ArrowUp on an empty draft recalls the last sent prompt, ArrowUp/Down walk the stack, editing a recalled draft exits it.
65
+
66
+ New `labels.commands` (listbox name, default "Commands"). Existing behavior (IME guard, canSubmit, drag-drop, multiline hysteresis) unchanged — all 24 composer tests green incl. the new palette/history/keyboard cases.
67
+
68
+ - [#78](https://github.com/neuronection/assistant-ui/pull/78) [`7fb0f6e`](https://github.com/neuronection/assistant-ui/commit/7fb0f6ea2cb2fdec737a68e4379b917bf20ea79a) Thanks [@constLiakos](https://github.com/constLiakos)! - **Media & list polish (plan 101 P4):**
69
+
70
+ - **Image lightbox:** `MarkdownSurface lightbox` — markdown images become labelled zoom buttons opening the library `Modal` (Escape closes, Radix focus handling). Aimed at health's medical images and study screenshots; inert images remain the default.
71
+ - **Inline session rename:** `ChatSessionList onRenameCommit(id, title)` — the rename action edits the title in place (autofocused input, Enter/blur commits, Escape cancels, keystrokes never select the row). Dialog-based `onRename` flows are unchanged.
72
+ - **Session rows stagger in** (30 ms steps, `as-slide-up`, reduced-motion safe) via the new `data-as="chat-session-rows"` hook.
73
+ - **New `ChatSuggestionCard`** (`@neuronection/assistant-ui/chat-suggestion-card`) — the standard suggestion chip for `ChatWelcome suggestions` and composer strips: icon + title + hint, real labelled button, hover lift via border/shadow (no transform utilities — TW3-safe).
74
+
75
+ New labels: `MarkdownSurface` `zoomImage`/`closeImage`, `ChatSessionList` `renameInput`.
76
+
77
+ - [#78](https://github.com/neuronection/assistant-ui/pull/78) [`7fb0f6e`](https://github.com/neuronection/assistant-ui/commit/7fb0f6ea2cb2fdec737a68e4379b917bf20ea79a) Thanks [@constLiakos](https://github.com/constLiakos)! - **Transcript context (plan 101 P3):** orientation anchors inside long conversations.
78
+
79
+ - **Date separators:** `showDateSeparators` on `ChatTranscript` renders Today/Yesterday/date chips between day groups, read from `ChatMessageView.createdAt` (rows without one join the previous group). `formatDate` overrides the older-day format (default `MMM d, yyyy`); new labels `today` / `yesterday`.
80
+ - **Message anchoring:** `focusMessageId` scrolls the row into view and flashes it whenever it changes — wire branch-tree node clicks, citation links or deep links to it. Rows carry `data-message-id`.
81
+ - **Floating stop:** `onStop` on `ChatTranscript` renders a stop pill beside the jump pill while a live turn streams and the user has scrolled away (labelled, keyboard-reachable, `labels.stop`).
82
+
83
+ All opt-in; no behavior change for existing consumers.
84
+
85
+ - [#78](https://github.com/neuronection/assistant-ui/pull/78) [`7fb0f6e`](https://github.com/neuronection/assistant-ui/commit/7fb0f6ea2cb2fdec737a68e4379b917bf20ea79a) Thanks [@constLiakos](https://github.com/constLiakos)! - **Composer micro-interactions (plan 100 S4):** `ChatComposer` state changes now animate.
86
+
87
+ - **Send ↔ Stop morph:** the swap rotates through (−90° + fade in, `--as-duration-fast`) — only on state change, never on first mount, so pages don't animate on load. Buttons, labels and focus behavior unchanged.
88
+ - **Focus glow:** the input row's `:focus-within` affordance is now CSS-owned and token-timed (accent border + 3px primary glow ring) instead of Tailwind `focus-within:` classes — TW3 app CSS can never collide.
89
+ - **Drag-over pulse:** while files drag over the composer (`data-dragging`), a 1.4s primary drop-zone pulse runs under the existing dashed border styling.
90
+ - **Rails slide in:** the `attachments` and `suggestions` slot wrappers rise + fade on mount (`as-anim-slide-up`).
91
+
92
+ All of it is disabled under `prefers-reduced-motion: reduce` (enforced by the motion contract test). No API changes.
93
+
3
94
  ## 0.52.0
4
95
 
5
96
  ### Minor Changes
package/README.md CHANGED
@@ -94,7 +94,10 @@ Visual reference: [gallery](https://neuronection.github.io/assistant-ui/).
94
94
  | [`ai-button`](./docs/components/ai-button.md) / [`ai-actions-dropdown`](./docs/components/ai-actions-dropdown.md) / [`ai-magic-fill`](./docs/components/ai-magic-fill.md) | AI affordances: ask-with-suggestions (controlled open, icon-only mode) · action menu + custom prompt · describe-in-words fill modal — API calls stay app-side | [stories](https://neuronection.github.io/assistant-ui/?story=ai-patterns--ai-buttons) |
95
95
  | [`chat-core`](./docs/components/chat-core.md) | `useChatStream` (transport-injected live-turn state machine), `liveTurnReducer`, `ChatMessageView`, family `ChatStreamEvent` vocabulary, branch-tree utils (`buildBranchTree`, `walkActivePath`, `variantInfo`) | [stories](https://neuronection.github.io/assistant-ui/?story=chat-core--chat-core-story) |
96
96
  | [`chat-markdown`](./docs/components/chat-markdown.md) | `MarkdownSurface` (read-only streaming markdown: GFM + KaTeX + lazy mermaid + copyable code blocks; no raw HTML) · `MarkdownCodeBlock` · `MermaidDiagram` | [stories](https://neuronection.github.io/assistant-ui/?story=chat-markdown--default) |
97
- | [`chat-message`](./docs/components/chat-message.md) / [`chat-reasoning`](./docs/components/chat-reasoning.md) / [`chat-tool-card`](./docs/components/chat-tool-card.md) / [`chat-turn-status`](./docs/components/chat-turn-status.md) | `ChatMessage` (bubble: actions row, variant switcher, edit-and-resend, error/interrupted states) · `ChatReasoning` (collapsible thinking block) · `ChatToolCard` (tool observation: status, duration, args/result, app-provided result views via `renderResult`) · `ChatTurnStatus` (live pre-text turn status: dots, phase label, elapsed timer) | [stories](https://neuronection.github.io/assistant-ui/?story=chat-message--assistant) |
97
+ | [`chat-message`](./docs/components/chat-message.md) / [`chat-reasoning`](./docs/components/chat-reasoning.md) / [`chat-tool-card`](./docs/components/chat-tool-card.md) / [`chat-turn-status`](./docs/components/chat-turn-status.md) | `ChatMessage` (bubble: actions row, variant switcher, edit-and-resend, error/interrupted states) · `ChatReasoning` (collapsible thinking block: animated reveal, streaming accent, auto-collapse) · `ChatToolCard` (tool observation: status, duration, args/result, app-provided result views via `renderResult`) · `ChatTurnStatus` (live pre-text turn status: dots, phase label, elapsed timer) | [stories](https://neuronection.github.io/assistant-ui/?story=chat-message--assistant) |
98
+ | [`chat-pending`](./docs/components/chat-pending.md) | `ChatPending` — first-token latency placeholder: narrated phase row (`ChatTurnStatus`) over an AI-accented shimmer bubble for the transcript's `live` tail | [stories](https://neuronection.github.io/assistant-ui/?story=chat-pending--default) |
99
+ | [`chat-welcome`](./docs/components/chat-welcome.md) | `ChatWelcome` — chat empty-state kit: breathing `--as-ai` orb, greeting + subtitle, staggered suggestion slots (`page` / `sidebar` / `bubble` densities) | [stories](https://neuronection.github.io/assistant-ui/?story=chat-welcome--default) |
100
+ | [`chat-suggestion-card`](./docs/components/chat-suggestion-card.md) | `ChatSuggestionCard` — the standard suggestion chip for welcome screens and composer strips: icon + title + hint, hover lift | [stories](https://neuronection.github.io/assistant-ui/?story=chat-welcome--default) |
98
101
  | [`chat-hitl`](./docs/components/chat-hitl.md) | `HitlProposalCard` / `FieldDiff` — human-in-the-loop proposal cards: field-level before/after diffs (long text via TextDiffView, structured collection chips), approve/reject with armed destructive confirm, preview slot, pending/approved/rejected/conflict/expired/reverted states | [stories](https://neuronection.github.io/assistant-ui/) |
99
102
  | [`chat-composer`](./docs/components/chat-composer.md) | `ChatComposer` — auto-growing IME-safe input with send/stop states, toolbar/attachment/suggestion slots, drag-drop + paste wiring, `data-multiline` row styling hook | [stories](https://neuronection.github.io/assistant-ui/?story=chat-composer--default) |
100
103
  | [`chat-transcript`](./docs/components/chat-transcript.md) / [`chat-branch-tree`](./docs/components/chat-branch-tree.md) / [`chat-session-list`](./docs/components/chat-session-list.md) | `ChatTranscript` (log semantics, polite announcements, stick-to-bottom + jump pill, optional virtualization) · `ChatBranchTree` (OpenWebUI-style branch rail, keyboard tree nav) · `ChatSessionList` (fuzzy search, date groups, row actions) | [stories](https://neuronection.github.io/assistant-ui/?story=chat-surfaces--transcript) |
@@ -1,7 +1,20 @@
1
1
  import * as React from 'react';
2
2
  import { LucideIcon } from 'lucide-react';
3
- import { B as BranchTree } from './tree-4Hv9stjF.js';
4
- import './types-LhE1KFBf.js';
3
+ import { C as ChatRole } from './types-pivJdPC8.js';
4
+
5
+ interface BranchNode {
6
+ id: string;
7
+ role: ChatRole;
8
+ excerpt?: string;
9
+ parentId: string | null;
10
+ activeChildId: string | null;
11
+ /** In insertion (sibling-order) order; the last entry is the newest sibling. */
12
+ childIds: string[];
13
+ }
14
+ interface BranchTree {
15
+ activeRootId: string | null;
16
+ nodes: Record<string, BranchNode>;
17
+ }
5
18
 
6
19
  interface ChatBranchTreeIcons {
7
20
  user: LucideIcon;
@@ -7,28 +7,66 @@ interface ChatComposerLabels {
7
7
  placeholder: string;
8
8
  ariaLabel: string;
9
9
  dropFiles: string;
10
+ commands: string;
10
11
  }
11
12
  interface ChatComposerIcons {
12
13
  send: LucideIcon;
13
14
  stop: LucideIcon;
14
15
  }
16
+ interface ChatComposerCommand {
17
+ id: string;
18
+ label: string;
19
+ hint?: string;
20
+ icon?: LucideIcon;
21
+ }
22
+ interface ChatComposerCommandToken {
23
+ /** Draft offsets of the `trigger + query` token to replace on select. */
24
+ start: number;
25
+ end: number;
26
+ /** Text typed after the trigger character. */
27
+ query: string;
28
+ }
29
+ interface ChatComposerCommands {
30
+ /** Palette trigger character — `/` for slash commands, `@` for mentions. Default `/`. */
31
+ trigger?: string;
32
+ items: ChatComposerCommand[];
33
+ /** Max visible entries. Default 8. */
34
+ maxItems?: number;
35
+ /**
36
+ * Fired when a command is selected (Enter/Tab/click). The app owns the
37
+ * draft edit: replace `value.slice(token.start, token.end)` with the
38
+ * insertion of its choice.
39
+ */
40
+ onSelect: (id: string, token: ChatComposerCommandToken) => void;
41
+ }
15
42
  interface ChatComposerProps {
16
43
  value: string;
17
44
  onValueChange: (value: string) => void;
18
45
  /** Enter / Send — IME-safe (composition and keyCode 229 are ignored). */
19
46
  onSubmit: () => void;
20
- /** A turn is in flight — renders the stop control when `onStop` is provided. */
47
+ /** A turn is in flight — renders the stop control when `onStop` is provided. Escape stops too. */
21
48
  sending?: boolean;
22
49
  onStop?: () => void;
23
50
  disabled?: boolean;
24
51
  /**
25
52
  * Overrides the send button's blank-text guard. Apps that allow
26
- * attachment-only submits (health's image-only "what's this?" turn) pass
53
+ * attachment-only submits (health's image-only "what's what?" turn) pass
27
54
  * `true` while ready attachments exist; pass `false` to force-disable.
28
55
  * Default: the button enables only when `value.trim() !== ''`. The
29
56
  * Enter/form path is unaffected — the app's `onSubmit` stays the guard.
30
57
  */
31
58
  canSubmit?: boolean;
59
+ /**
60
+ * Slash-command / mention palette: opens while the caret touches a
61
+ * `trigger`-started word; ArrowUp/Down move, Enter/Tab select (never
62
+ * submit while open), Escape dismisses. Fuzzy-filtered via `searchScore`.
63
+ */
64
+ commands?: ChatComposerCommands;
65
+ /**
66
+ * Previously sent prompts (oldest → newest). ArrowUp on an empty draft
67
+ * recalls the last one; ArrowDown walks back toward the empty draft.
68
+ */
69
+ history?: string[];
32
70
  placeholder?: string;
33
71
  ariaLabel?: string;
34
72
  /** Auto-grow cap before the textarea scrolls. Default 8. */
@@ -51,7 +89,9 @@ interface ChatComposerProps {
51
89
  /**
52
90
  * The family chat input: auto-growing IME-safe textarea, send/stop
53
91
  * states, attachment/dictation/toolbar slots, drag-drop + paste file
54
- * wiring. Presentational + controlled; transports stay app-side.
92
+ * wiring, a slash-command/mention palette (`commands`), Escape-to-stop
93
+ * and ArrowUp prompt recall (`history`). Presentational + controlled;
94
+ * transports stay app-side.
55
95
  */
56
96
  declare const ChatComposer: React.ForwardRefExoticComponent<ChatComposerProps & React.RefAttributes<HTMLFormElement>>;
57
97
 
@@ -1,3 +1,3 @@
1
- export { ChatComposer } from './chunk-YQQZMWHL.js';
1
+ export { ChatComposer } from './chunk-P3QUNCBR.js';
2
2
  //# sourceMappingURL=chat-composer.js.map
3
3
  //# sourceMappingURL=chat-composer.js.map
@@ -1,6 +1,5 @@
1
- import { C as ChatError } from './types-LhE1KFBf.js';
2
- export { a as ChatAttachmentView, b as ChatMessageStatus, c as ChatMessageVariants, d as ChatMessageView, e as ChatRole } from './types-LhE1KFBf.js';
3
- export { a as BranchNode, b as BranchNodeInput, B as BranchTree, c as activePathSet, d as buildBranchTree, l as linearTree, v as variantInfo, w as walkActivePath } from './tree-4Hv9stjF.js';
1
+ import { C as ChatError, a as ChatRole } from './types-CxieoN2u.js';
2
+ export { b as ChatAttachmentView, c as ChatMessageStatus, d as ChatMessageVariants, e as ChatMessageView } from './types-CxieoN2u.js';
4
3
 
5
4
  interface FlowStepInfo {
6
5
  id: string;
@@ -127,6 +126,57 @@ declare const initialLiveTurnState: LiveTurnState;
127
126
  */
128
127
  declare function liveTurnReducer(state: LiveTurnState, action: LiveTurnAction): LiveTurnState;
129
128
 
129
+ interface BranchNode {
130
+ id: string;
131
+ role: ChatRole;
132
+ excerpt?: string;
133
+ parentId: string | null;
134
+ activeChildId: string | null;
135
+ /** In insertion (sibling-order) order; the last entry is the newest sibling. */
136
+ childIds: string[];
137
+ }
138
+ interface BranchTree {
139
+ activeRootId: string | null;
140
+ nodes: Record<string, BranchNode>;
141
+ }
142
+ type BranchNodeInput = Omit<BranchNode, 'childIds'>;
143
+ /**
144
+ * Index the server's branch-tree projection (family contract: the read-only
145
+ * `GET …/tree` shape) and compute child lists. Insertion order defines
146
+ * sibling order — the last child is the newest variant (fallback when a
147
+ * parent has no `activeChildId`).
148
+ */
149
+ declare function buildBranchTree(input: {
150
+ activeRootId?: string | null;
151
+ nodes: BranchNodeInput[];
152
+ }): BranchTree;
153
+ /**
154
+ * Degenerate single-path tree from a visible (already active-path) message
155
+ * list — for apps/backends without branching yet. Every message parents to
156
+ * the previous one; the tree renders identically to a branched one.
157
+ */
158
+ declare function linearTree(items: {
159
+ id: string;
160
+ role: ChatRole;
161
+ excerpt?: string;
162
+ }[]): BranchTree;
163
+ /**
164
+ * The visible conversation: pointer walk from the active root, following
165
+ * each node's `activeChildId` (fallback: newest sibling). Cycle-safe.
166
+ */
167
+ declare function walkActivePath(tree: BranchTree): string[];
168
+ declare function activePathSet(tree: BranchTree): Set<string>;
169
+ /**
170
+ * Sibling variant info for the inline `‹ n/N ›` switcher: the 1-based index
171
+ * of `nodeId` among its siblings (roots are siblings of each other) and the
172
+ * ordered sibling ids.
173
+ */
174
+ declare function variantInfo(tree: BranchTree, nodeId: string): {
175
+ index: number;
176
+ count: number;
177
+ siblingIds: string[];
178
+ };
179
+
130
180
  interface ChatStreamTransport {
131
181
  /** Enqueue/send a user turn. Resolves when accepted; errors surface as a failed turn. */
132
182
  send(input: {
@@ -163,4 +213,4 @@ interface UseChatStreamResult extends LiveTurnState {
163
213
  */
164
214
  declare function useChatStream(options: UseChatStreamOptions): UseChatStreamResult;
165
215
 
166
- export { ChatError, type ChatStreamEvent, type ChatStreamTransport, type FlowStepInfo, type LiveNodeState, type LiveToolCall, type LiveTurnAction, type LiveTurnState, type LiveTurnStatus, type UseChatStreamOptions, type UseChatStreamResult, initialLiveTurnState, liveTurnReducer, useChatStream };
216
+ export { type BranchNode, type BranchNodeInput, type BranchTree, ChatError, ChatRole, type ChatStreamEvent, type ChatStreamTransport, type FlowStepInfo, type LiveNodeState, type LiveToolCall, type LiveTurnAction, type LiveTurnState, type LiveTurnStatus, type UseChatStreamOptions, type UseChatStreamResult, activePathSet, buildBranchTree, initialLiveTurnState, linearTree, liveTurnReducer, useChatStream, variantInfo, walkActivePath };
@@ -1,3 +1,3 @@
1
- export { ChatLauncher } from './chunk-E3NZM4U7.js';
1
+ export { ChatLauncher } from './chunk-GO4ILLS6.js';
2
2
  //# sourceMappingURL=chat-launcher.js.map
3
3
  //# sourceMappingURL=chat-launcher.js.map
@@ -26,6 +26,10 @@ interface MarkdownSurfaceProps {
26
26
  value: string;
27
27
  /** Live turn: defers mermaid to the final render (streaming floods break diagrams). */
28
28
  streaming?: boolean;
29
+ /** Search highlight: case-insensitive matches wrap in `<mark data-as="chat-search-match">`. */
30
+ query?: string;
31
+ /** Click-to-zoom images in a modal (health's medical images, study screenshots). Default false. */
32
+ lightbox?: boolean;
29
33
  gfm?: boolean;
30
34
  math?: boolean;
31
35
  /** Render ```mermaid fences as diagrams (forced off while `streaming`). */
@@ -35,7 +39,10 @@ interface MarkdownSurfaceProps {
35
39
  components?: MarkdownComponents;
36
40
  urlTransform?: UrlTransform;
37
41
  showCodeLanguage?: boolean;
38
- labels?: Partial<MarkdownCodeBlockLabels>;
42
+ labels?: Partial<MarkdownCodeBlockLabels & {
43
+ zoomImage: string;
44
+ closeImage: string;
45
+ }>;
39
46
  className?: string;
40
47
  }
41
48
  /**
@@ -1,3 +1,3 @@
1
- export { MarkdownCodeBlock, MarkdownSurface, MermaidDiagram } from './chunk-HQ3X5SVR.js';
1
+ export { MarkdownCodeBlock, MarkdownSurface, MermaidDiagram } from './chunk-KQLKITZL.js';
2
2
  //# sourceMappingURL=chat-markdown.js.map
3
3
  //# sourceMappingURL=chat-markdown.js.map
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { LucideIcon } from 'lucide-react';
3
- import { c as ChatMessageVariants, e as ChatRole, C as ChatError } from './types-LhE1KFBf.js';
3
+ import { a as ChatMessageVariants, C as ChatRole, b as ChatError } from './types-pivJdPC8.js';
4
4
 
5
5
  interface ChatMessageEditorLabels {
6
6
  save: string;
@@ -52,6 +52,12 @@ interface ChatMessageAction {
52
52
  }
53
53
  interface ChatMessageActions {
54
54
  onCopy?: () => void;
55
+ /**
56
+ * Controlled copied feedback for the copy action (check morph).
57
+ * Uncontrolled by default: the library shows the check for 1.5 s
58
+ * after each copy click.
59
+ */
60
+ copied?: boolean;
55
61
  onEdit?: () => void;
56
62
  onRegenerate?: () => void;
57
63
  onRetry?: () => void;
@@ -66,6 +72,7 @@ interface ChatMessageActions {
66
72
  }
67
73
  interface ChatMessageLabels {
68
74
  copy: string;
75
+ copied: string;
69
76
  edit: string;
70
77
  regenerate: string;
71
78
  retry: string;
@@ -99,6 +106,14 @@ interface ChatMessageProps {
99
106
  chips?: React.ReactNode;
100
107
  /** Attachment rail above the content. */
101
108
  attachments?: React.ReactNode;
109
+ /** Leading identity node beside the bubble (user: trailing). Render group-start avatars only when grouping transcripts. */
110
+ avatar?: React.ReactNode;
111
+ /**
112
+ * Visual design: `bubbles` (default) — paired role bubbles; `flat` —
113
+ * assistant content renders as prose on the panel surface (user keeps
114
+ * its bubble). Reasoning/tool cards are unaffected.
115
+ */
116
+ design?: 'bubbles' | 'flat';
102
117
  labels?: Partial<ChatMessageLabels & ChatMessageEditorLabels & MessageVariantSwitcherLabels>;
103
118
  compact?: boolean;
104
119
  className?: string;
@@ -1,3 +1,3 @@
1
- export { ChatMessage, ChatMessageEditor, MessageVariantSwitcher } from './chunk-C5JZCCU7.js';
1
+ export { ChatMessage, ChatMessageEditor, MessageVariantSwitcher } from './chunk-NOAKHVBJ.js';
2
2
  //# sourceMappingURL=chat-message.js.map
3
3
  //# sourceMappingURL=chat-message.js.map
@@ -1,3 +1,3 @@
1
- export { ChatPanel } from './chunk-SEZZVAGP.js';
1
+ export { ChatPanel } from './chunk-SR4IN564.js';
2
2
  //# sourceMappingURL=chat-panel.js.map
3
3
  //# sourceMappingURL=chat-panel.js.map
@@ -0,0 +1,25 @@
1
+ import * as React from 'react';
2
+
3
+ interface ChatPendingProps {
4
+ /**
5
+ * Phase label narrated while the first token is awaited, e.g.
6
+ * "thinking" — usually the live turn's current node label.
7
+ */
8
+ label?: string;
9
+ /** Turn start timestamp (ms) — enables the elapsed timer. */
10
+ startedAt?: number;
11
+ /** Placeholder line count. Default 2 (capped at 6). */
12
+ lines?: number;
13
+ /** Extra node under the placeholder (model badge, app hints). */
14
+ children?: React.ReactNode;
15
+ className?: string;
16
+ }
17
+ /**
18
+ * The first-token latency placeholder (plan 100 S2): narrated phase row
19
+ * (dots + elapsed timer via `ChatTurnStatus`) over an assistant-aligned
20
+ * shimmer placeholder tinted with the `--as-ai` accent. Render it as the
21
+ * transcript's `live` tail between send and the first delta.
22
+ */
23
+ declare const ChatPending: React.ForwardRefExoticComponent<ChatPendingProps & React.RefAttributes<HTMLDivElement>>;
24
+
25
+ export { ChatPending, type ChatPendingProps };
@@ -0,0 +1,3 @@
1
+ export { ChatPending } from './chunk-F4BTJQLK.js';
2
+ //# sourceMappingURL=chat-pending.js.map
3
+ //# sourceMappingURL=chat-pending.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chat-pending.js"}
@@ -8,11 +8,17 @@ interface ChatReasoningLabels {
8
8
  interface ChatReasoningProps {
9
9
  /** Accumulated reasoning text (family `delta kind="reasoning"`). */
10
10
  text: string;
11
- /** Live reasoning stream — spinner + streaming label while on. */
11
+ /** Live reasoning stream — spinner + streaming label + `--as-ai` edge while on. */
12
12
  streaming?: boolean;
13
13
  open?: boolean;
14
14
  defaultOpen?: boolean;
15
15
  onOpenChange?: (open: boolean) => void;
16
+ /**
17
+ * Collapse the block when a live stream finishes (`streaming`
18
+ * true → false). Uncontrolled mode only — a controlled `open` stays
19
+ * app-driven. Default true.
20
+ */
21
+ autoCollapse?: boolean;
16
22
  labels?: Partial<ChatReasoningLabels>;
17
23
  icon?: LucideIcon;
18
24
  className?: string;
@@ -20,7 +26,9 @@ interface ChatReasoningProps {
20
26
  /**
21
27
  * Collapsible thinking block for reasoning models (study's
22
28
  * `ReasoningBubble`, family-standard): streams live while the model
23
- * reasons, collapses to a summary row when done. Controlled-first.
29
+ * reasons (AI-accent edge + spinner), collapses to a summary row when
30
+ * done — with a height reveal, and auto-collapse on the streaming →
31
+ * done transition in uncontrolled mode. Controlled-first.
24
32
  */
25
33
  declare const ChatReasoning: React.ForwardRefExoticComponent<ChatReasoningProps & React.RefAttributes<HTMLDivElement>>;
26
34
 
@@ -1,3 +1,3 @@
1
- export { ChatReasoning } from './chunk-S63SYV6O.js';
1
+ export { ChatReasoning } from './chunk-INXQJM2K.js';
2
2
  //# sourceMappingURL=chat-reasoning.js.map
3
3
  //# sourceMappingURL=chat-reasoning.js.map
@@ -12,6 +12,7 @@ interface ChatSessionListLabels {
12
12
  searchPlaceholder: string;
13
13
  newChat: string;
14
14
  rename: string;
15
+ renameInput: string;
15
16
  delete: string;
16
17
  export: string;
17
18
  today: string;
@@ -32,6 +33,12 @@ interface ChatSessionListProps {
32
33
  onSelect: (id: string) => void;
33
34
  onNew?: () => void;
34
35
  onRename?: (id: string) => void;
36
+ /**
37
+ * Inline rename: when provided, the rename action edits the title in
38
+ * place (Enter/blur commits, Escape cancels) instead of invoking
39
+ * `onRename` — keep `onRename` for dialog-based flows only.
40
+ */
41
+ onRenameCommit?: (id: string, title: string) => void;
35
42
  onDelete?: (id: string) => void;
36
43
  onExport?: (id: string) => void;
37
44
  searchable?: boolean;
@@ -1,3 +1,3 @@
1
- export { ChatSessionList } from './chunk-PC3CE4W2.js';
1
+ export { ChatSessionList } from './chunk-22MIIWC7.js';
2
2
  //# sourceMappingURL=chat-session-list.js.map
3
3
  //# sourceMappingURL=chat-session-list.js.map
@@ -0,0 +1,19 @@
1
+ import * as React from 'react';
2
+ import { LucideIcon } from 'lucide-react';
3
+
4
+ interface ChatSuggestionCardProps extends React.ComponentProps<'button'> {
5
+ /** Leading icon (defaults to none — pass `Sparkles`, `BookOpen`, …). */
6
+ icon?: LucideIcon;
7
+ /** Trailing hint text, e.g. "5 min". */
8
+ hint?: string;
9
+ children: React.ReactNode;
10
+ }
11
+ /**
12
+ * The family suggestion card (plan 101 P4): the standard action chip for
13
+ * `ChatWelcome suggestions` and composer suggestion strips — left-aligned
14
+ * icon + title + hint with a lift-on-hover affordance (border + shadow,
15
+ * no transform utilities: TW3-safe).
16
+ */
17
+ declare const ChatSuggestionCard: React.ForwardRefExoticComponent<Omit<ChatSuggestionCardProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
18
+
19
+ export { ChatSuggestionCard, type ChatSuggestionCardProps };
@@ -0,0 +1,3 @@
1
+ export { ChatSuggestionCard } from './chunk-PABMR4RA.js';
2
+ //# sourceMappingURL=chat-suggestion-card.js.map
3
+ //# sourceMappingURL=chat-suggestion-card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"chat-suggestion-card.js"}
@@ -1,3 +1,3 @@
1
- export { ChatToolCard } from './chunk-5BJ4VULP.js';
1
+ export { ChatToolCard } from './chunk-EQPXM2R4.js';
2
2
  //# sourceMappingURL=chat-tool-card.js.map
3
3
  //# sourceMappingURL=chat-tool-card.js.map