@epicbagel/saas-kit 1.0.0 → 1.2.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 +72 -3
- package/THIRD_PARTY_NOTICES.md +230 -7
- package/dist/chunk-2AU7ZRGX.cjs +96 -0
- package/dist/chunk-2BTDBZYN.cjs +154 -0
- package/dist/chunk-2HV2KKOE.cjs +38 -0
- package/dist/chunk-2KFZQJH5.cjs +29 -0
- package/dist/chunk-32Q4XOTU.cjs +204 -0
- package/dist/chunk-42RTTHND.js +29 -0
- package/dist/chunk-6FC65AZQ.js +38 -0
- package/dist/chunk-B765DSRG.cjs +66 -0
- package/dist/chunk-ELPV44S6.cjs +44 -0
- package/dist/chunk-EOUO3ORO.cjs +244 -0
- package/dist/chunk-EZCKWTH7.js +204 -0
- package/dist/chunk-F366BHWH.js +116 -0
- package/dist/chunk-GFG2R5BZ.js +132 -0
- package/dist/chunk-HAC32ALJ.js +244 -0
- package/dist/chunk-INNGGLMZ.js +44 -0
- package/dist/chunk-IW4ZIXXG.js +66 -0
- package/dist/chunk-JZOBIPFC.js +96 -0
- package/dist/chunk-KADJ56AH.cjs +416 -0
- package/dist/chunk-KENBU3NV.cjs +27 -0
- package/dist/chunk-M7FYGAGO.js +416 -0
- package/dist/chunk-MHYAVXOE.js +159 -0
- package/dist/chunk-RIWLAMME.cjs +159 -0
- package/dist/chunk-SUB4BAYE.cjs +73 -0
- package/dist/chunk-THWIJG5C.js +73 -0
- package/dist/chunk-V4YWTRLD.cjs +116 -0
- package/dist/chunk-VY5U4VGV.js +27 -0
- package/dist/chunk-XABXUP6L.cjs +132 -0
- package/dist/chunk-Z45YKVAM.js +154 -0
- package/dist/primitives/action-dock.cjs +8 -0
- package/dist/primitives/action-dock.d.cts +10 -0
- package/dist/primitives/action-dock.d.ts +10 -0
- package/dist/primitives/action-dock.js +8 -0
- package/dist/primitives/attachment.cjs +25 -203
- package/dist/primitives/attachment.d.cts +1 -1
- package/dist/primitives/attachment.d.ts +1 -1
- package/dist/primitives/attachment.js +12 -190
- package/dist/primitives/badge.d.cts +1 -1
- package/dist/primitives/badge.d.ts +1 -1
- package/dist/primitives/board-view.cjs +3 -3
- package/dist/primitives/board-view.js +2 -2
- package/dist/primitives/bubble.cjs +14 -0
- package/dist/primitives/bubble.d.cts +21 -0
- package/dist/primitives/bubble.d.ts +21 -0
- package/dist/primitives/bubble.js +14 -0
- package/dist/primitives/button.d.cts +3 -3
- package/dist/primitives/button.d.ts +3 -3
- package/dist/primitives/chat.cjs +881 -0
- package/dist/primitives/chat.d.cts +345 -0
- package/dist/primitives/chat.d.ts +345 -0
- package/dist/primitives/chat.js +881 -0
- package/dist/primitives/connection.cjs +6 -6
- package/dist/primitives/connection.js +7 -7
- package/dist/primitives/file-dropzone.cjs +7 -107
- package/dist/primitives/file-dropzone.d.cts +66 -3
- package/dist/primitives/file-dropzone.d.ts +66 -3
- package/dist/primitives/file-dropzone.js +13 -113
- package/dist/primitives/input-group.cjs +21 -0
- package/dist/primitives/input-group.d.cts +20 -0
- package/dist/primitives/input-group.d.ts +20 -0
- package/dist/primitives/input-group.js +21 -0
- package/dist/primitives/item.cjs +197 -0
- package/dist/primitives/item.d.cts +28 -0
- package/dist/primitives/item.d.ts +28 -0
- package/dist/primitives/item.js +197 -0
- package/dist/primitives/lazy-markdown.cjs +10 -0
- package/dist/primitives/lazy-markdown.d.cts +20 -0
- package/dist/primitives/lazy-markdown.d.ts +20 -0
- package/dist/primitives/lazy-markdown.js +10 -0
- package/dist/primitives/markdown.cjs +17 -0
- package/dist/primitives/markdown.d.cts +32 -0
- package/dist/primitives/markdown.d.ts +32 -0
- package/dist/primitives/markdown.js +17 -0
- package/dist/primitives/marker.cjs +14 -0
- package/dist/primitives/marker.d.cts +15 -0
- package/dist/primitives/marker.d.ts +15 -0
- package/dist/primitives/marker.js +14 -0
- package/dist/primitives/message-scroller.cjs +26 -0
- package/dist/primitives/message-scroller.d.cts +16 -0
- package/dist/primitives/message-scroller.d.ts +16 -0
- package/dist/primitives/message-scroller.js +26 -0
- package/dist/primitives/message.cjs +7 -84
- package/dist/primitives/message.js +8 -85
- package/dist/primitives/resource-list.cjs +3 -3
- package/dist/primitives/resource-list.js +2 -2
- package/dist/primitives/rich-text.cjs +3 -38
- package/dist/primitives/rich-text.js +3 -38
- package/dist/primitives/section-header.d.cts +1 -1
- package/dist/primitives/section-header.d.ts +1 -1
- package/dist/primitives/spinner.cjs +23 -0
- package/dist/primitives/spinner.d.cts +6 -0
- package/dist/primitives/spinner.d.ts +6 -0
- package/dist/primitives/spinner.js +23 -0
- package/dist/primitives/suggestion.cjs +11 -0
- package/dist/primitives/suggestion.d.cts +19 -0
- package/dist/primitives/suggestion.d.ts +19 -0
- package/dist/primitives/suggestion.js +11 -0
- package/dist/primitives/switch-field.cjs +2 -2
- package/dist/primitives/switch-field.js +3 -3
- package/dist/primitives/textarea.cjs +4 -33
- package/dist/primitives/textarea.js +3 -32
- package/dist/primitives/toggle-group.d.cts +2 -2
- package/dist/primitives/toggle-group.d.ts +2 -2
- package/dist/primitives/toggle.d.cts +2 -2
- package/dist/primitives/toggle.d.ts +2 -2
- package/dist/primitives/trace.cjs +23 -0
- package/dist/primitives/trace.d.cts +22 -0
- package/dist/primitives/trace.d.ts +22 -0
- package/dist/primitives/trace.js +23 -0
- package/dist/primitives/voice-dictation-button.cjs +5 -239
- package/dist/primitives/voice-dictation-button.js +4 -238
- package/package.json +125 -2
- package/src/styles/components/bubble.css +81 -0
- package/src/styles/components/marker.css +27 -0
- package/src/styles/components/message-scroller.css +11 -0
- package/src/styles/components.css +3 -0
- package/src/styles/utilities.css +3 -2
- package/dist/{chunk-UGF2K6NR.js → chunk-HRLP4BHJ.js} +6 -6
- package/dist/{chunk-RWWOFWLP.cjs → chunk-IH3COANJ.cjs} +3 -3
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
Button
|
|
4
|
+
} from "./chunk-HQRWRRZJ.js";
|
|
5
|
+
import {
|
|
6
|
+
cn
|
|
7
|
+
} from "./chunk-G6SRSWXB.js";
|
|
8
|
+
|
|
9
|
+
// src/primitives/attachment.tsx
|
|
10
|
+
import { cva } from "class-variance-authority";
|
|
11
|
+
import { Slot } from "radix-ui";
|
|
12
|
+
import { jsx } from "react/jsx-runtime";
|
|
13
|
+
var attachmentVariants = cva(
|
|
14
|
+
"cn-attachment group/attachment relative flex max-w-full min-w-0 shrink-0 flex-wrap border bg-card text-card-foreground transition-colors has-[>a,>button]:hover:bg-muted/50 data-[state=error]:border-destructive/30 data-[state=idle]:border-dashed",
|
|
15
|
+
{
|
|
16
|
+
variants: {
|
|
17
|
+
size: {
|
|
18
|
+
default: "cn-attachment-size-default",
|
|
19
|
+
sm: "cn-attachment-size-sm",
|
|
20
|
+
xs: "cn-attachment-size-xs"
|
|
21
|
+
},
|
|
22
|
+
orientation: {
|
|
23
|
+
horizontal: "cn-attachment-orientation-horizontal items-center",
|
|
24
|
+
vertical: "cn-attachment-orientation-vertical flex-col"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
function Attachment({
|
|
30
|
+
className,
|
|
31
|
+
state = "done",
|
|
32
|
+
size = "default",
|
|
33
|
+
orientation = "horizontal",
|
|
34
|
+
...props
|
|
35
|
+
}) {
|
|
36
|
+
const resolvedOrientation = orientation ?? "horizontal";
|
|
37
|
+
return /* @__PURE__ */ jsx(
|
|
38
|
+
"div",
|
|
39
|
+
{
|
|
40
|
+
"data-slot": "attachment",
|
|
41
|
+
"data-state": state,
|
|
42
|
+
"data-size": size,
|
|
43
|
+
"data-orientation": resolvedOrientation,
|
|
44
|
+
className: cn(attachmentVariants({ size, orientation }), className),
|
|
45
|
+
...props
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
var attachmentMediaVariants = cva(
|
|
50
|
+
"cn-attachment-media relative flex aspect-square shrink-0 items-center justify-center overflow-hidden group-data-[state=error]/attachment:bg-destructive/10 group-data-[state=error]/attachment:text-destructive [&_svg]:pointer-events-none",
|
|
51
|
+
{
|
|
52
|
+
variants: {
|
|
53
|
+
variant: {
|
|
54
|
+
icon: "cn-attachment-media-variant-icon",
|
|
55
|
+
image: "cn-attachment-media-variant-image *:[img]:aspect-square *:[img]:w-full *:[img]:object-cover"
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
defaultVariants: {
|
|
59
|
+
variant: "icon"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
);
|
|
63
|
+
function AttachmentMedia({
|
|
64
|
+
className,
|
|
65
|
+
variant = "icon",
|
|
66
|
+
...props
|
|
67
|
+
}) {
|
|
68
|
+
return /* @__PURE__ */ jsx(
|
|
69
|
+
"div",
|
|
70
|
+
{
|
|
71
|
+
"data-slot": "attachment-media",
|
|
72
|
+
"data-variant": variant,
|
|
73
|
+
className: cn(attachmentMediaVariants({ variant }), className),
|
|
74
|
+
...props
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
function AttachmentContent({
|
|
79
|
+
className,
|
|
80
|
+
...props
|
|
81
|
+
}) {
|
|
82
|
+
return /* @__PURE__ */ jsx(
|
|
83
|
+
"div",
|
|
84
|
+
{
|
|
85
|
+
"data-slot": "attachment-content",
|
|
86
|
+
className: cn(
|
|
87
|
+
"cn-attachment-content max-w-full min-w-0 flex-1",
|
|
88
|
+
className
|
|
89
|
+
),
|
|
90
|
+
...props
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
function AttachmentTitle({
|
|
95
|
+
className,
|
|
96
|
+
...props
|
|
97
|
+
}) {
|
|
98
|
+
return /* @__PURE__ */ jsx(
|
|
99
|
+
"span",
|
|
100
|
+
{
|
|
101
|
+
"data-slot": "attachment-title",
|
|
102
|
+
className: cn(
|
|
103
|
+
"cn-attachment-title block max-w-full min-w-0 truncate group-data-[state=processing]/attachment:shimmer group-data-[state=uploading]/attachment:shimmer",
|
|
104
|
+
className
|
|
105
|
+
),
|
|
106
|
+
...props
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
function AttachmentDescription({
|
|
111
|
+
className,
|
|
112
|
+
...props
|
|
113
|
+
}) {
|
|
114
|
+
return /* @__PURE__ */ jsx(
|
|
115
|
+
"span",
|
|
116
|
+
{
|
|
117
|
+
"data-slot": "attachment-description",
|
|
118
|
+
className: cn(
|
|
119
|
+
"cn-attachment-description block min-w-0 truncate text-muted-foreground group-data-[state=error]/attachment:text-destructive/80",
|
|
120
|
+
"max-w-full",
|
|
121
|
+
className
|
|
122
|
+
),
|
|
123
|
+
...props
|
|
124
|
+
}
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
function AttachmentActions({
|
|
128
|
+
className,
|
|
129
|
+
...props
|
|
130
|
+
}) {
|
|
131
|
+
return /* @__PURE__ */ jsx(
|
|
132
|
+
"div",
|
|
133
|
+
{
|
|
134
|
+
"data-slot": "attachment-actions",
|
|
135
|
+
className: cn(
|
|
136
|
+
"cn-attachment-actions flex shrink-0 items-center",
|
|
137
|
+
className
|
|
138
|
+
),
|
|
139
|
+
...props
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
function AttachmentAction({
|
|
144
|
+
className,
|
|
145
|
+
variant,
|
|
146
|
+
size = "icon-xs",
|
|
147
|
+
...props
|
|
148
|
+
}) {
|
|
149
|
+
return /* @__PURE__ */ jsx(
|
|
150
|
+
Button,
|
|
151
|
+
{
|
|
152
|
+
"data-slot": "attachment-action",
|
|
153
|
+
variant: variant ?? "ghost",
|
|
154
|
+
size,
|
|
155
|
+
className: cn("cn-attachment-action", className),
|
|
156
|
+
...props
|
|
157
|
+
}
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
function AttachmentTrigger({
|
|
161
|
+
className,
|
|
162
|
+
asChild = false,
|
|
163
|
+
type,
|
|
164
|
+
...props
|
|
165
|
+
}) {
|
|
166
|
+
const Comp = asChild ? Slot.Root : "button";
|
|
167
|
+
return /* @__PURE__ */ jsx(
|
|
168
|
+
Comp,
|
|
169
|
+
{
|
|
170
|
+
"data-slot": "attachment-trigger",
|
|
171
|
+
type: asChild ? void 0 : type ?? "button",
|
|
172
|
+
className: cn(
|
|
173
|
+
"cn-attachment-trigger absolute inset-0 z-10 outline-none",
|
|
174
|
+
className
|
|
175
|
+
),
|
|
176
|
+
...props
|
|
177
|
+
}
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
function AttachmentGroup({ className, ...props }) {
|
|
181
|
+
return /* @__PURE__ */ jsx(
|
|
182
|
+
"div",
|
|
183
|
+
{
|
|
184
|
+
"data-slot": "attachment-group",
|
|
185
|
+
className: cn(
|
|
186
|
+
"cn-attachment-group flex min-w-0 scroll-fade-x snap-x snap-mandatory scrollbar-none overflow-x-auto overscroll-x-contain *:data-[slot=attachment]:flex-none *:data-[slot=attachment]:snap-start",
|
|
187
|
+
className
|
|
188
|
+
),
|
|
189
|
+
...props
|
|
190
|
+
}
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export {
|
|
195
|
+
Attachment,
|
|
196
|
+
AttachmentMedia,
|
|
197
|
+
AttachmentContent,
|
|
198
|
+
AttachmentTitle,
|
|
199
|
+
AttachmentDescription,
|
|
200
|
+
AttachmentActions,
|
|
201
|
+
AttachmentAction,
|
|
202
|
+
AttachmentTrigger,
|
|
203
|
+
AttachmentGroup
|
|
204
|
+
};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
cn
|
|
4
|
+
} from "./chunk-G6SRSWXB.js";
|
|
5
|
+
|
|
6
|
+
// src/primitives/bubble.tsx
|
|
7
|
+
import { cva } from "class-variance-authority";
|
|
8
|
+
import { Slot } from "radix-ui";
|
|
9
|
+
import { jsx } from "react/jsx-runtime";
|
|
10
|
+
function BubbleGroup({ className, ...props }) {
|
|
11
|
+
return /* @__PURE__ */ jsx(
|
|
12
|
+
"div",
|
|
13
|
+
{
|
|
14
|
+
"data-slot": "bubble-group",
|
|
15
|
+
className: cn("cn-bubble-group flex min-w-0 flex-col", className),
|
|
16
|
+
...props
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
var bubbleVariants = cva(
|
|
21
|
+
"cn-bubble group/bubble relative flex w-fit min-w-0 flex-col",
|
|
22
|
+
{
|
|
23
|
+
variants: {
|
|
24
|
+
variant: {
|
|
25
|
+
default: "cn-bubble-variant-default",
|
|
26
|
+
secondary: "cn-bubble-variant-secondary",
|
|
27
|
+
muted: "cn-bubble-variant-muted",
|
|
28
|
+
tinted: "cn-bubble-variant-tinted",
|
|
29
|
+
outline: "cn-bubble-variant-outline",
|
|
30
|
+
ghost: "cn-bubble-variant-ghost",
|
|
31
|
+
destructive: "cn-bubble-variant-destructive"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
defaultVariants: {
|
|
35
|
+
variant: "default"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
);
|
|
39
|
+
function Bubble({
|
|
40
|
+
variant = "default",
|
|
41
|
+
align = "start",
|
|
42
|
+
className,
|
|
43
|
+
...props
|
|
44
|
+
}) {
|
|
45
|
+
return /* @__PURE__ */ jsx(
|
|
46
|
+
"div",
|
|
47
|
+
{
|
|
48
|
+
"data-slot": "bubble",
|
|
49
|
+
"data-variant": variant,
|
|
50
|
+
"data-align": align,
|
|
51
|
+
className: cn(bubbleVariants({ variant }), className),
|
|
52
|
+
...props
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
function BubbleContent({
|
|
57
|
+
asChild = false,
|
|
58
|
+
className,
|
|
59
|
+
...props
|
|
60
|
+
}) {
|
|
61
|
+
const Comp = asChild ? Slot.Root : "div";
|
|
62
|
+
return /* @__PURE__ */ jsx(
|
|
63
|
+
Comp,
|
|
64
|
+
{
|
|
65
|
+
"data-slot": "bubble-content",
|
|
66
|
+
className: cn(
|
|
67
|
+
"cn-bubble-content w-fit max-w-full min-w-0 overflow-hidden wrap-break-word [button]:text-left [button,a]:transition-colors",
|
|
68
|
+
className
|
|
69
|
+
),
|
|
70
|
+
...props
|
|
71
|
+
}
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
var bubbleReactionsVariants = cva(
|
|
75
|
+
"cn-bubble-reactions absolute z-10 flex w-fit items-center justify-center",
|
|
76
|
+
{
|
|
77
|
+
variants: {
|
|
78
|
+
side: {
|
|
79
|
+
top: "cn-bubble-reactions-side-top",
|
|
80
|
+
bottom: "cn-bubble-reactions-side-bottom"
|
|
81
|
+
},
|
|
82
|
+
align: {
|
|
83
|
+
start: "cn-bubble-reactions-align-start",
|
|
84
|
+
end: "cn-bubble-reactions-align-end"
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
defaultVariants: {
|
|
88
|
+
side: "bottom",
|
|
89
|
+
align: "end"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
function BubbleReactions({
|
|
94
|
+
side = "bottom",
|
|
95
|
+
align = "end",
|
|
96
|
+
className,
|
|
97
|
+
...props
|
|
98
|
+
}) {
|
|
99
|
+
return /* @__PURE__ */ jsx(
|
|
100
|
+
"div",
|
|
101
|
+
{
|
|
102
|
+
"data-slot": "bubble-reactions",
|
|
103
|
+
"data-align": align,
|
|
104
|
+
"data-side": side,
|
|
105
|
+
className: cn(bubbleReactionsVariants({ side, align }), className),
|
|
106
|
+
...props
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export {
|
|
112
|
+
BubbleGroup,
|
|
113
|
+
Bubble,
|
|
114
|
+
BubbleContent,
|
|
115
|
+
BubbleReactions
|
|
116
|
+
};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
Button
|
|
4
|
+
} from "./chunk-HQRWRRZJ.js";
|
|
5
|
+
import {
|
|
6
|
+
cn
|
|
7
|
+
} from "./chunk-G6SRSWXB.js";
|
|
8
|
+
|
|
9
|
+
// src/primitives/message-scroller.tsx
|
|
10
|
+
import {
|
|
11
|
+
MessageScroller as MessageScrollerPrimitive,
|
|
12
|
+
useMessageScroller,
|
|
13
|
+
useMessageScrollerScrollable,
|
|
14
|
+
useMessageScrollerVisibility
|
|
15
|
+
} from "@shadcn/react/message-scroller";
|
|
16
|
+
import { ArrowDown } from "lucide-react";
|
|
17
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
18
|
+
function MessageScrollerProvider(props) {
|
|
19
|
+
return /* @__PURE__ */ jsx(MessageScrollerPrimitive.Provider, { ...props });
|
|
20
|
+
}
|
|
21
|
+
function MessageScroller({
|
|
22
|
+
className,
|
|
23
|
+
...props
|
|
24
|
+
}) {
|
|
25
|
+
return /* @__PURE__ */ jsx(
|
|
26
|
+
MessageScrollerPrimitive.Root,
|
|
27
|
+
{
|
|
28
|
+
"data-slot": "message-scroller",
|
|
29
|
+
className: cn(
|
|
30
|
+
"cn-message-scroller group/message-scroller relative flex size-full min-h-0 flex-col overflow-hidden",
|
|
31
|
+
className
|
|
32
|
+
),
|
|
33
|
+
...props
|
|
34
|
+
}
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
function MessageScrollerViewport({
|
|
38
|
+
className,
|
|
39
|
+
...props
|
|
40
|
+
}) {
|
|
41
|
+
return /* @__PURE__ */ jsx(
|
|
42
|
+
MessageScrollerPrimitive.Viewport,
|
|
43
|
+
{
|
|
44
|
+
"data-slot": "message-scroller-viewport",
|
|
45
|
+
className: cn(
|
|
46
|
+
// @shadcn/react 0.3: while an automatic scroll runs the scrollbar goes
|
|
47
|
+
// transparent rather than away (so the gutter, and the text, never
|
|
48
|
+
// shift), and the viewport stays invisible until its opening scroll
|
|
49
|
+
// position is applied, so a long thread never flashes its first turn.
|
|
50
|
+
"cn-message-scroller-viewport size-full min-h-0 min-w-0 scroll-fade-b scrollbar-thin scrollbar-gutter-stable overflow-y-auto overscroll-contain contain-content data-autoscrolling:scrollbar-thumb-transparent data-autoscrolling:scrollbar-track-transparent data-pending-scroll:invisible",
|
|
51
|
+
className
|
|
52
|
+
),
|
|
53
|
+
...props
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
function MessageScrollerContent({
|
|
58
|
+
className,
|
|
59
|
+
...props
|
|
60
|
+
}) {
|
|
61
|
+
return /* @__PURE__ */ jsx(
|
|
62
|
+
MessageScrollerPrimitive.Content,
|
|
63
|
+
{
|
|
64
|
+
"data-slot": "message-scroller-content",
|
|
65
|
+
className: cn(
|
|
66
|
+
"cn-message-scroller-content flex h-max min-h-full flex-col",
|
|
67
|
+
className
|
|
68
|
+
),
|
|
69
|
+
...props
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
function MessageScrollerItem({
|
|
74
|
+
className,
|
|
75
|
+
scrollAnchor = false,
|
|
76
|
+
...props
|
|
77
|
+
}) {
|
|
78
|
+
return /* @__PURE__ */ jsx(
|
|
79
|
+
MessageScrollerPrimitive.Item,
|
|
80
|
+
{
|
|
81
|
+
"data-slot": "message-scroller-item",
|
|
82
|
+
scrollAnchor,
|
|
83
|
+
className: cn(
|
|
84
|
+
"cn-message-scroller-item min-w-0 shrink-0 [contain-intrinsic-size:auto_10rem] [content-visibility:auto]",
|
|
85
|
+
className
|
|
86
|
+
),
|
|
87
|
+
...props
|
|
88
|
+
}
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
function MessageScrollerButton({
|
|
92
|
+
direction = "end",
|
|
93
|
+
className,
|
|
94
|
+
children,
|
|
95
|
+
render,
|
|
96
|
+
variant = "secondary",
|
|
97
|
+
size = "icon-sm",
|
|
98
|
+
...props
|
|
99
|
+
}) {
|
|
100
|
+
return /* @__PURE__ */ jsx(
|
|
101
|
+
MessageScrollerPrimitive.Button,
|
|
102
|
+
{
|
|
103
|
+
"data-slot": "message-scroller-button",
|
|
104
|
+
"data-direction": direction,
|
|
105
|
+
"data-variant": variant,
|
|
106
|
+
"data-size": size,
|
|
107
|
+
direction,
|
|
108
|
+
className: cn(
|
|
109
|
+
"cn-message-scroller-button absolute inset-s-1/2 -translate-x-1/2 border-border bg-background text-foreground transition-[translate,scale,opacity] duration-200 hover:bg-muted hover:text-foreground data-[active=false]:pointer-events-none data-[active=false]:scale-95 data-[active=false]:opacity-0 data-[active=false]:duration-400 data-[active=false]:ease-[cubic-bezier(0.7,0,0.84,0)] data-[active=true]:translate-y-0 data-[active=true]:scale-100 data-[active=true]:opacity-100 data-[active=true]:ease-[cubic-bezier(0.23,1,0.32,1)] data-[direction=end]:bottom-4 data-[direction=end]:data-[active=false]:translate-y-full data-[direction=start]:top-4 data-[direction=start]:data-[active=false]:-translate-y-full rtl:translate-x-1/2 data-[direction=start]:[&_svg]:rotate-180",
|
|
110
|
+
className
|
|
111
|
+
),
|
|
112
|
+
render: render ?? /* @__PURE__ */ jsx(Button, { variant, size }),
|
|
113
|
+
...props,
|
|
114
|
+
children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
115
|
+
/* @__PURE__ */ jsx(ArrowDown, { className: "h-4 w-4" }),
|
|
116
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: direction === "end" ? "Scroll to end" : "Scroll to start" })
|
|
117
|
+
] })
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export {
|
|
123
|
+
useMessageScroller,
|
|
124
|
+
useMessageScrollerScrollable,
|
|
125
|
+
useMessageScrollerVisibility,
|
|
126
|
+
MessageScrollerProvider,
|
|
127
|
+
MessageScroller,
|
|
128
|
+
MessageScrollerViewport,
|
|
129
|
+
MessageScrollerContent,
|
|
130
|
+
MessageScrollerItem,
|
|
131
|
+
MessageScrollerButton
|
|
132
|
+
};
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
Button
|
|
4
|
+
} from "./chunk-HQRWRRZJ.js";
|
|
5
|
+
import {
|
|
6
|
+
cn
|
|
7
|
+
} from "./chunk-G6SRSWXB.js";
|
|
8
|
+
|
|
9
|
+
// src/primitives/voice-dictation-button.tsx
|
|
10
|
+
import {
|
|
11
|
+
useCallback,
|
|
12
|
+
useEffect,
|
|
13
|
+
useRef,
|
|
14
|
+
useState
|
|
15
|
+
} from "react";
|
|
16
|
+
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
17
|
+
import { Mic, X } from "lucide-react";
|
|
18
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
19
|
+
function VoiceDictationButton({
|
|
20
|
+
onCommit,
|
|
21
|
+
onCancel,
|
|
22
|
+
title = "Dictate your message",
|
|
23
|
+
caption = "listening",
|
|
24
|
+
lang = "en-US",
|
|
25
|
+
continuous = true,
|
|
26
|
+
className,
|
|
27
|
+
size = "sm",
|
|
28
|
+
showLabel = false,
|
|
29
|
+
children,
|
|
30
|
+
disabled = false,
|
|
31
|
+
visibility = "visible",
|
|
32
|
+
shrink = true
|
|
33
|
+
}) {
|
|
34
|
+
const [supported, setSupported] = useState(false);
|
|
35
|
+
const [open, setOpen] = useState(false);
|
|
36
|
+
const [transcript, setTranscript] = useState("");
|
|
37
|
+
const [interim, setInterim] = useState("");
|
|
38
|
+
const [errored, setErrored] = useState(false);
|
|
39
|
+
const recognitionRef = useRef(null);
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
const w = window;
|
|
42
|
+
const Ctor = w.SpeechRecognition ?? w.webkitSpeechRecognition;
|
|
43
|
+
setSupported(typeof Ctor === "function");
|
|
44
|
+
}, []);
|
|
45
|
+
const stop = useCallback(() => {
|
|
46
|
+
recognitionRef.current?.stop();
|
|
47
|
+
recognitionRef.current = null;
|
|
48
|
+
}, []);
|
|
49
|
+
const startRecognition = useCallback(() => {
|
|
50
|
+
const w = window;
|
|
51
|
+
const Ctor = w.SpeechRecognition ?? w.webkitSpeechRecognition;
|
|
52
|
+
if (!Ctor) return;
|
|
53
|
+
const rec = new Ctor();
|
|
54
|
+
rec.continuous = continuous;
|
|
55
|
+
rec.interimResults = true;
|
|
56
|
+
rec.lang = lang;
|
|
57
|
+
rec.onresult = (event) => {
|
|
58
|
+
let finalChunk = "";
|
|
59
|
+
let interimChunk = "";
|
|
60
|
+
for (let i = event.resultIndex; i < event.results.length; i++) {
|
|
61
|
+
const r = event.results[i];
|
|
62
|
+
if (!r) continue;
|
|
63
|
+
if (r.isFinal) finalChunk += r[0].transcript;
|
|
64
|
+
else interimChunk += r[0].transcript;
|
|
65
|
+
}
|
|
66
|
+
if (finalChunk) {
|
|
67
|
+
setTranscript((prev) => prev ? prev + " " + finalChunk : finalChunk);
|
|
68
|
+
setInterim("");
|
|
69
|
+
} else if (interimChunk) {
|
|
70
|
+
setInterim(interimChunk);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
rec.onerror = () => {
|
|
74
|
+
setErrored(true);
|
|
75
|
+
};
|
|
76
|
+
rec.onend = () => {
|
|
77
|
+
recognitionRef.current = null;
|
|
78
|
+
};
|
|
79
|
+
recognitionRef.current = rec;
|
|
80
|
+
setErrored(false);
|
|
81
|
+
rec.start();
|
|
82
|
+
}, [continuous, lang]);
|
|
83
|
+
const openOverlay = useCallback(() => {
|
|
84
|
+
setTranscript("");
|
|
85
|
+
setInterim("");
|
|
86
|
+
setOpen(true);
|
|
87
|
+
startRecognition();
|
|
88
|
+
}, [startRecognition]);
|
|
89
|
+
const closeOverlay = useCallback(() => {
|
|
90
|
+
stop();
|
|
91
|
+
setOpen(false);
|
|
92
|
+
setInterim("");
|
|
93
|
+
}, [stop]);
|
|
94
|
+
const handleDone = useCallback(() => {
|
|
95
|
+
const final = `${transcript} ${interim}`.trim();
|
|
96
|
+
closeOverlay();
|
|
97
|
+
if (final) onCommit(final);
|
|
98
|
+
else onCancel?.();
|
|
99
|
+
}, [transcript, interim, onCommit, onCancel, closeOverlay]);
|
|
100
|
+
const handleCancel = useCallback(() => {
|
|
101
|
+
closeOverlay();
|
|
102
|
+
onCancel?.();
|
|
103
|
+
}, [closeOverlay, onCancel]);
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
if (!open) return;
|
|
106
|
+
const onKey = (e) => {
|
|
107
|
+
if (e.key === "Enter" && !e.shiftKey) handleDone();
|
|
108
|
+
};
|
|
109
|
+
document.addEventListener("keydown", onKey);
|
|
110
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
111
|
+
}, [open, handleDone]);
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
return () => {
|
|
114
|
+
recognitionRef.current?.abort();
|
|
115
|
+
};
|
|
116
|
+
}, []);
|
|
117
|
+
if (!supported) return null;
|
|
118
|
+
const displayTranscript = `${transcript}${interim ? (transcript ? " " : "") + interim : ""}`;
|
|
119
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
120
|
+
children ? /* @__PURE__ */ jsx(
|
|
121
|
+
"button",
|
|
122
|
+
{
|
|
123
|
+
type: "button",
|
|
124
|
+
onClick: openOverlay,
|
|
125
|
+
disabled,
|
|
126
|
+
"aria-label": "Start dictation",
|
|
127
|
+
className: cn(visibility === "hidden" && "hidden", className),
|
|
128
|
+
children
|
|
129
|
+
}
|
|
130
|
+
) : /* @__PURE__ */ jsx(
|
|
131
|
+
Button,
|
|
132
|
+
{
|
|
133
|
+
type: "button",
|
|
134
|
+
onClick: openOverlay,
|
|
135
|
+
disabled,
|
|
136
|
+
variant: "outline",
|
|
137
|
+
size,
|
|
138
|
+
"aria-label": "Start dictation",
|
|
139
|
+
className: cn("transition-colors", visibility === "hidden" && "hidden", !shrink && "shrink-0", className),
|
|
140
|
+
children: /* @__PURE__ */ jsxs("span", { className: "flex items-center justify-center gap-2", children: [
|
|
141
|
+
/* @__PURE__ */ jsx(Mic, { className: "h-4 w-4" }),
|
|
142
|
+
showLabel && /* @__PURE__ */ jsx("span", { children: "Speak" })
|
|
143
|
+
] })
|
|
144
|
+
}
|
|
145
|
+
),
|
|
146
|
+
/* @__PURE__ */ jsx(
|
|
147
|
+
DialogPrimitive.Root,
|
|
148
|
+
{
|
|
149
|
+
open,
|
|
150
|
+
onOpenChange: (next) => {
|
|
151
|
+
if (!next) closeOverlay();
|
|
152
|
+
},
|
|
153
|
+
children: /* @__PURE__ */ jsx(DialogPrimitive.Portal, { children: /* @__PURE__ */ jsxs(
|
|
154
|
+
DialogPrimitive.Content,
|
|
155
|
+
{
|
|
156
|
+
"aria-label": "Voice dictation",
|
|
157
|
+
onOpenAutoFocus: (e) => e.preventDefault(),
|
|
158
|
+
onMouseDown: (e) => {
|
|
159
|
+
if (e.target === e.currentTarget) handleCancel();
|
|
160
|
+
},
|
|
161
|
+
className: "fixed inset-0 z-[200] flex flex-col bg-background outline-hidden md:items-center md:justify-center md:bg-black/40 md:backdrop-blur-sm",
|
|
162
|
+
children: [
|
|
163
|
+
/* @__PURE__ */ jsx(DialogPrimitive.Title, { className: "sr-only", children: "Voice dictation" }),
|
|
164
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 md:flex-initial w-full md:max-w-lg md:rounded-xl bg-background flex flex-col md:max-h-[80vh] md:shadow-2xl md:border md:border-border", children: [
|
|
165
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-3 border-b border-border md:rounded-t-xl", children: [
|
|
166
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono text-xs uppercase tracking-wider text-muted-foreground", children: caption }),
|
|
167
|
+
/* @__PURE__ */ jsx(
|
|
168
|
+
"button",
|
|
169
|
+
{
|
|
170
|
+
type: "button",
|
|
171
|
+
onClick: handleCancel,
|
|
172
|
+
"aria-label": "Cancel",
|
|
173
|
+
className: "p-1 -m-1 rounded-sm hover:bg-muted/60 transition-colors",
|
|
174
|
+
children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4" })
|
|
175
|
+
}
|
|
176
|
+
)
|
|
177
|
+
] }),
|
|
178
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col items-center justify-center px-6 text-center", children: [
|
|
179
|
+
/* @__PURE__ */ jsxs("div", { className: "relative w-24 h-24 mb-10 flex items-center justify-center", children: [
|
|
180
|
+
/* @__PURE__ */ jsx(
|
|
181
|
+
"span",
|
|
182
|
+
{
|
|
183
|
+
"aria-hidden": true,
|
|
184
|
+
className: cn(
|
|
185
|
+
"absolute inset-0 rounded-full",
|
|
186
|
+
errored ? "bg-destructive/20" : "bg-destructive/20 animate-ping"
|
|
187
|
+
)
|
|
188
|
+
}
|
|
189
|
+
),
|
|
190
|
+
/* @__PURE__ */ jsx(
|
|
191
|
+
"span",
|
|
192
|
+
{
|
|
193
|
+
"aria-hidden": true,
|
|
194
|
+
className: cn(
|
|
195
|
+
"absolute inset-2 rounded-full",
|
|
196
|
+
errored ? "bg-destructive/40" : "bg-destructive/40"
|
|
197
|
+
)
|
|
198
|
+
}
|
|
199
|
+
),
|
|
200
|
+
/* @__PURE__ */ jsx(Mic, { className: "relative h-9 w-9 text-destructive-foreground" })
|
|
201
|
+
] }),
|
|
202
|
+
title && /* @__PURE__ */ jsx("div", { className: "text-base font-medium text-muted-foreground mb-3", children: title }),
|
|
203
|
+
/* @__PURE__ */ jsx("p", { className: "text-xl md:text-2xl leading-relaxed min-h-[5rem] max-w-xl text-foreground", children: displayTranscript ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
204
|
+
/* @__PURE__ */ jsx("span", { children: transcript }),
|
|
205
|
+
interim && /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
|
|
206
|
+
transcript ? " " : "",
|
|
207
|
+
interim
|
|
208
|
+
] })
|
|
209
|
+
] }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground italic text-base", children: "Start speaking \u2014 I'm listening." }) }),
|
|
210
|
+
errored && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive mt-4", children: "Couldn't access the microphone. Check permissions." })
|
|
211
|
+
] }),
|
|
212
|
+
/* @__PURE__ */ jsxs("div", { className: "border-t border-border px-4 py-4 pb-[calc(1rem+env(safe-area-inset-bottom))] md:pb-4 md:rounded-b-xl flex flex-col items-stretch gap-2", children: [
|
|
213
|
+
/* @__PURE__ */ jsx(
|
|
214
|
+
Button,
|
|
215
|
+
{
|
|
216
|
+
size: "lg",
|
|
217
|
+
className: "h-12 w-full",
|
|
218
|
+
onClick: handleDone,
|
|
219
|
+
disabled: !displayTranscript.trim(),
|
|
220
|
+
children: "Done"
|
|
221
|
+
}
|
|
222
|
+
),
|
|
223
|
+
/* @__PURE__ */ jsx(
|
|
224
|
+
"button",
|
|
225
|
+
{
|
|
226
|
+
type: "button",
|
|
227
|
+
onClick: handleCancel,
|
|
228
|
+
className: "text-sm text-muted-foreground hover:text-foreground py-1",
|
|
229
|
+
children: "Cancel"
|
|
230
|
+
}
|
|
231
|
+
)
|
|
232
|
+
] })
|
|
233
|
+
] })
|
|
234
|
+
]
|
|
235
|
+
}
|
|
236
|
+
) })
|
|
237
|
+
}
|
|
238
|
+
)
|
|
239
|
+
] });
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export {
|
|
243
|
+
VoiceDictationButton
|
|
244
|
+
};
|