@devalok/shilp-sutra 0.49.4 → 0.50.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 (243) hide show
  1. package/AGENTS.md +12 -4
  2. package/MIGRATION.md +6 -0
  3. package/dist/_chunks/badge-group.js +12 -11
  4. package/dist/_chunks/badge-group.js.map +1 -1
  5. package/dist/_chunks/block-shell.js +1 -1
  6. package/dist/_chunks/block-shell.js.map +1 -1
  7. package/dist/_chunks/chat.js +18 -18
  8. package/dist/_chunks/chat.js.map +1 -1
  9. package/dist/_chunks/document-preview.js +1 -1
  10. package/dist/_chunks/document-preview.js.map +1 -1
  11. package/dist/_chunks/emoji-suggestion.js +1 -1
  12. package/dist/_chunks/emoji-suggestion.js.map +1 -1
  13. package/dist/_chunks/grid-lines.js +2 -2
  14. package/dist/_chunks/grid-lines.js.map +1 -1
  15. package/dist/_chunks/image-preview.js +1 -1
  16. package/dist/_chunks/image-preview.js.map +1 -1
  17. package/dist/_chunks/mention-suggestion.js +2 -2
  18. package/dist/_chunks/mention-suggestion.js.map +1 -1
  19. package/dist/_chunks/oauth-button.js +8 -8
  20. package/dist/_chunks/oauth-button.js.map +1 -1
  21. package/dist/_chunks/shared.js +2 -2
  22. package/dist/_chunks/shared.js.map +1 -1
  23. package/dist/_chunks/success.js +5 -5
  24. package/dist/_chunks/success.js.map +1 -1
  25. package/dist/_chunks/tiptap.js +3956 -1796
  26. package/dist/_chunks/tiptap.js.map +1 -1
  27. package/dist/_chunks/tooltip.js +2 -2
  28. package/dist/_chunks/tooltip.js.map +1 -1
  29. package/dist/_chunks/tree-view.js +2 -2
  30. package/dist/_chunks/tree-view.js.map +1 -1
  31. package/dist/_chunks/use-calendar.js +3 -3
  32. package/dist/_chunks/use-calendar.js.map +1 -1
  33. package/dist/ai/block-renderer.js +1 -1
  34. package/dist/ai/block-renderer.js.map +1 -1
  35. package/dist/ai/blocks/error.js +1 -1
  36. package/dist/ai/blocks/error.js.map +1 -1
  37. package/dist/ai/command-bar.js +15 -15
  38. package/dist/ai/command-bar.js.map +1 -1
  39. package/dist/ai/conversation.js +6 -6
  40. package/dist/ai/conversation.js.map +1 -1
  41. package/dist/composed/activity-feed.js +4 -4
  42. package/dist/composed/activity-feed.js.map +1 -1
  43. package/dist/composed/avatar-group.js +6 -6
  44. package/dist/composed/avatar-group.js.map +1 -1
  45. package/dist/composed/bulk-action-bar.js +1 -1
  46. package/dist/composed/bulk-action-bar.js.map +1 -1
  47. package/dist/composed/command-palette.js +12 -12
  48. package/dist/composed/command-palette.js.map +1 -1
  49. package/dist/composed/content-card.js +1 -1
  50. package/dist/composed/content-card.js.map +1 -1
  51. package/dist/composed/date-picker/index.js +17 -17
  52. package/dist/composed/date-picker/index.js.map +1 -1
  53. package/dist/composed/deadline-indicator.js +2 -2
  54. package/dist/composed/deadline-indicator.js.map +1 -1
  55. package/dist/composed/diff.d.ts +108 -0
  56. package/dist/composed/diff.d.ts.map +1 -0
  57. package/dist/composed/diff.js +1004 -0
  58. package/dist/composed/diff.js.map +1 -0
  59. package/dist/composed/emoji-picker.js +6 -6
  60. package/dist/composed/emoji-picker.js.map +1 -1
  61. package/dist/composed/empty-state.js +2 -2
  62. package/dist/composed/empty-state.js.map +1 -1
  63. package/dist/composed/error-boundary.js +6 -6
  64. package/dist/composed/error-boundary.js.map +1 -1
  65. package/dist/composed/file-preview.js +5 -5
  66. package/dist/composed/file-preview.js.map +1 -1
  67. package/dist/composed/filter-bar.js +3 -3
  68. package/dist/composed/filter-bar.js.map +1 -1
  69. package/dist/composed/form-section.js +2 -2
  70. package/dist/composed/form-section.js.map +1 -1
  71. package/dist/composed/inline-edit.d.ts +1 -1
  72. package/dist/composed/inline-edit.d.ts.map +1 -1
  73. package/dist/composed/inline-edit.js.map +1 -1
  74. package/dist/composed/loading-skeleton.js +3 -3
  75. package/dist/composed/loading-skeleton.js.map +1 -1
  76. package/dist/composed/markdown-viewer.js +11 -11
  77. package/dist/composed/markdown-viewer.js.map +1 -1
  78. package/dist/composed/master-detail.js +1 -1
  79. package/dist/composed/master-detail.js.map +1 -1
  80. package/dist/composed/member-picker.js +2 -2
  81. package/dist/composed/member-picker.js.map +1 -1
  82. package/dist/composed/multi-select-popover.js +5 -5
  83. package/dist/composed/multi-select-popover.js.map +1 -1
  84. package/dist/composed/page-header.js +3 -3
  85. package/dist/composed/page-header.js.map +1 -1
  86. package/dist/composed/page-skeletons.js +4 -4
  87. package/dist/composed/page-skeletons.js.map +1 -1
  88. package/dist/composed/priority-indicator.js +1 -1
  89. package/dist/composed/priority-indicator.js.map +1 -1
  90. package/dist/composed/responsive-modal.js +2 -2
  91. package/dist/composed/responsive-modal.js.map +1 -1
  92. package/dist/composed/rich-chat-input.js +27 -27
  93. package/dist/composed/rich-chat-input.js.map +1 -1
  94. package/dist/composed/rich-text-editor.d.ts +81 -6
  95. package/dist/composed/rich-text-editor.d.ts.map +1 -1
  96. package/dist/composed/rich-text-editor.js +365 -210
  97. package/dist/composed/rich-text-editor.js.map +1 -1
  98. package/dist/composed/schedule-view.js +4 -4
  99. package/dist/composed/schedule-view.js.map +1 -1
  100. package/dist/shell/bottom-navbar.js +4 -4
  101. package/dist/shell/bottom-navbar.js.map +1 -1
  102. package/dist/shell/notification-center.js +13 -13
  103. package/dist/shell/notification-center.js.map +1 -1
  104. package/dist/shell/notification-preferences.js +10 -10
  105. package/dist/shell/notification-preferences.js.map +1 -1
  106. package/dist/shell/sidebar.js +9 -9
  107. package/dist/shell/sidebar.js.map +1 -1
  108. package/dist/shell/top-bar.js +8 -8
  109. package/dist/shell/top-bar.js.map +1 -1
  110. package/dist/tokens/semantic.css +6 -1
  111. package/dist/tokens/typography-semantic.css +6 -6
  112. package/dist/tokens/utilities.css +8 -0
  113. package/dist/ui/accordion.js +2 -2
  114. package/dist/ui/accordion.js.map +1 -1
  115. package/dist/ui/alert-dialog.js +4 -4
  116. package/dist/ui/alert-dialog.js.map +1 -1
  117. package/dist/ui/alert.js +1 -1
  118. package/dist/ui/alert.js.map +1 -1
  119. package/dist/ui/autocomplete.d.ts.map +1 -1
  120. package/dist/ui/autocomplete.js +11 -3
  121. package/dist/ui/autocomplete.js.map +1 -1
  122. package/dist/ui/avatar.js +5 -5
  123. package/dist/ui/avatar.js.map +1 -1
  124. package/dist/ui/badge-group.d.ts +2 -6
  125. package/dist/ui/badge-group.d.ts.map +1 -1
  126. package/dist/ui/badge-indicator.d.ts +2 -6
  127. package/dist/ui/badge-indicator.d.ts.map +1 -1
  128. package/dist/ui/badge-indicator.js +19 -18
  129. package/dist/ui/badge-indicator.js.map +1 -1
  130. package/dist/ui/badge.d.ts +2 -4
  131. package/dist/ui/badge.d.ts.map +1 -1
  132. package/dist/ui/banner.js +1 -1
  133. package/dist/ui/banner.js.map +1 -1
  134. package/dist/ui/breadcrumb.js +1 -1
  135. package/dist/ui/breadcrumb.js.map +1 -1
  136. package/dist/ui/button.js +7 -7
  137. package/dist/ui/button.js.map +1 -1
  138. package/dist/ui/card.d.ts +1 -1
  139. package/dist/ui/card.js +1 -1
  140. package/dist/ui/card.js.map +1 -1
  141. package/dist/ui/charts/gauge-chart.js +2 -2
  142. package/dist/ui/charts/gauge-chart.js.map +1 -1
  143. package/dist/ui/charts/pie-chart.js +1 -1
  144. package/dist/ui/charts/pie-chart.js.map +1 -1
  145. package/dist/ui/charts/radar-chart.d.ts +19 -1
  146. package/dist/ui/charts/radar-chart.d.ts.map +1 -1
  147. package/dist/ui/charts/radar-chart.js +80 -42
  148. package/dist/ui/charts/radar-chart.js.map +1 -1
  149. package/dist/ui/code.js +2 -2
  150. package/dist/ui/code.js.map +1 -1
  151. package/dist/ui/color-input.d.ts.map +1 -1
  152. package/dist/ui/color-input.js +164 -157
  153. package/dist/ui/color-input.js.map +1 -1
  154. package/dist/ui/combobox.d.ts.map +1 -1
  155. package/dist/ui/combobox.js +143 -142
  156. package/dist/ui/combobox.js.map +1 -1
  157. package/dist/ui/context-menu.js +6 -6
  158. package/dist/ui/context-menu.js.map +1 -1
  159. package/dist/ui/data-table-body.js +1 -1
  160. package/dist/ui/data-table-body.js.map +1 -1
  161. package/dist/ui/data-table-bulk-actions.js +1 -1
  162. package/dist/ui/data-table-bulk-actions.js.map +1 -1
  163. package/dist/ui/data-table-card.js +1 -1
  164. package/dist/ui/data-table-card.js.map +1 -1
  165. package/dist/ui/data-table-header.js +1 -1
  166. package/dist/ui/data-table-header.js.map +1 -1
  167. package/dist/ui/data-table-pagination.js +3 -3
  168. package/dist/ui/data-table-pagination.js.map +1 -1
  169. package/dist/ui/data-table-toolbar.js +1 -1
  170. package/dist/ui/data-table-toolbar.js.map +1 -1
  171. package/dist/ui/data-table.js +1 -1
  172. package/dist/ui/data-table.js.map +1 -1
  173. package/dist/ui/dialog.js +2 -2
  174. package/dist/ui/dialog.js.map +1 -1
  175. package/dist/ui/dot.js +4 -4
  176. package/dist/ui/dot.js.map +1 -1
  177. package/dist/ui/dropdown-menu.js +6 -6
  178. package/dist/ui/dropdown-menu.js.map +1 -1
  179. package/dist/ui/file-upload.js +5 -5
  180. package/dist/ui/file-upload.js.map +1 -1
  181. package/dist/ui/form.js +1 -1
  182. package/dist/ui/form.js.map +1 -1
  183. package/dist/ui/input-otp.d.ts.map +1 -1
  184. package/dist/ui/input-otp.js +3 -3
  185. package/dist/ui/input-otp.js.map +1 -1
  186. package/dist/ui/input.js +8 -8
  187. package/dist/ui/input.js.map +1 -1
  188. package/dist/ui/label.js +1 -1
  189. package/dist/ui/label.js.map +1 -1
  190. package/dist/ui/lib/utils.d.ts.map +1 -1
  191. package/dist/ui/lib/utils.js +42 -13
  192. package/dist/ui/lib/utils.js.map +1 -1
  193. package/dist/ui/menubar.js +7 -7
  194. package/dist/ui/menubar.js.map +1 -1
  195. package/dist/ui/navigation-menu.js +1 -1
  196. package/dist/ui/navigation-menu.js.map +1 -1
  197. package/dist/ui/number-input.d.ts.map +1 -1
  198. package/dist/ui/number-input.js +6 -5
  199. package/dist/ui/number-input.js.map +1 -1
  200. package/dist/ui/pagination.js +1 -1
  201. package/dist/ui/pagination.js.map +1 -1
  202. package/dist/ui/progress-ring.js +3 -3
  203. package/dist/ui/progress-ring.js.map +1 -1
  204. package/dist/ui/progress.js +2 -2
  205. package/dist/ui/progress.js.map +1 -1
  206. package/dist/ui/segmented-control.js +3 -3
  207. package/dist/ui/segmented-control.js.map +1 -1
  208. package/dist/ui/select.d.ts.map +1 -1
  209. package/dist/ui/select.js +7 -6
  210. package/dist/ui/select.js.map +1 -1
  211. package/dist/ui/sheet.js +2 -2
  212. package/dist/ui/sheet.js.map +1 -1
  213. package/dist/ui/sidebar.js +7 -7
  214. package/dist/ui/sidebar.js.map +1 -1
  215. package/dist/ui/split-button.js +6 -6
  216. package/dist/ui/split-button.js.map +1 -1
  217. package/dist/ui/stat-card.d.ts +1 -1
  218. package/dist/ui/stat-card.js +7 -7
  219. package/dist/ui/stat-card.js.map +1 -1
  220. package/dist/ui/stepper.js +3 -3
  221. package/dist/ui/stepper.js.map +1 -1
  222. package/dist/ui/table.js +3 -3
  223. package/dist/ui/table.js.map +1 -1
  224. package/dist/ui/tabs.js +3 -3
  225. package/dist/ui/tabs.js.map +1 -1
  226. package/dist/ui/text.d.ts.map +1 -1
  227. package/dist/ui/text.js.map +1 -1
  228. package/dist/ui/textarea.d.ts.map +1 -1
  229. package/dist/ui/textarea.js +7 -6
  230. package/dist/ui/textarea.js.map +1 -1
  231. package/dist/ui/toast.js +11 -11
  232. package/dist/ui/toast.js.map +1 -1
  233. package/dist/ui/toggle.js +3 -3
  234. package/dist/ui/toggle.js.map +1 -1
  235. package/dist/ui/tooltip.js +1 -1
  236. package/dist/ui/tooltip.js.map +1 -1
  237. package/docs/components/composed/diff.md +50 -0
  238. package/docs/components/ui/data-table.md +2 -2
  239. package/llms.txt +2 -1
  240. package/mcp-manifest.json +147 -3
  241. package/package.json +8 -1
  242. package/skill/SKILL.md +1 -1
  243. package/skill/references/components.md +2 -1
@@ -1 +1 @@
1
- {"version":3,"file":"avatar.js","names":[],"sources":["../../src/ui/avatar.tsx"],"sourcesContent":["'use client'\n\nimport * as AvatarPrimitive from \"@primitives/react-avatar\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { motion } from \"framer-motion\"\nimport * as React from \"react\"\n\nimport { Dot, type DotColor, type DotSize } from \"./dot\"\nimport { springs } from \"./lib/motion\"\nimport { cn } from \"./lib/utils\"\nimport { Skeleton } from \"./skeleton\"\n\n// ── Contexts so AvatarFallback can inherit shape & size from Avatar ──\ntype AvatarShape = 'circle' | 'square' | 'rounded'\ntype AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'\nconst AvatarShapeContext = React.createContext<AvatarShape>('circle')\nconst AvatarSizeContext = React.createContext<AvatarSize>('md')\n\nexport const avatarVariants = cva(\n 'relative flex shrink-0 overflow-hidden',\n {\n variants: {\n size: {\n xs: 'h-ds-xs w-ds-xs',\n sm: 'h-ds-sm w-ds-sm',\n md: 'h-ds-md w-ds-md',\n lg: 'h-ds-lg w-ds-lg',\n xl: 'h-ds-xl w-ds-xl',\n },\n shape: {\n circle: 'rounded-pill',\n square: 'rounded-none',\n rounded: 'rounded-control',\n },\n },\n defaultVariants: { size: 'md', shape: 'circle' },\n }\n)\n\nexport type AvatarStatus = 'online' | 'offline' | 'busy' | 'away'\n\nexport type AvatarRing = 'none' | 'lead' | 'admin' | 'client'\n\n// Presence status → shared Dot intent colour.\nconst statusDotColor: Record<AvatarStatus, DotColor> = {\n online: 'success',\n offline: 'neutral',\n busy: 'error',\n away: 'warning',\n}\n\nconst statusLabelMap: Record<AvatarStatus, string> = {\n online: 'Online',\n offline: 'Offline',\n busy: 'Busy',\n away: 'Away',\n}\n\n/** Avatar size → Dot size (the status dot scales with the avatar). */\nconst statusDotSize: Record<AvatarSize, DotSize> = {\n xs: 'xs',\n sm: 'sm',\n md: 'md',\n lg: 'lg',\n xl: 'lg',\n}\n\n// ── Role ring ───────────────────────────────────────────────────────────────\n\nconst ringColorMap: Record<Exclude<AvatarRing, 'none'>, string> = {\n lead: 'ring-accent-7',\n admin: 'ring-warning-7',\n client: 'ring-info-7',\n}\n\nconst ringShapeMap: Record<string, string> = {\n circle: 'rounded-pill',\n square: 'rounded-none',\n rounded: 'rounded-control',\n}\n\n// ── Fallback font sizes that scale with avatar size ─────────────────────────\nconst fallbackTextSizeMap: Record<AvatarSize, string> = {\n xs: 'text-ds-2xs',\n sm: 'text-ds-xs',\n md: 'text-ds-sm',\n lg: 'text-ds-md',\n xl: 'text-ds-lg',\n}\n\n// ── Deterministic fallback colors ───────────────────────────────────────────\n\nconst FALLBACK_COLORS = [\n { bg: 'bg-accent-3', text: 'text-accent-11' },\n { bg: 'bg-success-3', text: 'text-success-11' },\n { bg: 'bg-warning-3', text: 'text-warning-11' },\n { bg: 'bg-error-3', text: 'text-error-11' },\n { bg: 'bg-info-3', text: 'text-info-11' },\n { bg: 'bg-category-teal-3', text: 'text-category-teal-11' },\n { bg: 'bg-category-indigo-3', text: 'text-category-indigo-11' },\n { bg: 'bg-category-cyan-3', text: 'text-category-cyan-11' },\n] as const\n\n/**\n * Simple string hash that produces a deterministic index into FALLBACK_COLORS.\n * Uses djb2 for a reasonable distribution with short strings.\n */\nfunction getFallbackColor(seed: string): (typeof FALLBACK_COLORS)[number] {\n let hash = 5381\n for (let i = 0; i < seed.length; i++) {\n hash = ((hash << 5) + hash + seed.charCodeAt(i)) | 0\n }\n const index = Math.abs(hash) % FALLBACK_COLORS.length\n return FALLBACK_COLORS[index]\n}\n\n/**\n * Props for Avatar — a user/entity image container with size, shape, and presence-status variants.\n *\n * **Sizes:** `xs` | `sm` | `md` (default) | `lg` | `xl` — the status dot scales with the avatar size.\n *\n * **Shapes:** `circle` (default, round) | `square` (sharp corners) | `rounded` (rounded corners, for bots/apps)\n *\n * **Status dot:** `status=\"online\"` (green) | `\"offline\"` (muted) | `\"busy\"` (red) | `\"away\"` (amber).\n * The dot renders with `role=\"img\"` and an accessible `aria-label` — it is not purely decorative.\n *\n * **Role ring:** `ring=\"lead\"` (accent) | `\"admin\"` (warning) | `\"client\"` (info) — a colored ring\n * around the avatar indicating the user's role.\n *\n * **Badge:** `badge={5}` (number) | `badge=\"dot\"` (notification dot) | `badge={<Icon />}` (custom).\n * Numbers > 99 display as \"99+\". Badge is hidden when `0` or `undefined`.\n *\n * **Loading:** `loading={true}` shows a pulse skeleton placeholder.\n *\n * **Children:** Use `<AvatarImage>` for the photo and `<AvatarFallback>` for initials when the image fails.\n *\n * @example\n * // User avatar with photo and fallback initials:\n * <Avatar size=\"md\">\n * <AvatarImage src={user.avatarUrl} alt={user.name} />\n * <AvatarFallback>JD</AvatarFallback>\n * </Avatar>\n *\n * @example\n * // Online presence indicator in a team roster:\n * <Avatar size=\"lg\" status=\"online\">\n * <AvatarImage src={user.photoUrl} alt={user.name} />\n * <AvatarFallback>{user.initials}</AvatarFallback>\n * </Avatar>\n *\n * @example\n * // Square shape for a bot/integration logo:\n * <Avatar shape=\"square\" size=\"xl\">\n * <AvatarImage src=\"/logos/github.png\" alt=\"GitHub\" />\n * </Avatar>\n * // These are just a few ways — feel free to combine props creatively!\n */\nexport interface AvatarProps\n extends Omit<React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>, 'children'>,\n VariantProps<typeof avatarVariants> {\n /** Optional status indicator displayed as a dot at the bottom-right corner */\n status?: AvatarStatus\n /** Role ring color indicator */\n ring?: AvatarRing\n /** Badge overlay: number, 'dot', or custom ReactNode */\n badge?: number | 'dot' | React.ReactNode\n /** Show loading skeleton instead of content */\n loading?: boolean\n children?: React.ReactNode\n}\n\nconst Avatar = React.forwardRef<\n React.ElementRef<typeof AvatarPrimitive.Root>,\n AvatarProps\n>(({ className, size, shape, status, ring, badge, loading, children, ...props }, ref) => {\n const resolvedShape = shape ?? 'circle'\n\n // Build ring classes for the outer wrapper\n const ringClasses = ring && ring !== 'none'\n ? cn('ring-2 ring-offset-2 ring-offset-surface-raised', ringColorMap[ring], ringShapeMap[resolvedShape])\n : undefined\n\n // Loading skeleton — early return\n if (loading) {\n return (\n <span ref={ref} className={cn('relative inline-flex shrink-0', ringClasses)}>\n <Skeleton\n className={cn(avatarVariants({ size, shape }))}\n data-slot=\"avatar-skeleton\"\n />\n </span>\n )\n }\n\n // Determine whether to render badge\n const showBadge = badge !== undefined && badge !== 0\n\n return (\n <AvatarShapeContext.Provider value={resolvedShape}>\n <AvatarSizeContext.Provider value={size ?? 'md'}>\n <span className={cn('relative inline-flex shrink-0', ringClasses)}>\n <AvatarPrimitive.Root\n ref={ref}\n className={cn(avatarVariants({ size, shape }), className)}\n {...props}\n >\n {children}\n </AvatarPrimitive.Root>\n {status && (\n <span\n className=\"absolute bottom-0 right-0\"\n role=\"img\"\n aria-label={statusLabelMap[status]}\n >\n {/* Shared Dot primitive: colour + contrast ring; wrapper owns position + a11y. */}\n <Dot color={statusDotColor[status]} size={statusDotSize[size ?? 'md']} withBorder aria-hidden />\n </span>\n )}\n {showBadge && (\n badge === 'dot' ? (\n <span\n className=\"absolute -right-0.5 -top-0.5 h-ds-03 w-ds-03 rounded-pill bg-error-9 ring-2 ring-surface-raised\"\n data-slot=\"avatar-badge-dot\"\n aria-hidden=\"true\"\n />\n ) : typeof badge === 'number' ? (\n <motion.span\n initial={{ scale: 0 }}\n animate={{ scale: 1 }}\n transition={springs.smooth}\n className=\"absolute -right-1 -top-1 flex min-w-ds-05 items-center justify-center rounded-pill bg-error-9 px-1 text-[10px] font-bold leading-[16px] text-error-fg ring-2 ring-surface-raised\"\n data-slot=\"avatar-badge\"\n role=\"status\"\n aria-label={`${badge > 99 ? '99+' : badge} notifications`}\n >\n {badge > 99 ? '99+' : badge}\n </motion.span>\n ) : (\n <span className=\"absolute -right-1 -top-1\" data-slot=\"avatar-badge-custom\">\n {badge}\n </span>\n )\n )}\n </span>\n </AvatarSizeContext.Provider>\n </AvatarShapeContext.Provider>\n )\n})\nAvatar.displayName = AvatarPrimitive.Root.displayName\n\nconst AvatarImage = React.forwardRef<\n React.ElementRef<typeof AvatarPrimitive.Image>,\n React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>\n>(({ className, ...props }, ref) => (\n <motion.span\n initial={{ scale: 0.96 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={springs.smooth}\n className=\"absolute inset-0 h-full w-full\"\n >\n <AvatarPrimitive.Image\n ref={ref}\n className={cn(\"aspect-square h-full w-full\", className)}\n {...props}\n />\n </motion.span>\n))\nAvatarImage.displayName = AvatarPrimitive.Image.displayName\n\nexport interface AvatarFallbackProps\n extends React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback> {\n /**\n * Seed string for deterministic color selection.\n * Falls back to the text content of `children` if not provided.\n */\n colorSeed?: string\n}\n\nconst AvatarFallback = React.forwardRef<\n React.ElementRef<typeof AvatarPrimitive.Fallback>,\n AvatarFallbackProps\n>(({ className, colorSeed, children, ...props }, ref) => {\n // Derive seed: explicit colorSeed > children text content > empty string\n const childrenText = typeof children === 'string' ? children : ''\n const seed = colorSeed ?? childrenText\n const color = getFallbackColor(seed)\n\n // Inherit shape and size from parent Avatar via context\n const shape = React.useContext(AvatarShapeContext)\n const size = React.useContext(AvatarSizeContext)\n const shapeClass = shape === 'square' ? 'rounded-none' : shape === 'rounded' ? 'rounded-control' : 'rounded-pill'\n\n // Letter-spacing based on character count\n const tracking = childrenText.length === 1 ? 'tracking-wide' : 'tracking-normal'\n\n return (\n <AvatarPrimitive.Fallback\n ref={ref}\n data-slot=\"avatar-fallback\"\n className={cn(\n 'flex h-full w-full items-center justify-center font-semibold',\n shapeClass,\n fallbackTextSizeMap[size],\n color.bg,\n color.text,\n tracking,\n className,\n )}\n {...props}\n >\n {children}\n </AvatarPrimitive.Fallback>\n )\n})\nAvatarFallback.displayName = AvatarPrimitive.Fallback.displayName\n\nexport { Avatar, AvatarFallback,AvatarImage }\n"],"mappings":"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"}
1
+ {"version":3,"file":"avatar.js","names":[],"sources":["../../src/ui/avatar.tsx"],"sourcesContent":["'use client'\n\nimport * as AvatarPrimitive from \"@primitives/react-avatar\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { motion } from \"framer-motion\"\nimport * as React from \"react\"\n\nimport { Dot, type DotColor, type DotSize } from \"./dot\"\nimport { springs } from \"./lib/motion\"\nimport { cn } from \"./lib/utils\"\nimport { Skeleton } from \"./skeleton\"\n\n// ── Contexts so AvatarFallback can inherit shape & size from Avatar ──\ntype AvatarShape = 'circle' | 'square' | 'rounded'\ntype AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl'\nconst AvatarShapeContext = React.createContext<AvatarShape>('circle')\nconst AvatarSizeContext = React.createContext<AvatarSize>('md')\n\nexport const avatarVariants = cva(\n 'relative flex shrink-0 overflow-hidden',\n {\n variants: {\n size: {\n xs: 'h-ds-xs w-ds-xs',\n sm: 'h-ds-sm w-ds-sm',\n md: 'h-ds-md w-ds-md',\n lg: 'h-ds-lg w-ds-lg',\n xl: 'h-ds-xl w-ds-xl',\n },\n shape: {\n circle: 'rounded-pill',\n square: 'rounded-none',\n rounded: 'rounded-control',\n },\n },\n defaultVariants: { size: 'md', shape: 'circle' },\n }\n)\n\nexport type AvatarStatus = 'online' | 'offline' | 'busy' | 'away'\n\nexport type AvatarRing = 'none' | 'lead' | 'admin' | 'client'\n\n// Presence status → shared Dot intent colour.\nconst statusDotColor: Record<AvatarStatus, DotColor> = {\n online: 'success',\n offline: 'neutral',\n busy: 'error',\n away: 'warning',\n}\n\nconst statusLabelMap: Record<AvatarStatus, string> = {\n online: 'Online',\n offline: 'Offline',\n busy: 'Busy',\n away: 'Away',\n}\n\n/** Avatar size → Dot size (the status dot scales with the avatar). */\nconst statusDotSize: Record<AvatarSize, DotSize> = {\n xs: 'xs',\n sm: 'sm',\n md: 'md',\n lg: 'lg',\n xl: 'lg',\n}\n\n// ── Role ring ───────────────────────────────────────────────────────────────\n\nconst ringColorMap: Record<Exclude<AvatarRing, 'none'>, string> = {\n lead: 'ring-accent-7',\n admin: 'ring-warning-7',\n client: 'ring-info-7',\n}\n\nconst ringShapeMap: Record<string, string> = {\n circle: 'rounded-pill',\n square: 'rounded-none',\n rounded: 'rounded-control',\n}\n\n// ── Fallback font sizes that scale with avatar size ─────────────────────────\nconst fallbackTextSizeMap: Record<AvatarSize, string> = {\n xs: 'text-body-xs',\n sm: 'text-body-xs',\n md: 'text-body-sm',\n lg: 'text-body-md',\n xl: 'text-heading-xs',\n}\n\n// ── Deterministic fallback colors ───────────────────────────────────────────\n\nconst FALLBACK_COLORS = [\n { bg: 'bg-accent-3', text: 'text-accent-11' },\n { bg: 'bg-success-3', text: 'text-success-11' },\n { bg: 'bg-warning-3', text: 'text-warning-11' },\n { bg: 'bg-error-3', text: 'text-error-11' },\n { bg: 'bg-info-3', text: 'text-info-11' },\n { bg: 'bg-category-teal-3', text: 'text-category-teal-11' },\n { bg: 'bg-category-indigo-3', text: 'text-category-indigo-11' },\n { bg: 'bg-category-cyan-3', text: 'text-category-cyan-11' },\n] as const\n\n/**\n * Simple string hash that produces a deterministic index into FALLBACK_COLORS.\n * Uses djb2 for a reasonable distribution with short strings.\n */\nfunction getFallbackColor(seed: string): (typeof FALLBACK_COLORS)[number] {\n let hash = 5381\n for (let i = 0; i < seed.length; i++) {\n hash = ((hash << 5) + hash + seed.charCodeAt(i)) | 0\n }\n const index = Math.abs(hash) % FALLBACK_COLORS.length\n return FALLBACK_COLORS[index]\n}\n\n/**\n * Props for Avatar — a user/entity image container with size, shape, and presence-status variants.\n *\n * **Sizes:** `xs` | `sm` | `md` (default) | `lg` | `xl` — the status dot scales with the avatar size.\n *\n * **Shapes:** `circle` (default, round) | `square` (sharp corners) | `rounded` (rounded corners, for bots/apps)\n *\n * **Status dot:** `status=\"online\"` (green) | `\"offline\"` (muted) | `\"busy\"` (red) | `\"away\"` (amber).\n * The dot renders with `role=\"img\"` and an accessible `aria-label` — it is not purely decorative.\n *\n * **Role ring:** `ring=\"lead\"` (accent) | `\"admin\"` (warning) | `\"client\"` (info) — a colored ring\n * around the avatar indicating the user's role.\n *\n * **Badge:** `badge={5}` (number) | `badge=\"dot\"` (notification dot) | `badge={<Icon />}` (custom).\n * Numbers > 99 display as \"99+\". Badge is hidden when `0` or `undefined`.\n *\n * **Loading:** `loading={true}` shows a pulse skeleton placeholder.\n *\n * **Children:** Use `<AvatarImage>` for the photo and `<AvatarFallback>` for initials when the image fails.\n *\n * @example\n * // User avatar with photo and fallback initials:\n * <Avatar size=\"md\">\n * <AvatarImage src={user.avatarUrl} alt={user.name} />\n * <AvatarFallback>JD</AvatarFallback>\n * </Avatar>\n *\n * @example\n * // Online presence indicator in a team roster:\n * <Avatar size=\"lg\" status=\"online\">\n * <AvatarImage src={user.photoUrl} alt={user.name} />\n * <AvatarFallback>{user.initials}</AvatarFallback>\n * </Avatar>\n *\n * @example\n * // Square shape for a bot/integration logo:\n * <Avatar shape=\"square\" size=\"xl\">\n * <AvatarImage src=\"/logos/github.png\" alt=\"GitHub\" />\n * </Avatar>\n * // These are just a few ways — feel free to combine props creatively!\n */\nexport interface AvatarProps\n extends Omit<React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>, 'children'>,\n VariantProps<typeof avatarVariants> {\n /** Optional status indicator displayed as a dot at the bottom-right corner */\n status?: AvatarStatus\n /** Role ring color indicator */\n ring?: AvatarRing\n /** Badge overlay: number, 'dot', or custom ReactNode */\n badge?: number | 'dot' | React.ReactNode\n /** Show loading skeleton instead of content */\n loading?: boolean\n children?: React.ReactNode\n}\n\nconst Avatar = React.forwardRef<\n React.ElementRef<typeof AvatarPrimitive.Root>,\n AvatarProps\n>(({ className, size, shape, status, ring, badge, loading, children, ...props }, ref) => {\n const resolvedShape = shape ?? 'circle'\n\n // Build ring classes for the outer wrapper\n const ringClasses = ring && ring !== 'none'\n ? cn('ring-2 ring-offset-2 ring-offset-surface-raised', ringColorMap[ring], ringShapeMap[resolvedShape])\n : undefined\n\n // Loading skeleton — early return\n if (loading) {\n return (\n <span ref={ref} className={cn('relative inline-flex shrink-0', ringClasses)}>\n <Skeleton\n className={cn(avatarVariants({ size, shape }))}\n data-slot=\"avatar-skeleton\"\n />\n </span>\n )\n }\n\n // Determine whether to render badge\n const showBadge = badge !== undefined && badge !== 0\n\n return (\n <AvatarShapeContext.Provider value={resolvedShape}>\n <AvatarSizeContext.Provider value={size ?? 'md'}>\n <span className={cn('relative inline-flex shrink-0', ringClasses)}>\n <AvatarPrimitive.Root\n ref={ref}\n className={cn(avatarVariants({ size, shape }), className)}\n {...props}\n >\n {children}\n </AvatarPrimitive.Root>\n {status && (\n <span\n className=\"absolute bottom-0 right-0\"\n role=\"img\"\n aria-label={statusLabelMap[status]}\n >\n {/* Shared Dot primitive: colour + contrast ring; wrapper owns position + a11y. */}\n <Dot color={statusDotColor[status]} size={statusDotSize[size ?? 'md']} withBorder aria-hidden />\n </span>\n )}\n {showBadge && (\n badge === 'dot' ? (\n <span\n className=\"absolute -right-0.5 -top-0.5 h-ds-03 w-ds-03 rounded-pill bg-error-9 ring-2 ring-surface-raised\"\n data-slot=\"avatar-badge-dot\"\n aria-hidden=\"true\"\n />\n ) : typeof badge === 'number' ? (\n <motion.span\n initial={{ scale: 0 }}\n animate={{ scale: 1 }}\n transition={springs.smooth}\n className=\"absolute -right-1 -top-1 flex min-w-ds-05 items-center justify-center rounded-pill bg-error-9 px-1 text-[10px] font-bold leading-[16px] text-error-fg ring-2 ring-surface-raised\"\n data-slot=\"avatar-badge\"\n role=\"status\"\n aria-label={`${badge > 99 ? '99+' : badge} notifications`}\n >\n {badge > 99 ? '99+' : badge}\n </motion.span>\n ) : (\n <span className=\"absolute -right-1 -top-1\" data-slot=\"avatar-badge-custom\">\n {badge}\n </span>\n )\n )}\n </span>\n </AvatarSizeContext.Provider>\n </AvatarShapeContext.Provider>\n )\n})\nAvatar.displayName = AvatarPrimitive.Root.displayName\n\nconst AvatarImage = React.forwardRef<\n React.ElementRef<typeof AvatarPrimitive.Image>,\n React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>\n>(({ className, ...props }, ref) => (\n <motion.span\n initial={{ scale: 0.96 }}\n animate={{ opacity: 1, scale: 1 }}\n transition={springs.smooth}\n className=\"absolute inset-0 h-full w-full\"\n >\n <AvatarPrimitive.Image\n ref={ref}\n className={cn(\"aspect-square h-full w-full\", className)}\n {...props}\n />\n </motion.span>\n))\nAvatarImage.displayName = AvatarPrimitive.Image.displayName\n\nexport interface AvatarFallbackProps\n extends React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback> {\n /**\n * Seed string for deterministic color selection.\n * Falls back to the text content of `children` if not provided.\n */\n colorSeed?: string\n}\n\nconst AvatarFallback = React.forwardRef<\n React.ElementRef<typeof AvatarPrimitive.Fallback>,\n AvatarFallbackProps\n>(({ className, colorSeed, children, ...props }, ref) => {\n // Derive seed: explicit colorSeed > children text content > empty string\n const childrenText = typeof children === 'string' ? children : ''\n const seed = colorSeed ?? childrenText\n const color = getFallbackColor(seed)\n\n // Inherit shape and size from parent Avatar via context\n const shape = React.useContext(AvatarShapeContext)\n const size = React.useContext(AvatarSizeContext)\n const shapeClass = shape === 'square' ? 'rounded-none' : shape === 'rounded' ? 'rounded-control' : 'rounded-pill'\n\n // Letter-spacing based on character count\n const tracking = childrenText.length === 1 ? 'tracking-wide' : 'tracking-normal'\n\n return (\n <AvatarPrimitive.Fallback\n ref={ref}\n data-slot=\"avatar-fallback\"\n className={cn(\n 'flex h-full w-full items-center justify-center font-semibold',\n shapeClass,\n fallbackTextSizeMap[size],\n color.bg,\n color.text,\n tracking,\n className,\n )}\n {...props}\n >\n {children}\n </AvatarPrimitive.Fallback>\n )\n})\nAvatarFallback.displayName = AvatarPrimitive.Fallback.displayName\n\nexport { Avatar, AvatarFallback,AvatarImage }\n"],"mappings":"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"}
@@ -6,17 +6,13 @@ declare const GAP_CLASSES: {
6
6
  readonly default: "gap-1.5";
7
7
  readonly loose: "gap-2";
8
8
  };
9
- export interface BadgeGroupProps {
9
+ export interface BadgeGroupProps extends React.HTMLAttributes<HTMLDivElement> {
10
10
  max?: number;
11
11
  gap?: keyof typeof GAP_CLASSES;
12
12
  size?: BadgeProps['size'];
13
13
  onOverflowClick?: () => void;
14
- className?: string;
15
14
  children: React.ReactNode;
16
15
  }
17
- export declare function BadgeGroup({ max, gap, size, onOverflowClick, className, children, }: BadgeGroupProps): React.JSX.Element;
18
- export declare namespace BadgeGroup {
19
- var displayName: string;
20
- }
16
+ export declare const BadgeGroup: React.ForwardRefExoticComponent<BadgeGroupProps & React.RefAttributes<HTMLDivElement>>;
21
17
  export {};
22
18
  //# sourceMappingURL=badge-group.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"badge-group.d.ts","sourceRoot":"","sources":["../../src/ui/badge-group.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAS,KAAK,UAAU,EAAE,MAAM,SAAS,CAAA;AAGhD,QAAA,MAAM,WAAW;;;;CAIP,CAAA;AAEV,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,OAAO,WAAW,CAAA;IAC9B,IAAI,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC,CAAA;IACzB,eAAe,CAAC,EAAE,MAAM,IAAI,CAAA;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAED,wBAAgB,UAAU,CAAC,EACzB,GAAG,EACH,GAAe,EACf,IAAI,EACJ,eAAe,EACf,SAAS,EACT,QAAQ,GACT,EAAE,eAAe,qBAyBjB;yBAhCe,UAAU"}
1
+ {"version":3,"file":"badge-group.d.ts","sourceRoot":"","sources":["../../src/ui/badge-group.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAS,KAAK,UAAU,EAAE,MAAM,SAAS,CAAA;AAGhD,QAAA,MAAM,WAAW;;;;CAIP,CAAA;AAEV,MAAM,WAAW,eAAgB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IAC3E,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,MAAM,OAAO,WAAW,CAAA;IAC9B,IAAI,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC,CAAA;IACzB,eAAe,CAAC,EAAE,MAAM,IAAI,CAAA;IAC5B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAED,eAAO,MAAM,UAAU,wFAgCrB,CAAA"}
@@ -13,7 +13,7 @@ declare const COLOR_CLASSES: {
13
13
  readonly accent: "bg-accent-9 text-accent-fg";
14
14
  readonly info: "bg-info-9 text-info-fg";
15
15
  };
16
- export interface BadgeIndicatorProps {
16
+ export interface BadgeIndicatorProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'color'> {
17
17
  count?: number;
18
18
  max?: number;
19
19
  dot?: boolean;
@@ -21,12 +21,8 @@ export interface BadgeIndicatorProps {
21
21
  invisible?: boolean;
22
22
  showZero?: boolean;
23
23
  placement?: keyof typeof PLACEMENT_CLASSES;
24
- className?: string;
25
24
  children: React.ReactNode;
26
25
  }
27
- export declare function BadgeIndicator({ count, max, dot, color, invisible, showZero, placement, className, children, }: BadgeIndicatorProps): React.JSX.Element;
28
- export declare namespace BadgeIndicator {
29
- var displayName: string;
30
- }
26
+ export declare const BadgeIndicator: React.ForwardRefExoticComponent<BadgeIndicatorProps & React.RefAttributes<HTMLSpanElement>>;
31
27
  export {};
32
28
  //# sourceMappingURL=badge-indicator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"badge-indicator.d.ts","sourceRoot":"","sources":["../../src/ui/badge-indicator.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAK9B,QAAA,MAAM,iBAAiB;;;;;CAKb,CAAA;AAEV,QAAA,MAAM,aAAa;;;;;;CAMT,CAAA;AAEV,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,OAAO,aAAa,CAAA;IAClC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,OAAO,iBAAiB,CAAA;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAED,wBAAgB,cAAc,CAAC,EAC7B,KAAK,EACL,GAAQ,EACR,GAAW,EACX,KAAe,EACf,SAAiB,EACjB,QAAgB,EAChB,SAAuB,EACvB,SAAS,EACT,QAAQ,GACT,EAAE,mBAAmB,qBA+BrB;yBAzCe,cAAc"}
1
+ {"version":3,"file":"badge-indicator.d.ts","sourceRoot":"","sources":["../../src/ui/badge-indicator.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAK9B,QAAA,MAAM,iBAAiB;;;;;CAKb,CAAA;AAEV,QAAA,MAAM,aAAa;;;;;;CAMT,CAAA;AAEV,MAAM,WAAW,mBAAoB,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC/F,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,OAAO,aAAa,CAAA;IAClC,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,OAAO,iBAAiB,CAAA;IAC1C,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAED,eAAO,MAAM,cAAc,6FA8CzB,CAAA"}
@@ -1,45 +1,46 @@
1
1
  "use client";
2
2
  import { springs as e } from "./lib/motion.js";
3
3
  import { cn as t } from "./lib/utils.js";
4
- import "react";
5
- import { jsx as n, jsxs as r } from "react/jsx-runtime";
6
- import { AnimatePresence as i, motion as a, useReducedMotion as o } from "framer-motion";
4
+ import * as n from "react";
5
+ import { jsx as r, jsxs as i } from "react/jsx-runtime";
6
+ import { AnimatePresence as a, motion as o, useReducedMotion as s } from "framer-motion";
7
7
  //#region src/ui/badge-indicator.tsx
8
- var s = {
8
+ var c = {
9
9
  "top-right": "-top-1 -right-1",
10
10
  "top-left": "-top-1 -left-1",
11
11
  "bottom-right": "-bottom-1 -right-1",
12
12
  "bottom-left": "-bottom-1 -left-1"
13
- }, c = {
13
+ }, l = {
14
14
  error: "bg-error-9 text-error-fg",
15
15
  success: "bg-success-9 text-success-fg",
16
16
  warning: "bg-warning-9 text-warning-fg",
17
17
  accent: "bg-accent-9 text-accent-fg",
18
18
  info: "bg-info-9 text-info-fg"
19
- };
20
- function l({ count: l, max: u = 99, dot: d = !1, color: f = "error", invisible: p = !1, showZero: m = !1, placement: h = "top-right", className: g, children: _ }) {
21
- let v = o(), y = !p && (d || l !== void 0 && (l > 0 || m)), b = l !== void 0 && l > u ? `${u}+` : l;
22
- return /* @__PURE__ */ r("span", {
19
+ }, u = n.forwardRef(function({ count: n, max: u = 99, dot: d = !1, color: f = "error", invisible: p = !1, showZero: m = !1, placement: h = "top-right", className: g, children: _, ...v }, y) {
20
+ let b = s(), x = !p && (d || n !== void 0 && (n > 0 || m)), S = n !== void 0 && n > u ? `${u}+` : n;
21
+ return /* @__PURE__ */ i("span", {
22
+ ref: y,
23
23
  className: t("relative inline-flex", g),
24
- children: [_, /* @__PURE__ */ n(i, { children: y && /* @__PURE__ */ n(a.span, {
25
- initial: v ? { opacity: 0 } : {
24
+ ...v,
25
+ children: [_, /* @__PURE__ */ r(a, { children: x && /* @__PURE__ */ r(o.span, {
26
+ initial: b ? { opacity: 0 } : {
26
27
  scale: 0,
27
28
  opacity: 0
28
29
  },
29
- animate: v ? { opacity: 1 } : {
30
+ animate: b ? { opacity: 1 } : {
30
31
  scale: 1,
31
32
  opacity: 1
32
33
  },
33
- exit: v ? { opacity: 0 } : {
34
+ exit: b ? { opacity: 0 } : {
34
35
  scale: 0,
35
36
  opacity: 0
36
37
  },
37
38
  transition: e.smooth,
38
- className: t("absolute flex items-center justify-center rounded-pill font-sans font-semibold ring-2 ring-surface-raised", c[f], s[h], d ? "h-2.5 w-2.5" : "min-w-[18px] h-[18px] px-1 text-[11px] leading-none"),
39
- children: !d && b
39
+ className: t("absolute flex items-center justify-center rounded-pill font-sans font-semibold ring-2 ring-surface-raised", l[f], c[h], d ? "h-2.5 w-2.5" : "min-w-[18px] h-[18px] px-1 text-[11px] leading-none"),
40
+ children: !d && S
40
41
  }, "indicator") })]
41
42
  });
42
- }
43
- l.displayName = "BadgeIndicator";
43
+ });
44
+ u.displayName = "BadgeIndicator";
44
45
  //#endregion
45
- export { l as BadgeIndicator };
46
+ export { u as BadgeIndicator };
@@ -1 +1 @@
1
- {"version":3,"file":"badge-indicator.js","names":[],"sources":["../../src/ui/badge-indicator.tsx"],"sourcesContent":["'use client'\n\nimport { AnimatePresence, motion, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { springs } from './lib/motion'\nimport { cn } from './lib/utils'\n\nconst PLACEMENT_CLASSES = {\n 'top-right': '-top-1 -right-1',\n 'top-left': '-top-1 -left-1',\n 'bottom-right': '-bottom-1 -right-1',\n 'bottom-left': '-bottom-1 -left-1',\n} as const\n\nconst COLOR_CLASSES = {\n error: 'bg-error-9 text-error-fg',\n success: 'bg-success-9 text-success-fg',\n warning: 'bg-warning-9 text-warning-fg',\n accent: 'bg-accent-9 text-accent-fg',\n info: 'bg-info-9 text-info-fg',\n} as const\n\nexport interface BadgeIndicatorProps {\n count?: number\n max?: number\n dot?: boolean\n color?: keyof typeof COLOR_CLASSES\n invisible?: boolean\n showZero?: boolean\n placement?: keyof typeof PLACEMENT_CLASSES\n className?: string\n children: React.ReactNode\n}\n\nexport function BadgeIndicator({\n count,\n max = 99,\n dot = false,\n color = 'error',\n invisible = false,\n showZero = false,\n placement = 'top-right',\n className,\n children,\n}: BadgeIndicatorProps) {\n const prefersReduced = useReducedMotion()\n const show = !invisible && (dot || (count !== undefined && (count > 0 || showZero)))\n const displayCount = count !== undefined && count > max ? `${max}+` : count\n\n return (\n <span className={cn('relative inline-flex', className)}>\n {children}\n <AnimatePresence>\n {show && (\n <motion.span\n key=\"indicator\"\n initial={prefersReduced ? { opacity: 0 } : { scale: 0, opacity: 0 }}\n animate={prefersReduced ? { opacity: 1 } : { scale: 1, opacity: 1 }}\n exit={prefersReduced ? { opacity: 0 } : { scale: 0, opacity: 0 }}\n transition={springs.smooth}\n className={cn(\n 'absolute flex items-center justify-center rounded-pill font-sans font-semibold ring-2 ring-surface-raised',\n COLOR_CLASSES[color],\n PLACEMENT_CLASSES[placement],\n dot\n ? 'h-2.5 w-2.5'\n : 'min-w-[18px] h-[18px] px-1 text-[11px] leading-none',\n )}\n >\n {!dot && displayCount}\n </motion.span>\n )}\n </AnimatePresence>\n </span>\n )\n}\n\nBadgeIndicator.displayName = 'BadgeIndicator'\n"],"mappings":";;;;;;;AAQA,IAAM,IAAoB;CACxB,aAAa;CACb,YAAY;CACZ,gBAAgB;CAChB,eAAe;AACjB,GAEM,IAAgB;CACpB,OAAO;CACP,SAAS;CACT,SAAS;CACT,QAAQ;CACR,MAAM;AACR;AAcA,SAAgB,EAAe,EAC7B,UACA,SAAM,IACN,SAAM,IACN,WAAQ,SACR,eAAY,IACZ,cAAW,IACX,eAAY,aACZ,cACA,eACsB;CACtB,IAAM,IAAiB,EAAiB,GAClC,IAAO,CAAC,MAAc,KAAQ,MAAU,KAAA,MAAc,IAAQ,KAAK,KACnE,IAAe,MAAU,KAAA,KAAa,IAAQ,IAAM,GAAG,EAAI,KAAK;CAEtE,OACE,kBAAC,QAAD;EAAM,WAAW,EAAG,wBAAwB,CAAS;YAArD,CACG,GACD,kBAAC,GAAD,EAAA,UACG,KACC,kBAAC,EAAO,MAAR;GAEE,SAAS,IAAiB,EAAE,SAAS,EAAE,IAAI;IAAE,OAAO;IAAG,SAAS;GAAE;GAClE,SAAS,IAAiB,EAAE,SAAS,EAAE,IAAI;IAAE,OAAO;IAAG,SAAS;GAAE;GAClE,MAAM,IAAiB,EAAE,SAAS,EAAE,IAAI;IAAE,OAAO;IAAG,SAAS;GAAE;GAC/D,YAAY,EAAQ;GACpB,WAAW,EACT,6GACA,EAAc,IACd,EAAkB,IAClB,IACI,gBACA,qDACN;aAEC,CAAC,KAAO;EACE,GAfP,WAeO,EAEA,CAAA,CACb;;AAEV;AAEA,EAAe,cAAc"}
1
+ {"version":3,"file":"badge-indicator.js","names":[],"sources":["../../src/ui/badge-indicator.tsx"],"sourcesContent":["'use client'\n\nimport { AnimatePresence, motion, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { springs } from './lib/motion'\nimport { cn } from './lib/utils'\n\nconst PLACEMENT_CLASSES = {\n 'top-right': '-top-1 -right-1',\n 'top-left': '-top-1 -left-1',\n 'bottom-right': '-bottom-1 -right-1',\n 'bottom-left': '-bottom-1 -left-1',\n} as const\n\nconst COLOR_CLASSES = {\n error: 'bg-error-9 text-error-fg',\n success: 'bg-success-9 text-success-fg',\n warning: 'bg-warning-9 text-warning-fg',\n accent: 'bg-accent-9 text-accent-fg',\n info: 'bg-info-9 text-info-fg',\n} as const\n\nexport interface BadgeIndicatorProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'color'> {\n count?: number\n max?: number\n dot?: boolean\n color?: keyof typeof COLOR_CLASSES\n invisible?: boolean\n showZero?: boolean\n placement?: keyof typeof PLACEMENT_CLASSES\n children: React.ReactNode\n}\n\nexport const BadgeIndicator = React.forwardRef<HTMLSpanElement, BadgeIndicatorProps>(\n function BadgeIndicator(\n {\n count,\n max = 99,\n dot = false,\n color = 'error',\n invisible = false,\n showZero = false,\n placement = 'top-right',\n className,\n children,\n ...rest\n },\n ref,\n ) {\n const prefersReduced = useReducedMotion()\n const show = !invisible && (dot || (count !== undefined && (count > 0 || showZero)))\n const displayCount = count !== undefined && count > max ? `${max}+` : count\n\n return (\n <span ref={ref} className={cn('relative inline-flex', className)} {...rest}>\n {children}\n <AnimatePresence>\n {show && (\n <motion.span\n key=\"indicator\"\n initial={prefersReduced ? { opacity: 0 } : { scale: 0, opacity: 0 }}\n animate={prefersReduced ? { opacity: 1 } : { scale: 1, opacity: 1 }}\n exit={prefersReduced ? { opacity: 0 } : { scale: 0, opacity: 0 }}\n transition={springs.smooth}\n className={cn(\n 'absolute flex items-center justify-center rounded-pill font-sans font-semibold ring-2 ring-surface-raised',\n COLOR_CLASSES[color],\n PLACEMENT_CLASSES[placement],\n dot\n ? 'h-2.5 w-2.5'\n : 'min-w-[18px] h-[18px] px-1 text-[11px] leading-none',\n )}\n >\n {!dot && displayCount}\n </motion.span>\n )}\n </AnimatePresence>\n </span>\n )\n})\n\nBadgeIndicator.displayName = 'BadgeIndicator'\n"],"mappings":";;;;;;;AAQA,IAAM,IAAoB;CACxB,aAAa;CACb,YAAY;CACZ,gBAAgB;CAChB,eAAe;AACjB,GAEM,IAAgB;CACpB,OAAO;CACP,SAAS;CACT,SAAS;CACT,QAAQ;CACR,MAAM;AACR,GAaa,IAAiB,EAAM,WAClC,SACE,EACE,UACA,SAAM,IACN,SAAM,IACN,WAAQ,SACR,eAAY,IACZ,cAAW,IACX,eAAY,aACZ,cACA,aACA,GAAG,KAEL,GACA;CACA,IAAM,IAAiB,EAAiB,GAClC,IAAO,CAAC,MAAc,KAAQ,MAAU,KAAA,MAAc,IAAQ,KAAK,KACnE,IAAe,MAAU,KAAA,KAAa,IAAQ,IAAM,GAAG,EAAI,KAAK;CAEtE,OACE,kBAAC,QAAD;EAAW;EAAK,WAAW,EAAG,wBAAwB,CAAS;EAAG,GAAI;YAAtE,CACG,GACH,kBAAC,GAAD,EAAA,UACG,KACC,kBAAC,EAAO,MAAR;GAEE,SAAS,IAAiB,EAAE,SAAS,EAAE,IAAI;IAAE,OAAO;IAAG,SAAS;GAAE;GAClE,SAAS,IAAiB,EAAE,SAAS,EAAE,IAAI;IAAE,OAAO;IAAG,SAAS;GAAE;GAClE,MAAM,IAAiB,EAAE,SAAS,EAAE,IAAI;IAAE,OAAO;IAAG,SAAS;GAAE;GAC/D,YAAY,EAAQ;GACpB,WAAW,EACT,6GACA,EAAc,IACd,EAAkB,IAClB,IACI,gBACA,qDACN;aAEC,CAAC,KAAO;EACE,GAfP,WAeO,EAEA,CAAA,CACb;;AAEV,CAAC;AAED,EAAe,cAAc"}
@@ -1,8 +1,6 @@
1
1
  "use client";
2
2
  import { VariantProps } from 'class-variance-authority';
3
3
  import { IconInput } from './lib/icon-input';
4
- import { BadgeGroup } from './badge-group';
5
- import { BadgeIndicator } from './badge-indicator';
6
4
  import * as React from 'react';
7
5
  declare const colorMap: {
8
6
  readonly default: {
@@ -154,8 +152,8 @@ interface BadgeProps extends Omit<React.HTMLAttributes<HTMLElement>, 'color'>, V
154
152
  circle?: boolean;
155
153
  }
156
154
  declare const BadgeCompound: React.ForwardRefExoticComponent<BadgeProps & React.RefAttributes<HTMLElement>> & {
157
- Indicator: typeof BadgeIndicator;
158
- Group: typeof BadgeGroup;
155
+ Indicator: React.ForwardRefExoticComponent<import('./badge-indicator').BadgeIndicatorProps & React.RefAttributes<HTMLSpanElement>>;
156
+ Group: React.ForwardRefExoticComponent<import('./badge-group').BadgeGroupProps & React.RefAttributes<HTMLDivElement>>;
159
157
  };
160
158
  export { BadgeCompound as Badge, type BadgeColor, type BadgeProps, badgeVariants };
161
159
  //# sourceMappingURL=badge.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"badge.d.ts","sourceRoot":"","sources":["../../src/ui/badge.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAEjE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAMjD,QAAA,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAeJ,CAAA;AAEV,KAAK,UAAU,GAAG,MAAM,OAAO,QAAQ,GAAG,QAAQ,CAAA;AAclD,QAAA,MAAM,aAAa;;;8EAsBlB,CAAA;AA0BD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,UAAU,UACR,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC,EACtD,YAAY,CAAC,OAAO,aAAa,CAAC;IACpC,2FAA2F;IAC3F,KAAK,CAAC,EAAE,UAAU,CAAA;IAClB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,uEAAuE;IACvE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AA0LD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAElD,QAAA,MAAM,aAAa;;;CAGjB,CAAA;AAEF,OAAO,EAAE,aAAa,IAAI,KAAK,EAAE,KAAK,UAAU,EAAC,KAAK,UAAU,EAAE,aAAa,EAAE,CAAA"}
1
+ {"version":3,"file":"badge.d.ts","sourceRoot":"","sources":["../../src/ui/badge.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAO,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAEjE,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAMjD,QAAA,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAeJ,CAAA;AAEV,KAAK,UAAU,GAAG,MAAM,OAAO,QAAQ,GAAG,QAAQ,CAAA;AAclD,QAAA,MAAM,aAAa;;;8EAsBlB,CAAA;AA0BD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,UAAU,UACR,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC,EACtD,YAAY,CAAC,OAAO,aAAa,CAAC;IACpC,2FAA2F;IAC3F,KAAK,CAAC,EAAE,UAAU,CAAA;IAClB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB,GAAG,CAAC,EAAE,OAAO,CAAA;IACb,uEAAuE;IACvE,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AA6LD,QAAA,MAAM,aAAa;;;CAGjB,CAAA;AAEF,OAAO,EAAE,aAAa,IAAI,KAAK,EAAE,KAAK,UAAU,EAAC,KAAK,UAAU,EAAE,aAAa,EAAE,CAAA"}
package/dist/ui/banner.js CHANGED
@@ -8,7 +8,7 @@ import { jsx as o, jsxs as s } from "react/jsx-runtime";
8
8
  import { IconAlertCircle as c, IconAlertTriangle as l, IconCircleCheck as u, IconInfoCircle as d, IconX as f } from "@tabler/icons-react";
9
9
  import { AnimatePresence as p, motion as m } from "framer-motion";
10
10
  //#region src/ui/banner.tsx
11
- var h = n("flex flex-wrap items-center gap-ds-04 px-ds-06 py-ds-04 text-ds-md font-medium border-b", {
11
+ var h = n("flex flex-wrap items-center gap-ds-04 px-ds-06 py-ds-04 text-body-md font-medium border-b", {
12
12
  variants: { color: {
13
13
  info: "bg-info-3 border-info-7 text-info-11",
14
14
  success: "bg-success-3 border-success-7 text-success-11",
@@ -1 +1 @@
1
- {"version":3,"file":"banner.js","names":[],"sources":["../../src/ui/banner.tsx"],"sourcesContent":["'use client'\n\nimport { IconAlertCircle, IconAlertTriangle,IconCircleCheck, IconInfoCircle, IconX } from '@tabler/icons-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { AnimatePresence,motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Icon } from './icon'\nimport { motionProps,springs } from './lib/motion'\nimport { cn } from './lib/utils'\n\nconst bannerVariants = cva(\n 'flex flex-wrap items-center gap-ds-04 px-ds-06 py-ds-04 text-ds-md font-medium border-b',\n {\n variants: {\n color: {\n info:\n 'bg-info-3 border-info-7 text-info-11',\n success:\n 'bg-success-3 border-success-7 text-success-11',\n warning:\n 'bg-warning-3 border-warning-7 text-warning-11',\n error:\n 'bg-error-3 border-error-7 text-error-11',\n neutral:\n 'bg-surface-raised border-surface-border-strong text-surface-fg [&>svg]:text-surface-fg-muted',\n },\n },\n defaultVariants: { color: 'info' },\n },\n)\n\nconst BANNER_ICONS: Record<string, React.ForwardRefExoticComponent<any>> = {\n info: IconInfoCircle,\n success: IconCircleCheck,\n warning: IconAlertTriangle,\n error: IconAlertCircle,\n neutral: IconInfoCircle,\n}\n\n/**\n * Props for Banner — a full-width notification strip with a colored icon, message, optional\n * action slot, and an optional dismiss button. Renders with `role=\"alert\"`.\n *\n * **Colors:** `info` (default) | `success` | `warning` | `error` | `neutral`\n *\n * **Banner vs Alert:** Banner spans the full width of its container (e.g., top of a page or section).\n * Alert is an inline block inside page content. Use Banner for system-level announcements.\n *\n * **`actions` slot:** Accepts any React node(s) — typically one or more `<Button variant=\"ghost\" size=\"sm\">`.\n * Multiple actions wrap gracefully on narrow viewports.\n * **Dismissible:** Provide `onDismiss` to show an × button.\n *\n * @example\n * // Maintenance warning at top of the dashboard:\n * <Banner color=\"warning\">\n * Scheduled maintenance on Sunday 2am–4am UTC. Expect brief downtime.\n * </Banner>\n *\n * @example\n * // Success banner with a CTA action button:\n * <Banner color=\"success\" actions={<Button variant=\"ghost\" size=\"sm\">View report</Button>}>\n * Your export is ready.\n * </Banner>\n *\n * @example\n * // Dismissible info banner for a new feature announcement:\n * <Banner color=\"info\" onDismiss={() => markAsSeen('feature-x')}>\n * New: You can now assign tasks directly from the calendar view.\n * </Banner>\n * // These are just a few ways — feel free to combine props creatively!\n */\nexport interface BannerProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color'>,\n VariantProps<typeof bannerVariants> {\n /** Action slot — accepts any React node(s), typically ghost Buttons. */\n actions?: React.ReactNode\n onDismiss?: () => void\n}\n\nconst Banner = React.forwardRef<HTMLDivElement, BannerProps>(\n ({ className, color = 'info', actions, onDismiss, children, ...props }, ref) => {\n const BannerIcon = BANNER_ICONS[color ?? 'info']\n const [isVisible, setIsVisible] = React.useState(true)\n\n const handleDismiss = React.useCallback(() => {\n setIsVisible(false)\n }, [])\n\n return (\n <AnimatePresence onExitComplete={onDismiss}>\n {isVisible && (\n <motion.div\n ref={ref}\n initial={{ height: 'auto', opacity: 1 }}\n exit={{ height: 0, opacity: 0 }}\n transition={springs.snappy}\n className={cn(bannerVariants({ color }), 'overflow-hidden', className)}\n role=\"alert\"\n {...motionProps(props)}\n >\n <Icon icon={BannerIcon} size=\"md\" className=\"shrink-0\" />\n <div className=\"min-w-0 flex-1\">{children}</div>\n {actions && (\n <div className=\"flex shrink-0 items-center gap-ds-02 [&_button]:transition-colors [&_button]:duration-moderate-01 [&_button]:ease-productive-standard [&_button:hover]:bg-current/10\">{actions}</div>\n )}\n {onDismiss && (\n <button\n type=\"button\"\n onClick={handleDismiss}\n className=\"shrink-0 min-h-ds-xs min-w-ds-xs flex items-center justify-center rounded-control-inner transition-colors duration-moderate-01 ease-productive-standard hover:bg-current/10 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9\"\n aria-label=\"Dismiss\"\n title=\"Dismiss\"\n >\n <Icon icon={IconX} size=\"sm\" />\n </button>\n )}\n </motion.div>\n )}\n </AnimatePresence>\n )\n },\n)\nBanner.displayName = 'Banner'\n\nexport { Banner, bannerVariants }\n"],"mappings":";;;;;;;;;;AAWA,IAAM,IAAiB,EACrB,2FACA;CACE,UAAU,EACR,OAAO;EACL,MACE;EACF,SACE;EACF,SACE;EACF,OACE;EACF,SACE;CACJ,EACF;CACA,iBAAiB,EAAE,OAAO,OAAO;AACnC,CACF,GAEM,IAAqE;CACzE,MAAS;CACT,SAAS;CACT,SAAS;CACT,OAAS;CACT,SAAS;AACX,GA0CM,IAAS,EAAM,YAClB,EAAE,cAAW,WAAQ,QAAQ,YAAS,cAAW,aAAU,GAAG,KAAS,MAAQ;CAC9E,IAAM,IAAa,EAAa,KAAS,SACnC,CAAC,GAAW,KAAgB,EAAM,SAAS,EAAI,GAE/C,IAAgB,EAAM,kBAAkB;EAC5C,EAAa,EAAK;CACpB,GAAG,CAAC,CAAC;CAEL,OACE,kBAAC,GAAD;EAAiB,gBAAgB;YAC9B,KACC,kBAAC,EAAO,KAAR;GACO;GACL,SAAS;IAAE,QAAQ;IAAQ,SAAS;GAAE;GACtC,MAAM;IAAE,QAAQ;IAAG,SAAS;GAAE;GAC9B,YAAY,EAAQ;GACpB,WAAW,EAAG,EAAe,EAAE,SAAM,CAAC,GAAG,mBAAmB,CAAS;GACrE,MAAK;GACL,GAAI,EAAY,CAAK;aAPvB;IASE,kBAAC,GAAD;KAAM,MAAM;KAAY,MAAK;KAAK,WAAU;IAAY,CAAA;IACxD,kBAAC,OAAD;KAAK,WAAU;KAAkB;IAAc,CAAA;IAC9C,KACC,kBAAC,OAAD;KAAK,WAAU;eAAwK;IAAa,CAAA;IAErM,KACC,kBAAC,UAAD;KACE,MAAK;KACL,SAAS;KACT,WAAU;KACV,cAAW;KACX,OAAM;eAEN,kBAAC,GAAD;MAAM,MAAM;MAAO,MAAK;KAAM,CAAA;IACxB,CAAA;GAEA;;CAEC,CAAA;AAErB,CACF;AACA,EAAO,cAAc"}
1
+ {"version":3,"file":"banner.js","names":[],"sources":["../../src/ui/banner.tsx"],"sourcesContent":["'use client'\n\nimport { IconAlertCircle, IconAlertTriangle,IconCircleCheck, IconInfoCircle, IconX } from '@tabler/icons-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { AnimatePresence,motion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { Icon } from './icon'\nimport { motionProps,springs } from './lib/motion'\nimport { cn } from './lib/utils'\n\nconst bannerVariants = cva(\n 'flex flex-wrap items-center gap-ds-04 px-ds-06 py-ds-04 text-body-md font-medium border-b',\n {\n variants: {\n color: {\n info:\n 'bg-info-3 border-info-7 text-info-11',\n success:\n 'bg-success-3 border-success-7 text-success-11',\n warning:\n 'bg-warning-3 border-warning-7 text-warning-11',\n error:\n 'bg-error-3 border-error-7 text-error-11',\n neutral:\n 'bg-surface-raised border-surface-border-strong text-surface-fg [&>svg]:text-surface-fg-muted',\n },\n },\n defaultVariants: { color: 'info' },\n },\n)\n\nconst BANNER_ICONS: Record<string, React.ForwardRefExoticComponent<any>> = {\n info: IconInfoCircle,\n success: IconCircleCheck,\n warning: IconAlertTriangle,\n error: IconAlertCircle,\n neutral: IconInfoCircle,\n}\n\n/**\n * Props for Banner — a full-width notification strip with a colored icon, message, optional\n * action slot, and an optional dismiss button. Renders with `role=\"alert\"`.\n *\n * **Colors:** `info` (default) | `success` | `warning` | `error` | `neutral`\n *\n * **Banner vs Alert:** Banner spans the full width of its container (e.g., top of a page or section).\n * Alert is an inline block inside page content. Use Banner for system-level announcements.\n *\n * **`actions` slot:** Accepts any React node(s) — typically one or more `<Button variant=\"ghost\" size=\"sm\">`.\n * Multiple actions wrap gracefully on narrow viewports.\n * **Dismissible:** Provide `onDismiss` to show an × button.\n *\n * @example\n * // Maintenance warning at top of the dashboard:\n * <Banner color=\"warning\">\n * Scheduled maintenance on Sunday 2am–4am UTC. Expect brief downtime.\n * </Banner>\n *\n * @example\n * // Success banner with a CTA action button:\n * <Banner color=\"success\" actions={<Button variant=\"ghost\" size=\"sm\">View report</Button>}>\n * Your export is ready.\n * </Banner>\n *\n * @example\n * // Dismissible info banner for a new feature announcement:\n * <Banner color=\"info\" onDismiss={() => markAsSeen('feature-x')}>\n * New: You can now assign tasks directly from the calendar view.\n * </Banner>\n * // These are just a few ways — feel free to combine props creatively!\n */\nexport interface BannerProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'color'>,\n VariantProps<typeof bannerVariants> {\n /** Action slot — accepts any React node(s), typically ghost Buttons. */\n actions?: React.ReactNode\n onDismiss?: () => void\n}\n\nconst Banner = React.forwardRef<HTMLDivElement, BannerProps>(\n ({ className, color = 'info', actions, onDismiss, children, ...props }, ref) => {\n const BannerIcon = BANNER_ICONS[color ?? 'info']\n const [isVisible, setIsVisible] = React.useState(true)\n\n const handleDismiss = React.useCallback(() => {\n setIsVisible(false)\n }, [])\n\n return (\n <AnimatePresence onExitComplete={onDismiss}>\n {isVisible && (\n <motion.div\n ref={ref}\n initial={{ height: 'auto', opacity: 1 }}\n exit={{ height: 0, opacity: 0 }}\n transition={springs.snappy}\n className={cn(bannerVariants({ color }), 'overflow-hidden', className)}\n role=\"alert\"\n {...motionProps(props)}\n >\n <Icon icon={BannerIcon} size=\"md\" className=\"shrink-0\" />\n <div className=\"min-w-0 flex-1\">{children}</div>\n {actions && (\n <div className=\"flex shrink-0 items-center gap-ds-02 [&_button]:transition-colors [&_button]:duration-moderate-01 [&_button]:ease-productive-standard [&_button:hover]:bg-current/10\">{actions}</div>\n )}\n {onDismiss && (\n <button\n type=\"button\"\n onClick={handleDismiss}\n className=\"shrink-0 min-h-ds-xs min-w-ds-xs flex items-center justify-center rounded-control-inner transition-colors duration-moderate-01 ease-productive-standard hover:bg-current/10 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9\"\n aria-label=\"Dismiss\"\n title=\"Dismiss\"\n >\n <Icon icon={IconX} size=\"sm\" />\n </button>\n )}\n </motion.div>\n )}\n </AnimatePresence>\n )\n },\n)\nBanner.displayName = 'Banner'\n\nexport { Banner, bannerVariants }\n"],"mappings":";;;;;;;;;;AAWA,IAAM,IAAiB,EACrB,6FACA;CACE,UAAU,EACR,OAAO;EACL,MACE;EACF,SACE;EACF,SACE;EACF,OACE;EACF,SACE;CACJ,EACF;CACA,iBAAiB,EAAE,OAAO,OAAO;AACnC,CACF,GAEM,IAAqE;CACzE,MAAS;CACT,SAAS;CACT,SAAS;CACT,OAAS;CACT,SAAS;AACX,GA0CM,IAAS,EAAM,YAClB,EAAE,cAAW,WAAQ,QAAQ,YAAS,cAAW,aAAU,GAAG,KAAS,MAAQ;CAC9E,IAAM,IAAa,EAAa,KAAS,SACnC,CAAC,GAAW,KAAgB,EAAM,SAAS,EAAI,GAE/C,IAAgB,EAAM,kBAAkB;EAC5C,EAAa,EAAK;CACpB,GAAG,CAAC,CAAC;CAEL,OACE,kBAAC,GAAD;EAAiB,gBAAgB;YAC9B,KACC,kBAAC,EAAO,KAAR;GACO;GACL,SAAS;IAAE,QAAQ;IAAQ,SAAS;GAAE;GACtC,MAAM;IAAE,QAAQ;IAAG,SAAS;GAAE;GAC9B,YAAY,EAAQ;GACpB,WAAW,EAAG,EAAe,EAAE,SAAM,CAAC,GAAG,mBAAmB,CAAS;GACrE,MAAK;GACL,GAAI,EAAY,CAAK;aAPvB;IASE,kBAAC,GAAD;KAAM,MAAM;KAAY,MAAK;KAAK,WAAU;IAAY,CAAA;IACxD,kBAAC,OAAD;KAAK,WAAU;KAAkB;IAAc,CAAA;IAC9C,KACC,kBAAC,OAAD;KAAK,WAAU;eAAwK;IAAa,CAAA;IAErM,KACC,kBAAC,UAAD;KACE,MAAK;KACL,SAAS;KACT,WAAU;KACV,cAAW;KACX,OAAM;eAEN,kBAAC,GAAD;MAAM,MAAM;MAAO,MAAK;KAAM,CAAA;IACxB,CAAA;GAEA;;CAEC,CAAA;AAErB,CACF;AACA,EAAO,cAAc"}
@@ -43,7 +43,7 @@ var a = (e) => /* @__PURE__ */ r("svg", {
43
43
  s.displayName = "Breadcrumb";
44
44
  var c = n.forwardRef(({ className: e, ...n }, i) => /* @__PURE__ */ r("ol", {
45
45
  ref: i,
46
- className: t("flex flex-wrap items-center gap-ds-02b break-words text-ds-md text-surface-fg-muted sm:gap-ds-03", e),
46
+ className: t("flex flex-wrap items-center gap-ds-02b break-words text-body-md text-surface-fg-muted sm:gap-ds-03", e),
47
47
  ...n
48
48
  }));
49
49
  c.displayName = "BreadcrumbList";
@@ -1 +1 @@
1
- {"version":3,"file":"breadcrumb.js","names":[],"sources":["../../src/ui/breadcrumb.tsx"],"sourcesContent":["// @server-safe\nimport { Slot } from '@primitives/react-slot'\nimport * as React from 'react'\n\nimport { cn } from './lib/utils'\n\n// Inline glyphs (no client `Icon` dependency) keep Breadcrumb server-renderable —\n// so server-safe consumers like PageHeader can compose it.\nconst ChevronGlyph = (props: React.SVGProps<SVGSVGElement>) => (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\" {...props}>\n <path d=\"M9 6l6 6l-6 6\" />\n </svg>\n)\n\nconst DotsGlyph = (props: React.SVGProps<SVGSVGElement>) => (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\" {...props}>\n <circle cx=\"5\" cy=\"12\" r=\"1.2\" />\n <circle cx=\"12\" cy=\"12\" r=\"1.2\" />\n <circle cx=\"19\" cy=\"12\" r=\"1.2\" />\n </svg>\n)\n\nconst Breadcrumb = React.forwardRef<\n HTMLElement,\n React.ComponentPropsWithoutRef<'nav'> & { separator?: React.ReactNode }\n>(({ ...props }, ref) => <nav ref={ref} aria-label=\"breadcrumb\" {...props} />)\nBreadcrumb.displayName = 'Breadcrumb'\n\nconst BreadcrumbList = React.forwardRef<HTMLOListElement, React.ComponentPropsWithoutRef<'ol'>>(\n ({ className, ...props }, ref) => (\n <ol\n ref={ref}\n className={cn(\n 'flex flex-wrap items-center gap-ds-02b break-words text-ds-md text-surface-fg-muted sm:gap-ds-03',\n className,\n )}\n {...props}\n />\n ),\n)\nBreadcrumbList.displayName = 'BreadcrumbList'\n\nconst BreadcrumbItem = React.forwardRef<HTMLLIElement, React.ComponentPropsWithoutRef<'li'>>(\n ({ className, ...props }, ref) => (\n <li ref={ref} className={cn('inline-flex items-center gap-ds-03', className)} {...props} />\n ),\n)\nBreadcrumbItem.displayName = 'BreadcrumbItem'\n\nconst BreadcrumbLink = React.forwardRef<\n HTMLAnchorElement,\n React.ComponentPropsWithoutRef<'a'> & { asChild?: boolean }\n>(({ className, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : 'a'\n\n return (\n <Comp\n ref={ref}\n className={cn(\n 'min-w-0 truncate max-w-[20ch] transition-colors duration-fast-01 ease-productive-standard hover:text-surface-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 rounded-control-inner',\n className,\n )}\n {...props}\n />\n )\n})\nBreadcrumbLink.displayName = 'BreadcrumbLink'\n\nconst BreadcrumbPage = React.forwardRef<HTMLSpanElement, React.ComponentPropsWithoutRef<'span'>>(\n ({ className, ...props }, ref) => (\n <span\n ref={ref}\n aria-current=\"page\"\n className={cn('min-w-0 truncate max-w-[20ch] font-medium text-surface-fg', className)}\n {...props}\n />\n ),\n)\nBreadcrumbPage.displayName = 'BreadcrumbPage'\n\nconst BreadcrumbSeparator = ({ children, className, ...props }: React.ComponentProps<'li'>) => (\n <li\n role=\"presentation\"\n aria-hidden=\"true\"\n className={cn('[&>svg]:h-ico-sm [&>svg]:w-ico-sm', className)}\n {...props}\n >\n {children ?? <ChevronGlyph />}\n </li>\n)\nBreadcrumbSeparator.displayName = 'BreadcrumbSeparator'\n\nconst BreadcrumbEllipsis = ({ className, ...props }: React.ComponentProps<'span'>) => (\n <span\n role=\"presentation\"\n aria-hidden=\"true\"\n className={cn('flex h-ds-sm-plus w-ds-sm-plus items-center justify-center', className)}\n {...props}\n >\n <DotsGlyph className=\"h-ico-sm w-ico-sm\" />\n <span className=\"sr-only\">More</span>\n </span>\n)\nBreadcrumbEllipsis.displayName = 'BreadcrumbEllipsis'\n\nexport type BreadcrumbProps = React.ComponentPropsWithoutRef<'nav'>\nexport type BreadcrumbLinkProps = React.ComponentPropsWithoutRef<'a'>\n\nexport {\n Breadcrumb,\n BreadcrumbEllipsis,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n}\n"],"mappings":";;;;;AAQA,IAAM,KAAgB,MACpB,kBAAC,OAAD;CAAK,SAAQ;CAAY,MAAK;CAAO,QAAO;CAAe,aAAa;CAAG,eAAc;CAAQ,gBAAe;CAAQ,eAAY;CAAO,GAAI;WAC7I,kBAAC,QAAD,EAAM,GAAE,gBAAiB,CAAA;AACtB,CAAA,GAGD,KAAa,MACjB,kBAAC,OAAD;CAAK,SAAQ;CAAY,MAAK;CAAe,eAAY;CAAO,GAAI;WAApE;EACE,kBAAC,UAAD;GAAQ,IAAG;GAAI,IAAG;GAAK,GAAE;EAAO,CAAA;EAChC,kBAAC,UAAD;GAAQ,IAAG;GAAK,IAAG;GAAK,GAAE;EAAO,CAAA;EACjC,kBAAC,UAAD;GAAQ,IAAG;GAAK,IAAG;GAAK,GAAE;EAAO,CAAA;CAC9B;IAGD,IAAa,EAAM,YAGtB,EAAE,GAAG,KAAS,MAAQ,kBAAC,OAAD;CAAU;CAAK,cAAW;CAAa,GAAI;AAAQ,CAAA,CAAC;AAC7E,EAAW,cAAc;AAEzB,IAAM,IAAiB,EAAM,YAC1B,EAAE,cAAW,GAAG,KAAS,MACxB,kBAAC,MAAD;CACO;CACL,WAAW,EACT,oGACA,CACF;CACA,GAAI;AACL,CAAA,CAEL;AACA,EAAe,cAAc;AAE7B,IAAM,IAAiB,EAAM,YAC1B,EAAE,cAAW,GAAG,KAAS,MACxB,kBAAC,MAAD;CAAS;CAAK,WAAW,EAAG,sCAAsC,CAAS;CAAG,GAAI;AAAQ,CAAA,CAE9F;AACA,EAAe,cAAc;AAE7B,IAAM,IAAiB,EAAM,YAG1B,EAAE,cAAW,aAAU,IAAO,GAAG,KAAS,MAIzC,kBAHW,IAAU,IAAO,KAG5B;CACO;CACL,WAAW,EACT,uNACA,CACF;CACA,GAAI;AACL,CAAA,CAEJ;AACD,EAAe,cAAc;AAE7B,IAAM,IAAiB,EAAM,YAC1B,EAAE,cAAW,GAAG,KAAS,MACxB,kBAAC,QAAD;CACO;CACL,gBAAa;CACb,WAAW,EAAG,6DAA6D,CAAS;CACpF,GAAI;AACL,CAAA,CAEL;AACA,EAAe,cAAc;AAE7B,IAAM,KAAuB,EAAE,aAAU,cAAW,GAAG,QACrD,kBAAC,MAAD;CACE,MAAK;CACL,eAAY;CACZ,WAAW,EAAG,qCAAqC,CAAS;CAC5D,GAAI;WAEH,KAAY,kBAAC,GAAD,CAAe,CAAA;AAC1B,CAAA;AAEN,EAAoB,cAAc;AAElC,IAAM,KAAsB,EAAE,cAAW,GAAG,QAC1C,kBAAC,QAAD;CACE,MAAK;CACL,eAAY;CACZ,WAAW,EAAG,8DAA8D,CAAS;CACrF,GAAI;WAJN,CAME,kBAAC,GAAD,EAAW,WAAU,oBAAqB,CAAA,GAC1C,kBAAC,QAAD;EAAM,WAAU;YAAU;CAAU,CAAA,CAChC;;AAER,EAAmB,cAAc"}
1
+ {"version":3,"file":"breadcrumb.js","names":[],"sources":["../../src/ui/breadcrumb.tsx"],"sourcesContent":["// @server-safe\nimport { Slot } from '@primitives/react-slot'\nimport * as React from 'react'\n\nimport { cn } from './lib/utils'\n\n// Inline glyphs (no client `Icon` dependency) keep Breadcrumb server-renderable —\n// so server-safe consumers like PageHeader can compose it.\nconst ChevronGlyph = (props: React.SVGProps<SVGSVGElement>) => (\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\" {...props}>\n <path d=\"M9 6l6 6l-6 6\" />\n </svg>\n)\n\nconst DotsGlyph = (props: React.SVGProps<SVGSVGElement>) => (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\" {...props}>\n <circle cx=\"5\" cy=\"12\" r=\"1.2\" />\n <circle cx=\"12\" cy=\"12\" r=\"1.2\" />\n <circle cx=\"19\" cy=\"12\" r=\"1.2\" />\n </svg>\n)\n\nconst Breadcrumb = React.forwardRef<\n HTMLElement,\n React.ComponentPropsWithoutRef<'nav'> & { separator?: React.ReactNode }\n>(({ ...props }, ref) => <nav ref={ref} aria-label=\"breadcrumb\" {...props} />)\nBreadcrumb.displayName = 'Breadcrumb'\n\nconst BreadcrumbList = React.forwardRef<HTMLOListElement, React.ComponentPropsWithoutRef<'ol'>>(\n ({ className, ...props }, ref) => (\n <ol\n ref={ref}\n className={cn(\n 'flex flex-wrap items-center gap-ds-02b break-words text-body-md text-surface-fg-muted sm:gap-ds-03',\n className,\n )}\n {...props}\n />\n ),\n)\nBreadcrumbList.displayName = 'BreadcrumbList'\n\nconst BreadcrumbItem = React.forwardRef<HTMLLIElement, React.ComponentPropsWithoutRef<'li'>>(\n ({ className, ...props }, ref) => (\n <li ref={ref} className={cn('inline-flex items-center gap-ds-03', className)} {...props} />\n ),\n)\nBreadcrumbItem.displayName = 'BreadcrumbItem'\n\nconst BreadcrumbLink = React.forwardRef<\n HTMLAnchorElement,\n React.ComponentPropsWithoutRef<'a'> & { asChild?: boolean }\n>(({ className, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : 'a'\n\n return (\n <Comp\n ref={ref}\n className={cn(\n 'min-w-0 truncate max-w-[20ch] transition-colors duration-fast-01 ease-productive-standard hover:text-surface-fg focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 rounded-control-inner',\n className,\n )}\n {...props}\n />\n )\n})\nBreadcrumbLink.displayName = 'BreadcrumbLink'\n\nconst BreadcrumbPage = React.forwardRef<HTMLSpanElement, React.ComponentPropsWithoutRef<'span'>>(\n ({ className, ...props }, ref) => (\n <span\n ref={ref}\n aria-current=\"page\"\n className={cn('min-w-0 truncate max-w-[20ch] font-medium text-surface-fg', className)}\n {...props}\n />\n ),\n)\nBreadcrumbPage.displayName = 'BreadcrumbPage'\n\nconst BreadcrumbSeparator = ({ children, className, ...props }: React.ComponentProps<'li'>) => (\n <li\n role=\"presentation\"\n aria-hidden=\"true\"\n className={cn('[&>svg]:h-ico-sm [&>svg]:w-ico-sm', className)}\n {...props}\n >\n {children ?? <ChevronGlyph />}\n </li>\n)\nBreadcrumbSeparator.displayName = 'BreadcrumbSeparator'\n\nconst BreadcrumbEllipsis = ({ className, ...props }: React.ComponentProps<'span'>) => (\n <span\n role=\"presentation\"\n aria-hidden=\"true\"\n className={cn('flex h-ds-sm-plus w-ds-sm-plus items-center justify-center', className)}\n {...props}\n >\n <DotsGlyph className=\"h-ico-sm w-ico-sm\" />\n <span className=\"sr-only\">More</span>\n </span>\n)\nBreadcrumbEllipsis.displayName = 'BreadcrumbEllipsis'\n\nexport type BreadcrumbProps = React.ComponentPropsWithoutRef<'nav'>\nexport type BreadcrumbLinkProps = React.ComponentPropsWithoutRef<'a'>\n\nexport {\n Breadcrumb,\n BreadcrumbEllipsis,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n}\n"],"mappings":";;;;;AAQA,IAAM,KAAgB,MACpB,kBAAC,OAAD;CAAK,SAAQ;CAAY,MAAK;CAAO,QAAO;CAAe,aAAa;CAAG,eAAc;CAAQ,gBAAe;CAAQ,eAAY;CAAO,GAAI;WAC7I,kBAAC,QAAD,EAAM,GAAE,gBAAiB,CAAA;AACtB,CAAA,GAGD,KAAa,MACjB,kBAAC,OAAD;CAAK,SAAQ;CAAY,MAAK;CAAe,eAAY;CAAO,GAAI;WAApE;EACE,kBAAC,UAAD;GAAQ,IAAG;GAAI,IAAG;GAAK,GAAE;EAAO,CAAA;EAChC,kBAAC,UAAD;GAAQ,IAAG;GAAK,IAAG;GAAK,GAAE;EAAO,CAAA;EACjC,kBAAC,UAAD;GAAQ,IAAG;GAAK,IAAG;GAAK,GAAE;EAAO,CAAA;CAC9B;IAGD,IAAa,EAAM,YAGtB,EAAE,GAAG,KAAS,MAAQ,kBAAC,OAAD;CAAU;CAAK,cAAW;CAAa,GAAI;AAAQ,CAAA,CAAC;AAC7E,EAAW,cAAc;AAEzB,IAAM,IAAiB,EAAM,YAC1B,EAAE,cAAW,GAAG,KAAS,MACxB,kBAAC,MAAD;CACO;CACL,WAAW,EACT,sGACA,CACF;CACA,GAAI;AACL,CAAA,CAEL;AACA,EAAe,cAAc;AAE7B,IAAM,IAAiB,EAAM,YAC1B,EAAE,cAAW,GAAG,KAAS,MACxB,kBAAC,MAAD;CAAS;CAAK,WAAW,EAAG,sCAAsC,CAAS;CAAG,GAAI;AAAQ,CAAA,CAE9F;AACA,EAAe,cAAc;AAE7B,IAAM,IAAiB,EAAM,YAG1B,EAAE,cAAW,aAAU,IAAO,GAAG,KAAS,MAIzC,kBAHW,IAAU,IAAO,KAG5B;CACO;CACL,WAAW,EACT,uNACA,CACF;CACA,GAAI;AACL,CAAA,CAEJ;AACD,EAAe,cAAc;AAE7B,IAAM,IAAiB,EAAM,YAC1B,EAAE,cAAW,GAAG,KAAS,MACxB,kBAAC,QAAD;CACO;CACL,gBAAa;CACb,WAAW,EAAG,6DAA6D,CAAS;CACpF,GAAI;AACL,CAAA,CAEL;AACA,EAAe,cAAc;AAE7B,IAAM,KAAuB,EAAE,aAAU,cAAW,GAAG,QACrD,kBAAC,MAAD;CACE,MAAK;CACL,eAAY;CACZ,WAAW,EAAG,qCAAqC,CAAS;CAC5D,GAAI;WAEH,KAAY,kBAAC,GAAD,CAAe,CAAA;AAC1B,CAAA;AAEN,EAAoB,cAAc;AAElC,IAAM,KAAsB,EAAE,cAAW,GAAG,QAC1C,kBAAC,QAAD;CACE,MAAK;CACL,eAAY;CACZ,WAAW,EAAG,8DAA8D,CAAS;CACrF,GAAI;WAJN,CAME,kBAAC,GAAD,EAAW,WAAU,oBAAqB,CAAA,GAC1C,kBAAC,QAAD;EAAM,WAAU;YAAU;CAAU,CAAA,CAChC;;AAER,EAAmB,cAAc"}
package/dist/ui/button.js CHANGED
@@ -35,13 +35,13 @@ var u = r("relative inline-flex items-center justify-center whitespace-nowrap fo
35
35
  normal: "font-normal"
36
36
  },
37
37
  size: {
38
- xs: "h-ds-xs-plus rounded-control px-ds-03 text-ds-sm gap-ds-02",
39
- sm: "h-ds-sm rounded-control px-ds-04 text-ds-sm gap-ds-02b",
40
- md: "h-ds-md rounded-control px-ds-05 text-ds-md gap-ds-03",
41
- lg: "h-ds-lg rounded-control px-ds-06 text-ds-base gap-2.5",
42
- "compact-xs": "rounded-control px-ds-02 py-[3px] text-ds-sm gap-ds-02",
43
- "compact-sm": "rounded-control px-ds-03 py-[5px] text-ds-sm gap-ds-02b",
44
- "compact-md": "rounded-control px-ds-04 py-ds-03 text-ds-md gap-ds-03",
38
+ xs: "h-ds-xs-plus rounded-control px-ds-03 text-body-sm gap-ds-02",
39
+ sm: "h-ds-sm rounded-control px-ds-04 text-body-sm gap-ds-02b",
40
+ md: "h-ds-md rounded-control px-ds-05 text-body-md gap-ds-03",
41
+ lg: "h-ds-lg rounded-control px-ds-06 text-body-lg gap-2.5",
42
+ "compact-xs": "rounded-control px-ds-02 py-[3px] text-body-sm gap-ds-02",
43
+ "compact-sm": "rounded-control px-ds-03 py-[5px] text-body-sm gap-ds-02b",
44
+ "compact-md": "rounded-control px-ds-04 py-ds-03 text-body-md gap-ds-03",
45
45
  icon: "h-ds-md w-ds-md rounded-control",
46
46
  "icon-xs": "h-ds-xs-plus w-ds-xs-plus rounded-control",
47
47
  "icon-sm": "h-ds-sm w-ds-sm rounded-control",
@@ -1 +1 @@
1
- {"version":3,"file":"button.js","names":[],"sources":["../../src/ui/button.tsx"],"sourcesContent":["'use client'\n\nimport { Slot, Slottable } from '@primitives/react-slot'\nimport { IconCheck, IconX } from '@tabler/icons-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { AnimatePresence, motion, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { getGroupPositionStyle,useButtonGroup, useButtonGroupItem } from './button-group'\nimport type { ProcessingSpeed } from './button-processing'\nimport { ProcessingOverlay } from './button-processing'\nimport { Icon } from './icon'\nimport type { IconSize } from './icon-context'\nimport { IconProvider } from './icon-context'\nimport type { IconInput } from './lib/icon-input'\nimport { motionProps,springs, tweens } from './lib/motion'\nimport { normalizeIcon } from './lib/normalize-icon'\nimport { cn } from './lib/utils'\nimport { Spinner } from './spinner'\n\nexport const buttonVariants = cva(\n 'relative inline-flex items-center justify-center whitespace-nowrap font-sans select-none overflow-hidden isolate focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-action-disabled disabled:cursor-not-allowed disabled:saturate-[0.3] [&>span:not([data-grain])]:relative [&>span:not([data-grain])]:z-[2]',\n {\n variants: {\n variant: {\n solid: '',\n soft: '',\n outline: 'border',\n ghost: '',\n link: 'underline-offset-4 hover:underline active:opacity-80',\n },\n color: {\n accent: '',\n error: '',\n success: '',\n warning: '',\n neutral: '',\n },\n weight: {\n semibold: 'font-semibold',\n normal: 'font-normal',\n },\n size: {\n xs: 'h-ds-xs-plus rounded-control px-ds-03 text-ds-sm gap-ds-02',\n sm: 'h-ds-sm rounded-control px-ds-04 text-ds-sm gap-ds-02b',\n md: 'h-ds-md rounded-control px-ds-05 text-ds-md gap-ds-03',\n lg: 'h-ds-lg rounded-control px-ds-06 text-ds-base gap-2.5',\n 'compact-xs': 'rounded-control px-ds-02 py-[3px] text-ds-sm gap-ds-02',\n 'compact-sm': 'rounded-control px-ds-03 py-[5px] text-ds-sm gap-ds-02b',\n 'compact-md': 'rounded-control px-ds-04 py-ds-03 text-ds-md gap-ds-03',\n icon: 'h-ds-md w-ds-md rounded-control',\n 'icon-xs': 'h-ds-xs-plus w-ds-xs-plus rounded-control',\n 'icon-sm': 'h-ds-sm w-ds-sm rounded-control',\n 'icon-md': 'h-ds-md w-ds-md rounded-control',\n 'icon-lg': 'h-ds-lg w-ds-lg rounded-control',\n },\n },\n compoundVariants: [\n // ============ SOLID ============ (tonal raised shadow; fill deepens on hover — no coloured bloom)\n { variant: 'solid', color: 'accent', className: 'bg-accent-9 text-accent-fg hover:bg-accent-10 shadow-raised' },\n { variant: 'solid', color: 'error', className: 'bg-error-9 text-error-fg hover:bg-error-10 shadow-raised' },\n { variant: 'solid', color: 'success', className: 'bg-success-9 text-success-fg hover:bg-success-10 shadow-raised' },\n { variant: 'solid', color: 'warning', className: 'bg-warning-9 text-warning-fg hover:bg-warning-10 shadow-raised' },\n { variant: 'solid', color: 'neutral', className: 'bg-neutral-5 text-surface-fg hover:bg-neutral-7 shadow-raised' },\n\n // ============ SOFT ============\n { variant: 'soft', color: 'accent', className: 'bg-accent-3 text-accent-11 hover:bg-accent-4 active:bg-accent-5' },\n { variant: 'soft', color: 'error', className: 'bg-error-3 text-error-11 hover:bg-error-4 active:bg-error-5' },\n { variant: 'soft', color: 'success', className: 'bg-success-3 text-success-11 hover:bg-success-4 active:bg-success-5' },\n { variant: 'soft', color: 'warning', className: 'bg-warning-3 text-warning-11 hover:bg-warning-4 active:bg-warning-5' },\n { variant: 'soft', color: 'neutral', className: 'bg-surface-raised-hover text-surface-fg-muted hover:bg-surface-raised-active active:bg-neutral-5' },\n\n // ============ OUTLINE ============\n { variant: 'outline', color: 'accent', className: 'bg-transparent text-accent-11 border-accent-7 hover:bg-accent-3 active:bg-accent-4' },\n { variant: 'outline', color: 'error', className: 'bg-transparent text-error-11 border-error-7 hover:bg-error-3 active:bg-error-4' },\n { variant: 'outline', color: 'success', className: 'bg-transparent text-success-11 border-success-7 hover:bg-success-3 active:bg-success-4' },\n { variant: 'outline', color: 'warning', className: 'bg-transparent text-warning-11 border-warning-7 hover:bg-warning-3 active:bg-warning-4' },\n { variant: 'outline', color: 'neutral', className: 'bg-transparent text-surface-fg border-surface-border-strong hover:bg-surface-raised-hover active:bg-surface-raised-active' },\n\n // ============ GHOST ============\n // ghost+accent uses neutral look for backward compat (most common ghost is toolbar/icon ghost)\n { variant: 'ghost', color: 'accent', className: 'bg-transparent text-surface-fg-muted hover:bg-surface-raised-hover hover:text-surface-fg active:bg-surface-raised-active' },\n { variant: 'ghost', color: 'error', className: 'bg-transparent text-error-11 hover:bg-error-3 active:bg-error-4' },\n { variant: 'ghost', color: 'success', className: 'bg-transparent text-success-11 hover:bg-success-3 active:bg-success-4' },\n { variant: 'ghost', color: 'warning', className: 'bg-transparent text-warning-11 hover:bg-warning-3 active:bg-warning-4' },\n { variant: 'ghost', color: 'neutral', className: 'bg-transparent text-surface-fg-muted hover:bg-surface-raised-hover hover:text-surface-fg active:bg-surface-raised-active' },\n\n // ============ LINK ============\n { variant: 'link', color: 'accent', className: 'text-accent-11' },\n { variant: 'link', color: 'error', className: 'text-error-11' },\n { variant: 'link', color: 'success', className: 'text-success-11' },\n { variant: 'link', color: 'warning', className: 'text-warning-11' },\n { variant: 'link', color: 'neutral', className: 'text-surface-fg-muted' },\n ],\n defaultVariants: {\n variant: 'solid',\n color: 'accent',\n weight: 'semibold',\n size: 'md',\n },\n },\n)\n\n/** Extra horizontal padding for pill shape — rounded ends eat into visual space */\nconst pillPaddingClass: Record<string, string> = {\n xs: 'px-ds-04',\n sm: 'px-ds-05',\n md: 'px-ds-06',\n lg: 'px-ds-07',\n 'compact-xs': 'px-ds-03',\n 'compact-sm': 'px-ds-04',\n 'compact-md': 'px-ds-05',\n}\n\n/** Negative margin to tighten icon side padding — pulls icon closer to button edge */\nconst iconInsetClass: Record<string, { start: string; end: string }> = {\n xs: { start: '-ml-0.5', end: '-mr-0.5' },\n sm: { start: '-ml-1', end: '-mr-1' },\n md: { start: '-ml-1.5', end: '-mr-1.5' },\n lg: { start: '-ml-2', end: '-mr-2' },\n 'compact-xs': { start: '-ml-0.5', end: '-mr-0.5' },\n 'compact-sm': { start: '-ml-0.5', end: '-mr-0.5' },\n 'compact-md': { start: '-ml-1', end: '-mr-1' },\n icon: { start: '', end: '' },\n 'icon-xs': { start: '', end: '' },\n 'icon-sm': { start: '', end: '' },\n 'icon-md': { start: '', end: '' },\n 'icon-lg': { start: '', end: '' },\n}\n\n/** Map button size to spinner size */\nconst BUTTON_TO_SPINNER_SIZE: Record<string, 'sm' | 'md'> = {\n xs: 'sm',\n sm: 'sm',\n md: 'sm',\n lg: 'md',\n 'compact-xs': 'sm',\n 'compact-sm': 'sm',\n 'compact-md': 'sm',\n icon: 'sm',\n 'icon-xs': 'sm',\n 'icon-sm': 'sm',\n 'icon-md': 'sm',\n 'icon-lg': 'md',\n}\n\n/** Map button size to Icon context size */\nconst BUTTON_TO_ICON_SIZE: Record<string, IconSize> = {\n xs: 'xs', sm: 'sm', md: 'md', lg: 'lg',\n 'compact-xs': 'xs', 'compact-sm': 'sm', 'compact-md': 'md',\n icon: 'md', 'icon-xs': 'xs', 'icon-sm': 'sm', 'icon-md': 'md', 'icon-lg': 'lg',\n}\n\n/**\n * Props for Button — the primary action component with a two-axis variant system,\n * multiple size options, icon slots, and a built-in loading state.\n *\n * **Two axes:**\n * - `variant` controls **visual style**: `\"solid\"` (default, filled) | `\"soft\"` (tinted bg) |\n * `\"outline\"` (bordered) | `\"ghost\"` (transparent, for toolbars) | `\"link\"` (underline, inline)\n * - `color` controls **semantic intent**: `\"accent\"` (default, brand) | `\"error\"` (destructive) |\n * `\"success\"` | `\"warning\"` | `\"neutral\"` (subdued)\n *\n * **Sizes:** `xs` | `sm` | `md` (default) | `lg` for text buttons;\n * `compact-xs` | `compact-sm` | `compact-md` for height-less inline buttons;\n * `icon` | `icon-xs` | `icon-sm` | `icon-md` | `icon-lg` for square icon-only buttons.\n *\n * **Shape:** `\"default\"` uses the `--radius-control` token; `\"pill\"` applies `rounded-pill` (fully-rounded).\n *\n * **Weight:** `\"semibold\"` (default) | `\"normal\"` for lighter labels.\n *\n * **Note:** `ghost` + `accent` renders with neutral styling for backward compat —\n * most ghost buttons are toolbar/icon actions where neutral is expected.\n *\n * **Loading:** When `loading={true}` the button is disabled and aria-busy is set.\n * Use `loadingPosition` to control where the spinner appears.\n *\n * @example\n * // Primary save action (default variant + color):\n * <Button onClick={handleSave}>Save changes</Button>\n *\n * @example\n * // Soft success feedback:\n * <Button variant=\"soft\" color=\"success\" startIcon={<Icon icon={IconCheck} />}>\n * Approved\n * </Button>\n *\n * @example\n * // Destructive delete with loading state:\n * <Button variant=\"solid\" color=\"error\" startIcon={<Icon icon={IconTrash} />} loading={isDeleting}>\n * Delete project\n * </Button>\n *\n * @example\n * // Compact pill tag:\n * <Button variant=\"soft\" color=\"warning\" size=\"compact-sm\" shape=\"pill\">\n * Overdue\n * </Button>\n *\n * @example\n * // Ghost toolbar action:\n * <Button variant=\"ghost\" size=\"sm\" startIcon={<Icon icon={IconEdit} />}>\n * Edit\n * </Button>\n */\nexport interface ButtonProps\n extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'color'>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean\n /** Button shape — 'pill' applies rounded-pill for chip/tag-like buttons */\n shape?: 'default' | 'pill'\n /** Icon element rendered before children — use <Icon icon={...} /> */\n startIcon?: IconInput\n /** Icon element rendered after children — use <Icon icon={...} /> */\n endIcon?: IconInput\n /** Show loading spinner and disable button */\n loading?: boolean\n /** Where to render the spinner: replaces startIcon, endIcon, or centers over children */\n loadingPosition?: 'start' | 'end' | 'center'\n /** Stretch to full width of parent */\n fullWidth?: boolean\n /**\n * Async click handler — auto-manages loading → success/error states.\n * When provided, the button shows a spinner while the promise is pending,\n * then briefly flashes green (success) or red (error) before reverting.\n * Overrides `onClick` and `loading` when active.\n */\n onClickAsync?: (e: React.MouseEvent<HTMLButtonElement>) => Promise<void>\n /** How long (ms) to show the success/error state before reverting. Default: 1500 */\n asyncFeedbackDuration?: number\n\n /**\n * Show processing animation — animated border/glow while content stays visible.\n * `true` = \"working\" speed. Semantic speeds:\n * - `\"ambient\"` (3s) — background sync, file upload\n * - `\"working\"` (2s) — standard API call, generation\n * - `\"urgent\"` (1s) — retry, nearly done\n */\n processing?: boolean | 'ambient' | 'working' | 'urgent'\n\n /** Override processing animation color. Defaults to button's own color. */\n processingColor?: 'accent' | 'error' | 'success' | 'warning' | 'neutral'\n\n /** Disable button during processing. Default: true. Set false for cancel-by-click patterns. */\n processingDisabled?: boolean\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n className,\n variant,\n color,\n weight,\n size,\n asChild = false,\n shape,\n startIcon,\n endIcon,\n loading: loadingProp = false,\n loadingPosition = 'start',\n fullWidth = false,\n disabled,\n onClick,\n onClickAsync,\n asyncFeedbackDuration = 1500,\n processing: processingProp,\n processingColor,\n processingDisabled = true,\n children,\n ...props\n },\n ref,\n ) => {\n const group = useButtonGroup()\n const groupItem = useButtonGroupItem()\n const resolvedVariant = variant ?? group.variant\n const resolvedColor = color ?? group.color\n const resolvedWeight = weight ?? group.weight ?? 'semibold'\n const resolvedShape = shape ?? group.shape ?? 'default'\n const resolvedSize = size ?? group.size ?? 'md'\n // ButtonGroup can propagate disabled to all children\n const resolvedDisabled = disabled ?? group.disabled\n\n // When inside an attached ButtonGroup, adjust border-radius based on position\n const groupRadiusStyle = groupItem && group.attached !== false\n ? getGroupPositionStyle(groupItem.position, group.orientation ?? 'horizontal')\n : undefined\n // Stretch to fill when inside a vertical or fullWidth ButtonGroup\n const groupStretch = group._stretch ?? false\n\n const prefersReduced = useReducedMotion()\n\n // Refs + effect for smooth width transitions (must be before any early returns)\n const wrapperRef = React.useRef<HTMLSpanElement>(null)\n const btnRef = React.useRef<HTMLButtonElement | null>(null)\n const rafRef = React.useRef<number | undefined>(undefined)\n\n \n React.useEffect(() => {\n const btn = btnRef.current\n const wrapper = wrapperRef.current\n if (!btn || !wrapper || fullWidth || groupStretch || prefersReduced) return\n\n rafRef.current = requestAnimationFrame(() => {\n wrapper.style.width = 'auto'\n const w = btn.offsetWidth\n if (w > 0) {\n wrapper.getBoundingClientRect()\n wrapper.style.width = `${w}px`\n }\n })\n return () => { if (rafRef.current) cancelAnimationFrame(rafRef.current) }\n }) // run on every render to catch content changes\n\n // Async state machine: idle → loading → success | error → idle\n type AsyncState = 'idle' | 'loading' | 'success' | 'error'\n const [asyncState, setAsyncState] = React.useState<AsyncState>('idle')\n const timeoutRef = React.useRef<ReturnType<typeof setTimeout> | undefined>(undefined)\n const isMountedRef = React.useRef(true)\n\n React.useEffect(() => () => {\n isMountedRef.current = false\n clearTimeout(timeoutRef.current)\n }, [])\n\n const handleAsyncClick = (e: React.MouseEvent<HTMLButtonElement>) => {\n if (!onClickAsync || asyncState !== 'idle') return\n setAsyncState('loading')\n onClickAsync(e)\n .then(() => { if (isMountedRef.current) setAsyncState('success') })\n .catch(() => { if (isMountedRef.current) setAsyncState('error') })\n .finally(() => {\n if (isMountedRef.current) {\n timeoutRef.current = setTimeout(() => {\n if (isMountedRef.current) setAsyncState('idle')\n }, asyncFeedbackDuration)\n }\n })\n }\n\n const isAsync = !!onClickAsync\n const loading = isAsync ? asyncState === 'loading' : loadingProp\n const isAsyncFeedback = asyncState === 'success' || asyncState === 'error'\n\n // Processing: explicit prop takes priority, otherwise auto-processing during onClickAsync.\n // Processing is always OFF during async feedback (success/error) so the feedback colors show.\n const autoProcessing = isAsync && asyncState === 'loading' && !processingProp\n const processingSpeed: ProcessingSpeed | undefined = isAsyncFeedback ? undefined\n : processingProp === true ? 'working'\n : processingProp === false || !processingProp\n ? (autoProcessing ? 'working' : undefined)\n : processingProp\n const isProcessing = !!processingSpeed\n const resolvedProcessingColor = processingColor ?? resolvedColor ?? 'accent'\n\n if (asChild) {\n // Slot merges all props into the child element via cloneElement at runtime.\n // We cast here because SlotProps only types React.HTMLAttributes<HTMLElement>,\n // which excludes button-specific attrs like `disabled`.\n const slotProps = {\n className: cn(\n buttonVariants({ variant: resolvedVariant, color: resolvedColor, weight: resolvedWeight, size: resolvedSize }),\n resolvedShape === 'pill' && 'rounded-pill',\n resolvedShape === 'pill' && pillPaddingClass[resolvedSize],\n (fullWidth || groupStretch) && 'w-full',\n className,\n ),\n ref,\n disabled: resolvedDisabled || loading,\n 'aria-busy': loading || undefined,\n ...props,\n } as React.ComponentPropsWithRef<typeof Slot>\n return (\n <Slot {...slotProps}>\n <Slottable>{children}</Slottable>\n </Slot>\n )\n }\n\n const inset = iconInsetClass[resolvedSize] ?? { start: '', end: '' }\n // Dim icons on filled variants (Radix pattern — icon is decorative, text is primary)\n const dimIcon = resolvedVariant === 'solid' || resolvedVariant === 'soft' || resolvedVariant === 'outline'\n\n const renderStartSlot = () => {\n if (loading && loadingPosition === 'start') {\n return (\n <span className={cn('inline-flex shrink-0 items-center justify-center', startIcon && inset.start)}>\n <Spinner size={BUTTON_TO_SPINNER_SIZE[resolvedSize]} variant=\"bare\" />\n </span>\n )\n }\n if (startIcon) {\n return (\n <span className={cn('inline-flex shrink-0 items-center justify-center pointer-events-none', inset.start, dimIcon && 'opacity-90')}>\n {normalizeIcon(startIcon)}\n </span>\n )\n }\n return null\n }\n\n const renderEndSlot = () => {\n if (loading && loadingPosition === 'end') {\n return (\n <span className={cn('inline-flex shrink-0 items-center justify-center', endIcon && inset.end)}>\n <Spinner size={BUTTON_TO_SPINNER_SIZE[resolvedSize]} variant=\"bare\" />\n </span>\n )\n }\n if (endIcon) {\n return (\n <span className={cn('inline-flex shrink-0 items-center justify-center pointer-events-none', inset.end, dimIcon && 'opacity-90')}>\n {normalizeIcon(endIcon)}\n </span>\n )\n }\n return null\n }\n\n // Separate DevalokGrain elements (need to be direct button children for absolute positioning)\n // from text/other content (needs z-elevation above grain)\n const childArray = React.Children.toArray(children)\n const grainElements: React.ReactNode[] = []\n const contentElements: React.ReactNode[] = []\n childArray.forEach((child) => {\n if (React.isValidElement(child) && (child.type as { displayName?: string })?.displayName === 'DevalokGrain') {\n grainElements.push(child)\n } else {\n contentElements.push(child)\n }\n })\n\n const renderChildren = () => {\n if (loading && loadingPosition === 'center') {\n return (\n <span className=\"relative inline-flex items-center justify-center\">\n <span className=\"invisible\">{contentElements}</span>\n <span className=\"absolute inset-0 flex items-center justify-center\">\n <Spinner size={BUTTON_TO_SPINNER_SIZE[resolvedSize]} variant=\"bare\" />\n </span>\n </span>\n )\n }\n // Only wrap in z-elevated span when grain is present (to sit above grain layers).\n // Without grain, render children directly to preserve flex layout.\n if (grainElements.length > 0) {\n return <span>{contentElements}</span>\n }\n return <>{contentElements}</>\n }\n\n // Async feedback: override color to show green/red\n const feedbackColorClass = isAsyncFeedback\n ? asyncState === 'success'\n ? 'bg-success-9 text-success-fg border-transparent hover:bg-success-9'\n : 'bg-error-9 text-error-fg border-transparent hover:bg-error-9'\n : undefined\n\n // Async feedback icon — uses Icon's draw animation for pen-stroke effect\n const asyncFeedbackIcon = isAsyncFeedback ? (\n <span className={cn('inline-flex shrink-0 items-center justify-center pointer-events-none', startIcon && inset.start)}>\n <Icon icon={asyncState === 'success' ? IconCheck : IconX} animate=\"draw\" />\n </span>\n ) : null\n\n const iconSize = BUTTON_TO_ICON_SIZE[resolvedSize] ?? 'md'\n\n const buttonEl = (\n <motion.button\n {...motionProps(props)}\n style={{ ...props.style, ...groupRadiusStyle }}\n className={cn(\n buttonVariants({\n // When processing (and not showing async feedback), force soft variant so ants pop\n variant: isProcessing && !isAsyncFeedback && resolvedVariant !== 'ghost' && resolvedVariant !== 'outline' && resolvedVariant !== 'link' ? 'soft' : resolvedVariant,\n color: resolvedColor,\n weight: resolvedWeight,\n size: resolvedSize,\n }),\n resolvedShape === 'pill' && 'rounded-pill',\n resolvedShape === 'pill' && pillPaddingClass[resolvedSize],\n (fullWidth || groupStretch) && 'w-full',\n // Asymmetric timing: hover-out is slow+relaxed, hover-in is fast+snappy (applied via hover: override)\n !loading && !isAsyncFeedback && 'transition-[color,background-color,border-color,box-shadow,transform,filter] duration-moderate-01 ease-productive-exit',\n !loading && !isAsyncFeedback && 'hover:duration-fast-02 hover:ease-productive-entrance',\n !loading && !isAsyncFeedback && 'active:scale-[0.95] active:brightness-[0.92] active:saturate-[1.1] active:duration-[0ms]',\n feedbackColorClass,\n isAsyncFeedback && 'transition-colors duration-moderate-01 ease-productive-standard',\n isProcessing && processingDisabled && 'pointer-events-none cursor-default',\n className,\n )}\n ref={(el: HTMLButtonElement | null) => {\n btnRef.current = el\n if (typeof ref === 'function') ref(el)\n else if (ref) (ref as React.MutableRefObject<HTMLButtonElement | null>).current = el\n }}\n disabled={resolvedDisabled || (loading && !isProcessing)}\n aria-busy={loading || isProcessing || undefined}\n aria-disabled={isProcessing && processingDisabled || undefined}\n onClick={isAsync ? handleAsyncClick : (isProcessing && processingDisabled ? undefined : onClick)}\n >\n {/* Grain layers render as direct children (need absolute positioning) */}\n {grainElements}\n {/* Content renders above grain via z-[2] span wrapper */}\n {isAsyncFeedback ? asyncFeedbackIcon : renderStartSlot()}\n {isAsyncFeedback ? contentElements : renderChildren()}\n {isAsyncFeedback ? null : renderEndSlot()}\n </motion.button>\n )\n\n // Always wrap in a positioned container so the overlay can render\n // as a sibling OUTSIDE the button (not affected by disabled opacity).\n // Keeping the wrapper always-on prevents React unmount/remount on\n // processing toggle, enabling smooth CSS transitions between states.\n return (\n <IconProvider size={iconSize}>\n <span\n ref={wrapperRef}\n className={cn('relative inline-flex', fullWidth && 'w-full')}\n style={{\n ...(fullWidth || groupStretch || prefersReduced ? undefined : { transition: 'width 0.2s cubic-bezier(0.25, 0.1, 0.25, 1)' }),\n ...groupRadiusStyle,\n }}\n >\n {buttonEl}\n <ProcessingOverlay\n active={isProcessing}\n speed={processingSpeed ?? 'working'}\n color={resolvedProcessingColor}\n />\n </span>\n </IconProvider>\n )\n },\n)\nButton.displayName = 'Button'\n\nexport { Button }\n"],"mappings":"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"}
1
+ {"version":3,"file":"button.js","names":[],"sources":["../../src/ui/button.tsx"],"sourcesContent":["'use client'\n\nimport { Slot, Slottable } from '@primitives/react-slot'\nimport { IconCheck, IconX } from '@tabler/icons-react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { AnimatePresence, motion, useReducedMotion } from 'framer-motion'\nimport * as React from 'react'\n\nimport { getGroupPositionStyle,useButtonGroup, useButtonGroupItem } from './button-group'\nimport type { ProcessingSpeed } from './button-processing'\nimport { ProcessingOverlay } from './button-processing'\nimport { Icon } from './icon'\nimport type { IconSize } from './icon-context'\nimport { IconProvider } from './icon-context'\nimport type { IconInput } from './lib/icon-input'\nimport { motionProps,springs, tweens } from './lib/motion'\nimport { normalizeIcon } from './lib/normalize-icon'\nimport { cn } from './lib/utils'\nimport { Spinner } from './spinner'\n\nexport const buttonVariants = cva(\n 'relative inline-flex items-center justify-center whitespace-nowrap font-sans select-none overflow-hidden isolate focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent-9 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-action-disabled disabled:cursor-not-allowed disabled:saturate-[0.3] [&>span:not([data-grain])]:relative [&>span:not([data-grain])]:z-[2]',\n {\n variants: {\n variant: {\n solid: '',\n soft: '',\n outline: 'border',\n ghost: '',\n link: 'underline-offset-4 hover:underline active:opacity-80',\n },\n color: {\n accent: '',\n error: '',\n success: '',\n warning: '',\n neutral: '',\n },\n weight: {\n semibold: 'font-semibold',\n normal: 'font-normal',\n },\n size: {\n xs: 'h-ds-xs-plus rounded-control px-ds-03 text-body-sm gap-ds-02',\n sm: 'h-ds-sm rounded-control px-ds-04 text-body-sm gap-ds-02b',\n md: 'h-ds-md rounded-control px-ds-05 text-body-md gap-ds-03',\n lg: 'h-ds-lg rounded-control px-ds-06 text-body-lg gap-2.5',\n 'compact-xs': 'rounded-control px-ds-02 py-[3px] text-body-sm gap-ds-02',\n 'compact-sm': 'rounded-control px-ds-03 py-[5px] text-body-sm gap-ds-02b',\n 'compact-md': 'rounded-control px-ds-04 py-ds-03 text-body-md gap-ds-03',\n icon: 'h-ds-md w-ds-md rounded-control',\n 'icon-xs': 'h-ds-xs-plus w-ds-xs-plus rounded-control',\n 'icon-sm': 'h-ds-sm w-ds-sm rounded-control',\n 'icon-md': 'h-ds-md w-ds-md rounded-control',\n 'icon-lg': 'h-ds-lg w-ds-lg rounded-control',\n },\n },\n compoundVariants: [\n // ============ SOLID ============ (tonal raised shadow; fill deepens on hover — no coloured bloom)\n { variant: 'solid', color: 'accent', className: 'bg-accent-9 text-accent-fg hover:bg-accent-10 shadow-raised' },\n { variant: 'solid', color: 'error', className: 'bg-error-9 text-error-fg hover:bg-error-10 shadow-raised' },\n { variant: 'solid', color: 'success', className: 'bg-success-9 text-success-fg hover:bg-success-10 shadow-raised' },\n { variant: 'solid', color: 'warning', className: 'bg-warning-9 text-warning-fg hover:bg-warning-10 shadow-raised' },\n { variant: 'solid', color: 'neutral', className: 'bg-neutral-5 text-surface-fg hover:bg-neutral-7 shadow-raised' },\n\n // ============ SOFT ============\n { variant: 'soft', color: 'accent', className: 'bg-accent-3 text-accent-11 hover:bg-accent-4 active:bg-accent-5' },\n { variant: 'soft', color: 'error', className: 'bg-error-3 text-error-11 hover:bg-error-4 active:bg-error-5' },\n { variant: 'soft', color: 'success', className: 'bg-success-3 text-success-11 hover:bg-success-4 active:bg-success-5' },\n { variant: 'soft', color: 'warning', className: 'bg-warning-3 text-warning-11 hover:bg-warning-4 active:bg-warning-5' },\n { variant: 'soft', color: 'neutral', className: 'bg-surface-raised-hover text-surface-fg-muted hover:bg-surface-raised-active active:bg-neutral-5' },\n\n // ============ OUTLINE ============\n { variant: 'outline', color: 'accent', className: 'bg-transparent text-accent-11 border-accent-7 hover:bg-accent-3 active:bg-accent-4' },\n { variant: 'outline', color: 'error', className: 'bg-transparent text-error-11 border-error-7 hover:bg-error-3 active:bg-error-4' },\n { variant: 'outline', color: 'success', className: 'bg-transparent text-success-11 border-success-7 hover:bg-success-3 active:bg-success-4' },\n { variant: 'outline', color: 'warning', className: 'bg-transparent text-warning-11 border-warning-7 hover:bg-warning-3 active:bg-warning-4' },\n { variant: 'outline', color: 'neutral', className: 'bg-transparent text-surface-fg border-surface-border-strong hover:bg-surface-raised-hover active:bg-surface-raised-active' },\n\n // ============ GHOST ============\n // ghost+accent uses neutral look for backward compat (most common ghost is toolbar/icon ghost)\n { variant: 'ghost', color: 'accent', className: 'bg-transparent text-surface-fg-muted hover:bg-surface-raised-hover hover:text-surface-fg active:bg-surface-raised-active' },\n { variant: 'ghost', color: 'error', className: 'bg-transparent text-error-11 hover:bg-error-3 active:bg-error-4' },\n { variant: 'ghost', color: 'success', className: 'bg-transparent text-success-11 hover:bg-success-3 active:bg-success-4' },\n { variant: 'ghost', color: 'warning', className: 'bg-transparent text-warning-11 hover:bg-warning-3 active:bg-warning-4' },\n { variant: 'ghost', color: 'neutral', className: 'bg-transparent text-surface-fg-muted hover:bg-surface-raised-hover hover:text-surface-fg active:bg-surface-raised-active' },\n\n // ============ LINK ============\n { variant: 'link', color: 'accent', className: 'text-accent-11' },\n { variant: 'link', color: 'error', className: 'text-error-11' },\n { variant: 'link', color: 'success', className: 'text-success-11' },\n { variant: 'link', color: 'warning', className: 'text-warning-11' },\n { variant: 'link', color: 'neutral', className: 'text-surface-fg-muted' },\n ],\n defaultVariants: {\n variant: 'solid',\n color: 'accent',\n weight: 'semibold',\n size: 'md',\n },\n },\n)\n\n/** Extra horizontal padding for pill shape — rounded ends eat into visual space */\nconst pillPaddingClass: Record<string, string> = {\n xs: 'px-ds-04',\n sm: 'px-ds-05',\n md: 'px-ds-06',\n lg: 'px-ds-07',\n 'compact-xs': 'px-ds-03',\n 'compact-sm': 'px-ds-04',\n 'compact-md': 'px-ds-05',\n}\n\n/** Negative margin to tighten icon side padding — pulls icon closer to button edge */\nconst iconInsetClass: Record<string, { start: string; end: string }> = {\n xs: { start: '-ml-0.5', end: '-mr-0.5' },\n sm: { start: '-ml-1', end: '-mr-1' },\n md: { start: '-ml-1.5', end: '-mr-1.5' },\n lg: { start: '-ml-2', end: '-mr-2' },\n 'compact-xs': { start: '-ml-0.5', end: '-mr-0.5' },\n 'compact-sm': { start: '-ml-0.5', end: '-mr-0.5' },\n 'compact-md': { start: '-ml-1', end: '-mr-1' },\n icon: { start: '', end: '' },\n 'icon-xs': { start: '', end: '' },\n 'icon-sm': { start: '', end: '' },\n 'icon-md': { start: '', end: '' },\n 'icon-lg': { start: '', end: '' },\n}\n\n/** Map button size to spinner size */\nconst BUTTON_TO_SPINNER_SIZE: Record<string, 'sm' | 'md'> = {\n xs: 'sm',\n sm: 'sm',\n md: 'sm',\n lg: 'md',\n 'compact-xs': 'sm',\n 'compact-sm': 'sm',\n 'compact-md': 'sm',\n icon: 'sm',\n 'icon-xs': 'sm',\n 'icon-sm': 'sm',\n 'icon-md': 'sm',\n 'icon-lg': 'md',\n}\n\n/** Map button size to Icon context size */\nconst BUTTON_TO_ICON_SIZE: Record<string, IconSize> = {\n xs: 'xs', sm: 'sm', md: 'md', lg: 'lg',\n 'compact-xs': 'xs', 'compact-sm': 'sm', 'compact-md': 'md',\n icon: 'md', 'icon-xs': 'xs', 'icon-sm': 'sm', 'icon-md': 'md', 'icon-lg': 'lg',\n}\n\n/**\n * Props for Button — the primary action component with a two-axis variant system,\n * multiple size options, icon slots, and a built-in loading state.\n *\n * **Two axes:**\n * - `variant` controls **visual style**: `\"solid\"` (default, filled) | `\"soft\"` (tinted bg) |\n * `\"outline\"` (bordered) | `\"ghost\"` (transparent, for toolbars) | `\"link\"` (underline, inline)\n * - `color` controls **semantic intent**: `\"accent\"` (default, brand) | `\"error\"` (destructive) |\n * `\"success\"` | `\"warning\"` | `\"neutral\"` (subdued)\n *\n * **Sizes:** `xs` | `sm` | `md` (default) | `lg` for text buttons;\n * `compact-xs` | `compact-sm` | `compact-md` for height-less inline buttons;\n * `icon` | `icon-xs` | `icon-sm` | `icon-md` | `icon-lg` for square icon-only buttons.\n *\n * **Shape:** `\"default\"` uses the `--radius-control` token; `\"pill\"` applies `rounded-pill` (fully-rounded).\n *\n * **Weight:** `\"semibold\"` (default) | `\"normal\"` for lighter labels.\n *\n * **Note:** `ghost` + `accent` renders with neutral styling for backward compat —\n * most ghost buttons are toolbar/icon actions where neutral is expected.\n *\n * **Loading:** When `loading={true}` the button is disabled and aria-busy is set.\n * Use `loadingPosition` to control where the spinner appears.\n *\n * @example\n * // Primary save action (default variant + color):\n * <Button onClick={handleSave}>Save changes</Button>\n *\n * @example\n * // Soft success feedback:\n * <Button variant=\"soft\" color=\"success\" startIcon={<Icon icon={IconCheck} />}>\n * Approved\n * </Button>\n *\n * @example\n * // Destructive delete with loading state:\n * <Button variant=\"solid\" color=\"error\" startIcon={<Icon icon={IconTrash} />} loading={isDeleting}>\n * Delete project\n * </Button>\n *\n * @example\n * // Compact pill tag:\n * <Button variant=\"soft\" color=\"warning\" size=\"compact-sm\" shape=\"pill\">\n * Overdue\n * </Button>\n *\n * @example\n * // Ghost toolbar action:\n * <Button variant=\"ghost\" size=\"sm\" startIcon={<Icon icon={IconEdit} />}>\n * Edit\n * </Button>\n */\nexport interface ButtonProps\n extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'color'>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean\n /** Button shape — 'pill' applies rounded-pill for chip/tag-like buttons */\n shape?: 'default' | 'pill'\n /** Icon element rendered before children — use <Icon icon={...} /> */\n startIcon?: IconInput\n /** Icon element rendered after children — use <Icon icon={...} /> */\n endIcon?: IconInput\n /** Show loading spinner and disable button */\n loading?: boolean\n /** Where to render the spinner: replaces startIcon, endIcon, or centers over children */\n loadingPosition?: 'start' | 'end' | 'center'\n /** Stretch to full width of parent */\n fullWidth?: boolean\n /**\n * Async click handler — auto-manages loading → success/error states.\n * When provided, the button shows a spinner while the promise is pending,\n * then briefly flashes green (success) or red (error) before reverting.\n * Overrides `onClick` and `loading` when active.\n */\n onClickAsync?: (e: React.MouseEvent<HTMLButtonElement>) => Promise<void>\n /** How long (ms) to show the success/error state before reverting. Default: 1500 */\n asyncFeedbackDuration?: number\n\n /**\n * Show processing animation — animated border/glow while content stays visible.\n * `true` = \"working\" speed. Semantic speeds:\n * - `\"ambient\"` (3s) — background sync, file upload\n * - `\"working\"` (2s) — standard API call, generation\n * - `\"urgent\"` (1s) — retry, nearly done\n */\n processing?: boolean | 'ambient' | 'working' | 'urgent'\n\n /** Override processing animation color. Defaults to button's own color. */\n processingColor?: 'accent' | 'error' | 'success' | 'warning' | 'neutral'\n\n /** Disable button during processing. Default: true. Set false for cancel-by-click patterns. */\n processingDisabled?: boolean\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n (\n {\n className,\n variant,\n color,\n weight,\n size,\n asChild = false,\n shape,\n startIcon,\n endIcon,\n loading: loadingProp = false,\n loadingPosition = 'start',\n fullWidth = false,\n disabled,\n onClick,\n onClickAsync,\n asyncFeedbackDuration = 1500,\n processing: processingProp,\n processingColor,\n processingDisabled = true,\n children,\n ...props\n },\n ref,\n ) => {\n const group = useButtonGroup()\n const groupItem = useButtonGroupItem()\n const resolvedVariant = variant ?? group.variant\n const resolvedColor = color ?? group.color\n const resolvedWeight = weight ?? group.weight ?? 'semibold'\n const resolvedShape = shape ?? group.shape ?? 'default'\n const resolvedSize = size ?? group.size ?? 'md'\n // ButtonGroup can propagate disabled to all children\n const resolvedDisabled = disabled ?? group.disabled\n\n // When inside an attached ButtonGroup, adjust border-radius based on position\n const groupRadiusStyle = groupItem && group.attached !== false\n ? getGroupPositionStyle(groupItem.position, group.orientation ?? 'horizontal')\n : undefined\n // Stretch to fill when inside a vertical or fullWidth ButtonGroup\n const groupStretch = group._stretch ?? false\n\n const prefersReduced = useReducedMotion()\n\n // Refs + effect for smooth width transitions (must be before any early returns)\n const wrapperRef = React.useRef<HTMLSpanElement>(null)\n const btnRef = React.useRef<HTMLButtonElement | null>(null)\n const rafRef = React.useRef<number | undefined>(undefined)\n\n \n React.useEffect(() => {\n const btn = btnRef.current\n const wrapper = wrapperRef.current\n if (!btn || !wrapper || fullWidth || groupStretch || prefersReduced) return\n\n rafRef.current = requestAnimationFrame(() => {\n wrapper.style.width = 'auto'\n const w = btn.offsetWidth\n if (w > 0) {\n wrapper.getBoundingClientRect()\n wrapper.style.width = `${w}px`\n }\n })\n return () => { if (rafRef.current) cancelAnimationFrame(rafRef.current) }\n }) // run on every render to catch content changes\n\n // Async state machine: idle → loading → success | error → idle\n type AsyncState = 'idle' | 'loading' | 'success' | 'error'\n const [asyncState, setAsyncState] = React.useState<AsyncState>('idle')\n const timeoutRef = React.useRef<ReturnType<typeof setTimeout> | undefined>(undefined)\n const isMountedRef = React.useRef(true)\n\n React.useEffect(() => () => {\n isMountedRef.current = false\n clearTimeout(timeoutRef.current)\n }, [])\n\n const handleAsyncClick = (e: React.MouseEvent<HTMLButtonElement>) => {\n if (!onClickAsync || asyncState !== 'idle') return\n setAsyncState('loading')\n onClickAsync(e)\n .then(() => { if (isMountedRef.current) setAsyncState('success') })\n .catch(() => { if (isMountedRef.current) setAsyncState('error') })\n .finally(() => {\n if (isMountedRef.current) {\n timeoutRef.current = setTimeout(() => {\n if (isMountedRef.current) setAsyncState('idle')\n }, asyncFeedbackDuration)\n }\n })\n }\n\n const isAsync = !!onClickAsync\n const loading = isAsync ? asyncState === 'loading' : loadingProp\n const isAsyncFeedback = asyncState === 'success' || asyncState === 'error'\n\n // Processing: explicit prop takes priority, otherwise auto-processing during onClickAsync.\n // Processing is always OFF during async feedback (success/error) so the feedback colors show.\n const autoProcessing = isAsync && asyncState === 'loading' && !processingProp\n const processingSpeed: ProcessingSpeed | undefined = isAsyncFeedback ? undefined\n : processingProp === true ? 'working'\n : processingProp === false || !processingProp\n ? (autoProcessing ? 'working' : undefined)\n : processingProp\n const isProcessing = !!processingSpeed\n const resolvedProcessingColor = processingColor ?? resolvedColor ?? 'accent'\n\n if (asChild) {\n // Slot merges all props into the child element via cloneElement at runtime.\n // We cast here because SlotProps only types React.HTMLAttributes<HTMLElement>,\n // which excludes button-specific attrs like `disabled`.\n const slotProps = {\n className: cn(\n buttonVariants({ variant: resolvedVariant, color: resolvedColor, weight: resolvedWeight, size: resolvedSize }),\n resolvedShape === 'pill' && 'rounded-pill',\n resolvedShape === 'pill' && pillPaddingClass[resolvedSize],\n (fullWidth || groupStretch) && 'w-full',\n className,\n ),\n ref,\n disabled: resolvedDisabled || loading,\n 'aria-busy': loading || undefined,\n ...props,\n } as React.ComponentPropsWithRef<typeof Slot>\n return (\n <Slot {...slotProps}>\n <Slottable>{children}</Slottable>\n </Slot>\n )\n }\n\n const inset = iconInsetClass[resolvedSize] ?? { start: '', end: '' }\n // Dim icons on filled variants (Radix pattern — icon is decorative, text is primary)\n const dimIcon = resolvedVariant === 'solid' || resolvedVariant === 'soft' || resolvedVariant === 'outline'\n\n const renderStartSlot = () => {\n if (loading && loadingPosition === 'start') {\n return (\n <span className={cn('inline-flex shrink-0 items-center justify-center', startIcon && inset.start)}>\n <Spinner size={BUTTON_TO_SPINNER_SIZE[resolvedSize]} variant=\"bare\" />\n </span>\n )\n }\n if (startIcon) {\n return (\n <span className={cn('inline-flex shrink-0 items-center justify-center pointer-events-none', inset.start, dimIcon && 'opacity-90')}>\n {normalizeIcon(startIcon)}\n </span>\n )\n }\n return null\n }\n\n const renderEndSlot = () => {\n if (loading && loadingPosition === 'end') {\n return (\n <span className={cn('inline-flex shrink-0 items-center justify-center', endIcon && inset.end)}>\n <Spinner size={BUTTON_TO_SPINNER_SIZE[resolvedSize]} variant=\"bare\" />\n </span>\n )\n }\n if (endIcon) {\n return (\n <span className={cn('inline-flex shrink-0 items-center justify-center pointer-events-none', inset.end, dimIcon && 'opacity-90')}>\n {normalizeIcon(endIcon)}\n </span>\n )\n }\n return null\n }\n\n // Separate DevalokGrain elements (need to be direct button children for absolute positioning)\n // from text/other content (needs z-elevation above grain)\n const childArray = React.Children.toArray(children)\n const grainElements: React.ReactNode[] = []\n const contentElements: React.ReactNode[] = []\n childArray.forEach((child) => {\n if (React.isValidElement(child) && (child.type as { displayName?: string })?.displayName === 'DevalokGrain') {\n grainElements.push(child)\n } else {\n contentElements.push(child)\n }\n })\n\n const renderChildren = () => {\n if (loading && loadingPosition === 'center') {\n return (\n <span className=\"relative inline-flex items-center justify-center\">\n <span className=\"invisible\">{contentElements}</span>\n <span className=\"absolute inset-0 flex items-center justify-center\">\n <Spinner size={BUTTON_TO_SPINNER_SIZE[resolvedSize]} variant=\"bare\" />\n </span>\n </span>\n )\n }\n // Only wrap in z-elevated span when grain is present (to sit above grain layers).\n // Without grain, render children directly to preserve flex layout.\n if (grainElements.length > 0) {\n return <span>{contentElements}</span>\n }\n return <>{contentElements}</>\n }\n\n // Async feedback: override color to show green/red\n const feedbackColorClass = isAsyncFeedback\n ? asyncState === 'success'\n ? 'bg-success-9 text-success-fg border-transparent hover:bg-success-9'\n : 'bg-error-9 text-error-fg border-transparent hover:bg-error-9'\n : undefined\n\n // Async feedback icon — uses Icon's draw animation for pen-stroke effect\n const asyncFeedbackIcon = isAsyncFeedback ? (\n <span className={cn('inline-flex shrink-0 items-center justify-center pointer-events-none', startIcon && inset.start)}>\n <Icon icon={asyncState === 'success' ? IconCheck : IconX} animate=\"draw\" />\n </span>\n ) : null\n\n const iconSize = BUTTON_TO_ICON_SIZE[resolvedSize] ?? 'md'\n\n const buttonEl = (\n <motion.button\n {...motionProps(props)}\n style={{ ...props.style, ...groupRadiusStyle }}\n className={cn(\n buttonVariants({\n // When processing (and not showing async feedback), force soft variant so ants pop\n variant: isProcessing && !isAsyncFeedback && resolvedVariant !== 'ghost' && resolvedVariant !== 'outline' && resolvedVariant !== 'link' ? 'soft' : resolvedVariant,\n color: resolvedColor,\n weight: resolvedWeight,\n size: resolvedSize,\n }),\n resolvedShape === 'pill' && 'rounded-pill',\n resolvedShape === 'pill' && pillPaddingClass[resolvedSize],\n (fullWidth || groupStretch) && 'w-full',\n // Asymmetric timing: hover-out is slow+relaxed, hover-in is fast+snappy (applied via hover: override)\n !loading && !isAsyncFeedback && 'transition-[color,background-color,border-color,box-shadow,transform,filter] duration-moderate-01 ease-productive-exit',\n !loading && !isAsyncFeedback && 'hover:duration-fast-02 hover:ease-productive-entrance',\n !loading && !isAsyncFeedback && 'active:scale-[0.95] active:brightness-[0.92] active:saturate-[1.1] active:duration-[0ms]',\n feedbackColorClass,\n isAsyncFeedback && 'transition-colors duration-moderate-01 ease-productive-standard',\n isProcessing && processingDisabled && 'pointer-events-none cursor-default',\n className,\n )}\n ref={(el: HTMLButtonElement | null) => {\n btnRef.current = el\n if (typeof ref === 'function') ref(el)\n else if (ref) (ref as React.MutableRefObject<HTMLButtonElement | null>).current = el\n }}\n disabled={resolvedDisabled || (loading && !isProcessing)}\n aria-busy={loading || isProcessing || undefined}\n aria-disabled={isProcessing && processingDisabled || undefined}\n onClick={isAsync ? handleAsyncClick : (isProcessing && processingDisabled ? undefined : onClick)}\n >\n {/* Grain layers render as direct children (need absolute positioning) */}\n {grainElements}\n {/* Content renders above grain via z-[2] span wrapper */}\n {isAsyncFeedback ? asyncFeedbackIcon : renderStartSlot()}\n {isAsyncFeedback ? contentElements : renderChildren()}\n {isAsyncFeedback ? null : renderEndSlot()}\n </motion.button>\n )\n\n // Always wrap in a positioned container so the overlay can render\n // as a sibling OUTSIDE the button (not affected by disabled opacity).\n // Keeping the wrapper always-on prevents React unmount/remount on\n // processing toggle, enabling smooth CSS transitions between states.\n return (\n <IconProvider size={iconSize}>\n <span\n ref={wrapperRef}\n className={cn('relative inline-flex', fullWidth && 'w-full')}\n style={{\n ...(fullWidth || groupStretch || prefersReduced ? undefined : { transition: 'width 0.2s cubic-bezier(0.25, 0.1, 0.25, 1)' }),\n ...groupRadiusStyle,\n }}\n >\n {buttonEl}\n <ProcessingOverlay\n active={isProcessing}\n speed={processingSpeed ?? 'working'}\n color={resolvedProcessingColor}\n />\n </span>\n </IconProvider>\n )\n },\n)\nButton.displayName = 'Button'\n\nexport { Button }\n"],"mappings":"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"}
package/dist/ui/card.d.ts CHANGED
@@ -66,7 +66,7 @@ declare const cardVariants: (props?: ({
66
66
  * // Flat card for a sidebar panel section (no shadow):
67
67
  * <Card variant="flat">
68
68
  * <CardContent>
69
- * <p className="text-surface-fg-muted text-ds-sm">No recent activity</p>
69
+ * <p className="text-surface-fg-muted text-body-sm">No recent activity</p>
70
70
  * </CardContent>
71
71
  * </Card>
72
72
  */
package/dist/ui/card.js CHANGED
@@ -77,7 +77,7 @@ var u = i.forwardRef(({ className: e, ...t }, n) => /* @__PURE__ */ a("div", {
77
77
  u.displayName = "CardTitle";
78
78
  var d = i.forwardRef(({ className: e, ...t }, n) => /* @__PURE__ */ a("div", {
79
79
  ref: n,
80
- className: r("text-ds-md text-surface-fg-muted", e),
80
+ className: r("text-body-md text-surface-fg-muted", e),
81
81
  ...t
82
82
  }));
83
83
  d.displayName = "CardDescription";