@lessly/ui 0.14.0 → 0.15.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
@@ -1352,6 +1352,15 @@ interface NotificationProduct {
1352
1352
  }
1353
1353
  declare const severityLabels: Record<NotificationSeverity, string>;
1354
1354
  declare function severityBadgeVariant(severity: NotificationSeverity): 'destructive' | 'warning' | 'secondary';
1355
+ /** Per-severity dwell in seconds. `Infinity` means the toast stays until dismissed. */
1356
+ type NotificationToastDwell = Record<NotificationSeverity, number>;
1357
+ /**
1358
+ * Toasts peek, then tuck away — the record behind the bell is the durable copy, so
1359
+ * nothing is lost when a card leaves. Critical is the exception: it stays in the
1360
+ * corner until it is handled, because for an incident the persistent toast IS the
1361
+ * escalation. Timing lives in the toaster; this is only the default table.
1362
+ */
1363
+ declare const TOAST_DWELL: NotificationToastDwell;
1355
1364
  /**
1356
1365
  * Reads a stamp as a relative age. `now` is injectable so the components stay
1357
1366
  * testable and consumers can substitute an absolute or localized formatter; the
@@ -1428,4 +1437,40 @@ interface NotificationSettingsProps {
1428
1437
  }
1429
1438
  declare const NotificationSettings: React$1.ForwardRefExoticComponent<NotificationSettingsProps & React$1.RefAttributes<HTMLDivElement>>;
1430
1439
 
1431
- 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, Code, CodeBlock, type CodeBlockProps, type CodeLang, type CodeProps, 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, type CreateProductSubmit, CreateProductWindow, type CreateProductWindowOrganization, type CreateProductWindowProduct, type CreateProductWindowProps, 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, FeedbackButton, type FeedbackButtonLabels, type FeedbackButtonProps, 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, type NotifClass, type NotificationAction, NotificationBell, type NotificationBellProps, NotificationCenter, type NotificationCenterProps, type NotificationClass, type NotificationDeepLink, type NotificationItem, type NotificationMute, type NotificationPreferences, type NotificationProduct, NotificationSettings, type NotificationSettingsProps, type NotificationSeverity, type NotificationSubscription, type NotificationThreshold, OrgProductSwitcher, type OrgProductSwitcherAction, type OrgProductSwitcherItem, type OrgProductSwitcherProps, 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, type Severity, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarBackHeader, type SidebarBackHeaderProps, SidebarNav, SidebarNavLink, type SidebarNavLinkProps, type SidebarNavProps, SidebarProductHeader, type SidebarProductHeaderProps, SignInScreen, type SignInScreenProps, type SignInScreenState, 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, formatRelativeAge, isKnownExtensionIcon, isNotificationSettled, navigationMenuTriggerStyle, segmentChipVariants, severityBadgeVariant, severityLabels, statusDotVariants, toggleVariants, useCarousel, useFormField, useIsMobile, useSidebar, useTheme };
1440
+ interface NotificationToastProps {
1441
+ item: NotificationItem;
1442
+ /** Provenance shown once per run of same-source cards. Default `true`. */
1443
+ showSource?: boolean;
1444
+ /** A short state line under the body, e.g. "Awaiting your decision — expires in 20s." */
1445
+ note?: React$1.ReactNode;
1446
+ onItemClick?(item: NotificationItem): void;
1447
+ onAction?(action: NotificationAction, item: NotificationItem): void;
1448
+ onDismiss?(item: NotificationItem): void;
1449
+ /** Accessible label for the close button. Default `"Dismiss"`. */
1450
+ dismissLabel?: string;
1451
+ className?: string;
1452
+ }
1453
+ declare const NotificationToast: React$1.ForwardRefExoticComponent<NotificationToastProps & React$1.RefAttributes<HTMLDivElement>>;
1454
+
1455
+ type NotificationToasterPosition = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
1456
+ interface NotificationToasterProps {
1457
+ /** The live queue. The consumer decides what becomes a toast at all. */
1458
+ items: NotificationItem[];
1459
+ /** Per-severity dwell in seconds, merged over `TOAST_DWELL`. `Infinity` never hides. */
1460
+ dwell?: Partial<NotificationToastDwell>;
1461
+ /** Most cards on screen at once. Default `4`. */
1462
+ max?: number;
1463
+ position?: NotificationToasterPosition;
1464
+ /** Freeze every countdown while the pointer is over the stack. Default `true`. */
1465
+ pauseOnHover?: boolean;
1466
+ /** Fires on auto-hide and on the close button alike — the item leaves the same way. */
1467
+ onDismiss?(id: string): void;
1468
+ onItemClick?(item: NotificationItem): void;
1469
+ onAction?(action: NotificationAction, item: NotificationItem): void;
1470
+ /** Per-item state line, e.g. a TTL countdown the consumer already tracks. */
1471
+ renderNote?(item: NotificationItem): React$1.ReactNode;
1472
+ className?: string;
1473
+ }
1474
+ declare const NotificationToaster: React$1.ForwardRefExoticComponent<NotificationToasterProps & React$1.RefAttributes<HTMLDivElement>>;
1475
+
1476
+ 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, Code, CodeBlock, type CodeBlockProps, type CodeLang, type CodeProps, 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, type CreateProductSubmit, CreateProductWindow, type CreateProductWindowOrganization, type CreateProductWindowProduct, type CreateProductWindowProps, 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, FeedbackButton, type FeedbackButtonLabels, type FeedbackButtonProps, 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, type NotifClass, type NotificationAction, NotificationBell, type NotificationBellProps, NotificationCenter, type NotificationCenterProps, type NotificationClass, type NotificationDeepLink, type NotificationItem, type NotificationMute, type NotificationPreferences, type NotificationProduct, NotificationSettings, type NotificationSettingsProps, type NotificationSeverity, type NotificationSubscription, type NotificationThreshold, NotificationToast, type NotificationToastDwell, type NotificationToastProps, NotificationToaster, type NotificationToasterPosition, type NotificationToasterProps, OrgProductSwitcher, type OrgProductSwitcherAction, type OrgProductSwitcherItem, type OrgProductSwitcherProps, 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, type Severity, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, SidebarBackHeader, type SidebarBackHeaderProps, SidebarNav, SidebarNavLink, type SidebarNavLinkProps, type SidebarNavProps, SidebarProductHeader, type SidebarProductHeaderProps, SignInScreen, type SignInScreenProps, type SignInScreenState, Skeleton, Slider, StatCard, type StatCardProps, StatusDot, type StatusDotProps, Switch, type SwitchProps, TOAST_DWELL, 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, formatRelativeAge, isKnownExtensionIcon, isNotificationSettled, navigationMenuTriggerStyle, segmentChipVariants, severityBadgeVariant, severityLabels, statusDotVariants, toggleVariants, useCarousel, useFormField, useIsMobile, useSidebar, useTheme };
package/dist/index.js CHANGED
@@ -4285,6 +4285,11 @@ var severityBadgeVariants = {
4285
4285
  function severityBadgeVariant(severity) {
4286
4286
  return severityBadgeVariants[severity];
4287
4287
  }
4288
+ var TOAST_DWELL = {
4289
+ fyi: 6,
4290
+ important: 8,
4291
+ critical: Infinity
4292
+ };
4288
4293
  function formatRelativeAge(createdAt, now = /* @__PURE__ */ new Date()) {
4289
4294
  const then = createdAt instanceof Date ? createdAt : new Date(createdAt);
4290
4295
  const seconds = Math.max(0, Math.floor((now.getTime() - then.getTime()) / 1e3));
@@ -4871,6 +4876,184 @@ var NotificationSettings = React63.forwardRef(
4871
4876
  }
4872
4877
  );
4873
4878
  NotificationSettings.displayName = "NotificationSettings";
4879
+
4880
+ // src/components/notification-toast.tsx
4881
+ import * as React64 from "react";
4882
+ import { X as X3 } from "lucide-react";
4883
+ import { jsx as jsx77, jsxs as jsxs44 } from "react/jsx-runtime";
4884
+ var chipBase2 = "rounded-lg px-2.5 py-1 text-sm font-medium transition-colors";
4885
+ var chipPrimary = "bg-bg-brand text-text-on-brand hover:bg-bg-brand-hover";
4886
+ var chipDestructive = "bg-bg-elevated text-text-danger hover:bg-bg-surface";
4887
+ var linkAction = "text-sm font-semibold text-text-brand transition-colors hover:text-text-primary";
4888
+ var NotificationToast = React64.forwardRef(
4889
+ ({
4890
+ item,
4891
+ showSource = true,
4892
+ note,
4893
+ onItemClick,
4894
+ onAction,
4895
+ onDismiss,
4896
+ dismissLabel = "Dismiss",
4897
+ className
4898
+ }, ref) => {
4899
+ const actions = item.actions ?? [];
4900
+ return /* @__PURE__ */ jsxs44(
4901
+ "div",
4902
+ {
4903
+ ref,
4904
+ role: "status",
4905
+ "aria-live": item.severity === "critical" ? "assertive" : "polite",
4906
+ className: cn(
4907
+ "rounded-2xl border border-border-subtle bg-bg-elevated p-4 shadow-(--menu-shadow)",
4908
+ className
4909
+ ),
4910
+ children: [
4911
+ /* @__PURE__ */ jsxs44("div", { className: "flex items-center gap-2", children: [
4912
+ showSource && /* @__PURE__ */ jsx77("span", { className: "text-xs font-semibold uppercase tracking-[0.09em] text-text-secondary", children: item.source }),
4913
+ /* @__PURE__ */ jsx77(Badge, { variant: severityBadgeVariant(item.severity), children: severityLabels[item.severity] }),
4914
+ onDismiss && /* @__PURE__ */ jsx77(
4915
+ "button",
4916
+ {
4917
+ type: "button",
4918
+ "aria-label": dismissLabel,
4919
+ onClick: () => onDismiss(item),
4920
+ className: "-mr-1 ml-auto flex size-5 shrink-0 items-center justify-center rounded text-text-tertiary transition-colors hover:bg-bg-surface hover:text-text-primary",
4921
+ children: /* @__PURE__ */ jsx77(X3, { className: "size-3.5", "aria-hidden": "true" })
4922
+ }
4923
+ )
4924
+ ] }),
4925
+ onItemClick ? /* @__PURE__ */ jsx77(
4926
+ "button",
4927
+ {
4928
+ type: "button",
4929
+ onClick: () => onItemClick(item),
4930
+ className: "mt-1 block text-left text-sm font-semibold leading-snug text-text-primary underline-offset-2 hover:underline",
4931
+ children: item.title
4932
+ }
4933
+ ) : /* @__PURE__ */ jsx77("p", { className: "mt-1 text-sm font-semibold leading-snug text-text-primary", children: item.title }),
4934
+ item.body && /* @__PURE__ */ jsx77("p", { className: "mt-0.5 text-sm leading-snug text-text-secondary", children: item.body }),
4935
+ note && /* @__PURE__ */ jsx77("p", { className: "mt-1.5 text-xs font-medium text-text-warning", children: note }),
4936
+ actions.length > 0 && /* @__PURE__ */ jsx77("div", { className: "mt-2.5 flex flex-wrap items-center gap-2", children: actions.map((action) => {
4937
+ const variant = action.variant ?? "link";
4938
+ return /* @__PURE__ */ jsx77(
4939
+ "button",
4940
+ {
4941
+ type: "button",
4942
+ onClick: () => onAction?.(action, item),
4943
+ className: variant === "primary" ? cn(chipBase2, chipPrimary) : variant === "destructive" ? cn(chipBase2, chipDestructive) : linkAction,
4944
+ children: action.label
4945
+ },
4946
+ action.id
4947
+ );
4948
+ }) })
4949
+ ]
4950
+ }
4951
+ );
4952
+ }
4953
+ );
4954
+ NotificationToast.displayName = "NotificationToast";
4955
+
4956
+ // src/components/notification-toaster.tsx
4957
+ import * as React65 from "react";
4958
+ import { jsx as jsx78 } from "react/jsx-runtime";
4959
+ var positions = {
4960
+ "bottom-right": "bottom-6 right-6 flex-col",
4961
+ "bottom-left": "bottom-6 left-6 flex-col",
4962
+ "top-right": "top-6 right-6 flex-col-reverse",
4963
+ "top-left": "top-6 left-6 flex-col-reverse"
4964
+ };
4965
+ var NotificationToaster = React65.forwardRef(
4966
+ ({
4967
+ items,
4968
+ dwell,
4969
+ max = 4,
4970
+ position = "bottom-right",
4971
+ pauseOnHover = true,
4972
+ onDismiss,
4973
+ onItemClick,
4974
+ onAction,
4975
+ renderNote,
4976
+ className
4977
+ }, ref) => {
4978
+ const shown = items.slice(0, max);
4979
+ const [paused, setPaused] = React65.useState(false);
4980
+ const onDismissRef = React65.useRef(onDismiss);
4981
+ onDismissRef.current = onDismiss;
4982
+ const fyiDwell = dwell?.fyi;
4983
+ const importantDwell = dwell?.important;
4984
+ const criticalDwell = dwell?.critical;
4985
+ const remaining = React65.useRef(/* @__PURE__ */ new Map());
4986
+ const liveIds = shown.map((item) => `${item.id}:${item.severity}`).join(" ");
4987
+ React65.useEffect(() => {
4988
+ const owedById = remaining.current;
4989
+ const dwellSeconds = {
4990
+ fyi: fyiDwell ?? TOAST_DWELL.fyi,
4991
+ important: importantDwell ?? TOAST_DWELL.important,
4992
+ critical: criticalDwell ?? TOAST_DWELL.critical
4993
+ };
4994
+ const live = liveIds === "" ? [] : liveIds.split(" ");
4995
+ const ids = new Set(live.map((entry) => entry.slice(0, entry.lastIndexOf(":"))));
4996
+ for (const id of owedById.keys()) {
4997
+ if (!ids.has(id)) owedById.delete(id);
4998
+ }
4999
+ for (const entry of live) {
5000
+ const at = entry.lastIndexOf(":");
5001
+ const id = entry.slice(0, at);
5002
+ const severity = entry.slice(at + 1);
5003
+ if (!owedById.has(id)) {
5004
+ owedById.set(id, dwellSeconds[severity] * 1e3);
5005
+ }
5006
+ }
5007
+ if (paused) return;
5008
+ const startedAt = Date.now();
5009
+ const timers = [];
5010
+ for (const [id, owed] of owedById) {
5011
+ if (!Number.isFinite(owed)) continue;
5012
+ timers.push(
5013
+ setTimeout(() => {
5014
+ owedById.delete(id);
5015
+ onDismissRef.current?.(id);
5016
+ }, owed)
5017
+ );
5018
+ }
5019
+ return () => {
5020
+ timers.forEach(clearTimeout);
5021
+ const elapsed = Date.now() - startedAt;
5022
+ for (const [id, owed] of owedById) {
5023
+ if (Number.isFinite(owed)) owedById.set(id, Math.max(0, owed - elapsed));
5024
+ }
5025
+ };
5026
+ }, [liveIds, paused, fyiDwell, importantDwell, criticalDwell]);
5027
+ if (shown.length === 0) return null;
5028
+ return /* @__PURE__ */ jsx78(
5029
+ "div",
5030
+ {
5031
+ ref,
5032
+ role: "region",
5033
+ "aria-label": "Notifications",
5034
+ onMouseEnter: pauseOnHover ? () => setPaused(true) : void 0,
5035
+ onMouseLeave: pauseOnHover ? () => setPaused(false) : void 0,
5036
+ className: cn(
5037
+ "pointer-events-none fixed z-50 flex w-[350px] gap-3",
5038
+ positions[position],
5039
+ className
5040
+ ),
5041
+ children: shown.map((item, i) => /* @__PURE__ */ jsx78("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx78(
5042
+ NotificationToast,
5043
+ {
5044
+ item,
5045
+ showSource: i === 0 || shown[i - 1].source !== item.source,
5046
+ note: renderNote?.(item),
5047
+ onItemClick,
5048
+ onAction,
5049
+ onDismiss: onDismiss ? () => onDismiss(item.id) : void 0
5050
+ }
5051
+ ) }, item.id))
5052
+ }
5053
+ );
5054
+ }
5055
+ );
5056
+ NotificationToaster.displayName = "NotificationToaster";
4874
5057
  export {
4875
5058
  Accordion,
4876
5059
  AccordionContent,
@@ -5044,6 +5227,8 @@ export {
5044
5227
  NotificationBell,
5045
5228
  NotificationCenter,
5046
5229
  NotificationSettings,
5230
+ NotificationToast,
5231
+ NotificationToaster,
5047
5232
  OrgProductSwitcher,
5048
5233
  Pagination,
5049
5234
  PaginationContent,
@@ -5086,6 +5271,7 @@ export {
5086
5271
  StatCard,
5087
5272
  StatusDot,
5088
5273
  Switch,
5274
+ TOAST_DWELL,
5089
5275
  Table,
5090
5276
  TableBody,
5091
5277
  TableCaption,
package/dist/styles.css CHANGED
@@ -82,6 +82,7 @@
82
82
  --shadow-md: 0 2px 8px rgba(0,0,0,0.5), 0 1px 2px rgba(0,0,0,0.4);
83
83
  --shadow-lg: 0 8px 24px rgba(0,0,0,0.6), 0 2px 8px rgba(0,0,0,0.4);
84
84
  --shadow-xl: 0 16px 48px rgba(0,0,0,0.7), 0 4px 12px rgba(0,0,0,0.5);
85
+ --shadow-overlay: 0 8px 24px rgba(0,0,0,0.5);
85
86
  --shadow-inner: inset 0 1px 3px rgba(0,0,0,0.4);
86
87
  --shadow-glow-brand: 0 0 12px rgba(6,41,125,0.5);
87
88
  --overlay-backdrop: rgba(8,9,12,0.80);
@@ -325,6 +326,7 @@
325
326
  --shadow-md: 0 2px 8px rgba(0,0,0,0.08), 0 1px 2px rgba(0,0,0,0.04);
326
327
  --shadow-lg: 0 8px 24px rgba(0,0,0,0.12), 0 2px 8px rgba(0,0,0,0.06);
327
328
  --shadow-xl: 0 16px 48px rgba(0,0,0,0.16), 0 4px 12px rgba(0,0,0,0.08);
329
+ --shadow-overlay: 0 12px 32px rgba(16,24,40,0.1), 0 2px 8px rgba(16,24,40,0.06);
328
330
  --shadow-inner: inset 0 1px 3px rgba(0,0,0,0.08);
329
331
  --shadow-glow-brand: 0 0 12px rgba(6,41,125,0.2);
330
332
  --overlay-backdrop: rgba(14,16,21,0.50);
@@ -740,12 +742,11 @@
740
742
  }
741
743
  :root {
742
744
  /* === Nav / menu surfaces (0.3.0 sidebar) === */
743
- /* --menu-shadow stays a literal mirroring the 0.3.0 prototype's --shadow-md:
744
- @lessly/tokens ships its own --shadow-* scale, but with different values —
745
- switching to var(--shadow-md) would visibly change the menus. */
745
+ /* --menu-shadow sits on the package's --shadow-overlay role; theme.css re-resolves
746
+ it per theme, so `.light` needs no override. */
746
747
  --hov-bg: color-mix(in srgb, var(--text-primary) 7%, transparent);
747
748
  --menu-bg: var(--bg-elevated);
748
- --menu-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
749
+ --menu-shadow: var(--shadow-overlay);
749
750
  --menu-hov: var(--hov-bg);
750
751
 
751
752
  /* === Sign-in / auth screen (<SignInScreen/>) ===
@@ -764,10 +765,9 @@
764
765
  .light {
765
766
  /* Light keeps opaque plates: a translucent text-mix would vanish on a white menu.
766
767
  Pinned 0.3.0-prototype literals — deliberately NOT var(--bg-elevated), which
767
- only coincidentally resolves to the same white in the current package. */
768
+ resolves to #edeef0 in the package, not this white. */
768
769
  --hov-bg: #ffffff;
769
770
  --menu-bg: #ffffff;
770
- --menu-shadow: 0 12px 32px rgba(16, 24, 40, 0.1), 0 2px 8px rgba(16, 24, 40, 0.06);
771
771
  --menu-hov: #f2f4f7;
772
772
 
773
773
  /* Auth screen — see :root above. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lessly/ui",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "description": "Lessly design system — shared UI primitives, tokens, and theme",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@10.30.3",
@@ -62,7 +62,7 @@
62
62
  }
63
63
  },
64
64
  "dependencies": {
65
- "@lessly/tokens": "^0.3.1",
65
+ "@lessly/tokens": "^0.4.0",
66
66
  "@radix-ui/react-accordion": "^1.2.16",
67
67
  "@radix-ui/react-alert-dialog": "^1.1.19",
68
68
  "@radix-ui/react-aspect-ratio": "^1.1.11",
@@ -103,6 +103,7 @@
103
103
  "@changesets/cli": "^2.31.0",
104
104
  "@eslint/js": "^9.39.5",
105
105
  "@storybook/addon-essentials": "^8.6.14",
106
+ "@storybook/blocks": "8.6.18",
106
107
  "@storybook/react": "^8.6.18",
107
108
  "@storybook/react-vite": "^8.6.18",
108
109
  "@tailwindcss/cli": "^4",