@lessly/ui 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1057,4 +1057,37 @@ interface RequestRowProps extends Omit<React$1.HTMLAttributes<HTMLDivElement>, '
1057
1057
  }
1058
1058
  declare const RequestRow: React$1.ForwardRefExoticComponent<RequestRowProps & React$1.RefAttributes<HTMLDivElement>>;
1059
1059
 
1060
- 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, type BadgeProps, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, type ButtonProps, Calendar, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, type CarouselApi, CarouselContent, type CarouselContextProps, CarouselItem, CarouselNext, type CarouselOptions, type CarouselPlugin, CarouselPrevious, type CarouselProps, Checkbox, Col, type ColProps, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ConfirmDialog, type ConfirmDialogProps, type ConnectionAuth, ConnectionCard, type ConnectionCardProps, type ConnectionScope, type ConnectionStatus, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, type CopyButtonProps, DatePicker, type DatePickerProps, type DeltaDirection, type DeltaTone, 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, Grid, GridOverlay, type GridOverlayProps, type GridProps, HoverCard, HoverCardContent, HoverCardTrigger, InlineError, type InlineErrorProps, Input, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, type InputProps, 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, type PaginationLinkProps, PaginationNext, PaginationPrevious, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, RadioGroup, RadioGroupItem, RequestRow, type RequestRowProps, type RequestState, type RequestSurface, type ResolvedTheme, type Responsive, ScrollArea, ScrollBar, SectionIntro, type SectionIntroProps, SegmentChip, type SegmentChipProps, Select, type SelectOption, type SelectProps, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarNav, SidebarNavLink, type SidebarNavLinkProps, type SidebarNavProps, SidebarProductHeader, type SidebarProductHeaderProps, Skeleton, Slider, StatCard, type StatCardProps, StatusDot, type StatusDotProps, Switch, type SwitchProps, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, type TextareaProps, type Theme, 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, segmentChipVariants, statusDotVariants, toggleVariants, useCarousel, useFormField, useIsMobile, useSidebar, useTheme };
1060
+ interface FeedbackWidgetLabels {
1061
+ /** Floating trigger button + its aria-label. */
1062
+ trigger: string;
1063
+ /** Heading shown above the form. */
1064
+ title: string;
1065
+ /** Label for the Title input. */
1066
+ titleField: string;
1067
+ /** Label for the Details textarea. */
1068
+ detailsField: string;
1069
+ /** Submit button. */
1070
+ submit: string;
1071
+ /** Message shown after a successful submit. */
1072
+ success: string;
1073
+ /** Message shown after a failed submit. */
1074
+ error: string;
1075
+ }
1076
+ interface FeedbackWidgetProps {
1077
+ /**
1078
+ * Called with the entered feedback when the form is submitted. The widget is
1079
+ * presentational: it knows nothing about APIs, auth, or routing — the parent
1080
+ * decides what to do with the data. Rejecting shows the error state.
1081
+ */
1082
+ onSubmit: (data: {
1083
+ title: string;
1084
+ details: string;
1085
+ }) => Promise<void>;
1086
+ /** Override any of the default copy. */
1087
+ labels?: Partial<FeedbackWidgetLabels>;
1088
+ /** Merged onto the fixed positioning wrapper (e.g. to reposition the button). */
1089
+ className?: string;
1090
+ }
1091
+ declare function FeedbackWidget({ onSubmit, labels, className }: FeedbackWidgetProps): React$1.JSX.Element;
1092
+
1093
+ 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, type BadgeProps, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, type ButtonProps, Calendar, type CalendarProps, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, type CarouselApi, CarouselContent, type CarouselContextProps, CarouselItem, CarouselNext, type CarouselOptions, type CarouselPlugin, CarouselPrevious, type CarouselProps, Checkbox, Col, type ColProps, Collapsible, CollapsibleContent, CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ConfirmDialog, type ConfirmDialogProps, type ConnectionAuth, ConnectionCard, type ConnectionCardProps, type ConnectionScope, type ConnectionStatus, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, CopyButton, type CopyButtonProps, DatePicker, type DatePickerProps, type DeltaDirection, type DeltaTone, 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, FeedbackWidget, type FeedbackWidgetLabels, type FeedbackWidgetProps, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, Grid, GridOverlay, type GridOverlayProps, type GridProps, HoverCard, HoverCardContent, HoverCardTrigger, InlineError, type InlineErrorProps, Input, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, type InputProps, 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, type PaginationLinkProps, PaginationNext, PaginationPrevious, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, RadioGroup, RadioGroupItem, RequestRow, type RequestRowProps, type RequestState, type RequestSurface, type ResolvedTheme, type Responsive, ScrollArea, ScrollBar, SectionIntro, type SectionIntroProps, SegmentChip, type SegmentChipProps, Select, type SelectOption, type SelectProps, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarNav, SidebarNavLink, type SidebarNavLinkProps, type SidebarNavProps, SidebarProductHeader, type SidebarProductHeaderProps, Skeleton, Slider, StatCard, type StatCardProps, StatusDot, type StatusDotProps, Switch, type SwitchProps, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, type TextareaProps, type Theme, 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, segmentChipVariants, statusDotVariants, toggleVariants, useCarousel, useFormField, useIsMobile, useSidebar, useTheme };
package/dist/index.js CHANGED
@@ -3565,6 +3565,116 @@ var RequestRow = React57.forwardRef(
3565
3565
  }
3566
3566
  );
3567
3567
  RequestRow.displayName = "RequestRow";
3568
+
3569
+ // src/components/feedback-widget.tsx
3570
+ import * as React58 from "react";
3571
+ import { MessageSquare, Loader2 as Loader22, CheckCircle2 } from "lucide-react";
3572
+ import { jsx as jsx68, jsxs as jsxs35 } from "react/jsx-runtime";
3573
+ var TITLE_MAX = 256;
3574
+ var DETAILS_MAX = 65536;
3575
+ var DEFAULT_LABELS = {
3576
+ trigger: "Feedback",
3577
+ title: "Send feedback",
3578
+ titleField: "Title",
3579
+ detailsField: "Details",
3580
+ submit: "Send feedback",
3581
+ success: "Thanks! Your feedback was sent.",
3582
+ error: "Couldn't send feedback. Please try again."
3583
+ };
3584
+ function FeedbackWidget({ onSubmit, labels, className }) {
3585
+ const l = { ...DEFAULT_LABELS, ...labels };
3586
+ const uid = React58.useId();
3587
+ const titleId = `${uid}-title`;
3588
+ const detailsId = `${uid}-details`;
3589
+ const titleErrId = `${uid}-title-error`;
3590
+ const detailsErrId = `${uid}-details-error`;
3591
+ const [open, setOpen] = React58.useState(false);
3592
+ const [status, setStatus] = React58.useState("idle");
3593
+ const [title, setTitle] = React58.useState("");
3594
+ const [details, setDetails] = React58.useState("");
3595
+ const titleTooLong = title.length > TITLE_MAX;
3596
+ const detailsTooLong = details.length > DETAILS_MAX;
3597
+ const titleEmpty = title.trim().length === 0;
3598
+ const detailsEmpty = details.trim().length === 0;
3599
+ const valid = !titleEmpty && !detailsEmpty && !titleTooLong && !detailsTooLong;
3600
+ const submitting = status === "submitting";
3601
+ const changeOpen = (next) => {
3602
+ if (submitting) return;
3603
+ setOpen(next);
3604
+ if (!next) setStatus("idle");
3605
+ };
3606
+ const handleSubmit = async (e) => {
3607
+ e.preventDefault();
3608
+ if (!valid || submitting) return;
3609
+ setStatus("submitting");
3610
+ try {
3611
+ await onSubmit({ title, details });
3612
+ setStatus("success");
3613
+ setTitle("");
3614
+ setDetails("");
3615
+ } catch {
3616
+ setStatus("error");
3617
+ }
3618
+ };
3619
+ return /* @__PURE__ */ jsxs35(Popover, { open, onOpenChange: changeOpen, children: [
3620
+ /* @__PURE__ */ jsx68("div", { className: cn("fixed bottom-4 right-4 z-50", className), children: /* @__PURE__ */ jsx68(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs35(Button, { "aria-label": l.trigger, children: [
3621
+ /* @__PURE__ */ jsx68(MessageSquare, { className: "size-4", "aria-hidden": "true" }),
3622
+ l.trigger
3623
+ ] }) }) }),
3624
+ /* @__PURE__ */ jsx68(PopoverContent, { align: "end", side: "top", className: "w-80", children: status === "success" ? /* @__PURE__ */ jsxs35("div", { className: "flex flex-col items-center gap-3 py-2 text-center", children: [
3625
+ /* @__PURE__ */ jsx68(CheckCircle2, { className: "size-8 text-text-success", "aria-hidden": "true" }),
3626
+ /* @__PURE__ */ jsx68("p", { role: "status", className: "text-sm text-text-primary", children: l.success }),
3627
+ /* @__PURE__ */ jsx68(Button, { variant: "outline", size: "sm", onClick: () => changeOpen(false), children: "Close" })
3628
+ ] }) : /* @__PURE__ */ jsxs35("form", { onSubmit: handleSubmit, className: "flex flex-col gap-3", children: [
3629
+ /* @__PURE__ */ jsx68("p", { className: "text-sm font-medium text-text-primary", children: l.title }),
3630
+ /* @__PURE__ */ jsxs35("div", { className: "flex flex-col gap-1.5", children: [
3631
+ /* @__PURE__ */ jsx68(Label2, { htmlFor: titleId, children: l.titleField }),
3632
+ /* @__PURE__ */ jsx68(
3633
+ Input,
3634
+ {
3635
+ id: titleId,
3636
+ value: title,
3637
+ onChange: (e) => setTitle(e.target.value),
3638
+ disabled: submitting,
3639
+ "aria-invalid": titleTooLong || void 0,
3640
+ "aria-describedby": titleTooLong ? titleErrId : void 0
3641
+ }
3642
+ ),
3643
+ titleTooLong && /* @__PURE__ */ jsxs35("p", { id: titleErrId, className: "text-xs text-text-danger", children: [
3644
+ l.titleField,
3645
+ " must be ",
3646
+ TITLE_MAX,
3647
+ " characters or fewer."
3648
+ ] })
3649
+ ] }),
3650
+ /* @__PURE__ */ jsxs35("div", { className: "flex flex-col gap-1.5", children: [
3651
+ /* @__PURE__ */ jsx68(Label2, { htmlFor: detailsId, children: l.detailsField }),
3652
+ /* @__PURE__ */ jsx68(
3653
+ Textarea,
3654
+ {
3655
+ id: detailsId,
3656
+ value: details,
3657
+ onChange: (e) => setDetails(e.target.value),
3658
+ disabled: submitting,
3659
+ "aria-invalid": detailsTooLong || void 0,
3660
+ "aria-describedby": detailsTooLong ? detailsErrId : void 0
3661
+ }
3662
+ ),
3663
+ detailsTooLong && /* @__PURE__ */ jsxs35("p", { id: detailsErrId, className: "text-xs text-text-danger", children: [
3664
+ l.detailsField,
3665
+ " must be ",
3666
+ DETAILS_MAX,
3667
+ " characters or fewer."
3668
+ ] })
3669
+ ] }),
3670
+ status === "error" && /* @__PURE__ */ jsx68(InlineError, { children: l.error }),
3671
+ /* @__PURE__ */ jsxs35(Button, { type: "submit", disabled: !valid || submitting, children: [
3672
+ submitting && /* @__PURE__ */ jsx68(Loader22, { className: "size-4 animate-spin", "aria-hidden": "true" }),
3673
+ l.submit
3674
+ ] })
3675
+ ] }) })
3676
+ ] });
3677
+ }
3568
3678
  export {
3569
3679
  Accordion,
3570
3680
  AccordionContent,
@@ -3684,6 +3794,7 @@ export {
3684
3794
  EmptyState,
3685
3795
  ExtensionIcon,
3686
3796
  ExtensionLink,
3797
+ FeedbackWidget,
3687
3798
  Form,
3688
3799
  FormControl,
3689
3800
  FormDescription,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lessly/ui",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Lessly design system — shared UI primitives, tokens, and theme",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@10.30.3",