@epicbagel/saas-kit 1.18.0 → 1.20.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 (30) hide show
  1. package/README.md +22 -0
  2. package/dist/{chunk-HSSSNAVX.cjs → chunk-23IETCLV.cjs} +2 -2
  3. package/dist/{chunk-V3XA7SDK.js → chunk-36LNA4WM.js} +4 -2
  4. package/dist/{chunk-6AMSRIQ4.cjs → chunk-DMPSKGFM.cjs} +4 -2
  5. package/dist/{chunk-TP74SBRH.cjs → chunk-E2UVQXBO.cjs} +6 -6
  6. package/dist/{chunk-C3VZMTVB.js → chunk-FPOJ2NGG.js} +1 -1
  7. package/dist/{chunk-EXXJXOUO.js → chunk-OUZSIA5G.js} +1 -1
  8. package/dist/primitives/chat.cjs +170 -17
  9. package/dist/primitives/chat.d.cts +9 -1
  10. package/dist/primitives/chat.d.ts +9 -1
  11. package/dist/primitives/chat.js +158 -5
  12. package/dist/primitives/document-preview.cjs +5 -5
  13. package/dist/primitives/document-preview.js +3 -3
  14. package/dist/primitives/file-preview-internals.cjs +4 -4
  15. package/dist/primitives/file-preview-internals.js +3 -3
  16. package/dist/primitives/file-preview.cjs +12 -12
  17. package/dist/primitives/file-preview.js +3 -3
  18. package/dist/primitives/message-scroller.cjs +3 -3
  19. package/dist/primitives/message-scroller.js +2 -2
  20. package/dist/primitives/responsive-dialog.cjs +3 -3
  21. package/dist/primitives/responsive-dialog.js +2 -2
  22. package/dist/primitives/scroll-navigator.cjs +2 -2
  23. package/dist/primitives/scroll-navigator.d.cts +2 -0
  24. package/dist/primitives/scroll-navigator.d.ts +2 -0
  25. package/dist/primitives/scroll-navigator.js +1 -1
  26. package/package.json +1 -1
  27. package/src/styles/components/frosted-surface.css +38 -0
  28. package/src/styles/components.css +1 -0
  29. package/dist/{chunk-BTHYGHOH.cjs → chunk-AO56ET4F.cjs} +2 -2
  30. package/dist/{chunk-JTI4244T.js → chunk-CRZ4INEJ.js} +10 -10
package/README.md CHANGED
@@ -15,6 +15,15 @@ npm install @epicbagel/saas-kit
15
15
  Peer dependencies: `react` and `react-dom` (18 or 19), `lucide-react`
16
16
  (`>=0.400.0 <2`), `react-icons` (5) and `tailwindcss` (4.3 or later).
17
17
 
18
+ ## Frosted scroll navigation
19
+
20
+ `ScrollNavigator frosted` gives its floating controls a translucent themed
21
+ background with 16px backdrop blur. `MessageScrollerNavigator` forwards the same
22
+ option. The default appearance, list layout and navigation behavior are unchanged.
23
+ The surface stays opaque when backdrop blur is unsupported, reduced transparency
24
+ is requested, or forced colours are active. Import the kit's `globals.css` (or
25
+ `tokens.css` and `utilities.css`) as usual.
26
+
18
27
  ## Page header actions
19
28
 
20
29
  `PageHeaderActions` expands its actions on desktop and collapses them into
@@ -235,6 +244,19 @@ public in 1.1.0, and these were the decisions about its props then:
235
244
  [])`: the draft and staged files stay, and a failure is reported without
236
245
  touching them. Suggestions are disabled while `pending`; pass none once
237
246
  they no longer apply.
247
+ - **Compact mobile suggestions (1.20.0).** Opt into `mobileCompactSuggestions`
248
+ to put the first reply in a shaded row inside the composer on phones
249
+ below 768px. Its button sends directly; the separate `+N more` button opens
250
+ a bottom sheet with every reply in full, wrapping onto as many lines as
251
+ needed. One reply needs no picker and no replies leave no row. Desktop
252
+ keeps the existing chips. The sheet uses `replySuggestionsLabel` as its
253
+ title; `replySuggestionsMoreLabel(count)` and `replySuggestionsCloseLabel`
254
+ replace the opener and close wording. These mobile picks preserve the
255
+ draft and files without focusing the textarea or opening the keyboard.
256
+ Pending sends, changed choices, a new latest message, or a move to desktop
257
+ dismiss the picker. Equivalent arrays from a refresh leave it open.
258
+ `ChatInput.header` provides the same inside-surface top slot for other
259
+ compositions; changing the header keeps its textarea mounted.
238
260
  - **Failed sends.** When `onSend` rejects, Chat puts the text back in the
239
261
  composer and calls `onSendError`; without one it reports the rejection
240
262
  through `reportError`, so a failure is never silent.
@@ -1,7 +1,7 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }"use client";
2
2
 
3
3
 
4
- var _chunk6AMSRIQ4cjs = require('./chunk-6AMSRIQ4.cjs');
4
+ var _chunkDMPSKGFMcjs = require('./chunk-DMPSKGFM.cjs');
5
5
 
6
6
 
7
7
  var _chunkJDEXZGIYcjs = require('./chunk-JDEXZGIY.cjs');
@@ -23,7 +23,7 @@ function MessageScrollerProvider(props) {
23
23
  }
24
24
  function MessageScrollerNavigator(props) {
25
25
  const { scrollToMessage } = _messagescroller.useMessageScroller.call(void 0, );
26
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6AMSRIQ4cjs.ScrollNavigator, { ...props, onNavigate: (id, target, options) => {
26
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkDMPSKGFMcjs.ScrollNavigator, { ...props, onNavigate: (id, target, options) => {
27
27
  if (_optionalChain([props, 'access', _ => _.onNavigate, 'optionalCall', _2 => _2(id, target, options)]) === true) return true;
28
28
  const message = target.closest("[data-message-id]");
29
29
  const messageId = _optionalChain([message, 'optionalAccess', _3 => _3.dataset, 'access', _4 => _4.messageId]);
@@ -58,6 +58,7 @@ var ScrollNavigator = forwardRef(function ScrollNavigator2({
58
58
  scrollRoot,
59
59
  onNavigate,
60
60
  className,
61
+ frosted = false,
61
62
  ...props
62
63
  }, forwardedRef) {
63
64
  const rootRef = useRef(null);
@@ -195,7 +196,8 @@ var ScrollNavigator = forwardRef(function ScrollNavigator2({
195
196
  "aria-label": label,
196
197
  "data-slot": "scroll-navigator-controls",
197
198
  "data-orientation": row ? "horizontal" : "vertical",
198
- className: cn("fixed z-20 flex rounded-full border border-border/60 bg-background/95 p-1 shadow-sm backdrop-blur-sm", row ? "items-center gap-1" : "flex-col items-center gap-1"),
199
+ "data-frosted-surface": frosted ? "background" : void 0,
200
+ className: cn("fixed z-20 flex rounded-full border border-border/60 p-1 shadow-sm", !frosted && "bg-background/95 backdrop-blur-sm", row ? "items-center gap-1" : "flex-col items-center gap-1"),
199
201
  style: { top: placement.top, left: placement.left, width: placement.width, maxHeight: placement.maxHeight },
200
202
  onBlur: (event) => {
201
203
  if (!event.currentTarget.contains(event.relatedTarget)) setFocusId(null);
@@ -249,7 +251,7 @@ var ScrollNavigator = forwardRef(function ScrollNavigator2({
249
251
  ))
250
252
  }
251
253
  ),
252
- /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", className: cn("shrink-0 text-center text-[10px] tabular-nums text-muted-foreground", row ? "px-2" : "pb-1"), children: [
254
+ /* @__PURE__ */ jsxs("span", { "aria-hidden": "true", className: cn("shrink-0 text-center text-[10px] tabular-nums", frosted ? "text-foreground" : "text-muted-foreground", row ? "px-2" : "pb-1"), children: [
253
255
  placement.active + 1,
254
256
  " / ",
255
257
  items.length
@@ -58,6 +58,7 @@ var ScrollNavigator = _react.forwardRef.call(void 0, function ScrollNavigator2({
58
58
  scrollRoot,
59
59
  onNavigate,
60
60
  className,
61
+ frosted = false,
61
62
  ...props
62
63
  }, forwardedRef) {
63
64
  const rootRef = _react.useRef.call(void 0, null);
@@ -195,7 +196,8 @@ var ScrollNavigator = _react.forwardRef.call(void 0, function ScrollNavigator2({
195
196
  "aria-label": label,
196
197
  "data-slot": "scroll-navigator-controls",
197
198
  "data-orientation": row ? "horizontal" : "vertical",
198
- className: _chunkKWLSBTB2cjs.cn.call(void 0, "fixed z-20 flex rounded-full border border-border/60 bg-background/95 p-1 shadow-sm backdrop-blur-sm", row ? "items-center gap-1" : "flex-col items-center gap-1"),
199
+ "data-frosted-surface": frosted ? "background" : void 0,
200
+ className: _chunkKWLSBTB2cjs.cn.call(void 0, "fixed z-20 flex rounded-full border border-border/60 p-1 shadow-sm", !frosted && "bg-background/95 backdrop-blur-sm", row ? "items-center gap-1" : "flex-col items-center gap-1"),
199
201
  style: { top: placement.top, left: placement.left, width: placement.width, maxHeight: placement.maxHeight },
200
202
  onBlur: (event) => {
201
203
  if (!event.currentTarget.contains(event.relatedTarget)) setFocusId(null);
@@ -249,7 +251,7 @@ var ScrollNavigator = _react.forwardRef.call(void 0, function ScrollNavigator2({
249
251
  ))
250
252
  }
251
253
  ),
252
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { "aria-hidden": "true", className: _chunkKWLSBTB2cjs.cn.call(void 0, "shrink-0 text-center text-[10px] tabular-nums text-muted-foreground", row ? "px-2" : "pb-1"), children: [
254
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { "aria-hidden": "true", className: _chunkKWLSBTB2cjs.cn.call(void 0, "shrink-0 text-center text-[10px] tabular-nums", frosted ? "text-foreground" : "text-muted-foreground", row ? "px-2" : "pb-1"), children: [
253
255
  placement.active + 1,
254
256
  " / ",
255
257
  items.length
@@ -6,7 +6,7 @@
6
6
 
7
7
 
8
8
 
9
- var _chunkBTHYGHOHcjs = require('./chunk-BTHYGHOH.cjs');
9
+ var _chunkAO56ET4Fcjs = require('./chunk-AO56ET4F.cjs');
10
10
 
11
11
 
12
12
  var _chunkT2ZFSPE4cjs = require('./chunk-T2ZFSPE4.cjs');
@@ -29,10 +29,10 @@ function PreviewDialog({
29
29
  downloadLabel,
30
30
  children
31
31
  }) {
32
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkBTHYGHOHcjs.ResponsiveDialog, { open, onOpenChange, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkBTHYGHOHcjs.ResponsiveDialogContent, { presentation: "preview", className: "h-[92dvh] outline-none", children: [
33
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkBTHYGHOHcjs.ResponsiveDialogHeader, { className: "shrink-0 border-b border-border", children: [
32
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAO56ET4Fcjs.ResponsiveDialog, { open, onOpenChange, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAO56ET4Fcjs.ResponsiveDialogContent, { presentation: "preview", className: "h-[92dvh] outline-none", children: [
33
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAO56ET4Fcjs.ResponsiveDialogHeader, { className: "shrink-0 border-b border-border", children: [
34
34
  /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "flex min-w-0 items-center gap-2", children: [
35
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkBTHYGHOHcjs.ResponsiveDialogTitle, { className: "min-w-0 flex-1 truncate text-left", children: title }),
35
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAO56ET4Fcjs.ResponsiveDialogTitle, { className: "min-w-0 flex-1 truncate text-left", children: title }),
36
36
  onDownload && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
37
37
  _chunkJDEXZGIYcjs.Button,
38
38
  {
@@ -46,7 +46,7 @@ function PreviewDialog({
46
46
  children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkT2ZFSPE4cjs.Icon, { icon: downloading ? _lucidereact.Loader2 : _lucidereact.Download, size: "sm", spin: downloading })
47
47
  }
48
48
  ),
49
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkBTHYGHOHcjs.ResponsiveDialogClose, { asChild: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
49
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkAO56ET4Fcjs.ResponsiveDialogClose, { asChild: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
50
50
  _chunkJDEXZGIYcjs.Button,
51
51
  {
52
52
  type: "button",
@@ -58,7 +58,7 @@ function PreviewDialog({
58
58
  }
59
59
  ) })
60
60
  ] }),
61
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkBTHYGHOHcjs.ResponsiveDialogDescription, { className: "sr-only", children: [
61
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkAO56ET4Fcjs.ResponsiveDialogDescription, { className: "sr-only", children: [
62
62
  "Preview of ",
63
63
  title
64
64
  ] })
@@ -6,7 +6,7 @@ import {
6
6
  ResponsiveDialogDescription,
7
7
  ResponsiveDialogHeader,
8
8
  ResponsiveDialogTitle
9
- } from "./chunk-JTI4244T.js";
9
+ } from "./chunk-CRZ4INEJ.js";
10
10
  import {
11
11
  Icon
12
12
  } from "./chunk-KN4RPX35.js";
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  ScrollNavigator
4
- } from "./chunk-V3XA7SDK.js";
4
+ } from "./chunk-36LNA4WM.js";
5
5
  import {
6
6
  Button
7
7
  } from "./chunk-W326GKML.js";
@@ -26,8 +26,8 @@ var _chunkB765DSRGcjs = require('../chunk-B765DSRG.cjs');
26
26
 
27
27
 
28
28
 
29
- var _chunkHSSSNAVXcjs = require('../chunk-HSSSNAVX.cjs');
30
- require('../chunk-6AMSRIQ4.cjs');
29
+ var _chunk23IETCLVcjs = require('../chunk-23IETCLV.cjs');
30
+ require('../chunk-DMPSKGFM.cjs');
31
31
 
32
32
 
33
33
 
@@ -54,6 +54,14 @@ require('../chunk-ELPV44S6.cjs');
54
54
 
55
55
 
56
56
 
57
+
58
+
59
+ var _chunk2BHI5ZWJcjs = require('../chunk-2BHI5ZWJ.cjs');
60
+
61
+
62
+
63
+
64
+
57
65
  var _chunkZAITUDYDcjs = require('../chunk-ZAITUDYD.cjs');
58
66
  require('../chunk-U2NES7VR.cjs');
59
67
 
@@ -120,6 +128,7 @@ var _react = require('react');
120
128
 
121
129
 
122
130
 
131
+
123
132
  var _lucidereact = require('lucide-react');
124
133
  var _jsxruntime = require('react/jsx-runtime');
125
134
  function offersActions(message) {
@@ -179,15 +188,15 @@ var ChatThread = _react.forwardRef.call(void 0,
179
188
  const markers = timelineMarkers(messages, /* @__PURE__ */ new Date());
180
189
  const anchorId = useArrivingUserTurnId(messages);
181
190
  const workspace = appearance === "workspace";
182
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkHSSSNAVXcjs.MessageScrollerProvider, { autoScroll: true, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
183
- _chunkHSSSNAVXcjs.MessageScroller,
191
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk23IETCLVcjs.MessageScrollerProvider, { autoScroll: true, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
192
+ _chunk23IETCLVcjs.MessageScroller,
184
193
  {
185
194
  ref,
186
195
  style: { maxHeight },
187
196
  className: _chunkKWLSBTB2cjs.cn.call(void 0, "min-h-0", className),
188
197
  children: [
189
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkHSSSNAVXcjs.MessageScrollerViewport, { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
190
- _chunkHSSSNAVXcjs.MessageScrollerContent,
198
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk23IETCLVcjs.MessageScrollerViewport, { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
199
+ _chunk23IETCLVcjs.MessageScrollerContent,
191
200
  {
192
201
  className: _chunkKWLSBTB2cjs.cn.call(void 0,
193
202
  workspace ? "mx-auto w-full max-w-3xl gap-10 px-4 py-6 md:px-6 md:py-8" : "gap-2.5 px-px py-px"
@@ -196,7 +205,7 @@ var ChatThread = _react.forwardRef.call(void 0,
196
205
  messages.map((m, index) => {
197
206
  const isUser = m.role === "user";
198
207
  if (m.status === "running") {
199
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkHSSSNAVXcjs.MessageScrollerItem, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
208
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk23IETCLVcjs.MessageScrollerItem, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
200
209
  ChatRunningLine,
201
210
  {
202
211
  label: m.text || pendingLabel,
@@ -209,7 +218,7 @@ var ChatThread = _react.forwardRef.call(void 0,
209
218
  const marker = markers[index];
210
219
  const actions = messageActions && offersActions(m) ? messageActions(m) : null;
211
220
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
212
- _chunkHSSSNAVXcjs.MessageScrollerItem,
221
+ _chunk23IETCLVcjs.MessageScrollerItem,
213
222
  {
214
223
  messageId: m.id,
215
224
  scrollAnchor: m.id === anchorId,
@@ -265,15 +274,15 @@ var ChatThread = _react.forwardRef.call(void 0,
265
274
  m.id
266
275
  );
267
276
  }),
268
- pending && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkHSSSNAVXcjs.MessageScrollerItem, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ChatRunningLine, { label: pendingLabel, workspace }) }),
277
+ pending && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk23IETCLVcjs.MessageScrollerItem, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ChatRunningLine, { label: pendingLabel, workspace }) }),
269
278
  footer && // Always painted: content-visibility:auto would contain the
270
279
  // footer's paint and layout, clipping a ring or shadow at its
271
280
  // edge and re-parenting anything fixed inside it.
272
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkHSSSNAVXcjs.MessageScrollerItem, { className: "[content-visibility:visible]", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkNWDPH2Z7cjs.Message, { align: "start", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkNWDPH2Z7cjs.MessageContent, { children: footer }) }) })
281
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk23IETCLVcjs.MessageScrollerItem, { className: "[content-visibility:visible]", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkNWDPH2Z7cjs.Message, { align: "start", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkNWDPH2Z7cjs.MessageContent, { children: footer }) }) })
273
282
  ]
274
283
  }
275
284
  ) }),
276
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkHSSSNAVXcjs.MessageScrollerButton, { variant: "outline", className: "rounded-full shadow-sm", children: [
285
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunk23IETCLVcjs.MessageScrollerButton, { variant: "outline", className: "rounded-full shadow-sm", children: [
277
286
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.ArrowDown, { className: "h-4 w-4" }),
278
287
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "sr-only", children: scrollButtonLabel })
279
288
  ] })
@@ -396,6 +405,7 @@ function ChatInput({
396
405
  addFilesLabel = "Add files",
397
406
  appearance = "default",
398
407
  compactOnBlur = false,
408
+ header,
399
409
  helperText,
400
410
  privacyNote
401
411
  }) {
@@ -469,6 +479,16 @@ function ChatInput({
469
479
  className
470
480
  ),
471
481
  children: [
482
+ header && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
483
+ _chunk7LDJAXRXcjs.InputGroupAddon,
484
+ {
485
+ align: "block-start",
486
+ className: "w-full cursor-default border-b border-border bg-muted/50 p-0 [.border-b]:pb-0",
487
+ onClick: () => {
488
+ },
489
+ children: header
490
+ }
491
+ ),
472
492
  liveVoiceActive && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk7LDJAXRXcjs.InputGroupAddon, { align: "block-start", className: "w-full cursor-default border-b border-border p-0 [.border-b]:pb-0", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkYMI3X2YLcjs.VoiceSessionControls, { ...voiceSession }) }),
473
493
  attachments.length > 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
474
494
  ChatAttachmentList,
@@ -697,6 +717,123 @@ function ChatSuggestions({
697
717
  )
698
718
  ] });
699
719
  }
720
+ function MobileReplySuggestions({
721
+ items,
722
+ onSelect,
723
+ label,
724
+ moreLabel,
725
+ closeLabel,
726
+ disabled
727
+ }) {
728
+ const [open, setOpen] = _react.useState.call(void 0, false);
729
+ const triggerRef = _react.useRef.call(void 0, null);
730
+ const closeRef = _react.useRef.call(void 0, null);
731
+ _react.useEffect.call(void 0, () => {
732
+ if (disabled) setOpen(false);
733
+ }, [disabled]);
734
+ const select = (item) => {
735
+ if (disabled) return;
736
+ setOpen(false);
737
+ onSelect(item);
738
+ };
739
+ const primary = items[0];
740
+ if (primary === void 0) return null;
741
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunk2BHI5ZWJcjs.Drawer, { open, onOpenChange: setOpen, shouldScaleBackground: false, repositionInputs: false, children: [
742
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
743
+ "div",
744
+ {
745
+ "data-slot": "chat-replies",
746
+ "data-variant": "compact",
747
+ role: "group",
748
+ "aria-label": label,
749
+ className: "flex w-full min-w-0 items-center text-foreground",
750
+ children: [
751
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
752
+ _chunkJDEXZGIYcjs.Button,
753
+ {
754
+ type: "button",
755
+ variant: "ghost",
756
+ size: "bare",
757
+ disabled,
758
+ className: "h-[44px] min-h-[44px] min-w-0 flex-1 justify-start gap-2 px-3 text-left focus-visible:-ring-offset-2",
759
+ onClick: () => select(primary),
760
+ children: [
761
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.ArrowUpRight, { "aria-hidden": "true" }),
762
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "min-w-0 truncate", children: primary })
763
+ ]
764
+ }
765
+ ),
766
+ items.length > 1 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk2BHI5ZWJcjs.DrawerTrigger, { asChild: true, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
767
+ _chunkJDEXZGIYcjs.Button,
768
+ {
769
+ ref: triggerRef,
770
+ type: "button",
771
+ variant: "ghost",
772
+ size: "bare",
773
+ disabled,
774
+ className: "h-[44px] min-h-[44px] shrink-0 gap-1 px-3 text-muted-foreground focus-visible:-ring-offset-2",
775
+ children: [
776
+ moreLabel(items.length - 1),
777
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.ChevronUp, { "aria-hidden": "true" })
778
+ ]
779
+ }
780
+ ) })
781
+ ]
782
+ }
783
+ ),
784
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
785
+ _chunk2BHI5ZWJcjs.DrawerContent,
786
+ {
787
+ "aria-describedby": void 0,
788
+ className: "max-h-[min(85dvh,40rem)] overflow-hidden pb-[env(safe-area-inset-bottom)]",
789
+ onOpenAutoFocus: (event) => {
790
+ event.preventDefault();
791
+ _optionalChain([closeRef, 'access', _9 => _9.current, 'optionalAccess', _10 => _10.focus, 'call', _11 => _11({ preventScroll: true })]);
792
+ },
793
+ onCloseAutoFocus: (event) => {
794
+ event.preventDefault();
795
+ if (_optionalChain([triggerRef, 'access', _12 => _12.current, 'optionalAccess', _13 => _13.isConnected]) && !triggerRef.current.disabled) {
796
+ triggerRef.current.focus({ preventScroll: true });
797
+ }
798
+ },
799
+ children: [
800
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunk2BHI5ZWJcjs.DrawerHeader, { align: "start", className: "flex shrink-0 items-center justify-between gap-3 border-b px-4 py-2", children: [
801
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk2BHI5ZWJcjs.DrawerTitle, { className: "min-w-0 break-words leading-snug", children: label }),
802
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk2BHI5ZWJcjs.DrawerClose, { asChild: true, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
803
+ _chunkJDEXZGIYcjs.Button,
804
+ {
805
+ ref: closeRef,
806
+ type: "button",
807
+ variant: "ghost",
808
+ size: "icon",
809
+ "aria-label": closeLabel,
810
+ className: "h-[44px] w-[44px] shrink-0",
811
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.X, { "aria-hidden": "true" })
812
+ }
813
+ ) })
814
+ ] }),
815
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "min-h-0 overflow-y-auto overscroll-contain", role: "group", "aria-label": label, children: items.map((item) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
816
+ _chunkJDEXZGIYcjs.Button,
817
+ {
818
+ type: "button",
819
+ variant: "ghost",
820
+ size: "bare",
821
+ disabled,
822
+ "data-slot": "chat-reply-option",
823
+ className: "min-h-[56px] w-full justify-between gap-4 rounded-none border-b px-4 py-4 text-left text-base font-normal whitespace-normal last:border-b-0 focus-visible:-ring-offset-2",
824
+ onClick: () => select(item),
825
+ children: [
826
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "min-w-0 break-words", children: item }),
827
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.ArrowUpRight, { "aria-hidden": "true" })
828
+ ]
829
+ },
830
+ item
831
+ )) })
832
+ ]
833
+ }
834
+ )
835
+ ] });
836
+ }
700
837
  function ExamplePromptsLoading({ label, className }) {
701
838
  const list = Array.isArray(label) ? label : [label];
702
839
  const [idx, setIdx] = _react.useState.call(void 0, 0);
@@ -740,6 +877,9 @@ var Chat = _react.forwardRef.call(void 0, function Chat2({
740
877
  examplePromptsLoadingLabel = "Loading suggestions\u2026",
741
878
  replySuggestions = [],
742
879
  replySuggestionsLabel = "Suggested replies",
880
+ mobileCompactSuggestions = false,
881
+ replySuggestionsMoreLabel = (count) => `+${count} more`,
882
+ replySuggestionsCloseLabel = "Close suggested replies",
743
883
  compactEmptyState = false,
744
884
  defaultMode,
745
885
  placeholder = "Type your message\u2026",
@@ -809,12 +949,12 @@ var Chat = _react.forwardRef.call(void 0, function Chat2({
809
949
  }
810
950
  reportSendError(cause);
811
951
  }
812
- window.setTimeout(() => _optionalChain([inputRef, 'access', _9 => _9.current, 'optionalAccess', _10 => _10.focus, 'call', _11 => _11()]), 0);
952
+ window.setTimeout(() => _optionalChain([inputRef, 'access', _14 => _14.current, 'optionalAccess', _15 => _15.focus, 'call', _16 => _16()]), 0);
813
953
  },
814
954
  [attachments, mode, onSend, pending, reportSendError]
815
955
  );
816
956
  const sendSuggestion = _react.useCallback.call(void 0,
817
- async (text) => {
957
+ async (text, focusInput = true) => {
818
958
  const trimmed = text.trim();
819
959
  if (!trimmed || pending) return;
820
960
  try {
@@ -822,14 +962,14 @@ var Chat = _react.forwardRef.call(void 0, function Chat2({
822
962
  } catch (cause) {
823
963
  reportSendError(cause);
824
964
  }
825
- window.setTimeout(() => _optionalChain([inputRef, 'access', _12 => _12.current, 'optionalAccess', _13 => _13.focus, 'call', _14 => _14()]), 0);
965
+ if (focusInput) window.setTimeout(() => _optionalChain([inputRef, 'access', _17 => _17.current, 'optionalAccess', _18 => _18.focus, 'call', _19 => _19()]), 0);
826
966
  },
827
967
  [onSend, pending, reportSendError]
828
968
  );
829
969
  _react.useImperativeHandle.call(void 0,
830
970
  ref,
831
971
  () => ({
832
- focusInput: () => _optionalChain([inputRef, 'access', _15 => _15.current, 'optionalAccess', _16 => _16.focus, 'call', _17 => _17()]),
972
+ focusInput: () => _optionalChain([inputRef, 'access', _20 => _20.current, 'optionalAccess', _21 => _21.focus, 'call', _22 => _22()]),
833
973
  clearInput: () => setInput("")
834
974
  }),
835
975
  []
@@ -837,12 +977,13 @@ var Chat = _react.forwardRef.call(void 0, function Chat2({
837
977
  const dropFiles = _react.useCallback.call(void 0,
838
978
  (files) => {
839
979
  if (!conversationStarted && mode === "voice") setUserMode("text");
840
- return _optionalChain([onFilesSelected, 'optionalCall', _18 => _18(files)]);
980
+ return _optionalChain([onFilesSelected, 'optionalCall', _23 => _23(files)]);
841
981
  },
842
982
  [conversationStarted, mode, onFilesSelected]
843
983
  );
844
984
  const application = layout === "application";
845
985
  const workspace = layout === "workspace";
986
+ const compactSuggestions = mobileCompactSuggestions && isMobile;
846
987
  const showEmptyFileDropzone = emptyFileDropzone && Boolean(onFilesSelected) && attachments.length === 0;
847
988
  const liveVoiceActive = voiceSession && voiceSession.state !== "disconnected" && voiceSession.state !== "error";
848
989
  const showEmptyPending = !conversationStarted && pending && Boolean(emptyPendingContent) && !liveVoiceActive;
@@ -1019,7 +1160,7 @@ var Chat = _react.forwardRef.call(void 0, function Chat2({
1019
1160
  workspace && mobileCompactComposer && "max-md:pb-[max(0.75rem,env(safe-area-inset-bottom))] max-md:pt-3"
1020
1161
  ),
1021
1162
  children: [
1022
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1163
+ !compactSuggestions && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1023
1164
  ChatSuggestions,
1024
1165
  {
1025
1166
  slot: "chat-replies",
@@ -1034,6 +1175,18 @@ var Chat = _react.forwardRef.call(void 0, function Chat2({
1034
1175
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1035
1176
  ChatInput,
1036
1177
  {
1178
+ header: compactSuggestions && replySuggestions.length > 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
1179
+ MobileReplySuggestions,
1180
+ {
1181
+ items: replySuggestions,
1182
+ onSelect: (reply) => void sendSuggestion(reply, false),
1183
+ label: replySuggestionsLabel,
1184
+ moreLabel: replySuggestionsMoreLabel,
1185
+ closeLabel: replySuggestionsCloseLabel,
1186
+ disabled: pending
1187
+ },
1188
+ JSON.stringify([_optionalChain([messages, 'access', _24 => _24.at, 'call', _25 => _25(-1), 'optionalAccess', _26 => _26.id]), replySuggestions])
1189
+ ) : void 0,
1037
1190
  value: input,
1038
1191
  onChange: setInput,
1039
1192
  onSend: (text) => void send(text),
@@ -197,6 +197,8 @@ interface ChatInputProps {
197
197
  * this only for an active mobile conversation with `mobileCompactComposer`.
198
198
  */
199
199
  compactOnBlur?: boolean;
200
+ /** Content inside the composer surface, above its files and text field. */
201
+ header?: ReactNode;
200
202
  /** Quiet contextual copy between the composer controls. */
201
203
  helperText?: ReactNode;
202
204
  /** Privacy or visibility reassurance rendered below the composer. */
@@ -219,7 +221,7 @@ interface ChatInputProps {
219
221
  * `<Chat>` instead of composing `<ChatInput>` directly if you want
220
222
  * device-aware default modes.
221
223
  */
222
- declare function ChatInput({ value, onChange, onSend, pending, disabled, placeholder, size, uploadingLabel, voice, voiceSession, voiceTitle, voiceLang, submitLabel, autoFocus, className, inputRef, attachments, onFilesSelected, onRemoveAttachment, accept, multiple, addFilesLabel, appearance, compactOnBlur, helperText, privacyNote, }: ChatInputProps): react_jsx_runtime.JSX.Element;
224
+ declare function ChatInput({ value, onChange, onSend, pending, disabled, placeholder, size, uploadingLabel, voice, voiceSession, voiceTitle, voiceLang, submitLabel, autoFocus, className, inputRef, attachments, onFilesSelected, onRemoveAttachment, accept, multiple, addFilesLabel, appearance, compactOnBlur, header, helperText, privacyNote, }: ChatInputProps): react_jsx_runtime.JSX.Element;
223
225
  interface ChatProps {
224
226
  /** Conversation messages. */
225
227
  messages: ChatMessage[];
@@ -329,6 +331,12 @@ interface ChatProps {
329
331
  replySuggestions?: ReadonlyArray<string>;
330
332
  /** The reply suggestions' accessible name. Defaults to "Suggested replies". */
331
333
  replySuggestionsLabel?: string;
334
+ /** Below 768px, show replies inside the composer as the first reply and a bottom-sheet picker. Desktop chips are unchanged. */
335
+ mobileCompactSuggestions?: boolean;
336
+ /** The mobile picker's opener, given the number of additional replies. Defaults to `+N more`. */
337
+ replySuggestionsMoreLabel?: (count: number) => string;
338
+ /** Accessible label for closing the mobile picker. Defaults to "Close suggested replies". */
339
+ replySuggestionsCloseLabel?: string;
332
340
  /** Visual treatment for both empty and active text composers. */
333
341
  composerAppearance?: ChatInputProps["appearance"];
334
342
  /**
@@ -197,6 +197,8 @@ interface ChatInputProps {
197
197
  * this only for an active mobile conversation with `mobileCompactComposer`.
198
198
  */
199
199
  compactOnBlur?: boolean;
200
+ /** Content inside the composer surface, above its files and text field. */
201
+ header?: ReactNode;
200
202
  /** Quiet contextual copy between the composer controls. */
201
203
  helperText?: ReactNode;
202
204
  /** Privacy or visibility reassurance rendered below the composer. */
@@ -219,7 +221,7 @@ interface ChatInputProps {
219
221
  * `<Chat>` instead of composing `<ChatInput>` directly if you want
220
222
  * device-aware default modes.
221
223
  */
222
- declare function ChatInput({ value, onChange, onSend, pending, disabled, placeholder, size, uploadingLabel, voice, voiceSession, voiceTitle, voiceLang, submitLabel, autoFocus, className, inputRef, attachments, onFilesSelected, onRemoveAttachment, accept, multiple, addFilesLabel, appearance, compactOnBlur, helperText, privacyNote, }: ChatInputProps): react_jsx_runtime.JSX.Element;
224
+ declare function ChatInput({ value, onChange, onSend, pending, disabled, placeholder, size, uploadingLabel, voice, voiceSession, voiceTitle, voiceLang, submitLabel, autoFocus, className, inputRef, attachments, onFilesSelected, onRemoveAttachment, accept, multiple, addFilesLabel, appearance, compactOnBlur, header, helperText, privacyNote, }: ChatInputProps): react_jsx_runtime.JSX.Element;
223
225
  interface ChatProps {
224
226
  /** Conversation messages. */
225
227
  messages: ChatMessage[];
@@ -329,6 +331,12 @@ interface ChatProps {
329
331
  replySuggestions?: ReadonlyArray<string>;
330
332
  /** The reply suggestions' accessible name. Defaults to "Suggested replies". */
331
333
  replySuggestionsLabel?: string;
334
+ /** Below 768px, show replies inside the composer as the first reply and a bottom-sheet picker. Desktop chips are unchanged. */
335
+ mobileCompactSuggestions?: boolean;
336
+ /** The mobile picker's opener, given the number of additional replies. Defaults to `+N more`. */
337
+ replySuggestionsMoreLabel?: (count: number) => string;
338
+ /** Accessible label for closing the mobile picker. Defaults to "Close suggested replies". */
339
+ replySuggestionsCloseLabel?: string;
332
340
  /** Visual treatment for both empty and active text composers. */
333
341
  composerAppearance?: ChatInputProps["appearance"];
334
342
  /**
@@ -26,8 +26,8 @@ import {
26
26
  MessageScrollerItem,
27
27
  MessageScrollerProvider,
28
28
  MessageScrollerViewport
29
- } from "../chunk-EXXJXOUO.js";
30
- import "../chunk-V3XA7SDK.js";
29
+ } from "../chunk-OUZSIA5G.js";
30
+ import "../chunk-36LNA4WM.js";
31
31
  import {
32
32
  Message,
33
33
  MessageAction,
@@ -49,6 +49,14 @@ import {
49
49
  LazyMarkdown
50
50
  } from "../chunk-VY5U4VGV.js";
51
51
  import "../chunk-INNGGLMZ.js";
52
+ import {
53
+ Drawer,
54
+ DrawerClose,
55
+ DrawerContent,
56
+ DrawerHeader,
57
+ DrawerTitle,
58
+ DrawerTrigger
59
+ } from "../chunk-4HWCNRK4.js";
52
60
  import {
53
61
  DropdownMenu,
54
62
  DropdownMenuContent,
@@ -113,6 +121,7 @@ import {
113
121
  ArrowUp,
114
122
  ArrowUpRight,
115
123
  Check,
124
+ ChevronUp,
116
125
  Copy,
117
126
  Download,
118
127
  FileText,
@@ -396,6 +405,7 @@ function ChatInput({
396
405
  addFilesLabel = "Add files",
397
406
  appearance = "default",
398
407
  compactOnBlur = false,
408
+ header,
399
409
  helperText,
400
410
  privacyNote
401
411
  }) {
@@ -469,6 +479,16 @@ function ChatInput({
469
479
  className
470
480
  ),
471
481
  children: [
482
+ header && /* @__PURE__ */ jsx(
483
+ InputGroupAddon,
484
+ {
485
+ align: "block-start",
486
+ className: "w-full cursor-default border-b border-border bg-muted/50 p-0 [.border-b]:pb-0",
487
+ onClick: () => {
488
+ },
489
+ children: header
490
+ }
491
+ ),
472
492
  liveVoiceActive && /* @__PURE__ */ jsx(InputGroupAddon, { align: "block-start", className: "w-full cursor-default border-b border-border p-0 [.border-b]:pb-0", children: /* @__PURE__ */ jsx(VoiceSessionControls, { ...voiceSession }) }),
473
493
  attachments.length > 0 && /* @__PURE__ */ jsx(
474
494
  ChatAttachmentList,
@@ -697,6 +717,123 @@ function ChatSuggestions({
697
717
  )
698
718
  ] });
699
719
  }
720
+ function MobileReplySuggestions({
721
+ items,
722
+ onSelect,
723
+ label,
724
+ moreLabel,
725
+ closeLabel,
726
+ disabled
727
+ }) {
728
+ const [open, setOpen] = useState(false);
729
+ const triggerRef = useRef(null);
730
+ const closeRef = useRef(null);
731
+ useEffect(() => {
732
+ if (disabled) setOpen(false);
733
+ }, [disabled]);
734
+ const select = (item) => {
735
+ if (disabled) return;
736
+ setOpen(false);
737
+ onSelect(item);
738
+ };
739
+ const primary = items[0];
740
+ if (primary === void 0) return null;
741
+ return /* @__PURE__ */ jsxs(Drawer, { open, onOpenChange: setOpen, shouldScaleBackground: false, repositionInputs: false, children: [
742
+ /* @__PURE__ */ jsxs(
743
+ "div",
744
+ {
745
+ "data-slot": "chat-replies",
746
+ "data-variant": "compact",
747
+ role: "group",
748
+ "aria-label": label,
749
+ className: "flex w-full min-w-0 items-center text-foreground",
750
+ children: [
751
+ /* @__PURE__ */ jsxs(
752
+ Button,
753
+ {
754
+ type: "button",
755
+ variant: "ghost",
756
+ size: "bare",
757
+ disabled,
758
+ className: "h-[44px] min-h-[44px] min-w-0 flex-1 justify-start gap-2 px-3 text-left focus-visible:-ring-offset-2",
759
+ onClick: () => select(primary),
760
+ children: [
761
+ /* @__PURE__ */ jsx(ArrowUpRight, { "aria-hidden": "true" }),
762
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 truncate", children: primary })
763
+ ]
764
+ }
765
+ ),
766
+ items.length > 1 && /* @__PURE__ */ jsx(DrawerTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
767
+ Button,
768
+ {
769
+ ref: triggerRef,
770
+ type: "button",
771
+ variant: "ghost",
772
+ size: "bare",
773
+ disabled,
774
+ className: "h-[44px] min-h-[44px] shrink-0 gap-1 px-3 text-muted-foreground focus-visible:-ring-offset-2",
775
+ children: [
776
+ moreLabel(items.length - 1),
777
+ /* @__PURE__ */ jsx(ChevronUp, { "aria-hidden": "true" })
778
+ ]
779
+ }
780
+ ) })
781
+ ]
782
+ }
783
+ ),
784
+ /* @__PURE__ */ jsxs(
785
+ DrawerContent,
786
+ {
787
+ "aria-describedby": void 0,
788
+ className: "max-h-[min(85dvh,40rem)] overflow-hidden pb-[env(safe-area-inset-bottom)]",
789
+ onOpenAutoFocus: (event) => {
790
+ event.preventDefault();
791
+ closeRef.current?.focus({ preventScroll: true });
792
+ },
793
+ onCloseAutoFocus: (event) => {
794
+ event.preventDefault();
795
+ if (triggerRef.current?.isConnected && !triggerRef.current.disabled) {
796
+ triggerRef.current.focus({ preventScroll: true });
797
+ }
798
+ },
799
+ children: [
800
+ /* @__PURE__ */ jsxs(DrawerHeader, { align: "start", className: "flex shrink-0 items-center justify-between gap-3 border-b px-4 py-2", children: [
801
+ /* @__PURE__ */ jsx(DrawerTitle, { className: "min-w-0 break-words leading-snug", children: label }),
802
+ /* @__PURE__ */ jsx(DrawerClose, { asChild: true, children: /* @__PURE__ */ jsx(
803
+ Button,
804
+ {
805
+ ref: closeRef,
806
+ type: "button",
807
+ variant: "ghost",
808
+ size: "icon",
809
+ "aria-label": closeLabel,
810
+ className: "h-[44px] w-[44px] shrink-0",
811
+ children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true" })
812
+ }
813
+ ) })
814
+ ] }),
815
+ /* @__PURE__ */ jsx("div", { className: "min-h-0 overflow-y-auto overscroll-contain", role: "group", "aria-label": label, children: items.map((item) => /* @__PURE__ */ jsxs(
816
+ Button,
817
+ {
818
+ type: "button",
819
+ variant: "ghost",
820
+ size: "bare",
821
+ disabled,
822
+ "data-slot": "chat-reply-option",
823
+ className: "min-h-[56px] w-full justify-between gap-4 rounded-none border-b px-4 py-4 text-left text-base font-normal whitespace-normal last:border-b-0 focus-visible:-ring-offset-2",
824
+ onClick: () => select(item),
825
+ children: [
826
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 break-words", children: item }),
827
+ /* @__PURE__ */ jsx(ArrowUpRight, { "aria-hidden": "true" })
828
+ ]
829
+ },
830
+ item
831
+ )) })
832
+ ]
833
+ }
834
+ )
835
+ ] });
836
+ }
700
837
  function ExamplePromptsLoading({ label, className }) {
701
838
  const list = Array.isArray(label) ? label : [label];
702
839
  const [idx, setIdx] = useState(0);
@@ -740,6 +877,9 @@ var Chat = forwardRef(function Chat2({
740
877
  examplePromptsLoadingLabel = "Loading suggestions\u2026",
741
878
  replySuggestions = [],
742
879
  replySuggestionsLabel = "Suggested replies",
880
+ mobileCompactSuggestions = false,
881
+ replySuggestionsMoreLabel = (count) => `+${count} more`,
882
+ replySuggestionsCloseLabel = "Close suggested replies",
743
883
  compactEmptyState = false,
744
884
  defaultMode,
745
885
  placeholder = "Type your message\u2026",
@@ -814,7 +954,7 @@ var Chat = forwardRef(function Chat2({
814
954
  [attachments, mode, onSend, pending, reportSendError]
815
955
  );
816
956
  const sendSuggestion = useCallback(
817
- async (text) => {
957
+ async (text, focusInput = true) => {
818
958
  const trimmed = text.trim();
819
959
  if (!trimmed || pending) return;
820
960
  try {
@@ -822,7 +962,7 @@ var Chat = forwardRef(function Chat2({
822
962
  } catch (cause) {
823
963
  reportSendError(cause);
824
964
  }
825
- window.setTimeout(() => inputRef.current?.focus(), 0);
965
+ if (focusInput) window.setTimeout(() => inputRef.current?.focus(), 0);
826
966
  },
827
967
  [onSend, pending, reportSendError]
828
968
  );
@@ -843,6 +983,7 @@ var Chat = forwardRef(function Chat2({
843
983
  );
844
984
  const application = layout === "application";
845
985
  const workspace = layout === "workspace";
986
+ const compactSuggestions = mobileCompactSuggestions && isMobile;
846
987
  const showEmptyFileDropzone = emptyFileDropzone && Boolean(onFilesSelected) && attachments.length === 0;
847
988
  const liveVoiceActive = voiceSession && voiceSession.state !== "disconnected" && voiceSession.state !== "error";
848
989
  const showEmptyPending = !conversationStarted && pending && Boolean(emptyPendingContent) && !liveVoiceActive;
@@ -1019,7 +1160,7 @@ var Chat = forwardRef(function Chat2({
1019
1160
  workspace && mobileCompactComposer && "max-md:pb-[max(0.75rem,env(safe-area-inset-bottom))] max-md:pt-3"
1020
1161
  ),
1021
1162
  children: [
1022
- /* @__PURE__ */ jsx(
1163
+ !compactSuggestions && /* @__PURE__ */ jsx(
1023
1164
  ChatSuggestions,
1024
1165
  {
1025
1166
  slot: "chat-replies",
@@ -1034,6 +1175,18 @@ var Chat = forwardRef(function Chat2({
1034
1175
  /* @__PURE__ */ jsx(
1035
1176
  ChatInput,
1036
1177
  {
1178
+ header: compactSuggestions && replySuggestions.length > 0 ? /* @__PURE__ */ jsx(
1179
+ MobileReplySuggestions,
1180
+ {
1181
+ items: replySuggestions,
1182
+ onSelect: (reply) => void sendSuggestion(reply, false),
1183
+ label: replySuggestionsLabel,
1184
+ moreLabel: replySuggestionsMoreLabel,
1185
+ closeLabel: replySuggestionsCloseLabel,
1186
+ disabled: pending
1187
+ },
1188
+ JSON.stringify([messages.at(-1)?.id, replySuggestions])
1189
+ ) : void 0,
1037
1190
  value: input,
1038
1191
  onChange: setInput,
1039
1192
  onSend: (text) => void send(text),
@@ -5,10 +5,10 @@
5
5
 
6
6
 
7
7
 
8
- var _chunkTP74SBRHcjs = require('../chunk-TP74SBRH.cjs');
9
- require('../chunk-BTHYGHOH.cjs');
10
- require('../chunk-2BHI5ZWJ.cjs');
8
+ var _chunkE2UVQXBOcjs = require('../chunk-E2UVQXBO.cjs');
9
+ require('../chunk-AO56ET4F.cjs');
11
10
  require('../chunk-WDXEJDMO.cjs');
11
+ require('../chunk-2BHI5ZWJ.cjs');
12
12
  require('../chunk-T2ZFSPE4.cjs');
13
13
  require('../chunk-JDEXZGIY.cjs');
14
14
  require('../chunk-KWLSBTB2.cjs');
@@ -29,7 +29,7 @@ function DocumentPreview({
29
29
  fallback
30
30
  }) {
31
31
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
32
- _chunkTP74SBRHcjs.PreviewDialog,
32
+ _chunkE2UVQXBOcjs.PreviewDialog,
33
33
  {
34
34
  open,
35
35
  onOpenChange,
@@ -37,7 +37,7 @@ function DocumentPreview({
37
37
  onDownload,
38
38
  downloading,
39
39
  downloadLabel,
40
- children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTP74SBRHcjs.PreviewStage, { children: loading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTP74SBRHcjs.PreviewLoading, { label: "Loading preview\u2026" }) : error ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTP74SBRHcjs.PreviewNotice, { icon: _lucidereact.FileWarning, alert: true, message: error, children: fallback }) : src ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
40
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkE2UVQXBOcjs.PreviewStage, { children: loading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkE2UVQXBOcjs.PreviewLoading, { label: "Loading preview\u2026" }) : error ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkE2UVQXBOcjs.PreviewNotice, { icon: _lucidereact.FileWarning, alert: true, message: error, children: fallback }) : src ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
41
41
  "iframe",
42
42
  {
43
43
  src,
@@ -5,10 +5,10 @@ import {
5
5
  PreviewLoading,
6
6
  PreviewNotice,
7
7
  PreviewStage
8
- } from "../chunk-C3VZMTVB.js";
9
- import "../chunk-JTI4244T.js";
10
- import "../chunk-4HWCNRK4.js";
8
+ } from "../chunk-FPOJ2NGG.js";
9
+ import "../chunk-CRZ4INEJ.js";
11
10
  import "../chunk-3QT5VYZ3.js";
11
+ import "../chunk-4HWCNRK4.js";
12
12
  import "../chunk-KN4RPX35.js";
13
13
  import "../chunk-W326GKML.js";
14
14
  import "../chunk-G6SRSWXB.js";
@@ -5,10 +5,10 @@
5
5
 
6
6
 
7
7
 
8
- var _chunkTP74SBRHcjs = require('../chunk-TP74SBRH.cjs');
9
- require('../chunk-BTHYGHOH.cjs');
10
- require('../chunk-2BHI5ZWJ.cjs');
8
+ var _chunkE2UVQXBOcjs = require('../chunk-E2UVQXBO.cjs');
9
+ require('../chunk-AO56ET4F.cjs');
11
10
  require('../chunk-WDXEJDMO.cjs');
11
+ require('../chunk-2BHI5ZWJ.cjs');
12
12
  require('../chunk-T2ZFSPE4.cjs');
13
13
  require('../chunk-JDEXZGIY.cjs');
14
14
  require('../chunk-KWLSBTB2.cjs');
@@ -17,4 +17,4 @@ require('../chunk-KWLSBTB2.cjs');
17
17
 
18
18
 
19
19
 
20
- exports.PreviewDialog = _chunkTP74SBRHcjs.PreviewDialog; exports.PreviewLoading = _chunkTP74SBRHcjs.PreviewLoading; exports.PreviewNotice = _chunkTP74SBRHcjs.PreviewNotice; exports.PreviewStage = _chunkTP74SBRHcjs.PreviewStage;
20
+ exports.PreviewDialog = _chunkE2UVQXBOcjs.PreviewDialog; exports.PreviewLoading = _chunkE2UVQXBOcjs.PreviewLoading; exports.PreviewNotice = _chunkE2UVQXBOcjs.PreviewNotice; exports.PreviewStage = _chunkE2UVQXBOcjs.PreviewStage;
@@ -5,10 +5,10 @@ import {
5
5
  PreviewLoading,
6
6
  PreviewNotice,
7
7
  PreviewStage
8
- } from "../chunk-C3VZMTVB.js";
9
- import "../chunk-JTI4244T.js";
10
- import "../chunk-4HWCNRK4.js";
8
+ } from "../chunk-FPOJ2NGG.js";
9
+ import "../chunk-CRZ4INEJ.js";
11
10
  import "../chunk-3QT5VYZ3.js";
11
+ import "../chunk-4HWCNRK4.js";
12
12
  import "../chunk-KN4RPX35.js";
13
13
  import "../chunk-W326GKML.js";
14
14
  import "../chunk-G6SRSWXB.js";
@@ -8,14 +8,14 @@ var _chunk4UUTKR3Vcjs = require('../chunk-4UUTKR3V.cjs');
8
8
 
9
9
 
10
10
 
11
- var _chunkTP74SBRHcjs = require('../chunk-TP74SBRH.cjs');
12
- require('../chunk-BTHYGHOH.cjs');
13
- require('../chunk-2BHI5ZWJ.cjs');
11
+ var _chunkE2UVQXBOcjs = require('../chunk-E2UVQXBO.cjs');
12
+ require('../chunk-AO56ET4F.cjs');
14
13
  require('../chunk-WDXEJDMO.cjs');
15
14
 
16
15
 
17
16
  var _chunkKENBU3NVcjs = require('../chunk-KENBU3NV.cjs');
18
17
  require('../chunk-ELPV44S6.cjs');
18
+ require('../chunk-2BHI5ZWJ.cjs');
19
19
 
20
20
 
21
21
  var _chunkBGCNGYPLcjs = require('../chunk-BGCNGYPL.cjs');
@@ -155,7 +155,7 @@ function FilePreview({
155
155
  truncatedLabel = "Showing the start of this file. Download it to see the rest."
156
156
  }) {
157
157
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
158
- _chunkTP74SBRHcjs.PreviewDialog,
158
+ _chunkE2UVQXBOcjs.PreviewDialog,
159
159
  {
160
160
  open,
161
161
  onOpenChange,
@@ -266,17 +266,17 @@ function FilePreviewBody({
266
266
  const reads = kind === "text" || kind === "markdown";
267
267
  const text = useFileText(ready && reads ? file : null, ready && reads ? src : null);
268
268
  const objectUrl = useObjectUrl(ready && !reads ? file : null, kind === "pdf" ? "application/pdf" : void 0);
269
- const pending = /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTP74SBRHcjs.PreviewStage, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTP74SBRHcjs.PreviewLoading, { label: loadingLabel }) });
270
- const failed = (message) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTP74SBRHcjs.PreviewStage, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTP74SBRHcjs.PreviewNotice, { icon: _lucidereact.FileWarning, alert: true, message, children: _nullishCoalesce(fallback, () => ( download)) }) });
269
+ const pending = /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkE2UVQXBOcjs.PreviewStage, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkE2UVQXBOcjs.PreviewLoading, { label: loadingLabel }) });
270
+ const failed = (message) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkE2UVQXBOcjs.PreviewStage, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkE2UVQXBOcjs.PreviewNotice, { icon: _lucidereact.FileWarning, alert: true, message, children: _nullishCoalesce(fallback, () => ( download)) }) });
271
271
  if (loading) return pending;
272
272
  if (error) return failed(error);
273
273
  if (kind === "none" || !file && !src) {
274
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTP74SBRHcjs.PreviewStage, { children: _nullishCoalesce(fallback, () => ( /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTP74SBRHcjs.PreviewNotice, { icon: _lucidereact.FileQuestion, message: unavailableLabel, children: download }))) });
274
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkE2UVQXBOcjs.PreviewStage, { children: _nullishCoalesce(fallback, () => ( /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkE2UVQXBOcjs.PreviewNotice, { icon: _lucidereact.FileQuestion, message: unavailableLabel, children: download }))) });
275
275
  }
276
276
  if (reads) {
277
277
  if (!text || text.status === "reading") return pending;
278
278
  if (text.status === "failed") return failed(failedLabel);
279
- return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkTP74SBRHcjs.PreviewStage, { layout: "scroll", label: `Preview of ${title}`, children: [
279
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkE2UVQXBOcjs.PreviewStage, { layout: "scroll", label: `Preview of ${title}`, children: [
280
280
  text.truncated && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk373W6VADcjs.Text, { variant: "caption", marginBottom: "sm", children: truncatedLabel }),
281
281
  kind === "markdown" ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkKENBU3NVcjs.LazyMarkdown, { components: { a: NewTabLink, ...markdownComponents }, children: text.text }) : (
282
282
  // The theme's relaxed leading is a fixed 1.8rem, which spaces a
@@ -300,13 +300,13 @@ function ShownFile({
300
300
  const fail = () => setBroken(true);
301
301
  const label = `Preview of ${title}`;
302
302
  if (kind === "image") {
303
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTP74SBRHcjs.PreviewStage, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex h-full w-full items-center justify-center p-4", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4UUTKR3Vcjs.Image, { src: url, alt: title, fit: "contain", radius: "sm", className: "max-h-full max-w-full", onError: fail }) }) });
303
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkE2UVQXBOcjs.PreviewStage, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex h-full w-full items-center justify-center p-4", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk4UUTKR3Vcjs.Image, { src: url, alt: title, fit: "contain", radius: "sm", className: "max-h-full max-w-full", onError: fail }) }) });
304
304
  }
305
305
  if (kind === "audio") {
306
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTP74SBRHcjs.PreviewStage, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "w-full max-w-md p-6", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "audio", { src: url, controls: true, preload: "metadata", "aria-label": label, className: "w-full", onError: fail }) }) });
306
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkE2UVQXBOcjs.PreviewStage, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "w-full max-w-md p-6", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "audio", { src: url, controls: true, preload: "metadata", "aria-label": label, className: "w-full", onError: fail }) }) });
307
307
  }
308
308
  if (kind === "video") {
309
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTP74SBRHcjs.PreviewStage, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex h-full w-full items-center justify-center p-4", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
309
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkE2UVQXBOcjs.PreviewStage, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex h-full w-full items-center justify-center p-4", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
310
310
  "video",
311
311
  {
312
312
  src: url,
@@ -319,7 +319,7 @@ function ShownFile({
319
319
  }
320
320
  ) }) });
321
321
  }
322
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkTP74SBRHcjs.PreviewStage, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "iframe", { src: url, title: label, referrerPolicy: "no-referrer", className: "h-full w-full border-0 bg-background" }) });
322
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkE2UVQXBOcjs.PreviewStage, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "iframe", { src: url, title: label, referrerPolicy: "no-referrer", className: "h-full w-full border-0 bg-background" }) });
323
323
  }
324
324
 
325
325
 
@@ -8,14 +8,14 @@ import {
8
8
  PreviewLoading,
9
9
  PreviewNotice,
10
10
  PreviewStage
11
- } from "../chunk-C3VZMTVB.js";
12
- import "../chunk-JTI4244T.js";
13
- import "../chunk-4HWCNRK4.js";
11
+ } from "../chunk-FPOJ2NGG.js";
12
+ import "../chunk-CRZ4INEJ.js";
14
13
  import "../chunk-3QT5VYZ3.js";
15
14
  import {
16
15
  LazyMarkdown
17
16
  } from "../chunk-VY5U4VGV.js";
18
17
  import "../chunk-INNGGLMZ.js";
18
+ import "../chunk-4HWCNRK4.js";
19
19
  import {
20
20
  CodeBlock
21
21
  } from "../chunk-HTPPNW74.js";
@@ -11,8 +11,8 @@
11
11
 
12
12
 
13
13
 
14
- var _chunkHSSSNAVXcjs = require('../chunk-HSSSNAVX.cjs');
15
- require('../chunk-6AMSRIQ4.cjs');
14
+ var _chunk23IETCLVcjs = require('../chunk-23IETCLV.cjs');
15
+ require('../chunk-DMPSKGFM.cjs');
16
16
  require('../chunk-Z2H4LJVG.cjs');
17
17
  require('../chunk-WABCLRBR.cjs');
18
18
  require('../chunk-JDEXZGIY.cjs');
@@ -28,4 +28,4 @@ require('../chunk-KWLSBTB2.cjs');
28
28
 
29
29
 
30
30
 
31
- exports.MessageScroller = _chunkHSSSNAVXcjs.MessageScroller; exports.MessageScrollerButton = _chunkHSSSNAVXcjs.MessageScrollerButton; exports.MessageScrollerContent = _chunkHSSSNAVXcjs.MessageScrollerContent; exports.MessageScrollerItem = _chunkHSSSNAVXcjs.MessageScrollerItem; exports.MessageScrollerNavigator = _chunkHSSSNAVXcjs.MessageScrollerNavigator; exports.MessageScrollerProvider = _chunkHSSSNAVXcjs.MessageScrollerProvider; exports.MessageScrollerViewport = _chunkHSSSNAVXcjs.MessageScrollerViewport; exports.useMessageScroller = _chunkHSSSNAVXcjs.useMessageScroller; exports.useMessageScrollerScrollable = _chunkHSSSNAVXcjs.useMessageScrollerScrollable; exports.useMessageScrollerVisibility = _chunkHSSSNAVXcjs.useMessageScrollerVisibility;
31
+ exports.MessageScroller = _chunk23IETCLVcjs.MessageScroller; exports.MessageScrollerButton = _chunk23IETCLVcjs.MessageScrollerButton; exports.MessageScrollerContent = _chunk23IETCLVcjs.MessageScrollerContent; exports.MessageScrollerItem = _chunk23IETCLVcjs.MessageScrollerItem; exports.MessageScrollerNavigator = _chunk23IETCLVcjs.MessageScrollerNavigator; exports.MessageScrollerProvider = _chunk23IETCLVcjs.MessageScrollerProvider; exports.MessageScrollerViewport = _chunk23IETCLVcjs.MessageScrollerViewport; exports.useMessageScroller = _chunk23IETCLVcjs.useMessageScroller; exports.useMessageScrollerScrollable = _chunk23IETCLVcjs.useMessageScrollerScrollable; exports.useMessageScrollerVisibility = _chunk23IETCLVcjs.useMessageScrollerVisibility;
@@ -11,8 +11,8 @@ import {
11
11
  useMessageScroller,
12
12
  useMessageScrollerScrollable,
13
13
  useMessageScrollerVisibility
14
- } from "../chunk-EXXJXOUO.js";
15
- import "../chunk-V3XA7SDK.js";
14
+ } from "../chunk-OUZSIA5G.js";
15
+ import "../chunk-36LNA4WM.js";
16
16
  import "../chunk-GA5SX7FE.js";
17
17
  import "../chunk-3OWGL4Q2.js";
18
18
  import "../chunk-W326GKML.js";
@@ -9,9 +9,9 @@
9
9
 
10
10
 
11
11
 
12
- var _chunkBTHYGHOHcjs = require('../chunk-BTHYGHOH.cjs');
13
- require('../chunk-2BHI5ZWJ.cjs');
12
+ var _chunkAO56ET4Fcjs = require('../chunk-AO56ET4F.cjs');
14
13
  require('../chunk-WDXEJDMO.cjs');
14
+ require('../chunk-2BHI5ZWJ.cjs');
15
15
  require('../chunk-KWLSBTB2.cjs');
16
16
 
17
17
 
@@ -23,4 +23,4 @@ require('../chunk-KWLSBTB2.cjs');
23
23
 
24
24
 
25
25
 
26
- exports.ResponsiveDialog = _chunkBTHYGHOHcjs.ResponsiveDialog; exports.ResponsiveDialogBody = _chunkBTHYGHOHcjs.ResponsiveDialogBody; exports.ResponsiveDialogClose = _chunkBTHYGHOHcjs.ResponsiveDialogClose; exports.ResponsiveDialogContent = _chunkBTHYGHOHcjs.ResponsiveDialogContent; exports.ResponsiveDialogDescription = _chunkBTHYGHOHcjs.ResponsiveDialogDescription; exports.ResponsiveDialogFooter = _chunkBTHYGHOHcjs.ResponsiveDialogFooter; exports.ResponsiveDialogHeader = _chunkBTHYGHOHcjs.ResponsiveDialogHeader; exports.ResponsiveDialogTitle = _chunkBTHYGHOHcjs.ResponsiveDialogTitle; exports.ResponsiveDialogTrigger = _chunkBTHYGHOHcjs.ResponsiveDialogTrigger;
26
+ exports.ResponsiveDialog = _chunkAO56ET4Fcjs.ResponsiveDialog; exports.ResponsiveDialogBody = _chunkAO56ET4Fcjs.ResponsiveDialogBody; exports.ResponsiveDialogClose = _chunkAO56ET4Fcjs.ResponsiveDialogClose; exports.ResponsiveDialogContent = _chunkAO56ET4Fcjs.ResponsiveDialogContent; exports.ResponsiveDialogDescription = _chunkAO56ET4Fcjs.ResponsiveDialogDescription; exports.ResponsiveDialogFooter = _chunkAO56ET4Fcjs.ResponsiveDialogFooter; exports.ResponsiveDialogHeader = _chunkAO56ET4Fcjs.ResponsiveDialogHeader; exports.ResponsiveDialogTitle = _chunkAO56ET4Fcjs.ResponsiveDialogTitle; exports.ResponsiveDialogTrigger = _chunkAO56ET4Fcjs.ResponsiveDialogTrigger;
@@ -9,9 +9,9 @@ import {
9
9
  ResponsiveDialogHeader,
10
10
  ResponsiveDialogTitle,
11
11
  ResponsiveDialogTrigger
12
- } from "../chunk-JTI4244T.js";
13
- import "../chunk-4HWCNRK4.js";
12
+ } from "../chunk-CRZ4INEJ.js";
14
13
  import "../chunk-3QT5VYZ3.js";
14
+ import "../chunk-4HWCNRK4.js";
15
15
  import "../chunk-G6SRSWXB.js";
16
16
  export {
17
17
  ResponsiveDialog,
@@ -2,10 +2,10 @@
2
2
  "use client";
3
3
 
4
4
 
5
- var _chunk6AMSRIQ4cjs = require('../chunk-6AMSRIQ4.cjs');
5
+ var _chunkDMPSKGFMcjs = require('../chunk-DMPSKGFM.cjs');
6
6
  require('../chunk-Z2H4LJVG.cjs');
7
7
  require('../chunk-WABCLRBR.cjs');
8
8
  require('../chunk-KWLSBTB2.cjs');
9
9
 
10
10
 
11
- exports.ScrollNavigator = _chunk6AMSRIQ4cjs.ScrollNavigator;
11
+ exports.ScrollNavigator = _chunkDMPSKGFMcjs.ScrollNavigator;
@@ -18,6 +18,8 @@ interface ScrollNavigatorScrollOptions {
18
18
  interface ScrollNavigatorProps extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
19
19
  items: readonly ScrollNavigatorItem[];
20
20
  label?: string;
21
+ /** Translucent, blurred floating controls with a solid fallback. Cards are unchanged. */
22
+ frosted?: boolean;
21
23
  /** Card columns above the small breakpoint; always one column on mobile. */
22
24
  columns?: 1 | 2 | 3 | 4;
23
25
  /** Space below a sticky header inside the scroll viewport, in pixels. */
@@ -18,6 +18,8 @@ interface ScrollNavigatorScrollOptions {
18
18
  interface ScrollNavigatorProps extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
19
19
  items: readonly ScrollNavigatorItem[];
20
20
  label?: string;
21
+ /** Translucent, blurred floating controls with a solid fallback. Cards are unchanged. */
22
+ frosted?: boolean;
21
23
  /** Card columns above the small breakpoint; always one column on mobile. */
22
24
  columns?: 1 | 2 | 3 | 4;
23
25
  /** Space below a sticky header inside the scroll viewport, in pixels. */
@@ -2,7 +2,7 @@
2
2
  "use client";
3
3
  import {
4
4
  ScrollNavigator
5
- } from "../chunk-V3XA7SDK.js";
5
+ } from "../chunk-36LNA4WM.js";
6
6
  import "../chunk-GA5SX7FE.js";
7
7
  import "../chunk-3OWGL4Q2.js";
8
8
  import "../chunk-G6SRSWXB.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@epicbagel/saas-kit",
3
- "version": "1.18.0",
3
+ "version": "1.20.0",
4
4
  "description": "Accessible React primitives, layout components and design tokens for SaaS apps, built on Radix UI and Tailwind CSS v4.",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -0,0 +1,38 @@
1
+ /* Opt-in chrome surfaces. Complete semantic colours keep every palette and
2
+ * mode working; unsupported blur, reduced transparency and forced colours
3
+ * retain an opaque, readable surface. No sizing or positioning lives here. */
4
+ @layer components {
5
+ [data-frosted-surface="background"] { --color-frosted-surface: var(--color-background); }
6
+ [data-frosted-surface="card"] { --color-frosted-surface: var(--color-card); }
7
+ [data-frosted-surface="muted"] { --color-frosted-surface: var(--color-muted); }
8
+
9
+ [data-frosted-surface] {
10
+ background-color: var(--color-frosted-surface);
11
+ }
12
+
13
+ @supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
14
+ [data-frosted-surface] {
15
+ background-color: color-mix(in oklab, var(--color-frosted-surface) 70%, transparent);
16
+ -webkit-backdrop-filter: blur(16px);
17
+ backdrop-filter: blur(16px);
18
+ }
19
+ }
20
+
21
+ @media (prefers-reduced-transparency: reduce) {
22
+ [data-frosted-surface] {
23
+ background-color: var(--color-frosted-surface);
24
+ -webkit-backdrop-filter: none;
25
+ backdrop-filter: none;
26
+ }
27
+ }
28
+
29
+ @media (forced-colors: active) {
30
+ [data-frosted-surface] {
31
+ background-color: Canvas;
32
+ color: CanvasText;
33
+ border-color: CanvasText;
34
+ -webkit-backdrop-filter: none;
35
+ backdrop-filter: none;
36
+ }
37
+ }
38
+ }
@@ -4,3 +4,4 @@
4
4
  @import "./components/marker.css";
5
5
  @import "./components/message.css";
6
6
  @import "./components/message-scroller.css";
7
+ @import "./components/frosted-surface.css";
@@ -8,7 +8,7 @@
8
8
 
9
9
 
10
10
 
11
- var _chunk2BHI5ZWJcjs = require('./chunk-2BHI5ZWJ.cjs');
11
+ var _chunkWDXEJDMOcjs = require('./chunk-WDXEJDMO.cjs');
12
12
 
13
13
 
14
14
 
@@ -18,7 +18,7 @@ var _chunk2BHI5ZWJcjs = require('./chunk-2BHI5ZWJ.cjs');
18
18
 
19
19
 
20
20
 
21
- var _chunkWDXEJDMOcjs = require('./chunk-WDXEJDMO.cjs');
21
+ var _chunk2BHI5ZWJcjs = require('./chunk-2BHI5ZWJ.cjs');
22
22
 
23
23
 
24
24
  var _chunkKWLSBTB2cjs = require('./chunk-KWLSBTB2.cjs');
@@ -1,14 +1,4 @@
1
1
  "use client";
2
- import {
3
- Drawer,
4
- DrawerClose,
5
- DrawerContent,
6
- DrawerDescription,
7
- DrawerFooter,
8
- DrawerHeader,
9
- DrawerTitle,
10
- DrawerTrigger
11
- } from "./chunk-4HWCNRK4.js";
12
2
  import {
13
3
  Dialog,
14
4
  DialogClose,
@@ -19,6 +9,16 @@ import {
19
9
  DialogTitle,
20
10
  DialogTrigger
21
11
  } from "./chunk-3QT5VYZ3.js";
12
+ import {
13
+ Drawer,
14
+ DrawerClose,
15
+ DrawerContent,
16
+ DrawerDescription,
17
+ DrawerFooter,
18
+ DrawerHeader,
19
+ DrawerTitle,
20
+ DrawerTrigger
21
+ } from "./chunk-4HWCNRK4.js";
22
22
  import {
23
23
  cn
24
24
  } from "./chunk-G6SRSWXB.js";