@lessly/ui 0.8.0 → 0.10.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
@@ -885,6 +885,43 @@ type SidebarProductHeaderProps = SidebarProductHeaderOwnProps & Omit<React$1.Com
885
885
  * which anchors a `MenuPopup` at left:12 with the default sideOffset, no alignOffset. */
886
886
  declare const SidebarProductHeader: React$1.ForwardRefExoticComponent<SidebarProductHeaderProps & React$1.RefAttributes<HTMLButtonElement>>;
887
887
 
888
+ /** A slot's native attributes plus an explicit `data-*` index, so an object literal like
889
+ * `{ 'data-testid': 'drill-back' }` passes excess-property checking — plain
890
+ * `React.HTMLAttributes` does not declare `data-*` as a named property. */
891
+ type SidebarBackHeaderSlotProps = React$1.HTMLAttributes<HTMLElement> & {
892
+ [attr: `data-${string}`]: string | number | boolean | undefined;
893
+ };
894
+ interface SidebarBackHeaderProps extends Omit<React$1.HTMLAttributes<HTMLElement>, 'title'> {
895
+ /** Title text/node beside the arrow. In single mode it is also the row's accessible name. */
896
+ title: React$1.ReactNode;
897
+ /** Back action — the arrow in split mode, the whole row in single mode. */
898
+ onBack: () => void;
899
+ /** Title action. Its presence switches the row into split mode (arrow + title are two
900
+ * separate controls). Omit it for single mode (the whole row is one back button). */
901
+ onTitleClick?: () => void;
902
+ /** Accessible name for the back control in split mode. Defaults to `"Back"`. Unused in
903
+ * single mode, where the row's accessible name is the title text. */
904
+ backLabel?: string;
905
+ /** Attributes for the arrow control — the arrow `<button>` in split mode, the arrow-plate
906
+ * `<span>` in single mode. Lets a consumer attach e.g. `data-testid`. */
907
+ arrowProps?: SidebarBackHeaderSlotProps;
908
+ /** Attributes for the title control — the title `<button>` in split mode, the title
909
+ * `<span>` in single mode. */
910
+ titleProps?: SidebarBackHeaderSlotProps;
911
+ }
912
+ /** Accessible sidebar back-header (`← Title`) reproducing `lessly-workspace` DrillPanel's
913
+ * back-row one-to-one, with a flexible action model:
914
+ *
915
+ * - **Split mode** (`onTitleClick` given): two native buttons — arrow (`onBack`) and title
916
+ * (`onTitleClick`).
917
+ * - **Single mode** (`onTitleClick` omitted): the whole row is one native button (`onBack`).
918
+ *
919
+ * The row adds NO horizontal padding of its own — the parent pane owns horizontal inset. */
920
+ declare function SidebarBackHeader({ title, onBack, onTitleClick, backLabel, arrowProps, titleProps, className, ...rowProps }: SidebarBackHeaderProps): React$1.JSX.Element;
921
+ declare namespace SidebarBackHeader {
922
+ var displayName: string;
923
+ }
924
+
888
925
  interface AppShellProps {
889
926
  /** The sidebar, typically an <AppSidebar/>. Rendered in the desktop rail and,
890
927
  * on mobile, inside a Sheet (force-expanded via cloneElement collapsed=false). */
@@ -1057,4 +1094,37 @@ interface RequestRowProps extends Omit<React$1.HTMLAttributes<HTMLDivElement>, '
1057
1094
  }
1058
1095
  declare const RequestRow: React$1.ForwardRefExoticComponent<RequestRowProps & React$1.RefAttributes<HTMLDivElement>>;
1059
1096
 
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 };
1097
+ interface FeedbackWidgetLabels {
1098
+ /** Floating trigger button + its aria-label. */
1099
+ trigger: string;
1100
+ /** Heading shown above the form. */
1101
+ title: string;
1102
+ /** Label for the Title input. */
1103
+ titleField: string;
1104
+ /** Label for the Details textarea. */
1105
+ detailsField: string;
1106
+ /** Submit button. */
1107
+ submit: string;
1108
+ /** Message shown after a successful submit. */
1109
+ success: string;
1110
+ /** Message shown after a failed submit. */
1111
+ error: string;
1112
+ }
1113
+ interface FeedbackWidgetProps {
1114
+ /**
1115
+ * Called with the entered feedback when the form is submitted. The widget is
1116
+ * presentational: it knows nothing about APIs, auth, or routing — the parent
1117
+ * decides what to do with the data. Rejecting shows the error state.
1118
+ */
1119
+ onSubmit: (data: {
1120
+ title: string;
1121
+ details: string;
1122
+ }) => Promise<void>;
1123
+ /** Override any of the default copy. */
1124
+ labels?: Partial<FeedbackWidgetLabels>;
1125
+ /** Merged onto the fixed positioning wrapper (e.g. to reposition the button). */
1126
+ className?: string;
1127
+ }
1128
+ declare function FeedbackWidget({ onSubmit, labels, className }: FeedbackWidgetProps): React$1.JSX.Element;
1129
+
1130
+ 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, SidebarBackHeader, type SidebarBackHeaderProps, 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
@@ -3108,11 +3108,72 @@ var SidebarProductHeader = React50.forwardRef(
3108
3108
  );
3109
3109
  SidebarProductHeader.displayName = "SidebarProductHeader";
3110
3110
 
3111
+ // src/components/sidebar-back-header.tsx
3112
+ import { ArrowLeft as ArrowLeft2 } from "lucide-react";
3113
+ import { jsx as jsx61, jsxs as jsxs31 } from "react/jsx-runtime";
3114
+ var focusRing = "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus";
3115
+ var arrowPlate = "flex size-5 items-center justify-center rounded-md transition-colors hover:bg-[color-mix(in_srgb,var(--text-primary)_12%,transparent)] hover:text-text-primary";
3116
+ var arrowBox = "flex shrink-0 cursor-pointer items-center rounded-xl py-2 pr-0 pl-2.5 text-text-secondary";
3117
+ var titleBox = "min-w-0 flex-1 cursor-pointer truncate rounded-xl py-2 pr-2.5 pl-[14px] text-left text-sm font-semibold text-text-primary";
3118
+ var Arrow = () => /* @__PURE__ */ jsx61(ArrowLeft2, { size: 16, "aria-hidden": "true" });
3119
+ function SidebarBackHeader({
3120
+ title,
3121
+ onBack,
3122
+ onTitleClick,
3123
+ backLabel = "Back",
3124
+ arrowProps,
3125
+ titleProps,
3126
+ className,
3127
+ ...rowProps
3128
+ }) {
3129
+ const { className: arrowClassName, ...arrowRest } = arrowProps ?? {};
3130
+ const { className: titleClassName, ...titleRest } = titleProps ?? {};
3131
+ if (!onTitleClick) {
3132
+ return /* @__PURE__ */ jsxs31(
3133
+ "button",
3134
+ {
3135
+ type: "button",
3136
+ onClick: onBack,
3137
+ className: cn("flex items-center rounded-xl", focusRing, className),
3138
+ ...rowProps,
3139
+ children: [
3140
+ /* @__PURE__ */ jsx61("span", { className: arrowBox, children: /* @__PURE__ */ jsx61("span", { className: cn(arrowPlate, arrowClassName), ...arrowRest, children: /* @__PURE__ */ jsx61(Arrow, {}) }) }),
3141
+ /* @__PURE__ */ jsx61("span", { className: cn(titleBox, titleClassName), ...titleRest, children: title })
3142
+ ]
3143
+ }
3144
+ );
3145
+ }
3146
+ return /* @__PURE__ */ jsxs31("div", { className: cn("flex items-center", className), ...rowProps, children: [
3147
+ /* @__PURE__ */ jsx61(
3148
+ "button",
3149
+ {
3150
+ type: "button",
3151
+ "aria-label": backLabel,
3152
+ onClick: onBack,
3153
+ className: cn(arrowBox, focusRing, arrowClassName),
3154
+ ...arrowRest,
3155
+ children: /* @__PURE__ */ jsx61("span", { className: arrowPlate, children: /* @__PURE__ */ jsx61(Arrow, {}) })
3156
+ }
3157
+ ),
3158
+ /* @__PURE__ */ jsx61(
3159
+ "button",
3160
+ {
3161
+ type: "button",
3162
+ onClick: onTitleClick,
3163
+ className: cn(titleBox, focusRing, titleClassName),
3164
+ ...titleRest,
3165
+ children: title
3166
+ }
3167
+ )
3168
+ ] });
3169
+ }
3170
+ SidebarBackHeader.displayName = "SidebarBackHeader";
3171
+
3111
3172
  // src/components/app-shell.tsx
3112
3173
  import * as React51 from "react";
3113
3174
  import { Menu as Menu2 } from "lucide-react";
3114
3175
  import { useLocation as useLocation2 } from "react-router";
3115
- import { jsx as jsx61, jsxs as jsxs31 } from "react/jsx-runtime";
3176
+ import { jsx as jsx62, jsxs as jsxs32 } from "react/jsx-runtime";
3116
3177
  function expandedSidebar(sidebar) {
3117
3178
  return React51.isValidElement(sidebar) ? React51.cloneElement(sidebar, { collapsed: false }) : sidebar;
3118
3179
  }
@@ -3124,26 +3185,26 @@ function AppShell({ sidebar, topBar, children, className }) {
3124
3185
  }, [pathname]);
3125
3186
  const isMobile = useIsMobile();
3126
3187
  if (isMobile) {
3127
- return /* @__PURE__ */ jsx61(TooltipProvider, { children: /* @__PURE__ */ jsxs31("div", { className: cn("flex min-h-screen flex-col bg-bg-surface", className), children: [
3128
- /* @__PURE__ */ jsxs31("header", { className: "flex shrink-0 items-center justify-between border-b border-border-subtle bg-bg-surface px-4 py-3", children: [
3129
- /* @__PURE__ */ jsxs31(Sheet, { open: mobileOpen, onOpenChange: setMobileOpen, children: [
3130
- /* @__PURE__ */ jsx61(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsx61(Button, { variant: "ghost", size: "icon", className: "size-8 text-text-secondary", "aria-label": "Open navigation", children: /* @__PURE__ */ jsx61(Menu2, { className: "size-5" }) }) }),
3131
- /* @__PURE__ */ jsxs31(SheetContent, { side: "left", className: "w-[248px] bg-bg-surface p-0", children: [
3132
- /* @__PURE__ */ jsx61(SheetTitle, { className: "sr-only", children: "Navigation" }),
3133
- /* @__PURE__ */ jsx61(SheetDescription, { className: "sr-only", children: "Application navigation menu" }),
3188
+ return /* @__PURE__ */ jsx62(TooltipProvider, { children: /* @__PURE__ */ jsxs32("div", { className: cn("flex min-h-screen flex-col bg-bg-surface", className), children: [
3189
+ /* @__PURE__ */ jsxs32("header", { className: "flex shrink-0 items-center justify-between border-b border-border-subtle bg-bg-surface px-4 py-3", children: [
3190
+ /* @__PURE__ */ jsxs32(Sheet, { open: mobileOpen, onOpenChange: setMobileOpen, children: [
3191
+ /* @__PURE__ */ jsx62(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsx62(Button, { variant: "ghost", size: "icon", className: "size-8 text-text-secondary", "aria-label": "Open navigation", children: /* @__PURE__ */ jsx62(Menu2, { className: "size-5" }) }) }),
3192
+ /* @__PURE__ */ jsxs32(SheetContent, { side: "left", className: "w-[248px] bg-bg-surface p-0", children: [
3193
+ /* @__PURE__ */ jsx62(SheetTitle, { className: "sr-only", children: "Navigation" }),
3194
+ /* @__PURE__ */ jsx62(SheetDescription, { className: "sr-only", children: "Application navigation menu" }),
3134
3195
  expandedSidebar(sidebar)
3135
3196
  ] })
3136
3197
  ] }),
3137
- /* @__PURE__ */ jsx61("div", { className: "flex items-center gap-2", children: topBar })
3198
+ /* @__PURE__ */ jsx62("div", { className: "flex items-center gap-2", children: topBar })
3138
3199
  ] }),
3139
- /* @__PURE__ */ jsx61("main", { className: "flex-1 overflow-auto", children })
3200
+ /* @__PURE__ */ jsx62("main", { className: "flex-1 overflow-auto", children })
3140
3201
  ] }) });
3141
3202
  }
3142
- return /* @__PURE__ */ jsx61(TooltipProvider, { children: /* @__PURE__ */ jsxs31("div", { className: cn("flex min-h-screen gap-3 bg-bg-surface p-4", className), children: [
3143
- /* @__PURE__ */ jsx61("div", { className: "sticky top-4 h-[calc(100vh-32px)] shrink-0", children: sidebar }),
3144
- /* @__PURE__ */ jsxs31("div", { className: "flex min-w-0 flex-1 flex-col overflow-hidden", children: [
3145
- topBar && /* @__PURE__ */ jsx61("div", { className: "flex shrink-0 items-center justify-end gap-2", children: topBar }),
3146
- /* @__PURE__ */ jsx61("main", { className: "flex-1 overflow-y-auto", children })
3203
+ return /* @__PURE__ */ jsx62(TooltipProvider, { children: /* @__PURE__ */ jsxs32("div", { className: cn("flex min-h-screen gap-3 bg-bg-surface p-4", className), children: [
3204
+ /* @__PURE__ */ jsx62("div", { className: "sticky top-4 h-[calc(100vh-32px)] shrink-0", children: sidebar }),
3205
+ /* @__PURE__ */ jsxs32("div", { className: "flex min-w-0 flex-1 flex-col overflow-hidden", children: [
3206
+ topBar && /* @__PURE__ */ jsx62("div", { className: "flex shrink-0 items-center justify-end gap-2", children: topBar }),
3207
+ /* @__PURE__ */ jsx62("main", { className: "flex-1 overflow-y-auto", children })
3147
3208
  ] })
3148
3209
  ] }) });
3149
3210
  }
@@ -3152,11 +3213,11 @@ var AuthenticatedLayout = AppShell;
3152
3213
  // src/components/grid.tsx
3153
3214
  import * as React52 from "react";
3154
3215
  import { Slot as Slot6 } from "@radix-ui/react-slot";
3155
- import { jsx as jsx62 } from "react/jsx-runtime";
3216
+ import { jsx as jsx63 } from "react/jsx-runtime";
3156
3217
  var Grid = React52.forwardRef(
3157
3218
  ({ fluid = false, asChild = false, className, ...props }, ref) => {
3158
3219
  const Comp = asChild ? Slot6 : "div";
3159
- return /* @__PURE__ */ jsx62(
3220
+ return /* @__PURE__ */ jsx63(
3160
3221
  Comp,
3161
3222
  {
3162
3223
  ref,
@@ -3176,7 +3237,7 @@ Grid.displayName = "Grid";
3176
3237
  // src/components/col.tsx
3177
3238
  import * as React53 from "react";
3178
3239
  import { Slot as Slot7 } from "@radix-ui/react-slot";
3179
- import { jsx as jsx63 } from "react/jsx-runtime";
3240
+ import { jsx as jsx64 } from "react/jsx-runtime";
3180
3241
  var TIER_MAX = { base: 4, md: 8, xl: 12 };
3181
3242
  var SPAN = {
3182
3243
  base: { 1: "col-span-1", 2: "col-span-2", 3: "col-span-3", 4: "col-span-4" },
@@ -3299,19 +3360,19 @@ function responsiveClasses(span, offset) {
3299
3360
  var Col = React53.forwardRef(
3300
3361
  ({ span, offset, asChild = false, className, ...props }, ref) => {
3301
3362
  const Comp = asChild ? Slot7 : "div";
3302
- return /* @__PURE__ */ jsx63(Comp, { ref, className: cn(responsiveClasses(span, offset), className), ...props });
3363
+ return /* @__PURE__ */ jsx64(Comp, { ref, className: cn(responsiveClasses(span, offset), className), ...props });
3303
3364
  }
3304
3365
  );
3305
3366
  Col.displayName = "Col";
3306
3367
 
3307
3368
  // src/components/grid-overlay.tsx
3308
3369
  import * as React54 from "react";
3309
- import { jsx as jsx64 } from "react/jsx-runtime";
3370
+ import { jsx as jsx65 } from "react/jsx-runtime";
3310
3371
  var BASELINE = "var(--grid-gutter) / 2";
3311
3372
  var GridOverlay = React54.forwardRef(
3312
3373
  ({ columns, baseline = false, className, style, ...props }, ref) => {
3313
3374
  const count = Number.isFinite(columns) ? Math.max(1, Math.floor(columns)) : 1;
3314
- return /* @__PURE__ */ jsx64(
3375
+ return /* @__PURE__ */ jsx65(
3315
3376
  "div",
3316
3377
  {
3317
3378
  ref,
@@ -3328,7 +3389,7 @@ var GridOverlay = React54.forwardRef(
3328
3389
  ...style
3329
3390
  },
3330
3391
  ...props,
3331
- children: Array.from({ length: count }).map((_, i) => /* @__PURE__ */ jsx64("span", { style: { backgroundColor: "var(--bg-brand)", opacity: 0.1 } }, i))
3392
+ children: Array.from({ length: count }).map((_, i) => /* @__PURE__ */ jsx65("span", { style: { backgroundColor: "var(--bg-brand)", opacity: 0.1 } }, i))
3332
3393
  }
3333
3394
  );
3334
3395
  }
@@ -3339,7 +3400,7 @@ GridOverlay.displayName = "GridOverlay";
3339
3400
  import * as React55 from "react";
3340
3401
  import { cva as cva9 } from "class-variance-authority";
3341
3402
  import { Link2 as Link22, KeyRound, Clock, Plus } from "lucide-react";
3342
- import { jsx as jsx65, jsxs as jsxs32 } from "react/jsx-runtime";
3403
+ import { jsx as jsx66, jsxs as jsxs33 } from "react/jsx-runtime";
3343
3404
  var segmentChipVariants = cva9(
3344
3405
  "inline-flex items-center gap-1.5 rounded-lg border px-2.5 py-1 text-sm font-medium leading-tight",
3345
3406
  {
@@ -3363,8 +3424,8 @@ var kindIcons = {
3363
3424
  var SegmentChip = React55.forwardRef(
3364
3425
  ({ kind, resource, icon, hideIcon = false, className, ...props }, ref) => {
3365
3426
  const Icon = icon ?? kindIcons[kind ?? "granted"];
3366
- return /* @__PURE__ */ jsxs32("span", { ref, className: cn(segmentChipVariants({ kind }), className), ...props, children: [
3367
- !hideIcon && /* @__PURE__ */ jsx65(Icon, { className: "size-3.5 shrink-0 opacity-90", "aria-hidden": "true" }),
3427
+ return /* @__PURE__ */ jsxs33("span", { ref, className: cn(segmentChipVariants({ kind }), className), ...props, children: [
3428
+ !hideIcon && /* @__PURE__ */ jsx66(Icon, { className: "size-3.5 shrink-0 opacity-90", "aria-hidden": "true" }),
3368
3429
  resource
3369
3430
  ] });
3370
3431
  }
@@ -3374,7 +3435,7 @@ SegmentChip.displayName = "SegmentChip";
3374
3435
  // src/components/connection-card.tsx
3375
3436
  import * as React56 from "react";
3376
3437
  import { AlertTriangle, ChevronDown as ChevronDown4 } from "lucide-react";
3377
- import { Fragment as Fragment5, jsx as jsx66, jsxs as jsxs33 } from "react/jsx-runtime";
3438
+ import { Fragment as Fragment5, jsx as jsx67, jsxs as jsxs34 } from "react/jsx-runtime";
3378
3439
  var authLabels = { app: "App", oauth: "OAuth", token: "token" };
3379
3440
  var statusMeta = {
3380
3441
  connected: { label: "Connected", badge: "success", dot: "success" },
@@ -3405,7 +3466,7 @@ var ConnectionCard = React56.forwardRef(
3405
3466
  }, ref) => {
3406
3467
  const meta = statusMeta[status];
3407
3468
  const connected = status !== "disconnected";
3408
- const glyphBox = /* @__PURE__ */ jsx66(
3469
+ const glyphBox = /* @__PURE__ */ jsx67(
3409
3470
  "div",
3410
3471
  {
3411
3472
  "aria-hidden": "true",
@@ -3413,51 +3474,51 @@ var ConnectionCard = React56.forwardRef(
3413
3474
  children: glyph ?? monogram(name)
3414
3475
  }
3415
3476
  );
3416
- const identity = /* @__PURE__ */ jsxs33("div", { className: "min-w-0", children: [
3417
- /* @__PURE__ */ jsx66("p", { className: "truncate text-sm font-semibold text-text-primary", children: name }),
3418
- /* @__PURE__ */ jsxs33("div", { className: "mt-0.5 flex flex-wrap gap-1", children: [
3419
- /* @__PURE__ */ jsx66(Badge, { variant: "secondary", children: scope }),
3420
- /* @__PURE__ */ jsx66(Badge, { variant: "secondary", children: authLabels[auth] })
3477
+ const identity = /* @__PURE__ */ jsxs34("div", { className: "min-w-0", children: [
3478
+ /* @__PURE__ */ jsx67("p", { className: "truncate text-sm font-semibold text-text-primary", children: name }),
3479
+ /* @__PURE__ */ jsxs34("div", { className: "mt-0.5 flex flex-wrap gap-1", children: [
3480
+ /* @__PURE__ */ jsx67(Badge, { variant: "secondary", children: scope }),
3481
+ /* @__PURE__ */ jsx67(Badge, { variant: "secondary", children: authLabels[auth] })
3421
3482
  ] })
3422
3483
  ] });
3423
- const statusBadge = /* @__PURE__ */ jsxs33(Badge, { variant: meta.badge, className: "gap-1.5", children: [
3424
- /* @__PURE__ */ jsx66(StatusDot, { status: meta.dot, size: "sm" }),
3484
+ const statusBadge = /* @__PURE__ */ jsxs34(Badge, { variant: meta.badge, className: "gap-1.5", children: [
3485
+ /* @__PURE__ */ jsx67(StatusDot, { status: meta.dot, size: "sm" }),
3425
3486
  statusLabel ?? meta.label
3426
3487
  ] });
3427
- const accessNote = access ? /* @__PURE__ */ jsxs33(
3488
+ const accessNote = access ? /* @__PURE__ */ jsxs34(
3428
3489
  "div",
3429
3490
  {
3430
3491
  role: "note",
3431
3492
  className: "flex items-start gap-2 border-t border-border-subtle bg-bg-warning-subtle px-4 py-2.5 text-xs font-medium text-text-warning",
3432
3493
  children: [
3433
- /* @__PURE__ */ jsx66(AlertTriangle, { className: "mt-0.5 size-3.5 shrink-0", "aria-hidden": "true" }),
3434
- /* @__PURE__ */ jsx66("span", { children: access })
3494
+ /* @__PURE__ */ jsx67(AlertTriangle, { className: "mt-0.5 size-3.5 shrink-0", "aria-hidden": "true" }),
3495
+ /* @__PURE__ */ jsx67("span", { children: access })
3435
3496
  ]
3436
3497
  }
3437
3498
  ) : null;
3438
3499
  const footerAction = collapsible ? action : connected && action;
3439
- const footer = grantedCount !== void 0 || footerAction ? /* @__PURE__ */ jsxs33("div", { className: "flex items-center justify-between border-t border-border-subtle px-4 py-3", children: [
3440
- /* @__PURE__ */ jsx66("span", { className: "text-sm text-text-secondary", children: grantedCount !== void 0 ? /* @__PURE__ */ jsxs33(Fragment5, { children: [
3500
+ const footer = grantedCount !== void 0 || footerAction ? /* @__PURE__ */ jsxs34("div", { className: "flex items-center justify-between border-t border-border-subtle px-4 py-3", children: [
3501
+ /* @__PURE__ */ jsx67("span", { className: "text-sm text-text-secondary", children: grantedCount !== void 0 ? /* @__PURE__ */ jsxs34(Fragment5, { children: [
3441
3502
  "Granted to ",
3442
- /* @__PURE__ */ jsx66("span", { className: "font-semibold text-text-primary", children: grantedCount }),
3503
+ /* @__PURE__ */ jsx67("span", { className: "font-semibold text-text-primary", children: grantedCount }),
3443
3504
  " ",
3444
3505
  grantedCount === 1 ? "product" : "products"
3445
- ] }) : /* @__PURE__ */ jsx66("span", { className: "text-text-tertiary", children: "Not granted to any product yet" }) }),
3506
+ ] }) : /* @__PURE__ */ jsx67("span", { className: "text-text-tertiary", children: "Not granted to any product yet" }) }),
3446
3507
  footerAction
3447
3508
  ] }) : null;
3448
- const drawer = children ? /* @__PURE__ */ jsx66("div", { "data-slot": "drawer", className: "border-t border-border-subtle", children }) : null;
3509
+ const drawer = children ? /* @__PURE__ */ jsx67("div", { "data-slot": "drawer", className: "border-t border-border-subtle", children }) : null;
3449
3510
  if (!collapsible) {
3450
- return /* @__PURE__ */ jsxs33(
3511
+ return /* @__PURE__ */ jsxs34(
3451
3512
  Card,
3452
3513
  {
3453
3514
  ref,
3454
3515
  className: cn(status === "disconnected" && "border-dashed border-border-default", className),
3455
3516
  ...props,
3456
3517
  children: [
3457
- /* @__PURE__ */ jsxs33("div", { className: "flex items-center gap-3 p-4", children: [
3518
+ /* @__PURE__ */ jsxs34("div", { className: "flex items-center gap-3 p-4", children: [
3458
3519
  glyphBox,
3459
3520
  identity,
3460
- /* @__PURE__ */ jsx66("div", { className: "ml-auto shrink-0", children: connected ? statusBadge : action })
3521
+ /* @__PURE__ */ jsx67("div", { className: "ml-auto shrink-0", children: connected ? statusBadge : action })
3461
3522
  ] }),
3462
3523
  accessNote,
3463
3524
  footer,
@@ -3466,7 +3527,7 @@ var ConnectionCard = React56.forwardRef(
3466
3527
  }
3467
3528
  );
3468
3529
  }
3469
- return /* @__PURE__ */ jsx66(Collapsible, { defaultOpen, open, onOpenChange, children: /* @__PURE__ */ jsxs33(
3530
+ return /* @__PURE__ */ jsx67(Collapsible, { defaultOpen, open, onOpenChange, children: /* @__PURE__ */ jsxs34(
3470
3531
  Card,
3471
3532
  {
3472
3533
  ref,
@@ -3477,7 +3538,7 @@ var ConnectionCard = React56.forwardRef(
3477
3538
  ),
3478
3539
  ...props,
3479
3540
  children: [
3480
- /* @__PURE__ */ jsx66(CollapsibleTrigger2, { asChild: true, children: /* @__PURE__ */ jsxs33(
3541
+ /* @__PURE__ */ jsx67(CollapsibleTrigger2, { asChild: true, children: /* @__PURE__ */ jsxs34(
3481
3542
  "button",
3482
3543
  {
3483
3544
  type: "button",
@@ -3485,9 +3546,9 @@ var ConnectionCard = React56.forwardRef(
3485
3546
  children: [
3486
3547
  glyphBox,
3487
3548
  identity,
3488
- /* @__PURE__ */ jsxs33("div", { className: "ml-auto flex shrink-0 items-center gap-2", children: [
3549
+ /* @__PURE__ */ jsxs34("div", { className: "ml-auto flex shrink-0 items-center gap-2", children: [
3489
3550
  statusBadge,
3490
- /* @__PURE__ */ jsx66(
3551
+ /* @__PURE__ */ jsx67(
3491
3552
  ChevronDown4,
3492
3553
  {
3493
3554
  "aria-hidden": "true",
@@ -3498,7 +3559,7 @@ var ConnectionCard = React56.forwardRef(
3498
3559
  ]
3499
3560
  }
3500
3561
  ) }),
3501
- /* @__PURE__ */ jsxs33(CollapsibleContent2, { children: [
3562
+ /* @__PURE__ */ jsxs34(CollapsibleContent2, { children: [
3502
3563
  accessNote,
3503
3564
  footer,
3504
3565
  drawer
@@ -3512,7 +3573,7 @@ ConnectionCard.displayName = "ConnectionCard";
3512
3573
 
3513
3574
  // src/components/request-row.tsx
3514
3575
  import * as React57 from "react";
3515
- import { Fragment as Fragment6, jsx as jsx67, jsxs as jsxs34 } from "react/jsx-runtime";
3576
+ import { Fragment as Fragment6, jsx as jsx68, jsxs as jsxs35 } from "react/jsx-runtime";
3516
3577
  function monogram2(name) {
3517
3578
  return name.replace(/[^a-zA-Z0-9 ]/g, " ").split(/\s+/).filter(Boolean).slice(0, 2).map((w) => w[0].toUpperCase()).join("");
3518
3579
  }
@@ -3521,22 +3582,22 @@ var RequestRow = React57.forwardRef(
3521
3582
  let controls = action;
3522
3583
  if (controls === void 0) {
3523
3584
  if (surface === "org" && state2 === "pending") {
3524
- controls = /* @__PURE__ */ jsxs34(Fragment6, { children: [
3525
- /* @__PURE__ */ jsx67(Button, { variant: "outline", size: "sm", onClick: onDeny, children: "Deny" }),
3526
- /* @__PURE__ */ jsx67(Button, { size: "sm", onClick: onApprove, children: "Approve" })
3585
+ controls = /* @__PURE__ */ jsxs35(Fragment6, { children: [
3586
+ /* @__PURE__ */ jsx68(Button, { variant: "outline", size: "sm", onClick: onDeny, children: "Deny" }),
3587
+ /* @__PURE__ */ jsx68(Button, { size: "sm", onClick: onApprove, children: "Approve" })
3527
3588
  ] });
3528
3589
  } else if (state2 === "available") {
3529
- controls = /* @__PURE__ */ jsx67(Button, { size: "sm", onClick: onRequest, children: "Request" });
3590
+ controls = /* @__PURE__ */ jsx68(Button, { size: "sm", onClick: onRequest, children: "Request" });
3530
3591
  } else if (state2 === "pending") {
3531
- controls = /* @__PURE__ */ jsxs34(Badge, { variant: "secondary", className: "gap-1.5", children: [
3532
- /* @__PURE__ */ jsx67(StatusDot, { status: "neutral", size: "sm" }),
3592
+ controls = /* @__PURE__ */ jsxs35(Badge, { variant: "secondary", className: "gap-1.5", children: [
3593
+ /* @__PURE__ */ jsx68(StatusDot, { status: "neutral", size: "sm" }),
3533
3594
  "Pending"
3534
3595
  ] });
3535
3596
  } else if (state2 === "granted") {
3536
- controls = /* @__PURE__ */ jsx67(SegmentChip, { kind: "granted", resource: grantedResource ?? "a segment" });
3597
+ controls = /* @__PURE__ */ jsx68(SegmentChip, { kind: "granted", resource: grantedResource ?? "a segment" });
3537
3598
  }
3538
3599
  }
3539
- return /* @__PURE__ */ jsxs34(
3600
+ return /* @__PURE__ */ jsxs35(
3540
3601
  "div",
3541
3602
  {
3542
3603
  ref,
@@ -3546,7 +3607,7 @@ var RequestRow = React57.forwardRef(
3546
3607
  ),
3547
3608
  ...props,
3548
3609
  children: [
3549
- /* @__PURE__ */ jsx67(
3610
+ /* @__PURE__ */ jsx68(
3550
3611
  "div",
3551
3612
  {
3552
3613
  "aria-hidden": "true",
@@ -3554,17 +3615,127 @@ var RequestRow = React57.forwardRef(
3554
3615
  children: glyph ?? monogram2(name)
3555
3616
  }
3556
3617
  ),
3557
- /* @__PURE__ */ jsxs34("div", { className: "min-w-0", children: [
3558
- /* @__PURE__ */ jsx67("p", { className: "truncate text-sm font-semibold text-text-primary", children: name }),
3559
- subtitle && /* @__PURE__ */ jsx67("p", { className: "truncate text-xs text-text-tertiary", children: subtitle })
3618
+ /* @__PURE__ */ jsxs35("div", { className: "min-w-0", children: [
3619
+ /* @__PURE__ */ jsx68("p", { className: "truncate text-sm font-semibold text-text-primary", children: name }),
3620
+ subtitle && /* @__PURE__ */ jsx68("p", { className: "truncate text-xs text-text-tertiary", children: subtitle })
3560
3621
  ] }),
3561
- /* @__PURE__ */ jsx67("div", { className: "ml-auto flex shrink-0 items-center gap-2", children: controls })
3622
+ /* @__PURE__ */ jsx68("div", { className: "ml-auto flex shrink-0 items-center gap-2", children: controls })
3562
3623
  ]
3563
3624
  }
3564
3625
  );
3565
3626
  }
3566
3627
  );
3567
3628
  RequestRow.displayName = "RequestRow";
3629
+
3630
+ // src/components/feedback-widget.tsx
3631
+ import * as React58 from "react";
3632
+ import { MessageSquare, Loader2 as Loader22, CheckCircle2 } from "lucide-react";
3633
+ import { jsx as jsx69, jsxs as jsxs36 } from "react/jsx-runtime";
3634
+ var TITLE_MAX = 256;
3635
+ var DETAILS_MAX = 65536;
3636
+ var DEFAULT_LABELS = {
3637
+ trigger: "Feedback",
3638
+ title: "Send feedback",
3639
+ titleField: "Title",
3640
+ detailsField: "Details",
3641
+ submit: "Send feedback",
3642
+ success: "Thanks! Your feedback was sent.",
3643
+ error: "Couldn't send feedback. Please try again."
3644
+ };
3645
+ function FeedbackWidget({ onSubmit, labels, className }) {
3646
+ const l = { ...DEFAULT_LABELS, ...labels };
3647
+ const uid = React58.useId();
3648
+ const titleId = `${uid}-title`;
3649
+ const detailsId = `${uid}-details`;
3650
+ const titleErrId = `${uid}-title-error`;
3651
+ const detailsErrId = `${uid}-details-error`;
3652
+ const [open, setOpen] = React58.useState(false);
3653
+ const [status, setStatus] = React58.useState("idle");
3654
+ const [title, setTitle] = React58.useState("");
3655
+ const [details, setDetails] = React58.useState("");
3656
+ const titleTooLong = title.length > TITLE_MAX;
3657
+ const detailsTooLong = details.length > DETAILS_MAX;
3658
+ const titleEmpty = title.trim().length === 0;
3659
+ const detailsEmpty = details.trim().length === 0;
3660
+ const valid = !titleEmpty && !detailsEmpty && !titleTooLong && !detailsTooLong;
3661
+ const submitting = status === "submitting";
3662
+ const changeOpen = (next) => {
3663
+ if (submitting) return;
3664
+ setOpen(next);
3665
+ if (!next) setStatus("idle");
3666
+ };
3667
+ const handleSubmit = async (e) => {
3668
+ e.preventDefault();
3669
+ if (!valid || submitting) return;
3670
+ setStatus("submitting");
3671
+ try {
3672
+ await onSubmit({ title, details });
3673
+ setStatus("success");
3674
+ setTitle("");
3675
+ setDetails("");
3676
+ } catch {
3677
+ setStatus("error");
3678
+ }
3679
+ };
3680
+ return /* @__PURE__ */ jsxs36(Popover, { open, onOpenChange: changeOpen, children: [
3681
+ /* @__PURE__ */ jsx69("div", { className: cn("fixed bottom-4 right-4 z-50", className), children: /* @__PURE__ */ jsx69(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs36(Button, { "aria-label": l.trigger, children: [
3682
+ /* @__PURE__ */ jsx69(MessageSquare, { className: "size-4", "aria-hidden": "true" }),
3683
+ l.trigger
3684
+ ] }) }) }),
3685
+ /* @__PURE__ */ jsx69(PopoverContent, { align: "end", side: "top", className: "w-80", children: status === "success" ? /* @__PURE__ */ jsxs36("div", { className: "flex flex-col items-center gap-3 py-2 text-center", children: [
3686
+ /* @__PURE__ */ jsx69(CheckCircle2, { className: "size-8 text-text-success", "aria-hidden": "true" }),
3687
+ /* @__PURE__ */ jsx69("p", { role: "status", className: "text-sm text-text-primary", children: l.success }),
3688
+ /* @__PURE__ */ jsx69(Button, { variant: "outline", size: "sm", onClick: () => changeOpen(false), children: "Close" })
3689
+ ] }) : /* @__PURE__ */ jsxs36("form", { onSubmit: handleSubmit, className: "flex flex-col gap-3", children: [
3690
+ /* @__PURE__ */ jsx69("p", { className: "text-sm font-medium text-text-primary", children: l.title }),
3691
+ /* @__PURE__ */ jsxs36("div", { className: "flex flex-col gap-1.5", children: [
3692
+ /* @__PURE__ */ jsx69(Label2, { htmlFor: titleId, children: l.titleField }),
3693
+ /* @__PURE__ */ jsx69(
3694
+ Input,
3695
+ {
3696
+ id: titleId,
3697
+ value: title,
3698
+ onChange: (e) => setTitle(e.target.value),
3699
+ disabled: submitting,
3700
+ "aria-invalid": titleTooLong || void 0,
3701
+ "aria-describedby": titleTooLong ? titleErrId : void 0
3702
+ }
3703
+ ),
3704
+ titleTooLong && /* @__PURE__ */ jsxs36("p", { id: titleErrId, className: "text-xs text-text-danger", children: [
3705
+ l.titleField,
3706
+ " must be ",
3707
+ TITLE_MAX,
3708
+ " characters or fewer."
3709
+ ] })
3710
+ ] }),
3711
+ /* @__PURE__ */ jsxs36("div", { className: "flex flex-col gap-1.5", children: [
3712
+ /* @__PURE__ */ jsx69(Label2, { htmlFor: detailsId, children: l.detailsField }),
3713
+ /* @__PURE__ */ jsx69(
3714
+ Textarea,
3715
+ {
3716
+ id: detailsId,
3717
+ value: details,
3718
+ onChange: (e) => setDetails(e.target.value),
3719
+ disabled: submitting,
3720
+ "aria-invalid": detailsTooLong || void 0,
3721
+ "aria-describedby": detailsTooLong ? detailsErrId : void 0
3722
+ }
3723
+ ),
3724
+ detailsTooLong && /* @__PURE__ */ jsxs36("p", { id: detailsErrId, className: "text-xs text-text-danger", children: [
3725
+ l.detailsField,
3726
+ " must be ",
3727
+ DETAILS_MAX,
3728
+ " characters or fewer."
3729
+ ] })
3730
+ ] }),
3731
+ status === "error" && /* @__PURE__ */ jsx69(InlineError, { children: l.error }),
3732
+ /* @__PURE__ */ jsxs36(Button, { type: "submit", disabled: !valid || submitting, children: [
3733
+ submitting && /* @__PURE__ */ jsx69(Loader22, { className: "size-4 animate-spin", "aria-hidden": "true" }),
3734
+ l.submit
3735
+ ] })
3736
+ ] }) })
3737
+ ] });
3738
+ }
3568
3739
  export {
3569
3740
  Accordion,
3570
3741
  AccordionContent,
@@ -3684,6 +3855,7 @@ export {
3684
3855
  EmptyState,
3685
3856
  ExtensionIcon,
3686
3857
  ExtensionLink,
3858
+ FeedbackWidget,
3687
3859
  Form,
3688
3860
  FormControl,
3689
3861
  FormDescription,
@@ -3762,6 +3934,7 @@ export {
3762
3934
  SheetPortal,
3763
3935
  SheetTitle,
3764
3936
  SheetTrigger,
3937
+ SidebarBackHeader,
3765
3938
  SidebarNav,
3766
3939
  SidebarNavLink,
3767
3940
  SidebarProductHeader,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lessly/ui",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "Lessly design system — shared UI primitives, tokens, and theme",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@10.30.3",