@kinetixui/ui 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1050,6 +1050,40 @@ interface NavigationBarProps extends Omit<React$1.HTMLAttributes<HTMLElement>, "
1050
1050
  }
1051
1051
  declare const NavigationBar: React$1.ForwardRefExoticComponent<NavigationBarProps & React$1.RefAttributes<HTMLElement>>;
1052
1052
 
1053
+ /**
1054
+ * AppBar — a web application top bar: a brand slot, a row of primary nav
1055
+ * links, and a trailing actions slot inside a sticky bordered header. Below
1056
+ * the `md` breakpoint the nav collapses behind a menu toggle into a panel
1057
+ * under the bar.
1058
+ *
1059
+ * <AppBar>
1060
+ * <AppBarBrand>Acme</AppBarBrand>
1061
+ * <AppBarNav>
1062
+ * <AppBarLink href="/" active>Overview</AppBarLink>
1063
+ * <AppBarLink href="/reports">Reports</AppBarLink>
1064
+ * </AppBarNav>
1065
+ * <AppBarActions><Button size="sm">New</Button></AppBarActions>
1066
+ * </AppBar>
1067
+ *
1068
+ * `NavigationBar` is the mobile back-button bar; this is the desktop app shell.
1069
+ */
1070
+ interface AppBarCtx {
1071
+ open: boolean;
1072
+ setOpen: React$1.Dispatch<React$1.SetStateAction<boolean>>;
1073
+ }
1074
+ declare const useAppBar: () => AppBarCtx;
1075
+ declare const AppBar: React$1.ForwardRefExoticComponent<React$1.HTMLAttributes<HTMLElement> & React$1.RefAttributes<HTMLElement>>;
1076
+ declare const AppBarBrand: React$1.ForwardRefExoticComponent<React$1.HTMLAttributes<HTMLDivElement> & React$1.RefAttributes<HTMLDivElement>>;
1077
+ declare const AppBarNav: React$1.ForwardRefExoticComponent<React$1.HTMLAttributes<HTMLElement> & React$1.RefAttributes<HTMLElement>>;
1078
+ interface AppBarLinkProps extends React$1.AnchorHTMLAttributes<HTMLAnchorElement> {
1079
+ /** Marks the current destination — sets `aria-current="page"` and the active style. */
1080
+ active?: boolean;
1081
+ /** Render as the child element (e.g. a framework `<Link>`), forwarding props. */
1082
+ asChild?: boolean;
1083
+ }
1084
+ declare const AppBarLink: React$1.ForwardRefExoticComponent<AppBarLinkProps & React$1.RefAttributes<HTMLAnchorElement>>;
1085
+ declare const AppBarActions: React$1.ForwardRefExoticComponent<React$1.HTMLAttributes<HTMLDivElement> & React$1.RefAttributes<HTMLDivElement>>;
1086
+
1053
1087
  /**
1054
1088
  * FileUpload — a drag-and-drop zone plus file list, single or multiple.
1055
1089
  * Upload logic (network, storage) is the consumer's — this component is
@@ -1198,4 +1232,4 @@ declare const TableOfContents: React$1.ForwardRefExoticComponent<TableOfContents
1198
1232
  /** Merges Tailwind class names, resolving conflicts (clsx + tailwind-merge). */
1199
1233
  declare function cn(...inputs: ClassValue[]): string;
1200
1234
 
1201
- export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AspectRatio, AudioPlayer, type AudioPlayerProps, Avatar, AvatarFallback, AvatarGroup, type AvatarGroupProps, AvatarImage, Badge, type BadgeProps, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, type ButtonProps, Calendar, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, type CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, type ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, Checkbox, CircularProgress, type CircularProgressProps, CodeBlock, type CodeBlockFile, type CodeBlockProps, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, DataTable, DatePicker, type DatePickerProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Fab, type FabProps, Field, FieldControl, FieldDescription, FieldLabel, FieldMessage, FileUpload, FileUploadItem, type FileUploadItemProps, type FileUploadProps, Footer, FooterBottom, FooterColumn, type FooterColumnProps, FooterLink, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, HoverCard, HoverCardContent, HoverCardTrigger, Image, type ImageProps, Inform, type InformProps, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, type InputProps, Label, List, ListItem, type ListItemProps, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, Metric, type MetricProps, Modal, type ModalProps, type ModalType, NavigationBar, type NavigationBarProps, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, NumberInput, type NumberInputProps, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PasswordInput, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, Quote, type QuoteProps, RadioGroup, RadioGroupItem, Rating, type RatingProps, ResizableHandle, ResizablePanel, ResizablePanelGroup, ScrollArea, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarProvider, SidebarSeparator, SidebarTrigger, Skeleton, Slider, Spinner, type SpinnerProps, Stepper, type StepperProps, type StepperStep, Switch, TabBar, TabBarItem, type TabBarItemProps, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableOfContents, type TableOfContentsProps, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, type TagProps, Textarea, type TextareaProps, Toaster, type TocItem, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, type UploadFile, badgeVariants, buttonVariants, cn, fabVariants, formatBytes, informVariants, inputVariants, messageVariants, navigationMenuTriggerStyle, spinnerVariants, tagVariants, textareaVariants, toggleVariants, useFormField, useSidebar };
1235
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AppBar, AppBarActions, AppBarBrand, AppBarLink, type AppBarLinkProps, AppBarNav, AspectRatio, AudioPlayer, type AudioPlayerProps, Avatar, AvatarFallback, AvatarGroup, type AvatarGroupProps, AvatarImage, Badge, type BadgeProps, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, type ButtonProps, Calendar, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, type CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, type ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, Checkbox, CircularProgress, type CircularProgressProps, CodeBlock, type CodeBlockFile, type CodeBlockProps, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, DataTable, DatePicker, type DatePickerProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Fab, type FabProps, Field, FieldControl, FieldDescription, FieldLabel, FieldMessage, FileUpload, FileUploadItem, type FileUploadItemProps, type FileUploadProps, Footer, FooterBottom, FooterColumn, type FooterColumnProps, FooterLink, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, HoverCard, HoverCardContent, HoverCardTrigger, Image, type ImageProps, Inform, type InformProps, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, type InputProps, Label, List, ListItem, type ListItemProps, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, Metric, type MetricProps, Modal, type ModalProps, type ModalType, NavigationBar, type NavigationBarProps, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, NumberInput, type NumberInputProps, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PasswordInput, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, Quote, type QuoteProps, RadioGroup, RadioGroupItem, Rating, type RatingProps, ResizableHandle, ResizablePanel, ResizablePanelGroup, ScrollArea, ScrollBar, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarProvider, SidebarSeparator, SidebarTrigger, Skeleton, Slider, Spinner, type SpinnerProps, Stepper, type StepperProps, type StepperStep, Switch, TabBar, TabBarItem, type TabBarItemProps, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableOfContents, type TableOfContentsProps, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Tag, type TagProps, Textarea, type TextareaProps, Toaster, type TocItem, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, type UploadFile, badgeVariants, buttonVariants, cn, fabVariants, formatBytes, informVariants, inputVariants, messageVariants, navigationMenuTriggerStyle, spinnerVariants, tagVariants, textareaVariants, toggleVariants, useAppBar, useFormField, useSidebar };
package/dist/index.js CHANGED
@@ -3304,10 +3304,103 @@ var NavigationBar = React55.forwardRef(
3304
3304
  );
3305
3305
  NavigationBar.displayName = "NavigationBar";
3306
3306
 
3307
- // src/components/file-upload.tsx
3307
+ // src/components/app-bar.tsx
3308
3308
  import * as React56 from "react";
3309
- import { File, Loader2, TriangleAlert as TriangleAlert3, Upload, X as X6 } from "lucide-react";
3309
+ import { Slot as Slot7 } from "@radix-ui/react-slot";
3310
+ import { Menu as Menu2, X as X6 } from "lucide-react";
3310
3311
  import { jsx as jsx62, jsxs as jsxs33 } from "react/jsx-runtime";
3312
+ var Ctx = React56.createContext(null);
3313
+ var useAppBar = () => {
3314
+ const ctx = React56.useContext(Ctx);
3315
+ if (!ctx) throw new Error("AppBar parts must be used within <AppBar>");
3316
+ return ctx;
3317
+ };
3318
+ var AppBar = React56.forwardRef(
3319
+ ({ className, children, ...props }, ref) => {
3320
+ const [open, setOpen] = React56.useState(false);
3321
+ const nav = React56.Children.toArray(children).find(
3322
+ (c) => React56.isValidElement(c) && c.type === AppBarNav
3323
+ );
3324
+ return /* @__PURE__ */ jsx62(Ctx.Provider, { value: { open, setOpen }, children: /* @__PURE__ */ jsxs33(
3325
+ "header",
3326
+ {
3327
+ ref,
3328
+ className: cn(
3329
+ "sticky top-0 z-40 w-full border-b border-border bg-background/95 font-sans",
3330
+ "backdrop-blur supports-[backdrop-filter]:bg-background/75",
3331
+ className
3332
+ ),
3333
+ ...props,
3334
+ children: [
3335
+ /* @__PURE__ */ jsxs33("div", { className: "mx-auto flex h-14 max-w-screen-2xl items-center gap-4 px-4", children: [
3336
+ children,
3337
+ nav && /* @__PURE__ */ jsx62(
3338
+ "button",
3339
+ {
3340
+ type: "button",
3341
+ "aria-label": open ? "Close menu" : "Open menu",
3342
+ "aria-expanded": open,
3343
+ onClick: () => setOpen((o) => !o),
3344
+ className: cn(
3345
+ "ml-auto inline-flex size-9 items-center justify-center rounded-md text-foreground outline-none transition-colors md:hidden",
3346
+ "hover:bg-accent focus-visible:ring-2 focus-visible:ring-ring"
3347
+ ),
3348
+ children: open ? /* @__PURE__ */ jsx62(X6, { className: "size-5" }) : /* @__PURE__ */ jsx62(Menu2, { className: "size-5" })
3349
+ }
3350
+ )
3351
+ ] }),
3352
+ nav && open && /* @__PURE__ */ jsx62("nav", { className: "flex flex-col gap-1 border-t border-border p-2 md:hidden", children: nav.props.children })
3353
+ ]
3354
+ }
3355
+ ) });
3356
+ }
3357
+ );
3358
+ AppBar.displayName = "AppBar";
3359
+ var AppBarBrand = React56.forwardRef(
3360
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx62(
3361
+ "div",
3362
+ {
3363
+ ref,
3364
+ className: cn("flex shrink-0 items-center gap-2 text-[15px] font-semibold text-foreground", className),
3365
+ ...props
3366
+ }
3367
+ )
3368
+ );
3369
+ AppBarBrand.displayName = "AppBarBrand";
3370
+ var AppBarNav = React56.forwardRef(
3371
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx62("nav", { ref, className: cn("hidden items-center gap-1 md:flex", className), ...props })
3372
+ );
3373
+ AppBarNav.displayName = "AppBarNav";
3374
+ var AppBarLink = React56.forwardRef(
3375
+ ({ className, active, asChild, ...props }, ref) => {
3376
+ const Comp = asChild ? Slot7 : "a";
3377
+ return /* @__PURE__ */ jsx62(
3378
+ Comp,
3379
+ {
3380
+ ref,
3381
+ "data-active": active ? "" : void 0,
3382
+ "aria-current": active ? "page" : void 0,
3383
+ className: cn(
3384
+ "inline-flex items-center rounded-md px-3 py-1.5 text-sm font-medium outline-none transition-colors",
3385
+ "text-muted-foreground hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring",
3386
+ "data-[active]:bg-accent data-[active]:text-foreground",
3387
+ className
3388
+ ),
3389
+ ...props
3390
+ }
3391
+ );
3392
+ }
3393
+ );
3394
+ AppBarLink.displayName = "AppBarLink";
3395
+ var AppBarActions = React56.forwardRef(
3396
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx62("div", { ref, className: cn("ml-auto flex shrink-0 items-center gap-2", className), ...props })
3397
+ );
3398
+ AppBarActions.displayName = "AppBarActions";
3399
+
3400
+ // src/components/file-upload.tsx
3401
+ import * as React57 from "react";
3402
+ import { File, Loader2, TriangleAlert as TriangleAlert3, Upload, X as X7 } from "lucide-react";
3403
+ import { jsx as jsx63, jsxs as jsxs34 } from "react/jsx-runtime";
3311
3404
  function formatBytes(bytes) {
3312
3405
  if (!bytes) return "";
3313
3406
  const units = ["B", "KB", "MB", "GB"];
@@ -3319,16 +3412,16 @@ function formatBytes(bytes) {
3319
3412
  }
3320
3413
  return `${v.toFixed(v < 10 && i > 0 ? 1 : 0)} ${units[i]}`;
3321
3414
  }
3322
- var FileUpload = React56.forwardRef(
3415
+ var FileUpload = React57.forwardRef(
3323
3416
  ({ className, multiple, accept, disabled, helperText, buttonLabel = "Browse files", files = [], onFilesSelected, onRemove, onRetry, ...props }, ref) => {
3324
- const inputRef = React56.useRef(null);
3325
- const [dragging, setDragging] = React56.useState(false);
3417
+ const inputRef = React57.useRef(null);
3418
+ const [dragging, setDragging] = React57.useState(false);
3326
3419
  const pick = (list) => {
3327
3420
  if (!list || !list.length) return;
3328
3421
  onFilesSelected?.(Array.from(list));
3329
3422
  };
3330
- return /* @__PURE__ */ jsxs33("div", { ref, className: cn("flex w-full flex-col gap-3 font-sans", className), ...props, children: [
3331
- /* @__PURE__ */ jsxs33(
3423
+ return /* @__PURE__ */ jsxs34("div", { ref, className: cn("flex w-full flex-col gap-3 font-sans", className), ...props, children: [
3424
+ /* @__PURE__ */ jsxs34(
3332
3425
  "div",
3333
3426
  {
3334
3427
  role: "button",
@@ -3358,13 +3451,13 @@ var FileUpload = React56.forwardRef(
3358
3451
  disabled && "pointer-events-none opacity-50"
3359
3452
  ),
3360
3453
  children: [
3361
- /* @__PURE__ */ jsx62(Upload, { className: "size-6 text-muted-foreground", "aria-hidden": true }),
3362
- /* @__PURE__ */ jsxs33("p", { className: "text-body-sm text-muted-foreground", children: [
3454
+ /* @__PURE__ */ jsx63(Upload, { className: "size-6 text-muted-foreground", "aria-hidden": true }),
3455
+ /* @__PURE__ */ jsxs34("p", { className: "text-body-sm text-muted-foreground", children: [
3363
3456
  "Drag & drop ",
3364
3457
  multiple ? "files" : "a file",
3365
3458
  " here, or"
3366
3459
  ] }),
3367
- /* @__PURE__ */ jsx62(
3460
+ /* @__PURE__ */ jsx63(
3368
3461
  Button,
3369
3462
  {
3370
3463
  type: "button",
@@ -3378,8 +3471,8 @@ var FileUpload = React56.forwardRef(
3378
3471
  children: buttonLabel
3379
3472
  }
3380
3473
  ),
3381
- helperText && /* @__PURE__ */ jsx62("p", { className: "text-body-sm text-muted-foreground", children: helperText }),
3382
- /* @__PURE__ */ jsx62(
3474
+ helperText && /* @__PURE__ */ jsx63("p", { className: "text-body-sm text-muted-foreground", children: helperText }),
3475
+ /* @__PURE__ */ jsx63(
3383
3476
  "input",
3384
3477
  {
3385
3478
  ref: inputRef,
@@ -3397,7 +3490,7 @@ var FileUpload = React56.forwardRef(
3397
3490
  ]
3398
3491
  }
3399
3492
  ),
3400
- files.length > 0 && /* @__PURE__ */ jsx62("ul", { className: "flex flex-col gap-2", children: files.map((f) => /* @__PURE__ */ jsx62(FileUploadItem, { file: f, onRemove, onRetry }, f.id)) })
3493
+ files.length > 0 && /* @__PURE__ */ jsx63("ul", { className: "flex flex-col gap-2", children: files.map((f) => /* @__PURE__ */ jsx63(FileUploadItem, { file: f, onRemove, onRetry }, f.id)) })
3401
3494
  ] });
3402
3495
  }
3403
3496
  );
@@ -3405,14 +3498,14 @@ FileUpload.displayName = "FileUpload";
3405
3498
  function FileUploadItem({ file, onRemove, onRetry }) {
3406
3499
  const isError = file.status === "error";
3407
3500
  const isLoading = file.status === "loading";
3408
- return /* @__PURE__ */ jsxs33("li", { className: cn("flex items-center gap-2.5 rounded-md border p-2.5 text-body-sm", isError ? "border-destructive bg-destructive/5" : "border-input"), children: [
3409
- isLoading ? /* @__PURE__ */ jsx62(Loader2, { className: "size-4 shrink-0 animate-spin text-muted-foreground", "aria-hidden": true }) : isError ? /* @__PURE__ */ jsx62(TriangleAlert3, { className: "size-4 shrink-0 text-destructive", "aria-hidden": true }) : /* @__PURE__ */ jsx62(File, { className: "size-4 shrink-0 text-muted-foreground", "aria-hidden": true }),
3410
- /* @__PURE__ */ jsxs33("div", { className: "min-w-0 flex-1", children: [
3411
- /* @__PURE__ */ jsx62("p", { className: "truncate text-foreground", children: file.name }),
3412
- isError && file.error ? /* @__PURE__ */ jsx62("p", { className: "text-destructive", children: file.error }) : /* @__PURE__ */ jsx62("p", { className: "text-muted-foreground", children: formatBytes(file.size) }),
3413
- isLoading && typeof file.progress === "number" && /* @__PURE__ */ jsx62("div", { className: "mt-1 h-1 w-full overflow-hidden rounded-full bg-muted", children: /* @__PURE__ */ jsx62("div", { className: "h-full bg-primary transition-[width]", style: { width: `${Math.max(0, Math.min(100, file.progress))}%` } }) })
3501
+ return /* @__PURE__ */ jsxs34("li", { className: cn("flex items-center gap-2.5 rounded-md border p-2.5 text-body-sm", isError ? "border-destructive bg-destructive/5" : "border-input"), children: [
3502
+ isLoading ? /* @__PURE__ */ jsx63(Loader2, { className: "size-4 shrink-0 animate-spin text-muted-foreground", "aria-hidden": true }) : isError ? /* @__PURE__ */ jsx63(TriangleAlert3, { className: "size-4 shrink-0 text-destructive", "aria-hidden": true }) : /* @__PURE__ */ jsx63(File, { className: "size-4 shrink-0 text-muted-foreground", "aria-hidden": true }),
3503
+ /* @__PURE__ */ jsxs34("div", { className: "min-w-0 flex-1", children: [
3504
+ /* @__PURE__ */ jsx63("p", { className: "truncate text-foreground", children: file.name }),
3505
+ isError && file.error ? /* @__PURE__ */ jsx63("p", { className: "text-destructive", children: file.error }) : /* @__PURE__ */ jsx63("p", { className: "text-muted-foreground", children: formatBytes(file.size) }),
3506
+ isLoading && typeof file.progress === "number" && /* @__PURE__ */ jsx63("div", { className: "mt-1 h-1 w-full overflow-hidden rounded-full bg-muted", children: /* @__PURE__ */ jsx63("div", { className: "h-full bg-primary transition-[width]", style: { width: `${Math.max(0, Math.min(100, file.progress))}%` } }) })
3414
3507
  ] }),
3415
- isError && onRetry && /* @__PURE__ */ jsx62(
3508
+ isError && onRetry && /* @__PURE__ */ jsx63(
3416
3509
  "button",
3417
3510
  {
3418
3511
  type: "button",
@@ -3421,14 +3514,14 @@ function FileUploadItem({ file, onRemove, onRetry }) {
3421
3514
  children: "Retry"
3422
3515
  }
3423
3516
  ),
3424
- onRemove && /* @__PURE__ */ jsx62(
3517
+ onRemove && /* @__PURE__ */ jsx63(
3425
3518
  "button",
3426
3519
  {
3427
3520
  type: "button",
3428
3521
  onClick: () => onRemove(file.id),
3429
3522
  "aria-label": `Remove ${file.name}`,
3430
3523
  className: "shrink-0 rounded-[2px] p-0.5 text-muted-foreground outline-none transition-colors hover:text-foreground focus-visible:ring-1 focus-visible:ring-current",
3431
- children: /* @__PURE__ */ jsx62(X6, { className: "size-3.5" })
3524
+ children: /* @__PURE__ */ jsx63(X7, { className: "size-3.5" })
3432
3525
  }
3433
3526
  )
3434
3527
  ] });
@@ -3436,17 +3529,17 @@ function FileUploadItem({ file, onRemove, onRetry }) {
3436
3529
  FileUploadItem.displayName = "FileUploadItem";
3437
3530
 
3438
3531
  // src/components/date-picker.tsx
3439
- import * as React57 from "react";
3532
+ import * as React58 from "react";
3440
3533
  import { CalendarIcon } from "lucide-react";
3441
3534
  import { format } from "date-fns";
3442
- import { jsx as jsx63, jsxs as jsxs34 } from "react/jsx-runtime";
3443
- var DatePicker = React57.forwardRef(
3535
+ import { jsx as jsx64, jsxs as jsxs35 } from "react/jsx-runtime";
3536
+ var DatePicker = React58.forwardRef(
3444
3537
  ({ value, onChange, placeholder = "Select date", label, helperText, error, disabled, className, formatStr = "PP", calendarProps }, ref) => {
3445
- const [open, setOpen] = React57.useState(false);
3446
- return /* @__PURE__ */ jsxs34("div", { className: cn("flex flex-col gap-1.5 font-sans", className), children: [
3447
- label && /* @__PURE__ */ jsx63("label", { className: "text-label-md font-medium text-foreground", children: label }),
3448
- /* @__PURE__ */ jsxs34(Popover, { open, onOpenChange: setOpen, children: [
3449
- /* @__PURE__ */ jsx63(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs34(
3538
+ const [open, setOpen] = React58.useState(false);
3539
+ return /* @__PURE__ */ jsxs35("div", { className: cn("flex flex-col gap-1.5 font-sans", className), children: [
3540
+ label && /* @__PURE__ */ jsx64("label", { className: "text-label-md font-medium text-foreground", children: label }),
3541
+ /* @__PURE__ */ jsxs35(Popover, { open, onOpenChange: setOpen, children: [
3542
+ /* @__PURE__ */ jsx64(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs35(
3450
3543
  Button,
3451
3544
  {
3452
3545
  ref,
@@ -3455,12 +3548,12 @@ var DatePicker = React57.forwardRef(
3455
3548
  disabled,
3456
3549
  className: cn("w-full justify-start px-3 font-normal", !value && "text-muted-foreground", error && "border-destructive text-destructive"),
3457
3550
  children: [
3458
- /* @__PURE__ */ jsx63(CalendarIcon, { className: "size-4" }),
3551
+ /* @__PURE__ */ jsx64(CalendarIcon, { className: "size-4" }),
3459
3552
  value ? format(value, formatStr) : placeholder
3460
3553
  ]
3461
3554
  }
3462
3555
  ) }),
3463
- /* @__PURE__ */ jsx63(PopoverContent, { className: "w-auto p-0", align: "start", children: /* @__PURE__ */ jsx63(
3556
+ /* @__PURE__ */ jsx64(PopoverContent, { className: "w-auto p-0", align: "start", children: /* @__PURE__ */ jsx64(
3464
3557
  Calendar,
3465
3558
  {
3466
3559
  mode: "single",
@@ -3473,21 +3566,21 @@ var DatePicker = React57.forwardRef(
3473
3566
  }
3474
3567
  ) })
3475
3568
  ] }),
3476
- helperText && /* @__PURE__ */ jsx63("p", { className: cn("text-body-sm", error ? "text-destructive" : "text-muted-foreground"), children: helperText })
3569
+ helperText && /* @__PURE__ */ jsx64("p", { className: cn("text-body-sm", error ? "text-destructive" : "text-muted-foreground"), children: helperText })
3477
3570
  ] });
3478
3571
  }
3479
3572
  );
3480
3573
  DatePicker.displayName = "DatePicker";
3481
3574
 
3482
3575
  // src/components/code-block.tsx
3483
- import * as React58 from "react";
3576
+ import * as React59 from "react";
3484
3577
  import { Check as Check7, Copy } from "lucide-react";
3485
- import { jsx as jsx64, jsxs as jsxs35 } from "react/jsx-runtime";
3486
- var CodeBlock = React58.forwardRef(
3578
+ import { jsx as jsx65, jsxs as jsxs36 } from "react/jsx-runtime";
3579
+ var CodeBlock = React59.forwardRef(
3487
3580
  ({ className, code, language, filename, files, hideCopy, ...props }, ref) => {
3488
3581
  const tabs = files && files.length > 0 ? files : [{ name: filename ?? language ?? "", code: code ?? "" }];
3489
- const [active, setActive] = React58.useState(0);
3490
- const [copied, setCopied] = React58.useState(false);
3582
+ const [active, setActive] = React59.useState(0);
3583
+ const [copied, setCopied] = React59.useState(false);
3491
3584
  const current = tabs[active] ?? tabs[0];
3492
3585
  const hasHeader = tabs.length > 1 || !!current.name;
3493
3586
  const copy = async () => {
@@ -3498,9 +3591,9 @@ var CodeBlock = React58.forwardRef(
3498
3591
  } catch {
3499
3592
  }
3500
3593
  };
3501
- return /* @__PURE__ */ jsxs35("div", { ref, className: cn("overflow-hidden rounded-md border border-input bg-muted font-sans", className), ...props, children: [
3502
- hasHeader && /* @__PURE__ */ jsxs35("div", { className: "flex items-center justify-between border-b border-input bg-background px-2", children: [
3503
- /* @__PURE__ */ jsx64("div", { className: "flex", children: tabs.map((t, i) => /* @__PURE__ */ jsx64(
3594
+ return /* @__PURE__ */ jsxs36("div", { ref, className: cn("overflow-hidden rounded-md border border-input bg-muted font-sans", className), ...props, children: [
3595
+ hasHeader && /* @__PURE__ */ jsxs36("div", { className: "flex items-center justify-between border-b border-input bg-background px-2", children: [
3596
+ /* @__PURE__ */ jsx65("div", { className: "flex", children: tabs.map((t, i) => /* @__PURE__ */ jsx65(
3504
3597
  "button",
3505
3598
  {
3506
3599
  type: "button",
@@ -3513,29 +3606,29 @@ var CodeBlock = React58.forwardRef(
3513
3606
  },
3514
3607
  t.name || i
3515
3608
  )) }),
3516
- !hideCopy && /* @__PURE__ */ jsx64(
3609
+ !hideCopy && /* @__PURE__ */ jsx65(
3517
3610
  "button",
3518
3611
  {
3519
3612
  type: "button",
3520
3613
  onClick: copy,
3521
3614
  "aria-label": "Copy code",
3522
3615
  className: "rounded-[2px] p-1.5 text-muted-foreground outline-none transition-colors hover:text-foreground focus-visible:ring-1 focus-visible:ring-current",
3523
- children: copied ? /* @__PURE__ */ jsx64(Check7, { className: "size-4" }) : /* @__PURE__ */ jsx64(Copy, { className: "size-4" })
3616
+ children: copied ? /* @__PURE__ */ jsx65(Check7, { className: "size-4" }) : /* @__PURE__ */ jsx65(Copy, { className: "size-4" })
3524
3617
  }
3525
3618
  )
3526
3619
  ] }),
3527
- /* @__PURE__ */ jsxs35("div", { className: "relative", children: [
3528
- !hasHeader && !hideCopy && /* @__PURE__ */ jsx64(
3620
+ /* @__PURE__ */ jsxs36("div", { className: "relative", children: [
3621
+ !hasHeader && !hideCopy && /* @__PURE__ */ jsx65(
3529
3622
  "button",
3530
3623
  {
3531
3624
  type: "button",
3532
3625
  onClick: copy,
3533
3626
  "aria-label": "Copy code",
3534
3627
  className: "absolute right-2 top-2 rounded-[2px] p-1.5 text-muted-foreground outline-none transition-colors hover:text-foreground focus-visible:ring-1 focus-visible:ring-current",
3535
- children: copied ? /* @__PURE__ */ jsx64(Check7, { className: "size-4" }) : /* @__PURE__ */ jsx64(Copy, { className: "size-4" })
3628
+ children: copied ? /* @__PURE__ */ jsx65(Check7, { className: "size-4" }) : /* @__PURE__ */ jsx65(Copy, { className: "size-4" })
3536
3629
  }
3537
3630
  ),
3538
- /* @__PURE__ */ jsx64("pre", { className: "overflow-x-auto p-4 text-body-sm text-foreground", children: /* @__PURE__ */ jsx64("code", { children: current.code }) })
3631
+ /* @__PURE__ */ jsx65("pre", { className: "overflow-x-auto p-4 text-body-sm text-foreground", children: /* @__PURE__ */ jsx65("code", { children: current.code }) })
3539
3632
  ] })
3540
3633
  ] });
3541
3634
  }
@@ -3543,18 +3636,18 @@ var CodeBlock = React58.forwardRef(
3543
3636
  CodeBlock.displayName = "CodeBlock";
3544
3637
 
3545
3638
  // src/components/metric.tsx
3546
- import * as React59 from "react";
3639
+ import * as React60 from "react";
3547
3640
  import { ArrowDown, ArrowUp } from "lucide-react";
3548
- import { jsx as jsx65, jsxs as jsxs36 } from "react/jsx-runtime";
3549
- var Metric = React59.forwardRef(
3550
- ({ className, label, value, trend, change, icon, chart, ...props }, ref) => /* @__PURE__ */ jsxs36("div", { ref, className: cn("flex flex-col gap-2 rounded-md border border-input p-4 font-sans", className), ...props, children: [
3551
- /* @__PURE__ */ jsxs36("div", { className: "flex items-center justify-between", children: [
3552
- /* @__PURE__ */ jsx65("p", { className: "text-body-sm text-muted-foreground", children: label }),
3553
- icon && /* @__PURE__ */ jsx65("span", { className: "text-muted-foreground [&_svg]:size-5", children: icon })
3641
+ import { jsx as jsx66, jsxs as jsxs37 } from "react/jsx-runtime";
3642
+ var Metric = React60.forwardRef(
3643
+ ({ className, label, value, trend, change, icon, chart, ...props }, ref) => /* @__PURE__ */ jsxs37("div", { ref, className: cn("flex flex-col gap-2 rounded-md border border-input p-4 font-sans", className), ...props, children: [
3644
+ /* @__PURE__ */ jsxs37("div", { className: "flex items-center justify-between", children: [
3645
+ /* @__PURE__ */ jsx66("p", { className: "text-body-sm text-muted-foreground", children: label }),
3646
+ icon && /* @__PURE__ */ jsx66("span", { className: "text-muted-foreground [&_svg]:size-5", children: icon })
3554
3647
  ] }),
3555
- /* @__PURE__ */ jsxs36("div", { className: "flex items-end justify-between gap-2", children: [
3556
- /* @__PURE__ */ jsx65("p", { className: "text-headline-sm font-medium text-foreground", children: value }),
3557
- trend && /* @__PURE__ */ jsxs36(
3648
+ /* @__PURE__ */ jsxs37("div", { className: "flex items-end justify-between gap-2", children: [
3649
+ /* @__PURE__ */ jsx66("p", { className: "text-headline-sm font-medium text-foreground", children: value }),
3650
+ trend && /* @__PURE__ */ jsxs37(
3558
3651
  "span",
3559
3652
  {
3560
3653
  className: cn(
@@ -3564,25 +3657,25 @@ var Metric = React59.forwardRef(
3564
3657
  trend === "neutral" && "text-muted-foreground"
3565
3658
  ),
3566
3659
  children: [
3567
- trend === "up" && /* @__PURE__ */ jsx65(ArrowUp, { className: "size-3.5" }),
3568
- trend === "down" && /* @__PURE__ */ jsx65(ArrowDown, { className: "size-3.5" }),
3660
+ trend === "up" && /* @__PURE__ */ jsx66(ArrowUp, { className: "size-3.5" }),
3661
+ trend === "down" && /* @__PURE__ */ jsx66(ArrowDown, { className: "size-3.5" }),
3569
3662
  change
3570
3663
  ]
3571
3664
  }
3572
3665
  )
3573
3666
  ] }),
3574
- chart && /* @__PURE__ */ jsx65("div", { className: "mt-1", children: chart })
3667
+ chart && /* @__PURE__ */ jsx66("div", { className: "mt-1", children: chart })
3575
3668
  ] })
3576
3669
  );
3577
3670
  Metric.displayName = "Metric";
3578
3671
 
3579
3672
  // src/components/number-input.tsx
3580
- import * as React60 from "react";
3673
+ import * as React61 from "react";
3581
3674
  import { Minus as Minus3, Plus } from "lucide-react";
3582
- import { jsx as jsx66, jsxs as jsxs37 } from "react/jsx-runtime";
3583
- var NumberInput = React60.forwardRef(
3675
+ import { jsx as jsx67, jsxs as jsxs38 } from "react/jsx-runtime";
3676
+ var NumberInput = React61.forwardRef(
3584
3677
  ({ className, value, defaultValue = 0, min, max, step = 1, onChange, disabled, ...props }, ref) => {
3585
- const [internal, setInternal] = React60.useState(defaultValue);
3678
+ const [internal, setInternal] = React61.useState(defaultValue);
3586
3679
  const current = value ?? internal;
3587
3680
  const clamp = (n) => {
3588
3681
  let v = n;
@@ -3595,7 +3688,7 @@ var NumberInput = React60.forwardRef(
3595
3688
  setInternal(v);
3596
3689
  onChange?.(v);
3597
3690
  };
3598
- return /* @__PURE__ */ jsxs37(
3691
+ return /* @__PURE__ */ jsxs38(
3599
3692
  "div",
3600
3693
  {
3601
3694
  className: cn(
@@ -3604,7 +3697,7 @@ var NumberInput = React60.forwardRef(
3604
3697
  className
3605
3698
  ),
3606
3699
  children: [
3607
- /* @__PURE__ */ jsx66(
3700
+ /* @__PURE__ */ jsx67(
3608
3701
  "button",
3609
3702
  {
3610
3703
  type: "button",
@@ -3612,10 +3705,10 @@ var NumberInput = React60.forwardRef(
3612
3705
  disabled: disabled || min != null && current <= min,
3613
3706
  onClick: () => set(current - step),
3614
3707
  className: "flex w-9 shrink-0 items-center justify-center text-muted-foreground outline-none transition-colors hover:bg-accent hover:text-foreground focus-visible:bg-accent focus-visible:text-foreground focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
3615
- children: /* @__PURE__ */ jsx66(Minus3, { className: "size-4" })
3708
+ children: /* @__PURE__ */ jsx67(Minus3, { className: "size-4" })
3616
3709
  }
3617
3710
  ),
3618
- /* @__PURE__ */ jsx66(
3711
+ /* @__PURE__ */ jsx67(
3619
3712
  "input",
3620
3713
  {
3621
3714
  ref,
@@ -3634,7 +3727,7 @@ var NumberInput = React60.forwardRef(
3634
3727
  ...props
3635
3728
  }
3636
3729
  ),
3637
- /* @__PURE__ */ jsx66(
3730
+ /* @__PURE__ */ jsx67(
3638
3731
  "button",
3639
3732
  {
3640
3733
  type: "button",
@@ -3642,7 +3735,7 @@ var NumberInput = React60.forwardRef(
3642
3735
  disabled: disabled || max != null && current >= max,
3643
3736
  onClick: () => set(current + step),
3644
3737
  className: "flex w-9 shrink-0 items-center justify-center text-muted-foreground outline-none transition-colors hover:bg-accent hover:text-foreground focus-visible:bg-accent focus-visible:text-foreground focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
3645
- children: /* @__PURE__ */ jsx66(Plus, { className: "size-4" })
3738
+ children: /* @__PURE__ */ jsx67(Plus, { className: "size-4" })
3646
3739
  }
3647
3740
  )
3648
3741
  ]
@@ -3653,20 +3746,20 @@ var NumberInput = React60.forwardRef(
3653
3746
  NumberInput.displayName = "NumberInput";
3654
3747
 
3655
3748
  // src/components/quote.tsx
3656
- import * as React61 from "react";
3657
- import { jsx as jsx67, jsxs as jsxs38 } from "react/jsx-runtime";
3658
- var Quote = React61.forwardRef(
3659
- ({ className, author, authorTitle, avatar, children, ...props }, ref) => /* @__PURE__ */ jsxs38("figure", { ref, className: cn("flex flex-col gap-4 font-sans", className), ...props, children: [
3660
- /* @__PURE__ */ jsxs38("blockquote", { className: "text-title-md font-medium text-foreground", children: [
3749
+ import * as React62 from "react";
3750
+ import { jsx as jsx68, jsxs as jsxs39 } from "react/jsx-runtime";
3751
+ var Quote = React62.forwardRef(
3752
+ ({ className, author, authorTitle, avatar, children, ...props }, ref) => /* @__PURE__ */ jsxs39("figure", { ref, className: cn("flex flex-col gap-4 font-sans", className), ...props, children: [
3753
+ /* @__PURE__ */ jsxs39("blockquote", { className: "text-title-md font-medium text-foreground", children: [
3661
3754
  "\u201C",
3662
3755
  children,
3663
3756
  "\u201D"
3664
3757
  ] }),
3665
- (author || authorTitle) && /* @__PURE__ */ jsxs38("figcaption", { className: "flex items-center gap-3", children: [
3758
+ (author || authorTitle) && /* @__PURE__ */ jsxs39("figcaption", { className: "flex items-center gap-3", children: [
3666
3759
  avatar,
3667
- /* @__PURE__ */ jsxs38("div", { children: [
3668
- author && /* @__PURE__ */ jsx67("p", { className: "text-body-md font-medium text-foreground", children: author }),
3669
- authorTitle && /* @__PURE__ */ jsx67("p", { className: "text-body-sm text-muted-foreground", children: authorTitle })
3760
+ /* @__PURE__ */ jsxs39("div", { children: [
3761
+ author && /* @__PURE__ */ jsx68("p", { className: "text-body-md font-medium text-foreground", children: author }),
3762
+ authorTitle && /* @__PURE__ */ jsx68("p", { className: "text-body-sm text-muted-foreground", children: authorTitle })
3670
3763
  ] })
3671
3764
  ] })
3672
3765
  ] })
@@ -3674,21 +3767,21 @@ var Quote = React61.forwardRef(
3674
3767
  Quote.displayName = "Quote";
3675
3768
 
3676
3769
  // src/components/footer.tsx
3677
- import * as React62 from "react";
3678
- import { jsx as jsx68, jsxs as jsxs39 } from "react/jsx-runtime";
3679
- var Footer = React62.forwardRef(
3680
- ({ className, children, ...props }, ref) => /* @__PURE__ */ jsx68("footer", { ref, className: cn("w-full border-t border-border bg-background px-6 py-10 font-sans", className), ...props, children })
3770
+ import * as React63 from "react";
3771
+ import { jsx as jsx69, jsxs as jsxs40 } from "react/jsx-runtime";
3772
+ var Footer = React63.forwardRef(
3773
+ ({ className, children, ...props }, ref) => /* @__PURE__ */ jsx69("footer", { ref, className: cn("w-full border-t border-border bg-background px-6 py-10 font-sans", className), ...props, children })
3681
3774
  );
3682
3775
  Footer.displayName = "Footer";
3683
- var FooterColumn = React62.forwardRef(
3684
- ({ className, title, children, ...props }, ref) => /* @__PURE__ */ jsxs39("div", { ref, className: cn("flex flex-col gap-3", className), ...props, children: [
3685
- /* @__PURE__ */ jsx68("p", { className: "text-label-md font-medium text-foreground", children: title }),
3686
- /* @__PURE__ */ jsx68("div", { className: "flex flex-col gap-2", children })
3776
+ var FooterColumn = React63.forwardRef(
3777
+ ({ className, title, children, ...props }, ref) => /* @__PURE__ */ jsxs40("div", { ref, className: cn("flex flex-col gap-3", className), ...props, children: [
3778
+ /* @__PURE__ */ jsx69("p", { className: "text-label-md font-medium text-foreground", children: title }),
3779
+ /* @__PURE__ */ jsx69("div", { className: "flex flex-col gap-2", children })
3687
3780
  ] })
3688
3781
  );
3689
3782
  FooterColumn.displayName = "FooterColumn";
3690
- var FooterLink = React62.forwardRef(
3691
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx68(
3783
+ var FooterLink = React63.forwardRef(
3784
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx69(
3692
3785
  "a",
3693
3786
  {
3694
3787
  ref,
@@ -3701,8 +3794,8 @@ var FooterLink = React62.forwardRef(
3701
3794
  )
3702
3795
  );
3703
3796
  FooterLink.displayName = "FooterLink";
3704
- var FooterBottom = React62.forwardRef(
3705
- ({ className, ...props }, ref) => /* @__PURE__ */ jsx68(
3797
+ var FooterBottom = React63.forwardRef(
3798
+ ({ className, ...props }, ref) => /* @__PURE__ */ jsx69(
3706
3799
  "div",
3707
3800
  {
3708
3801
  ref,
@@ -3717,12 +3810,12 @@ var FooterBottom = React62.forwardRef(
3717
3810
  FooterBottom.displayName = "FooterBottom";
3718
3811
 
3719
3812
  // src/components/table-of-contents.tsx
3720
- import * as React63 from "react";
3721
- import { jsx as jsx69 } from "react/jsx-runtime";
3722
- var TableOfContents = React63.forwardRef(
3723
- ({ className, items, active, ...props }, ref) => /* @__PURE__ */ jsx69("nav", { ref, "aria-label": "Table of contents", className: cn("flex flex-col gap-0.5 font-sans", className), ...props, children: items.map((item) => {
3813
+ import * as React64 from "react";
3814
+ import { jsx as jsx70 } from "react/jsx-runtime";
3815
+ var TableOfContents = React64.forwardRef(
3816
+ ({ className, items, active, ...props }, ref) => /* @__PURE__ */ jsx70("nav", { ref, "aria-label": "Table of contents", className: cn("flex flex-col gap-0.5 font-sans", className), ...props, children: items.map((item) => {
3724
3817
  const isActive = item.id === active;
3725
- return /* @__PURE__ */ jsx69(
3818
+ return /* @__PURE__ */ jsx70(
3726
3819
  "a",
3727
3820
  {
3728
3821
  href: `#${item.id}`,
@@ -3758,6 +3851,11 @@ export {
3758
3851
  AlertDialogTitle,
3759
3852
  AlertDialogTrigger,
3760
3853
  AlertTitle,
3854
+ AppBar,
3855
+ AppBarActions,
3856
+ AppBarBrand,
3857
+ AppBarLink,
3858
+ AppBarNav,
3761
3859
  AspectRatio,
3762
3860
  AudioPlayer,
3763
3861
  Avatar,
@@ -4024,6 +4122,7 @@ export {
4024
4122
  textareaVariants,
4025
4123
  toast,
4026
4124
  toggleVariants,
4125
+ useAppBar,
4027
4126
  useFormField,
4028
4127
  useSidebar
4029
4128
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kinetixui/ui",
3
- "version": "0.5.1",
3
+ "version": "0.6.0",
4
4
  "private": false,
5
5
  "description": "KinetixUI React components — CVA + Radix + Tailwind on the KinetixUI token contract. Also distributed via the kinetixui CLI as a component registry.",
6
6
  "keywords": [
@@ -89,7 +89,7 @@
89
89
  "react-dom": ">=18"
90
90
  },
91
91
  "devDependencies": {
92
- "@kinetixui/tokens": "0.5.1",
92
+ "@kinetixui/tokens": "0.6.0",
93
93
  "@testing-library/jest-dom": "^6.6.3",
94
94
  "@testing-library/react": "^16.1.0",
95
95
  "@testing-library/user-event": "^14.5.2",
@@ -0,0 +1,139 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import { Slot } from "@radix-ui/react-slot";
5
+ import { Menu, X } from "lucide-react";
6
+ import { cn } from "../lib/utils";
7
+
8
+ /**
9
+ * AppBar — a web application top bar: a brand slot, a row of primary nav
10
+ * links, and a trailing actions slot inside a sticky bordered header. Below
11
+ * the `md` breakpoint the nav collapses behind a menu toggle into a panel
12
+ * under the bar.
13
+ *
14
+ * <AppBar>
15
+ * <AppBarBrand>Acme</AppBarBrand>
16
+ * <AppBarNav>
17
+ * <AppBarLink href="/" active>Overview</AppBarLink>
18
+ * <AppBarLink href="/reports">Reports</AppBarLink>
19
+ * </AppBarNav>
20
+ * <AppBarActions><Button size="sm">New</Button></AppBarActions>
21
+ * </AppBar>
22
+ *
23
+ * `NavigationBar` is the mobile back-button bar; this is the desktop app shell.
24
+ */
25
+
26
+ interface AppBarCtx {
27
+ open: boolean;
28
+ setOpen: React.Dispatch<React.SetStateAction<boolean>>;
29
+ }
30
+ const Ctx = React.createContext<AppBarCtx | null>(null);
31
+ const useAppBar = () => {
32
+ const ctx = React.useContext(Ctx);
33
+ if (!ctx) throw new Error("AppBar parts must be used within <AppBar>");
34
+ return ctx;
35
+ };
36
+
37
+ const AppBar = React.forwardRef<HTMLElement, React.HTMLAttributes<HTMLElement>>(
38
+ ({ className, children, ...props }, ref) => {
39
+ const [open, setOpen] = React.useState(false);
40
+
41
+ const nav = React.Children.toArray(children).find(
42
+ (c): c is React.ReactElement<React.ComponentProps<typeof AppBarNav>> =>
43
+ React.isValidElement(c) && c.type === AppBarNav,
44
+ );
45
+
46
+ return (
47
+ <Ctx.Provider value={{ open, setOpen }}>
48
+ <header
49
+ ref={ref}
50
+ className={cn(
51
+ "sticky top-0 z-40 w-full border-b border-border bg-background/95 font-sans",
52
+ "backdrop-blur supports-[backdrop-filter]:bg-background/75",
53
+ className,
54
+ )}
55
+ {...props}
56
+ >
57
+ <div className="mx-auto flex h-14 max-w-screen-2xl items-center gap-4 px-4">
58
+ {children}
59
+ {nav && (
60
+ <button
61
+ type="button"
62
+ aria-label={open ? "Close menu" : "Open menu"}
63
+ aria-expanded={open}
64
+ onClick={() => setOpen((o) => !o)}
65
+ className={cn(
66
+ "ml-auto inline-flex size-9 items-center justify-center rounded-md text-foreground outline-none transition-colors md:hidden",
67
+ "hover:bg-accent focus-visible:ring-2 focus-visible:ring-ring",
68
+ )}
69
+ >
70
+ {open ? <X className="size-5" /> : <Menu className="size-5" />}
71
+ </button>
72
+ )}
73
+ </div>
74
+ {nav && open && (
75
+ <nav className="flex flex-col gap-1 border-t border-border p-2 md:hidden">
76
+ {nav.props.children}
77
+ </nav>
78
+ )}
79
+ </header>
80
+ </Ctx.Provider>
81
+ );
82
+ },
83
+ );
84
+ AppBar.displayName = "AppBar";
85
+
86
+ const AppBarBrand = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
87
+ ({ className, ...props }, ref) => (
88
+ <div
89
+ ref={ref}
90
+ className={cn("flex shrink-0 items-center gap-2 text-[15px] font-semibold text-foreground", className)}
91
+ {...props}
92
+ />
93
+ ),
94
+ );
95
+ AppBarBrand.displayName = "AppBarBrand";
96
+
97
+ const AppBarNav = React.forwardRef<HTMLElement, React.HTMLAttributes<HTMLElement>>(
98
+ ({ className, ...props }, ref) => (
99
+ <nav ref={ref} className={cn("hidden items-center gap-1 md:flex", className)} {...props} />
100
+ ),
101
+ );
102
+ AppBarNav.displayName = "AppBarNav";
103
+
104
+ export interface AppBarLinkProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
105
+ /** Marks the current destination — sets `aria-current="page"` and the active style. */
106
+ active?: boolean;
107
+ /** Render as the child element (e.g. a framework `<Link>`), forwarding props. */
108
+ asChild?: boolean;
109
+ }
110
+
111
+ const AppBarLink = React.forwardRef<HTMLAnchorElement, AppBarLinkProps>(
112
+ ({ className, active, asChild, ...props }, ref) => {
113
+ const Comp = asChild ? Slot : "a";
114
+ return (
115
+ <Comp
116
+ ref={ref}
117
+ data-active={active ? "" : undefined}
118
+ aria-current={active ? "page" : undefined}
119
+ className={cn(
120
+ "inline-flex items-center rounded-md px-3 py-1.5 text-sm font-medium outline-none transition-colors",
121
+ "text-muted-foreground hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring",
122
+ "data-[active]:bg-accent data-[active]:text-foreground",
123
+ className,
124
+ )}
125
+ {...props}
126
+ />
127
+ );
128
+ },
129
+ );
130
+ AppBarLink.displayName = "AppBarLink";
131
+
132
+ const AppBarActions = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
133
+ ({ className, ...props }, ref) => (
134
+ <div ref={ref} className={cn("ml-auto flex shrink-0 items-center gap-2", className)} {...props} />
135
+ ),
136
+ );
137
+ AppBarActions.displayName = "AppBarActions";
138
+
139
+ export { AppBar, AppBarBrand, AppBarNav, AppBarLink, AppBarActions, useAppBar };
package/src/index.ts CHANGED
@@ -284,6 +284,15 @@ export { Stepper, type StepperProps, type StepperStep } from "./components/stepp
284
284
  export { Fab, fabVariants, type FabProps } from "./components/fab";
285
285
  export { TabBar, TabBarItem, type TabBarItemProps } from "./components/tab-bar";
286
286
  export { NavigationBar, type NavigationBarProps } from "./components/navigation-bar";
287
+ export {
288
+ AppBar,
289
+ AppBarBrand,
290
+ AppBarNav,
291
+ AppBarLink,
292
+ AppBarActions,
293
+ useAppBar,
294
+ type AppBarLinkProps,
295
+ } from "./components/app-bar";
287
296
  export {
288
297
  FileUpload,
289
298
  FileUploadItem,
@@ -0,0 +1,46 @@
1
+ /* AUTO-GENERATED by scripts/gen-stories.mjs — do not edit.
2
+ Source of truth: apps/web/src/registry/demos.tsx */
3
+ import * as React from "react";
4
+ import type { Meta, StoryObj } from "@storybook/react-vite";
5
+ import { AppBar, AppBarActions, AppBarBrand, AppBarLink, AppBarNav } from "@kinetixui/ui";
6
+ import { Bell } from "lucide-react";
7
+
8
+ const Demo = () => (
9
+ <AppBar className="w-full max-w-2xl rounded-md border">
10
+ <AppBarBrand>
11
+ <span className="grid size-6 place-items-center rounded bg-primary text-[11px] font-bold text-primary-foreground">
12
+ A
13
+ </span>
14
+ Acme
15
+ </AppBarBrand>
16
+ <AppBarNav>
17
+ <AppBarLink href="#" active>
18
+ Overview
19
+ </AppBarLink>
20
+ <AppBarLink href="#">Reports</AppBarLink>
21
+ <AppBarLink href="#">Team</AppBarLink>
22
+ </AppBarNav>
23
+ <AppBarActions>
24
+ <button
25
+ type="button"
26
+ aria-label="Notifications"
27
+ className="flex size-9 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground"
28
+ >
29
+ <Bell className="size-4" />
30
+ </button>
31
+ <span className="grid size-8 place-items-center rounded-full bg-muted text-xs font-medium">KZ</span>
32
+ </AppBarActions>
33
+ </AppBar>
34
+ );
35
+
36
+ const meta = {
37
+ title: "Components/AppBar",
38
+ parameters: {
39
+ layout: "centered",
40
+ docs: { source: { code: "<AppBar>\\n <AppBarBrand>Acme</AppBarBrand>\\n <AppBarNav>\\n <AppBarLink href=\"/\" active>Overview</AppBarLink>\\n <AppBarLink href=\"/reports\">Reports</AppBarLink>\\n <AppBarLink href=\"/team\">Team</AppBarLink>\\n </AppBarNav>\\n <AppBarActions>\\n <Button variant=\"Ghost\" size=\"icon\"><Bell /></Button>\\n <Avatar>…</Avatar>\\n </AppBarActions>\\n</AppBar>", language: "tsx" } },
41
+ },
42
+ } satisfies Meta;
43
+
44
+ export default meta;
45
+
46
+ export const Default: StoryObj<typeof meta> = { render: () => <Demo /> };