@alexkroman1/aai-ui 0.12.2 → 0.13.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/README.md +257 -0
- package/dist/_colors-CpZO-88A.js +78 -0
- package/dist/_module-url-C13kAJ87.js +15 -0
- package/dist/_page-shell.d.ts +11 -0
- package/dist/_recover-run.d.ts +79 -0
- package/dist/_repeat-until.d.ts +30 -0
- package/dist/_run-controls.d.ts +33 -0
- package/dist/_submission-state.d.ts +92 -0
- package/dist/_tap-to-talk-state.d.ts +88 -0
- package/dist/_utils-Mi-SCFA1.js +47 -0
- package/dist/_utils.d.ts +26 -0
- package/dist/_web-storage.d.ts +43 -0
- package/dist/_workflow-api-ref.d.ts +37 -0
- package/dist/_workflow-files.d.ts +34 -0
- package/dist/_workflow-test-defs.d.ts +38 -0
- package/dist/aai-logo-D8pMVn9_.js +85 -0
- package/dist/agent-state-labels.d.ts +65 -0
- package/dist/agent-state.d.ts +108 -0
- package/dist/audio/capture.d.ts +44 -0
- package/dist/audio/index.d.ts +18 -0
- package/dist/audio/index.js +431 -0
- package/dist/audio/preconnect.d.ts +87 -0
- package/dist/audio/voice-io.d.ts +112 -0
- package/dist/build-default-client.d.ts +1 -0
- package/dist/chat-view-BCbI7gD4.js +396 -0
- package/dist/client-config-C7fQrioM.js +139 -0
- package/dist/client-config.d.ts +119 -0
- package/dist/client-dir.d.ts +44 -0
- package/dist/client-dir.js +58 -0
- package/dist/client-identity.d.ts +131 -0
- package/dist/client-tool.d.ts +51 -0
- package/dist/components/_colors.d.ts +73 -0
- package/dist/components/_form-readiness.d.ts +56 -0
- package/dist/components/_form-values.d.ts +19 -0
- package/dist/components/aai-logo.d.ts +12 -0
- package/dist/components/audio-result.d.ts +94 -0
- package/dist/components/auto-scroll.d.ts +74 -0
- package/dist/components/bullet-list.d.ts +74 -0
- package/dist/components/button.d.ts +58 -0
- package/dist/components/button.js +85 -0
- package/dist/components/chat-view.d.ts +35 -0
- package/dist/components/chat-view.js +3 -0
- package/dist/components/console-shell.d.ts +85 -0
- package/dist/components/controls.d.ts +33 -0
- package/dist/components/controls.js +49 -0
- package/dist/components/conversation-view.d.ts +130 -0
- package/dist/components/eyebrow.d.ts +12 -0
- package/dist/components/facts.d.ts +81 -0
- package/dist/components/form-fields.d.ts +142 -0
- package/dist/components/form-types.d.ts +73 -0
- package/dist/components/form.d.ts +96 -0
- package/dist/components/markdown.d.ts +57 -0
- package/dist/components/message-list.d.ts +48 -0
- package/dist/components/message-list.js +3 -0
- package/dist/components/session-controls.d.ts +125 -0
- package/dist/components/session-error-banner.d.ts +69 -0
- package/dist/components/session-state-dot.d.ts +111 -0
- package/dist/components/sidebar-layout.d.ts +42 -0
- package/dist/components/sidebar-layout.js +56 -0
- package/dist/components/start-screen.d.ts +37 -0
- package/dist/components/start-screen.js +71 -0
- package/dist/components/tool-call-block.d.ts +28 -0
- package/dist/components/tool-call-block.js +3 -0
- package/dist/components/tool-call-row.d.ts +75 -0
- package/dist/components/tool-config-context.d.ts +22 -0
- package/dist/components/upload-progress.d.ts +76 -0
- package/dist/components/url-chips.d.ts +29 -0
- package/dist/components/workflow-fields.d.ts +46 -0
- package/dist/components/workflow-pending-note.d.ts +81 -0
- package/dist/components/workflow-progress.d.ts +81 -0
- package/dist/components/workflow-run-error.d.ts +48 -0
- package/dist/components/workflow-run-panel.d.ts +79 -0
- package/dist/context.d.ts +288 -0
- package/dist/context.js +382 -0
- package/dist/conversation-log.d.ts +88 -0
- package/dist/default-client/assets/_module-url-BX0RuRU2.js +1 -0
- package/dist/default-client/assets/audio-cGFGID-2.js +1 -0
- package/dist/default-client/assets/capture-processor-BUABoo3_.js +90 -0
- package/dist/default-client/assets/index-8ihb1Urm.css +2 -0
- package/dist/default-client/assets/index-BQURVARl.js +126 -0
- package/dist/default-client/assets/playback-processor-ABOa11j0.js +314 -0
- package/dist/default-client/favicon.ico +0 -0
- package/dist/default-client/index.html +15 -0
- package/dist/default-client.d.ts +23 -0
- package/dist/define-client.d.ts +162 -26
- package/dist/define-client.js +201 -55
- package/dist/eyebrow-UfmSz9yy.js +27 -0
- package/dist/hooks-DN4gHYsj.js +182 -0
- package/dist/hooks.d.ts +172 -0
- package/dist/hooks.js +3 -0
- package/dist/hooks.test-d.d.ts +14 -0
- package/dist/inbox-protocol.d.ts +128 -0
- package/dist/inbox.d.ts +132 -0
- package/dist/index.d.ts +129 -32
- package/dist/index.js +5503 -18
- package/dist/internal.d.ts +43 -0
- package/dist/internal.js +8 -0
- package/dist/linked-client.d.ts +70 -0
- package/dist/message-list-DHZcLhRA.js +682 -0
- package/dist/notice-player.d.ts +70 -0
- package/dist/page.d.ts +114 -0
- package/dist/phone.d.ts +50 -0
- package/dist/route-fetch.d.ts +79 -0
- package/dist/session/audio-effects.d.ts +31 -0
- package/dist/session/audio-setup.d.ts +57 -0
- package/dist/session/audio-state.d.ts +157 -0
- package/dist/session/browser-session.d.ts +30 -0
- package/dist/session/close.d.ts +26 -0
- package/dist/session/dial.d.ts +65 -0
- package/dist/session/handshake.d.ts +60 -0
- package/dist/session/index.d.ts +17 -0
- package/dist/session/index.js +2 -0
- package/dist/session/messages.d.ts +63 -0
- package/dist/session/mic.d.ts +64 -0
- package/dist/session/preconnect.d.ts +48 -0
- package/dist/session/reconnect.d.ts +25 -0
- package/dist/session/resume-store.d.ts +57 -0
- package/dist/session/state.d.ts +146 -0
- package/dist/session/ticket.d.ts +44 -0
- package/dist/session/types.d.ts +476 -0
- package/dist/session/url.d.ts +17 -0
- package/dist/session/user-turn.d.ts +55 -0
- package/dist/session-CE0Ipsb3.js +2129 -0
- package/dist/stored-value.d.ts +103 -0
- package/dist/tool-call-block-uXtMOUWN.js +204 -0
- package/dist/tool-config-context-Es4YUzV2.js +19 -0
- package/dist/types.d.ts +272 -34
- package/dist/types.js +35 -4
- package/dist/upload/files.d.ts +83 -0
- package/dist/upload/index.d.ts +15 -0
- package/dist/upload/pause.d.ts +31 -0
- package/dist/upload/recall.d.ts +67 -0
- package/dist/upload/report.d.ts +26 -0
- package/dist/upload/session.d.ts +99 -0
- package/dist/url-chips-oyy_Eiqh.js +239 -0
- package/dist/use-client-runs.d.ts +87 -0
- package/dist/use-conversation-log.d.ts +86 -0
- package/dist/use-conversation.d.ts +131 -0
- package/dist/use-copy.d.ts +74 -0
- package/dist/use-download-url.d.ts +84 -0
- package/dist/use-flash.d.ts +61 -0
- package/dist/use-inbox.d.ts +101 -0
- package/dist/use-push-to-talk.d.ts +105 -0
- package/dist/use-route-mutation.d.ts +113 -0
- package/dist/use-route.d.ts +82 -0
- package/dist/use-run-key.d.ts +133 -0
- package/dist/use-session-controls.d.ts +69 -0
- package/dist/use-session-id.d.ts +57 -0
- package/dist/use-tap-to-talk.d.ts +138 -0
- package/dist/use-user-transcript-uyHhzy4d.js +73 -0
- package/dist/use-user-transcript.d.ts +75 -0
- package/dist/use-workflow-form.d.ts +285 -0
- package/dist/use-workflow-progress.d.ts +137 -0
- package/dist/use-workflow-run-DdhWmbx-.js +697 -0
- package/dist/use-workflow-run.d.ts +100 -0
- package/dist/use-workflow-runs.d.ts +71 -0
- package/dist/use-workflow-stream.d.ts +154 -0
- package/dist/use-workflows.d.ts +77 -0
- package/dist/workflow-client.d.ts +136 -0
- package/dist/workflow-def-types.d.ts +31 -0
- package/dist/workflow-events.d.ts +39 -0
- package/dist/workflow-field-kind.d.ts +95 -0
- package/dist/workflow-status-labels.d.ts +35 -0
- package/dist/worklets/_module-url.d.ts +10 -0
- package/dist/worklets/_playback-bench-harness.d.ts +181 -0
- package/dist/worklets/_playback-bench-host.d.ts +63 -0
- package/dist/worklets/_playback-bench-page.d.ts +65 -0
- package/dist/worklets/_tts-trace-harness.d.ts +142 -0
- package/dist/worklets/_worklet-test-utils.d.ts +27 -0
- package/dist/worklets/capture-processor.d.ts +4 -2
- package/dist/worklets/capture-processor.js +73 -33
- package/dist/worklets/playback-processor.d.ts +4 -2
- package/dist/worklets/playback-processor.js +258 -42
- package/package.json +58 -31
- package/styles.css +152 -30
- package/dist/_components/app.d.ts +0 -23
- package/dist/_components/app.js +0 -41
- package/dist/_components/button.d.ts +0 -50
- package/dist/_components/button.js +0 -46
- package/dist/_components/chat-view.d.ts +0 -29
- package/dist/_components/chat-view.js +0 -61
- package/dist/_components/controls.d.ts +0 -18
- package/dist/_components/controls.js +0 -37
- package/dist/_components/error-banner.d.ts +0 -21
- package/dist/_components/error-banner.js +0 -27
- package/dist/_components/message-bubble.d.ts +0 -23
- package/dist/_components/message-bubble.js +0 -35
- package/dist/_components/message-list.d.ts +0 -21
- package/dist/_components/message-list.js +0 -76
- package/dist/_components/sidebar-layout.d.ts +0 -21
- package/dist/_components/sidebar-layout.js +0 -36
- package/dist/_components/start-screen.d.ts +0 -26
- package/dist/_components/start-screen.js +0 -51
- package/dist/_components/state-indicator.d.ts +0 -29
- package/dist/_components/state-indicator.js +0 -37
- package/dist/_components/thinking-indicator.d.ts +0 -16
- package/dist/_components/thinking-indicator.js +0 -34
- package/dist/_components/tool-call-block.d.ts +0 -27
- package/dist/_components/tool-call-block.js +0 -118
- package/dist/_components/tool-icons.d.ts +0 -17
- package/dist/_components/tool-icons.js +0 -128
- package/dist/_components/transcript.d.ts +0 -25
- package/dist/_components/transcript.js +0 -35
- package/dist/audio.d.ts +0 -45
- package/dist/audio.js +0 -121
- package/dist/client-context.d.ts +0 -33
- package/dist/client-context.js +0 -15
- package/dist/client-handler.d.ts +0 -43
- package/dist/session-CWB7vmqz.js +0 -429
- package/dist/session.d.ts +0 -69
- package/dist/session.js +0 -2
- package/dist/signals.d.ts +0 -120
- package/dist/signals.js +0 -161
- package/dist/tsdown.config.d.ts +0 -2
- package/dist/types.test-d.d.ts +0 -7
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filesystem location of the prebuilt default client — **Node only**.
|
|
3
|
+
*
|
|
4
|
+
* Its own subpath rather than the root barrel because it imports `node:module`
|
|
5
|
+
* and `node:path`: the root export is browser code, and pulling Node builtins
|
|
6
|
+
* into it would break every bundler that consumes this package.
|
|
7
|
+
*
|
|
8
|
+
* This exists because locating the directory is otherwise three lines of module
|
|
9
|
+
* archaeology plus knowledge of an internal `dist/` layout, and everybody
|
|
10
|
+
* serving the default UI has to write them — `aai-cli`'s dev server had its own
|
|
11
|
+
* copy, as did every self-hosted example. Three places that would all silently
|
|
12
|
+
* serve nothing if the build output moved.
|
|
13
|
+
*
|
|
14
|
+
* @module client-dir
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Absolute path to the prebuilt browser client's static files — pass it to
|
|
18
|
+
* `createServerForRuntime`/`createAgentServer` as `clientDir`.
|
|
19
|
+
*
|
|
20
|
+
* A function, not a constant: resolution touches the module graph and throws
|
|
21
|
+
* when the package is missing, and a module-level constant would move that
|
|
22
|
+
* failure to import time — where it fires for callers that never wanted the
|
|
23
|
+
* client, and before any of their own error handling is in place.
|
|
24
|
+
*
|
|
25
|
+
* Resolved through this package's own `package.json` rather than relative to
|
|
26
|
+
* this module, so it lands in the same place whether the caller resolved the
|
|
27
|
+
* `@dev/source` TypeScript entry or the compiled one under `dist/`.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* import { agent } from "@alexkroman1/aai";
|
|
32
|
+
* import { createAgentServer } from "@alexkroman1/aai-runtime";
|
|
33
|
+
* import { defaultClientDir } from "@alexkroman1/aai-ui/client-dir";
|
|
34
|
+
*
|
|
35
|
+
* const server = createAgentServer({
|
|
36
|
+
* agent: agent({ name: "Support" }),
|
|
37
|
+
* env: {},
|
|
38
|
+
* clientDir: defaultClientDir(),
|
|
39
|
+
* });
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* @public
|
|
43
|
+
*/
|
|
44
|
+
export declare function defaultClientDir(): string;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
//#region src/client-dir.ts
|
|
4
|
+
/**
|
|
5
|
+
* Filesystem location of the prebuilt default client — **Node only**.
|
|
6
|
+
*
|
|
7
|
+
* Its own subpath rather than the root barrel because it imports `node:module`
|
|
8
|
+
* and `node:path`: the root export is browser code, and pulling Node builtins
|
|
9
|
+
* into it would break every bundler that consumes this package.
|
|
10
|
+
*
|
|
11
|
+
* This exists because locating the directory is otherwise three lines of module
|
|
12
|
+
* archaeology plus knowledge of an internal `dist/` layout, and everybody
|
|
13
|
+
* serving the default UI has to write them — `aai-cli`'s dev server had its own
|
|
14
|
+
* copy, as did every self-hosted example. Three places that would all silently
|
|
15
|
+
* serve nothing if the build output moved.
|
|
16
|
+
*
|
|
17
|
+
* @module client-dir
|
|
18
|
+
*/
|
|
19
|
+
const require = createRequire(import.meta.url);
|
|
20
|
+
/**
|
|
21
|
+
* Absolute path to the prebuilt browser client's static files — pass it to
|
|
22
|
+
* `createServerForRuntime`/`createAgentServer` as `clientDir`.
|
|
23
|
+
*
|
|
24
|
+
* A function, not a constant: resolution touches the module graph and throws
|
|
25
|
+
* when the package is missing, and a module-level constant would move that
|
|
26
|
+
* failure to import time — where it fires for callers that never wanted the
|
|
27
|
+
* client, and before any of their own error handling is in place.
|
|
28
|
+
*
|
|
29
|
+
* Resolved through this package's own `package.json` rather than relative to
|
|
30
|
+
* this module, so it lands in the same place whether the caller resolved the
|
|
31
|
+
* `@dev/source` TypeScript entry or the compiled one under `dist/`.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* import { agent } from "@alexkroman1/aai";
|
|
36
|
+
* import { createAgentServer } from "@alexkroman1/aai-runtime";
|
|
37
|
+
* import { defaultClientDir } from "@alexkroman1/aai-ui/client-dir";
|
|
38
|
+
*
|
|
39
|
+
* const server = createAgentServer({
|
|
40
|
+
* agent: agent({ name: "Support" }),
|
|
41
|
+
* env: {},
|
|
42
|
+
* clientDir: defaultClientDir(),
|
|
43
|
+
* });
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* @public
|
|
47
|
+
*/
|
|
48
|
+
function defaultClientDir() {
|
|
49
|
+
let pkgPath;
|
|
50
|
+
try {
|
|
51
|
+
pkgPath = require.resolve("@alexkroman1/aai-ui/package.json");
|
|
52
|
+
} catch (err) {
|
|
53
|
+
throw new Error("Could not locate the default client UI — is @alexkroman1/aai-ui installed? Try reinstalling dependencies (pnpm install).", { cause: err });
|
|
54
|
+
}
|
|
55
|
+
return path.join(path.dirname(pkgPath), "dist", "default-client");
|
|
56
|
+
}
|
|
57
|
+
//#endregion
|
|
58
|
+
export { defaultClientDir };
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Who this browser is to an agent: the id `mountClient({ client: "auto" })`
|
|
3
|
+
* sends as `?client=`, the inbox HOLDER id of this tab, and the
|
|
4
|
+
* `session.identity` handle both are read from.
|
|
5
|
+
*
|
|
6
|
+
* ## Why the SDK mints the client id
|
|
7
|
+
*
|
|
8
|
+
* A client id is what a tool hands a workflow run (`sessionClientId(ctx)`) so
|
|
9
|
+
* the run's `stepNotifyClient` can reach this browser AFTER the session that
|
|
10
|
+
* started it has closed — a reminder due tomorrow is delivered to whoever holds
|
|
11
|
+
* the id tomorrow. So it must be the SAME id on the session socket and on the
|
|
12
|
+
* inbox socket, and it must outlive the tab. Every app that wanted a reminder in
|
|
13
|
+
* a browser wrote the same thirty lines (a `localStorage` read, a validity
|
|
14
|
+
* check, a fallback for private mode) and got the second half of this module
|
|
15
|
+
* wrong: see the holder below.
|
|
16
|
+
*
|
|
17
|
+
* - **`localStorage`, keyed by the agent's URL** (`_web-storage.ts`'s rule). Two
|
|
18
|
+
* agents served from one origin — every deployed agent, at `/:slug/` — must
|
|
19
|
+
* not share one: the id is the ONLY credential for a client's durable
|
|
20
|
+
* conversation (`VoiceSessionOptions.client`), so agent A's server, which
|
|
21
|
+
* receives it, could otherwise present it to agent B and read B's history.
|
|
22
|
+
* - **Unguessable**: 128 random bits, from `crypto.getRandomValues` — which,
|
|
23
|
+
* unlike `crypto.randomUUID`, exists outside a secure context, and `aai dev`
|
|
24
|
+
* on a LAN address is plain `http:`.
|
|
25
|
+
* - **Private mode** (storage throws or is absent) degrades to an id for THIS
|
|
26
|
+
* TAB, held in memory: the session and inbox still agree, a reminder set in
|
|
27
|
+
* the tab reaches the tab, and nothing outlives it.
|
|
28
|
+
*
|
|
29
|
+
* ## Why the holder is per TAB, not per browser
|
|
30
|
+
*
|
|
31
|
+
* The inbox keeps one socket per (client, holder) pair, and the same pair again
|
|
32
|
+
* REPLACES the old socket — right for a device back from a Wi-Fi drop, whose old
|
|
33
|
+
* socket is half-dead. Every tab of a browser shares `localStorage`, so an app
|
|
34
|
+
* that used the browser-wide id as the holder had two tabs presenting the same
|
|
35
|
+
* pair: each connect knocked the other tab off, the other reconnected on its
|
|
36
|
+
* backoff and knocked this one off, about once a second, forever. The holder is
|
|
37
|
+
* the browser id plus a suffix minted once per PAGE LOAD, so tabs coexist as
|
|
38
|
+
* holders of one client and every one of them is offered the notice.
|
|
39
|
+
*
|
|
40
|
+
* @module
|
|
41
|
+
*/
|
|
42
|
+
/**
|
|
43
|
+
* This browser's stable client id for the agent at `platformUrl` —
|
|
44
|
+
* `browser-<32 hex>`, minted once and kept in `localStorage`. The id
|
|
45
|
+
* `mountClient({ client: "auto" })` sends; call it yourself to compose it, e.g.
|
|
46
|
+
* a page joined to a speaker that sends the speaker's id instead:
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* import { browserClientId, mountClient } from "@alexkroman1/aai-ui";
|
|
51
|
+
*
|
|
52
|
+
* declare function linkedSpeaker(): string | undefined;
|
|
53
|
+
*
|
|
54
|
+
* mountClient({ client: () => linkedSpeaker() ?? browserClientId() });
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* A stored value that is not a valid client id (letters, digits, `-`, `_`, at
|
|
58
|
+
* most 64) is replaced. Where storage is unavailable the id lasts for this tab.
|
|
59
|
+
*
|
|
60
|
+
* @param platformUrl - The agent's base URL; the id is per agent. Defaults to
|
|
61
|
+
* the page's own, which is `mountClient()`'s default too.
|
|
62
|
+
* @returns The id — the same one on every call for the same agent.
|
|
63
|
+
*
|
|
64
|
+
* @public
|
|
65
|
+
*/
|
|
66
|
+
export declare function browserClientId(platformUrl?: string): string;
|
|
67
|
+
/**
|
|
68
|
+
* This TAB's inbox holder id for the agent at `platformUrl`: the browser id
|
|
69
|
+
* plus a per-page-load suffix. Never the browser id alone — see the module doc
|
|
70
|
+
* for the two tabs that knocked each other off once a second.
|
|
71
|
+
*
|
|
72
|
+
* @internal
|
|
73
|
+
*/
|
|
74
|
+
export declare function inboxHolderId(platformUrl: string): string;
|
|
75
|
+
/**
|
|
76
|
+
* Who a session is to its agent — `session.identity`. Everything here is read
|
|
77
|
+
* NOW (a getter `client` can change between attempts), and nothing is a
|
|
78
|
+
* subscription: `useClientId()` and `useSessionId()` are the reactive reads.
|
|
79
|
+
*
|
|
80
|
+
* @sealed Only `createBrowserSession` produces one.
|
|
81
|
+
*
|
|
82
|
+
* @public
|
|
83
|
+
*/
|
|
84
|
+
export type SessionIdentity = {
|
|
85
|
+
/** The agent's base URL the session dials — `VoiceSessionOptions.platformUrl`. */
|
|
86
|
+
readonly platformUrl: string;
|
|
87
|
+
/**
|
|
88
|
+
* The client id the next connection attempt sends as `?client=`, trimmed, or
|
|
89
|
+
* `undefined` when it sends none. With `client: "auto"` it is
|
|
90
|
+
* {@link browserClientId}; with a getter it is the getter's answer now.
|
|
91
|
+
*/
|
|
92
|
+
clientId(): string | undefined;
|
|
93
|
+
/**
|
|
94
|
+
* This tab's `?holder=` for the client's `WS /inbox` socket — per TAB, so two
|
|
95
|
+
* tabs of one browser coexist instead of replacing each other's socket.
|
|
96
|
+
*/
|
|
97
|
+
holderId(): string;
|
|
98
|
+
/**
|
|
99
|
+
* The server's id for the current session: `undefined` until the first
|
|
100
|
+
* `config` frame of a session, and again after `end()`. A resume or a new
|
|
101
|
+
* session sets it from its own `config` frame. Sensitive — see
|
|
102
|
+
* `VoiceSessionOptions.onSessionId`.
|
|
103
|
+
*/
|
|
104
|
+
sessionId(): string | undefined;
|
|
105
|
+
/**
|
|
106
|
+
* A session ticket for ANOTHER socket on the same server — what `useInbox()`
|
|
107
|
+
* presents on `WS /inbox`, which a gated server checks exactly like
|
|
108
|
+
* `/websocket`. The session's own `token` option when it has one; otherwise a
|
|
109
|
+
* fresh one from the server's `client-config` (`aai dev` with
|
|
110
|
+
* `AAI_SESSION_SECRET`), until a lookup shows the server issues none.
|
|
111
|
+
* `undefined` means "present none". Fresh on every call: tickets are short-lived.
|
|
112
|
+
*/
|
|
113
|
+
ticket(): string | undefined | Promise<string | undefined>;
|
|
114
|
+
};
|
|
115
|
+
/** The client option as the dialer reads it: `"auto"` resolved, everything else as given. */
|
|
116
|
+
export declare function resolveClientOption(client: string | (() => string | undefined) | undefined, platformUrl: string): string | (() => string | undefined) | undefined;
|
|
117
|
+
/** A string-or-getter option resolved NOW, trimmed; an empty answer is none. */
|
|
118
|
+
export declare function resolveReported(value: string | (() => string | undefined) | undefined): string | undefined;
|
|
119
|
+
/** What the identity reads from the session's dialer. */
|
|
120
|
+
type IdentitySource = Pick<SessionIdentity, "sessionId" | "ticket">;
|
|
121
|
+
/**
|
|
122
|
+
* Build a session's {@link SessionIdentity}. `sessionId` and `ticket` are the
|
|
123
|
+
* dialer's (read through `source`, which may answer nothing): it owns the id
|
|
124
|
+
* because it sees every `config` frame, `end()` and `resume()`, and the ticket
|
|
125
|
+
* because it holds the `token` option and the server's `client-config` latch.
|
|
126
|
+
*/
|
|
127
|
+
export declare function createSessionIdentity(options: {
|
|
128
|
+
platformUrl: string;
|
|
129
|
+
client?: string | (() => string | undefined) | undefined;
|
|
130
|
+
}, source: () => IdentitySource | undefined): SessionIdentity;
|
|
131
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The page's half of a `clientTool`: run the handler when the agent calls the
|
|
3
|
+
* tool, and send what it returned back as the call's result.
|
|
4
|
+
*
|
|
5
|
+
* Built on {@link useToolCallStart}, so it inherits that hook's dedup — one run
|
|
6
|
+
* per `toolCallId` per mounted hook — and its mount rule: a call still PENDING
|
|
7
|
+
* when the hook mounts is run (the server may be waiting on it, e.g. across a
|
|
8
|
+
* resume), a call that already completed is history and is not.
|
|
9
|
+
*
|
|
10
|
+
* @module
|
|
11
|
+
*/
|
|
12
|
+
import type { ToolCallInfo } from "./types.ts";
|
|
13
|
+
/**
|
|
14
|
+
* Run a `clientTool` in this page and answer the agent with its result.
|
|
15
|
+
*
|
|
16
|
+
* When the model calls the tool named `toolName`, `handler` runs with the
|
|
17
|
+
* call's arguments. What it returns (or resolves to) is JSON-serialized and
|
|
18
|
+
* becomes the tool's result — the value the model reads. A handler that throws
|
|
19
|
+
* or rejects fails the call, and the model is told the error's message, as it
|
|
20
|
+
* would be for a server tool.
|
|
21
|
+
*
|
|
22
|
+
* The server waits only as long as the tool's `timeoutMs` (default 30 s); an
|
|
23
|
+
* answer after that, or while disconnected, is dropped. Mount the hook once per
|
|
24
|
+
* tool: two mounted handlers both run, and only the first answer counts.
|
|
25
|
+
*
|
|
26
|
+
* @example Let the agent ask for the caller's location
|
|
27
|
+
* ```tsx
|
|
28
|
+
* import { useClientTool } from "@alexkroman1/aai-ui";
|
|
29
|
+
*
|
|
30
|
+
* function LocationTool() {
|
|
31
|
+
* useClientTool("get_location", () =>
|
|
32
|
+
* new Promise((resolve, reject) =>
|
|
33
|
+
* navigator.geolocation.getCurrentPosition(
|
|
34
|
+
* (p) => resolve({ lat: p.coords.latitude, lon: p.coords.longitude }),
|
|
35
|
+
* (err) => reject(new Error(err.message)),
|
|
36
|
+
* ),
|
|
37
|
+
* ),
|
|
38
|
+
* );
|
|
39
|
+
* return null;
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @typeParam A - The tool's argument shape. Name it, or derive it with a
|
|
44
|
+
* TYPE-ONLY import of the server tool: `useClientTool<InferToolInput<typeof
|
|
45
|
+
* getLocation>>(…)`.
|
|
46
|
+
* @param toolName - The name of the `clientTool` — its `tools/<name>.ts` file.
|
|
47
|
+
* @param handler - Runs the call; its return value is the result.
|
|
48
|
+
*
|
|
49
|
+
* @public
|
|
50
|
+
*/
|
|
51
|
+
export declare function useClientTool<A = ToolCallInfo["args"]>(toolName: string, handler: (args: A, toolCall: ToolCallInfo) => unknown): void;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared tints used by the default components (AssemblyAI design system,
|
|
3
|
+
* "website refresh": warm neutrals over the cream/white surfaces).
|
|
4
|
+
*
|
|
5
|
+
* These sit on top of the {@link ClientTheme} colors, which own the opaque
|
|
6
|
+
* palette. The neutral text steps are **derived from the theme** rather than
|
|
7
|
+
* hardcoded: `ClientTheme` documents `bg`/`surface`/`text` as free-form
|
|
8
|
+
* colors, so a client is free to hand the components a dark ground — and a
|
|
9
|
+
* fixed warm-grey scale tuned for cream leaves the AGENT/TOOL labels, every
|
|
10
|
+
* tool-call args preview, the chevron and both URL chips below WCAG AA while
|
|
11
|
+
* the prose and bubbles around them follow the theme correctly. Measured on a
|
|
12
|
+
* plausible dark theme before this was derived: 14 text nodes under 4.5:1
|
|
13
|
+
* (the faint step at 3.2–3.5:1, the muted step at 2.5:1), against zero on the
|
|
14
|
+
* default light theme.
|
|
15
|
+
*
|
|
16
|
+
* `ERROR_COLOR` and `THINKING_COLOR` stay fixed: they are *semantic* colors
|
|
17
|
+
* whose hue carries the meaning, so they cannot be re-derived from a theme
|
|
18
|
+
* that knows nothing about severity.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Blend `text` into `surface` by `pct`, giving a neutral step that stays on
|
|
22
|
+
* the theme's own ink/ground axis. On a light theme this walks *down* from
|
|
23
|
+
* the surface toward the ink; on a dark one it walks *up* from the ground
|
|
24
|
+
* toward the light ink — the same call reads correctly either way, which is
|
|
25
|
+
* the whole reason to derive rather than hardcode.
|
|
26
|
+
*/
|
|
27
|
+
export declare function inkTint(text: string, surface: string, pct: number): string;
|
|
28
|
+
/**
|
|
29
|
+
* Muted text — subtitles, secondary labels, thinking dots (fg-muted).
|
|
30
|
+
* 75% lands within a couple of RGB steps of the design system's `#57534B`
|
|
31
|
+
* on the default theme.
|
|
32
|
+
*/
|
|
33
|
+
export declare const INK_MUTED_PCT = 75;
|
|
34
|
+
/**
|
|
35
|
+
* Faint text — live transcripts, state indicator, start-screen subtitle.
|
|
36
|
+
* 65% reproduces the design system's `#6F6A60` on the default theme.
|
|
37
|
+
*/
|
|
38
|
+
export declare const INK_FAINT_PCT = 65;
|
|
39
|
+
/** Subtle surface tint — inline code, tool-call chips, message bubbles. */
|
|
40
|
+
export declare const INK_SURFACE_PCT = 3;
|
|
41
|
+
/** Error red tuned for warm light surfaces. */
|
|
42
|
+
export declare const ERROR_COLOR = "#B3261E";
|
|
43
|
+
/** Amber used by the "thinking" state indicator. */
|
|
44
|
+
export declare const THINKING_COLOR = "#B98900";
|
|
45
|
+
/**
|
|
46
|
+
* Derive the user-bubble fill/edge from the theme primary (the mock's
|
|
47
|
+
* indigo-50 background with an indigo-100 border), so custom themes keep a
|
|
48
|
+
* coherent tinted bubble instead of a hardcoded indigo.
|
|
49
|
+
*/
|
|
50
|
+
export declare function primaryTint(primary: string, surface: string, pct: number): string;
|
|
51
|
+
/**
|
|
52
|
+
* The focus ring, as the class half of a pair.
|
|
53
|
+
*
|
|
54
|
+
* The ring is the only thing a keyboard user gets, and it has regressed to
|
|
55
|
+
* invisible twice — `outline-none` shipped here with no replacement, on the
|
|
56
|
+
* button and then on the URL chips, which is WCAG 2.4.7 on every control in the
|
|
57
|
+
* default client. Written as a SHORTHAND so it cannot be undone by Tailwind's
|
|
58
|
+
* shared `--tw-outline-style` variable.
|
|
59
|
+
*
|
|
60
|
+
* It is inert on its own: an outline with no colour draws nothing, so a control
|
|
61
|
+
* using this must also spread {@link focusRingStyle}. Naming the two together
|
|
62
|
+
* is what stops the next control shipping one without the other.
|
|
63
|
+
*/
|
|
64
|
+
export declare const FOCUS_RING = "outline-none focus-visible:[outline:2px_solid] focus-visible:[outline-offset:2px]";
|
|
65
|
+
/**
|
|
66
|
+
* The style half of {@link FOCUS_RING} — the colour the outline draws in.
|
|
67
|
+
*
|
|
68
|
+
* A real CSS property rather than a variant class, so the `focus-visible` rule
|
|
69
|
+
* only has to turn the outline on.
|
|
70
|
+
*/
|
|
71
|
+
export declare function focusRingStyle(primary: string): {
|
|
72
|
+
outlineColor: string;
|
|
73
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a form's own fields exist yet.
|
|
3
|
+
*
|
|
4
|
+
* `<Form>` leans entirely on NATIVE validation — it is a real `<form>` with no
|
|
5
|
+
* `noValidate`, so a `required` field is what stops an empty submit, and the
|
|
6
|
+
* module doc next door says so. That has one hole, and it is the whole reason
|
|
7
|
+
* this exists: a field set declared REMOTELY is not in the DOM while its
|
|
8
|
+
* declaration is in flight, so there is nothing for the browser to validate and
|
|
9
|
+
* an empty submit sails through.
|
|
10
|
+
*
|
|
11
|
+
* It is not theoretical. `<WorkflowFields>` renders `null` until the workflow
|
|
12
|
+
* listing lands, so the transcription desk's first click — before the one-request
|
|
13
|
+
* lookup answered — submitted a form holding only its button. The browser was
|
|
14
|
+
* happy, the payload was `{}`, and the run was refused by the agent with
|
|
15
|
+
* `Invalid input for workflow "transcribeStream": recording: Invalid input`: a
|
|
16
|
+
* schema complaint about a field the person had not been shown, naming a workflow
|
|
17
|
+
* they did not choose by name, for a file picker that appeared a moment later.
|
|
18
|
+
*
|
|
19
|
+
* ## Readiness is DECLARED by the children, because only they know
|
|
20
|
+
*
|
|
21
|
+
* `Form` cannot ask. It renders `{children}` and reads the DOM on submit, and a
|
|
22
|
+
* pending fetch leaves no trace in the DOM at all — which is exactly the
|
|
23
|
+
* difference from `data-aai-read`, the other thing a child tells the form: that
|
|
24
|
+
* one describes an element that EXISTS. So this is a context rather than an
|
|
25
|
+
* attribute, and it carries the one fact a DOM read cannot recover.
|
|
26
|
+
*
|
|
27
|
+
* A form with no such children is ready by definition — `useFormReadiness`
|
|
28
|
+
* outside a provider reports nothing pending, so every hand-written form is
|
|
29
|
+
* unaffected and `Form` keeps working outside this package.
|
|
30
|
+
*/
|
|
31
|
+
/** What a child calls to say whether its own fields are ready. */
|
|
32
|
+
type Readiness = (key: string, pending: boolean) => void;
|
|
33
|
+
export declare const FormReadinessProvider: import("react").Provider<Readiness | undefined>;
|
|
34
|
+
/**
|
|
35
|
+
* Track which children are still waiting for their fields.
|
|
36
|
+
*
|
|
37
|
+
* A SET keyed by the child's own `useId`, not a counter: a child that re-renders
|
|
38
|
+
* while pending must not increment twice, and one that unmounts mid-flight must
|
|
39
|
+
* not leave the form disabled forever. Both are the ordinary lifecycle here — a
|
|
40
|
+
* page that switches workflows swaps one `<WorkflowFields>` for another.
|
|
41
|
+
*/
|
|
42
|
+
export declare function useFormReadiness(): {
|
|
43
|
+
pending: boolean;
|
|
44
|
+
declare: Readiness;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Declare from a child that its fields are, or are no longer, still loading.
|
|
48
|
+
*
|
|
49
|
+
* Reports through an EFFECT rather than during render, because this writes to a
|
|
50
|
+
* parent's state — doing it in the render body is the "cannot update a component
|
|
51
|
+
* while rendering a different component" warning, and under StrictMode it is a
|
|
52
|
+
* double report the parent has to be idempotent about anyway. The cleanup
|
|
53
|
+
* releases the claim, so an unmounted field set never holds the form shut.
|
|
54
|
+
*/
|
|
55
|
+
export declare function useDeclareFieldsPending(pending: boolean): void;
|
|
56
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading a `<form>`'s named controls into a plain object.
|
|
3
|
+
*
|
|
4
|
+
* Split from `form.tsx` because it is the half with no JSX in it and the half
|
|
5
|
+
* that carries the rules: what a control CONTRIBUTES is the contract — the
|
|
6
|
+
* object goes straight into a workflow's input, where a zod schema is waiting —
|
|
7
|
+
* and each branch below is a decision about that rather than about rendering.
|
|
8
|
+
*
|
|
9
|
+
* See `form.tsx`'s module doc for why the values come off the DOM at all.
|
|
10
|
+
*/
|
|
11
|
+
import type { FormValues } from "./form-types.ts";
|
|
12
|
+
/**
|
|
13
|
+
* Read one `<form>`'s named controls into a plain object.
|
|
14
|
+
*
|
|
15
|
+
* Exported for tests and for a caller doing its own submit handling.
|
|
16
|
+
*
|
|
17
|
+
* @internal
|
|
18
|
+
*/
|
|
19
|
+
export declare function collectValues(form: HTMLFormElement): Promise<FormValues>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The AssemblyAI wordmark (design-system "website refresh" asset).
|
|
3
|
+
*
|
|
4
|
+
* The mark keeps its brand blues; the letterforms inherit the theme's text
|
|
5
|
+
* color so the logo works on the cream default and custom themes alike.
|
|
6
|
+
*
|
|
7
|
+
* @param size - Rendered height in px. Defaults to 20.
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export declare const AaiLogo: import("react").MemoExoticComponent<({ size }: {
|
|
11
|
+
size?: number;
|
|
12
|
+
}) => import("react").JSX.Element>;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import type { UseDownloadUrlResult } from "../use-download-url.ts";
|
|
3
|
+
/**
|
|
4
|
+
* A one-cue caption track for {@link AudioResult}: the words the clip speaks,
|
|
5
|
+
* spanning its whole length.
|
|
6
|
+
*
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
export type AudioResultCaptions = {
|
|
10
|
+
/** The spoken text — the one cue. */
|
|
11
|
+
text: string;
|
|
12
|
+
/** The clip's length, which is where the cue ends. */
|
|
13
|
+
durationMs: number;
|
|
14
|
+
/** The track's `label`. Defaults to the player's `label`. */
|
|
15
|
+
label?: string | undefined;
|
|
16
|
+
/** The track's `srcLang`. Default `"en"`. */
|
|
17
|
+
srcLang?: string | undefined;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Props of {@link AudioResult}.
|
|
21
|
+
*
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
export type AudioResultProps = {
|
|
25
|
+
/** What {@link useDownloadUrl} returned for the run's audio upload. */
|
|
26
|
+
download: UseDownloadUrlResult;
|
|
27
|
+
/** The name the download link saves as — `"summary.wav"`, `"audit.mp3"`. */
|
|
28
|
+
filename: string;
|
|
29
|
+
/** The player's `aria-label`: what this audio IS — `"Summary read aloud"`. */
|
|
30
|
+
label: string;
|
|
31
|
+
/**
|
|
32
|
+
* The heading over the player — typically the duration and size, which the
|
|
33
|
+
* run's output carries. Omitted, there is no heading.
|
|
34
|
+
*/
|
|
35
|
+
heading?: ReactNode | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* The spoken text as a caption track. Omit it deliberately when the same
|
|
38
|
+
* words are rendered in full beside the player (see the component doc);
|
|
39
|
+
* pass it when they are not, or when a real track is what a page needs.
|
|
40
|
+
*/
|
|
41
|
+
captions?: AudioResultCaptions | undefined;
|
|
42
|
+
/** Additional CSS class names for the wrapping `<section>`, appended to its own. */
|
|
43
|
+
className?: string | undefined;
|
|
44
|
+
/** Rendered under the player — the spoken text, usually. */
|
|
45
|
+
children?: ReactNode;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* The player for a file a RUN produced: a heading, the fetch's pending line,
|
|
49
|
+
* its announced error, the `<audio>` with an optional caption track, the
|
|
50
|
+
* download link, and whatever the page renders beneath — the spoken text.
|
|
51
|
+
*
|
|
52
|
+
* Two templates exist because of the audio round trip, and both had written
|
|
53
|
+
* this block over {@link useDownloadUrl} identically: the same pending
|
|
54
|
+
* sentence, the same `role="alert"` paragraph, the same `<audio controls>` over
|
|
55
|
+
* the object URL, the same anchor with `download` set. The `download` attribute
|
|
56
|
+
* works on an object URL because the bytes are already in the tab — it was the
|
|
57
|
+
* `href` that could not carry the agent's bearer token, never the attribute —
|
|
58
|
+
* and that is the whole reason both pages hand this a hook result rather than a
|
|
59
|
+
* path.
|
|
60
|
+
*
|
|
61
|
+
* **A caption track is a judgement, not a default.** `spoken-summary-workflow` passes
|
|
62
|
+
* `captions`: the summary was written before it was spoken, so one cue
|
|
63
|
+
* spanning the clip is an honest transcript of it. `call-audit-workflow` deliberately
|
|
64
|
+
* does not: the spoken text is rendered in full immediately below the player,
|
|
65
|
+
* which is the same information a track would carry. Both are right, which is
|
|
66
|
+
* why the prop is optional in both directions.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```tsx
|
|
70
|
+
* import { AudioResult, createWorkflowApi, useDownloadUrl } from "@alexkroman1/aai-ui";
|
|
71
|
+
*
|
|
72
|
+
* const api = createWorkflowApi();
|
|
73
|
+
*
|
|
74
|
+
* function Player({ id, spoken, ms }: { id: string; spoken: string; ms: number }) {
|
|
75
|
+
* const audio = useDownloadUrl(id, { api });
|
|
76
|
+
* return (
|
|
77
|
+
* <AudioResult
|
|
78
|
+
* download={audio}
|
|
79
|
+
* filename="summary.wav"
|
|
80
|
+
* label="Summary read aloud"
|
|
81
|
+
* heading="Read aloud"
|
|
82
|
+
* captions={{ text: spoken, durationMs: ms }}
|
|
83
|
+
* >
|
|
84
|
+
* <p className="text-sm opacity-70">{spoken}</p>
|
|
85
|
+
* </AudioResult>
|
|
86
|
+
* );
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*
|
|
90
|
+
* @param props - See {@link AudioResultProps}.
|
|
91
|
+
*
|
|
92
|
+
* @public
|
|
93
|
+
*/
|
|
94
|
+
export declare function AudioResult({ download, filename, label, heading, captions, className, children, }: AudioResultProps): ReactNode;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { CSSProperties, ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* A scroll container that stays pinned to the bottom as its content grows,
|
|
4
|
+
* releases when the reader scrolls up, and re-engages once they return to the
|
|
5
|
+
* bottom.
|
|
6
|
+
*
|
|
7
|
+
* For clients that render their own chat chrome instead of using
|
|
8
|
+
* {@link MessageList} — a terminal, a dispatch board, a themed transcript.
|
|
9
|
+
* `MessageList` already behaves this way; this is the same mechanism with no
|
|
10
|
+
* opinion about what goes inside it.
|
|
11
|
+
*
|
|
12
|
+
* @remarks
|
|
13
|
+
* The pattern this replaces is a `useEffect` that calls
|
|
14
|
+
* `ref.current?.scrollIntoView()` on every message change. That version has
|
|
15
|
+
* three faults, and they compound: it fights the reader, since scrolling up to
|
|
16
|
+
* re-read is undone by the next transcript delta; it misses growth that is not
|
|
17
|
+
* a new message, because a streamed reply, an expanding tool block or a
|
|
18
|
+
* markdown reflow changes height without changing the dependency array; and it
|
|
19
|
+
* needs a synthetic dependency (`messages.length + transcript.length`) to fire
|
|
20
|
+
* at all, which is where the dead `if (version < 0) return;` line comes from.
|
|
21
|
+
* A `ResizeObserver` on the content — what this uses — has none of those.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```tsx
|
|
25
|
+
* import { AutoScroll, useSession } from "@alexkroman1/aai-ui";
|
|
26
|
+
*
|
|
27
|
+
* function Transcript() {
|
|
28
|
+
* const session = useSession();
|
|
29
|
+
* return (
|
|
30
|
+
* <AutoScroll className="flex-1 min-h-0" contentClassName="flex flex-col gap-2 p-4">
|
|
31
|
+
* {session.messages.map((m) => (
|
|
32
|
+
* <div key={m.id}>{m.content}</div>
|
|
33
|
+
* ))}
|
|
34
|
+
* </AutoScroll>
|
|
35
|
+
* );
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @param props - Scroll container props.
|
|
40
|
+
*
|
|
41
|
+
* @public
|
|
42
|
+
*/
|
|
43
|
+
export declare function AutoScroll({ children, className, contentClassName, scrollClassName, style, initial, resize, }: {
|
|
44
|
+
/** The scrollable content. */
|
|
45
|
+
children: ReactNode;
|
|
46
|
+
/**
|
|
47
|
+
* Classes for the outer container, appended to its own.
|
|
48
|
+
*
|
|
49
|
+
* **The container must end up with a bounded height** (`flex-1 min-h-0`,
|
|
50
|
+
* `h-full`, a fixed height). This is the one constraint callers get wrong:
|
|
51
|
+
* an unbounded container grows with its content and never scrolls, so
|
|
52
|
+
* nothing pins and the component silently does nothing.
|
|
53
|
+
*/
|
|
54
|
+
className?: string | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* Classes for the inner content element, where padding and the children's
|
|
57
|
+
* own layout belong.
|
|
58
|
+
*/
|
|
59
|
+
contentClassName?: string | undefined;
|
|
60
|
+
/**
|
|
61
|
+
* Classes for the scrolling element itself. Defaults to hiding the
|
|
62
|
+
* scrollbar; pass `"overflow-y-auto"` to show a native one.
|
|
63
|
+
*/
|
|
64
|
+
scrollClassName?: string | undefined;
|
|
65
|
+
/** Inline styles for the outer container. */
|
|
66
|
+
style?: CSSProperties | undefined;
|
|
67
|
+
/**
|
|
68
|
+
* Scroll behavior on mount. Defaults to `"instant"` — start at the latest
|
|
69
|
+
* content without animating a scroll the reader did not ask for.
|
|
70
|
+
*/
|
|
71
|
+
initial?: "instant" | "smooth" | undefined;
|
|
72
|
+
/** Scroll behavior when pinned content grows. Defaults to `"smooth"`. */
|
|
73
|
+
resize?: "instant" | "smooth" | undefined;
|
|
74
|
+
}): ReactNode;
|