@neuronection/assistant-ui 0.29.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/README.md +1 -1
- package/dist/chat-composer.js +1 -1
- package/dist/chat-launcher.d.ts +8 -0
- package/dist/chat-launcher.js +1 -1
- package/dist/chat-session-list.js +1 -1
- package/dist/chat-tools-catalog.js +1 -1
- package/dist/{chunk-NKYPNEOX.js → chunk-66K355IZ.js} +3 -3
- package/dist/chunk-66K355IZ.js.map +1 -0
- package/dist/{chunk-743FJDRA.js → chunk-IN6ORI3V.js} +9 -2
- package/dist/chunk-IN6ORI3V.js.map +1 -0
- package/dist/{chunk-RPLEI6LQ.js → chunk-OUJJLZ6C.js} +5 -4
- package/dist/chunk-OUJJLZ6C.js.map +1 -0
- package/dist/{chunk-N55WQMBA.js → chunk-TC4NQL3H.js} +3 -3
- package/dist/{chunk-N55WQMBA.js.map → chunk-TC4NQL3H.js.map} +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.js +4 -4
- package/package.json +1 -1
- package/dist/chunk-743FJDRA.js.map +0 -1
- package/dist/chunk-NKYPNEOX.js.map +0 -1
- package/dist/chunk-RPLEI6LQ.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# @neuronection/assistant-ui
|
|
2
2
|
|
|
3
|
+
## 0.30.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`815aecb`](https://github.com/neuronection/assistant-ui/commit/815aecbbbde173d2b569a2552d1773d7eaca84c2) Thanks [@constLiakos](https://github.com/constLiakos)! - ChatComposer: the input row now exposes styling hooks —
|
|
8
|
+
`data-as="chat-composer-row"` plus a `data-multiline` attribute that is
|
|
9
|
+
present whenever the auto-growing textarea renders more than one line
|
|
10
|
+
(measured in the same layout pass as the auto-grow height). Layout stays
|
|
11
|
+
unchanged by default; apps opt in via the hook (first consumer:
|
|
12
|
+
desktop-assistant wraps the toolbars into a footer row under the
|
|
13
|
+
full-width textarea once a draft is multiline).
|
|
14
|
+
|
|
15
|
+
- [`068b817`](https://github.com/neuronection/assistant-ui/commit/068b8174e2701a20d9b4beae411127cbaf0f826c) Thanks [@constLiakos](https://github.com/constLiakos)! - ChatLauncher: new `showClose` prop (default `true`). Set it to `false`
|
|
16
|
+
when the panel body renders its own header actions — the overlaid
|
|
17
|
+
close button pinned to the panel's top-right corner intercepted clicks
|
|
18
|
+
meant for top-right header buttons (career's bubble panel: the
|
|
19
|
+
"New chat" action was unclickable with a mouse). Compose the close
|
|
20
|
+
into the header actions via `onOpenChange(false)` instead.
|
|
21
|
+
|
|
22
|
+
## 0.29.1
|
|
23
|
+
|
|
24
|
+
### Patch Changes
|
|
25
|
+
|
|
26
|
+
- [`6c8882c`](https://github.com/neuronection/assistant-ui/commit/6c8882cfc951a167b728b3977b5e1cffdda87a0b) Thanks [@constLiakos](https://github.com/constLiakos)! - fix(a11y): ChatSessionList and ChatToolsCatalog no longer render their empty/no-matches `<p>` states as children of `role="list"` (aria-required-children, critical — a list expects listitem children). The `role="list"` container now renders only when there are items to show; empty and no-results states render standalone with unchanged copy and styling. Found by desktop-assistant's new exclusion-free axe scans of the chat desktop window; regression axe tests for both components and a SessionListEmpty Ladle story added.
|
|
27
|
+
|
|
3
28
|
## 0.29.0
|
|
4
29
|
|
|
5
30
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -91,7 +91,7 @@ Visual reference: [gallery](https://neuronection.github.io/assistant-ui/).
|
|
|
91
91
|
| [`chat-core`](./docs/components/chat-core.md) | `useChatStream` (transport-injected live-turn state machine), `liveTurnReducer`, `ChatMessageView`, family `ChatStreamEvent` vocabulary, branch-tree utils (`buildBranchTree`, `walkActivePath`, `variantInfo`) | [stories](https://neuronection.github.io/assistant-ui/?story=chat-core--chat-core-story) |
|
|
92
92
|
| [`chat-markdown`](./docs/components/chat-markdown.md) | `MarkdownSurface` (read-only streaming markdown: GFM + KaTeX + lazy mermaid + copyable code blocks; no raw HTML) · `MarkdownCodeBlock` · `MermaidDiagram` | [stories](https://neuronection.github.io/assistant-ui/?story=chat-markdown--default) |
|
|
93
93
|
| [`chat-message`](./docs/components/chat-message.md) / [`chat-reasoning`](./docs/components/chat-reasoning.md) / [`chat-tool-card`](./docs/components/chat-tool-card.md) / [`chat-turn-status`](./docs/components/chat-turn-status.md) | `ChatMessage` (bubble: actions row, variant switcher, edit-and-resend, error/interrupted states) · `ChatReasoning` (collapsible thinking block) · `ChatToolCard` (tool observation: status, duration, args/result, app-provided result views via `renderResult`) · `ChatTurnStatus` (live pre-text turn status: dots, phase label, elapsed timer) | [stories](https://neuronection.github.io/assistant-ui/?story=chat-message--assistant) |
|
|
94
|
-
| [`chat-composer`](./docs/components/chat-composer.md) | `ChatComposer` — auto-growing IME-safe input with send/stop states, toolbar/attachment/suggestion slots, drag-drop + paste wiring | [stories](https://neuronection.github.io/assistant-ui/?story=chat-composer--default) |
|
|
94
|
+
| [`chat-composer`](./docs/components/chat-composer.md) | `ChatComposer` — auto-growing IME-safe input with send/stop states, toolbar/attachment/suggestion slots, drag-drop + paste wiring, `data-multiline` row styling hook | [stories](https://neuronection.github.io/assistant-ui/?story=chat-composer--default) |
|
|
95
95
|
| [`chat-transcript`](./docs/components/chat-transcript.md) / [`chat-branch-tree`](./docs/components/chat-branch-tree.md) / [`chat-session-list`](./docs/components/chat-session-list.md) | `ChatTranscript` (log semantics, polite announcements, stick-to-bottom + jump pill, optional virtualization) · `ChatBranchTree` (OpenWebUI-style branch rail, keyboard tree nav) · `ChatSessionList` (fuzzy search, date groups, row actions) | [stories](https://neuronection.github.io/assistant-ui/?story=chat-surfaces--transcript) |
|
|
96
96
|
| [`chat-panel`](./docs/components/chat-panel.md) / [`chat-drawer`](./docs/components/chat-drawer.md) / [`chat-launcher`](./docs/components/chat-launcher.md) | the three chat surfaces from one assembly — `ChatPanel` host (`page` \| `sidebar` \| `bubble`) · `ChatDrawer` (resizable sidepanel on Radix Dialog, keyboard resize) · `ChatLauncher` (floating bubble → anchored panel, badge) | [stories](https://neuronection.github.io/assistant-ui/?story=chat-surfaces--transcript) |
|
|
97
97
|
| [`chat-tools-catalog`](./docs/components/chat-tools-catalog.md) | `ChatToolsCatalog` — searchable disclosure catalog of the tools an assistant can use (name, title, scope, arguments, example, response); fetching stays app-side | [stories](https://neuronection.github.io/assistant-ui/?story=chat-tools-catalog--default) |
|
package/dist/chat-composer.js
CHANGED
package/dist/chat-launcher.d.ts
CHANGED
|
@@ -14,6 +14,14 @@ interface ChatLauncherProps {
|
|
|
14
14
|
closeIcon?: LucideIcon;
|
|
15
15
|
/** Unread / activity badge. */
|
|
16
16
|
badge?: number | string;
|
|
17
|
+
/**
|
|
18
|
+
* Render the floating close button pinned to the panel's top-right
|
|
19
|
+
* corner (default). Turn this off when the panel body renders its own
|
|
20
|
+
* header actions — an overlaid close intercepts clicks meant for
|
|
21
|
+
* top-right header buttons; compose the close into those actions
|
|
22
|
+
* (calling `onOpenChange(false)`) instead.
|
|
23
|
+
*/
|
|
24
|
+
showClose?: boolean;
|
|
17
25
|
container?: HTMLElement | null;
|
|
18
26
|
panelClassName?: string;
|
|
19
27
|
className?: string;
|
package/dist/chat-launcher.js
CHANGED
|
@@ -111,7 +111,7 @@ var ChatSessionList = React.forwardRef(
|
|
|
111
111
|
}
|
|
112
112
|
) : null
|
|
113
113
|
] }),
|
|
114
|
-
|
|
114
|
+
sessions.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-2 py-3 text-xs text-[var(--as-muted-fg)]", children: labels?.empty ?? "No conversations yet" }) : filtered.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-2 py-3 text-xs text-[var(--as-muted-fg)]", children: labels?.noResults ?? "No matches" }) : /* @__PURE__ */ jsx("div", { role: "list", "aria-label": labels?.search ?? "Conversations", className: "min-h-0 flex-1 overflow-y-auto", children: groups.map((group) => /* @__PURE__ */ jsxs("div", { className: "mb-2", children: [
|
|
115
115
|
group.label ? /* @__PURE__ */ jsx("p", { className: "px-2 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-wide text-[var(--as-muted-fg)]", children: group.label }) : null,
|
|
116
116
|
group.sessions.map((session) => {
|
|
117
117
|
const isActive = session.id === activeId;
|
|
@@ -194,5 +194,5 @@ var ChatSessionList = React.forwardRef(
|
|
|
194
194
|
);
|
|
195
195
|
|
|
196
196
|
export { ChatSessionList };
|
|
197
|
-
//# sourceMappingURL=chunk-
|
|
198
|
-
//# sourceMappingURL=chunk-
|
|
197
|
+
//# sourceMappingURL=chunk-66K355IZ.js.map
|
|
198
|
+
//# sourceMappingURL=chunk-66K355IZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/chat-session-list/ChatSessionList.tsx"],"names":["ChatSessionList"],"mappings":";;;;;;;AAmDA,SAAS,OAAO,KAAA,EAA6D;AAC3E,EAAA,IAAI,UAAU,MAAA,EAAW;AACvB,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,IAAI,iBAAiB,IAAA,EAAM;AACzB,IAAA,OAAO,KAAA;AAAA,EACT;AACA,EAAA,IAAI,OAAO,UAAU,QAAA,EAAU;AAC7B,IAAA,OAAO,IAAI,KAAK,KAAK,CAAA;AAAA,EACvB;AACA,EAAA,OAAO,SAAS,KAAK,CAAA;AACvB;AAEA,SAAS,SAAS,IAAA,EAAoE;AACpF,EAAA,IAAI,SAAS,MAAA,EAAW;AACtB,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,IAAI,OAAA,CAAQ,IAAI,CAAA,EAAG;AACjB,IAAA,OAAO,OAAA;AAAA,EACT;AACA,EAAA,IAAI,WAAA,CAAY,IAAI,CAAA,EAAG;AACrB,IAAA,OAAO,WAAA;AAAA,EACT;AACA,EAAA,OAAO,SAAA;AACT;AAQO,IAAM,eAAA,GAAwB,KAAA,CAAA,UAAA;AAAA,EACnC,SAASA,gBAAAA,CACP;AAAA,IACE,QAAA;AAAA,IACA,QAAA;AAAA,IACA,QAAA;AAAA,IACA,KAAA;AAAA,IACA,QAAA;AAAA,IACA,QAAA;AAAA,IACA,QAAA;AAAA,IACA,UAAA,GAAa,IAAA;AAAA,IACb,WAAA,GAAc,IAAA;AAAA,IACd,MAAA;AAAA,IACA,KAAA;AAAA,IACA;AAAA,KAEF,GAAA,EACA;AACA,IAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAU,eAAS,EAAE,CAAA;AAC3C,IAAA,MAAM,OAAA,GAAU,OAAO,OAAA,IAAW,iBAAA;AAClC,IAAA,MAAM,UAAA,GAAa,OAAO,MAAA,IAAU,MAAA;AACpC,IAAA,MAAM,UAAA,GAAa,OAAO,MAAA,IAAU,MAAA;AACpC,IAAA,MAAM,UAAA,GAAa,OAAO,MAAA,IAAU,QAAA;AAEpC,IAAA,MAAM,QAAA,GAAiB,cAAQ,MAAM;AACnC,MAAA,MAAM,OAAA,GAAU,MAAM,IAAA,EAAK;AAC3B,MAAA,IAAI,YAAY,EAAA,EAAI;AAClB,QAAA,OAAO,QAAA;AAAA,MACT;AACA,MAAA,OAAO,QAAA,CACJ,GAAA,CAAI,CAAC,OAAA,MAAa;AAAA,QACjB,OAAA;AAAA,QACA,KAAA,EAAO,WAAA,CAAY,OAAA,EAAS,OAAA,CAAQ,KAAK;AAAA,OAC3C,CAAE,CAAA,CACD,MAAA,CAAO,CAAC,KAAA,KAAU,MAAM,KAAA,KAAU,IAAI,CAAA,CACtC,IAAA,CAAK,CAAC,CAAA,EAAG,OAAO,CAAA,CAAE,KAAA,IAAS,CAAA,KAAM,CAAA,CAAE,KAAA,IAAS,CAAA,CAAE,EAC9C,GAAA,CAAI,CAAC,KAAA,KAAU,KAAA,CAAM,OAAO,CAAA;AAAA,IACjC,CAAA,EAAG,CAAC,QAAA,EAAU,KAAK,CAAC,CAAA;AAEpB,IAAA,MAAM,MAAA,GAAe,cAAQ,MAAM;AACjC,MAAA,IAAI,CAAC,WAAA,EAAa;AAChB,QAAA,OAAO,CAAC,EAAE,GAAA,EAAK,KAAA,EAAO,OAAO,IAAA,EAAuB,QAAA,EAAU,UAAU,CAAA;AAAA,MAC1E;AACA,MAAA,MAAM,OAAA,GAAU,CAAC,GAAG,QAAQ,EAAE,IAAA,CAAK,CAAC,GAAG,CAAA,KAAM;AAC3C,QAAA,MAAM,QAAQ,MAAA,CAAO,CAAA,CAAE,SAAS,CAAA,EAAG,SAAQ,IAAK,CAAA;AAChD,QAAA,MAAM,QAAQ,MAAA,CAAO,CAAA,CAAE,SAAS,CAAA,EAAG,SAAQ,IAAK,CAAA;AAChD,QAAA,OAAO,KAAA,GAAQ,KAAA;AAAA,MACjB,CAAC,CAAA;AACD,MAAA,MAAM,QAAA,uBAAe,GAAA,EAA+B;AACpD,MAAA,KAAA,MAAW,WAAW,OAAA,EAAS;AAC7B,QAAA,MAAM,MAAA,GAAS,QAAA,CAAS,MAAA,CAAO,OAAA,CAAQ,SAAS,CAAC,CAAA;AACjD,QAAA,MAAM,IAAA,GAAO,QAAA,CAAS,GAAA,CAAI,MAAM,KAAK,EAAC;AACtC,QAAA,IAAA,CAAK,KAAK,OAAO,CAAA;AACjB,QAAA,QAAA,CAAS,GAAA,CAAI,QAAQ,IAAI,CAAA;AAAA,MAC3B;AACA,MAAA,MAAM,KAAA,GAAQ,CAAC,OAAA,EAAS,WAAA,EAAa,WAAW,MAAM,CAAA;AACtD,MAAA,OAAO,KAAA,CACJ,MAAA,CAAO,CAAC,MAAA,KAAW,QAAA,CAAS,GAAA,CAAI,MAAM,CAAC,CAAA,CACvC,GAAA,CAAI,CAAC,MAAA,MAAY;AAAA,QAChB,GAAA,EAAK,MAAA;AAAA,QACL,KAAA,EACE,MAAA,KAAW,OAAA,GACN,MAAA,EAAQ,SAAS,OAAA,GAClB,MAAA,KAAW,WAAA,GACR,MAAA,EAAQ,aAAa,WAAA,GACtB,MAAA,KAAW,SAAA,GACR,MAAA,EAAQ,WAAW,SAAA,GACpB,IAAA;AAAA,QACV,QAAA,EAAU,QAAA,CAAS,GAAA,CAAI,MAAM,KAAK;AAAC,OACrC,CAAE,CAAA;AAAA,IACN,CAAA,EAAG,CAAC,QAAA,EAAU,WAAA,EAAa,MAAM,CAAC,CAAA;AAElC,IAAA,uBACE,IAAA,CAAC,SAAI,GAAA,EAAU,SAAA,EAAQ,qBAAoB,SAAA,EAAW,EAAA,CAAG,2CAAA,EAA6C,SAAS,CAAA,EAC7G,QAAA,EAAA;AAAA,sBAAA,IAAA,CAAC,KAAA,EAAA,EAAI,WAAU,yBAAA,EACZ,QAAA,EAAA;AAAA,QAAA,UAAA,mBACC,IAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,yBAAA,EACb,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,MAAA,EAAA,EAAO,SAAA,EAAU,kGAAA,EAAmG,aAAA,EAAW,IAAA,EAAC,CAAA;AAAA,0BACjI,GAAA;AAAA,YAAC,OAAA;AAAA,YAAA;AAAA,cACC,IAAA,EAAK,QAAA;AAAA,cACL,IAAA,EAAK,WAAA;AAAA,cACL,KAAA,EAAO,KAAA;AAAA,cACP,YAAA,EAAY,QAAQ,MAAA,IAAU,sBAAA;AAAA,cAC9B,WAAA,EAAa,QAAQ,iBAAA,IAAqB,cAAA;AAAA,cAC1C,UAAU,CAAC,KAAA,KAAU,QAAA,CAAS,KAAA,CAAM,OAAO,KAAK,CAAA;AAAA,cAChD,SAAA,EAAU;AAAA;AAAA;AACZ,SAAA,EACF,CAAA,GACE,IAAA;AAAA,QACH,KAAA,mBACC,GAAA;AAAA,UAAC,QAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,OAAA,EAAS,KAAA;AAAA,YACT,YAAA,EAAY,QAAQ,OAAA,IAAW,kBAAA;AAAA,YAC/B,KAAA,EAAO,QAAQ,OAAA,IAAW,kBAAA;AAAA,YAC1B,SAAA,EAAU,8SAAA;AAAA,YAEV,QAAA,kBAAA,GAAA,CAAC,OAAA,EAAA,EAAQ,SAAA,EAAU,QAAA,EAAS,eAAW,IAAA,EAAC;AAAA;AAAA,SAC1C,GACE;AAAA,OAAA,EACN,CAAA;AAAA,MACC,SAAS,MAAA,KAAW,CAAA,mBACnB,GAAA,CAAC,GAAA,EAAA,EAAE,WAAU,6CAAA,EAA+C,QAAA,EAAA,MAAA,EAAQ,KAAA,IAAS,sBAAA,EAAuB,IAClG,QAAA,CAAS,MAAA,KAAW,oBACtB,GAAA,CAAC,GAAA,EAAA,EAAE,WAAU,6CAAA,EAA+C,QAAA,EAAA,MAAA,EAAQ,SAAA,IAAa,YAAA,EAAa,oBAE9F,GAAA,CAAC,KAAA,EAAA,EAAI,MAAK,MAAA,EAAO,YAAA,EAAY,QAAQ,MAAA,IAAU,eAAA,EAAiB,SAAA,EAAU,gCAAA,EACvE,iBAAO,GAAA,CAAI,CAAC,0BACX,IAAA,CAAC,KAAA,EAAA,EAAoB,WAAU,MAAA,EAC5B,QAAA,EAAA;AAAA,QAAA,KAAA,CAAM,wBACL,GAAA,CAAC,GAAA,EAAA,EAAE,WAAU,4FAAA,EACV,QAAA,EAAA,KAAA,CAAM,OACT,CAAA,GACE,IAAA;AAAA,QACH,KAAA,CAAM,QAAA,CAAS,GAAA,CAAI,CAAC,OAAA,KAAY;AAC/B,UAAA,MAAM,QAAA,GAAW,QAAQ,EAAA,KAAO,QAAA;AAChC,UAAA,MAAM,IAAA,GAAO,MAAA,CAAO,OAAA,CAAQ,SAAS,CAAA;AACrC,UAAA,MAAM,OAAA,GACJ,QAAA,IAAY,QAAA,IAAY,QAAA,GACpB;AAAA,YACE,QAAA,GACI;AAAA,cACE,GAAA,EAAK,QAAA;AAAA,cACL,KAAA,EAAO,QAAQ,MAAA,IAAU,QAAA;AAAA,cACzB,sBAAM,GAAA,CAAC,UAAA,EAAA,EAAW,SAAA,EAAU,UAAA,EAAW,eAAW,IAAA,EAAC,CAAA;AAAA,cACnD,QAAA,EAAU,MAAM,QAAA,CAAS,OAAA,CAAQ,EAAE;AAAA,aACrC,GACA,IAAA;AAAA,YACJ,QAAA,GACI;AAAA,cACE,GAAA,EAAK,QAAA;AAAA,cACL,KAAA,EAAO,QAAQ,MAAA,IAAU,QAAA;AAAA,cACzB,sBAAM,GAAA,CAAC,UAAA,EAAA,EAAW,SAAA,EAAU,UAAA,EAAW,eAAW,IAAA,EAAC,CAAA;AAAA,cACnD,QAAA,EAAU,MAAM,QAAA,CAAS,OAAA,CAAQ,EAAE;AAAA,aACrC,GACA,IAAA;AAAA,YACJ,QAAA,GACI;AAAA,cACE,GAAA,EAAK,QAAA;AAAA,cACL,KAAA,EAAO,QAAQ,MAAA,IAAU,QAAA;AAAA,cACzB,sBAAM,GAAA,CAAC,UAAA,EAAA,EAAW,SAAA,EAAU,UAAA,EAAW,eAAW,IAAA,EAAC,CAAA;AAAA,cACnD,QAAA,EAAU,MAAM,QAAA,CAAS,OAAA,CAAQ,EAAE,CAAA;AAAA,cACnC,MAAA,EAAQ;AAAA,aACV,GACA;AAAA,YACJ,MAAA,CAAO,CAAC,SAA2C,IAAA,KAAS,IAAI,IAClE,EAAC;AACP,UAAA,uBACE,IAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cAEC,IAAA,EAAK,UAAA;AAAA,cACL,cAAA,EAAc,WAAW,MAAA,GAAS,MAAA;AAAA,cAClC,eAAa,QAAA,IAAY,MAAA;AAAA,cACzB,SAAA,EAAW,EAAA;AAAA,gBACT,2JAAA;AAAA,gBACA,QAAA,IAAY;AAAA,eACd;AAAA,cACA,OAAA,EAAS,MAAM,QAAA,CAAS,OAAA,CAAQ,EAAE,CAAA;AAAA,cAClC,SAAA,EAAW,CAAC,KAAA,KAAU;AACpB,gBAAA,IAAI,KAAA,CAAM,GAAA,KAAQ,OAAA,IAAW,KAAA,CAAM,QAAQ,GAAA,EAAK;AAC9C,kBAAA,KAAA,CAAM,cAAA,EAAe;AACrB,kBAAA,QAAA,CAAS,QAAQ,EAAE,CAAA;AAAA,gBACrB;AAAA,cACF,CAAA;AAAA,cACA,QAAA,EAAU,CAAA;AAAA,cAEV,QAAA,EAAA;AAAA,gCAAA,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,6CAAA,EAA+C,QAAA,EAAA,OAAA,CAAQ,KAAA,EAAM,CAAA;AAAA,gBAC5E,IAAA,mBACC,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,gDAAA,EACb,QAAA,EAAA,mBAAA,CAAoB,IAAA,EAAM,EAAE,SAAA,EAAW,IAAA,EAAM,CAAA,EAChD,CAAA,GACE,IAAA;AAAA,gBACH,OAAA,CAAQ,SAAS,CAAA,mBAChB,GAAA;AAAA,kBAAC,MAAA;AAAA,kBAAA;AAAA,oBACC,IAAA,EAAK,OAAA;AAAA,oBACL,YAAA,EAAY,QAAQ,MAAA,IAAU,sBAAA;AAAA,oBAC9B,SAAA,EAAU,0HAAA;AAAA,oBACV,OAAA,EAAS,CAAC,KAAA,KAAU,KAAA,CAAM,eAAA,EAAgB;AAAA,oBAC1C,SAAA,EAAW,CAAC,KAAA,KAAU,KAAA,CAAM,eAAA,EAAgB;AAAA,oBAE3C,QAAA,EAAA,OAAA,CAAQ,GAAA,CAAI,CAAC,MAAA,qBACZ,GAAA;AAAA,sBAAC,QAAA;AAAA,sBAAA;AAAA,wBAEC,IAAA,EAAK,QAAA;AAAA,wBACL,cAAY,MAAA,CAAO,KAAA;AAAA,wBACnB,OAAO,MAAA,CAAO,KAAA;AAAA,wBACd,SAAS,MAAA,CAAO,QAAA;AAAA,wBAChB,SAAA,EAAW,EAAA;AAAA,0BACT,oQAAA;AAAA,0BACA,OAAO,MAAA,IAAU;AAAA,yBACnB;AAAA,wBAEC,QAAA,EAAA,MAAA,CAAO;AAAA,uBAAA;AAAA,sBAVH,MAAA,CAAO;AAAA,qBAYf;AAAA;AAAA,iBACH,GACE;AAAA;AAAA,aAAA;AAAA,YA/CC,OAAA,CAAQ;AAAA,WAgDd;AAAA,QAEJ,CAAC;AAAA,OAAA,EAAA,EA3FM,KAAA,CAAM,GA4Fd,CACD,CAAA,EAEL;AAAA,KAAA,EAEJ,CAAA;AAAA,EAEJ;AACF","file":"chunk-66K355IZ.js","sourcesContent":["import * as React from 'react'\nimport { Download, MessageSquarePlus, Pencil, Search, Trash2 } from 'lucide-react'\nimport type { LucideIcon } from 'lucide-react'\nimport { formatDistanceToNow, isToday, isYesterday, parseISO } from 'date-fns'\n\nimport { cn } from '../../lib/utils'\nimport { searchScore } from '../../lib/fuzzy'\n\nexport interface ChatSessionView {\n id: string\n title: string\n updatedAt?: string | number | Date\n meta?: Record<string, unknown>\n}\n\nexport interface ChatSessionListLabels {\n search: string\n searchPlaceholder: string\n newChat: string\n rename: string\n delete: string\n export: string\n today: string\n yesterday: string\n earlier: string\n empty: string\n noResults: string\n}\n\nexport interface ChatSessionListIcons {\n newChat: LucideIcon\n rename: LucideIcon\n delete: LucideIcon\n export: LucideIcon\n}\n\nexport interface ChatSessionListProps {\n sessions: ChatSessionView[]\n activeId?: string | null\n onSelect: (id: string) => void\n onNew?: () => void\n onRename?: (id: string) => void\n onDelete?: (id: string) => void\n onExport?: (id: string) => void\n searchable?: boolean\n groupByDate?: boolean\n labels?: Partial<ChatSessionListLabels>\n icons?: Partial<ChatSessionListIcons>\n className?: string\n}\n\nfunction toDate(value: string | number | Date | undefined): Date | undefined {\n if (value === undefined) {\n return undefined\n }\n if (value instanceof Date) {\n return value\n }\n if (typeof value === 'number') {\n return new Date(value)\n }\n return parseISO(value)\n}\n\nfunction bucketOf(date: Date | undefined): 'today' | 'yesterday' | 'earlier' | 'none' {\n if (date === undefined) {\n return 'none'\n }\n if (isToday(date)) {\n return 'today'\n }\n if (isYesterday(date)) {\n return 'yesterday'\n }\n return 'earlier'\n}\n\n/**\n * The session list beside a full-page chat (study's `ChatSessionList` +\n * health's history overlay, generalized): fuzzy search, date grouping,\n * active marking, per-session actions (rename/delete/export) via the\n * menu when handlers are provided. All actions stay app-side.\n */\nexport const ChatSessionList = React.forwardRef<HTMLDivElement, ChatSessionListProps>(\n function ChatSessionList(\n {\n sessions,\n activeId,\n onSelect,\n onNew,\n onRename,\n onDelete,\n onExport,\n searchable = true,\n groupByDate = true,\n labels,\n icons,\n className,\n },\n ref,\n ) {\n const [query, setQuery] = React.useState('')\n const NewIcon = icons?.newChat ?? MessageSquarePlus\n const RenameIcon = icons?.rename ?? Pencil\n const DeleteIcon = icons?.delete ?? Trash2\n const ExportIcon = icons?.export ?? Download\n\n const filtered = React.useMemo(() => {\n const trimmed = query.trim()\n if (trimmed === '') {\n return sessions\n }\n return sessions\n .map((session) => ({\n session,\n score: searchScore(trimmed, session.title),\n }))\n .filter((entry) => entry.score !== null)\n .sort((a, b) => (b.score ?? 0) - (a.score ?? 0))\n .map((entry) => entry.session)\n }, [sessions, query])\n\n const groups = React.useMemo(() => {\n if (!groupByDate) {\n return [{ key: 'all', label: null as string | null, sessions: filtered }]\n }\n const ordered = [...filtered].sort((a, b) => {\n const dateA = toDate(a.updatedAt)?.getTime() ?? 0\n const dateB = toDate(b.updatedAt)?.getTime() ?? 0\n return dateB - dateA\n })\n const byBucket = new Map<string, ChatSessionView[]>()\n for (const session of ordered) {\n const bucket = bucketOf(toDate(session.updatedAt))\n const list = byBucket.get(bucket) ?? []\n list.push(session)\n byBucket.set(bucket, list)\n }\n const order = ['today', 'yesterday', 'earlier', 'none']\n return order\n .filter((bucket) => byBucket.has(bucket))\n .map((bucket) => ({\n key: bucket,\n label:\n bucket === 'today'\n ? (labels?.today ?? 'Today')\n : bucket === 'yesterday'\n ? (labels?.yesterday ?? 'Yesterday')\n : bucket === 'earlier'\n ? (labels?.earlier ?? 'Earlier')\n : null,\n sessions: byBucket.get(bucket) ?? [],\n }))\n }, [filtered, groupByDate, labels])\n\n return (\n <div ref={ref} data-as=\"chat-session-list\" className={cn('flex h-full min-h-0 w-full flex-col gap-2', className)}>\n <div className=\"flex items-center gap-2\">\n {searchable ? (\n <div className=\"relative min-w-0 flex-1\">\n <Search className=\"pointer-events-none absolute start-2 top-1/2 size-3.5 -translate-y-1/2 text-[var(--as-muted-fg)]\" aria-hidden />\n <input\n type=\"search\"\n role=\"searchbox\"\n value={query}\n aria-label={labels?.search ?? 'Search conversations'}\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 {onNew ? (\n <button\n type=\"button\"\n onClick={onNew}\n aria-label={labels?.newChat ?? 'New conversation'}\n title={labels?.newChat ?? 'New conversation'}\n className=\"flex size-7 shrink-0 items-center justify-center rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface)] text-[var(--as-fg)] transition-colors hover:bg-[var(--as-secondary)] focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]\"\n >\n <NewIcon className=\"size-4\" aria-hidden />\n </button>\n ) : null}\n </div>\n {sessions.length === 0 ? (\n <p className=\"px-2 py-3 text-xs text-[var(--as-muted-fg)]\">{labels?.empty ?? 'No conversations yet'}</p>\n ) : filtered.length === 0 ? (\n <p className=\"px-2 py-3 text-xs text-[var(--as-muted-fg)]\">{labels?.noResults ?? 'No matches'}</p>\n ) : (\n <div role=\"list\" aria-label={labels?.search ?? 'Conversations'} className=\"min-h-0 flex-1 overflow-y-auto\">\n {groups.map((group) => (\n <div key={group.key} className=\"mb-2\">\n {group.label ? (\n <p className=\"px-2 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-wide text-[var(--as-muted-fg)]\">\n {group.label}\n </p>\n ) : null}\n {group.sessions.map((session) => {\n const isActive = session.id === activeId\n const date = toDate(session.updatedAt)\n const actions =\n onRename || onDelete || onExport\n ? [\n onRename\n ? {\n key: 'rename',\n label: labels?.rename ?? 'Rename',\n icon: <RenameIcon className=\"size-3.5\" aria-hidden />,\n onSelect: () => onRename(session.id),\n }\n : null,\n onExport\n ? {\n key: 'export',\n label: labels?.export ?? 'Export',\n icon: <ExportIcon className=\"size-3.5\" aria-hidden />,\n onSelect: () => onExport(session.id),\n }\n : null,\n onDelete\n ? {\n key: 'delete',\n label: labels?.delete ?? 'Delete',\n icon: <DeleteIcon className=\"size-3.5\" aria-hidden />,\n onSelect: () => onDelete(session.id),\n danger: true,\n }\n : null,\n ].filter((item): item is NonNullable<typeof item> => item !== null)\n : []\n return (\n <div\n key={session.id}\n role=\"listitem\"\n aria-current={isActive ? 'true' : undefined}\n data-active={isActive || undefined}\n className={cn(\n 'group/session flex cursor-pointer items-center gap-2 rounded-[var(--as-radius)] px-2 py-1.5 text-xs transition-colors hover:bg-[var(--as-surface-raised)]',\n isActive && 'bg-[var(--as-surface-raised)] font-medium text-[var(--as-fg)]',\n )}\n onClick={() => onSelect(session.id)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n onSelect(session.id)\n }\n }}\n tabIndex={0}\n >\n <span className=\"min-w-0 flex-1 truncate text-[var(--as-fg)]\">{session.title}</span>\n {date ? (\n <span className=\"shrink-0 text-[10px] text-[var(--as-muted-fg)]\">\n {formatDistanceToNow(date, { addSuffix: true })}\n </span>\n ) : null}\n {actions.length > 0 ? (\n <span\n role=\"group\"\n aria-label={labels?.rename ?? 'Conversation actions'}\n className=\"flex shrink-0 items-center gap-0.5 opacity-0 transition-opacity focus-within:opacity-100 group-hover/session:opacity-100\"\n onClick={(event) => event.stopPropagation()}\n onKeyDown={(event) => event.stopPropagation()}\n >\n {actions.map((action) => (\n <button\n key={action.key}\n type=\"button\"\n aria-label={action.label}\n title={action.label}\n onClick={action.onSelect}\n className={cn(\n 'rounded-[var(--as-radius-sm)] p-1 text-[var(--as-muted-fg)] transition-colors hover:bg-[var(--as-surface)] hover:text-[var(--as-fg)] focus-visible:opacity-100 focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]',\n action.danger && 'hover:text-[var(--as-danger)]',\n )}\n >\n {action.icon}\n </button>\n ))}\n </span>\n ) : null}\n </div>\n )\n })}\n </div>\n ))\n }\n </div>\n )}\n </div>\n )\n },\n)\n"]}
|
|
@@ -29,6 +29,7 @@ var ChatComposer = React.forwardRef(
|
|
|
29
29
|
}, ref) {
|
|
30
30
|
const internalTextareaRef = React.useRef(null);
|
|
31
31
|
const [dragging, setDragging] = React.useState(false);
|
|
32
|
+
const [multiline, setMultiline] = React.useState(false);
|
|
32
33
|
const dragDepth = React.useRef(0);
|
|
33
34
|
const setTextarea = (element) => {
|
|
34
35
|
internalTextareaRef.current = element;
|
|
@@ -47,6 +48,10 @@ var ChatComposer = React.forwardRef(
|
|
|
47
48
|
const cap = maxRows * 22;
|
|
48
49
|
element.style.height = element.scrollHeight > 0 ? `${Math.min(element.scrollHeight, cap)}px` : "auto";
|
|
49
50
|
element.style.overflowY = element.scrollHeight > cap ? "auto" : "hidden";
|
|
51
|
+
const style = window.getComputedStyle(element);
|
|
52
|
+
const lineHeight = Number.parseFloat(style.lineHeight) || 22;
|
|
53
|
+
const verticalPadding = (Number.parseFloat(style.paddingTop) || 0) + (Number.parseFloat(style.paddingBottom) || 0);
|
|
54
|
+
setMultiline(element.scrollHeight > lineHeight + verticalPadding + 1);
|
|
50
55
|
}, [value, maxRows]);
|
|
51
56
|
const submit = () => {
|
|
52
57
|
if (disabled || sending) {
|
|
@@ -124,6 +129,8 @@ var ChatComposer = React.forwardRef(
|
|
|
124
129
|
/* @__PURE__ */ jsxs(
|
|
125
130
|
"div",
|
|
126
131
|
{
|
|
132
|
+
"data-as": "chat-composer-row",
|
|
133
|
+
"data-multiline": multiline || void 0,
|
|
127
134
|
"data-dragging": dragging || void 0,
|
|
128
135
|
className: cn(
|
|
129
136
|
"flex items-end gap-1.5 rounded-[var(--as-radius-lg)] border border-[var(--as-border)] bg-[var(--as-surface)] px-2 py-1.5 transition-colors focus-within:border-[var(--as-primary)]",
|
|
@@ -180,5 +187,5 @@ var ChatComposer = React.forwardRef(
|
|
|
180
187
|
);
|
|
181
188
|
|
|
182
189
|
export { ChatComposer };
|
|
183
|
-
//# sourceMappingURL=chunk-
|
|
184
|
-
//# sourceMappingURL=chunk-
|
|
190
|
+
//# sourceMappingURL=chunk-IN6ORI3V.js.map
|
|
191
|
+
//# sourceMappingURL=chunk-IN6ORI3V.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/chat-composer/ChatComposer.tsx"],"names":["ChatComposer"],"mappings":"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","file":"chunk-IN6ORI3V.js","sourcesContent":["import * as React from 'react'\nimport { ArrowUp, Square } from 'lucide-react'\nimport type { LucideIcon } from 'lucide-react'\n\nimport { cn } from '../../lib/utils'\n\nexport interface ChatComposerLabels {\n send: string\n stop: string\n placeholder: string\n ariaLabel: string\n dropFiles: string\n}\n\nexport interface ChatComposerIcons {\n send: LucideIcon\n stop: LucideIcon\n}\n\nexport interface ChatComposerProps {\n value: string\n onValueChange: (value: string) => void\n /** Enter / Send — IME-safe (composition and keyCode 229 are ignored). */\n onSubmit: () => void\n /** A turn is in flight — renders the stop control when `onStop` is provided. */\n sending?: boolean\n onStop?: () => void\n disabled?: boolean\n placeholder?: string\n ariaLabel?: string\n /** Auto-grow cap before the textarea scrolls. Default 8. */\n maxRows?: number\n /** Leading slot inside the input row (attach menu, equation, draw…). */\n toolbarStart?: React.ReactNode\n /** Trailing slot inside the input row (dictation, tools…). */\n toolbarEnd?: React.ReactNode\n /** Attachment rail above the input (usually `FileQueue` / chips). */\n attachments?: React.ReactNode\n /** Suggestion chips / context strip above everything. */\n suggestions?: React.ReactNode\n /** Drag-drop + paste wiring for file attachments. */\n onAttachFiles?: (files: File[]) => void\n labels?: Partial<ChatComposerLabels>\n icons?: Partial<ChatComposerIcons>\n textareaRef?: React.Ref<HTMLTextAreaElement>\n className?: string\n}\n\nfunction isIMEComposition(event: React.KeyboardEvent<HTMLTextAreaElement>): boolean {\n return event.nativeEvent.isComposing || event.keyCode === 229\n}\n\n/**\n * The family chat input: auto-growing IME-safe textarea, send/stop\n * states, attachment/dictation/toolbar slots, drag-drop + paste file\n * wiring. Presentational + controlled; transports stay app-side.\n */\nexport const ChatComposer = React.forwardRef<HTMLFormElement, ChatComposerProps>(\n function ChatComposer(\n {\n value,\n onValueChange,\n onSubmit,\n sending = false,\n onStop,\n disabled = false,\n placeholder,\n ariaLabel,\n maxRows = 8,\n toolbarStart,\n toolbarEnd,\n attachments,\n suggestions,\n onAttachFiles,\n labels,\n icons,\n textareaRef,\n className,\n },\n ref,\n ) {\n const internalTextareaRef = React.useRef<HTMLTextAreaElement | null>(null)\n const [dragging, setDragging] = React.useState(false)\n const [multiline, setMultiline] = React.useState(false)\n const dragDepth = React.useRef(0)\n\n const setTextarea = (element: HTMLTextAreaElement | null) => {\n internalTextareaRef.current = element\n if (typeof textareaRef === 'function') {\n textareaRef(element)\n } else if (textareaRef && typeof textareaRef === 'object') {\n ;(textareaRef as React.MutableRefObject<HTMLTextAreaElement | null>).current = element\n }\n }\n\n React.useLayoutEffect(() => {\n const element = internalTextareaRef.current\n if (element === null) {\n return\n }\n element.style.height = 'auto'\n const cap = maxRows * 22\n element.style.height = element.scrollHeight > 0 ? `${Math.min(element.scrollHeight, cap)}px` : 'auto'\n element.style.overflowY = element.scrollHeight > cap ? 'auto' : 'hidden'\n const style = window.getComputedStyle(element)\n const lineHeight = Number.parseFloat(style.lineHeight) || 22\n const verticalPadding =\n (Number.parseFloat(style.paddingTop) || 0) + (Number.parseFloat(style.paddingBottom) || 0)\n setMultiline(element.scrollHeight > lineHeight + verticalPadding + 1)\n }, [value, maxRows])\n\n const submit = () => {\n if (disabled || sending) {\n return\n }\n onSubmit()\n }\n\n const onKeyDown: React.KeyboardEventHandler<HTMLTextAreaElement> = (event) => {\n if (event.key !== 'Enter' || event.shiftKey) {\n return\n }\n if (isIMEComposition(event)) {\n return\n }\n event.preventDefault()\n submit()\n }\n\n const emitFiles = (fileList: FileList | null | undefined) => {\n const files = fileList ? Array.from(fileList) : []\n if (files.length > 0) {\n onAttachFiles?.(files)\n }\n }\n\n const dragCounterHandlers = {\n onDragEnter: (event: React.DragEvent) => {\n if (onAttachFiles === undefined || !event.dataTransfer.types.includes('Files')) {\n return\n }\n event.preventDefault()\n dragDepth.current += 1\n setDragging(true)\n },\n onDragOver: (event: React.DragEvent) => {\n if (onAttachFiles === undefined || !event.dataTransfer.types.includes('Files')) {\n return\n }\n event.preventDefault()\n },\n onDragLeave: () => {\n if (dragDepth.current > 0) {\n dragDepth.current -= 1\n if (dragDepth.current === 0) {\n setDragging(false)\n }\n }\n },\n onDrop: (event: React.DragEvent) => {\n if (onAttachFiles === undefined) {\n return\n }\n event.preventDefault()\n dragDepth.current = 0\n setDragging(false)\n emitFiles(event.dataTransfer.files)\n },\n }\n\n const SendIcon = icons?.send ?? ArrowUp\n const StopIcon = icons?.stop ?? Square\n const showStop = sending && onStop !== undefined\n\n return (\n <form\n ref={ref}\n data-as=\"chat-composer\"\n data-sending={sending}\n onSubmit={(event) => {\n event.preventDefault()\n submit()\n }}\n className={cn('flex w-full flex-col gap-2', className)}\n {...dragCounterHandlers}\n >\n {suggestions ? <div className=\"flex flex-wrap gap-1.5\">{suggestions}</div> : null}\n {attachments ? <div className=\"flex flex-wrap gap-1.5\">{attachments}</div> : null}\n <div\n data-as=\"chat-composer-row\"\n data-multiline={multiline || undefined}\n data-dragging={dragging || undefined}\n className={cn(\n 'flex items-end gap-1.5 rounded-[var(--as-radius-lg)] border border-[var(--as-border)] bg-[var(--as-surface)] px-2 py-1.5 transition-colors focus-within:border-[var(--as-primary)]',\n dragging && 'border-dashed border-[var(--as-primary)] bg-[var(--as-primary)]/5',\n disabled && 'opacity-50',\n )}\n >\n {toolbarStart ? <div className=\"flex shrink-0 items-center gap-0.5 pb-0.5\">{toolbarStart}</div> : null}\n <textarea\n ref={setTextarea}\n value={value}\n rows={1}\n disabled={disabled}\n placeholder={placeholder ?? labels?.placeholder ?? 'Send a message…'}\n aria-label={ariaLabel ?? labels?.ariaLabel ?? 'Message'}\n onChange={(event) => onValueChange(event.target.value)}\n onKeyDown={onKeyDown}\n onPaste={(event) => emitFiles(event.clipboardData.files)}\n className=\"max-h-40 min-h-[1.5rem] w-full flex-1 resize-none bg-transparent px-1 py-1 text-sm leading-relaxed text-[var(--as-fg)] placeholder:text-[var(--as-muted-fg)] focus-visible:outline-none disabled:cursor-not-allowed\"\n />\n {toolbarEnd ? <div className=\"flex shrink-0 items-center gap-0.5 pb-0.5\">{toolbarEnd}</div> : null}\n {showStop ? (\n <button\n type=\"button\"\n aria-label={labels?.stop ?? 'Stop generating'}\n title={labels?.stop ?? 'Stop generating'}\n onClick={onStop}\n className=\"mb-0.5 flex size-7 shrink-0 items-center justify-center rounded-full border border-[var(--as-border)] bg-[var(--as-surface-raised)] text-[var(--as-fg)] transition-colors hover:bg-[var(--as-secondary)] focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]\"\n >\n <StopIcon className=\"size-3.5\" aria-hidden />\n </button>\n ) : (\n <button\n type=\"submit\"\n aria-label={labels?.send ?? 'Send message'}\n title={labels?.send ?? 'Send message'}\n disabled={disabled || value.trim() === '' || sending}\n className=\"mb-0.5 flex size-7 shrink-0 items-center justify-center rounded-full bg-[var(--as-primary)] text-[var(--as-primary-fg)] transition-opacity hover:opacity-90 disabled:pointer-events-none disabled:opacity-30 focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]\"\n >\n <SendIcon className=\"size-4\" aria-hidden />\n </button>\n )}\n </div>\n {dragging && onAttachFiles ? (\n <p className=\"text-xs text-[var(--as-muted-fg)]\" role=\"status\">\n {labels?.dropFiles ?? 'Drop files to attach'}\n </p>\n ) : null}\n </form>\n )\n },\n)\n"]}
|
|
@@ -16,6 +16,7 @@ var ChatLauncher = React.forwardRef(
|
|
|
16
16
|
icon: Icon = MessageCircle,
|
|
17
17
|
closeIcon: CloseIcon = X,
|
|
18
18
|
badge,
|
|
19
|
+
showClose = true,
|
|
19
20
|
container,
|
|
20
21
|
panelClassName,
|
|
21
22
|
className
|
|
@@ -58,7 +59,7 @@ var ChatLauncher = React.forwardRef(
|
|
|
58
59
|
"aria-label": label,
|
|
59
60
|
children: [
|
|
60
61
|
panel,
|
|
61
|
-
/* @__PURE__ */ jsx(
|
|
62
|
+
showClose ? /* @__PURE__ */ jsx(
|
|
62
63
|
"button",
|
|
63
64
|
{
|
|
64
65
|
type: "button",
|
|
@@ -67,7 +68,7 @@ var ChatLauncher = React.forwardRef(
|
|
|
67
68
|
className: "absolute right-2 top-2 z-10 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)]",
|
|
68
69
|
children: /* @__PURE__ */ jsx(CloseIcon, { "aria-hidden": true, className: "size-4" })
|
|
69
70
|
}
|
|
70
|
-
)
|
|
71
|
+
) : null
|
|
71
72
|
]
|
|
72
73
|
}
|
|
73
74
|
) }) : null,
|
|
@@ -98,5 +99,5 @@ var ChatLauncher = React.forwardRef(
|
|
|
98
99
|
);
|
|
99
100
|
|
|
100
101
|
export { ChatLauncher };
|
|
101
|
-
//# sourceMappingURL=chunk-
|
|
102
|
-
//# sourceMappingURL=chunk-
|
|
102
|
+
//# sourceMappingURL=chunk-OUJJLZ6C.js.map
|
|
103
|
+
//# sourceMappingURL=chunk-OUJJLZ6C.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/chat-launcher/ChatLauncher.tsx"],"names":["ChatLauncher"],"mappings":"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","file":"chunk-OUJJLZ6C.js","sourcesContent":["import * as React from 'react'\nimport { MessageCircle, X } from 'lucide-react'\nimport type { LucideIcon } from 'lucide-react'\n\nimport { cn } from '../../lib/utils'\nimport { Portal } from '../portal/Portal'\n\nexport interface ChatLauncherProps {\n /** The anchored panel body — usually `ChatPanel variant=\"bubble\"`. */\n panel: React.ReactNode\n open?: boolean\n defaultOpen?: boolean\n onOpenChange?: (open: boolean) => void\n position?: 'bottom-right' | 'bottom-left'\n label?: string\n closeLabel?: string\n icon?: LucideIcon\n closeIcon?: LucideIcon\n /** Unread / activity badge. */\n badge?: number | string\n /**\n * Render the floating close button pinned to the panel's top-right\n * corner (default). Turn this off when the panel body renders its own\n * header actions — an overlaid close intercepts clicks meant for\n * top-right header buttons; compose the close into those actions\n * (calling `onOpenChange(false)`) instead.\n */\n showClose?: boolean\n container?: HTMLElement | null\n panelClassName?: string\n className?: string\n}\n\n/**\n * The floating chat bubble (career's `ChatWidget` launcher,\n * family-standard): fixed launcher button opening an anchored, non-modal\n * panel. `aria-expanded` wiring, Escape closes while focus is inside.\n */\nexport const ChatLauncher = React.forwardRef<HTMLButtonElement, ChatLauncherProps>(\n function ChatLauncher(\n {\n panel,\n open: openProp,\n defaultOpen = false,\n onOpenChange,\n position = 'bottom-right',\n label = 'Chat',\n closeLabel = 'Close chat',\n icon: Icon = MessageCircle,\n closeIcon: CloseIcon = X,\n badge,\n showClose = true,\n container,\n panelClassName,\n className,\n },\n ref,\n ) {\n const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen)\n const isControlled = openProp !== undefined\n const open = isControlled ? openProp : uncontrolledOpen\n const panelRef = React.useRef<HTMLDivElement | null>(null)\n\n const setOpen = (next: boolean) => {\n if (!isControlled) {\n setUncontrolledOpen(next)\n }\n onOpenChange?.(next)\n }\n\n React.useEffect(() => {\n if (!open) {\n return\n }\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape' && panelRef.current?.contains(document.activeElement)) {\n setOpen(false)\n }\n }\n document.addEventListener('keydown', onKeyDown)\n return () => document.removeEventListener('keydown', onKeyDown)\n })\n\n const showBadge = badge !== undefined && badge !== 0 && badge !== ''\n\n return (\n <>\n {open ? (\n <Portal container={container}>\n <div\n ref={panelRef}\n data-as=\"chat-launcher-panel\"\n className={cn(\n 'as-anim-pop fixed bottom-20 z-[var(--as-z-modal)] flex h-[min(36rem,calc(100dvh-11rem))] w-[min(26rem,calc(100vw-2rem))] flex-col overflow-hidden rounded-[var(--as-radius-lg)] border border-[var(--as-border)] bg-[var(--as-surface)] text-[var(--as-fg)] shadow-[var(--as-shadow-3)]',\n position === 'bottom-right' ? 'right-4' : 'left-4',\n panelClassName,\n )}\n role=\"complementary\"\n aria-label={label}\n >\n {panel}\n {showClose ? (\n <button\n type=\"button\"\n aria-label={closeLabel}\n onClick={() => setOpen(false)}\n className=\"absolute right-2 top-2 z-10 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 <CloseIcon aria-hidden className=\"size-4\" />\n </button>\n ) : null}\n </div>\n </Portal>\n ) : null}\n <button\n ref={ref}\n type=\"button\"\n aria-expanded={open}\n aria-label={open ? closeLabel : label}\n title={open ? closeLabel : label}\n onClick={() => setOpen(!open)}\n data-as=\"chat-launcher\"\n data-open={open || undefined}\n className={cn(\n 'fixed bottom-4 z-[var(--as-z-popover)] flex size-12 items-center justify-center rounded-full bg-[var(--as-primary)] text-[var(--as-primary-fg)] shadow-[var(--as-shadow-2)] transition-transform hover:scale-105 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--as-focus-ring)]',\n position === 'bottom-right' ? 'right-4' : 'left-4',\n className,\n )}\n >\n <Icon className=\"size-5\" aria-hidden />\n {showBadge ? (\n <span className=\"absolute -right-0.5 -top-0.5 flex h-5 min-w-5 items-center justify-center rounded-full border-2 border-[var(--as-surface)] bg-[var(--as-danger)] px-1 text-[10px] font-semibold text-[var(--as-danger-fg)]\">\n {badge}\n </span>\n ) : null}\n </button>\n </>\n )\n },\n)\n"]}
|
|
@@ -58,7 +58,7 @@ var ChatToolsCatalog = React.forwardRef(
|
|
|
58
58
|
}
|
|
59
59
|
)
|
|
60
60
|
] }) : null,
|
|
61
|
-
|
|
61
|
+
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" }) : /* @__PURE__ */ jsx("div", { role: "list", "aria-label": labels?.tools ?? "Tools", className: "flex flex-col gap-2", children: filtered.map((tool) => {
|
|
62
62
|
const open = openOverrides[tool.name] ?? defaultOpen;
|
|
63
63
|
const regionId = `${uid}-${tool.name}`;
|
|
64
64
|
const toggle = () => setOpenOverrides((current) => ({ ...current, [tool.name]: !open }));
|
|
@@ -152,5 +152,5 @@ var ChatToolsCatalog = React.forwardRef(
|
|
|
152
152
|
);
|
|
153
153
|
|
|
154
154
|
export { ChatToolsCatalog };
|
|
155
|
-
//# sourceMappingURL=chunk-
|
|
156
|
-
//# sourceMappingURL=chunk-
|
|
155
|
+
//# sourceMappingURL=chunk-TC4NQL3H.js.map
|
|
156
|
+
//# sourceMappingURL=chunk-TC4NQL3H.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/chat-tools-catalog/ChatToolsCatalog.tsx"],"names":["ChatToolsCatalog"],"mappings":"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","file":"chunk-N55WQMBA.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 break-words\">\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\n title={tool.scope}\n className=\"max-w-[40%] shrink-0 truncate rounded-full bg-[var(--as-surface-raised)] px-1.5 py-0.5 text-[10px] uppercase tracking-wide text-[var(--as-muted-fg)]\"\n >\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"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/chat-tools-catalog/ChatToolsCatalog.tsx"],"names":["ChatToolsCatalog"],"mappings":"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","file":"chunk-TC4NQL3H.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 {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 <div role=\"list\" aria-label={labels?.tools ?? 'Tools'} className=\"flex flex-col gap-2\">\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 break-words\">\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\n title={tool.scope}\n className=\"max-w-[40%] shrink-0 truncate rounded-full bg-[var(--as-surface-raised)] px-1.5 py-0.5 text-[10px] uppercase tracking-wide text-[var(--as-muted-fg)]\"\n >\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 </div>\n )}\n </div>\n )\n },\n)\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -2539,6 +2539,14 @@ interface ChatLauncherProps {
|
|
|
2539
2539
|
closeIcon?: LucideIcon;
|
|
2540
2540
|
/** Unread / activity badge. */
|
|
2541
2541
|
badge?: number | string;
|
|
2542
|
+
/**
|
|
2543
|
+
* Render the floating close button pinned to the panel's top-right
|
|
2544
|
+
* corner (default). Turn this off when the panel body renders its own
|
|
2545
|
+
* header actions — an overlaid close intercepts clicks meant for
|
|
2546
|
+
* top-right header buttons; compose the close into those actions
|
|
2547
|
+
* (calling `onOpenChange(false)`) instead.
|
|
2548
|
+
*/
|
|
2549
|
+
showClose?: boolean;
|
|
2542
2550
|
container?: HTMLElement | null;
|
|
2543
2551
|
panelClassName?: string;
|
|
2544
2552
|
className?: string;
|
package/dist/index.js
CHANGED
|
@@ -43,22 +43,22 @@ export { ChatHistoryButton } from './chunk-YYPO24TA.js';
|
|
|
43
43
|
export { PopoverButton } from './chunk-BE3XFZWU.js';
|
|
44
44
|
export { ChatTraceMeta } from './chunk-QMQ73C23.js';
|
|
45
45
|
export { ChatTraceTimeline } from './chunk-HC6DBXYJ.js';
|
|
46
|
-
export { ChatToolsCatalog } from './chunk-
|
|
46
|
+
export { ChatToolsCatalog } from './chunk-TC4NQL3H.js';
|
|
47
47
|
export { ConnectionTestRow } from './chunk-OGQF4XJB.js';
|
|
48
48
|
export { CheckIndicator } from './chunk-XE4TFW63.js';
|
|
49
49
|
export { ChipInput } from './chunk-HIRR2F4R.js';
|
|
50
50
|
export { ChatBranchTree } from './chunk-HQIYSW2D.js';
|
|
51
51
|
export { ChatDrawer } from './chunk-WBSGFOSD.js';
|
|
52
52
|
export { ChatReasoning } from './chunk-QVDCFZSE.js';
|
|
53
|
-
export { ChatSessionList } from './chunk-
|
|
53
|
+
export { ChatSessionList } from './chunk-66K355IZ.js';
|
|
54
54
|
export { ChatToolCard } from './chunk-NBT7NLNU.js';
|
|
55
55
|
export { ChatTurnStatus } from './chunk-P75QKU5J.js';
|
|
56
56
|
export { buildChatMarkdown, chatExportFileName, downloadChatMarkdown } from './chunk-DRJGZ5TB.js';
|
|
57
57
|
export { initialLiveTurnState, liveTurnReducer, useChatStream } from './chunk-6GNLY2EB.js';
|
|
58
58
|
export { activePathSet, buildBranchTree, linearTree, variantInfo, walkActivePath } from './chunk-Z4IBQ53C.js';
|
|
59
|
-
export { ChatLauncher } from './chunk-
|
|
59
|
+
export { ChatLauncher } from './chunk-OUJJLZ6C.js';
|
|
60
60
|
export { Portal } from './chunk-XZWLTTHA.js';
|
|
61
|
-
export { ChatComposer } from './chunk-
|
|
61
|
+
export { ChatComposer } from './chunk-IN6ORI3V.js';
|
|
62
62
|
export { ChatPanel } from './chunk-MVT4F6TA.js';
|
|
63
63
|
export { ChatTranscript } from './chunk-FS7M7PNS.js';
|
|
64
64
|
export { ChatMessage, ChatMessageEditor, MessageVariantSwitcher } from './chunk-FGYGWZ6S.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neuronection/assistant-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.0",
|
|
4
4
|
"description": "Shared React component library for the Assistant family (career-, study-, health-assistant). Family look by default, app-flavored via CSS-variable tokens.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/chat-composer/ChatComposer.tsx"],"names":["ChatComposer"],"mappings":"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","file":"chunk-743FJDRA.js","sourcesContent":["import * as React from 'react'\nimport { ArrowUp, Square } from 'lucide-react'\nimport type { LucideIcon } from 'lucide-react'\n\nimport { cn } from '../../lib/utils'\n\nexport interface ChatComposerLabels {\n send: string\n stop: string\n placeholder: string\n ariaLabel: string\n dropFiles: string\n}\n\nexport interface ChatComposerIcons {\n send: LucideIcon\n stop: LucideIcon\n}\n\nexport interface ChatComposerProps {\n value: string\n onValueChange: (value: string) => void\n /** Enter / Send — IME-safe (composition and keyCode 229 are ignored). */\n onSubmit: () => void\n /** A turn is in flight — renders the stop control when `onStop` is provided. */\n sending?: boolean\n onStop?: () => void\n disabled?: boolean\n placeholder?: string\n ariaLabel?: string\n /** Auto-grow cap before the textarea scrolls. Default 8. */\n maxRows?: number\n /** Leading slot inside the input row (attach menu, equation, draw…). */\n toolbarStart?: React.ReactNode\n /** Trailing slot inside the input row (dictation, tools…). */\n toolbarEnd?: React.ReactNode\n /** Attachment rail above the input (usually `FileQueue` / chips). */\n attachments?: React.ReactNode\n /** Suggestion chips / context strip above everything. */\n suggestions?: React.ReactNode\n /** Drag-drop + paste wiring for file attachments. */\n onAttachFiles?: (files: File[]) => void\n labels?: Partial<ChatComposerLabels>\n icons?: Partial<ChatComposerIcons>\n textareaRef?: React.Ref<HTMLTextAreaElement>\n className?: string\n}\n\nfunction isIMEComposition(event: React.KeyboardEvent<HTMLTextAreaElement>): boolean {\n return event.nativeEvent.isComposing || event.keyCode === 229\n}\n\n/**\n * The family chat input: auto-growing IME-safe textarea, send/stop\n * states, attachment/dictation/toolbar slots, drag-drop + paste file\n * wiring. Presentational + controlled; transports stay app-side.\n */\nexport const ChatComposer = React.forwardRef<HTMLFormElement, ChatComposerProps>(\n function ChatComposer(\n {\n value,\n onValueChange,\n onSubmit,\n sending = false,\n onStop,\n disabled = false,\n placeholder,\n ariaLabel,\n maxRows = 8,\n toolbarStart,\n toolbarEnd,\n attachments,\n suggestions,\n onAttachFiles,\n labels,\n icons,\n textareaRef,\n className,\n },\n ref,\n ) {\n const internalTextareaRef = React.useRef<HTMLTextAreaElement | null>(null)\n const [dragging, setDragging] = React.useState(false)\n const dragDepth = React.useRef(0)\n\n const setTextarea = (element: HTMLTextAreaElement | null) => {\n internalTextareaRef.current = element\n if (typeof textareaRef === 'function') {\n textareaRef(element)\n } else if (textareaRef && typeof textareaRef === 'object') {\n ;(textareaRef as React.MutableRefObject<HTMLTextAreaElement | null>).current = element\n }\n }\n\n React.useLayoutEffect(() => {\n const element = internalTextareaRef.current\n if (element === null) {\n return\n }\n element.style.height = 'auto'\n const cap = maxRows * 22\n element.style.height = element.scrollHeight > 0 ? `${Math.min(element.scrollHeight, cap)}px` : 'auto'\n element.style.overflowY = element.scrollHeight > cap ? 'auto' : 'hidden'\n }, [value, maxRows])\n\n const submit = () => {\n if (disabled || sending) {\n return\n }\n onSubmit()\n }\n\n const onKeyDown: React.KeyboardEventHandler<HTMLTextAreaElement> = (event) => {\n if (event.key !== 'Enter' || event.shiftKey) {\n return\n }\n if (isIMEComposition(event)) {\n return\n }\n event.preventDefault()\n submit()\n }\n\n const emitFiles = (fileList: FileList | null | undefined) => {\n const files = fileList ? Array.from(fileList) : []\n if (files.length > 0) {\n onAttachFiles?.(files)\n }\n }\n\n const dragCounterHandlers = {\n onDragEnter: (event: React.DragEvent) => {\n if (onAttachFiles === undefined || !event.dataTransfer.types.includes('Files')) {\n return\n }\n event.preventDefault()\n dragDepth.current += 1\n setDragging(true)\n },\n onDragOver: (event: React.DragEvent) => {\n if (onAttachFiles === undefined || !event.dataTransfer.types.includes('Files')) {\n return\n }\n event.preventDefault()\n },\n onDragLeave: () => {\n if (dragDepth.current > 0) {\n dragDepth.current -= 1\n if (dragDepth.current === 0) {\n setDragging(false)\n }\n }\n },\n onDrop: (event: React.DragEvent) => {\n if (onAttachFiles === undefined) {\n return\n }\n event.preventDefault()\n dragDepth.current = 0\n setDragging(false)\n emitFiles(event.dataTransfer.files)\n },\n }\n\n const SendIcon = icons?.send ?? ArrowUp\n const StopIcon = icons?.stop ?? Square\n const showStop = sending && onStop !== undefined\n\n return (\n <form\n ref={ref}\n data-as=\"chat-composer\"\n data-sending={sending}\n onSubmit={(event) => {\n event.preventDefault()\n submit()\n }}\n className={cn('flex w-full flex-col gap-2', className)}\n {...dragCounterHandlers}\n >\n {suggestions ? <div className=\"flex flex-wrap gap-1.5\">{suggestions}</div> : null}\n {attachments ? <div className=\"flex flex-wrap gap-1.5\">{attachments}</div> : null}\n <div\n data-dragging={dragging || undefined}\n className={cn(\n 'flex items-end gap-1.5 rounded-[var(--as-radius-lg)] border border-[var(--as-border)] bg-[var(--as-surface)] px-2 py-1.5 transition-colors focus-within:border-[var(--as-primary)]',\n dragging && 'border-dashed border-[var(--as-primary)] bg-[var(--as-primary)]/5',\n disabled && 'opacity-50',\n )}\n >\n {toolbarStart ? <div className=\"flex shrink-0 items-center gap-0.5 pb-0.5\">{toolbarStart}</div> : null}\n <textarea\n ref={setTextarea}\n value={value}\n rows={1}\n disabled={disabled}\n placeholder={placeholder ?? labels?.placeholder ?? 'Send a message…'}\n aria-label={ariaLabel ?? labels?.ariaLabel ?? 'Message'}\n onChange={(event) => onValueChange(event.target.value)}\n onKeyDown={onKeyDown}\n onPaste={(event) => emitFiles(event.clipboardData.files)}\n className=\"max-h-40 min-h-[1.5rem] w-full flex-1 resize-none bg-transparent px-1 py-1 text-sm leading-relaxed text-[var(--as-fg)] placeholder:text-[var(--as-muted-fg)] focus-visible:outline-none disabled:cursor-not-allowed\"\n />\n {toolbarEnd ? <div className=\"flex shrink-0 items-center gap-0.5 pb-0.5\">{toolbarEnd}</div> : null}\n {showStop ? (\n <button\n type=\"button\"\n aria-label={labels?.stop ?? 'Stop generating'}\n title={labels?.stop ?? 'Stop generating'}\n onClick={onStop}\n className=\"mb-0.5 flex size-7 shrink-0 items-center justify-center rounded-full border border-[var(--as-border)] bg-[var(--as-surface-raised)] text-[var(--as-fg)] transition-colors hover:bg-[var(--as-secondary)] focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]\"\n >\n <StopIcon className=\"size-3.5\" aria-hidden />\n </button>\n ) : (\n <button\n type=\"submit\"\n aria-label={labels?.send ?? 'Send message'}\n title={labels?.send ?? 'Send message'}\n disabled={disabled || value.trim() === '' || sending}\n className=\"mb-0.5 flex size-7 shrink-0 items-center justify-center rounded-full bg-[var(--as-primary)] text-[var(--as-primary-fg)] transition-opacity hover:opacity-90 disabled:pointer-events-none disabled:opacity-30 focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]\"\n >\n <SendIcon className=\"size-4\" aria-hidden />\n </button>\n )}\n </div>\n {dragging && onAttachFiles ? (\n <p className=\"text-xs text-[var(--as-muted-fg)]\" role=\"status\">\n {labels?.dropFiles ?? 'Drop files to attach'}\n </p>\n ) : null}\n </form>\n )\n },\n)\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/chat-session-list/ChatSessionList.tsx"],"names":["ChatSessionList"],"mappings":"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","file":"chunk-NKYPNEOX.js","sourcesContent":["import * as React from 'react'\nimport { Download, MessageSquarePlus, Pencil, Search, Trash2 } from 'lucide-react'\nimport type { LucideIcon } from 'lucide-react'\nimport { formatDistanceToNow, isToday, isYesterday, parseISO } from 'date-fns'\n\nimport { cn } from '../../lib/utils'\nimport { searchScore } from '../../lib/fuzzy'\n\nexport interface ChatSessionView {\n id: string\n title: string\n updatedAt?: string | number | Date\n meta?: Record<string, unknown>\n}\n\nexport interface ChatSessionListLabels {\n search: string\n searchPlaceholder: string\n newChat: string\n rename: string\n delete: string\n export: string\n today: string\n yesterday: string\n earlier: string\n empty: string\n noResults: string\n}\n\nexport interface ChatSessionListIcons {\n newChat: LucideIcon\n rename: LucideIcon\n delete: LucideIcon\n export: LucideIcon\n}\n\nexport interface ChatSessionListProps {\n sessions: ChatSessionView[]\n activeId?: string | null\n onSelect: (id: string) => void\n onNew?: () => void\n onRename?: (id: string) => void\n onDelete?: (id: string) => void\n onExport?: (id: string) => void\n searchable?: boolean\n groupByDate?: boolean\n labels?: Partial<ChatSessionListLabels>\n icons?: Partial<ChatSessionListIcons>\n className?: string\n}\n\nfunction toDate(value: string | number | Date | undefined): Date | undefined {\n if (value === undefined) {\n return undefined\n }\n if (value instanceof Date) {\n return value\n }\n if (typeof value === 'number') {\n return new Date(value)\n }\n return parseISO(value)\n}\n\nfunction bucketOf(date: Date | undefined): 'today' | 'yesterday' | 'earlier' | 'none' {\n if (date === undefined) {\n return 'none'\n }\n if (isToday(date)) {\n return 'today'\n }\n if (isYesterday(date)) {\n return 'yesterday'\n }\n return 'earlier'\n}\n\n/**\n * The session list beside a full-page chat (study's `ChatSessionList` +\n * health's history overlay, generalized): fuzzy search, date grouping,\n * active marking, per-session actions (rename/delete/export) via the\n * menu when handlers are provided. All actions stay app-side.\n */\nexport const ChatSessionList = React.forwardRef<HTMLDivElement, ChatSessionListProps>(\n function ChatSessionList(\n {\n sessions,\n activeId,\n onSelect,\n onNew,\n onRename,\n onDelete,\n onExport,\n searchable = true,\n groupByDate = true,\n labels,\n icons,\n className,\n },\n ref,\n ) {\n const [query, setQuery] = React.useState('')\n const NewIcon = icons?.newChat ?? MessageSquarePlus\n const RenameIcon = icons?.rename ?? Pencil\n const DeleteIcon = icons?.delete ?? Trash2\n const ExportIcon = icons?.export ?? Download\n\n const filtered = React.useMemo(() => {\n const trimmed = query.trim()\n if (trimmed === '') {\n return sessions\n }\n return sessions\n .map((session) => ({\n session,\n score: searchScore(trimmed, session.title),\n }))\n .filter((entry) => entry.score !== null)\n .sort((a, b) => (b.score ?? 0) - (a.score ?? 0))\n .map((entry) => entry.session)\n }, [sessions, query])\n\n const groups = React.useMemo(() => {\n if (!groupByDate) {\n return [{ key: 'all', label: null as string | null, sessions: filtered }]\n }\n const ordered = [...filtered].sort((a, b) => {\n const dateA = toDate(a.updatedAt)?.getTime() ?? 0\n const dateB = toDate(b.updatedAt)?.getTime() ?? 0\n return dateB - dateA\n })\n const byBucket = new Map<string, ChatSessionView[]>()\n for (const session of ordered) {\n const bucket = bucketOf(toDate(session.updatedAt))\n const list = byBucket.get(bucket) ?? []\n list.push(session)\n byBucket.set(bucket, list)\n }\n const order = ['today', 'yesterday', 'earlier', 'none']\n return order\n .filter((bucket) => byBucket.has(bucket))\n .map((bucket) => ({\n key: bucket,\n label:\n bucket === 'today'\n ? (labels?.today ?? 'Today')\n : bucket === 'yesterday'\n ? (labels?.yesterday ?? 'Yesterday')\n : bucket === 'earlier'\n ? (labels?.earlier ?? 'Earlier')\n : null,\n sessions: byBucket.get(bucket) ?? [],\n }))\n }, [filtered, groupByDate, labels])\n\n return (\n <div ref={ref} data-as=\"chat-session-list\" className={cn('flex h-full min-h-0 w-full flex-col gap-2', className)}>\n <div className=\"flex items-center gap-2\">\n {searchable ? (\n <div className=\"relative min-w-0 flex-1\">\n <Search className=\"pointer-events-none absolute start-2 top-1/2 size-3.5 -translate-y-1/2 text-[var(--as-muted-fg)]\" aria-hidden />\n <input\n type=\"search\"\n role=\"searchbox\"\n value={query}\n aria-label={labels?.search ?? 'Search conversations'}\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 {onNew ? (\n <button\n type=\"button\"\n onClick={onNew}\n aria-label={labels?.newChat ?? 'New conversation'}\n title={labels?.newChat ?? 'New conversation'}\n className=\"flex size-7 shrink-0 items-center justify-center rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface)] text-[var(--as-fg)] transition-colors hover:bg-[var(--as-secondary)] focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]\"\n >\n <NewIcon className=\"size-4\" aria-hidden />\n </button>\n ) : null}\n </div>\n <div role=\"list\" aria-label={labels?.search ?? 'Conversations'} className=\"min-h-0 flex-1 overflow-y-auto\">\n {sessions.length === 0 ? (\n <p className=\"px-2 py-3 text-xs text-[var(--as-muted-fg)]\">{labels?.empty ?? 'No conversations yet'}</p>\n ) : filtered.length === 0 ? (\n <p className=\"px-2 py-3 text-xs text-[var(--as-muted-fg)]\">{labels?.noResults ?? 'No matches'}</p>\n ) : (\n groups.map((group) => (\n <div key={group.key} className=\"mb-2\">\n {group.label ? (\n <p className=\"px-2 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-wide text-[var(--as-muted-fg)]\">\n {group.label}\n </p>\n ) : null}\n {group.sessions.map((session) => {\n const isActive = session.id === activeId\n const date = toDate(session.updatedAt)\n const actions =\n onRename || onDelete || onExport\n ? [\n onRename\n ? {\n key: 'rename',\n label: labels?.rename ?? 'Rename',\n icon: <RenameIcon className=\"size-3.5\" aria-hidden />,\n onSelect: () => onRename(session.id),\n }\n : null,\n onExport\n ? {\n key: 'export',\n label: labels?.export ?? 'Export',\n icon: <ExportIcon className=\"size-3.5\" aria-hidden />,\n onSelect: () => onExport(session.id),\n }\n : null,\n onDelete\n ? {\n key: 'delete',\n label: labels?.delete ?? 'Delete',\n icon: <DeleteIcon className=\"size-3.5\" aria-hidden />,\n onSelect: () => onDelete(session.id),\n danger: true,\n }\n : null,\n ].filter((item): item is NonNullable<typeof item> => item !== null)\n : []\n return (\n <div\n key={session.id}\n role=\"listitem\"\n aria-current={isActive ? 'true' : undefined}\n data-active={isActive || undefined}\n className={cn(\n 'group/session flex cursor-pointer items-center gap-2 rounded-[var(--as-radius)] px-2 py-1.5 text-xs transition-colors hover:bg-[var(--as-surface-raised)]',\n isActive && 'bg-[var(--as-surface-raised)] font-medium text-[var(--as-fg)]',\n )}\n onClick={() => onSelect(session.id)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n onSelect(session.id)\n }\n }}\n tabIndex={0}\n >\n <span className=\"min-w-0 flex-1 truncate text-[var(--as-fg)]\">{session.title}</span>\n {date ? (\n <span className=\"shrink-0 text-[10px] text-[var(--as-muted-fg)]\">\n {formatDistanceToNow(date, { addSuffix: true })}\n </span>\n ) : null}\n {actions.length > 0 ? (\n <span\n role=\"group\"\n aria-label={labels?.rename ?? 'Conversation actions'}\n className=\"flex shrink-0 items-center gap-0.5 opacity-0 transition-opacity focus-within:opacity-100 group-hover/session:opacity-100\"\n onClick={(event) => event.stopPropagation()}\n onKeyDown={(event) => event.stopPropagation()}\n >\n {actions.map((action) => (\n <button\n key={action.key}\n type=\"button\"\n aria-label={action.label}\n title={action.label}\n onClick={action.onSelect}\n className={cn(\n 'rounded-[var(--as-radius-sm)] p-1 text-[var(--as-muted-fg)] transition-colors hover:bg-[var(--as-surface)] hover:text-[var(--as-fg)] focus-visible:opacity-100 focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]',\n action.danger && 'hover:text-[var(--as-danger)]',\n )}\n >\n {action.icon}\n </button>\n ))}\n </span>\n ) : null}\n </div>\n )\n })}\n </div>\n ))\n )}\n </div>\n </div>\n )\n },\n)\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/chat-launcher/ChatLauncher.tsx"],"names":["ChatLauncher"],"mappings":"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","file":"chunk-RPLEI6LQ.js","sourcesContent":["import * as React from 'react'\nimport { MessageCircle, X } from 'lucide-react'\nimport type { LucideIcon } from 'lucide-react'\n\nimport { cn } from '../../lib/utils'\nimport { Portal } from '../portal/Portal'\n\nexport interface ChatLauncherProps {\n /** The anchored panel body — usually `ChatPanel variant=\"bubble\"`. */\n panel: React.ReactNode\n open?: boolean\n defaultOpen?: boolean\n onOpenChange?: (open: boolean) => void\n position?: 'bottom-right' | 'bottom-left'\n label?: string\n closeLabel?: string\n icon?: LucideIcon\n closeIcon?: LucideIcon\n /** Unread / activity badge. */\n badge?: number | string\n container?: HTMLElement | null\n panelClassName?: string\n className?: string\n}\n\n/**\n * The floating chat bubble (career's `ChatWidget` launcher,\n * family-standard): fixed launcher button opening an anchored, non-modal\n * panel. `aria-expanded` wiring, Escape closes while focus is inside.\n */\nexport const ChatLauncher = React.forwardRef<HTMLButtonElement, ChatLauncherProps>(\n function ChatLauncher(\n {\n panel,\n open: openProp,\n defaultOpen = false,\n onOpenChange,\n position = 'bottom-right',\n label = 'Chat',\n closeLabel = 'Close chat',\n icon: Icon = MessageCircle,\n closeIcon: CloseIcon = X,\n badge,\n container,\n panelClassName,\n className,\n },\n ref,\n ) {\n const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen)\n const isControlled = openProp !== undefined\n const open = isControlled ? openProp : uncontrolledOpen\n const panelRef = React.useRef<HTMLDivElement | null>(null)\n\n const setOpen = (next: boolean) => {\n if (!isControlled) {\n setUncontrolledOpen(next)\n }\n onOpenChange?.(next)\n }\n\n React.useEffect(() => {\n if (!open) {\n return\n }\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape' && panelRef.current?.contains(document.activeElement)) {\n setOpen(false)\n }\n }\n document.addEventListener('keydown', onKeyDown)\n return () => document.removeEventListener('keydown', onKeyDown)\n })\n\n const showBadge = badge !== undefined && badge !== 0 && badge !== ''\n\n return (\n <>\n {open ? (\n <Portal container={container}>\n <div\n ref={panelRef}\n data-as=\"chat-launcher-panel\"\n className={cn(\n 'as-anim-pop fixed bottom-20 z-[var(--as-z-modal)] flex h-[min(36rem,calc(100dvh-11rem))] w-[min(26rem,calc(100vw-2rem))] flex-col overflow-hidden rounded-[var(--as-radius-lg)] border border-[var(--as-border)] bg-[var(--as-surface)] text-[var(--as-fg)] shadow-[var(--as-shadow-3)]',\n position === 'bottom-right' ? 'right-4' : 'left-4',\n panelClassName,\n )}\n role=\"complementary\"\n aria-label={label}\n >\n {panel}\n <button\n type=\"button\"\n aria-label={closeLabel}\n onClick={() => setOpen(false)}\n className=\"absolute right-2 top-2 z-10 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 <CloseIcon aria-hidden className=\"size-4\" />\n </button>\n </div>\n </Portal>\n ) : null}\n <button\n ref={ref}\n type=\"button\"\n aria-expanded={open}\n aria-label={open ? closeLabel : label}\n title={open ? closeLabel : label}\n onClick={() => setOpen(!open)}\n data-as=\"chat-launcher\"\n data-open={open || undefined}\n className={cn(\n 'fixed bottom-4 z-[var(--as-z-popover)] flex size-12 items-center justify-center rounded-full bg-[var(--as-primary)] text-[var(--as-primary-fg)] shadow-[var(--as-shadow-2)] transition-transform hover:scale-105 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--as-focus-ring)]',\n position === 'bottom-right' ? 'right-4' : 'left-4',\n className,\n )}\n >\n <Icon className=\"size-5\" aria-hidden />\n {showBadge ? (\n <span className=\"absolute -right-0.5 -top-0.5 flex h-5 min-w-5 items-center justify-center rounded-full border-2 border-[var(--as-surface)] bg-[var(--as-danger)] px-1 text-[10px] font-semibold text-[var(--as-danger-fg)]\">\n {badge}\n </span>\n ) : null}\n </button>\n </>\n )\n },\n)\n"]}
|