fix(ui): update coss ui components (#26989)

* fix(ui): update coss ui components

* fix(sidebar): remove redundant overflow-auto from SidebarContent

ScrollArea already provides the scroll container, so keeping overflow-auto
on the child creates a nested scroll area and prevents scrollFade from
reflecting actual overflow.

Addresses Cubic AI review feedback with confidence 9/10.

Co-Authored-By: unknown <>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
authored and GitHub committed 2026-01-19 09:45:20 +00:00
1 parent d137787330
commit 950f9555ee
40 files changed
+720 -223

No files matched your search

@@ -28,14 +28,17 @@ function AccordionTrigger({
<AccordionPrimitive.Header className="flex">
<AccordionPrimitive.Trigger
className={cn(
"flex flex-1 cursor-pointer items-start justify-between gap-4 rounded-md py-4 text-left font-medium text-sm outline-none transition-all focus-visible:ring-[3px] focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-64 [&[data-panel-open]>svg]:rotate-180",
"flex flex-1 cursor-pointer items-start justify-between gap-4 rounded-md py-4 text-left font-medium text-sm outline-none transition-all focus-visible:ring-[3px] focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-64 data-panel-open:*:data-[slot=accordion-indicator]:rotate-180",
className,
)}
data-slot="accordion-trigger"
{...props}
>
{children}
<ChevronDownIcon className="pointer-events-none size-4 shrink-0 translate-y-0.5 opacity-80 transition-transform duration-200 ease-in-out" />
<ChevronDownIcon
className="pointer-events-none size-4 shrink-0 translate-y-0.5 opacity-80 transition-transform duration-200 ease-in-out"
data-slot="accordion-indicator"
/>
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
);
@@ -4,6 +4,8 @@ import { AlertDialog as AlertDialogPrimitive } from "@base-ui/react/alert-dialog
import { cn } from "@coss/ui/lib/utils";
const AlertDialogCreateHandle = AlertDialogPrimitive.createHandle;
const AlertDialog = AlertDialogPrimitive.Root;
const AlertDialogPortal = AlertDialogPrimitive.Portal;
@@ -37,7 +39,7 @@ function AlertDialogViewport({
return (
<AlertDialogPrimitive.Viewport
className={cn(
"fixed inset-0 z-50 grid grid-rows-[1fr_auto] justify-items-center pt-6 sm:grid-rows-[1fr_auto_3fr] sm:p-4",
"fixed inset-0 z-50 grid grid-rows-[1fr_auto_3fr] justify-items-center p-4",
className,
)}
data-slot="alert-dialog-viewport"
@@ -48,15 +50,25 @@ function AlertDialogViewport({
function AlertDialogPopup({
className,
bottomStickOnMobile = true,
...props
}: AlertDialogPrimitive.Popup.Props) {
}: AlertDialogPrimitive.Popup.Props & {
bottomStickOnMobile?: boolean;
}) {
return (
<AlertDialogPortal>
<AlertDialogBackdrop />
<AlertDialogViewport>
<AlertDialogViewport
className={cn(
bottomStickOnMobile &&
"max-sm:grid-rows-[1fr_auto] max-sm:p-0 max-sm:pt-12",
)}
>
<AlertDialogPrimitive.Popup
className={cn(
"sm:-translate-y-[calc(1.25rem*var(--nested-dialogs))] relative row-start-2 grid max-h-full w-full min-w-0 border-t bg-popover bg-clip-padding text-popover-foreground opacity-[calc(1-0.1*var(--nested-dialogs))] shadow-lg transition-[scale,opacity,translate] duration-200 ease-in-out will-change-transform before:pointer-events-none before:absolute before:inset-0 before:shadow-[0_1px_--theme(--color-black/4%)] data-nested-dialog-open:origin-top data-ending-style:opacity-0 data-starting-style:opacity-0 max-sm:opacity-[calc(1-min(var(--nested-dialogs),1))] max-sm:data-ending-style:translate-y-4 max-sm:data-starting-style:translate-y-4 max-sm:before:hidden sm:max-w-lg sm:data-nested:data-ending-style:translate-y-8 sm:data-nested:data-starting-style:translate-y-8 sm:scale-[calc(1-0.1*var(--nested-dialogs))] sm:rounded-2xl sm:border sm:data-ending-style:scale-98 sm:data-starting-style:scale-98 sm:before:rounded-[calc(var(--radius-2xl)-1px)] dark:bg-clip-border dark:before:shadow-[0_-1px_--theme(--color-white/8%)]",
"-translate-y-[calc(1.25rem*var(--nested-dialogs))] relative row-start-2 flex max-h-full min-h-0 w-full min-w-0 max-w-lg scale-[calc(1-0.1*var(--nested-dialogs))] flex-col rounded-2xl border bg-popover not-dark:bg-clip-padding text-popover-foreground opacity-[calc(1-0.1*var(--nested-dialogs))] shadow-lg/5 transition-[scale,opacity,translate] duration-200 ease-in-out will-change-transform before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-2xl)-1px)] before:shadow-[0_1px_--theme(--color-black/6%)] data-nested:data-ending-style:translate-y-8 data-nested:data-starting-style:translate-y-8 data-nested-dialog-open:origin-top data-ending-style:scale-98 data-starting-style:scale-98 data-ending-style:opacity-0 data-starting-style:opacity-0 dark:before:shadow-[0_-1px_--theme(--color-white/6%)]",
bottomStickOnMobile &&
"max-sm:max-w-none max-sm:rounded-none max-sm:border-x-0 max-sm:border-t max-sm:border-b-0 max-sm:opacity-[calc(1-min(var(--nested-dialogs),1))] max-sm:data-ending-style:translate-y-4 max-sm:data-starting-style:translate-y-4 max-sm:before:hidden max-sm:before:rounded-none",
className,
)}
data-slot="alert-dialog-popup"
@@ -94,7 +106,7 @@ function AlertDialogFooter({
<div
className={cn(
"flex flex-col-reverse gap-2 px-6 sm:flex-row sm:justify-end sm:rounded-b-[calc(var(--radius-2xl)-1px)]",
variant === "default" && "border-t bg-muted/50 py-4",
variant === "default" && "border-t bg-muted/72 py-4",
variant === "bare" && "pt-4 pb-6",
className,
)}
@@ -110,7 +122,10 @@ function AlertDialogTitle({
}: AlertDialogPrimitive.Title.Props) {
return (
<AlertDialogPrimitive.Title
className={cn("font-heading text-xl leading-none", className)}
className={cn(
"font-heading font-semibold text-xl leading-none",
className,
)}
data-slot="alert-dialog-title"
{...props}
/>
@@ -137,6 +152,7 @@ function AlertDialogClose(props: AlertDialogPrimitive.Close.Props) {
}
export {
AlertDialogCreateHandle,
AlertDialog,
AlertDialogPortal,
AlertDialogBackdrop,
@@ -13,26 +13,40 @@ function AutocompleteInput({
className,
showTrigger = false,
showClear = false,
startAddon,
size,
...props
}: Omit<AutocompletePrimitive.Input.Props, "size"> & {
showTrigger?: boolean;
showClear?: boolean;
startAddon?: React.ReactNode;
size?: "sm" | "default" | "lg" | number;
ref?: React.Ref<HTMLInputElement>;
}) {
const sizeValue = (size ?? "default") as "sm" | "default" | "lg" | number;
return (
<div className="relative w-full">
<div className="relative not-has-[>*.w-full]:w-fit w-full has-disabled:opacity-64">
{startAddon && (
<div
aria-hidden="true"
className="[&_svg]:-mx-0.5 pointer-events-none absolute inset-y-0 start-px z-10 flex items-center ps-[calc(--spacing(3)-1px)] opacity-80 has-[+[data-size=sm]]:ps-[calc(--spacing(2.5)-1px)] [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4"
data-slot="autocomplete-start-addon"
>
{startAddon}
</div>
)}
<AutocompletePrimitive.Input
className={cn(
startAddon &&
"data-[size=sm]:*:data-[slot=autocomplete-input]:ps-[calc(--spacing(7.5)-1px)] *:data-[slot=autocomplete-input]:ps-[calc(--spacing(8.5)-1px)] sm:data-[size=sm]:*:data-[slot=autocomplete-input]:ps-[calc(--spacing(7)-1px)] sm:*:data-[slot=autocomplete-input]:ps-[calc(--spacing(8)-1px)]",
sizeValue === "sm"
? "has-[+[data-slot=autocomplete-trigger],+[data-slot=autocomplete-clear]]:*:data-[slot=autocomplete-input]:pe-6.5"
: "has-[+[data-slot=autocomplete-trigger],+[data-slot=autocomplete-clear]]:*:data-[slot=autocomplete-input]:pe-7",
className,
)}
data-slot="autocomplete-input"
render={<Input size={sizeValue} />}
render={<Input nativeInput size={sizeValue} />}
{...props}
/>
{showTrigger && (
@@ -76,7 +90,7 @@ function AutocompletePopup({
>
<span
className={cn(
"relative flex max-h-full origin-(--transform-origin) rounded-lg border bg-popover bg-clip-padding transition-[scale,opacity] before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-lg has-data-starting-style:scale-98 has-data-starting-style:opacity-0 dark:not-in-data-[slot=group]:bg-clip-border",
"relative flex max-h-full origin-(--transform-origin) rounded-lg border bg-popover not-dark:bg-clip-padding shadow-lg/5 transition-[scale,opacity] before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-[0_1px_--theme(--color-black/6%)] dark:before:shadow-[0_-1px_--theme(--color-white/6%)]",
className,
)}
>
@@ -131,7 +145,7 @@ function AutocompleteGroup({
}: AutocompletePrimitive.Group.Props) {
return (
<AutocompletePrimitive.Group
className={className}
className={cn("[[role=group]+&]:mt-1.5", className)}
data-slot="autocomplete-group"
{...props}
/>
@@ -197,7 +211,7 @@ function AutocompleteList({
<ScrollArea scrollbarGutter scrollFade>
<AutocompletePrimitive.List
className={cn(
"not-empty:scroll-py-1 not-empty:px-1 not-empty:py-1 in-data-has-overflow-y:pe-3",
"not-empty:scroll-py-1 not-empty:p-1 in-data-has-overflow-y:pe-3",
className,
)}
data-slot="autocomplete-list"
@@ -265,6 +279,8 @@ function AutocompleteTrigger({
);
}
const useAutocompleteFilter = AutocompletePrimitive.useFilter;
export {
Autocomplete,
AutocompleteInput,
@@ -281,4 +297,5 @@ export {
AutocompleteStatus,
AutocompleteRow,
AutocompleteCollection,
useAutocompleteFilter,
};
+3 -1
View File
@@ -1,3 +1,5 @@
"use client";
import { mergeProps } from "@base-ui/react/merge-props";
import { useRender } from "@base-ui/react/use-render";
import { cva, type VariantProps } from "class-variance-authority";
@@ -27,7 +29,7 @@ const badgeVariants = cva(
"bg-destructive/8 text-destructive-foreground dark:bg-destructive/16",
info: "bg-info/8 text-info-foreground dark:bg-info/16",
outline:
"border-border bg-transparent dark:bg-input/32 [button,a&]:hover:bg-accent/50 dark:[button,a&]:hover:bg-input/48",
"border-input bg-background dark:bg-input/32 [button,a&]:hover:bg-accent/50 dark:[button,a&]:hover:bg-input/48",
secondary:
"bg-secondary text-secondary-foreground [button,a&]:hover:bg-secondary/90",
success: "bg-success/8 text-success-foreground dark:bg-success/16",
@@ -1,3 +1,5 @@
"use client";
import { mergeProps } from "@base-ui/react/merge-props";
import { useRender } from "@base-ui/react/use-render";
import { ChevronRight, MoreHorizontal } from "lucide-react";
@@ -14,7 +16,7 @@ function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
<ol
className={cn(
"wrap-break-word flex flex-wrap items-center gap-1.5 text-muted-foreground text-sm sm:gap-2.5",
className
className,
)}
data-slot="breadcrumb-list"
{...props}
@@ -51,6 +53,7 @@ function BreadcrumbLink({
function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
return (
// biome-ignore lint(a11y/useFocusableInteractive): known
<span
aria-current="page"
aria-disabled="true"
+10 -7
View File
@@ -1,3 +1,5 @@
"use client";
import { mergeProps } from "@base-ui/react/merge-props";
import { useRender } from "@base-ui/react/use-render";
import { cva, type VariantProps } from "class-variance-authority";
@@ -29,17 +31,18 @@ const buttonVariants = cva(
},
variant: {
default:
"not-disabled:inset-shadow-[0_1px_--theme(--color-white/16%)] border-primary bg-primary text-primary-foreground shadow-primary/24 shadow-xs hover:bg-primary/90 [:active,[data-pressed]]:inset-shadow-[0_1px_--theme(--color-black/8%)] [:disabled,:active,[data-pressed]]:shadow-none",
"not-disabled:inset-shadow-[0_1px_--theme(--color-white/16%)] border-primary bg-primary text-primary-foreground shadow-primary/24 shadow-xs [:active,[data-pressed]]:inset-shadow-[0_1px_--theme(--color-black/8%)] [:disabled,:active,[data-pressed]]:shadow-none [:hover,[data-pressed]]:bg-primary/90",
destructive:
"not-disabled:inset-shadow-[0_1px_--theme(--color-white/16%)] border-destructive bg-destructive text-white shadow-destructive/24 shadow-xs hover:bg-destructive/90 [:active,[data-pressed]]:inset-shadow-[0_1px_--theme(--color-black/8%)] [:disabled,:active,[data-pressed]]:shadow-none",
"not-disabled:inset-shadow-[0_1px_--theme(--color-white/16%)] border-destructive bg-destructive text-white shadow-destructive/24 shadow-xs [:active,[data-pressed]]:inset-shadow-[0_1px_--theme(--color-black/8%)] [:disabled,:active,[data-pressed]]:shadow-none [:hover,[data-pressed]]:bg-destructive/90",
"destructive-outline":
"border-border bg-transparent bg-clip-padding text-destructive-foreground shadow-xs not-disabled:not-active:not-data-pressed:before:shadow-[0_1px_--theme(--color-black/4%)] dark:bg-input/32 dark:not-in-data-[slot=group]:bg-clip-border dark:not-disabled:before:shadow-[0_-1px_--theme(--color-white/4%)] dark:not-disabled:not-active:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/8%)] [:disabled,:active,[data-pressed]]:shadow-none [:hover,[data-pressed]]:bg-destructive/4",
ghost: "border-transparent hover:bg-accent data-pressed:bg-accent",
link: "border-transparent underline-offset-4 hover:underline",
"border-input bg-transparent not-dark:bg-clip-padding text-destructive-foreground shadow-xs/5 not-disabled:not-active:not-data-pressed:before:shadow-[0_1px_--theme(--color-black/6%)] dark:bg-input/32 dark:not-disabled:before:shadow-[0_-1px_--theme(--color-white/2%)] dark:not-disabled:not-active:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/6%)] [:disabled,:active,[data-pressed]]:shadow-none [:hover,[data-pressed]]:border-destructive/32 [:hover,[data-pressed]]:bg-destructive/4",
ghost:
"border-transparent data-pressed:bg-accent [:hover,[data-pressed]]:bg-accent",
link: "border-transparent underline-offset-4 [:hover,[data-pressed]]:underline",
outline:
"border-border bg-background bg-clip-padding shadow-xs not-disabled:not-active:not-data-pressed:before:shadow-[0_1px_--theme(--color-black/4%)] dark:bg-input/32 dark:not-in-data-[slot=group]:bg-clip-border dark:not-disabled:before:shadow-[0_-1px_--theme(--color-white/4%)] dark:not-disabled:not-active:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/8%)] [:disabled,:active,[data-pressed]]:shadow-none [:hover,[data-pressed]]:bg-accent/50 dark:[:hover,[data-pressed]]:bg-input/64",
"border-input bg-background not-dark:bg-clip-padding shadow-xs/5 not-disabled:not-active:not-data-pressed:before:shadow-[0_1px_--theme(--color-black/6%)] dark:bg-input/32 dark:not-disabled:before:shadow-[0_-1px_--theme(--color-white/2%)] dark:not-disabled:not-active:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/6%)] [:disabled,:active,[data-pressed]]:shadow-none [:hover,[data-pressed]]:bg-accent/50 dark:[:hover,[data-pressed]]:bg-input/64",
secondary:
"border-secondary bg-secondary text-secondary-foreground hover:bg-secondary/90 data-pressed:bg-secondary/90",
"border-transparent bg-secondary text-secondary-foreground [:active,[data-pressed]]:bg-secondary/80 [:hover,[data-pressed]]:bg-secondary/90",
},
},
},
+121 -69
View File
@@ -1,93 +1,145 @@
import type * as React from "react";
"use client";
import { mergeProps } from "@base-ui/react/merge-props";
import { useRender } from "@base-ui/react/use-render";
import { cn } from "@coss/ui/lib/utils";
function Card({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
className={cn(
"relative flex flex-col gap-6 rounded-2xl border bg-card bg-clip-padding py-6 text-card-foreground shadow-xs before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-2xl)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] dark:bg-clip-border dark:before:shadow-[0_-1px_--theme(--color-white/8%)]",
className,
)}
data-slot="card"
{...props}
/>
);
function Card({
className,
render,
...props
}: useRender.ComponentProps<"div">) {
const defaultProps = {
className: cn(
"relative flex flex-col gap-6 rounded-2xl border bg-card not-dark:bg-clip-padding py-6 text-card-foreground shadow-xs/5 before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-2xl)-1px)] before:shadow-[0_1px_--theme(--color-black/6%)] dark:before:shadow-[0_-1px_--theme(--color-white/6%)]",
className,
),
"data-slot": "card",
};
return useRender({
defaultTagName: "div",
props: mergeProps<"div">(defaultProps, props),
render,
});
}
function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
className={cn(
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
className,
)}
data-slot="card-header"
{...props}
/>
);
function CardHeader({
className,
render,
...props
}: useRender.ComponentProps<"div">) {
const defaultProps = {
className: cn(
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
className,
),
"data-slot": "card-header",
};
return useRender({
defaultTagName: "div",
props: mergeProps<"div">(defaultProps, props),
render,
});
}
function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
className={cn("font-semibold text-lg leading-none", className)}
data-slot="card-title"
{...props}
/>
);
function CardTitle({
className,
render,
...props
}: useRender.ComponentProps<"div">) {
const defaultProps = {
className: cn("font-semibold text-lg leading-none", className),
"data-slot": "card-title",
};
return useRender({
defaultTagName: "div",
props: mergeProps<"div">(defaultProps, props),
render,
});
}
function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
className={cn("text-muted-foreground text-sm", className)}
data-slot="card-description"
{...props}
/>
);
function CardDescription({
className,
render,
...props
}: useRender.ComponentProps<"div">) {
const defaultProps = {
className: cn("text-muted-foreground text-sm", className),
"data-slot": "card-description",
};
return useRender({
defaultTagName: "div",
props: mergeProps<"div">(defaultProps, props),
render,
});
}
function CardAction({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
className={cn(
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
className,
)}
data-slot="card-action"
{...props}
/>
);
function CardAction({
className,
render,
...props
}: useRender.ComponentProps<"div">) {
const defaultProps = {
className: cn(
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
className,
),
"data-slot": "card-action",
};
return useRender({
defaultTagName: "div",
props: mergeProps<"div">(defaultProps, props),
render,
});
}
function CardPanel({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
className={cn("px-6", className)}
data-slot="card-content"
{...props}
/>
);
function CardPanel({
className,
render,
...props
}: useRender.ComponentProps<"div">) {
const defaultProps = {
className: cn("px-6", className),
"data-slot": "card-content",
};
return useRender({
defaultTagName: "div",
props: mergeProps<"div">(defaultProps, props),
render,
});
}
function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
data-slot="card-footer"
{...props}
/>
);
function CardFooter({
className,
render,
...props
}: useRender.ComponentProps<"div">) {
const defaultProps = {
className: cn("flex items-center px-6 [.border-t]:pt-6", className),
"data-slot": "card-footer",
};
return useRender({
defaultTagName: "div",
props: mergeProps<"div">(defaultProps, props),
render,
});
}
export {
Card,
CardHeader,
CardFooter,
CardTitle,
CardAction,
CardDescription,
CardFooter,
CardHeader,
CardPanel,
CardPanel as CardContent,
CardTitle,
};
+1 -1
View File
@@ -8,7 +8,7 @@ function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) {
return (
<CheckboxPrimitive.Root
className={cn(
"relative inline-flex size-4.5 shrink-0 items-center justify-center rounded-[4px] border border-input bg-background bg-clip-padding shadow-xs outline-none ring-ring transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[3px] not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_1px_--theme(--color-black/4%)] focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-offset-background aria-invalid:border-destructive/36 focus-visible:aria-invalid:border-destructive/64 focus-visible:aria-invalid:ring-destructive/48 data-disabled:opacity-64 sm:size-4 dark:not-data-checked:bg-input/32 dark:bg-clip-border dark:aria-invalid:ring-destructive/24 dark:not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/8%)] [[data-disabled],[data-checked],[aria-invalid]]:shadow-none",
"relative inline-flex size-4.5 shrink-0 items-center justify-center rounded-[4px] border border-input bg-background not-dark:bg-clip-padding shadow-xs/5 outline-none ring-ring transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[3px] not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_1px_--theme(--color-black/6%)] focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-offset-background aria-invalid:border-destructive/36 focus-visible:aria-invalid:border-destructive/64 focus-visible:aria-invalid:ring-destructive/48 data-disabled:opacity-64 sm:size-4 dark:not-data-checked:bg-input/32 dark:aria-invalid:ring-destructive/24 dark:not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/6%)] [[data-disabled],[data-checked],[aria-invalid]]:shadow-none",
className,
)}
data-slot="checkbox"
+60 -7
View File
@@ -38,12 +38,15 @@ function ComboboxInput({
className,
showTrigger = true,
showClear = false,
startAddon,
size,
...props
}: Omit<ComboboxPrimitive.Input.Props, "size"> & {
showTrigger?: boolean;
showClear?: boolean;
startAddon?: React.ReactNode;
size?: "sm" | "default" | "lg" | number;
ref?: React.Ref<HTMLInputElement>;
}) {
const { multiple } = React.useContext(ComboboxContext);
const sizeValue = (size ?? "default") as "sm" | "default" | "lg" | number;
@@ -64,18 +67,36 @@ function ComboboxInput({
/>
);
}
// single mode
return (
<div className="relative w-full has-disabled:opacity-64">
<div className="relative not-has-[>*.w-full]:w-fit w-full has-disabled:opacity-64">
{startAddon && (
<div
aria-hidden="true"
className="[&_svg]:-mx-0.5 pointer-events-none absolute inset-y-0 start-px z-10 flex items-center ps-[calc(--spacing(3)-1px)] opacity-80 has-[+[data-size=sm]]:ps-[calc(--spacing(2.5)-1px)] [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4"
data-slot="combobox-start-addon"
>
{startAddon}
</div>
)}
<ComboboxPrimitive.Input
className={cn(
startAddon &&
"data-[size=sm]:*:data-[slot=combobox-input]:ps-[calc(--spacing(7.5)-1px)] *:data-[slot=combobox-input]:ps-[calc(--spacing(8.5)-1px)] sm:data-[size=sm]:*:data-[slot=combobox-input]:ps-[calc(--spacing(7)-1px)] sm:*:data-[slot=combobox-input]:ps-[calc(--spacing(8)-1px)]",
sizeValue === "sm"
? "has-[+[data-slot=combobox-trigger],+[data-slot=combobox-clear]]:*:data-[slot=combobox-input]:pe-6.5"
: "has-[+[data-slot=combobox-trigger],+[data-slot=combobox-clear]]:*:data-[slot=combobox-input]:pe-7",
className,
)}
data-slot="combobox-input"
render={<Input className="has-disabled:opacity-100" size={sizeValue} />}
render={
<Input
className="has-disabled:opacity-100"
nativeInput
size={sizeValue}
/>
}
{...props}
/>
{showTrigger && (
@@ -135,7 +156,7 @@ function ComboboxPopup({
>
<span
className={cn(
"relative flex max-h-full origin-(--transform-origin) rounded-lg border bg-popover bg-clip-padding transition-[scale,opacity] before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-lg has-data-starting-style:scale-98 has-data-starting-style:opacity-0 dark:not-in-data-[slot=group]:bg-clip-border",
"relative flex max-h-full origin-(--transform-origin) rounded-lg border bg-popover not-dark:bg-clip-padding shadow-lg/5 transition-[scale,opacity] before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-[0_1px_--theme(--color-black/6%)] dark:before:shadow-[0_-1px_--theme(--color-white/6%)]",
className,
)}
>
@@ -202,7 +223,7 @@ function ComboboxSeparator({
function ComboboxGroup({ className, ...props }: ComboboxPrimitive.Group.Props) {
return (
<ComboboxPrimitive.Group
className={className}
className={cn("[[role=group]+&]:mt-1.5", className)}
data-slot="combobox-group"
{...props}
/>
@@ -299,19 +320,48 @@ function ComboboxCollection(props: ComboboxPrimitive.Collection.Props) {
);
}
function ComboboxChips({ className, ...props }: ComboboxPrimitive.Chips.Props) {
function ComboboxChips({
className,
children,
startAddon,
...props
}: ComboboxPrimitive.Chips.Props & {
startAddon?: React.ReactNode;
}) {
const { chipsRef } = React.useContext(ComboboxContext);
return (
<ComboboxPrimitive.Chips
className={cn(
"relative inline-flex min-h-9 w-full flex-wrap gap-1 rounded-lg border border-input bg-background bg-clip-padding p-[calc(--spacing(1)-1px)] text-base shadow-xs outline-none ring-ring/24 transition-shadow *:min-h-7 before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] not-has-disabled:not-focus-within:not-aria-invalid:before:shadow-[0_1px_--theme(--color-black/4%)] focus-within:border-ring focus-within:ring-[3px] has-disabled:pointer-events-none has-data-[size=lg]:min-h-10 has-data-[size=sm]:min-h-8 has-aria-invalid:border-destructive/36 has-disabled:opacity-64 has-[:disabled,:focus-within,[aria-invalid]]:shadow-none focus-within:has-aria-invalid:border-destructive/64 focus-within:has-aria-invalid:ring-destructive/16 has-data-[size=lg]:*:min-h-8 has-data-[size=sm]:*:min-h-6 sm:min-h-8 sm:text-sm sm:has-data-[size=lg]:min-h-9 sm:has-data-[size=sm]:min-h-7 sm:*:min-h-6 sm:has-data-[size=lg]:*:min-h-7 sm:has-data-[size=sm]:*:min-h-5 dark:not-has-disabled:bg-input/32 dark:not-in-data-[slot=group]:bg-clip-border dark:has-aria-invalid:ring-destructive/24 dark:not-has-disabled:not-focus-within:not-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/8%)]",
"relative inline-flex min-h-9 w-full flex-wrap gap-1 rounded-lg border border-input bg-background not-dark:bg-clip-padding p-[calc(--spacing(1)-1px)] text-base shadow-xs/5 outline-none ring-ring/24 transition-shadow *:min-h-7 before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] not-has-disabled:not-focus-within:not-aria-invalid:before:shadow-[0_1px_--theme(--color-black/6%)] focus-within:border-ring focus-within:ring-[3px] has-disabled:pointer-events-none has-data-[size=lg]:min-h-10 has-data-[size=sm]:min-h-8 has-aria-invalid:border-destructive/36 has-disabled:opacity-64 has-[:disabled,:focus-within,[aria-invalid]]:shadow-none focus-within:has-aria-invalid:border-destructive/64 focus-within:has-aria-invalid:ring-destructive/16 has-data-[size=lg]:*:min-h-8 has-data-[size=sm]:*:min-h-6 sm:min-h-8 sm:text-sm sm:has-data-[size=lg]:min-h-9 sm:has-data-[size=sm]:min-h-7 sm:*:min-h-6 sm:has-data-[size=lg]:*:min-h-7 sm:has-data-[size=sm]:*:min-h-5 dark:not-has-disabled:bg-input/32 dark:has-aria-invalid:ring-destructive/24 dark:not-has-disabled:not-focus-within:not-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/6%)]",
className,
)}
data-slot="combobox-chips"
onMouseDown={(e) => {
const target = e.target as HTMLElement;
const isChip = target.closest('[data-slot="combobox-chip"]');
if (isChip || !chipsRef?.current) return;
e.preventDefault();
const input: HTMLInputElement | null =
chipsRef.current.querySelector("input");
if (input && !chipsRef.current.querySelector("input:focus")) {
input.focus();
}
}}
ref={chipsRef as React.Ref<HTMLDivElement> | null}
{...props}
/>
>
{startAddon && (
<div
aria-hidden="true"
className="[&_svg]:-ms-0.5 [&_svg]:-me-1.5 flex shrink-0 items-center ps-2 opacity-80 has-[~[data-size=sm]]:has-[+[data-slot=combobox-chip]]:pe-1.5 has-[~[data-size=sm]]:ps-1.5 has-[+[data-slot=combobox-chip]]:pe-2 [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none"
data-slot="combobox-start-addon"
>
{startAddon}
</div>
)}
{children}
</ComboboxPrimitive.Chips>
);
}
@@ -341,6 +391,8 @@ function ComboboxChipRemove(props: ComboboxPrimitive.ChipRemove.Props) {
);
}
const useComboboxFilter = ComboboxPrimitive.useFilter;
export {
Combobox,
ComboboxInput,
@@ -359,4 +411,5 @@ export {
ComboboxCollection,
ComboboxChips,
ComboboxChip,
useComboboxFilter,
};
+264
View File
@@ -0,0 +1,264 @@
"use client";
import { Dialog as CommandDialogPrimitive } from "@base-ui/react/dialog";
import { SearchIcon } from "lucide-react";
import type * as React from "react";
import { cn } from "@coss/ui/lib/utils";
import {
Autocomplete,
AutocompleteCollection,
AutocompleteEmpty,
AutocompleteGroup,
AutocompleteGroupLabel,
AutocompleteInput,
AutocompleteItem,
AutocompleteList,
AutocompleteSeparator,
} from "@coss/ui/components/autocomplete";
const CommandDialog = CommandDialogPrimitive.Root;
const CommandDialogPortal = CommandDialogPrimitive.Portal;
const CommandCreateHandle = CommandDialogPrimitive.createHandle;
function CommandDialogTrigger(props: CommandDialogPrimitive.Trigger.Props) {
return (
<CommandDialogPrimitive.Trigger
data-slot="command-dialog-trigger"
{...props}
/>
);
}
function CommandDialogBackdrop({
className,
...props
}: CommandDialogPrimitive.Backdrop.Props) {
return (
<CommandDialogPrimitive.Backdrop
className={cn(
"fixed inset-0 z-50 bg-black/32 backdrop-blur-sm transition-all duration-200 data-ending-style:opacity-0 data-starting-style:opacity-0",
className,
)}
data-slot="command-dialog-backdrop"
{...props}
/>
);
}
function CommandDialogViewport({
className,
...props
}: CommandDialogPrimitive.Viewport.Props) {
return (
<CommandDialogPrimitive.Viewport
className={cn(
"fixed inset-0 z-50 flex flex-col items-center px-4 py-[max(--spacing(4),4vh)] sm:py-[10vh]",
className,
)}
data-slot="command-dialog-viewport"
{...props}
/>
);
}
function CommandDialogPopup({
className,
children,
...props
}: CommandDialogPrimitive.Popup.Props) {
return (
<CommandDialogPortal>
<CommandDialogBackdrop />
<CommandDialogViewport>
<CommandDialogPrimitive.Popup
className={cn(
"-translate-y-[calc(1.25rem*var(--nested-dialogs))] relative row-start-2 flex max-h-105 min-h-0 w-full min-w-0 max-w-xl scale-[calc(1-0.1*var(--nested-dialogs))] flex-col rounded-2xl border bg-popover not-dark:bg-clip-padding text-popover-foreground opacity-[calc(1-0.1*var(--nested-dialogs))] shadow-lg/5 outline-none transition-[scale,opacity,translate] duration-200 ease-in-out will-change-transform before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-2xl)-1px)] before:bg-muted/72 before:shadow-[0_1px_--theme(--color-black/6%)] data-nested:data-ending-style:translate-y-8 data-nested:data-starting-style:translate-y-8 data-nested-dialog-open:origin-top data-ending-style:scale-98 data-starting-style:scale-98 data-ending-style:opacity-0 data-starting-style:opacity-0 **:data-[slot=scroll-area-viewport]:data-has-overflow-y:pe-1 dark:before:shadow-[0_-1px_--theme(--color-white/6%)]",
className,
)}
data-slot="command-dialog-popup"
{...props}
>
{children}
</CommandDialogPrimitive.Popup>
</CommandDialogViewport>
</CommandDialogPortal>
);
}
function Command({
autoHighlight = "always",
keepHighlight = true,
...props
}: React.ComponentProps<typeof Autocomplete>) {
return (
<Autocomplete
autoHighlight={autoHighlight}
inline
keepHighlight={keepHighlight}
open
{...props}
/>
);
}
function CommandInput({
className,
placeholder = undefined,
...props
}: React.ComponentProps<typeof AutocompleteInput>) {
return (
<div className="px-2.5 py-1.5">
<AutocompleteInput
autoFocus
className={cn(
"border-transparent! bg-transparent! shadow-none before:hidden has-focus-visible:ring-0",
className,
)}
placeholder={placeholder}
size="lg"
startAddon={<SearchIcon />}
{...props}
/>
</div>
);
}
function CommandList({
className,
...props
}: React.ComponentProps<typeof AutocompleteList>) {
return (
<AutocompleteList
className={cn("not-empty:scroll-py-2 not-empty:p-2", className)}
data-slot="command-list"
{...props}
/>
);
}
function CommandEmpty({
className,
...props
}: React.ComponentProps<typeof AutocompleteEmpty>) {
return (
<AutocompleteEmpty
className={cn("not-empty:py-6", className)}
data-slot="command-empty"
{...props}
/>
);
}
function CommandPanel({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
className="-mx-px not-has-[+[data-slot=command-footer]]:-mb-px relative min-h-0 rounded-t-xl not-has-[+[data-slot=command-footer]]:rounded-b-2xl border border-b-0 bg-popover not-dark:bg-clip-padding shadow-xs/5 [clip-path:inset(0_1px)] not-has-[+[data-slot=command-footer]]:[clip-path:inset(0_1px_1px_1px_round_0_0_calc(var(--radius-2xl)-1px)_calc(var(--radius-2xl)-1px))] before:pointer-events-none before:absolute before:inset-0 before:rounded-t-[calc(var(--radius-xl)-1px)] **:data-[slot=scroll-area-scrollbar]:mt-2 dark:before:shadow-[0_-1px_--theme(--color-white/6%)]"
{...props}
/>
);
}
function CommandGroup({
className,
...props
}: React.ComponentProps<typeof AutocompleteGroup>) {
return (
<AutocompleteGroup
className={className}
data-slot="command-group"
{...props}
/>
);
}
function CommandGroupLabel({
className,
...props
}: React.ComponentProps<typeof AutocompleteGroupLabel>) {
return (
<AutocompleteGroupLabel
className={className}
data-slot="command-group-label"
{...props}
/>
);
}
function CommandCollection({
...props
}: React.ComponentProps<typeof AutocompleteCollection>) {
return <AutocompleteCollection data-slot="command-collection" {...props} />;
}
function CommandItem({
className,
...props
}: React.ComponentProps<typeof AutocompleteItem>) {
return (
<AutocompleteItem
className={cn("py-1.5", className)}
data-slot="command-item"
{...props}
/>
);
}
function CommandSeparator({
className,
...props
}: React.ComponentProps<typeof AutocompleteSeparator>) {
return (
<AutocompleteSeparator
className={cn("my-2", className)}
data-slot="command-separator"
{...props}
/>
);
}
function CommandShortcut({ className, ...props }: React.ComponentProps<"kbd">) {
return (
<kbd
className={cn(
"ms-auto font-medium font-sans text-muted-foreground/72 text-xs tracking-widest",
className,
)}
data-slot="command-shortcut"
{...props}
/>
);
}
function CommandFooter({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
className={cn(
"flex items-center justify-between gap-2 rounded-b-[calc(var(--radius-2xl)-1px)] border-t px-5 py-3 text-muted-foreground text-xs",
className,
)}
data-slot="command-footer"
{...props}
/>
);
}
export {
CommandCreateHandle,
Command,
CommandCollection,
CommandDialog,
CommandDialogPopup,
CommandDialogTrigger,
CommandEmpty,
CommandFooter,
CommandGroup,
CommandGroupLabel,
CommandInput,
CommandItem,
CommandList,
CommandPanel,
CommandSeparator,
CommandShortcut,
};
+26 -7
View File
@@ -6,6 +6,8 @@ import { cn } from "@coss/ui/lib/utils";
import { Button } from "@coss/ui/components/button";
import { ScrollArea } from "@coss/ui/components/scroll-area";
const DialogCreateHandle = DialogPrimitive.createHandle;
const Dialog = DialogPrimitive.Root;
const DialogPortal = DialogPrimitive.Portal;
@@ -41,7 +43,7 @@ function DialogViewport({
return (
<DialogPrimitive.Viewport
className={cn(
"fixed inset-0 z-50 grid grid-rows-[1fr_auto] justify-items-center pt-12 sm:grid-rows-[1fr_auto_3fr] sm:p-4",
"fixed inset-0 z-50 grid grid-rows-[1fr_auto_3fr] justify-items-center p-4",
className,
)}
data-slot="dialog-viewport"
@@ -54,17 +56,26 @@ function DialogPopup({
className,
children,
showCloseButton = true,
bottomStickOnMobile = true,
...props
}: DialogPrimitive.Popup.Props & {
showCloseButton?: boolean;
bottomStickOnMobile?: boolean;
}) {
return (
<DialogPortal>
<DialogBackdrop />
<DialogViewport>
<DialogViewport
className={cn(
bottomStickOnMobile &&
"max-sm:grid-rows-[1fr_auto] max-sm:p-0 max-sm:pt-12",
)}
>
<DialogPrimitive.Popup
className={cn(
"sm:-translate-y-[calc(1.25rem*var(--nested-dialogs))] relative row-start-2 flex max-h-full min-h-0 w-full min-w-0 flex-col border-t bg-popover bg-clip-padding text-popover-foreground opacity-[calc(1-0.1*var(--nested-dialogs))] shadow-lg transition-[scale,opacity,translate] duration-200 ease-in-out will-change-transform before:pointer-events-none before:absolute before:inset-0 before:shadow-[0_1px_--theme(--color-black/4%)] data-nested-dialog-open:origin-top data-ending-style:opacity-0 data-starting-style:opacity-0 max-sm:opacity-[calc(1-min(var(--nested-dialogs),1))] max-sm:data-ending-style:translate-y-4 max-sm:data-starting-style:translate-y-4 max-sm:before:hidden sm:max-w-lg sm:data-nested:data-ending-style:translate-y-8 sm:data-nested:data-starting-style:translate-y-8 sm:scale-[calc(1-0.1*var(--nested-dialogs))] sm:rounded-2xl sm:border sm:data-ending-style:scale-98 sm:data-starting-style:scale-98 sm:before:rounded-[calc(var(--radius-2xl)-1px)] dark:bg-clip-border dark:before:shadow-[0_-1px_--theme(--color-white/8%)]",
"-translate-y-[calc(1.25rem*var(--nested-dialogs))] relative row-start-2 flex max-h-full min-h-0 w-full min-w-0 max-w-lg scale-[calc(1-0.1*var(--nested-dialogs))] flex-col rounded-2xl border bg-popover not-dark:bg-clip-padding text-popover-foreground opacity-[calc(1-0.1*var(--nested-dialogs))] shadow-lg/5 transition-[scale,opacity,translate] duration-200 ease-in-out will-change-transform before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-2xl)-1px)] before:shadow-[0_1px_--theme(--color-black/6%)] data-nested:data-ending-style:translate-y-8 data-nested:data-starting-style:translate-y-8 data-nested-dialog-open:origin-top data-ending-style:scale-98 data-starting-style:scale-98 data-ending-style:opacity-0 data-starting-style:opacity-0 dark:before:shadow-[0_-1px_--theme(--color-white/6%)]",
bottomStickOnMobile &&
"max-sm:max-w-none max-sm:rounded-none max-sm:border-x-0 max-sm:border-t max-sm:border-b-0 max-sm:opacity-[calc(1-min(var(--nested-dialogs),1))] max-sm:data-ending-style:translate-y-4 max-sm:data-starting-style:translate-y-4 max-sm:before:hidden max-sm:before:rounded-none",
className,
)}
data-slot="dialog-popup"
@@ -110,7 +121,7 @@ function DialogFooter({
<div
className={cn(
"flex flex-col-reverse gap-2 px-6 sm:flex-row sm:justify-end sm:rounded-b-[calc(var(--radius-2xl)-1px)]",
variant === "default" && "border-t bg-muted/50 py-4",
variant === "default" && "border-t bg-muted/72 py-4",
variant === "bare" &&
"in-[[data-slot=dialog-popup]:has([data-slot=dialog-panel])]:pt-3 pt-4 pb-6",
className,
@@ -124,7 +135,10 @@ function DialogFooter({
function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) {
return (
<DialogPrimitive.Title
className={cn("font-heading text-xl leading-none", className)}
className={cn(
"font-heading font-semibold text-xl leading-none",
className,
)}
data-slot="dialog-title"
{...props}
/>
@@ -144,9 +158,13 @@ function DialogDescription({
);
}
function DialogPanel({ className, ...props }: React.ComponentProps<"div">) {
function DialogPanel({
className,
scrollFade = true,
...props
}: React.ComponentProps<"div"> & { scrollFade?: boolean }) {
return (
<ScrollArea>
<ScrollArea scrollFade={scrollFade}>
<div
className={cn(
"px-6 in-[[data-slot=dialog-popup]:has([data-slot=dialog-header])]:pt-1 in-[[data-slot=dialog-popup]:not(:has([data-slot=dialog-header]))]:pt-6 in-[[data-slot=dialog-popup]:not(:has([data-slot=dialog-footer]))]:pb-6! in-[[data-slot=dialog-popup]:not(:has([data-slot=dialog-footer].border-t))]:pb-1 pb-6",
@@ -160,6 +178,7 @@ function DialogPanel({ className, ...props }: React.ComponentProps<"div">) {
}
export {
DialogCreateHandle,
Dialog,
DialogTrigger,
DialogPortal,
+4 -4
View File
@@ -6,7 +6,7 @@ function Empty({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
className={cn(
"flex min-w-0 flex-1 flex-col items-center justify-center gap-6 text-balance rounded-xl border-dashed p-6 text-center md:p-12",
"flex min-w-0 flex-1 flex-col items-center justify-center gap-6 text-balance p-6 text-center md:p-12",
className,
)}
data-slot="empty"
@@ -37,7 +37,7 @@ const emptyMediaVariants = cva(
variants: {
variant: {
default: "bg-transparent",
icon: "relative flex size-9 shrink-0 items-center justify-center rounded-md border bg-card text-foreground shadow-black/5 shadow-sm before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-md)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] dark:before:shadow-[0_-1px_--theme(--color-white/8%)] [&_svg:not([class*='size-'])]:size-4.5",
icon: "relative flex size-9 shrink-0 items-center justify-center rounded-md border bg-card text-foreground shadow-sm/5 before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-md)-1px)] before:shadow-[0_1px_--theme(--color-black/6%)] dark:before:shadow-[0_-1px_--theme(--color-white/6%)] [&_svg:not([class*='size-'])]:size-4.5",
},
},
},
@@ -84,7 +84,7 @@ function EmptyMedia({
function EmptyTitle({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
className={cn("font-heading text-xl leading-none", className)}
className={cn("font-heading font-semibold text-xl", className)}
data-slot="empty-title"
{...props}
/>
@@ -95,7 +95,7 @@ function EmptyDescription({ className, ...props }: React.ComponentProps<"p">) {
return (
<div
className={cn(
"text-muted-foreground text-sm/relaxed [&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4 [[data-slot=empty-title]+&]:mt-1",
"text-muted-foreground text-sm [&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4 [[data-slot=empty-title]+&]:mt-1",
className,
)}
data-slot="empty-description"
+11
View File
@@ -27,6 +27,16 @@ function FieldLabel({ className, ...props }: FieldPrimitive.Label.Props) {
);
}
function FieldItem({ className, ...props }: FieldPrimitive.Item.Props) {
return (
<FieldPrimitive.Item
className={cn("flex", className)}
data-slot="field-item"
{...props}
/>
);
}
function FieldDescription({
className,
...props
@@ -59,5 +69,6 @@ export {
FieldDescription,
FieldError,
FieldControl,
FieldItem,
FieldValidity,
};
+4 -10
View File
@@ -2,18 +2,12 @@ import type * as React from "react";
import { cn } from "@coss/ui/lib/utils";
function Frame({
className,
stackedPanels = false,
...props
}: React.ComponentProps<"div"> & { stackedPanels?: boolean }) {
function Frame({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
className={cn(
"relative flex flex-col rounded-2xl bg-muted/50 p-1",
stackedPanels
? "*:has-[+[data-slot=frame-panel]]:rounded-b-none *:has-[+[data-slot=frame-panel]]:before:hidden dark:*:has-[+[data-slot=frame-panel]]:before:block *:[[data-slot=frame-panel]+[data-slot=frame-panel]]:rounded-t-none *:[[data-slot=frame-panel]+[data-slot=frame-panel]]:border-t-0 dark:*:[[data-slot=frame-panel]+[data-slot=frame-panel]]:before:hidden"
: "*:[[data-slot=frame-panel]+[data-slot=frame-panel]]:mt-1",
"relative flex flex-col rounded-2xl bg-muted/72 p-1",
"*:[[data-slot=frame-panel]+[data-slot=frame-panel]]:mt-1",
className,
)}
data-slot="frame"
@@ -26,7 +20,7 @@ function FramePanel({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
className={cn(
"relative rounded-xl border bg-background bg-clip-padding p-5 shadow-xs before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-xl)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] dark:bg-clip-border dark:before:shadow-[0_-1px_--theme(--color-white/8%)]",
"relative rounded-xl border bg-background bg-clip-padding p-5 shadow-xs/5 before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-xl)-1px)] before:shadow-[0_1px_--theme(--color-black/6%)] dark:before:shadow-[0_-1px_--theme(--color-white/6%)]",
className,
)}
data-slot="frame-panel"
+7 -5
View File
@@ -1,3 +1,5 @@
"use client";
import { mergeProps } from "@base-ui/react/merge-props";
import { useRender } from "@base-ui/react/use-render";
import { cva, type VariantProps } from "class-variance-authority";
@@ -7,7 +9,7 @@ import { cn } from "@coss/ui/lib/utils";
import { Separator } from "@coss/ui/components/separator";
const groupVariants = cva(
"flex w-fit *:focus-visible:z-10 has-[>[data-slot=group]]:gap-2 *:has-focus-visible:z-10",
"flex w-fit *:focus-visible:z-1 has-[>[data-slot=group]]:gap-2 *:has-focus-visible:z-1 dark:*:[[data-slot=button]:hover~[data-slot=separator]:not([data-slot]:hover~[data-slot=separator]~[data-slot=separator]),[data-slot][data-pressed]~[data-slot=separator]:not([data-slot][data-pressed]~[data-slot=separator]~[data-slot=separator])]:before:bg-input/64 dark:*:[[data-slot=separator]:has(~[data-slot=button]:hover):not(:has(~[data-slot=separator]~[data-slot]:hover)),[data-slot=separator]:has(~[data-slot][data-pressed]):not(:has(~[data-slot=separator]~[data-slot][data-pressed]))]:before:bg-input/64",
{
defaultVariants: {
orientation: "horizontal",
@@ -15,9 +17,9 @@ const groupVariants = cva(
variants: {
orientation: {
horizontal:
"*:not-first:before:-start-[0.5px] *:not-nth-last-[1_of_:not(span[data-base-ui-focus-guard],span[data-base-ui-inert])]:before:-end-[0.5px] *:not-first:rounded-s-none *:not-nth-last-[1_of_:not(span[data-base-ui-focus-guard],span[data-base-ui-inert])]:rounded-e-none *:not-first:border-s-0 *:not-nth-last-[1_of_:not(span[data-base-ui-focus-guard],span[data-base-ui-inert])]:border-e-0 *:not-first:before:rounded-s-none *:not-nth-last-[1_of_:not(span[data-base-ui-focus-guard],span[data-base-ui-inert])]:before:rounded-e-none *:after:absolute *:after:start-full *:after:h-full *:after:w-px *:pointer-coarse:after:min-w-auto",
"*:[[data-slot]~[data-slot]:not([data-slot=separator])]:before:-start-[0.5px] *:data-slot:not-data-[slot=separator]:has-[~[data-slot]]:before:-end-[0.5px] *:pointer-coarse:after:min-w-auto *:data-slot:has-[~[data-slot]]:rounded-e-none *:data-slot:has-[~[data-slot]]:border-e-0 *:data-slot:has-[~[data-slot]]:before:rounded-e-none *:[[data-slot]~[data-slot]]:rounded-s-none *:[[data-slot]~[data-slot]]:border-s-0 *:[[data-slot]~[data-slot]]:before:rounded-s-none",
vertical:
"*:not-first:before:-top-[0.5px] *:not-nth-last-[1_of_:not(span[data-base-ui-focus-guard],span[data-base-ui-inert])]:before:-bottom-[0.5px] flex-col *:not-first:rounded-t-none *:not-nth-last-[1_of_:not(span[data-base-ui-focus-guard],span[data-base-ui-inert])]:rounded-b-none *:not-first:border-t-0 *:not-nth-last-[1_of_:not(span[data-base-ui-focus-guard],span[data-base-ui-inert])]:border-b-0 *:not-nth-last-[1_of_:not(span[data-base-ui-focus-guard],span[data-base-ui-inert])]:before:hidden *:not-first:before:rounded-t-none *:not-nth-last-[1_of_:not(span[data-base-ui-focus-guard],span[data-base-ui-inert])]:before:rounded-b-none *:after:absolute *:after:top-full *:after:h-px *:pointer-coarse:after:min-h-auto *:after:w-full dark:*:last:before:hidden dark:*:first:before:block",
"*:[[data-slot]~[data-slot]:not([data-slot=separator])]:before:-top-[0.5px] *:data-slot:not-data-[slot=separator]:has-[~[data-slot]]:before:-bottom-[0.5px] flex-col *:pointer-coarse:after:min-h-auto *:data-slot:has-[~[data-slot]]:rounded-b-none *:data-slot:has-[~[data-slot]]:border-b-0 *:data-slot:not-data-[slot=separator]:has-[~[data-slot]]:before:hidden *:data-slot:has-[~[data-slot]]:before:rounded-b-none dark:*:last:before:hidden dark:*:first:before:block *:[[data-slot]~[data-slot]]:rounded-t-none *:[[data-slot]~[data-slot]]:border-t-0 *:[[data-slot]~[data-slot]]:before:rounded-t-none",
},
},
},
@@ -53,7 +55,7 @@ function GroupText({
}: useRender.ComponentProps<"div">) {
const defaultProps = {
className: cn(
"relative inline-flex items-center whitespace-nowrap rounded-lg border border-border bg-muted bg-clip-padding px-[calc(--spacing(3)-1px)] text-muted-foreground text-base sm:text-sm shadow-xs outline-none transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] dark:bg-input/64 dark:before:shadow-[0_-1px_--theme(--color-white/8%)] [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 [&_svg]:-mx-0.5",
"relative inline-flex items-center whitespace-nowrap rounded-lg border border-input bg-muted not-dark:bg-clip-padding px-[calc(--spacing(3)-1px)] text-muted-foreground text-base sm:text-sm shadow-xs/5 outline-none transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-[0_1px_--theme(--color-black/6%)] dark:bg-input/64 dark:before:shadow-[0_-1px_--theme(--color-white/6%)] [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 [&_svg]:-mx-0.5",
className,
),
"data-slot": "group-text",
@@ -75,7 +77,7 @@ function GroupSeparator({
return (
<Separator
className={cn(
"[[data-slot=input-control]:focus-within+&,[data-slot=select-trigger]:focus-visible+*+&]:-translate-x-px pointer-events-none relative z-20 has-[+[data-slot=input-control]:focus-within,+[data-slot=select-trigger]:focus-visible+*,+[data-slot=number-field]:focus-within]:translate-x-px has-[+[data-slot=input-control]:focus-within,+[data-slot=select-trigger]:focus-visible+*,+[data-slot=number-field]:focus-within]:bg-ring [[data-slot=input-control]:focus-within+&,[data-slot=select-trigger]:focus-visible+*+&,[data-slot=number-field]:focus-within+&]:bg-ring",
"[[data-slot=input-control]:focus-within+&,[data-slot=input-group]:focus-within+&,[data-slot=select-trigger]:focus-visible+*+&,[data-slot=number-field]:focus-within+input+&]:-translate-x-px pointer-events-none relative z-2 before:absolute before:inset-0 has-[+[data-slot=input-control]:focus-within,+[data-slot=input-group]:focus-within,+[data-slot=select-trigger]:focus-visible+*,+[data-slot=number-field]:focus-within]:translate-x-px has-[+[data-slot=input-control]:focus-within,+[data-slot=input-group]:focus-within,+[data-slot=select-trigger]:focus-visible+*,+[data-slot=number-field]:focus-within]:bg-ring dark:before:bg-input/32 [[data-slot=input-control]:focus-within+&,[data-slot=input-group]:focus-within+&,[data-slot=select-trigger]:focus-visible+*+&,[data-slot=number-field]:focus-within+&,[data-slot=number-field]:focus-within+input+&]:bg-ring",
className,
)}
orientation={orientation}
@@ -11,7 +11,7 @@ function InputGroup({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
className={cn(
"relative inline-flex w-full min-w-0 items-center rounded-lg border border-input bg-background bg-clip-padding text-base shadow-xs ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] not-has-[input:disabled,textarea:disabled]:not-has-[input:focus-visible,textarea:focus-visible]:not-has-[input[aria-invalid],textarea[aria-invalid]]:before:shadow-[0_1px_--theme(--color-black/4%)] has-[input:focus-visible,textarea:focus-visible]:has-[input[aria-invalid],textarea[aria-invalid]]:border-destructive/64 has-[input:focus-visible,textarea:focus-visible]:has-[input[aria-invalid],textarea[aria-invalid]]:ring-destructive/16 has-[textarea]:h-auto has-data-[align=block-end]:h-auto has-data-[align=block-start]:h-auto has-data-[align=block-end]:flex-col has-data-[align=block-start]:flex-col has-[input:focus-visible,textarea:focus-visible]:border-ring has-[input[aria-invalid],textarea[aria-invalid]]:border-destructive/36 has-[input:disabled,textarea:disabled]:opacity-64 has-[input:disabled,textarea:disabled,input:focus-visible,textarea:focus-visible,input[aria-invalid],textarea[aria-invalid]]:shadow-none has-[input:focus-visible,textarea:focus-visible]:ring-[3px] sm:text-sm dark:bg-input/32 dark:bg-clip-border dark:has-[input[aria-invalid],textarea[aria-invalid]]:ring-destructive/24 dark:not-has-[input:disabled,textarea:disabled]:not-has-[input:focus-visible,textarea:focus-visible]:not-has-[input[aria-invalid],textarea[aria-invalid]]:before:shadow-[0_-1px_--theme(--color-white/8%)] has-data-[align=inline-start]:**:[[data-size=sm]_input]:ps-1.5 has-data-[align=inline-end]:**:[[data-size=sm]_input]:pe-1.5 *:[[data-slot=input-control],[data-slot=textarea-control]]:contents *:[[data-slot=input-control],[data-slot=textarea-control]]:before:hidden has-[[data-align=block-start],[data-align=block-end]]:**:[input]:h-auto has-data-[align=inline-start]:**:[input]:ps-2 has-data-[align=inline-end]:**:[input]:pe-2 has-data-[align=block-end]:**:[input]:pt-1.5 has-data-[align=block-start]:**:[input]:pb-1.5 **:[textarea]:min-h-20.5 **:[textarea]:resize-none **:[textarea]:py-[calc(--spacing(3)-1px)] **:[textarea]:max-sm:min-h-23.5 **:[textarea_button]:rounded-[calc(var(--radius-md)-1px)]",
"relative inline-flex w-full min-w-0 items-center rounded-lg border border-input bg-background not-dark:bg-clip-padding text-base shadow-xs/5 ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] not-has-[input:disabled,textarea:disabled]:not-has-[input:focus-visible,textarea:focus-visible]:not-has-[input[aria-invalid],textarea[aria-invalid]]:before:shadow-[0_1px_--theme(--color-black/6%)] has-[input:focus-visible,textarea:focus-visible]:has-[input[aria-invalid],textarea[aria-invalid]]:border-destructive/64 has-[input:focus-visible,textarea:focus-visible]:has-[input[aria-invalid],textarea[aria-invalid]]:ring-destructive/16 has-[textarea]:h-auto has-data-[align=block-end]:h-auto has-data-[align=block-start]:h-auto has-data-[align=block-end]:flex-col has-data-[align=block-start]:flex-col has-[input:focus-visible,textarea:focus-visible]:border-ring has-[input[aria-invalid],textarea[aria-invalid]]:border-destructive/36 has-[input:disabled,textarea:disabled]:opacity-64 has-[input:disabled,textarea:disabled,input:focus-visible,textarea:focus-visible,input[aria-invalid],textarea[aria-invalid]]:shadow-none has-[input:focus-visible,textarea:focus-visible]:ring-[3px] sm:text-sm dark:bg-input/32 dark:has-[input[aria-invalid],textarea[aria-invalid]]:ring-destructive/24 dark:not-has-[input:disabled,textarea:disabled]:not-has-[input:focus-visible,textarea:focus-visible]:not-has-[input[aria-invalid],textarea[aria-invalid]]:before:shadow-[0_-1px_--theme(--color-white/6%)] has-data-[align=inline-start]:**:[[data-size=sm]_input]:ps-1.5 has-data-[align=inline-end]:**:[[data-size=sm]_input]:pe-1.5 *:[[data-slot=input-control],[data-slot=textarea-control]]:contents *:[[data-slot=input-control],[data-slot=textarea-control]]:before:hidden has-[[data-align=block-start],[data-align=block-end]]:**:[input]:h-auto has-data-[align=inline-start]:**:[input]:ps-2 has-data-[align=inline-end]:**:[input]:pe-2 has-data-[align=block-end]:**:[input]:pt-1.5 has-data-[align=block-start]:**:[input]:pb-1.5 **:[textarea]:min-h-20.5 **:[textarea]:resize-none **:[textarea]:py-[calc(--spacing(3)-1px)] **:[textarea]:max-sm:min-h-23.5 **:[textarea_button]:rounded-[calc(var(--radius-md)-1px)]",
className,
)}
data-slot="input-group"
@@ -22,7 +22,7 @@ function InputGroup({ className, ...props }: React.ComponentProps<"div">) {
}
const inputGroupAddonVariants = cva(
"[&_svg]:-mx-0.5 not-has-[button]:**:[svg]:not([class*='opacity-'])]:opacity-80 flex h-auto cursor-text select-none items-center justify-center gap-2 [&>kbd]:rounded-[calc(var(--radius)-5px)] in-[[data-slot=input-group]:has([data-slot=input-control],[data-slot=textarea-control])]:[&_svg:not([class*='size-'])]:size-4.5 sm:in-[[data-slot=input-group]:has([data-slot=input-control],[data-slot=textarea-control])]:[&_svg:not([class*='size-'])]:size-4",
"[&_svg]:-mx-0.5 flex h-auto cursor-text select-none items-center justify-center gap-2 leading-none [&>kbd]:rounded-[calc(var(--radius)-5px)] in-[[data-slot=input-group]:has([data-slot=input-control],[data-slot=textarea-control])]:[&_svg:not([class*='size-'])]:size-4.5 sm:in-[[data-slot=input-group]:has([data-slot=input-control],[data-slot=textarea-control])]:[&_svg:not([class*='size-'])]:size-4 not-has-[button]:**:[svg:not([class*='opacity-'])]:opacity-80",
{
defaultVariants: {
align: "inline-start",
@@ -54,7 +54,9 @@ function InputGroupAddon({
data-slot="input-group-addon"
onMouseDown={(e) => {
const target = e.target as HTMLElement;
const isInteractive = target.closest("button, a");
const isInteractive = target.closest(
"button, a, input, select, textarea, [role='button'], [role='combobox'], [role='listbox'], [data-slot='select-trigger']",
);
if (isInteractive) return;
e.preventDefault();
const parent = e.currentTarget.parentElement;
@@ -74,7 +76,7 @@ function InputGroupText({ className, ...props }: React.ComponentProps<"span">) {
return (
<span
className={cn(
"[&_svg]:-mx-0.5 line-clamp-1 flex items-center gap-2 text-muted-foreground in-[[data-slot=input-group]:has([data-slot=input-control],[data-slot=textarea-control])]:[&_svg:not([class*='size-'])]:size-4.5 sm:in-[[data-slot=input-group]:has([data-slot=input-control],[data-slot=textarea-control])]:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none",
"[&_svg]:-mx-0.5 line-clamp-1 flex items-center gap-2 text-muted-foreground leading-none in-[[data-slot=input-group]:has([data-slot=input-control],[data-slot=textarea-control])]:[&_svg:not([class*='size-'])]:size-4.5 sm:in-[[data-slot=input-group]:has([data-slot=input-control],[data-slot=textarea-control])]:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none",
className,
)}
{...props}
+29 -16
View File
@@ -11,41 +11,54 @@ type InputProps = Omit<
> & {
size?: "sm" | "default" | "lg" | number;
unstyled?: boolean;
nativeInput?: boolean;
};
function Input({
className,
size = "default",
unstyled = false,
nativeInput = false,
...props
}: InputProps) {
const inputClassName = cn(
"h-8.5 w-full min-w-0 rounded-[inherit] px-[calc(--spacing(3)-1px)] leading-8.5 outline-none placeholder:text-muted-foreground/72 sm:h-7.5 sm:leading-7.5",
size === "sm" &&
"h-7.5 px-[calc(--spacing(2.5)-1px)] leading-7.5 sm:h-6.5 sm:leading-6.5",
size === "lg" && "h-9.5 leading-9.5 sm:h-8.5 sm:leading-8.5",
props.type === "search" &&
"[&::-webkit-search-cancel-button]:appearance-none [&::-webkit-search-decoration]:appearance-none [&::-webkit-search-results-button]:appearance-none [&::-webkit-search-results-decoration]:appearance-none",
props.type === "file" &&
"text-muted-foreground file:me-3 file:bg-transparent file:font-medium file:text-foreground file:text-sm",
);
return (
<span
className={
cn(
!unstyled &&
"relative inline-flex w-full rounded-lg border border-input bg-background bg-clip-padding text-base shadow-xs ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] not-has-disabled:not-has-focus-visible:not-has-aria-invalid:before:shadow-[0_1px_--theme(--color-black/4%)] has-focus-visible:has-aria-invalid:border-destructive/64 has-focus-visible:has-aria-invalid:ring-destructive/16 has-aria-invalid:border-destructive/36 has-focus-visible:border-ring has-disabled:opacity-64 has-[:disabled,:focus-visible,[aria-invalid]]:shadow-none has-focus-visible:ring-[3px] sm:text-sm dark:bg-input/32 dark:not-in-data-[slot=group]:bg-clip-border dark:has-aria-invalid:ring-destructive/24 dark:not-has-disabled:not-has-focus-visible:not-has-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/8%)]",
"relative inline-flex w-full rounded-lg border border-input bg-background not-dark:bg-clip-padding text-base shadow-xs/5 ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] not-has-disabled:not-has-focus-visible:not-has-aria-invalid:before:shadow-[0_1px_--theme(--color-black/6%)] has-focus-visible:has-aria-invalid:border-destructive/64 has-focus-visible:has-aria-invalid:ring-destructive/16 has-aria-invalid:border-destructive/36 has-focus-visible:border-ring has-disabled:opacity-64 has-[:disabled,:focus-visible,[aria-invalid]]:shadow-none has-focus-visible:ring-[3px] sm:text-sm dark:bg-input/32 dark:has-aria-invalid:ring-destructive/24 dark:not-has-disabled:not-has-focus-visible:not-has-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/6%)]",
className,
) || undefined
}
data-size={size}
data-slot="input-control"
>
<InputPrimitive
className={cn(
"h-8.5 w-full min-w-0 rounded-[inherit] px-[calc(--spacing(3)-1px)] leading-8.5 outline-none placeholder:text-muted-foreground/72 sm:h-7.5 sm:leading-7.5",
size === "sm" &&
"h-7.5 px-[calc(--spacing(2.5)-1px)] leading-7.5 sm:h-6.5 sm:leading-6.5",
size === "lg" && "h-9.5 leading-9.5 sm:h-8.5 sm:leading-8.5",
props.type === "search" &&
"[&::-webkit-search-cancel-button]:appearance-none [&::-webkit-search-decoration]:appearance-none [&::-webkit-search-results-button]:appearance-none [&::-webkit-search-results-decoration]:appearance-none",
props.type === "file" &&
"text-muted-foreground file:me-3 file:bg-transparent file:font-medium file:text-foreground file:text-sm",
)}
data-slot="input"
size={typeof size === "number" ? size : undefined}
{...props}
/>
{nativeInput ? (
<input
className={inputClassName}
data-slot="input"
size={typeof size === "number" ? size : undefined}
{...props}
/>
) : (
<InputPrimitive
className={inputClassName}
data-slot="input"
size={typeof size === "number" ? size : undefined}
{...props}
/>
)}
</span>
);
}
@@ -1,3 +1,5 @@
"use client";
import { mergeProps } from "@base-ui/react/merge-props";
import { useRender } from "@base-ui/react/use-render";
+47 -23
View File
@@ -5,6 +5,8 @@ import { ChevronRightIcon } from "lucide-react";
import type * as React from "react";
import { cn } from "@coss/ui/lib/utils";
const MenuCreateHandle = MenuPrimitive.createHandle;
const Menu = MenuPrimitive.Root;
const MenuPortal = MenuPrimitive.Portal;
@@ -39,7 +41,7 @@ function MenuPopup({
>
<MenuPrimitive.Popup
className={cn(
"relative flex not-[class*='w-']:min-w-32 origin-(--transform-origin) rounded-lg border bg-popover bg-clip-padding shadow-lg outline-none transition-[scale,opacity] before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] focus:outline-none has-data-starting-style:scale-98 has-data-starting-style:opacity-0 dark:bg-clip-border dark:before:shadow-[0_-1px_--theme(--color-white/8%)]",
"relative flex not-[class*='w-']:min-w-32 origin-(--transform-origin) rounded-lg border bg-popover not-dark:bg-clip-padding shadow-lg/5 outline-none before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-[0_1px_--theme(--color-black/6%)] focus:outline-none dark:before:shadow-[0_-1px_--theme(--color-white/6%)]",
className,
)}
data-slot="menu-popup"
@@ -70,7 +72,7 @@ function MenuItem({
return (
<MenuPrimitive.Item
className={cn(
"[&_svg]:-mx-0.5 flex min-h-8 cursor-default select-none items-center gap-2 rounded-sm px-2 py-1 text-base outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-inset:ps-8 data-[variant=destructive]:text-destructive-foreground data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&_svg:not([class*='opacity-'])]:opacity-80 [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
"[&>svg]:-mx-0.5 flex min-h-8 cursor-default select-none items-center gap-2 rounded-sm px-2 py-1 text-base outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-inset:ps-8 data-[variant=destructive]:text-destructive-foreground data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&>svg:not([class*='opacity-'])]:opacity-80 [&>svg:not([class*='size-'])]:size-4.5 sm:[&>svg:not([class*='size-'])]:size-4 [&>svg]:pointer-events-none [&>svg]:shrink-0",
className,
)}
data-inset={inset}
@@ -85,34 +87,54 @@ function MenuCheckboxItem({
className,
children,
checked,
variant = "default",
...props
}: MenuPrimitive.CheckboxItem.Props) {
}: MenuPrimitive.CheckboxItem.Props & {
variant?: "default" | "switch";
}) {
return (
<MenuPrimitive.CheckboxItem
checked={checked}
className={cn(
"grid min-h-8 in-data-[side=none]:min-w-[calc(var(--anchor-width)+1.25rem)] cursor-default grid-cols-[1rem_1fr] items-center gap-2 rounded-sm py-1 ps-2 pe-4 text-base outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
"grid min-h-8 in-data-[side=none]:min-w-[calc(var(--anchor-width)+1.25rem)] cursor-default items-center gap-2 rounded-sm py-1 ps-2 text-base outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
variant === "switch"
? "grid-cols-[1fr_auto] gap-4 pe-1.5"
: "grid-cols-[1rem_1fr] pe-4",
className,
)}
data-slot="menu-checkbox-item"
{...props}
>
<MenuPrimitive.CheckboxItemIndicator className="col-start-1">
<svg
fill="none"
height="24"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M5.252 12.7 10.2 18.63 18.748 5.37" />
</svg>
</MenuPrimitive.CheckboxItemIndicator>
<span className="col-start-2">{children}</span>
{variant === "switch" ? (
<>
<span className="col-start-1">{children}</span>
<MenuPrimitive.CheckboxItemIndicator
className="inset-shadow-[0_1px_--theme(--color-black/6%)] inline-flex h-[calc(var(--thumb-size)+2px)] w-[calc(var(--thumb-size)*2-2px)] shrink-0 items-center rounded-full p-px outline-none transition-[background-color,box-shadow] duration-200 [--thumb-size:--spacing(4)] focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background data-checked:bg-primary data-unchecked:bg-input data-disabled:opacity-64 sm:[--thumb-size:--spacing(3)]"
keepMounted
>
<span className="pointer-events-none block aspect-square h-full in-[[data-slot=menu-checkbox-item][data-checked]]:origin-[var(--thumb-size)_50%] origin-left in-[[data-slot=menu-checkbox-item][data-checked]]:translate-x-[calc(var(--thumb-size)-4px)] in-[[data-slot=menu-checkbox-item]:active]:not-data-disabled:scale-x-110 in-[[data-slot=menu-checkbox-item]:active]:rounded-[var(--thumb-size)/calc(var(--thumb-size)*1.10)] rounded-(--thumb-size) bg-background shadow-sm/5 will-change-transform [transition:translate_.15s,border-radius_.15s,scale_.1s_.1s,transform-origin_.15s]" />
</MenuPrimitive.CheckboxItemIndicator>
</>
) : (
<>
<MenuPrimitive.CheckboxItemIndicator className="col-start-1">
<svg
fill="none"
height="24"
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
viewBox="0 0 24 24"
width="24"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M5.252 12.7 10.2 18.63 18.748 5.37" />
</svg>
</MenuPrimitive.CheckboxItemIndicator>
<span className="col-start-2">{children}</span>
</>
)}
</MenuPrimitive.CheckboxItem>
);
}
@@ -185,11 +207,11 @@ function MenuSeparator({ className, ...props }: MenuPrimitive.Separator.Props) {
);
}
function MenuShortcut({ className, ...props }: React.ComponentProps<"span">) {
function MenuShortcut({ className, ...props }: React.ComponentProps<"kbd">) {
return (
<span
<kbd
className={cn(
"ms-auto font-medium text-muted-foreground/72 text-xs tracking-widest",
"ms-auto font-medium font-sans text-muted-foreground/72 text-xs tracking-widest",
className,
)}
data-slot="menu-shortcut"
@@ -253,6 +275,8 @@ function MenuSubPopup({
}
export {
MenuCreateHandle,
MenuCreateHandle as DropdownMenuCreateHandle,
Menu,
Menu as DropdownMenu,
MenuPortal,
@@ -42,7 +42,7 @@ function NumberFieldGroup({
return (
<NumberFieldPrimitive.Group
className={cn(
"relative flex w-full justify-between rounded-lg border border-input bg-background bg-clip-padding text-base shadow-xs ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] not-data-disabled:not-focus-within:not-aria-invalid:before:shadow-[0_1px_--theme(--color-black/4%)] focus-within:border-ring focus-within:ring-[3px] has-aria-invalid:border-destructive/36 focus-within:has-aria-invalid:border-destructive/64 focus-within:has-aria-invalid:ring-destructive/48 data-disabled:pointer-events-none data-disabled:opacity-64 sm:text-sm dark:bg-input/32 dark:not-in-data-[slot=group]:bg-clip-border dark:has-aria-invalid:ring-destructive/24 dark:not-data-disabled:not-focus-within:not-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/8%)] [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0 [[data-disabled],:focus-within,[aria-invalid]]:shadow-none",
"relative flex w-full justify-between rounded-lg border border-input bg-background not-dark:bg-clip-padding text-base shadow-xs/5 ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] not-data-disabled:not-focus-within:not-aria-invalid:before:shadow-[0_1px_--theme(--color-black/6%)] focus-within:border-ring focus-within:ring-[3px] has-aria-invalid:border-destructive/36 focus-within:has-aria-invalid:border-destructive/64 focus-within:has-aria-invalid:ring-destructive/48 data-disabled:pointer-events-none data-disabled:opacity-64 sm:text-sm dark:bg-input/32 dark:has-aria-invalid:ring-destructive/24 dark:not-data-disabled:not-focus-within:not-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/6%)] [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0 [[data-disabled],:focus-within,[aria-invalid]]:shadow-none",
className,
)}
data-slot="number-field-group"
@@ -1,3 +1,5 @@
"use client";
import { mergeProps } from "@base-ui/react/merge-props";
import { useRender } from "@base-ui/react/use-render";
import {
+2 -2
View File
@@ -40,9 +40,9 @@ function PopoverPopup({
>
<PopoverPrimitive.Popup
className={cn(
"relative flex h-(--popup-height,auto) w-(--popup-width,auto) origin-(--transform-origin) rounded-lg border bg-popover bg-clip-padding text-popover-foreground shadow-lg transition-[width,height,scale,opacity] before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] data-starting-style:scale-98 data-starting-style:opacity-0 dark:bg-clip-border dark:before:shadow-[0_-1px_--theme(--color-white/8%)]",
"relative flex h-(--popup-height,auto) w-(--popup-width,auto) origin-(--transform-origin) rounded-lg border bg-popover not-dark:bg-clip-padding text-popover-foreground shadow-lg/5 transition-[width,height,scale,opacity] before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-[0_1px_--theme(--color-black/6%)] data-starting-style:scale-98 data-starting-style:opacity-0 dark:before:shadow-[0_-1px_--theme(--color-white/6%)]",
tooltipStyle &&
"w-fit text-balance rounded-md text-xs shadow-black/5 shadow-md before:rounded-[calc(var(--radius-md)-1px)]",
"w-fit text-balance rounded-md text-xs shadow-md/5 before:rounded-[calc(var(--radius-md)-1px)]",
className,
)}
data-slot="popover-popup"
@@ -32,7 +32,7 @@ function PreviewCardPopup({
>
<PreviewCardPrimitive.Popup
className={cn(
"relative flex w-64 origin-(--transform-origin) text-balance rounded-lg border bg-popover bg-clip-padding p-4 text-popover-foreground text-sm shadow-lg transition-[scale,opacity] before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] data-ending-style:scale-98 data-starting-style:scale-98 data-ending-style:opacity-0 data-starting-style:opacity-0 dark:bg-clip-border dark:before:shadow-[0_-1px_--theme(--color-white/8%)]",
"relative flex w-64 origin-(--transform-origin) text-balance rounded-lg border bg-popover not-dark:bg-clip-padding p-4 text-popover-foreground text-sm shadow-lg/5 transition-[scale,opacity] before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-[0_1px_--theme(--color-black/6%)] data-ending-style:scale-98 data-starting-style:scale-98 data-ending-style:opacity-0 data-starting-style:opacity-0 dark:before:shadow-[0_-1px_--theme(--color-white/6%)]",
className,
)}
data-slot="preview-card-content"
@@ -19,7 +19,7 @@ function Radio({ className, ...props }: RadioPrimitive.Root.Props) {
return (
<RadioPrimitive.Root
className={cn(
"relative inline-flex size-4.5 shrink-0 items-center justify-center rounded-full border border-input bg-background bg-clip-padding shadow-xs outline-none transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-full not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_1px_--theme(--color-black/4%)] focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background aria-invalid:border-destructive/36 focus-visible:aria-invalid:border-destructive/64 focus-visible:aria-invalid:ring-destructive/48 data-disabled:opacity-64 sm:size-4 dark:not-data-checked:bg-input/32 dark:bg-clip-border dark:aria-invalid:ring-destructive/24 dark:not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/8%)] [[data-disabled],[data-checked],[aria-invalid]]:shadow-none",
"relative inline-flex size-4.5 shrink-0 items-center justify-center rounded-full border border-input bg-background not-dark:bg-clip-padding shadow-xs/5 outline-none transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-full not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_1px_--theme(--color-black/6%)] focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background aria-invalid:border-destructive/36 focus-visible:aria-invalid:border-destructive/64 focus-visible:aria-invalid:ring-destructive/48 data-disabled:opacity-64 sm:size-4 dark:not-data-checked:bg-input/32 dark:aria-invalid:ring-destructive/24 dark:not-data-disabled:not-data-checked:not-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/6%)] [[data-disabled],[data-checked],[aria-invalid]]:shadow-none",
className,
)}
data-slot="radio"
@@ -21,7 +21,7 @@ function ScrollArea({
>
<ScrollAreaPrimitive.Viewport
className={cn(
"h-full overscroll-contain rounded-[inherit] outline-none transition-shadows focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background",
"h-full rounded-[inherit] outline-none transition-shadows focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background data-has-overflow-x:overscroll-x-contain",
scrollFade &&
"mask-t-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-start)))] mask-b-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-end)))] mask-l-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-start)))] mask-r-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-end)))] [--fade-size:1.5rem]",
scrollbarGutter &&
+4 -4
View File
@@ -22,7 +22,7 @@ function SelectTrigger({
return (
<SelectPrimitive.Trigger
className={cn(
"relative inline-flex min-h-9 w-full min-w-36 select-none items-center justify-between gap-2 rounded-lg border border-input bg-background bg-clip-padding px-[calc(--spacing(3)-1px)] text-left text-base shadow-xs outline-none ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] not-data-disabled:not-focus-visible:not-aria-invalid:not-data-pressed:before:shadow-[0_1px_--theme(--color-black/4%)] pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 focus-visible:border-ring focus-visible:ring-[3px] aria-invalid:border-destructive/36 focus-visible:aria-invalid:border-destructive/64 focus-visible:aria-invalid:ring-destructive/16 data-disabled:pointer-events-none data-disabled:opacity-64 sm:min-h-8 sm:text-sm dark:bg-input/32 dark:not-in-data-[slot=group]:bg-clip-border dark:aria-invalid:ring-destructive/24 dark:not-data-disabled:not-focus-visible:not-aria-invalid:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/8%)] [&_svg:not([class*='opacity-'])]:opacity-80 [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0 [[data-disabled],:focus-visible,[aria-invalid],[data-pressed]]:shadow-none",
"relative inline-flex min-h-9 w-full min-w-36 select-none items-center justify-center gap-2 rounded-lg border border-input bg-background not-dark:bg-clip-padding px-[calc(--spacing(3)-1px)] text-left text-base shadow-xs/5 outline-none ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] not-data-disabled:not-focus-visible:not-aria-invalid:not-data-pressed:before:shadow-[0_1px_--theme(--color-black/4%)] pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 focus-visible:border-ring focus-visible:ring-[3px] aria-invalid:border-destructive/36 focus-visible:aria-invalid:border-destructive/64 focus-visible:aria-invalid:ring-destructive/16 data-disabled:pointer-events-none data-disabled:opacity-64 sm:min-h-8 sm:text-sm dark:bg-input/32 dark:aria-invalid:ring-destructive/24 dark:not-data-disabled:not-focus-visible:not-aria-invalid:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/6%)] [&_svg:not([class*='opacity-'])]:opacity-80 [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0 [[data-disabled],:focus-visible,[aria-invalid],[data-pressed]]:shadow-none",
size === "sm" &&
"min-h-8 gap-1.5 px-[calc(--spacing(2.5)-1px)] sm:min-h-7",
size === "lg" && "min-h-10 sm:min-h-9",
@@ -71,7 +71,7 @@ function SelectPopup({
sideOffset={sideOffset}
>
<SelectPrimitive.Popup
className="origin-(--transform-origin) transition-[scale,opacity] has-data-[side=none]:scale-100 has-data-starting-style:scale-98 has-data-starting-style:opacity-0 has-data-[side=none]:transition-none"
className="origin-(--transform-origin)"
data-slot="select-popup"
{...props}
>
@@ -81,7 +81,7 @@ function SelectPopup({
>
<ChevronUpIcon className="relative size-4.5 sm:size-4" />
</SelectPrimitive.ScrollUpArrow>
<span className="relative block h-full rounded-lg border bg-popover bg-clip-padding before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-lg dark:not-in-data-[slot=group]:bg-clip-border">
<div className="relative h-full rounded-lg border bg-popover not-dark:bg-clip-padding shadow-lg/5 before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-[0_1px_--theme(--color-black/6%)] dark:before:shadow-[0_-1px_--theme(--color-white/6%)]">
<SelectPrimitive.List
className={cn(
"max-h-(--available-height) min-w-(--anchor-width) overflow-y-auto p-1",
@@ -91,7 +91,7 @@ function SelectPopup({
>
{children}
</SelectPrimitive.List>
</span>
</div>
<SelectPrimitive.ScrollDownArrow
className="bottom-0 z-50 flex h-6 w-full cursor-default items-center justify-center before:pointer-events-none before:absolute before:inset-x-px before:bottom-px before:h-[200%] before:rounded-b-[calc(var(--radius-lg)-1px)] before:bg-linear-to-t before:from-50% before:from-popover"
data-slot="select-scroll-down-arrow"
@@ -10,7 +10,7 @@ function Separator({
return (
<SeparatorPrimitive
className={cn(
"shrink-0 bg-border data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-px data-[orientation=vertical]:not-[[class^='h-']]:not-[[class*='_h-']]:self-stretch",
"shrink-0 bg-input data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-px data-[orientation=vertical]:not-[[class^='h-']]:not-[[class*='_h-']]:self-stretch",
className,
)}
data-slot="separator"
+6 -3
View File
@@ -74,7 +74,7 @@ function SheetPopup({
<SheetViewport inset={inset} side={side}>
<SheetPrimitive.Popup
className={cn(
"relative flex max-h-full min-h-0 w-full min-w-0 flex-col bg-popover bg-clip-padding text-popover-foreground shadow-lg transition-[opacity,translate] duration-200 ease-in-out will-change-transform before:pointer-events-none before:absolute before:inset-0 before:shadow-[0_1px_--theme(--color-black/4%)] data-ending-style:opacity-0 data-starting-style:opacity-0 max-sm:before:hidden dark:bg-clip-border dark:before:shadow-[0_-1px_--theme(--color-white/8%)]",
"relative flex max-h-full min-h-0 w-full min-w-0 flex-col bg-popover not-dark:bg-clip-padding text-popover-foreground shadow-lg/5 transition-[opacity,translate] duration-200 ease-in-out will-change-transform before:pointer-events-none before:absolute before:inset-0 before:shadow-[0_1px_--theme(--color-black/6%)] data-ending-style:opacity-0 data-starting-style:opacity-0 max-sm:before:hidden dark:before:shadow-[0_-1px_--theme(--color-white/6%)]",
side === "bottom" &&
"row-start-2 border-t data-ending-style:translate-y-8 data-starting-style:translate-y-8",
side === "top" &&
@@ -130,7 +130,7 @@ function SheetFooter({
<div
className={cn(
"flex flex-col-reverse gap-2 px-6 sm:flex-row sm:justify-end",
variant === "default" && "border-t bg-muted/50 py-4",
variant === "default" && "border-t bg-muted/72 py-4",
variant === "bare" &&
"in-[[data-slot=sheet-popup]:has([data-slot=sheet-panel])]:pt-3 pt-4 pb-6",
className,
@@ -144,7 +144,10 @@ function SheetFooter({
function SheetTitle({ className, ...props }: SheetPrimitive.Title.Props) {
return (
<SheetPrimitive.Title
className={cn("font-heading text-xl leading-none", className)}
className={cn(
"font-heading font-semibold text-xl leading-none",
className,
)}
data-slot="sheet-title"
{...props}
/>
+17 -11
View File
@@ -10,6 +10,7 @@ import { useIsMobile } from "@coss/ui/hooks/use-mobile";
import { cn } from "@coss/ui/lib/utils";
import { Button } from "@coss/ui/components/button";
import { Input } from "@coss/ui/components/input";
import { ScrollArea } from "@coss/ui/components/scroll-area";
import { Separator } from "@coss/ui/components/separator";
import {
Sheet,
@@ -245,7 +246,7 @@ function Sidebar({
{...props}
>
<div
className="flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow-sm"
className="flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow-sm/5"
data-sidebar="sidebar"
data-slot="sidebar-inner"
>
@@ -313,7 +314,7 @@ function SidebarInset({ className, ...props }: React.ComponentProps<"main">) {
<main
className={cn(
"relative flex w-full flex-1 flex-col bg-background",
"md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ms-2 md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ms-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm",
"md:peer-data-[variant=inset]:peer-data-[state=collapsed]:ms-2 md:peer-data-[variant=inset]:m-2 md:peer-data-[variant=inset]:ms-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow-sm/5",
className,
)}
data-slot="sidebar-inset"
@@ -374,15 +375,20 @@ function SidebarSeparator({
function SidebarContent({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
className={cn(
"flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
className,
)}
data-sidebar="content"
data-slot="sidebar-content"
{...props}
/>
<ScrollArea
className="**:data-[slot=scroll-area-scrollbar]:hidden"
scrollFade
>
<div
className={cn(
"flex min-h-0 flex-1 flex-col gap-2 group-data-[collapsible=icon]:overflow-hidden",
className,
)}
data-sidebar="content"
data-slot="sidebar-content"
{...props}
/>
</ScrollArea>
);
}
+1 -1
View File
@@ -52,7 +52,7 @@ function Slider({
/>
{Array.from({ length: _values.length }, (_, index) => (
<SliderPrimitive.Thumb
className="block size-5 shrink-0 select-none rounded-full border border-input bg-white bg-clip-padding shadow-xs outline-none transition-shadow before:absolute before:inset-0 before:rounded-full before:shadow-[0_1px_--theme(--color-black/4%)] focus-visible:ring-[3px] focus-visible:ring-ring/24 has-focus-visible:ring-[3px] has-focus-visible:ring-ring/24 data-dragging:ring-[3px] data-dragging:ring-ring/24 sm:size-4 dark:border-background dark:bg-clip-border dark:data-dragging:ring-ring/48 dark:focus-visible:ring-ring/48 [:focus-visible,[data-dragging]]:shadow-none"
className="block size-5 shrink-0 select-none rounded-full border border-input bg-white not-dark:bg-clip-padding shadow-xs/5 outline-none transition-[box-shadow,scale] before:absolute before:inset-0 before:rounded-full before:shadow-[0_1px_--theme(--color-black/6%)] focus-visible:ring-[3px] focus-visible:ring-ring/24 has-focus-visible:ring-[3px] has-focus-visible:ring-ring/24 data-dragging:scale-120 data-dragging:ring-[3px] data-dragging:ring-ring/24 sm:size-4 dark:border-background dark:data-dragging:ring-ring/48 dark:focus-visible:ring-ring/48 [:focus-visible,[data-dragging]]:shadow-none"
data-slot="slider-thumb"
key={String(index)}
/>
+4 -2
View File
@@ -1,8 +1,10 @@
import { Loader2Icon } from "lucide-react";
import { cn } from "@coss/ui/lib/utils";
function Spinner({ className, ...props }: React.ComponentProps<typeof Loader2Icon>) {
function Spinner({
className,
...props
}: React.ComponentProps<typeof Loader2Icon>) {
return (
<Loader2Icon
aria-label="Loading"
+2 -2
View File
@@ -8,7 +8,7 @@ function Switch({ className, ...props }: SwitchPrimitive.Root.Props) {
return (
<SwitchPrimitive.Root
className={cn(
"group/switch inset-shadow-[0_1px_--theme(--color-black/4%)] inline-flex h-5.5 w-9.5 shrink-0 items-center rounded-full p-px outline-none transition-all focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background data-checked:bg-primary data-unchecked:bg-input data-disabled:opacity-64 sm:h-4.5 sm:w-7.5",
"inset-shadow-[0_1px_--theme(--color-black/6%)] inline-flex h-[calc(var(--thumb-size)+2px)] w-[calc(var(--thumb-size)*2-2px)] shrink-0 items-center rounded-full p-px outline-none transition-[background-color,box-shadow] duration-200 [--thumb-size:--spacing(5)] focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background data-checked:bg-primary data-unchecked:bg-input data-disabled:opacity-64 sm:[--thumb-size:--spacing(4)]",
className,
)}
data-slot="switch"
@@ -16,7 +16,7 @@ function Switch({ className, ...props }: SwitchPrimitive.Root.Props) {
>
<SwitchPrimitive.Thumb
className={cn(
"pointer-events-none block size-5 rounded-full bg-background shadow-sm transition-[translate,width] group-active/switch:not-data-disabled:w-5.5 data-checked:translate-x-4 data-unchecked:translate-x-0 data-checked:group-active/switch:translate-x-3.5 sm:size-4 sm:data-checked:translate-x-3 sm:group-active/switch:not-data-disabled:w-4.5 sm:data-checked:group-active/switch:translate-x-2.5",
"pointer-events-none block aspect-square h-full origin-left in-[[role=switch]:active,[data-slot=label]:active]:not-data-disabled:scale-x-110 in-[[role=switch]:active,[data-slot=label]:active]:rounded-[var(--thumb-size)/calc(var(--thumb-size)*1.1)] rounded-(--thumb-size) bg-background shadow-sm/5 will-change-transform [transition:translate_.15s,border-radius_.15s,scale_.1s_.1s,transform-origin_.15s] data-checked:origin-[var(--thumb-size)_50%] data-checked:translate-x-[calc(var(--thumb-size)-4px)]",
)}
data-slot="switch-thumb"
/>
+5 -5
View File
@@ -37,7 +37,7 @@ function TableBody({ className, ...props }: React.ComponentProps<"tbody">) {
return (
<tbody
className={cn(
"relative in-data-[slot=frame]:rounded-xl in-data-[slot=frame]:shadow-xs before:pointer-events-none before:absolute before:inset-px not-in-data-[slot=frame]:before:hidden before:rounded-[calc(var(--radius-xl)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] dark:bg-clip-border dark:before:shadow-[0_-1px_--theme(--color-white/8%)] [&_tr:last-child]:border-0 in-data-[slot=frame]:*:[tr]:border-0 in-data-[slot=frame]:*:[tr]:*:[td]:border-b in-data-[slot=frame]:*:[tr]:*:[td]:bg-background in-data-[slot=frame]:*:[tr]:*:[td]:bg-clip-padding in-data-[slot=frame]:*:[tr]:first:*:[td]:first:rounded-ss-xl in-data-[slot=frame]:*:[tr]:*:[td]:first:border-s in-data-[slot=frame]:*:[tr]:first:*:[td]:border-t in-data-[slot=frame]:*:[tr]:last:*:[td]:last:rounded-ee-xl in-data-[slot=frame]:*:[tr]:*:[td]:last:border-e in-data-[slot=frame]:*:[tr]:first:*:[td]:last:rounded-se-xl in-data-[slot=frame]:*:[tr]:last:*:[td]:first:rounded-es-xl in-data-[slot=frame]:*:[tr]:hover:*:[td]:bg-transparent in-data-[slot=frame]:*:[tr]:data-[state=selected]:*:[td]:bg-muted/50",
"relative in-data-[slot=frame]:rounded-xl in-data-[slot=frame]:shadow-xs/5 before:pointer-events-none before:absolute before:inset-px not-in-data-[slot=frame]:before:hidden before:rounded-[calc(var(--radius-xl)-1px)] before:shadow-[0_1px_--theme(--color-black/6%)] dark:before:shadow-[0_-1px_--theme(--color-white/8%)] [&_tr:last-child]:border-0 in-data-[slot=frame]:*:[tr]:border-0 in-data-[slot=frame]:*:[tr]:*:[td]:border-b in-data-[slot=frame]:*:[tr]:*:[td]:bg-background in-data-[slot=frame]:*:[tr]:*:[td]:bg-clip-padding in-data-[slot=frame]:*:[tr]:first:*:[td]:first:rounded-ss-xl in-data-[slot=frame]:*:[tr]:*:[td]:first:border-s in-data-[slot=frame]:*:[tr]:first:*:[td]:border-t in-data-[slot=frame]:*:[tr]:last:*:[td]:last:rounded-ee-xl in-data-[slot=frame]:*:[tr]:*:[td]:last:border-e in-data-[slot=frame]:*:[tr]:first:*:[td]:last:rounded-se-xl in-data-[slot=frame]:*:[tr]:last:*:[td]:first:rounded-es-xl in-data-[slot=frame]:*:[tr]:hover:*:[td]:bg-transparent in-data-[slot=frame]:*:[tr]:data-[state=selected]:*:[td]:bg-muted/72",
className,
)}
data-slot="table-body"
@@ -50,7 +50,7 @@ function TableFooter({ className, ...props }: React.ComponentProps<"tfoot">) {
return (
<tfoot
className={cn(
"border-t in-data-[slot=frame]:border-none bg-muted/50 in-data-[slot=frame]:bg-transparent font-medium [&>tr]:last:border-b-0 in-data-[slot=frame]:*:[tr]:hover:bg-transparent",
"border-t in-data-[slot=frame]:border-none bg-muted/72 in-data-[slot=frame]:bg-transparent font-medium [&>tr]:last:border-b-0 in-data-[slot=frame]:*:[tr]:hover:bg-transparent",
className,
)}
data-slot="table-footer"
@@ -63,7 +63,7 @@ function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
return (
<tr
className={cn(
"border-b transition-colors hover:bg-muted/50 in-data-[slot=frame]:hover:bg-transparent data-[state=selected]:bg-muted/50 in-data-[slot=frame]:data-[state=selected]:bg-transparent",
"border-b transition-colors hover:bg-muted/72 in-data-[slot=frame]:hover:bg-transparent data-[state=selected]:bg-muted/72 in-data-[slot=frame]:data-[state=selected]:bg-transparent",
className,
)}
data-slot="table-row"
@@ -76,7 +76,7 @@ function TableHead({ className, ...props }: React.ComponentProps<"th">) {
return (
<th
className={cn(
"h-10 whitespace-nowrap px-2 text-left align-middle font-medium text-muted-foreground has-[[role=checkbox]]:w-px has-[[role=checkbox]]:pe-0 *:[[role=checkbox]]:translate-y-0.5",
"h-10 whitespace-nowrap px-2.5 text-left align-middle font-medium text-muted-foreground leading-none has-[[role=checkbox]]:w-px has-[[role=checkbox]]:pe-0",
className,
)}
data-slot="table-head"
@@ -89,7 +89,7 @@ function TableCell({ className, ...props }: React.ComponentProps<"td">) {
return (
<td
className={cn(
"whitespace-nowrap p-2 align-middle has-[[role=checkbox]]:pe-0 *:[[role=checkbox]]:translate-y-0.5",
"whitespace-nowrap p-2.5 align-middle leading-none in-data-[slot=frame]:first:p-[calc(--spacing(2.5)-1px)] in-data-[slot=frame]:last:p-[calc(--spacing(2.5)-1px)] has-[[role=checkbox]]:pe-0",
className,
)}
data-slot="table-cell"
+4 -7
View File
@@ -34,7 +34,7 @@ function TabsList({
"data-[orientation=vertical]:flex-col",
variant === "default"
? "rounded-lg bg-muted p-0.5 text-muted-foreground/72"
: "data-[orientation=vertical]:px-1 data-[orientation=horizontal]:py-1 *:data-[slot=tabs-trigger]:hover:bg-accent",
: "data-[orientation=vertical]:px-1 data-[orientation=horizontal]:py-1 *:data-[slot=tabs-tab]:hover:bg-accent",
className,
)}
data-slot="tabs-list"
@@ -46,7 +46,7 @@ function TabsList({
"-translate-y-(--active-tab-bottom) absolute bottom-0 left-0 h-(--active-tab-height) w-(--active-tab-width) translate-x-(--active-tab-left) transition-[width,translate] duration-200 ease-in-out",
variant === "underline"
? "data-[orientation=vertical]:-translate-x-px z-10 bg-primary data-[orientation=horizontal]:h-0.5 data-[orientation=vertical]:w-0.5 data-[orientation=horizontal]:translate-y-px"
: "-z-1 rounded-md bg-background shadow-sm dark:bg-accent",
: "-z-1 rounded-md bg-background shadow-sm/5 dark:bg-input",
)}
data-slot="tab-indicator"
/>
@@ -58,13 +58,10 @@ function TabsTab({ className, ...props }: TabsPrimitive.Tab.Props) {
return (
<TabsPrimitive.Tab
className={cn(
"[&_svg]:-mx-0.5 flex shrink-0 grow cursor-pointer items-center justify-center whitespace-nowrap rounded-md border border-transparent font-medium text-base outline-none transition-[color,background-color,box-shadow] focus-visible:ring-2 focus-visible:ring-ring data-disabled:pointer-events-none data-disabled:opacity-64 sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
"hover:text-muted-foreground data-active:text-foreground",
"h-9 gap-1.5 px-[calc(--spacing(2.5)-1px)] sm:h-8",
"data-[orientation=vertical]:w-full data-[orientation=vertical]:justify-start",
"[&_svg]:-mx-0.5 flex h-9 shrink-0 grow cursor-pointer items-center justify-center gap-1.5 whitespace-nowrap rounded-md border border-transparent px-[calc(--spacing(2.5)-1px)] font-medium text-base outline-none transition-[color,background-color,box-shadow] hover:text-muted-foreground focus-visible:ring-2 focus-visible:ring-ring data-disabled:pointer-events-none data-[orientation=vertical]:w-full data-[orientation=vertical]:justify-start data-active:text-foreground data-disabled:opacity-64 sm:h-8 sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
className,
)}
data-slot="tabs-trigger"
data-slot="tabs-tab"
{...props}
/>
);
+1 -1
View File
@@ -22,7 +22,7 @@ function Textarea({
className={
cn(
!unstyled &&
"relative inline-flex w-full rounded-lg border border-input bg-background bg-clip-padding text-base shadow-xs ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] has-focus-visible:has-aria-invalid:border-destructive/64 has-focus-visible:has-aria-invalid:ring-destructive/16 has-aria-invalid:border-destructive/36 has-focus-visible:border-ring has-disabled:opacity-64 has-[:disabled,:focus-visible,[aria-invalid]]:shadow-none has-focus-visible:ring-[3px] not-has-disabled:has-not-focus-visible:not-has-aria-invalid:before:shadow-[0_1px_--theme(--color-black/4%)] sm:text-sm dark:bg-input/32 dark:bg-clip-border dark:has-aria-invalid:ring-destructive/24 dark:not-has-disabled:has-not-focus-visible:not-has-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/8%)]",
"relative inline-flex w-full rounded-lg border border-input bg-background not-dark:bg-clip-padding text-base shadow-xs/5 ring-ring/24 transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] has-focus-visible:has-aria-invalid:border-destructive/64 has-focus-visible:has-aria-invalid:ring-destructive/16 has-aria-invalid:border-destructive/36 has-focus-visible:border-ring has-disabled:opacity-64 has-[:disabled,:focus-visible,[aria-invalid]]:shadow-none has-focus-visible:ring-[3px] not-has-disabled:has-not-focus-visible:not-has-aria-invalid:before:shadow-[0_1px_--theme(--color-black/6%)] sm:text-sm dark:bg-input/32 dark:has-aria-invalid:ring-destructive/24 dark:not-has-disabled:has-not-focus-visible:not-has-aria-invalid:before:shadow-[0_-1px_--theme(--color-white/6%)]",
className,
) || undefined
}
+4 -4
View File
@@ -76,7 +76,7 @@ function Toasts({ position = "bottom-right" }: { position: ToastPosition }) {
return (
<Toast.Root
className={cn(
"absolute z-[calc(9999-var(--toast-index))] h-(--toast-calc-height) w-full select-none rounded-lg border bg-popover bg-clip-padding text-popover-foreground shadow-lg [transition:transform_.5s_cubic-bezier(.22,1,.36,1),opacity_.5s,height_.15s] before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] dark:bg-clip-border dark:before:shadow-[0_-1px_--theme(--color-white/8%)]",
"absolute z-[calc(9999-var(--toast-index))] h-(--toast-calc-height) w-full select-none rounded-lg border bg-popover not-dark:bg-clip-padding text-popover-foreground shadow-lg/5 [transition:transform_.5s_cubic-bezier(.22,1,.36,1),opacity_.5s,height_.15s] before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-[0_1px_--theme(--color-black/6%)] dark:before:shadow-[0_-1px_--theme(--color-white/6%)]",
// Base positioning using data-position
"data-[position*=right]:right-0 data-[position*=right]:left-auto",
"data-[position*=left]:right-auto data-[position*=left]:left-0",
@@ -206,10 +206,10 @@ function AnchoredToasts() {
>
<Toast.Root
className={cn(
"relative text-balance border bg-popover bg-clip-padding text-popover-foreground text-xs transition-[scale,opacity] before:pointer-events-none before:absolute before:inset-0 before:shadow-[0_1px_--theme(--color-black/4%)] data-ending-style:scale-98 data-starting-style:scale-98 data-ending-style:opacity-0 data-starting-style:opacity-0 dark:bg-clip-border dark:before:shadow-[0_-1px_--theme(--color-white/8%)]",
"relative text-balance border bg-popover not-dark:bg-clip-padding text-popover-foreground text-xs transition-[scale,opacity] before:pointer-events-none before:absolute before:inset-0 before:shadow-[0_1px_--theme(--color-black/6%)] data-ending-style:scale-98 data-starting-style:scale-98 data-ending-style:opacity-0 data-starting-style:opacity-0 dark:before:shadow-[0_-1px_--theme(--color-white/6%)]",
tooltipStyle
? "rounded-md shadow-black/5 shadow-md before:rounded-[calc(var(--radius-md)-1px)]"
: "rounded-lg shadow-lg before:rounded-[calc(var(--radius-lg)-1px)]",
? "rounded-md shadow-md/5 before:rounded-[calc(var(--radius-md)-1px)]"
: "rounded-lg shadow-lg/5 before:rounded-[calc(var(--radius-lg)-1px)]",
)}
data-slot="toast-popup"
toast={toast}
@@ -30,15 +30,15 @@ function ToggleGroup({
return (
<ToggleGroupPrimitive
className={cn(
"flex w-fit *:focus-visible:z-10",
"flex w-fit *:focus-visible:z-10 dark:*:[[data-slot=separator]:has(+[data-slot=toggle]:hover)]:before:bg-input/64 dark:*:[[data-slot=separator]:has(+[data-slot=toggle][data-pressed])]:before:bg-input dark:*:[[data-slot=toggle]:hover+[data-slot=separator]]:before:bg-input/64 dark:*:[[data-slot=toggle][data-pressed]+[data-slot=separator]]:before:bg-input",
orientation === "horizontal"
? "*:pointer-coarse:after:min-w-auto"
: "*:pointer-coarse:after:min-h-auto",
variant === "default"
? "gap-0.5"
: orientation === "horizontal"
? "*:not-first:before:-start-[0.5px] *:not-last:before:-end-[0.5px] *:not-first:rounded-s-none *:not-last:rounded-e-none *:not-first:border-s-0 *:not-last:border-e-0 *:not-first:before:rounded-s-none *:not-last:before:rounded-e-none"
: "*:not-first:before:-top-[0.5px] *:not-last:before:-bottom-[0.5px] flex-col *:not-first:rounded-t-none *:not-last:rounded-b-none *:not-first:border-t-0 *:not-last:border-b-0 *:not-last:before:hidden *:not-first:before:rounded-t-none *:not-last:before:rounded-b-none dark:*:last:before:hidden dark:*:first:before:block",
? "*:not-first:not-data-[slot=separator]:before:-start-[0.5px] *:not-last:not-data-[slot=separator]:before:-end-[0.5px] *:not-first:rounded-s-none *:not-last:rounded-e-none *:not-first:border-s-0 *:not-last:border-e-0 *:not-first:before:rounded-s-none *:not-last:before:rounded-e-none"
: "*:not-first:not-data-[slot=separator]:before:-top-[0.5px] *:not-last:not-data-[slot=separator]:before:-bottom-[0.5px] flex-col *:not-first:rounded-t-none *:not-last:rounded-b-none *:not-first:border-t-0 *:not-last:border-b-0 *:not-first:before:rounded-t-none *:not-last:before:rounded-b-none *:data-[slot=toggle]:not-last:before:hidden dark:*:last:before:hidden dark:*:first:before:block",
className,
)}
data-size={size}
@@ -88,7 +88,14 @@ function ToggleGroupSeparator({
className?: string;
} & React.ComponentProps<typeof Separator>) {
return (
<Separator className={className} orientation={orientation} {...props} />
<Separator
className={cn(
"pointer-events-none relative before:absolute before:inset-0 dark:before:bg-input/32",
className,
)}
orientation={orientation}
{...props}
/>
);
}
+2 -2
View File
@@ -6,7 +6,7 @@ import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@coss/ui/lib/utils";
const toggleVariants = cva(
"[&_svg]:-mx-0.5 relative inline-flex shrink-0 cursor-pointer select-none items-center justify-center gap-2 whitespace-nowrap rounded-lg border font-medium text-base outline-none transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 hover:bg-accent/50 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 data-pressed:bg-accent data-pressed:text-accent-foreground data-pressed:transition-none sm:text-sm dark:data-pressed:bg-input/80 dark:hover:bg-accent [&_svg:not([class*='opacity-'])]:opacity-80 [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
"[&_svg]:-mx-0.5 relative inline-flex shrink-0 cursor-pointer select-none items-center justify-center gap-2 whitespace-nowrap rounded-lg border font-medium text-base outline-none transition-shadow before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11 hover:bg-accent focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 data-pressed:bg-input/64 data-pressed:text-accent-foreground sm:text-sm [&_svg:not([class*='opacity-'])]:opacity-80 [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
{
defaultVariants: {
size: "default",
@@ -21,7 +21,7 @@ const toggleVariants = cva(
variant: {
default: "border-transparent",
outline:
"border-border bg-clip-padding shadow-xs not-disabled:not-active:not-data-pressed:before:shadow-[0_1px_--theme(--color-black/4%)] dark:bg-input/32 dark:hover:bg-input/64 dark:not-disabled:not-active:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/8%)] dark:not-disabled:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/4%)] [:disabled,:active,[data-pressed]]:shadow-none",
"border-input bg-background not-dark:bg-clip-padding shadow-xs/5 not-disabled:not-active:not-data-pressed:before:shadow-[0_1px_--theme(--color-black/6%)] dark:bg-input/32 dark:data-pressed:bg-input dark:hover:bg-input/64 dark:not-disabled:not-active:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/6%)] dark:not-disabled:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/2%)] [:disabled,:active,[data-pressed]]:shadow-none",
},
},
},
+1 -1
View File
@@ -8,7 +8,7 @@ function Toolbar({ className, ...props }: ToolbarPrimitive.Root.Props) {
return (
<ToolbarPrimitive.Root
className={cn(
"relative flex gap-2 rounded-xl border bg-card bg-clip-padding p-1 text-card-foreground",
"relative flex gap-2 rounded-xl border bg-card not-dark:bg-clip-padding p-1 text-card-foreground",
className,
)}
data-slot="toolbar"
+1 -1
View File
@@ -37,7 +37,7 @@ function TooltipPopup({
>
<TooltipPrimitive.Popup
className={cn(
"relative flex h-(--popup-height,auto) w-(--popup-width,auto) origin-(--transform-origin) text-balance rounded-md border bg-popover bg-clip-padding text-popover-foreground text-xs shadow-black/5 shadow-md transition-[width,height,scale,opacity] before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-md)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] data-ending-style:scale-98 data-starting-style:scale-98 data-ending-style:opacity-0 data-starting-style:opacity-0 data-instant:duration-0 dark:bg-clip-border dark:before:shadow-[0_-1px_--theme(--color-white/8%)]",
"relative flex h-(--popup-height,auto) w-(--popup-width,auto) origin-(--transform-origin) text-balance rounded-md border bg-popover not-dark:bg-clip-padding text-popover-foreground text-xs shadow-md/5 transition-[width,height,scale,opacity] before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-md)-1px)] before:shadow-[0_1px_--theme(--color-black/6%)] data-ending-style:scale-98 data-starting-style:scale-98 data-ending-style:opacity-0 data-starting-style:opacity-0 data-instant:duration-0 dark:before:shadow-[0_-1px_--theme(--color-white/6%)]",
className,
)}
data-slot="tooltip-popup"