@olympusoss/canvas 2.6.27 → 2.7.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/package.json +1 -1
- package/src/components/atoms/button.tsx +3 -2
- package/src/components/charts/service-health-list.tsx +21 -9
- package/src/components/molecules/breadcrumb.tsx +1 -5
- package/src/components/molecules/page-header.tsx +2 -2
- package/src/components/molecules/tooltip.tsx +20 -16
- package/src/components/organisms/accordion.tsx +1 -1
- package/src/components/organisms/alert-dialog.tsx +17 -13
- package/src/components/organisms/carousel.tsx +2 -2
- package/src/components/organisms/context-menu.tsx +16 -12
- package/src/components/organisms/dashboard-grid.tsx +26 -17
- package/src/components/organisms/dialog.tsx +23 -19
- package/src/components/organisms/drawer.tsx +26 -4
- package/src/components/organisms/dropdown-menu.tsx +18 -14
- package/src/components/organisms/editors/prose-canvas-classes.ts +2 -2
- package/src/components/organisms/menubar.tsx +19 -15
- package/src/components/organisms/navbar.tsx +2 -2
- package/src/components/organisms/popover.tsx +18 -14
- package/src/components/organisms/resizable.tsx +25 -6
- package/src/components/organisms/select.tsx +6 -1
- package/src/components/organisms/sheet.tsx +20 -12
- package/src/index.ts +1 -0
- package/styles/tokens.css +43 -4
package/package.json
CHANGED
|
@@ -15,7 +15,7 @@ const buttonVariants = cva(
|
|
|
15
15
|
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
|
|
16
16
|
secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
|
17
17
|
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
18
|
-
link: "text-primary
|
|
18
|
+
link: "text-primary hover:text-brand",
|
|
19
19
|
},
|
|
20
20
|
size: {
|
|
21
21
|
default: "h-9 px-4 py-2",
|
|
@@ -37,7 +37,8 @@ export interface ButtonProps
|
|
|
37
37
|
/**
|
|
38
38
|
* Visual emphasis preset. `default` is the primary action, `destructive`
|
|
39
39
|
* is for irreversible actions, `outline` and `secondary` are quieter,
|
|
40
|
-
* `ghost` is borderless, `link` looks like body-text
|
|
40
|
+
* `ghost` is borderless, `link` looks like body-text with a soft
|
|
41
|
+
* color shift on hover (no underline).
|
|
41
42
|
* @default "default"
|
|
42
43
|
*/
|
|
43
44
|
variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link";
|
|
@@ -41,17 +41,29 @@ export const ServiceHealthList = React.forwardRef<HTMLDivElement, ServiceHealthL
|
|
|
41
41
|
<ul className="flex flex-col gap-2.5">
|
|
42
42
|
{items.map((item) => {
|
|
43
43
|
const hsl = DOT_TOKENS[item.status];
|
|
44
|
+
const isHealthy = item.status === "healthy";
|
|
44
45
|
return (
|
|
45
46
|
<li key={item.name} className="flex items-center gap-2.5 text-[13px]">
|
|
46
|
-
<span
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
47
|
+
<span className="relative flex size-2 shrink-0">
|
|
48
|
+
{isHealthy && (
|
|
49
|
+
<span
|
|
50
|
+
aria-hidden
|
|
51
|
+
className="absolute inline-flex h-full w-full animate-ping rounded-full opacity-75"
|
|
52
|
+
style={{ background: `hsl(${hsl})` }}
|
|
53
|
+
/>
|
|
54
|
+
)}
|
|
55
|
+
<span
|
|
56
|
+
role="img"
|
|
57
|
+
aria-label={`Status: ${item.status}`}
|
|
58
|
+
className="relative inline-flex size-2 rounded-full"
|
|
59
|
+
style={{
|
|
60
|
+
background: `hsl(${hsl})`,
|
|
61
|
+
boxShadow: isHealthy
|
|
62
|
+
? `0 0 6px hsl(${hsl}), 0 0 0 3px hsl(${hsl} / 0.18)`
|
|
63
|
+
: `0 0 0 3px hsl(${hsl} / 0.18)`,
|
|
64
|
+
}}
|
|
65
|
+
/>
|
|
66
|
+
</span>
|
|
55
67
|
<span className="flex-1 font-medium">{item.name}</span>
|
|
56
68
|
{item.meta?.map((cell, i) => (
|
|
57
69
|
<span
|
|
@@ -76,11 +76,7 @@ const BreadcrumbLink = React.forwardRef<HTMLAnchorElement, BreadcrumbLinkProps>(
|
|
|
76
76
|
const Comp = asChild ? Slot : "a";
|
|
77
77
|
|
|
78
78
|
return (
|
|
79
|
-
<Comp
|
|
80
|
-
ref={ref}
|
|
81
|
-
className={cn("transition-colors hover:text-foreground", className)}
|
|
82
|
-
{...props}
|
|
83
|
-
/>
|
|
79
|
+
<Comp ref={ref} className={cn("transition-colors hover:text-brand", className)} {...props} />
|
|
84
80
|
);
|
|
85
81
|
},
|
|
86
82
|
);
|
|
@@ -44,11 +44,11 @@ export function PageHeader({
|
|
|
44
44
|
<span key={crumb.label} className="flex items-center gap-1">
|
|
45
45
|
{crumb.href ? (
|
|
46
46
|
LinkComp ? (
|
|
47
|
-
<LinkComp href={crumb.href} className="hover:text-
|
|
47
|
+
<LinkComp href={crumb.href} className="hover:text-brand transition-colors">
|
|
48
48
|
{crumb.label}
|
|
49
49
|
</LinkComp>
|
|
50
50
|
) : (
|
|
51
|
-
<a href={crumb.href} className="hover:text-
|
|
51
|
+
<a href={crumb.href} className="hover:text-brand transition-colors">
|
|
52
52
|
{crumb.label}
|
|
53
53
|
</a>
|
|
54
54
|
)
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
|
4
4
|
import * as React from "react";
|
|
5
5
|
|
|
6
|
+
import { usePortalContainer } from "../../lib/portal-container";
|
|
6
7
|
import { cn } from "../../lib/utils";
|
|
7
8
|
|
|
8
9
|
export interface TooltipProviderProps
|
|
@@ -129,22 +130,25 @@ export interface TooltipContentProps
|
|
|
129
130
|
const TooltipContent = React.forwardRef<
|
|
130
131
|
React.ElementRef<typeof TooltipPrimitive.Content>,
|
|
131
132
|
TooltipContentProps
|
|
132
|
-
>(({ className, sideOffset = 6, children, ...props }, ref) =>
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
className
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
133
|
+
>(({ className, sideOffset = 6, children, ...props }, ref) => {
|
|
134
|
+
const container = usePortalContainer();
|
|
135
|
+
return (
|
|
136
|
+
<TooltipPrimitive.Portal container={container ?? undefined}>
|
|
137
|
+
<TooltipPrimitive.Content
|
|
138
|
+
ref={ref}
|
|
139
|
+
sideOffset={sideOffset}
|
|
140
|
+
className={cn(
|
|
141
|
+
"z-50 max-w-xs overflow-hidden rounded-md border border-border/50 bg-popover px-2 py-1 text-[11px] font-medium text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1 origin-[var(--radix-tooltip-content-transform-origin)]",
|
|
142
|
+
className,
|
|
143
|
+
)}
|
|
144
|
+
{...props}
|
|
145
|
+
>
|
|
146
|
+
{children}
|
|
147
|
+
<TooltipPrimitive.Arrow width={10} height={5} style={{ fill: "hsl(var(--popover))" }} />
|
|
148
|
+
</TooltipPrimitive.Content>
|
|
149
|
+
</TooltipPrimitive.Portal>
|
|
150
|
+
);
|
|
151
|
+
});
|
|
148
152
|
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
|
149
153
|
|
|
150
154
|
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };
|
|
@@ -103,7 +103,7 @@ const AccordionTrigger = React.forwardRef<
|
|
|
103
103
|
<AccordionPrimitive.Trigger
|
|
104
104
|
ref={ref}
|
|
105
105
|
className={cn(
|
|
106
|
-
"flex flex-1 items-center justify-between py-4 text-sm font-medium transition-
|
|
106
|
+
"flex flex-1 items-center justify-between py-4 text-sm font-medium transition-colors hover:text-brand text-left [&[data-state=open]>svg]:rotate-180",
|
|
107
107
|
className,
|
|
108
108
|
)}
|
|
109
109
|
{...props}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
|
|
4
4
|
import * as React from "react";
|
|
5
5
|
|
|
6
|
+
import { usePortalContainer } from "../../lib/portal-container";
|
|
6
7
|
import { cn } from "../../lib/utils";
|
|
7
8
|
import { buttonVariants } from "../atoms/button";
|
|
8
9
|
|
|
@@ -115,19 +116,22 @@ export interface AlertDialogContentProps
|
|
|
115
116
|
const AlertDialogContent = React.forwardRef<
|
|
116
117
|
React.ElementRef<typeof AlertDialogPrimitive.Content>,
|
|
117
118
|
AlertDialogContentProps
|
|
118
|
-
>(({ className, ...props }, ref) =>
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
<
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
className
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
119
|
+
>(({ className, ...props }, ref) => {
|
|
120
|
+
const container = usePortalContainer();
|
|
121
|
+
return (
|
|
122
|
+
<AlertDialogPortal container={container ?? undefined}>
|
|
123
|
+
<AlertDialogOverlay />
|
|
124
|
+
<AlertDialogPrimitive.Content
|
|
125
|
+
ref={ref}
|
|
126
|
+
className={cn(
|
|
127
|
+
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border border-border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]",
|
|
128
|
+
className,
|
|
129
|
+
)}
|
|
130
|
+
{...props}
|
|
131
|
+
/>
|
|
132
|
+
</AlertDialogPortal>
|
|
133
|
+
);
|
|
134
|
+
});
|
|
131
135
|
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
|
|
132
136
|
|
|
133
137
|
export interface AlertDialogHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
@@ -191,7 +191,7 @@ const CarouselPrevious = React.forwardRef<HTMLButtonElement, React.ComponentProp
|
|
|
191
191
|
"absolute h-8 w-8 rounded-full",
|
|
192
192
|
orientation === "horizontal"
|
|
193
193
|
? "-left-12 top-1/2 -translate-y-1/2"
|
|
194
|
-
: "-top-
|
|
194
|
+
: "-top-10 left-1/2 -translate-x-1/2 rotate-90",
|
|
195
195
|
className,
|
|
196
196
|
)}
|
|
197
197
|
disabled={!canScrollPrev}
|
|
@@ -219,7 +219,7 @@ const CarouselNext = React.forwardRef<HTMLButtonElement, React.ComponentProps<ty
|
|
|
219
219
|
"absolute h-8 w-8 rounded-full",
|
|
220
220
|
orientation === "horizontal"
|
|
221
221
|
? "-right-12 top-1/2 -translate-y-1/2"
|
|
222
|
-
: "-bottom-
|
|
222
|
+
: "-bottom-10 left-1/2 -translate-x-1/2 rotate-90",
|
|
223
223
|
className,
|
|
224
224
|
)}
|
|
225
225
|
disabled={!canScrollNext}
|
|
@@ -4,6 +4,7 @@ import * as ContextMenuPrimitive from "@radix-ui/react-context-menu";
|
|
|
4
4
|
import { Check, ChevronRight, Circle } from "lucide-react";
|
|
5
5
|
import * as React from "react";
|
|
6
6
|
|
|
7
|
+
import { usePortalContainer } from "../../lib/portal-container";
|
|
7
8
|
import { cn } from "../../lib/utils";
|
|
8
9
|
|
|
9
10
|
export interface ContextMenuProps extends React.ComponentProps<typeof ContextMenuPrimitive.Root> {
|
|
@@ -154,18 +155,21 @@ export interface ContextMenuContentProps
|
|
|
154
155
|
const ContextMenuContent = React.forwardRef<
|
|
155
156
|
React.ElementRef<typeof ContextMenuPrimitive.Content>,
|
|
156
157
|
ContextMenuContentProps
|
|
157
|
-
>(({ className, ...props }, ref) =>
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
className
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
158
|
+
>(({ className, ...props }, ref) => {
|
|
159
|
+
const container = usePortalContainer();
|
|
160
|
+
return (
|
|
161
|
+
<ContextMenuPrimitive.Portal container={container ?? undefined}>
|
|
162
|
+
<ContextMenuPrimitive.Content
|
|
163
|
+
ref={ref}
|
|
164
|
+
className={cn(
|
|
165
|
+
"z-50 max-h-[var(--radix-context-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[var(--radix-context-menu-content-transform-origin)]",
|
|
166
|
+
className,
|
|
167
|
+
)}
|
|
168
|
+
{...props}
|
|
169
|
+
/>
|
|
170
|
+
</ContextMenuPrimitive.Portal>
|
|
171
|
+
);
|
|
172
|
+
});
|
|
169
173
|
ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;
|
|
170
174
|
|
|
171
175
|
export interface ContextMenuItemProps
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { GripVertical } from "lucide-react";
|
|
3
|
+
import { GripVertical, Trash2 } from "lucide-react";
|
|
4
4
|
import * as React from "react";
|
|
5
5
|
import type { Layout, Layouts } from "react-grid-layout";
|
|
6
6
|
import GridLayout from "react-grid-layout";
|
|
@@ -332,24 +332,33 @@ export const DashboardGrid = React.forwardRef<HTMLDivElement, DashboardGridProps
|
|
|
332
332
|
preventCollision={false}
|
|
333
333
|
>
|
|
334
334
|
{items.map((item) => (
|
|
335
|
-
<div key={item.i} className="group/dashboard-grid-item
|
|
335
|
+
<div key={item.i} className="group/dashboard-grid-item relative h-full overflow-hidden">
|
|
336
|
+
{/* Inner wrapper forces the rendered widget to fill the cell —
|
|
337
|
+
consumers shouldn't have to add `h-full` to every card just to
|
|
338
|
+
make rows align. Kept separate from the drag handle so the
|
|
339
|
+
`*:h-full *:w-full` rule doesn't blow up the absolute handle. */}
|
|
340
|
+
<div className="h-full w-full *:h-full *:w-full">{renderItem(item)}</div>
|
|
336
341
|
{editing && (
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
342
|
+
<>
|
|
343
|
+
<div
|
|
344
|
+
role="button"
|
|
345
|
+
tabIndex={0}
|
|
346
|
+
className="dashboard-grid-handle absolute right-2 top-2 z-10 flex h-6 w-6 cursor-grab items-center justify-center rounded-md border border-border bg-background/80 text-muted-foreground shadow-sm backdrop-blur-sm transition-colors hover:bg-accent hover:text-foreground active:cursor-grabbing"
|
|
347
|
+
aria-label={`Drag ${item.i}`}
|
|
348
|
+
>
|
|
349
|
+
<GripVertical className="h-3.5 w-3.5" />
|
|
350
|
+
</div>
|
|
351
|
+
<button
|
|
352
|
+
type="button"
|
|
353
|
+
onClick={() => onItemsChange?.(items.filter((it) => it.i !== item.i))}
|
|
354
|
+
className="absolute bottom-2 left-1/2 z-10 flex h-7 -translate-x-1/2 items-center gap-1.5 rounded-md border border-border bg-background/80 px-2.5 text-xs font-medium text-destructive shadow-sm backdrop-blur-sm transition-colors hover:bg-destructive hover:text-destructive-foreground"
|
|
355
|
+
aria-label={`Remove ${item.i}`}
|
|
356
|
+
>
|
|
357
|
+
<Trash2 className="h-3.5 w-3.5" />
|
|
358
|
+
Remove
|
|
359
|
+
</button>
|
|
360
|
+
</>
|
|
345
361
|
)}
|
|
346
|
-
{/* The inner wrapper forces ANY direct child of the rendered widget to
|
|
347
|
-
fill the cell (`*:h-full *:w-full`). This is the grid's job, not the
|
|
348
|
-
widget's — consumers shouldn't have to add `h-full` to every card just
|
|
349
|
-
to make rows align. */}
|
|
350
|
-
<div className="min-h-0 flex-1 overflow-hidden *:h-full *:w-full">
|
|
351
|
-
{renderItem(item)}
|
|
352
|
-
</div>
|
|
353
362
|
</div>
|
|
354
363
|
))}
|
|
355
364
|
</ResponsiveGridLayout>
|
|
@@ -4,6 +4,7 @@ import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
|
4
4
|
import { X } from "lucide-react";
|
|
5
5
|
import * as React from "react";
|
|
6
6
|
|
|
7
|
+
import { usePortalContainer } from "../../lib/portal-container";
|
|
7
8
|
import { cn } from "../../lib/utils";
|
|
8
9
|
|
|
9
10
|
/* ────────────────────────────────────────────────────────────────
|
|
@@ -183,25 +184,28 @@ export interface DialogContentProps
|
|
|
183
184
|
const DialogContent = React.forwardRef<
|
|
184
185
|
React.ElementRef<typeof DialogPrimitive.Content>,
|
|
185
186
|
DialogContentProps
|
|
186
|
-
>(({ className, children, ...props }, ref) =>
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
<
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
className
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
<
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
187
|
+
>(({ className, children, ...props }, ref) => {
|
|
188
|
+
const container = usePortalContainer();
|
|
189
|
+
return (
|
|
190
|
+
<DialogPortal container={container ?? undefined}>
|
|
191
|
+
<DialogOverlay />
|
|
192
|
+
<DialogPrimitive.Content
|
|
193
|
+
ref={ref}
|
|
194
|
+
className={cn(
|
|
195
|
+
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border border-border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]",
|
|
196
|
+
className,
|
|
197
|
+
)}
|
|
198
|
+
{...props}
|
|
199
|
+
>
|
|
200
|
+
{children}
|
|
201
|
+
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
|
202
|
+
<X className="h-4 w-4" />
|
|
203
|
+
<span className="sr-only">Close</span>
|
|
204
|
+
</DialogPrimitive.Close>
|
|
205
|
+
</DialogPrimitive.Content>
|
|
206
|
+
</DialogPortal>
|
|
207
|
+
);
|
|
208
|
+
});
|
|
205
209
|
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
|
206
210
|
|
|
207
211
|
export interface DialogHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
@@ -3,14 +3,23 @@
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { Drawer as DrawerPrimitive } from "vaul";
|
|
5
5
|
|
|
6
|
+
import { usePortalContainer } from "../../lib/portal-container";
|
|
6
7
|
import { cn } from "../../lib/utils";
|
|
7
8
|
|
|
8
9
|
const Drawer = ({
|
|
9
10
|
shouldScaleBackground = true,
|
|
11
|
+
container,
|
|
10
12
|
...props
|
|
11
|
-
}: React.ComponentProps<typeof DrawerPrimitive.Root>) =>
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
}: React.ComponentProps<typeof DrawerPrimitive.Root>) => {
|
|
14
|
+
const fallbackContainer = usePortalContainer();
|
|
15
|
+
return (
|
|
16
|
+
<DrawerPrimitive.Root
|
|
17
|
+
shouldScaleBackground={shouldScaleBackground}
|
|
18
|
+
container={container ?? fallbackContainer ?? undefined}
|
|
19
|
+
{...props}
|
|
20
|
+
/>
|
|
21
|
+
);
|
|
22
|
+
};
|
|
14
23
|
Drawer.displayName = "Drawer";
|
|
15
24
|
|
|
16
25
|
const DrawerTrigger = DrawerPrimitive.Trigger;
|
|
@@ -31,6 +40,18 @@ const DrawerOverlay = React.forwardRef<
|
|
|
31
40
|
));
|
|
32
41
|
DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName;
|
|
33
42
|
|
|
43
|
+
const DrawerHandle = React.forwardRef<
|
|
44
|
+
React.ElementRef<typeof DrawerPrimitive.Handle>,
|
|
45
|
+
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Handle>
|
|
46
|
+
>(({ className, ...props }, ref) => (
|
|
47
|
+
<DrawerPrimitive.Handle
|
|
48
|
+
ref={ref}
|
|
49
|
+
className={cn("mx-auto mt-4 !h-2 !w-[100px] rounded-full bg-muted", className)}
|
|
50
|
+
{...props}
|
|
51
|
+
/>
|
|
52
|
+
));
|
|
53
|
+
DrawerHandle.displayName = "DrawerHandle";
|
|
54
|
+
|
|
34
55
|
const DrawerContent = React.forwardRef<
|
|
35
56
|
React.ElementRef<typeof DrawerPrimitive.Content>,
|
|
36
57
|
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
|
|
@@ -45,7 +66,7 @@ const DrawerContent = React.forwardRef<
|
|
|
45
66
|
)}
|
|
46
67
|
{...props}
|
|
47
68
|
>
|
|
48
|
-
<
|
|
69
|
+
<DrawerHandle />
|
|
49
70
|
{children}
|
|
50
71
|
</DrawerPrimitive.Content>
|
|
51
72
|
</DrawerPortal>
|
|
@@ -92,6 +113,7 @@ export {
|
|
|
92
113
|
DrawerContent,
|
|
93
114
|
DrawerDescription,
|
|
94
115
|
DrawerFooter,
|
|
116
|
+
DrawerHandle,
|
|
95
117
|
DrawerHeader,
|
|
96
118
|
DrawerOverlay,
|
|
97
119
|
DrawerPortal,
|
|
@@ -4,6 +4,7 @@ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
|
|
4
4
|
import { Check, ChevronRight, Circle } from "lucide-react";
|
|
5
5
|
import * as React from "react";
|
|
6
6
|
|
|
7
|
+
import { usePortalContainer } from "../../lib/portal-container";
|
|
7
8
|
import { cn } from "../../lib/utils";
|
|
8
9
|
|
|
9
10
|
export interface DropdownMenuProps extends React.ComponentProps<typeof DropdownMenuPrimitive.Root> {
|
|
@@ -220,20 +221,23 @@ export interface DropdownMenuContentProps
|
|
|
220
221
|
const DropdownMenuContent = React.forwardRef<
|
|
221
222
|
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
|
222
223
|
DropdownMenuContentProps
|
|
223
|
-
>(({ className, sideOffset = 4, ...props }, ref) =>
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
224
|
+
>(({ className, sideOffset = 4, ...props }, ref) => {
|
|
225
|
+
const container = usePortalContainer();
|
|
226
|
+
return (
|
|
227
|
+
<DropdownMenuPrimitive.Portal container={container ?? undefined}>
|
|
228
|
+
<DropdownMenuPrimitive.Content
|
|
229
|
+
ref={ref}
|
|
230
|
+
sideOffset={sideOffset}
|
|
231
|
+
className={cn(
|
|
232
|
+
"z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md",
|
|
233
|
+
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[var(--radix-dropdown-menu-content-transform-origin)]",
|
|
234
|
+
className,
|
|
235
|
+
)}
|
|
236
|
+
{...props}
|
|
237
|
+
/>
|
|
238
|
+
</DropdownMenuPrimitive.Portal>
|
|
239
|
+
);
|
|
240
|
+
});
|
|
237
241
|
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
|
|
238
242
|
|
|
239
243
|
export interface DropdownMenuItemProps
|
|
@@ -23,8 +23,8 @@ export const PROSE_CANVAS_CLASSES = [
|
|
|
23
23
|
"[&_em]:italic",
|
|
24
24
|
"[&_u]:underline [&_u]:underline-offset-2",
|
|
25
25
|
"[&_s]:line-through",
|
|
26
|
-
// links
|
|
27
|
-
"[&_a]:text-brand [&_a]:
|
|
26
|
+
// links — brand color, fades slightly on hover (no underline)
|
|
27
|
+
"[&_a]:text-brand [&_a]:transition-colors hover:[&_a]:text-brand/80",
|
|
28
28
|
// code
|
|
29
29
|
"[&_code]:rounded [&_code]:bg-muted [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:font-mono [&_code]:text-[0.85em] [&_code]:text-foreground",
|
|
30
30
|
"[&_pre]:rounded-md [&_pre]:border [&_pre]:border-border [&_pre]:bg-muted/50 [&_pre]:p-3 [&_pre]:my-3 [&_pre]:overflow-x-auto",
|
|
@@ -4,6 +4,7 @@ import * as MenubarPrimitive from "@radix-ui/react-menubar";
|
|
|
4
4
|
import { Check, ChevronRight, Circle } from "lucide-react";
|
|
5
5
|
import * as React from "react";
|
|
6
6
|
|
|
7
|
+
import { usePortalContainer } from "../../lib/portal-container";
|
|
7
8
|
import { cn } from "../../lib/utils";
|
|
8
9
|
|
|
9
10
|
export interface MenubarProps extends React.ComponentPropsWithoutRef<typeof MenubarPrimitive.Root> {
|
|
@@ -272,21 +273,24 @@ export interface MenubarContentProps
|
|
|
272
273
|
const MenubarContent = React.forwardRef<
|
|
273
274
|
React.ElementRef<typeof MenubarPrimitive.Content>,
|
|
274
275
|
MenubarContentProps
|
|
275
|
-
>(({ className, align = "start", alignOffset = -4, sideOffset = 8, ...props }, ref) =>
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
className
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
276
|
+
>(({ className, align = "start", alignOffset = -4, sideOffset = 8, ...props }, ref) => {
|
|
277
|
+
const container = usePortalContainer();
|
|
278
|
+
return (
|
|
279
|
+
<MenubarPrimitive.Portal container={container ?? undefined}>
|
|
280
|
+
<MenubarPrimitive.Content
|
|
281
|
+
ref={ref}
|
|
282
|
+
align={align}
|
|
283
|
+
alignOffset={alignOffset}
|
|
284
|
+
sideOffset={sideOffset}
|
|
285
|
+
className={cn(
|
|
286
|
+
"z-50 min-w-[12rem] overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[var(--radix-menubar-content-transform-origin)]",
|
|
287
|
+
className,
|
|
288
|
+
)}
|
|
289
|
+
{...props}
|
|
290
|
+
/>
|
|
291
|
+
</MenubarPrimitive.Portal>
|
|
292
|
+
);
|
|
293
|
+
});
|
|
290
294
|
MenubarContent.displayName = MenubarPrimitive.Content.displayName;
|
|
291
295
|
|
|
292
296
|
export interface MenubarItemProps
|
|
@@ -47,7 +47,7 @@ const NavBar = React.forwardRef<HTMLElement, NavBarProps>(
|
|
|
47
47
|
<LinkEl
|
|
48
48
|
key={link.href}
|
|
49
49
|
href={link.href}
|
|
50
|
-
className="text-sm font-medium text-muted-foreground no-underline transition-colors hover:text-
|
|
50
|
+
className="text-sm font-medium text-muted-foreground no-underline transition-colors hover:text-brand"
|
|
51
51
|
{...(link.external ? { target: "_blank", rel: "noopener noreferrer" } : {})}
|
|
52
52
|
>
|
|
53
53
|
{link.label}
|
|
@@ -79,7 +79,7 @@ const NavBar = React.forwardRef<HTMLElement, NavBarProps>(
|
|
|
79
79
|
key={link.href}
|
|
80
80
|
href={link.href}
|
|
81
81
|
onClick={() => setMobileOpen(false)}
|
|
82
|
-
className="rounded-md px-3 py-2.5 text-sm font-medium text-muted-foreground no-underline transition-colors hover:bg-accent hover:text-
|
|
82
|
+
className="rounded-md px-3 py-2.5 text-sm font-medium text-muted-foreground no-underline transition-colors hover:bg-accent hover:text-brand"
|
|
83
83
|
{...(link.external ? { target: "_blank", rel: "noopener noreferrer" } : {})}
|
|
84
84
|
>
|
|
85
85
|
{link.label}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
4
4
|
import * as React from "react";
|
|
5
5
|
|
|
6
|
+
import { usePortalContainer } from "../../lib/portal-container";
|
|
6
7
|
import { cn } from "../../lib/utils";
|
|
7
8
|
|
|
8
9
|
export interface PopoverProps extends React.ComponentProps<typeof PopoverPrimitive.Root> {
|
|
@@ -125,20 +126,23 @@ export interface PopoverContentProps
|
|
|
125
126
|
const PopoverContent = React.forwardRef<
|
|
126
127
|
React.ElementRef<typeof PopoverPrimitive.Content>,
|
|
127
128
|
PopoverContentProps
|
|
128
|
-
>(({ className, align = "center", sideOffset = 4, ...props }, ref) =>
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
className
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
129
|
+
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => {
|
|
130
|
+
const container = usePortalContainer();
|
|
131
|
+
return (
|
|
132
|
+
<PopoverPrimitive.Portal container={container ?? undefined}>
|
|
133
|
+
<PopoverPrimitive.Content
|
|
134
|
+
ref={ref}
|
|
135
|
+
align={align}
|
|
136
|
+
sideOffset={sideOffset}
|
|
137
|
+
className={cn(
|
|
138
|
+
"z-50 w-72 rounded-md border border-border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[var(--radix-popover-content-transform-origin)]",
|
|
139
|
+
className,
|
|
140
|
+
)}
|
|
141
|
+
{...props}
|
|
142
|
+
/>
|
|
143
|
+
</PopoverPrimitive.Portal>
|
|
144
|
+
);
|
|
145
|
+
});
|
|
142
146
|
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
|
|
143
147
|
|
|
144
148
|
export { Popover, PopoverAnchor, PopoverContent, PopoverTrigger };
|
|
@@ -5,11 +5,30 @@ import { Group, Panel, Separator } from "react-resizable-panels";
|
|
|
5
5
|
|
|
6
6
|
import { cn } from "../../lib/utils";
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
/**
|
|
9
|
+
* `react-resizable-panels` v4 emits `data-group` on the panel group and forces
|
|
10
|
+
* inline `height: 100%; width: 100%`, which means a `className="h-32"` passed
|
|
11
|
+
* directly to the group is ignored. The library expects the parent to size it.
|
|
12
|
+
*
|
|
13
|
+
* To keep `<ResizablePanelGroup className="h-32">` ergonomic for consumers, we
|
|
14
|
+
* wrap the library's `Group` in a sizing container — `className` lands on that
|
|
15
|
+
* wrapper, the inner `Group` then fills 100%.
|
|
16
|
+
*
|
|
17
|
+
* Orientation note: the library only emits `aria-orientation` on the
|
|
18
|
+
* `Separator` (and the separator's orientation is OPPOSITE the group's — a
|
|
19
|
+
* horizontal group has vertical separators). So group flex direction is set
|
|
20
|
+
* here in JS from the prop, while separator dimension styles key off
|
|
21
|
+
* `aria-orientation=horizontal` (separator inside a `vertical` group).
|
|
22
|
+
*/
|
|
23
|
+
const ResizablePanelGroup = ({
|
|
24
|
+
className,
|
|
25
|
+
orientation,
|
|
26
|
+
style,
|
|
27
|
+
...props
|
|
28
|
+
}: React.ComponentProps<typeof Group>) => (
|
|
29
|
+
<div className={cn("flex h-full w-full", className)} style={style}>
|
|
30
|
+
<Group orientation={orientation} {...props} />
|
|
31
|
+
</div>
|
|
13
32
|
);
|
|
14
33
|
|
|
15
34
|
const ResizablePanel = Panel;
|
|
@@ -23,7 +42,7 @@ const ResizableHandle = ({
|
|
|
23
42
|
}) => (
|
|
24
43
|
<Separator
|
|
25
44
|
className={cn(
|
|
26
|
-
"relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1
|
|
45
|
+
"relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 aria-[orientation=horizontal]:h-px aria-[orientation=horizontal]:w-full aria-[orientation=horizontal]:after:left-0 aria-[orientation=horizontal]:after:h-1 aria-[orientation=horizontal]:after:w-full aria-[orientation=horizontal]:after:-translate-y-1/2 aria-[orientation=horizontal]:after:translate-x-0 [&[aria-orientation=horizontal]>div]:rotate-90",
|
|
27
46
|
className,
|
|
28
47
|
)}
|
|
29
48
|
{...props}
|
|
@@ -265,7 +265,12 @@ const SelectItem = React.forwardRef<React.ElementRef<typeof SelectPrimitive.Item
|
|
|
265
265
|
<Check className="h-4 w-4" />
|
|
266
266
|
</SelectPrimitive.ItemIndicator>
|
|
267
267
|
</span>
|
|
268
|
-
<SelectPrimitive.ItemText>
|
|
268
|
+
<SelectPrimitive.ItemText>
|
|
269
|
+
{/* Wrap children in a flex row so an inline icon + label compose
|
|
270
|
+
* horizontally instead of stacking — Tailwind's preflight makes
|
|
271
|
+
* <svg> block-level, which would otherwise push the text below. */}
|
|
272
|
+
<span className="flex items-center gap-2">{children}</span>
|
|
273
|
+
</SelectPrimitive.ItemText>
|
|
269
274
|
</SelectPrimitive.Item>
|
|
270
275
|
),
|
|
271
276
|
);
|
|
@@ -5,6 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority";
|
|
|
5
5
|
import { X } from "lucide-react";
|
|
6
6
|
import * as React from "react";
|
|
7
7
|
|
|
8
|
+
import { usePortalContainer } from "../../lib/portal-container";
|
|
8
9
|
import { cn } from "../../lib/utils";
|
|
9
10
|
|
|
10
11
|
export interface SheetProps extends React.ComponentProps<typeof SheetPrimitive.Root> {
|
|
@@ -158,18 +159,25 @@ export interface SheetContentProps
|
|
|
158
159
|
const SheetContent = React.forwardRef<
|
|
159
160
|
React.ElementRef<typeof SheetPrimitive.Content>,
|
|
160
161
|
SheetContentProps
|
|
161
|
-
>(({ side = "right", className, children, ...props }, ref) =>
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
<
|
|
165
|
-
<
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
162
|
+
>(({ side = "right", className, children, ...props }, ref) => {
|
|
163
|
+
const container = usePortalContainer();
|
|
164
|
+
return (
|
|
165
|
+
<SheetPortal container={container ?? undefined}>
|
|
166
|
+
<SheetOverlay />
|
|
167
|
+
<SheetPrimitive.Content
|
|
168
|
+
ref={ref}
|
|
169
|
+
className={cn(sheetVariants({ side }), className)}
|
|
170
|
+
{...props}
|
|
171
|
+
>
|
|
172
|
+
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
|
|
173
|
+
<X className="h-4 w-4" />
|
|
174
|
+
<span className="sr-only">Close</span>
|
|
175
|
+
</SheetPrimitive.Close>
|
|
176
|
+
{children}
|
|
177
|
+
</SheetPrimitive.Content>
|
|
178
|
+
</SheetPortal>
|
|
179
|
+
);
|
|
180
|
+
});
|
|
173
181
|
SheetContent.displayName = SheetPrimitive.Content.displayName;
|
|
174
182
|
|
|
175
183
|
export interface SheetHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
|
package/src/index.ts
CHANGED
package/styles/tokens.css
CHANGED
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
--muted-foreground: 240 3.8% 46.1%;
|
|
40
40
|
--accent: 240 4.8% 95.9%;
|
|
41
41
|
--accent-foreground: 240 5.9% 10%;
|
|
42
|
-
--destructive:
|
|
42
|
+
--destructive: 4 78% 50%;
|
|
43
43
|
--destructive-foreground: 0 0% 98%;
|
|
44
44
|
--brand: 213 94% 68%;
|
|
45
45
|
--brand-foreground: 0 0% 100%;
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
--stat-blue: 217 91% 60%; /* #3b82f6 */
|
|
78
78
|
--stat-success: 160 84% 39%; /* #10b981 */
|
|
79
79
|
--stat-purple: 258 90% 66%; /* #8b5cf6 */
|
|
80
|
-
--stat-destructive:
|
|
80
|
+
--stat-destructive: 4 78% 50%; /* #df341d */
|
|
81
81
|
--stat-amber: 38 92% 50%; /* #f59e0b */
|
|
82
82
|
|
|
83
83
|
/* ── Typography ────────────────────────────────────────────── */
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
--accent: 225 14% 22%;
|
|
120
120
|
--accent-foreground: 220 14% 92%;
|
|
121
121
|
|
|
122
|
-
--destructive:
|
|
122
|
+
--destructive: 4 88% 62%;
|
|
123
123
|
--destructive-foreground: 0 0% 98%;
|
|
124
124
|
--brand: 213 94% 68%;
|
|
125
125
|
--brand-foreground: 0 0% 100%;
|
|
@@ -151,7 +151,7 @@
|
|
|
151
151
|
--stat-blue: 217 91% 60%;
|
|
152
152
|
--stat-success: 160 84% 39%;
|
|
153
153
|
--stat-purple: 258 90% 66%;
|
|
154
|
-
--stat-destructive:
|
|
154
|
+
--stat-destructive: 4 88% 62%;
|
|
155
155
|
--stat-amber: 38 92% 50%;
|
|
156
156
|
}
|
|
157
157
|
|
|
@@ -163,6 +163,45 @@
|
|
|
163
163
|
background: hsl(var(--background));
|
|
164
164
|
color: hsl(var(--foreground));
|
|
165
165
|
}
|
|
166
|
+
|
|
167
|
+
/* ──────────────────────────────────────────────────────────────
|
|
168
|
+
* Themed scrollbars — applied globally so every overflow:auto /
|
|
169
|
+
* overflow:scroll element in canvas (and consumer apps that load
|
|
170
|
+
* tokens.css) gets canvas-token-tinted scrollbars instead of the
|
|
171
|
+
* stark OS defaults. WebKit (Chrome/Safari) uses pseudo-elements;
|
|
172
|
+
* Firefox uses the `scrollbar-*` properties. Both target the
|
|
173
|
+
* `--muted-foreground` token at 30%/45%/60% opacity for
|
|
174
|
+
* idle/hover/active so scrollbars stay subtle in dark mode and
|
|
175
|
+
* still legible in light mode.
|
|
176
|
+
* ────────────────────────────────────────────────────────────── */
|
|
177
|
+
* {
|
|
178
|
+
scrollbar-width: thin;
|
|
179
|
+
scrollbar-color: hsl(var(--muted-foreground) / 0.3) transparent;
|
|
180
|
+
}
|
|
181
|
+
*::-webkit-scrollbar {
|
|
182
|
+
width: 10px;
|
|
183
|
+
height: 10px;
|
|
184
|
+
}
|
|
185
|
+
*::-webkit-scrollbar-track {
|
|
186
|
+
background: transparent;
|
|
187
|
+
}
|
|
188
|
+
*::-webkit-scrollbar-thumb {
|
|
189
|
+
background-color: hsl(var(--muted-foreground) / 0.3);
|
|
190
|
+
border-radius: 6px;
|
|
191
|
+
/* Border creates the inset gap that makes the thumb feel like a
|
|
192
|
+
* floating pill rather than filling the gutter. */
|
|
193
|
+
border: 2px solid transparent;
|
|
194
|
+
background-clip: content-box;
|
|
195
|
+
}
|
|
196
|
+
*::-webkit-scrollbar-thumb:hover {
|
|
197
|
+
background-color: hsl(var(--muted-foreground) / 0.45);
|
|
198
|
+
}
|
|
199
|
+
*::-webkit-scrollbar-thumb:active {
|
|
200
|
+
background-color: hsl(var(--muted-foreground) / 0.6);
|
|
201
|
+
}
|
|
202
|
+
*::-webkit-scrollbar-corner {
|
|
203
|
+
background: transparent;
|
|
204
|
+
}
|
|
166
205
|
}
|
|
167
206
|
|
|
168
207
|
@custom-variant dark (&:is(.dark *));
|