@neuronection/assistant-ui 0.25.0 → 0.27.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 (45) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/README.md +4 -0
  3. package/dist/ai-magic-fill.js +1 -1
  4. package/dist/chat-drawer.js +1 -1
  5. package/dist/chat-export.d.ts +29 -0
  6. package/dist/chat-export.js +3 -0
  7. package/dist/chat-export.js.map +1 -0
  8. package/dist/chat-history-button.d.ts +31 -0
  9. package/dist/chat-history-button.js +3 -0
  10. package/dist/chat-history-button.js.map +1 -0
  11. package/dist/chat-message.js +1 -1
  12. package/dist/chat-panel.d.ts +1 -1
  13. package/dist/chat-panel.js +1 -1
  14. package/dist/chat-tools-catalog.d.ts +50 -0
  15. package/dist/chat-tools-catalog.js +3 -0
  16. package/dist/chat-tools-catalog.js.map +1 -0
  17. package/dist/chat-trace-meta.d.ts +19 -0
  18. package/dist/chat-trace-meta.js +3 -0
  19. package/dist/chat-trace-meta.js.map +1 -0
  20. package/dist/chat-transcript.js +1 -1
  21. package/dist/chunk-DRJGZ5TB.js +47 -0
  22. package/dist/chunk-DRJGZ5TB.js.map +1 -0
  23. package/dist/{chunk-5QTHDB3D.js → chunk-EODV6JK7.js} +3 -3
  24. package/dist/{chunk-5QTHDB3D.js.map → chunk-EODV6JK7.js.map} +1 -1
  25. package/dist/{chunk-BSIWLVDX.js → chunk-FGYGWZ6S.js} +3 -3
  26. package/dist/{chunk-BSIWLVDX.js.map → chunk-FGYGWZ6S.js.map} +1 -1
  27. package/dist/{chunk-BVJT67B5.js → chunk-FS7M7PNS.js} +3 -3
  28. package/dist/{chunk-BVJT67B5.js.map → chunk-FS7M7PNS.js.map} +1 -1
  29. package/dist/{chunk-S62VJVWB.js → chunk-LFSICACE.js} +13 -5
  30. package/dist/chunk-LFSICACE.js.map +1 -0
  31. package/dist/chunk-QMQ73C23.js +41 -0
  32. package/dist/chunk-QMQ73C23.js.map +1 -0
  33. package/dist/{chunk-X3C2FBMR.js → chunk-WBSGFOSD.js} +4 -3
  34. package/dist/chunk-WBSGFOSD.js.map +1 -0
  35. package/dist/chunk-YYPO24TA.js +38 -0
  36. package/dist/chunk-YYPO24TA.js.map +1 -0
  37. package/dist/chunk-ZSCL34WT.js +149 -0
  38. package/dist/chunk-ZSCL34WT.js.map +1 -0
  39. package/dist/index.d.ts +4 -0
  40. package/dist/index.js +30 -26
  41. package/dist/index.js.map +1 -1
  42. package/dist/styles.css +1 -1
  43. package/package.json +17 -1
  44. package/dist/chunk-S62VJVWB.js.map +0 -1
  45. package/dist/chunk-X3C2FBMR.js.map +0 -1
@@ -12,7 +12,6 @@ var ChatPanel = React.forwardRef(
12
12
  "data-variant": variant,
13
13
  className: cn(
14
14
  "flex h-full min-h-0 w-full flex-col bg-[var(--as-surface)] text-[var(--as-fg)]",
15
- variant === "page" && "mx-auto w-full max-w-3xl",
16
15
  variant === "bubble" && "overflow-hidden",
17
16
  className
18
17
  ),
@@ -22,8 +21,17 @@ var ChatPanel = React.forwardRef(
22
21
  actions ? /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center gap-0.5", children: actions }) : null
23
22
  ] }) : null,
24
23
  banner ? /* @__PURE__ */ jsx("div", { "data-as": "chat-panel-banner", className: "shrink-0 px-3 py-1.5 text-xs text-[var(--as-muted-fg)]", children: banner }) : null,
25
- /* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1 flex-col", children: transcript }),
26
- composer ? /* @__PURE__ */ jsx("div", { className: "shrink-0 border-t border-[var(--as-border)] p-2", children: composer }) : null,
24
+ /* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1 flex-col", children: /* @__PURE__ */ jsx(
25
+ "div",
26
+ {
27
+ className: cn(
28
+ "flex min-h-0 w-full flex-1 flex-col",
29
+ variant === "page" && "mx-auto max-w-3xl"
30
+ ),
31
+ children: transcript
32
+ }
33
+ ) }),
34
+ composer ? /* @__PURE__ */ jsx("div", { className: "shrink-0 border-t border-[var(--as-border)] p-2", children: /* @__PURE__ */ jsx("div", { className: cn(variant === "page" && "mx-auto w-full max-w-3xl"), children: composer }) }) : null,
27
35
  footer ? /* @__PURE__ */ jsx("div", { className: "shrink-0 px-3 pb-2 pt-1 text-center text-[10px] text-[var(--as-muted-fg)]", children: footer }) : null
28
36
  ]
29
37
  }
@@ -32,5 +40,5 @@ var ChatPanel = React.forwardRef(
32
40
  );
33
41
 
34
42
  export { ChatPanel };
35
- //# sourceMappingURL=chunk-S62VJVWB.js.map
36
- //# sourceMappingURL=chunk-S62VJVWB.js.map
43
+ //# sourceMappingURL=chunk-LFSICACE.js.map
44
+ //# sourceMappingURL=chunk-LFSICACE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/chat-panel/ChatPanel.tsx"],"names":["ChatPanel"],"mappings":";;;;AA6BO,IAAM,SAAA,GAAkB,KAAA,CAAA,UAAA;AAAA,EAC7B,SAASA,UAAAA,CAAU,EAAE,OAAA,EAAS,KAAA,EAAO,OAAA,EAAS,MAAA,EAAQ,UAAA,EAAY,QAAA,EAAU,MAAA,EAAQ,SAAA,EAAU,EAAG,GAAA,EAAK;AACpG,IAAA,uBACE,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,SAAA,EAAQ,YAAA;AAAA,QACR,cAAA,EAAc,OAAA;AAAA,QACd,SAAA,EAAW,EAAA;AAAA,UACT,gFAAA;AAAA,UACA,YAAY,QAAA,IAAY,iBAAA;AAAA,UACxB;AAAA,SACF;AAAA,QAEC,QAAA,EAAA;AAAA,UAAA,KAAA,KAAU,UAAa,OAAA,KAAY,MAAA,mBAClC,IAAA,CAAC,QAAA,EAAA,EAAO,WAAU,+EAAA,EAChB,QAAA,EAAA;AAAA,4BAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,+CAAA,EAAiD,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,YACrE,0BAAU,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,oCAAA,EAAsC,mBAAQ,CAAA,GAAS;AAAA,WAAA,EACnF,CAAA,GACE,IAAA;AAAA,UACH,MAAA,uBACE,KAAA,EAAA,EAAI,SAAA,EAAQ,qBAAoB,SAAA,EAAU,wDAAA,EACxC,kBACH,CAAA,GACE,IAAA;AAAA,0BACJ,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,8BAAA,EACb,QAAA,kBAAA,GAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,SAAA,EAAW,EAAA;AAAA,gBACT,qCAAA;AAAA,gBACA,YAAY,MAAA,IAAU;AAAA,eACxB;AAAA,cAEC,QAAA,EAAA;AAAA;AAAA,WACH,EACF,CAAA;AAAA,UACC,QAAA,mBACC,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,mDACb,QAAA,kBAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,EAAA,CAAG,YAAY,MAAA,IAAU,0BAA0B,CAAA,EAAI,QAAA,EAAA,QAAA,EAAS,GAClF,CAAA,GACE,IAAA;AAAA,UACH,yBACC,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,2EAAA,EAA6E,kBAAO,CAAA,GACjG;AAAA;AAAA;AAAA,KACN;AAAA,EAEJ;AACF","file":"chunk-LFSICACE.js","sourcesContent":["import * as React from 'react'\n\nimport { cn } from '../../lib/utils'\n\nexport type ChatPanelVariant = 'page' | 'sidebar' | 'bubble'\n\nexport interface ChatPanelProps {\n /** Layout tier: full page (full-bleed shell, centered conversation column), sidebar (dense column), bubble (compact widget body). */\n variant: ChatPanelVariant\n /** Header row: title node + action nodes (session list, branch tree, expand, close). */\n title?: React.ReactNode\n actions?: React.ReactNode\n /** Status strip under the header (connection warnings, context summary). */\n banner?: React.ReactNode\n /** Usually `<ChatTranscript …/>`. */\n transcript: React.ReactNode\n /** Usually `<ChatComposer …/>`. */\n composer?: React.ReactNode\n /** Disclaimer row under the composer (health guidance, etc.). */\n footer?: React.ReactNode\n className?: string\n}\n\n/**\n * The composed chat host — the one uniform surface assembly behind the\n * family's three shapes (full page / sidepanel / bubble). Owns layout\n * only; transcript, composer and every feature slot stay app-composed\n * (ADR-006 tier 3, `RichTextEditor` precedent).\n */\nexport const ChatPanel = React.forwardRef<HTMLDivElement, ChatPanelProps>(\n function ChatPanel({ variant, title, actions, banner, transcript, composer, footer, className }, ref) {\n return (\n <div\n ref={ref}\n data-as=\"chat-panel\"\n data-variant={variant}\n className={cn(\n 'flex h-full min-h-0 w-full flex-col bg-[var(--as-surface)] text-[var(--as-fg)]',\n variant === 'bubble' && 'overflow-hidden',\n className,\n )}\n >\n {title !== undefined || actions !== undefined ? (\n <header className=\"flex shrink-0 items-center gap-2 border-b border-[var(--as-border)] px-3 py-2\">\n <div className=\"min-w-0 flex-1 truncate text-sm font-semibold\">{title}</div>\n {actions ? <div className=\"flex shrink-0 items-center gap-0.5\">{actions}</div> : null}\n </header>\n ) : null}\n {banner ? (\n <div data-as=\"chat-panel-banner\" className=\"shrink-0 px-3 py-1.5 text-xs text-[var(--as-muted-fg)]\">\n {banner}\n </div>\n ) : null}\n <div className=\"flex min-h-0 flex-1 flex-col\">\n <div\n className={cn(\n 'flex min-h-0 w-full flex-1 flex-col',\n variant === 'page' && 'mx-auto max-w-3xl',\n )}\n >\n {transcript}\n </div>\n </div>\n {composer ? (\n <div className=\"shrink-0 border-t border-[var(--as-border)] p-2\">\n <div className={cn(variant === 'page' && 'mx-auto w-full max-w-3xl')}>{composer}</div>\n </div>\n ) : null}\n {footer ? (\n <div className=\"shrink-0 px-3 pb-2 pt-1 text-center text-[10px] text-[var(--as-muted-fg)]\">{footer}</div>\n ) : null}\n </div>\n )\n },\n)\n"]}
@@ -0,0 +1,41 @@
1
+ import { cn } from './chunk-BLJWR4ZV.js';
2
+ import * as React from 'react';
3
+ import { jsxs, jsx } from 'react/jsx-runtime';
4
+
5
+ function formatDuration(ms) {
6
+ if (ms < 1e3) {
7
+ return `${Math.round(ms)} ms`;
8
+ }
9
+ return `${(ms / 1e3).toFixed(1)} s`;
10
+ }
11
+ var ChatTraceMeta = React.forwardRef(
12
+ function ChatTraceMeta2({ model, durationMs, toolCount, className }, ref) {
13
+ const hasModel = typeof model === "string" && model !== "";
14
+ const hasDuration = typeof durationMs === "number";
15
+ const hasTools = typeof toolCount === "number" && toolCount > 0;
16
+ if (!hasModel && !hasDuration && !hasTools) {
17
+ return null;
18
+ }
19
+ return /* @__PURE__ */ jsxs(
20
+ "div",
21
+ {
22
+ ref,
23
+ "data-as": "chat-trace-meta",
24
+ className: cn("mt-1 flex flex-wrap items-center gap-2 font-mono text-[10px] text-[var(--as-muted-fg)]", className),
25
+ children: [
26
+ hasModel ? /* @__PURE__ */ jsx("span", { children: model }) : null,
27
+ hasDuration ? /* @__PURE__ */ jsx("span", { children: formatDuration(durationMs) }) : null,
28
+ hasTools ? /* @__PURE__ */ jsxs("span", { children: [
29
+ toolCount,
30
+ " ",
31
+ toolCount === 1 ? "tool" : "tools"
32
+ ] }) : null
33
+ ]
34
+ }
35
+ );
36
+ }
37
+ );
38
+
39
+ export { ChatTraceMeta };
40
+ //# sourceMappingURL=chunk-QMQ73C23.js.map
41
+ //# sourceMappingURL=chunk-QMQ73C23.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/chat-trace-meta/ChatTraceMeta.tsx"],"names":["ChatTraceMeta"],"mappings":";;;;AAcA,SAAS,eAAe,EAAA,EAAoB;AAC1C,EAAA,IAAI,KAAK,GAAA,EAAM;AACb,IAAA,OAAO,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,EAAE,CAAC,CAAA,GAAA,CAAA;AAAA,EAC1B;AACA,EAAA,OAAO,CAAA,EAAA,CAAI,EAAA,GAAK,GAAA,EAAM,OAAA,CAAQ,CAAC,CAAC,CAAA,EAAA,CAAA;AAClC;AAOO,IAAM,aAAA,GAAsB,KAAA,CAAA,UAAA;AAAA,EACjC,SAASA,eAAc,EAAE,KAAA,EAAO,YAAY,SAAA,EAAW,SAAA,IAAa,GAAA,EAAK;AACvE,IAAA,MAAM,QAAA,GAAW,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,EAAA;AACxD,IAAA,MAAM,WAAA,GAAc,OAAO,UAAA,KAAe,QAAA;AAC1C,IAAA,MAAM,QAAA,GAAW,OAAO,SAAA,KAAc,QAAA,IAAY,SAAA,GAAY,CAAA;AAC9D,IAAA,IAAI,CAAC,QAAA,IAAY,CAAC,WAAA,IAAe,CAAC,QAAA,EAAU;AAC1C,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,uBACE,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,SAAA,EAAQ,iBAAA;AAAA,QACR,SAAA,EAAW,EAAA,CAAG,wFAAA,EAA0F,SAAS,CAAA;AAAA,QAEhH,QAAA,EAAA;AAAA,UAAA,QAAA,mBAAW,GAAA,CAAC,MAAA,EAAA,EAAM,QAAA,EAAA,KAAA,EAAM,CAAA,GAAU,IAAA;AAAA,UAClC,8BAAc,GAAA,CAAC,MAAA,EAAA,EAAM,QAAA,EAAA,cAAA,CAAe,UAAU,GAAE,CAAA,GAAU,IAAA;AAAA,UAC1D,QAAA,wBACE,MAAA,EAAA,EACE,QAAA,EAAA;AAAA,YAAA,SAAA;AAAA,YAAU,GAAA;AAAA,YAAE,SAAA,KAAc,IAAI,MAAA,GAAS;AAAA,WAAA,EAC1C,CAAA,GACE;AAAA;AAAA;AAAA,KACN;AAAA,EAEJ;AACF","file":"chunk-QMQ73C23.js","sourcesContent":["import * as React from 'react'\n\nimport { cn } from '../../lib/utils'\n\nexport interface ChatTraceMetaProps {\n /** Model identifier that produced the reply. */\n model?: string\n /** Turn elapsed time (formatted ms below 1 s, then seconds). */\n durationMs?: number\n /** Number of tools the turn executed (renders `N tools`). */\n toolCount?: number\n className?: string\n}\n\nfunction formatDuration(ms: number): string {\n if (ms < 1000) {\n return `${Math.round(ms)} ms`\n }\n return `${(ms / 1000).toFixed(1)} s`\n}\n\n/**\n * Compact turn-trace badges (\"gpt-5.6 · 1.9 s · 3 tools\", career's\n * `TraceMeta`, generalized): renders nothing without data. Reads a\n * normalized view-model — parsing `metadata_json` stays app-side.\n */\nexport const ChatTraceMeta = React.forwardRef<HTMLDivElement, ChatTraceMetaProps>(\n function ChatTraceMeta({ model, durationMs, toolCount, className }, ref) {\n const hasModel = typeof model === 'string' && model !== ''\n const hasDuration = typeof durationMs === 'number'\n const hasTools = typeof toolCount === 'number' && toolCount > 0\n if (!hasModel && !hasDuration && !hasTools) {\n return null\n }\n return (\n <div\n ref={ref}\n data-as=\"chat-trace-meta\"\n className={cn('mt-1 flex flex-wrap items-center gap-2 font-mono text-[10px] text-[var(--as-muted-fg)]', className)}\n >\n {hasModel ? <span>{model}</span> : null}\n {hasDuration ? <span>{formatDuration(durationMs)}</span> : null}\n {hasTools ? (\n <span>\n {toolCount} {toolCount === 1 ? 'tool' : 'tools'}\n </span>\n ) : null}\n </div>\n )\n },\n)\n"]}
@@ -38,7 +38,7 @@ var ChatDrawer = React.forwardRef(
38
38
  container,
39
39
  overlayClassName,
40
40
  className
41
- }) {
41
+ }, ref) {
42
42
  const narrow = useIsNarrow(fullScreenBreakpointPx);
43
43
  const draggingRef = React.useRef(false);
44
44
  const clamp = (value) => Math.min(maxWidth, Math.max(minWidth, value));
@@ -90,6 +90,7 @@ var ChatDrawer = React.forwardRef(
90
90
  /* @__PURE__ */ jsxs(
91
91
  DialogPrimitive.Content,
92
92
  {
93
+ ref,
93
94
  "data-as": "chat-drawer",
94
95
  "data-side": side,
95
96
  "data-full-screen": narrow || void 0,
@@ -137,5 +138,5 @@ var ChatDrawer = React.forwardRef(
137
138
  );
138
139
 
139
140
  export { ChatDrawer };
140
- //# sourceMappingURL=chunk-X3C2FBMR.js.map
141
- //# sourceMappingURL=chunk-X3C2FBMR.js.map
141
+ //# sourceMappingURL=chunk-WBSGFOSD.js.map
142
+ //# sourceMappingURL=chunk-WBSGFOSD.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/chat-drawer/ChatDrawer.tsx"],"names":["ChatDrawer"],"mappings":"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","file":"chunk-WBSGFOSD.js","sourcesContent":["import * as React from 'react'\nimport * as DialogPrimitive from '@radix-ui/react-dialog'\nimport { X } from 'lucide-react'\n\nimport { cn } from '../../lib/utils'\n\nexport interface ChatDrawerProps {\n open: boolean\n onOpenChange: (open: boolean) => void\n /** The sidepanel content — usually `ChatPanel variant=\"sidebar\"`. */\n panel: React.ReactNode\n side?: 'right' | 'left'\n /** Controlled width in px (persist app-side). Default 480. */\n width?: number\n onWidthChange?: (width: number) => void\n minWidth?: number\n maxWidth?: number\n resizable?: boolean\n closeLabel?: string\n resizeLabel?: string\n /** Accessible dialog name (visually hidden). Default \"Chat\". */\n title?: string\n /** Below this viewport width the drawer goes full-screen. Default 768. */\n fullScreenBreakpointPx?: number\n container?: HTMLElement | null\n overlayClassName?: string\n className?: string\n}\n\nfunction useIsNarrow(breakpointPx: number): boolean {\n const [narrow, setNarrow] = React.useState(() =>\n typeof window !== 'undefined' && window.matchMedia !== undefined\n ? window.matchMedia(`(max-width: ${breakpointPx - 1}px)`).matches\n : false,\n )\n React.useEffect(() => {\n if (typeof window === 'undefined' || window.matchMedia === undefined) {\n return\n }\n const query = window.matchMedia(`(max-width: ${breakpointPx - 1}px)`)\n const listener = (event: MediaQueryListEvent) => setNarrow(event.matches)\n query.addEventListener('change', listener)\n setNarrow(query.matches)\n return () => query.removeEventListener('change', listener)\n }, [breakpointPx])\n return narrow\n}\n\n/**\n * The resizable chat sidepanel (health's `AIDrawer` + study's resizable\n * sidebar, family-standard): portal overlay on Radix Dialog (focus trap,\n * Escape), drag + keyboard resize, full-screen below the breakpoint.\n */\nexport const ChatDrawer = React.forwardRef<HTMLDivElement, ChatDrawerProps>(\n function ChatDrawer(\n {\n open,\n onOpenChange,\n panel,\n side = 'right',\n width = 480,\n onWidthChange,\n minWidth = 320,\n maxWidth = 860,\n resizable = true,\n closeLabel = 'Close chat',\n resizeLabel = 'Resize chat panel',\n title = 'Chat',\n fullScreenBreakpointPx = 768,\n container,\n overlayClassName,\n className,\n },\n ref,\n ) {\n const narrow = useIsNarrow(fullScreenBreakpointPx)\n const draggingRef = React.useRef(false)\n\n const clamp = (value: number) => Math.min(maxWidth, Math.max(minWidth, value))\n\n const onHandleKeyDown = (event: React.KeyboardEvent) => {\n if (!resizable || narrow) {\n return\n }\n const step = event.shiftKey ? 48 : 16\n if (event.key === (side === 'right' ? 'ArrowLeft' : 'ArrowRight')) {\n event.preventDefault()\n onWidthChange?.(clamp(width + step))\n } else if (event.key === (side === 'right' ? 'ArrowRight' : 'ArrowLeft')) {\n event.preventDefault()\n onWidthChange?.(clamp(width - step))\n }\n }\n\n const onHandlePointerDown = (event: React.PointerEvent<HTMLDivElement>) => {\n if (!resizable || narrow || event.button !== 0) {\n return\n }\n event.preventDefault()\n draggingRef.current = true\n event.currentTarget.setPointerCapture(event.pointerId)\n }\n\n const onHandlePointerMove = (event: React.PointerEvent<HTMLDivElement>) => {\n if (!draggingRef.current) {\n return\n }\n const delta = side === 'right' ? window.innerWidth - event.clientX : event.clientX\n onWidthChange?.(clamp(delta))\n }\n\n const onHandlePointerUp = (event: React.PointerEvent<HTMLDivElement>) => {\n if (!draggingRef.current) {\n return\n }\n draggingRef.current = false\n if (event.currentTarget.hasPointerCapture(event.pointerId)) {\n event.currentTarget.releasePointerCapture(event.pointerId)\n }\n }\n\n return (\n <DialogPrimitive.Root open={open} onOpenChange={onOpenChange}>\n <DialogPrimitive.Portal container={container}>\n <DialogPrimitive.Overlay\n data-as=\"chat-drawer-overlay\"\n className={cn('as-anim-fade fixed inset-0 z-[var(--as-z-modal)] bg-[var(--as-overlay)]', overlayClassName)}\n />\n <DialogPrimitive.Content\n ref={ref}\n data-as=\"chat-drawer\"\n data-side={side}\n data-full-screen={narrow || undefined}\n style={narrow ? undefined : { width: `${width}px`, maxWidth: '100vw' }}\n className={cn(\n 'as-anim-drawer fixed top-0 z-[var(--as-z-modal)] flex h-dvh flex-col border-[var(--as-border)] bg-[var(--as-surface)] text-[var(--as-fg)] shadow-[var(--as-shadow-3)] focus:outline-none',\n narrow\n ? 'inset-x-0 bottom-0 border-t'\n : side === 'right'\n ? 'bottom-0 right-0 border-l'\n : 'bottom-0 left-0 border-r',\n className,\n )}\n >\n {resizable && !narrow ? (\n <div\n role=\"separator\"\n aria-orientation=\"vertical\"\n aria-label={resizeLabel}\n tabIndex={0}\n onKeyDown={onHandleKeyDown}\n onPointerDown={onHandlePointerDown}\n onPointerMove={onHandlePointerMove}\n onPointerUp={onHandlePointerUp}\n onPointerCancel={onHandlePointerUp}\n className={cn(\n 'group/handle absolute top-0 z-10 h-dvh w-1.5 cursor-col-resize focus-visible:outline-2 focus-visible:outline-[var(--as-focus-ring)]',\n side === 'right' ? '-left-1' : '-right-1',\n )}\n >\n <span className=\"mx-auto block h-full w-px bg-transparent transition-colors group-hover/handle:bg-[var(--as-border)]\" />\n </div>\n ) : null}\n <DialogPrimitive.Title className=\"sr-only\">{title}</DialogPrimitive.Title>\n <div className=\"flex min-h-0 flex-1 flex-col\">{panel}</div>\n <DialogPrimitive.Close\n aria-label={closeLabel}\n className=\"absolute right-3 top-2.5 rounded-[var(--as-radius-sm)] p-1 text-[var(--as-muted-fg)] transition-colors hover:bg-[var(--as-secondary)] hover:text-[var(--as-fg)] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--as-focus-ring)]\"\n >\n <X aria-hidden className=\"size-4\" />\n </DialogPrimitive.Close>\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n </DialogPrimitive.Root>\n )\n },\n)\n"]}
@@ -0,0 +1,38 @@
1
+ import { PopoverButton } from './chunk-BE3XFZWU.js';
2
+ import { cn } from './chunk-BLJWR4ZV.js';
3
+ import * as React from 'react';
4
+ import { History } from 'lucide-react';
5
+ import { jsx } from 'react/jsx-runtime';
6
+
7
+ function ChatHistoryButton({
8
+ children,
9
+ icon: Icon = History,
10
+ onOpen,
11
+ align = "end",
12
+ panelClassName,
13
+ labels,
14
+ className
15
+ }) {
16
+ const [closeSignal, setCloseSignal] = React.useState(0);
17
+ const close = React.useCallback(() => setCloseSignal((signal) => signal + 1), []);
18
+ return /* @__PURE__ */ jsx("span", { className: cn("inline-flex", className), "data-as": "chat-history-button", children: /* @__PURE__ */ jsx(
19
+ PopoverButton,
20
+ {
21
+ label: labels?.open ?? "Chat history",
22
+ trigger: /* @__PURE__ */ jsx(Icon, { className: "size-4", "aria-hidden": true }),
23
+ align,
24
+ closeSignal,
25
+ onOpenChange: (open) => {
26
+ if (open) {
27
+ onOpen?.();
28
+ }
29
+ },
30
+ panelClassName: cn("h-96 w-72 p-2", panelClassName),
31
+ children: children(close)
32
+ }
33
+ ) });
34
+ }
35
+
36
+ export { ChatHistoryButton };
37
+ //# sourceMappingURL=chunk-YYPO24TA.js.map
38
+ //# sourceMappingURL=chunk-YYPO24TA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/chat-history-button/ChatHistoryButton.tsx"],"names":[],"mappings":";;;;;;AAkCO,SAAS,iBAAA,CAAkB;AAAA,EAChC,QAAA;AAAA,EACA,MAAM,IAAA,GAAO,OAAA;AAAA,EACb,MAAA;AAAA,EACA,KAAA,GAAQ,KAAA;AAAA,EACR,cAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF,CAAA,EAA2B;AACzB,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAU,eAAS,CAAC,CAAA;AACtD,EAAA,MAAM,KAAA,GAAc,KAAA,CAAA,WAAA,CAAY,MAAM,cAAA,CAAe,CAAC,WAAW,MAAA,GAAS,CAAC,CAAA,EAAG,EAAE,CAAA;AAChF,EAAA,uBACE,GAAA,CAAC,UAAK,SAAA,EAAW,EAAA,CAAG,eAAe,SAAS,CAAA,EAAG,WAAQ,qBAAA,EACrD,QAAA,kBAAA,GAAA;AAAA,IAAC,aAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,QAAQ,IAAA,IAAQ,cAAA;AAAA,MACvB,yBAAS,GAAA,CAAC,IAAA,EAAA,EAAK,SAAA,EAAU,QAAA,EAAS,eAAW,IAAA,EAAC,CAAA;AAAA,MAC9C,KAAA;AAAA,MACA,WAAA;AAAA,MACA,YAAA,EAAc,CAAC,IAAA,KAAS;AACtB,QAAA,IAAI,IAAA,EAAM;AACR,UAAA,MAAA,IAAS;AAAA,QACX;AAAA,MACF,CAAA;AAAA,MACA,cAAA,EAAgB,EAAA,CAAG,eAAA,EAAiB,cAAc,CAAA;AAAA,MAEjD,mBAAS,KAAK;AAAA;AAAA,GACjB,EACF,CAAA;AAEJ","file":"chunk-YYPO24TA.js","sourcesContent":["import * as React from 'react'\nimport { History } from 'lucide-react'\nimport type { LucideIcon } from 'lucide-react'\n\nimport { cn } from '../../lib/utils'\nimport { PopoverButton } from '../popover-button/PopoverButton'\n\nexport interface ChatHistoryButtonLabels {\n open: string\n}\n\nexport interface ChatHistoryButtonProps {\n /**\n * Popover content, typically the app's session-list glue. Called with\n * `close` — invoke it after a pick to dismiss the popover (the\n * `closeSignal` pattern underneath).\n */\n children: (close: () => void) => React.ReactNode\n icon?: LucideIcon\n /** Called every time the popover opens — refresh the session list here. */\n onOpen?: () => void\n align?: 'start' | 'center' | 'end'\n panelClassName?: string\n labels?: Partial<ChatHistoryButtonLabels>\n className?: string\n}\n\n/**\n * Header entry point for a chat's session history (career's\n * `HistoryButton` + study's ChatPanel history popover, generalized): a\n * labelled popover trigger wrapping the app's session list. The list\n * itself (search, actions) stays app-side via\n * [`ChatSessionList`](../chat-session-list) glue.\n */\nexport function ChatHistoryButton({\n children,\n icon: Icon = History,\n onOpen,\n align = 'end',\n panelClassName,\n labels,\n className,\n}: ChatHistoryButtonProps) {\n const [closeSignal, setCloseSignal] = React.useState(0)\n const close = React.useCallback(() => setCloseSignal((signal) => signal + 1), [])\n return (\n <span className={cn('inline-flex', className)} data-as=\"chat-history-button\">\n <PopoverButton\n label={labels?.open ?? 'Chat history'}\n trigger={<Icon className=\"size-4\" aria-hidden />}\n align={align}\n closeSignal={closeSignal}\n onOpenChange={(open) => {\n if (open) {\n onOpen?.()\n }\n }}\n panelClassName={cn('h-96 w-72 p-2', panelClassName)}\n >\n {children(close)}\n </PopoverButton>\n </span>\n )\n}\n"]}
@@ -0,0 +1,149 @@
1
+ import { searchScore } from './chunk-B2G66OSQ.js';
2
+ import { cn } from './chunk-BLJWR4ZV.js';
3
+ import * as React from 'react';
4
+ import { Search, Wrench, ChevronDown } from 'lucide-react';
5
+ import { jsxs, jsx } from 'react/jsx-runtime';
6
+
7
+ var ChatToolsCatalog = React.forwardRef(
8
+ function ChatToolsCatalog2({
9
+ tools,
10
+ searchable = true,
11
+ defaultOpen = false,
12
+ labels,
13
+ icon: Icon = Wrench,
14
+ className
15
+ }, ref) {
16
+ const uid = React.useId();
17
+ const [query, setQuery] = React.useState("");
18
+ const [openOverrides, setOpenOverrides] = React.useState({});
19
+ const filtered = React.useMemo(() => {
20
+ const trimmed = query.trim();
21
+ if (trimmed === "") {
22
+ return tools;
23
+ }
24
+ return tools.map((tool) => ({
25
+ tool,
26
+ score: Math.max(
27
+ searchScore(trimmed, tool.title ?? tool.name) ?? -1,
28
+ searchScore(trimmed, tool.name) ?? -1,
29
+ searchScore(trimmed, tool.description ?? "") ?? -1
30
+ )
31
+ })).filter((entry) => entry.score >= 0).sort((a, b) => b.score - a.score).map((entry) => entry.tool);
32
+ }, [tools, query]);
33
+ return /* @__PURE__ */ jsxs(
34
+ "div",
35
+ {
36
+ ref,
37
+ "data-as": "chat-tools-catalog",
38
+ className: cn("flex min-h-0 w-full flex-col gap-2", className),
39
+ children: [
40
+ searchable ? /* @__PURE__ */ jsxs("div", { className: "relative shrink-0", children: [
41
+ /* @__PURE__ */ jsx(
42
+ Search,
43
+ {
44
+ className: "pointer-events-none absolute start-2 top-1/2 size-3.5 -translate-y-1/2 text-[var(--as-muted-fg)]",
45
+ "aria-hidden": true
46
+ }
47
+ ),
48
+ /* @__PURE__ */ jsx(
49
+ "input",
50
+ {
51
+ type: "search",
52
+ role: "searchbox",
53
+ value: query,
54
+ "aria-label": labels?.search ?? "Search tools",
55
+ placeholder: labels?.searchPlaceholder ?? "Search\u2026",
56
+ onChange: (event) => setQuery(event.target.value),
57
+ className: "w-full rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface)] py-1.5 pe-2 ps-8 text-xs text-[var(--as-fg)] placeholder:text-[var(--as-muted-fg)] focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]"
58
+ }
59
+ )
60
+ ] }) : null,
61
+ /* @__PURE__ */ jsx("div", { role: "list", "aria-label": labels?.tools ?? "Tools", className: "flex flex-col gap-2", children: tools.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-1 py-3 text-xs text-[var(--as-muted-fg)]", children: labels?.empty ?? "No tools available" }) : filtered.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-1 py-3 text-xs text-[var(--as-muted-fg)]", children: labels?.noResults ?? "No matching tools" }) : filtered.map((tool) => {
62
+ const open = openOverrides[tool.name] ?? defaultOpen;
63
+ const regionId = `${uid}-${tool.name}`;
64
+ const toggle = () => setOpenOverrides((current) => ({ ...current, [tool.name]: !open }));
65
+ return /* @__PURE__ */ jsxs(
66
+ "div",
67
+ {
68
+ role: "listitem",
69
+ "data-as": "chat-tools-catalog-entry",
70
+ "data-open": open || void 0,
71
+ className: "rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface)] text-xs",
72
+ children: [
73
+ /* @__PURE__ */ jsxs(
74
+ "button",
75
+ {
76
+ type: "button",
77
+ "aria-expanded": open,
78
+ "aria-controls": regionId,
79
+ onClick: toggle,
80
+ className: "flex w-full items-center gap-2 px-2.5 py-1.5 text-left focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--as-focus-ring)]",
81
+ children: [
82
+ /* @__PURE__ */ jsx(Icon, { className: "size-3.5 shrink-0 text-[var(--as-muted-fg)]", "aria-hidden": true }),
83
+ /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
84
+ /* @__PURE__ */ jsx("span", { className: "font-mono font-medium text-[var(--as-fg)]", children: tool.name }),
85
+ tool.title ? /* @__PURE__ */ jsx("span", { className: "ml-1.5 text-[var(--as-muted-fg)]", children: tool.title }) : null
86
+ ] }),
87
+ tool.scope ? /* @__PURE__ */ jsx("span", { className: "shrink-0 rounded-full bg-[var(--as-surface-raised)] px-1.5 py-0.5 text-[10px] uppercase tracking-wide text-[var(--as-muted-fg)]", children: tool.scope }) : null,
88
+ /* @__PURE__ */ jsx(
89
+ ChevronDown,
90
+ {
91
+ className: cn(
92
+ "size-3.5 shrink-0 text-[var(--as-muted-fg)] transition-transform",
93
+ open && "rotate-180"
94
+ ),
95
+ "aria-hidden": true
96
+ }
97
+ )
98
+ ]
99
+ }
100
+ ),
101
+ open ? /* @__PURE__ */ jsxs("div", { id: regionId, className: "flex flex-col gap-2 border-t border-[var(--as-border)] px-2.5 py-2", children: [
102
+ tool.description ? /* @__PURE__ */ jsx("p", { className: "text-[var(--as-fg)]", children: tool.description }) : null,
103
+ tool.arguments && tool.arguments.length > 0 ? /* @__PURE__ */ jsxs("div", { children: [
104
+ /* @__PURE__ */ jsx("p", { className: "mb-1 font-medium uppercase tracking-wide text-[var(--as-muted-fg)]", children: labels?.arguments ?? "Arguments" }),
105
+ /* @__PURE__ */ jsx("ul", { className: "flex flex-col gap-1.5", children: tool.arguments.map((argument) => /* @__PURE__ */ jsxs(
106
+ "li",
107
+ {
108
+ className: "rounded-[var(--as-radius-sm)] border border-[var(--as-border)] bg-[var(--as-surface-raised)] px-2 py-1.5",
109
+ children: [
110
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-x-2 gap-y-1", children: [
111
+ /* @__PURE__ */ jsx("span", { className: "font-mono font-medium text-[var(--as-fg)]", children: argument.name }),
112
+ argument.type ? /* @__PURE__ */ jsx("span", { className: "rounded-full border border-[var(--as-border)] bg-[var(--as-surface)] px-1.5 py-px font-mono text-[10px] leading-4 text-[var(--as-muted-fg)]", children: argument.type }) : null,
113
+ /* @__PURE__ */ jsx(
114
+ "span",
115
+ {
116
+ className: cn(
117
+ "text-[10px] font-medium uppercase tracking-wide",
118
+ argument.required ? "text-[var(--as-warning)]" : "text-[var(--as-muted-fg)]"
119
+ ),
120
+ children: argument.required ? labels?.required ?? "required" : labels?.optional ?? "optional"
121
+ }
122
+ )
123
+ ] }),
124
+ argument.description ? /* @__PURE__ */ jsx("p", { className: "mt-0.5 leading-snug text-[var(--as-muted-fg)]", children: argument.description }) : null
125
+ ]
126
+ },
127
+ argument.name
128
+ )) })
129
+ ] }) : null,
130
+ tool.example ? /* @__PURE__ */ jsx("pre", { className: "max-h-40 overflow-auto whitespace-pre-wrap break-words rounded-[var(--as-radius-sm)] bg-[var(--as-surface-raised)] p-2 font-mono text-[11px] leading-relaxed", children: tool.example }) : null,
131
+ tool.response ? /* @__PURE__ */ jsxs("div", { children: [
132
+ /* @__PURE__ */ jsx("p", { className: "mb-1 font-medium uppercase tracking-wide text-[var(--as-muted-fg)]", children: labels?.response ?? "Response" }),
133
+ /* @__PURE__ */ jsx("p", { className: "text-[var(--as-fg)]", children: tool.response })
134
+ ] }) : null
135
+ ] }) : null
136
+ ]
137
+ },
138
+ tool.name
139
+ );
140
+ }) })
141
+ ]
142
+ }
143
+ );
144
+ }
145
+ );
146
+
147
+ export { ChatToolsCatalog };
148
+ //# sourceMappingURL=chunk-ZSCL34WT.js.map
149
+ //# sourceMappingURL=chunk-ZSCL34WT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/chat-tools-catalog/ChatToolsCatalog.tsx"],"names":["ChatToolsCatalog"],"mappings":"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","file":"chunk-ZSCL34WT.js","sourcesContent":["import * as React from 'react'\nimport { ChevronDown, Search, Wrench } from 'lucide-react'\nimport type { LucideIcon } from 'lucide-react'\n\nimport { cn } from '../../lib/utils'\nimport { searchScore } from '../../lib/fuzzy'\n\nexport interface ChatToolCatalogArgument {\n name: string\n type?: string\n required?: boolean\n description?: string | null\n}\n\nexport interface ChatToolCatalogEntry {\n /** Stable tool identifier (rendered mono). */\n name: string\n /** Human title; falls back to `name`. */\n title?: string\n description?: string\n arguments?: ChatToolCatalogArgument[]\n example?: string | null\n response?: string | null\n scope?: string | null\n}\n\nexport interface ChatToolsCatalogLabels {\n /** Accessible name of the tool list. */\n tools: string\n search: string\n searchPlaceholder: string\n arguments: string\n response: string\n required: string\n optional: string\n empty: string\n noResults: string\n}\n\nexport interface ChatToolsCatalogProps {\n tools: ChatToolCatalogEntry[]\n searchable?: boolean\n /** Expand every entry's details initially (uncontrolled per entry after that). */\n defaultOpen?: boolean\n labels?: Partial<ChatToolsCatalogLabels>\n icon?: LucideIcon\n className?: string\n}\n\n/**\n * Catalog of the tools an assistant can use (study's `ToolsDialog` body,\n * generalized): searchable disclosure cards with description, argument\n * list, example and response shape. Presentational only — fetching and\n * the surrounding modal/popover stay app-side.\n */\nexport const ChatToolsCatalog = React.forwardRef<HTMLDivElement, ChatToolsCatalogProps>(\n function ChatToolsCatalog(\n {\n tools,\n searchable = true,\n defaultOpen = false,\n labels,\n icon: Icon = Wrench,\n className,\n },\n ref,\n ) {\n const uid = React.useId()\n const [query, setQuery] = React.useState('')\n const [openOverrides, setOpenOverrides] = React.useState<Record<string, boolean>>({})\n\n const filtered = React.useMemo(() => {\n const trimmed = query.trim()\n if (trimmed === '') {\n return tools\n }\n return tools\n .map((tool) => ({\n tool,\n score: Math.max(\n searchScore(trimmed, tool.title ?? tool.name) ?? -1,\n searchScore(trimmed, tool.name) ?? -1,\n searchScore(trimmed, tool.description ?? '') ?? -1,\n ),\n }))\n .filter((entry) => entry.score >= 0)\n .sort((a, b) => b.score - a.score)\n .map((entry) => entry.tool)\n }, [tools, query])\n\n return (\n <div\n ref={ref}\n data-as=\"chat-tools-catalog\"\n className={cn('flex min-h-0 w-full flex-col gap-2', className)}\n >\n {searchable ? (\n <div className=\"relative shrink-0\">\n <Search\n className=\"pointer-events-none absolute start-2 top-1/2 size-3.5 -translate-y-1/2 text-[var(--as-muted-fg)]\"\n aria-hidden\n />\n <input\n type=\"search\"\n role=\"searchbox\"\n value={query}\n aria-label={labels?.search ?? 'Search tools'}\n placeholder={labels?.searchPlaceholder ?? 'Search…'}\n onChange={(event) => setQuery(event.target.value)}\n className=\"w-full rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface)] py-1.5 pe-2 ps-8 text-xs text-[var(--as-fg)] placeholder:text-[var(--as-muted-fg)] focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]\"\n />\n </div>\n ) : null}\n <div role=\"list\" aria-label={labels?.tools ?? 'Tools'} className=\"flex flex-col gap-2\">\n {tools.length === 0 ? (\n <p className=\"px-1 py-3 text-xs text-[var(--as-muted-fg)]\">\n {labels?.empty ?? 'No tools available'}\n </p>\n ) : filtered.length === 0 ? (\n <p className=\"px-1 py-3 text-xs text-[var(--as-muted-fg)]\">\n {labels?.noResults ?? 'No matching tools'}\n </p>\n ) : (\n filtered.map((tool) => {\n const open = openOverrides[tool.name] ?? defaultOpen\n const regionId = `${uid}-${tool.name}`\n const toggle = () =>\n setOpenOverrides((current) => ({ ...current, [tool.name]: !open }))\n return (\n <div\n key={tool.name}\n role=\"listitem\"\n data-as=\"chat-tools-catalog-entry\"\n data-open={open || undefined}\n className=\"rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface)] text-xs\"\n >\n <button\n type=\"button\"\n aria-expanded={open}\n aria-controls={regionId}\n onClick={toggle}\n className=\"flex w-full items-center gap-2 px-2.5 py-1.5 text-left focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--as-focus-ring)]\"\n >\n <Icon className=\"size-3.5 shrink-0 text-[var(--as-muted-fg)]\" aria-hidden />\n <span className=\"min-w-0 flex-1\">\n <span className=\"font-mono font-medium text-[var(--as-fg)]\">{tool.name}</span>\n {tool.title ? (\n <span className=\"ml-1.5 text-[var(--as-muted-fg)]\">{tool.title}</span>\n ) : null}\n </span>\n {tool.scope ? (\n <span className=\"shrink-0 rounded-full bg-[var(--as-surface-raised)] px-1.5 py-0.5 text-[10px] uppercase tracking-wide text-[var(--as-muted-fg)]\">\n {tool.scope}\n </span>\n ) : null}\n <ChevronDown\n className={cn(\n 'size-3.5 shrink-0 text-[var(--as-muted-fg)] transition-transform',\n open && 'rotate-180',\n )}\n aria-hidden\n />\n </button>\n {open ? (\n <div id={regionId} className=\"flex flex-col gap-2 border-t border-[var(--as-border)] px-2.5 py-2\">\n {tool.description ? (\n <p className=\"text-[var(--as-fg)]\">{tool.description}</p>\n ) : null}\n {tool.arguments && tool.arguments.length > 0 ? (\n <div>\n <p className=\"mb-1 font-medium uppercase tracking-wide text-[var(--as-muted-fg)]\">\n {labels?.arguments ?? 'Arguments'}\n </p>\n <ul className=\"flex flex-col gap-1.5\">\n {tool.arguments.map((argument) => (\n <li\n key={argument.name}\n className=\"rounded-[var(--as-radius-sm)] border border-[var(--as-border)] bg-[var(--as-surface-raised)] px-2 py-1.5\"\n >\n <div className=\"flex flex-wrap items-center gap-x-2 gap-y-1\">\n <span className=\"font-mono font-medium text-[var(--as-fg)]\">\n {argument.name}\n </span>\n {argument.type ? (\n <span className=\"rounded-full border border-[var(--as-border)] bg-[var(--as-surface)] px-1.5 py-px font-mono text-[10px] leading-4 text-[var(--as-muted-fg)]\">\n {argument.type}\n </span>\n ) : null}\n <span\n className={cn(\n 'text-[10px] font-medium uppercase tracking-wide',\n argument.required\n ? 'text-[var(--as-warning)]'\n : 'text-[var(--as-muted-fg)]',\n )}\n >\n {argument.required\n ? (labels?.required ?? 'required')\n : (labels?.optional ?? 'optional')}\n </span>\n </div>\n {argument.description ? (\n <p className=\"mt-0.5 leading-snug text-[var(--as-muted-fg)]\">\n {argument.description}\n </p>\n ) : null}\n </li>\n ))}\n </ul>\n </div>\n ) : null}\n {tool.example ? (\n <pre className=\"max-h-40 overflow-auto whitespace-pre-wrap break-words rounded-[var(--as-radius-sm)] bg-[var(--as-surface-raised)] p-2 font-mono text-[11px] leading-relaxed\">\n {tool.example}\n </pre>\n ) : null}\n {tool.response ? (\n <div>\n <p className=\"mb-1 font-medium uppercase tracking-wide text-[var(--as-muted-fg)]\">\n {labels?.response ?? 'Response'}\n </p>\n <p className=\"text-[var(--as-fg)]\">{tool.response}</p>\n </div>\n ) : null}\n </div>\n ) : null}\n </div>\n )\n })\n )}\n </div>\n </div>\n )\n },\n)\n"]}
package/dist/index.d.ts CHANGED
@@ -74,6 +74,10 @@ export { ChatComposer, ChatComposerIcons, ChatComposerLabels, ChatComposerProps
74
74
  export { ChatTranscript, ChatTranscriptLabels, ChatTranscriptProps } from './chat-transcript.js';
75
75
  export { ChatBranchTree, ChatBranchTreeIcons, ChatBranchTreeLabels, ChatBranchTreeNode, ChatBranchTreeProps } from './chat-branch-tree.js';
76
76
  export { ChatSessionList, ChatSessionListIcons, ChatSessionListLabels, ChatSessionListProps, ChatSessionView } from './chat-session-list.js';
77
+ export { ChatToolCatalogArgument, ChatToolCatalogEntry, ChatToolsCatalog, ChatToolsCatalogLabels, ChatToolsCatalogProps } from './chat-tools-catalog.js';
78
+ export { ChatExportMessage, ChatExportOptions, buildChatMarkdown, chatExportFileName, downloadChatMarkdown } from './chat-export.js';
79
+ export { ChatHistoryButton, ChatHistoryButtonLabels, ChatHistoryButtonProps } from './chat-history-button.js';
80
+ export { ChatTraceMeta, ChatTraceMetaProps } from './chat-trace-meta.js';
77
81
  export { ChatPanel, ChatPanelProps, ChatPanelVariant } from './chat-panel.js';
78
82
  export { ChatDrawer, ChatDrawerProps } from './chat-drawer.js';
79
83
  export { ChatLauncher, ChatLauncherProps } from './chat-launcher.js';
package/dist/index.js CHANGED
@@ -1,61 +1,65 @@
1
+ export { UserMenu } from './chunk-535TM7SK.js';
2
+ export { ThemeScope } from './chunk-TGU3PKNM.js';
3
+ export { TimeList } from './chunk-GVOC3ARM.js';
4
+ export { TimePicker, TimePickerContent } from './chunk-CR42EAF4.js';
1
5
  export { InfoTooltip, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './chunk-34NO2UOB.js';
2
6
  export { UndoNotice } from './chunk-OUHUVACM.js';
3
7
  export { ViewToggle } from './chunk-MXOBOS4Y.js';
4
8
  export { Stepper, Wizard } from './chunk-YMCMUAIF.js';
9
+ export { ModelRegistry } from './chunk-BHHDCY2B.js';
10
+ export { CapabilityChips } from './chunk-G3DWN2DJ.js';
11
+ export { SelectionBar } from './chunk-HSUCCANX.js';
5
12
  export { Table } from './chunk-5LRRVD27.js';
6
13
  export { TaskAssignmentPicker } from './chunk-Q5THPPNL.js';
7
14
  export { SettingsShell } from './chunk-ZK2V2LPA.js';
8
15
  export { SidebarNav } from './chunk-SW3YNICQ.js';
9
- export { UserMenu } from './chunk-535TM7SK.js';
10
- export { ThemeScope } from './chunk-TGU3PKNM.js';
11
- export { TimeList } from './chunk-GVOC3ARM.js';
12
- export { TimePicker, TimePickerContent } from './chunk-CR42EAF4.js';
16
+ export { ProviderForm } from './chunk-4WDXLXHL.js';
13
17
  export { RangeBar } from './chunk-PFAH25VU.js';
14
18
  export { ScaleSlider, scaleColorForValue } from './chunk-PSFJN7WH.js';
15
19
  export { SearchInput } from './chunk-H5U4KNXF.js';
16
- export { ModelRegistry } from './chunk-BHHDCY2B.js';
17
- export { CapabilityChips } from './chunk-G3DWN2DJ.js';
18
- export { SelectionBar } from './chunk-HSUCCANX.js';
19
- export { MarqueeBand, MarqueeSurface, hitTestIds, marqueeRect, rectsIntersect, useMarquee } from './chunk-RU3DEF2O.js';
20
- export { ModelPicker } from './chunk-S4WHBQJ2.js';
21
- export { PanelModal } from './chunk-G6557MEN.js';
22
- export { ProviderForm } from './chunk-4WDXLXHL.js';
23
- export { Input } from './chunk-M4V7XHL7.js';
24
20
  export { RichTextEditor } from './chunk-AY77TWLT.js';
25
21
  export { DictationButton, DictationStrip, useDictation } from './chunk-KAC2DOLH.js';
26
22
  export { useAiTextTransform } from './chunk-BKAO7BTU.js';
27
23
  export { TextDiffView, computeLineDiff, wordSegments } from './chunk-2PR6POP6.js';
28
- export { EmptyState } from './chunk-KDJLYKR6.js';
29
- export { ErrorBanner } from './chunk-BJOY3XL7.js';
30
- export { ExpandableSearch } from './chunk-4SW3ESVI.js';
24
+ export { MarqueeBand, MarqueeSurface, hitTestIds, marqueeRect, rectsIntersect, useMarquee } from './chunk-RU3DEF2O.js';
25
+ export { ModelPicker } from './chunk-S4WHBQJ2.js';
26
+ export { PanelModal } from './chunk-G6557MEN.js';
31
27
  export { FileQueue } from './chunk-IQKP2BWE.js';
32
- export { FileCard, formatBytes } from './chunk-J4OELYDR.js';
33
28
  export { FlowStatusCard } from './chunk-PRHTQBCP.js';
34
29
  export { FieldLabel } from './chunk-I5J6SDLK.js';
35
30
  export { InfoButton } from './chunk-OT6EQFMP.js';
36
- export { PopoverButton } from './chunk-BE3XFZWU.js';
37
- export { CheckIndicator } from './chunk-XE4TFW63.js';
38
- export { ChipInput } from './chunk-HIRR2F4R.js';
39
- export { Combobox, ComboboxMulti } from './chunk-WDLUZS2G.js';
31
+ export { Input } from './chunk-M4V7XHL7.js';
40
32
  export { ConfirmationModal } from './chunk-2YQSA5AE.js';
41
33
  export { ContextMenu } from './chunk-YIGLULRG.js';
42
34
  export { ActionMenu, Menu, MenuCheckboxItem, MenuContent, MenuGroup, MenuItem, MenuLabel, MenuSeparator, MenuTrigger } from './chunk-XSJ3TWWZ.js';
43
35
  export { DatePicker } from './chunk-6VCJX4CP.js';
36
+ export { EmptyState } from './chunk-KDJLYKR6.js';
37
+ export { ErrorBanner } from './chunk-BJOY3XL7.js';
38
+ export { ExpandableSearch } from './chunk-4SW3ESVI.js';
39
+ export { FileCard, formatBytes } from './chunk-J4OELYDR.js';
40
+ export { ChatHistoryButton } from './chunk-YYPO24TA.js';
41
+ export { PopoverButton } from './chunk-BE3XFZWU.js';
42
+ export { ChatTraceMeta } from './chunk-QMQ73C23.js';
43
+ export { ChatToolsCatalog } from './chunk-ZSCL34WT.js';
44
+ export { ConnectionTestRow } from './chunk-OGQF4XJB.js';
45
+ export { CheckIndicator } from './chunk-XE4TFW63.js';
46
+ export { ChipInput } from './chunk-HIRR2F4R.js';
47
+ export { Combobox, ComboboxMulti } from './chunk-WDLUZS2G.js';
44
48
  export { ChatBranchTree } from './chunk-HQIYSW2D.js';
45
- export { ChatDrawer } from './chunk-X3C2FBMR.js';
49
+ export { ChatDrawer } from './chunk-WBSGFOSD.js';
46
50
  export { ChatReasoning } from './chunk-QVDCFZSE.js';
47
51
  export { ChatSessionList } from './chunk-NKYPNEOX.js';
48
52
  export { ChatToolCard } from './chunk-NBT7NLNU.js';
49
53
  export { ChatTurnStatus } from './chunk-P75QKU5J.js';
50
- export { ConnectionTestRow } from './chunk-OGQF4XJB.js';
54
+ export { buildChatMarkdown, chatExportFileName, downloadChatMarkdown } from './chunk-DRJGZ5TB.js';
51
55
  export { initialLiveTurnState, liveTurnReducer, useChatStream } from './chunk-6GNLY2EB.js';
52
56
  export { activePathSet, buildBranchTree, linearTree, variantInfo, walkActivePath } from './chunk-Z4IBQ53C.js';
53
57
  export { ChatLauncher } from './chunk-RPLEI6LQ.js';
54
58
  export { Portal } from './chunk-XZWLTTHA.js';
55
59
  export { ChatComposer } from './chunk-743FJDRA.js';
56
- export { ChatPanel } from './chunk-S62VJVWB.js';
57
- export { ChatTranscript } from './chunk-BVJT67B5.js';
58
- export { ChatMessage, ChatMessageEditor, MessageVariantSwitcher } from './chunk-BSIWLVDX.js';
60
+ export { ChatPanel } from './chunk-LFSICACE.js';
61
+ export { ChatTranscript } from './chunk-FS7M7PNS.js';
62
+ export { ChatMessage, ChatMessageEditor, MessageVariantSwitcher } from './chunk-FGYGWZ6S.js';
59
63
  export { MarkdownCodeBlock, MarkdownSurface, MermaidDiagram } from './chunk-DZBTJZZV.js';
60
64
  export { CopyButton } from './chunk-3JJ2WCPN.js';
61
65
  export { rawTokens, semanticTokens } from './chunk-GDGKARRB.js';
@@ -66,7 +70,7 @@ export { ChipList } from './chunk-QUPGIPTT.js';
66
70
  export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from './chunk-RYE5YCFF.js';
67
71
  export { AiButton } from './chunk-3VCFRIIK.js';
68
72
  export { Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger } from './chunk-SIIY2EGI.js';
69
- export { AiMagicFill } from './chunk-5QTHDB3D.js';
73
+ export { AiMagicFill } from './chunk-EODV6JK7.js';
70
74
  export { FormModal } from './chunk-62GIJMWT.js';
71
75
  export { Modal, ModalClose, ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalTitle, ModalTrigger, modalContentVariants } from './chunk-Y7BKBG57.js';
72
76
  export { Button, buttonVariants } from './chunk-GTXGTQ6F.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/upload-dropzone/UploadDropzone.tsx"],"names":["UploadDropzone"],"mappings":"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","file":"index.js","sourcesContent":["import * as React from 'react'\nimport { FolderUp, Loader2, Upload } from 'lucide-react'\nimport { cn } from '../../lib/utils'\n\nexport interface UploadDropzoneProps {\n onFiles: (files: File[]) => void\n uploading?: boolean\n variant?: 'block' | 'row'\n label?: string\n hint?: string\n browseLabel?: string\n folderLabel?: string\n accept?: string\n multiple?: boolean\n allowFolders?: boolean\n disabled?: boolean\n className?: string\n}\n\n/**\n * Presentational dropzone: drag events and file-picker results go out via\n * `onFiles` — uploading, storage and progress stay app-side. Pass\n * `uploading` to render a busy state and suppress input.\n */\nexport const UploadDropzone = React.forwardRef<HTMLDivElement, UploadDropzoneProps>(\n function UploadDropzone(\n {\n onFiles,\n uploading = false,\n variant = 'block',\n label = 'Drop files here or click to browse',\n hint,\n browseLabel = 'Choose files',\n folderLabel = 'Choose folder',\n accept,\n multiple = true,\n allowFolders = false,\n disabled = false,\n className,\n },\n ref,\n ) {\n const [dragging, setDragging] = React.useState(false)\n const fileInput = React.useRef<HTMLInputElement>(null)\n const folderInput = React.useRef<HTMLInputElement>(null)\n\n const active = !disabled && !uploading\n\n const emit = (list: FileList | null) => {\n if (!active || !list || list.length === 0) return\n onFiles(Array.from(list))\n }\n\n const input = allowFolders ? (\n <>\n <input\n ref={fileInput}\n type=\"file\"\n accept={accept}\n multiple={multiple}\n className=\"hidden\"\n aria-hidden\n tabIndex={-1}\n onChange={(event) => {\n emit(event.target.files)\n event.target.value = ''\n }}\n />\n <input\n ref={folderInput}\n type=\"file\"\n multiple\n className=\"hidden\"\n // @ts-expect-error non-standard but universally supported directory picker\n webkitdirectory=\"\"\n aria-hidden\n tabIndex={-1}\n onChange={(event) => {\n emit(event.target.files)\n event.target.value = ''\n }}\n />\n </>\n ) : (\n <input\n ref={fileInput}\n type=\"file\"\n accept={accept}\n multiple={multiple}\n className=\"hidden\"\n aria-hidden\n tabIndex={-1}\n onChange={(event) => {\n emit(event.target.files)\n event.target.value = ''\n }}\n />\n )\n\n return (\n <>\n {input}\n <div\n ref={ref}\n data-as=\"upload-dropzone\"\n data-variant={variant}\n data-dragging={dragging || undefined}\n role=\"button\"\n tabIndex={active ? 0 : -1}\n aria-label={label}\n aria-disabled={disabled || uploading || undefined}\n onClick={() => active && fileInput.current?.click()}\n onKeyDown={(event) => {\n if (active && (event.key === 'Enter' || event.key === ' ')) {\n event.preventDefault()\n fileInput.current?.click()\n }\n }}\n onDragOver={(event) => {\n event.preventDefault()\n if (active) setDragging(true)\n }}\n onDragLeave={() => setDragging(false)}\n onDrop={(event) => {\n event.preventDefault()\n setDragging(false)\n emit(event.dataTransfer.files)\n }}\n className={cn(\n 'flex cursor-pointer items-center justify-center gap-3 border border-dashed border-[var(--as-border)] bg-[var(--as-surface)] text-[var(--as-muted-fg)] transition-colors',\n 'hover:border-[var(--as-primary)] hover:text-[var(--as-fg)]',\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--as-focus-ring)]',\n variant === 'block' ? 'rounded-[var(--as-radius-lg)] p-8' : 'rounded-[var(--as-radius)] px-4 py-3',\n dragging && 'border-[var(--as-primary)] bg-[color-mix(in_srgb,var(--as-primary)_8%,transparent)] text-[var(--as-fg)]',\n uploading && 'cursor-progress opacity-70',\n disabled && 'pointer-events-none opacity-50',\n className,\n )}\n >\n {uploading ? (\n <Loader2 className=\"size-5 shrink-0 animate-spin\" aria-hidden />\n ) : allowFolders ? (\n <FolderUp className=\"size-5 shrink-0\" aria-hidden />\n ) : (\n <Upload className=\"size-5 shrink-0\" aria-hidden />\n )}\n <span className=\"flex min-w-0 flex-col\">\n <span className=\"truncate text-sm font-medium\" role={uploading ? 'status' : undefined}>\n {uploading ? `${browseLabel}…` : dragging ? folderLabel : label}\n </span>\n {hint ? <span className=\"truncate text-xs\">{hint}</span> : null}\n </span>\n </div>\n </>\n )\n },\n)\n"]}
1
+ {"version":3,"sources":["../src/components/upload-dropzone/UploadDropzone.tsx"],"names":["UploadDropzone"],"mappings":"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","file":"index.js","sourcesContent":["import * as React from 'react'\nimport { FolderUp, Loader2, Upload } from 'lucide-react'\nimport { cn } from '../../lib/utils'\n\nexport interface UploadDropzoneProps {\n onFiles: (files: File[]) => void\n uploading?: boolean\n variant?: 'block' | 'row'\n label?: string\n hint?: string\n browseLabel?: string\n folderLabel?: string\n accept?: string\n multiple?: boolean\n allowFolders?: boolean\n disabled?: boolean\n className?: string\n}\n\n/**\n * Presentational dropzone: drag events and file-picker results go out via\n * `onFiles` — uploading, storage and progress stay app-side. Pass\n * `uploading` to render a busy state and suppress input.\n */\nexport const UploadDropzone = React.forwardRef<HTMLDivElement, UploadDropzoneProps>(\n function UploadDropzone(\n {\n onFiles,\n uploading = false,\n variant = 'block',\n label = 'Drop files here or click to browse',\n hint,\n browseLabel = 'Choose files',\n folderLabel = 'Choose folder',\n accept,\n multiple = true,\n allowFolders = false,\n disabled = false,\n className,\n },\n ref,\n ) {\n const [dragging, setDragging] = React.useState(false)\n const fileInput = React.useRef<HTMLInputElement>(null)\n const folderInput = React.useRef<HTMLInputElement>(null)\n\n const active = !disabled && !uploading\n\n const emit = (list: FileList | null) => {\n if (!active || !list || list.length === 0) return\n onFiles(Array.from(list))\n }\n\n const input = allowFolders ? (\n <>\n <input\n ref={fileInput}\n type=\"file\"\n accept={accept}\n multiple={multiple}\n className=\"hidden\"\n aria-hidden\n tabIndex={-1}\n onChange={(event) => {\n emit(event.target.files)\n event.target.value = ''\n }}\n />\n <input\n ref={folderInput}\n type=\"file\"\n multiple\n className=\"hidden\"\n // @ts-expect-error non-standard but universally supported directory picker\n webkitdirectory=\"\"\n aria-hidden\n tabIndex={-1}\n onChange={(event) => {\n emit(event.target.files)\n event.target.value = ''\n }}\n />\n </>\n ) : (\n <input\n ref={fileInput}\n type=\"file\"\n accept={accept}\n multiple={multiple}\n className=\"hidden\"\n aria-hidden\n tabIndex={-1}\n onChange={(event) => {\n emit(event.target.files)\n event.target.value = ''\n }}\n />\n )\n\n return (\n <>\n {input}\n <div\n ref={ref}\n data-as=\"upload-dropzone\"\n data-variant={variant}\n data-dragging={dragging || undefined}\n role=\"button\"\n tabIndex={active ? 0 : -1}\n aria-label={label}\n aria-disabled={disabled || uploading || undefined}\n onClick={() => active && fileInput.current?.click()}\n onKeyDown={(event) => {\n if (active && (event.key === 'Enter' || event.key === ' ')) {\n event.preventDefault()\n fileInput.current?.click()\n }\n }}\n onDragOver={(event) => {\n event.preventDefault()\n if (active) setDragging(true)\n }}\n onDragLeave={() => setDragging(false)}\n onDrop={(event) => {\n event.preventDefault()\n setDragging(false)\n emit(event.dataTransfer.files)\n }}\n className={cn(\n 'flex cursor-pointer items-center justify-center gap-3 border border-dashed border-[var(--as-border)] bg-[var(--as-surface)] text-[var(--as-muted-fg)] transition-colors',\n 'hover:border-[var(--as-primary)] hover:text-[var(--as-fg)]',\n 'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--as-focus-ring)]',\n variant === 'block' ? 'rounded-[var(--as-radius-lg)] p-8' : 'rounded-[var(--as-radius)] px-4 py-3',\n dragging && 'border-[var(--as-primary)] bg-[color-mix(in_srgb,var(--as-primary)_8%,transparent)] text-[var(--as-fg)]',\n uploading && 'cursor-progress opacity-70',\n disabled && 'pointer-events-none opacity-50',\n className,\n )}\n >\n {uploading ? (\n <Loader2 className=\"size-5 shrink-0 animate-spin\" aria-hidden />\n ) : allowFolders ? (\n <FolderUp className=\"size-5 shrink-0\" aria-hidden />\n ) : (\n <Upload className=\"size-5 shrink-0\" aria-hidden />\n )}\n <span className=\"flex min-w-0 flex-col\">\n <span className=\"truncate text-sm font-medium\" role={uploading ? 'status' : undefined}>\n {uploading ? `${browseLabel}…` : dragging ? folderLabel : label}\n </span>\n {hint ? <span className=\"truncate text-xs\">{hint}</span> : null}\n </span>\n </div>\n </>\n )\n },\n)\n"]}