@djangocfg/ui-tools 2.1.408 → 2.1.409
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/README.md +3 -1
- package/package.json +6 -6
- package/src/tools/Chat/README.md +10 -0
- package/src/tools/Chat/shell/ChatRoot.tsx +20 -1
package/README.md
CHANGED
|
@@ -163,7 +163,9 @@ Need a fully custom input row (e.g. mention autocomplete via `MarkdownEditor`)?
|
|
|
163
163
|
|
|
164
164
|
Drop `<VoiceComposerSlot />` from `@djangocfg/ui-tools/speech-recognition` into the composer's `slots.blockStart` (`composer={{ slots: { blockStart: <VoiceComposerSlot /> } }}`) for live mic-to-text — **zero props**, reads / writes the composer through `ComposerHandle` registered in chat context. Set `headerSlots={{ languagePicker: true }}` on `<ChatLauncher>` for a flag-button language picker (66 BCP-47 tags). Both auto-hide on Firefox / in-app browsers / missing `getUserMedia`. See [`SpeechRecognition`](#speech-recognition--quick-start) below.
|
|
165
165
|
|
|
166
|
-
|
|
166
|
+
**Page-context.** The assistant can see the page the user is on. The `page-snapshot` engine (`src/lib/page-snapshot`) walks the live DOM into a token-efficient, redacted snapshot; wire `getDynamicMetadata` on `<ChatRoot>` / `<ChatProvider>` (typically from `usePageSnapshot().getChatMetadata`) and it rides the request `metadata`. When the assistant replies with `point` directives, `<HighlightOverlay>` (`src/tools/Chat/highlight`) spotlights the referenced elements. Story: `UI Tools/Chat/Highlight`.
|
|
167
|
+
|
|
168
|
+
Full docs: [`Chat/README.md`](src/tools/Chat/README.md). Stories are grouped under `UI Tools/Chat` into `Getting Started`, `Messages`, `Composer`, `Launcher`, `Transports`, `Highlight` — plus `Overview` and a one-screen `Showcase`.
|
|
167
169
|
|
|
168
170
|
---
|
|
169
171
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/ui-tools",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.409",
|
|
4
4
|
"description": "Heavy React tools with lazy loading - for Electron, Vite, CRA, Next.js apps",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ui-tools",
|
|
@@ -154,8 +154,8 @@
|
|
|
154
154
|
"test:watch": "vitest"
|
|
155
155
|
},
|
|
156
156
|
"peerDependencies": {
|
|
157
|
-
"@djangocfg/i18n": "^2.1.
|
|
158
|
-
"@djangocfg/ui-core": "^2.1.
|
|
157
|
+
"@djangocfg/i18n": "^2.1.409",
|
|
158
|
+
"@djangocfg/ui-core": "^2.1.409",
|
|
159
159
|
"consola": "^3.4.2",
|
|
160
160
|
"lodash-es": "^4.18.1",
|
|
161
161
|
"lucide-react": "^0.545.0",
|
|
@@ -210,9 +210,9 @@
|
|
|
210
210
|
"@maplibre/maplibre-gl-geocoder": "^1.7.0"
|
|
211
211
|
},
|
|
212
212
|
"devDependencies": {
|
|
213
|
-
"@djangocfg/i18n": "^2.1.
|
|
214
|
-
"@djangocfg/typescript-config": "^2.1.
|
|
215
|
-
"@djangocfg/ui-core": "^2.1.
|
|
213
|
+
"@djangocfg/i18n": "^2.1.409",
|
|
214
|
+
"@djangocfg/typescript-config": "^2.1.409",
|
|
215
|
+
"@djangocfg/ui-core": "^2.1.409",
|
|
216
216
|
"@types/lodash-es": "^4.17.12",
|
|
217
217
|
"@types/mapbox__mapbox-gl-draw": "^1.4.8",
|
|
218
218
|
"@types/node": "^24.7.2",
|
package/src/tools/Chat/README.md
CHANGED
|
@@ -56,6 +56,8 @@ export function MyChat() {
|
|
|
56
56
|
- **Voice composer slot.** `<VoiceComposerSlot />` drops into `composer.slots.blockStart` with **zero props** — reads/writes the composer through the `ComposerHandle` registered in chat context. The built-in `<Composer>` and TipTap-backed `MarkdownEditor` register themselves automatically; custom composers wire it via `useRegisterComposer({ focus, moveCursorToEnd, getValue, setValue })`. Auto-gates on Firefox / in-app WebViews / missing `getUserMedia`, preserves typed prefix, 90-second countdown, silence auto-stop, Esc / Enter hotkeys, start / stop earcons. See [`SpeechRecognition`](../SpeechRecognition/README.md).
|
|
57
57
|
- **Language flag button.** `headerSlots.languagePicker: true` slots a 28×28 country flag into the dock header — opens a searchable `<Combobox>` with 66 BCP-47 tags from the Chrome Web Speech catalogue. Selection persists via `useSpeechPrefs`, picked up by every `useSpeechRecognition` downstream. (Raw `<ChatHeaderLanguageButton>` still exported for custom shells.)
|
|
58
58
|
- **Auto-focus on stream end.** `<ChatProvider>` re-focuses the registered composer on the streaming → idle edge — type → send → read → keep typing without reaching for the mouse. Works for **every** usage pattern (`ChatRoot`, hand-rolled `ChatProvider` + `Composer`, headless), not just `ChatRoot`. Opt out with `<ChatProvider autoFocusOnStreamEnd={false}>`. The standalone `useAutoFocusOnStreamEnd()` hook is still exported for advanced cases (focus a non-composer target, drive `isStreaming` from your own store).
|
|
59
|
+
- **Page-context snapshot.** Optional `getDynamicMetadata` contributor on `<ChatProvider>` / `<ChatRoot>` — called fresh at send time, merged into transport `metadata`. Pairs with the `page-snapshot` engine (`src/lib/page-snapshot`) to attach a token-efficient, redacted snapshot of the page the user is looking at, so the assistant can answer in context. The snapshot rides a separate `metadata` field, never the message text.
|
|
60
|
+
- **AI highlight directives.** `highlight/` — when the assistant returns `point` directives, `<HighlightOverlay>` resolves each CST ref to a live element and draws an SVG-mask spotlight (optionally moves focus). Read-only: it points at the UI, never changes data. See [`highlight/README.md`](./highlight/README.md).
|
|
59
61
|
- **Centralized colors.** Role-aware className tokens (`BUBBLE_SURFACE` / `ANCHOR` / `TOGGLE` / `DESTRUCTIVE_SURFACE`) + hooks (`useChatBubbleStyles`, `useChatRoleStyles`, `useChatDestructiveStyles`).
|
|
60
62
|
- **Responsive.** FAB `size='responsive'` (default): phone → `sm`, tablet → `md`, desktop → `lg`. Side mode is desktop-only and falls back to popover below `lg`.
|
|
61
63
|
- **Mobile fullscreen.** Dock auto-fills viewport below 768px via `useIsMobile`. Heights use `dvh/svh/lvh` so iOS Safari URL bar doesn't clip the chat.
|
|
@@ -671,9 +673,17 @@ for await (const event of parseSSE(res, { map: createPydanticAISSEMap() })) {
|
|
|
671
673
|
|
|
672
674
|
// behavior
|
|
673
675
|
focusOnEmptyClick // default true
|
|
676
|
+
|
|
677
|
+
// page context — extra metadata computed fresh per send
|
|
678
|
+
getDynamicMetadata={() => ({ pageContext })}
|
|
674
679
|
/>
|
|
675
680
|
```
|
|
676
681
|
|
|
682
|
+
`getDynamicMetadata` is forwarded to the `<ChatProvider>` that `ChatRoot`
|
|
683
|
+
creates; it is **ignored** when `ChatRoot` mounts under an ambient
|
|
684
|
+
provider — set it on that provider instead. Typically wired from
|
|
685
|
+
`usePageSnapshot().getChatMetadata` (see `src/lib/page-snapshot`).
|
|
686
|
+
|
|
677
687
|
The `slots.header` / `slots.empty` accept either a `ReactNode` or a render
|
|
678
688
|
function — there is no separate `renderHeader` / `renderEmpty` prop and no
|
|
679
689
|
"which one wins" precedence. `composer.render` fully replaces the built-in
|
|
@@ -148,10 +148,28 @@ export interface ChatRootProps {
|
|
|
148
148
|
* @default true
|
|
149
149
|
*/
|
|
150
150
|
focusOnEmptyClick?: boolean;
|
|
151
|
+
/**
|
|
152
|
+
* Contribute extra transport metadata, computed fresh per send.
|
|
153
|
+
* Forwarded to the `<ChatProvider>` this component creates — ignored
|
|
154
|
+
* when mounted under an ambient provider (set it on that provider
|
|
155
|
+
* instead). Used to attach the page-context snapshot.
|
|
156
|
+
*/
|
|
157
|
+
getDynamicMetadata?: () => Record<string, unknown> | undefined;
|
|
151
158
|
}
|
|
152
159
|
|
|
153
160
|
export function ChatRoot(props: ChatRootProps) {
|
|
154
|
-
const {
|
|
161
|
+
const {
|
|
162
|
+
transport,
|
|
163
|
+
config,
|
|
164
|
+
session,
|
|
165
|
+
streaming,
|
|
166
|
+
audio,
|
|
167
|
+
debug,
|
|
168
|
+
className,
|
|
169
|
+
listClassName,
|
|
170
|
+
getDynamicMetadata,
|
|
171
|
+
...rest
|
|
172
|
+
} = props;
|
|
155
173
|
// When mounted under a launcher-owned `<ChatProvider>`, reuse that
|
|
156
174
|
// provider instead of wrapping in a second one. This lets host code
|
|
157
175
|
// freely nest `<ChatRoot>` inside `<ChatLauncher>` without losing
|
|
@@ -175,6 +193,7 @@ export function ChatRoot(props: ChatRootProps) {
|
|
|
175
193
|
audio={audio}
|
|
176
194
|
debug={debug}
|
|
177
195
|
blockRegistry={rest.messages?.blockRegistry}
|
|
196
|
+
getDynamicMetadata={getDynamicMetadata}
|
|
178
197
|
>
|
|
179
198
|
<ChatRootShell className={className} listClassName={listClassName} parts={rest} />
|
|
180
199
|
</ChatProvider>
|