@lessly/ui 0.2.1 → 0.3.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 +62 -1
- package/dist/index.js +194 -80
- package/dist/styles.css +16 -3
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -730,6 +730,67 @@ interface UseSidebarResult {
|
|
|
730
730
|
*/
|
|
731
731
|
declare function useSidebar(options?: UseSidebarOptions): UseSidebarResult;
|
|
732
732
|
|
|
733
|
+
type NavRowVariant = 'rail' | 'menu';
|
|
734
|
+
interface NavRowOwnProps {
|
|
735
|
+
/** Leading glyph. Rendered in a fixed 20px box; SVGs are normalized to 18px.
|
|
736
|
+
* A falsy value (`null`/`false`/`0`/`''`) renders nothing — there is no reserved
|
|
737
|
+
* empty slot, so the row's content shifts left when `icon` is falsy. */
|
|
738
|
+
icon?: React$1.ReactNode;
|
|
739
|
+
label: string;
|
|
740
|
+
active?: boolean;
|
|
741
|
+
variant: NavRowVariant;
|
|
742
|
+
/** Right-aligned adornment: chevron, checkmark, action. Keeps its own size.
|
|
743
|
+
* A falsy value (`null`/`false`/`0`/`''`) renders nothing — e.g. passing
|
|
744
|
+
* `trailing={count}` with `count === 0` produces no adornment, not a "0". */
|
|
745
|
+
trailing?: React$1.ReactNode;
|
|
746
|
+
/** Icon-only row (collapsed rails). `label` becomes the aria-label. */
|
|
747
|
+
hideLabel?: boolean;
|
|
748
|
+
}
|
|
749
|
+
/** Render the single child element instead of a button, e.g. a router <Link>.
|
|
750
|
+
* The row composes its content from props, so the child's own children are replaced —
|
|
751
|
+
* `children` is only accepted when `asChild` is true; otherwise it is rejected at the
|
|
752
|
+
* type level rather than silently dropped at render time. */
|
|
753
|
+
type NavRowProps = NavRowOwnProps & Omit<React$1.ComponentPropsWithoutRef<'button'>, 'children'> & ({
|
|
754
|
+
asChild: true;
|
|
755
|
+
children: React$1.ReactElement;
|
|
756
|
+
} | {
|
|
757
|
+
asChild?: false;
|
|
758
|
+
children?: never;
|
|
759
|
+
});
|
|
760
|
+
/** Nav row primitive (rail and menu variants). Composes an icon, label and trailing slot
|
|
761
|
+
* into a button, or into a single child via `asChild` (e.g. a router `<Link>`).
|
|
762
|
+
*
|
|
763
|
+
* Rail rows are designed for the `bg-surface` canvas: in the light theme `--hov-bg`
|
|
764
|
+
* equals `--color-bg-elevated`/`--menu-bg` (`#ffffff`), so a rail `NavRow` placed on an
|
|
765
|
+
* elevated/white surface has no hover contrast in light mode. This is the approved
|
|
766
|
+
* design and the token is not expected to change — avoid using rail `NavRow` off the
|
|
767
|
+
* `bg-surface` canvas in light theme. */
|
|
768
|
+
declare const NavRow: React$1.ForwardRefExoticComponent<NavRowProps & React$1.RefAttributes<HTMLButtonElement>>;
|
|
769
|
+
|
|
770
|
+
type NavSectionLabelProps = React$1.HTMLAttributes<HTMLDivElement>;
|
|
771
|
+
/** Section header for nav rails and menu popups. Insets match the 0.3.0 prototype
|
|
772
|
+
* (4px 4px 2px 8px), so it hangs slightly left of the rows it labels. */
|
|
773
|
+
declare const NavSectionLabel: React$1.ForwardRefExoticComponent<NavSectionLabelProps & React$1.RefAttributes<HTMLDivElement>>;
|
|
774
|
+
|
|
775
|
+
interface MenuPopupProps {
|
|
776
|
+
/** The element that opens the menu. Rendered via PopoverTrigger asChild. */
|
|
777
|
+
trigger: React$1.ReactNode;
|
|
778
|
+
children: React$1.ReactNode;
|
|
779
|
+
open?: boolean;
|
|
780
|
+
defaultOpen?: boolean;
|
|
781
|
+
onOpenChange?: (open: boolean) => void;
|
|
782
|
+
/** Which way the panel opens from its trigger. Default 'down'. */
|
|
783
|
+
direction?: 'up' | 'down';
|
|
784
|
+
align?: 'start' | 'center' | 'end';
|
|
785
|
+
/** Gap between trigger and panel, in px. Default 6 (prototype). */
|
|
786
|
+
sideOffset?: number;
|
|
787
|
+
className?: string;
|
|
788
|
+
}
|
|
789
|
+
/** Popup menu shell. Wraps the repo's Radix Popover, so outside-click close, focus
|
|
790
|
+
* management and portalling come from the primitive rather than being re-implemented. */
|
|
791
|
+
declare function MenuPopup({ trigger, children, open, defaultOpen, onOpenChange, direction, align, sideOffset, className, }: MenuPopupProps): React$1.JSX.Element;
|
|
792
|
+
declare const MenuDivider: React$1.ForwardRefExoticComponent<React$1.HTMLAttributes<HTMLDivElement> & React$1.RefAttributes<HTMLDivElement>>;
|
|
793
|
+
|
|
733
794
|
interface NavItem {
|
|
734
795
|
label: string;
|
|
735
796
|
href: string;
|
|
@@ -788,4 +849,4 @@ declare function AppShell({ sidebar, topBar, children, className }: AppShellProp
|
|
|
788
849
|
/** Alias of AppShell — reads better in app router files. */
|
|
789
850
|
declare const AuthenticatedLayout: typeof AppShell;
|
|
790
851
|
|
|
791
|
-
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AppShell, type AppShellProps, AppSidebar, type AppSidebarProps, AspectRatio, AuthenticatedLayout, Avatar, AvatarFallback, AvatarImage, Badge, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, Calendar, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, type CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ConfirmDialog, type ConfirmDialogProps, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, type CopyButtonProps, DatePicker, type DatePickerProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DocsLink, type DocsLinkProps, 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, EmptyState, type EmptyStateProps, ExtensionIcon, type ExtensionIconProps, ExtensionLink, type ExtensionLinkProps, type ExtensionLinkUiMode, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, HoverCard, HoverCardContent, HoverCardTrigger, InlineError, type InlineErrorProps, Input, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Label, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, type NavItem, type NavLinkComponent, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, RadioGroup, RadioGroupItem, ScrollArea, ScrollBar, SectionIntro, Select, type SelectOption, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarNav, SidebarNavLink, type SidebarNavLinkProps, type SidebarNavProps, Skeleton, Slider, StatCard, type StatCardProps, StatusDot, type StatusDotProps, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, type TextareaProps, ThemeToggle, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, type UseSidebarOptions, type UseSidebarResult, UserMenu, type UserMenuItem, type UserMenuProps, type UserMenuUser, alertVariants, badgeVariants, buttonVariants, cn, isKnownExtensionIcon, navigationMenuTriggerStyle, statusDotVariants, toggleVariants, useCarousel, useFormField, useIsMobile, useSidebar, useTheme };
|
|
852
|
+
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AppShell, type AppShellProps, AppSidebar, type AppSidebarProps, AspectRatio, AuthenticatedLayout, Avatar, AvatarFallback, AvatarImage, Badge, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, Calendar, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, type CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, Checkbox, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ConfirmDialog, type ConfirmDialogProps, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, type CopyButtonProps, DatePicker, type DatePickerProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DocsLink, type DocsLinkProps, 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, EmptyState, type EmptyStateProps, ExtensionIcon, type ExtensionIconProps, ExtensionLink, type ExtensionLinkProps, type ExtensionLinkUiMode, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, HoverCard, HoverCardContent, HoverCardTrigger, InlineError, type InlineErrorProps, Input, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Label, MenuDivider, MenuPopup, type MenuPopupProps, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, type NavItem, type NavLinkComponent, NavRow, type NavRowProps, type NavRowVariant, NavSectionLabel, type NavSectionLabelProps, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, RadioGroup, RadioGroupItem, ScrollArea, ScrollBar, SectionIntro, Select, type SelectOption, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarNav, SidebarNavLink, type SidebarNavLinkProps, type SidebarNavProps, Skeleton, Slider, StatCard, type StatCardProps, StatusDot, type StatusDotProps, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, type TextareaProps, ThemeToggle, Toaster, Toggle, ToggleGroup, ToggleGroupItem, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, type UseSidebarOptions, type UseSidebarResult, UserMenu, type UserMenuItem, type UserMenuProps, type UserMenuUser, alertVariants, badgeVariants, buttonVariants, cn, isKnownExtensionIcon, navigationMenuTriggerStyle, statusDotVariants, toggleVariants, useCarousel, useFormField, useIsMobile, useSidebar, useTheme };
|
package/dist/index.js
CHANGED
|
@@ -2632,7 +2632,7 @@ function UserMenu({ user, items, collapsed = false, align = "end" }) {
|
|
|
2632
2632
|
"button",
|
|
2633
2633
|
{
|
|
2634
2634
|
type: "button",
|
|
2635
|
-
className: "flex w-full items-center gap-2 rounded-
|
|
2635
|
+
className: "flex w-full items-center gap-2.5 rounded-xl px-2.5 py-1.5 text-left transition-colors hover:bg-[var(--hov-bg)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
2636
2636
|
children: [
|
|
2637
2637
|
avatar,
|
|
2638
2638
|
/* @__PURE__ */ jsxs25("span", { className: "min-w-0 flex-1", children: [
|
|
@@ -2649,30 +2649,41 @@ function UserMenu({ user, items, collapsed = false, align = "end" }) {
|
|
|
2649
2649
|
/* @__PURE__ */ jsx52(TooltipTrigger, { asChild: true, children: menuTrigger }),
|
|
2650
2650
|
/* @__PURE__ */ jsx52(TooltipContent, { side: "right", children: user.name })
|
|
2651
2651
|
] }) }) : menuTrigger,
|
|
2652
|
-
/* @__PURE__ */ jsxs25(
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2652
|
+
/* @__PURE__ */ jsxs25(
|
|
2653
|
+
DropdownMenuContent,
|
|
2654
|
+
{
|
|
2655
|
+
align,
|
|
2656
|
+
sideOffset: 6,
|
|
2657
|
+
className: "flex w-56 flex-col gap-px rounded-xl border-border-subtle bg-[var(--menu-bg)] p-1 shadow-(--menu-shadow)",
|
|
2658
|
+
children: [
|
|
2659
|
+
/* @__PURE__ */ jsxs25(DropdownMenuLabel, { className: "px-2 pt-1.5 pb-1 text-xs font-medium text-text-tertiary", children: [
|
|
2660
|
+
/* @__PURE__ */ jsx52("span", { className: "block truncate text-sm font-medium text-text-primary", children: user.name }),
|
|
2661
|
+
user.email && /* @__PURE__ */ jsx52("span", { className: "block truncate text-xs font-normal text-text-tertiary", children: user.email })
|
|
2662
|
+
] }),
|
|
2663
|
+
/* @__PURE__ */ jsx52(DropdownMenuSeparator, { className: "mx-0 shrink-0 bg-border-subtle" }),
|
|
2664
|
+
items.map((item, i) => {
|
|
2665
|
+
const Icon = item.icon;
|
|
2666
|
+
const content = /* @__PURE__ */ jsxs25(Fragment, { children: [
|
|
2667
|
+
Icon && /* @__PURE__ */ jsx52(Icon, { className: "size-4", "aria-hidden": "true" }),
|
|
2668
|
+
item.label
|
|
2669
|
+
] });
|
|
2670
|
+
return /* @__PURE__ */ jsx52(
|
|
2671
|
+
DropdownMenuItem,
|
|
2672
|
+
{
|
|
2673
|
+
onSelect: item.onSelect,
|
|
2674
|
+
className: cn(
|
|
2675
|
+
"gap-2 rounded-md px-2 py-1.5 text-sm font-medium text-text-secondary focus:bg-[var(--menu-hov)] focus:text-text-primary",
|
|
2676
|
+
item.destructive && "text-text-danger focus:text-text-danger"
|
|
2677
|
+
),
|
|
2678
|
+
asChild: Boolean(item.href),
|
|
2679
|
+
children: item.href ? /* @__PURE__ */ jsx52("a", { href: item.href, children: content }) : content
|
|
2680
|
+
},
|
|
2681
|
+
`${item.label}-${i}`
|
|
2682
|
+
);
|
|
2683
|
+
})
|
|
2684
|
+
]
|
|
2685
|
+
}
|
|
2686
|
+
)
|
|
2676
2687
|
] });
|
|
2677
2688
|
return menu;
|
|
2678
2689
|
}
|
|
@@ -2770,9 +2781,113 @@ function useSidebar(options = {}) {
|
|
|
2770
2781
|
return { collapsed, setCollapsed, toggle };
|
|
2771
2782
|
}
|
|
2772
2783
|
|
|
2784
|
+
// src/components/nav-row.tsx
|
|
2785
|
+
import * as React47 from "react";
|
|
2786
|
+
import { Slot as Slot4 } from "@radix-ui/react-slot";
|
|
2787
|
+
import { Fragment as Fragment2, jsx as jsx55, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
2788
|
+
var base = "flex w-full items-center text-left text-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus";
|
|
2789
|
+
var shape = {
|
|
2790
|
+
rail: "gap-[14px] rounded-xl px-2.5 py-2",
|
|
2791
|
+
menu: "gap-2 rounded-md px-2 py-1.5"
|
|
2792
|
+
};
|
|
2793
|
+
var state = {
|
|
2794
|
+
rail: {
|
|
2795
|
+
idle: "font-medium text-text-secondary hover:bg-[var(--hov-bg)] hover:text-text-primary",
|
|
2796
|
+
active: "bg-bg-brand-subtle font-semibold text-text-brand"
|
|
2797
|
+
},
|
|
2798
|
+
menu: {
|
|
2799
|
+
idle: "font-medium text-text-secondary hover:bg-[var(--menu-hov)]",
|
|
2800
|
+
active: "font-semibold text-text-brand hover:bg-[var(--menu-hov)]"
|
|
2801
|
+
}
|
|
2802
|
+
};
|
|
2803
|
+
var NavRow = React47.forwardRef(function NavRow2({ icon, label, active = false, variant, trailing, hideLabel = false, asChild = false, className, children, ...props }, ref) {
|
|
2804
|
+
const content = /* @__PURE__ */ jsxs26(Fragment2, { children: [
|
|
2805
|
+
icon && /* @__PURE__ */ jsx55(
|
|
2806
|
+
"span",
|
|
2807
|
+
{
|
|
2808
|
+
className: "flex size-5 shrink-0 items-center justify-center [&_svg]:size-[18px]",
|
|
2809
|
+
"aria-hidden": "true",
|
|
2810
|
+
children: icon
|
|
2811
|
+
}
|
|
2812
|
+
),
|
|
2813
|
+
!hideLabel && /* @__PURE__ */ jsx55("span", { className: "min-w-0 flex-1 truncate", children: label }),
|
|
2814
|
+
trailing && /* @__PURE__ */ jsx55("span", { className: "flex shrink-0 items-center", children: trailing })
|
|
2815
|
+
] });
|
|
2816
|
+
const classes = cn(base, shape[variant], state[variant][active ? "active" : "idle"], className);
|
|
2817
|
+
if (asChild) {
|
|
2818
|
+
const child = React47.Children.only(children);
|
|
2819
|
+
return /* @__PURE__ */ jsx55(Slot4, { ref, className: classes, "aria-label": hideLabel ? label : void 0, ...props, children: React47.cloneElement(child, void 0, content) });
|
|
2820
|
+
}
|
|
2821
|
+
return /* @__PURE__ */ jsx55("button", { ref, type: "button", className: classes, "aria-label": hideLabel ? label : void 0, ...props, children: content });
|
|
2822
|
+
});
|
|
2823
|
+
NavRow.displayName = "NavRow";
|
|
2824
|
+
|
|
2825
|
+
// src/components/nav-section-label.tsx
|
|
2826
|
+
import * as React48 from "react";
|
|
2827
|
+
import { jsx as jsx56 } from "react/jsx-runtime";
|
|
2828
|
+
var NavSectionLabel = React48.forwardRef(
|
|
2829
|
+
function NavSectionLabel2({ className, ...props }, ref) {
|
|
2830
|
+
return /* @__PURE__ */ jsx56(
|
|
2831
|
+
"div",
|
|
2832
|
+
{
|
|
2833
|
+
ref,
|
|
2834
|
+
className: cn("pt-1 pr-1 pb-0.5 pl-2 text-xs font-medium text-text-tertiary", className),
|
|
2835
|
+
...props
|
|
2836
|
+
}
|
|
2837
|
+
);
|
|
2838
|
+
}
|
|
2839
|
+
);
|
|
2840
|
+
NavSectionLabel.displayName = "NavSectionLabel";
|
|
2841
|
+
|
|
2842
|
+
// src/components/menu-popup.tsx
|
|
2843
|
+
import * as React49 from "react";
|
|
2844
|
+
import { jsx as jsx57, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
2845
|
+
function MenuPopup({
|
|
2846
|
+
trigger,
|
|
2847
|
+
children,
|
|
2848
|
+
open,
|
|
2849
|
+
defaultOpen,
|
|
2850
|
+
onOpenChange,
|
|
2851
|
+
direction = "down",
|
|
2852
|
+
align = "start",
|
|
2853
|
+
sideOffset = 6,
|
|
2854
|
+
className
|
|
2855
|
+
}) {
|
|
2856
|
+
return /* @__PURE__ */ jsxs27(Popover, { open, defaultOpen, onOpenChange, children: [
|
|
2857
|
+
/* @__PURE__ */ jsx57(PopoverTrigger, { asChild: true, children: trigger }),
|
|
2858
|
+
/* @__PURE__ */ jsx57(
|
|
2859
|
+
PopoverContent,
|
|
2860
|
+
{
|
|
2861
|
+
side: direction === "up" ? "top" : "bottom",
|
|
2862
|
+
align,
|
|
2863
|
+
sideOffset,
|
|
2864
|
+
className: cn(
|
|
2865
|
+
"flex w-56 flex-col gap-px rounded-xl border border-border-subtle bg-[var(--menu-bg)] p-1 shadow-(--menu-shadow)",
|
|
2866
|
+
className
|
|
2867
|
+
),
|
|
2868
|
+
children
|
|
2869
|
+
}
|
|
2870
|
+
)
|
|
2871
|
+
] });
|
|
2872
|
+
}
|
|
2873
|
+
var MenuDivider = React49.forwardRef(
|
|
2874
|
+
function MenuDivider2({ className, ...props }, ref) {
|
|
2875
|
+
return /* @__PURE__ */ jsx57(
|
|
2876
|
+
"div",
|
|
2877
|
+
{
|
|
2878
|
+
ref,
|
|
2879
|
+
role: "separator",
|
|
2880
|
+
className: cn("my-1 h-px shrink-0 bg-border-subtle", className),
|
|
2881
|
+
...props
|
|
2882
|
+
}
|
|
2883
|
+
);
|
|
2884
|
+
}
|
|
2885
|
+
);
|
|
2886
|
+
MenuDivider.displayName = "MenuDivider";
|
|
2887
|
+
|
|
2773
2888
|
// src/components/sidebar-nav.tsx
|
|
2774
2889
|
import { Link as Link3, useLocation } from "react-router";
|
|
2775
|
-
import { jsx as
|
|
2890
|
+
import { jsx as jsx58, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
2776
2891
|
function isActivePath(pathname, full, exact) {
|
|
2777
2892
|
if (exact) return pathname === full;
|
|
2778
2893
|
return pathname === full || pathname.startsWith(`${full}/`);
|
|
@@ -2788,28 +2903,23 @@ function SidebarNavLink({
|
|
|
2788
2903
|
const Comp = LinkComponent ?? Link3;
|
|
2789
2904
|
const to = `${basePath}${item.href}`;
|
|
2790
2905
|
const Icon = item.icon;
|
|
2791
|
-
const link = /* @__PURE__ */
|
|
2792
|
-
|
|
2906
|
+
const link = /* @__PURE__ */ jsx58(
|
|
2907
|
+
NavRow,
|
|
2793
2908
|
{
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
"aria-current": active ? "page" : void 0
|
|
2802
|
-
"aria-label": collapsed ? item.label : void 0,
|
|
2803
|
-
children: [
|
|
2804
|
-
Icon && /* @__PURE__ */ jsx55(Icon, { className: "size-[18px] shrink-0", "aria-hidden": "true" }),
|
|
2805
|
-
!collapsed && item.label
|
|
2806
|
-
]
|
|
2909
|
+
variant: "rail",
|
|
2910
|
+
active,
|
|
2911
|
+
label: item.label,
|
|
2912
|
+
hideLabel: collapsed,
|
|
2913
|
+
icon: Icon ? /* @__PURE__ */ jsx58(Icon, { "aria-hidden": "true" }) : void 0,
|
|
2914
|
+
className: cn(collapsed && "size-9 justify-center px-0 py-0", className),
|
|
2915
|
+
asChild: true,
|
|
2916
|
+
children: /* @__PURE__ */ jsx58(Comp, { to, "aria-current": active ? "page" : void 0 })
|
|
2807
2917
|
}
|
|
2808
2918
|
);
|
|
2809
2919
|
if (!collapsed) return link;
|
|
2810
|
-
return /* @__PURE__ */
|
|
2811
|
-
/* @__PURE__ */
|
|
2812
|
-
/* @__PURE__ */
|
|
2920
|
+
return /* @__PURE__ */ jsxs28(Tooltip, { children: [
|
|
2921
|
+
/* @__PURE__ */ jsx58(TooltipTrigger, { asChild: true, children: link }),
|
|
2922
|
+
/* @__PURE__ */ jsx58(TooltipContent, { side: "right", children: item.label })
|
|
2813
2923
|
] });
|
|
2814
2924
|
}
|
|
2815
2925
|
function SidebarNav({
|
|
@@ -2821,18 +2931,18 @@ function SidebarNav({
|
|
|
2821
2931
|
className
|
|
2822
2932
|
}) {
|
|
2823
2933
|
const { pathname } = useLocation();
|
|
2824
|
-
const nav = /* @__PURE__ */
|
|
2934
|
+
const nav = /* @__PURE__ */ jsx58(
|
|
2825
2935
|
"nav",
|
|
2826
2936
|
{
|
|
2827
2937
|
className: cn(
|
|
2828
2938
|
"flex flex-col gap-0.5",
|
|
2829
|
-
collapsed ? "items-center px-1" : "px-
|
|
2939
|
+
collapsed ? "items-center px-1" : "px-3",
|
|
2830
2940
|
className
|
|
2831
2941
|
),
|
|
2832
2942
|
children: items.map((item) => {
|
|
2833
2943
|
const full = `${basePath}${item.href}`;
|
|
2834
2944
|
const active = isItemActive ? isItemActive(item, pathname) : isActivePath(pathname, full, item.exact);
|
|
2835
|
-
return /* @__PURE__ */
|
|
2945
|
+
return /* @__PURE__ */ jsx58(
|
|
2836
2946
|
SidebarNavLink,
|
|
2837
2947
|
{
|
|
2838
2948
|
item,
|
|
@@ -2846,12 +2956,12 @@ function SidebarNav({
|
|
|
2846
2956
|
})
|
|
2847
2957
|
}
|
|
2848
2958
|
);
|
|
2849
|
-
return collapsed ? /* @__PURE__ */
|
|
2959
|
+
return collapsed ? /* @__PURE__ */ jsx58(TooltipProvider, { children: nav }) : nav;
|
|
2850
2960
|
}
|
|
2851
2961
|
|
|
2852
2962
|
// src/components/app-sidebar.tsx
|
|
2853
2963
|
import { PanelLeft } from "lucide-react";
|
|
2854
|
-
import { jsx as
|
|
2964
|
+
import { jsx as jsx59, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
2855
2965
|
function AppSidebar({
|
|
2856
2966
|
items,
|
|
2857
2967
|
logo,
|
|
@@ -2871,7 +2981,7 @@ function AppSidebar({
|
|
|
2871
2981
|
defaultCollapsed,
|
|
2872
2982
|
onCollapsedChange
|
|
2873
2983
|
});
|
|
2874
|
-
return /* @__PURE__ */
|
|
2984
|
+
return /* @__PURE__ */ jsxs29(
|
|
2875
2985
|
"aside",
|
|
2876
2986
|
{
|
|
2877
2987
|
"data-collapsed": collapsed,
|
|
@@ -2881,76 +2991,76 @@ function AppSidebar({
|
|
|
2881
2991
|
className
|
|
2882
2992
|
),
|
|
2883
2993
|
children: [
|
|
2884
|
-
collapsed ? /* @__PURE__ */
|
|
2885
|
-
/* @__PURE__ */
|
|
2886
|
-
/* @__PURE__ */
|
|
2994
|
+
collapsed ? /* @__PURE__ */ jsx59("div", { className: "flex justify-center border-b border-border-subtle p-2", children: header ?? /* @__PURE__ */ jsxs29("div", { className: "group relative flex size-8 items-center justify-center", children: [
|
|
2995
|
+
/* @__PURE__ */ jsx59("span", { className: "pointer-events-none transition-opacity group-hover:opacity-0 group-focus-within:opacity-0", children: logoCollapsed ?? logo }),
|
|
2996
|
+
/* @__PURE__ */ jsx59(
|
|
2887
2997
|
"button",
|
|
2888
2998
|
{
|
|
2889
2999
|
type: "button",
|
|
2890
3000
|
onClick: toggle,
|
|
2891
3001
|
"aria-label": "Expand sidebar",
|
|
2892
3002
|
"aria-expanded": false,
|
|
2893
|
-
className: "absolute inset-0 flex items-center justify-center rounded-md text-text-secondary opacity-0 transition-opacity hover:bg-bg
|
|
2894
|
-
children: /* @__PURE__ */
|
|
3003
|
+
className: "absolute inset-0 flex items-center justify-center rounded-md text-text-secondary opacity-0 transition-opacity hover:bg-[var(--hov-bg)] focus-visible:outline-none focus-visible:opacity-100 focus-visible:ring-2 focus-visible:ring-border-focus group-hover:opacity-100 group-focus-within:opacity-100",
|
|
3004
|
+
children: /* @__PURE__ */ jsx59(PanelLeft, { className: "size-4", "aria-hidden": "true" })
|
|
2895
3005
|
}
|
|
2896
3006
|
)
|
|
2897
|
-
] }) }) : /* @__PURE__ */
|
|
3007
|
+
] }) }) : /* @__PURE__ */ jsxs29("div", { className: "flex items-center justify-between border-b border-border-subtle p-3", children: [
|
|
2898
3008
|
header ?? logo,
|
|
2899
|
-
/* @__PURE__ */
|
|
3009
|
+
/* @__PURE__ */ jsx59(
|
|
2900
3010
|
"button",
|
|
2901
3011
|
{
|
|
2902
3012
|
type: "button",
|
|
2903
3013
|
onClick: toggle,
|
|
2904
3014
|
"aria-label": "Collapse sidebar",
|
|
2905
3015
|
"aria-expanded": true,
|
|
2906
|
-
className: "flex size-6 items-center justify-center rounded-md text-text-secondary transition-colors hover:bg-bg
|
|
2907
|
-
children: /* @__PURE__ */
|
|
3016
|
+
className: "flex size-6 items-center justify-center rounded-md text-text-secondary transition-colors hover:bg-[var(--hov-bg)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus",
|
|
3017
|
+
children: /* @__PURE__ */ jsx59(PanelLeft, { className: "size-4", "aria-hidden": "true" })
|
|
2908
3018
|
}
|
|
2909
3019
|
)
|
|
2910
3020
|
] }),
|
|
2911
|
-
/* @__PURE__ */
|
|
2912
|
-
footer && /* @__PURE__ */
|
|
3021
|
+
/* @__PURE__ */ jsx59("div", { className: "flex-1 overflow-y-auto overflow-x-hidden pt-3 pb-2", children: /* @__PURE__ */ jsx59(SidebarNav, { items, collapsed, basePath, LinkComponent, isItemActive }) }),
|
|
3022
|
+
footer && /* @__PURE__ */ jsx59("div", { className: cn("border-t border-border-subtle", collapsed ? "px-1 py-2" : "px-3 py-3"), children: footer })
|
|
2913
3023
|
]
|
|
2914
3024
|
}
|
|
2915
3025
|
);
|
|
2916
3026
|
}
|
|
2917
3027
|
|
|
2918
3028
|
// src/components/app-shell.tsx
|
|
2919
|
-
import * as
|
|
3029
|
+
import * as React50 from "react";
|
|
2920
3030
|
import { Menu as Menu2 } from "lucide-react";
|
|
2921
3031
|
import { useLocation as useLocation2 } from "react-router";
|
|
2922
|
-
import { jsx as
|
|
3032
|
+
import { jsx as jsx60, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
2923
3033
|
function expandedSidebar(sidebar) {
|
|
2924
|
-
return
|
|
3034
|
+
return React50.isValidElement(sidebar) ? React50.cloneElement(sidebar, { collapsed: false }) : sidebar;
|
|
2925
3035
|
}
|
|
2926
3036
|
function AppShell({ sidebar, topBar, children, className }) {
|
|
2927
3037
|
const { pathname } = useLocation2();
|
|
2928
|
-
const [mobileOpen, setMobileOpen] =
|
|
2929
|
-
|
|
3038
|
+
const [mobileOpen, setMobileOpen] = React50.useState(false);
|
|
3039
|
+
React50.useEffect(() => {
|
|
2930
3040
|
setMobileOpen(false);
|
|
2931
3041
|
}, [pathname]);
|
|
2932
3042
|
const isMobile = useIsMobile();
|
|
2933
3043
|
if (isMobile) {
|
|
2934
|
-
return /* @__PURE__ */
|
|
2935
|
-
/* @__PURE__ */
|
|
2936
|
-
/* @__PURE__ */
|
|
2937
|
-
/* @__PURE__ */
|
|
2938
|
-
/* @__PURE__ */
|
|
2939
|
-
/* @__PURE__ */
|
|
2940
|
-
/* @__PURE__ */
|
|
3044
|
+
return /* @__PURE__ */ jsx60(TooltipProvider, { children: /* @__PURE__ */ jsxs30("div", { className: cn("flex min-h-screen flex-col bg-bg-sunken", className), children: [
|
|
3045
|
+
/* @__PURE__ */ jsxs30("header", { className: "flex shrink-0 items-center justify-between border-b border-border-subtle bg-bg-surface px-4 py-3", children: [
|
|
3046
|
+
/* @__PURE__ */ jsxs30(Sheet, { open: mobileOpen, onOpenChange: setMobileOpen, children: [
|
|
3047
|
+
/* @__PURE__ */ jsx60(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsx60(Button, { variant: "ghost", size: "icon", className: "size-8 text-text-secondary", "aria-label": "Open navigation", children: /* @__PURE__ */ jsx60(Menu2, { className: "size-5" }) }) }),
|
|
3048
|
+
/* @__PURE__ */ jsxs30(SheetContent, { side: "left", className: "w-[240px] bg-bg-surface p-0", children: [
|
|
3049
|
+
/* @__PURE__ */ jsx60(SheetTitle, { className: "sr-only", children: "Navigation" }),
|
|
3050
|
+
/* @__PURE__ */ jsx60(SheetDescription, { className: "sr-only", children: "Application navigation menu" }),
|
|
2941
3051
|
expandedSidebar(sidebar)
|
|
2942
3052
|
] })
|
|
2943
3053
|
] }),
|
|
2944
|
-
/* @__PURE__ */
|
|
3054
|
+
/* @__PURE__ */ jsx60("div", { className: "flex items-center gap-2", children: topBar })
|
|
2945
3055
|
] }),
|
|
2946
|
-
/* @__PURE__ */
|
|
3056
|
+
/* @__PURE__ */ jsx60("main", { className: "flex-1 overflow-auto p-4", children })
|
|
2947
3057
|
] }) });
|
|
2948
3058
|
}
|
|
2949
|
-
return /* @__PURE__ */
|
|
2950
|
-
/* @__PURE__ */
|
|
2951
|
-
/* @__PURE__ */
|
|
2952
|
-
/* @__PURE__ */
|
|
2953
|
-
/* @__PURE__ */
|
|
3059
|
+
return /* @__PURE__ */ jsx60(TooltipProvider, { children: /* @__PURE__ */ jsxs30("div", { className: cn("flex min-h-screen gap-2 bg-bg-sunken p-4", className), children: [
|
|
3060
|
+
/* @__PURE__ */ jsx60("div", { className: "sticky top-4 h-[calc(100vh-32px)] shrink-0", children: sidebar }),
|
|
3061
|
+
/* @__PURE__ */ jsxs30("div", { className: "flex min-w-0 flex-1 flex-col overflow-hidden rounded-2xl border border-border-subtle bg-bg-surface", children: [
|
|
3062
|
+
/* @__PURE__ */ jsx60("div", { className: "flex min-h-[52px] shrink-0 items-center justify-end gap-2 border-b border-border-subtle px-5", children: topBar }),
|
|
3063
|
+
/* @__PURE__ */ jsx60("main", { className: "flex-1 overflow-auto px-7 py-8", children })
|
|
2954
3064
|
] })
|
|
2955
3065
|
] }) });
|
|
2956
3066
|
}
|
|
@@ -3089,6 +3199,8 @@ export {
|
|
|
3089
3199
|
InputOTPSeparator,
|
|
3090
3200
|
InputOTPSlot,
|
|
3091
3201
|
Label2 as Label,
|
|
3202
|
+
MenuDivider,
|
|
3203
|
+
MenuPopup,
|
|
3092
3204
|
Menubar,
|
|
3093
3205
|
MenubarCheckboxItem,
|
|
3094
3206
|
MenubarContent,
|
|
@@ -3105,6 +3217,8 @@ export {
|
|
|
3105
3217
|
MenubarSubContent,
|
|
3106
3218
|
MenubarSubTrigger,
|
|
3107
3219
|
MenubarTrigger,
|
|
3220
|
+
NavRow,
|
|
3221
|
+
NavSectionLabel,
|
|
3108
3222
|
NavigationMenu,
|
|
3109
3223
|
NavigationMenuContent,
|
|
3110
3224
|
NavigationMenuIndicator,
|
package/dist/styles.css
CHANGED
|
@@ -107,6 +107,14 @@
|
|
|
107
107
|
--color-border-success: #1da456;
|
|
108
108
|
--color-border-warning: #b3780e;
|
|
109
109
|
--color-border-danger: #e82020;
|
|
110
|
+
/* === Nav / menu surfaces (0.3.0 sidebar) === */
|
|
111
|
+
/* --menu-shadow is a literal: this package ships no --shadow-* variables (shadows live
|
|
112
|
+
in the generated Tailwind preset's boxShadow map), so var(--shadow-md) would resolve
|
|
113
|
+
to nothing. Value mirrors the 0.3.0 prototype DS's own --shadow-md. */
|
|
114
|
+
--hov-bg: color-mix(in srgb, var(--color-text-primary) 7%, transparent);
|
|
115
|
+
--menu-bg: var(--color-bg-elevated);
|
|
116
|
+
--menu-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
|
|
117
|
+
--menu-hov: var(--hov-bg);
|
|
110
118
|
}
|
|
111
119
|
|
|
112
120
|
.light {
|
|
@@ -116,7 +124,7 @@
|
|
|
116
124
|
--color-bg-elevated: #ffffff;
|
|
117
125
|
--color-bg-sunken: #e1e2e4;
|
|
118
126
|
--color-bg-brand: #06297d;
|
|
119
|
-
--color-bg-brand-subtle: #
|
|
127
|
+
--color-bg-brand-subtle: #e4ecfe;
|
|
120
128
|
--color-bg-brand-bright: #165ff2;
|
|
121
129
|
--color-bg-brand-hover: #05226a;
|
|
122
130
|
--color-bg-success: #13703c;
|
|
@@ -137,7 +145,7 @@
|
|
|
137
145
|
--color-text-on-success: #f6f7f7;
|
|
138
146
|
--color-text-on-warning: #08090c;
|
|
139
147
|
--color-text-on-danger: #f6f7f7;
|
|
140
|
-
--color-text-brand: #
|
|
148
|
+
--color-text-brand: #0b4cd5;
|
|
141
149
|
--color-text-success: #13703c;
|
|
142
150
|
--color-text-warning: #7a5409;
|
|
143
151
|
--color-text-danger: #94120e;
|
|
@@ -146,7 +154,7 @@
|
|
|
146
154
|
--color-icon-primary: #252936;
|
|
147
155
|
--color-icon-secondary: #535a6e;
|
|
148
156
|
--color-icon-disabled: #8a91a7;
|
|
149
|
-
--color-icon-brand: #
|
|
157
|
+
--color-icon-brand: #165ff2;
|
|
150
158
|
--color-icon-success: #13703c;
|
|
151
159
|
--color-icon-warning: #7a5409;
|
|
152
160
|
--color-icon-danger: #94120e;
|
|
@@ -158,6 +166,11 @@
|
|
|
158
166
|
--color-border-success: #188a49;
|
|
159
167
|
--color-border-warning: #b3780e;
|
|
160
168
|
--color-border-danger: #e82020;
|
|
169
|
+
/* Light keeps opaque plates: a translucent text-mix would vanish on a white menu. */
|
|
170
|
+
--hov-bg: #ffffff;
|
|
171
|
+
--menu-bg: #ffffff;
|
|
172
|
+
--menu-shadow: 0 12px 32px rgba(16, 24, 40, 0.1), 0 2px 8px rgba(16, 24, 40, 0.06);
|
|
173
|
+
--menu-hov: #f2f4f7;
|
|
161
174
|
}
|
|
162
175
|
|
|
163
176
|
/* === Base === */
|