diff --git a/.claude/skills/openbot-screen-layout/SKILL.md b/.claude/skills/openbot-screen-layout/SKILL.md index 04ebc41ce..958b5a120 100644 --- a/.claude/skills/openbot-screen-layout/SKILL.md +++ b/.claude/skills/openbot-screen-layout/SKILL.md @@ -15,8 +15,9 @@ behind a list. Twelve screens render through `PageShell` today and seven build t It does not cover where the data comes from — that is `openbot-data-access`, which owns queries, mutations, and the pending/error/empty/rows branching. It does not cover the gallery components under `components/gallery`, which a Bot draws inside a conversation rather than a person navigating -to. It does not cover the primitives under `components/ui`, which are shadcn files with their own -upstream. +to. It does not cover the primitives under `components/ui`, which are this repository's own design-system +primitives: they began as shadcn output, but there is no upstream to re-pull from, and they are +formatted and linted like the rest of the app. ## The Default diff --git a/app/components.json b/app/components.json deleted file mode 100644 index 52a3b2ad8..000000000 --- a/app/components.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "$schema": "https://ui.shadcn.com/schema.json", - "style": "base-nova", - "rsc": false, - "tsx": true, - "tailwind": { - "config": "", - "css": "src/styles.css", - "baseColor": "neutral", - "cssVariables": true, - "prefix": "" - }, - "iconLibrary": "tabler", - "rtl": false, - "menuColor": "default", - "menuAccent": "subtle", - "aliases": { - "components": "@/components", - "utils": "@/lib/utils", - "ui": "@/components/ui", - "lib": "@/lib", - "hooks": "@/hooks" - }, - "registries": {} -} diff --git a/app/src/components/ui/bubble.tsx b/app/src/components/ui/bubble.tsx index 0b4bfe2ff..2d007406e 100644 --- a/app/src/components/ui/bubble.tsx +++ b/app/src/components/ui/bubble.tsx @@ -1,9 +1,9 @@ -import * as React from "react" -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 type * as React from "react"; +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 { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; function BubbleGroup({ className, ...props }: React.ComponentProps<"div">) { return ( @@ -12,7 +12,7 @@ function BubbleGroup({ className, ...props }: React.ComponentProps<"div">) { className={cn("flex min-w-0 flex-col gap-2", className)} {...props} /> - ) + ); } const bubbleVariants = cva( @@ -39,8 +39,8 @@ const bubbleVariants = cva( defaultVariants: { variant: "default", }, - } -) + }, +); function Bubble({ variant = "default", @@ -49,7 +49,7 @@ function Bubble({ ...props }: React.ComponentProps<"div"> & VariantProps & { - align?: "start" | "end" + align?: "start" | "end"; }) { return (
- ) + ); } function BubbleContent({ @@ -73,16 +73,16 @@ function BubbleContent({ { className: cn( "w-fit max-w-full min-w-0 overflow-hidden rounded-xl border border-transparent px-3 py-2 text-sm leading-relaxed wrap-break-word group-data-[align=end]/bubble:self-end [button]:text-left [button,a]:transition-colors [button,a]:outline-none [button,a]:focus-visible:border-ring [button,a]:focus-visible:ring-3 [button,a]:focus-visible:ring-ring/50", - className + className, ), }, - props + props, ), render, state: { slot: "bubble-content", }, - }) + }); } const bubbleReactionsVariants = cva( @@ -102,8 +102,8 @@ const bubbleReactionsVariants = cva( side: "bottom", align: "end", }, - } -) + }, +); function BubbleReactions({ side = "bottom", @@ -111,8 +111,8 @@ function BubbleReactions({ className, ...props }: React.ComponentProps<"div"> & { - align?: "start" | "end" - side?: "top" | "bottom" + align?: "start" | "end"; + side?: "top" | "bottom"; }) { return (
- ) + ); } -export { BubbleGroup, Bubble, BubbleContent, BubbleReactions } +export { BubbleGroup, Bubble, BubbleContent, BubbleReactions }; diff --git a/app/src/components/ui/button.tsx b/app/src/components/ui/button.tsx index 2b49c9e21..06a2c1e31 100644 --- a/app/src/components/ui/button.tsx +++ b/app/src/components/ui/button.tsx @@ -1,7 +1,7 @@ -import { Button as ButtonPrimitive } from "@base-ui/react/button" -import { cva, type VariantProps } from "class-variance-authority" +import { Button as ButtonPrimitive } from "@base-ui/react/button"; +import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; const buttonVariants = cva( "group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-[color,background-color,border-color,box-shadow,translate,opacity] duration-150 ease-out outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", @@ -37,8 +37,8 @@ const buttonVariants = cva( variant: "default", size: "default", }, - } -) + }, +); function Button({ className, @@ -72,7 +72,7 @@ function Button({ render={render} {...props} /> - ) + ); } -export { Button, buttonVariants } +export { Button, buttonVariants }; diff --git a/app/src/components/ui/carousel.tsx b/app/src/components/ui/carousel.tsx index 90d0674ce..a795131dd 100644 --- a/app/src/components/ui/carousel.tsx +++ b/app/src/components/ui/carousel.tsx @@ -1,46 +1,46 @@ -import * as React from "react" +import * as React from "react"; // Upstream generates `import { cn } from "cn"`, pulling in a second class-merging package. This app // already has one at `@/lib/utils` — which is what `components.json` declares as the `utils` alias — // and every other file in this directory imports it from there. Re-point on regeneration. -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; import useEmblaCarousel, { type UseEmblaCarouselType, -} from "embla-carousel-react" +} from "embla-carousel-react"; -import { Button } from "@/components/ui/button" -import { IconChevronLeft, IconChevronRight } from "@tabler/icons-react" +import { Button } from "@/components/ui/button"; +import { IconChevronLeft, IconChevronRight } from "@tabler/icons-react"; -type CarouselApi = UseEmblaCarouselType[1] -type UseCarouselParameters = Parameters -type CarouselOptions = UseCarouselParameters[0] -type CarouselPlugin = UseCarouselParameters[1] +type CarouselApi = UseEmblaCarouselType[1]; +type UseCarouselParameters = Parameters; +type CarouselOptions = UseCarouselParameters[0]; +type CarouselPlugin = UseCarouselParameters[1]; type CarouselProps = { - opts?: CarouselOptions - plugins?: CarouselPlugin - orientation?: "horizontal" | "vertical" - setApi?: (api: CarouselApi) => void -} + opts?: CarouselOptions; + plugins?: CarouselPlugin; + orientation?: "horizontal" | "vertical"; + setApi?: (api: CarouselApi) => void; +}; type CarouselContextProps = { - carouselRef: ReturnType[0] - api: ReturnType[1] - scrollPrev: () => void - scrollNext: () => void - canScrollPrev: boolean - canScrollNext: boolean -} & CarouselProps + carouselRef: ReturnType[0]; + api: ReturnType[1]; + scrollPrev: () => void; + scrollNext: () => void; + canScrollPrev: boolean; + canScrollNext: boolean; +} & CarouselProps; -const CarouselContext = React.createContext(null) +const CarouselContext = React.createContext(null); function useCarousel() { - const context = React.useContext(CarouselContext) + const context = React.useContext(CarouselContext); if (!context) { - throw new Error("useCarousel must be used within a ") + throw new Error("useCarousel must be used within a "); } - return context + return context; } function Carousel({ @@ -57,53 +57,53 @@ function Carousel({ ...opts, axis: orientation === "horizontal" ? "x" : "y", }, - plugins - ) - const [canScrollPrev, setCanScrollPrev] = React.useState(false) - const [canScrollNext, setCanScrollNext] = React.useState(false) + plugins, + ); + const [canScrollPrev, setCanScrollPrev] = React.useState(false); + const [canScrollNext, setCanScrollNext] = React.useState(false); const onSelect = React.useCallback((api: CarouselApi) => { - if (!api) return - setCanScrollPrev(api.canScrollPrev()) - setCanScrollNext(api.canScrollNext()) - }, []) + if (!api) return; + setCanScrollPrev(api.canScrollPrev()); + setCanScrollNext(api.canScrollNext()); + }, []); const scrollPrev = React.useCallback(() => { - api?.scrollPrev() - }, [api]) + api?.scrollPrev(); + }, [api]); const scrollNext = React.useCallback(() => { - api?.scrollNext() - }, [api]) + api?.scrollNext(); + }, [api]); const handleKeyDown = React.useCallback( (event: React.KeyboardEvent) => { if (event.key === "ArrowLeft") { - event.preventDefault() - scrollPrev() + event.preventDefault(); + scrollPrev(); } else if (event.key === "ArrowRight") { - event.preventDefault() - scrollNext() + event.preventDefault(); + scrollNext(); } }, - [scrollPrev, scrollNext] - ) + [scrollPrev, scrollNext], + ); React.useEffect(() => { - if (!api || !setApi) return - setApi(api) - }, [api, setApi]) + if (!api || !setApi) return; + setApi(api); + }, [api, setApi]); React.useEffect(() => { - if (!api) return - onSelect(api) - api.on("reInit", onSelect) - api.on("select", onSelect) + if (!api) return; + onSelect(api); + api.on("reInit", onSelect); + api.on("select", onSelect); return () => { - api?.off("select", onSelect) - } - }, [api, onSelect]) + api?.off("select", onSelect); + }; + }, [api, onSelect]); return ( - ) + ); } function CarouselContent({ className, ...props }: React.ComponentProps<"div">) { - const { carouselRef, orientation } = useCarousel() + const { carouselRef, orientation } = useCarousel(); return (
) { className={cn( "flex", orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col", - className + className, )} {...props} />
- ) + ); } function CarouselItem({ className, ...props }: React.ComponentProps<"div">) { - const { orientation } = useCarousel() + const { orientation } = useCarousel(); return (
) { className={cn( "min-w-0 shrink-0 grow-0 basis-full", orientation === "horizontal" ? "pl-4" : "pt-4", - className + className, )} {...props} /> - ) + ); } function CarouselPrevious({ @@ -178,7 +178,7 @@ function CarouselPrevious({ size = "icon-sm", ...props }: React.ComponentProps) { - const { orientation, scrollPrev, canScrollPrev } = useCarousel() + const { orientation, scrollPrev, canScrollPrev } = useCarousel(); return ( - ) + ); } function CarouselNext({ @@ -208,7 +208,7 @@ function CarouselNext({ size = "icon-sm", ...props }: React.ComponentProps) { - const { orientation, scrollNext, canScrollNext } = useCarousel() + const { orientation, scrollNext, canScrollNext } = useCarousel(); return ( - ) + ); } export { @@ -240,4 +240,4 @@ export { CarouselPrevious, CarouselNext, useCarousel, -} +}; diff --git a/app/src/components/ui/checkbox.tsx b/app/src/components/ui/checkbox.tsx index a863a7054..8b9aaf935 100644 --- a/app/src/components/ui/checkbox.tsx +++ b/app/src/components/ui/checkbox.tsx @@ -1,7 +1,7 @@ -import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox" -import { IconCheck } from "@tabler/icons-react" +import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox"; +import { IconCheck } from "@tabler/icons-react"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) { return ( @@ -9,7 +9,7 @@ function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) { data-slot="checkbox" className={cn( "peer flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-input shadow-xs outline-none transition-[background-color,border-color,box-shadow] duration-150 ease-out focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground data-disabled:cursor-not-allowed data-disabled:opacity-50", - className + className, )} {...props} > @@ -20,7 +20,7 @@ function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) { - ) + ); } -export { Checkbox } +export { Checkbox }; diff --git a/app/src/components/ui/combobox.tsx b/app/src/components/ui/combobox.tsx index f741ca397..93cc871e7 100644 --- a/app/src/components/ui/combobox.tsx +++ b/app/src/components/ui/combobox.tsx @@ -1,22 +1,22 @@ -"use client" +"use client"; -import * as React from "react" -import { Combobox as ComboboxPrimitive } from "@base-ui/react" +import * as React from "react"; +import { Combobox as ComboboxPrimitive } from "@base-ui/react"; -import { cn } from "@/lib/utils" -import { Button } from "@/components/ui/button" +import { cn } from "@/lib/utils"; +import { Button } from "@/components/ui/button"; import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, -} from "@/components/ui/input-group" -import { IconChevronDown, IconX, IconCheck } from "@tabler/icons-react" +} from "@/components/ui/input-group"; +import { IconChevronDown, IconX, IconCheck } from "@tabler/icons-react"; -const Combobox = ComboboxPrimitive.Root +const Combobox = ComboboxPrimitive.Root; function ComboboxValue({ ...props }: ComboboxPrimitive.Value.Props) { - return + return ; } function ComboboxTrigger({ @@ -33,7 +33,7 @@ function ComboboxTrigger({ {children} - ) + ); } function ComboboxClear({ className, ...props }: ComboboxPrimitive.Clear.Props) { @@ -46,7 +46,7 @@ function ComboboxClear({ className, ...props }: ComboboxPrimitive.Clear.Props) { > - ) + ); } function ComboboxInput({ @@ -57,8 +57,8 @@ function ComboboxInput({ showClear = false, ...props }: ComboboxPrimitive.Input.Props & { - showTrigger?: boolean - showClear?: boolean + showTrigger?: boolean; + showClear?: boolean; }) { return ( @@ -84,7 +84,7 @@ function ComboboxInput({ {children} - ) + ); } function ComboboxContent({ @@ -113,12 +113,15 @@ function ComboboxContent({ - ) + ); } function ComboboxList({ className, ...props }: ComboboxPrimitive.List.Props) { @@ -127,11 +130,11 @@ function ComboboxList({ className, ...props }: ComboboxPrimitive.List.Props) { data-slot="combobox-list" className={cn( "no-scrollbar max-h-[min(calc(--spacing(72)---spacing(9)),calc(var(--available-height)---spacing(9)))] scroll-py-1 overflow-y-auto overscroll-contain p-1 data-empty:p-0", - className + className, )} {...props} /> - ) + ); } function ComboboxItem({ @@ -144,7 +147,7 @@ function ComboboxItem({ data-slot="combobox-item" className={cn( "relative flex w-full cursor-default items-center gap-2 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none data-highlighted:bg-accent data-highlighted:text-accent-foreground not-data-[variant=destructive]:data-highlighted:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", - className + className, )} {...props} > @@ -157,7 +160,7 @@ function ComboboxItem({ - ) + ); } function ComboboxGroup({ className, ...props }: ComboboxPrimitive.Group.Props) { @@ -167,7 +170,7 @@ function ComboboxGroup({ className, ...props }: ComboboxPrimitive.Group.Props) { className={cn(className)} {...props} /> - ) + ); } function ComboboxLabel({ @@ -180,13 +183,13 @@ function ComboboxLabel({ className={cn("px-2 py-1.5 text-xs text-muted-foreground", className)} {...props} /> - ) + ); } function ComboboxCollection({ ...props }: ComboboxPrimitive.Collection.Props) { return ( - ) + ); } function ComboboxEmpty({ className, ...props }: ComboboxPrimitive.Empty.Props) { @@ -195,11 +198,11 @@ function ComboboxEmpty({ className, ...props }: ComboboxPrimitive.Empty.Props) { data-slot="combobox-empty" className={cn( "hidden w-full justify-center py-2 text-center text-sm text-muted-foreground group-data-empty/combobox-content:flex", - className + className, )} {...props} /> - ) + ); } function ComboboxSeparator({ @@ -212,7 +215,7 @@ function ComboboxSeparator({ className={cn("-mx-1 my-1 h-px bg-border", className)} {...props} /> - ) + ); } function ComboboxChips({ @@ -225,11 +228,11 @@ function ComboboxChips({ data-slot="combobox-chips" className={cn( "flex min-h-8 flex-wrap items-center gap-1 rounded-lg border border-input bg-transparent bg-clip-padding px-2.5 py-1 text-sm transition-colors focus-within:border-ring focus-within:ring-3 focus-within:ring-ring/50 has-aria-invalid:border-destructive has-aria-invalid:ring-3 has-aria-invalid:ring-destructive/20 has-data-[slot=combobox-chip]:px-1 dark:bg-input/30 dark:has-aria-invalid:border-destructive/50 dark:has-aria-invalid:ring-destructive/40", - className + className, )} {...props} /> - ) + ); } function ComboboxChip({ @@ -238,14 +241,14 @@ function ComboboxChip({ showRemove = true, ...props }: ComboboxPrimitive.Chip.Props & { - showRemove?: boolean + showRemove?: boolean; }) { return ( @@ -260,7 +263,7 @@ function ComboboxChip({ )} - ) + ); } function ComboboxChipsInput({ @@ -273,11 +276,11 @@ function ComboboxChipsInput({ className={cn("min-w-16 flex-1 outline-none", className)} {...props} /> - ) + ); } function useComboboxAnchor() { - return React.useRef(null) + return React.useRef(null); } export { @@ -297,4 +300,4 @@ export { ComboboxTrigger, ComboboxValue, useComboboxAnchor, -} +}; diff --git a/app/src/components/ui/context-menu.tsx b/app/src/components/ui/context-menu.tsx index 3b23d1810..e2edfb1fe 100644 --- a/app/src/components/ui/context-menu.tsx +++ b/app/src/components/ui/context-menu.tsx @@ -1,17 +1,17 @@ -import * as React from "react" -import { ContextMenu as ContextMenuPrimitive } from "@base-ui/react/context-menu" +import type * as React from "react"; +import { ContextMenu as ContextMenuPrimitive } from "@base-ui/react/context-menu"; -import { cn } from "@/lib/utils" -import { IconChevronRight, IconCheck } from "@tabler/icons-react" +import { cn } from "@/lib/utils"; +import { IconChevronRight, IconCheck } from "@tabler/icons-react"; function ContextMenu({ ...props }: ContextMenuPrimitive.Root.Props) { - return + return ; } function ContextMenuPortal({ ...props }: ContextMenuPrimitive.Portal.Props) { return ( - ) + ); } function ContextMenuTrigger({ @@ -24,7 +24,7 @@ function ContextMenuTrigger({ className={cn("select-none", className)} {...props} /> - ) + ); } function ContextMenuContent({ @@ -50,18 +50,21 @@ function ContextMenuContent({ > - ) + ); } function ContextMenuGroup({ ...props }: ContextMenuPrimitive.Group.Props) { return ( - ) + ); } function ContextMenuLabel({ @@ -69,7 +72,7 @@ function ContextMenuLabel({ inset, ...props }: ContextMenuPrimitive.GroupLabel.Props & { - inset?: boolean + inset?: boolean; }) { return ( - ) + ); } function ContextMenuItem({ @@ -90,8 +93,8 @@ function ContextMenuItem({ variant = "default", ...props }: ContextMenuPrimitive.Item.Props & { - inset?: boolean - variant?: "default" | "destructive" + inset?: boolean; + variant?: "default" | "destructive"; }) { return ( - ) + ); } function ContextMenuSub({ ...props }: ContextMenuPrimitive.SubmenuRoot.Props) { return ( - ) + ); } function ContextMenuSubTrigger({ @@ -119,7 +122,7 @@ function ContextMenuSubTrigger({ children, ...props }: ContextMenuPrimitive.SubmenuTrigger.Props & { - inset?: boolean + inset?: boolean; }) { return ( {children} - ) + ); } function ContextMenuSubContent({ @@ -147,7 +150,7 @@ function ContextMenuSubContent({ side="right" {...props} /> - ) + ); } function ContextMenuCheckboxItem({ @@ -157,7 +160,7 @@ function ContextMenuCheckboxItem({ inset, ...props }: ContextMenuPrimitive.CheckboxItem.Props & { - inset?: boolean + inset?: boolean; }) { return ( - + {children} - ) + ); } function ContextMenuRadioGroup({ @@ -189,7 +191,7 @@ function ContextMenuRadioGroup({ data-slot="context-menu-radio-group" {...props} /> - ) + ); } function ContextMenuRadioItem({ @@ -198,7 +200,7 @@ function ContextMenuRadioItem({ inset, ...props }: ContextMenuPrimitive.RadioItem.Props & { - inset?: boolean + inset?: boolean; }) { return ( - + {children} - ) + ); } function ContextMenuSeparator({ @@ -231,7 +232,7 @@ function ContextMenuSeparator({ className={cn("-mx-1 my-1 h-px bg-border", className)} {...props} /> - ) + ); } function ContextMenuShortcut({ @@ -243,11 +244,11 @@ function ContextMenuShortcut({ data-slot="context-menu-shortcut" className={cn( "ml-auto text-xs tracking-widest text-muted-foreground group-focus/context-menu-item:text-accent-foreground", - className + className, )} {...props} /> - ) + ); } export { @@ -266,4 +267,4 @@ export { ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuRadioGroup, -} +}; diff --git a/app/src/components/ui/dialog.tsx b/app/src/components/ui/dialog.tsx index bd5f78798..a33ce6bc6 100644 --- a/app/src/components/ui/dialog.tsx +++ b/app/src/components/ui/dialog.tsx @@ -32,7 +32,10 @@ function DialogPortal({ ...props }: DialogPrimitive.Portal.Props) { return ; } -function DialogOverlay({ className, ...props }: DialogPrimitive.Backdrop.Props) { +function DialogOverlay({ + className, + ...props +}: DialogPrimitive.Backdrop.Props) { return ( ); diff --git a/app/src/components/ui/dropdown-menu.tsx b/app/src/components/ui/dropdown-menu.tsx index 46ef9f2f9..4a7eeed5e 100644 --- a/app/src/components/ui/dropdown-menu.tsx +++ b/app/src/components/ui/dropdown-menu.tsx @@ -1,19 +1,19 @@ -import * as React from "react" -import { Menu as MenuPrimitive } from "@base-ui/react/menu" +import type * as React from "react"; +import { Menu as MenuPrimitive } from "@base-ui/react/menu"; -import { cn } from "@/lib/utils" -import { IconChevronRight, IconCheck } from "@tabler/icons-react" +import { cn } from "@/lib/utils"; +import { IconChevronRight, IconCheck } from "@tabler/icons-react"; function DropdownMenu({ ...props }: MenuPrimitive.Root.Props) { - return + return ; } function DropdownMenuPortal({ ...props }: MenuPrimitive.Portal.Props) { - return + return ; } function DropdownMenuTrigger({ ...props }: MenuPrimitive.Trigger.Props) { - return + return ; } function DropdownMenuContent({ @@ -39,16 +39,19 @@ function DropdownMenuContent({ > - ) + ); } function DropdownMenuGroup({ ...props }: MenuPrimitive.Group.Props) { - return + return ; } function DropdownMenuLabel({ @@ -56,7 +59,7 @@ function DropdownMenuLabel({ inset, ...props }: MenuPrimitive.GroupLabel.Props & { - inset?: boolean + inset?: boolean; }) { return ( - ) + ); } function DropdownMenuItem({ @@ -77,8 +80,8 @@ function DropdownMenuItem({ variant = "default", ...props }: MenuPrimitive.Item.Props & { - inset?: boolean - variant?: "default" | "destructive" + inset?: boolean; + variant?: "default" | "destructive"; }) { return ( - ) + ); } function DropdownMenuSub({ ...props }: MenuPrimitive.SubmenuRoot.Props) { - return + return ; } function DropdownMenuSubTrigger({ @@ -104,7 +107,7 @@ function DropdownMenuSubTrigger({ children, ...props }: MenuPrimitive.SubmenuTrigger.Props & { - inset?: boolean + inset?: boolean; }) { return ( {children} - ) + ); } function DropdownMenuSubContent({ @@ -133,14 +136,17 @@ function DropdownMenuSubContent({ return ( - ) + ); } function DropdownMenuCheckboxItem({ @@ -150,7 +156,7 @@ function DropdownMenuCheckboxItem({ inset, ...props }: MenuPrimitive.CheckboxItem.Props & { - inset?: boolean + inset?: boolean; }) { return ( - + {children} - ) + ); } function DropdownMenuRadioGroup({ ...props }: MenuPrimitive.RadioGroup.Props) { @@ -183,7 +188,7 @@ function DropdownMenuRadioGroup({ ...props }: MenuPrimitive.RadioGroup.Props) { data-slot="dropdown-menu-radio-group" {...props} /> - ) + ); } function DropdownMenuRadioItem({ @@ -192,7 +197,7 @@ function DropdownMenuRadioItem({ inset, ...props }: MenuPrimitive.RadioItem.Props & { - inset?: boolean + inset?: boolean; }) { return ( @@ -209,13 +214,12 @@ function DropdownMenuRadioItem({ data-slot="dropdown-menu-radio-item-indicator" > - + {children} - ) + ); } function DropdownMenuSeparator({ @@ -228,7 +232,7 @@ function DropdownMenuSeparator({ className={cn("-mx-1 my-1 h-px bg-border", className)} {...props} /> - ) + ); } function DropdownMenuShortcut({ @@ -240,11 +244,11 @@ function DropdownMenuShortcut({ data-slot="dropdown-menu-shortcut" className={cn( "ml-auto text-xs tracking-widest text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground", - className + className, )} {...props} /> - ) + ); } export { @@ -263,4 +267,4 @@ export { DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, -} +}; diff --git a/app/src/components/ui/empty.tsx b/app/src/components/ui/empty.tsx index b23187b04..c58117a1d 100644 --- a/app/src/components/ui/empty.tsx +++ b/app/src/components/ui/empty.tsx @@ -1,6 +1,6 @@ -import { cva, type VariantProps } from "class-variance-authority" +import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; function Empty({ className, ...props }: React.ComponentProps<"div">) { return ( @@ -8,11 +8,11 @@ function Empty({ className, ...props }: React.ComponentProps<"div">) { data-slot="empty" className={cn( "flex w-full min-w-0 flex-1 flex-col items-center justify-center gap-4 rounded-xl border-dashed p-6 text-center text-balance", - className + className, )} {...props} /> - ) + ); } function EmptyHeader({ className, ...props }: React.ComponentProps<"div">) { @@ -22,7 +22,7 @@ function EmptyHeader({ className, ...props }: React.ComponentProps<"div">) { className={cn("flex max-w-sm flex-col items-center gap-2", className)} {...props} /> - ) + ); } const emptyMediaVariants = cva( @@ -37,8 +37,8 @@ const emptyMediaVariants = cva( defaultVariants: { variant: "default", }, - } -) + }, +); function EmptyMedia({ className, @@ -52,7 +52,7 @@ function EmptyMedia({ className={cn(emptyMediaVariants({ variant, className }))} {...props} /> - ) + ); } function EmptyTitle({ className, ...props }: React.ComponentProps<"div">) { @@ -61,11 +61,11 @@ function EmptyTitle({ className, ...props }: React.ComponentProps<"div">) { data-slot="empty-title" className={cn( "font-heading text-sm font-medium tracking-tight", - className + className, )} {...props} /> - ) + ); } function EmptyDescription({ className, ...props }: React.ComponentProps<"p">) { @@ -74,11 +74,11 @@ function EmptyDescription({ className, ...props }: React.ComponentProps<"p">) { data-slot="empty-description" className={cn( "text-sm/relaxed text-muted-foreground [&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary", - className + className, )} {...props} /> - ) + ); } function EmptyContent({ className, ...props }: React.ComponentProps<"div">) { @@ -87,11 +87,11 @@ function EmptyContent({ className, ...props }: React.ComponentProps<"div">) { data-slot="empty-content" className={cn( "flex w-full max-w-sm min-w-0 flex-col items-center gap-2.5 text-sm text-balance", - className + className, )} {...props} /> - ) + ); } export { @@ -101,4 +101,4 @@ export { EmptyDescription, EmptyContent, EmptyMedia, -} +}; diff --git a/app/src/components/ui/field.tsx b/app/src/components/ui/field.tsx index 68e319c64..f7c1761d8 100644 --- a/app/src/components/ui/field.tsx +++ b/app/src/components/ui/field.tsx @@ -192,15 +192,15 @@ function FieldError({ ...new Map(errors.map((error) => [error?.message, error])).values(), ]; - if (uniqueErrors?.length == 1) { + if (uniqueErrors?.length === 1) { return uniqueErrors[0]?.message; } return (
    {uniqueErrors.map( - (error, index) => - error?.message &&
  • {error.message}
  • , + (error) => + error?.message &&
  • {error.message}
  • , )}
); diff --git a/app/src/components/ui/input-group.tsx b/app/src/components/ui/input-group.tsx index b38b35086..beb07031e 100644 --- a/app/src/components/ui/input-group.tsx +++ b/app/src/components/ui/input-group.tsx @@ -1,10 +1,10 @@ -import * as React from "react" -import { cva, type VariantProps } from "class-variance-authority" +import type * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "@/lib/utils" -import { Button } from "@/components/ui/button" -import { Input } from "@/components/ui/input" -import { Textarea } from "@/components/ui/textarea" +import { cn } from "@/lib/utils"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Textarea } from "@/components/ui/textarea"; function InputGroup({ className, ...props }: React.ComponentProps<"div">) { return ( @@ -13,11 +13,11 @@ function InputGroup({ className, ...props }: React.ComponentProps<"div">) { role="group" className={cn( "group/input-group relative flex h-9 w-full min-w-0 items-center rounded-lg border border-input transition-colors outline-none in-data-[slot=combobox-content]:focus-within:border-inherit in-data-[slot=combobox-content]:focus-within:ring-0 has-disabled:bg-input/50 has-disabled:opacity-50 has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-3 has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-3 has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>textarea]:h-auto dark:bg-input/30 dark:has-disabled:bg-input/80 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5", - className + className, )} {...props} /> - ) + ); } const inputGroupAddonVariants = cva( @@ -38,8 +38,8 @@ const inputGroupAddonVariants = cva( defaultVariants: { align: "inline-start", }, - } -) + }, +); function InputGroupAddon({ className, @@ -54,13 +54,13 @@ function InputGroupAddon({ className={cn(inputGroupAddonVariants({ align }), className)} onClick={(e) => { if ((e.target as HTMLElement).closest("button")) { - return + return; } - e.currentTarget.parentElement?.querySelector("input")?.focus() + e.currentTarget.parentElement?.querySelector("input")?.focus(); }} {...props} /> - ) + ); } const inputGroupButtonVariants = cva( @@ -78,8 +78,8 @@ const inputGroupButtonVariants = cva( defaultVariants: { size: "xs", }, - } -) + }, +); function InputGroupButton({ className, @@ -89,7 +89,7 @@ function InputGroupButton({ ...props }: Omit, "size" | "type"> & VariantProps & { - type?: "button" | "submit" | "reset" + type?: "button" | "submit" | "reset"; }) { return (
- ) + ); } function QuestionnaireError({ @@ -184,7 +187,7 @@ function QuestionnaireError({ className={cn("mt-2 text-sm text-destructive", className)} {...props} /> - ) + ); } function QuestionnaireActions({ @@ -196,11 +199,11 @@ function QuestionnaireActions({ data-slot="questionnaire-actions" className={cn( "grid min-h-11 w-full grid-cols-[minmax(0,1fr)_auto_auto] items-center gap-2 sm:min-h-8", - className + className, )} {...props} /> - ) + ); } function QuestionnairePrevious({ @@ -219,13 +222,13 @@ function QuestionnairePrevious({ className={cn( buttonVariants({ size, variant }), "col-start-1 row-start-1 min-h-11 justify-self-start sm:min-h-0", - className + className, )} {...props} > {children ?? "Previous"} - ) + ); } function QuestionnaireSkip({ @@ -244,13 +247,13 @@ function QuestionnaireSkip({ className={cn( buttonVariants({ size, variant }), "col-start-2 row-start-1 min-h-11 justify-self-end sm:min-h-0", - className + className, )} {...props} > {children ?? "Skip"} - ) + ); } function QuestionnaireNext({ @@ -269,13 +272,13 @@ function QuestionnaireNext({ className={cn( buttonVariants({ size, variant }), "col-start-3 row-start-1 min-h-11 justify-self-end sm:min-h-0", - className + className, )} {...props} > {children ?? "Next"} - ) + ); } function QuestionnaireSubmit({ @@ -294,13 +297,13 @@ function QuestionnaireSubmit({ className={cn( buttonVariants({ size, variant }), "col-start-3 row-start-1 min-h-11 justify-self-end sm:min-h-0", - className + className, )} {...props} > {children ?? "Submit"} - ) + ); } export { @@ -319,4 +322,4 @@ export { QuestionnaireSkip, QuestionnaireSubmit, QuestionnaireTitle, -} +}; diff --git a/app/src/components/ui/select.tsx b/app/src/components/ui/select.tsx index e89995e3a..c7419857a 100644 --- a/app/src/components/ui/select.tsx +++ b/app/src/components/ui/select.tsx @@ -1,4 +1,4 @@ -import * as React from "react"; +import type * as React from "react"; import { Select as SelectPrimitive } from "@base-ui/react/select"; import { cn } from "@/lib/utils"; diff --git a/app/src/components/ui/sheet.tsx b/app/src/components/ui/sheet.tsx index 4d14062ed..b2a861c84 100644 --- a/app/src/components/ui/sheet.tsx +++ b/app/src/components/ui/sheet.tsx @@ -1,4 +1,4 @@ -import * as React from "react"; +import type * as React from "react"; import { Dialog as SheetPrimitive } from "@base-ui/react/dialog"; import { cn } from "@/lib/utils"; diff --git a/app/src/components/ui/sidebar.tsx b/app/src/components/ui/sidebar.tsx index ceec714c1..a9d79fb63 100644 --- a/app/src/components/ui/sidebar.tsx +++ b/app/src/components/ui/sidebar.tsx @@ -107,7 +107,7 @@ function SidebarProvider({ // Helper to toggle the sidebar. const toggleSidebar = React.useCallback(() => { return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open); - }, [isMobile, setOpen, setOpenMobile]); + }, [isMobile, setOpen]); // Adds a keyboard shortcut to toggle the sidebar. React.useEffect(() => { @@ -139,7 +139,7 @@ function SidebarProvider({ setOpenMobile, toggleSidebar, }), - [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar], + [state, open, setOpen, isMobile, openMobile, toggleSidebar], ); return ( diff --git a/app/src/components/ui/switch.tsx b/app/src/components/ui/switch.tsx index 7ed946b88..3b0e10c66 100644 --- a/app/src/components/ui/switch.tsx +++ b/app/src/components/ui/switch.tsx @@ -1,13 +1,13 @@ -import { Switch as SwitchPrimitive } from "@base-ui/react/switch" +import { Switch as SwitchPrimitive } from "@base-ui/react/switch"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; function Switch({ className, size = "default", ...props }: SwitchPrimitive.Root.Props & { - size?: "sm" | "default" + size?: "sm" | "default"; }) { return ( @@ -24,7 +24,7 @@ function Switch({ className="pointer-events-none block rounded-full bg-background ring-0 transition-transform duration-150 ease-out group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=default]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-checked:translate-x-[calc(100%-2px)] dark:data-checked:bg-primary-foreground group-data-[size=default]/switch:data-unchecked:translate-x-0 group-data-[size=sm]/switch:data-unchecked:translate-x-0 dark:data-unchecked:bg-foreground" /> - ) + ); } -export { Switch } +export { Switch }; diff --git a/app/src/components/ui/textarea.tsx b/app/src/components/ui/textarea.tsx index 04d27f7d1..9da9eab61 100644 --- a/app/src/components/ui/textarea.tsx +++ b/app/src/components/ui/textarea.tsx @@ -1,6 +1,6 @@ -import * as React from "react" +import type * as React from "react"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; function Textarea({ className, ...props }: React.ComponentProps<"textarea">) { return ( @@ -8,11 +8,11 @@ function Textarea({ className, ...props }: React.ComponentProps<"textarea">) { data-slot="textarea" className={cn( "flex field-sizing-content min-h-16 w-full rounded-lg border border-input bg-transparent px-2.5 py-2 text-base transition-colors outline-none placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40", - className + className, )} {...props} /> - ) + ); } -export { Textarea } +export { Textarea }; diff --git a/app/src/styles.css b/app/src/styles.css index 2326b7d04..653b84df5 100644 --- a/app/src/styles.css +++ b/app/src/styles.css @@ -244,10 +244,10 @@ body { /* * Row descriptions wrap on sense rather than on width. * - * Here rather than on the `ItemDescription` primitive, which is where this started. That file has an - * upstream: it is vendored from shadcn and the layout skill says not to edit it, so a class added - * inside it is one the next `shadcn add item` silently removes — and the loss would surface as "the - * screens look slightly worse" months later, with nothing to attribute it to. + * Here rather than on the `ItemDescription` primitive, which is where this started. The reason was + * that the primitive was vendored and the next `shadcn add item` would silently remove anything put + * inside it; the primitives are the repository's own now, so that is no longer true. It stays here + * because it belongs with the other layout rules rather than inside one primitive. * * The primitive already emits the attribute this selects, so nothing has to be edited for it to * apply, and nothing upstream can take it away. diff --git a/biome.json b/biome.json index 9887f67d0..4bdd1512b 100644 --- a/biome.json +++ b/biome.json @@ -5,7 +5,6 @@ "**", "!**/dist", "!.", - "!app/src/components/ui", "!app/src/lib/generated/application-config.ts", "!app/src/routeTree.gen.ts", "!desktop/src-tauri/gen", @@ -35,6 +34,18 @@ } } } + }, + { + "includes": ["app/src/components/ui/**"], + "linter": { + "rules": { + "a11y": { + "useSemanticElements": "off", + "noLabelWithoutControl": "off", + "useKeyWithClickEvents": "off" + } + } + } } ] } diff --git a/bun.lock b/bun.lock index 5819897eb..77185aa7a 100644 --- a/bun.lock +++ b/bun.lock @@ -217,7 +217,7 @@ "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q=="], - "@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.29.7", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.29.7", "@babel/helper-create-class-features-plugin": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", "@babel/plugin-syntax-typescript": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw=="], + "@babel/plugin-transform-typescript": ["@babel/plugin-transform-typescript@7.29.9", "", { "dependencies": { "@babel/helper-annotate-as-pure": "^7.29.7", "@babel/helper-create-class-features-plugin": "^7.29.7", "@babel/helper-plugin-utils": "^7.29.7", "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", "@babel/plugin-syntax-typescript": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-FFwIwzU+7SCOuxxV4YtJql6T9981ZVTm+FHO5GhVsRqCTdy0WwrEZh3l42ARpXruJUDGOptdduHW6Zr7pNPLNg=="], "@babel/preset-typescript": ["@babel/preset-typescript@7.29.7", "", { "dependencies": { "@babel/helper-plugin-utils": "^7.29.7", "@babel/helper-validator-option": "^7.29.7", "@babel/plugin-syntax-jsx": "^7.29.7", "@babel/plugin-transform-modules-commonjs": "^7.29.7", "@babel/plugin-transform-typescript": "^7.29.7" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ=="], @@ -957,7 +957,7 @@ "asn1": ["asn1@0.2.6", "", { "dependencies": { "safer-buffer": "~2.1.0" } }, "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ=="], - "ast-types": ["ast-types@0.16.1", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg=="], + "ast-types": ["ast-types@0.16.3", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-FvWoWYfSCM6kRxCSH+MGLHIKKGRL6A6AW7Zek2O32REPQRdg131428uRTKMBYAeRd3XXAaHDS60Wpri7CdKDrA=="], "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], @@ -987,7 +987,7 @@ "boring-avatars": ["boring-avatars@2.0.4", "", { "peerDependencies": { "react": ">=18.0.0", "react-dom": ">=18.0.0" } }, "sha512-xhZO/w/6aFmRfkaWohcl2NfyIy87gK5SBbys8kctZeTGF1Apjpv/10pfUuv+YEfVPkESU/h2Y6tt/Dwp+bIZPw=="], - "brace-expansion": ["brace-expansion@5.0.9", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg=="], + "brace-expansion": ["brace-expansion@5.0.12", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ=="], "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], @@ -1051,6 +1051,8 @@ "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], + "cn": ["cn@0.2.6", "", { "bin": { "cn": "bin/cn.mjs" } }, "sha512-+i4L0zUGgRcEnhsxueVrP7iBGxBx5iD0WOTYg1MwFEu2ZyCmH5Ov2V1cul2Ht5UchRQQgftCf4be/RxspuW6QQ=="], + "code-block-writer": ["code-block-writer@13.0.3", "", {}, "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg=="], "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], @@ -1539,7 +1541,7 @@ "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], - "js-yaml": ["js-yaml@4.3.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ=="], + "js-yaml": ["js-yaml@4.3.2", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA=="], "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], @@ -1839,7 +1841,7 @@ "oniguruma-to-es": ["oniguruma-to-es@4.3.6", "", { "dependencies": { "oniguruma-parser": "^0.12.2", "regex": "^6.1.0", "regex-recursion": "^6.0.2" } }, "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA=="], - "open": ["open@11.0.1", "", { "dependencies": { "default-browser": "^5.4.0", "define-lazy-prop": "^3.0.0", "is-in-ssh": "^1.0.0", "is-inside-container": "^1.0.0", "powershell-utils": "^0.2.0", "wsl-utils": "^1.0.0" } }, "sha512-NzwMUB6C1D0+Kd+9iMS/H4k+Ck3cTX6Ckyfr/gAGlmvSE1LUQZnEZvWBi4PYmMwH/S5SMeTXnE+9uAz8uF+pWw=="], + "open": ["open@11.0.4", "", { "dependencies": { "default-browser": "^5.5.1", "define-lazy-prop": "^3.0.0", "is-in-ssh": "^1.0.0", "is-inside-container": "^1.0.0", "powershell-utils": "^0.2.1", "wsl-utils": "^1.0.0" } }, "sha512-++Zlftm0kVLPmzC06t6epuWmcRMDbI4z5P3NNX979WA/k23+NtSOynEGzsVfZwguKw2mi5umVgnBlJQMwRz4Pg=="], "openai": ["openai@7.5.0", "", { "peerDependencies": { "@aws-sdk/credential-provider-node": ">=3.972.0 <4", "@smithy/hash-node": ">=4.3.0 <5", "@smithy/signature-v4": ">=5.4.0 <6", "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["@aws-sdk/credential-provider-node", "@smithy/hash-node", "@smithy/signature-v4", "ws", "zod"] }, "sha512-ZbDBz8FSB8Mv8fFYIUvzTFMdV5vl93/octp1MdtK2lfYepSpfv/ewmeugpKz/cwGtFSx+YuUM4NwpZ2P55YiPA=="], @@ -1915,13 +1917,13 @@ "postcss": ["postcss@8.5.26", "", { "dependencies": { "nanoid": "^3.3.17", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ=="], - "postcss-selector-parser": ["postcss-selector-parser@7.1.5", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-KvvtD7SrlBP7dlgkBghEE3r84CABm5SmV2aNcG4oCA+qDnJ/tvKonFVvwWAyyWUEwxuNawdfEAZKP9zM3oZ2Uw=="], + "postcss-selector-parser": ["postcss-selector-parser@7.1.6", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-7qASPzhKF2l2KLboRZux8CCTRMdGiV08vWmyKzPz22qZ7ZjQBOeY7rNzNoCLSUiftJ7HUq0GERHmxw/t0dCdMw=="], "postgres": ["postgres@3.4.9", "", {}, "sha512-GD3qdB0x1z9xgFI6cdRD6xu2Sp2WCOEoe3mtnyB5Ee0XrrL5Pe+e4CCnJrRMnL1zYtRDZmQQVbvOttLnKDLnaw=="], "posthog-node": ["posthog-node@5.51.6", "", { "dependencies": { "@posthog/core": "^1.50.0" }, "peerDependencies": { "rxjs": "^7.0.0" }, "optionalPeers": ["rxjs"] }, "sha512-r+Ge3p0OnOcOWeTnvKZmAtDwECeIoyNTyxBxuZc8wM6RHCQ9j2Xrhogrf39HSq1Y2gIOpWLqIDRmWDcu7xmqcA=="], - "powershell-utils": ["powershell-utils@0.2.0", "", {}, "sha512-ZlsFlG7MtSFCoc5xreOvBAozCJ6Pf06opgJjh9ONEv418xpZSAzNjstD36C6+JwOnfSqOW/9uDkqKjezTdxZhw=="], + "powershell-utils": ["powershell-utils@0.2.1", "", {}, "sha512-C+y9x90UElAddDZmV4qOx9W53B61PO7cIqWz2dQsWlwswuq4mr8NEwytdGKboYbQlGZ3awrkTeNvcZiZNHnQ8A=="], "prettier": ["prettier@3.9.6", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g=="], @@ -2083,7 +2085,7 @@ "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], - "shadcn": ["shadcn@4.19.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/parser": "^7.28.0", "@babel/plugin-transform-typescript": "^7.28.0", "@babel/preset-typescript": "^7.27.1", "@dotenvx/dotenvx": "^1.48.4", "@modelcontextprotocol/sdk": "^1.26.0", "@types/validate-npm-package-name": "^4.0.2", "browserslist": "^4.26.2", "commander": "^14.0.0", "cosmiconfig": "^9.0.0", "dedent": "^1.6.0", "deepmerge": "^4.3.1", "diff": "^8.0.2", "execa": "^9.6.0", "fast-glob": "^3.3.3", "fs-extra": "^11.3.1", "fuzzysort": "^3.1.0", "kleur": "^4.1.5", "open": "^11.0.0", "ora": "^8.2.0", "postcss": "^8.5.6", "postcss-selector-parser": "^7.1.0", "prompts": "^2.4.2", "recast": "^0.23.11", "socks": "^2.8.8", "stringify-object": "^5.0.0", "tailwind-merge": "^3.0.1", "ts-morph": "^26.0.0", "tsconfig-paths": "^4.2.0", "undici": "^7.27.2", "validate-npm-package-name": "^7.0.1", "zod": "^3.24.1", "zod-to-json-schema": "^3.24.6" }, "bin": { "shadcn": "dist/index.js" } }, "sha512-EQF6R+CUXTsEP2BpyhxrUEAFesrtFD1POvVOf5jM+wkgtA4kG1EW1+1Wlmi9LqiprSL681JJXBcS0u8WkVVVyQ=="], + "shadcn": ["shadcn@4.21.0", "", { "dependencies": { "@babel/core": "^7.28.0", "@babel/parser": "^7.28.0", "@babel/plugin-transform-typescript": "^7.28.0", "@babel/preset-typescript": "^7.27.1", "@dotenvx/dotenvx": "^1.48.4", "@modelcontextprotocol/sdk": "^1.26.0", "@types/validate-npm-package-name": "^4.0.2", "browserslist": "^4.26.2", "cn": "^0.2.4", "commander": "^14.0.0", "cosmiconfig": "^9.0.0", "dedent": "^1.6.0", "deepmerge": "^4.3.1", "diff": "^8.0.2", "execa": "^9.6.0", "fast-glob": "^3.3.3", "fs-extra": "^11.3.1", "fuzzysort": "^3.1.0", "kleur": "^4.1.5", "open": "^11.0.0", "ora": "^8.2.0", "postcss": "^8.5.6", "postcss-selector-parser": "^7.1.0", "prompts": "^2.4.2", "recast": "^0.23.11", "socks": "^2.8.8", "stringify-object": "^5.0.0", "ts-morph": "^26.0.0", "tsconfig-paths": "^4.2.0", "undici": "^7.27.2", "validate-npm-package-name": "^7.0.1", "zod": "^3.24.1", "zod-to-json-schema": "^3.24.6" }, "bin": { "shadcn": "dist/index.js" } }, "sha512-UU2mFNusW8C5rvadKdH69vERYZqUlOOlXBcf0MYhYLdTGP6DPti7X4qovCu+RTfCqsAgq/T+YfE0Vnttxh9aiw=="], "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], @@ -2105,7 +2107,7 @@ "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="], - "socks": ["socks@2.8.9", "", { "dependencies": { "ip-address": "^10.1.1", "smart-buffer": "^4.2.0" } }, "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw=="], + "socks": ["socks@2.8.10", "", { "dependencies": { "ip-address": "^10.1.1", "smart-buffer": "^4.2.0" } }, "sha512-e0VyvkVTwVYViNovRkZ9aodhxVlyoMn7eJhVUPxZ+eK9P/7CBkxvvsBOHqFPEH416726W8tLXXXjKwqgTErrCQ=="], "sonic-boom": ["sonic-boom@4.2.1", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q=="], @@ -2157,7 +2159,7 @@ "supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], - "systeminformation": ["systeminformation@5.33.1", "", { "os": "!aix", "bin": { "systeminformation": "lib/cli.js" } }, "sha512-DEN6ICHk3Tk0Uf/hrAHh7xlt7iL5CJFBtPZinA0H62DrGG/KPKqq/Nzj6lCXPS4Ay/sf/14zNnk9LpqKzBIc+w=="], + "systeminformation": ["systeminformation@5.33.11", "", { "os": "!aix", "bin": { "systeminformation": "lib/cli.js" } }, "sha512-CNGk+882EQbsbPzaoxeBcYyx+nk0uTj5JzW8w0EXGSCazndNRAh9SE0V5tyMbdONGKilbIBJsyskF4WmZDk7uA=="], "tailwind-merge": ["tailwind-merge@3.6.0", "", {}, "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w=="],