@tribepad/themis 1.3.4 → 1.4.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 (63) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/elements/ChatInterface/ChatInputArea.d.ts +37 -0
  3. package/dist/elements/ChatInterface/ChatInputArea.d.ts.map +1 -0
  4. package/dist/elements/ChatInterface/ChatInterface.d.ts +24 -0
  5. package/dist/elements/ChatInterface/ChatInterface.d.ts.map +1 -0
  6. package/dist/elements/ChatInterface/ChatInterface.hooks.d.ts +46 -0
  7. package/dist/elements/ChatInterface/ChatInterface.hooks.d.ts.map +1 -0
  8. package/dist/elements/ChatInterface/ChatInterface.styles.d.ts +83 -0
  9. package/dist/elements/ChatInterface/ChatInterface.styles.d.ts.map +1 -0
  10. package/dist/elements/ChatInterface/ChatInterface.types.d.ts +340 -0
  11. package/dist/elements/ChatInterface/ChatInterface.types.d.ts.map +1 -0
  12. package/dist/elements/ChatInterface/ChatLiveRegions.d.ts +13 -0
  13. package/dist/elements/ChatInterface/ChatLiveRegions.d.ts.map +1 -0
  14. package/dist/elements/ChatInterface/ChatMessageBubble.d.ts +24 -0
  15. package/dist/elements/ChatInterface/ChatMessageBubble.d.ts.map +1 -0
  16. package/dist/elements/ChatInterface/ChatMessageList.d.ts +32 -0
  17. package/dist/elements/ChatInterface/ChatMessageList.d.ts.map +1 -0
  18. package/dist/elements/ChatInterface/ChatThinkingDisplay.d.ts +20 -0
  19. package/dist/elements/ChatInterface/ChatThinkingDisplay.d.ts.map +1 -0
  20. package/dist/elements/ChatInterface/ChatTypingIndicator.d.ts +11 -0
  21. package/dist/elements/ChatInterface/ChatTypingIndicator.d.ts.map +1 -0
  22. package/dist/elements/ChatInterface/DefaultChatInput.d.ts +18 -0
  23. package/dist/elements/ChatInterface/DefaultChatInput.d.ts.map +1 -0
  24. package/dist/elements/ChatInterface/index.d.ts +7 -0
  25. package/dist/elements/ChatInterface/index.d.ts.map +1 -0
  26. package/dist/elements/ChatInterface/index.js +3 -0
  27. package/dist/elements/ChatInterface/index.js.map +1 -0
  28. package/dist/elements/ChatInterface/index.mjs +3 -0
  29. package/dist/elements/ChatInterface/index.mjs.map +1 -0
  30. package/dist/elements/DatePicker/Calendar.d.ts +1 -1
  31. package/dist/elements/DatePicker/DateField.d.ts +1 -1
  32. package/dist/elements/DatePicker/DateField.d.ts.map +1 -1
  33. package/dist/elements/DatePicker/DatePicker.d.ts +1 -1
  34. package/dist/elements/DatePicker/DatePicker.d.ts.map +1 -1
  35. package/dist/elements/DatePicker/DatePicker.types.d.ts +1 -1
  36. package/dist/elements/DatePicker/DateRangePicker.d.ts +1 -1
  37. package/dist/elements/DatePicker/DateRangePicker.d.ts.map +1 -1
  38. package/dist/elements/FileField/FileField.types.d.ts +1 -1
  39. package/dist/elements/FileField/FileProgress.variants.d.ts +1 -1
  40. package/dist/elements/OTPInput/index.js +1 -1
  41. package/dist/elements/OTPInput/index.js.map +1 -1
  42. package/dist/elements/OTPInput/index.mjs +1 -1
  43. package/dist/elements/OTPInput/index.mjs.map +1 -1
  44. package/dist/elements/Resizable/index.js +1 -1
  45. package/dist/elements/Resizable/index.js.map +1 -1
  46. package/dist/elements/Resizable/index.mjs +1 -1
  47. package/dist/elements/Resizable/index.mjs.map +1 -1
  48. package/dist/elements/TimeField/TimeField.d.ts +1 -1
  49. package/dist/elements/TimeField/TimeField.d.ts.map +1 -1
  50. package/dist/elements/index.d.ts +3 -0
  51. package/dist/elements/index.d.ts.map +1 -1
  52. package/dist/elements/index.js +1 -1
  53. package/dist/elements/index.js.map +1 -1
  54. package/dist/elements/index.mjs +1 -1
  55. package/dist/elements/index.mjs.map +1 -1
  56. package/dist/index.js +2 -2
  57. package/dist/index.js.map +1 -1
  58. package/dist/index.mjs +2 -2
  59. package/dist/index.mjs.map +1 -1
  60. package/dist/styles/defaults.css +3 -0
  61. package/package.json +29 -21
  62. package/src/elements/ChatInterface/ChatInterface.stories.tsx +495 -0
  63. package/src/elements/ChatInterface/README.md +408 -0
package/CHANGELOG.md CHANGED
@@ -5,6 +5,39 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.4.0] - 2026-04-30
9
+
10
+ ### Added
11
+ - **ChatInterface** — accessible chatbot UI element for hosting AI support chats (WCAG 2.2 AAA target).
12
+ - Stateless / fully controlled: consumer owns `messages[]`, `status`, websocket, persistence; ChatInterface emits events (`onSendMessage`, `onStopGeneration`, `onRetry`, `onEscalate`).
13
+ - Live-region architecture: `<div role="log">` is visual + navigable (no `aria-live`); a single sr-only `<div role="status" aria-live="polite">` is the canonical AT announcement channel with FIFO queue, 500ms min interval, 1s dedup, 32-entry cap, 200ms hold.
14
+ - Announcements: completion (preview from rendered DOM `innerText`, normalised + truncated to clamped [50, 1000] chars), generation-stopped, response-failed, bounded slow-response "still working" pings (3s/15s/60s, capped at 3, visibility-gated, suppressible via `progressAnnouncements: false`).
15
+ - Pluggable input: built-in Themis-styled multi-line textarea (`field-sizing: content` primary path with rAF-batched JS fallback, IME-safe Enter via `event.isComposing || keyCode === 229`, `autoComplete="off"`); consumers can swap in a rich-text editor via `inputComponent` honouring a small forwardRef contract (`focus`/`clear`/`submit`/`setValue`).
16
+ - Render-prop content: `renderAssistantContent` / `renderUserContent` for consumer-owned markdown rendering (library treats `content` as opaque). Bounded LRU cache (200 entries, `(id, content)` keyed) skips re-rendering completed messages on token ticks.
17
+ - Memoised bubble with custom comparator covering `id`/`role`/`status`/`content`/`errorMessage`/`createdAt` + shallow-equal `parts`; documented immutability requirement on the `messages` prop.
18
+ - Auto-scroll: IntersectionObserver sentinel (256px `rootMargin` to tolerate `content-visibility: auto` placeholder churn); `overflow-anchor: none` to prevent browser anchoring fighting auto-scroll; rAF-throttled scroll on streaming-bubble growth; reduced-motion forces non-smooth.
19
+ - Reduced motion: streaming bubble shows static "Generating response…" placeholder instead of revealing tokens; typing dots, thinking pill, running tool-call spinner are static; `prefers-reduced-motion: reduce` honoured throughout.
20
+ - Three-layer architecture: Send/Stop/Retry/Escalate/Jump-to-latest all reuse Themis Button's 44×44 touch targets; input wrapper has `min-h-[44px]` to align with buttons.
21
+ - Discriminated-union message model (user / assistant / system) with strict (`.strict()`) Zod schemas. System messages bypass renderers; thinking parts (`text` / `tool_call`) render as visible rows during thinking, collapse into a `<details>` "Thoughts" disclosure when the response begins.
22
+ - Security: no `dangerouslySetInnerHTML` anywhere (regression-tested); JSX-escaping for all consumer-supplied strings; Unicode normalisation strips C0/C1, zero-width, bidi overrides, isolates, BOM from announcement text; `maxInputLength` enforced as defence-in-depth at the ChatInterface boundary; XSS-as-text test matrix.
23
+ - 85 new tests across `.contract.test.ts`, `.test.tsx`, `.a11y.test.tsx`. Storybook stories: Empty, PlainConversation, Streaming, Thinking, ErrorState, ByoMarkdown (with documented secure `react-markdown` + `rehype-sanitize` setup), CustomInput (RTE example), LongConversation (200 turns), ReducedMotion.
24
+ - Comprehensive component README at `src/elements/ChatInterface/README.md` documenting performance rules, security model, custom-input contract, AT behaviour, and v1 limitations (no message virtualisation past ~1000–2000 messages, no parts-first model, no attachments, no message editing UI; all v2 candidates).
25
+
26
+ ### Changed
27
+ - **`src/styles/defaults.css`** — added `--chat-input-max-lines` token (default `6`) for the ChatInterface input cap.
28
+
29
+ ## [1.3.5] - 2026-04-27
30
+
31
+ ### Security
32
+ - Patched the lone `pnpm audit` advisory by adding a `pnpm.overrides` entry for `postcss@<8.5.10` → `^8.5.12` (GHSA-qx2v-qp2m-jg93, XSS via unescaped `</style>` in CSS stringify output).
33
+
34
+ ### Changed
35
+ - Bumped 19 dependencies to latest patch/minor/major: `react-aria` 3.47→3.48, `react-aria-components` 1.16→1.17, `react-stately` 3.45→3.46, `eslint` 9→10 (with matching `@eslint/js`), `@vitejs/plugin-react` 5→6, `jsdom` 28→29, `size-limit` + `@size-limit/preset-small-lib` 11→12, `@storybook/addon-mcp` 0.4→0.6, `@internationalized/date` 3.12.0→3.12.1, `@tailwindcss/vite` 4.2.2→4.2.4, `@typescript-eslint/*` 8.58→8.59, `vite` 8.0.8→8.0.10, `vitest` 4.1.4→4.1.5, `@vitest/coverage-v8` 4.1.4→4.1.5, `lucide-react` 1.8→1.11, `eslint-plugin-storybook` 10.3.3→10.3.5. TypeScript held at 5.9.3 to keep emitted `.d.ts` compatible with downstream consumers on TS 5.
36
+
37
+ ### Fixed
38
+ - **`useResizable`** — removed dead initialisation of `newRightSize` (was unconditionally overwritten before being read); now declared via `let newRightSize: number;`. Behaviour unchanged.
39
+ - **`useOTPInput`** — same dead-initialisation cleanup for `isValid` in two locations; declared via `let isValid: boolean;`. Behaviour unchanged. Both fixes silence the new ESLint 10 `no-useless-assignment` rule.
40
+
8
41
  ## [1.3.2] - 2026-04-23
9
42
 
10
43
  ### Fixed
@@ -0,0 +1,37 @@
1
+ import { type ReactNode } from 'react';
2
+ import type { ChatInputComponent, ChatInputComponentHandle, ChatTopLevelStatus } from './ChatInterface.types';
3
+ /**
4
+ * Wraps the (default or custom) input + Send/Stop button + inputActions slot.
5
+ *
6
+ * The Send button is ALWAYS enabled when the input area isn't disabled — it does not gate on
7
+ * input emptiness. The contract guarantees `submit()` is no-op on empty input, so harmless
8
+ * clicks on an empty input produce no message.
9
+ *
10
+ * `isDisabled` truth table (forwarded to the input):
11
+ * - consumer.isDisabled === true → true
12
+ * - status === 'streaming' → true
13
+ * - status === 'error' → true
14
+ * - otherwise → false
15
+ *
16
+ * Stop button is shown only when status === 'streaming'.
17
+ */
18
+ interface ChatInputAreaProps {
19
+ status: ChatTopLevelStatus;
20
+ consumerDisabled: boolean;
21
+ inputComponent?: ChatInputComponent;
22
+ placeholder?: string;
23
+ maxInputLength?: number;
24
+ sendShortcut: 'enter' | 'mod-enter';
25
+ inputActions?: ReactNode;
26
+ inputAriaLabel: string;
27
+ /** Forwarded to consumer's `onSendMessage`. ChatInterface enforces maxInputLength backstop here. */
28
+ onSendMessage: (text: string) => void;
29
+ onStopGeneration?: () => void;
30
+ /** Receives the input handle so the parent can implement `chatRef.current.focusInput()`. */
31
+ registerInputHandle: (handle: ChatInputComponentHandle | null) => void;
32
+ /** Tells ChatInterface that an `error` → `idle` transition just happened so it can move focus. */
33
+ className?: string;
34
+ }
35
+ export declare function ChatInputArea({ status, consumerDisabled, inputComponent, placeholder, maxInputLength, sendShortcut, inputActions, inputAriaLabel, onSendMessage, onStopGeneration, registerInputHandle, className, }: ChatInputAreaProps): React.ReactElement;
36
+ export {};
37
+ //# sourceMappingURL=ChatInputArea.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatInputArea.d.ts","sourceRoot":"","sources":["../../../src/elements/ChatInterface/ChatInputArea.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAuB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAM5D,OAAO,KAAK,EACV,kBAAkB,EAClB,wBAAwB,EACxB,kBAAkB,EACnB,MAAM,uBAAuB,CAAC;AAE/B;;;;;;;;;;;;;;GAcG;AACH,UAAU,kBAAkB;IAC1B,MAAM,EAAE,kBAAkB,CAAC;IAC3B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,kBAAkB,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,OAAO,GAAG,WAAW,CAAC;IACpC,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,oGAAoG;IACpG,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,4FAA4F;IAC5F,mBAAmB,EAAE,CAAC,MAAM,EAAE,wBAAwB,GAAG,IAAI,KAAK,IAAI,CAAC;IACvE,kGAAkG;IAClG,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,aAAa,CAAC,EAC5B,MAAM,EACN,gBAAgB,EAChB,cAAc,EACd,WAAW,EACX,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,SAAS,GACV,EAAE,kBAAkB,GAAG,KAAK,CAAC,YAAY,CAiGzC"}
@@ -0,0 +1,24 @@
1
+ import type { ChatInterfaceHandle, ChatInterfaceProps } from './ChatInterface.types';
2
+ /**
3
+ * ChatInterface — WCAG 2.2 AAA-compliant chatbot UI.
4
+ *
5
+ * Stateless from the library's perspective: consumer owns the messages array,
6
+ * status, and websocket. ChatInterface renders + emits events.
7
+ *
8
+ * Live-region architecture:
9
+ * - `<div role="log">` — visual + navigable, no `aria-live`. AT users locate via landmarks/rotor.
10
+ * - `<div role="status" aria-live="polite">` — single sr-only AT announcement channel.
11
+ * - Tokens mutate the streaming bubble's text content in place (silent).
12
+ * - On streaming → complete, the bubble's rendered DOM `innerText` is normalised, truncated,
13
+ * and pinged into the status region as `"Assistant replied: <preview>"`.
14
+ *
15
+ * IMMUTABILITY: Pass a new message object when its content/parts/status/errorMessage/createdAt
16
+ * changes. In-place mutation will not re-render (memoised bubbles).
17
+ *
18
+ * Markdown rendering is the consumer's responsibility via `renderAssistantContent` /
19
+ * `renderUserContent`. ChatInterface treats content as opaque string. See README for
20
+ * `react-markdown` + `rehype-sanitize` integration guidance.
21
+ */
22
+ declare const ChatInterface: import("react").ForwardRefExoticComponent<ChatInterfaceProps & import("react").RefAttributes<ChatInterfaceHandle>>;
23
+ export { ChatInterface };
24
+ //# sourceMappingURL=ChatInterface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatInterface.d.ts","sourceRoot":"","sources":["../../../src/elements/ChatInterface/ChatInterface.tsx"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAGV,mBAAmB,EACnB,kBAAkB,EAEnB,MAAM,uBAAuB,CAAC;AAE/B;;;;;;;;;;;;;;;;;;;GAmBG;AACH,QAAA,MAAM,aAAa,oHAuUlB,CAAC;AAgBF,OAAO,EAAE,aAAa,EAAE,CAAC"}
@@ -0,0 +1,46 @@
1
+ export declare function normaliseAnnouncementText(input: string): string;
2
+ /**
3
+ * Truncate to `maxChars`, suffixing with the supplied `suffix` if truncated.
4
+ * `maxChars` is clamped to [50, 1000] before truncation.
5
+ */
6
+ export declare function truncateAnnouncement(text: string, maxChars: number | undefined, suffix?: string): string;
7
+ /**
8
+ * Auto-resize a textarea based on its scrollHeight, capped at `--chat-input-max-lines × line-height`.
9
+ * On browsers supporting `field-sizing: content`, the JS path is a no-op (CSS handles it).
10
+ * On older browsers, the JS measurement is rAF-batched to collapse N keystrokes per frame into one reflow.
11
+ */
12
+ export declare function useAutoResizeTextarea(textareaRef: React.RefObject<HTMLTextAreaElement | null>, value: string, maxLines?: number): void;
13
+ /**
14
+ * Track whether the user is "stuck to bottom" using an IntersectionObserver on a sentinel element
15
+ * at the bottom of the log. No scroll listener — browser-native.
16
+ *
17
+ * `rootMargin` is wide (256px) to tolerate scrollHeight churn from `content-visibility: auto`
18
+ * placeholders being measured as bubbles scroll into view.
19
+ *
20
+ * Returns:
21
+ * - `isAtBottom` — true if the bottom sentinel is intersecting the root.
22
+ * - `scrollToBottom(opts?)` — imperative scroll (respects reduced-motion).
23
+ */
24
+ export declare function useTranscriptScroll(scrollContainerRef: React.RefObject<HTMLDivElement | null>, sentinelRef: React.RefObject<HTMLDivElement | null>, prefersReducedMotion: boolean): {
25
+ isAtBottom: boolean;
26
+ scrollToBottom: (opts?: {
27
+ smooth?: boolean;
28
+ }) => void;
29
+ };
30
+ export declare function useStillWorkingTimer(args: {
31
+ isStreaming: boolean;
32
+ streamingContentLength: number;
33
+ enabled: boolean;
34
+ message: string;
35
+ onAnnounce: (text: string) => void;
36
+ }): void;
37
+ export declare function useAnnouncementQueue(opts?: {
38
+ minIntervalMs?: number;
39
+ dedupWindowMs?: number;
40
+ holdMs?: number;
41
+ maxQueueSize?: number;
42
+ }): {
43
+ current: string;
44
+ enqueue: (text: string) => void;
45
+ };
46
+ //# sourceMappingURL=ChatInterface.hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatInterface.hooks.d.ts","sourceRoot":"","sources":["../../../src/elements/ChatInterface/ChatInterface.hooks.ts"],"names":[],"mappings":"AA6BA,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAU/D;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,MAAM,SAAiC,GACtC,MAAM,CAUR;AAeD;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,mBAAmB,GAAG,IAAI,CAAC,EACxD,KAAK,EAAE,MAAM,EACb,QAAQ,SAAI,GACX,IAAI,CAqCN;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,kBAAkB,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,EAC1D,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,EACnD,oBAAoB,EAAE,OAAO,GAC5B;IACD,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,CAAC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;CACvD,CA+BA;AAkBD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,WAAW,EAAE,OAAO,CAAC;IACrB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC,GAAG,IAAI,CA2EP;AAiBD,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE;IAC1C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,CAgFvD"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Root container — fills the parent.
3
+ */
4
+ export declare const chatRootVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
5
+ export declare const chatHeaderVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
6
+ /**
7
+ * Log region — visual + navigable. NO `aria-live`. Scroll container.
8
+ * `overflow-anchor: none` prevents browser scroll-anchoring fighting auto-scroll while the streaming bubble grows.
9
+ */
10
+ export declare const chatLogVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
11
+ /**
12
+ * Message bubble — wrapper for a single message row.
13
+ * `content-visibility: auto` skips layout for offscreen bubbles. Skip on streaming bubble.
14
+ */
15
+ export declare const chatBubbleRowVariants: (props?: ({
16
+ align?: "user" | "assistant" | "system" | null | undefined;
17
+ offscreen?: boolean | null | undefined;
18
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
19
+ /**
20
+ * The visible bubble itself.
21
+ */
22
+ export declare const chatBubbleVariants: (props?: ({
23
+ role?: "user" | "assistant" | "system" | null | undefined;
24
+ isError?: boolean | null | undefined;
25
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
26
+ /**
27
+ * Avatar slot beside a bubble.
28
+ */
29
+ export declare const chatAvatarSlotVariants: (props?: ({
30
+ role?: "user" | "assistant" | "system" | null | undefined;
31
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
32
+ /**
33
+ * Input area at the bottom of the chat.
34
+ */
35
+ export declare const chatInputAreaVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
36
+ /**
37
+ * The default input wrapper (Layer 1 of the input).
38
+ *
39
+ * `min-h-[44px]` matches the Button outer touch-target height so an empty single-line input
40
+ * visually aligns with the Send/Stop button. With `field-sizing: content` on the textarea,
41
+ * the wrapper grows naturally as the user types multi-line; `items-end` on the parent keeps
42
+ * the bottoms aligned (the wrapper's top rises while the button stays anchored).
43
+ */
44
+ export declare const chatInputWrapperVariants: (props?: ({
45
+ isDisabled?: boolean | null | undefined;
46
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
47
+ /**
48
+ * The textarea inside the wrapper. JS path for browsers that don't support `field-sizing: content`.
49
+ */
50
+ export declare const chatInputTextareaVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
51
+ /**
52
+ * Typing indicator (three dots) shown during active token streaming.
53
+ */
54
+ export declare const chatTypingIndicatorVariants: (props?: ({
55
+ animate?: boolean | null | undefined;
56
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
57
+ /**
58
+ * Thinking pill shown while assistant message has status === 'thinking'.
59
+ */
60
+ export declare const chatThinkingPillVariants: (props?: ({
61
+ animate?: boolean | null | undefined;
62
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
63
+ /**
64
+ * Tool-call row inside the thinking display.
65
+ */
66
+ export declare const chatToolCallRowVariants: (props?: ({
67
+ status?: "error" | "running" | "done" | null | undefined;
68
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
69
+ /**
70
+ * Jump-to-latest floating button. 44x44 layer-1 + visual layer.
71
+ */
72
+ export declare const chatJumpToLatestVariants: (props?: ({
73
+ visible?: boolean | null | undefined;
74
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
75
+ /**
76
+ * sr-only utility for the status region. Stays out of visual flow but accessible.
77
+ */
78
+ export declare const chatStatusRegionVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
79
+ /**
80
+ * Action row below an errored assistant bubble (Try again / Submit a support request).
81
+ */
82
+ export declare const chatErrorActionsVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
83
+ //# sourceMappingURL=ChatInterface.styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatInterface.styles.d.ts","sourceRoot":"","sources":["../../../src/elements/ChatInterface/ChatInterface.styles.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,eAAO,MAAM,gBAAgB,oFAE5B,CAAC;AAEF,eAAO,MAAM,kBAAkB,oFAE9B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,oFAE3B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,qBAAqB;;;8EAahC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,kBAAkB;;;8EAiB9B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,sBAAsB;;8EAYlC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB,oFAEjC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB;;8EAWpC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,yBAAyB,oFAErC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,2BAA2B;;8EAWvC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,wBAAwB;;8EAWpC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB;;8EAYnC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,wBAAwB;;8EAWpC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,wBAAwB,oFAEpC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,wBAAwB,oFAEpC,CAAC"}
@@ -0,0 +1,340 @@
1
+ import { z } from 'zod';
2
+ import type { ForwardRefExoticComponent, ReactNode, RefAttributes } from 'react';
3
+ /**
4
+ * ChatInterface — public types and Zod schemas.
5
+ *
6
+ * Schemas use `.strict()` so unknown keys throw rather than strip silently.
7
+ * Production callers should NEVER call `.parse()` directly — internal validation
8
+ * is gated on `process.env.NODE_ENV !== 'production'` so tsup tree-shakes it out.
9
+ */
10
+ export declare const ChatRoleSchema: z.ZodEnum<{
11
+ user: "user";
12
+ assistant: "assistant";
13
+ system: "system";
14
+ }>;
15
+ export type ChatRole = z.infer<typeof ChatRoleSchema>;
16
+ export declare const ChatMessageStatusSchema: z.ZodEnum<{
17
+ error: "error";
18
+ complete: "complete";
19
+ streaming: "streaming";
20
+ thinking: "thinking";
21
+ }>;
22
+ export type ChatMessageStatus = z.infer<typeof ChatMessageStatusSchema>;
23
+ export declare const ChatTopLevelStatusSchema: z.ZodEnum<{
24
+ error: "error";
25
+ streaming: "streaming";
26
+ idle: "idle";
27
+ }>;
28
+ export type ChatTopLevelStatus = z.infer<typeof ChatTopLevelStatusSchema>;
29
+ export declare const ThinkingPartSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
30
+ kind: z.ZodLiteral<"text">;
31
+ text: z.ZodString;
32
+ }, z.core.$strict>, z.ZodObject<{
33
+ kind: z.ZodLiteral<"tool_call">;
34
+ name: z.ZodString;
35
+ status: z.ZodEnum<{
36
+ error: "error";
37
+ running: "running";
38
+ done: "done";
39
+ }>;
40
+ summary: z.ZodOptional<z.ZodString>;
41
+ }, z.core.$strict>], "kind">;
42
+ export type ThinkingPart = z.infer<typeof ThinkingPartSchema>;
43
+ declare const ChatUserMessageSchema: z.ZodObject<{
44
+ id: z.ZodString;
45
+ role: z.ZodLiteral<"user">;
46
+ status: z.ZodEnum<{
47
+ error: "error";
48
+ complete: "complete";
49
+ }>;
50
+ content: z.ZodString;
51
+ createdAt: z.ZodOptional<z.ZodNumber>;
52
+ }, z.core.$strict>;
53
+ export type ChatUserMessage = z.infer<typeof ChatUserMessageSchema>;
54
+ declare const ChatAssistantMessageSchema: z.ZodObject<{
55
+ id: z.ZodString;
56
+ role: z.ZodLiteral<"assistant">;
57
+ status: z.ZodEnum<{
58
+ error: "error";
59
+ complete: "complete";
60
+ streaming: "streaming";
61
+ thinking: "thinking";
62
+ }>;
63
+ content: z.ZodString;
64
+ parts: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
65
+ kind: z.ZodLiteral<"text">;
66
+ text: z.ZodString;
67
+ }, z.core.$strict>, z.ZodObject<{
68
+ kind: z.ZodLiteral<"tool_call">;
69
+ name: z.ZodString;
70
+ status: z.ZodEnum<{
71
+ error: "error";
72
+ running: "running";
73
+ done: "done";
74
+ }>;
75
+ summary: z.ZodOptional<z.ZodString>;
76
+ }, z.core.$strict>], "kind">>>;
77
+ errorMessage: z.ZodOptional<z.ZodString>;
78
+ createdAt: z.ZodOptional<z.ZodNumber>;
79
+ }, z.core.$strict>;
80
+ export type ChatAssistantMessage = z.infer<typeof ChatAssistantMessageSchema>;
81
+ /**
82
+ * System messages bypass `renderAssistantContent` / `renderUserContent`.
83
+ * `content` is `ReactNode` (not validated by Zod beyond presence) so consumers
84
+ * can drop in formatted blocks ("Conversation started", session expiry notes).
85
+ */
86
+ export interface ChatSystemMessage {
87
+ id: string;
88
+ role: 'system';
89
+ status: 'complete';
90
+ content: ReactNode;
91
+ /** Default false — system messages are visual-only. Set true to announce via the status region. */
92
+ announce?: boolean;
93
+ createdAt?: number;
94
+ }
95
+ export declare const ChatMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
96
+ id: z.ZodString;
97
+ role: z.ZodLiteral<"user">;
98
+ status: z.ZodEnum<{
99
+ error: "error";
100
+ complete: "complete";
101
+ }>;
102
+ content: z.ZodString;
103
+ createdAt: z.ZodOptional<z.ZodNumber>;
104
+ }, z.core.$strict>, z.ZodObject<{
105
+ id: z.ZodString;
106
+ role: z.ZodLiteral<"assistant">;
107
+ status: z.ZodEnum<{
108
+ error: "error";
109
+ complete: "complete";
110
+ streaming: "streaming";
111
+ thinking: "thinking";
112
+ }>;
113
+ content: z.ZodString;
114
+ parts: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
115
+ kind: z.ZodLiteral<"text">;
116
+ text: z.ZodString;
117
+ }, z.core.$strict>, z.ZodObject<{
118
+ kind: z.ZodLiteral<"tool_call">;
119
+ name: z.ZodString;
120
+ status: z.ZodEnum<{
121
+ error: "error";
122
+ running: "running";
123
+ done: "done";
124
+ }>;
125
+ summary: z.ZodOptional<z.ZodString>;
126
+ }, z.core.$strict>], "kind">>>;
127
+ errorMessage: z.ZodOptional<z.ZodString>;
128
+ createdAt: z.ZodOptional<z.ZodNumber>;
129
+ }, z.core.$strict>, z.ZodObject<{
130
+ id: z.ZodString;
131
+ role: z.ZodLiteral<"system">;
132
+ status: z.ZodLiteral<"complete">;
133
+ content: z.ZodUnknown;
134
+ announce: z.ZodOptional<z.ZodBoolean>;
135
+ createdAt: z.ZodOptional<z.ZodNumber>;
136
+ }, z.core.$strict>]>;
137
+ export type ChatMessage = ChatUserMessage | ChatAssistantMessage | ChatSystemMessage;
138
+ /**
139
+ * Props ChatInterface passes to the input component (default OR custom).
140
+ *
141
+ * Trust boundary: the input emits `markdown: string` via `onSubmit`. ChatInterface
142
+ * treats it as opaque and forwards to `props.onSendMessage`. Sanitisation is the
143
+ * consumer's responsibility (in `renderAssistantContent` / `renderUserContent`).
144
+ */
145
+ export interface ChatInputComponentProps {
146
+ /** True while top-level status is streaming/error or consumer-disabled. Custom inputs MUST honour. */
147
+ isDisabled: boolean;
148
+ placeholder?: string;
149
+ /** Best-effort cap. Default input enforces strictly; ChatInterface enforces a defence-in-depth backstop. */
150
+ maxLength?: number;
151
+ 'aria-label'?: string;
152
+ /**
153
+ * Called when the user confirms (Enter, Cmd+Enter, RTE submit, etc.).
154
+ * The string MUST be markdown. Must NOT be called with empty/whitespace.
155
+ */
156
+ onSubmit: (markdown: string) => void;
157
+ /**
158
+ * Optional. Fires on value changes for char-count UX or analytics.
159
+ * Custom inputs MAY debounce or throttle. ChatInterface does NOT use this to drive Send button state —
160
+ * Send is always enabled when ChatInterface isn't disabled.
161
+ */
162
+ onChange?: (markdown: string) => void;
163
+ onFocus?: () => void;
164
+ onBlur?: () => void;
165
+ }
166
+ /**
167
+ * Imperative methods the input must expose via `forwardRef` + `useImperativeHandle`.
168
+ */
169
+ export interface ChatInputComponentHandle {
170
+ /** Move focus to the input. ChatInterface delegates `chatRef.current.focusInput()` here. */
171
+ focus: () => void;
172
+ /** Reset the input's value. Called after a successful send. */
173
+ clear: () => void;
174
+ /**
175
+ * Trigger a submit. The input extracts its current value and invokes its own `onSubmit`.
176
+ * No-op when empty/whitespace — never calls `onSubmit` with empty string.
177
+ * This empty-guard is the contract: Send button is always enabled when ChatInterface isn't disabled,
178
+ * and harmless clicks on an empty input produce no message.
179
+ */
180
+ submit: () => void;
181
+ /**
182
+ * Programmatically set the input's value (suggested-question prefill, edit-prior-message).
183
+ * Does NOT change focus. Cursor lands at end. Consumers wanting focus call `focus()` separately.
184
+ * `setValue` followed by `submit` is a documented feature; consumers wanting human-only origination
185
+ * should track origination state themselves.
186
+ */
187
+ setValue: (markdown: string) => void;
188
+ }
189
+ export type ChatInputComponent = ForwardRefExoticComponent<ChatInputComponentProps & RefAttributes<ChatInputComponentHandle>>;
190
+ export interface ChatInterfaceHandle {
191
+ focusInput: () => void;
192
+ scrollToBottom: (opts?: {
193
+ smooth?: boolean;
194
+ }) => void;
195
+ }
196
+ /**
197
+ * Zod schema for runtime validation. Production callers should not invoke `.parse()` —
198
+ * internal validation is dev-only.
199
+ */
200
+ export declare const ChatInterfacePropsSchema: z.ZodObject<{
201
+ className: z.ZodOptional<z.ZodString>;
202
+ children: z.ZodOptional<z.ZodAny>;
203
+ id: z.ZodOptional<z.ZodString>;
204
+ 'aria-label': z.ZodOptional<z.ZodString>;
205
+ 'aria-labelledby': z.ZodOptional<z.ZodString>;
206
+ 'aria-describedby': z.ZodOptional<z.ZodString>;
207
+ 'aria-live': z.ZodOptional<z.ZodEnum<{
208
+ off: "off";
209
+ polite: "polite";
210
+ assertive: "assertive";
211
+ }>>;
212
+ 'aria-hidden': z.ZodOptional<z.ZodBoolean>;
213
+ 'data-testid': z.ZodOptional<z.ZodString>;
214
+ status: z.ZodEnum<{
215
+ error: "error";
216
+ streaming: "streaming";
217
+ idle: "idle";
218
+ }>;
219
+ messages: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
220
+ id: z.ZodString;
221
+ role: z.ZodLiteral<"user">;
222
+ status: z.ZodEnum<{
223
+ error: "error";
224
+ complete: "complete";
225
+ }>;
226
+ content: z.ZodString;
227
+ createdAt: z.ZodOptional<z.ZodNumber>;
228
+ }, z.core.$strict>, z.ZodObject<{
229
+ id: z.ZodString;
230
+ role: z.ZodLiteral<"assistant">;
231
+ status: z.ZodEnum<{
232
+ error: "error";
233
+ complete: "complete";
234
+ streaming: "streaming";
235
+ thinking: "thinking";
236
+ }>;
237
+ content: z.ZodString;
238
+ parts: z.ZodOptional<z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
239
+ kind: z.ZodLiteral<"text">;
240
+ text: z.ZodString;
241
+ }, z.core.$strict>, z.ZodObject<{
242
+ kind: z.ZodLiteral<"tool_call">;
243
+ name: z.ZodString;
244
+ status: z.ZodEnum<{
245
+ error: "error";
246
+ running: "running";
247
+ done: "done";
248
+ }>;
249
+ summary: z.ZodOptional<z.ZodString>;
250
+ }, z.core.$strict>], "kind">>>;
251
+ errorMessage: z.ZodOptional<z.ZodString>;
252
+ createdAt: z.ZodOptional<z.ZodNumber>;
253
+ }, z.core.$strict>, z.ZodObject<{
254
+ id: z.ZodString;
255
+ role: z.ZodLiteral<"system">;
256
+ status: z.ZodLiteral<"complete">;
257
+ content: z.ZodUnknown;
258
+ announce: z.ZodOptional<z.ZodBoolean>;
259
+ createdAt: z.ZodOptional<z.ZodNumber>;
260
+ }, z.core.$strict>]>>;
261
+ onSendMessage: z.ZodCustom<(text: string) => void, (text: string) => void>;
262
+ onStopGeneration: z.ZodOptional<z.ZodCustom<() => void, () => void>>;
263
+ onRetry: z.ZodOptional<z.ZodCustom<(messageId: string) => void, (messageId: string) => void>>;
264
+ onEscalate: z.ZodOptional<z.ZodCustom<() => void, () => void>>;
265
+ renderAssistantContent: z.ZodOptional<z.ZodAny>;
266
+ renderUserContent: z.ZodOptional<z.ZodAny>;
267
+ inputComponent: z.ZodOptional<z.ZodAny>;
268
+ assistantAvatar: z.ZodOptional<z.ZodAny>;
269
+ userAvatar: z.ZodOptional<z.ZodAny>;
270
+ header: z.ZodOptional<z.ZodAny>;
271
+ emptyState: z.ZodOptional<z.ZodAny>;
272
+ inputActions: z.ZodOptional<z.ZodAny>;
273
+ placeholder: z.ZodOptional<z.ZodString>;
274
+ isDisabled: z.ZodOptional<z.ZodBoolean>;
275
+ maxInputLength: z.ZodOptional<z.ZodNumber>;
276
+ sendShortcut: z.ZodOptional<z.ZodEnum<{
277
+ enter: "enter";
278
+ "mod-enter": "mod-enter";
279
+ }>>;
280
+ progressAnnouncements: z.ZodOptional<z.ZodBoolean>;
281
+ completionAnnouncementMaxChars: z.ZodOptional<z.ZodNumber>;
282
+ logLabel: z.ZodOptional<z.ZodString>;
283
+ thinkingDisclosureLabel: z.ZodOptional<z.ZodString>;
284
+ }, z.core.$strict>;
285
+ /**
286
+ * Render-prop renderers. Consumers parse markdown and produce a ReactNode.
287
+ * MUST be pure render functions — no side effects. MUST NOT include `aria-live`,
288
+ * `aria-busy`, or `role="log"` (ChatInterface owns the live-region semantics).
289
+ */
290
+ export type ChatAssistantRenderer = (message: ChatAssistantMessage) => ReactNode;
291
+ export type ChatUserRenderer = (message: ChatUserMessage) => ReactNode;
292
+ export interface ChatInterfaceProps {
293
+ /**
294
+ * The full conversation transcript. ChatInterface is fully controlled — the consumer
295
+ * owns this array and updates it via setState/reducer/etc.
296
+ *
297
+ * IMMUTABILITY: Pass a new message object when its `content`, `parts`, `status`,
298
+ * `errorMessage`, or `createdAt` changes. In-place mutation will not re-render.
299
+ */
300
+ messages: ChatMessage[];
301
+ /** Top-level status drives the input area (Send vs Stop, disabled state). */
302
+ status: ChatTopLevelStatus;
303
+ /** Required when status can be 'streaming'. */
304
+ onSendMessage: (text: string) => void;
305
+ onStopGeneration?: () => void;
306
+ onRetry?: (messageId: string) => void;
307
+ onEscalate?: () => void;
308
+ /** @see ChatAssistantRenderer for purity rules. */
309
+ renderAssistantContent?: ChatAssistantRenderer;
310
+ renderUserContent?: ChatUserRenderer;
311
+ /** Custom input component honouring the ChatInputComponent contract. Defaults to the built-in Themis-styled multi-line input. */
312
+ inputComponent?: ChatInputComponent;
313
+ /** Memoize inline JSX (e.g. `useMemo(() => <Avatar ... />, [])`) so it doesn't bust the bubble memo. */
314
+ assistantAvatar?: ReactNode;
315
+ userAvatar?: ReactNode;
316
+ header?: ReactNode;
317
+ emptyState?: ReactNode;
318
+ inputActions?: ReactNode;
319
+ placeholder?: string;
320
+ isDisabled?: boolean;
321
+ maxInputLength?: number;
322
+ /** Default 'enter'. 'mod-enter' = Cmd/Ctrl+Enter. Only honoured by the default input. */
323
+ sendShortcut?: 'enter' | 'mod-enter';
324
+ /**
325
+ * Default true. When false, suppresses the bounded "still working" pings (3s/15s/60s slow-response safety net).
326
+ * Note: disabling removes the only AT signal of a hung stream.
327
+ */
328
+ progressAnnouncements?: boolean;
329
+ /** Default 200. Clamped to [50, 1000] at runtime; out-of-range values dev-warn and clamp. */
330
+ completionAnnouncementMaxChars?: number;
331
+ 'aria-label'?: string;
332
+ /** Default "Conversation transcript". */
333
+ logLabel?: string;
334
+ /** Default "Thoughts". */
335
+ thinkingDisclosureLabel?: string;
336
+ className?: string;
337
+ 'data-testid'?: string;
338
+ }
339
+ export {};
340
+ //# sourceMappingURL=ChatInterface.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatInterface.types.d.ts","sourceRoot":"","sources":["../../../src/elements/ChatInterface/ChatInterface.types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Single sr-only `role="status"` region — the canonical AT announcement channel.
3
+ * The log region (separate component) has NO `aria-live`; all announcements flow through here.
4
+ *
5
+ * @see ChatInterface.hooks.ts → useAnnouncementQueue for the FIFO + dedup + rate-limit logic.
6
+ */
7
+ declare const ChatLiveRegions: import("react").NamedExoticComponent<{
8
+ current: string;
9
+ className?: string;
10
+ testId?: string;
11
+ }>;
12
+ export { ChatLiveRegions };
13
+ //# sourceMappingURL=ChatLiveRegions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatLiveRegions.d.ts","sourceRoot":"","sources":["../../../src/elements/ChatInterface/ChatLiveRegions.tsx"],"names":[],"mappings":"AAMA;;;;;GAKG;AACH,QAAA,MAAM,eAAe;aAKV,MAAM;gBACH,MAAM;aACT,MAAM;EAaf,CAAC;AAEH,OAAO,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { type ReactNode } from 'react';
2
+ import type { ChatAssistantRenderer, ChatMessage, ChatUserRenderer } from './ChatInterface.types';
3
+ /**
4
+ * Single message bubble. Memoized with a custom comparator covering all visual-relevant fields.
5
+ *
6
+ * IMMUTABILITY: consumers MUST pass a new message object when content/parts/status/errorMessage/createdAt changes.
7
+ * In-place mutation will not re-render. (Documented on the public `messages` prop.)
8
+ */
9
+ interface BubbleProps {
10
+ message: ChatMessage;
11
+ isStreamingHere: boolean;
12
+ isOffscreen: boolean;
13
+ assistantAvatar?: ReactNode;
14
+ userAvatar?: ReactNode;
15
+ renderAssistantContent?: ChatAssistantRenderer;
16
+ renderUserContent?: ChatUserRenderer;
17
+ thinkingDisclosureLabel: string;
18
+ contentRef?: React.RefCallback<HTMLDivElement>;
19
+ onRetry?: (id: string) => void;
20
+ onEscalate?: () => void;
21
+ }
22
+ declare const ChatMessageBubble: import("react").NamedExoticComponent<BubbleProps>;
23
+ export { ChatMessageBubble };
24
+ //# sourceMappingURL=ChatMessageBubble.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatMessageBubble.d.ts","sourceRoot":"","sources":["../../../src/elements/ChatInterface/ChatMessageBubble.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAQ,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAY7C,OAAO,KAAK,EAEV,qBAAqB,EACrB,WAAW,EAGX,gBAAgB,EACjB,MAAM,uBAAuB,CAAC;AAE/B;;;;;GAKG;AAEH,UAAU,WAAW;IACnB,OAAO,EAAE,WAAW,CAAC;IACrB,eAAe,EAAE,OAAO,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,CAAC,EAAE,SAAS,CAAC;IAC5B,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB,sBAAsB,CAAC,EAAE,qBAAqB,CAAC;IAC/C,iBAAiB,CAAC,EAAE,gBAAgB,CAAC;IACrC,uBAAuB,EAAE,MAAM,CAAC;IAChC,UAAU,CAAC,EAAE,KAAK,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAqDD,QAAA,MAAM,iBAAiB,mDAqCH,CAAC;AA6JrB,OAAO,EAAE,iBAAiB,EAAE,CAAC"}