sparkdesign 0.4.7 → 0.4.9
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/cli/registry/AGENTS.md +1 -1
- package/cli/registry/agent-manifest.json +3996 -67
- package/cli/registry/basic/accordion.tsx +79 -0
- package/cli/registry/basic/alert-dialog.tsx +3 -6
- package/cli/registry/basic/badge.tsx +49 -0
- package/cli/registry/basic/button.tsx +32 -14
- package/cli/registry/basic/card.tsx +20 -8
- package/cli/registry/basic/collapsible-card.tsx +12 -5
- package/cli/registry/basic/combobox.tsx +104 -46
- package/cli/registry/basic/context-menu.tsx +2 -3
- package/cli/registry/basic/date-picker.tsx +78 -7
- package/cli/registry/basic/dialog.tsx +3 -8
- package/cli/registry/basic/drawer.tsx +3 -5
- package/cli/registry/basic/dropdown-menu.tsx +2 -3
- package/cli/registry/basic/ellipsis-text.tsx +151 -0
- package/cli/registry/basic/form.tsx +186 -0
- package/cli/registry/basic/hover-card.tsx +2 -3
- package/cli/registry/basic/icon-button.tsx +29 -14
- package/cli/registry/basic/input-group.tsx +4 -4
- package/cli/registry/basic/input.tsx +29 -13
- package/cli/registry/basic/popover.tsx +2 -3
- package/cli/registry/basic/select.tsx +24 -4
- package/cli/registry/basic/sidebar.tsx +665 -0
- package/cli/registry/basic/sonner.tsx +10 -10
- package/cli/registry/basic/spinner.tsx +20 -5
- package/cli/registry/basic/textarea.tsx +30 -12
- package/cli/registry/basic/tooltip.tsx +2 -1
- package/cli/registry/chat/chat-input/compound.tsx +1 -0
- package/cli/registry/chat/user-question/compound.tsx +2 -0
- package/cli/registry/meta.json +250 -30
- package/dist/registry/basic/accordion.d.ts +15 -0
- package/dist/registry/basic/alert-dialog.d.ts +1 -1
- package/dist/registry/basic/avatar.d.ts +1 -1
- package/dist/registry/basic/badge.d.ts +23 -0
- package/dist/registry/basic/button.d.ts +3 -1
- package/dist/registry/basic/card.d.ts +9 -4
- package/dist/registry/basic/combobox.d.ts +20 -9
- package/dist/registry/basic/date-picker.d.ts +18 -9
- package/dist/registry/basic/dialog.d.ts +1 -1
- package/dist/registry/basic/ellipsis-text.d.ts +45 -0
- package/dist/registry/basic/form.d.ts +23 -0
- package/dist/registry/basic/icon-button.d.ts +17 -3
- package/dist/registry/basic/input-group.d.ts +5 -3
- package/dist/registry/basic/input.d.ts +8 -3
- package/dist/registry/basic/item.d.ts +3 -3
- package/dist/registry/basic/resizable.d.ts +48 -48
- package/dist/registry/basic/select.d.ts +7 -2
- package/dist/registry/basic/sidebar.d.ts +72 -0
- package/dist/registry/basic/spinner.d.ts +6 -2
- package/dist/registry/basic/tag.d.ts +1 -1
- package/dist/registry/basic/textarea.d.ts +9 -3
- package/dist/registry/basic/toggle.d.ts +1 -1
- package/dist/scale/computed.css +11 -0
- package/dist/scale/config.css +11 -0
- package/dist/scale/presets/compact.css +7 -0
- package/dist/scale/presets/dense.css +7 -0
- package/dist/scale/presets/sharp.css +7 -0
- package/dist/scale/presets/soft.css +7 -0
- package/dist/spark-design.cjs.js +34 -37
- package/dist/spark-design.es.js +7200 -4933
- package/dist/sparkdesign.css +1 -1
- package/dist/src/components/basic/Accordion/index.d.ts +13 -0
- package/dist/src/components/basic/Badge/index.d.ts +13 -0
- package/dist/src/components/basic/EllipsisText/index.d.ts +4 -36
- package/dist/src/components/basic/Form/index.d.ts +12 -0
- package/dist/src/components/basic/Sidebar/index.d.ts +13 -0
- package/dist/src/components/index.d.ts +7 -3
- package/dist/src/lib/index.d.ts +1 -1
- package/dist/src/lib/motion.d.ts +79 -0
- package/dist/theme-base.css +22 -0
- package/dist/themes/dark-mint.css +6 -0
- package/dist/themes/dark-parchment.css +6 -0
- package/dist/themes/light-parchment.css +6 -0
- package/dist/tokens/scale/computed.css +11 -0
- package/dist/tokens/scale/config.css +11 -0
- package/dist/tokens/scale/presets/compact.css +7 -0
- package/dist/tokens/scale/presets/dense.css +7 -0
- package/dist/tokens/scale/presets/sharp.css +7 -0
- package/dist/tokens/scale/presets/soft.css +7 -0
- package/dist/tokens/theme-base.css +22 -0
- package/dist/tokens/themes/dark-mint.css +6 -0
- package/dist/tokens/themes/dark-parchment.css +6 -0
- package/dist/tokens/themes/light-parchment.css +6 -0
- package/docs/agent/component-selection.md +106 -4
- package/package.json +8 -3
- package/registry/agent-manifest.json +3996 -67
- package/cli/registry/chat/user-question/UserQuestionCard.tsx +0 -198
- package/cli/registry/chat/user-question/UserQuestionFooter.tsx +0 -66
- package/cli/registry/chat/user-question/UserQuestionHeader.tsx +0 -64
- package/cli/registry/chat/user-question/useUserQuestionState.ts +0 -165
- package/dist/registry/chat/user-question/UserQuestionCard.d.ts +0 -36
- package/dist/registry/chat/user-question/UserQuestionFooter.d.ts +0 -24
- package/dist/registry/chat/user-question/UserQuestionHeader.d.ts +0 -26
- package/dist/registry/chat/user-question/useUserQuestionState.d.ts +0 -26
- package/dist/src/components/basic/CollapsibleSection/index.d.ts +0 -43
- package/dist/src/components/chat/Response/StreamingMarkdownBlock.d.ts +0 -12
|
@@ -0,0 +1,665 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { Slot } from "@radix-ui/react-slot"
|
|
5
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
6
|
+
import { PanelLeft } from "lucide-react"
|
|
7
|
+
|
|
8
|
+
import { cn } from "@/lib/utils"
|
|
9
|
+
import { Button } from "./button"
|
|
10
|
+
import { Input } from "./input"
|
|
11
|
+
import { Separator } from "./separator"
|
|
12
|
+
import { Sheet, SheetContent } from "./sheet"
|
|
13
|
+
import { Skeleton } from "./skeleton"
|
|
14
|
+
import { Tooltip } from "./tooltip"
|
|
15
|
+
|
|
16
|
+
const SIDEBAR_WIDTH = "16rem"
|
|
17
|
+
const SIDEBAR_WIDTH_ICON = "3rem"
|
|
18
|
+
const SIDEBAR_WIDTH_MOBILE = "18rem"
|
|
19
|
+
const MOBILE_BREAKPOINT = "(max-width: 767px)"
|
|
20
|
+
|
|
21
|
+
type SidebarContextValue = {
|
|
22
|
+
state: "expanded" | "collapsed"
|
|
23
|
+
open: boolean
|
|
24
|
+
setOpen: (open: boolean) => void
|
|
25
|
+
openMobile: boolean
|
|
26
|
+
setOpenMobile: (open: boolean) => void
|
|
27
|
+
isMobile: boolean
|
|
28
|
+
toggleSidebar: () => void
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const SidebarContext = React.createContext<SidebarContextValue | null>(null)
|
|
32
|
+
|
|
33
|
+
function useIsMobile() {
|
|
34
|
+
const [isMobile, setIsMobile] = React.useState(false)
|
|
35
|
+
|
|
36
|
+
React.useEffect(() => {
|
|
37
|
+
const media = window.matchMedia(MOBILE_BREAKPOINT)
|
|
38
|
+
const update = () => setIsMobile(media.matches)
|
|
39
|
+
update()
|
|
40
|
+
media.addEventListener("change", update)
|
|
41
|
+
return () => media.removeEventListener("change", update)
|
|
42
|
+
}, [])
|
|
43
|
+
|
|
44
|
+
return isMobile
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function useSidebar() {
|
|
48
|
+
const context = React.useContext(SidebarContext)
|
|
49
|
+
|
|
50
|
+
if (!context) {
|
|
51
|
+
throw new Error("useSidebar must be used within a SidebarProvider.")
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return context
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function SidebarProvider({
|
|
58
|
+
defaultOpen = true,
|
|
59
|
+
open: openProp,
|
|
60
|
+
onOpenChange: setOpenProp,
|
|
61
|
+
className,
|
|
62
|
+
style,
|
|
63
|
+
children,
|
|
64
|
+
...props
|
|
65
|
+
}: React.ComponentProps<"div"> & {
|
|
66
|
+
defaultOpen?: boolean
|
|
67
|
+
open?: boolean
|
|
68
|
+
onOpenChange?: (open: boolean) => void
|
|
69
|
+
}) {
|
|
70
|
+
const isMobile = useIsMobile()
|
|
71
|
+
const [openMobile, setOpenMobile] = React.useState(false)
|
|
72
|
+
const [_open, _setOpen] = React.useState(defaultOpen)
|
|
73
|
+
const open = openProp ?? _open
|
|
74
|
+
|
|
75
|
+
const setOpen = React.useCallback(
|
|
76
|
+
(value: boolean) => {
|
|
77
|
+
setOpenProp?.(value)
|
|
78
|
+
if (openProp === undefined) _setOpen(value)
|
|
79
|
+
},
|
|
80
|
+
[openProp, setOpenProp]
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
const toggleSidebar = React.useCallback(() => {
|
|
84
|
+
if (isMobile) {
|
|
85
|
+
setOpenMobile((value) => !value)
|
|
86
|
+
return
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
setOpen(!open)
|
|
90
|
+
}, [isMobile, open, setOpen])
|
|
91
|
+
|
|
92
|
+
const state = open ? "expanded" : "collapsed"
|
|
93
|
+
|
|
94
|
+
const contextValue = React.useMemo<SidebarContextValue>(
|
|
95
|
+
() => ({
|
|
96
|
+
state,
|
|
97
|
+
open,
|
|
98
|
+
setOpen,
|
|
99
|
+
isMobile,
|
|
100
|
+
openMobile,
|
|
101
|
+
setOpenMobile,
|
|
102
|
+
toggleSidebar,
|
|
103
|
+
}),
|
|
104
|
+
[state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<SidebarContext.Provider value={contextValue}>
|
|
109
|
+
<div
|
|
110
|
+
data-slot="sidebar-wrapper"
|
|
111
|
+
style={
|
|
112
|
+
{
|
|
113
|
+
"--sidebar-width": SIDEBAR_WIDTH,
|
|
114
|
+
"--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
|
|
115
|
+
...style,
|
|
116
|
+
} as React.CSSProperties
|
|
117
|
+
}
|
|
118
|
+
className={cn(
|
|
119
|
+
"group/sidebar-wrapper flex min-h-svh w-full has-data-[variant=inset]:bg-bg-base",
|
|
120
|
+
className
|
|
121
|
+
)}
|
|
122
|
+
{...props}
|
|
123
|
+
>
|
|
124
|
+
{children}
|
|
125
|
+
</div>
|
|
126
|
+
</SidebarContext.Provider>
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function Sidebar({
|
|
131
|
+
side = "left",
|
|
132
|
+
variant = "sidebar",
|
|
133
|
+
collapsible = "offcanvas",
|
|
134
|
+
className,
|
|
135
|
+
children,
|
|
136
|
+
...props
|
|
137
|
+
}: React.ComponentProps<"div"> & {
|
|
138
|
+
side?: "left" | "right"
|
|
139
|
+
variant?: "sidebar" | "floating" | "inset"
|
|
140
|
+
collapsible?: "offcanvas" | "icon" | "none"
|
|
141
|
+
}) {
|
|
142
|
+
const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
|
|
143
|
+
|
|
144
|
+
if (collapsible === "none") {
|
|
145
|
+
return (
|
|
146
|
+
<div
|
|
147
|
+
data-slot="sidebar"
|
|
148
|
+
className={cn(
|
|
149
|
+
"flex h-full w-[var(--sidebar-width)] flex-col bg-bg-container text-text",
|
|
150
|
+
className
|
|
151
|
+
)}
|
|
152
|
+
{...props}
|
|
153
|
+
>
|
|
154
|
+
{children}
|
|
155
|
+
</div>
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (isMobile) {
|
|
160
|
+
return (
|
|
161
|
+
<Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}>
|
|
162
|
+
<SheetContent
|
|
163
|
+
data-sidebar="sidebar"
|
|
164
|
+
data-slot="sidebar"
|
|
165
|
+
side={side}
|
|
166
|
+
showCloseButton={false}
|
|
167
|
+
className="w-[var(--sidebar-width)] border-border-tertiary bg-bg-container p-0 text-text [&>button]:hidden"
|
|
168
|
+
style={{ "--sidebar-width": SIDEBAR_WIDTH_MOBILE } as React.CSSProperties}
|
|
169
|
+
>
|
|
170
|
+
<div className="flex h-full w-full flex-col">{children}</div>
|
|
171
|
+
</SheetContent>
|
|
172
|
+
</Sheet>
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return (
|
|
177
|
+
<div
|
|
178
|
+
className="group peer hidden text-text md:block"
|
|
179
|
+
data-state={state}
|
|
180
|
+
data-collapsible={state === "collapsed" ? collapsible : ""}
|
|
181
|
+
data-variant={variant}
|
|
182
|
+
data-side={side}
|
|
183
|
+
data-slot="sidebar"
|
|
184
|
+
>
|
|
185
|
+
<div
|
|
186
|
+
className={cn(
|
|
187
|
+
"relative h-svh w-[var(--sidebar-width)] bg-transparent transition-[width] duration-200 ease-linear",
|
|
188
|
+
"group-data-[collapsible=offcanvas]:w-0",
|
|
189
|
+
"group-data-[collapsible=icon]:w-[var(--sidebar-width-icon)]"
|
|
190
|
+
)}
|
|
191
|
+
/>
|
|
192
|
+
<div
|
|
193
|
+
className={cn(
|
|
194
|
+
"fixed inset-y-0 z-10 hidden h-svh w-[var(--sidebar-width)] transition-[left,right,width] duration-200 ease-linear md:flex",
|
|
195
|
+
side === "left"
|
|
196
|
+
? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]"
|
|
197
|
+
: "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
|
|
198
|
+
"group-data-[collapsible=icon]:w-[var(--sidebar-width-icon)]",
|
|
199
|
+
variant === "floating" || variant === "inset"
|
|
200
|
+
? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)+1rem)]"
|
|
201
|
+
: "group-data-[side=left]:border-r group-data-[side=right]:border-l border-border-tertiary",
|
|
202
|
+
className
|
|
203
|
+
)}
|
|
204
|
+
{...props}
|
|
205
|
+
>
|
|
206
|
+
<div
|
|
207
|
+
data-sidebar="sidebar"
|
|
208
|
+
className={cn(
|
|
209
|
+
"flex h-full w-full flex-col bg-bg-container",
|
|
210
|
+
variant === "floating" &&
|
|
211
|
+
"rounded-lg border border-border-tertiary shadow-sm"
|
|
212
|
+
)}
|
|
213
|
+
>
|
|
214
|
+
{children}
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
</div>
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function SidebarTrigger({
|
|
222
|
+
className,
|
|
223
|
+
onClick,
|
|
224
|
+
children,
|
|
225
|
+
...props
|
|
226
|
+
}: Omit<React.ComponentProps<typeof Button>, "children" | "variant" | "size"> & {
|
|
227
|
+
children?: React.ReactNode
|
|
228
|
+
}) {
|
|
229
|
+
const { toggleSidebar } = useSidebar()
|
|
230
|
+
|
|
231
|
+
return (
|
|
232
|
+
<Button
|
|
233
|
+
data-sidebar="trigger"
|
|
234
|
+
data-slot="sidebar-trigger"
|
|
235
|
+
variant="ghost"
|
|
236
|
+
size="md"
|
|
237
|
+
className={cn("size-8 p-0", className)}
|
|
238
|
+
onClick={(event) => {
|
|
239
|
+
onClick?.(event)
|
|
240
|
+
toggleSidebar()
|
|
241
|
+
}}
|
|
242
|
+
{...props}
|
|
243
|
+
>
|
|
244
|
+
{children ?? (
|
|
245
|
+
<>
|
|
246
|
+
<PanelLeft className="size-4" />
|
|
247
|
+
<span className="sr-only">Toggle Sidebar</span>
|
|
248
|
+
</>
|
|
249
|
+
)}
|
|
250
|
+
</Button>
|
|
251
|
+
)
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function SidebarRail({ className, ...props }: React.ComponentProps<"button">) {
|
|
255
|
+
const { toggleSidebar } = useSidebar()
|
|
256
|
+
|
|
257
|
+
return (
|
|
258
|
+
<button
|
|
259
|
+
data-sidebar="rail"
|
|
260
|
+
data-slot="sidebar-rail"
|
|
261
|
+
aria-label="Toggle Sidebar"
|
|
262
|
+
tabIndex={-1}
|
|
263
|
+
onClick={toggleSidebar}
|
|
264
|
+
title="Toggle Sidebar"
|
|
265
|
+
className={cn(
|
|
266
|
+
"absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear after:absolute after:inset-y-0 after:left-1/2 after:w-0.5 hover:after:bg-border md:flex",
|
|
267
|
+
"group-data-[side=left]:-right-4 group-data-[side=right]:left-0",
|
|
268
|
+
className
|
|
269
|
+
)}
|
|
270
|
+
{...props}
|
|
271
|
+
/>
|
|
272
|
+
)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {
|
|
276
|
+
return (
|
|
277
|
+
<main
|
|
278
|
+
data-slot="sidebar-inset"
|
|
279
|
+
className={cn(
|
|
280
|
+
"relative flex min-h-svh flex-1 flex-col bg-bg-base",
|
|
281
|
+
"peer-data-[variant=inset]:m-2 peer-data-[variant=inset]:rounded-lg peer-data-[variant=inset]:border peer-data-[variant=inset]:border-border-tertiary",
|
|
282
|
+
className
|
|
283
|
+
)}
|
|
284
|
+
{...props}
|
|
285
|
+
/>
|
|
286
|
+
)
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function SidebarInput({
|
|
290
|
+
className,
|
|
291
|
+
...props
|
|
292
|
+
}: React.ComponentProps<typeof Input>) {
|
|
293
|
+
return (
|
|
294
|
+
<Input
|
|
295
|
+
data-slot="sidebar-input"
|
|
296
|
+
data-sidebar="input"
|
|
297
|
+
className={cn("h-8 bg-bg-base shadow-none", className)}
|
|
298
|
+
{...props}
|
|
299
|
+
/>
|
|
300
|
+
)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function SidebarHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
304
|
+
return (
|
|
305
|
+
<div
|
|
306
|
+
data-slot="sidebar-header"
|
|
307
|
+
data-sidebar="header"
|
|
308
|
+
className={cn("flex flex-col gap-2 p-2", className)}
|
|
309
|
+
{...props}
|
|
310
|
+
/>
|
|
311
|
+
)
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
function SidebarFooter({ className, ...props }: React.ComponentProps<"div">) {
|
|
315
|
+
return (
|
|
316
|
+
<div
|
|
317
|
+
data-slot="sidebar-footer"
|
|
318
|
+
data-sidebar="footer"
|
|
319
|
+
className={cn("flex flex-col gap-2 p-2", className)}
|
|
320
|
+
{...props}
|
|
321
|
+
/>
|
|
322
|
+
)
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function SidebarSeparator({
|
|
326
|
+
className,
|
|
327
|
+
...props
|
|
328
|
+
}: React.ComponentProps<typeof Separator>) {
|
|
329
|
+
return (
|
|
330
|
+
<Separator
|
|
331
|
+
data-slot="sidebar-separator"
|
|
332
|
+
data-sidebar="separator"
|
|
333
|
+
className={cn("mx-2 w-auto bg-border-tertiary", className)}
|
|
334
|
+
{...props}
|
|
335
|
+
/>
|
|
336
|
+
)
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function SidebarContent({ className, ...props }: React.ComponentProps<"div">) {
|
|
340
|
+
return (
|
|
341
|
+
<div
|
|
342
|
+
data-slot="sidebar-content"
|
|
343
|
+
data-sidebar="content"
|
|
344
|
+
className={cn(
|
|
345
|
+
"flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
|
|
346
|
+
className
|
|
347
|
+
)}
|
|
348
|
+
{...props}
|
|
349
|
+
/>
|
|
350
|
+
)
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function SidebarGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
354
|
+
return (
|
|
355
|
+
<div
|
|
356
|
+
data-slot="sidebar-group"
|
|
357
|
+
data-sidebar="group"
|
|
358
|
+
className={cn("relative flex w-full min-w-0 flex-col p-2", className)}
|
|
359
|
+
{...props}
|
|
360
|
+
/>
|
|
361
|
+
)
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function SidebarGroupLabel({
|
|
365
|
+
className,
|
|
366
|
+
asChild = false,
|
|
367
|
+
...props
|
|
368
|
+
}: React.ComponentProps<"div"> & { asChild?: boolean }) {
|
|
369
|
+
const Comp = asChild ? Slot : "div"
|
|
370
|
+
|
|
371
|
+
return (
|
|
372
|
+
<Comp
|
|
373
|
+
data-slot="sidebar-group-label"
|
|
374
|
+
data-sidebar="group-label"
|
|
375
|
+
className={cn(
|
|
376
|
+
"flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-text-tertiary outline-none transition-[margin,opacity] duration-200 ease-linear",
|
|
377
|
+
"group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
|
|
378
|
+
className
|
|
379
|
+
)}
|
|
380
|
+
{...props}
|
|
381
|
+
/>
|
|
382
|
+
)
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function SidebarGroupAction({
|
|
386
|
+
className,
|
|
387
|
+
asChild = false,
|
|
388
|
+
...props
|
|
389
|
+
}: React.ComponentProps<"button"> & { asChild?: boolean }) {
|
|
390
|
+
const Comp = asChild ? Slot : "button"
|
|
391
|
+
|
|
392
|
+
return (
|
|
393
|
+
<Comp
|
|
394
|
+
data-slot="sidebar-group-action"
|
|
395
|
+
data-sidebar="group-action"
|
|
396
|
+
className={cn(
|
|
397
|
+
"absolute right-3 top-3.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-text-tertiary outline-none transition-colors hover:bg-fill-secondary hover:text-text focus-visible:ring-2 focus-visible:ring-primary-border",
|
|
398
|
+
"after:absolute after:-inset-2 md:after:hidden",
|
|
399
|
+
"group-data-[collapsible=icon]:hidden",
|
|
400
|
+
className
|
|
401
|
+
)}
|
|
402
|
+
{...props}
|
|
403
|
+
/>
|
|
404
|
+
)
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function SidebarGroupContent({
|
|
408
|
+
className,
|
|
409
|
+
...props
|
|
410
|
+
}: React.ComponentProps<"div">) {
|
|
411
|
+
return (
|
|
412
|
+
<div
|
|
413
|
+
data-slot="sidebar-group-content"
|
|
414
|
+
data-sidebar="group-content"
|
|
415
|
+
className={cn("w-full text-sm", className)}
|
|
416
|
+
{...props}
|
|
417
|
+
/>
|
|
418
|
+
)
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
function SidebarMenu({ className, ...props }: React.ComponentProps<"ul">) {
|
|
422
|
+
return (
|
|
423
|
+
<ul
|
|
424
|
+
data-slot="sidebar-menu"
|
|
425
|
+
data-sidebar="menu"
|
|
426
|
+
className={cn("flex w-full min-w-0 flex-col gap-1", className)}
|
|
427
|
+
{...props}
|
|
428
|
+
/>
|
|
429
|
+
)
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function SidebarMenuItem({ className, ...props }: React.ComponentProps<"li">) {
|
|
433
|
+
return (
|
|
434
|
+
<li
|
|
435
|
+
data-slot="sidebar-menu-item"
|
|
436
|
+
data-sidebar="menu-item"
|
|
437
|
+
className={cn("group/menu-item relative", className)}
|
|
438
|
+
{...props}
|
|
439
|
+
/>
|
|
440
|
+
)
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
const sidebarMenuButtonVariants = cva(
|
|
444
|
+
"peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none transition-[width,height,padding,color,background-color] hover:bg-fill-secondary hover:text-text focus-visible:ring-2 focus-visible:ring-primary-border active:bg-fill data-[active=true]:bg-fill-secondary data-[active=true]:font-medium data-[active=true]:text-text disabled:pointer-events-none disabled:opacity-50 group-data-[collapsible=icon]:size-8 group-data-[collapsible=icon]:p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
|
|
445
|
+
{
|
|
446
|
+
variants: {
|
|
447
|
+
variant: {
|
|
448
|
+
default: "text-text-secondary",
|
|
449
|
+
outline:
|
|
450
|
+
"border border-border-tertiary bg-bg-container text-text-secondary shadow-sm hover:bg-fill-secondary",
|
|
451
|
+
},
|
|
452
|
+
size: {
|
|
453
|
+
default: "h-8 text-sm",
|
|
454
|
+
sm: "h-7 text-xs",
|
|
455
|
+
lg: "h-12 text-sm group-data-[collapsible=icon]:p-0",
|
|
456
|
+
},
|
|
457
|
+
},
|
|
458
|
+
defaultVariants: {
|
|
459
|
+
variant: "default",
|
|
460
|
+
size: "default",
|
|
461
|
+
},
|
|
462
|
+
}
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
function SidebarMenuButton({
|
|
466
|
+
asChild = false,
|
|
467
|
+
isActive = false,
|
|
468
|
+
variant = "default",
|
|
469
|
+
size = "default",
|
|
470
|
+
tooltip,
|
|
471
|
+
className,
|
|
472
|
+
...props
|
|
473
|
+
}: React.ComponentProps<"button"> & {
|
|
474
|
+
asChild?: boolean
|
|
475
|
+
isActive?: boolean
|
|
476
|
+
tooltip?: string | Omit<React.ComponentProps<typeof Tooltip>, "children">
|
|
477
|
+
} & VariantProps<typeof sidebarMenuButtonVariants>) {
|
|
478
|
+
const Comp = asChild ? Slot : "button"
|
|
479
|
+
const { state } = useSidebar()
|
|
480
|
+
|
|
481
|
+
const button = (
|
|
482
|
+
<Comp
|
|
483
|
+
data-slot="sidebar-menu-button"
|
|
484
|
+
data-sidebar="menu-button"
|
|
485
|
+
data-size={size}
|
|
486
|
+
data-active={isActive}
|
|
487
|
+
className={cn(sidebarMenuButtonVariants({ variant, size }), className)}
|
|
488
|
+
{...props}
|
|
489
|
+
/>
|
|
490
|
+
)
|
|
491
|
+
|
|
492
|
+
if (!tooltip) return button
|
|
493
|
+
|
|
494
|
+
const tooltipProps =
|
|
495
|
+
typeof tooltip === "string" ? { content: tooltip } : tooltip
|
|
496
|
+
|
|
497
|
+
if (state !== "collapsed") return button
|
|
498
|
+
|
|
499
|
+
return (
|
|
500
|
+
<Tooltip side="right" {...tooltipProps}>
|
|
501
|
+
{button}
|
|
502
|
+
</Tooltip>
|
|
503
|
+
)
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function SidebarMenuAction({
|
|
507
|
+
className,
|
|
508
|
+
asChild = false,
|
|
509
|
+
showOnHover = false,
|
|
510
|
+
...props
|
|
511
|
+
}: React.ComponentProps<"button"> & {
|
|
512
|
+
asChild?: boolean
|
|
513
|
+
showOnHover?: boolean
|
|
514
|
+
}) {
|
|
515
|
+
const Comp = asChild ? Slot : "button"
|
|
516
|
+
|
|
517
|
+
return (
|
|
518
|
+
<Comp
|
|
519
|
+
data-slot="sidebar-menu-action"
|
|
520
|
+
data-sidebar="menu-action"
|
|
521
|
+
className={cn(
|
|
522
|
+
"absolute right-1 top-1.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-text-tertiary outline-none transition-colors hover:bg-fill-secondary hover:text-text focus-visible:ring-2 focus-visible:ring-primary-border",
|
|
523
|
+
"after:absolute after:-inset-2 md:after:hidden",
|
|
524
|
+
"peer-data-[size=sm]/menu-button:top-1",
|
|
525
|
+
"peer-data-[size=default]/menu-button:top-1.5",
|
|
526
|
+
"peer-data-[size=lg]/menu-button:top-2.5",
|
|
527
|
+
"group-data-[collapsible=icon]:hidden",
|
|
528
|
+
showOnHover &&
|
|
529
|
+
"opacity-0 group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100",
|
|
530
|
+
className
|
|
531
|
+
)}
|
|
532
|
+
{...props}
|
|
533
|
+
/>
|
|
534
|
+
)
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
function SidebarMenuBadge({ className, ...props }: React.ComponentProps<"div">) {
|
|
538
|
+
return (
|
|
539
|
+
<div
|
|
540
|
+
data-slot="sidebar-menu-badge"
|
|
541
|
+
data-sidebar="menu-badge"
|
|
542
|
+
className={cn(
|
|
543
|
+
"pointer-events-none absolute right-1 flex h-5 min-w-5 select-none items-center justify-center rounded-md px-1 text-xs font-medium text-text-tertiary",
|
|
544
|
+
"peer-hover/menu-button:text-text peer-data-[active=true]/menu-button:text-text",
|
|
545
|
+
"peer-data-[size=sm]/menu-button:top-1",
|
|
546
|
+
"peer-data-[size=default]/menu-button:top-1.5",
|
|
547
|
+
"peer-data-[size=lg]/menu-button:top-2.5",
|
|
548
|
+
"group-data-[collapsible=icon]:hidden",
|
|
549
|
+
className
|
|
550
|
+
)}
|
|
551
|
+
{...props}
|
|
552
|
+
/>
|
|
553
|
+
)
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
function SidebarMenuSkeleton({
|
|
557
|
+
className,
|
|
558
|
+
showIcon = false,
|
|
559
|
+
width = "70%",
|
|
560
|
+
...props
|
|
561
|
+
}: React.ComponentProps<"div"> & {
|
|
562
|
+
showIcon?: boolean
|
|
563
|
+
width?: string
|
|
564
|
+
}) {
|
|
565
|
+
return (
|
|
566
|
+
<div
|
|
567
|
+
data-slot="sidebar-menu-skeleton"
|
|
568
|
+
data-sidebar="menu-skeleton"
|
|
569
|
+
className={cn("flex h-8 items-center gap-2 rounded-md px-2", className)}
|
|
570
|
+
{...props}
|
|
571
|
+
>
|
|
572
|
+
{showIcon && <Skeleton className="size-4 rounded-md" />}
|
|
573
|
+
<Skeleton
|
|
574
|
+
className="h-4 max-w-[var(--skeleton-width)] flex-1"
|
|
575
|
+
style={{ "--skeleton-width": width } as React.CSSProperties}
|
|
576
|
+
/>
|
|
577
|
+
</div>
|
|
578
|
+
)
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
function SidebarMenuSub({ className, ...props }: React.ComponentProps<"ul">) {
|
|
582
|
+
return (
|
|
583
|
+
<ul
|
|
584
|
+
data-slot="sidebar-menu-sub"
|
|
585
|
+
data-sidebar="menu-sub"
|
|
586
|
+
className={cn(
|
|
587
|
+
"mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-border-tertiary px-2.5 py-0.5",
|
|
588
|
+
"group-data-[collapsible=icon]:hidden",
|
|
589
|
+
className
|
|
590
|
+
)}
|
|
591
|
+
{...props}
|
|
592
|
+
/>
|
|
593
|
+
)
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
function SidebarMenuSubItem({
|
|
597
|
+
className,
|
|
598
|
+
...props
|
|
599
|
+
}: React.ComponentProps<"li">) {
|
|
600
|
+
return (
|
|
601
|
+
<li
|
|
602
|
+
data-slot="sidebar-menu-sub-item"
|
|
603
|
+
data-sidebar="menu-sub-item"
|
|
604
|
+
className={cn("group/menu-sub-item relative", className)}
|
|
605
|
+
{...props}
|
|
606
|
+
/>
|
|
607
|
+
)
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
function SidebarMenuSubButton({
|
|
611
|
+
asChild = false,
|
|
612
|
+
size = "md",
|
|
613
|
+
isActive = false,
|
|
614
|
+
className,
|
|
615
|
+
...props
|
|
616
|
+
}: React.ComponentProps<"a"> & {
|
|
617
|
+
asChild?: boolean
|
|
618
|
+
size?: "sm" | "md"
|
|
619
|
+
isActive?: boolean
|
|
620
|
+
}) {
|
|
621
|
+
const Comp = asChild ? Slot : "a"
|
|
622
|
+
|
|
623
|
+
return (
|
|
624
|
+
<Comp
|
|
625
|
+
data-slot="sidebar-menu-sub-button"
|
|
626
|
+
data-sidebar="menu-sub-button"
|
|
627
|
+
data-size={size}
|
|
628
|
+
data-active={isActive}
|
|
629
|
+
className={cn(
|
|
630
|
+
"flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 text-text-secondary outline-none hover:bg-fill-secondary hover:text-text focus-visible:ring-2 focus-visible:ring-primary-border active:bg-fill data-[active=true]:bg-fill-secondary data-[active=true]:text-text disabled:pointer-events-none disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
|
|
631
|
+
"data-[size=sm]:text-xs data-[size=md]:text-sm",
|
|
632
|
+
className
|
|
633
|
+
)}
|
|
634
|
+
{...props}
|
|
635
|
+
/>
|
|
636
|
+
)
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
export {
|
|
640
|
+
Sidebar,
|
|
641
|
+
SidebarContent,
|
|
642
|
+
SidebarFooter,
|
|
643
|
+
SidebarGroup,
|
|
644
|
+
SidebarGroupAction,
|
|
645
|
+
SidebarGroupContent,
|
|
646
|
+
SidebarGroupLabel,
|
|
647
|
+
SidebarHeader,
|
|
648
|
+
SidebarInput,
|
|
649
|
+
SidebarInset,
|
|
650
|
+
SidebarMenu,
|
|
651
|
+
SidebarMenuAction,
|
|
652
|
+
SidebarMenuBadge,
|
|
653
|
+
SidebarMenuButton,
|
|
654
|
+
SidebarMenuItem,
|
|
655
|
+
SidebarMenuSkeleton,
|
|
656
|
+
SidebarMenuSub,
|
|
657
|
+
SidebarMenuSubButton,
|
|
658
|
+
SidebarMenuSubItem,
|
|
659
|
+
SidebarProvider,
|
|
660
|
+
SidebarRail,
|
|
661
|
+
SidebarSeparator,
|
|
662
|
+
SidebarTrigger,
|
|
663
|
+
sidebarMenuButtonVariants,
|
|
664
|
+
useSidebar,
|
|
665
|
+
}
|
|
@@ -14,23 +14,23 @@ export type ToasterProps = Omit<SonnerToasterProps, 'theme'> & {
|
|
|
14
14
|
dataTheme?: string
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
/**
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
17
|
+
/** 图标/文字用最小 token 间距;按钮与容器边缘、按钮之间用 spacing-2 */
|
|
18
|
+
const TOAST_INNER_GAP = 'calc(var(--spacing-px) * 2)'
|
|
19
|
+
const TOAST_EDGE_PADDING = 'var(--spacing-2)'
|
|
20
|
+
const TOAST_BUTTON_GAP = 'var(--spacing-2)'
|
|
21
21
|
|
|
22
22
|
/** 强制 toast 四边内边距 + 根节点 text-sm 变量 + 非首个按钮左间距;选择器带 data-styled 以覆盖 sonner */
|
|
23
|
-
const
|
|
23
|
+
const TOAST_PADDING_TOP_BOTTOM = 'var(--spacing-3)'
|
|
24
24
|
/** 根节点用设计系统 text-sm 变量;[data-content] 撑满中间;非首个按钮左间距 */
|
|
25
|
-
const TOAST_LAYOUT_FIX_CSS = `[data-sonner-toaster] [data-sonner-toast][data-styled="true"] { padding-left: ${
|
|
25
|
+
const TOAST_LAYOUT_FIX_CSS = `[data-sonner-toaster] [data-sonner-toast][data-styled="true"] { padding-left: ${TOAST_EDGE_PADDING} !important; padding-right: ${TOAST_EDGE_PADDING} !important; padding-top: ${TOAST_PADDING_TOP_BOTTOM} !important; padding-bottom: ${TOAST_PADDING_TOP_BOTTOM} !important; font-size: var(--font-size-sm) !important; line-height: var(--font-size-sm--line-height) !important; }
|
|
26
26
|
[data-sonner-toaster] [data-sonner-toast] [data-content] { flex: 1 !important; min-width: 0 !important; }
|
|
27
|
-
[data-sonner-toaster] [data-sonner-toast] [data-button]:not(:first-of-type) { margin-left: ${
|
|
27
|
+
[data-sonner-toaster] [data-sonner-toast] [data-button]:not(:first-of-type) { margin-left: ${TOAST_BUTTON_GAP} !important; }`
|
|
28
28
|
|
|
29
29
|
const defaultToastOptions: NonNullable<SonnerToasterProps['toastOptions']> = {
|
|
30
30
|
className: 'text-sm',
|
|
31
31
|
style: {
|
|
32
|
-
padding:
|
|
33
|
-
gap:
|
|
32
|
+
padding: `${TOAST_PADDING_TOP_BOTTOM} ${TOAST_EDGE_PADDING}`,
|
|
33
|
+
gap: TOAST_INNER_GAP,
|
|
34
34
|
background: 'var(--color-bg-container)',
|
|
35
35
|
borderColor: 'var(--color-border-tertiary)',
|
|
36
36
|
color: 'var(--color-text)',
|
|
@@ -87,7 +87,7 @@ export function Toaster({ theme, toastOptions, dataStyle, dataTheme, icons, gap
|
|
|
87
87
|
fontFamily: 'inherit',
|
|
88
88
|
'--gap': `${gap}px`,
|
|
89
89
|
'--toast-icon-margin-start': '0',
|
|
90
|
-
'--toast-icon-margin-end':
|
|
90
|
+
'--toast-icon-margin-end': TOAST_INNER_GAP,
|
|
91
91
|
/* 控制 action/cancel 按钮间距:按钮间仅靠 toast 根 gap,不再额外 margin */
|
|
92
92
|
'--toast-button-margin-start': 'auto',
|
|
93
93
|
'--toast-button-margin-end': '0',
|