Migrate UI primitives from Radix to Base UI.
Local Build and Deploy / deploy (push) Successful in 54s
Local Build and Deploy / deploy (push) Successful in 54s
Co-authored-by: Cursor <[email protected]>
This commit is contained in:
1 parent
90cff7e5d5
commit
25f01b61b3
18 files changed
+485
-821
No files matched your search
+1
-11
@@ -21,23 +21,13 @@
|
|||||||
"jobs:worker": "tsx scripts/jobs-worker.ts"
|
"jobs:worker": "tsx scripts/jobs-worker.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@base-ui/react": "^1.6.0",
|
||||||
"@dnd-kit/core": "^6.3.1",
|
"@dnd-kit/core": "^6.3.1",
|
||||||
"@dnd-kit/sortable": "^10.0.0",
|
"@dnd-kit/sortable": "^10.0.0",
|
||||||
"@dnd-kit/utilities": "^3.2.2",
|
"@dnd-kit/utilities": "^3.2.2",
|
||||||
"@hookform/resolvers": "^5.4.0",
|
"@hookform/resolvers": "^5.4.0",
|
||||||
"@prisma/adapter-mariadb": "^7.8.0",
|
"@prisma/adapter-mariadb": "^7.8.0",
|
||||||
"@prisma/client": "^7.8.0",
|
"@prisma/client": "^7.8.0",
|
||||||
"@radix-ui/react-checkbox": "^1.3.7",
|
|
||||||
"@radix-ui/react-context-menu": "^2.3.3",
|
|
||||||
"@radix-ui/react-dialog": "^1.1.19",
|
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.20",
|
|
||||||
"@radix-ui/react-label": "^2.1.11",
|
|
||||||
"@radix-ui/react-popover": "^1.1.19",
|
|
||||||
"@radix-ui/react-select": "^2.3.3",
|
|
||||||
"@radix-ui/react-slot": "^1.3.0",
|
|
||||||
"@radix-ui/react-switch": "^1.3.3",
|
|
||||||
"@radix-ui/react-tabs": "^1.1.17",
|
|
||||||
"@radix-ui/react-tooltip": "^1.2.12",
|
|
||||||
"@tanstack/react-virtual": "^3.14.5",
|
"@tanstack/react-virtual": "^3.14.5",
|
||||||
"bcryptjs": "^3.0.2",
|
"bcryptjs": "^3.0.2",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
|
|||||||
Generated
+73
-565
File diff suppressed because it is too large.
Load diff
@@ -364,8 +364,8 @@ export function FurniClient({ room, items = [], canEdit }: Props) {
|
|||||||
|
|
||||||
<Select
|
<Select
|
||||||
value={typeFilter}
|
value={typeFilter}
|
||||||
onValueChange={(v: "all" | "floor" | "wall") => {
|
onValueChange={(v) => {
|
||||||
setTypeFilter(v);
|
setTypeFilter(v as "all" | "floor" | "wall");
|
||||||
setPage(1);
|
setPage(1);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -25,17 +25,14 @@ export function CatalogManagerDialog() {
|
|||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={open} onOpenChange={setOpen}>
|
<Dialog open={open} onOpenChange={setOpen} disablePointerDismissal>
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
<Button variant="outline" className="gap-2">
|
<Button variant="outline" className="gap-2">
|
||||||
<LayoutGrid className="h-4 w-4" />
|
<LayoutGrid className="h-4 w-4" />
|
||||||
Visual Manager
|
Visual Manager
|
||||||
</Button>
|
</Button>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
<DialogContent
|
<DialogContent className="max-w-full w-[98vw] h-[95vh] max-h-[95vh] p-0 flex flex-col gap-0 sm:max-w-[98vw]">
|
||||||
className="max-w-full w-[98vw] h-[95vh] max-h-[95vh] p-0 flex flex-col gap-0 sm:max-w-[98vw]"
|
|
||||||
onInteractOutside={(e) => e.preventDefault()}
|
|
||||||
>
|
|
||||||
<CatalogManagerProvider>
|
<CatalogManagerProvider>
|
||||||
<CatalogManagerInner open={open} onOpenChange={setOpen} />
|
<CatalogManagerInner open={open} onOpenChange={setOpen} />
|
||||||
</CatalogManagerProvider>
|
</CatalogManagerProvider>
|
||||||
|
|||||||
+31
-13
@@ -1,6 +1,7 @@
|
|||||||
|
import { mergeProps } from "@base-ui/react/merge-props";
|
||||||
|
import { useRender } from "@base-ui/react/use-render";
|
||||||
import { cva, type VariantProps } from "class-variance-authority";
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
import { Slot } from "@radix-ui/react-slot";
|
import { isValidElement, type ReactElement, type ReactNode } from "react";
|
||||||
import type * as React from "react";
|
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
@@ -30,19 +31,36 @@ function Badge({
|
|||||||
className,
|
className,
|
||||||
variant = "default",
|
variant = "default",
|
||||||
asChild = false,
|
asChild = false,
|
||||||
|
render,
|
||||||
|
children,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<"span"> &
|
}: useRender.ComponentProps<"span"> &
|
||||||
VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
|
VariantProps<typeof badgeVariants> & {
|
||||||
const Comp = asChild ? Slot : "span";
|
asChild?: boolean;
|
||||||
|
}) {
|
||||||
|
let resolvedRender = render;
|
||||||
|
let resolvedChildren: ReactNode = children;
|
||||||
|
|
||||||
return (
|
if (!resolvedRender && asChild && isValidElement(children)) {
|
||||||
<Comp
|
resolvedRender = children as ReactElement;
|
||||||
data-slot="badge"
|
resolvedChildren = (children.props as { children?: ReactNode }).children;
|
||||||
data-variant={variant}
|
}
|
||||||
className={cn(badgeVariants({ variant }), className)}
|
|
||||||
{...props}
|
return useRender({
|
||||||
/>
|
defaultTagName: "span",
|
||||||
);
|
props: mergeProps<"span">(
|
||||||
|
{
|
||||||
|
className: cn(badgeVariants({ variant }), className),
|
||||||
|
children: resolvedChildren,
|
||||||
|
},
|
||||||
|
props,
|
||||||
|
),
|
||||||
|
render: resolvedRender,
|
||||||
|
state: {
|
||||||
|
slot: "badge",
|
||||||
|
variant,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Badge, badgeVariants };
|
export { Badge, badgeVariants };
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
|
import { Button as ButtonPrimitive } from "@base-ui/react/button";
|
||||||
import { cva, type VariantProps } from "class-variance-authority";
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
import { Slot } from "@radix-ui/react-slot";
|
|
||||||
import type * as React from "react";
|
import type * as React from "react";
|
||||||
|
|
||||||
|
import { resolveAsChild } from "@/lib/as-child";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const buttonVariants = cva(
|
const buttonVariants = cva(
|
||||||
@@ -43,21 +44,26 @@ function Button({
|
|||||||
variant = "default",
|
variant = "default",
|
||||||
size = "default",
|
size = "default",
|
||||||
asChild = false,
|
asChild = false,
|
||||||
|
children,
|
||||||
|
render,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<"button"> &
|
}: ButtonPrimitive.Props &
|
||||||
VariantProps<typeof buttonVariants> & {
|
VariantProps<typeof buttonVariants> & {
|
||||||
asChild?: boolean;
|
asChild?: boolean;
|
||||||
}) {
|
}) {
|
||||||
const Comp = asChild ? Slot : "button";
|
const resolved = resolveAsChild(asChild, children, render);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Comp
|
<ButtonPrimitive
|
||||||
data-slot="button"
|
data-slot="button"
|
||||||
data-variant={variant}
|
data-variant={variant}
|
||||||
data-size={size}
|
data-size={size}
|
||||||
className={cn(buttonVariants({ variant, size, className }))}
|
className={cn(buttonVariants({ variant, size, className }))}
|
||||||
|
render={resolved.render}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
>
|
||||||
|
{resolved.children}
|
||||||
|
</ButtonPrimitive>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,16 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox";
|
||||||
import { CheckIcon } from "lucide-react";
|
import { CheckIcon } from "lucide-react";
|
||||||
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
|
|
||||||
import type * as React from "react";
|
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function Checkbox({
|
function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) {
|
||||||
className,
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
|
|
||||||
return (
|
return (
|
||||||
<CheckboxPrimitive.Root
|
<CheckboxPrimitive.Root
|
||||||
data-slot="checkbox"
|
data-slot="checkbox"
|
||||||
className={cn(
|
className={cn(
|
||||||
"peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
"peer border-input dark:bg-input/30 data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary data-checked:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -35,11 +35,15 @@ function CommandDialog({
|
|||||||
className,
|
className,
|
||||||
showCloseButton = true,
|
showCloseButton = true,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof Dialog> & {
|
}: {
|
||||||
title?: string;
|
title?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
showCloseButton?: boolean;
|
showCloseButton?: boolean;
|
||||||
|
children?: React.ReactNode;
|
||||||
|
open?: boolean;
|
||||||
|
defaultOpen?: boolean;
|
||||||
|
onOpenChange?: (open: boolean) => void;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<Dialog {...props}>
|
<Dialog {...props}>
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,16 +1,12 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as LabelPrimitive from "@radix-ui/react-label";
|
|
||||||
import type * as React from "react";
|
import type * as React from "react";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function Label({
|
function Label({ className, ...props }: React.ComponentProps<"label">) {
|
||||||
className,
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof LabelPrimitive.Root>) {
|
|
||||||
return (
|
return (
|
||||||
<LabelPrimitive.Root
|
<label
|
||||||
data-slot="label"
|
data-slot="label"
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
|
"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,7 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as SwitchPrimitive from "@radix-ui/react-switch";
|
import { Switch as SwitchPrimitive } from "@base-ui/react/switch";
|
||||||
import type * as React from "react";
|
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
@@ -9,7 +8,7 @@ function Switch({
|
|||||||
className,
|
className,
|
||||||
size = "default",
|
size = "default",
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof SwitchPrimitive.Root> & {
|
}: SwitchPrimitive.Root.Props & {
|
||||||
size?: "sm" | "default";
|
size?: "sm" | "default";
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
@@ -17,7 +16,7 @@ function Switch({
|
|||||||
data-slot="switch"
|
data-slot="switch"
|
||||||
data-size={size}
|
data-size={size}
|
||||||
className={cn(
|
className={cn(
|
||||||
"peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 group/switch inline-flex shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-[1.15rem] data-[size=default]:w-8 data-[size=sm]:h-3.5 data-[size=sm]:w-6",
|
"peer data-checked:bg-primary data-unchecked:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-unchecked:bg-input/80 group/switch inline-flex shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-[1.15rem] data-[size=default]:w-8 data-[size=sm]:h-3.5 data-[size=sm]:w-6",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
@@ -25,7 +24,7 @@ function Switch({
|
|||||||
<SwitchPrimitive.Thumb
|
<SwitchPrimitive.Thumb
|
||||||
data-slot="switch-thumb"
|
data-slot="switch-thumb"
|
||||||
className={cn(
|
className={cn(
|
||||||
"bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block rounded-full ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0",
|
"bg-background dark:data-unchecked:bg-foreground dark:data-checked:bg-primary-foreground pointer-events-none block rounded-full ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 data-checked:translate-x-[calc(100%-2px)] data-unchecked:translate-x-0",
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</SwitchPrimitive.Root>
|
</SwitchPrimitive.Root>
|
||||||
|
|||||||
+11
-19
@@ -1,8 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { Tabs as TabsPrimitive } from "@base-ui/react/tabs";
|
||||||
import { cva, type VariantProps } from "class-variance-authority";
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
import * as TabsPrimitive from "@radix-ui/react-tabs";
|
|
||||||
import type * as React from "react";
|
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
@@ -10,7 +9,7 @@ function Tabs({
|
|||||||
className,
|
className,
|
||||||
orientation = "horizontal",
|
orientation = "horizontal",
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof TabsPrimitive.Root>) {
|
}: TabsPrimitive.Root.Props) {
|
||||||
return (
|
return (
|
||||||
<TabsPrimitive.Root
|
<TabsPrimitive.Root
|
||||||
data-slot="tabs"
|
data-slot="tabs"
|
||||||
@@ -44,8 +43,7 @@ function TabsList({
|
|||||||
className,
|
className,
|
||||||
variant = "default",
|
variant = "default",
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof TabsPrimitive.List> &
|
}: TabsPrimitive.List.Props & VariantProps<typeof tabsListVariants>) {
|
||||||
VariantProps<typeof tabsListVariants>) {
|
|
||||||
return (
|
return (
|
||||||
<TabsPrimitive.List
|
<TabsPrimitive.List
|
||||||
data-slot="tabs-list"
|
data-slot="tabs-list"
|
||||||
@@ -56,18 +54,15 @@ function TabsList({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function TabsTrigger({
|
function TabsTrigger({ className, ...props }: TabsPrimitive.Tab.Props) {
|
||||||
className,
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
|
|
||||||
return (
|
return (
|
||||||
<TabsPrimitive.Trigger
|
<TabsPrimitive.Tab
|
||||||
data-slot="tabs-trigger"
|
data-slot="tabs-trigger"
|
||||||
className={cn(
|
className={cn(
|
||||||
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring text-foreground/60 hover:text-foreground dark:text-muted-foreground dark:hover:text-foreground relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring text-foreground/60 hover:text-foreground dark:text-muted-foreground dark:hover:text-foreground relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||||
"group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:border-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent",
|
"group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent",
|
||||||
"data-[state=active]:bg-background dark:data-[state=active]:text-foreground dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 data-[state=active]:text-foreground",
|
"data-active:bg-background dark:data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 data-active:text-foreground",
|
||||||
"after:bg-foreground after:absolute after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-[state=active]:after:opacity-100",
|
"after:bg-foreground after:absolute after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
@@ -75,12 +70,9 @@ function TabsTrigger({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function TabsContent({
|
function TabsContent({ className, ...props }: TabsPrimitive.Panel.Props) {
|
||||||
className,
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof TabsPrimitive.Content>) {
|
|
||||||
return (
|
return (
|
||||||
<TabsPrimitive.Content
|
<TabsPrimitive.Panel
|
||||||
data-slot="tabs-content"
|
data-slot="tabs-content"
|
||||||
className={cn("flex-1 outline-none", className)}
|
className={cn("flex-1 outline-none", className)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -1,55 +1,83 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
|
import { Tooltip as TooltipPrimitive } from "@base-ui/react/tooltip";
|
||||||
import type * as React from "react";
|
|
||||||
|
|
||||||
|
import { resolveAsChild } from "@/lib/as-child";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
function TooltipProvider({
|
function TooltipProvider({
|
||||||
delayDuration = 0,
|
delay = 0,
|
||||||
|
delayDuration,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
|
}: TooltipPrimitive.Provider.Props & {
|
||||||
|
/** @deprecated Radix compat — use `delay` */
|
||||||
|
delayDuration?: number;
|
||||||
|
}) {
|
||||||
return (
|
return (
|
||||||
<TooltipPrimitive.Provider
|
<TooltipPrimitive.Provider
|
||||||
data-slot="tooltip-provider"
|
data-slot="tooltip-provider"
|
||||||
delayDuration={delayDuration}
|
delay={delayDuration ?? delay}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function Tooltip({
|
function Tooltip({ ...props }: TooltipPrimitive.Root.Props) {
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof TooltipPrimitive.Root>) {
|
|
||||||
return <TooltipPrimitive.Root data-slot="tooltip" {...props} />;
|
return <TooltipPrimitive.Root data-slot="tooltip" {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function TooltipTrigger({
|
function TooltipTrigger({
|
||||||
|
asChild = false,
|
||||||
|
children,
|
||||||
|
render,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
|
}: TooltipPrimitive.Trigger.Props & { asChild?: boolean }) {
|
||||||
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
|
const resolved = resolveAsChild(asChild, children, render);
|
||||||
|
return (
|
||||||
|
<TooltipPrimitive.Trigger
|
||||||
|
data-slot="tooltip-trigger"
|
||||||
|
render={resolved.render}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{resolved.children}
|
||||||
|
</TooltipPrimitive.Trigger>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function TooltipContent({
|
function TooltipContent({
|
||||||
className,
|
className,
|
||||||
sideOffset = 0,
|
sideOffset = 0,
|
||||||
|
side = "top",
|
||||||
|
align = "center",
|
||||||
|
alignOffset = 0,
|
||||||
children,
|
children,
|
||||||
...props
|
...props
|
||||||
}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
|
}: TooltipPrimitive.Popup.Props &
|
||||||
|
Pick<
|
||||||
|
TooltipPrimitive.Positioner.Props,
|
||||||
|
"align" | "alignOffset" | "side" | "sideOffset"
|
||||||
|
>) {
|
||||||
return (
|
return (
|
||||||
<TooltipPrimitive.Portal>
|
<TooltipPrimitive.Portal>
|
||||||
<TooltipPrimitive.Content
|
<TooltipPrimitive.Positioner
|
||||||
data-slot="tooltip-content"
|
align={align}
|
||||||
|
alignOffset={alignOffset}
|
||||||
|
side={side}
|
||||||
sideOffset={sideOffset}
|
sideOffset={sideOffset}
|
||||||
|
className="isolate z-50"
|
||||||
|
>
|
||||||
|
<TooltipPrimitive.Popup
|
||||||
|
data-slot="tooltip-content"
|
||||||
className={cn(
|
className={cn(
|
||||||
"bg-foreground text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
|
"bg-foreground text-background animate-in fade-in-0 zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
<TooltipPrimitive.Arrow className="bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
|
<TooltipPrimitive.Arrow className="bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
|
||||||
</TooltipPrimitive.Content>
|
</TooltipPrimitive.Popup>
|
||||||
|
</TooltipPrimitive.Positioner>
|
||||||
</TooltipPrimitive.Portal>
|
</TooltipPrimitive.Portal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { isValidElement, type ReactNode } from "react";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map Radix-style `asChild` onto Base UI's `render` prop.
|
||||||
|
*/
|
||||||
|
export function resolveAsChild(
|
||||||
|
asChild: boolean | undefined,
|
||||||
|
children: ReactNode,
|
||||||
|
render?: any,
|
||||||
|
): {
|
||||||
|
render?: any;
|
||||||
|
children: ReactNode;
|
||||||
|
} {
|
||||||
|
if (render != null) return { render, children };
|
||||||
|
if (asChild && isValidElement(children)) {
|
||||||
|
return {
|
||||||
|
render: children,
|
||||||
|
children: (children.props as { children?: ReactNode }).children,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return { children };
|
||||||
|
}
|
||||||
Reference in new issue
Block a user