@epicbagel/saas-kit 1.11.1 → 1.13.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 (33) hide show
  1. package/README.md +41 -4
  2. package/THIRD_PARTY_NOTICES.md +20 -0
  3. package/dist/{chunk-ZZ7ICQR2.cjs → chunk-7Q4EFCUI.cjs} +93 -28
  4. package/dist/{chunk-EDEN7TAL.js → chunk-JKVVTFAP.js} +5 -4
  5. package/dist/chunk-KI7SWNIN.js +53 -0
  6. package/dist/{chunk-D47AMKT4.cjs → chunk-QWUMIAYD.cjs} +6 -5
  7. package/dist/{chunk-HLAHOVEI.js → chunk-RPSRCB5O.js} +79 -14
  8. package/dist/chunk-SJB4DPGQ.cjs +51 -0
  9. package/dist/chunk-SRIGG5I5.js +51 -0
  10. package/dist/chunk-VKYRB37O.cjs +53 -0
  11. package/dist/hooks/use-dictation.cjs +2 -2
  12. package/dist/hooks/use-dictation.d.cts +27 -5
  13. package/dist/hooks/use-dictation.d.ts +27 -5
  14. package/dist/hooks/use-dictation.js +1 -1
  15. package/dist/primitives/chat.cjs +16 -12
  16. package/dist/primitives/chat.d.cts +13 -6
  17. package/dist/primitives/chat.d.ts +13 -6
  18. package/dist/primitives/chat.js +13 -9
  19. package/dist/primitives/dictation-provider.cjs +2 -2
  20. package/dist/primitives/dictation-provider.d.cts +1 -1
  21. package/dist/primitives/dictation-provider.d.ts +1 -1
  22. package/dist/primitives/dictation-provider.js +1 -1
  23. package/dist/primitives/notes.cjs +259 -0
  24. package/dist/primitives/notes.d.cts +123 -0
  25. package/dist/primitives/notes.d.ts +123 -0
  26. package/dist/primitives/notes.js +259 -0
  27. package/dist/primitives/panel-section.cjs +4 -48
  28. package/dist/primitives/panel-section.js +3 -47
  29. package/dist/primitives/section-header.cjs +4 -45
  30. package/dist/primitives/section-header.js +4 -45
  31. package/dist/primitives/voice-dictation-button.cjs +3 -3
  32. package/dist/primitives/voice-dictation-button.js +2 -2
  33. package/package.json +11 -1
@@ -154,7 +154,11 @@ interface ChatInputProps {
154
154
  uploadingLabel?: string;
155
155
  /** Show the inline voice dictation button. Defaults to true. */
156
156
  voice?: boolean;
157
- /** A separate live voice control alongside dictation. The host owns its transport and lifecycle. */
157
+ /**
158
+ * Live voice controls, separate from dictation. With no text or staged files,
159
+ * the round voice action replaces Send; an active call keeps its controls
160
+ * above the input. The host owns the transport and lifecycle.
161
+ */
158
162
  voiceSession?: VoiceSessionControlsProps;
159
163
  /** Title shown inside the voice overlay. */
160
164
  voiceTitle?: string;
@@ -164,6 +168,7 @@ interface ChatInputProps {
164
168
  * Label for the submit button. When set, the button renders as a labelled
165
169
  * primary action (`{label} →`) instead of the default icon-only send — use
166
170
  * it to name the outcome, e.g. "Propose 3 times", "Create link", "Send".
171
+ * An empty composer with live voice still shows the voice action first.
167
172
  */
168
173
  submitLabel?: ReactNode;
169
174
  /** Auto-focus the textarea on mount. */
@@ -200,9 +205,10 @@ interface ChatInputProps {
200
205
  /**
201
206
  * Compact text input: a form around one bordered input group, with any
202
207
  * staged files on top, a textarea that grows with its text, then an action
203
- * bar (the file menu and voice mic on the left, the submit button on the
204
- * right). Always text-first; voice is a secondary affordance. Enter sends;
205
- * Shift+Enter newlines, and Enter that commits an IME candidate never sends.
208
+ * bar ending in one primary action. When live voice is available, an empty
209
+ * composer shows its round start action; text or staged files replace it
210
+ * with Send. Dictation remains a separate mic. Enter sends; Shift+Enter
211
+ * newlines, and Enter that commits an IME candidate never sends or starts a call.
206
212
  *
207
213
  * The submit button is icon-only by default; pass `submitLabel` to name the
208
214
  * outcome ("Propose 3 times", "Create link") — it then renders as a labelled
@@ -294,7 +300,8 @@ interface ChatProps {
294
300
  * Label for the submit button (empty-state input). When set, the button
295
301
  * names the outcome (`{label} →`) instead of the icon-only send — e.g.
296
302
  * "Propose 3 times". Once the conversation is active the input reverts to
297
- * the compact icon send.
303
+ * the compact icon send. With live voice available, an empty composer shows
304
+ * the voice action until text or files are staged.
298
305
  */
299
306
  submitLabel?: ReactNode;
300
307
  /** Files currently staged in the composer. */
@@ -357,7 +364,7 @@ interface ChatProps {
357
364
  fileDropDescription?: ReactNode;
358
365
  /** Enable voice dictation. Defaults to true. */
359
366
  voice?: boolean;
360
- /** Controlled live voice UI, used instead of browser dictation when provided. */
367
+ /** Controlled live voice UI; its empty-input action is separate from the dictation mic. */
361
368
  voiceSession?: VoiceSessionControlsProps;
362
369
  /** Title shown inside the voice overlay. */
363
370
  voiceTitle?: string;
@@ -1,5 +1,8 @@
1
1
  "use client";
2
2
  "use client";
3
+ import {
4
+ VoiceDictationButton
5
+ } from "../chunk-JKVVTFAP.js";
3
6
  import {
4
7
  VoiceSessionControls
5
8
  } from "../chunk-KF4X37DP.js";
@@ -8,9 +11,6 @@ import {
8
11
  TraceLine,
9
12
  TraceTitle
10
13
  } from "../chunk-Z45YKVAM.js";
11
- import {
12
- VoiceDictationButton
13
- } from "../chunk-EDEN7TAL.js";
14
14
  import {
15
15
  Suggestion,
16
16
  Suggestions
@@ -86,7 +86,7 @@ import "../chunk-GJ7S3L6R.js";
86
86
  import {
87
87
  useCopyToClipboard
88
88
  } from "../chunk-ZWZAAGQF.js";
89
- import "../chunk-HLAHOVEI.js";
89
+ import "../chunk-RPSRCB5O.js";
90
90
  import {
91
91
  useIsMobile
92
92
  } from "../chunk-PIU5SSUV.js";
@@ -402,8 +402,9 @@ function ChatInput({
402
402
  const [editing, setEditing] = useState(false);
403
403
  const focusVersion = useRef(0);
404
404
  const isDisabled = pending || disabled;
405
+ const hasText = Boolean(value.trim());
405
406
  const attachmentsReady = attachments.length > 0 && attachments.every((item) => item.state !== "uploading");
406
- const canSubmit = !isDisabled && (Boolean(value.trim()) || attachmentsReady);
407
+ const canSubmit = !isDisabled && (hasText || attachmentsReady);
407
408
  const liveVoiceActive = voiceSession && voiceSession.state !== "disconnected" && voiceSession.state !== "error";
408
409
  const submit = () => {
409
410
  const trimmed = value.trim();
@@ -555,8 +556,7 @@ function ChatInput({
555
556
  )
556
557
  }
557
558
  ),
558
- voiceSession && !liveVoiceActive && /* @__PURE__ */ jsx(VoiceSessionControls, { ...voiceSession, disabled: voiceSession.disabled || isDisabled }),
559
- submitLabel ? /* @__PURE__ */ jsxs(
559
+ voiceSession && !liveVoiceActive && !hasText && attachments.length === 0 ? /* @__PURE__ */ jsx(VoiceSessionControls, { ...voiceSession, disabled: voiceSession.disabled || isDisabled }) : submitLabel ? /* @__PURE__ */ jsxs(
560
560
  Button,
561
561
  {
562
562
  type: "submit",
@@ -572,11 +572,15 @@ function ChatInput({
572
572
  Button,
573
573
  {
574
574
  type: "submit",
575
- size: spacious && !compact ? "icon-lg" : "icon",
575
+ size: !voiceSession && spacious && !compact ? "icon-lg" : "icon",
576
+ shape: voiceSession ? "circle" : void 0,
576
577
  disabled: !canSubmit,
577
578
  "aria-label": "Send",
578
579
  "data-chat-action": "submit",
579
- className: cn(spacious && "rounded-xl", compactOnBlur && "min-h-[44px] min-w-[44px] shrink-0"),
580
+ className: cn(
581
+ spacious && !voiceSession && "rounded-xl",
582
+ (voiceSession || compactOnBlur) && "min-h-[44px] min-w-[44px] shrink-0"
583
+ ),
580
584
  children: /* @__PURE__ */ jsx(ArrowUp, { className: cn(spacious && "h-5 w-5") })
581
585
  }
582
586
  )
@@ -2,7 +2,7 @@
2
2
  "use client";
3
3
 
4
4
 
5
- var _chunkZZ7ICQR2cjs = require('../chunk-ZZ7ICQR2.cjs');
5
+ var _chunk7Q4EFCUIcjs = require('../chunk-7Q4EFCUI.cjs');
6
6
 
7
7
 
8
- exports.DictationProvider = _chunkZZ7ICQR2cjs.DictationProvider;
8
+ exports.DictationProvider = _chunk7Q4EFCUIcjs.DictationProvider;
@@ -1,2 +1,2 @@
1
- export { DictationProvider, DictationProviderProps, DictationTranscribe, DictationTranscribeOptions } from '../hooks/use-dictation.cjs';
1
+ export { DictationProvider, DictationProviderProps, DictationStream, DictationStreamOptions, DictationStreamSession, DictationTranscribe, DictationTranscribeOptions } from '../hooks/use-dictation.cjs';
2
2
  import 'react';
@@ -1,2 +1,2 @@
1
- export { DictationProvider, DictationProviderProps, DictationTranscribe, DictationTranscribeOptions } from '../hooks/use-dictation.js';
1
+ export { DictationProvider, DictationProviderProps, DictationStream, DictationStreamOptions, DictationStreamSession, DictationTranscribe, DictationTranscribeOptions } from '../hooks/use-dictation.js';
2
2
  import 'react';
@@ -2,7 +2,7 @@
2
2
  "use client";
3
3
  import {
4
4
  DictationProvider
5
- } from "../chunk-HLAHOVEI.js";
5
+ } from "../chunk-RPSRCB5O.js";
6
6
  export {
7
7
  DictationProvider
8
8
  };
@@ -0,0 +1,259 @@
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
+ "use client";
3
+
4
+
5
+ var _chunkSJB4DPGQcjs = require('../chunk-SJB4DPGQ.cjs');
6
+
7
+
8
+ var _chunkVKYRB37Ocjs = require('../chunk-VKYRB37O.cjs');
9
+
10
+
11
+ var _chunkR3DQS6U4cjs = require('../chunk-R3DQS6U4.cjs');
12
+
13
+
14
+ var _chunk2HV2KKOEcjs = require('../chunk-2HV2KKOE.cjs');
15
+
16
+
17
+ var _chunkJ467F76Icjs = require('../chunk-J467F76I.cjs');
18
+
19
+
20
+ var _chunk373W6VADcjs = require('../chunk-373W6VAD.cjs');
21
+
22
+
23
+ var _chunkT2ZFSPE4cjs = require('../chunk-T2ZFSPE4.cjs');
24
+ require('../chunk-VGTINL5Q.cjs');
25
+
26
+
27
+ var _chunkI6GUOEBOcjs = require('../chunk-I6GUOEBO.cjs');
28
+
29
+
30
+ var _chunkCLYAASFNcjs = require('../chunk-CLYAASFN.cjs');
31
+
32
+
33
+ var _chunkVBPPFC7Xcjs = require('../chunk-VBPPFC7X.cjs');
34
+
35
+
36
+ var _chunkJDEXZGIYcjs = require('../chunk-JDEXZGIY.cjs');
37
+ require('../chunk-KWLSBTB2.cjs');
38
+
39
+ // src/primitives/notes.tsx
40
+ var _lucidereact = require('lucide-react');
41
+ var _react = require('react');
42
+ var _jsxruntime = require('react/jsx-runtime');
43
+ function present(value) {
44
+ return value != null && value !== false && value !== "";
45
+ }
46
+ function NoteList({
47
+ count,
48
+ loading = false,
49
+ title = "Notes",
50
+ empty = { title: "No notes yet" },
51
+ composer,
52
+ children,
53
+ border = "bottom",
54
+ ...props
55
+ }) {
56
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkVKYRB37Ocjs.PanelSection, { "data-slot": "note-list", border, ...props, children: [
57
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkSJB4DPGQcjs.SectionHeader, { label: title, count: loading ? void 0 : count }),
58
+ loading ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJ467F76Icjs.Stack, { direction: "vertical", gap: "sm", marginTop: "md", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkVBPPFC7Xcjs.Skeleton, { preset: "row", radius: "xl" }) }) : count > 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJ467F76Icjs.Stack, { direction: "vertical", gap: "sm", marginTop: "md", children }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
59
+ _chunkCLYAASFNcjs.EmptyState,
60
+ {
61
+ variant: "empty",
62
+ size: "inline",
63
+ icon: _lucidereact.StickyNote,
64
+ title: empty.title,
65
+ description: _nullishCoalesce(empty.description, () => ( ""))
66
+ }
67
+ ),
68
+ composer
69
+ ] });
70
+ }
71
+ var NOTE_CARD_LABELS = {
72
+ voice: "\xB7 voice",
73
+ delete: "Delete note"
74
+ };
75
+ var NOTE_ICON = { voice: _lucidereact.Mic, agent: _lucidereact.Sparkles, note: _lucidereact.MessageSquare };
76
+ function NoteCard({
77
+ author,
78
+ kind = "note",
79
+ pinned,
80
+ scope,
81
+ date,
82
+ text,
83
+ onDelete,
84
+ revealDelete = "hover",
85
+ labels,
86
+ ...props
87
+ }) {
88
+ const voiceLabel = _optionalChain([labels, 'optionalAccess', _ => _.voice]) !== void 0 ? labels.voice : NOTE_CARD_LABELS.voice;
89
+ const deleteLabel = _nullishCoalesce(_optionalChain([labels, 'optionalAccess', _2 => _2.delete]), () => ( NOTE_CARD_LABELS.delete));
90
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkR3DQS6U4cjs.Card, { interaction: "group", surface: pinned ? "card" : "muted", padding: "row", ...props, children: [
91
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkJ467F76Icjs.Stack, { direction: "horizontal", gap: "xs", align: "center", justify: "between", marginBottom: "md", minWidth: "zero", wrap: true, children: [
92
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkJ467F76Icjs.Stack, { direction: "horizontal", gap: "sm", align: "center", textSize: "xs", tone: "muted", minWidth: "zero", className: "max-w-full", wrap: true, children: [
93
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunk373W6VADcjs.Text, { variant: "inherit", as: "span", display: "inline-flex", weight: "medium", tone: "soft", minWidth: "zero", className: "max-w-full", children: [
94
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkT2ZFSPE4cjs.Icon, { icon: NOTE_ICON[kind], size: "xs" }),
95
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk373W6VADcjs.Text, { variant: "inherit", as: "span", minWidth: "zero", className: "[overflow-wrap:anywhere]", children: author })
96
+ ] }),
97
+ pinned && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkI6GUOEBOcjs.Badge, { as: "span", variant: "info", size: "micro", weight: "semibold", title: pinned.title, className: "max-w-full whitespace-normal [overflow-wrap:anywhere]", children: pinned.label }),
98
+ kind === "voice" && present(voiceLabel) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk373W6VADcjs.Text, { variant: "inherit", as: "span", tone: "subtle", children: voiceLabel }),
99
+ scope && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
100
+ _chunkI6GUOEBOcjs.Badge,
101
+ {
102
+ as: "span",
103
+ variant: scope.highlighted ? "info" : "default",
104
+ size: "micro",
105
+ weight: "semibold",
106
+ title: scope.title,
107
+ className: "max-w-full whitespace-normal [overflow-wrap:anywhere]",
108
+ children: scope.label
109
+ }
110
+ )
111
+ ] }),
112
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkJ467F76Icjs.Stack, { direction: "horizontal", gap: "xs", align: "center", minWidth: "zero", className: "max-w-full", children: [
113
+ present(date) ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk373W6VADcjs.Text, { variant: "inherit", as: "span", size: "xs", tone: "muted", minWidth: "zero", className: "[overflow-wrap:anywhere]", children: date }) : null,
114
+ onDelete && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
115
+ _chunkJDEXZGIYcjs.Button,
116
+ {
117
+ type: "button",
118
+ size: "icon-sm",
119
+ reveal: revealDelete === "always" ? "always" : "parent-hover-responsive",
120
+ variant: "ghost-destructive",
121
+ onClick: () => onDelete(),
122
+ title: deleteLabel,
123
+ children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkT2ZFSPE4cjs.Icon, { icon: _lucidereact.Trash2, size: "sm" })
124
+ }
125
+ )
126
+ ] })
127
+ ] }),
128
+ present(text) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk373W6VADcjs.Text, { size: "sm", whitespace: "pre-wrap", className: "break-words [overflow-wrap:anywhere]", children: text })
129
+ ] });
130
+ }
131
+ function Notes({ notes, ...props }) {
132
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, NoteList, { "data-slot": "notes", count: notes.length, ...props, children: notes.map(({ id, ...note }) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, NoteCard, { ...note }, id)) });
133
+ }
134
+ var COMPOSER_LABELS = {
135
+ voice: "Tap to speak",
136
+ type: "or type instead",
137
+ input: "Note",
138
+ placeholder: "Type your note\u2026",
139
+ cancel: "Cancel",
140
+ submit: "Add note",
141
+ error: "Could not save your note. Try again."
142
+ };
143
+ function NoteComposer({
144
+ onVoice,
145
+ onSubmit,
146
+ suggestions = [],
147
+ labels,
148
+ value,
149
+ onValueChange,
150
+ editing,
151
+ onEditingChange,
152
+ onCancel,
153
+ disabled = false,
154
+ error,
155
+ maxLength,
156
+ ...props
157
+ }) {
158
+ const copy = { ...COMPOSER_LABELS, ...labels };
159
+ const [draft, setDraft] = _react.useState.call(void 0, "");
160
+ const [localEditing, setLocalEditing] = _react.useState.call(void 0, false);
161
+ const [saving, setSaving] = _react.useState.call(void 0, false);
162
+ const [failed, setFailed] = _react.useState.call(void 0, false);
163
+ const pending = _react.useRef.call(void 0, false);
164
+ const mounted = _react.useRef.call(void 0, true);
165
+ const errorId = _react.useId.call(void 0, );
166
+ const text = _nullishCoalesce(value, () => ( draft));
167
+ const latestText = _react.useRef.call(void 0, text);
168
+ latestText.current = text;
169
+ const busy = disabled || saving;
170
+ const message = _nullishCoalesce(error, () => ( (failed ? copy.error : null)));
171
+ const typing = (_nullishCoalesce(editing, () => ( localEditing))) || Boolean(text) || Boolean(message) || !onVoice;
172
+ _react.useEffect.call(void 0, () => {
173
+ mounted.current = true;
174
+ return () => {
175
+ mounted.current = false;
176
+ };
177
+ }, []);
178
+ function changeText(next) {
179
+ if (value === void 0) setDraft(next);
180
+ _optionalChain([onValueChange, 'optionalCall', _3 => _3(next)]);
181
+ latestText.current = next;
182
+ }
183
+ function changeEditing(next) {
184
+ if (editing === void 0) setLocalEditing(next);
185
+ _optionalChain([onEditingChange, 'optionalCall', _4 => _4(next)]);
186
+ }
187
+ function cancel() {
188
+ if (disabled || pending.current) return;
189
+ changeText("");
190
+ changeEditing(false);
191
+ setFailed(false);
192
+ _optionalChain([onCancel, 'optionalCall', _5 => _5()]);
193
+ }
194
+ async function submit(input) {
195
+ const trimmed = input.trim();
196
+ if (disabled || pending.current || !trimmed || maxLength != null && trimmed.length > maxLength) return;
197
+ pending.current = true;
198
+ setSaving(true);
199
+ setFailed(false);
200
+ const previous = latestText.current;
201
+ try {
202
+ await onSubmit(trimmed);
203
+ if (!mounted.current) return;
204
+ if (value === void 0 && latestText.current === previous) {
205
+ changeText("");
206
+ changeEditing(false);
207
+ }
208
+ } catch (e) {
209
+ if (!mounted.current) return;
210
+ if (latestText.current === previous) changeText(input);
211
+ changeEditing(true);
212
+ setFailed(true);
213
+ } finally {
214
+ pending.current = false;
215
+ if (mounted.current) setSaving(false);
216
+ }
217
+ }
218
+ return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkJ467F76Icjs.Stack, { "data-slot": "note-composer", direction: "vertical", gap: "sm", marginTop: "md", "aria-busy": saving, ...props, children: [
219
+ message ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk373W6VADcjs.Text, { id: errorId, role: "alert", size: "sm", tone: "destructive", children: message }) : null,
220
+ typing ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
221
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
222
+ _chunk2HV2KKOEcjs.Textarea,
223
+ {
224
+ "aria-label": copy.input,
225
+ "aria-describedby": message ? errorId : void 0,
226
+ resize: "vertical",
227
+ placeholder: copy.placeholder,
228
+ value: text,
229
+ onChange: (event) => changeText(event.target.value),
230
+ maxLength,
231
+ disabled: busy,
232
+ autoFocus: Boolean(onVoice)
233
+ }
234
+ ),
235
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkJ467F76Icjs.Stack, { direction: "horizontal", gap: "sm", align: "center", wrap: true, children: [
236
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJDEXZGIYcjs.Button, { type: "button", size: "sm", variant: "ghost", onClick: cancel, disabled: busy, children: copy.cancel }),
237
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkJDEXZGIYcjs.Button, { type: "button", size: "sm", onClick: () => void submit(text), disabled: busy || !text.trim() || maxLength != null && text.trim().length > maxLength, children: [
238
+ saving ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkT2ZFSPE4cjs.Icon, { icon: _lucidereact.Loader2, size: "sm", spin: true }) : null,
239
+ copy.submit
240
+ ] })
241
+ ] })
242
+ ] }) : /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
243
+ /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _chunkJ467F76Icjs.Stack, { direction: "vertical", gap: "sm", align: "center", paddingY: "md", children: [
244
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJDEXZGIYcjs.Button, { type: "button", variant: "outline", size: "voice", "aria-label": copy.voice, disabled: busy, onClick: () => {
245
+ if (!pending.current && !disabled) _optionalChain([onVoice, 'optionalCall', _6 => _6()]);
246
+ }, children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkT2ZFSPE4cjs.Icon, { icon: _lucidereact.Mic, size: 28, tone: "muted" }) }),
247
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk373W6VADcjs.Text, { variant: "inherit", as: "span", size: "sm", weight: "medium", children: copy.voice }),
248
+ /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJDEXZGIYcjs.Button, { type: "button", variant: "quiet", size: "bare", disabled: busy, onClick: () => changeEditing(true), children: copy.type })
249
+ ] }),
250
+ suggestions.length > 0 ? /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJ467F76Icjs.Stack, { direction: "horizontal", gap: "xs", justify: "center", wrap: true, children: suggestions.map((suggestion) => /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkJDEXZGIYcjs.Button, { type: "button", variant: "outline-muted", size: "suggestion", disabled: busy, onClick: () => void submit(suggestion), children: suggestion }, suggestion)) }) : null
251
+ ] })
252
+ ] });
253
+ }
254
+
255
+
256
+
257
+
258
+
259
+ exports.NoteCard = NoteCard; exports.NoteComposer = NoteComposer; exports.NoteList = NoteList; exports.Notes = Notes;
@@ -0,0 +1,123 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { HTMLAttributes, ReactNode } from 'react';
3
+
4
+ interface NotesEmptyCopy {
5
+ title: string;
6
+ description?: string;
7
+ }
8
+ interface NoteListProps extends Omit<HTMLAttributes<HTMLElement>, "title" | "children"> {
9
+ /** How many notes there are. Zero shows the empty state instead of `children`. */
10
+ count: number;
11
+ /** A skeleton row in place of the list, and no count yet. */
12
+ loading?: boolean;
13
+ /** The section heading. */
14
+ title?: ReactNode;
15
+ /** The blank slate's wording. Defaults to "No notes yet". */
16
+ empty?: NotesEmptyCopy;
17
+ /** Below the notes, usually a NoteComposer. */
18
+ composer?: ReactNode;
19
+ /** The notes, usually NoteCards, newest or pinned first. */
20
+ children?: ReactNode;
21
+ /** The kit PanelSection's divider. */
22
+ border?: "none" | "top" | "bottom";
23
+ }
24
+ /**
25
+ * A notes section, as a counted section: a skeleton row while they
26
+ * load, then the host's note cards, or the kit's empty state when there are
27
+ * none, with the composer underneath so a new note lands below the last.
28
+ *
29
+ * The root is the kit PanelSection, marked `data-slot="note-list"`.
30
+ */
31
+ declare function NoteList({ count, loading, title, empty, composer, children, border, ...props }: NoteListProps): react_jsx_runtime.JSX.Element;
32
+ /** How a note was left, which picks its glyph: dictated, written by an assistant, or typed. */
33
+ type NoteKind = "voice" | "agent" | "note";
34
+ /** Marks a note that stays at the top of the list and is edited elsewhere. */
35
+ interface NotePinned {
36
+ /** The badge text, such as "Client note · pinned". */
37
+ label: ReactNode;
38
+ /** The badge tooltip, such as where to edit it. */
39
+ title?: string;
40
+ }
41
+ /** The context this note belongs to. */
42
+ interface NoteScope {
43
+ /** The badge text, such as a project name or "General". */
44
+ label: ReactNode;
45
+ /** The badge tooltip. */
46
+ title?: string;
47
+ /** An info-toned badge, for a note tied to a context, instead of the neutral one. */
48
+ highlighted?: boolean;
49
+ }
50
+ interface NoteCardLabels {
51
+ /** After the author on a dictated note. Pass `null` to leave it out. */
52
+ voice: ReactNode;
53
+ /** The delete button's tooltip and accessible name. */
54
+ delete: string;
55
+ }
56
+ interface NoteCardProps extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
57
+ /** Who left it, already resolved to a display name. */
58
+ author: ReactNode;
59
+ kind?: NoteKind;
60
+ /** Pins the note: it sits on the card surface, not the muted one, with this badge. */
61
+ pinned?: NotePinned;
62
+ scope?: NoteScope;
63
+ /** When it was left, already formatted. */
64
+ date?: ReactNode;
65
+ /** The note, kept as written: line breaks are preserved. */
66
+ text?: ReactNode;
67
+ /** Adds a delete button. Confirm in the host before deleting anything. */
68
+ onDelete?: () => void;
69
+ /** Whether the delete button is always shown or appears on hover. Use `always` on touch screens. */
70
+ revealDelete?: "always" | "hover";
71
+ labels?: Partial<NoteCardLabels>;
72
+ }
73
+ /**
74
+ * One attributed note: who left it and how, an optional pinned badge, its
75
+ * optional context, when, and the text, with a delete button that appears
76
+ * on hover or always. The host resolves authors and context and confirms
77
+ * deletes.
78
+ *
79
+ * The root is the kit Card and keeps the kit's own `data-slot="card"`, which
80
+ * theme stylesheets select on.
81
+ */
82
+ declare function NoteCard({ author, kind, pinned, scope, date, text, onDelete, revealDelete, labels, ...props }: NoteCardProps): react_jsx_runtime.JSX.Element;
83
+ /** A display record: hosts resolve identity, context and dates before rendering. */
84
+ interface NoteItem extends Pick<NoteCardProps, "author" | "kind" | "pinned" | "scope" | "date" | "text" | "onDelete" | "revealDelete" | "labels"> {
85
+ id: string | number;
86
+ }
87
+ interface NotesProps extends Omit<NoteListProps, "count" | "children"> {
88
+ /** Displayed in the supplied order. Stable IDs keep each note's identity. */
89
+ notes: readonly NoteItem[];
90
+ }
91
+ /** Reusable notes area. The array owns the count and the rendered cards. */
92
+ declare function Notes({ notes, ...props }: NotesProps): react_jsx_runtime.JSX.Element;
93
+ interface NoteComposerLabels {
94
+ voice: string;
95
+ type: string;
96
+ input: string;
97
+ placeholder: string;
98
+ cancel: string;
99
+ submit: string;
100
+ error: string;
101
+ }
102
+ interface NoteComposerProps extends Omit<HTMLAttributes<HTMLElement>, "children" | "onSubmit" | "onChange"> {
103
+ /** Starts the host's recorder. Without it the composer opens for typing. */
104
+ onVoice?: () => void;
105
+ /** Receives trimmed text. Resolve only once saved; reject to preserve the draft. */
106
+ onSubmit: (text: string) => Promise<void>;
107
+ suggestions?: readonly string[];
108
+ labels?: Partial<NoteComposerLabels>;
109
+ /** Controlled text. In this mode the host clears or replaces it after saving. */
110
+ value?: string;
111
+ onValueChange?: (text: string) => void;
112
+ /** The host can keep a recovered draft open even when its text becomes empty. */
113
+ editing?: boolean;
114
+ onEditingChange?: (editing: boolean) => void;
115
+ onCancel?: () => void;
116
+ disabled?: boolean;
117
+ error?: ReactNode;
118
+ maxLength?: number;
119
+ }
120
+ /** Voice or text composer with one pending save and recoverable drafts. */
121
+ declare function NoteComposer({ onVoice, onSubmit, suggestions, labels, value, onValueChange, editing, onEditingChange, onCancel, disabled, error, maxLength, ...props }: NoteComposerProps): react_jsx_runtime.JSX.Element;
122
+
123
+ export { NoteCard, type NoteCardLabels, type NoteCardProps, NoteComposer, type NoteComposerLabels, type NoteComposerProps, type NoteItem, type NoteKind, NoteList, type NoteListProps, type NotePinned, type NoteScope, Notes, type NotesEmptyCopy, type NotesProps };
@@ -0,0 +1,123 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { HTMLAttributes, ReactNode } from 'react';
3
+
4
+ interface NotesEmptyCopy {
5
+ title: string;
6
+ description?: string;
7
+ }
8
+ interface NoteListProps extends Omit<HTMLAttributes<HTMLElement>, "title" | "children"> {
9
+ /** How many notes there are. Zero shows the empty state instead of `children`. */
10
+ count: number;
11
+ /** A skeleton row in place of the list, and no count yet. */
12
+ loading?: boolean;
13
+ /** The section heading. */
14
+ title?: ReactNode;
15
+ /** The blank slate's wording. Defaults to "No notes yet". */
16
+ empty?: NotesEmptyCopy;
17
+ /** Below the notes, usually a NoteComposer. */
18
+ composer?: ReactNode;
19
+ /** The notes, usually NoteCards, newest or pinned first. */
20
+ children?: ReactNode;
21
+ /** The kit PanelSection's divider. */
22
+ border?: "none" | "top" | "bottom";
23
+ }
24
+ /**
25
+ * A notes section, as a counted section: a skeleton row while they
26
+ * load, then the host's note cards, or the kit's empty state when there are
27
+ * none, with the composer underneath so a new note lands below the last.
28
+ *
29
+ * The root is the kit PanelSection, marked `data-slot="note-list"`.
30
+ */
31
+ declare function NoteList({ count, loading, title, empty, composer, children, border, ...props }: NoteListProps): react_jsx_runtime.JSX.Element;
32
+ /** How a note was left, which picks its glyph: dictated, written by an assistant, or typed. */
33
+ type NoteKind = "voice" | "agent" | "note";
34
+ /** Marks a note that stays at the top of the list and is edited elsewhere. */
35
+ interface NotePinned {
36
+ /** The badge text, such as "Client note · pinned". */
37
+ label: ReactNode;
38
+ /** The badge tooltip, such as where to edit it. */
39
+ title?: string;
40
+ }
41
+ /** The context this note belongs to. */
42
+ interface NoteScope {
43
+ /** The badge text, such as a project name or "General". */
44
+ label: ReactNode;
45
+ /** The badge tooltip. */
46
+ title?: string;
47
+ /** An info-toned badge, for a note tied to a context, instead of the neutral one. */
48
+ highlighted?: boolean;
49
+ }
50
+ interface NoteCardLabels {
51
+ /** After the author on a dictated note. Pass `null` to leave it out. */
52
+ voice: ReactNode;
53
+ /** The delete button's tooltip and accessible name. */
54
+ delete: string;
55
+ }
56
+ interface NoteCardProps extends Omit<HTMLAttributes<HTMLDivElement>, "children"> {
57
+ /** Who left it, already resolved to a display name. */
58
+ author: ReactNode;
59
+ kind?: NoteKind;
60
+ /** Pins the note: it sits on the card surface, not the muted one, with this badge. */
61
+ pinned?: NotePinned;
62
+ scope?: NoteScope;
63
+ /** When it was left, already formatted. */
64
+ date?: ReactNode;
65
+ /** The note, kept as written: line breaks are preserved. */
66
+ text?: ReactNode;
67
+ /** Adds a delete button. Confirm in the host before deleting anything. */
68
+ onDelete?: () => void;
69
+ /** Whether the delete button is always shown or appears on hover. Use `always` on touch screens. */
70
+ revealDelete?: "always" | "hover";
71
+ labels?: Partial<NoteCardLabels>;
72
+ }
73
+ /**
74
+ * One attributed note: who left it and how, an optional pinned badge, its
75
+ * optional context, when, and the text, with a delete button that appears
76
+ * on hover or always. The host resolves authors and context and confirms
77
+ * deletes.
78
+ *
79
+ * The root is the kit Card and keeps the kit's own `data-slot="card"`, which
80
+ * theme stylesheets select on.
81
+ */
82
+ declare function NoteCard({ author, kind, pinned, scope, date, text, onDelete, revealDelete, labels, ...props }: NoteCardProps): react_jsx_runtime.JSX.Element;
83
+ /** A display record: hosts resolve identity, context and dates before rendering. */
84
+ interface NoteItem extends Pick<NoteCardProps, "author" | "kind" | "pinned" | "scope" | "date" | "text" | "onDelete" | "revealDelete" | "labels"> {
85
+ id: string | number;
86
+ }
87
+ interface NotesProps extends Omit<NoteListProps, "count" | "children"> {
88
+ /** Displayed in the supplied order. Stable IDs keep each note's identity. */
89
+ notes: readonly NoteItem[];
90
+ }
91
+ /** Reusable notes area. The array owns the count and the rendered cards. */
92
+ declare function Notes({ notes, ...props }: NotesProps): react_jsx_runtime.JSX.Element;
93
+ interface NoteComposerLabels {
94
+ voice: string;
95
+ type: string;
96
+ input: string;
97
+ placeholder: string;
98
+ cancel: string;
99
+ submit: string;
100
+ error: string;
101
+ }
102
+ interface NoteComposerProps extends Omit<HTMLAttributes<HTMLElement>, "children" | "onSubmit" | "onChange"> {
103
+ /** Starts the host's recorder. Without it the composer opens for typing. */
104
+ onVoice?: () => void;
105
+ /** Receives trimmed text. Resolve only once saved; reject to preserve the draft. */
106
+ onSubmit: (text: string) => Promise<void>;
107
+ suggestions?: readonly string[];
108
+ labels?: Partial<NoteComposerLabels>;
109
+ /** Controlled text. In this mode the host clears or replaces it after saving. */
110
+ value?: string;
111
+ onValueChange?: (text: string) => void;
112
+ /** The host can keep a recovered draft open even when its text becomes empty. */
113
+ editing?: boolean;
114
+ onEditingChange?: (editing: boolean) => void;
115
+ onCancel?: () => void;
116
+ disabled?: boolean;
117
+ error?: ReactNode;
118
+ maxLength?: number;
119
+ }
120
+ /** Voice or text composer with one pending save and recoverable drafts. */
121
+ declare function NoteComposer({ onVoice, onSubmit, suggestions, labels, value, onValueChange, editing, onEditingChange, onCancel, disabled, error, maxLength, ...props }: NoteComposerProps): react_jsx_runtime.JSX.Element;
122
+
123
+ export { NoteCard, type NoteCardLabels, type NoteCardProps, NoteComposer, type NoteComposerLabels, type NoteComposerProps, type NoteItem, type NoteKind, NoteList, type NoteListProps, type NotePinned, type NoteScope, Notes, type NotesEmptyCopy, type NotesProps };