@artooi/ag-ui-web-component 0.21.0 → 0.22.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.
- package/CHANGELOG.md +81 -1
- package/README.md +127 -12
- package/dist/ag-ui-web-component.bundle.js +404 -99
- package/dist/ag-ui-web-component.bundle.js.map +3 -3
- package/dist/constants.d.ts +29 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/core/ag_ui_chat.d.ts +11 -0
- package/dist/core/ag_ui_chat.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +550 -106
- package/dist/index.js.map +2 -2
- package/dist/ui/styles.d.ts +1 -1
- package/dist/ui/styles.d.ts.map +1 -1
- package/dist/ui/ui_strings.d.ts +8 -1
- package/dist/ui/ui_strings.d.ts.map +1 -1
- package/dist/ui/voice_input.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/constants.ts +35 -0
- package/src/core/ag_ui_chat.ts +197 -32
- package/src/index.ts +2 -0
- package/src/ui/styles.ts +383 -78
- package/src/ui/ui_strings.ts +9 -1
- package/src/ui/voice_input.ts +7 -1
- package/src/version.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,85 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.22.0] — 2026-08-11
|
|
11
|
+
|
|
12
|
+
Two complaints about how the widget *feels*, and both turned out to be structural
|
|
13
|
+
rather than cosmetic.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- **The composer is one surface, not four boxes.** The input row was a flat flex
|
|
18
|
+
row — attach, mic, textarea, send — with every sibling stretched to the
|
|
19
|
+
textarea's two-row height. That gave a paperclip the same visual weight as the
|
|
20
|
+
field it sits next to and made Send a full-height filled slab. The border,
|
|
21
|
+
background and focus ring now belong to a wrapping `composer-surface`: the
|
|
22
|
+
field is borderless and **grows with what is typed** (from one row up to
|
|
23
|
+
`--ag-ui-composer-max-height`, then scrolls), and a `composer-tools` row
|
|
24
|
+
underneath carries the paperclip and mic as quiet icon buttons with a circular
|
|
25
|
+
Send closing the right-hand end.
|
|
26
|
+
|
|
27
|
+
Send is now icon-only. Its accessible name still comes from the `send` /
|
|
28
|
+
`stop` strings (`aria-label` + `title`), and the run state swaps its glyph
|
|
29
|
+
rather than its text, so nothing moves when a run starts. A host that sized
|
|
30
|
+
`::part(send)` by its padding should switch to `--ag-ui-send-size`.
|
|
31
|
+
|
|
32
|
+
- **Collapsing goes to a round floating launcher.** `collapsed` used to leave the
|
|
33
|
+
full-width header bar sitting on the page, which is most of a chat widget's
|
|
34
|
+
footprint for none of its use. The panel now scales down into a launcher in the
|
|
35
|
+
corner it already occupies and the launcher grows back out of that point;
|
|
36
|
+
`transform` and `opacity` are all that animate, so the morph is
|
|
37
|
+
compositor-only and cannot reflow the host page. `placement="sidebar"` keeps
|
|
38
|
+
its edge rail (and now genuinely *slides* out through the edge it docks
|
|
39
|
+
against — the transition was declared but never wired to a transform), and
|
|
40
|
+
`embedded` / `page` keep the header bar, being host-laid-out and full-screen
|
|
41
|
+
respectively.
|
|
42
|
+
|
|
43
|
+
This changes what an existing floating embed looks like when collapsed. The
|
|
44
|
+
collapsed host keeps its box with `pointer-events: none`, so the page beneath
|
|
45
|
+
stays interactive and the launcher takes the clicks.
|
|
46
|
+
|
|
47
|
+
- **The chat-history drawer and the checkpoints panel slide.** Both were toggled
|
|
48
|
+
with `hidden` alone, which snaps. They now keep their box and hide with
|
|
49
|
+
`visibility`, which is what lets a surface animate *in and out* — an element
|
|
50
|
+
that was never rendered has no before-change style to animate from, and one
|
|
51
|
+
whose `display` flips to `none` cannot animate at all.
|
|
52
|
+
|
|
53
|
+
- **The chrome's glyphs are inline SVG** (send, stop, paperclip, mic, launcher)
|
|
54
|
+
rather than emoji, each in a slot with the mark as its fallback:
|
|
55
|
+
`icon-send`, `icon-stop`, `icon-attach`, `icon-voice`, `launcher`.
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
|
|
59
|
+
- **An unread badge on the launcher.** A collapsed widget is the one state where
|
|
60
|
+
an answer can arrive with nothing on screen to say so, so the launcher now
|
|
61
|
+
counts the answers that finished while it was closed (capped at `9+`) and
|
|
62
|
+
expanding marks them read. It is the only affordance here that is **on by
|
|
63
|
+
default**; `data-unread-badge="false"` turns the badge off, and the count keeps
|
|
64
|
+
running so a host chrome can render its own from the new `ag-ui-unread` event
|
|
65
|
+
(`UNREAD_EVENT` / `UnreadDetail`, plus a `chat.unread` getter). The count is
|
|
66
|
+
also the launcher's accessible name — a coloured dot says nothing to a screen
|
|
67
|
+
reader — via the new `expandUnread` string. Tokens:
|
|
68
|
+
`--ag-ui-badge-{bg,fg,size,font-size}`; part `launcher-badge`.
|
|
69
|
+
|
|
70
|
+
- **`data-launcher-icon-url`** — an icon for the collapsed launcher when it should
|
|
71
|
+
differ from the header's. Falls back to `data-icon-url`, so one attribute still
|
|
72
|
+
feeds both.
|
|
73
|
+
|
|
74
|
+
- **Motion tokens** — `--ag-ui-motion`, `--ag-ui-ease`, `--ag-ui-ease-pop`. One
|
|
75
|
+
duration and two curves drive every collapse, expand and slide-over. Under
|
|
76
|
+
`prefers-reduced-motion` the duration collapses to a frame; `--ag-ui-motion: 0s`
|
|
77
|
+
switches the animation off outright.
|
|
78
|
+
|
|
79
|
+
- **Launcher and composer tokens** — `--ag-ui-launcher-{size,bg,fg,radius,icon-size,inset}`,
|
|
80
|
+
`--ag-ui-composer-{radius,max-height}`, `--ag-ui-send-size`, `--ag-ui-tool-btn-size`,
|
|
81
|
+
`--ag-ui-glyph-{size,stroke}`; parts `composer-surface` and `composer-tools`.
|
|
82
|
+
|
|
83
|
+
- **Motion tests that run in a real browser.** happy-dom runs no transitions, so
|
|
84
|
+
every assertion about this would pass on a stylesheet where nothing animates.
|
|
85
|
+
The Chromium project now asserts on `getAnimations()` — that the browser
|
|
86
|
+
actually *started* the transitions a collapse, an expand and a drawer open are
|
|
87
|
+
supposed to start.
|
|
88
|
+
|
|
10
89
|
## [0.21.0] — 2026-08-11
|
|
11
90
|
|
|
12
91
|
Ten findings from a real embed — a cross-origin, cookie-authenticated React host.
|
|
@@ -1171,7 +1250,8 @@ hosts that both arrange the page the way it expects.
|
|
|
1171
1250
|
### Notes
|
|
1172
1251
|
- First release — exercising the automated npm OIDC publish pipeline end-to-end.
|
|
1173
1252
|
|
|
1174
|
-
[Unreleased]: https://github.com/Artui/ag-ui-web-component/compare/v0.
|
|
1253
|
+
[Unreleased]: https://github.com/Artui/ag-ui-web-component/compare/v0.22.0...HEAD
|
|
1254
|
+
[0.22.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.21.0...v0.22.0
|
|
1175
1255
|
[0.21.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.20.1...v0.21.0
|
|
1176
1256
|
[0.20.1]: https://github.com/Artui/ag-ui-web-component/compare/v0.20.0...v0.20.1
|
|
1177
1257
|
[0.20.0]: https://github.com/Artui/ag-ui-web-component/compare/v0.19.0...v0.20.0
|
package/README.md
CHANGED
|
@@ -47,6 +47,7 @@ No framework, no Django, no admin specifics live here. Downstream consumers (e.g
|
|
|
47
47
|
- [DOM-driver and animation primitives](#dom-driver-and-animation-primitives)
|
|
48
48
|
- [Page-action tools](#page-action-tools)
|
|
49
49
|
- [New chat and collapse](#new-chat-and-collapse)
|
|
50
|
+
- [Collapsing to the launcher](#collapsing-to-the-launcher)
|
|
50
51
|
- [Tool-call display modes](#tool-call-display-modes)
|
|
51
52
|
- [Markdown rendering](#markdown-rendering)
|
|
52
53
|
- [Run notices: compaction and agent skills](#run-notices-compaction-and-agent-skills)
|
|
@@ -163,17 +164,20 @@ another origin, add `credentials="include"` too; see
|
|
|
163
164
|
| `data-tools-url` | — | URL of a server tool-label catalog (`[{ name, summary, description? }]`), fetched with the element's headers and cookie policy; labels tool-call cards for server-side tools. |
|
|
164
165
|
| `data-threads-url` | — | URL of a server thread index (django-ag-ui's `ThreadsView`); enables durable, cross-device chat history. |
|
|
165
166
|
| `data-runs-url` | — | URL of a server run index (django-ag-ui's `RunsView`); reveals the header's ⭯ *Continue a run* panel. See [Resuming a run](#resuming-a-run). |
|
|
166
|
-
| `data-attachments-url` | — | URL of the file-upload endpoint (django-ag-ui's `AttachmentsView`); reveals the composer's
|
|
167
|
+
| `data-attachments-url` | — | URL of the file-upload endpoint (django-ag-ui's `AttachmentsView`); reveals the composer's paperclip picker + drag-and-drop. |
|
|
167
168
|
| `data-attachment-accept` | — | `<input accept>` list for client-side type filtering (e.g. `image/*,.pdf`). The server stays authoritative. |
|
|
168
169
|
| `data-attachment-max-bytes` | — | Client-side upload size cap in bytes (default 10 MiB; `0` disables). The server stays authoritative. |
|
|
169
|
-
| `data-transcribe-url` | — | URL of the voice-transcription endpoint (django-ag-ui's `TranscribeView`); reveals the composer's
|
|
170
|
+
| `data-transcribe-url` | — | URL of the voice-transcription endpoint (django-ag-ui's `TranscribeView`); reveals the composer's mic button. See [Voice input](#voice-input). |
|
|
170
171
|
| `data-theme-toggle` | — | Boolean: show a built-in header light⇄dark toggle (persists per tab). Off by default. See [Theme toggle](#theme-toggle). |
|
|
171
172
|
| `data-strings` | `strings` | Partial JSON override of the UI string table (localization). The property wins key-by-key over the attribute; see [Internationalization](#internationalization-i18n). |
|
|
172
|
-
| `data-icon-url` | — | Header (and
|
|
173
|
+
| `data-icon-url` | — | Header (and launcher) icon image URL. A slotted `slot="icon"` wins; see [Header & launcher icon](#header-and-launcher-icon). |
|
|
174
|
+
| `data-launcher-icon-url` | — | Icon image URL for the collapsed launcher only, when it should differ from the header's. Falls back to `data-icon-url`; a slotted `slot="launcher"` wins over both. |
|
|
175
|
+
| `data-unread-badge` | — | **On by default.** `="false"` hides the launcher's unread badge; the count and the `ag-ui-unread` event keep running. See [Collapsing to the launcher](#collapsing-to-the-launcher). |
|
|
173
176
|
|
|
174
177
|
Each header control also takes its own icon slot — `icon-history`, `icon-checkpoints`,
|
|
175
178
|
`icon-new`, `icon-collapse` — with the built-in glyph as the fallback, so a host can project a
|
|
176
|
-
brand `<img>` or `<svg>` rather than only restyling the character
|
|
179
|
+
brand `<img>` or `<svg>` rather than only restyling the character. The composer's glyphs work the
|
|
180
|
+
same way: `icon-send`, `icon-stop`, `icon-attach`, `icon-voice`.
|
|
177
181
|
|
|
178
182
|
```html
|
|
179
183
|
<ag-ui-chat endpoint="/agent/">
|
|
@@ -183,7 +187,7 @@ brand `<img>` or `<svg>` rather than only restyling the character:
|
|
|
183
187
|
| `data-page-actions` | — | Opt-in built-in page-action tools: a comma list of `scroll` / `drag` (e.g. `"scroll,drag"`). See [Page-action tools](#page-action-tools). |
|
|
184
188
|
| `data-side` | — | CSS-only, for `placement="sidebar"`: which edge it docks to — `right` (default) / `left`. |
|
|
185
189
|
| `data-answer-well` | — | CSS-only boolean: box each assistant turn (its text, tool cards, and thinking) in one bordered "well". Off by default. See [The answer well](#the-answer-well). |
|
|
186
|
-
| `collapsed` | `collapsed` | Reflected boolean; collapses the widget (to a rail under `placement="sidebar"`). Persisted per-tab in `sessionStorage`. |
|
|
190
|
+
| `collapsed` | `collapsed` | Reflected boolean; collapses the widget to its [launcher](#collapsing-to-the-launcher) (a rail under `placement="sidebar"`, the header bar under `embedded` / `page`). Persisted per-tab in `sessionStorage`. |
|
|
187
191
|
| `theme` | — | CSS-only: `light` (default) / `dark` / `auto` / `code`. |
|
|
188
192
|
| `density` | — | CSS-only: `comfortable` (default) / `compact`. |
|
|
189
193
|
| `placement` | — | CSS-only: `floating` (default) / `bottom-left` / `side` / `sidebar` / `full` / `page` / `embedded`. |
|
|
@@ -686,6 +690,71 @@ chat.toggleCollapsed();
|
|
|
686
690
|
chat.addEventListener("ag-ui-toggle", (e) => console.log(e.detail.collapsed));
|
|
687
691
|
```
|
|
688
692
|
|
|
693
|
+
### Collapsing to the launcher
|
|
694
|
+
|
|
695
|
+
A collapsed widget shrinks to a round **floating launcher** in the corner it already occupies: the
|
|
696
|
+
panel scales down into it and fades, the launcher grows out of the same point, and clicking the
|
|
697
|
+
launcher reverses it. Only `transform` and `opacity` animate, so the motion is compositor-only and
|
|
698
|
+
never reflows your page. Two placements collapse to something else instead — `sidebar` slides out
|
|
699
|
+
to its [edge rail](#sidebar-placement), and `embedded` / `page` keep the header bar, since one is
|
|
700
|
+
laid out by your page and the other is a full-screen route.
|
|
701
|
+
|
|
702
|
+
The launcher's mark comes from the same seam as the header icon, most specific first: a slotted
|
|
703
|
+
`slot="launcher"` child, then `data-launcher-icon-url`, then `data-icon-url`, then the built-in
|
|
704
|
+
speech bubble.
|
|
705
|
+
|
|
706
|
+
```html
|
|
707
|
+
<ag-ui-chat endpoint="/agent/" data-launcher-icon-url="/mark.svg"></ag-ui-chat>
|
|
708
|
+
|
|
709
|
+
<!-- or any markup at all -->
|
|
710
|
+
<ag-ui-chat endpoint="/agent/">
|
|
711
|
+
<svg slot="launcher" width="26" height="26"><!-- ... --></svg>
|
|
712
|
+
</ag-ui-chat>
|
|
713
|
+
```
|
|
714
|
+
|
|
715
|
+
```css
|
|
716
|
+
ag-ui-chat {
|
|
717
|
+
--ag-ui-launcher-size: 56px;
|
|
718
|
+
--ag-ui-launcher-radius: 50%; /* 12px for a squircle */
|
|
719
|
+
--ag-ui-launcher-bg: #14532d; /* defaults to the header background */
|
|
720
|
+
--ag-ui-launcher-fg: #ffffff;
|
|
721
|
+
--ag-ui-launcher-icon-size: 26px;
|
|
722
|
+
--ag-ui-launcher-inset: auto 0 0 auto; /* which corner of the widget's box */
|
|
723
|
+
}
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
> **The collapsed host keeps its box.** Animating the element's own width and height would animate
|
|
727
|
+
> layout; instead the box stays put with `pointer-events: none`, and the launcher takes the clicks.
|
|
728
|
+
> A host measuring `getBoundingClientRect()` on a collapsed widget still sees the panel's
|
|
729
|
+
> footprint — nothing there paints or takes input.
|
|
730
|
+
|
|
731
|
+
#### The unread badge
|
|
732
|
+
|
|
733
|
+
A collapsed widget is the one state where an answer can arrive with nothing on screen to say so,
|
|
734
|
+
so the launcher carries a count of the answers that finished while it was closed (capped at `9+`).
|
|
735
|
+
Expanding — or `newChat()` — marks them read. It is the only affordance here that is **on by
|
|
736
|
+
default**; `data-unread-badge="false"` turns the badge off.
|
|
737
|
+
|
|
738
|
+
The count is also the launcher's accessible name (`Expand — 2 unread`, from the `expandUnread`
|
|
739
|
+
string), because a coloured dot says nothing to a screen reader.
|
|
740
|
+
|
|
741
|
+
```js
|
|
742
|
+
chat.unread; // 2
|
|
743
|
+
|
|
744
|
+
// Every change, whether or not the badge renders it — so a host that hides the
|
|
745
|
+
// badge can put the count in its own chrome.
|
|
746
|
+
chat.addEventListener("ag-ui-unread", (e) => setDockBadge(e.detail.unread));
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
```css
|
|
750
|
+
ag-ui-chat {
|
|
751
|
+
--ag-ui-badge-bg: #b91c1c; /* defaults to --ag-ui-danger */
|
|
752
|
+
--ag-ui-badge-fg: #ffffff;
|
|
753
|
+
--ag-ui-badge-size: 18px;
|
|
754
|
+
--ag-ui-badge-font-size: 11px;
|
|
755
|
+
}
|
|
756
|
+
```
|
|
757
|
+
|
|
689
758
|
---
|
|
690
759
|
|
|
691
760
|
## Tool-call display modes
|
|
@@ -1149,6 +1218,7 @@ re-export point. Internal modules import from leaf paths.
|
|
|
1149
1218
|
| `MessageRole` | type | Role of a rendered chat message. |
|
|
1150
1219
|
| `SubmitDetail` | type | `detail` shape of the submit event. |
|
|
1151
1220
|
| `ToggleDetail` | type | `detail` shape of the `ag-ui-toggle` event (`{ collapsed }`). |
|
|
1221
|
+
| `UnreadDetail` | type | `detail` shape of the `ag-ui-unread` event (`{ unread }`). |
|
|
1152
1222
|
|
|
1153
1223
|
### AG-UI client & agent
|
|
1154
1224
|
|
|
@@ -1236,6 +1306,7 @@ re-export point. Internal modules import from leaf paths.
|
|
|
1236
1306
|
| `ELEMENT_TAG` | The registered tag name (`ag-ui-chat`). |
|
|
1237
1307
|
| `SUBMIT_EVENT` | The submit CustomEvent name. |
|
|
1238
1308
|
| `TOGGLE_EVENT` | The collapse-toggle CustomEvent name (`ag-ui-toggle`). |
|
|
1309
|
+
| `UNREAD_EVENT` | The unread-count CustomEvent name (`ag-ui-unread`). |
|
|
1239
1310
|
| `MESSAGE_ROLE` | Message role constants. |
|
|
1240
1311
|
| `TOOL_CALL_STATUS` | Tool-call card status constants. |
|
|
1241
1312
|
| `TOOL_DISPLAY` | Tool-call display-mode constants (`minimal` / `compact` / `full`). |
|
|
@@ -1364,14 +1435,14 @@ Available parts: `panel`, `header`, `title`, `icon`, `header-controls`, `header-
|
|
|
1364
1435
|
`-args` / `-actions` / `-button` / `-cancel` / `-confirm`),
|
|
1365
1436
|
`approval` (plus `approval-body` / `-actions` / `-button` / `-approve` / `-deny`),
|
|
1366
1437
|
`question` (plus `question-body` / `-options` / `-choice` / `-choice-text` / `-radio` / `-input` /
|
|
1367
|
-
`-actions` / `-button`), `composer
|
|
1438
|
+
`-actions` / `-button`), `composer` (plus `composer-surface` / `composer-tools`), `input`, `send`,
|
|
1368
1439
|
`attach-button`, `voice-button`,
|
|
1369
1440
|
the attachment chips — `attachment-tray` and `attachment-chips` (the read-only chips on sent
|
|
1370
1441
|
bubbles) with the shared chip parts `attachment-chip` (plus `-icon` / `-name` / `-size` / `-bar` /
|
|
1371
1442
|
`-bar-fill` / `-retry` / `-remove`),
|
|
1372
1443
|
the skills UI (`skill-chips`, `skill-chip`, `skill-palette`, `skill-item`, `skill-item-title`,
|
|
1373
1444
|
`skill-item-desc`, and the missing-placeholder `skill-hint`),
|
|
1374
|
-
`launcher`, `launcher-icon`, and the drawer parts
|
|
1445
|
+
`launcher`, `launcher-icon`, `launcher-badge`, and the drawer parts
|
|
1375
1446
|
(`drawer`, `drawer-backdrop`, `drawer-panel`, `drawer-header`, `drawer-title`, `drawer-new`,
|
|
1376
1447
|
`drawer-list`, `drawer-empty`, `drawer-row`, `drawer-row-select`, `drawer-row-title`,
|
|
1377
1448
|
`drawer-row-time`, `drawer-row-preview`, `drawer-row-actions`, `drawer-row-rename`,
|
|
@@ -1407,7 +1478,10 @@ with a matching `slot=`):
|
|
|
1407
1478
|
| `header-actions` | Extra controls between the title and the built-in buttons. |
|
|
1408
1479
|
| `empty` | The empty-state shown before any message. |
|
|
1409
1480
|
| `footer` | Below the composer. |
|
|
1410
|
-
| `launcher` | The collapsed sidebar rail
|
|
1481
|
+
| `launcher` | The collapsed widget's mark — the floating launcher, or the sidebar rail. |
|
|
1482
|
+
| `icon-send` / `icon-stop` | The composer button's two glyphs (idle and mid-run). |
|
|
1483
|
+
| `icon-attach` / `icon-voice` | The paperclip and mic glyphs. |
|
|
1484
|
+
| `icon-history` / `icon-checkpoints` / `icon-new` / `icon-collapse` | The header controls' glyphs. |
|
|
1411
1485
|
|
|
1412
1486
|
```html
|
|
1413
1487
|
<ag-ui-chat endpoint="/agent/">
|
|
@@ -1430,9 +1504,11 @@ stays icon-less. The same icon seam feeds the collapsed sidebar rail. Size it vi
|
|
|
1430
1504
|
### Sidebar placement
|
|
1431
1505
|
|
|
1432
1506
|
`placement="sidebar"` is a full-height **docked** panel that slides open/closed and collapses to a
|
|
1433
|
-
slim **icon rail**
|
|
1434
|
-
|
|
1435
|
-
|
|
1507
|
+
slim **icon rail** rather than the [floating launcher](#collapsing-to-the-launcher) — the same
|
|
1508
|
+
element, shaped by the placement. It docks right by default; `data-side="left"` docks it left. The
|
|
1509
|
+
panel slides out through the edge it docks against. Collapse state reuses the `collapsed` attribute
|
|
1510
|
+
(persisted per-tab), and the rail carries `aria-expanded`. The slide honours
|
|
1511
|
+
`prefers-reduced-motion`.
|
|
1436
1512
|
|
|
1437
1513
|
```html
|
|
1438
1514
|
<ag-ui-chat endpoint="/agent/" placement="sidebar" data-side="left"></ag-ui-chat>
|
|
@@ -1476,9 +1552,48 @@ web component handles the `REASONING_*` event family (and the deprecated `THINKI
|
|
|
1476
1552
|
`@ag-ui/client` maps onto it), so no client config is needed — the thoughts appear whenever the
|
|
1477
1553
|
server forwards reasoning.
|
|
1478
1554
|
|
|
1555
|
+
### The composer
|
|
1556
|
+
|
|
1557
|
+
The composer is one bordered surface (part `composer-surface`) that owns the border and the focus
|
|
1558
|
+
ring: the field sits on top and grows with what is typed until it hits its ceiling and scrolls,
|
|
1559
|
+
and a tool row (part `composer-tools`) sits underneath with the paperclip and mic as quiet icon
|
|
1560
|
+
buttons on the left and a circular **Send** on the right. Send is icon-only — its accessible name
|
|
1561
|
+
still comes from the `send` / `stop` [strings](#internationalization-i18n) — and it becomes the
|
|
1562
|
+
Stop control mid-run by swapping its glyph, so nothing moves when a run starts.
|
|
1563
|
+
|
|
1564
|
+
```css
|
|
1565
|
+
ag-ui-chat {
|
|
1566
|
+
--ag-ui-composer-radius: 14px;
|
|
1567
|
+
--ag-ui-composer-max-height: 40vh; /* where the growing field starts scrolling */
|
|
1568
|
+
--ag-ui-tool-btn-size: 30px; /* the paperclip / mic hit targets */
|
|
1569
|
+
--ag-ui-send-size: 30px; /* the send circle */
|
|
1570
|
+
--ag-ui-glyph-size: 18px;
|
|
1571
|
+
--ag-ui-glyph-stroke: 1.75;
|
|
1572
|
+
}
|
|
1573
|
+
```
|
|
1574
|
+
|
|
1575
|
+
Every glyph is a slot with the built-in mark as its fallback (`icon-send`, `icon-stop`,
|
|
1576
|
+
`icon-attach`, `icon-voice`), so projecting your own icon set never means restyling a character.
|
|
1577
|
+
|
|
1578
|
+
### Motion
|
|
1579
|
+
|
|
1580
|
+
One duration and two curves drive every collapse, expand and slide-over, so the whole widget
|
|
1581
|
+
settles as one thing:
|
|
1582
|
+
|
|
1583
|
+
```css
|
|
1584
|
+
ag-ui-chat {
|
|
1585
|
+
--ag-ui-motion: 0.28s;
|
|
1586
|
+
--ag-ui-ease: cubic-bezier(0.32, 0.72, 0, 1); /* the settle */
|
|
1587
|
+
--ag-ui-ease-pop: cubic-bezier(0.34, 1.36, 0.64, 1); /* the arrival, with overshoot */
|
|
1588
|
+
}
|
|
1589
|
+
```
|
|
1590
|
+
|
|
1591
|
+
Under `prefers-reduced-motion: reduce` the duration collapses to a single frame: states still
|
|
1592
|
+
change, nothing travels. Set `--ag-ui-motion: 0s` to switch the animation off outright.
|
|
1593
|
+
|
|
1479
1594
|
### Voice input
|
|
1480
1595
|
|
|
1481
|
-
Set `data-transcribe-url` (django-ag-ui's `TranscribeView`) to reveal a
|
|
1596
|
+
Set `data-transcribe-url` (django-ag-ui's `TranscribeView`) to reveal a mic button in the
|
|
1482
1597
|
composer (part `voice-button`). Click it to record via `MediaRecorder`, click again to stop — the
|
|
1483
1598
|
clip is POSTed to the endpoint and the returned transcript is dropped into the textarea. Swap the
|
|
1484
1599
|
transport with a custom `transcribeHandler` — `(audio: Blob) => Promise<string>` — to use a
|