@hilum/ui 3.4.0 → 3.5.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 +4 -0
- package/dist/{chunk-MAHPAP65.js → chunk-RI6QJR2L.js} +6 -3
- package/dist/chunk-RI6QJR2L.js.map +1 -0
- package/dist/index.d.ts +789 -115
- package/dist/index.js +10404 -1099
- package/dist/index.js.map +1 -1
- package/dist/tokens.css +17 -0
- package/dist/tokens.d.ts +3 -0
- package/dist/tokens.js +1 -1
- package/llms.txt +18 -4
- package/package.json +19 -1
- package/src/components/accordion.tsx +746 -58
- package/src/components/alert-dialog.tsx +11 -5
- package/src/components/ask-user-questions.tsx +1366 -0
- package/src/components/badge.tsx +105 -24
- package/src/components/button.tsx +207 -38
- package/src/components/card.tsx +3 -2
- package/src/components/chat-message.tsx +116 -0
- package/src/components/checkbox-group.tsx +403 -0
- package/src/components/checkbox.tsx +6 -3
- package/src/components/color-input.tsx +3 -1
- package/src/components/color-picker.tsx +1992 -80
- package/src/components/dialog.tsx +141 -81
- package/src/components/dropdown-menu.tsx +21 -13
- package/src/components/dropdown.tsx +245 -0
- package/src/components/file-thumbnail.tsx +156 -0
- package/src/components/hover-card.tsx +2 -0
- package/src/components/input-copy.tsx +307 -0
- package/src/components/input-group.tsx +303 -108
- package/src/components/input-message.tsx +883 -0
- package/src/components/input.tsx +6 -3
- package/src/components/menu-item.tsx +156 -0
- package/src/components/mobile-drawer.tsx +50 -0
- package/src/components/nav-item.tsx +43 -0
- package/src/components/nav-menu.tsx +47 -0
- package/src/components/popover.tsx +3 -1
- package/src/components/radio-group.tsx +381 -35
- package/src/components/scroll-area.tsx +9 -2
- package/src/components/select.tsx +708 -121
- package/src/components/sheet.tsx +15 -6
- package/src/components/slider.tsx +1583 -20
- package/src/components/status-badge.tsx +2 -0
- package/src/components/switch.tsx +245 -28
- package/src/components/table.tsx +191 -77
- package/src/components/tabs-subtle.tsx +411 -0
- package/src/components/tabs.tsx +459 -49
- package/src/components/textarea.tsx +7 -3
- package/src/components/thinking-indicator.tsx +106 -0
- package/src/components/thinking-steps.tsx +382 -0
- package/src/components/tooltip.tsx +158 -33
- package/src/hooks/use-merge-split.tsx +359 -0
- package/src/hooks/use-proximity-hover.ts +208 -0
- package/src/index.ts +14 -0
- package/src/lib/elevated.tsx +52 -0
- package/src/lib/font-weight.ts +18 -0
- package/src/lib/icon-context.tsx +98 -0
- package/src/lib/icon-map.tsx +669 -0
- package/src/lib/interaction.ts +102 -0
- package/src/lib/scroll-fade.tsx +241 -0
- package/src/lib/shape-context.tsx +121 -0
- package/src/lib/springs.ts +30 -0
- package/src/lib/surface-classes.ts +43 -0
- package/src/lib/surface-context.tsx +17 -0
- package/src/tokens/tokens.ts +3 -0
- package/dist/chunk-MAHPAP65.js.map +0 -1
|
@@ -1,39 +1,385 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
Children,
|
|
5
|
+
useRef,
|
|
6
|
+
useState,
|
|
7
|
+
useEffect,
|
|
8
|
+
createContext,
|
|
9
|
+
useContext,
|
|
10
|
+
forwardRef,
|
|
11
|
+
isValidElement,
|
|
12
|
+
cloneElement,
|
|
13
|
+
type ReactNode,
|
|
14
|
+
type HTMLAttributes,
|
|
15
|
+
} from "react";
|
|
16
|
+
import { motion, AnimatePresence } from "framer-motion";
|
|
17
|
+
import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
|
|
5
18
|
import { cn } from "../lib/utils";
|
|
19
|
+
import { spring } from "../lib/springs";
|
|
20
|
+
import { fontWeights } from "../lib/font-weight";
|
|
21
|
+
import { useProximityHover } from "../hooks/use-proximity-hover";
|
|
22
|
+
import { useShape } from "../lib/shape-context";
|
|
6
23
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
24
|
+
interface RadioGroupContextValue {
|
|
25
|
+
registerItem: (index: number, element: HTMLElement | null) => void;
|
|
26
|
+
activeIndex: number | null;
|
|
27
|
+
selectedIndex: number | null;
|
|
28
|
+
selectedValue?: string;
|
|
29
|
+
onValueChange?: (value: string) => void;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const RadioGroupContext = createContext<RadioGroupContextValue | null>(null);
|
|
33
|
+
|
|
34
|
+
function useRadioGroupContext() {
|
|
35
|
+
const ctx = useContext(RadioGroupContext);
|
|
36
|
+
if (!ctx) throw new Error("useRadioGroup must be used within a RadioGroup");
|
|
37
|
+
return ctx;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface RadioGroupProps extends Omit<HTMLAttributes<HTMLDivElement>, "onSelect"> {
|
|
41
|
+
children: ReactNode;
|
|
42
|
+
selectedIndex?: number;
|
|
43
|
+
value?: string;
|
|
44
|
+
defaultValue?: string;
|
|
45
|
+
onValueChange?: (value: string) => void;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const RadioGroup = forwardRef<HTMLDivElement, RadioGroupProps>(
|
|
49
|
+
({ children, selectedIndex, value, defaultValue, onValueChange, className, ...props }, ref) => {
|
|
50
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
51
|
+
const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
|
|
52
|
+
const currentValue = value ?? uncontrolledValue;
|
|
53
|
+
const childValues = Children.toArray(children)
|
|
54
|
+
.filter(isValidElement)
|
|
55
|
+
.map((child) => (child.props as { value?: string }).value);
|
|
56
|
+
const {
|
|
57
|
+
activeIndex,
|
|
58
|
+
setActiveIndex,
|
|
59
|
+
itemRects,
|
|
60
|
+
sessionRef,
|
|
61
|
+
handlers,
|
|
62
|
+
registerItem,
|
|
63
|
+
measureItems,
|
|
64
|
+
} = useProximityHover(containerRef);
|
|
65
|
+
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
measureItems();
|
|
68
|
+
}, [measureItems, children]);
|
|
69
|
+
|
|
70
|
+
const [focusedIndex, setFocusedIndex] = useState<number | null>(null);
|
|
71
|
+
const resolvedSelectedIndex =
|
|
72
|
+
currentValue !== undefined
|
|
73
|
+
? childValues.findIndex((childValue) => childValue === currentValue)
|
|
74
|
+
: (selectedIndex ?? -1);
|
|
75
|
+
|
|
76
|
+
const activeRect = activeIndex !== null ? itemRects[activeIndex] : null;
|
|
77
|
+
const focusRect = focusedIndex !== null ? itemRects[focusedIndex] : null;
|
|
78
|
+
const selectedRect = resolvedSelectedIndex >= 0 ? itemRects[resolvedSelectedIndex] : null;
|
|
79
|
+
const isHoveringOther = activeIndex !== null && activeIndex !== resolvedSelectedIndex;
|
|
80
|
+
const shape = useShape();
|
|
81
|
+
|
|
82
|
+
const indexedChildren = Children.map(children, (child, index) => {
|
|
83
|
+
if (!isValidElement(child)) return child;
|
|
84
|
+
return cloneElement(child, { index } as Record<string, unknown>);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const handleValueChange = (nextValue: string) => {
|
|
88
|
+
if (value === undefined) setUncontrolledValue(nextValue);
|
|
89
|
+
onValueChange?.(nextValue);
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const content = (
|
|
93
|
+
<div
|
|
94
|
+
ref={(node) => {
|
|
95
|
+
(containerRef as React.MutableRefObject<HTMLDivElement | null>).current = node;
|
|
96
|
+
if (typeof ref === "function") ref(node);
|
|
97
|
+
else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node;
|
|
98
|
+
}}
|
|
99
|
+
onMouseEnter={handlers.onMouseEnter}
|
|
100
|
+
onMouseMove={handlers.onMouseMove}
|
|
101
|
+
onMouseLeave={handlers.onMouseLeave}
|
|
102
|
+
onFocus={(e) => {
|
|
103
|
+
const indexAttr = (e.target as HTMLElement)
|
|
104
|
+
.closest("[data-proximity-index]")
|
|
105
|
+
?.getAttribute("data-proximity-index");
|
|
106
|
+
if (indexAttr != null) {
|
|
107
|
+
const idx = Number(indexAttr);
|
|
108
|
+
setActiveIndex(idx);
|
|
109
|
+
setFocusedIndex((e.target as HTMLElement).matches(":focus-visible") ? idx : null);
|
|
110
|
+
}
|
|
111
|
+
}}
|
|
112
|
+
onBlur={(e) => {
|
|
113
|
+
if (containerRef.current?.contains(e.relatedTarget as Node)) return;
|
|
114
|
+
setFocusedIndex(null);
|
|
115
|
+
setActiveIndex(null);
|
|
116
|
+
}}
|
|
117
|
+
onKeyDown={(e) => {
|
|
118
|
+
const items = Array.from(
|
|
119
|
+
containerRef.current?.querySelectorAll('[role="radio"]') ?? [],
|
|
120
|
+
) as HTMLElement[];
|
|
121
|
+
const currentIdx = items.indexOf(e.target as HTMLElement);
|
|
122
|
+
if (currentIdx === -1) return;
|
|
123
|
+
|
|
124
|
+
if (["ArrowDown", "ArrowUp", "ArrowRight", "ArrowLeft"].includes(e.key)) {
|
|
125
|
+
e.preventDefault();
|
|
126
|
+
const next = ["ArrowDown", "ArrowRight"].includes(e.key)
|
|
127
|
+
? (currentIdx + 1) % items.length
|
|
128
|
+
: (currentIdx - 1 + items.length) % items.length;
|
|
129
|
+
items[next].focus();
|
|
130
|
+
items[next].click();
|
|
131
|
+
} else if (e.key === "Home") {
|
|
132
|
+
e.preventDefault();
|
|
133
|
+
items[0]?.focus();
|
|
134
|
+
items[0]?.click();
|
|
135
|
+
} else if (e.key === "End") {
|
|
136
|
+
e.preventDefault();
|
|
137
|
+
items[items.length - 1]?.focus();
|
|
138
|
+
items[items.length - 1]?.click();
|
|
139
|
+
}
|
|
140
|
+
}}
|
|
141
|
+
role="radiogroup"
|
|
142
|
+
className={cn("relative flex flex-col w-72 max-w-full select-none", className)}
|
|
143
|
+
{...props}
|
|
144
|
+
>
|
|
145
|
+
{/* Selected background */}
|
|
146
|
+
{selectedRect && (
|
|
147
|
+
<motion.div
|
|
148
|
+
className={`absolute ${shape.bg} bg-active pointer-events-none`}
|
|
149
|
+
initial={false}
|
|
150
|
+
animate={{
|
|
151
|
+
top: selectedRect.top,
|
|
152
|
+
left: selectedRect.left,
|
|
153
|
+
width: selectedRect.width,
|
|
154
|
+
height: selectedRect.height,
|
|
155
|
+
opacity: isHoveringOther ? 0.8 : 1,
|
|
156
|
+
}}
|
|
157
|
+
transition={{
|
|
158
|
+
...spring.moderate,
|
|
159
|
+
opacity: { duration: 0.08 },
|
|
160
|
+
}}
|
|
161
|
+
/>
|
|
162
|
+
)}
|
|
163
|
+
|
|
164
|
+
{/* Hover background */}
|
|
165
|
+
<AnimatePresence>
|
|
166
|
+
{activeRect && (
|
|
167
|
+
<motion.div
|
|
168
|
+
key={sessionRef.current}
|
|
169
|
+
className={`absolute ${shape.bg} bg-hover pointer-events-none`}
|
|
170
|
+
initial={{
|
|
171
|
+
opacity: 0,
|
|
172
|
+
top: activeRect.top,
|
|
173
|
+
left: activeRect.left,
|
|
174
|
+
width: activeRect.width,
|
|
175
|
+
height: activeRect.height,
|
|
176
|
+
}}
|
|
177
|
+
animate={{
|
|
178
|
+
opacity: 1,
|
|
179
|
+
top: activeRect.top,
|
|
180
|
+
left: activeRect.left,
|
|
181
|
+
width: activeRect.width,
|
|
182
|
+
height: activeRect.height,
|
|
183
|
+
}}
|
|
184
|
+
exit={{ opacity: 0, transition: spring.fast.exit }}
|
|
185
|
+
transition={{
|
|
186
|
+
...spring.fast,
|
|
187
|
+
opacity: { duration: 0.08 },
|
|
188
|
+
}}
|
|
189
|
+
/>
|
|
190
|
+
)}
|
|
191
|
+
</AnimatePresence>
|
|
192
|
+
|
|
193
|
+
{/* Focus ring */}
|
|
194
|
+
<AnimatePresence>
|
|
195
|
+
{focusRect && (
|
|
196
|
+
<motion.div
|
|
197
|
+
className={`absolute ${shape.focusRing} pointer-events-none z-20 border border-[#6B97FF]`}
|
|
198
|
+
initial={false}
|
|
199
|
+
animate={{
|
|
200
|
+
left: focusRect.left - 2,
|
|
201
|
+
top: focusRect.top - 2,
|
|
202
|
+
width: focusRect.width + 4,
|
|
203
|
+
height: focusRect.height + 4,
|
|
204
|
+
}}
|
|
205
|
+
exit={{ opacity: 0, transition: spring.fast.exit }}
|
|
206
|
+
transition={{
|
|
207
|
+
...spring.fast,
|
|
208
|
+
opacity: { duration: 0.08 },
|
|
209
|
+
}}
|
|
210
|
+
/>
|
|
211
|
+
)}
|
|
212
|
+
</AnimatePresence>
|
|
213
|
+
|
|
214
|
+
{indexedChildren}
|
|
215
|
+
</div>
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
// If Radix value/onValueChange provided, wrap with Radix RadioGroup
|
|
219
|
+
if (currentValue !== undefined) {
|
|
220
|
+
return (
|
|
221
|
+
<RadioGroupContext.Provider
|
|
222
|
+
value={{
|
|
223
|
+
registerItem,
|
|
224
|
+
activeIndex,
|
|
225
|
+
selectedIndex: resolvedSelectedIndex >= 0 ? resolvedSelectedIndex : null,
|
|
226
|
+
selectedValue: currentValue,
|
|
227
|
+
onValueChange: handleValueChange,
|
|
228
|
+
}}
|
|
229
|
+
>
|
|
230
|
+
<RadioGroupPrimitive.Root value={currentValue} onValueChange={handleValueChange} asChild>
|
|
231
|
+
{content}
|
|
232
|
+
</RadioGroupPrimitive.Root>
|
|
233
|
+
</RadioGroupContext.Provider>
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return (
|
|
238
|
+
<RadioGroupContext.Provider
|
|
239
|
+
value={{
|
|
240
|
+
registerItem,
|
|
241
|
+
activeIndex,
|
|
242
|
+
selectedIndex: selectedIndex ?? null,
|
|
243
|
+
}}
|
|
244
|
+
>
|
|
245
|
+
{content}
|
|
246
|
+
</RadioGroupContext.Provider>
|
|
247
|
+
);
|
|
248
|
+
},
|
|
249
|
+
);
|
|
250
|
+
|
|
251
|
+
RadioGroup.displayName = "RadioGroup";
|
|
252
|
+
|
|
253
|
+
interface RadioItemProps extends HTMLAttributes<HTMLDivElement> {
|
|
254
|
+
label?: string;
|
|
255
|
+
index?: number;
|
|
256
|
+
selected?: boolean;
|
|
257
|
+
onSelect?: () => void;
|
|
258
|
+
value?: string;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const RadioItem = forwardRef<HTMLDivElement, RadioItemProps>(
|
|
262
|
+
({ label, index = 0, selected, onSelect, value, className, children, ...props }, ref) => {
|
|
263
|
+
const internalRef = useRef<HTMLDivElement>(null);
|
|
264
|
+
const hasMounted = useRef(false);
|
|
265
|
+
const { registerItem, activeIndex, selectedIndex, selectedValue, onValueChange } =
|
|
266
|
+
useRadioGroupContext();
|
|
267
|
+
|
|
268
|
+
useEffect(() => {
|
|
269
|
+
registerItem(index, internalRef.current);
|
|
270
|
+
return () => registerItem(index, null);
|
|
271
|
+
}, [index, registerItem]);
|
|
272
|
+
|
|
273
|
+
useEffect(() => {
|
|
274
|
+
hasMounted.current = true;
|
|
275
|
+
}, []);
|
|
276
|
+
|
|
277
|
+
const isActive = activeIndex === index;
|
|
278
|
+
const skipAnimation = !hasMounted.current;
|
|
279
|
+
const shape = useShape();
|
|
280
|
+
const isSelected =
|
|
281
|
+
value !== undefined && selectedValue !== undefined
|
|
282
|
+
? selectedValue === value
|
|
283
|
+
: (selected ?? selectedIndex === index);
|
|
284
|
+
|
|
285
|
+
const handleSelect = () => {
|
|
286
|
+
if (value !== undefined) {
|
|
287
|
+
onValueChange?.(value);
|
|
288
|
+
}
|
|
289
|
+
onSelect?.();
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
return (
|
|
293
|
+
<div
|
|
294
|
+
ref={(node) => {
|
|
295
|
+
(internalRef as React.MutableRefObject<HTMLDivElement | null>).current = node;
|
|
296
|
+
if (typeof ref === "function") ref(node);
|
|
297
|
+
else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node;
|
|
298
|
+
}}
|
|
299
|
+
data-proximity-index={index}
|
|
300
|
+
tabIndex={isSelected ? 0 : -1}
|
|
301
|
+
role="radio"
|
|
302
|
+
aria-checked={isSelected}
|
|
303
|
+
aria-label={label ?? (typeof children === "string" ? children : value)}
|
|
304
|
+
onClick={handleSelect}
|
|
305
|
+
onKeyDown={(e) => {
|
|
306
|
+
if (e.key === " " || e.key === "Enter") {
|
|
307
|
+
e.preventDefault();
|
|
308
|
+
handleSelect();
|
|
309
|
+
}
|
|
310
|
+
}}
|
|
311
|
+
className={cn(
|
|
312
|
+
`relative z-10 flex items-center gap-2.5 ${shape.item} px-3 py-1.5 cursor-pointer outline-none`,
|
|
313
|
+
className,
|
|
314
|
+
)}
|
|
315
|
+
{...props}
|
|
316
|
+
>
|
|
317
|
+
{/* Radio circle */}
|
|
318
|
+
<div className="relative w-[15px] h-[15px] shrink-0">
|
|
319
|
+
{/* Border */}
|
|
320
|
+
<div
|
|
321
|
+
className={cn(
|
|
322
|
+
"absolute inset-0 rounded-full border-solid transition-all duration-80",
|
|
323
|
+
isSelected
|
|
324
|
+
? "border-[1.5px] border-transparent"
|
|
325
|
+
: isActive
|
|
326
|
+
? "border-[1.5px] border-neutral-400 dark:border-neutral-500"
|
|
327
|
+
: "border-[1.5px] border-border",
|
|
328
|
+
)}
|
|
329
|
+
/>
|
|
330
|
+
{/* Dot */}
|
|
331
|
+
<AnimatePresence>
|
|
332
|
+
{isSelected && (
|
|
333
|
+
<motion.div
|
|
334
|
+
className="absolute inset-0 flex items-center justify-center"
|
|
335
|
+
initial={{
|
|
336
|
+
opacity: skipAnimation ? 1 : 0,
|
|
337
|
+
scale: skipAnimation ? 1 : 0.3,
|
|
338
|
+
}}
|
|
339
|
+
animate={{ opacity: 1, scale: 1 }}
|
|
340
|
+
exit={{ opacity: 0, scale: 0.3, transition: { duration: 0.04 } }}
|
|
341
|
+
transition={spring.fast}
|
|
342
|
+
>
|
|
343
|
+
<div className="w-[8px] h-[8px] rounded-full bg-foreground" />
|
|
344
|
+
</motion.div>
|
|
345
|
+
)}
|
|
346
|
+
</AnimatePresence>
|
|
347
|
+
</div>
|
|
348
|
+
|
|
349
|
+
{/* Label */}
|
|
350
|
+
<span className="inline-grid text-[13px]">
|
|
351
|
+
<span
|
|
352
|
+
className="col-start-1 row-start-1 invisible"
|
|
353
|
+
style={{ fontVariationSettings: fontWeights.semibold }}
|
|
354
|
+
aria-hidden="true"
|
|
355
|
+
>
|
|
356
|
+
{label ?? children ?? value}
|
|
357
|
+
</span>
|
|
358
|
+
<span
|
|
359
|
+
className={cn(
|
|
360
|
+
"col-start-1 row-start-1 transition-[color,font-variation-settings] duration-80",
|
|
361
|
+
isSelected || isActive ? "text-foreground" : "text-muted-foreground",
|
|
362
|
+
)}
|
|
363
|
+
style={{
|
|
364
|
+
fontVariationSettings: isSelected ? fontWeights.semibold : fontWeights.normal,
|
|
365
|
+
}}
|
|
366
|
+
>
|
|
367
|
+
{label ?? children ?? value}
|
|
368
|
+
</span>
|
|
369
|
+
</span>
|
|
370
|
+
|
|
371
|
+
{/* Hidden Radix radio input for accessibility */}
|
|
372
|
+
{value !== undefined && (
|
|
373
|
+
<RadioGroupPrimitive.Item value={value} className="sr-only" tabIndex={-1} aria-hidden />
|
|
374
|
+
)}
|
|
375
|
+
</div>
|
|
376
|
+
);
|
|
377
|
+
},
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
RadioItem.displayName = "RadioItem";
|
|
381
|
+
|
|
382
|
+
const RadioGroupItem = RadioItem;
|
|
383
|
+
|
|
384
|
+
export { RadioGroup, RadioItem, RadioGroupItem };
|
|
385
|
+
export default RadioGroup;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { ScrollArea } from "radix-ui";
|
|
5
5
|
import { cn } from "../lib/utils";
|
|
6
|
+
import { motionClasses } from "../lib/interaction";
|
|
6
7
|
|
|
7
8
|
const ScrollAreaRoot = React.forwardRef<
|
|
8
9
|
React.ComponentRef<typeof ScrollArea.Root>,
|
|
@@ -27,14 +28,20 @@ const ScrollAreaScrollbar = React.forwardRef<
|
|
|
27
28
|
ref={ref}
|
|
28
29
|
orientation={orientation}
|
|
29
30
|
className={cn(
|
|
30
|
-
"flex touch-none select-none
|
|
31
|
+
"flex touch-none select-none",
|
|
32
|
+
motionClasses,
|
|
31
33
|
orientation === "vertical" && "h-full w-2 border-l border-l-transparent p-px",
|
|
32
34
|
orientation === "horizontal" && "h-2 flex-col border-t border-t-transparent p-px",
|
|
33
35
|
className,
|
|
34
36
|
)}
|
|
35
37
|
{...props}
|
|
36
38
|
>
|
|
37
|
-
<ScrollArea.Thumb
|
|
39
|
+
<ScrollArea.Thumb
|
|
40
|
+
className={cn(
|
|
41
|
+
"relative flex-1 rounded-full bg-muted hover:bg-muted-foreground/30",
|
|
42
|
+
motionClasses,
|
|
43
|
+
)}
|
|
44
|
+
/>
|
|
38
45
|
</ScrollArea.Scrollbar>
|
|
39
46
|
));
|
|
40
47
|
ScrollAreaScrollbar.displayName = "ScrollAreaScrollbar";
|