@7onic-ui/react 0.3.9 → 0.3.10
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 +2 -2
- package/dist/chart.mjs +3 -9
- package/dist/chart.mjs.map +1 -1
- package/dist/chunk-234NAXGV.mjs +252 -0
- package/dist/chunk-234NAXGV.mjs.map +1 -0
- package/dist/chunk-53MIUPSY.mjs +13 -0
- package/dist/chunk-53MIUPSY.mjs.map +1 -0
- package/dist/chunk-BN5BEA3V.mjs +195 -0
- package/dist/chunk-BN5BEA3V.mjs.map +1 -0
- package/dist/chunk-COW3B62M.mjs +214 -0
- package/dist/chunk-COW3B62M.mjs.map +1 -0
- package/dist/chunk-CTH6SN5Y.mjs +114 -0
- package/dist/chunk-CTH6SN5Y.mjs.map +1 -0
- package/dist/chunk-D3NTQNDW.mjs +440 -0
- package/dist/chunk-D3NTQNDW.mjs.map +1 -0
- package/dist/chunk-DDRYEJBJ.mjs +164 -0
- package/dist/chunk-DDRYEJBJ.mjs.map +1 -0
- package/dist/chunk-DJAEXCRU.mjs +190 -0
- package/dist/chunk-DJAEXCRU.mjs.map +1 -0
- package/dist/chunk-DRVHHEAY.mjs +145 -0
- package/dist/chunk-DRVHHEAY.mjs.map +1 -0
- package/dist/chunk-DTLNWOTR.mjs +482 -0
- package/dist/chunk-DTLNWOTR.mjs.map +1 -0
- package/dist/chunk-DYYQOHQR.mjs +214 -0
- package/dist/chunk-DYYQOHQR.mjs.map +1 -0
- package/dist/chunk-FHUAH6AJ.mjs +93 -0
- package/dist/chunk-FHUAH6AJ.mjs.map +1 -0
- package/dist/chunk-GD4YE5AE.mjs +209 -0
- package/dist/chunk-GD4YE5AE.mjs.map +1 -0
- package/dist/chunk-GRCJ35DX.mjs +144 -0
- package/dist/chunk-GRCJ35DX.mjs.map +1 -0
- package/dist/chunk-HHX4GABH.mjs +129 -0
- package/dist/chunk-HHX4GABH.mjs.map +1 -0
- package/dist/chunk-IPCIC2BI.mjs +148 -0
- package/dist/chunk-IPCIC2BI.mjs.map +1 -0
- package/dist/chunk-IY3R2VGB.mjs +272 -0
- package/dist/chunk-IY3R2VGB.mjs.map +1 -0
- package/dist/chunk-JCJEVXER.mjs +170 -0
- package/dist/chunk-JCJEVXER.mjs.map +1 -0
- package/dist/chunk-KBPYAMGS.mjs +157 -0
- package/dist/chunk-KBPYAMGS.mjs.map +1 -0
- package/dist/chunk-LJJ6K4IU.mjs +318 -0
- package/dist/chunk-LJJ6K4IU.mjs.map +1 -0
- package/dist/chunk-MRUVGHGP.mjs +375 -0
- package/dist/chunk-MRUVGHGP.mjs.map +1 -0
- package/dist/chunk-N4K2BDGM.mjs +153 -0
- package/dist/chunk-N4K2BDGM.mjs.map +1 -0
- package/dist/chunk-NWFMJWGX.mjs +165 -0
- package/dist/chunk-NWFMJWGX.mjs.map +1 -0
- package/dist/chunk-PTAPPOKU.mjs +117 -0
- package/dist/chunk-PTAPPOKU.mjs.map +1 -0
- package/dist/chunk-PVTBM7V7.mjs +316 -0
- package/dist/chunk-PVTBM7V7.mjs.map +1 -0
- package/dist/chunk-Q5WVLK2L.mjs +77 -0
- package/dist/chunk-Q5WVLK2L.mjs.map +1 -0
- package/dist/chunk-RKSB2N5L.mjs +206 -0
- package/dist/chunk-RKSB2N5L.mjs.map +1 -0
- package/dist/chunk-S4DGVKBK.mjs +151 -0
- package/dist/chunk-S4DGVKBK.mjs.map +1 -0
- package/dist/chunk-S4T4PU7F.mjs +114 -0
- package/dist/chunk-S4T4PU7F.mjs.map +1 -0
- package/dist/chunk-SZPZOGPC.mjs +394 -0
- package/dist/chunk-SZPZOGPC.mjs.map +1 -0
- package/dist/chunk-T546XBQG.mjs +443 -0
- package/dist/chunk-T546XBQG.mjs.map +1 -0
- package/dist/chunk-UWTT5AE6.mjs +145 -0
- package/dist/chunk-UWTT5AE6.mjs.map +1 -0
- package/dist/chunk-V5UFWYFI.mjs +255 -0
- package/dist/chunk-V5UFWYFI.mjs.map +1 -0
- package/dist/chunk-VUPGBB5X.mjs +150 -0
- package/dist/chunk-VUPGBB5X.mjs.map +1 -0
- package/dist/chunk-W6YNEU53.mjs +175 -0
- package/dist/chunk-W6YNEU53.mjs.map +1 -0
- package/dist/chunk-WWSN5YME.mjs +222 -0
- package/dist/chunk-WWSN5YME.mjs.map +1 -0
- package/dist/chunk-XK52LYR4.mjs +182 -0
- package/dist/chunk-XK52LYR4.mjs.map +1 -0
- package/dist/chunk-YIAH6KHV.mjs +164 -0
- package/dist/chunk-YIAH6KHV.mjs.map +1 -0
- package/dist/chunk-Z6JWWCNL.mjs +108 -0
- package/dist/chunk-Z6JWWCNL.mjs.map +1 -0
- package/dist/chunk-ZDRUTJ4T.mjs +119 -0
- package/dist/chunk-ZDRUTJ4T.mjs.map +1 -0
- package/dist/components/accordion.mjs +19 -0
- package/dist/components/accordion.mjs.map +1 -0
- package/dist/components/alert.mjs +15 -0
- package/dist/components/alert.mjs.map +1 -0
- package/dist/components/avatar.mjs +23 -0
- package/dist/components/avatar.mjs.map +1 -0
- package/dist/components/badge.mjs +11 -0
- package/dist/components/badge.mjs.map +1 -0
- package/dist/components/breadcrumb.mjs +23 -0
- package/dist/components/breadcrumb.mjs.map +1 -0
- package/dist/components/button-group.mjs +11 -0
- package/dist/components/button-group.mjs.map +1 -0
- package/dist/components/button.mjs +12 -0
- package/dist/components/button.mjs.map +1 -0
- package/dist/components/card.mjs +25 -0
- package/dist/components/card.mjs.map +1 -0
- package/dist/components/chat-input.mjs +15 -0
- package/dist/components/chat-input.mjs.map +1 -0
- package/dist/components/chat-message.mjs +17 -0
- package/dist/components/chat-message.mjs.map +1 -0
- package/dist/components/checkbox.mjs +12 -0
- package/dist/components/checkbox.mjs.map +1 -0
- package/dist/components/divider.mjs +11 -0
- package/dist/components/divider.mjs.map +1 -0
- package/dist/components/drawer.mjs +33 -0
- package/dist/components/drawer.mjs.map +1 -0
- package/dist/components/dropdown.mjs +35 -0
- package/dist/components/dropdown.mjs.map +1 -0
- package/dist/components/field.mjs +17 -0
- package/dist/components/field.mjs.map +1 -0
- package/dist/components/icon-button.mjs +12 -0
- package/dist/components/icon-button.mjs.map +1 -0
- package/dist/components/input.mjs +12 -0
- package/dist/components/input.mjs.map +1 -0
- package/dist/components/metric-card.mjs +23 -0
- package/dist/components/metric-card.mjs.map +1 -0
- package/dist/components/modal.mjs +57 -0
- package/dist/components/modal.mjs.map +1 -0
- package/dist/components/navigation-menu.mjs +27 -0
- package/dist/components/navigation-menu.mjs.map +1 -0
- package/dist/components/pagination.mjs +33 -0
- package/dist/components/pagination.mjs.map +1 -0
- package/dist/components/popover.mjs +23 -0
- package/dist/components/popover.mjs.map +1 -0
- package/dist/components/progress.mjs +11 -0
- package/dist/components/progress.mjs.map +1 -0
- package/dist/components/quick-reply.mjs +15 -0
- package/dist/components/quick-reply.mjs.map +1 -0
- package/dist/components/radio-group.mjs +16 -0
- package/dist/components/radio-group.mjs.map +1 -0
- package/dist/components/segmented.mjs +15 -0
- package/dist/components/segmented.mjs.map +1 -0
- package/dist/components/select.mjs +23 -0
- package/dist/components/select.mjs.map +1 -0
- package/dist/components/skeleton.mjs +11 -0
- package/dist/components/skeleton.mjs.map +1 -0
- package/dist/components/slider.mjs +11 -0
- package/dist/components/slider.mjs.map +1 -0
- package/dist/components/spinner.mjs +11 -0
- package/dist/components/spinner.mjs.map +1 -0
- package/dist/components/switch.mjs +12 -0
- package/dist/components/switch.mjs.map +1 -0
- package/dist/components/table.mjs +23 -0
- package/dist/components/table.mjs.map +1 -0
- package/dist/components/tabs.mjs +19 -0
- package/dist/components/tabs.mjs.map +1 -0
- package/dist/components/textarea.mjs +12 -0
- package/dist/components/textarea.mjs.map +1 -0
- package/dist/components/toast.mjs +13 -0
- package/dist/components/toast.mjs.map +1 -0
- package/dist/components/toggle-group.mjs +15 -0
- package/dist/components/toggle-group.mjs.map +1 -0
- package/dist/components/toggle.mjs +11 -0
- package/dist/components/toggle.mjs.map +1 -0
- package/dist/components/tooltip.mjs +21 -0
- package/dist/components/tooltip.mjs.map +1 -0
- package/dist/components/typing-indicator.mjs +11 -0
- package/dist/components/typing-indicator.mjs.map +1 -0
- package/dist/index.mjs +296 -7536
- package/dist/index.mjs.map +1 -1
- package/llms.txt +23 -23
- package/package.json +4 -3
- package/dist/chart.d.mts +0 -147
- package/dist/index.d.mts +0 -1535
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
cn
|
|
4
|
+
} from "./chunk-53MIUPSY.mjs";
|
|
5
|
+
|
|
6
|
+
// src/components/ui/chat-input.tsx
|
|
7
|
+
import * as React from "react";
|
|
8
|
+
import { cva } from "class-variance-authority";
|
|
9
|
+
var fieldPaddingMap = {
|
|
10
|
+
sm: "pt-2.5 px-3 text-md",
|
|
11
|
+
default: "pt-3 px-4 text-md",
|
|
12
|
+
lg: "pt-4 px-5 text-base"
|
|
13
|
+
};
|
|
14
|
+
var submitWrapperMap = {
|
|
15
|
+
sm: "px-2.5 pb-2.5",
|
|
16
|
+
default: "px-3 pb-3",
|
|
17
|
+
lg: "px-4 pb-4"
|
|
18
|
+
};
|
|
19
|
+
var submitSizeMap = {
|
|
20
|
+
sm: "h-7 w-7",
|
|
21
|
+
default: "h-8 w-8",
|
|
22
|
+
lg: "h-9 w-9"
|
|
23
|
+
};
|
|
24
|
+
var submitRadiusMap = {
|
|
25
|
+
sm: "rounded-md",
|
|
26
|
+
md: "rounded-md",
|
|
27
|
+
lg: "rounded-md",
|
|
28
|
+
xl: "rounded-lg",
|
|
29
|
+
"2xl": "rounded-xl",
|
|
30
|
+
full: "rounded-full"
|
|
31
|
+
};
|
|
32
|
+
var buttonRadiusClassMap = {
|
|
33
|
+
sm: "rounded-sm",
|
|
34
|
+
md: "rounded-md",
|
|
35
|
+
lg: "rounded-lg",
|
|
36
|
+
xl: "rounded-xl",
|
|
37
|
+
"2xl": "rounded-2xl",
|
|
38
|
+
full: "rounded-full"
|
|
39
|
+
};
|
|
40
|
+
var submitIconSizeMap = {
|
|
41
|
+
sm: "icon-xs",
|
|
42
|
+
default: "icon-xs",
|
|
43
|
+
lg: "icon-sm"
|
|
44
|
+
};
|
|
45
|
+
var countStyleMap = {
|
|
46
|
+
sm: "text-xs",
|
|
47
|
+
default: "text-xs",
|
|
48
|
+
lg: "text-sm"
|
|
49
|
+
};
|
|
50
|
+
var lineHeightMap = {
|
|
51
|
+
sm: 20,
|
|
52
|
+
default: 22,
|
|
53
|
+
lg: 24
|
|
54
|
+
};
|
|
55
|
+
var inlineFieldPaddingMap = {
|
|
56
|
+
sm: "px-3 text-md",
|
|
57
|
+
default: "px-4 text-md",
|
|
58
|
+
lg: "px-5 text-base"
|
|
59
|
+
};
|
|
60
|
+
var submitWrapperInlineMap = {
|
|
61
|
+
sm: "px-2.5 py-2.5",
|
|
62
|
+
default: "px-3 py-3",
|
|
63
|
+
lg: "px-4 py-4"
|
|
64
|
+
};
|
|
65
|
+
var chatInputVariants = cva(
|
|
66
|
+
[
|
|
67
|
+
"flex flex-col w-full overflow-hidden cursor-text",
|
|
68
|
+
"transition-colors duration-micro"
|
|
69
|
+
].join(" "),
|
|
70
|
+
{
|
|
71
|
+
variants: {
|
|
72
|
+
variant: {
|
|
73
|
+
outline: [
|
|
74
|
+
"border border-border bg-background",
|
|
75
|
+
"hover:border-border-strong",
|
|
76
|
+
"focus-within:border-border-strong focus-within:hover:border-border-strong"
|
|
77
|
+
].join(" "),
|
|
78
|
+
filled: [
|
|
79
|
+
"border border-transparent bg-background-muted",
|
|
80
|
+
"focus-within:border-border"
|
|
81
|
+
].join(" ")
|
|
82
|
+
},
|
|
83
|
+
radius: {
|
|
84
|
+
sm: "rounded-sm",
|
|
85
|
+
md: "rounded-md",
|
|
86
|
+
lg: "rounded-lg",
|
|
87
|
+
xl: "rounded-xl",
|
|
88
|
+
"2xl": "rounded-2xl",
|
|
89
|
+
full: "rounded-full"
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
defaultVariants: {
|
|
93
|
+
variant: "outline",
|
|
94
|
+
radius: "xl"
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
var ChatInputContext = React.createContext({
|
|
99
|
+
size: "default",
|
|
100
|
+
color: "default",
|
|
101
|
+
layout: "default",
|
|
102
|
+
radius: "xl",
|
|
103
|
+
disabled: false,
|
|
104
|
+
isEmpty: true,
|
|
105
|
+
charCount: 0,
|
|
106
|
+
showCount: false,
|
|
107
|
+
maxLength: void 0,
|
|
108
|
+
_setIsEmpty: () => {
|
|
109
|
+
},
|
|
110
|
+
_setCharCount: () => {
|
|
111
|
+
},
|
|
112
|
+
_setShowCount: () => {
|
|
113
|
+
},
|
|
114
|
+
_setMaxLength: () => {
|
|
115
|
+
},
|
|
116
|
+
_fieldRef: { current: null },
|
|
117
|
+
_handleSubmit: () => {
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
var ChatInput = React.forwardRef(
|
|
121
|
+
({
|
|
122
|
+
className,
|
|
123
|
+
variant = "outline",
|
|
124
|
+
radius = "xl",
|
|
125
|
+
size = "default",
|
|
126
|
+
color = "default",
|
|
127
|
+
layout = "default",
|
|
128
|
+
disabled = false,
|
|
129
|
+
onSubmit,
|
|
130
|
+
children,
|
|
131
|
+
...props
|
|
132
|
+
}, ref) => {
|
|
133
|
+
const [isEmpty, setIsEmpty] = React.useState(true);
|
|
134
|
+
const [charCount, setCharCount] = React.useState(0);
|
|
135
|
+
const [showCount, setShowCount] = React.useState(false);
|
|
136
|
+
const [maxLength, setMaxLength] = React.useState(void 0);
|
|
137
|
+
const fieldRef = React.useRef(null);
|
|
138
|
+
const handleSubmit = React.useCallback(() => {
|
|
139
|
+
const el = fieldRef.current;
|
|
140
|
+
if (!el || disabled) return;
|
|
141
|
+
const value = el.value.trim();
|
|
142
|
+
if (!value) return;
|
|
143
|
+
onSubmit?.(value);
|
|
144
|
+
el.value = "";
|
|
145
|
+
el.style.height = "auto";
|
|
146
|
+
setIsEmpty(true);
|
|
147
|
+
setCharCount(0);
|
|
148
|
+
}, [disabled, onSubmit]);
|
|
149
|
+
const contextValue = React.useMemo(
|
|
150
|
+
() => ({
|
|
151
|
+
size,
|
|
152
|
+
color,
|
|
153
|
+
layout,
|
|
154
|
+
radius,
|
|
155
|
+
disabled,
|
|
156
|
+
isEmpty,
|
|
157
|
+
charCount,
|
|
158
|
+
showCount,
|
|
159
|
+
maxLength,
|
|
160
|
+
_setIsEmpty: setIsEmpty,
|
|
161
|
+
_setCharCount: setCharCount,
|
|
162
|
+
_setShowCount: setShowCount,
|
|
163
|
+
_setMaxLength: setMaxLength,
|
|
164
|
+
_fieldRef: fieldRef,
|
|
165
|
+
_handleSubmit: handleSubmit
|
|
166
|
+
}),
|
|
167
|
+
[size, color, layout, radius, disabled, isEmpty, charCount, showCount, maxLength, handleSubmit]
|
|
168
|
+
);
|
|
169
|
+
const handleContainerClick = React.useCallback(
|
|
170
|
+
(e) => {
|
|
171
|
+
if (!disabled && !e.target.closest("button")) {
|
|
172
|
+
fieldRef.current?.focus();
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
[disabled]
|
|
176
|
+
);
|
|
177
|
+
return /* @__PURE__ */ React.createElement(ChatInputContext.Provider, { value: contextValue }, /* @__PURE__ */ React.createElement(
|
|
178
|
+
"div",
|
|
179
|
+
{
|
|
180
|
+
ref,
|
|
181
|
+
"data-disabled": disabled || void 0,
|
|
182
|
+
onClick: handleContainerClick,
|
|
183
|
+
className: cn(
|
|
184
|
+
chatInputVariants({ variant, radius }),
|
|
185
|
+
layout === "inline" && "flex-row",
|
|
186
|
+
disabled && "opacity-50 pointer-events-none",
|
|
187
|
+
className
|
|
188
|
+
),
|
|
189
|
+
...props
|
|
190
|
+
},
|
|
191
|
+
children
|
|
192
|
+
));
|
|
193
|
+
}
|
|
194
|
+
);
|
|
195
|
+
ChatInput.displayName = "ChatInput";
|
|
196
|
+
var ChatInputField = React.forwardRef(
|
|
197
|
+
({
|
|
198
|
+
className,
|
|
199
|
+
maxRows = 8,
|
|
200
|
+
showCount = false,
|
|
201
|
+
maxLength,
|
|
202
|
+
placeholder,
|
|
203
|
+
onChange,
|
|
204
|
+
onKeyDown,
|
|
205
|
+
disabled,
|
|
206
|
+
...props
|
|
207
|
+
}, forwardedRef) => {
|
|
208
|
+
const ctx = React.useContext(ChatInputContext);
|
|
209
|
+
const internalRef = React.useRef(null);
|
|
210
|
+
const isDisabled = disabled ?? ctx.disabled;
|
|
211
|
+
React.useEffect(() => {
|
|
212
|
+
ctx._setShowCount(showCount);
|
|
213
|
+
ctx._setMaxLength(maxLength);
|
|
214
|
+
}, [showCount, maxLength]);
|
|
215
|
+
const setRef = React.useCallback(
|
|
216
|
+
(el) => {
|
|
217
|
+
internalRef.current = el;
|
|
218
|
+
ctx._fieldRef.current = el;
|
|
219
|
+
if (typeof forwardedRef === "function") {
|
|
220
|
+
forwardedRef(el);
|
|
221
|
+
} else if (forwardedRef) {
|
|
222
|
+
forwardedRef.current = el;
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
226
|
+
[forwardedRef]
|
|
227
|
+
);
|
|
228
|
+
const autoResize = React.useCallback(() => {
|
|
229
|
+
const el = internalRef.current;
|
|
230
|
+
if (!el) return;
|
|
231
|
+
el.style.height = "auto";
|
|
232
|
+
const maxHeight = maxRows * lineHeightMap[ctx.size];
|
|
233
|
+
const newHeight = Math.min(el.scrollHeight, maxHeight);
|
|
234
|
+
el.style.height = `${newHeight}px`;
|
|
235
|
+
el.style.overflowY = el.scrollHeight > maxHeight ? "auto" : "hidden";
|
|
236
|
+
}, [ctx.size, maxRows]);
|
|
237
|
+
const handleChange = React.useCallback(
|
|
238
|
+
(e) => {
|
|
239
|
+
const val = e.target.value;
|
|
240
|
+
ctx._setIsEmpty(val.trim() === "");
|
|
241
|
+
ctx._setCharCount(val.length);
|
|
242
|
+
autoResize();
|
|
243
|
+
onChange?.(e);
|
|
244
|
+
},
|
|
245
|
+
[ctx, autoResize, onChange]
|
|
246
|
+
);
|
|
247
|
+
const handleKeyDown = React.useCallback(
|
|
248
|
+
(e) => {
|
|
249
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
250
|
+
e.preventDefault();
|
|
251
|
+
ctx._handleSubmit();
|
|
252
|
+
}
|
|
253
|
+
onKeyDown?.(e);
|
|
254
|
+
},
|
|
255
|
+
[ctx, onKeyDown]
|
|
256
|
+
);
|
|
257
|
+
return /* @__PURE__ */ React.createElement("div", { className: cn("flex-1 min-w-0", ctx.layout === "inline" && "flex items-center self-stretch") }, /* @__PURE__ */ React.createElement(
|
|
258
|
+
"textarea",
|
|
259
|
+
{
|
|
260
|
+
ref: setRef,
|
|
261
|
+
rows: 1,
|
|
262
|
+
placeholder,
|
|
263
|
+
maxLength,
|
|
264
|
+
disabled: isDisabled,
|
|
265
|
+
className: cn(
|
|
266
|
+
"w-full bg-transparent text-foreground placeholder:text-foreground/30",
|
|
267
|
+
"resize-none outline-none focus:outline-none",
|
|
268
|
+
"disabled:cursor-not-allowed",
|
|
269
|
+
"overflow-hidden",
|
|
270
|
+
ctx.layout === "inline" ? inlineFieldPaddingMap[ctx.size] : fieldPaddingMap[ctx.size],
|
|
271
|
+
className
|
|
272
|
+
),
|
|
273
|
+
onChange: handleChange,
|
|
274
|
+
onKeyDown: handleKeyDown,
|
|
275
|
+
...props
|
|
276
|
+
}
|
|
277
|
+
));
|
|
278
|
+
}
|
|
279
|
+
);
|
|
280
|
+
ChatInputField.displayName = "ChatInputField";
|
|
281
|
+
var ChatInputSubmit = React.forwardRef(
|
|
282
|
+
({
|
|
283
|
+
className,
|
|
284
|
+
loading = false,
|
|
285
|
+
onStop,
|
|
286
|
+
children,
|
|
287
|
+
disabled,
|
|
288
|
+
onClick,
|
|
289
|
+
buttonRadius,
|
|
290
|
+
...props
|
|
291
|
+
}, ref) => {
|
|
292
|
+
const ctx = React.useContext(ChatInputContext);
|
|
293
|
+
const isDisabled = (disabled ?? ctx.disabled) || !loading && ctx.isEmpty;
|
|
294
|
+
const handleClick = React.useCallback(
|
|
295
|
+
(e) => {
|
|
296
|
+
if (loading) {
|
|
297
|
+
onStop?.();
|
|
298
|
+
} else if (!isDisabled) {
|
|
299
|
+
ctx._handleSubmit();
|
|
300
|
+
}
|
|
301
|
+
onClick?.(e);
|
|
302
|
+
},
|
|
303
|
+
[ctx, isDisabled, loading, onStop, onClick]
|
|
304
|
+
);
|
|
305
|
+
return /* @__PURE__ */ React.createElement("div", { className: cn("flex items-center justify-end gap-2 shrink-0 cursor-default", ctx.layout === "inline" ? submitWrapperInlineMap[ctx.size] : submitWrapperMap[ctx.size]) }, ctx.showCount && ctx.maxLength != null && /* @__PURE__ */ React.createElement("span", { className: cn("text-text-subtle select-none", countStyleMap[ctx.size]) }, ctx.charCount, " / ", ctx.maxLength), /* @__PURE__ */ React.createElement(
|
|
306
|
+
"button",
|
|
307
|
+
{
|
|
308
|
+
ref,
|
|
309
|
+
type: "button",
|
|
310
|
+
disabled: isDisabled && !loading,
|
|
311
|
+
"aria-label": loading ? "Stop generating" : "Send message",
|
|
312
|
+
className: cn(
|
|
313
|
+
"inline-flex items-center justify-center shrink-0",
|
|
314
|
+
buttonRadius ? buttonRadiusClassMap[buttonRadius] : submitRadiusMap[ctx.radius],
|
|
315
|
+
"transition-all duration-fast",
|
|
316
|
+
"focus-visible:outline-none focus-visible:focus-ring",
|
|
317
|
+
submitSizeMap[ctx.size],
|
|
318
|
+
// Loading state — enabled, pulsing
|
|
319
|
+
loading && ctx.color === "default" && "bg-foreground text-background animate-pulse cursor-pointer",
|
|
320
|
+
loading && ctx.color === "primary" && "bg-primary text-primary-foreground animate-pulse cursor-pointer",
|
|
321
|
+
// Enabled state
|
|
322
|
+
!loading && !isDisabled && ctx.color === "default" && [
|
|
323
|
+
"bg-foreground text-background",
|
|
324
|
+
"hover:bg-foreground/90 active:bg-foreground/80 active:scale-pressed cursor-pointer"
|
|
325
|
+
],
|
|
326
|
+
!loading && !isDisabled && ctx.color === "primary" && [
|
|
327
|
+
"bg-primary text-primary-foreground",
|
|
328
|
+
"hover:bg-primary-hover active:scale-pressed cursor-pointer"
|
|
329
|
+
],
|
|
330
|
+
// Disabled state
|
|
331
|
+
!loading && isDisabled && "bg-background-muted text-text-subtle pointer-events-none",
|
|
332
|
+
className
|
|
333
|
+
),
|
|
334
|
+
onClick: handleClick,
|
|
335
|
+
...props
|
|
336
|
+
},
|
|
337
|
+
/* @__PURE__ */ React.createElement(
|
|
338
|
+
"span",
|
|
339
|
+
{
|
|
340
|
+
"aria-hidden": "true",
|
|
341
|
+
className: cn("flex items-center justify-center", submitIconSizeMap[ctx.size])
|
|
342
|
+
},
|
|
343
|
+
children ?? (loading ? /* @__PURE__ */ React.createElement(StopIcon, null) : /* @__PURE__ */ React.createElement(SendIcon, null))
|
|
344
|
+
)
|
|
345
|
+
));
|
|
346
|
+
}
|
|
347
|
+
);
|
|
348
|
+
ChatInputSubmit.displayName = "ChatInputSubmit";
|
|
349
|
+
function SendIcon() {
|
|
350
|
+
return /* @__PURE__ */ React.createElement(
|
|
351
|
+
"svg",
|
|
352
|
+
{
|
|
353
|
+
viewBox: "0 0 24 24",
|
|
354
|
+
fill: "none",
|
|
355
|
+
stroke: "currentColor",
|
|
356
|
+
strokeWidth: 2.5,
|
|
357
|
+
strokeLinecap: "round",
|
|
358
|
+
strokeLinejoin: "round",
|
|
359
|
+
className: "w-full h-full"
|
|
360
|
+
},
|
|
361
|
+
/* @__PURE__ */ React.createElement("path", { d: "M22 2 11 13" }),
|
|
362
|
+
/* @__PURE__ */ React.createElement("path", { d: "M22 2 15 22 11 13 2 9l20-7Z" })
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
function StopIcon() {
|
|
366
|
+
return /* @__PURE__ */ React.createElement("svg", { viewBox: "0 0 24 24", fill: "currentColor", className: "w-full h-full" }, /* @__PURE__ */ React.createElement("rect", { x: "5", y: "5", width: "14", height: "14", rx: "2" }));
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
export {
|
|
370
|
+
chatInputVariants,
|
|
371
|
+
ChatInput,
|
|
372
|
+
ChatInputField,
|
|
373
|
+
ChatInputSubmit
|
|
374
|
+
};
|
|
375
|
+
//# sourceMappingURL=chunk-MRUVGHGP.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/ui/chat-input.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@/lib/utils'\n\n// ============================================================================\n// Size maps\n// ============================================================================\n\n/** Textarea padding per size */\nconst fieldPaddingMap = {\n sm: 'pt-2.5 px-3 text-md',\n default: 'pt-3 px-4 text-md',\n lg: 'pt-4 px-5 text-base',\n} as const\n\n/** Submit row padding per size */\nconst submitWrapperMap = {\n sm: 'px-2.5 pb-2.5',\n default: 'px-3 pb-3',\n lg: 'px-4 pb-4',\n} as const\n\n/** Submit button dimensions per size */\nconst submitSizeMap = {\n sm: 'h-7 w-7',\n default: 'h-8 w-8',\n lg: 'h-9 w-9',\n} as const\n\n/** Submit button radius — auto-calculated from container radius (min rounded-md) */\nconst submitRadiusMap = {\n sm: 'rounded-md',\n md: 'rounded-md',\n lg: 'rounded-md',\n xl: 'rounded-lg',\n '2xl': 'rounded-xl',\n full: 'rounded-full',\n} as const\n\n/** Submit button radius — direct class map for explicit buttonRadius prop */\nconst buttonRadiusClassMap: Record<ChatInputRadius, string> = {\n sm: 'rounded-sm',\n md: 'rounded-md',\n lg: 'rounded-lg',\n xl: 'rounded-xl',\n '2xl': 'rounded-2xl',\n full: 'rounded-full',\n}\n\n/** Submit icon size class per size */\nconst submitIconSizeMap = {\n sm: 'icon-xs',\n default: 'icon-xs',\n lg: 'icon-sm',\n} as const\n\n/** Character count text size per size */\nconst countStyleMap = {\n sm: 'text-xs',\n default: 'text-xs',\n lg: 'text-sm',\n} as const\n\n/** Approximate line-height (px) per size for auto-resize */\nconst lineHeightMap = {\n sm: 20,\n default: 22,\n lg: 24,\n} as const\n\n/** Field padding in inline layout — horizontal only (vertical centering via flex) */\nconst inlineFieldPaddingMap = {\n sm: 'px-3 text-md',\n default: 'px-4 text-md',\n lg: 'px-5 text-base',\n} as const\n\n/** Submit wrapper padding in inline layout — symmetric vertical */\nconst submitWrapperInlineMap = {\n sm: 'px-2.5 py-2.5',\n default: 'px-3 py-3',\n lg: 'px-4 py-4',\n} as const\n\n// ============================================================================\n// CVA — root container variants\n// ============================================================================\n\nconst chatInputVariants = cva(\n [\n 'flex flex-col w-full overflow-hidden cursor-text',\n 'transition-colors duration-micro',\n ].join(' '),\n {\n variants: {\n variant: {\n outline: [\n 'border border-border bg-background',\n 'hover:border-border-strong',\n 'focus-within:border-border-strong focus-within:hover:border-border-strong',\n ].join(' '),\n filled: [\n 'border border-transparent bg-background-muted',\n 'focus-within:border-border',\n ].join(' '),\n },\n radius: {\n sm: 'rounded-sm',\n md: 'rounded-md',\n lg: 'rounded-lg',\n xl: 'rounded-xl',\n '2xl': 'rounded-2xl',\n full: 'rounded-full',\n },\n },\n defaultVariants: {\n variant: 'outline',\n radius: 'xl',\n },\n }\n)\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type ChatInputSize = 'sm' | 'default' | 'lg'\nexport type ChatInputVariant = 'outline' | 'filled'\nexport type ChatInputRadius = 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full'\nexport type ChatInputColor = 'default' | 'primary'\nexport type ChatInputLayout = 'default' | 'inline'\n\n// ============================================================================\n// Context\n// ============================================================================\n\ninterface ChatInputContextValue {\n size: ChatInputSize\n color: ChatInputColor\n layout: ChatInputLayout\n radius: ChatInputRadius\n disabled: boolean\n isEmpty: boolean\n charCount: number\n showCount: boolean\n maxLength: number | undefined\n _setIsEmpty: React.Dispatch<React.SetStateAction<boolean>>\n _setCharCount: React.Dispatch<React.SetStateAction<number>>\n _setShowCount: React.Dispatch<React.SetStateAction<boolean>>\n _setMaxLength: React.Dispatch<React.SetStateAction<number | undefined>>\n _fieldRef: React.MutableRefObject<HTMLTextAreaElement | null>\n _handleSubmit: () => void\n}\n\nconst ChatInputContext = React.createContext<ChatInputContextValue>({\n size: 'default',\n color: 'default',\n layout: 'default',\n radius: 'xl',\n disabled: false,\n isEmpty: true,\n charCount: 0,\n showCount: false,\n maxLength: undefined,\n _setIsEmpty: () => {},\n _setCharCount: () => {},\n _setShowCount: () => {},\n _setMaxLength: () => {},\n _fieldRef: { current: null },\n _handleSubmit: () => {},\n})\n\n// ============================================================================\n// Props interfaces\n// ============================================================================\n\nexport interface ChatInputRootProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSubmit'>,\n VariantProps<typeof chatInputVariants> {\n /** Visual style of the container */\n variant?: ChatInputVariant\n /** Corner radius */\n radius?: ChatInputRadius\n /** Size scale */\n size?: ChatInputSize\n /** Submit button color — default (dark) or primary (brand) */\n color?: ChatInputColor\n /** Layout direction — default (stacked) or inline (field + button side by side) */\n layout?: ChatInputLayout\n /** Disable all interaction */\n disabled?: boolean\n /** Called when the user submits (Enter key or Submit button) — receives current field value */\n onSubmit?: (value: string) => void\n}\n\nexport interface ChatInputFieldProps\n extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'children'> {\n /** Maximum visible rows before the field scrolls */\n maxRows?: number\n /** Show character counter — requires maxLength to be set */\n showCount?: boolean\n}\n\nexport interface ChatInputSubmitProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Show loading/stop state — keeps button enabled so user can stop generation */\n loading?: boolean\n /** Called when clicked during loading state (e.g., stop generation) */\n onStop?: () => void\n /** Override the auto-calculated button radius */\n buttonRadius?: ChatInputRadius\n}\n\n// ============================================================================\n// ChatInput — Root container\n// ============================================================================\n\nconst ChatInput = React.forwardRef<HTMLDivElement, ChatInputRootProps>(\n (\n {\n className,\n variant = 'outline',\n radius = 'xl',\n size = 'default',\n color = 'default',\n layout = 'default',\n disabled = false,\n onSubmit,\n children,\n ...props\n },\n ref\n ) => {\n const [isEmpty, setIsEmpty] = React.useState(true)\n const [charCount, setCharCount] = React.useState(0)\n const [showCount, setShowCount] = React.useState(false)\n const [maxLength, setMaxLength] = React.useState<number | undefined>(undefined)\n const fieldRef = React.useRef<HTMLTextAreaElement | null>(null)\n\n const handleSubmit = React.useCallback(() => {\n const el = fieldRef.current\n if (!el || disabled) return\n const value = el.value.trim()\n if (!value) return\n onSubmit?.(value)\n // Auto-clear in uncontrolled mode\n // Controlled-mode users should clear value inside their onSubmit callback\n el.value = ''\n el.style.height = 'auto'\n setIsEmpty(true)\n setCharCount(0)\n }, [disabled, onSubmit])\n\n const contextValue = React.useMemo<ChatInputContextValue>(\n () => ({\n size,\n color,\n layout,\n radius,\n disabled,\n isEmpty,\n charCount,\n showCount,\n maxLength,\n _setIsEmpty: setIsEmpty,\n _setCharCount: setCharCount,\n _setShowCount: setShowCount,\n _setMaxLength: setMaxLength,\n _fieldRef: fieldRef,\n _handleSubmit: handleSubmit,\n }),\n [size, color, layout, radius, disabled, isEmpty, charCount, showCount, maxLength, handleSubmit]\n )\n\n const handleContainerClick = React.useCallback(\n (e: React.MouseEvent<HTMLDivElement>) => {\n // Focus the textarea when clicking anywhere in the container (not on a button)\n if (!disabled && !(e.target as HTMLElement).closest('button')) {\n fieldRef.current?.focus()\n }\n },\n [disabled]\n )\n\n return (\n <ChatInputContext.Provider value={contextValue}>\n <div\n ref={ref}\n data-disabled={disabled || undefined}\n onClick={handleContainerClick}\n className={cn(\n chatInputVariants({ variant, radius }),\n layout === 'inline' && 'flex-row',\n disabled && 'opacity-50 pointer-events-none',\n className\n )}\n {...props}\n >\n {children}\n </div>\n </ChatInputContext.Provider>\n )\n }\n)\nChatInput.displayName = 'ChatInput'\n\n// ============================================================================\n// ChatInputField — Auto-resizing textarea\n// ============================================================================\n\nconst ChatInputField = React.forwardRef<HTMLTextAreaElement, ChatInputFieldProps>(\n (\n {\n className,\n maxRows = 8,\n showCount = false,\n maxLength,\n placeholder,\n onChange,\n onKeyDown,\n disabled,\n ...props\n },\n forwardedRef\n ) => {\n const ctx = React.useContext(ChatInputContext)\n const internalRef = React.useRef<HTMLTextAreaElement | null>(null)\n const isDisabled = disabled ?? ctx.disabled\n\n // Sync showCount + maxLength into root context on mount/update\n React.useEffect(() => {\n ctx._setShowCount(showCount)\n ctx._setMaxLength(maxLength)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [showCount, maxLength])\n\n // Merge forwarded ref + internal ref + context field ref\n const setRef = React.useCallback(\n (el: HTMLTextAreaElement | null) => {\n internalRef.current = el\n ctx._fieldRef.current = el\n if (typeof forwardedRef === 'function') {\n forwardedRef(el)\n } else if (forwardedRef) {\n (forwardedRef as React.MutableRefObject<HTMLTextAreaElement | null>).current = el\n }\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [forwardedRef]\n )\n\n // Adjust textarea height to content, bounded by maxRows\n const autoResize = React.useCallback(() => {\n const el = internalRef.current\n if (!el) return\n el.style.height = 'auto'\n const maxHeight = maxRows * lineHeightMap[ctx.size]\n const newHeight = Math.min(el.scrollHeight, maxHeight)\n el.style.height = `${newHeight}px`\n el.style.overflowY = el.scrollHeight > maxHeight ? 'auto' : 'hidden'\n }, [ctx.size, maxRows])\n\n const handleChange = React.useCallback(\n (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n const val = e.target.value\n ctx._setIsEmpty(val.trim() === '')\n ctx._setCharCount(val.length)\n autoResize()\n onChange?.(e)\n },\n [ctx, autoResize, onChange]\n )\n\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n // Enter = submit | Shift+Enter = new line\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n ctx._handleSubmit()\n }\n onKeyDown?.(e)\n },\n [ctx, onKeyDown]\n )\n\n return (\n <div className={cn('flex-1 min-w-0', ctx.layout === 'inline' && 'flex items-center self-stretch')}>\n <textarea\n ref={setRef}\n rows={1}\n placeholder={placeholder}\n maxLength={maxLength}\n disabled={isDisabled}\n className={cn(\n 'w-full bg-transparent text-foreground placeholder:text-foreground/30',\n 'resize-none outline-none focus:outline-none',\n 'disabled:cursor-not-allowed',\n 'overflow-hidden',\n ctx.layout === 'inline' ? inlineFieldPaddingMap[ctx.size] : fieldPaddingMap[ctx.size],\n className\n )}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n {...props}\n />\n </div>\n )\n }\n)\nChatInputField.displayName = 'ChatInputField'\n\n// ============================================================================\n// ChatInputSubmit — Send / stop button\n// ============================================================================\n\nconst ChatInputSubmit = React.forwardRef<HTMLButtonElement, ChatInputSubmitProps>(\n (\n {\n className,\n loading = false,\n onStop,\n children,\n disabled,\n onClick,\n buttonRadius,\n ...props\n },\n ref\n ) => {\n const ctx = React.useContext(ChatInputContext)\n\n // Disabled: context disabled | user prop | empty field (only when not loading)\n const isDisabled = (disabled ?? ctx.disabled) || (!loading && ctx.isEmpty)\n\n const handleClick = React.useCallback(\n (e: React.MouseEvent<HTMLButtonElement>) => {\n if (loading) {\n onStop?.()\n } else if (!isDisabled) {\n ctx._handleSubmit()\n }\n onClick?.(e)\n },\n [ctx, isDisabled, loading, onStop, onClick]\n )\n\n return (\n <div className={cn('flex items-center justify-end gap-2 shrink-0 cursor-default', ctx.layout === 'inline' ? submitWrapperInlineMap[ctx.size] : submitWrapperMap[ctx.size])}>\n {ctx.showCount && ctx.maxLength != null && (\n <span className={cn('text-text-subtle select-none', countStyleMap[ctx.size])}>\n {ctx.charCount} / {ctx.maxLength}\n </span>\n )}\n <button\n ref={ref}\n type=\"button\"\n disabled={isDisabled && !loading}\n aria-label={loading ? 'Stop generating' : 'Send message'}\n className={cn(\n 'inline-flex items-center justify-center shrink-0',\n buttonRadius ? buttonRadiusClassMap[buttonRadius] : submitRadiusMap[ctx.radius],\n 'transition-all duration-fast',\n 'focus-visible:outline-none focus-visible:focus-ring',\n submitSizeMap[ctx.size],\n // Loading state — enabled, pulsing\n loading && ctx.color === 'default' && 'bg-foreground text-background animate-pulse cursor-pointer',\n loading && ctx.color === 'primary' && 'bg-primary text-primary-foreground animate-pulse cursor-pointer',\n // Enabled state\n !loading && !isDisabled && ctx.color === 'default' && [\n 'bg-foreground text-background',\n 'hover:bg-foreground/90 active:bg-foreground/80 active:scale-pressed cursor-pointer',\n ],\n !loading && !isDisabled && ctx.color === 'primary' && [\n 'bg-primary text-primary-foreground',\n 'hover:bg-primary-hover active:scale-pressed cursor-pointer',\n ],\n // Disabled state\n !loading && isDisabled && 'bg-background-muted text-text-subtle pointer-events-none',\n className\n )}\n onClick={handleClick}\n {...props}\n >\n <span\n aria-hidden=\"true\"\n className={cn('flex items-center justify-center', submitIconSizeMap[ctx.size])}\n >\n {children ?? (loading ? <StopIcon /> : <SendIcon />)}\n </span>\n </button>\n </div>\n )\n }\n)\nChatInputSubmit.displayName = 'ChatInputSubmit'\n\n// ============================================================================\n// Built-in SVG icons — no external icon dependency\n// ============================================================================\n\nfunction SendIcon() {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2.5}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"w-full h-full\"\n >\n <path d=\"M22 2 11 13\" />\n <path d=\"M22 2 15 22 11 13 2 9l20-7Z\" />\n </svg>\n )\n}\n\nfunction StopIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" className=\"w-full h-full\">\n <rect x=\"5\" y=\"5\" width=\"14\" height=\"14\" rx=\"2\" />\n </svg>\n )\n}\n\nexport {\n ChatInput,\n ChatInputField,\n ChatInputSubmit,\n chatInputVariants,\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
useFieldContext
|
|
4
|
+
} from "./chunk-Z6JWWCNL.mjs";
|
|
5
|
+
import {
|
|
6
|
+
cn
|
|
7
|
+
} from "./chunk-53MIUPSY.mjs";
|
|
8
|
+
|
|
9
|
+
// src/components/ui/textarea.tsx
|
|
10
|
+
import * as React from "react";
|
|
11
|
+
import { cva } from "class-variance-authority";
|
|
12
|
+
var textareaVariants = cva(
|
|
13
|
+
[
|
|
14
|
+
"flex w-full bg-background text-foreground placeholder:text-foreground/30",
|
|
15
|
+
"border transition-colors duration-micro outline-transparent",
|
|
16
|
+
"focus:[outline:2px_solid_transparent]",
|
|
17
|
+
"disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-background-muted"
|
|
18
|
+
].join(" "),
|
|
19
|
+
{
|
|
20
|
+
variants: {
|
|
21
|
+
variant: {
|
|
22
|
+
default: "border-border hover:border-border-strong",
|
|
23
|
+
filled: "border-transparent bg-background-muted"
|
|
24
|
+
},
|
|
25
|
+
focusRing: {
|
|
26
|
+
true: "",
|
|
27
|
+
false: ""
|
|
28
|
+
},
|
|
29
|
+
size: {
|
|
30
|
+
compact: "px-3 py-2 text-md",
|
|
31
|
+
// 12px padding / 14px font - compact spaces
|
|
32
|
+
default: "px-4 py-3 text-base"
|
|
33
|
+
// 16px padding / 16px font - standard
|
|
34
|
+
},
|
|
35
|
+
radius: {
|
|
36
|
+
none: "rounded-none",
|
|
37
|
+
sm: "rounded-sm",
|
|
38
|
+
base: "rounded",
|
|
39
|
+
default: "rounded-md",
|
|
40
|
+
lg: "rounded-lg",
|
|
41
|
+
xl: "rounded-xl",
|
|
42
|
+
"2xl": "rounded-2xl",
|
|
43
|
+
"3xl": "rounded-3xl",
|
|
44
|
+
full: "rounded-3xl"
|
|
45
|
+
// rounded-full looks unnatural on textarea, using 3xl instead
|
|
46
|
+
},
|
|
47
|
+
resize: {
|
|
48
|
+
none: "resize-none",
|
|
49
|
+
vertical: "resize-y",
|
|
50
|
+
horizontal: "resize-x",
|
|
51
|
+
both: "resize"
|
|
52
|
+
},
|
|
53
|
+
state: {
|
|
54
|
+
default: "",
|
|
55
|
+
error: "border-error hover:border-error focus:border-error shadow-[0_0_0_2px_var(--color-focus-ring-error)]"
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
compoundVariants: [
|
|
59
|
+
// focusRing: true → show custom focus ring
|
|
60
|
+
{ focusRing: true, className: "focus-visible:shadow-[0_0_0_2px_var(--color-focus-ring)]" },
|
|
61
|
+
// focusRing: false → keep same state as hover
|
|
62
|
+
{ variant: "default", focusRing: false, className: "focus:border-border-strong" },
|
|
63
|
+
// filled + error
|
|
64
|
+
{
|
|
65
|
+
variant: "filled",
|
|
66
|
+
state: "error",
|
|
67
|
+
className: "border-transparent hover:border-transparent focus:border-transparent bg-[var(--color-error-bg)] hover:bg-[var(--color-error-bg)] focus:bg-[var(--color-error-bg)] shadow-none"
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
defaultVariants: {
|
|
71
|
+
variant: "default",
|
|
72
|
+
size: "default",
|
|
73
|
+
radius: "default",
|
|
74
|
+
resize: "vertical",
|
|
75
|
+
state: "default",
|
|
76
|
+
focusRing: false
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
var Textarea = React.forwardRef(
|
|
81
|
+
({ className, variant, size, radius, resize, state, error, focusRing, id, rows = 4, onPointerDown, onFocus, onBlur, ...props }, ref) => {
|
|
82
|
+
const fieldContext = useFieldContext();
|
|
83
|
+
const resolvedError = error ?? fieldContext?.error;
|
|
84
|
+
const resolvedState = resolvedError ? "error" : state;
|
|
85
|
+
const textareaId = id ?? fieldContext?.id;
|
|
86
|
+
const isDisabled = props.disabled ?? fieldContext?.disabled;
|
|
87
|
+
const pointerRef = React.useRef(false);
|
|
88
|
+
const windowBlurredRef = React.useRef(false);
|
|
89
|
+
const [keyboardFocus, setKeyboardFocus] = React.useState(false);
|
|
90
|
+
React.useEffect(() => {
|
|
91
|
+
const onBlur2 = () => {
|
|
92
|
+
windowBlurredRef.current = true;
|
|
93
|
+
};
|
|
94
|
+
const onFocus2 = () => {
|
|
95
|
+
requestAnimationFrame(() => {
|
|
96
|
+
windowBlurredRef.current = false;
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
window.addEventListener("blur", onBlur2);
|
|
100
|
+
window.addEventListener("focus", onFocus2);
|
|
101
|
+
return () => {
|
|
102
|
+
window.removeEventListener("blur", onBlur2);
|
|
103
|
+
window.removeEventListener("focus", onFocus2);
|
|
104
|
+
};
|
|
105
|
+
}, []);
|
|
106
|
+
const handlePointerDown = React.useCallback((e) => {
|
|
107
|
+
pointerRef.current = true;
|
|
108
|
+
onPointerDown?.(e);
|
|
109
|
+
}, [onPointerDown]);
|
|
110
|
+
const handleFocus = React.useCallback((e) => {
|
|
111
|
+
if (!pointerRef.current && !focusRing && !windowBlurredRef.current) {
|
|
112
|
+
setKeyboardFocus(true);
|
|
113
|
+
}
|
|
114
|
+
pointerRef.current = false;
|
|
115
|
+
onFocus?.(e);
|
|
116
|
+
}, [focusRing, onFocus]);
|
|
117
|
+
const handleBlur = React.useCallback((e) => {
|
|
118
|
+
setKeyboardFocus(false);
|
|
119
|
+
pointerRef.current = false;
|
|
120
|
+
onBlur?.(e);
|
|
121
|
+
}, [onBlur]);
|
|
122
|
+
const ariaDescribedBy = fieldContext ? [
|
|
123
|
+
resolvedError ? `${fieldContext.id}-error` : null
|
|
124
|
+
].filter(Boolean).join(" ") || void 0 : void 0;
|
|
125
|
+
return /* @__PURE__ */ React.createElement(
|
|
126
|
+
"textarea",
|
|
127
|
+
{
|
|
128
|
+
id: textareaId,
|
|
129
|
+
rows,
|
|
130
|
+
className: cn(
|
|
131
|
+
textareaVariants({ variant, size, radius, resize, state: resolvedState, focusRing }),
|
|
132
|
+
keyboardFocus && "shadow-[0_0_0_2px_var(--color-focus-ring)]",
|
|
133
|
+
className
|
|
134
|
+
),
|
|
135
|
+
"aria-invalid": resolvedError || void 0,
|
|
136
|
+
"aria-describedby": ariaDescribedBy,
|
|
137
|
+
disabled: isDisabled,
|
|
138
|
+
ref,
|
|
139
|
+
onPointerDown: handlePointerDown,
|
|
140
|
+
onFocus: handleFocus,
|
|
141
|
+
onBlur: handleBlur,
|
|
142
|
+
...props
|
|
143
|
+
}
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
);
|
|
147
|
+
Textarea.displayName = "Textarea";
|
|
148
|
+
|
|
149
|
+
export {
|
|
150
|
+
textareaVariants,
|
|
151
|
+
Textarea
|
|
152
|
+
};
|
|
153
|
+
//# sourceMappingURL=chunk-N4K2BDGM.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/ui/textarea.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@/lib/utils'\nimport { useFieldContext } from './field'\n\nconst textareaVariants = cva(\n [\n 'flex w-full bg-background text-foreground placeholder:text-foreground/30',\n 'border transition-colors duration-micro outline-transparent',\n 'focus:[outline:2px_solid_transparent]',\n 'disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-background-muted',\n ].join(' '),\n {\n variants: {\n variant: {\n default: 'border-border hover:border-border-strong',\n filled: 'border-transparent bg-background-muted',\n },\n focusRing: {\n true: '',\n false: '',\n },\n size: {\n compact: 'px-3 py-2 text-md', // 12px padding / 14px font - compact spaces\n default: 'px-4 py-3 text-base', // 16px padding / 16px font - standard\n },\n radius: {\n none: 'rounded-none',\n sm: 'rounded-sm',\n base: 'rounded',\n default: 'rounded-md',\n lg: 'rounded-lg',\n xl: 'rounded-xl',\n '2xl': 'rounded-2xl',\n '3xl': 'rounded-3xl',\n full: 'rounded-3xl', // rounded-full looks unnatural on textarea, using 3xl instead\n },\n resize: {\n none: 'resize-none',\n vertical: 'resize-y',\n horizontal: 'resize-x',\n both: 'resize',\n },\n state: {\n default: '',\n error: 'border-error hover:border-error focus:border-error shadow-[0_0_0_2px_var(--color-focus-ring-error)]',\n },\n },\n compoundVariants: [\n // focusRing: true → show custom focus ring\n { focusRing: true, className: 'focus-visible:shadow-[0_0_0_2px_var(--color-focus-ring)]' },\n // focusRing: false → keep same state as hover\n { variant: 'default', focusRing: false, className: 'focus:border-border-strong' },\n // filled + error\n {\n variant: 'filled',\n state: 'error',\n className: 'border-transparent hover:border-transparent focus:border-transparent bg-[var(--color-error-bg)] hover:bg-[var(--color-error-bg)] focus:bg-[var(--color-error-bg)] shadow-none',\n },\n ],\n defaultVariants: {\n variant: 'default',\n size: 'default',\n radius: 'default',\n resize: 'vertical',\n state: 'default',\n focusRing: false,\n },\n }\n)\n\nexport interface TextareaProps\n extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'size'>,\n VariantProps<typeof textareaVariants> {\n error?: boolean\n focusRing?: boolean\n}\n\nconst Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(\n ({ className, variant, size, radius, resize, state, error, focusRing, id, rows = 4, onPointerDown, onFocus, onBlur, ...props }, ref) => {\n const fieldContext = useFieldContext()\n const resolvedError = error ?? fieldContext?.error\n const resolvedState = resolvedError ? 'error' : state\n const textareaId = id ?? fieldContext?.id\n const isDisabled = props.disabled ?? fieldContext?.disabled\n\n // Keyboard focus detection (when focusRing: false, auto-show ring on Tab navigation)\n const pointerRef = React.useRef(false)\n const windowBlurredRef = React.useRef(false)\n const [keyboardFocus, setKeyboardFocus] = React.useState(false)\n\n // Track window blur/focus to distinguish Tab navigation from window re-activation\n React.useEffect(() => {\n const onBlur = () => { windowBlurredRef.current = true }\n const onFocus = () => { requestAnimationFrame(() => { windowBlurredRef.current = false }) }\n window.addEventListener('blur', onBlur)\n window.addEventListener('focus', onFocus)\n return () => { window.removeEventListener('blur', onBlur); window.removeEventListener('focus', onFocus) }\n }, [])\n\n const handlePointerDown = React.useCallback((e: React.PointerEvent<HTMLTextAreaElement>) => {\n pointerRef.current = true\n onPointerDown?.(e)\n }, [onPointerDown])\n\n const handleFocus = React.useCallback((e: React.FocusEvent<HTMLTextAreaElement>) => {\n if (!pointerRef.current && !focusRing && !windowBlurredRef.current) {\n setKeyboardFocus(true)\n }\n pointerRef.current = false\n onFocus?.(e)\n }, [focusRing, onFocus])\n\n const handleBlur = React.useCallback((e: React.FocusEvent<HTMLTextAreaElement>) => {\n setKeyboardFocus(false)\n pointerRef.current = false\n onBlur?.(e)\n }, [onBlur])\n\n // Build aria-describedby from context\n const ariaDescribedBy = fieldContext\n ? [\n resolvedError ? `${fieldContext.id}-error` : null,\n ]\n .filter(Boolean)\n .join(' ') || undefined\n : undefined\n\n return (\n <textarea\n id={textareaId}\n rows={rows}\n className={cn(\n textareaVariants({ variant, size, radius, resize, state: resolvedState, focusRing }),\n keyboardFocus && 'shadow-[0_0_0_2px_var(--color-focus-ring)]',\n className\n )}\n aria-invalid={resolvedError || undefined}\n aria-describedby={ariaDescribedBy}\n disabled={isDisabled}\n ref={ref}\n onPointerDown={handlePointerDown}\n onFocus={handleFocus}\n onBlur={handleBlur}\n {...props}\n />\n )\n }\n)\nTextarea.displayName = 'Textarea'\n\nexport { Textarea, textareaVariants }\n"],"mappings":"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","names":["onBlur","onFocus"]}
|