@devalok/shilp-sutra 0.45.1 → 0.47.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.
Files changed (62) hide show
  1. package/AGENTS.md +13 -1
  2. package/MIGRATION.md +846 -808
  3. package/dist/_chunks/chat.js +6 -6
  4. package/dist/_chunks/chat.js.map +1 -1
  5. package/dist/_chunks/document-preview.js +5 -5
  6. package/dist/_chunks/image-preview.js +7 -7
  7. package/dist/_chunks/success.js +16 -16
  8. package/dist/composed/activity-feed.js +19 -19
  9. package/dist/composed/deadline-indicator.d.ts.map +1 -1
  10. package/dist/composed/deadline-indicator.js +31 -31
  11. package/dist/composed/deadline-indicator.js.map +1 -1
  12. package/dist/composed/emoji-picker.js +15 -15
  13. package/dist/composed/file-preview.js +18 -18
  14. package/dist/composed/file-preview.js.map +1 -1
  15. package/dist/composed/filter-bar.js +1 -1
  16. package/dist/composed/filter-bar.js.map +1 -1
  17. package/dist/composed/multi-select-popover.js +1 -1
  18. package/dist/composed/multi-select-popover.js.map +1 -1
  19. package/dist/tokens/base.css +6 -0
  20. package/dist/tokens/index.css +1 -1
  21. package/dist/tokens/semantic.css +1 -1
  22. package/dist/tokens/typography.css +10 -0
  23. package/dist/tokens/utilities.css +6 -0
  24. package/dist/ui/avatar.d.ts.map +1 -1
  25. package/dist/ui/avatar.js +57 -56
  26. package/dist/ui/avatar.js.map +1 -1
  27. package/dist/ui/badge-indicator.js +1 -1
  28. package/dist/ui/badge-indicator.js.map +1 -1
  29. package/dist/ui/data-table-body.js +27 -27
  30. package/dist/ui/data-table-card.js +20 -20
  31. package/dist/ui/data-table-toolbar.d.ts.map +1 -1
  32. package/dist/ui/data-table-toolbar.js +40 -36
  33. package/dist/ui/data-table-toolbar.js.map +1 -1
  34. package/dist/ui/index.d.ts +1 -0
  35. package/dist/ui/index.d.ts.map +1 -1
  36. package/dist/ui/index.js +37 -36
  37. package/dist/ui/index.js.map +1 -1
  38. package/dist/ui/radio.js +1 -1
  39. package/dist/ui/radio.js.map +1 -1
  40. package/dist/ui/sidebar.js +7 -7
  41. package/dist/ui/stat-card.d.ts.map +1 -1
  42. package/dist/ui/stat-card.js +48 -47
  43. package/dist/ui/stat-card.js.map +1 -1
  44. package/dist/ui/surface.d.ts +46 -0
  45. package/dist/ui/surface.d.ts.map +1 -0
  46. package/dist/ui/surface.js +51 -0
  47. package/dist/ui/surface.js.map +1 -0
  48. package/dist/ui/text.js +6 -6
  49. package/dist/ui/text.js.map +1 -1
  50. package/docs/components/ui/surface.md +55 -0
  51. package/docs/recipes/install-tanstack-start.md +91 -44
  52. package/fonts/Manrope-Variable.woff2 +0 -0
  53. package/llms.txt +2 -1
  54. package/make-kit/components/overview.md +7 -3
  55. package/make-kit/components/surface.md +60 -0
  56. package/mcp-manifest.json +135 -3
  57. package/mcp-manifest.schema.json +6 -0
  58. package/package.json +7 -2
  59. package/scripts/welcome.mjs +4 -2
  60. package/skill/SKILL.md +1 -1
  61. package/skill/references/components.md +2 -1
  62. package/skill/references/setup-tanstack-start.md +91 -44
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/ui/lib/check-tokens.ts","../../src/ui/index.ts"],"sourcesContent":["/**\n * Dev-mode check for missing token CSS.\n *\n * If the consumer forgets `import '@devalok/shilp-sutra/tokens'`, all CSS\n * custom properties resolve to empty strings and components render with\n * transparent/broken backgrounds. This check detects that condition and\n * warns in the console.\n *\n * Only runs once, only in development, only in the browser.\n */\nlet checked = false\n\nexport function checkTokensLoaded(): void {\n if (checked) return\n if (typeof window === 'undefined') return\n\n // Skip in production — bundlers (Vite, Next.js, webpack) define import.meta.env or process.env\n try {\n // @ts-expect-error -- import.meta.env is Vite-specific, not in base TS lib\n if (import.meta.env?.PROD) return\n } catch { /* not in Vite */ }\n\n checked = true\n\n // Wait for stylesheets to load\n requestAnimationFrame(() => {\n const value = getComputedStyle(document.documentElement).getPropertyValue('--color-accent-9').trim()\n if (!value) {\n console.warn(\n '[shilp-sutra] Design system tokens CSS not loaded. ' +\n 'Add `import \\'@devalok/shilp-sutra/tokens\\'` to your root layout. ' +\n 'Without it, components will render with missing colors, spacing, and typography.'\n )\n }\n })\n}\n","/**\n * @module @devalok/shilp-sutra/ui\n *\n * Core UI primitives: buttons, inputs, dialogs, cards, tables, badges, navigation, and more.\n * Most components require client-side React (\"use client\").\n *\n * **Server-safe components** (import individually for Server Components):\n * `Text`, `Skeleton`, `Stack`, `Container`, `Table`, `Code`, `VisuallyHidden`\n *\n * @example\n * // Server Component — import individually:\n * import { Text } from '@devalok/shilp-sutra/ui/text'\n * import { Stack } from '@devalok/shilp-sutra/ui/stack'\n *\n * // Client Component — barrel import:\n * import { Button, Dialog } from '@devalok/shilp-sutra/ui'\n */\n\n// Dev-mode token presence check — runs once on first import\nimport { checkTokensLoaded } from './lib/check-tokens'\ncheckTokensLoaded()\n\n// Core\nexport { Button, type ButtonProps,buttonVariants } from './button'\nexport { ButtonGroup, type ButtonGroupProps,useButtonGroup } from './button-group'\nexport { ColorInput, type ColorInputProps } from './color-input'\nexport { Icon, type IconProps } from './icon'\nexport { IconButton, type IconButtonProps } from './icon-button'\nexport { IconContext, type IconContextValue, IconProvider, type IconSize, type IconStroke,useIconContext } from './icon-context'\nexport { IconGroup, type IconGroupProps } from './icon-group'\nexport { Input, type InputProps, type InputState, inputWrapperVariants } from './input'\nexport { Label, type LabelProps } from './label'\nexport { Separator, type SeparatorProps } from './separator'\nexport { SplitButton, type SplitButtonProps } from './split-button'\nexport { VisuallyHidden, type VisuallyHiddenProps } from './visually-hidden'\n\n// Autocomplete\nexport { Autocomplete, type AutocompleteOption,type AutocompleteProps } from './autocomplete'\n\n// Combobox\nexport { Combobox, type ComboboxOption, type ComboboxProps, type ComboboxSize,comboboxTriggerVariants } from './combobox'\n\n// FileUpload\nexport { FileUpload, type FileUploadProps } from './file-upload'\n\n// Form Controls\nexport { Checkbox, type CheckboxProps } from './checkbox'\nexport { FormField, type FormFieldProps, type FormHelperState, FormHelperText, type FormHelperTextProps,useFormField } from './form'\n// InputOTP removed from barrel in 0.40.0 — hard peer `input-otp` was breaking\n// fresh-consumer builds. Import per-component instead:\n// import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from '@devalok/shilp-sutra/ui/input-otp'\nexport { NumberInput, type NumberInputProps, type NumberInputSize, type NumberInputState,numberInputWrapperVariants } from './number-input'\nexport { RadioGroup, RadioGroupItem, type RadioGroupItemProps,type RadioGroupProps } from './radio'\nexport { SearchInput, type SearchInputProps } from './search-input'\nexport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectScrollDownButton,\n SelectScrollUpButton,\n SelectSeparator,\n SelectTrigger,\n type SelectTriggerProps,\n selectTriggerVariants,\n SelectValue,\n} from './select'\nexport { Slider, type SliderColor,type SliderProps, type SliderSize, sliderThumbVariants, sliderTrackVariants } from './slider'\nexport { Switch, type SwitchProps } from './switch'\nexport { Textarea, type TextareaProps,textareaVariants } from './textarea'\nexport { Toggle, type ToggleProps,toggleVariants } from './toggle'\nexport { ToggleGroup, ToggleGroupItem, type ToggleGroupItemProps,type ToggleGroupProps } from './toggle-group'\nexport { TruncatedText, type TruncatedTextProps } from './truncated-text'\n\n// Feedback & Overlays\nexport {\n AlertDialog,\n AlertDialogAction,\n type AlertDialogActionProps,\n AlertDialogCancel,\n type AlertDialogCancelProps,\n AlertDialogContent,\n type AlertDialogContentProps,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogOverlay,\n AlertDialogPortal,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from './alert-dialog'\nexport { Collapsible, CollapsibleContent, type CollapsibleProps,CollapsibleTrigger } from './collapsible'\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n type DialogContentProps,\n DialogContentRaw,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n type DialogTitleProps,\n DialogTrigger,\n} from './dialog'\nexport { HoverCard, HoverCardContent, type HoverCardContentProps,HoverCardTrigger } from './hover-card'\nexport { Popover, PopoverAnchor, PopoverContent, type PopoverContentProps,PopoverTrigger } from './popover'\nexport {\n Sheet,\n SheetClose,\n SheetContent,\n type SheetContentProps,\n SheetDescription,\n SheetFooter,\n SheetHeader,\n SheetOverlay,\n SheetPortal,\n SheetTitle,\n SheetTrigger,\n} from './sheet'\n// toast + Toaster removed from barrel in 0.40.0 — hard peer `sonner` was\n// breaking fresh-consumer builds when consumers imported other UI symbols\n// from the barrel without sonner installed. Import per-component instead:\n// import { toast, formatFileSize, type ToastOptions } from '@devalok/shilp-sutra/ui/toast'\n// import { Toaster } from '@devalok/shilp-sutra/ui/toaster'\nexport { Tooltip, TooltipContent, type TooltipContentProps,TooltipProvider, TooltipTrigger } from './tooltip'\n// ---------------------------------------------------------------------------\n// Notifications — pick the right one:\n// Alert — inline, static feedback within a form or page section (no user action needed to show)\n// Banner — persistent, page-level notice shown above main content (survives navigation)\n// Toast — imperative, transient, action-triggered (fires on user action, auto-dismisses)\n// Requires <Toaster /> mounted once at layout root. Use toast.success() etc. from anywhere.\n// ---------------------------------------------------------------------------\nexport { Alert, type AlertProps,alertVariants } from './alert'\nexport { Banner, type BannerProps,bannerVariants } from './banner'\nexport { Spinner, type SpinnerProps } from './spinner'\n\n// Data Display\nexport { AspectRatio } from './aspect-ratio'\nexport { Avatar, AvatarFallback, type AvatarFallbackProps, AvatarImage, type AvatarProps, type AvatarRing,type AvatarStatus, avatarVariants } from './avatar'\nexport { Badge, type BadgeProps,badgeVariants } from './badge'\nexport { BadgeGroup, type BadgeGroupProps } from './badge-group'\nexport { BadgeIndicator, type BadgeIndicatorProps } from './badge-indicator'\nexport { Card, CardAction, type CardActionPlacement, type CardActionProps, CardBleed, type CardBleedProps, type CardBleedSide, CardContent, CardDescription, CardFooter, CardHeader, type CardProps,CardSection, CardTitle, cardVariants } from './card'\nexport { Code, type CodeProps } from './code'\nexport { ColorSwatch, type ColorSwatchProps } from './color-swatch'\nexport { Progress, progressIndicatorVariants, type ProgressProps,progressTrackVariants } from './progress'\nexport { MultiProgressRing, type MultiProgressRingProps,ProgressRing, type ProgressRingProps } from './progress-ring'\nexport {\n Skeleton,\n SkeletonAvatar,\n type SkeletonAvatarProps,\n SkeletonButton,\n type SkeletonButtonProps,\n SkeletonChart,\n type SkeletonChartProps,\n SkeletonGroup,\n type SkeletonGroupProps,\n SkeletonImage,\n type SkeletonImageProps,\n SkeletonInput,\n type SkeletonInputProps,\n type SkeletonProps,\n SkeletonText,\n type SkeletonTextProps,\n skeletonVariants,\n} from './skeleton'\nexport { StatCard, type StatCardProps } from './stat-card'\nexport {\n type FlashPreset,\n type FlashSpec,\n type FlashSpeed,\n type FlashTone,\n StatFlash,\n type StatFlashProps,\n} from './stat-flash'\nexport { StatusDot, type StatusDotProps, type StatusDotStatus } from './status-dot'\nexport { Table, TableBody, TableCaption, TableCell, type TableCellBaseProps,type TableCellProps,type TableDensity, TableFooter, TableHead, TableHeader, type TableProps, TableRow, TableRowActions, type TableRowActionsProps,type TableRowProps } from './table'\nexport { TableRowLink, type TableRowLinkProps } from './table-row-link'\n\n// Navigation\nexport { Accordion, AccordionContent, type AccordionContentProps,AccordionItem, type AccordionItemProps, AccordionTrigger, type AccordionTriggerProps } from './accordion'\nexport {\n Breadcrumb,\n BreadcrumbEllipsis,\n BreadcrumbItem,\n BreadcrumbLink,\n type BreadcrumbLinkProps,\n BreadcrumbList,\n BreadcrumbPage,\n type BreadcrumbProps,\n BreadcrumbSeparator,\n} from './breadcrumb'\nexport {\n ContextMenu,\n ContextMenuCheckboxItem,\n ContextMenuContent,\n type ContextMenuContentProps,\n ContextMenuGroup,\n ContextMenuItem,\n type ContextMenuItemProps,\n ContextMenuLabel,\n ContextMenuPortal,\n ContextMenuRadioGroup,\n ContextMenuRadioItem,\n ContextMenuSeparator,\n ContextMenuShortcut,\n ContextMenuSub,\n ContextMenuSubContent,\n ContextMenuSubTrigger,\n ContextMenuTrigger,\n} from './context-menu'\nexport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n type DropdownMenuContentProps,\n DropdownMenuGroup,\n DropdownMenuItem,\n type DropdownMenuItemProps,\n DropdownMenuLabel,\n DropdownMenuPortal,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n} from './dropdown-menu'\nexport {\n Menubar,\n MenubarCheckboxItem,\n MenubarContent,\n type MenubarContentProps,\n MenubarGroup,\n MenubarItem,\n type MenubarItemProps,\n MenubarLabel,\n MenubarMenu,\n MenubarPortal,\n MenubarRadioGroup,\n MenubarRadioItem,\n MenubarSeparator,\n MenubarShortcut,\n MenubarSub,\n MenubarSubContent,\n MenubarSubTrigger,\n MenubarTrigger,\n} from './menubar'\nexport {\n NavigationMenu,\n NavigationMenuContent,\n type NavigationMenuContentProps,\n NavigationMenuIndicator,\n NavigationMenuItem,\n NavigationMenuLink,\n NavigationMenuList,\n type NavigationMenuProps,\n NavigationMenuTrigger,\n NavigationMenuViewport,\n} from './navigation-menu'\nexport {\n generatePagination,\n PaginationContent,\n PaginationEllipsis,\n PaginationItem,\n PaginationLink,\n type PaginationLinkProps,\n PaginationNav,\n type PaginationNavProps,\n PaginationNext,\n PaginationPrevious,\n PaginationRoot,\n} from './pagination'\nexport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupAction,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarInput,\n SidebarInset,\n SidebarMenu,\n SidebarMenuAction,\n SidebarMenuBadge,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSkeleton,\n SidebarMenuSub,\n SidebarMenuSubButton,\n SidebarMenuSubItem,\n type SidebarProps,\n SidebarProvider,\n SidebarRail,\n SidebarSeparator,\n SidebarTrigger,\n useSidebar,\n} from './sidebar'\nexport { Tabs, type TabsColor, TabsContent, type TabsContentProps, TabsList, type TabsListProps, type TabsOrientation,type TabsProps, type TabsSize, TabsTrigger, type TabsTriggerProps } from './tabs'\n\n// Workflow\nexport { Step, Stepper, type StepperProps, type StepProps } from './stepper'\n\n\n// Typography\nexport { Text, type TextProps, type TextVariant,textVariants } from './text'\n\n// Layout\nexport { Container, type ContainerProps } from './container'\nexport { type SpacingToken,Stack, type StackProps } from './stack'\n\n// Tree View\nexport { TreeItem, type TreeItemProps, type TreeNode,TreeView, type TreeViewProps, useTree } from './tree-view'\n\n// Segmented Control\nexport {\n SegmentedControl,\n type SegmentedControlOption,\n type SegmentedControlProps,\n type SegmentedControlSize,\n type SegmentedControlVariant,\n} from './segmented-control'\n\n// Brand Texture\nexport { DevalokGrain, type DevalokGrainProps, type GrainIntensity } from './devalok-grain'\n\n// Chat primitives\nexport {\n DateSeparator,\n type DateSeparatorProps,\n Message,\n type MessageActionProps,\n type MessageActionsProps,\n type MessageAuthorProps,\n type MessageAvatarProps,\n type MessageBodyProps,\n type MessageContentProps,\n type MessageContextValue,\n type MessageEditableBodyProps,\n MessageInput,\n type MessageInputProps,\n MessageList,\n type MessageListProps,\n type MessageProps,\n type MessageReactionsProps,\n SystemMessage,\n type SystemMessageProps,\n TypingIndicator,\n type TypingIndicatorProps,\n UnreadSeparator,\n type UnreadSeparatorProps,\n useMessageContext,\n} from './chat'\n\n// Other\nexport { Link, type LinkProps } from './link'\n\n// OAuth / Social sign-in\nexport {\n getOAuthLabel,\n getOAuthName,\n OAuth,\n type OAuthAppearance,\n OAuthButton,\n type OAuthButtonProps,\n OAuthConnectionRow,\n type OAuthConnectionRowProps,\n OAuthDivider,\n type OAuthDividerProps,\n OAuthGlyph,\n type OAuthGlyphProps,\n OAuthGroup,\n type OAuthGroupProps,\n type OAuthIntent,\n type OAuthProvider,\n type OAuthVariant,\n} from './oauth-button'\n\n// Utilities\nexport { formatRelativeTime } from './lib/date-utils'\nexport type { SpringPreset, TweenPreset } from './lib/motion'\nexport { springs, stagger, tweens, withReducedMotion } from './lib/motion'\nexport { cn } from './lib/utils'\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAUA,IAAI,IAAU;AAEd,SAAgB,KAA0B;AACpC,WACA,SAAO,SAAW,MAGtB;MAAI;AAEyB;UACrB;AAKR,EAHA,IAAU,IAGV,4BAA4B;AAE1B,GADc,iBAAiB,SAAS,gBAAgB,CAAC,iBAAiB,mBAAmB,CAAC,MAAM,IAElG,QAAQ,KACN,sMAGD;IAEH;;;;;ACdJ,IAAmB"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/ui/lib/check-tokens.ts","../../src/ui/index.ts"],"sourcesContent":["/**\n * Dev-mode check for missing token CSS.\n *\n * If the consumer forgets `import '@devalok/shilp-sutra/tokens'`, all CSS\n * custom properties resolve to empty strings and components render with\n * transparent/broken backgrounds. This check detects that condition and\n * warns in the console.\n *\n * Only runs once, only in development, only in the browser.\n */\nlet checked = false\n\nexport function checkTokensLoaded(): void {\n if (checked) return\n if (typeof window === 'undefined') return\n\n // Skip in production — bundlers (Vite, Next.js, webpack) define import.meta.env or process.env\n try {\n // @ts-expect-error -- import.meta.env is Vite-specific, not in base TS lib\n if (import.meta.env?.PROD) return\n } catch { /* not in Vite */ }\n\n checked = true\n\n // Wait for stylesheets to load\n requestAnimationFrame(() => {\n const value = getComputedStyle(document.documentElement).getPropertyValue('--color-accent-9').trim()\n if (!value) {\n console.warn(\n '[shilp-sutra] Design system tokens CSS not loaded. ' +\n 'Add `import \\'@devalok/shilp-sutra/tokens\\'` to your root layout. ' +\n 'Without it, components will render with missing colors, spacing, and typography.'\n )\n }\n })\n}\n","/**\n * @module @devalok/shilp-sutra/ui\n *\n * Core UI primitives: buttons, inputs, dialogs, cards, tables, badges, navigation, and more.\n * Most components require client-side React (\"use client\").\n *\n * **Server-safe components** (import individually for Server Components):\n * `Text`, `Skeleton`, `Stack`, `Container`, `Table`, `Code`, `VisuallyHidden`\n *\n * @example\n * // Server Component — import individually:\n * import { Text } from '@devalok/shilp-sutra/ui/text'\n * import { Stack } from '@devalok/shilp-sutra/ui/stack'\n *\n * // Client Component — barrel import:\n * import { Button, Dialog } from '@devalok/shilp-sutra/ui'\n */\n\n// Dev-mode token presence check — runs once on first import\nimport { checkTokensLoaded } from './lib/check-tokens'\ncheckTokensLoaded()\n\n// Core\nexport { Button, type ButtonProps,buttonVariants } from './button'\nexport { ButtonGroup, type ButtonGroupProps,useButtonGroup } from './button-group'\nexport { ColorInput, type ColorInputProps } from './color-input'\nexport { Icon, type IconProps } from './icon'\nexport { IconButton, type IconButtonProps } from './icon-button'\nexport { IconContext, type IconContextValue, IconProvider, type IconSize, type IconStroke,useIconContext } from './icon-context'\nexport { IconGroup, type IconGroupProps } from './icon-group'\nexport { Input, type InputProps, type InputState, inputWrapperVariants } from './input'\nexport { Label, type LabelProps } from './label'\nexport { Separator, type SeparatorProps } from './separator'\nexport { SplitButton, type SplitButtonProps } from './split-button'\nexport { VisuallyHidden, type VisuallyHiddenProps } from './visually-hidden'\n\n// Autocomplete\nexport { Autocomplete, type AutocompleteOption,type AutocompleteProps } from './autocomplete'\n\n// Combobox\nexport { Combobox, type ComboboxOption, type ComboboxProps, type ComboboxSize,comboboxTriggerVariants } from './combobox'\n\n// FileUpload\nexport { FileUpload, type FileUploadProps } from './file-upload'\n\n// Form Controls\nexport { Checkbox, type CheckboxProps } from './checkbox'\nexport { FormField, type FormFieldProps, type FormHelperState, FormHelperText, type FormHelperTextProps,useFormField } from './form'\n// InputOTP removed from barrel in 0.40.0 — hard peer `input-otp` was breaking\n// fresh-consumer builds. Import per-component instead:\n// import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from '@devalok/shilp-sutra/ui/input-otp'\nexport { NumberInput, type NumberInputProps, type NumberInputSize, type NumberInputState,numberInputWrapperVariants } from './number-input'\nexport { RadioGroup, RadioGroupItem, type RadioGroupItemProps,type RadioGroupProps } from './radio'\nexport { SearchInput, type SearchInputProps } from './search-input'\nexport {\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectScrollDownButton,\n SelectScrollUpButton,\n SelectSeparator,\n SelectTrigger,\n type SelectTriggerProps,\n selectTriggerVariants,\n SelectValue,\n} from './select'\nexport { Slider, type SliderColor,type SliderProps, type SliderSize, sliderThumbVariants, sliderTrackVariants } from './slider'\nexport { Switch, type SwitchProps } from './switch'\nexport { Textarea, type TextareaProps,textareaVariants } from './textarea'\nexport { Toggle, type ToggleProps,toggleVariants } from './toggle'\nexport { ToggleGroup, ToggleGroupItem, type ToggleGroupItemProps,type ToggleGroupProps } from './toggle-group'\nexport { TruncatedText, type TruncatedTextProps } from './truncated-text'\n\n// Feedback & Overlays\nexport {\n AlertDialog,\n AlertDialogAction,\n type AlertDialogActionProps,\n AlertDialogCancel,\n type AlertDialogCancelProps,\n AlertDialogContent,\n type AlertDialogContentProps,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogOverlay,\n AlertDialogPortal,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from './alert-dialog'\nexport { Collapsible, CollapsibleContent, type CollapsibleProps,CollapsibleTrigger } from './collapsible'\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n type DialogContentProps,\n DialogContentRaw,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogOverlay,\n DialogPortal,\n DialogTitle,\n type DialogTitleProps,\n DialogTrigger,\n} from './dialog'\nexport { HoverCard, HoverCardContent, type HoverCardContentProps,HoverCardTrigger } from './hover-card'\nexport { Popover, PopoverAnchor, PopoverContent, type PopoverContentProps,PopoverTrigger } from './popover'\nexport {\n Sheet,\n SheetClose,\n SheetContent,\n type SheetContentProps,\n SheetDescription,\n SheetFooter,\n SheetHeader,\n SheetOverlay,\n SheetPortal,\n SheetTitle,\n SheetTrigger,\n} from './sheet'\n// toast + Toaster removed from barrel in 0.40.0 — hard peer `sonner` was\n// breaking fresh-consumer builds when consumers imported other UI symbols\n// from the barrel without sonner installed. Import per-component instead:\n// import { toast, formatFileSize, type ToastOptions } from '@devalok/shilp-sutra/ui/toast'\n// import { Toaster } from '@devalok/shilp-sutra/ui/toaster'\nexport { Tooltip, TooltipContent, type TooltipContentProps,TooltipProvider, TooltipTrigger } from './tooltip'\n// ---------------------------------------------------------------------------\n// Notifications — pick the right one:\n// Alert — inline, static feedback within a form or page section (no user action needed to show)\n// Banner — persistent, page-level notice shown above main content (survives navigation)\n// Toast — imperative, transient, action-triggered (fires on user action, auto-dismisses)\n// Requires <Toaster /> mounted once at layout root. Use toast.success() etc. from anywhere.\n// ---------------------------------------------------------------------------\nexport { Alert, type AlertProps,alertVariants } from './alert'\nexport { Banner, type BannerProps,bannerVariants } from './banner'\nexport { Spinner, type SpinnerProps } from './spinner'\n\n// Data Display\nexport { AspectRatio } from './aspect-ratio'\nexport { Avatar, AvatarFallback, type AvatarFallbackProps, AvatarImage, type AvatarProps, type AvatarRing,type AvatarStatus, avatarVariants } from './avatar'\nexport { Badge, type BadgeProps,badgeVariants } from './badge'\nexport { BadgeGroup, type BadgeGroupProps } from './badge-group'\nexport { BadgeIndicator, type BadgeIndicatorProps } from './badge-indicator'\nexport { Card, CardAction, type CardActionPlacement, type CardActionProps, CardBleed, type CardBleedProps, type CardBleedSide, CardContent, CardDescription, CardFooter, CardHeader, type CardProps,CardSection, CardTitle, cardVariants } from './card'\nexport { Code, type CodeProps } from './code'\nexport { ColorSwatch, type ColorSwatchProps } from './color-swatch'\nexport { Progress, progressIndicatorVariants, type ProgressProps,progressTrackVariants } from './progress'\nexport { MultiProgressRing, type MultiProgressRingProps,ProgressRing, type ProgressRingProps } from './progress-ring'\nexport {\n Skeleton,\n SkeletonAvatar,\n type SkeletonAvatarProps,\n SkeletonButton,\n type SkeletonButtonProps,\n SkeletonChart,\n type SkeletonChartProps,\n SkeletonGroup,\n type SkeletonGroupProps,\n SkeletonImage,\n type SkeletonImageProps,\n SkeletonInput,\n type SkeletonInputProps,\n type SkeletonProps,\n SkeletonText,\n type SkeletonTextProps,\n skeletonVariants,\n} from './skeleton'\nexport { StatCard, type StatCardProps } from './stat-card'\nexport {\n type FlashPreset,\n type FlashSpec,\n type FlashSpeed,\n type FlashTone,\n StatFlash,\n type StatFlashProps,\n} from './stat-flash'\nexport { StatusDot, type StatusDotProps, type StatusDotStatus } from './status-dot'\nexport { Surface, type SurfaceProps, surfaceVariants } from './surface'\nexport { Table, TableBody, TableCaption, TableCell, type TableCellBaseProps,type TableCellProps,type TableDensity, TableFooter, TableHead, TableHeader, type TableProps, TableRow, TableRowActions, type TableRowActionsProps,type TableRowProps } from './table'\nexport { TableRowLink, type TableRowLinkProps } from './table-row-link'\n\n// Navigation\nexport { Accordion, AccordionContent, type AccordionContentProps,AccordionItem, type AccordionItemProps, AccordionTrigger, type AccordionTriggerProps } from './accordion'\nexport {\n Breadcrumb,\n BreadcrumbEllipsis,\n BreadcrumbItem,\n BreadcrumbLink,\n type BreadcrumbLinkProps,\n BreadcrumbList,\n BreadcrumbPage,\n type BreadcrumbProps,\n BreadcrumbSeparator,\n} from './breadcrumb'\nexport {\n ContextMenu,\n ContextMenuCheckboxItem,\n ContextMenuContent,\n type ContextMenuContentProps,\n ContextMenuGroup,\n ContextMenuItem,\n type ContextMenuItemProps,\n ContextMenuLabel,\n ContextMenuPortal,\n ContextMenuRadioGroup,\n ContextMenuRadioItem,\n ContextMenuSeparator,\n ContextMenuShortcut,\n ContextMenuSub,\n ContextMenuSubContent,\n ContextMenuSubTrigger,\n ContextMenuTrigger,\n} from './context-menu'\nexport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n type DropdownMenuContentProps,\n DropdownMenuGroup,\n DropdownMenuItem,\n type DropdownMenuItemProps,\n DropdownMenuLabel,\n DropdownMenuPortal,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n} from './dropdown-menu'\nexport {\n Menubar,\n MenubarCheckboxItem,\n MenubarContent,\n type MenubarContentProps,\n MenubarGroup,\n MenubarItem,\n type MenubarItemProps,\n MenubarLabel,\n MenubarMenu,\n MenubarPortal,\n MenubarRadioGroup,\n MenubarRadioItem,\n MenubarSeparator,\n MenubarShortcut,\n MenubarSub,\n MenubarSubContent,\n MenubarSubTrigger,\n MenubarTrigger,\n} from './menubar'\nexport {\n NavigationMenu,\n NavigationMenuContent,\n type NavigationMenuContentProps,\n NavigationMenuIndicator,\n NavigationMenuItem,\n NavigationMenuLink,\n NavigationMenuList,\n type NavigationMenuProps,\n NavigationMenuTrigger,\n NavigationMenuViewport,\n} from './navigation-menu'\nexport {\n generatePagination,\n PaginationContent,\n PaginationEllipsis,\n PaginationItem,\n PaginationLink,\n type PaginationLinkProps,\n PaginationNav,\n type PaginationNavProps,\n PaginationNext,\n PaginationPrevious,\n PaginationRoot,\n} from './pagination'\nexport {\n Sidebar,\n SidebarContent,\n SidebarFooter,\n SidebarGroup,\n SidebarGroupAction,\n SidebarGroupContent,\n SidebarGroupLabel,\n SidebarHeader,\n SidebarInput,\n SidebarInset,\n SidebarMenu,\n SidebarMenuAction,\n SidebarMenuBadge,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarMenuSkeleton,\n SidebarMenuSub,\n SidebarMenuSubButton,\n SidebarMenuSubItem,\n type SidebarProps,\n SidebarProvider,\n SidebarRail,\n SidebarSeparator,\n SidebarTrigger,\n useSidebar,\n} from './sidebar'\nexport { Tabs, type TabsColor, TabsContent, type TabsContentProps, TabsList, type TabsListProps, type TabsOrientation,type TabsProps, type TabsSize, TabsTrigger, type TabsTriggerProps } from './tabs'\n\n// Workflow\nexport { Step, Stepper, type StepperProps, type StepProps } from './stepper'\n\n\n// Typography\nexport { Text, type TextProps, type TextVariant,textVariants } from './text'\n\n// Layout\nexport { Container, type ContainerProps } from './container'\nexport { type SpacingToken,Stack, type StackProps } from './stack'\n\n// Tree View\nexport { TreeItem, type TreeItemProps, type TreeNode,TreeView, type TreeViewProps, useTree } from './tree-view'\n\n// Segmented Control\nexport {\n SegmentedControl,\n type SegmentedControlOption,\n type SegmentedControlProps,\n type SegmentedControlSize,\n type SegmentedControlVariant,\n} from './segmented-control'\n\n// Brand Texture\nexport { DevalokGrain, type DevalokGrainProps, type GrainIntensity } from './devalok-grain'\n\n// Chat primitives\nexport {\n DateSeparator,\n type DateSeparatorProps,\n Message,\n type MessageActionProps,\n type MessageActionsProps,\n type MessageAuthorProps,\n type MessageAvatarProps,\n type MessageBodyProps,\n type MessageContentProps,\n type MessageContextValue,\n type MessageEditableBodyProps,\n MessageInput,\n type MessageInputProps,\n MessageList,\n type MessageListProps,\n type MessageProps,\n type MessageReactionsProps,\n SystemMessage,\n type SystemMessageProps,\n TypingIndicator,\n type TypingIndicatorProps,\n UnreadSeparator,\n type UnreadSeparatorProps,\n useMessageContext,\n} from './chat'\n\n// Other\nexport { Link, type LinkProps } from './link'\n\n// OAuth / Social sign-in\nexport {\n getOAuthLabel,\n getOAuthName,\n OAuth,\n type OAuthAppearance,\n OAuthButton,\n type OAuthButtonProps,\n OAuthConnectionRow,\n type OAuthConnectionRowProps,\n OAuthDivider,\n type OAuthDividerProps,\n OAuthGlyph,\n type OAuthGlyphProps,\n OAuthGroup,\n type OAuthGroupProps,\n type OAuthIntent,\n type OAuthProvider,\n type OAuthVariant,\n} from './oauth-button'\n\n// Utilities\nexport { formatRelativeTime } from './lib/date-utils'\nexport type { SpringPreset, TweenPreset } from './lib/motion'\nexport { springs, stagger, tweens, withReducedMotion } from './lib/motion'\nexport { cn } from './lib/utils'\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAUA,IAAI,IAAU;AAEd,SAAgB,KAA0B;AACpC,WACA,SAAO,SAAW,MAGtB;MAAI;AAEyB;UACrB;AAKR,EAHA,IAAU,IAGV,4BAA4B;AAE1B,GADc,iBAAiB,SAAS,gBAAgB,CAAC,iBAAiB,mBAAmB,CAAC,MAAM,IAElG,QAAQ,KACN,sMAGD;IAEH;;;;;ACdJ,IAAmB"}
package/dist/ui/radio.js CHANGED
@@ -39,7 +39,7 @@ var d = {
39
39
  className: "flex items-center justify-center",
40
40
  initial: { scale: 0 },
41
41
  animate: { scale: 1 },
42
- transition: r.bouncy,
42
+ transition: r.snappy,
43
43
  children: /* @__PURE__ */ s(c, { className: i(f[a], "fill-accent-9 text-accent-11") })
44
44
  })
45
45
  })
@@ -1 +1 @@
1
- {"version":3,"file":"radio.js","names":[],"sources":["../../src/ui/radio.tsx"],"sourcesContent":["'use client'\n\nimport * as RadioGroupPrimitive from '@primitives/react-radio-group'\nimport { IconCircle } from '@tabler/icons-react'\nimport { AnimatePresence, motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useFormField } from './form'\nimport { springs } from './lib/motion'\nimport { cn } from './lib/utils'\n\nconst RadioGroup = React.forwardRef<\n React.ElementRef<typeof RadioGroupPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>\n>(({ className, ...props }, ref) => {\n const fieldCtx = useFormField()\n const isError = fieldCtx.state === 'error'\n const ariaDescribedBy = props['aria-describedby'] ?? fieldCtx.helperTextId\n const ariaRequired = props['aria-required'] ?? fieldCtx.required\n\n return (\n <RadioGroupPrimitive.Root\n className={cn('grid gap-ds-03', className)}\n aria-invalid={isError || undefined}\n aria-describedby={ariaDescribedBy}\n aria-required={ariaRequired || undefined}\n {...props}\n ref={ref}\n />\n )\n})\nRadioGroup.displayName = RadioGroupPrimitive.Root.displayName\n\nexport interface RadioGroupItemProps extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item> {\n /** Control size — `sm` (20px), `md` (24px, default, WCAG compliant), `lg` (28px). */\n size?: 'sm' | 'md' | 'lg'\n}\n\nconst radioSizeClasses = {\n sm: 'h-5 w-5',\n md: 'h-6 w-6',\n lg: 'h-7 w-7',\n} as const\n\nconst radioIndicatorClasses = {\n sm: 'h-1.5 w-1.5',\n md: 'h-ds-03 w-ds-03',\n lg: 'h-2.5 w-2.5',\n} as const\n\nconst RadioGroupItem = React.forwardRef<\n React.ElementRef<typeof RadioGroupPrimitive.Item>,\n RadioGroupItemProps\n>(({ className, size = 'md', ...props }, ref) => {\n return (\n <RadioGroupPrimitive.Item\n ref={ref}\n className={cn(\n 'touch-target aspect-square rounded-pill',\n radioSizeClasses[size],\n 'border border-surface-border-strong bg-surface-raised-hover',\n 'transition-colors duration-fast-01',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2',\n 'disabled:cursor-not-allowed disabled:opacity-action-disabled',\n 'hover:border-accent-7 hover:bg-surface-raised-active',\n 'data-[state=checked]:border-accent-7',\n className,\n )}\n {...props}\n >\n <RadioGroupPrimitive.Indicator asChild className=\"flex items-center justify-center\">\n <motion.span\n className=\"flex items-center justify-center\"\n initial={{ scale: 0 }}\n animate={{ scale: 1 }}\n transition={springs.bouncy}\n >\n <IconCircle className={cn(radioIndicatorClasses[size], 'fill-accent-9 text-accent-11')} />\n </motion.span>\n </RadioGroupPrimitive.Indicator>\n </RadioGroupPrimitive.Item>\n )\n})\nRadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName\n\nexport type RadioGroupProps = React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>\n\nexport { RadioGroup, RadioGroupItem }\n"],"mappings":";;;;;;;;;;AAWA,IAAM,IAAa,EAAM,YAGtB,EAAE,cAAW,GAAG,KAAS,MAAQ;CAClC,IAAM,IAAW,GAAc,EACzB,IAAU,EAAS,UAAU,SAC7B,IAAkB,EAAM,uBAAuB,EAAS,cACxD,IAAe,EAAM,oBAAoB,EAAS;AAExD,QACE,kBAAC,GAAD;EACE,WAAW,EAAG,kBAAkB,EAAU;EAC1C,gBAAc,KAAW,KAAA;EACzB,oBAAkB;EAClB,iBAAe,KAAgB,KAAA;EAC/B,GAAI;EACC;EACL,CAAA;EAEJ;AACF,EAAW,cAAA,EAAuC;AAOlD,IAAM,IAAmB;CACvB,IAAI;CACJ,IAAI;CACJ,IAAI;CACL,EAEK,IAAwB;CAC5B,IAAI;CACJ,IAAI;CACJ,IAAI;CACL,EAEK,IAAiB,EAAM,YAG1B,EAAE,cAAW,UAAO,MAAM,GAAG,KAAS,MAErC,kBAAC,GAAD;CACO;CACL,WAAW,EACT,2CACA,EAAiB,IACjB,+DACA,sCACA,6GACA,gEACA,wDACA,wCACA,EACD;CACD,GAAI;WAEJ,kBAAC,GAAD;EAA+B,SAAA;EAAQ,WAAU;YAC/C,kBAAC,EAAO,MAAR;GACE,WAAU;GACV,SAAS,EAAE,OAAO,GAAG;GACrB,SAAS,EAAE,OAAO,GAAG;GACrB,YAAY,EAAQ;aAEpB,kBAAC,GAAD,EAAY,WAAW,EAAG,EAAsB,IAAO,+BAA+B,EAAI,CAAA;GAC9E,CAAA;EACgB,CAAA;CACP,CAAA,CAE7B;AACF,EAAe,cAAA,EAAuC"}
1
+ {"version":3,"file":"radio.js","names":[],"sources":["../../src/ui/radio.tsx"],"sourcesContent":["'use client'\n\nimport * as RadioGroupPrimitive from '@primitives/react-radio-group'\nimport { IconCircle } from '@tabler/icons-react'\nimport { AnimatePresence, motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { useFormField } from './form'\nimport { springs } from './lib/motion'\nimport { cn } from './lib/utils'\n\nconst RadioGroup = React.forwardRef<\n React.ElementRef<typeof RadioGroupPrimitive.Root>,\n React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>\n>(({ className, ...props }, ref) => {\n const fieldCtx = useFormField()\n const isError = fieldCtx.state === 'error'\n const ariaDescribedBy = props['aria-describedby'] ?? fieldCtx.helperTextId\n const ariaRequired = props['aria-required'] ?? fieldCtx.required\n\n return (\n <RadioGroupPrimitive.Root\n className={cn('grid gap-ds-03', className)}\n aria-invalid={isError || undefined}\n aria-describedby={ariaDescribedBy}\n aria-required={ariaRequired || undefined}\n {...props}\n ref={ref}\n />\n )\n})\nRadioGroup.displayName = RadioGroupPrimitive.Root.displayName\n\nexport interface RadioGroupItemProps extends React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item> {\n /** Control size — `sm` (20px), `md` (24px, default, WCAG compliant), `lg` (28px). */\n size?: 'sm' | 'md' | 'lg'\n}\n\nconst radioSizeClasses = {\n sm: 'h-5 w-5',\n md: 'h-6 w-6',\n lg: 'h-7 w-7',\n} as const\n\nconst radioIndicatorClasses = {\n sm: 'h-1.5 w-1.5',\n md: 'h-ds-03 w-ds-03',\n lg: 'h-2.5 w-2.5',\n} as const\n\nconst RadioGroupItem = React.forwardRef<\n React.ElementRef<typeof RadioGroupPrimitive.Item>,\n RadioGroupItemProps\n>(({ className, size = 'md', ...props }, ref) => {\n return (\n <RadioGroupPrimitive.Item\n ref={ref}\n className={cn(\n 'touch-target aspect-square rounded-pill',\n radioSizeClasses[size],\n 'border border-surface-border-strong bg-surface-raised-hover',\n 'transition-colors duration-fast-01',\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2',\n 'disabled:cursor-not-allowed disabled:opacity-action-disabled',\n 'hover:border-accent-7 hover:bg-surface-raised-active',\n 'data-[state=checked]:border-accent-7',\n className,\n )}\n {...props}\n >\n <RadioGroupPrimitive.Indicator asChild className=\"flex items-center justify-center\">\n <motion.span\n className=\"flex items-center justify-center\"\n initial={{ scale: 0 }}\n animate={{ scale: 1 }}\n transition={springs.snappy}\n >\n <IconCircle className={cn(radioIndicatorClasses[size], 'fill-accent-9 text-accent-11')} />\n </motion.span>\n </RadioGroupPrimitive.Indicator>\n </RadioGroupPrimitive.Item>\n )\n})\nRadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName\n\nexport type RadioGroupProps = React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>\n\nexport { RadioGroup, RadioGroupItem }\n"],"mappings":";;;;;;;;;;AAWA,IAAM,IAAa,EAAM,YAGtB,EAAE,cAAW,GAAG,KAAS,MAAQ;CAClC,IAAM,IAAW,GAAc,EACzB,IAAU,EAAS,UAAU,SAC7B,IAAkB,EAAM,uBAAuB,EAAS,cACxD,IAAe,EAAM,oBAAoB,EAAS;AAExD,QACE,kBAAC,GAAD;EACE,WAAW,EAAG,kBAAkB,EAAU;EAC1C,gBAAc,KAAW,KAAA;EACzB,oBAAkB;EAClB,iBAAe,KAAgB,KAAA;EAC/B,GAAI;EACC;EACL,CAAA;EAEJ;AACF,EAAW,cAAA,EAAuC;AAOlD,IAAM,IAAmB;CACvB,IAAI;CACJ,IAAI;CACJ,IAAI;CACL,EAEK,IAAwB;CAC5B,IAAI;CACJ,IAAI;CACJ,IAAI;CACL,EAEK,IAAiB,EAAM,YAG1B,EAAE,cAAW,UAAO,MAAM,GAAG,KAAS,MAErC,kBAAC,GAAD;CACO;CACL,WAAW,EACT,2CACA,EAAiB,IACjB,+DACA,sCACA,6GACA,gEACA,wDACA,wCACA,EACD;CACD,GAAI;WAEJ,kBAAC,GAAD;EAA+B,SAAA;EAAQ,WAAU;YAC/C,kBAAC,EAAO,MAAR;GACE,WAAU;GACV,SAAS,EAAE,OAAO,GAAG;GACrB,SAAS,EAAE,OAAO,GAAG;GACrB,YAAY,EAAQ;aAEpB,kBAAC,GAAD,EAAY,WAAW,EAAG,EAAsB,IAAO,+BAA+B,EAAI,CAAA;GAC9E,CAAA;EACgB,CAAA;CACP,CAAA,CAE7B;AACF,EAAe,cAAA,EAAuC"}
@@ -5,8 +5,8 @@ import { t as n } from "../_chunks/vendor-utils.js";
5
5
  import { cn as r } from "./lib/utils.js";
6
6
  import { Icon as i } from "./icon.js";
7
7
  import { useIsMobile as a } from "../hooks/use-mobile.js";
8
- import { Button as o } from "./button.js";
9
- import { Skeleton as s } from "./skeleton.js";
8
+ import { Skeleton as o } from "./skeleton.js";
9
+ import { Button as s } from "./button.js";
10
10
  import { Input as c } from "./input.js";
11
11
  import { Separator as l } from "./separator.js";
12
12
  import { Tooltip as u, TooltipContent as d, TooltipProvider as f, TooltipTrigger as p } from "./tooltip.js";
@@ -138,15 +138,15 @@ var M = _(({ side: e = "left", variant: t = "sidebar", collapsible: n = "offcanv
138
138
  });
139
139
  M.displayName = "Sidebar";
140
140
  var N = _(({ className: e, onClick: t, ...n }, a) => {
141
- let { toggleSidebar: s } = A();
142
- return /* @__PURE__ */ E(o, {
141
+ let { toggleSidebar: o } = A();
142
+ return /* @__PURE__ */ E(s, {
143
143
  ref: a,
144
144
  "data-sidebar": "trigger",
145
145
  variant: "ghost",
146
146
  size: "icon-md",
147
147
  className: r("h-ds-xs-plus w-ds-xs-plus", e),
148
148
  onClick: (e) => {
149
- t?.(e), s();
149
+ t?.(e), o();
150
150
  },
151
151
  ...n,
152
152
  children: [/* @__PURE__ */ T(i, {
@@ -326,10 +326,10 @@ var X = _(({ className: e, showIcon: t = !1, ...n }, i) => {
326
326
  "data-sidebar": "menu-skeleton",
327
327
  className: r("flex h-ds-sm items-center gap-ds-03 rounded-control px-ds-03", e),
328
328
  ...n,
329
- children: [t && /* @__PURE__ */ T(s, {
329
+ children: [t && /* @__PURE__ */ T(o, {
330
330
  className: "h-ico-sm w-ico-sm rounded-control",
331
331
  "data-sidebar": "menu-skeleton-icon"
332
- }), /* @__PURE__ */ T(s, {
332
+ }), /* @__PURE__ */ T(o, {
333
333
  className: "h-4 max-w-(--skeleton-width) flex-1",
334
334
  "data-sidebar": "menu-skeleton-text",
335
335
  style: { "--skeleton-width": a }
@@ -1 +1 @@
1
- {"version":3,"file":"stat-card.d.ts","sourceRoot":"","sources":["../../src/ui/stat-card.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAiC,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAGrE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAKjD,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAY,MAAM,cAAc,CAAA;AAE1F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IACxF,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IACtB,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE;QACN,KAAK,EAAE,MAAM,CAAA;QACb,SAAS,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CAAA;KACrC,CAAA;IACD,kJAAkJ;IAClJ,cAAc,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAA;IACnC,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,sEAAsE;IACtE,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,kEAAkE;IAClE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,qFAAqF;IACrF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,+IAA+I;IAC/I,OAAO,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,CAAA;IACrD;;;;OAIG;IACH,IAAI,CAAC,EAAE,QAAQ,CAAA;IACf,yJAAyJ;IACzJ,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAA;IACtC,uGAAuG;IACvG,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IAC3B;;;;OAIG;IACH,KAAK,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;IAC/B,iFAAiF;IACjF,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,yEAAyE;IACzE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,yEAAyE;IACzE,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CACzB;AA+FD,QAAA,MAAM,QAAQ,sFA0Qb,CAAA;AAID,OAAO,EAAE,QAAQ,EAAE,CAAA"}
1
+ {"version":3,"file":"stat-card.d.ts","sourceRoot":"","sources":["../../src/ui/stat-card.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAiC,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAGrE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAMjD,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAY,MAAM,cAAc,CAAA;AAE1F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,MAAM,WAAW,aAAc,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IACxF,oEAAoE;IACpE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;IACtB,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE;QACN,KAAK,EAAE,MAAM,CAAA;QACb,SAAS,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CAAA;KACrC,CAAA;IACD,kJAAkJ;IAClJ,cAAc,CAAC,EAAE,OAAO,GAAG,QAAQ,CAAA;IACnC,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,sEAAsE;IACtE,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,kEAAkE;IAClE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,qFAAqF;IACrF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,+IAA+I;IAC/I,OAAO,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,CAAA;IACrD;;;;OAIG;IACH,IAAI,CAAC,EAAE,QAAQ,CAAA;IACf,yJAAyJ;IACzJ,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAA;IACtC,uGAAuG;IACvG,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IAC3B;;;;OAIG;IACH,KAAK,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;IAC/B,iFAAiF;IACjF,UAAU,CAAC,EAAE,UAAU,CAAA;IACvB,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,+CAA+C;IAC/C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IACpB,yEAAyE;IACzE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,yEAAyE;IACzE,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CACzB;AA+FD,QAAA,MAAM,QAAQ,sFA0Qb,CAAA;AAID,OAAO,EAAE,QAAQ,EAAE,CAAA"}
@@ -3,16 +3,17 @@ import { IconProvider as e } from "./icon-context.js";
3
3
  import { springs as t, tweens as n } from "./lib/motion.js";
4
4
  import { cn as r } from "./lib/utils.js";
5
5
  import { Icon as i } from "./icon.js";
6
- import { t as a } from "../_chunks/normalize-icon.js";
7
- import { Card as o, CardContent as s, CardFooter as c } from "./card.js";
6
+ import { Skeleton as a } from "./skeleton.js";
7
+ import { t as o } from "../_chunks/normalize-icon.js";
8
+ import { Card as s, CardContent as c, CardFooter as ee } from "./card.js";
8
9
  import { n as l } from "../_chunks/link-context.js";
9
10
  import { StatFlash as u } from "./stat-flash.js";
10
11
  import * as d from "react";
11
12
  import { Fragment as f, jsx as p, jsxs as m } from "react/jsx-runtime";
12
- import { IconMinus as h, IconTrendingDown as ee, IconTrendingUp as g } from "@tabler/icons-react";
13
- import { motion as _ } from "framer-motion";
13
+ import { IconMinus as h, IconTrendingDown as g, IconTrendingUp as _ } from "@tabler/icons-react";
14
+ import { motion as v } from "framer-motion";
14
15
  //#region src/ui/stat-card.tsx
15
- function v(e, t, n) {
16
+ function y(e, t, n) {
16
17
  let r = e.filter((e) => Number.isFinite(e));
17
18
  if (r.length < 2) return "";
18
19
  let i = Math.min(...r), a = Math.max(...r) - i || 1, o = t / (r.length - 1);
@@ -21,8 +22,8 @@ function v(e, t, n) {
21
22
  return `${t === 0 ? "M" : "L"}${r.toFixed(1)},${s.toFixed(1)}`;
22
23
  }).join(" ");
23
24
  }
24
- function y({ data: e, colorClass: t }) {
25
- let n = d.useId(), i = d.useRef(null), [a, o] = d.useState(0), s = v(e, 80, 32);
25
+ function b({ data: e, colorClass: t }) {
26
+ let n = d.useId(), i = d.useRef(null), [a, o] = d.useState(0), s = y(e, 80, 32);
26
27
  if (d.useEffect(() => {
27
28
  i.current && o(i.current.getTotalLength());
28
29
  }, [s]), !s) return null;
@@ -74,7 +75,7 @@ function y({ data: e, colorClass: t }) {
74
75
  }), a > 0 && /* @__PURE__ */ p("style", { children: `@keyframes sparkline-draw-${n.replace(/:/g, "")} { to { stroke-dashoffset: 0; } }` })]
75
76
  });
76
77
  }
77
- function b({ progress: e, label: t }) {
78
+ function x({ progress: e, label: t }) {
78
79
  let n = Math.max(0, Math.min(100, e)), i = n >= 90 ? "bg-success-9" : n >= 70 ? "bg-warning-9" : "bg-accent-9";
79
80
  return /* @__PURE__ */ p("div", {
80
81
  className: "h-1 w-full rounded-pill bg-surface-raised",
@@ -89,25 +90,25 @@ function b({ progress: e, label: t }) {
89
90
  })
90
91
  });
91
92
  }
92
- var x = d.forwardRef(({ className: d, label: v, title: x, value: S, prefix: C, suffix: w, delta: T, deltaPlacement: E = "block", icon: D, loading: O, comparisonLabel: k, secondaryLabel: A, progress: j, variant: M = "default", size: N = "md", accentStyle: P = "none", iconFill: F = "soft", flash: I, flashSpeed: L, sparkline: R, onClick: z, href: B, footer: V, ...H }, U) => {
93
- let W = l(), G = x ?? v ?? "", K = (z || B) && !H["aria-label"] ? `View ${G}` : H["aria-label"];
94
- if (O) return /* @__PURE__ */ p(o, {
93
+ var S = d.forwardRef(({ className: d, label: y, title: S, value: C, prefix: w, suffix: T, delta: E, deltaPlacement: D = "block", icon: O, loading: te, comparisonLabel: k, secondaryLabel: A, progress: j, variant: M = "default", size: N = "md", accentStyle: P = "none", iconFill: F = "soft", flash: I, flashSpeed: L, sparkline: R, onClick: z, href: B, footer: V, ...H }, U) => {
94
+ let W = l(), G = S ?? y ?? "", K = (z || B) && !H["aria-label"] ? `View ${G}` : H["aria-label"];
95
+ if (te) return /* @__PURE__ */ p(s, {
95
96
  ref: U,
96
97
  variant: M,
97
98
  size: N,
98
99
  className: d,
99
100
  "aria-busy": "true",
100
101
  ...H,
101
- children: /* @__PURE__ */ m(s, {
102
+ children: /* @__PURE__ */ m(c, {
102
103
  className: "flex flex-col gap-ds-03",
103
104
  children: [
104
- /* @__PURE__ */ p("div", { className: "h-ds-04 w-24 rounded-control-inner bg-skeleton-base animate-pulse" }),
105
- /* @__PURE__ */ p("div", { className: "h-ds-sm w-32 rounded-control bg-skeleton-base animate-pulse" }),
106
- /* @__PURE__ */ p("div", { className: "h-3 w-16 rounded-control-inner bg-skeleton-base animate-pulse" })
105
+ /* @__PURE__ */ p(a, { className: "h-ds-04 w-24 rounded-control-inner" }),
106
+ /* @__PURE__ */ p(a, { className: "h-ds-sm w-32" }),
107
+ /* @__PURE__ */ p(a, { className: "h-3 w-16 rounded-control-inner" })
107
108
  ]
108
109
  })
109
110
  });
110
- let q = T?.direction === "up" ? g : T?.direction === "down" ? ee : h, J = T?.direction === "up" ? "text-success-11" : T?.direction === "down" ? "text-error-11" : "text-surface-fg-muted", Y = T?.direction === "up" ? "text-success-11" : T?.direction === "down" ? "text-error-11" : "text-accent-11", X = T ? /* @__PURE__ */ m(_.div, {
111
+ let q = E?.direction === "up" ? _ : E?.direction === "down" ? g : h, J = E?.direction === "up" ? "text-success-11" : E?.direction === "down" ? "text-error-11" : "text-surface-fg-muted", Y = E?.direction === "up" ? "text-success-11" : E?.direction === "down" ? "text-error-11" : "text-accent-11", X = E ? /* @__PURE__ */ m(v.div, {
111
112
  className: r("flex items-center gap-ds-02 text-ds-sm font-medium", J),
112
113
  initial: {
113
114
  opacity: 0,
@@ -122,7 +123,7 @@ var x = d.forwardRef(({ className: d, label: v, title: x, value: S, prefix: C, s
122
123
  delay: .2
123
124
  },
124
125
  children: [
125
- /* @__PURE__ */ p(_.span, {
126
+ /* @__PURE__ */ p(v.span, {
126
127
  className: "inline-flex",
127
128
  initial: {
128
129
  opacity: .5,
@@ -132,13 +133,13 @@ var x = d.forwardRef(({ className: d, label: v, title: x, value: S, prefix: C, s
132
133
  opacity: 1,
133
134
  scale: 1
134
135
  },
135
- transition: t.bouncy,
136
+ transition: t.smooth,
136
137
  children: /* @__PURE__ */ p(i, {
137
138
  icon: q,
138
139
  size: "sm"
139
140
  })
140
141
  }),
141
- /* @__PURE__ */ p("span", { children: T.value }),
142
+ /* @__PURE__ */ p("span", { children: E.value }),
142
143
  k && /* @__PURE__ */ p("span", {
143
144
  className: "text-surface-fg-subtle font-normal",
144
145
  children: k
@@ -147,7 +148,7 @@ var x = d.forwardRef(({ className: d, label: v, title: x, value: S, prefix: C, s
147
148
  }) : null, Z = /* @__PURE__ */ m(f, { children: [
148
149
  /* @__PURE__ */ m("div", {
149
150
  className: "flex items-center justify-between",
150
- children: [/* @__PURE__ */ p(_.p, {
151
+ children: [/* @__PURE__ */ p(v.p, {
151
152
  className: "text-ds-md font-medium text-surface-fg-muted",
152
153
  initial: { opacity: 0 },
153
154
  animate: { opacity: 1 },
@@ -155,15 +156,15 @@ var x = d.forwardRef(({ className: d, label: v, title: x, value: S, prefix: C, s
155
156
  children: G
156
157
  }), /* @__PURE__ */ m("div", {
157
158
  className: "flex items-center gap-ds-03",
158
- children: [R && R.length >= 2 && /* @__PURE__ */ p(y, {
159
+ children: [R && R.length >= 2 && /* @__PURE__ */ p(b, {
159
160
  data: R,
160
161
  colorClass: Y
161
- }), D && I ? /* @__PURE__ */ p(u, {
162
- icon: D,
162
+ }), O && I ? /* @__PURE__ */ p(u, {
163
+ icon: O,
163
164
  flash: I,
164
165
  fill: F,
165
166
  speed: L
166
- }) : D ? P === "icon" ? /* @__PURE__ */ p(_.span, {
167
+ }) : O ? P === "icon" ? /* @__PURE__ */ p(v.span, {
167
168
  className: r("inline-flex items-center justify-center rounded-control p-ds-02", F === "solid" ? "bg-accent-9 text-accent-fg" : "bg-accent-3 text-accent-11"),
168
169
  initial: {
169
170
  opacity: 0,
@@ -177,9 +178,9 @@ var x = d.forwardRef(({ className: d, label: v, title: x, value: S, prefix: C, s
177
178
  "aria-hidden": "true",
178
179
  children: /* @__PURE__ */ p(e, {
179
180
  size: "md",
180
- children: a(D, "md")
181
+ children: o(O, "md")
181
182
  })
182
- }) : /* @__PURE__ */ p(_.span, {
183
+ }) : /* @__PURE__ */ p(v.span, {
183
184
  className: "text-surface-fg-muted",
184
185
  initial: {
185
186
  opacity: 0,
@@ -193,7 +194,7 @@ var x = d.forwardRef(({ className: d, label: v, title: x, value: S, prefix: C, s
193
194
  "aria-hidden": "true",
194
195
  children: /* @__PURE__ */ p(e, {
195
196
  size: "lg",
196
- children: a(D, "lg")
197
+ children: o(O, "lg")
197
198
  })
198
199
  }) : null]
199
200
  })]
@@ -201,10 +202,10 @@ var x = d.forwardRef(({ className: d, label: v, title: x, value: S, prefix: C, s
201
202
  /* @__PURE__ */ m("div", {
202
203
  className: "flex flex-col gap-ds-01",
203
204
  children: [/* @__PURE__ */ m("div", {
204
- className: r(E === "inline" && T && "flex items-baseline gap-ds-03"),
205
+ className: r(D === "inline" && E && "flex items-baseline gap-ds-03"),
205
206
  children: [/* @__PURE__ */ p("div", {
206
207
  className: "overflow-hidden",
207
- children: /* @__PURE__ */ m(_.p, {
208
+ children: /* @__PURE__ */ m(v.p, {
208
209
  className: r("inline-block font-semibold", N === "sm" ? "text-ds-2xl" : "text-ds-3xl", P === "tint" ? "text-accent-11" : "text-surface-fg"),
209
210
  initial: {
210
211
  opacity: 0,
@@ -216,22 +217,22 @@ var x = d.forwardRef(({ className: d, label: v, title: x, value: S, prefix: C, s
216
217
  },
217
218
  transition: t.smooth,
218
219
  children: [
219
- C && /* @__PURE__ */ p("span", {
220
+ w && /* @__PURE__ */ p("span", {
220
221
  className: r("text-surface-fg-muted", N === "sm" ? "text-ds-md" : "text-ds-lg"),
221
- children: C
222
+ children: w
222
223
  }),
223
224
  /* @__PURE__ */ p("span", {
224
225
  className: "tabular-nums",
225
- children: S
226
+ children: C
226
227
  }),
227
- w && /* @__PURE__ */ p("span", {
228
+ T && /* @__PURE__ */ p("span", {
228
229
  className: r("text-surface-fg-muted", N === "sm" ? "text-ds-md" : "text-ds-lg"),
229
- children: w
230
+ children: T
230
231
  })
231
232
  ]
232
233
  })
233
- }), E === "inline" && X]
234
- }), A && /* @__PURE__ */ p(_.p, {
234
+ }), D === "inline" && X]
235
+ }), A && /* @__PURE__ */ p(v.p, {
235
236
  className: "text-ds-sm text-surface-fg-subtle",
236
237
  initial: { opacity: 0 },
237
238
  animate: { opacity: 1 },
@@ -242,28 +243,28 @@ var x = d.forwardRef(({ className: d, label: v, title: x, value: S, prefix: C, s
242
243
  children: A
243
244
  })]
244
245
  }),
245
- j != null && /* @__PURE__ */ p(_.div, {
246
+ j != null && /* @__PURE__ */ p(v.div, {
246
247
  initial: { opacity: 0 },
247
248
  animate: { opacity: 1 },
248
249
  transition: {
249
250
  ...n.fade,
250
251
  delay: .15
251
252
  },
252
- children: /* @__PURE__ */ p(b, {
253
+ children: /* @__PURE__ */ p(x, {
253
254
  progress: j,
254
255
  label: G
255
256
  })
256
257
  }),
257
- E === "block" && X
258
- ] }), Q = P === "tint" ? "bg-linear-to-t from-accent-2 to-surface-raised" : void 0, $ = /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p(s, {
258
+ D === "block" && X
259
+ ] }), Q = P === "tint" ? "bg-linear-to-t from-accent-2 to-surface-raised" : void 0, $ = /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p(c, {
259
260
  className: "flex flex-col gap-ds-03",
260
261
  children: Z
261
262
  }), V && /* @__PURE__ */ m(f, { children: [/* @__PURE__ */ p("div", {
262
263
  "aria-hidden": "true",
263
264
  className: "h-px w-full bg-surface-border-subtle"
264
- }), /* @__PURE__ */ p(c, {
265
+ }), /* @__PURE__ */ p(ee, {
265
266
  className: "text-ds-sm",
266
- children: /* @__PURE__ */ p(_.div, {
267
+ children: /* @__PURE__ */ p(v.div, {
267
268
  className: "w-full",
268
269
  initial: { opacity: 0 },
269
270
  animate: { opacity: 1 },
@@ -281,14 +282,14 @@ var x = d.forwardRef(({ className: d, label: v, title: x, value: S, prefix: C, s
281
282
  className: "block no-underline",
282
283
  "aria-label": K,
283
284
  ...H,
284
- children: /* @__PURE__ */ p(o, {
285
+ children: /* @__PURE__ */ p(s, {
285
286
  variant: M,
286
287
  size: N,
287
288
  interactive: !0,
288
289
  className: Q,
289
290
  children: $
290
291
  })
291
- }) : z ? /* @__PURE__ */ p(o, {
292
+ }) : z ? /* @__PURE__ */ p(s, {
292
293
  ref: U,
293
294
  variant: M,
294
295
  size: N,
@@ -303,7 +304,7 @@ var x = d.forwardRef(({ className: d, label: v, title: x, value: S, prefix: C, s
303
304
  },
304
305
  ...H,
305
306
  children: $
306
- }) : /* @__PURE__ */ p(o, {
307
+ }) : /* @__PURE__ */ p(s, {
307
308
  ref: U,
308
309
  variant: M,
309
310
  size: N,
@@ -312,6 +313,6 @@ var x = d.forwardRef(({ className: d, label: v, title: x, value: S, prefix: C, s
312
313
  children: $
313
314
  });
314
315
  });
315
- x.displayName = "StatCard";
316
+ S.displayName = "StatCard";
316
317
  //#endregion
317
- export { x as StatCard };
318
+ export { S as StatCard };
@@ -1 +1 @@
1
- {"version":3,"file":"stat-card.js","names":[],"sources":["../../src/ui/stat-card.tsx"],"sourcesContent":["'use client'\n\nimport { IconMinus, IconTrendingDown, IconTrendingUp } from '@tabler/icons-react'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Card, CardContent, CardFooter, type CardSize } from './card'\nimport { Icon } from './icon'\nimport { IconProvider } from './icon-context'\nimport type { IconInput } from './lib/icon-input'\nimport { useLink } from './lib/link-context'\nimport { springs, tweens } from './lib/motion'\nimport { normalizeIcon } from './lib/normalize-icon'\nimport { cn } from './lib/utils'\nimport { type FlashPreset, type FlashSpec, type FlashSpeed,StatFlash } from './stat-flash'\n\n/**\n * Props for StatCard — a dashboard metric tile displaying a label, a large numeric value,\n * an optional trend delta (with directional arrow icon), and an optional header icon.\n *\n * **Surface:** delegated to `Card` via `variant` — `default` (ring-in-shadow, no border) |\n * `elevated` | `outline` (border, no shadow) | `flat`. StatCard composes `<Card>`, so the surface,\n * padding (gap model), and elevation all live in one place.\n *\n * **Accent:** `accentStyle=\"none\"` (default) is neutral; `\"icon\"` wraps `icon` in an accent chip\n * (`iconFill=\"soft\" | \"solid\"`); `\"tint\"` applies a subtle accent surface wash + accent value.\n * (Replaces the removed `accent` left-rail prop — see CHANGELOG migration.)\n *\n * **Delta direction:** `'up'` renders a green trending-up arrow, `'down'` renders a red\n * trending-down arrow, `'neutral'` renders a grey dash. The `delta.value` is a formatted\n * string (e.g. `\"+8%\"` or `\"−120\"`).\n *\n * **Loading state:** Pass `loading={true}` to render a pulse-skeleton placeholder instead of data.\n *\n * @example\n * // Revenue metric with a positive trend:\n * <StatCard\n * label=\"Monthly Revenue\"\n * value=\"$48,200\"\n * delta={{ value: \"+12%\", direction: \"up\" }}\n * icon={<IconCurrencyDollar />}\n * />\n *\n * @example\n * // Open ticket count with a downward trend (good for support queues):\n * <StatCard\n * label=\"Open Tickets\"\n * value={142}\n * delta={{ value: \"−18\", direction: \"down\" }}\n * />\n *\n * @example\n * // Loading skeleton while data is fetching:\n * <StatCard label=\"Users\" value={0} loading={isFetching} />\n *\n * @example\n * // Simple metric with no trend (stable, neutral):\n * <StatCard\n * label=\"Storage Used\"\n * value=\"4.2 GB\"\n * delta={{ value: \"No change\", direction: \"neutral\" }}\n * />\n * // These are just a few ways — feel free to combine props creatively!\n */\nexport interface StatCardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color'> {\n /** Heading text for the metric. `title` is an alias for `label`. */\n label?: string\n /** Alias for `label` — use whichever feels natural. */\n title?: string\n value: string | number\n /** Prefix before value, e.g. \"$\" */\n prefix?: string\n /** Suffix after value, e.g. \"users\" */\n suffix?: string\n delta?: {\n value: string\n direction: 'up' | 'down' | 'neutral'\n }\n /** Where the delta sits relative to the value: `block` (below — default) or `inline` (on the value's baseline, to its right). @default 'block' */\n deltaPlacement?: 'block' | 'inline'\n icon?: IconInput\n loading?: boolean\n /** Comparison period label shown after delta, e.g. \"vs last month\" */\n comparisonLabel?: string\n /** Secondary metric below main value, e.g. \"of $50,000 target\" */\n secondaryLabel?: string\n /** Progress toward a target (0-100). Renders a thin progress bar below the value. */\n progress?: number\n /** Surface variant, delegated to Card: `default` (ring-in-shadow) | `elevated` | `outline` (border, no shadow) | `flat`. @default 'default' */\n variant?: 'default' | 'elevated' | 'outline' | 'flat'\n /**\n * Tile density, delegated to Card's size axis. `sm` tightens padding to 16px and steps\n * the value down to `text-ds-2xl` — use it for dense KPI rows and narrow stat grids\n * (e.g. stat-row's 140px tiles). @default 'md'\n */\n size?: CardSize\n /** How the brand accent reads: `none` (neutral — default), `icon` (accent chip around `icon`), or `tint` (subtle accent surface wash + accent value). */\n accentStyle?: 'none' | 'icon' | 'tint'\n /** When `accentStyle=\"icon\"`: `soft` (tinted chip) or `solid` (filled accent chip). @default 'soft' */\n iconFill?: 'soft' | 'solid'\n /**\n * Opt-in entrance flash: the icon chip mounts showing a transient state (e.g. a green up-arrow)\n * then settles to `icon`. A preset (`'up' | 'down' | 'goal' | 'record' | 'alert' | 'live'`) or an\n * explicit `{ tone, icon }`. Requires `icon`; implies the icon chip. Off by default.\n */\n flash?: FlashPreset | FlashSpec\n /** Speed of the entrance flash: `fast` | `normal` | `slow`. @default 'normal' */\n flashSpeed?: FlashSpeed\n /** Sparkline data points. Renders a mini SVG line chart in the card. */\n sparkline?: number[]\n /** Make the card clickable with hover state */\n onClick?: () => void\n /** Href — makes the card a link (uses the LinkContext Link component) */\n href?: string\n /** Footer content rendered below the card body, e.g. \"View details →\" */\n footer?: React.ReactNode\n}\n\nfunction buildSparklinePath(raw: number[], width: number, height: number): string {\n const data = raw.filter((v) => Number.isFinite(v))\n if (data.length < 2) return ''\n const min = Math.min(...data)\n const max = Math.max(...data)\n const range = max - min || 1\n const stepX = width / (data.length - 1)\n return data\n .map((v, i) => {\n const x = i * stepX\n const y = height - ((v - min) / range) * height\n return `${i === 0 ? 'M' : 'L'}${x.toFixed(1)},${y.toFixed(1)}`\n })\n .join(' ')\n}\n\nfunction Sparkline({\n data,\n colorClass,\n}: {\n data: number[]\n colorClass: string\n}) {\n const id = React.useId()\n const pathRef = React.useRef<SVGPathElement>(null)\n const [pathLength, setPathLength] = React.useState(0)\n const svgWidth = 80\n const svgHeight = 32\n const path = buildSparklinePath(data, svgWidth, svgHeight)\n\n React.useEffect(() => {\n if (pathRef.current) {\n setPathLength(pathRef.current.getTotalLength())\n }\n }, [path])\n\n if (!path) return null\n\n // Build area fill path (close to bottom-right then bottom-left)\n const areaPath = `${path} L${svgWidth.toFixed(1)},${svgHeight.toFixed(1)} L0,${svgHeight.toFixed(1)} Z`\n\n return (\n <div className={cn('w-20 h-8', colorClass)} aria-hidden=\"true\">\n <svg\n viewBox={`0 0 ${svgWidth} ${svgHeight}`}\n className=\"w-full h-full overflow-visible\"\n preserveAspectRatio=\"none\"\n >\n <defs>\n <linearGradient id={`sparkline-fill-${id}`} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stopColor=\"currentColor\" stopOpacity=\"0.1\" />\n <stop offset=\"100%\" stopColor=\"currentColor\" stopOpacity=\"0\" />\n </linearGradient>\n </defs>\n <path d={areaPath} fill={`url(#sparkline-fill-${id})`} />\n <path\n ref={pathRef}\n d={path}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n style={{\n opacity: pathLength === 0 ? 0 : 1,\n strokeDasharray: pathLength,\n strokeDashoffset: pathLength,\n animation: pathLength > 0 ? `sparkline-draw-${id.replace(/:/g, '')} 1s ease-out forwards` : 'none',\n }}\n />\n </svg>\n {pathLength > 0 && (\n <style>{`@keyframes sparkline-draw-${id.replace(/:/g, '')} { to { stroke-dashoffset: 0; } }`}</style>\n )}\n </div>\n )\n}\n\nfunction ProgressBar({ progress, label }: { progress: number; label: string }) {\n const clamped = Math.max(0, Math.min(100, progress))\n const barColor =\n clamped >= 90 ? 'bg-success-9' : clamped >= 70 ? 'bg-warning-9' : 'bg-accent-9'\n\n return (\n <div className=\"h-1 w-full rounded-pill bg-surface-raised\" role=\"progressbar\" aria-label={`${label} progress`} aria-valuenow={clamped} aria-valuemin={0} aria-valuemax={100}>\n <div\n className={cn('h-full rounded-pill transition-[width] duration-moderate-02 ease-productive-standard', barColor)}\n style={{ width: `${clamped}%` }}\n />\n </div>\n )\n}\n\nconst StatCard = React.forwardRef<HTMLDivElement, StatCardProps>(\n (\n {\n className,\n label,\n title,\n value,\n prefix,\n suffix,\n delta,\n deltaPlacement = 'block',\n icon,\n loading,\n comparisonLabel,\n secondaryLabel,\n progress,\n variant = 'default',\n size = 'md',\n accentStyle = 'none',\n iconFill = 'soft',\n flash,\n flashSpeed,\n sparkline,\n onClick,\n href,\n footer,\n ...props\n },\n ref,\n ) => {\n const Link = useLink()\n const resolvedLabel = title ?? label ?? ''\n const isClickable = !!(onClick || href)\n const computedAriaLabel =\n isClickable && !props['aria-label'] ? `View ${resolvedLabel}` : props['aria-label']\n\n if (loading) {\n return (\n <Card ref={ref} variant={variant} size={size} className={className} aria-busy=\"true\" {...props}>\n <CardContent className=\"flex flex-col gap-ds-03\">\n <div className=\"h-ds-04 w-24 rounded-control-inner bg-skeleton-base animate-pulse\" />\n <div className=\"h-ds-sm w-32 rounded-control bg-skeleton-base animate-pulse\" />\n <div className=\"h-3 w-16 rounded-control-inner bg-skeleton-base animate-pulse\" />\n </CardContent>\n </Card>\n )\n }\n\n const DeltaIcon =\n delta?.direction === 'up'\n ? IconTrendingUp\n : delta?.direction === 'down'\n ? IconTrendingDown\n : IconMinus\n\n const deltaColour =\n delta?.direction === 'up'\n ? 'text-success-11'\n : delta?.direction === 'down'\n ? 'text-error-11'\n : 'text-surface-fg-muted'\n\n const sparklineColor =\n delta?.direction === 'up'\n ? 'text-success-11'\n : delta?.direction === 'down'\n ? 'text-error-11'\n : 'text-accent-11'\n\n const deltaNode = delta ? (\n <motion.div\n className={cn(\n // Rhythm comes from CardContent's flex gap — no placement margins.\n 'flex items-center gap-ds-02 text-ds-sm font-medium',\n deltaColour,\n )}\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ ...springs.smooth, delay: 0.2 }}\n >\n <motion.span\n className=\"inline-flex\"\n initial={{ opacity: 0.5, scale: 1.4 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={springs.bouncy}\n >\n <Icon icon={DeltaIcon} size=\"sm\" />\n </motion.span>\n <span>{delta.value}</span>\n {comparisonLabel && (\n <span className=\"text-surface-fg-subtle font-normal\">{comparisonLabel}</span>\n )}\n </motion.div>\n ) : null\n\n const cardContent = (\n <>\n <div className=\"flex items-center justify-between\">\n <motion.p\n className=\"text-ds-md font-medium text-surface-fg-muted\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={tweens.fade}\n >\n {resolvedLabel}\n </motion.p>\n <div className=\"flex items-center gap-ds-03\">\n {sparkline && sparkline.length >= 2 && (\n <Sparkline data={sparkline} colorClass={sparklineColor} />\n )}\n {icon && flash ? (\n <StatFlash icon={icon} flash={flash} fill={iconFill} speed={flashSpeed} />\n ) : icon ? (\n accentStyle === 'icon' ? (\n <motion.span\n className={cn(\n 'inline-flex items-center justify-center rounded-control p-ds-02',\n iconFill === 'solid'\n ? 'bg-accent-9 text-accent-fg'\n : 'bg-accent-3 text-accent-11',\n )}\n initial={{ opacity: 0, scale: 0.96 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={springs.snappy}\n aria-hidden=\"true\"\n >\n <IconProvider size=\"md\">{normalizeIcon(icon, 'md')}</IconProvider>\n </motion.span>\n ) : (\n <motion.span\n className=\"text-surface-fg-muted\"\n initial={{ opacity: 0, scale: 0.96 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={springs.snappy}\n aria-hidden=\"true\"\n >\n <IconProvider size=\"lg\">{normalizeIcon(icon, 'lg')}</IconProvider>\n </motion.span>\n )\n ) : null}\n </div>\n </div>\n <div className=\"flex flex-col gap-ds-01\">\n <div className={cn(deltaPlacement === 'inline' && delta && 'flex items-baseline gap-ds-03')}>\n <div className=\"overflow-hidden\">\n <motion.p\n className={cn(\n 'inline-block font-semibold',\n size === 'sm' ? 'text-ds-2xl' : 'text-ds-3xl',\n accentStyle === 'tint' ? 'text-accent-11' : 'text-surface-fg',\n )}\n initial={{ opacity: 0, y: '100%' }}\n animate={{ opacity: 1, y: 0 }}\n transition={springs.smooth}\n >\n {prefix && (\n <span className={cn('text-surface-fg-muted', size === 'sm' ? 'text-ds-md' : 'text-ds-lg')}>{prefix}</span>\n )}\n <span className=\"tabular-nums\">{value}</span>\n {suffix && (\n <span className={cn('text-surface-fg-muted', size === 'sm' ? 'text-ds-md' : 'text-ds-lg')}>{suffix}</span>\n )}\n </motion.p>\n </div>\n {deltaPlacement === 'inline' && deltaNode}\n </div>\n {secondaryLabel && (\n <motion.p\n className=\"text-ds-sm text-surface-fg-subtle\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ ...tweens.fade, delay: 0.1 }}\n >\n {secondaryLabel}\n </motion.p>\n )}\n </div>\n {progress != null && (\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ ...tweens.fade, delay: 0.15 }}\n >\n <ProgressBar progress={progress} label={resolvedLabel} />\n </motion.div>\n )}\n {deltaPlacement === 'block' && deltaNode}\n </>\n )\n\n // accentStyle=\"tint\" → a subtle accent gradient wash over Card's surface.\n const tintClass =\n accentStyle === 'tint' ? 'bg-linear-to-t from-accent-2 to-surface-raised' : undefined\n // Footer sits outside CardContent behind a full-width divider (both are direct\n // children of Card, so the rule spans edge-to-edge — no inset border-t).\n const body = (\n <>\n <CardContent className=\"flex flex-col gap-ds-03\">{cardContent}</CardContent>\n {footer && (\n <>\n <div aria-hidden=\"true\" className=\"h-px w-full bg-surface-border-subtle\" />\n <CardFooter className=\"text-ds-sm\">\n <motion.div\n className=\"w-full\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ ...tweens.fade, delay: 0.25 }}\n >\n {footer}\n </motion.div>\n </CardFooter>\n </>\n )}\n </>\n )\n\n // href → wrap Card in the framework Link (Card stays the shell; hover-lift inside).\n if (href) {\n return (\n <Link\n ref={ref as React.Ref<HTMLAnchorElement>}\n href={href}\n onClick={onClick}\n className=\"block no-underline\"\n aria-label={computedAriaLabel}\n {...(props as React.AnchorHTMLAttributes<HTMLAnchorElement>)}\n >\n <Card variant={variant} size={size} interactive className={tintClass}>\n {body}\n </Card>\n </Link>\n )\n }\n\n // onClick → interactive Card with button semantics + keyboard activation.\n if (onClick) {\n return (\n <Card\n ref={ref}\n variant={variant}\n size={size}\n interactive\n className={cn(tintClass, className)}\n role=\"button\"\n tabIndex={0}\n aria-label={computedAriaLabel}\n onClick={onClick}\n onKeyDown={(e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n onClick()\n }\n }}\n {...props}\n >\n {body}\n </Card>\n )\n }\n\n return (\n <Card ref={ref} variant={variant} size={size} className={cn(tintClass, className)} {...props}>\n {body}\n </Card>\n )\n },\n)\n\nStatCard.displayName = 'StatCard'\n\nexport { StatCard }\n"],"mappings":";;;;;;;;;;;;;;AAsHA,SAAS,EAAmB,GAAe,GAAe,GAAwB;CAChF,IAAM,IAAO,EAAI,QAAQ,MAAM,OAAO,SAAS,EAAE,CAAC;AAClD,KAAI,EAAK,SAAS,EAAG,QAAO;CAC5B,IAAM,IAAM,KAAK,IAAI,GAAG,EAAK,EAEvB,IADM,KAAK,IAAI,GAAG,EAAK,GACT,KAAO,GACrB,IAAQ,KAAS,EAAK,SAAS;AACrC,QAAO,EACJ,KAAK,GAAG,MAAM;EACb,IAAM,IAAI,IAAI,GACR,IAAI,KAAW,IAAI,KAAO,IAAS;AACzC,SAAO,GAAG,MAAM,IAAI,MAAM,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,EAAE,QAAQ,EAAE;GAC5D,CACD,KAAK,IAAI;;AAGd,SAAS,EAAU,EACjB,SACA,iBAIC;CACD,IAAM,IAAK,EAAM,OAAO,EAClB,IAAU,EAAM,OAAuB,KAAK,EAC5C,CAAC,GAAY,KAAiB,EAAM,SAAS,EAAE,EAG/C,IAAO,EAAmB,GAAM,IAAU,GAAU;AAQ1D,KANA,EAAM,gBAAgB;AACpB,EAAI,EAAQ,WACV,EAAc,EAAQ,QAAQ,gBAAgB,CAAC;IAEhD,CAAC,EAAK,CAAC,EAEN,CAAC,EAAM,QAAO;CAGlB,IAAM,IAAW,GAAG,EAAK,IAAI,IAAS,QAAQ,EAAE,CAAC,GAAG,IAAU,QAAQ,EAAE,CAAC,MAAM,IAAU,QAAQ,EAAE,CAAC;AAEpG,QACE,kBAAC,OAAD;EAAK,WAAW,EAAG,YAAY,EAAW;EAAE,eAAY;YAAxD,CACE,kBAAC,OAAD;GACE,SAAS;GACT,WAAU;GACV,qBAAoB;aAHtB;IAKE,kBAAC,QAAD,EAAA,UACE,kBAAC,kBAAD;KAAgB,IAAI,kBAAkB;KAAM,IAAG;KAAI,IAAG;KAAI,IAAG;KAAI,IAAG;eAApE,CACE,kBAAC,QAAD;MAAM,QAAO;MAAK,WAAU;MAAe,aAAY;MAAQ,CAAA,EAC/D,kBAAC,QAAD;MAAM,QAAO;MAAO,WAAU;MAAe,aAAY;MAAM,CAAA,CAChD;QACZ,CAAA;IACP,kBAAC,QAAD;KAAM,GAAG;KAAU,MAAM,uBAAuB,EAAG;KAAM,CAAA;IACzD,kBAAC,QAAD;KACE,KAAK;KACL,GAAG;KACH,MAAK;KACL,QAAO;KACP,aAAY;KACZ,eAAc;KACd,gBAAe;KACf,OAAO;MACL,SAAS,MAAe,IAAI,IAAI;MAChC,iBAAiB;MACjB,kBAAkB;MAClB,WAAW,IAAa,IAAI,kBAAkB,EAAG,QAAQ,MAAM,GAAG,CAAC,yBAAyB;MAC7F;KACD,CAAA;IACE;MACL,IAAa,KACZ,kBAAC,SAAD,EAAA,UAAQ,6BAA6B,EAAG,QAAQ,MAAM,GAAG,CAAC,oCAA2C,CAAA,CAEnG;;;AAIV,SAAS,EAAY,EAAE,aAAU,YAA8C;CAC7E,IAAM,IAAU,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,EAAS,CAAC,EAC9C,IACJ,KAAW,KAAK,iBAAiB,KAAW,KAAK,iBAAiB;AAEpE,QACE,kBAAC,OAAD;EAAK,WAAU;EAA4C,MAAK;EAAc,cAAY,GAAG,EAAM;EAAY,iBAAe;EAAS,iBAAe;EAAG,iBAAe;YACtK,kBAAC,OAAD;GACE,WAAW,EAAG,wFAAwF,EAAS;GAC/G,OAAO,EAAE,OAAO,GAAG,EAAQ,IAAI;GAC/B,CAAA;EACE,CAAA;;AAIV,IAAM,IAAW,EAAM,YAEnB,EACE,cACA,UACA,UACA,UACA,WACA,WACA,UACA,oBAAiB,SACjB,SACA,YACA,oBACA,mBACA,aACA,aAAU,WACV,UAAO,MACP,iBAAc,QACd,cAAW,QACX,UACA,eACA,cACA,YACA,SACA,WACA,GAAG,KAEL,MACG;CACH,IAAM,IAAO,GAAS,EAChB,IAAgB,KAAS,KAAS,IAElC,KADiB,KAAW,MAEjB,CAAC,EAAM,gBAAgB,QAAQ,MAAkB,EAAM;AAExE,KAAI,EACF,QACE,kBAAC,GAAD;EAAW;EAAc;EAAe;EAAiB;EAAW,aAAU;EAAO,GAAI;YACvF,kBAAC,GAAD;GAAa,WAAU;aAAvB;IACE,kBAAC,OAAD,EAAK,WAAU,qEAAsE,CAAA;IACrF,kBAAC,OAAD,EAAK,WAAU,+DAAgE,CAAA;IAC/E,kBAAC,OAAD,EAAK,WAAU,iEAAkE,CAAA;IACrE;;EACT,CAAA;CAIX,IAAM,IACJ,GAAO,cAAc,OACjB,IACA,GAAO,cAAc,SACnB,KACA,GAEF,IACJ,GAAO,cAAc,OACjB,oBACA,GAAO,cAAc,SACnB,kBACA,yBAEF,IACJ,GAAO,cAAc,OACjB,oBACA,GAAO,cAAc,SACnB,kBACA,kBAEF,IAAY,IAChB,kBAAC,EAAO,KAAR;EACE,WAAW,EAET,sDACA,EACD;EACD,SAAS;GAAE,SAAS;GAAG,GAAG;GAAG;EAC7B,SAAS;GAAE,SAAS;GAAG,GAAG;GAAG;EAC7B,YAAY;GAAE,GAAG,EAAQ;GAAQ,OAAO;GAAK;YAR/C;GAUE,kBAAC,EAAO,MAAR;IACE,WAAU;IACV,SAAS;KAAE,SAAS;KAAK,OAAO;KAAK;IACrC,SAAS;KAAE,SAAS;KAAG,OAAO;KAAG;IACjC,YAAY,EAAQ;cAEpB,kBAAC,GAAD;KAAM,MAAM;KAAW,MAAK;KAAO,CAAA;IACvB,CAAA;GACd,kBAAC,QAAD,EAAA,UAAO,EAAM,OAAa,CAAA;GACzB,KACC,kBAAC,QAAD;IAAM,WAAU;cAAsC;IAAuB,CAAA;GAEpE;MACX,MAEE,IACJ,kBAAA,GAAA,EAAA,UAAA;EACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,EAAO,GAAR;IACE,WAAU;IACV,SAAS,EAAE,SAAS,GAAG;IACvB,SAAS,EAAE,SAAS,GAAG;IACvB,YAAY,EAAO;cAElB;IACQ,CAAA,EACX,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,KAAa,EAAU,UAAU,KAChC,kBAAC,GAAD;KAAW,MAAM;KAAW,YAAY;KAAkB,CAAA,EAE3D,KAAQ,IACP,kBAAC,GAAD;KAAiB;KAAa;KAAO,MAAM;KAAU,OAAO;KAAc,CAAA,GACxE,IACF,MAAgB,SACd,kBAAC,EAAO,MAAR;KACE,WAAW,EACT,mEACA,MAAa,UACT,+BACA,6BACL;KACD,SAAS;MAAE,SAAS;MAAG,OAAO;MAAM;KACpC,SAAS;MAAE,SAAS;MAAG,OAAO;MAAG;KACjC,YAAY,EAAQ;KACpB,eAAY;eAEZ,kBAAC,GAAD;MAAc,MAAK;gBAAM,EAAc,GAAM,KAAK;MAAgB,CAAA;KACtD,CAAA,GAEd,kBAAC,EAAO,MAAR;KACE,WAAU;KACV,SAAS;MAAE,SAAS;MAAG,OAAO;MAAM;KACpC,SAAS;MAAE,SAAS;MAAG,OAAO;MAAG;KACjC,YAAY,EAAQ;KACpB,eAAY;eAEZ,kBAAC,GAAD;MAAc,MAAK;gBAAM,EAAc,GAAM,KAAK;MAAgB,CAAA;KACtD,CAAA,GAEd,KACA;MACF;;EACN,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAW,EAAG,MAAmB,YAAY,KAAS,gCAAgC;cAA3F,CACE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,EAAO,GAAR;MACE,WAAW,EACT,8BACA,MAAS,OAAO,gBAAgB,eAChC,MAAgB,SAAS,mBAAmB,kBAC7C;MACD,SAAS;OAAE,SAAS;OAAG,GAAG;OAAQ;MAClC,SAAS;OAAE,SAAS;OAAG,GAAG;OAAG;MAC7B,YAAY,EAAQ;gBARtB;OAUG,KACC,kBAAC,QAAD;QAAM,WAAW,EAAG,yBAAyB,MAAS,OAAO,eAAe,aAAa;kBAAG;QAAc,CAAA;OAE5G,kBAAC,QAAD;QAAM,WAAU;kBAAgB;QAAa,CAAA;OAC5C,KACC,kBAAC,QAAD;QAAM,WAAW,EAAG,yBAAyB,MAAS,OAAO,eAAe,aAAa;kBAAG;QAAc,CAAA;OAEnG;;KACP,CAAA,EACL,MAAmB,YAAY,EAC5B;OACL,KACC,kBAAC,EAAO,GAAR;IACE,WAAU;IACV,SAAS,EAAE,SAAS,GAAG;IACvB,SAAS,EAAE,SAAS,GAAG;IACvB,YAAY;KAAE,GAAG,EAAO;KAAM,OAAO;KAAK;cAEzC;IACQ,CAAA,CAET;;EACL,KAAY,QACX,kBAAC,EAAO,KAAR;GACE,SAAS,EAAE,SAAS,GAAG;GACvB,SAAS,EAAE,SAAS,GAAG;GACvB,YAAY;IAAE,GAAG,EAAO;IAAM,OAAO;IAAM;aAE3C,kBAAC,GAAD;IAAuB;IAAU,OAAO;IAAiB,CAAA;GAC9C,CAAA;EAEd,MAAmB,WAAW;EAC9B,EAAA,CAAA,EAIC,IACJ,MAAgB,SAAS,mDAAmD,KAAA,GAGxE,IACJ,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD;EAAa,WAAU;YAA2B;EAA0B,CAAA,EAC3E,KACC,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD;EAAK,eAAY;EAAO,WAAU;EAAyC,CAAA,EAC3E,kBAAC,GAAD;EAAY,WAAU;YACpB,kBAAC,EAAO,KAAR;GACE,WAAU;GACV,SAAS,EAAE,SAAS,GAAG;GACvB,SAAS,EAAE,SAAS,GAAG;GACvB,YAAY;IAAE,GAAG,EAAO;IAAM,OAAO;IAAM;aAE1C;GACU,CAAA;EACF,CAAA,CACZ,EAAA,CAAA,CAEJ,EAAA,CAAA;AA+CL,QA3CI,IAEA,kBAAC,GAAD;EACO;EACC;EACG;EACT,WAAU;EACV,cAAY;EACZ,GAAK;YAEL,kBAAC,GAAD;GAAe;GAAe;GAAM,aAAA;GAAY,WAAW;aACxD;GACI,CAAA;EACF,CAAA,GAKP,IAEA,kBAAC,GAAD;EACO;EACI;EACH;EACN,aAAA;EACA,WAAW,EAAG,GAAW,EAAU;EACnC,MAAK;EACL,UAAU;EACV,cAAY;EACH;EACT,YAAY,MAA2B;AACrC,IAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,SACjC,EAAE,gBAAgB,EAClB,GAAS;;EAGb,GAAI;YAEH;EACI,CAAA,GAKT,kBAAC,GAAD;EAAW;EAAc;EAAe;EAAM,WAAW,EAAG,GAAW,EAAU;EAAE,GAAI;YACpF;EACI,CAAA;EAGZ;AAED,EAAS,cAAc"}
1
+ {"version":3,"file":"stat-card.js","names":[],"sources":["../../src/ui/stat-card.tsx"],"sourcesContent":["'use client'\n\nimport { IconMinus, IconTrendingDown, IconTrendingUp } from '@tabler/icons-react'\nimport { motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Card, CardContent, CardFooter, type CardSize } from './card'\nimport { Icon } from './icon'\nimport { IconProvider } from './icon-context'\nimport type { IconInput } from './lib/icon-input'\nimport { useLink } from './lib/link-context'\nimport { springs, tweens } from './lib/motion'\nimport { normalizeIcon } from './lib/normalize-icon'\nimport { cn } from './lib/utils'\nimport { Skeleton } from './skeleton'\nimport { type FlashPreset, type FlashSpec, type FlashSpeed,StatFlash } from './stat-flash'\n\n/**\n * Props for StatCard — a dashboard metric tile displaying a label, a large numeric value,\n * an optional trend delta (with directional arrow icon), and an optional header icon.\n *\n * **Surface:** delegated to `Card` via `variant` — `default` (ring-in-shadow, no border) |\n * `elevated` | `outline` (border, no shadow) | `flat`. StatCard composes `<Card>`, so the surface,\n * padding (gap model), and elevation all live in one place.\n *\n * **Accent:** `accentStyle=\"none\"` (default) is neutral; `\"icon\"` wraps `icon` in an accent chip\n * (`iconFill=\"soft\" | \"solid\"`); `\"tint\"` applies a subtle accent surface wash + accent value.\n * (Replaces the removed `accent` left-rail prop — see CHANGELOG migration.)\n *\n * **Delta direction:** `'up'` renders a green trending-up arrow, `'down'` renders a red\n * trending-down arrow, `'neutral'` renders a grey dash. The `delta.value` is a formatted\n * string (e.g. `\"+8%\"` or `\"−120\"`).\n *\n * **Loading state:** Pass `loading={true}` to render a pulse-skeleton placeholder instead of data.\n *\n * @example\n * // Revenue metric with a positive trend:\n * <StatCard\n * label=\"Monthly Revenue\"\n * value=\"$48,200\"\n * delta={{ value: \"+12%\", direction: \"up\" }}\n * icon={<IconCurrencyDollar />}\n * />\n *\n * @example\n * // Open ticket count with a downward trend (good for support queues):\n * <StatCard\n * label=\"Open Tickets\"\n * value={142}\n * delta={{ value: \"−18\", direction: \"down\" }}\n * />\n *\n * @example\n * // Loading skeleton while data is fetching:\n * <StatCard label=\"Users\" value={0} loading={isFetching} />\n *\n * @example\n * // Simple metric with no trend (stable, neutral):\n * <StatCard\n * label=\"Storage Used\"\n * value=\"4.2 GB\"\n * delta={{ value: \"No change\", direction: \"neutral\" }}\n * />\n * // These are just a few ways — feel free to combine props creatively!\n */\nexport interface StatCardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color'> {\n /** Heading text for the metric. `title` is an alias for `label`. */\n label?: string\n /** Alias for `label` — use whichever feels natural. */\n title?: string\n value: string | number\n /** Prefix before value, e.g. \"$\" */\n prefix?: string\n /** Suffix after value, e.g. \"users\" */\n suffix?: string\n delta?: {\n value: string\n direction: 'up' | 'down' | 'neutral'\n }\n /** Where the delta sits relative to the value: `block` (below — default) or `inline` (on the value's baseline, to its right). @default 'block' */\n deltaPlacement?: 'block' | 'inline'\n icon?: IconInput\n loading?: boolean\n /** Comparison period label shown after delta, e.g. \"vs last month\" */\n comparisonLabel?: string\n /** Secondary metric below main value, e.g. \"of $50,000 target\" */\n secondaryLabel?: string\n /** Progress toward a target (0-100). Renders a thin progress bar below the value. */\n progress?: number\n /** Surface variant, delegated to Card: `default` (ring-in-shadow) | `elevated` | `outline` (border, no shadow) | `flat`. @default 'default' */\n variant?: 'default' | 'elevated' | 'outline' | 'flat'\n /**\n * Tile density, delegated to Card's size axis. `sm` tightens padding to 16px and steps\n * the value down to `text-ds-2xl` — use it for dense KPI rows and narrow stat grids\n * (e.g. stat-row's 140px tiles). @default 'md'\n */\n size?: CardSize\n /** How the brand accent reads: `none` (neutral — default), `icon` (accent chip around `icon`), or `tint` (subtle accent surface wash + accent value). */\n accentStyle?: 'none' | 'icon' | 'tint'\n /** When `accentStyle=\"icon\"`: `soft` (tinted chip) or `solid` (filled accent chip). @default 'soft' */\n iconFill?: 'soft' | 'solid'\n /**\n * Opt-in entrance flash: the icon chip mounts showing a transient state (e.g. a green up-arrow)\n * then settles to `icon`. A preset (`'up' | 'down' | 'goal' | 'record' | 'alert' | 'live'`) or an\n * explicit `{ tone, icon }`. Requires `icon`; implies the icon chip. Off by default.\n */\n flash?: FlashPreset | FlashSpec\n /** Speed of the entrance flash: `fast` | `normal` | `slow`. @default 'normal' */\n flashSpeed?: FlashSpeed\n /** Sparkline data points. Renders a mini SVG line chart in the card. */\n sparkline?: number[]\n /** Make the card clickable with hover state */\n onClick?: () => void\n /** Href — makes the card a link (uses the LinkContext Link component) */\n href?: string\n /** Footer content rendered below the card body, e.g. \"View details →\" */\n footer?: React.ReactNode\n}\n\nfunction buildSparklinePath(raw: number[], width: number, height: number): string {\n const data = raw.filter((v) => Number.isFinite(v))\n if (data.length < 2) return ''\n const min = Math.min(...data)\n const max = Math.max(...data)\n const range = max - min || 1\n const stepX = width / (data.length - 1)\n return data\n .map((v, i) => {\n const x = i * stepX\n const y = height - ((v - min) / range) * height\n return `${i === 0 ? 'M' : 'L'}${x.toFixed(1)},${y.toFixed(1)}`\n })\n .join(' ')\n}\n\nfunction Sparkline({\n data,\n colorClass,\n}: {\n data: number[]\n colorClass: string\n}) {\n const id = React.useId()\n const pathRef = React.useRef<SVGPathElement>(null)\n const [pathLength, setPathLength] = React.useState(0)\n const svgWidth = 80\n const svgHeight = 32\n const path = buildSparklinePath(data, svgWidth, svgHeight)\n\n React.useEffect(() => {\n if (pathRef.current) {\n setPathLength(pathRef.current.getTotalLength())\n }\n }, [path])\n\n if (!path) return null\n\n // Build area fill path (close to bottom-right then bottom-left)\n const areaPath = `${path} L${svgWidth.toFixed(1)},${svgHeight.toFixed(1)} L0,${svgHeight.toFixed(1)} Z`\n\n return (\n <div className={cn('w-20 h-8', colorClass)} aria-hidden=\"true\">\n <svg\n viewBox={`0 0 ${svgWidth} ${svgHeight}`}\n className=\"w-full h-full overflow-visible\"\n preserveAspectRatio=\"none\"\n >\n <defs>\n <linearGradient id={`sparkline-fill-${id}`} x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stopColor=\"currentColor\" stopOpacity=\"0.1\" />\n <stop offset=\"100%\" stopColor=\"currentColor\" stopOpacity=\"0\" />\n </linearGradient>\n </defs>\n <path d={areaPath} fill={`url(#sparkline-fill-${id})`} />\n <path\n ref={pathRef}\n d={path}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n style={{\n opacity: pathLength === 0 ? 0 : 1,\n strokeDasharray: pathLength,\n strokeDashoffset: pathLength,\n animation: pathLength > 0 ? `sparkline-draw-${id.replace(/:/g, '')} 1s ease-out forwards` : 'none',\n }}\n />\n </svg>\n {pathLength > 0 && (\n <style>{`@keyframes sparkline-draw-${id.replace(/:/g, '')} { to { stroke-dashoffset: 0; } }`}</style>\n )}\n </div>\n )\n}\n\nfunction ProgressBar({ progress, label }: { progress: number; label: string }) {\n const clamped = Math.max(0, Math.min(100, progress))\n const barColor =\n clamped >= 90 ? 'bg-success-9' : clamped >= 70 ? 'bg-warning-9' : 'bg-accent-9'\n\n return (\n <div className=\"h-1 w-full rounded-pill bg-surface-raised\" role=\"progressbar\" aria-label={`${label} progress`} aria-valuenow={clamped} aria-valuemin={0} aria-valuemax={100}>\n <div\n className={cn('h-full rounded-pill transition-[width] duration-moderate-02 ease-productive-standard', barColor)}\n style={{ width: `${clamped}%` }}\n />\n </div>\n )\n}\n\nconst StatCard = React.forwardRef<HTMLDivElement, StatCardProps>(\n (\n {\n className,\n label,\n title,\n value,\n prefix,\n suffix,\n delta,\n deltaPlacement = 'block',\n icon,\n loading,\n comparisonLabel,\n secondaryLabel,\n progress,\n variant = 'default',\n size = 'md',\n accentStyle = 'none',\n iconFill = 'soft',\n flash,\n flashSpeed,\n sparkline,\n onClick,\n href,\n footer,\n ...props\n },\n ref,\n ) => {\n const Link = useLink()\n const resolvedLabel = title ?? label ?? ''\n const isClickable = !!(onClick || href)\n const computedAriaLabel =\n isClickable && !props['aria-label'] ? `View ${resolvedLabel}` : props['aria-label']\n\n if (loading) {\n return (\n <Card ref={ref} variant={variant} size={size} className={className} aria-busy=\"true\" {...props}>\n <CardContent className=\"flex flex-col gap-ds-03\">\n <Skeleton className=\"h-ds-04 w-24 rounded-control-inner\" />\n <Skeleton className=\"h-ds-sm w-32\" />\n <Skeleton className=\"h-3 w-16 rounded-control-inner\" />\n </CardContent>\n </Card>\n )\n }\n\n const DeltaIcon =\n delta?.direction === 'up'\n ? IconTrendingUp\n : delta?.direction === 'down'\n ? IconTrendingDown\n : IconMinus\n\n const deltaColour =\n delta?.direction === 'up'\n ? 'text-success-11'\n : delta?.direction === 'down'\n ? 'text-error-11'\n : 'text-surface-fg-muted'\n\n const sparklineColor =\n delta?.direction === 'up'\n ? 'text-success-11'\n : delta?.direction === 'down'\n ? 'text-error-11'\n : 'text-accent-11'\n\n const deltaNode = delta ? (\n <motion.div\n className={cn(\n // Rhythm comes from CardContent's flex gap — no placement margins.\n 'flex items-center gap-ds-02 text-ds-sm font-medium',\n deltaColour,\n )}\n initial={{ opacity: 0, y: 8 }}\n animate={{ opacity: 1, y: 0 }}\n transition={{ ...springs.smooth, delay: 0.2 }}\n >\n <motion.span\n className=\"inline-flex\"\n initial={{ opacity: 0.5, scale: 1.4 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={springs.smooth}\n >\n <Icon icon={DeltaIcon} size=\"sm\" />\n </motion.span>\n <span>{delta.value}</span>\n {comparisonLabel && (\n <span className=\"text-surface-fg-subtle font-normal\">{comparisonLabel}</span>\n )}\n </motion.div>\n ) : null\n\n const cardContent = (\n <>\n <div className=\"flex items-center justify-between\">\n <motion.p\n className=\"text-ds-md font-medium text-surface-fg-muted\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={tweens.fade}\n >\n {resolvedLabel}\n </motion.p>\n <div className=\"flex items-center gap-ds-03\">\n {sparkline && sparkline.length >= 2 && (\n <Sparkline data={sparkline} colorClass={sparklineColor} />\n )}\n {icon && flash ? (\n <StatFlash icon={icon} flash={flash} fill={iconFill} speed={flashSpeed} />\n ) : icon ? (\n accentStyle === 'icon' ? (\n <motion.span\n className={cn(\n 'inline-flex items-center justify-center rounded-control p-ds-02',\n iconFill === 'solid'\n ? 'bg-accent-9 text-accent-fg'\n : 'bg-accent-3 text-accent-11',\n )}\n initial={{ opacity: 0, scale: 0.96 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={springs.snappy}\n aria-hidden=\"true\"\n >\n <IconProvider size=\"md\">{normalizeIcon(icon, 'md')}</IconProvider>\n </motion.span>\n ) : (\n <motion.span\n className=\"text-surface-fg-muted\"\n initial={{ opacity: 0, scale: 0.96 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={springs.snappy}\n aria-hidden=\"true\"\n >\n <IconProvider size=\"lg\">{normalizeIcon(icon, 'lg')}</IconProvider>\n </motion.span>\n )\n ) : null}\n </div>\n </div>\n <div className=\"flex flex-col gap-ds-01\">\n <div className={cn(deltaPlacement === 'inline' && delta && 'flex items-baseline gap-ds-03')}>\n <div className=\"overflow-hidden\">\n <motion.p\n className={cn(\n 'inline-block font-semibold',\n size === 'sm' ? 'text-ds-2xl' : 'text-ds-3xl',\n accentStyle === 'tint' ? 'text-accent-11' : 'text-surface-fg',\n )}\n initial={{ opacity: 0, y: '100%' }}\n animate={{ opacity: 1, y: 0 }}\n transition={springs.smooth}\n >\n {prefix && (\n <span className={cn('text-surface-fg-muted', size === 'sm' ? 'text-ds-md' : 'text-ds-lg')}>{prefix}</span>\n )}\n <span className=\"tabular-nums\">{value}</span>\n {suffix && (\n <span className={cn('text-surface-fg-muted', size === 'sm' ? 'text-ds-md' : 'text-ds-lg')}>{suffix}</span>\n )}\n </motion.p>\n </div>\n {deltaPlacement === 'inline' && deltaNode}\n </div>\n {secondaryLabel && (\n <motion.p\n className=\"text-ds-sm text-surface-fg-subtle\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ ...tweens.fade, delay: 0.1 }}\n >\n {secondaryLabel}\n </motion.p>\n )}\n </div>\n {progress != null && (\n <motion.div\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ ...tweens.fade, delay: 0.15 }}\n >\n <ProgressBar progress={progress} label={resolvedLabel} />\n </motion.div>\n )}\n {deltaPlacement === 'block' && deltaNode}\n </>\n )\n\n // accentStyle=\"tint\" → a subtle accent gradient wash over Card's surface.\n const tintClass =\n accentStyle === 'tint' ? 'bg-linear-to-t from-accent-2 to-surface-raised' : undefined\n // Footer sits outside CardContent behind a full-width divider (both are direct\n // children of Card, so the rule spans edge-to-edge — no inset border-t).\n const body = (\n <>\n <CardContent className=\"flex flex-col gap-ds-03\">{cardContent}</CardContent>\n {footer && (\n <>\n <div aria-hidden=\"true\" className=\"h-px w-full bg-surface-border-subtle\" />\n <CardFooter className=\"text-ds-sm\">\n <motion.div\n className=\"w-full\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n transition={{ ...tweens.fade, delay: 0.25 }}\n >\n {footer}\n </motion.div>\n </CardFooter>\n </>\n )}\n </>\n )\n\n // href → wrap Card in the framework Link (Card stays the shell; hover-lift inside).\n if (href) {\n return (\n <Link\n ref={ref as React.Ref<HTMLAnchorElement>}\n href={href}\n onClick={onClick}\n className=\"block no-underline\"\n aria-label={computedAriaLabel}\n {...(props as React.AnchorHTMLAttributes<HTMLAnchorElement>)}\n >\n <Card variant={variant} size={size} interactive className={tintClass}>\n {body}\n </Card>\n </Link>\n )\n }\n\n // onClick → interactive Card with button semantics + keyboard activation.\n if (onClick) {\n return (\n <Card\n ref={ref}\n variant={variant}\n size={size}\n interactive\n className={cn(tintClass, className)}\n role=\"button\"\n tabIndex={0}\n aria-label={computedAriaLabel}\n onClick={onClick}\n onKeyDown={(e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n onClick()\n }\n }}\n {...props}\n >\n {body}\n </Card>\n )\n }\n\n return (\n <Card ref={ref} variant={variant} size={size} className={cn(tintClass, className)} {...props}>\n {body}\n </Card>\n )\n },\n)\n\nStatCard.displayName = 'StatCard'\n\nexport { StatCard }\n"],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import { VariantProps } from 'class-variance-authority';
2
+ import * as React from 'react';
3
+ declare const surfaceVariants: (props?: ({
4
+ elevation?: "flat" | "overlay" | "floating" | "raised" | null | undefined;
5
+ padding?: "none" | "sm" | "md" | "lg" | null | undefined;
6
+ radius?: "none" | "overlay" | "pill" | "surface" | "control" | null | undefined;
7
+ bordered?: boolean | null | undefined;
8
+ } & import('class-variance-authority/types').ClassProp) | undefined) => string;
9
+ export interface SurfaceProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof surfaceVariants> {
10
+ /** Render as the passed child element (Radix Slot) instead of a `div` — wrap a link,
11
+ * section, or `motion.div` without adding a wrapper node. */
12
+ asChild?: boolean;
13
+ }
14
+ /**
15
+ * Surface — the low-level elevated container primitive.
16
+ *
17
+ * The building block every panel, card, popover, and toast surface sits on. It owns
18
+ * exactly one job: paint a tokened surface (background + shadow), with optional radius,
19
+ * padding, and border. It has no slots, no color axis, and no motion — those belong to
20
+ * the components composed on top of it (Card = Surface + gap-model padding + slots).
21
+ *
22
+ * **Elevation:** `flat` (bg, no shadow — pair with `bordered`) | `raised` (card level,
23
+ * default) | `floating` (toasts, floating toolbars) | `overlay` (popovers, menus, dialogs).
24
+ *
25
+ * **Padding:** `none` (default) | `sm` (12px) | `md` (16px) | `lg` (24px) — simple all-side.
26
+ *
27
+ * **Edge vs. elevation:** use a shadow (`raised`/`floating`/`overlay`) OR a `bordered`
28
+ * `flat` — never both (the double-edge anti-pattern; dev-warns).
29
+ *
30
+ * @example
31
+ * // A raised panel with comfortable padding:
32
+ * <Surface elevation="raised" padding="md">…</Surface>
33
+ *
34
+ * @example
35
+ * // An on-page, border-led tile (no shadow):
36
+ * <Surface elevation="flat" bordered padding="sm">…</Surface>
37
+ *
38
+ * @example
39
+ * // Wrap a link as the surface itself:
40
+ * <Surface asChild elevation="raised" padding="sm">
41
+ * <a href="/upgrade">…</a>
42
+ * </Surface>
43
+ */
44
+ declare const Surface: React.ForwardRefExoticComponent<SurfaceProps & React.RefAttributes<HTMLDivElement>>;
45
+ export { Surface, surfaceVariants };
46
+ //# sourceMappingURL=surface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surface.d.ts","sourceRoot":"","sources":["../../src/ui/surface.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACjE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAO9B,QAAA,MAAM,eAAe;;;;;8EA0CnB,CAAA;AAEF,MAAM,WAAW,YACf,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAC1C,YAAY,CAAC,OAAO,eAAe,CAAC;IACtC;iEAC6D;IAC7D,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,QAAA,MAAM,OAAO,qFA2BZ,CAAA;AAGD,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,CAAA"}