@gv-tech/ui-web 2.16.0 → 2.18.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/README.md CHANGED
@@ -5,7 +5,7 @@ Web-based implementations of the GV Tech design system components, built on top
5
5
  ## Installation
6
6
 
7
7
  ```bash
8
- yarn add @gv-tech/ui-web
8
+ bun add @gv-tech/ui-web
9
9
  ```
10
10
 
11
11
  ## Features
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const N=require("./utils-cdbZV8DZ.js"),M=require("./accordion.cjs"),w=require("./alert.cjs"),t=require("./alert-dialog.cjs"),V=require("./aspect-ratio.cjs"),v=require("./avatar.cjs"),I=require("./badge.cjs"),C=require("./breadcrumb.cjs"),F=require("./button.cjs"),L=require("./calendar.cjs"),b=require("./card.cjs"),m=require("./carousel.cjs"),T=require("./chart.cjs"),O=require("./checkbox.cjs"),P=require("./collapsible.cjs"),u=require("./command.cjs"),r=require("./context-menu.cjs"),a=require("./dialog.cjs"),n=require("./drawer.cjs"),o=require("./dropdown-menu.cjs"),s=require("./form.cjs"),q=require("./hover-card.cjs"),z=require("./input.cjs"),f=require("./label.cjs"),e=require("./menubar.cjs"),g=require("./navigation-menu.cjs"),d=require("./pagination.cjs"),D=require("./popover.cjs"),E=require("./progress.cjs"),B=require("./radio-group.cjs"),A=require("./resizable.cjs"),G=require("./scroll-area.cjs"),R=require("./search.cjs"),i=require("./select.cjs"),j=require("./separator.cjs"),l=require("./sheet.cjs"),U=require("./skeleton.cjs"),_=require("./slider.cjs"),J=require("./sonner.cjs"),K=require("./switch.cjs"),c=require("./table.cjs"),S=require("./tabs.cjs"),H=require("./text.cjs"),Q=require("./textarea.cjs"),W=require("./toggle.cjs"),y=require("./toggle-group.cjs"),h=require("./tooltip.cjs"),p=require("./toast.cjs"),X=require("./theme-provider.cjs"),k=require("./theme-toggle-DXQGNfCe.js"),x=require("./toaster-C_S9hnXa.js"),Y=require("./table-of-contents.cjs"),Z=require("@gv-tech/ui-core");exports.cn=N.cn;exports.Accordion=M.Accordion;exports.AccordionContent=M.AccordionContent;exports.AccordionItem=M.AccordionItem;exports.AccordionTrigger=M.AccordionTrigger;exports.Alert=w.Alert;exports.AlertDescription=w.AlertDescription;exports.AlertTitle=w.AlertTitle;exports.AlertDialog=t.AlertDialog;exports.AlertDialogAction=t.AlertDialogAction;exports.AlertDialogCancel=t.AlertDialogCancel;exports.AlertDialogContent=t.AlertDialogContent;exports.AlertDialogDescription=t.AlertDialogDescription;exports.AlertDialogFooter=t.AlertDialogFooter;exports.AlertDialogHeader=t.AlertDialogHeader;exports.AlertDialogOverlay=t.AlertDialogOverlay;exports.AlertDialogPortal=t.AlertDialogPortal;exports.AlertDialogTitle=t.AlertDialogTitle;exports.AlertDialogTrigger=t.AlertDialogTrigger;exports.AspectRatio=V.AspectRatio;exports.Avatar=v.Avatar;exports.AvatarFallback=v.AvatarFallback;exports.AvatarImage=v.AvatarImage;exports.Badge=I.Badge;exports.badgeVariants=I.badgeVariants;exports.Breadcrumb=C.Breadcrumb;exports.BreadcrumbEllipsis=C.BreadcrumbEllipsis;exports.BreadcrumbItem=C.BreadcrumbItem;exports.BreadcrumbLink=C.BreadcrumbLink;exports.BreadcrumbList=C.BreadcrumbList;exports.BreadcrumbPage=C.BreadcrumbPage;exports.BreadcrumbSeparator=C.BreadcrumbSeparator;exports.Button=F.Button;exports.buttonVariants=F.buttonVariants;exports.Calendar=L.Calendar;exports.CalendarDayButton=L.CalendarDayButton;exports.Card=b.Card;exports.CardContent=b.CardContent;exports.CardDescription=b.CardDescription;exports.CardFooter=b.CardFooter;exports.CardHeader=b.CardHeader;exports.CardTitle=b.CardTitle;exports.Carousel=m.Carousel;exports.CarouselContent=m.CarouselContent;exports.CarouselItem=m.CarouselItem;exports.CarouselNext=m.CarouselNext;exports.CarouselPrevious=m.CarouselPrevious;exports.ChartContainer=T.ChartContainer;exports.ChartLegend=T.ChartLegend;exports.ChartLegendContent=T.ChartLegendContent;exports.ChartStyle=T.ChartStyle;exports.ChartTooltip=T.ChartTooltip;exports.ChartTooltipContent=T.ChartTooltipContent;exports.Checkbox=O.Checkbox;exports.Collapsible=P.Collapsible;exports.CollapsibleContent=P.CollapsibleContent;exports.CollapsibleTrigger=P.CollapsibleTrigger;exports.Command=u.Command;exports.CommandDialog=u.CommandDialog;exports.CommandEmpty=u.CommandEmpty;exports.CommandGroup=u.CommandGroup;exports.CommandInput=u.CommandInput;exports.CommandItem=u.CommandItem;exports.CommandList=u.CommandList;exports.CommandSeparator=u.CommandSeparator;exports.CommandShortcut=u.CommandShortcut;exports.ContextMenu=r.ContextMenu;exports.ContextMenuCheckboxItem=r.ContextMenuCheckboxItem;exports.ContextMenuContent=r.ContextMenuContent;exports.ContextMenuGroup=r.ContextMenuGroup;exports.ContextMenuItem=r.ContextMenuItem;exports.ContextMenuLabel=r.ContextMenuLabel;exports.ContextMenuPortal=r.ContextMenuPortal;exports.ContextMenuRadioGroup=r.ContextMenuRadioGroup;exports.ContextMenuRadioItem=r.ContextMenuRadioItem;exports.ContextMenuSeparator=r.ContextMenuSeparator;exports.ContextMenuShortcut=r.ContextMenuShortcut;exports.ContextMenuSub=r.ContextMenuSub;exports.ContextMenuSubContent=r.ContextMenuSubContent;exports.ContextMenuSubTrigger=r.ContextMenuSubTrigger;exports.ContextMenuTrigger=r.ContextMenuTrigger;exports.Dialog=a.Dialog;exports.DialogClose=a.DialogClose;exports.DialogContent=a.DialogContent;exports.DialogDescription=a.DialogDescription;exports.DialogFooter=a.DialogFooter;exports.DialogHeader=a.DialogHeader;exports.DialogOverlay=a.DialogOverlay;exports.DialogPortal=a.DialogPortal;exports.DialogTitle=a.DialogTitle;exports.DialogTrigger=a.DialogTrigger;exports.Drawer=n.Drawer;exports.DrawerClose=n.DrawerClose;exports.DrawerContent=n.DrawerContent;exports.DrawerDescription=n.DrawerDescription;exports.DrawerFooter=n.DrawerFooter;exports.DrawerHeader=n.DrawerHeader;exports.DrawerOverlay=n.DrawerOverlay;exports.DrawerPortal=n.DrawerPortal;exports.DrawerTitle=n.DrawerTitle;exports.DrawerTrigger=n.DrawerTrigger;exports.DropdownMenu=o.DropdownMenu;exports.DropdownMenuCheckboxItem=o.DropdownMenuCheckboxItem;exports.DropdownMenuContent=o.DropdownMenuContent;exports.DropdownMenuGroup=o.DropdownMenuGroup;exports.DropdownMenuItem=o.DropdownMenuItem;exports.DropdownMenuLabel=o.DropdownMenuLabel;exports.DropdownMenuPortal=o.DropdownMenuPortal;exports.DropdownMenuRadioGroup=o.DropdownMenuRadioGroup;exports.DropdownMenuRadioItem=o.DropdownMenuRadioItem;exports.DropdownMenuSeparator=o.DropdownMenuSeparator;exports.DropdownMenuShortcut=o.DropdownMenuShortcut;exports.DropdownMenuSub=o.DropdownMenuSub;exports.DropdownMenuSubContent=o.DropdownMenuSubContent;exports.DropdownMenuSubTrigger=o.DropdownMenuSubTrigger;exports.DropdownMenuTrigger=o.DropdownMenuTrigger;exports.Form=s.Form;exports.FormControl=s.FormControl;exports.FormDescription=s.FormDescription;exports.FormField=s.FormField;exports.FormItem=s.FormItem;exports.FormLabel=s.FormLabel;exports.FormMessage=s.FormMessage;exports.useFormField=s.useFormField;exports.HoverCard=q.HoverCard;exports.HoverCardContent=q.HoverCardContent;exports.HoverCardTrigger=q.HoverCardTrigger;exports.Input=z.Input;exports.Label=f.Label;exports.Menubar=e.Menubar;exports.MenubarCheckboxItem=e.MenubarCheckboxItem;exports.MenubarContent=e.MenubarContent;exports.MenubarGroup=e.MenubarGroup;exports.MenubarItem=e.MenubarItem;exports.MenubarLabel=e.MenubarLabel;exports.MenubarMenu=e.MenubarMenu;exports.MenubarPortal=e.MenubarPortal;exports.MenubarRadioGroup=e.MenubarRadioGroup;exports.MenubarRadioItem=e.MenubarRadioItem;exports.MenubarSeparator=e.MenubarSeparator;exports.MenubarShortcut=e.MenubarShortcut;exports.MenubarSub=e.MenubarSub;exports.MenubarSubContent=e.MenubarSubContent;exports.MenubarSubTrigger=e.MenubarSubTrigger;exports.MenubarTrigger=e.MenubarTrigger;exports.NavigationMenu=g.NavigationMenu;exports.NavigationMenuContent=g.NavigationMenuContent;exports.NavigationMenuIndicator=g.NavigationMenuIndicator;exports.NavigationMenuItem=g.NavigationMenuItem;exports.NavigationMenuLink=g.NavigationMenuLink;exports.NavigationMenuList=g.NavigationMenuList;exports.NavigationMenuTrigger=g.NavigationMenuTrigger;exports.NavigationMenuViewport=g.NavigationMenuViewport;exports.navigationMenuTriggerStyle=g.navigationMenuTriggerStyle;exports.Pagination=d.Pagination;exports.PaginationContent=d.PaginationContent;exports.PaginationEllipsis=d.PaginationEllipsis;exports.PaginationItem=d.PaginationItem;exports.PaginationLink=d.PaginationLink;exports.PaginationNext=d.PaginationNext;exports.PaginationPrevious=d.PaginationPrevious;exports.Popover=D.Popover;exports.PopoverAnchor=D.PopoverAnchor;exports.PopoverContent=D.PopoverContent;exports.PopoverTrigger=D.PopoverTrigger;exports.Progress=E.Progress;exports.RadioGroup=B.RadioGroup;exports.RadioGroupItem=B.RadioGroupItem;exports.ResizableHandle=A.ResizableHandle;exports.ResizablePanel=A.ResizablePanel;exports.ResizablePanelGroup=A.ResizablePanelGroup;exports.ScrollArea=G.ScrollArea;exports.ScrollBar=G.ScrollBar;exports.Search=R.Search;exports.SearchTrigger=R.SearchTrigger;exports.Select=i.Select;exports.SelectContent=i.SelectContent;exports.SelectGroup=i.SelectGroup;exports.SelectItem=i.SelectItem;exports.SelectLabel=i.SelectLabel;exports.SelectScrollDownButton=i.SelectScrollDownButton;exports.SelectScrollUpButton=i.SelectScrollUpButton;exports.SelectSeparator=i.SelectSeparator;exports.SelectTrigger=i.SelectTrigger;exports.SelectValue=i.SelectValue;exports.Separator=j.Separator;exports.Sheet=l.Sheet;exports.SheetClose=l.SheetClose;exports.SheetContent=l.SheetContent;exports.SheetDescription=l.SheetDescription;exports.SheetFooter=l.SheetFooter;exports.SheetHeader=l.SheetHeader;exports.SheetOverlay=l.SheetOverlay;exports.SheetPortal=l.SheetPortal;exports.SheetTitle=l.SheetTitle;exports.SheetTrigger=l.SheetTrigger;exports.Skeleton=U.Skeleton;exports.Slider=_.Slider;exports.SonnerToaster=J.Toaster;exports.Switch=K.Switch;exports.Table=c.Table;exports.TableBody=c.TableBody;exports.TableCaption=c.TableCaption;exports.TableCell=c.TableCell;exports.TableFooter=c.TableFooter;exports.TableHead=c.TableHead;exports.TableHeader=c.TableHeader;exports.TableRow=c.TableRow;exports.Tabs=S.Tabs;exports.TabsContent=S.TabsContent;exports.TabsList=S.TabsList;exports.TabsTrigger=S.TabsTrigger;exports.Text=H.Text;exports.textVariants=H.textVariants;exports.Textarea=Q.Textarea;exports.Toggle=W.Toggle;exports.ToggleGroup=y.ToggleGroup;exports.ToggleGroupItem=y.ToggleGroupItem;exports.Tooltip=h.Tooltip;exports.TooltipContent=h.TooltipContent;exports.TooltipProvider=h.TooltipProvider;exports.TooltipTrigger=h.TooltipTrigger;exports.Toast=p.Toast;exports.ToastAction=p.ToastAction;exports.ToastClose=p.ToastClose;exports.ToastDescription=p.ToastDescription;exports.ToastProvider=p.ToastProvider;exports.ToastTitle=p.ToastTitle;exports.ToastViewport=p.ToastViewport;exports.ThemeProvider=X.ThemeProvider;exports.ThemeToggle=k.ThemeToggle;exports.useTheme=k.useTheme;exports.Toaster=x.Toaster;exports.toast=x.toast;exports.useToast=x.useToast;exports.TableOfContents=Y.TableOfContents;Object.defineProperty(exports,"toggleVariants",{enumerable:!0,get:()=>Z.toggleVariants});
1
+ "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const N=require("./utils-cdbZV8DZ.js"),M=require("./accordion.cjs"),w=require("./alert.cjs"),t=require("./alert-dialog.cjs"),V=require("./aspect-ratio.cjs"),v=require("./avatar.cjs"),I=require("./badge.cjs"),C=require("./breadcrumb.cjs"),F=require("./button.cjs"),L=require("./calendar.cjs"),b=require("./card.cjs"),m=require("./carousel.cjs"),T=require("./chart.cjs"),O=require("./checkbox.cjs"),P=require("./collapsible.cjs"),u=require("./command.cjs"),r=require("./context-menu.cjs"),a=require("./dialog.cjs"),n=require("./drawer.cjs"),o=require("./dropdown-menu.cjs"),s=require("./form.cjs"),q=require("./hover-card.cjs"),z=require("./input.cjs"),f=require("./label.cjs"),e=require("./menubar.cjs"),g=require("./navigation-menu.cjs"),d=require("./pagination.cjs"),D=require("./popover.cjs"),E=require("./progress.cjs"),B=require("./radio-group.cjs"),A=require("./resizable.cjs"),G=require("./scroll-area.cjs"),j=require("./scroll-to-top.cjs"),U=require("./support-fab.cjs"),R=require("./search.cjs"),i=require("./select.cjs"),_=require("./separator.cjs"),l=require("./sheet.cjs"),J=require("./skeleton.cjs"),K=require("./slider.cjs"),Q=require("./sonner.cjs"),W=require("./switch.cjs"),c=require("./table.cjs"),S=require("./tabs.cjs"),H=require("./text.cjs"),X=require("./textarea.cjs"),Y=require("./toggle.cjs"),y=require("./toggle-group.cjs"),h=require("./tooltip.cjs"),p=require("./toast.cjs"),Z=require("./theme-provider.cjs"),k=require("./theme-toggle-DXQGNfCe.js"),x=require("./toaster-C_S9hnXa.js"),$=require("./table-of-contents.cjs"),ee=require("@gv-tech/ui-core");exports.cn=N.cn;exports.Accordion=M.Accordion;exports.AccordionContent=M.AccordionContent;exports.AccordionItem=M.AccordionItem;exports.AccordionTrigger=M.AccordionTrigger;exports.Alert=w.Alert;exports.AlertDescription=w.AlertDescription;exports.AlertTitle=w.AlertTitle;exports.AlertDialog=t.AlertDialog;exports.AlertDialogAction=t.AlertDialogAction;exports.AlertDialogCancel=t.AlertDialogCancel;exports.AlertDialogContent=t.AlertDialogContent;exports.AlertDialogDescription=t.AlertDialogDescription;exports.AlertDialogFooter=t.AlertDialogFooter;exports.AlertDialogHeader=t.AlertDialogHeader;exports.AlertDialogOverlay=t.AlertDialogOverlay;exports.AlertDialogPortal=t.AlertDialogPortal;exports.AlertDialogTitle=t.AlertDialogTitle;exports.AlertDialogTrigger=t.AlertDialogTrigger;exports.AspectRatio=V.AspectRatio;exports.Avatar=v.Avatar;exports.AvatarFallback=v.AvatarFallback;exports.AvatarImage=v.AvatarImage;exports.Badge=I.Badge;exports.badgeVariants=I.badgeVariants;exports.Breadcrumb=C.Breadcrumb;exports.BreadcrumbEllipsis=C.BreadcrumbEllipsis;exports.BreadcrumbItem=C.BreadcrumbItem;exports.BreadcrumbLink=C.BreadcrumbLink;exports.BreadcrumbList=C.BreadcrumbList;exports.BreadcrumbPage=C.BreadcrumbPage;exports.BreadcrumbSeparator=C.BreadcrumbSeparator;exports.Button=F.Button;exports.buttonVariants=F.buttonVariants;exports.Calendar=L.Calendar;exports.CalendarDayButton=L.CalendarDayButton;exports.Card=b.Card;exports.CardContent=b.CardContent;exports.CardDescription=b.CardDescription;exports.CardFooter=b.CardFooter;exports.CardHeader=b.CardHeader;exports.CardTitle=b.CardTitle;exports.Carousel=m.Carousel;exports.CarouselContent=m.CarouselContent;exports.CarouselItem=m.CarouselItem;exports.CarouselNext=m.CarouselNext;exports.CarouselPrevious=m.CarouselPrevious;exports.ChartContainer=T.ChartContainer;exports.ChartLegend=T.ChartLegend;exports.ChartLegendContent=T.ChartLegendContent;exports.ChartStyle=T.ChartStyle;exports.ChartTooltip=T.ChartTooltip;exports.ChartTooltipContent=T.ChartTooltipContent;exports.Checkbox=O.Checkbox;exports.Collapsible=P.Collapsible;exports.CollapsibleContent=P.CollapsibleContent;exports.CollapsibleTrigger=P.CollapsibleTrigger;exports.Command=u.Command;exports.CommandDialog=u.CommandDialog;exports.CommandEmpty=u.CommandEmpty;exports.CommandGroup=u.CommandGroup;exports.CommandInput=u.CommandInput;exports.CommandItem=u.CommandItem;exports.CommandList=u.CommandList;exports.CommandSeparator=u.CommandSeparator;exports.CommandShortcut=u.CommandShortcut;exports.ContextMenu=r.ContextMenu;exports.ContextMenuCheckboxItem=r.ContextMenuCheckboxItem;exports.ContextMenuContent=r.ContextMenuContent;exports.ContextMenuGroup=r.ContextMenuGroup;exports.ContextMenuItem=r.ContextMenuItem;exports.ContextMenuLabel=r.ContextMenuLabel;exports.ContextMenuPortal=r.ContextMenuPortal;exports.ContextMenuRadioGroup=r.ContextMenuRadioGroup;exports.ContextMenuRadioItem=r.ContextMenuRadioItem;exports.ContextMenuSeparator=r.ContextMenuSeparator;exports.ContextMenuShortcut=r.ContextMenuShortcut;exports.ContextMenuSub=r.ContextMenuSub;exports.ContextMenuSubContent=r.ContextMenuSubContent;exports.ContextMenuSubTrigger=r.ContextMenuSubTrigger;exports.ContextMenuTrigger=r.ContextMenuTrigger;exports.Dialog=a.Dialog;exports.DialogClose=a.DialogClose;exports.DialogContent=a.DialogContent;exports.DialogDescription=a.DialogDescription;exports.DialogFooter=a.DialogFooter;exports.DialogHeader=a.DialogHeader;exports.DialogOverlay=a.DialogOverlay;exports.DialogPortal=a.DialogPortal;exports.DialogTitle=a.DialogTitle;exports.DialogTrigger=a.DialogTrigger;exports.Drawer=n.Drawer;exports.DrawerClose=n.DrawerClose;exports.DrawerContent=n.DrawerContent;exports.DrawerDescription=n.DrawerDescription;exports.DrawerFooter=n.DrawerFooter;exports.DrawerHeader=n.DrawerHeader;exports.DrawerOverlay=n.DrawerOverlay;exports.DrawerPortal=n.DrawerPortal;exports.DrawerTitle=n.DrawerTitle;exports.DrawerTrigger=n.DrawerTrigger;exports.DropdownMenu=o.DropdownMenu;exports.DropdownMenuCheckboxItem=o.DropdownMenuCheckboxItem;exports.DropdownMenuContent=o.DropdownMenuContent;exports.DropdownMenuGroup=o.DropdownMenuGroup;exports.DropdownMenuItem=o.DropdownMenuItem;exports.DropdownMenuLabel=o.DropdownMenuLabel;exports.DropdownMenuPortal=o.DropdownMenuPortal;exports.DropdownMenuRadioGroup=o.DropdownMenuRadioGroup;exports.DropdownMenuRadioItem=o.DropdownMenuRadioItem;exports.DropdownMenuSeparator=o.DropdownMenuSeparator;exports.DropdownMenuShortcut=o.DropdownMenuShortcut;exports.DropdownMenuSub=o.DropdownMenuSub;exports.DropdownMenuSubContent=o.DropdownMenuSubContent;exports.DropdownMenuSubTrigger=o.DropdownMenuSubTrigger;exports.DropdownMenuTrigger=o.DropdownMenuTrigger;exports.Form=s.Form;exports.FormControl=s.FormControl;exports.FormDescription=s.FormDescription;exports.FormField=s.FormField;exports.FormItem=s.FormItem;exports.FormLabel=s.FormLabel;exports.FormMessage=s.FormMessage;exports.useFormField=s.useFormField;exports.HoverCard=q.HoverCard;exports.HoverCardContent=q.HoverCardContent;exports.HoverCardTrigger=q.HoverCardTrigger;exports.Input=z.Input;exports.Label=f.Label;exports.Menubar=e.Menubar;exports.MenubarCheckboxItem=e.MenubarCheckboxItem;exports.MenubarContent=e.MenubarContent;exports.MenubarGroup=e.MenubarGroup;exports.MenubarItem=e.MenubarItem;exports.MenubarLabel=e.MenubarLabel;exports.MenubarMenu=e.MenubarMenu;exports.MenubarPortal=e.MenubarPortal;exports.MenubarRadioGroup=e.MenubarRadioGroup;exports.MenubarRadioItem=e.MenubarRadioItem;exports.MenubarSeparator=e.MenubarSeparator;exports.MenubarShortcut=e.MenubarShortcut;exports.MenubarSub=e.MenubarSub;exports.MenubarSubContent=e.MenubarSubContent;exports.MenubarSubTrigger=e.MenubarSubTrigger;exports.MenubarTrigger=e.MenubarTrigger;exports.NavigationMenu=g.NavigationMenu;exports.NavigationMenuContent=g.NavigationMenuContent;exports.NavigationMenuIndicator=g.NavigationMenuIndicator;exports.NavigationMenuItem=g.NavigationMenuItem;exports.NavigationMenuLink=g.NavigationMenuLink;exports.NavigationMenuList=g.NavigationMenuList;exports.NavigationMenuTrigger=g.NavigationMenuTrigger;exports.NavigationMenuViewport=g.NavigationMenuViewport;exports.navigationMenuTriggerStyle=g.navigationMenuTriggerStyle;exports.Pagination=d.Pagination;exports.PaginationContent=d.PaginationContent;exports.PaginationEllipsis=d.PaginationEllipsis;exports.PaginationItem=d.PaginationItem;exports.PaginationLink=d.PaginationLink;exports.PaginationNext=d.PaginationNext;exports.PaginationPrevious=d.PaginationPrevious;exports.Popover=D.Popover;exports.PopoverAnchor=D.PopoverAnchor;exports.PopoverContent=D.PopoverContent;exports.PopoverTrigger=D.PopoverTrigger;exports.Progress=E.Progress;exports.RadioGroup=B.RadioGroup;exports.RadioGroupItem=B.RadioGroupItem;exports.ResizableHandle=A.ResizableHandle;exports.ResizablePanel=A.ResizablePanel;exports.ResizablePanelGroup=A.ResizablePanelGroup;exports.ScrollArea=G.ScrollArea;exports.ScrollBar=G.ScrollBar;exports.ScrollToTop=j.ScrollToTop;exports.SupportFab=U.SupportFab;exports.Search=R.Search;exports.SearchTrigger=R.SearchTrigger;exports.Select=i.Select;exports.SelectContent=i.SelectContent;exports.SelectGroup=i.SelectGroup;exports.SelectItem=i.SelectItem;exports.SelectLabel=i.SelectLabel;exports.SelectScrollDownButton=i.SelectScrollDownButton;exports.SelectScrollUpButton=i.SelectScrollUpButton;exports.SelectSeparator=i.SelectSeparator;exports.SelectTrigger=i.SelectTrigger;exports.SelectValue=i.SelectValue;exports.Separator=_.Separator;exports.Sheet=l.Sheet;exports.SheetClose=l.SheetClose;exports.SheetContent=l.SheetContent;exports.SheetDescription=l.SheetDescription;exports.SheetFooter=l.SheetFooter;exports.SheetHeader=l.SheetHeader;exports.SheetOverlay=l.SheetOverlay;exports.SheetPortal=l.SheetPortal;exports.SheetTitle=l.SheetTitle;exports.SheetTrigger=l.SheetTrigger;exports.Skeleton=J.Skeleton;exports.Slider=K.Slider;exports.SonnerToaster=Q.Toaster;exports.Switch=W.Switch;exports.Table=c.Table;exports.TableBody=c.TableBody;exports.TableCaption=c.TableCaption;exports.TableCell=c.TableCell;exports.TableFooter=c.TableFooter;exports.TableHead=c.TableHead;exports.TableHeader=c.TableHeader;exports.TableRow=c.TableRow;exports.Tabs=S.Tabs;exports.TabsContent=S.TabsContent;exports.TabsList=S.TabsList;exports.TabsTrigger=S.TabsTrigger;exports.Text=H.Text;exports.textVariants=H.textVariants;exports.Textarea=X.Textarea;exports.Toggle=Y.Toggle;exports.ToggleGroup=y.ToggleGroup;exports.ToggleGroupItem=y.ToggleGroupItem;exports.Tooltip=h.Tooltip;exports.TooltipContent=h.TooltipContent;exports.TooltipProvider=h.TooltipProvider;exports.TooltipTrigger=h.TooltipTrigger;exports.Toast=p.Toast;exports.ToastAction=p.ToastAction;exports.ToastClose=p.ToastClose;exports.ToastDescription=p.ToastDescription;exports.ToastProvider=p.ToastProvider;exports.ToastTitle=p.ToastTitle;exports.ToastViewport=p.ToastViewport;exports.ThemeProvider=Z.ThemeProvider;exports.ThemeToggle=k.ThemeToggle;exports.useTheme=k.useTheme;exports.Toaster=x.Toaster;exports.toast=x.toast;exports.useToast=x.useToast;exports.TableOfContents=$.TableOfContents;Object.defineProperty(exports,"toggleVariants",{enumerable:!0,get:()=>ee.toggleVariants});
package/dist/index.d.ts CHANGED
@@ -186,6 +186,7 @@ import { ResizablePanelBaseProps as ResizablePanelProps } from '../../ui-core/sr
186
186
  import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
187
187
  import { ScrollAreaBaseProps as ScrollAreaProps } from '../../ui-core/src';
188
188
  import { ScrollBarBaseProps as ScrollBarProps } from '../../ui-core/src';
189
+ import { ScrollToTopBaseProps } from '../../ui-core/src';
189
190
  import { SearchBaseProps } from '../../ui-core/src';
190
191
  import { SearchTriggerBaseProps } from '../../ui-core/src';
191
192
  import { SelectContentBaseProps as SelectContentProps } from '../../ui-core/src';
@@ -1002,6 +1003,13 @@ export declare const ScrollBar: React_2.ForwardRefExoticComponent<Omit<ScrollAre
1002
1003
 
1003
1004
  export { ScrollBarProps }
1004
1005
 
1006
+ export declare function ScrollToTop({ threshold, exitDuration, behavior, scrollTarget, className, label, onClick, tabIndex, type, ...props }: ScrollToTopProps): JSX.Element;
1007
+
1008
+ export declare interface ScrollToTopProps extends React_2.ButtonHTMLAttributes<HTMLButtonElement>, ScrollToTopBaseProps {
1009
+ /** Optional custom scroll container; defaults to window when undefined. */
1010
+ scrollTarget?: Window | HTMLElement | null;
1011
+ }
1012
+
1005
1013
  export declare function Search({ children, open: customOpen, onOpenChange }: SearchProps): JSX.Element;
1006
1014
 
1007
1015
  export declare type SearchProps = SearchBaseProps;
@@ -1118,6 +1126,22 @@ export declare type SonnerProps = React_2.ComponentProps<typeof Toaster_2> & Son
1118
1126
 
1119
1127
  export declare const SonnerToaster: ({ ...props }: SonnerProps) => JSX.Element;
1120
1128
 
1129
+ export declare function SupportFab({ supportUrl, creatorId, title, description, iframeTitle, open, defaultOpen, onOpenChange, positionClassName, buttonClassName, panelClassName, className, type, onClick, ...buttonProps }: SupportFabProps): JSX.Element;
1130
+
1131
+ export declare interface SupportFabProps extends Omit<React_2.ButtonHTMLAttributes<HTMLButtonElement>, 'onChange'> {
1132
+ supportUrl?: string;
1133
+ creatorId: string;
1134
+ title?: string;
1135
+ description?: string;
1136
+ iframeTitle?: string;
1137
+ open?: boolean;
1138
+ defaultOpen?: boolean;
1139
+ onOpenChange?: (open: boolean) => void;
1140
+ positionClassName?: string;
1141
+ buttonClassName?: string;
1142
+ panelClassName?: string;
1143
+ }
1144
+
1121
1145
  export declare const Switch: React_2.ForwardRefExoticComponent<Omit<SwitchPrimitives.SwitchProps & React_2.RefAttributes<HTMLButtonElement>, "ref"> & SwitchProps & React_2.RefAttributes<HTMLButtonElement>>;
1122
1146
 
1123
1147
  export { SwitchProps }
package/dist/index.mjs CHANGED
@@ -31,27 +31,29 @@ import { Progress as Hr } from "./progress.mjs";
31
31
  import { RadioGroup as kr, RadioGroupItem as yr } from "./radio-group.mjs";
32
32
  import { ResizableHandle as Or, ResizablePanel as zr, ResizablePanelGroup as Er } from "./resizable.mjs";
33
33
  import { ScrollArea as jr, ScrollBar as qr } from "./scroll-area.mjs";
34
- import { Search as Kr, SearchTrigger as Qr } from "./search.mjs";
35
- import { Select as Xr, SelectContent as Yr, SelectGroup as Zr, SelectItem as _r, SelectLabel as $r, SelectScrollDownButton as et, SelectScrollUpButton as ot, SelectSeparator as rt, SelectTrigger as tt, SelectValue as at } from "./select.mjs";
36
- import { Separator as it } from "./separator.mjs";
37
- import { Sheet as pt, SheetClose as mt, SheetContent as ut, SheetDescription as gt, SheetFooter as Ct, SheetHeader as xt, SheetOverlay as dt, SheetPortal as st, SheetTitle as Tt, SheetTrigger as bt } from "./sheet.mjs";
38
- import { Skeleton as Dt } from "./skeleton.mjs";
39
- import { Slider as ft } from "./slider.mjs";
40
- import { Toaster as ht } from "./sonner.mjs";
41
- import { Switch as vt } from "./switch.mjs";
42
- import { Table as At, TableBody as It, TableCaption as Ft, TableCell as Lt, TableFooter as Bt, TableHead as Gt, TableHeader as Rt, TableRow as Ht } from "./table.mjs";
43
- import { Tabs as kt, TabsContent as yt, TabsList as Vt, TabsTrigger as Ot } from "./tabs.mjs";
44
- import { Text as Et, textVariants as Ut } from "./text.mjs";
45
- import { Textarea as qt } from "./textarea.mjs";
46
- import { Toggle as Kt } from "./toggle.mjs";
47
- import { ToggleGroup as Wt, ToggleGroupItem as Xt } from "./toggle-group.mjs";
48
- import { Tooltip as Zt, TooltipContent as _t, TooltipProvider as $t, TooltipTrigger as ea } from "./tooltip.mjs";
49
- import { Toast as ra, ToastAction as ta, ToastClose as aa, ToastDescription as na, ToastProvider as ia, ToastTitle as la, ToastViewport as pa } from "./toast.mjs";
50
- import { ThemeProvider as ua } from "./theme-provider.mjs";
51
- import { T as Ca, u as xa } from "./theme-toggle-tHXIbr8W.mjs";
52
- import { T as sa, t as Ta, u as ba } from "./toaster-k5DnQSsh.mjs";
53
- import { TableOfContents as Da } from "./table-of-contents.mjs";
54
- import { toggleVariants as fa } from "@gv-tech/ui-core";
34
+ import { ScrollToTop as Kr } from "./scroll-to-top.mjs";
35
+ import { SupportFab as Wr } from "./support-fab.mjs";
36
+ import { Search as Yr, SearchTrigger as Zr } from "./search.mjs";
37
+ import { Select as $r, SelectContent as et, SelectGroup as ot, SelectItem as rt, SelectLabel as tt, SelectScrollDownButton as at, SelectScrollUpButton as nt, SelectSeparator as it, SelectTrigger as lt, SelectValue as pt } from "./select.mjs";
38
+ import { Separator as ut } from "./separator.mjs";
39
+ import { Sheet as Ct, SheetClose as xt, SheetContent as dt, SheetDescription as st, SheetFooter as Tt, SheetHeader as bt, SheetOverlay as ct, SheetPortal as Dt, SheetTitle as Mt, SheetTrigger as ft } from "./sheet.mjs";
40
+ import { Skeleton as ht } from "./skeleton.mjs";
41
+ import { Slider as vt } from "./slider.mjs";
42
+ import { Toaster as At } from "./sonner.mjs";
43
+ import { Switch as Ft } from "./switch.mjs";
44
+ import { Table as Bt, TableBody as Gt, TableCaption as Rt, TableCell as Ht, TableFooter as Nt, TableHead as kt, TableHeader as yt, TableRow as Vt } from "./table.mjs";
45
+ import { Tabs as zt, TabsContent as Et, TabsList as Ut, TabsTrigger as jt } from "./tabs.mjs";
46
+ import { Text as Jt, textVariants as Kt } from "./text.mjs";
47
+ import { Textarea as Wt } from "./textarea.mjs";
48
+ import { Toggle as Yt } from "./toggle.mjs";
49
+ import { ToggleGroup as _t, ToggleGroupItem as $t } from "./toggle-group.mjs";
50
+ import { Tooltip as oa, TooltipContent as ra, TooltipProvider as ta, TooltipTrigger as aa } from "./tooltip.mjs";
51
+ import { Toast as ia, ToastAction as la, ToastClose as pa, ToastDescription as ma, ToastProvider as ua, ToastTitle as ga, ToastViewport as Ca } from "./toast.mjs";
52
+ import { ThemeProvider as da } from "./theme-provider.mjs";
53
+ import { T as Ta, u as ba } from "./theme-toggle-tHXIbr8W.mjs";
54
+ import { T as Da, t as Ma, u as fa } from "./toaster-k5DnQSsh.mjs";
55
+ import { TableOfContents as ha } from "./table-of-contents.mjs";
56
+ import { toggleVariants as va } from "@gv-tech/ui-core";
55
57
  export {
56
58
  a as Accordion,
57
59
  n as AccordionContent,
@@ -221,73 +223,75 @@ export {
221
223
  Er as ResizablePanelGroup,
222
224
  jr as ScrollArea,
223
225
  qr as ScrollBar,
224
- Kr as Search,
225
- Qr as SearchTrigger,
226
- Xr as Select,
227
- Yr as SelectContent,
228
- Zr as SelectGroup,
229
- _r as SelectItem,
230
- $r as SelectLabel,
231
- et as SelectScrollDownButton,
232
- ot as SelectScrollUpButton,
233
- rt as SelectSeparator,
234
- tt as SelectTrigger,
235
- at as SelectValue,
236
- it as Separator,
237
- pt as Sheet,
238
- mt as SheetClose,
239
- ut as SheetContent,
240
- gt as SheetDescription,
241
- Ct as SheetFooter,
242
- xt as SheetHeader,
243
- dt as SheetOverlay,
244
- st as SheetPortal,
245
- Tt as SheetTitle,
246
- bt as SheetTrigger,
247
- Dt as Skeleton,
248
- ft as Slider,
249
- ht as SonnerToaster,
250
- vt as Switch,
251
- At as Table,
252
- It as TableBody,
253
- Ft as TableCaption,
254
- Lt as TableCell,
255
- Bt as TableFooter,
256
- Gt as TableHead,
257
- Rt as TableHeader,
258
- Da as TableOfContents,
259
- Ht as TableRow,
260
- kt as Tabs,
261
- yt as TabsContent,
262
- Vt as TabsList,
263
- Ot as TabsTrigger,
264
- Et as Text,
265
- qt as Textarea,
266
- ua as ThemeProvider,
267
- Ca as ThemeToggle,
268
- ra as Toast,
269
- ta as ToastAction,
270
- aa as ToastClose,
271
- na as ToastDescription,
272
- ia as ToastProvider,
273
- la as ToastTitle,
274
- pa as ToastViewport,
275
- sa as Toaster,
276
- Kt as Toggle,
277
- Wt as ToggleGroup,
278
- Xt as ToggleGroupItem,
279
- Zt as Tooltip,
280
- _t as TooltipContent,
281
- $t as TooltipProvider,
282
- ea as TooltipTrigger,
226
+ Kr as ScrollToTop,
227
+ Yr as Search,
228
+ Zr as SearchTrigger,
229
+ $r as Select,
230
+ et as SelectContent,
231
+ ot as SelectGroup,
232
+ rt as SelectItem,
233
+ tt as SelectLabel,
234
+ at as SelectScrollDownButton,
235
+ nt as SelectScrollUpButton,
236
+ it as SelectSeparator,
237
+ lt as SelectTrigger,
238
+ pt as SelectValue,
239
+ ut as Separator,
240
+ Ct as Sheet,
241
+ xt as SheetClose,
242
+ dt as SheetContent,
243
+ st as SheetDescription,
244
+ Tt as SheetFooter,
245
+ bt as SheetHeader,
246
+ ct as SheetOverlay,
247
+ Dt as SheetPortal,
248
+ Mt as SheetTitle,
249
+ ft as SheetTrigger,
250
+ ht as Skeleton,
251
+ vt as Slider,
252
+ At as SonnerToaster,
253
+ Wr as SupportFab,
254
+ Ft as Switch,
255
+ Bt as Table,
256
+ Gt as TableBody,
257
+ Rt as TableCaption,
258
+ Ht as TableCell,
259
+ Nt as TableFooter,
260
+ kt as TableHead,
261
+ yt as TableHeader,
262
+ ha as TableOfContents,
263
+ Vt as TableRow,
264
+ zt as Tabs,
265
+ Et as TabsContent,
266
+ Ut as TabsList,
267
+ jt as TabsTrigger,
268
+ Jt as Text,
269
+ Wt as Textarea,
270
+ da as ThemeProvider,
271
+ Ta as ThemeToggle,
272
+ ia as Toast,
273
+ la as ToastAction,
274
+ pa as ToastClose,
275
+ ma as ToastDescription,
276
+ ua as ToastProvider,
277
+ ga as ToastTitle,
278
+ Ca as ToastViewport,
279
+ Da as Toaster,
280
+ Yt as Toggle,
281
+ _t as ToggleGroup,
282
+ $t as ToggleGroupItem,
283
+ oa as Tooltip,
284
+ ra as TooltipContent,
285
+ ta as TooltipProvider,
286
+ aa as TooltipTrigger,
283
287
  G as badgeVariants,
284
288
  j as buttonVariants,
285
289
  r as cn,
286
290
  Dr as navigationMenuTriggerStyle,
287
- Ut as textVariants,
288
- Ta as toast,
289
- fa as toggleVariants,
291
+ Kt as textVariants,
292
+ Ma as toast,
293
+ va as toggleVariants,
290
294
  Vo as useFormField,
291
- xa as useTheme,
292
- ba as useToast
295
+ ba as useTheme,
296
+ fa as useToast
293
297
  };
@@ -0,0 +1 @@
1
+ "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("./jsx-runtime-nZSsnGb7.js"),E=require("lucide-react"),R=require("react"),S=require("./button.cjs"),O=require("./utils-cdbZV8DZ.js");function T(e){const i=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const n in e)if(n!=="default"){const t=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(i,n,t.get?t:{enumerable:!0,get:()=>e[n]})}}return i.default=e,Object.freeze(i)}const l=T(R),N=e=>typeof e.scrollY=="number",m=e=>N(e)?e.scrollY:e.scrollTop;function q({threshold:e=240,exitDuration:i=450,behavior:n="smooth",scrollTarget:t,className:x,label:b="Scroll to top",onClick:y,tabIndex:v,type:g,...h}){const[_,u]=l.useState(!1),[c,f]=l.useState(!1),d=l.useRef(null);l.useEffect(()=>{const o=t===void 0?window:t;if(!o){u(!1);return}const r=()=>{const p=m(o);if(c){p<=e&&(u(!1),f(!1));return}u(p>e)};return r(),o.addEventListener("scroll",r,{passive:!0}),()=>{o.removeEventListener("scroll",r)}},[c,t,e]),l.useEffect(()=>()=>{d.current!==null&&window.clearTimeout(d.current)},[]);const s=c?"exiting":_?"visible":"hidden",j=o=>{if(y?.(o),o.defaultPrevented||c)return;const r=t===void 0?window:t;if(!r)return;f(!0);const p=Math.max(0,i);d.current=window.setTimeout(()=>{r.scrollTo({top:0,behavior:n});const w=m(r);u(!1),w<=e&&f(!1)},p)};return a.jsxRuntimeExports.jsxs(S.Button,{"aria-label":b,"data-state":s,type:g??"button",variant:"default",size:"icon",tabIndex:s==="hidden"?-1:v,className:O.cn("group border-primary/40 bg-primary text-primary-foreground focus-visible:ring-ring fixed right-6 bottom-6 z-50 inline-flex h-14 w-14 items-center justify-center overflow-hidden rounded-full border shadow-[0_18px_40px_-22px_hsl(var(--primary)/0.9)] transition-all duration-500 ease-out focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none","before:pointer-events-none before:absolute before:inset-0 before:bg-[radial-gradient(circle_at_35%_30%,rgba(255,255,255,0.45),transparent_55%)] before:opacity-80","hover:-translate-y-1 hover:scale-105 hover:shadow-[0_24px_48px_-24px_hsl(var(--primary)/0.95)] active:translate-y-0 active:scale-95",s==="visible"&&"translate-y-0 scale-100 opacity-100",s==="hidden"&&"pointer-events-none translate-y-24 scale-75 opacity-0 blur-[1px] motion-safe:animate-none",s==="exiting"&&"pointer-events-none translate-y-28 scale-90 opacity-0 blur-[2px] motion-safe:animate-none",x),onClick:j,...h,children:[a.jsxRuntimeExports.jsx("span",{className:"bg-primary-foreground/20 absolute inset-0 rounded-full opacity-0 transition-opacity duration-500 group-hover:animate-pulse group-hover:opacity-100"}),a.jsxRuntimeExports.jsx("span",{className:"border-primary-foreground/35 absolute inset-0 rounded-full border opacity-0 transition-opacity duration-300 group-hover:animate-ping group-hover:opacity-100"}),a.jsxRuntimeExports.jsx(E.ArrowUp,{className:"relative z-10 h-5 w-5 drop-shadow-[0_2px_2px_rgba(0,0,0,0.2)]"}),a.jsxRuntimeExports.jsx("span",{className:"sr-only",children:b})]})}exports.ScrollToTop=q;
@@ -0,0 +1,12 @@
1
+ import { JSX } from 'react/jsx-runtime';
2
+ import * as React_2 from 'react';
3
+ import { ScrollToTopBaseProps } from '../../ui-core/src';
4
+
5
+ export declare function ScrollToTop({ threshold, exitDuration, behavior, scrollTarget, className, label, onClick, tabIndex, type, ...props }: ScrollToTopProps): JSX.Element;
6
+
7
+ export declare interface ScrollToTopProps extends React_2.ButtonHTMLAttributes<HTMLButtonElement>, ScrollToTopBaseProps {
8
+ /** Optional custom scroll container; defaults to window when undefined. */
9
+ scrollTarget?: Window | HTMLElement | null;
10
+ }
11
+
12
+ export { }
@@ -0,0 +1,86 @@
1
+ "use client";
2
+ import { j as n } from "./jsx-runtime-tc70JA_2.mjs";
3
+ import { ArrowUp as E } from "lucide-react";
4
+ import * as s from "react";
5
+ import { Button as N } from "./button.mjs";
6
+ import { c as S } from "./utils-DY6fhrgS.mjs";
7
+ const R = (e) => typeof e.scrollY == "number", d = (e) => R(e) ? e.scrollY : e.scrollTop;
8
+ function k({
9
+ threshold: e = 240,
10
+ exitDuration: m = 450,
11
+ behavior: b = "smooth",
12
+ scrollTarget: r,
13
+ className: v,
14
+ label: p = "Scroll to top",
15
+ onClick: x,
16
+ tabIndex: y,
17
+ type: g,
18
+ ...h
19
+ }) {
20
+ const [w, a] = s.useState(!1), [l, u] = s.useState(!1), f = s.useRef(null);
21
+ s.useEffect(() => {
22
+ const t = r === void 0 ? window : r;
23
+ if (!t) {
24
+ a(!1);
25
+ return;
26
+ }
27
+ const o = () => {
28
+ const c = d(t);
29
+ if (l) {
30
+ c <= e && (a(!1), u(!1));
31
+ return;
32
+ }
33
+ a(c > e);
34
+ };
35
+ return o(), t.addEventListener("scroll", o, { passive: !0 }), () => {
36
+ t.removeEventListener("scroll", o);
37
+ };
38
+ }, [l, r, e]), s.useEffect(() => () => {
39
+ f.current !== null && window.clearTimeout(f.current);
40
+ }, []);
41
+ const i = l ? "exiting" : w ? "visible" : "hidden", _ = (t) => {
42
+ if (x?.(t), t.defaultPrevented || l)
43
+ return;
44
+ const o = r === void 0 ? window : r;
45
+ if (!o)
46
+ return;
47
+ u(!0);
48
+ const c = Math.max(0, m);
49
+ f.current = window.setTimeout(() => {
50
+ o.scrollTo({ top: 0, behavior: b });
51
+ const j = d(o);
52
+ a(!1), j <= e && u(!1);
53
+ }, c);
54
+ };
55
+ return /* @__PURE__ */ n.jsxs(
56
+ N,
57
+ {
58
+ "aria-label": p,
59
+ "data-state": i,
60
+ type: g ?? "button",
61
+ variant: "default",
62
+ size: "icon",
63
+ tabIndex: i === "hidden" ? -1 : y,
64
+ className: S(
65
+ "group border-primary/40 bg-primary text-primary-foreground focus-visible:ring-ring fixed right-6 bottom-6 z-50 inline-flex h-14 w-14 items-center justify-center overflow-hidden rounded-full border shadow-[0_18px_40px_-22px_hsl(var(--primary)/0.9)] transition-all duration-500 ease-out focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none",
66
+ "before:pointer-events-none before:absolute before:inset-0 before:bg-[radial-gradient(circle_at_35%_30%,rgba(255,255,255,0.45),transparent_55%)] before:opacity-80",
67
+ "hover:-translate-y-1 hover:scale-105 hover:shadow-[0_24px_48px_-24px_hsl(var(--primary)/0.95)] active:translate-y-0 active:scale-95",
68
+ i === "visible" && "translate-y-0 scale-100 opacity-100",
69
+ i === "hidden" && "pointer-events-none translate-y-24 scale-75 opacity-0 blur-[1px] motion-safe:animate-none",
70
+ i === "exiting" && "pointer-events-none translate-y-28 scale-90 opacity-0 blur-[2px] motion-safe:animate-none",
71
+ v
72
+ ),
73
+ onClick: _,
74
+ ...h,
75
+ children: [
76
+ /* @__PURE__ */ n.jsx("span", { className: "bg-primary-foreground/20 absolute inset-0 rounded-full opacity-0 transition-opacity duration-500 group-hover:animate-pulse group-hover:opacity-100" }),
77
+ /* @__PURE__ */ n.jsx("span", { className: "border-primary-foreground/35 absolute inset-0 rounded-full border opacity-0 transition-opacity duration-300 group-hover:animate-ping group-hover:opacity-100" }),
78
+ /* @__PURE__ */ n.jsx(E, { className: "relative z-10 h-5 w-5 drop-shadow-[0_2px_2px_rgba(0,0,0,0.2)]" }),
79
+ /* @__PURE__ */ n.jsx("span", { className: "sr-only", children: p })
80
+ ]
81
+ }
82
+ );
83
+ }
84
+ export {
85
+ k as ScrollToTop
86
+ };
@@ -0,0 +1 @@
1
+ "use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./jsx-runtime-nZSsnGb7.js"),g=require("lucide-react"),P=require("react"),z=require("./button.cjs"),a=require("./dialog.cjs"),c=require("./drawer.cjs"),x=require("./utils-cdbZV8DZ.js");function I(t){const s=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(t){for(const n in t)if(n!=="default"){const r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(s,n,r.get?r:{enumerable:!0,get:()=>t[n]})}}return s.default=t,Object.freeze(s)}const i=I(P),w="(max-width: 767px)",E=t=>{const s=t.trim();return s.endsWith("/")?s.slice(0,-1):s},R=t=>t.trim().replace(/^@+/,""),U=(t,s)=>{const n=E(t),r=encodeURIComponent(R(s));return`${n}/${r}`},F=(t,s)=>{const n=E(t),r=encodeURIComponent(R(s));return`${n}/widget/page/${r}`},L=()=>{const t=()=>typeof window>"u"||typeof window.matchMedia!="function"?!1:window.matchMedia(w).matches,[s,n]=i.useState(t);return i.useEffect(()=>{if(typeof window>"u"||typeof window.matchMedia!="function")return;const r=window.matchMedia(w),l=u=>n(u.matches);return n(r.matches),r.addEventListener("change",l),()=>{r.removeEventListener("change",l)}},[]),s};function T({supportUrl:t="https://www.buymeacoffee.com",creatorId:s,title:n="Buy me a coffee",description:r="Support the project directly from this panel.",iframeTitle:l="Buy Me a Coffee support form",open:u,defaultOpen:y=!1,onOpenChange:p,positionClassName:v,buttonClassName:M,panelClassName:f,className:D,type:N,onClick:C,...O}){const S=L(),d=u!==void 0,[_,k]=i.useState(y),j=d?u:_,m=i.useCallback(o=>{d||k(o),p?.(o)},[d,p]),q=i.useMemo(()=>U(t,s),[s,t]),B=i.useMemo(()=>F(t,s),[s,t]),h=e.jsxRuntimeExports.jsxs("div",{className:"flex max-h-[75vh] flex-col gap-3",children:[e.jsxRuntimeExports.jsx("div",{className:"overflow-hidden rounded-md border",children:e.jsxRuntimeExports.jsx("iframe",{title:l,src:B,className:"h-[560px] w-full border-0",loading:"lazy",referrerPolicy:"strict-origin-when-cross-origin"})}),e.jsxRuntimeExports.jsxs("div",{className:"text-muted-foreground flex items-center justify-between gap-2 text-xs",children:[e.jsxRuntimeExports.jsx("span",{children:"If the embedded checkout is unavailable, open the support page directly."}),e.jsxRuntimeExports.jsxs("a",{href:q,target:"_blank",rel:"noopener noreferrer",className:"text-foreground inline-flex items-center gap-1 font-medium underline underline-offset-2",children:["Open Buy Me a Coffee",e.jsxRuntimeExports.jsx(g.ExternalLink,{className:"h-3.5 w-3.5"})]})]})]}),b=e.jsxRuntimeExports.jsx("div",{className:x.cn("fixed right-6 bottom-6 z-50",v),children:e.jsxRuntimeExports.jsxs(z.Button,{"aria-label":"Support this project",type:N??"button",className:x.cn("inline-flex h-14 w-14 rounded-full border border-black/15 bg-[#ffdd00] text-black shadow-[0_16px_36px_-18px_rgba(0,0,0,0.8)] transition hover:-translate-y-0.5 hover:scale-105 hover:bg-[#ffe347] focus-visible:ring-2 focus-visible:ring-offset-2 active:translate-y-0 active:scale-95",M,D),onClick:o=>{C?.(o),o.defaultPrevented||m(!0)},...O,children:[e.jsxRuntimeExports.jsx(g.Coffee,{className:"h-6 w-6"}),e.jsxRuntimeExports.jsx("span",{className:"sr-only",children:"Support this project"})]})});return S?e.jsxRuntimeExports.jsxs(e.jsxRuntimeExports.Fragment,{children:[b,e.jsxRuntimeExports.jsx(c.Drawer,{open:j,onOpenChange:m,children:e.jsxRuntimeExports.jsxs(c.DrawerContent,{className:x.cn("mx-auto w-full max-w-xl",f),children:[e.jsxRuntimeExports.jsxs(c.DrawerHeader,{children:[e.jsxRuntimeExports.jsx(c.DrawerTitle,{children:n}),e.jsxRuntimeExports.jsx(c.DrawerDescription,{children:r})]}),e.jsxRuntimeExports.jsx("div",{className:"px-4 pb-4",children:h})]})})]}):e.jsxRuntimeExports.jsxs(e.jsxRuntimeExports.Fragment,{children:[b,e.jsxRuntimeExports.jsx(a.Dialog,{open:j,onOpenChange:m,children:e.jsxRuntimeExports.jsxs(a.DialogContent,{className:x.cn("max-w-xl p-5",f),children:[e.jsxRuntimeExports.jsxs(a.DialogHeader,{children:[e.jsxRuntimeExports.jsx(a.DialogTitle,{children:n}),e.jsxRuntimeExports.jsx(a.DialogDescription,{children:r})]}),h]})})]})}exports.SupportFab=T;
@@ -0,0 +1,20 @@
1
+ import { JSX } from 'react/jsx-runtime';
2
+ import * as React_2 from 'react';
3
+
4
+ export declare function SupportFab({ supportUrl, creatorId, title, description, iframeTitle, open, defaultOpen, onOpenChange, positionClassName, buttonClassName, panelClassName, className, type, onClick, ...buttonProps }: SupportFabProps): JSX.Element;
5
+
6
+ export declare interface SupportFabProps extends Omit<React_2.ButtonHTMLAttributes<HTMLButtonElement>, 'onChange'> {
7
+ supportUrl?: string;
8
+ creatorId: string;
9
+ title?: string;
10
+ description?: string;
11
+ iframeTitle?: string;
12
+ open?: boolean;
13
+ defaultOpen?: boolean;
14
+ onOpenChange?: (open: boolean) => void;
15
+ positionClassName?: string;
16
+ buttonClassName?: string;
17
+ panelClassName?: string;
18
+ }
19
+
20
+ export { }
@@ -0,0 +1,120 @@
1
+ "use client";
2
+ import { j as e } from "./jsx-runtime-tc70JA_2.mjs";
3
+ import { Coffee as _, ExternalLink as I } from "lucide-react";
4
+ import * as o from "react";
5
+ import { Button as R } from "./button.mjs";
6
+ import { Dialog as U, DialogContent as z, DialogHeader as L, DialogTitle as $, DialogDescription as F } from "./dialog.mjs";
7
+ import { Drawer as P, DrawerContent as H, DrawerHeader as Q, DrawerTitle as T, DrawerDescription as W } from "./drawer.mjs";
8
+ import { c as l } from "./utils-DY6fhrgS.mjs";
9
+ const g = "(max-width: 767px)", w = (t) => {
10
+ const n = t.trim();
11
+ return n.endsWith("/") ? n.slice(0, -1) : n;
12
+ }, b = (t) => t.trim().replace(/^@+/, ""), Y = (t, n) => {
13
+ const s = w(t), r = encodeURIComponent(b(n));
14
+ return `${s}/${r}`;
15
+ }, q = (t, n) => {
16
+ const s = w(t), r = encodeURIComponent(b(n));
17
+ return `${s}/widget/page/${r}`;
18
+ }, A = () => {
19
+ const t = () => typeof window > "u" || typeof window.matchMedia != "function" ? !1 : window.matchMedia(g).matches, [n, s] = o.useState(t);
20
+ return o.useEffect(() => {
21
+ if (typeof window > "u" || typeof window.matchMedia != "function")
22
+ return;
23
+ const r = window.matchMedia(g), a = (c) => s(c.matches);
24
+ return s(r.matches), r.addEventListener("change", a), () => {
25
+ r.removeEventListener("change", a);
26
+ };
27
+ }, []), n;
28
+ };
29
+ function ee({
30
+ supportUrl: t = "https://www.buymeacoffee.com",
31
+ creatorId: n,
32
+ title: s = "Buy me a coffee",
33
+ description: r = "Support the project directly from this panel.",
34
+ iframeTitle: a = "Buy Me a Coffee support form",
35
+ open: c,
36
+ defaultOpen: j = !1,
37
+ onOpenChange: f,
38
+ positionClassName: v,
39
+ buttonClassName: y,
40
+ panelClassName: h,
41
+ className: M,
42
+ type: C,
43
+ onClick: D,
44
+ ...N
45
+ }) {
46
+ const E = A(), d = c !== void 0, [k, B] = o.useState(j), u = d ? c : k, m = o.useCallback(
47
+ (i) => {
48
+ d || B(i), f?.(i);
49
+ },
50
+ [d, f]
51
+ ), O = o.useMemo(() => Y(t, n), [n, t]), S = o.useMemo(() => q(t, n), [n, t]), p = /* @__PURE__ */ e.jsxs("div", { className: "flex max-h-[75vh] flex-col gap-3", children: [
52
+ /* @__PURE__ */ e.jsx("div", { className: "overflow-hidden rounded-md border", children: /* @__PURE__ */ e.jsx(
53
+ "iframe",
54
+ {
55
+ title: a,
56
+ src: S,
57
+ className: "h-[560px] w-full border-0",
58
+ loading: "lazy",
59
+ referrerPolicy: "strict-origin-when-cross-origin"
60
+ }
61
+ ) }),
62
+ /* @__PURE__ */ e.jsxs("div", { className: "text-muted-foreground flex items-center justify-between gap-2 text-xs", children: [
63
+ /* @__PURE__ */ e.jsx("span", { children: "If the embedded checkout is unavailable, open the support page directly." }),
64
+ /* @__PURE__ */ e.jsxs(
65
+ "a",
66
+ {
67
+ href: O,
68
+ target: "_blank",
69
+ rel: "noopener noreferrer",
70
+ className: "text-foreground inline-flex items-center gap-1 font-medium underline underline-offset-2",
71
+ children: [
72
+ "Open Buy Me a Coffee",
73
+ /* @__PURE__ */ e.jsx(I, { className: "h-3.5 w-3.5" })
74
+ ]
75
+ }
76
+ )
77
+ ] })
78
+ ] }), x = /* @__PURE__ */ e.jsx("div", { className: l("fixed right-6 bottom-6 z-50", v), children: /* @__PURE__ */ e.jsxs(
79
+ R,
80
+ {
81
+ "aria-label": "Support this project",
82
+ type: C ?? "button",
83
+ className: l(
84
+ "inline-flex h-14 w-14 rounded-full border border-black/15 bg-[#ffdd00] text-black shadow-[0_16px_36px_-18px_rgba(0,0,0,0.8)] transition hover:-translate-y-0.5 hover:scale-105 hover:bg-[#ffe347] focus-visible:ring-2 focus-visible:ring-offset-2 active:translate-y-0 active:scale-95",
85
+ y,
86
+ M
87
+ ),
88
+ onClick: (i) => {
89
+ D?.(i), i.defaultPrevented || m(!0);
90
+ },
91
+ ...N,
92
+ children: [
93
+ /* @__PURE__ */ e.jsx(_, { className: "h-6 w-6" }),
94
+ /* @__PURE__ */ e.jsx("span", { className: "sr-only", children: "Support this project" })
95
+ ]
96
+ }
97
+ ) });
98
+ return E ? /* @__PURE__ */ e.jsxs(e.Fragment, { children: [
99
+ x,
100
+ /* @__PURE__ */ e.jsx(P, { open: u, onOpenChange: m, children: /* @__PURE__ */ e.jsxs(H, { className: l("mx-auto w-full max-w-xl", h), children: [
101
+ /* @__PURE__ */ e.jsxs(Q, { children: [
102
+ /* @__PURE__ */ e.jsx(T, { children: s }),
103
+ /* @__PURE__ */ e.jsx(W, { children: r })
104
+ ] }),
105
+ /* @__PURE__ */ e.jsx("div", { className: "px-4 pb-4", children: p })
106
+ ] }) })
107
+ ] }) : /* @__PURE__ */ e.jsxs(e.Fragment, { children: [
108
+ x,
109
+ /* @__PURE__ */ e.jsx(U, { open: u, onOpenChange: m, children: /* @__PURE__ */ e.jsxs(z, { className: l("max-w-xl p-5", h), children: [
110
+ /* @__PURE__ */ e.jsxs(L, { children: [
111
+ /* @__PURE__ */ e.jsx($, { children: s }),
112
+ /* @__PURE__ */ e.jsx(F, { children: r })
113
+ ] }),
114
+ p
115
+ ] }) })
116
+ ] });
117
+ }
118
+ export {
119
+ ee as SupportFab
120
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gv-tech/ui-web",
3
- "version": "2.16.0",
3
+ "version": "2.18.0",
4
4
  "description": "Web (DOM/Radix) implementations of the GV Tech design system components",
5
5
  "repository": {
6
6
  "type": "git",
package/src/index.ts CHANGED
@@ -335,6 +335,14 @@ export type { ResizableHandleProps, ResizablePanelGroupProps, ResizablePanelProp
335
335
  export { ScrollArea, ScrollBar } from './scroll-area';
336
336
  export type { ScrollAreaProps, ScrollBarProps } from './scroll-area';
337
337
 
338
+ // Scroll To Top
339
+ export { ScrollToTop } from './scroll-to-top';
340
+ export type { ScrollToTopProps } from './scroll-to-top';
341
+
342
+ // Support FAB
343
+ export { SupportFab } from './support-fab';
344
+ export type { SupportFabProps } from './support-fab';
345
+
338
346
  // Search
339
347
  export { Search, SearchTrigger } from './search';
340
348
  export type { SearchProps, SearchTriggerProps } from './search';
@@ -0,0 +1,134 @@
1
+ 'use client';
2
+
3
+ import { ScrollToTopBaseProps } from '@gv-tech/ui-core';
4
+ import { ArrowUp } from 'lucide-react';
5
+ import * as React from 'react';
6
+ import { Button } from './button';
7
+ import { cn } from './lib/utils';
8
+
9
+ export interface ScrollToTopProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, ScrollToTopBaseProps {
10
+ /** Optional custom scroll container; defaults to window when undefined. */
11
+ scrollTarget?: Window | HTMLElement | null;
12
+ }
13
+
14
+ type ScrollTarget = Window | HTMLElement | null;
15
+
16
+ const isWindowTarget = (target: Exclude<ScrollTarget, null>): target is Window =>
17
+ typeof (target as Window).scrollY === 'number';
18
+
19
+ const getScrollOffset = (target: Exclude<ScrollTarget, null>) =>
20
+ isWindowTarget(target) ? target.scrollY : target.scrollTop;
21
+
22
+ export function ScrollToTop({
23
+ threshold = 240,
24
+ exitDuration = 450,
25
+ behavior = 'smooth',
26
+ scrollTarget,
27
+ className,
28
+ label = 'Scroll to top',
29
+ onClick,
30
+ tabIndex,
31
+ type,
32
+ ...props
33
+ }: ScrollToTopProps) {
34
+ const [isVisible, setIsVisible] = React.useState(false);
35
+ const [isExiting, setIsExiting] = React.useState(false);
36
+ const timeoutRef = React.useRef<number | null>(null);
37
+
38
+ React.useEffect(() => {
39
+ const target = scrollTarget === undefined ? window : scrollTarget;
40
+
41
+ if (!target) {
42
+ setIsVisible(false);
43
+ return;
44
+ }
45
+
46
+ const updateVisibility = () => {
47
+ const offset = getScrollOffset(target);
48
+
49
+ if (isExiting) {
50
+ // Keep the control dismissed during the return-to-top animation,
51
+ // then release once we are back under the visibility threshold.
52
+ if (offset <= threshold) {
53
+ setIsVisible(false);
54
+ setIsExiting(false);
55
+ }
56
+ return;
57
+ }
58
+
59
+ setIsVisible(offset > threshold);
60
+ };
61
+
62
+ updateVisibility();
63
+ target.addEventListener('scroll', updateVisibility, { passive: true });
64
+
65
+ return () => {
66
+ target.removeEventListener('scroll', updateVisibility);
67
+ };
68
+ }, [isExiting, scrollTarget, threshold]);
69
+
70
+ React.useEffect(() => {
71
+ return () => {
72
+ if (timeoutRef.current !== null) {
73
+ window.clearTimeout(timeoutRef.current);
74
+ }
75
+ };
76
+ }, []);
77
+
78
+ const state = isExiting ? 'exiting' : isVisible ? 'visible' : 'hidden';
79
+
80
+ const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
81
+ onClick?.(event);
82
+ if (event.defaultPrevented || isExiting) {
83
+ return;
84
+ }
85
+
86
+ const target = scrollTarget === undefined ? window : scrollTarget;
87
+ if (!target) {
88
+ return;
89
+ }
90
+
91
+ setIsExiting(true);
92
+
93
+ const timeout = Math.max(0, exitDuration);
94
+ timeoutRef.current = window.setTimeout(() => {
95
+ target.scrollTo({ top: 0, behavior });
96
+
97
+ const offset = getScrollOffset(target);
98
+ setIsVisible(false);
99
+
100
+ if (offset <= threshold) {
101
+ setIsExiting(false);
102
+ }
103
+ }, timeout);
104
+ };
105
+
106
+ return (
107
+ <Button
108
+ aria-label={label}
109
+ data-state={state}
110
+ type={type ?? 'button'}
111
+ variant="default"
112
+ size="icon"
113
+ tabIndex={state === 'hidden' ? -1 : tabIndex}
114
+ className={cn(
115
+ 'group border-primary/40 bg-primary text-primary-foreground focus-visible:ring-ring fixed right-6 bottom-6 z-50 inline-flex h-14 w-14 items-center justify-center overflow-hidden rounded-full border shadow-[0_18px_40px_-22px_hsl(var(--primary)/0.9)] transition-all duration-500 ease-out focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none',
116
+ 'before:pointer-events-none before:absolute before:inset-0 before:bg-[radial-gradient(circle_at_35%_30%,rgba(255,255,255,0.45),transparent_55%)] before:opacity-80',
117
+ 'hover:-translate-y-1 hover:scale-105 hover:shadow-[0_24px_48px_-24px_hsl(var(--primary)/0.95)] active:translate-y-0 active:scale-95',
118
+ state === 'visible' && 'translate-y-0 scale-100 opacity-100',
119
+ state === 'hidden' &&
120
+ 'pointer-events-none translate-y-24 scale-75 opacity-0 blur-[1px] motion-safe:animate-none',
121
+ state === 'exiting' &&
122
+ 'pointer-events-none translate-y-28 scale-90 opacity-0 blur-[2px] motion-safe:animate-none',
123
+ className,
124
+ )}
125
+ onClick={handleClick}
126
+ {...props}
127
+ >
128
+ <span className="bg-primary-foreground/20 absolute inset-0 rounded-full opacity-0 transition-opacity duration-500 group-hover:animate-pulse group-hover:opacity-100" />
129
+ <span className="border-primary-foreground/35 absolute inset-0 rounded-full border opacity-0 transition-opacity duration-300 group-hover:animate-ping group-hover:opacity-100" />
130
+ <ArrowUp className="relative z-10 h-5 w-5 drop-shadow-[0_2px_2px_rgba(0,0,0,0.2)]" />
131
+ <span className="sr-only">{label}</span>
132
+ </Button>
133
+ );
134
+ }
package/src/setupTests.ts CHANGED
@@ -1,4 +1,4 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
1
+ /* @typescript-eslint/no-explicit-any */
2
2
  import '@testing-library/jest-dom';
3
3
  import { vi } from 'vitest';
4
4
 
@@ -0,0 +1,190 @@
1
+ 'use client';
2
+
3
+ import { Coffee, ExternalLink } from 'lucide-react';
4
+ import * as React from 'react';
5
+ import { Button } from './button';
6
+ import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from './dialog';
7
+ import { Drawer, DrawerContent, DrawerDescription, DrawerHeader, DrawerTitle } from './drawer';
8
+ import { cn } from './lib/utils';
9
+
10
+ const MOBILE_QUERY = '(max-width: 767px)';
11
+
12
+ const normalizeBaseUrl = (url: string) => {
13
+ const trimmed = url.trim();
14
+ return trimmed.endsWith('/') ? trimmed.slice(0, -1) : trimmed;
15
+ };
16
+
17
+ const sanitizeCreator = (creatorId: string) => creatorId.trim().replace(/^@+/, '');
18
+
19
+ const buildPageUrl = (supportUrl: string, creatorId: string) => {
20
+ const base = normalizeBaseUrl(supportUrl);
21
+ const creator = encodeURIComponent(sanitizeCreator(creatorId));
22
+ return `${base}/${creator}`;
23
+ };
24
+
25
+ const buildEmbedUrl = (supportUrl: string, creatorId: string) => {
26
+ const base = normalizeBaseUrl(supportUrl);
27
+ const creator = encodeURIComponent(sanitizeCreator(creatorId));
28
+ return `${base}/widget/page/${creator}`;
29
+ };
30
+
31
+ const useIsMobile = () => {
32
+ const getInitial = () => {
33
+ if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {
34
+ return false;
35
+ }
36
+ return window.matchMedia(MOBILE_QUERY).matches;
37
+ };
38
+
39
+ const [isMobile, setIsMobile] = React.useState(getInitial);
40
+
41
+ React.useEffect(() => {
42
+ if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {
43
+ return;
44
+ }
45
+
46
+ const mediaQuery = window.matchMedia(MOBILE_QUERY);
47
+ const onChange = (event: MediaQueryListEvent) => setIsMobile(event.matches);
48
+
49
+ setIsMobile(mediaQuery.matches);
50
+ mediaQuery.addEventListener('change', onChange);
51
+
52
+ return () => {
53
+ mediaQuery.removeEventListener('change', onChange);
54
+ };
55
+ }, []);
56
+
57
+ return isMobile;
58
+ };
59
+
60
+ export interface SupportFabProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onChange'> {
61
+ supportUrl?: string;
62
+ creatorId: string;
63
+ title?: string;
64
+ description?: string;
65
+ iframeTitle?: string;
66
+ open?: boolean;
67
+ defaultOpen?: boolean;
68
+ onOpenChange?: (open: boolean) => void;
69
+ positionClassName?: string;
70
+ buttonClassName?: string;
71
+ panelClassName?: string;
72
+ }
73
+
74
+ export function SupportFab({
75
+ supportUrl = 'https://www.buymeacoffee.com',
76
+ creatorId,
77
+ title = 'Buy me a coffee',
78
+ description = 'Support the project directly from this panel.',
79
+ iframeTitle = 'Buy Me a Coffee support form',
80
+ open,
81
+ defaultOpen = false,
82
+ onOpenChange,
83
+ positionClassName,
84
+ buttonClassName,
85
+ panelClassName,
86
+ className,
87
+ type,
88
+ onClick,
89
+ ...buttonProps
90
+ }: SupportFabProps) {
91
+ const isMobile = useIsMobile();
92
+ const isControlled = open !== undefined;
93
+ const [internalOpen, setInternalOpen] = React.useState(defaultOpen);
94
+ const isOpen = isControlled ? open : internalOpen;
95
+
96
+ const setOpen = React.useCallback(
97
+ (nextOpen: boolean) => {
98
+ if (!isControlled) {
99
+ setInternalOpen(nextOpen);
100
+ }
101
+ onOpenChange?.(nextOpen);
102
+ },
103
+ [isControlled, onOpenChange],
104
+ );
105
+
106
+ const pageUrl = React.useMemo(() => buildPageUrl(supportUrl, creatorId), [creatorId, supportUrl]);
107
+ const embedUrl = React.useMemo(() => buildEmbedUrl(supportUrl, creatorId), [creatorId, supportUrl]);
108
+
109
+ const panelBody = (
110
+ <div className="flex max-h-[75vh] flex-col gap-3">
111
+ <div className="overflow-hidden rounded-md border">
112
+ <iframe
113
+ title={iframeTitle}
114
+ src={embedUrl}
115
+ className="h-[560px] w-full border-0"
116
+ loading="lazy"
117
+ referrerPolicy="strict-origin-when-cross-origin"
118
+ />
119
+ </div>
120
+ <div className="text-muted-foreground flex items-center justify-between gap-2 text-xs">
121
+ <span>If the embedded checkout is unavailable, open the support page directly.</span>
122
+ <a
123
+ href={pageUrl}
124
+ target="_blank"
125
+ rel="noopener noreferrer"
126
+ className="text-foreground inline-flex items-center gap-1 font-medium underline underline-offset-2"
127
+ >
128
+ Open Buy Me a Coffee
129
+ <ExternalLink className="h-3.5 w-3.5" />
130
+ </a>
131
+ </div>
132
+ </div>
133
+ );
134
+
135
+ const trigger = (
136
+ <div className={cn('fixed right-6 bottom-6 z-50', positionClassName)}>
137
+ <Button
138
+ aria-label="Support this project"
139
+ type={type ?? 'button'}
140
+ className={cn(
141
+ 'inline-flex h-14 w-14 rounded-full border border-black/15 bg-[#ffdd00] text-black shadow-[0_16px_36px_-18px_rgba(0,0,0,0.8)] transition hover:-translate-y-0.5 hover:scale-105 hover:bg-[#ffe347] focus-visible:ring-2 focus-visible:ring-offset-2 active:translate-y-0 active:scale-95',
142
+ buttonClassName,
143
+ className,
144
+ )}
145
+ onClick={(event) => {
146
+ onClick?.(event);
147
+ if (!event.defaultPrevented) {
148
+ setOpen(true);
149
+ }
150
+ }}
151
+ {...buttonProps}
152
+ >
153
+ <Coffee className="h-6 w-6" />
154
+ <span className="sr-only">Support this project</span>
155
+ </Button>
156
+ </div>
157
+ );
158
+
159
+ if (isMobile) {
160
+ return (
161
+ <>
162
+ {trigger}
163
+ <Drawer open={isOpen} onOpenChange={setOpen}>
164
+ <DrawerContent className={cn('mx-auto w-full max-w-xl', panelClassName)}>
165
+ <DrawerHeader>
166
+ <DrawerTitle>{title}</DrawerTitle>
167
+ <DrawerDescription>{description}</DrawerDescription>
168
+ </DrawerHeader>
169
+ <div className="px-4 pb-4">{panelBody}</div>
170
+ </DrawerContent>
171
+ </Drawer>
172
+ </>
173
+ );
174
+ }
175
+
176
+ return (
177
+ <>
178
+ {trigger}
179
+ <Dialog open={isOpen} onOpenChange={setOpen}>
180
+ <DialogContent className={cn('max-w-xl p-5', panelClassName)}>
181
+ <DialogHeader>
182
+ <DialogTitle>{title}</DialogTitle>
183
+ <DialogDescription>{description}</DialogDescription>
184
+ </DialogHeader>
185
+ {panelBody}
186
+ </DialogContent>
187
+ </Dialog>
188
+ </>
189
+ );
190
+ }