-
-
+ )
+}
+
+export function CommandDialogPopup({
+ className,
+ children,
+ portalProps,
+ ...props
+}: CommandDialogPrimitive.Popup.Props & {
+ portalProps?: CommandDialogPrimitive.Portal.Props
+}): React.ReactElement {
+ return (
+
+
+
+
+ {children}
+
+
+
+ )
+}
+
+export function Command({
+ autoHighlight = "always",
+ keepHighlight = true,
+ ...props
+}: React.ComponentProps
): React.ReactElement {
+ return (
+
+ )
+}
+
+export function CommandInput({
+ className,
+ placeholder = undefined,
+ ...props
+}: React.ComponentProps): React.ReactElement {
+ return (
+
)
}
-function CommandList({ className, ...props }: React.ComponentProps) {
+export function CommandList({
+ className,
+ ...props
+}: React.ComponentProps): React.ReactElement {
return (
-
)
}
-function CommandEmpty({
+export function CommandEmpty({
className,
...props
-}: React.ComponentProps) {
+}: React.ComponentProps): React.ReactElement {
return (
-
)
}
-function CommandGroup({
+export function CommandPanel({
+ className,
+ ...props
+}: React.ComponentProps<"div">): React.ReactElement {
+ return (
+
+ )
+}
+
+export function CommandGroup({
className,
...props
-}: React.ComponentProps) {
+}: React.ComponentProps): React.ReactElement {
+ return
+}
+
+export function CommandGroupLabel({
+ className,
+ ...props
+}: React.ComponentProps): React.ReactElement {
+ return
+}
+
+export function CommandCollection({
+ ...props
+}: React.ComponentProps): React.ReactElement {
+ return
+}
+
+export function CommandItem({
+ className,
+ ...props
+}: React.ComponentProps): React.ReactElement {
+ return (
+
+ )
+}
+
+export function CommandSeparator({
+ className,
+ ...props
+}: React.ComponentProps): React.ReactElement {
+ return (
+
+ )
+}
+
+export function CommandShortcut({
+ className,
+ ...props
+}: React.ComponentProps<"kbd">): React.ReactElement {
return (
-
)
}
-function CommandItem({ className, ...props }: React.ComponentProps) {
+export function CommandFooter({
+ className,
+ ...props
+}: React.ComponentProps<"div">): React.ReactElement {
return (
-
)
}
-export { Command, CommandInput, CommandList, CommandEmpty, CommandGroup, CommandItem }
+export { CommandDialogPrimitive }
diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx
index 25b7d81..f7c8b45 100644
--- a/src/components/ui/input.tsx
+++ b/src/components/ui/input.tsx
@@ -1,21 +1,67 @@
-import * as React from "react"
+"use client"
+
+import { Input as InputPrimitive } from "@base-ui/react/input"
+import type * as React from "react"
import { cn } from "@/lib/utils"
-export interface InputProps extends React.InputHTMLAttributes {
- ref?: React.Ref
+export type InputProps = Omit<
+ InputPrimitive.Props & React.RefAttributes,
+ "size"
+> & {
+ size?: "sm" | "default" | "lg" | number
+ unstyled?: boolean
+ nativeInput?: boolean
}
-const Input = ({ className, type, ref, ...props }: InputProps) => (
-
-)
-Input.displayName = "Input"
+export function Input({
+ className,
+ size = "default",
+ unstyled = false,
+ nativeInput = false,
+ style,
+ ...props
+}: InputProps): React.ReactElement {
+ const inputClassName = cn(
+ "h-8.5 w-full min-w-0 rounded-[inherit] px-[calc(--spacing(3)-1px)] leading-8.5 outline-none [transition:background-color_5000000s_ease-in-out_0s] 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 (
+
+ {nativeInput ? (
+
+ ) : (
+
+ )}
+
+ )
+}
-export { Input }
+export { InputPrimitive }
diff --git a/src/components/ui/popover.tsx b/src/components/ui/popover.tsx
index b10d511..463e66b 100644
--- a/src/components/ui/popover.tsx
+++ b/src/components/ui/popover.tsx
@@ -1,72 +1,112 @@
-import * as React from "react"
-import { Popover as PopoverPrimitive } from "radix-ui"
+"use client"
+import { Popover as PopoverPrimitive } from "@base-ui/react/popover"
+import type React from "react"
import { cn } from "@/lib/utils"
-function Popover({ ...props }: React.ComponentProps) {
- return
-}
+export const PopoverCreateHandle: typeof PopoverPrimitive.createHandle =
+ PopoverPrimitive.createHandle
+
+export const Popover: typeof PopoverPrimitive.Root = PopoverPrimitive.Root
-function PopoverTrigger({ ...props }: React.ComponentProps) {
- return
+export function PopoverTrigger({
+ className,
+ children,
+ ...props
+}: PopoverPrimitive.Trigger.Props): React.ReactElement {
+ return (
+
+ {children}
+
+ )
}
-function PopoverContent({
+export function PopoverPopup({
+ children,
className,
+ side = "bottom",
align = "center",
sideOffset = 4,
+ alignOffset = 0,
+ tooltipStyle = false,
+ anchor,
+ portalProps,
...props
-}: React.ComponentProps) {
+}: PopoverPrimitive.Popup.Props & {
+ portalProps?: PopoverPrimitive.Portal.Props
+ side?: PopoverPrimitive.Positioner.Props["side"]
+ align?: PopoverPrimitive.Positioner.Props["align"]
+ sideOffset?: PopoverPrimitive.Positioner.Props["sideOffset"]
+ alignOffset?: PopoverPrimitive.Positioner.Props["alignOffset"]
+ tooltipStyle?: boolean
+ anchor?: PopoverPrimitive.Positioner.Props["anchor"]
+}): React.ReactElement {
return (
-
-
+
+ >
+
+
+ {children}
+
+
+
)
}
-function PopoverAnchor({ ...props }: React.ComponentProps) {
- return
+export function PopoverClose({ ...props }: PopoverPrimitive.Close.Props): React.ReactElement {
+ return
}
-function PopoverHeader({ className, ...props }: React.ComponentProps<"div">) {
+export function PopoverTitle({
+ className,
+ ...props
+}: PopoverPrimitive.Title.Props): React.ReactElement {
return (
-
)
}
-function PopoverTitle({ className, ...props }: React.ComponentProps<"h2">) {
- return
-}
-
-function PopoverDescription({ className, ...props }: React.ComponentProps<"p">) {
+export function PopoverDescription({
+ className,
+ ...props
+}: PopoverPrimitive.Description.Props): React.ReactElement {
return (
-
)
}
-export {
- Popover,
- PopoverTrigger,
- PopoverContent,
- PopoverAnchor,
- PopoverHeader,
- PopoverTitle,
- PopoverDescription,
-}
+export { PopoverPrimitive, PopoverPopup as PopoverContent }
diff --git a/src/components/ui/scroll-area.tsx b/src/components/ui/scroll-area.tsx
index 96013df..ae6ae4a 100644
--- a/src/components/ui/scroll-area.tsx
+++ b/src/components/ui/scroll-area.tsx
@@ -1,47 +1,67 @@
-import * as React from "react"
-import { ScrollArea as ScrollAreaPrimitive } from "radix-ui"
+"use client"
+
+import { ScrollArea as ScrollAreaPrimitive } from "@base-ui/react/scroll-area"
+import type React from "react"
import { cn } from "@/lib/utils"
-interface ScrollAreaProps extends React.ComponentPropsWithoutRef {
- ref?: React.Ref>
+export function ScrollArea({
+ className,
+ children,
+ scrollFade = false,
+ scrollbarGutter = false,
+ fill = false,
+ ...props
+}: ScrollAreaPrimitive.Root.Props & {
+ scrollFade?: boolean
+ scrollbarGutter?: boolean
+ fill?: boolean
+}): React.ReactElement {
+ return (
+
+
+
+ {children}
+
+
+
+
+
+
+ )
}
-const ScrollArea = ({ className, children, ref, ...props }: ScrollAreaProps) => (
-
-
- {children}
-
-
-
-
-)
-ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
-
-interface ScrollBarProps extends React.ComponentPropsWithoutRef<
- typeof ScrollAreaPrimitive.ScrollAreaScrollbar
-> {
- ref?: React.Ref>
+export function ScrollBar({
+ className,
+ orientation = "vertical",
+ ...props
+}: ScrollAreaPrimitive.Scrollbar.Props): React.ReactElement {
+ return (
+
+
+
+ )
}
-const ScrollBar = ({ className, orientation = "vertical", ref, ...props }: ScrollBarProps) => (
-
-
-
-)
-ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
-
-export { ScrollArea, ScrollBar }
+export { ScrollAreaPrimitive }
diff --git a/src/components/ui/select.tsx b/src/components/ui/select.tsx
index 7fd63bd..ba27ffc 100644
--- a/src/components/ui/select.tsx
+++ b/src/components/ui/select.tsx
@@ -1,131 +1,243 @@
-import * as React from "react"
-import { Select as SelectPrimitive } from "radix-ui"
-import { Check, ChevronDown } from "lucide-react"
+"use client"
+
+import { mergeProps } from "@base-ui/react/merge-props"
+import { Select as SelectPrimitive } from "@base-ui/react/select"
+import { useRender } from "@base-ui/react/use-render"
+import { cva, type VariantProps } from "class-variance-authority"
+import { ChevronDownIcon, ChevronsUpDownIcon, ChevronUpIcon } from "lucide-react"
+import type * as React from "react"
import { cn } from "@/lib/utils"
-const Select = SelectPrimitive.Root
-const SelectGroup = SelectPrimitive.Group
-const SelectValue = SelectPrimitive.Value
+export const Select: typeof SelectPrimitive.Root = SelectPrimitive.Root
+
+export const selectTriggerVariants = cva(
+ "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 not-dark:bg-clip-padding px-[calc(--spacing(3)-1px)] text-left text-base text-foreground 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",
+ {
+ defaultVariants: {
+ size: "default",
+ },
+ variants: {
+ size: {
+ default: "",
+ lg: "min-h-10 sm:min-h-9",
+ sm: "min-h-8 gap-1.5 px-[calc(--spacing(2.5)-1px)] sm:min-h-7",
+ },
+ },
+ }
+)
+
+export const selectTriggerIconClassName = "-me-1 size-4.5 opacity-80 sm:size-4"
-interface SelectTriggerProps extends React.ComponentPropsWithoutRef<
- typeof SelectPrimitive.Trigger
-> {
- ref?: React.Ref>
+export interface SelectButtonProps extends useRender.ComponentProps<"button"> {
+ size?: VariantProps["size"]
}
-const SelectTrigger = ({ className, children, ref, ...props }: SelectTriggerProps) => (
- span]:line-clamp-1",
- className
- )}
- {...props}
- >
- {children}
-
-
-
-
-)
-SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
+export function SelectButton({
+ className,
+ size,
+ render,
+ children,
+ ...props
+}: SelectButtonProps): React.ReactElement {
+ const typeValue: React.ButtonHTMLAttributes["type"] = render
+ ? undefined
+ : "button"
+
+ const defaultProps = {
+ children: (
+ <>
+
+ {children}
+
+
+ >
+ ),
+ className: cn(selectTriggerVariants({ size }), "min-w-0", className),
+ "data-slot": "select-button",
+ type: typeValue,
+ }
+
+ return useRender({
+ defaultTagName: "button",
+ props: mergeProps<"button">(defaultProps, props),
+ render,
+ })
+}
+
+export function SelectTrigger({
+ className,
+ size = "default",
+ children,
+ ...props
+}: SelectPrimitive.Trigger.Props & VariantProps): React.ReactElement {
+ return (
+
+ {children}
+
+
+
+
+ )
+}
-interface SelectContentProps extends React.ComponentPropsWithoutRef<
- typeof SelectPrimitive.Content
-> {
- ref?: React.Ref>
+export function SelectValue({
+ className,
+ ...props
+}: SelectPrimitive.Value.Props): React.ReactElement {
+ return (
+
+ )
+}
+
+export function SelectPopup({
+ className,
+ children,
+ side = "bottom",
+ sideOffset = 4,
+ align = "start",
+ alignOffset = 0,
+ alignItemWithTrigger = true,
+ anchor,
+ portalProps,
+ ...props
+}: SelectPrimitive.Popup.Props & {
+ portalProps?: SelectPrimitive.Portal.Props
+ side?: SelectPrimitive.Positioner.Props["side"]
+ sideOffset?: SelectPrimitive.Positioner.Props["sideOffset"]
+ align?: SelectPrimitive.Positioner.Props["align"]
+ alignOffset?: SelectPrimitive.Positioner.Props["alignOffset"]
+ alignItemWithTrigger?: SelectPrimitive.Positioner.Props["alignItemWithTrigger"]
+ anchor?: SelectPrimitive.Positioner.Props["anchor"]
+}): React.ReactElement {
+ return (
+
+
+
+
+
+
+
+
+ {children}
+
+
+
+
+
+
+
+
+ )
}
-const SelectContent = ({
+export function SelectItem({
className,
children,
- position = "popper",
- ref,
...props
-}: SelectContentProps) => (
-
-
-
+
+
+
+
{children}
-
-
-
-)
-SelectContent.displayName = SelectPrimitive.Content.displayName
-
-interface SelectItemProps extends React.ComponentPropsWithoutRef {
- ref?: React.Ref>
+
+
+ )
}
-const SelectItem = ({ className, children, ref, ...props }: SelectItemProps) => (
-
-
-
-
-
-
- {children}
-
-)
-SelectItem.displayName = SelectPrimitive.Item.displayName
-
-interface SelectLabelProps extends React.ComponentPropsWithoutRef {
- ref?: React.Ref>
+export function SelectSeparator({
+ className,
+ ...props
+}: SelectPrimitive.Separator.Props): React.ReactElement {
+ return (
+
+ )
}
-const SelectLabel = ({ className, ref, ...props }: SelectLabelProps) => (
-
-)
-SelectLabel.displayName = SelectPrimitive.Label.displayName
+export function SelectGroup(props: SelectPrimitive.Group.Props): React.ReactElement {
+ return
+}
-interface SelectSeparatorProps extends React.ComponentPropsWithoutRef<
- typeof SelectPrimitive.Separator
-> {
- ref?: React.Ref>
+export function SelectLabel({
+ className,
+ ...props
+}: SelectPrimitive.Label.Props): React.ReactElement {
+ return (
+
+ )
}
-const SelectSeparator = ({ className, ref, ...props }: SelectSeparatorProps) => (
-
-)
-SelectSeparator.displayName = SelectPrimitive.Separator.displayName
-
-export {
- Select,
- SelectGroup,
- SelectValue,
- SelectTrigger,
- SelectContent,
- SelectItem,
- SelectLabel,
- SelectSeparator,
+export function SelectGroupLabel(props: SelectPrimitive.GroupLabel.Props): React.ReactElement {
+ return (
+
+ )
}
+
+export { SelectPrimitive, SelectPopup as SelectContent }
diff --git a/src/components/ui/slider.tsx b/src/components/ui/slider.tsx
new file mode 100644
index 0000000..fb06cd0
--- /dev/null
+++ b/src/components/ui/slider.tsx
@@ -0,0 +1,76 @@
+"use client"
+
+import { Slider as SliderPrimitive } from "@base-ui/react/slider"
+import * as React from "react"
+import { cn } from "@/lib/utils"
+
+export function Slider({
+ className,
+ children,
+ defaultValue,
+ value,
+ min = 0,
+ max = 100,
+ ...props
+}: SliderPrimitive.Root.Props): React.ReactElement {
+ const _values = React.useMemo(() => {
+ if (value !== undefined) {
+ return Array.isArray(value) ? value : [value]
+ }
+ if (defaultValue !== undefined) {
+ return Array.isArray(defaultValue) ? defaultValue : [defaultValue]
+ }
+ return [min]
+ }, [value, defaultValue, min])
+
+ return (
+
+ {children}
+
+
+
+ {Array.from({ length: _values.length }, (_, index) => (
+
+ ))}
+
+
+
+ )
+}
+
+export function SliderValue({
+ className,
+ ...props
+}: SliderPrimitive.Value.Props): React.ReactElement {
+ return (
+
+ )
+}
+
+export { SliderPrimitive }
diff --git a/src/components/ui/spinner.tsx b/src/components/ui/spinner.tsx
new file mode 100644
index 0000000..60a69c1
--- /dev/null
+++ b/src/components/ui/spinner.tsx
@@ -0,0 +1,17 @@
+import { Loader2Icon } from "lucide-react"
+import type React from "react"
+import { cn } from "@/lib/utils"
+
+export function Spinner({
+ className,
+ ...props
+}: React.ComponentProps): React.ReactElement {
+ return (
+
+ )
+}
diff --git a/src/components/ui/switch.tsx b/src/components/ui/switch.tsx
index e87e1ef..41bc7cd 100644
--- a/src/components/ui/switch.tsx
+++ b/src/components/ui/switch.tsx
@@ -1,43 +1,27 @@
-import { cn } from "@/lib/utils"
-import type { ButtonHTMLAttributes, Ref } from "react"
+"use client"
-type Props = Omit, "onChange"> & {
- checked: boolean
- onCheckedChange: (v: boolean) => void
- ref?: Ref
-}
+import { Switch as SwitchPrimitive } from "@base-ui/react/switch"
+import type React from "react"
+import { cn } from "@/lib/utils"
-export function Switch({
- checked,
- onCheckedChange,
- disabled,
- id,
- className,
- ref,
- ...props
-}: Props) {
+export function Switch({ className, ...props }: SwitchPrimitive.Root.Props): React.ReactElement {
return (
-
+
)
}
+
+export { SwitchPrimitive }
diff --git a/src/components/ui/toolbar.tsx b/src/components/ui/toolbar.tsx
new file mode 100644
index 0000000..7766788
--- /dev/null
+++ b/src/components/ui/toolbar.tsx
@@ -0,0 +1,70 @@
+"use client"
+
+import { Toolbar as ToolbarPrimitive } from "@base-ui/react/toolbar"
+import type React from "react"
+import { cn } from "@/lib/utils"
+
+export function Toolbar({ className, ...props }: ToolbarPrimitive.Root.Props): React.ReactElement {
+ return (
+
+ )
+}
+
+export function ToolbarButton({
+ className,
+ ...props
+}: ToolbarPrimitive.Button.Props): React.ReactElement {
+ return
+}
+
+export function ToolbarLink({
+ className,
+ ...props
+}: ToolbarPrimitive.Link.Props): React.ReactElement {
+ return
+}
+
+export function ToolbarInput({
+ className,
+ ...props
+}: ToolbarPrimitive.Input.Props): React.ReactElement {
+ return
+}
+
+export function ToolbarGroup({
+ className,
+ ...props
+}: ToolbarPrimitive.Group.Props): React.ReactElement {
+ return (
+
+ )
+}
+
+export function ToolbarSeparator({
+ className,
+ ...props
+}: ToolbarPrimitive.Separator.Props): React.ReactElement {
+ return (
+
+ )
+}
+
+export { ToolbarPrimitive }
diff --git a/src/components/ui/tooltip.tsx b/src/components/ui/tooltip.tsx
index 3ca47c4..d147056 100644
--- a/src/components/ui/tooltip.tsx
+++ b/src/components/ui/tooltip.tsx
@@ -1,51 +1,64 @@
-import * as React from "react"
-import { Tooltip as TooltipPrimitive } from "radix-ui"
+"use client"
+import { Tooltip as TooltipPrimitive } from "@base-ui/react/tooltip"
+import type React from "react"
import { cn } from "@/lib/utils"
-function TooltipProvider({
- delayDuration = 0,
- ...props
-}: React.ComponentProps) {
- return (
-
- )
-}
+export const TooltipCreateHandle: typeof TooltipPrimitive.createHandle =
+ TooltipPrimitive.createHandle
-function Tooltip({ ...props }: React.ComponentProps) {
- return
-}
+export const TooltipProvider: typeof TooltipPrimitive.Provider = TooltipPrimitive.Provider
+
+export const Tooltip: typeof TooltipPrimitive.Root = TooltipPrimitive.Root
-function TooltipTrigger({ ...props }: React.ComponentProps) {
+export function TooltipTrigger(props: TooltipPrimitive.Trigger.Props): React.ReactElement {
return
}
-function TooltipContent({
+export function TooltipPopup({
className,
- sideOffset = 0,
+ align = "center",
+ sideOffset = 4,
+ side = "top",
+ anchor,
children,
+ portalProps,
...props
-}: React.ComponentProps) {
+}: TooltipPrimitive.Popup.Props & {
+ align?: TooltipPrimitive.Positioner.Props["align"]
+ side?: TooltipPrimitive.Positioner.Props["side"]
+ sideOffset?: TooltipPrimitive.Positioner.Props["sideOffset"]
+ anchor?: TooltipPrimitive.Positioner.Props["anchor"]
+ portalProps?: TooltipPrimitive.Portal.Props
+}): React.ReactElement {
return (
-
-
+
- {children}
-
-
+
+
+ {children}
+
+
+
)
}
-export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
+export { TooltipPrimitive, TooltipPopup as TooltipContent }
diff --git a/src/index.css b/src/index.css
index 35247ee..2120e7f 100644
--- a/src/index.css
+++ b/src/index.css
@@ -79,6 +79,10 @@
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
+ --font-sans:
+ "Inter Variable", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
+ --font-mono:
+ "Geist Mono Variable", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}
@layer base {
@@ -94,13 +98,7 @@
body {
background: var(--background);
color: var(--foreground);
- font-family:
- ui-sans-serif,
- system-ui,
- -apple-system,
- "Segoe UI",
- Roboto,
- sans-serif;
+ font-family: var(--font-sans);
-webkit-font-smoothing: antialiased;
overflow: hidden;
}
@@ -129,7 +127,7 @@
}
/* Custom Leaflet divIcon for the panorama marker. Kept here so the icon
- HTML returned from React doesn't carry an inline