@epicbagel/saas-kit 1.15.0 → 1.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -42,16 +42,20 @@ does not import a voice provider. Stop and release audio tracks before setting
42
42
  Wrap the application in `DictationProvider` to use an authenticated transcription
43
43
  API for every `VoiceDictationButton`, including buttons nested in chat, forms or
44
44
  another component library. The recorder opens beside its microphone on desktop
45
- and fills the screen below 768px, with elapsed time, LiveKit audio bars and
46
- Done/Cancel controls. The bars use the recording stream without opening a second
47
- microphone. Resizing keeps the current recording alive.
45
+ and fills the screen below 768px. Its roomy panel puts the title and close control
46
+ above a microphone, live audio bars and elapsed time, followed by the transcript
47
+ and Done/Cancel controls. The microphone and bars share the palette's first chart
48
+ colour; surfaces and buttons keep their normal theme. The bars use the recording
49
+ stream without opening a second microphone; native recognition has no meter and
50
+ shows no waveform. No device selector is shown because the capture API does not
51
+ offer device selection. Resizing keeps the current recording alive.
48
52
 
49
53
  For hidden/programmatic triggers, it uses the focused visible button as the
50
54
  desktop anchor. Hosts can pass an explicit `anchorRef` for a custom trigger.
51
55
  Without a visible anchor it opens full-screen. Nested and sibling dialogs keep
52
56
  their focus and cancellation behavior.
53
57
  The recorder runs until **Done**, finishes the last words, then commits the returned text once. Failed requests keep the
54
- take available for retry. Cancel stops microphone tracks, aborts the request and
58
+ take available for retry. Cancel and the header's close control stop microphone tracks, abort the request and
55
59
  ignores a late answer. The kit never persists audio or knows provider credentials.
56
60
 
57
61
  ```tsx
@@ -448,6 +452,11 @@ with stable `id`, accessible `label`, optional `imageSrc`/`fallback`, and
448
452
  visible. The item at the top of the scroll viewport is highlighted; the index
449
453
  scrolls independently for long lists. With insufficient left gutter, it uses
450
454
  a compact horizontal row above the content. Single-item lists have no index.
455
+ Set `columns` for a responsive card grid (one column on mobile). The first card
456
+ in the row at the reading edge is highlighted; changing columns preserves each
457
+ card's local state.
458
+ The available gutter stays within the outer main content landmark, so the
459
+ index never counts an application's sidebar as free space.
451
460
 
452
461
  It detects the nearest scrolling ancestor, supports an explicit `scrollRoot`
453
462
  and `topOffset` for sticky headers, and offers `onNavigate` for custom scroll
@@ -1,6 +1,9 @@
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 _chunkZ2H4LJVGcjs = require('./chunk-Z2H4LJVG.cjs');
5
+
6
+
4
7
 
5
8
 
6
9
  var _chunkWABCLRBRcjs = require('./chunk-WABCLRBR.cjs');
@@ -22,7 +25,7 @@ function findScrollRoot(element) {
22
25
  }
23
26
  return null;
24
27
  }
25
- function viewportBounds(root) {
28
+ function viewportBounds(root, element) {
26
29
  const viewport = window.visualViewport;
27
30
  const top = _nullishCoalesce(_optionalChain([viewport, 'optionalAccess', _ => _.offsetTop]), () => ( 0));
28
31
  const left = _nullishCoalesce(_optionalChain([viewport, 'optionalAccess', _2 => _2.offsetLeft]), () => ( 0));
@@ -36,11 +39,21 @@ function viewportBounds(root) {
36
39
  bounds.right = Math.min(bounds.right, rect.left + parent.clientLeft + parent.clientWidth);
37
40
  bounds.bottom = Math.min(bounds.bottom, rect.top + parent.clientTop + parent.clientHeight);
38
41
  }
42
+ let landmark = _optionalChain([element, 'optionalAccess', _5 => _5.closest, 'call', _6 => _6("main, [role='main']")]);
43
+ for (let parent = _optionalChain([landmark, 'optionalAccess', _7 => _7.parentElement, 'optionalAccess', _8 => _8.closest, 'call', _9 => _9("main, [role='main']")]); parent; parent = _optionalChain([parent, 'access', _10 => _10.parentElement, 'optionalAccess', _11 => _11.closest, 'call', _12 => _12("main, [role='main']")])) {
44
+ landmark = parent;
45
+ }
46
+ if (landmark) {
47
+ const rect = landmark.getBoundingClientRect();
48
+ bounds.left = Math.max(bounds.left, rect.left);
49
+ bounds.right = Math.min(bounds.right, rect.right);
50
+ }
39
51
  return bounds;
40
52
  }
41
53
  var ScrollNavigator = _react.forwardRef.call(void 0, function ScrollNavigator2({
42
54
  items,
43
55
  label = "Browse items",
56
+ columns = 1,
44
57
  topOffset = 0,
45
58
  scrollRoot,
46
59
  onNavigate,
@@ -70,14 +83,14 @@ var ScrollNavigator = _react.forwardRef.call(void 0, function ScrollNavigator2({
70
83
  }
71
84
  const scrollElement = scrollRoot === void 0 ? findScrollRoot(element) : scrollRoot;
72
85
  scroller.current = scrollElement;
73
- const view = viewportBounds(scrollElement);
86
+ const view = viewportBounds(scrollElement, element);
74
87
  const box = element.getBoundingClientRect();
75
88
  const mode = box.left - view.left >= RAIL_WIDTH + GAP ? "rail" : "row";
76
89
  const top = Math.max(view.top + topOffset + GAP, box.top);
77
90
  const bottom = Math.min(view.bottom, box.bottom) - GAP;
78
91
  const visible = box.width > 0 && box.right > view.left && box.left < view.right && bottom - top >= ROW_HEIGHT;
79
92
  const readingEdge = view.top + topOffset + GAP + (mode === "row" ? ROW_HEIGHT : 0);
80
- const active = visible ? Math.max(0, items.findIndex((item) => (_nullishCoalesce(_optionalChain([targets, 'access', _5 => _5.current, 'access', _6 => _6.get, 'call', _7 => _7(item.id), 'optionalAccess', _8 => _8.getBoundingClientRect, 'call', _9 => _9(), 'access', _10 => _10.bottom]), () => ( 0))) > readingEdge + 1)) : 0;
93
+ const active = visible ? Math.max(0, items.findIndex((item) => (_nullishCoalesce(_optionalChain([targets, 'access', _13 => _13.current, 'access', _14 => _14.get, 'call', _15 => _15(item.id), 'optionalAccess', _16 => _16.getBoundingClientRect, 'call', _17 => _17(), 'access', _18 => _18.bottom]), () => ( 0))) > readingEdge + 1)) : 0;
81
94
  const next = {
82
95
  mode,
83
96
  top,
@@ -93,33 +106,33 @@ var ScrollNavigator = _react.forwardRef.call(void 0, function ScrollNavigator2({
93
106
  if (!frame) frame = requestAnimationFrame(measure);
94
107
  };
95
108
  const visibility = typeof IntersectionObserver === "undefined" ? null : new IntersectionObserver((entries) => {
96
- intersects = _nullishCoalesce(_optionalChain([entries, 'access', _11 => _11[entries.length - 1], 'optionalAccess', _12 => _12.isIntersecting]), () => ( intersects));
109
+ intersects = _nullishCoalesce(_optionalChain([entries, 'access', _19 => _19[entries.length - 1], 'optionalAccess', _20 => _20.isIntersecting]), () => ( intersects));
97
110
  schedule();
98
111
  });
99
- _optionalChain([visibility, 'optionalAccess', _13 => _13.observe, 'call', _14 => _14(element)]);
112
+ _optionalChain([visibility, 'optionalAccess', _21 => _21.observe, 'call', _22 => _22(element)]);
100
113
  const resize = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(schedule);
101
114
  for (let parent = element; parent; parent = parent.parentElement) {
102
- _optionalChain([resize, 'optionalAccess', _15 => _15.observe, 'call', _16 => _16(parent)]);
115
+ _optionalChain([resize, 'optionalAccess', _23 => _23.observe, 'call', _24 => _24(parent)]);
103
116
  }
104
- targets.current.forEach((target) => _optionalChain([resize, 'optionalAccess', _17 => _17.observe, 'call', _18 => _18(target)]));
117
+ targets.current.forEach((target) => _optionalChain([resize, 'optionalAccess', _25 => _25.observe, 'call', _26 => _26(target)]));
105
118
  document.addEventListener("scroll", schedule, { passive: true, capture: true });
106
119
  window.addEventListener("resize", schedule);
107
- _optionalChain([window, 'access', _19 => _19.visualViewport, 'optionalAccess', _20 => _20.addEventListener, 'call', _21 => _21("resize", schedule)]);
108
- _optionalChain([window, 'access', _22 => _22.visualViewport, 'optionalAccess', _23 => _23.addEventListener, 'call', _24 => _24("scroll", schedule)]);
120
+ _optionalChain([window, 'access', _27 => _27.visualViewport, 'optionalAccess', _28 => _28.addEventListener, 'call', _29 => _29("resize", schedule)]);
121
+ _optionalChain([window, 'access', _30 => _30.visualViewport, 'optionalAccess', _31 => _31.addEventListener, 'call', _32 => _32("scroll", schedule)]);
109
122
  measure();
110
123
  return () => {
111
124
  cancelAnimationFrame(frame);
112
- _optionalChain([resize, 'optionalAccess', _25 => _25.disconnect, 'call', _26 => _26()]);
113
- _optionalChain([visibility, 'optionalAccess', _27 => _27.disconnect, 'call', _28 => _28()]);
125
+ _optionalChain([resize, 'optionalAccess', _33 => _33.disconnect, 'call', _34 => _34()]);
126
+ _optionalChain([visibility, 'optionalAccess', _35 => _35.disconnect, 'call', _36 => _36()]);
114
127
  document.removeEventListener("scroll", schedule, true);
115
128
  window.removeEventListener("resize", schedule);
116
- _optionalChain([window, 'access', _29 => _29.visualViewport, 'optionalAccess', _30 => _30.removeEventListener, 'call', _31 => _31("resize", schedule)]);
117
- _optionalChain([window, 'access', _32 => _32.visualViewport, 'optionalAccess', _33 => _33.removeEventListener, 'call', _34 => _34("scroll", schedule)]);
129
+ _optionalChain([window, 'access', _37 => _37.visualViewport, 'optionalAccess', _38 => _38.removeEventListener, 'call', _39 => _39("resize", schedule)]);
130
+ _optionalChain([window, 'access', _40 => _40.visualViewport, 'optionalAccess', _41 => _41.removeEventListener, 'call', _42 => _42("scroll", schedule)]);
118
131
  };
119
- }, [keys, navigable, topOffset, scrollRoot]);
132
+ }, [keys, navigable, columns, topOffset, scrollRoot]);
120
133
  _react.useEffect.call(void 0, () => {
121
134
  const index = indexRef.current;
122
- const button = controls.current.get(_nullishCoalesce(_nullishCoalesce(focusId, () => ( _optionalChain([items, 'access', _35 => _35[placement.active], 'optionalAccess', _36 => _36.id]))), () => ( "")));
135
+ const button = controls.current.get(_nullishCoalesce(_nullishCoalesce(focusId, () => ( _optionalChain([items, 'access', _43 => _43[placement.active], 'optionalAccess', _44 => _44.id]))), () => ( "")));
123
136
  if (!index || !button || !placement.visible) return;
124
137
  const horizontal = placement.mode === "row";
125
138
  const start = horizontal ? button.offsetLeft : button.offsetTop;
@@ -137,14 +150,14 @@ var ScrollNavigator = _react.forwardRef.call(void 0, function ScrollNavigator2({
137
150
  offset: topOffset + GAP + (placement.mode === "row" ? ROW_HEIGHT : 0),
138
151
  behavior: window.matchMedia("(prefers-reduced-motion: reduce)").matches ? "instant" : "smooth"
139
152
  };
140
- if (_optionalChain([onNavigate, 'optionalCall', _37 => _37(item.id, target, options)]) === true) return;
153
+ if (_optionalChain([onNavigate, 'optionalCall', _45 => _45(item.id, target, options)]) === true) return;
141
154
  const scrollElement = scroller.current;
142
- const view = viewportBounds(scrollElement);
143
- const top = (_nullishCoalesce(_optionalChain([scrollElement, 'optionalAccess', _38 => _38.scrollTop]), () => ( window.scrollY))) + target.getBoundingClientRect().top - view.top - options.offset;
155
+ const view = viewportBounds(scrollElement, rootRef.current);
156
+ const top = (_nullishCoalesce(_optionalChain([scrollElement, 'optionalAccess', _46 => _46.scrollTop]), () => ( window.scrollY))) + target.getBoundingClientRect().top - view.top - options.offset;
144
157
  if (scrollElement) scrollElement.scrollTo({ top, behavior: options.behavior });
145
158
  else window.scrollTo({ top, behavior: options.behavior });
146
159
  }
147
- const activeId = _optionalChain([items, 'access', _39 => _39[placement.active], 'optionalAccess', _40 => _40.id]);
160
+ const activeId = _optionalChain([items, 'access', _47 => _47[placement.active], 'optionalAccess', _48 => _48.id]);
148
161
  const tabId = focusId && items.some((item) => item.id === focusId) ? focusId : activeId;
149
162
  const row = placement.mode === "row";
150
163
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
@@ -160,7 +173,7 @@ var ScrollNavigator = _react.forwardRef.call(void 0, function ScrollNavigator2({
160
173
  },
161
174
  className: _chunkKWLSBTB2cjs.cn.call(void 0, "relative min-w-0", navigable && row && "pt-16", className),
162
175
  children: [
163
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex min-w-0 flex-col gap-4", children: items.map((item, index) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
176
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkZ2H4LJVGcjs.Grid, { columns, gap: "md", responsive: true, className: "min-w-0", children: items.map((item, index) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
164
177
  "div",
165
178
  {
166
179
  id: `${id}-${index}`,
@@ -204,7 +217,7 @@ var ScrollNavigator = _react.forwardRef.call(void 0, function ScrollNavigator2({
204
217
  else return;
205
218
  event.preventDefault();
206
219
  const button = controls.current.get(items[next].id);
207
- _optionalChain([button, 'optionalAccess', _41 => _41.focus, 'call', _42 => _42({ preventScroll: true })]);
220
+ _optionalChain([button, 'optionalAccess', _49 => _49.focus, 'call', _50 => _50({ preventScroll: true })]);
208
221
  const index = indexRef.current;
209
222
  if (index && button) {
210
223
  if (row) index.scrollLeft = button.offsetLeft - (index.clientWidth - button.offsetWidth) / 2;
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  ScrollNavigator
4
- } from "./chunk-VT2WDFSU.js";
4
+ } from "./chunk-V3XA7SDK.js";
5
5
  import {
6
6
  Button
7
7
  } from "./chunk-W326GKML.js";
@@ -0,0 +1,48 @@
1
+ "use client";
2
+ import {
3
+ cn
4
+ } from "./chunk-G6SRSWXB.js";
5
+
6
+ // src/primitives/grid.tsx
7
+ import { forwardRef } from "react";
8
+ import { jsx } from "react/jsx-runtime";
9
+ var fixedColumns = {
10
+ 1: "grid-cols-1",
11
+ 2: "grid-cols-2",
12
+ 3: "grid-cols-3",
13
+ 4: "grid-cols-4"
14
+ };
15
+ var responsiveColumns = {
16
+ 1: "grid-cols-1",
17
+ 2: "grid-cols-1 sm:grid-cols-2",
18
+ 3: "grid-cols-1 sm:grid-cols-3",
19
+ 4: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4"
20
+ };
21
+ var gaps = { sm: "gap-2", compact: "gap-3", md: "gap-4", lg: "gap-6" };
22
+ var Grid = forwardRef(function Grid2({ columns = 2, gap = "md", responsive = true, layout = "grid", maxWidth = "none", centered = false, template = "equal", as, className, ...props }, ref) {
23
+ const Component = as ?? "div";
24
+ return /* @__PURE__ */ jsx(
25
+ Component,
26
+ {
27
+ ref,
28
+ className: cn(
29
+ layout === "grid" ? "grid" : "grid sm:flex sm:justify-end",
30
+ layout === "grid" && template === "equal" && columns !== null && (responsive ? responsiveColumns[columns] : fixedColumns[columns]),
31
+ layout === "responsive-actions" && columns !== null && fixedColumns[columns],
32
+ template === "compact-leading-three" && "grid-cols-[5rem_1fr_1fr]",
33
+ template === "responsive-form-row-six" && "grid-cols-1 items-center sm:grid-cols-[1fr_1.4fr_1fr_1fr_1fr_auto]",
34
+ template === "master-detail" && "grid-cols-1 lg:grid-cols-[360px_1fr]",
35
+ template === "gallery" && "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
36
+ gaps[gap],
37
+ maxWidth === "xl" && "max-w-2xl",
38
+ centered && "mx-auto",
39
+ className
40
+ ),
41
+ ...props
42
+ }
43
+ );
44
+ });
45
+
46
+ export {
47
+ Grid
48
+ };
@@ -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 _chunk34AS3OCCcjs = require('./chunk-34AS3OCC.cjs');
4
+ var _chunk6AMSRIQ4cjs = require('./chunk-6AMSRIQ4.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, _chunk34AS3OCCcjs.ScrollNavigator, { ...props, onNavigate: (id, target, options) => {
26
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk6AMSRIQ4cjs.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]);
@@ -118,40 +118,72 @@ function VoiceDictationButton({
118
118
  }
119
119
  };
120
120
  const content = /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
121
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkKWLSBTB2cjs.cn.call(void 0, "flex min-w-0 items-start justify-between gap-3", !anchored && "w-full max-w-xl self-center"), children: [
122
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "min-w-0 space-y-1", children: [
123
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: _chunkKWLSBTB2cjs.cn.call(void 0, "font-medium", anchored ? "text-sm" : "text-lg"), children: title || "Voice dictation" }),
124
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { role: "status", className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
125
- busy ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.LoaderCircle, { "aria-hidden": "true", className: "size-3.5 animate-spin motion-reduce:animate-none" }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Mic, { "aria-hidden": "true", className: "size-3.5" }),
121
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkKWLSBTB2cjs.cn.call(void 0, "flex min-w-0 shrink-0 items-start justify-between gap-4", !anchored && "w-full max-w-xl self-center"), children: [
122
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "min-w-0 space-y-2 pt-1", children: [
123
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "h2", { className: "break-words text-xl font-semibold leading-tight", children: title || "Voice dictation" }),
124
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { role: "status", className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
125
+ busy && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.LoaderCircle, { "aria-hidden": "true", className: "size-4 shrink-0 animate-spin motion-reduce:animate-none" }),
126
126
  capture.state === "transcribing" ? "Finishing transcript\u2026" : capture.state === "requesting" ? "Starting dictation\u2026" : error ? "Recording not saved" : capture.state === "ready" ? "Ready" : caption
127
127
  ] })
128
128
  ] }),
129
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "time", { "aria-label": "Recording duration", dateTime: `PT${elapsed}S`, className: "pt-0.5 font-mono text-xs tabular-nums text-muted-foreground", children: [
130
- Math.floor(elapsed / 60).toString().padStart(2, "0"),
131
- ":",
132
- (elapsed % 60).toString().padStart(2, "0")
133
- ] })
129
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
130
+ _chunkJDEXZGIYcjs.Button,
131
+ {
132
+ type: "button",
133
+ variant: "ghost",
134
+ size: "icon",
135
+ shape: "circle",
136
+ "aria-label": "Cancel dictation",
137
+ className: "size-[44px] shrink-0 text-muted-foreground [&_svg]:size-5",
138
+ onClick: handleCancel,
139
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.X, { "aria-hidden": "true", className: "size-5" })
140
+ }
141
+ )
134
142
  ] }),
135
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkKWLSBTB2cjs.cn.call(void 0, "flex min-h-0 flex-col gap-3", !anchored && "w-full max-w-xl flex-1 justify-center self-center py-8 text-center"), children: [
136
- capture.audioLevels && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DictationWaveform, { source: capture.audioLevels, state: capture.state, className: !anchored ? "h-20" : void 0 }),
137
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { id: descriptionId, className: "text-xs text-muted-foreground", children: capture.state === "transcribing" ? "Finishing your last words\u2026" : capture.state === "requesting" ? "Allow microphone access to start." : error ? capture.canRetry ? "Retry this take or record again." : "Try recording again." : "Speak, then choose Done to add the text." }),
138
- displayTranscript && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "max-h-40 overflow-y-auto text-sm leading-relaxed", children: [
143
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkKWLSBTB2cjs.cn.call(void 0, "flex flex-col gap-5", !anchored && "w-full max-w-xl flex-1 justify-center self-center py-6"), children: [
144
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { "data-slot": "dictation-meter", className: "flex min-w-0 items-center gap-3 py-5 text-[hsl(var(--chart-1))] sm:gap-5 sm:py-7", children: [
145
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
146
+ "div",
147
+ {
148
+ "aria-hidden": "true",
149
+ "data-slot": "dictation-microphone",
150
+ className: "flex size-[72px] shrink-0 items-center justify-center rounded-full bg-current/10 sm:size-[96px]",
151
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex size-[52px] items-center justify-center rounded-full bg-[hsl(var(--chart-1))] text-popover sm:size-[72px]", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Mic, { className: "size-7 sm:size-9" }) })
152
+ }
153
+ ),
154
+ capture.audioLevels && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DictationWaveform, { source: capture.audioLevels, state: capture.state }),
155
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
156
+ "time",
157
+ {
158
+ "aria-label": "Recording duration",
159
+ dateTime: `PT${elapsed}S`,
160
+ className: "ml-auto shrink-0 font-mono text-xl tabular-nums text-muted-foreground sm:text-2xl",
161
+ children: [
162
+ Math.floor(elapsed / 60).toString().padStart(2, "0"),
163
+ ":",
164
+ (elapsed % 60).toString().padStart(2, "0")
165
+ ]
166
+ }
167
+ )
168
+ ] }),
169
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { id: descriptionId, className: "text-base leading-relaxed text-muted-foreground", children: capture.state === "transcribing" ? "Finishing your last words\u2026" : capture.state === "requesting" ? "Allow microphone access to start." : error ? capture.canRetry ? "Retry this take or record again." : "Try recording again." : "Speak, then choose Done to add the text." }),
170
+ displayTranscript && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "p", { className: "max-h-48 overflow-y-auto break-words text-base leading-relaxed", children: [
139
171
  transcript,
140
172
  interim && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "text-muted-foreground", children: [
141
173
  transcript ? " " : "",
142
174
  interim
143
175
  ] })
144
176
  ] }),
145
- error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { role: "alert", className: "text-xs text-destructive", children: error }),
146
- !error && capture.previewError && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { role: "status", className: "text-xs text-muted-foreground", children: capture.previewError })
177
+ error && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { role: "alert", className: "text-sm leading-relaxed text-destructive", children: error }),
178
+ !error && capture.previewError && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "p", { role: "status", className: "text-sm leading-relaxed text-muted-foreground", children: capture.previewError })
147
179
  ] }),
148
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkKWLSBTB2cjs.cn.call(void 0, "gap-2", anchored ? "flex flex-wrap items-center justify-end" : "mt-auto grid w-full max-w-xl grid-cols-2 gap-3 self-center"), children: [
149
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJDEXZGIYcjs.Button, { ref: cancelControl, type: "button", variant: "ghost", size: "sm", className: anchored ? "min-h-[44px]" : "min-h-[48px]", onClick: handleCancel, children: "Cancel" }),
150
- capture.canRetry && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJDEXZGIYcjs.Button, { type: "button", variant: "outline", size: "sm", className: anchored ? "min-h-[44px]" : "order-first col-span-2 min-h-[48px]", onClick: () => {
180
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: _chunkKWLSBTB2cjs.cn.call(void 0, "shrink-0 gap-3 pt-2", anchored ? "flex flex-wrap items-center justify-end" : "mt-auto grid w-full max-w-xl grid-cols-[auto_minmax(0,1fr)] self-center"), children: [
181
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJDEXZGIYcjs.Button, { ref: cancelControl, type: "button", variant: "ghost", className: "min-h-[48px] px-5", onClick: handleCancel, children: "Cancel" }),
182
+ capture.canRetry && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJDEXZGIYcjs.Button, { type: "button", variant: "outline", className: _chunkKWLSBTB2cjs.cn.call(void 0, "min-h-[48px] px-5", !anchored && "order-first col-span-2"), onClick: () => {
151
183
  _optionalChain([cancelControl, 'access', _13 => _13.current, 'optionalAccess', _14 => _14.focus, 'call', _15 => _15({ preventScroll: true })]);
152
184
  void capture.start();
153
185
  }, children: "Record again" }),
154
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJDEXZGIYcjs.Button, { type: "button", size: "sm", className: anchored ? "min-h-[44px]" : "min-h-[48px]", onClick: () => void handleDone(), disabled: busy, children: capture.state === "transcribing" ? "Transcribing\u2026" : capture.canRetry ? "Retry transcription" : error ? "Try again" : "Done" })
186
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJDEXZGIYcjs.Button, { type: "button", className: "min-h-[48px] min-w-24 px-6", onClick: () => void handleDone(), disabled: busy, children: capture.state === "transcribing" ? "Transcribing\u2026" : capture.canRetry ? "Retry transcription" : error ? "Try again" : "Done" })
155
187
  ] })
156
188
  ] });
157
189
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
@@ -195,13 +227,13 @@ function VoiceDictationButton({
195
227
  "data-placement": "anchored",
196
228
  side: "top",
197
229
  align: "center",
198
- sideOffset: 8,
230
+ sideOffset: 12,
199
231
  collisionPadding: 12,
200
232
  avoidCollisions: true,
201
233
  onCloseAutoFocus: closeAutoFocus,
202
234
  onKeyDown,
203
235
  onEscapeKeyDown: (event) => event.stopPropagation(),
204
- className: "z-[200] flex max-h-[var(--radix-popover-content-available-height)] w-96 max-w-[calc(100vw-1.5rem)] flex-col gap-3 overflow-y-auto rounded-2xl border border-border bg-background p-4 text-foreground shadow-lg outline-hidden",
236
+ className: "z-[200] flex max-h-[var(--radix-popover-content-available-height)] w-[560px] max-w-[calc(100vw-24px)] flex-col gap-6 overflow-y-auto rounded-2xl border border-border bg-popover p-6 text-popover-foreground shadow-xl outline-hidden",
205
237
  children: content
206
238
  }
207
239
  ) })
@@ -221,7 +253,7 @@ function VoiceDictationButton({
221
253
  onCloseAutoFocus: closeAutoFocus,
222
254
  onKeyDown,
223
255
  onEscapeKeyDown: (event) => event.stopPropagation(),
224
- className: "fixed inset-0 z-[200] flex h-dvh w-screen flex-col gap-6 overflow-y-auto overscroll-contain bg-background px-6 pt-[max(1.5rem,env(safe-area-inset-top))] pb-[max(1.5rem,env(safe-area-inset-bottom))] text-foreground outline-hidden",
256
+ className: "fixed inset-0 z-[200] flex h-dvh w-screen flex-col gap-6 overflow-y-auto overscroll-contain bg-popover px-5 pt-[max(1.5rem,env(safe-area-inset-top))] pb-[max(1.5rem,env(safe-area-inset-bottom))] text-popover-foreground outline-hidden",
225
257
  children: [
226
258
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DialogPrimitive.Title, { className: "sr-only", children: "Voice dictation" }),
227
259
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, DialogPrimitive.Description, { className: "sr-only", children: "Record your message, then choose Done to add the text. Cancel discards the recording." }),
@@ -234,7 +266,7 @@ function VoiceDictationButton({
234
266
  }
235
267
  var SILENCE = [];
236
268
  var silence = () => SILENCE;
237
- function DictationWaveform({ source, state, className }) {
269
+ function DictationWaveform({ source, state }) {
238
270
  const bands = _react.useSyncExternalStore.call(void 0, source.subscribe, source.getSnapshot, silence);
239
271
  return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
240
272
  _chunkNKWHDI4Ccjs.AgentAudioVisualizerBar,
@@ -245,7 +277,8 @@ function DictationWaveform({ source, state, className }) {
245
277
  barCount: 24,
246
278
  state: state === "recording" ? "listening" : state === "transcribing" ? "thinking" : state === "requesting" ? "connecting" : "disconnected",
247
279
  volumeBands: state === "recording" ? bands : void 0,
248
- className: _chunkKWLSBTB2cjs.cn.call(void 0, "h-9 w-full text-foreground", className)
280
+ className: "h-[64px] min-w-0 flex-1 gap-[3px] sm:h-[88px] sm:gap-[4px]",
281
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "min-h-[4px] max-w-[6px] flex-1 rounded-full bg-current/15 transition-colors duration-200 motion-reduce:transition-none data-[lk-highlighted=true]:bg-current" })
249
282
  }
250
283
  );
251
284
  }
@@ -1,4 +1,7 @@
1
1
  "use client";
2
+ import {
3
+ Grid
4
+ } from "./chunk-GA5SX7FE.js";
2
5
  import {
3
6
  Avatar,
4
7
  AvatarFallback,
@@ -22,7 +25,7 @@ function findScrollRoot(element) {
22
25
  }
23
26
  return null;
24
27
  }
25
- function viewportBounds(root) {
28
+ function viewportBounds(root, element) {
26
29
  const viewport = window.visualViewport;
27
30
  const top = viewport?.offsetTop ?? 0;
28
31
  const left = viewport?.offsetLeft ?? 0;
@@ -36,11 +39,21 @@ function viewportBounds(root) {
36
39
  bounds.right = Math.min(bounds.right, rect.left + parent.clientLeft + parent.clientWidth);
37
40
  bounds.bottom = Math.min(bounds.bottom, rect.top + parent.clientTop + parent.clientHeight);
38
41
  }
42
+ let landmark = element?.closest("main, [role='main']");
43
+ for (let parent = landmark?.parentElement?.closest("main, [role='main']"); parent; parent = parent.parentElement?.closest("main, [role='main']")) {
44
+ landmark = parent;
45
+ }
46
+ if (landmark) {
47
+ const rect = landmark.getBoundingClientRect();
48
+ bounds.left = Math.max(bounds.left, rect.left);
49
+ bounds.right = Math.min(bounds.right, rect.right);
50
+ }
39
51
  return bounds;
40
52
  }
41
53
  var ScrollNavigator = forwardRef(function ScrollNavigator2({
42
54
  items,
43
55
  label = "Browse items",
56
+ columns = 1,
44
57
  topOffset = 0,
45
58
  scrollRoot,
46
59
  onNavigate,
@@ -70,7 +83,7 @@ var ScrollNavigator = forwardRef(function ScrollNavigator2({
70
83
  }
71
84
  const scrollElement = scrollRoot === void 0 ? findScrollRoot(element) : scrollRoot;
72
85
  scroller.current = scrollElement;
73
- const view = viewportBounds(scrollElement);
86
+ const view = viewportBounds(scrollElement, element);
74
87
  const box = element.getBoundingClientRect();
75
88
  const mode = box.left - view.left >= RAIL_WIDTH + GAP ? "rail" : "row";
76
89
  const top = Math.max(view.top + topOffset + GAP, box.top);
@@ -116,7 +129,7 @@ var ScrollNavigator = forwardRef(function ScrollNavigator2({
116
129
  window.visualViewport?.removeEventListener("resize", schedule);
117
130
  window.visualViewport?.removeEventListener("scroll", schedule);
118
131
  };
119
- }, [keys, navigable, topOffset, scrollRoot]);
132
+ }, [keys, navigable, columns, topOffset, scrollRoot]);
120
133
  useEffect(() => {
121
134
  const index = indexRef.current;
122
135
  const button = controls.current.get(focusId ?? items[placement.active]?.id ?? "");
@@ -139,7 +152,7 @@ var ScrollNavigator = forwardRef(function ScrollNavigator2({
139
152
  };
140
153
  if (onNavigate?.(item.id, target, options) === true) return;
141
154
  const scrollElement = scroller.current;
142
- const view = viewportBounds(scrollElement);
155
+ const view = viewportBounds(scrollElement, rootRef.current);
143
156
  const top = (scrollElement?.scrollTop ?? window.scrollY) + target.getBoundingClientRect().top - view.top - options.offset;
144
157
  if (scrollElement) scrollElement.scrollTo({ top, behavior: options.behavior });
145
158
  else window.scrollTo({ top, behavior: options.behavior });
@@ -160,7 +173,7 @@ var ScrollNavigator = forwardRef(function ScrollNavigator2({
160
173
  },
161
174
  className: cn("relative min-w-0", navigable && row && "pt-16", className),
162
175
  children: [
163
- /* @__PURE__ */ jsx("div", { className: "flex min-w-0 flex-col gap-4", children: items.map((item, index) => /* @__PURE__ */ jsx(
176
+ /* @__PURE__ */ jsx(Grid, { columns, gap: "md", responsive: true, className: "min-w-0", children: items.map((item, index) => /* @__PURE__ */ jsx(
164
177
  "div",
165
178
  {
166
179
  id: `${id}-${index}`,
@@ -0,0 +1,48 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }"use client";
2
+
3
+
4
+ var _chunkKWLSBTB2cjs = require('./chunk-KWLSBTB2.cjs');
5
+
6
+ // src/primitives/grid.tsx
7
+ var _react = require('react');
8
+ var _jsxruntime = require('react/jsx-runtime');
9
+ var fixedColumns = {
10
+ 1: "grid-cols-1",
11
+ 2: "grid-cols-2",
12
+ 3: "grid-cols-3",
13
+ 4: "grid-cols-4"
14
+ };
15
+ var responsiveColumns = {
16
+ 1: "grid-cols-1",
17
+ 2: "grid-cols-1 sm:grid-cols-2",
18
+ 3: "grid-cols-1 sm:grid-cols-3",
19
+ 4: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4"
20
+ };
21
+ var gaps = { sm: "gap-2", compact: "gap-3", md: "gap-4", lg: "gap-6" };
22
+ var Grid = _react.forwardRef.call(void 0, function Grid2({ columns = 2, gap = "md", responsive = true, layout = "grid", maxWidth = "none", centered = false, template = "equal", as, className, ...props }, ref) {
23
+ const Component = _nullishCoalesce(as, () => ( "div"));
24
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
25
+ Component,
26
+ {
27
+ ref,
28
+ className: _chunkKWLSBTB2cjs.cn.call(void 0,
29
+ layout === "grid" ? "grid" : "grid sm:flex sm:justify-end",
30
+ layout === "grid" && template === "equal" && columns !== null && (responsive ? responsiveColumns[columns] : fixedColumns[columns]),
31
+ layout === "responsive-actions" && columns !== null && fixedColumns[columns],
32
+ template === "compact-leading-three" && "grid-cols-[5rem_1fr_1fr]",
33
+ template === "responsive-form-row-six" && "grid-cols-1 items-center sm:grid-cols-[1fr_1.4fr_1fr_1fr_1fr_auto]",
34
+ template === "master-detail" && "grid-cols-1 lg:grid-cols-[360px_1fr]",
35
+ template === "gallery" && "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
36
+ gaps[gap],
37
+ maxWidth === "xl" && "max-w-2xl",
38
+ centered && "mx-auto",
39
+ className
40
+ ),
41
+ ...props
42
+ }
43
+ );
44
+ });
45
+
46
+
47
+
48
+ exports.Grid = Grid;
@@ -23,7 +23,7 @@ import {
23
23
  } from "react";
24
24
  import * as DialogPrimitive from "@radix-ui/react-dialog";
25
25
  import * as PopoverPrimitive from "@radix-ui/react-popover";
26
- import { Mic, LoaderCircle } from "lucide-react";
26
+ import { Mic, LoaderCircle, X } from "lucide-react";
27
27
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
28
28
  function VoiceDictationButton({
29
29
  onCommit,
@@ -118,40 +118,72 @@ function VoiceDictationButton({
118
118
  }
119
119
  };
120
120
  const content = /* @__PURE__ */ jsxs(Fragment, { children: [
121
- /* @__PURE__ */ jsxs("div", { className: cn("flex min-w-0 items-start justify-between gap-3", !anchored && "w-full max-w-xl self-center"), children: [
122
- /* @__PURE__ */ jsxs("div", { className: "min-w-0 space-y-1", children: [
123
- /* @__PURE__ */ jsx("h2", { className: cn("font-medium", anchored ? "text-sm" : "text-lg"), children: title || "Voice dictation" }),
124
- /* @__PURE__ */ jsxs("span", { role: "status", className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
125
- busy ? /* @__PURE__ */ jsx(LoaderCircle, { "aria-hidden": "true", className: "size-3.5 animate-spin motion-reduce:animate-none" }) : /* @__PURE__ */ jsx(Mic, { "aria-hidden": "true", className: "size-3.5" }),
121
+ /* @__PURE__ */ jsxs("div", { className: cn("flex min-w-0 shrink-0 items-start justify-between gap-4", !anchored && "w-full max-w-xl self-center"), children: [
122
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 space-y-2 pt-1", children: [
123
+ /* @__PURE__ */ jsx("h2", { className: "break-words text-xl font-semibold leading-tight", children: title || "Voice dictation" }),
124
+ /* @__PURE__ */ jsxs("span", { role: "status", className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
125
+ busy && /* @__PURE__ */ jsx(LoaderCircle, { "aria-hidden": "true", className: "size-4 shrink-0 animate-spin motion-reduce:animate-none" }),
126
126
  capture.state === "transcribing" ? "Finishing transcript\u2026" : capture.state === "requesting" ? "Starting dictation\u2026" : error ? "Recording not saved" : capture.state === "ready" ? "Ready" : caption
127
127
  ] })
128
128
  ] }),
129
- /* @__PURE__ */ jsxs("time", { "aria-label": "Recording duration", dateTime: `PT${elapsed}S`, className: "pt-0.5 font-mono text-xs tabular-nums text-muted-foreground", children: [
130
- Math.floor(elapsed / 60).toString().padStart(2, "0"),
131
- ":",
132
- (elapsed % 60).toString().padStart(2, "0")
133
- ] })
129
+ /* @__PURE__ */ jsx(
130
+ Button,
131
+ {
132
+ type: "button",
133
+ variant: "ghost",
134
+ size: "icon",
135
+ shape: "circle",
136
+ "aria-label": "Cancel dictation",
137
+ className: "size-[44px] shrink-0 text-muted-foreground [&_svg]:size-5",
138
+ onClick: handleCancel,
139
+ children: /* @__PURE__ */ jsx(X, { "aria-hidden": "true", className: "size-5" })
140
+ }
141
+ )
134
142
  ] }),
135
- /* @__PURE__ */ jsxs("div", { className: cn("flex min-h-0 flex-col gap-3", !anchored && "w-full max-w-xl flex-1 justify-center self-center py-8 text-center"), children: [
136
- capture.audioLevels && /* @__PURE__ */ jsx(DictationWaveform, { source: capture.audioLevels, state: capture.state, className: !anchored ? "h-20" : void 0 }),
137
- /* @__PURE__ */ jsx("p", { id: descriptionId, className: "text-xs text-muted-foreground", children: capture.state === "transcribing" ? "Finishing your last words\u2026" : capture.state === "requesting" ? "Allow microphone access to start." : error ? capture.canRetry ? "Retry this take or record again." : "Try recording again." : "Speak, then choose Done to add the text." }),
138
- displayTranscript && /* @__PURE__ */ jsxs("p", { className: "max-h-40 overflow-y-auto text-sm leading-relaxed", children: [
143
+ /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-5", !anchored && "w-full max-w-xl flex-1 justify-center self-center py-6"), children: [
144
+ /* @__PURE__ */ jsxs("div", { "data-slot": "dictation-meter", className: "flex min-w-0 items-center gap-3 py-5 text-[hsl(var(--chart-1))] sm:gap-5 sm:py-7", children: [
145
+ /* @__PURE__ */ jsx(
146
+ "div",
147
+ {
148
+ "aria-hidden": "true",
149
+ "data-slot": "dictation-microphone",
150
+ className: "flex size-[72px] shrink-0 items-center justify-center rounded-full bg-current/10 sm:size-[96px]",
151
+ children: /* @__PURE__ */ jsx("div", { className: "flex size-[52px] items-center justify-center rounded-full bg-[hsl(var(--chart-1))] text-popover sm:size-[72px]", children: /* @__PURE__ */ jsx(Mic, { className: "size-7 sm:size-9" }) })
152
+ }
153
+ ),
154
+ capture.audioLevels && /* @__PURE__ */ jsx(DictationWaveform, { source: capture.audioLevels, state: capture.state }),
155
+ /* @__PURE__ */ jsxs(
156
+ "time",
157
+ {
158
+ "aria-label": "Recording duration",
159
+ dateTime: `PT${elapsed}S`,
160
+ className: "ml-auto shrink-0 font-mono text-xl tabular-nums text-muted-foreground sm:text-2xl",
161
+ children: [
162
+ Math.floor(elapsed / 60).toString().padStart(2, "0"),
163
+ ":",
164
+ (elapsed % 60).toString().padStart(2, "0")
165
+ ]
166
+ }
167
+ )
168
+ ] }),
169
+ /* @__PURE__ */ jsx("p", { id: descriptionId, className: "text-base leading-relaxed text-muted-foreground", children: capture.state === "transcribing" ? "Finishing your last words\u2026" : capture.state === "requesting" ? "Allow microphone access to start." : error ? capture.canRetry ? "Retry this take or record again." : "Try recording again." : "Speak, then choose Done to add the text." }),
170
+ displayTranscript && /* @__PURE__ */ jsxs("p", { className: "max-h-48 overflow-y-auto break-words text-base leading-relaxed", children: [
139
171
  transcript,
140
172
  interim && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
141
173
  transcript ? " " : "",
142
174
  interim
143
175
  ] })
144
176
  ] }),
145
- error && /* @__PURE__ */ jsx("p", { role: "alert", className: "text-xs text-destructive", children: error }),
146
- !error && capture.previewError && /* @__PURE__ */ jsx("p", { role: "status", className: "text-xs text-muted-foreground", children: capture.previewError })
177
+ error && /* @__PURE__ */ jsx("p", { role: "alert", className: "text-sm leading-relaxed text-destructive", children: error }),
178
+ !error && capture.previewError && /* @__PURE__ */ jsx("p", { role: "status", className: "text-sm leading-relaxed text-muted-foreground", children: capture.previewError })
147
179
  ] }),
148
- /* @__PURE__ */ jsxs("div", { className: cn("gap-2", anchored ? "flex flex-wrap items-center justify-end" : "mt-auto grid w-full max-w-xl grid-cols-2 gap-3 self-center"), children: [
149
- /* @__PURE__ */ jsx(Button, { ref: cancelControl, type: "button", variant: "ghost", size: "sm", className: anchored ? "min-h-[44px]" : "min-h-[48px]", onClick: handleCancel, children: "Cancel" }),
150
- capture.canRetry && /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", className: anchored ? "min-h-[44px]" : "order-first col-span-2 min-h-[48px]", onClick: () => {
180
+ /* @__PURE__ */ jsxs("div", { className: cn("shrink-0 gap-3 pt-2", anchored ? "flex flex-wrap items-center justify-end" : "mt-auto grid w-full max-w-xl grid-cols-[auto_minmax(0,1fr)] self-center"), children: [
181
+ /* @__PURE__ */ jsx(Button, { ref: cancelControl, type: "button", variant: "ghost", className: "min-h-[48px] px-5", onClick: handleCancel, children: "Cancel" }),
182
+ capture.canRetry && /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", className: cn("min-h-[48px] px-5", !anchored && "order-first col-span-2"), onClick: () => {
151
183
  cancelControl.current?.focus({ preventScroll: true });
152
184
  void capture.start();
153
185
  }, children: "Record again" }),
154
- /* @__PURE__ */ jsx(Button, { type: "button", size: "sm", className: anchored ? "min-h-[44px]" : "min-h-[48px]", onClick: () => void handleDone(), disabled: busy, children: capture.state === "transcribing" ? "Transcribing\u2026" : capture.canRetry ? "Retry transcription" : error ? "Try again" : "Done" })
186
+ /* @__PURE__ */ jsx(Button, { type: "button", className: "min-h-[48px] min-w-24 px-6", onClick: () => void handleDone(), disabled: busy, children: capture.state === "transcribing" ? "Transcribing\u2026" : capture.canRetry ? "Retry transcription" : error ? "Try again" : "Done" })
155
187
  ] })
156
188
  ] });
157
189
  return /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -195,13 +227,13 @@ function VoiceDictationButton({
195
227
  "data-placement": "anchored",
196
228
  side: "top",
197
229
  align: "center",
198
- sideOffset: 8,
230
+ sideOffset: 12,
199
231
  collisionPadding: 12,
200
232
  avoidCollisions: true,
201
233
  onCloseAutoFocus: closeAutoFocus,
202
234
  onKeyDown,
203
235
  onEscapeKeyDown: (event) => event.stopPropagation(),
204
- className: "z-[200] flex max-h-[var(--radix-popover-content-available-height)] w-96 max-w-[calc(100vw-1.5rem)] flex-col gap-3 overflow-y-auto rounded-2xl border border-border bg-background p-4 text-foreground shadow-lg outline-hidden",
236
+ className: "z-[200] flex max-h-[var(--radix-popover-content-available-height)] w-[560px] max-w-[calc(100vw-24px)] flex-col gap-6 overflow-y-auto rounded-2xl border border-border bg-popover p-6 text-popover-foreground shadow-xl outline-hidden",
205
237
  children: content
206
238
  }
207
239
  ) })
@@ -221,7 +253,7 @@ function VoiceDictationButton({
221
253
  onCloseAutoFocus: closeAutoFocus,
222
254
  onKeyDown,
223
255
  onEscapeKeyDown: (event) => event.stopPropagation(),
224
- className: "fixed inset-0 z-[200] flex h-dvh w-screen flex-col gap-6 overflow-y-auto overscroll-contain bg-background px-6 pt-[max(1.5rem,env(safe-area-inset-top))] pb-[max(1.5rem,env(safe-area-inset-bottom))] text-foreground outline-hidden",
256
+ className: "fixed inset-0 z-[200] flex h-dvh w-screen flex-col gap-6 overflow-y-auto overscroll-contain bg-popover px-5 pt-[max(1.5rem,env(safe-area-inset-top))] pb-[max(1.5rem,env(safe-area-inset-bottom))] text-popover-foreground outline-hidden",
225
257
  children: [
226
258
  /* @__PURE__ */ jsx(DialogPrimitive.Title, { className: "sr-only", children: "Voice dictation" }),
227
259
  /* @__PURE__ */ jsx(DialogPrimitive.Description, { className: "sr-only", children: "Record your message, then choose Done to add the text. Cancel discards the recording." }),
@@ -234,7 +266,7 @@ function VoiceDictationButton({
234
266
  }
235
267
  var SILENCE = [];
236
268
  var silence = () => SILENCE;
237
- function DictationWaveform({ source, state, className }) {
269
+ function DictationWaveform({ source, state }) {
238
270
  const bands = useSyncExternalStore(source.subscribe, source.getSnapshot, silence);
239
271
  return /* @__PURE__ */ jsx(
240
272
  AgentAudioVisualizerBar,
@@ -245,7 +277,8 @@ function DictationWaveform({ source, state, className }) {
245
277
  barCount: 24,
246
278
  state: state === "recording" ? "listening" : state === "transcribing" ? "thinking" : state === "requesting" ? "connecting" : "disconnected",
247
279
  volumeBands: state === "recording" ? bands : void 0,
248
- className: cn("h-9 w-full text-foreground", className)
280
+ className: "h-[64px] min-w-0 flex-1 gap-[3px] sm:h-[88px] sm:gap-[4px]",
281
+ children: /* @__PURE__ */ jsx("div", { className: "min-h-[4px] max-w-[6px] flex-1 rounded-full bg-current/15 transition-colors duration-200 motion-reduce:transition-none data-[lk-highlighted=true]:bg-current" })
249
282
  }
250
283
  );
251
284
  }
@@ -4,7 +4,7 @@ import * as class_variance_authority_types from 'class-variance-authority/types'
4
4
  import { VariantProps } from 'class-variance-authority';
5
5
 
6
6
  declare const alertVariants: (props?: ({
7
- variant?: "success" | "default" | "destructive" | "warning" | null | undefined;
7
+ variant?: "default" | "destructive" | "success" | "warning" | null | undefined;
8
8
  } & class_variance_authority_types.ClassProp) | undefined) => string;
9
9
  interface AlertProps extends HTMLAttributes<HTMLDivElement>, VariantProps<typeof alertVariants> {
10
10
  marginBottom?: "none" | "md";
@@ -4,7 +4,7 @@ import * as class_variance_authority_types from 'class-variance-authority/types'
4
4
  import { VariantProps } from 'class-variance-authority';
5
5
 
6
6
  declare const alertVariants: (props?: ({
7
- variant?: "success" | "default" | "destructive" | "warning" | null | undefined;
7
+ variant?: "default" | "destructive" | "success" | "warning" | null | undefined;
8
8
  } & class_variance_authority_types.ClassProp) | undefined) => string;
9
9
  interface AlertProps extends HTMLAttributes<HTMLDivElement>, VariantProps<typeof alertVariants> {
10
10
  marginBottom?: "none" | "md";
@@ -4,7 +4,7 @@ import { VariantProps } from 'class-variance-authority';
4
4
  import { ElementType } from 'react';
5
5
 
6
6
  declare const badgeVariants: (props?: ({
7
- variant?: "neutral" | "error" | "success" | "default" | "secondary" | "destructive" | "outline" | "warning" | "info" | null | undefined;
7
+ variant?: "default" | "secondary" | "destructive" | "outline" | "success" | "warning" | "error" | "info" | "neutral" | null | undefined;
8
8
  } & class_variance_authority_types.ClassProp) | undefined) => string;
9
9
  interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {
10
10
  weight?: "normal" | "semibold" | "bold";
@@ -4,7 +4,7 @@ import { VariantProps } from 'class-variance-authority';
4
4
  import { ElementType } from 'react';
5
5
 
6
6
  declare const badgeVariants: (props?: ({
7
- variant?: "neutral" | "error" | "success" | "default" | "secondary" | "destructive" | "outline" | "warning" | "info" | null | undefined;
7
+ variant?: "default" | "secondary" | "destructive" | "outline" | "success" | "warning" | "error" | "info" | "neutral" | null | undefined;
8
8
  } & class_variance_authority_types.ClassProp) | undefined) => string;
9
9
  interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {
10
10
  weight?: "normal" | "semibold" | "bold";
@@ -5,7 +5,7 @@ import { VariantProps } from 'class-variance-authority';
5
5
 
6
6
  declare function BubbleGroup({ className, ...props }: React.ComponentProps<"div">): react_jsx_runtime.JSX.Element;
7
7
  declare const bubbleVariants: (props?: ({
8
- variant?: "default" | "muted" | "ghost" | "secondary" | "destructive" | "outline" | "tinted" | null | undefined;
8
+ variant?: "default" | "muted" | "secondary" | "destructive" | "outline" | "ghost" | "tinted" | null | undefined;
9
9
  } & class_variance_authority_types.ClassProp) | undefined) => string;
10
10
  declare function Bubble({ variant, align, className, ...props }: React.ComponentProps<"div"> & VariantProps<typeof bubbleVariants> & {
11
11
  align?: "start" | "end";
@@ -5,7 +5,7 @@ import { VariantProps } from 'class-variance-authority';
5
5
 
6
6
  declare function BubbleGroup({ className, ...props }: React.ComponentProps<"div">): react_jsx_runtime.JSX.Element;
7
7
  declare const bubbleVariants: (props?: ({
8
- variant?: "default" | "muted" | "ghost" | "secondary" | "destructive" | "outline" | "tinted" | null | undefined;
8
+ variant?: "default" | "muted" | "secondary" | "destructive" | "outline" | "ghost" | "tinted" | null | undefined;
9
9
  } & class_variance_authority_types.ClassProp) | undefined) => string;
10
10
  declare function Bubble({ variant, align, className, ...props }: React.ComponentProps<"div"> & VariantProps<typeof bubbleVariants> & {
11
11
  align?: "start" | "end";
@@ -4,8 +4,8 @@ import * as class_variance_authority_types from 'class-variance-authority/types'
4
4
  import { VariantProps } from 'class-variance-authority';
5
5
 
6
6
  declare const buttonVariants: (props?: ({
7
- variant?: "link" | "default" | "ghost" | "secondary" | "destructive" | "outline" | "outline-muted" | "quiet" | "ghost-destructive" | "link-muted" | "inverted" | "status-error" | "status-warning" | "status-muted" | null | undefined;
8
- size?: "filter" | "status" | "toolbar" | "sm" | "lg" | "default" | "micro" | "tone" | "compact" | "hero" | "icon" | "icon-lg" | "icon-sm" | "icon-md" | "icon-xs" | "icon-compact" | "icon-micro" | "bare" | "voice-sm" | "voice" | "suggestion" | null | undefined;
7
+ variant?: "link" | "default" | "secondary" | "destructive" | "outline" | "outline-muted" | "ghost" | "quiet" | "ghost-destructive" | "link-muted" | "inverted" | "status-error" | "status-warning" | "status-muted" | null | undefined;
8
+ size?: "filter" | "status" | "toolbar" | "sm" | "lg" | "default" | "micro" | "compact" | "hero" | "icon" | "icon-lg" | "icon-sm" | "icon-md" | "icon-xs" | "icon-compact" | "icon-micro" | "bare" | "voice-sm" | "voice" | "suggestion" | "tone" | null | undefined;
9
9
  width?: "auto" | "full" | "responsive" | null | undefined;
10
10
  align?: "center" | "start" | null | undefined;
11
11
  shrink?: boolean | null | undefined;
@@ -4,8 +4,8 @@ import * as class_variance_authority_types from 'class-variance-authority/types'
4
4
  import { VariantProps } from 'class-variance-authority';
5
5
 
6
6
  declare const buttonVariants: (props?: ({
7
- variant?: "link" | "default" | "ghost" | "secondary" | "destructive" | "outline" | "outline-muted" | "quiet" | "ghost-destructive" | "link-muted" | "inverted" | "status-error" | "status-warning" | "status-muted" | null | undefined;
8
- size?: "filter" | "status" | "toolbar" | "sm" | "lg" | "default" | "micro" | "tone" | "compact" | "hero" | "icon" | "icon-lg" | "icon-sm" | "icon-md" | "icon-xs" | "icon-compact" | "icon-micro" | "bare" | "voice-sm" | "voice" | "suggestion" | null | undefined;
7
+ variant?: "link" | "default" | "secondary" | "destructive" | "outline" | "outline-muted" | "ghost" | "quiet" | "ghost-destructive" | "link-muted" | "inverted" | "status-error" | "status-warning" | "status-muted" | null | undefined;
8
+ size?: "filter" | "status" | "toolbar" | "sm" | "lg" | "default" | "micro" | "compact" | "hero" | "icon" | "icon-lg" | "icon-sm" | "icon-md" | "icon-xs" | "icon-compact" | "icon-micro" | "bare" | "voice-sm" | "voice" | "suggestion" | "tone" | null | undefined;
9
9
  width?: "auto" | "full" | "responsive" | null | undefined;
10
10
  align?: "center" | "start" | null | undefined;
11
11
  shrink?: boolean | null | undefined;
@@ -7,7 +7,7 @@
7
7
  var _chunk2BTDBZYNcjs = require('../chunk-2BTDBZYN.cjs');
8
8
 
9
9
 
10
- var _chunkQWUMIAYDcjs = require('../chunk-QWUMIAYD.cjs');
10
+ var _chunkPH2TV7XIcjs = require('../chunk-PH2TV7XI.cjs');
11
11
 
12
12
 
13
13
  var _chunkYMI3X2YLcjs = require('../chunk-YMI3X2YL.cjs');
@@ -26,14 +26,15 @@ var _chunkB765DSRGcjs = require('../chunk-B765DSRG.cjs');
26
26
 
27
27
 
28
28
 
29
- var _chunkPD5UQEKYcjs = require('../chunk-PD5UQEKY.cjs');
30
- require('../chunk-34AS3OCC.cjs');
29
+ var _chunkHSSSNAVXcjs = require('../chunk-HSSSNAVX.cjs');
30
+ require('../chunk-6AMSRIQ4.cjs');
31
31
 
32
32
 
33
33
 
34
34
 
35
35
 
36
36
  var _chunkNWDPH2Z7cjs = require('../chunk-NWDPH2Z7.cjs');
37
+ require('../chunk-Z2H4LJVG.cjs');
37
38
 
38
39
 
39
40
 
@@ -178,15 +179,15 @@ var ChatThread = _react.forwardRef.call(void 0,
178
179
  const markers = timelineMarkers(messages, /* @__PURE__ */ new Date());
179
180
  const anchorId = useArrivingUserTurnId(messages);
180
181
  const workspace = appearance === "workspace";
181
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkPD5UQEKYcjs.MessageScrollerProvider, { autoScroll: true, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
182
- _chunkPD5UQEKYcjs.MessageScroller,
182
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkHSSSNAVXcjs.MessageScrollerProvider, { autoScroll: true, children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
183
+ _chunkHSSSNAVXcjs.MessageScroller,
183
184
  {
184
185
  ref,
185
186
  style: { maxHeight },
186
187
  className: _chunkKWLSBTB2cjs.cn.call(void 0, "min-h-0", className),
187
188
  children: [
188
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkPD5UQEKYcjs.MessageScrollerViewport, { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
189
- _chunkPD5UQEKYcjs.MessageScrollerContent,
189
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkHSSSNAVXcjs.MessageScrollerViewport, { children: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
190
+ _chunkHSSSNAVXcjs.MessageScrollerContent,
190
191
  {
191
192
  className: _chunkKWLSBTB2cjs.cn.call(void 0,
192
193
  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"
@@ -195,7 +196,7 @@ var ChatThread = _react.forwardRef.call(void 0,
195
196
  messages.map((m, index) => {
196
197
  const isUser = m.role === "user";
197
198
  if (m.status === "running") {
198
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkPD5UQEKYcjs.MessageScrollerItem, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
199
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkHSSSNAVXcjs.MessageScrollerItem, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
199
200
  ChatRunningLine,
200
201
  {
201
202
  label: m.text || pendingLabel,
@@ -208,7 +209,7 @@ var ChatThread = _react.forwardRef.call(void 0,
208
209
  const marker = markers[index];
209
210
  const actions = messageActions && offersActions(m) ? messageActions(m) : null;
210
211
  return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
211
- _chunkPD5UQEKYcjs.MessageScrollerItem,
212
+ _chunkHSSSNAVXcjs.MessageScrollerItem,
212
213
  {
213
214
  messageId: m.id,
214
215
  scrollAnchor: m.id === anchorId,
@@ -264,15 +265,15 @@ var ChatThread = _react.forwardRef.call(void 0,
264
265
  m.id
265
266
  );
266
267
  }),
267
- pending && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkPD5UQEKYcjs.MessageScrollerItem, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ChatRunningLine, { label: pendingLabel, workspace }) }),
268
+ pending && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkHSSSNAVXcjs.MessageScrollerItem, { children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, ChatRunningLine, { label: pendingLabel, workspace }) }),
268
269
  footer && // Always painted: content-visibility:auto would contain the
269
270
  // footer's paint and layout, clipping a ring or shadow at its
270
271
  // edge and re-parenting anything fixed inside it.
271
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkPD5UQEKYcjs.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 }) }) })
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 }) }) })
272
273
  ]
273
274
  }
274
275
  ) }),
275
- /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkPD5UQEKYcjs.MessageScrollerButton, { variant: "outline", className: "rounded-full shadow-sm", children: [
276
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkHSSSNAVXcjs.MessageScrollerButton, { variant: "outline", className: "rounded-full shadow-sm", children: [
276
277
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.ArrowDown, { className: "h-4 w-4" }),
277
278
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "sr-only", children: scrollButtonLabel })
278
279
  ] })
@@ -544,7 +545,7 @@ function ChatInput({
544
545
  ) : null,
545
546
  (!helperText || compact) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "flex-1" }),
546
547
  voice && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
547
- _chunkQWUMIAYDcjs.VoiceDictationButton,
548
+ _chunkPH2TV7XIcjs.VoiceDictationButton,
548
549
  {
549
550
  size: "icon",
550
551
  title: voiceTitle,
@@ -622,7 +623,7 @@ function VoiceHero({
622
623
  voiceSession ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
623
624
  /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkYMI3X2YLcjs.VoiceSessionControls, { ...voiceSession, size: "hero" }),
624
625
  voice && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
625
- _chunkQWUMIAYDcjs.VoiceDictationButton,
626
+ _chunkPH2TV7XIcjs.VoiceDictationButton,
626
627
  {
627
628
  size: "icon",
628
629
  title: voiceTitle,
@@ -632,7 +633,7 @@ function VoiceHero({
632
633
  }
633
634
  )
634
635
  ] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
635
- _chunkQWUMIAYDcjs.VoiceDictationButton,
636
+ _chunkPH2TV7XIcjs.VoiceDictationButton,
636
637
  {
637
638
  size: "lg",
638
639
  title: voiceTitle,
@@ -7,7 +7,7 @@ import {
7
7
  } from "../chunk-Z45YKVAM.js";
8
8
  import {
9
9
  VoiceDictationButton
10
- } from "../chunk-JKVVTFAP.js";
10
+ } from "../chunk-ZGTPNSR7.js";
11
11
  import {
12
12
  VoiceSessionControls
13
13
  } from "../chunk-KF4X37DP.js";
@@ -26,14 +26,15 @@ import {
26
26
  MessageScrollerItem,
27
27
  MessageScrollerProvider,
28
28
  MessageScrollerViewport
29
- } from "../chunk-UBTLWSKK.js";
30
- import "../chunk-VT2WDFSU.js";
29
+ } from "../chunk-EXXJXOUO.js";
30
+ import "../chunk-V3XA7SDK.js";
31
31
  import {
32
32
  Message,
33
33
  MessageAction,
34
34
  MessageActions,
35
35
  MessageContent
36
36
  } from "../chunk-H4XH2PPU.js";
37
+ import "../chunk-GA5SX7FE.js";
37
38
  import {
38
39
  InputGroup,
39
40
  InputGroupAddon,
@@ -1,47 +1,8 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }"use client";
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});"use client";
2
2
 
3
3
 
4
- var _chunkKWLSBTB2cjs = require('../chunk-KWLSBTB2.cjs');
4
+ var _chunkZ2H4LJVGcjs = require('../chunk-Z2H4LJVG.cjs');
5
+ require('../chunk-KWLSBTB2.cjs');
5
6
 
6
- // src/primitives/grid.tsx
7
- var _react = require('react');
8
- var _jsxruntime = require('react/jsx-runtime');
9
- var fixedColumns = {
10
- 1: "grid-cols-1",
11
- 2: "grid-cols-2",
12
- 3: "grid-cols-3",
13
- 4: "grid-cols-4"
14
- };
15
- var responsiveColumns = {
16
- 1: "grid-cols-1",
17
- 2: "grid-cols-1 sm:grid-cols-2",
18
- 3: "grid-cols-1 sm:grid-cols-3",
19
- 4: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4"
20
- };
21
- var gaps = { sm: "gap-2", compact: "gap-3", md: "gap-4", lg: "gap-6" };
22
- var Grid = _react.forwardRef.call(void 0, function Grid2({ columns = 2, gap = "md", responsive = true, layout = "grid", maxWidth = "none", centered = false, template = "equal", as, className, ...props }, ref) {
23
- const Component = _nullishCoalesce(as, () => ( "div"));
24
- return /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
25
- Component,
26
- {
27
- ref,
28
- className: _chunkKWLSBTB2cjs.cn.call(void 0,
29
- layout === "grid" ? "grid" : "grid sm:flex sm:justify-end",
30
- layout === "grid" && template === "equal" && columns !== null && (responsive ? responsiveColumns[columns] : fixedColumns[columns]),
31
- layout === "responsive-actions" && columns !== null && fixedColumns[columns],
32
- template === "compact-leading-three" && "grid-cols-[5rem_1fr_1fr]",
33
- template === "responsive-form-row-six" && "grid-cols-1 items-center sm:grid-cols-[1fr_1.4fr_1fr_1fr_1fr_auto]",
34
- template === "master-detail" && "grid-cols-1 lg:grid-cols-[360px_1fr]",
35
- template === "gallery" && "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
36
- gaps[gap],
37
- maxWidth === "xl" && "max-w-2xl",
38
- centered && "mx-auto",
39
- className
40
- ),
41
- ...props
42
- }
43
- );
44
- });
45
7
 
46
-
47
- exports.Grid = Grid;
8
+ exports.Grid = _chunkZ2H4LJVGcjs.Grid;
@@ -1,47 +1,8 @@
1
1
  "use client";
2
2
  import {
3
- cn
4
- } from "../chunk-G6SRSWXB.js";
5
-
6
- // src/primitives/grid.tsx
7
- import { forwardRef } from "react";
8
- import { jsx } from "react/jsx-runtime";
9
- var fixedColumns = {
10
- 1: "grid-cols-1",
11
- 2: "grid-cols-2",
12
- 3: "grid-cols-3",
13
- 4: "grid-cols-4"
14
- };
15
- var responsiveColumns = {
16
- 1: "grid-cols-1",
17
- 2: "grid-cols-1 sm:grid-cols-2",
18
- 3: "grid-cols-1 sm:grid-cols-3",
19
- 4: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4"
20
- };
21
- var gaps = { sm: "gap-2", compact: "gap-3", md: "gap-4", lg: "gap-6" };
22
- var Grid = forwardRef(function Grid2({ columns = 2, gap = "md", responsive = true, layout = "grid", maxWidth = "none", centered = false, template = "equal", as, className, ...props }, ref) {
23
- const Component = as ?? "div";
24
- return /* @__PURE__ */ jsx(
25
- Component,
26
- {
27
- ref,
28
- className: cn(
29
- layout === "grid" ? "grid" : "grid sm:flex sm:justify-end",
30
- layout === "grid" && template === "equal" && columns !== null && (responsive ? responsiveColumns[columns] : fixedColumns[columns]),
31
- layout === "responsive-actions" && columns !== null && fixedColumns[columns],
32
- template === "compact-leading-three" && "grid-cols-[5rem_1fr_1fr]",
33
- template === "responsive-form-row-six" && "grid-cols-1 items-center sm:grid-cols-[1fr_1.4fr_1fr_1fr_1fr_auto]",
34
- template === "master-detail" && "grid-cols-1 lg:grid-cols-[360px_1fr]",
35
- template === "gallery" && "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
36
- gaps[gap],
37
- maxWidth === "xl" && "max-w-2xl",
38
- centered && "mx-auto",
39
- className
40
- ),
41
- ...props
42
- }
43
- );
44
- });
3
+ Grid
4
+ } from "../chunk-GA5SX7FE.js";
5
+ import "../chunk-G6SRSWXB.js";
45
6
  export {
46
7
  Grid
47
8
  };
@@ -11,8 +11,9 @@
11
11
 
12
12
 
13
13
 
14
- var _chunkPD5UQEKYcjs = require('../chunk-PD5UQEKY.cjs');
15
- require('../chunk-34AS3OCC.cjs');
14
+ var _chunkHSSSNAVXcjs = require('../chunk-HSSSNAVX.cjs');
15
+ require('../chunk-6AMSRIQ4.cjs');
16
+ require('../chunk-Z2H4LJVG.cjs');
16
17
  require('../chunk-WABCLRBR.cjs');
17
18
  require('../chunk-JDEXZGIY.cjs');
18
19
  require('../chunk-KWLSBTB2.cjs');
@@ -27,4 +28,4 @@ require('../chunk-KWLSBTB2.cjs');
27
28
 
28
29
 
29
30
 
30
- exports.MessageScroller = _chunkPD5UQEKYcjs.MessageScroller; exports.MessageScrollerButton = _chunkPD5UQEKYcjs.MessageScrollerButton; exports.MessageScrollerContent = _chunkPD5UQEKYcjs.MessageScrollerContent; exports.MessageScrollerItem = _chunkPD5UQEKYcjs.MessageScrollerItem; exports.MessageScrollerNavigator = _chunkPD5UQEKYcjs.MessageScrollerNavigator; exports.MessageScrollerProvider = _chunkPD5UQEKYcjs.MessageScrollerProvider; exports.MessageScrollerViewport = _chunkPD5UQEKYcjs.MessageScrollerViewport; exports.useMessageScroller = _chunkPD5UQEKYcjs.useMessageScroller; exports.useMessageScrollerScrollable = _chunkPD5UQEKYcjs.useMessageScrollerScrollable; exports.useMessageScrollerVisibility = _chunkPD5UQEKYcjs.useMessageScrollerVisibility;
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;
@@ -11,8 +11,9 @@ import {
11
11
  useMessageScroller,
12
12
  useMessageScrollerScrollable,
13
13
  useMessageScrollerVisibility
14
- } from "../chunk-UBTLWSKK.js";
15
- import "../chunk-VT2WDFSU.js";
14
+ } from "../chunk-EXXJXOUO.js";
15
+ import "../chunk-V3XA7SDK.js";
16
+ import "../chunk-GA5SX7FE.js";
16
17
  import "../chunk-3OWGL4Q2.js";
17
18
  import "../chunk-W326GKML.js";
18
19
  import "../chunk-G6SRSWXB.js";
@@ -2,9 +2,10 @@
2
2
  "use client";
3
3
 
4
4
 
5
- var _chunk34AS3OCCcjs = require('../chunk-34AS3OCC.cjs');
5
+ var _chunk6AMSRIQ4cjs = require('../chunk-6AMSRIQ4.cjs');
6
+ require('../chunk-Z2H4LJVG.cjs');
6
7
  require('../chunk-WABCLRBR.cjs');
7
8
  require('../chunk-KWLSBTB2.cjs');
8
9
 
9
10
 
10
- exports.ScrollNavigator = _chunk34AS3OCCcjs.ScrollNavigator;
11
+ exports.ScrollNavigator = _chunk6AMSRIQ4cjs.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
+ /** Card columns above the small breakpoint; always one column on mobile. */
22
+ columns?: 1 | 2 | 3 | 4;
21
23
  /** Space below a sticky header inside the scroll viewport, in pixels. */
22
24
  topOffset?: number;
23
25
  /** The nearest vertically scrolling ancestor is detected by default. */
@@ -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
+ /** Card columns above the small breakpoint; always one column on mobile. */
22
+ columns?: 1 | 2 | 3 | 4;
21
23
  /** Space below a sticky header inside the scroll viewport, in pixels. */
22
24
  topOffset?: number;
23
25
  /** The nearest vertically scrolling ancestor is detected by default. */
@@ -2,7 +2,8 @@
2
2
  "use client";
3
3
  import {
4
4
  ScrollNavigator
5
- } from "../chunk-VT2WDFSU.js";
5
+ } from "../chunk-V3XA7SDK.js";
6
+ import "../chunk-GA5SX7FE.js";
6
7
  import "../chunk-3OWGL4Q2.js";
7
8
  import "../chunk-G6SRSWXB.js";
8
9
  export {
@@ -2,7 +2,7 @@
2
2
  "use client";
3
3
 
4
4
 
5
- var _chunkQWUMIAYDcjs = require('../chunk-QWUMIAYD.cjs');
5
+ var _chunkPH2TV7XIcjs = require('../chunk-PH2TV7XI.cjs');
6
6
  require('../chunk-NKWHDI4C.cjs');
7
7
  require('../chunk-JDEXZGIY.cjs');
8
8
  require('../chunk-KWLSBTB2.cjs');
@@ -10,4 +10,4 @@ require('../chunk-2BSFYU22.cjs');
10
10
  require('../chunk-7Q4EFCUI.cjs');
11
11
 
12
12
 
13
- exports.VoiceDictationButton = _chunkQWUMIAYDcjs.VoiceDictationButton;
13
+ exports.VoiceDictationButton = _chunkPH2TV7XIcjs.VoiceDictationButton;
@@ -2,7 +2,7 @@
2
2
  "use client";
3
3
  import {
4
4
  VoiceDictationButton
5
- } from "../chunk-JKVVTFAP.js";
5
+ } from "../chunk-ZGTPNSR7.js";
6
6
  import "../chunk-5OF6D3GH.js";
7
7
  import "../chunk-W326GKML.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.15.0",
3
+ "version": "1.17.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": [