@burtson-labs/ui 0.14.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (245) hide show
  1. package/LICENSES/DEPENDENCIES.txt +1 -1
  2. package/README.md +15 -11
  3. package/dist/components/accordion.d.ts +3 -3
  4. package/dist/components/accordion.js +13 -10
  5. package/dist/components/accordion.js.map +1 -1
  6. package/dist/components/agent-run.d.ts +22 -0
  7. package/dist/components/agent-run.js +131 -0
  8. package/dist/components/agent-run.js.map +1 -0
  9. package/dist/components/alert-dialog.d.ts +12 -10
  10. package/dist/components/alert-dialog.js +29 -20
  11. package/dist/components/alert-dialog.js.map +1 -1
  12. package/dist/components/alert.d.ts +5 -3
  13. package/dist/components/alert.js +11 -7
  14. package/dist/components/alert.js.map +1 -1
  15. package/dist/components/app-shell.d.ts +7 -6
  16. package/dist/components/app-shell.js +21 -14
  17. package/dist/components/app-shell.js.map +1 -1
  18. package/dist/components/attachment.d.ts +3 -3
  19. package/dist/components/attachment.js +10 -7
  20. package/dist/components/attachment.js.map +1 -1
  21. package/dist/components/audio-player.d.ts +2 -2
  22. package/dist/components/audio-player.js +8 -6
  23. package/dist/components/audio-player.js.map +1 -1
  24. package/dist/components/avatar-upload.d.ts +19 -0
  25. package/dist/components/avatar-upload.js +359 -0
  26. package/dist/components/avatar-upload.js.map +1 -0
  27. package/dist/components/avatar.d.ts +3 -3
  28. package/dist/components/avatar.js +10 -7
  29. package/dist/components/avatar.js.map +1 -1
  30. package/dist/components/badge.d.ts +1 -1
  31. package/dist/components/badge.js +12 -10
  32. package/dist/components/badge.js.map +1 -1
  33. package/dist/components/breadcrumb.d.ts +8 -8
  34. package/dist/components/breadcrumb.js +24 -17
  35. package/dist/components/breadcrumb.js.map +1 -1
  36. package/dist/components/button.d.ts +8 -1
  37. package/dist/components/button.js +12 -3
  38. package/dist/components/button.js.map +1 -1
  39. package/dist/components/card.d.ts +8 -8
  40. package/dist/components/card.js +32 -23
  41. package/dist/components/card.js.map +1 -1
  42. package/dist/components/chat-history.d.ts +1 -1
  43. package/dist/components/chat-history.js +10 -9
  44. package/dist/components/chat-history.js.map +1 -1
  45. package/dist/components/chat-layout.d.ts +1 -1
  46. package/dist/components/chat-layout.js +7 -3
  47. package/dist/components/chat-layout.js.map +1 -1
  48. package/dist/components/checkbox-card.d.ts +2 -2
  49. package/dist/components/checkbox-card.js +9 -7
  50. package/dist/components/checkbox-card.js.map +1 -1
  51. package/dist/components/checkbox.d.ts +23 -2
  52. package/dist/components/checkbox.js +48 -6
  53. package/dist/components/checkbox.js.map +1 -1
  54. package/dist/components/collapsible.d.ts +2 -2
  55. package/dist/components/collapsible.js +7 -5
  56. package/dist/components/collapsible.js.map +1 -1
  57. package/dist/components/combobox.d.ts +14 -4
  58. package/dist/components/combobox.js +18 -8
  59. package/dist/components/combobox.js.map +1 -1
  60. package/dist/components/command.d.ts +68 -12
  61. package/dist/components/command.js +38 -25
  62. package/dist/components/command.js.map +1 -1
  63. package/dist/components/composer.d.ts +2 -2
  64. package/dist/components/composer.js +9 -7
  65. package/dist/components/composer.js.map +1 -1
  66. package/dist/components/connection-status.d.ts +3 -3
  67. package/dist/components/connection-status.js +18 -14
  68. package/dist/components/connection-status.js.map +1 -1
  69. package/dist/components/context-menu.d.ts +14 -13
  70. package/dist/components/context-menu.js +33 -23
  71. package/dist/components/context-menu.js.map +1 -1
  72. package/dist/components/conversation.d.ts +1 -1
  73. package/dist/components/conversation.js +6 -5
  74. package/dist/components/conversation.js.map +1 -1
  75. package/dist/components/copy-button.d.ts +1 -1
  76. package/dist/components/copy-button.js +3 -2
  77. package/dist/components/copy-button.js.map +1 -1
  78. package/dist/components/data-table.d.ts +7 -2
  79. package/dist/components/data-table.js +16 -42
  80. package/dist/components/data-table.js.map +1 -1
  81. package/dist/components/dialog.d.ts +18 -9
  82. package/dist/components/dialog.js +38 -22
  83. package/dist/components/dialog.js.map +1 -1
  84. package/dist/components/dropdown-menu.d.ts +14 -13
  85. package/dist/components/dropdown-menu.js +33 -23
  86. package/dist/components/dropdown-menu.js.map +1 -1
  87. package/dist/components/editor-tabs.d.ts +1 -1
  88. package/dist/components/editor-tabs.js +6 -5
  89. package/dist/components/editor-tabs.js.map +1 -1
  90. package/dist/components/empty-state.d.ts +5 -5
  91. package/dist/components/empty-state.js +16 -11
  92. package/dist/components/empty-state.js.map +1 -1
  93. package/dist/components/error-summary.d.ts +21 -0
  94. package/dist/components/error-summary.js +62 -0
  95. package/dist/components/error-summary.js.map +1 -0
  96. package/dist/components/field.d.ts +66 -7
  97. package/dist/components/field.js +151 -20
  98. package/dist/components/field.js.map +1 -1
  99. package/dist/components/form-actions.d.ts +18 -0
  100. package/dist/components/form-actions.js +30 -0
  101. package/dist/components/form-actions.js.map +1 -0
  102. package/dist/components/icon-button.d.ts +3 -1
  103. package/dist/components/icon-button.js +5 -3
  104. package/dist/components/icon-button.js.map +1 -1
  105. package/dist/components/input.d.ts +42 -7
  106. package/dist/components/input.js +53 -10
  107. package/dist/components/input.js.map +1 -1
  108. package/dist/components/kbd.d.ts +2 -2
  109. package/dist/components/kbd.js +7 -5
  110. package/dist/components/kbd.js.map +1 -1
  111. package/dist/components/label.d.ts +6 -1
  112. package/dist/components/label.js +10 -4
  113. package/dist/components/label.js.map +1 -1
  114. package/dist/components/markdown.d.ts +4 -3
  115. package/dist/components/markdown.js +7 -6
  116. package/dist/components/markdown.js.map +1 -1
  117. package/dist/components/menubar.d.ts +16 -14
  118. package/dist/components/menubar.js +39 -27
  119. package/dist/components/menubar.js.map +1 -1
  120. package/dist/components/message-actions.d.ts +3 -3
  121. package/dist/components/message-actions.js +15 -12
  122. package/dist/components/message-actions.js.map +1 -1
  123. package/dist/components/message.d.ts +1 -1
  124. package/dist/components/message.js +5 -3
  125. package/dist/components/message.js.map +1 -1
  126. package/dist/components/mobile-nav.d.ts +1 -1
  127. package/dist/components/mobile-nav.js +6 -5
  128. package/dist/components/mobile-nav.js.map +1 -1
  129. package/dist/components/native-select.d.ts +16 -0
  130. package/dist/components/native-select.js +33 -0
  131. package/dist/components/native-select.js.map +1 -0
  132. package/dist/components/navigation-menu.d.ts +12 -11
  133. package/dist/components/navigation-menu.js +32 -23
  134. package/dist/components/navigation-menu.js.map +1 -1
  135. package/dist/components/number-input.d.ts +23 -0
  136. package/dist/components/number-input.js +45 -0
  137. package/dist/components/number-input.js.map +1 -0
  138. package/dist/components/onboarding-checklist.d.ts +1 -1
  139. package/dist/components/onboarding-checklist.js +4 -3
  140. package/dist/components/onboarding-checklist.js.map +1 -1
  141. package/dist/components/page-header.d.ts +7 -6
  142. package/dist/components/page-header.js +22 -15
  143. package/dist/components/page-header.js.map +1 -1
  144. package/dist/components/pagination.d.ts +1 -1
  145. package/dist/components/pagination.js +3 -2
  146. package/dist/components/pagination.js.map +1 -1
  147. package/dist/components/popover.d.ts +13 -10
  148. package/dist/components/popover.js +23 -17
  149. package/dist/components/popover.js.map +1 -1
  150. package/dist/components/progress.d.ts +1 -1
  151. package/dist/components/progress.js +6 -5
  152. package/dist/components/progress.js.map +1 -1
  153. package/dist/components/radio-group.d.ts +22 -3
  154. package/dist/components/radio-group.js +51 -10
  155. package/dist/components/radio-group.js.map +1 -1
  156. package/dist/components/reasoning.d.ts +3 -3
  157. package/dist/components/reasoning.js +9 -7
  158. package/dist/components/reasoning.js.map +1 -1
  159. package/dist/components/scroll-area.d.ts +3 -2
  160. package/dist/components/scroll-area.js +10 -7
  161. package/dist/components/scroll-area.js.map +1 -1
  162. package/dist/components/secret-input.d.ts +3 -2
  163. package/dist/components/secret-input.js +6 -4
  164. package/dist/components/secret-input.js.map +1 -1
  165. package/dist/components/select.d.ts +11 -6
  166. package/dist/components/select.js +24 -18
  167. package/dist/components/select.js.map +1 -1
  168. package/dist/components/separator.d.ts +1 -1
  169. package/dist/components/separator.js +4 -3
  170. package/dist/components/separator.js.map +1 -1
  171. package/dist/components/sheet.d.ts +10 -8
  172. package/dist/components/sheet.js +31 -20
  173. package/dist/components/sheet.js.map +1 -1
  174. package/dist/components/skeleton.d.ts +2 -1
  175. package/dist/components/skeleton.js +6 -4
  176. package/dist/components/skeleton.js.map +1 -1
  177. package/dist/components/slider.d.ts +10 -6
  178. package/dist/components/slider.js +15 -7
  179. package/dist/components/slider.js.map +1 -1
  180. package/dist/components/source.d.ts +2 -2
  181. package/dist/components/source.js +9 -7
  182. package/dist/components/source.js.map +1 -1
  183. package/dist/components/spinner.d.ts +4 -2
  184. package/dist/components/spinner.js +4 -3
  185. package/dist/components/spinner.js.map +1 -1
  186. package/dist/components/stat-card.d.ts +27 -2
  187. package/dist/components/stat-card.js +69 -9
  188. package/dist/components/stat-card.js.map +1 -1
  189. package/dist/components/status.d.ts +7 -6
  190. package/dist/components/status.js +11 -5
  191. package/dist/components/status.js.map +1 -1
  192. package/dist/components/steps.d.ts +1 -1
  193. package/dist/components/steps.js +4 -3
  194. package/dist/components/steps.js.map +1 -1
  195. package/dist/components/switch.d.ts +46 -2
  196. package/dist/components/switch.js +85 -8
  197. package/dist/components/switch.js.map +1 -1
  198. package/dist/components/table.d.ts +29 -12
  199. package/dist/components/table.js +79 -34
  200. package/dist/components/table.js.map +1 -1
  201. package/dist/components/tabs.d.ts +9 -4
  202. package/dist/components/tabs.js +22 -13
  203. package/dist/components/tabs.js.map +1 -1
  204. package/dist/components/textarea.d.ts +6 -1
  205. package/dist/components/textarea.js +3 -3
  206. package/dist/components/textarea.js.map +1 -1
  207. package/dist/components/toast.d.ts +10 -6
  208. package/dist/components/toast.js +27 -18
  209. package/dist/components/toast.js.map +1 -1
  210. package/dist/components/toaster.d.ts +4 -2
  211. package/dist/components/toaster.js +6 -2
  212. package/dist/components/toaster.js.map +1 -1
  213. package/dist/components/tool-call.d.ts +3 -3
  214. package/dist/components/tool-call.js +16 -12
  215. package/dist/components/tool-call.js.map +1 -1
  216. package/dist/components/toolbar.d.ts +9 -4
  217. package/dist/components/toolbar.js +14 -9
  218. package/dist/components/toolbar.js.map +1 -1
  219. package/dist/components/tooltip.d.ts +3 -2
  220. package/dist/components/tooltip.js +7 -4
  221. package/dist/components/tooltip.js.map +1 -1
  222. package/dist/components/tour.js +2 -2
  223. package/dist/components/tour.js.map +1 -1
  224. package/dist/components/tree-view.d.ts +1 -1
  225. package/dist/components/tree-view.js +9 -5
  226. package/dist/components/tree-view.js.map +1 -1
  227. package/dist/components/voice-recorder.d.ts +1 -1
  228. package/dist/components/voice-recorder.js +4 -2
  229. package/dist/components/voice-recorder.js.map +1 -1
  230. package/dist/index.d.ts +8 -1
  231. package/dist/index.js +19 -12
  232. package/dist/lib/media.d.ts +18 -0
  233. package/dist/lib/media.js +34 -0
  234. package/dist/lib/media.js.map +1 -0
  235. package/dist/lib/utils.d.ts +32 -0
  236. package/dist/lib/utils.js +33 -1
  237. package/dist/lib/utils.js.map +1 -1
  238. package/dist/mui/index.js +20 -8
  239. package/dist/mui/index.js.map +1 -1
  240. package/dist/styles.css +1 -1
  241. package/dist/theme.css +36 -17
  242. package/dist/tokens.d.ts +78 -36
  243. package/dist/tokens.js +63 -32
  244. package/dist/tokens.js.map +1 -1
  245. package/package.json +5 -3
@@ -1,41 +1,46 @@
1
1
  "use client";
2
- import { cn } from "../lib/utils.js";
2
+ import { cn, focusRingClasses } from "../lib/utils.js";
3
3
  import { Root as Slot } from "../primitives/vendor/radix/react-slot/slot.js";
4
- import "react";
4
+ import * as React from "react";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import ChevronRight from "@burtson-labs/icons/react/chevron-right";
7
7
  import MoreHorizontal from "@burtson-labs/icons/react/more-horizontal";
8
8
  //#region src/components/breadcrumb.tsx
9
- function Breadcrumb(props) {
9
+ var Breadcrumb = React.forwardRef(function Breadcrumb(props, ref) {
10
10
  return /* @__PURE__ */ jsx("nav", {
11
+ ref,
11
12
  "aria-label": "Breadcrumb",
12
13
  "data-slot": "breadcrumb",
13
14
  ...props
14
15
  });
15
- }
16
- function BreadcrumbList({ className, ...props }) {
16
+ });
17
+ var BreadcrumbList = React.forwardRef(function BreadcrumbList({ className, ...props }, ref) {
17
18
  return /* @__PURE__ */ jsx("ol", {
19
+ ref,
18
20
  "data-slot": "breadcrumb-list",
19
21
  className: cn("flex flex-wrap items-center gap-1.5 text-sm break-words text-muted-foreground", className),
20
22
  ...props
21
23
  });
22
- }
23
- function BreadcrumbItem({ className, ...props }) {
24
+ });
25
+ var BreadcrumbItem = React.forwardRef(function BreadcrumbItem({ className, ...props }, ref) {
24
26
  return /* @__PURE__ */ jsx("li", {
27
+ ref,
25
28
  "data-slot": "breadcrumb-item",
26
29
  className: cn("inline-flex items-center gap-1.5", className),
27
30
  ...props
28
31
  });
29
- }
30
- function BreadcrumbLink({ asChild, className, ...props }) {
32
+ });
33
+ var BreadcrumbLink = React.forwardRef(function BreadcrumbLink({ asChild, className, ...props }, ref) {
31
34
  return /* @__PURE__ */ jsx(asChild ? Slot : "a", {
35
+ ref,
32
36
  "data-slot": "breadcrumb-link",
33
- className: cn("transition-colors hover:text-foreground", className),
37
+ className: cn("rounded-xs transition-colors hover:text-foreground", focusRingClasses, className),
34
38
  ...props
35
39
  });
36
- }
37
- function BreadcrumbPage({ className, ...props }) {
40
+ });
41
+ var BreadcrumbPage = React.forwardRef(function BreadcrumbPage({ className, ...props }, ref) {
38
42
  return /* @__PURE__ */ jsx("span", {
43
+ ref,
39
44
  "data-slot": "breadcrumb-page",
40
45
  role: "link",
41
46
  "aria-disabled": "true",
@@ -43,9 +48,10 @@ function BreadcrumbPage({ className, ...props }) {
43
48
  className: cn("font-medium text-foreground", className),
44
49
  ...props
45
50
  });
46
- }
47
- function BreadcrumbSeparator({ children, className, ...props }) {
51
+ });
52
+ var BreadcrumbSeparator = React.forwardRef(function BreadcrumbSeparator({ children, className, ...props }, ref) {
48
53
  return /* @__PURE__ */ jsx("li", {
54
+ ref,
49
55
  "data-slot": "breadcrumb-separator",
50
56
  role: "presentation",
51
57
  "aria-hidden": "true",
@@ -53,9 +59,10 @@ function BreadcrumbSeparator({ children, className, ...props }) {
53
59
  ...props,
54
60
  children: children ?? /* @__PURE__ */ jsx(ChevronRight, {})
55
61
  });
56
- }
57
- function BreadcrumbEllipsis({ className, ...props }) {
62
+ });
63
+ var BreadcrumbEllipsis = React.forwardRef(function BreadcrumbEllipsis({ className, ...props }, ref) {
58
64
  return /* @__PURE__ */ jsxs("span", {
65
+ ref,
59
66
  "data-slot": "breadcrumb-ellipsis",
60
67
  role: "presentation",
61
68
  "aria-hidden": "true",
@@ -66,7 +73,7 @@ function BreadcrumbEllipsis({ className, ...props }) {
66
73
  children: "More"
67
74
  })]
68
75
  });
69
- }
76
+ });
70
77
  //#endregion
71
78
  export { Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator };
72
79
 
@@ -1 +1 @@
1
- {"version":3,"file":"breadcrumb.js","names":["Slot.Root"],"sources":["../../src/components/breadcrumb.tsx"],"sourcesContent":["import ChevronRight from '@burtson-labs/icons/react/chevron-right';\nimport MoreHorizontal from '@burtson-labs/icons/react/more-horizontal';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\nimport * as Slot from '../primitives/vendor/radix/react-slot';\n\nfunction Breadcrumb(props: React.ComponentProps<'nav'>) {\n return <nav aria-label=\"Breadcrumb\" data-slot=\"breadcrumb\" {...props} />;\n}\n\nfunction BreadcrumbList({ className, ...props }: React.ComponentProps<'ol'>) {\n return (\n <ol\n data-slot=\"breadcrumb-list\"\n className={cn(\n 'flex flex-wrap items-center gap-1.5 text-sm break-words text-muted-foreground',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction BreadcrumbItem({ className, ...props }: React.ComponentProps<'li'>) {\n return (\n <li\n data-slot=\"breadcrumb-item\"\n className={cn('inline-flex items-center gap-1.5', className)}\n {...props}\n />\n );\n}\n\nfunction BreadcrumbLink({\n asChild,\n className,\n ...props\n}: React.ComponentProps<'a'> & { asChild?: boolean }) {\n const Comp = asChild ? Slot.Root : 'a';\n return (\n <Comp\n data-slot=\"breadcrumb-link\"\n className={cn('transition-colors hover:text-foreground', className)}\n {...props}\n />\n );\n}\n\nfunction BreadcrumbPage({ className, ...props }: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"breadcrumb-page\"\n role=\"link\"\n aria-disabled=\"true\"\n aria-current=\"page\"\n className={cn('font-medium text-foreground', className)}\n {...props}\n />\n );\n}\n\nfunction BreadcrumbSeparator({ children, className, ...props }: React.ComponentProps<'li'>) {\n return (\n <li\n data-slot=\"breadcrumb-separator\"\n role=\"presentation\"\n aria-hidden=\"true\"\n className={cn('[&>svg]:size-3.5', className)}\n {...props}\n >\n {children ?? <ChevronRight />}\n </li>\n );\n}\n\nfunction BreadcrumbEllipsis({ className, ...props }: React.ComponentProps<'span'>) {\n return (\n <span\n data-slot=\"breadcrumb-ellipsis\"\n role=\"presentation\"\n aria-hidden=\"true\"\n className={cn('flex size-9 items-center justify-center', className)}\n {...props}\n >\n <MoreHorizontal className=\"size-4\" />\n <span className=\"sr-only\">More</span>\n </span>\n );\n}\n\nexport {\n Breadcrumb,\n BreadcrumbEllipsis,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n};\n"],"mappings":";;;;;;;;AAOA,SAAS,WAAW,OAAoC;CACtD,OAAO,oBAAC,OAAD;EAAK,cAAW;EAAa,aAAU;EAAa,GAAI;CAAQ,CAAA;AACzE;AAEA,SAAS,eAAe,EAAE,WAAW,GAAG,SAAqC;CAC3E,OACE,oBAAC,MAAD;EACE,aAAU;EACV,WAAW,GACT,iFACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,eAAe,EAAE,WAAW,GAAG,SAAqC;CAC3E,OACE,oBAAC,MAAD;EACE,aAAU;EACV,WAAW,GAAG,oCAAoC,SAAS;EAC3D,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,eAAe,EACtB,SACA,WACA,GAAG,SACiD;CAEpD,OACE,oBAFW,UAAUA,OAAY,KAEjC;EACE,aAAU;EACV,WAAW,GAAG,2CAA2C,SAAS;EAClE,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,eAAe,EAAE,WAAW,GAAG,SAAuC;CAC7E,OACE,oBAAC,QAAD;EACE,aAAU;EACV,MAAK;EACL,iBAAc;EACd,gBAAa;EACb,WAAW,GAAG,+BAA+B,SAAS;EACtD,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,oBAAoB,EAAE,UAAU,WAAW,GAAG,SAAqC;CAC1F,OACE,oBAAC,MAAD;EACE,aAAU;EACV,MAAK;EACL,eAAY;EACZ,WAAW,GAAG,oBAAoB,SAAS;EAC3C,GAAI;EAEH,UAAA,YAAY,oBAAC,cAAD,CAAe,CAAA;CAC1B,CAAA;AAER;AAEA,SAAS,mBAAmB,EAAE,WAAW,GAAG,SAAuC;CACjF,OACE,qBAAC,QAAD;EACE,aAAU;EACV,MAAK;EACL,eAAY;EACZ,WAAW,GAAG,2CAA2C,SAAS;EAClE,GAAI;EALN,UAAA,CAOE,oBAAC,gBAAD,EAAgB,WAAU,SAAU,CAAA,GACpC,oBAAC,QAAD;GAAM,WAAU;GAAU,UAAA;EAAU,CAAA,CAChC;;AAEV"}
1
+ {"version":3,"file":"breadcrumb.js","names":["Slot.Root"],"sources":["../../src/components/breadcrumb.tsx"],"sourcesContent":["import ChevronRight from '@burtson-labs/icons/react/chevron-right';\nimport MoreHorizontal from '@burtson-labs/icons/react/more-horizontal';\nimport * as React from 'react';\n\nimport { cn, focusRingClasses } from '../lib/utils';\nimport * as Slot from '../primitives/vendor/radix/react-slot';\n\nconst Breadcrumb = React.forwardRef<HTMLElement, React.ComponentProps<'nav'>>(\n function Breadcrumb(props, ref) {\n return <nav ref={ref} aria-label=\"Breadcrumb\" data-slot=\"breadcrumb\" {...props} />;\n },\n);\n\nconst BreadcrumbList = React.forwardRef<HTMLOListElement, React.ComponentProps<'ol'>>(\n function BreadcrumbList({ className, ...props }, ref) {\n return (\n <ol\n ref={ref}\n data-slot=\"breadcrumb-list\"\n className={cn(\n 'flex flex-wrap items-center gap-1.5 text-sm break-words text-muted-foreground',\n className,\n )}\n {...props}\n />\n );\n },\n);\n\nconst BreadcrumbItem = React.forwardRef<HTMLLIElement, React.ComponentProps<'li'>>(\n function BreadcrumbItem({ className, ...props }, ref) {\n return (\n <li\n ref={ref}\n data-slot=\"breadcrumb-item\"\n className={cn('inline-flex items-center gap-1.5', className)}\n {...props}\n />\n );\n },\n);\n\nconst BreadcrumbLink = React.forwardRef<\n HTMLAnchorElement,\n React.ComponentProps<'a'> & { asChild?: boolean }\n>(function BreadcrumbLink({ asChild, className, ...props }, ref) {\n const Comp = asChild ? Slot.Root : 'a';\n return (\n <Comp\n ref={ref}\n data-slot=\"breadcrumb-link\"\n className={cn(\n 'rounded-xs transition-colors hover:text-foreground',\n focusRingClasses,\n className,\n )}\n {...props}\n />\n );\n});\n\nconst BreadcrumbPage = React.forwardRef<HTMLSpanElement, React.ComponentProps<'span'>>(\n function BreadcrumbPage({ className, ...props }, ref) {\n return (\n <span\n ref={ref}\n data-slot=\"breadcrumb-page\"\n role=\"link\"\n aria-disabled=\"true\"\n aria-current=\"page\"\n className={cn('font-medium text-foreground', className)}\n {...props}\n />\n );\n },\n);\n\nconst BreadcrumbSeparator = React.forwardRef<HTMLLIElement, React.ComponentProps<'li'>>(\n function BreadcrumbSeparator({ children, className, ...props }, ref) {\n return (\n <li\n ref={ref}\n data-slot=\"breadcrumb-separator\"\n role=\"presentation\"\n aria-hidden=\"true\"\n className={cn('[&>svg]:size-3.5', className)}\n {...props}\n >\n {children ?? <ChevronRight />}\n </li>\n );\n },\n);\n\nconst BreadcrumbEllipsis = React.forwardRef<HTMLSpanElement, React.ComponentProps<'span'>>(\n function BreadcrumbEllipsis({ className, ...props }, ref) {\n return (\n <span\n ref={ref}\n data-slot=\"breadcrumb-ellipsis\"\n role=\"presentation\"\n aria-hidden=\"true\"\n className={cn('flex size-9 items-center justify-center', className)}\n {...props}\n >\n <MoreHorizontal className=\"size-4\" />\n <span className=\"sr-only\">More</span>\n </span>\n );\n },\n);\n\nexport {\n Breadcrumb,\n BreadcrumbEllipsis,\n BreadcrumbItem,\n BreadcrumbLink,\n BreadcrumbList,\n BreadcrumbPage,\n BreadcrumbSeparator,\n};\n"],"mappings":";;;;;;;;AAOA,IAAM,aAAa,MAAM,WACvB,SAAS,WAAW,OAAO,KAAK;CAC9B,OAAO,oBAAC,OAAD;EAAU;EAAK,cAAW;EAAa,aAAU;EAAa,GAAI;CAAQ,CAAA;AACnF,CACF;AAEA,IAAM,iBAAiB,MAAM,WAC3B,SAAS,eAAe,EAAE,WAAW,GAAG,SAAS,KAAK;CACpD,OACE,oBAAC,MAAD;EACO;EACL,aAAU;EACV,WAAW,GACT,iFACA,SACF;EACA,GAAI;CACL,CAAA;AAEL,CACF;AAEA,IAAM,iBAAiB,MAAM,WAC3B,SAAS,eAAe,EAAE,WAAW,GAAG,SAAS,KAAK;CACpD,OACE,oBAAC,MAAD;EACO;EACL,aAAU;EACV,WAAW,GAAG,oCAAoC,SAAS;EAC3D,GAAI;CACL,CAAA;AAEL,CACF;AAEA,IAAM,iBAAiB,MAAM,WAG3B,SAAS,eAAe,EAAE,SAAS,WAAW,GAAG,SAAS,KAAK;CAE/D,OACE,oBAFW,UAAUA,OAAY,KAEjC;EACO;EACL,aAAU;EACV,WAAW,GACT,sDACA,kBACA,SACF;EACA,GAAI;CACL,CAAA;AAEL,CAAC;AAED,IAAM,iBAAiB,MAAM,WAC3B,SAAS,eAAe,EAAE,WAAW,GAAG,SAAS,KAAK;CACpD,OACE,oBAAC,QAAD;EACO;EACL,aAAU;EACV,MAAK;EACL,iBAAc;EACd,gBAAa;EACb,WAAW,GAAG,+BAA+B,SAAS;EACtD,GAAI;CACL,CAAA;AAEL,CACF;AAEA,IAAM,sBAAsB,MAAM,WAChC,SAAS,oBAAoB,EAAE,UAAU,WAAW,GAAG,SAAS,KAAK;CACnE,OACE,oBAAC,MAAD;EACO;EACL,aAAU;EACV,MAAK;EACL,eAAY;EACZ,WAAW,GAAG,oBAAoB,SAAS;EAC3C,GAAI;EAEH,UAAA,YAAY,oBAAC,cAAD,CAAe,CAAA;CAC1B,CAAA;AAER,CACF;AAEA,IAAM,qBAAqB,MAAM,WAC/B,SAAS,mBAAmB,EAAE,WAAW,GAAG,SAAS,KAAK;CACxD,OACE,qBAAC,QAAD;EACO;EACL,aAAU;EACV,MAAK;EACL,eAAY;EACZ,WAAW,GAAG,2CAA2C,SAAS;EAClE,GAAI;EANN,UAAA,CAQE,oBAAC,gBAAD,EAAgB,WAAU,SAAU,CAAA,GACpC,oBAAC,QAAD;GAAM,WAAU;GAAU,UAAA;EAAU,CAAA,CAChC;;AAEV,CACF"}
@@ -2,11 +2,18 @@ import { type VariantProps } from 'class-variance-authority';
2
2
  import * as React from 'react';
3
3
  declare const buttonVariants: (props?: ({
4
4
  variant?: "secondary" | "destructive" | "brand" | "link" | "default" | "outline" | "soft" | "ghost" | null | undefined;
5
- size?: "default" | "icon" | "xs" | "sm" | "lg" | "icon-sm" | "icon-lg" | null | undefined;
5
+ size?: "sm" | "lg" | "default" | "icon" | "xs" | "icon-sm" | "icon-lg" | null | undefined;
6
6
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
7
  export interface ButtonProps extends React.ComponentProps<'button'>, VariantProps<typeof buttonVariants> {
8
8
  asChild?: boolean;
9
9
  loading?: boolean;
10
10
  }
11
+ /**
12
+ * The action primitive. On touch screens every button is at least 44px
13
+ * (`pointer-coarse:min-h-8` opts a button in a dense header out); link-styled
14
+ * buttons stay inline. `data-variant` and `data-size` are set for CSS that
15
+ * needs them. A trigger's `asChild` replaces `data-slot` with its own
16
+ * (`dialog-trigger`), which is why the sizing lives in the classes.
17
+ */
11
18
  declare const Button: React.ForwardRefExoticComponent<Omit<ButtonProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
12
19
  export { Button, buttonVariants };
@@ -1,11 +1,11 @@
1
1
  "use client";
2
- import { cn } from "../lib/utils.js";
2
+ import { cn, focusRingClasses } from "../lib/utils.js";
3
3
  import { Root as Slot } from "../primitives/vendor/radix/react-slot/slot.js";
4
4
  import * as React from "react";
5
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
6
  import { cva } from "class-variance-authority";
7
7
  //#region src/components/button.tsx
8
- var buttonVariants = cva("inline-flex shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-semibold tracking-[-0.01em] outline-none transition-[background-color,border-color,color,box-shadow,transform] duration-150 select-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:ring-[3px] focus-visible:ring-ring/20 active:translate-y-px disabled:pointer-events-none disabled:opacity-45 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {
8
+ var buttonVariants = cva(`inline-flex shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-semibold tracking-[-0.01em] transition-[background-color,border-color,color,box-shadow,transform,filter] select-none ${focusRingClasses} pointer-coarse:min-h-11 pointer-coarse:min-w-11 active:translate-y-px disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4`, {
9
9
  variants: {
10
10
  variant: {
11
11
  default: "border border-primary bg-primary text-primary-foreground shadow-xs hover:brightness-90",
@@ -15,7 +15,7 @@ var buttonVariants = cva("inline-flex shrink-0 items-center justify-center gap-2
15
15
  outline: "border border-border-strong bg-surface text-foreground shadow-xs hover:border-brand/35 hover:bg-accent/60 hover:text-accent-foreground",
16
16
  ghost: "border border-transparent text-foreground hover:bg-muted",
17
17
  destructive: "border border-destructive bg-destructive text-destructive-foreground shadow-xs hover:bg-destructive/90",
18
- link: "h-auto rounded-none border-0 p-0 text-brand shadow-none hover:text-brand-hover hover:underline hover:underline-offset-4 active:translate-y-0"
18
+ link: "h-auto rounded-none border-0 p-0 text-brand shadow-none hover:text-brand-hover hover:underline hover:underline-offset-4 active:translate-y-0 pointer-coarse:min-h-0 pointer-coarse:min-w-0"
19
19
  },
20
20
  size: {
21
21
  xs: "h-7 gap-1.5 rounded-sm px-2.5 text-xs [&_svg:not([class*=size-])]:size-3.5",
@@ -32,11 +32,20 @@ var buttonVariants = cva("inline-flex shrink-0 items-center justify-center gap-2
32
32
  size: "default"
33
33
  }
34
34
  });
35
+ /**
36
+ * The action primitive. On touch screens every button is at least 44px
37
+ * (`pointer-coarse:min-h-8` opts a button in a dense header out); link-styled
38
+ * buttons stay inline. `data-variant` and `data-size` are set for CSS that
39
+ * needs them. A trigger's `asChild` replaces `data-slot` with its own
40
+ * (`dialog-trigger`), which is why the sizing lives in the classes.
41
+ */
35
42
  var Button = React.forwardRef(function Button({ className, variant, size, asChild = false, loading = false, disabled, children, type, onClickCapture, onKeyDownCapture, ...props }, ref) {
36
43
  return /* @__PURE__ */ jsx(asChild ? Slot : "button", {
37
44
  ref,
38
45
  type: asChild ? void 0 : type ?? "button",
39
46
  "data-slot": "button",
47
+ "data-variant": variant ?? "default",
48
+ "data-size": size ?? "default",
40
49
  "data-loading": loading ? "" : void 0,
41
50
  "aria-busy": loading || void 0,
42
51
  disabled: !asChild ? disabled || loading : void 0,
@@ -1 +1 @@
1
- {"version":3,"file":"button.js","names":["Slot.Root","_Fragment"],"sources":["../../src/components/button.tsx"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\nimport * as Slot from '../primitives/vendor/radix/react-slot';\n\nconst buttonVariants = cva(\n \"inline-flex shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-semibold tracking-[-0.01em] outline-none transition-[background-color,border-color,color,box-shadow,transform] duration-150 select-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:ring-[3px] focus-visible:ring-ring/20 active:translate-y-px disabled:pointer-events-none disabled:opacity-45 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n {\n variants: {\n variant: {\n default:\n 'border border-primary bg-primary text-primary-foreground shadow-xs hover:brightness-90',\n brand:\n 'border border-primary bg-primary text-primary-foreground shadow-xs hover:brightness-90',\n soft: 'border border-brand/15 bg-brand-soft text-brand-soft-foreground hover:bg-brand/15',\n secondary:\n 'border border-border bg-secondary text-secondary-foreground shadow-xs hover:border-border-strong hover:bg-muted',\n outline:\n 'border border-border-strong bg-surface text-foreground shadow-xs hover:border-brand/35 hover:bg-accent/60 hover:text-accent-foreground',\n ghost: 'border border-transparent text-foreground hover:bg-muted',\n destructive:\n 'border border-destructive bg-destructive text-destructive-foreground shadow-xs hover:bg-destructive/90',\n link: 'h-auto rounded-none border-0 p-0 text-brand shadow-none hover:text-brand-hover hover:underline hover:underline-offset-4 active:translate-y-0',\n },\n size: {\n xs: 'h-7 gap-1.5 rounded-sm px-2.5 text-xs [&_svg:not([class*=size-])]:size-3.5',\n sm: 'h-8 px-3 text-[13px]',\n default: 'h-9 px-3.5',\n lg: 'h-10 rounded-lg px-4 text-[15px]',\n icon: 'size-9 px-0',\n 'icon-sm': 'size-8 px-0',\n 'icon-lg': 'size-10 rounded-lg px-0',\n },\n },\n defaultVariants: { variant: 'default', size: 'default' },\n },\n);\n\nexport interface ButtonProps\n extends React.ComponentProps<'button'>, VariantProps<typeof buttonVariants> {\n asChild?: boolean;\n loading?: boolean;\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(function Button(\n {\n className,\n variant,\n size,\n asChild = false,\n loading = false,\n disabled,\n children,\n type,\n onClickCapture,\n onKeyDownCapture,\n ...props\n }: ButtonProps,\n ref,\n) {\n const Comp = asChild ? Slot.Root : 'button';\n\n return (\n <Comp\n ref={ref}\n type={asChild ? undefined : (type ?? 'button')}\n data-slot=\"button\"\n data-loading={loading ? '' : undefined}\n aria-busy={loading || undefined}\n disabled={!asChild ? disabled || loading : undefined}\n className={cn(buttonVariants({ variant, size }), className)}\n {...props}\n aria-disabled={asChild && (disabled || loading) ? true : props['aria-disabled']}\n tabIndex={asChild && (disabled || loading) ? -1 : props.tabIndex}\n onClickCapture={(event) => {\n if (disabled || loading) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n onClickCapture?.(event);\n }}\n onKeyDownCapture={(event) => {\n if ((disabled || loading) && (event.key === 'Enter' || event.key === ' ')) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n onKeyDownCapture?.(event);\n }}\n >\n {asChild ? (\n // Slot needs exactly one child to merge onto, so no spinner here.\n children\n ) : (\n <>\n {loading ? (\n <span\n aria-hidden=\"true\"\n className=\"size-3.5 animate-spin rounded-full border-2 border-current border-r-transparent opacity-70\"\n />\n ) : null}\n {children}\n </>\n )}\n </Comp>\n );\n});\n\nexport { Button, buttonVariants };\n"],"mappings":";;;;;;;AAMA,IAAM,iBAAiB,IACrB,2gBACA;CACE,UAAU;EACR,SAAS;GACP,SACE;GACF,OACE;GACF,MAAM;GACN,WACE;GACF,SACE;GACF,OAAO;GACP,aACE;GACF,MAAM;EACR;EACA,MAAM;GACJ,IAAI;GACJ,IAAI;GACJ,SAAS;GACT,IAAI;GACJ,MAAM;GACN,WAAW;GACX,WAAW;EACb;CACF;CACA,iBAAiB;EAAE,SAAS;EAAW,MAAM;CAAU;AACzD,CACF;AAQA,IAAM,SAAS,MAAM,WAA2C,SAAS,OACvE,EACE,WACA,SACA,MACA,UAAU,OACV,UAAU,OACV,UACA,UACA,MACA,gBACA,kBACA,GAAG,SAEL,KACA;CAGA,OACE,oBAHW,UAAUA,OAAY,UAGjC;EACO;EACL,MAAM,UAAU,KAAA,IAAa,QAAQ;EACrC,aAAU;EACV,gBAAc,UAAU,KAAK,KAAA;EAC7B,aAAW,WAAW,KAAA;EACtB,UAAU,CAAC,UAAU,YAAY,UAAU,KAAA;EAC3C,WAAW,GAAG,eAAe;GAAE;GAAS;EAAK,CAAC,GAAG,SAAS;EAC1D,GAAI;EACJ,iBAAe,YAAY,YAAY,WAAW,OAAO,MAAM;EAC/D,UAAU,YAAY,YAAY,WAAW,KAAK,MAAM;EACxD,iBAAiB,UAAU;GACzB,IAAI,YAAY,SAAS;IACvB,MAAM,eAAe;IACrB,MAAM,gBAAgB;IACtB;GACF;GACA,iBAAiB,KAAK;EACxB;EACA,mBAAmB,UAAU;GAC3B,KAAK,YAAY,aAAa,MAAM,QAAQ,WAAW,MAAM,QAAQ,MAAM;IACzE,MAAM,eAAe;IACrB,MAAM,gBAAgB;IACtB;GACF;GACA,mBAAmB,KAAK;EAC1B;EAEC,UAAA,UAEC,WAEA,qBAAAC,UAAA,EAAA,UAAA,CACG,UACC,oBAAC,QAAD;GACE,eAAY;GACZ,WAAU;EACX,CAAA,IACC,MACH,QACD,EAAA,CAAA;CAEA,CAAA;AAEV,CAAC"}
1
+ {"version":3,"file":"button.js","names":["Slot.Root","_Fragment"],"sources":["../../src/components/button.tsx"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\nimport * as React from 'react';\n\nimport { cn, focusRingClasses } from '../lib/utils';\nimport * as Slot from '../primitives/vendor/radix/react-slot';\n\nconst buttonVariants = cva(\n `inline-flex shrink-0 items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-semibold tracking-[-0.01em] transition-[background-color,border-color,color,box-shadow,transform,filter] select-none ${focusRingClasses} pointer-coarse:min-h-11 pointer-coarse:min-w-11 active:translate-y-px disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4`,\n {\n variants: {\n variant: {\n default:\n 'border border-primary bg-primary text-primary-foreground shadow-xs hover:brightness-90',\n brand:\n 'border border-primary bg-primary text-primary-foreground shadow-xs hover:brightness-90',\n soft: 'border border-brand/15 bg-brand-soft text-brand-soft-foreground hover:bg-brand/15',\n secondary:\n 'border border-border bg-secondary text-secondary-foreground shadow-xs hover:border-border-strong hover:bg-muted',\n outline:\n 'border border-border-strong bg-surface text-foreground shadow-xs hover:border-brand/35 hover:bg-accent/60 hover:text-accent-foreground',\n ghost: 'border border-transparent text-foreground hover:bg-muted',\n destructive:\n 'border border-destructive bg-destructive text-destructive-foreground shadow-xs hover:bg-destructive/90',\n link: 'h-auto rounded-none border-0 p-0 text-brand shadow-none hover:text-brand-hover hover:underline hover:underline-offset-4 active:translate-y-0 pointer-coarse:min-h-0 pointer-coarse:min-w-0',\n },\n size: {\n xs: 'h-7 gap-1.5 rounded-sm px-2.5 text-xs [&_svg:not([class*=size-])]:size-3.5',\n sm: 'h-8 px-3 text-[13px]',\n default: 'h-9 px-3.5',\n lg: 'h-10 rounded-lg px-4 text-[15px]',\n icon: 'size-9 px-0',\n 'icon-sm': 'size-8 px-0',\n 'icon-lg': 'size-10 rounded-lg px-0',\n },\n },\n defaultVariants: { variant: 'default', size: 'default' },\n },\n);\n\nexport interface ButtonProps\n extends React.ComponentProps<'button'>, VariantProps<typeof buttonVariants> {\n asChild?: boolean;\n loading?: boolean;\n}\n\n/**\n * The action primitive. On touch screens every button is at least 44px\n * (`pointer-coarse:min-h-8` opts a button in a dense header out); link-styled\n * buttons stay inline. `data-variant` and `data-size` are set for CSS that\n * needs them. A trigger's `asChild` replaces `data-slot` with its own\n * (`dialog-trigger`), which is why the sizing lives in the classes.\n */\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(function Button(\n {\n className,\n variant,\n size,\n asChild = false,\n loading = false,\n disabled,\n children,\n type,\n onClickCapture,\n onKeyDownCapture,\n ...props\n }: ButtonProps,\n ref,\n) {\n const Comp = asChild ? Slot.Root : 'button';\n\n return (\n <Comp\n ref={ref}\n type={asChild ? undefined : (type ?? 'button')}\n data-slot=\"button\"\n data-variant={variant ?? 'default'}\n data-size={size ?? 'default'}\n data-loading={loading ? '' : undefined}\n aria-busy={loading || undefined}\n disabled={!asChild ? disabled || loading : undefined}\n className={cn(buttonVariants({ variant, size }), className)}\n {...props}\n aria-disabled={asChild && (disabled || loading) ? true : props['aria-disabled']}\n tabIndex={asChild && (disabled || loading) ? -1 : props.tabIndex}\n onClickCapture={(event) => {\n if (disabled || loading) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n onClickCapture?.(event);\n }}\n onKeyDownCapture={(event) => {\n if ((disabled || loading) && (event.key === 'Enter' || event.key === ' ')) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n onKeyDownCapture?.(event);\n }}\n >\n {asChild ? (\n // Slot needs exactly one child to merge onto, so no spinner here.\n children\n ) : (\n <>\n {loading ? (\n <span\n aria-hidden=\"true\"\n className=\"size-3.5 animate-spin rounded-full border-2 border-current border-r-transparent opacity-70\"\n />\n ) : null}\n {children}\n </>\n )}\n </Comp>\n );\n});\n\nexport { Button, buttonVariants };\n"],"mappings":";;;;;;;AAMA,IAAM,iBAAiB,IACrB,yNAAyN,iBAAiB,4MAC1O;CACE,UAAU;EACR,SAAS;GACP,SACE;GACF,OACE;GACF,MAAM;GACN,WACE;GACF,SACE;GACF,OAAO;GACP,aACE;GACF,MAAM;EACR;EACA,MAAM;GACJ,IAAI;GACJ,IAAI;GACJ,SAAS;GACT,IAAI;GACJ,MAAM;GACN,WAAW;GACX,WAAW;EACb;CACF;CACA,iBAAiB;EAAE,SAAS;EAAW,MAAM;CAAU;AACzD,CACF;;;;;;;;AAeA,IAAM,SAAS,MAAM,WAA2C,SAAS,OACvE,EACE,WACA,SACA,MACA,UAAU,OACV,UAAU,OACV,UACA,UACA,MACA,gBACA,kBACA,GAAG,SAEL,KACA;CAGA,OACE,oBAHW,UAAUA,OAAY,UAGjC;EACO;EACL,MAAM,UAAU,KAAA,IAAa,QAAQ;EACrC,aAAU;EACV,gBAAc,WAAW;EACzB,aAAW,QAAQ;EACnB,gBAAc,UAAU,KAAK,KAAA;EAC7B,aAAW,WAAW,KAAA;EACtB,UAAU,CAAC,UAAU,YAAY,UAAU,KAAA;EAC3C,WAAW,GAAG,eAAe;GAAE;GAAS;EAAK,CAAC,GAAG,SAAS;EAC1D,GAAI;EACJ,iBAAe,YAAY,YAAY,WAAW,OAAO,MAAM;EAC/D,UAAU,YAAY,YAAY,WAAW,KAAK,MAAM;EACxD,iBAAiB,UAAU;GACzB,IAAI,YAAY,SAAS;IACvB,MAAM,eAAe;IACrB,MAAM,gBAAgB;IACtB;GACF;GACA,iBAAiB,KAAK;EACxB;EACA,mBAAmB,UAAU;GAC3B,KAAK,YAAY,aAAa,MAAM,QAAQ,WAAW,MAAM,QAAQ,MAAM;IACzE,MAAM,eAAe;IACrB,MAAM,gBAAgB;IACtB;GACF;GACA,mBAAmB,KAAK;EAC1B;EAEC,UAAA,UAEC,WAEA,qBAAAC,UAAA,EAAA,UAAA,CACG,UACC,oBAAC,QAAD;GACE,eAAY;GACZ,WAAU;EACX,CAAA,IACC,MACH,QACD,EAAA,CAAA;CAEA,CAAA;AAEV,CAAC"}
@@ -6,12 +6,12 @@ declare const cardVariants: (props?: ({
6
6
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
7
  export interface CardProps extends React.ComponentProps<'div'>, VariantProps<typeof cardVariants> {
8
8
  }
9
- declare function Card({ className, variant, density, ...props }: CardProps): React.JSX.Element;
10
- declare function CardHeader({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
11
- declare function CardEyebrow({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
12
- declare function CardTitle({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
13
- declare function CardDescription({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
14
- declare function CardAction({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
15
- declare function CardContent({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
16
- declare function CardFooter({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
9
+ declare const Card: React.ForwardRefExoticComponent<Omit<CardProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
10
+ declare const CardHeader: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
11
+ declare const CardEyebrow: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
12
+ declare const CardTitle: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
13
+ declare const CardDescription: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
14
+ declare const CardAction: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
15
+ declare const CardContent: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
16
+ declare const CardFooter: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
17
17
  export { Card, CardAction, CardContent, CardDescription, CardEyebrow, CardFooter, CardHeader, CardTitle, cardVariants, };
@@ -1,22 +1,22 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/utils.js";
3
- import "react";
3
+ import * as React from "react";
4
4
  import { jsx } from "react/jsx-runtime";
5
5
  import { cva } from "class-variance-authority";
6
6
  //#region src/components/card.tsx
7
- var cardVariants = cva("group/card relative flex flex-col overflow-hidden rounded-lg border text-card-foreground transition-[border-color,background-color,box-shadow,transform] duration-150", {
7
+ var cardVariants = cva("group/card relative flex flex-col overflow-hidden rounded-lg border text-card-foreground transition-[border-color,background-color,box-shadow,transform]", {
8
8
  variants: {
9
9
  variant: {
10
10
  default: "border-border bg-card shadow-xs",
11
11
  raised: "border-border bg-surface-raised shadow-md",
12
12
  subtle: "border-border/70 bg-surface-muted shadow-none",
13
13
  interactive: "border-border bg-card shadow-xs hover:-translate-y-0.5 hover:border-brand/30 hover:shadow-md",
14
- terminal: "border-border-strong bg-code text-code-foreground shadow-md"
14
+ terminal: "border-border-strong bg-code text-code-foreground shadow-md [--foreground:var(--code-foreground)] [--muted-foreground:color-mix(in_srgb,var(--code-foreground)_72%,var(--code))] [--muted:color-mix(in_srgb,var(--code-foreground)_10%,var(--code))] [--border:color-mix(in_srgb,var(--code-foreground)_16%,var(--code))]"
15
15
  },
16
16
  density: {
17
- compact: "[&_[data-slot=card-header]]:p-4 [&_[data-slot=card-content]]:px-4 [&_[data-slot=card-footer]]:p-4",
18
- default: "[&_[data-slot=card-header]]:p-5 [&_[data-slot=card-content]]:px-5 [&_[data-slot=card-footer]]:p-5",
19
- roomy: "[&_[data-slot=card-header]]:p-6 [&_[data-slot=card-content]]:px-6 [&_[data-slot=card-footer]]:p-6"
17
+ compact: "[&_[data-slot=card-header]]:p-4 [&_[data-slot=card-content]]:px-4 [&_[data-slot=card-content]]:pb-4 [&_[data-slot=card-footer]]:p-4",
18
+ default: "[&_[data-slot=card-header]]:p-5 [&_[data-slot=card-content]]:px-5 [&_[data-slot=card-content]]:pb-5 [&_[data-slot=card-footer]]:p-5",
19
+ roomy: "[&_[data-slot=card-header]]:p-6 [&_[data-slot=card-content]]:px-6 [&_[data-slot=card-content]]:pb-6 [&_[data-slot=card-footer]]:p-6"
20
20
  }
21
21
  },
22
22
  defaultVariants: {
@@ -24,65 +24,74 @@ var cardVariants = cva("group/card relative flex flex-col overflow-hidden rounde
24
24
  density: "default"
25
25
  }
26
26
  });
27
- function Card({ className, variant, density, ...props }) {
27
+ var Card = React.forwardRef(function Card({ className, variant, density, ...props }, ref) {
28
28
  return /* @__PURE__ */ jsx("div", {
29
+ ref,
29
30
  "data-slot": "card",
31
+ "data-variant": variant ?? "default",
30
32
  className: cn(cardVariants({
31
33
  variant,
32
34
  density
33
35
  }), className),
34
36
  ...props
35
37
  });
36
- }
37
- function CardHeader({ className, ...props }) {
38
+ });
39
+ var CardHeader = React.forwardRef(function CardHeader({ className, ...props }, ref) {
38
40
  return /* @__PURE__ */ jsx("div", {
41
+ ref,
39
42
  "data-slot": "card-header",
40
- className: cn("grid grid-cols-[1fr_auto] items-start gap-x-4 gap-y-1 border-b border-transparent pb-3", className),
43
+ className: cn("grid grid-cols-[1fr_auto] items-start gap-x-4 gap-y-1", className),
41
44
  ...props
42
45
  });
43
- }
44
- function CardEyebrow({ className, ...props }) {
46
+ });
47
+ var CardEyebrow = React.forwardRef(function CardEyebrow({ className, ...props }, ref) {
45
48
  return /* @__PURE__ */ jsx("div", {
49
+ ref,
46
50
  "data-slot": "card-eyebrow",
47
51
  className: cn("col-span-full mb-0.5 text-[11px] font-semibold tracking-[0.12em] text-muted-foreground uppercase", className),
48
52
  ...props
49
53
  });
50
- }
51
- function CardTitle({ className, ...props }) {
54
+ });
55
+ var CardTitle = React.forwardRef(function CardTitle({ className, ...props }, ref) {
52
56
  return /* @__PURE__ */ jsx("div", {
57
+ ref,
53
58
  "data-slot": "card-title",
54
59
  className: cn("min-w-0 text-sm font-semibold tracking-[-0.015em]", className),
55
60
  ...props
56
61
  });
57
- }
58
- function CardDescription({ className, ...props }) {
62
+ });
63
+ var CardDescription = React.forwardRef(function CardDescription({ className, ...props }, ref) {
59
64
  return /* @__PURE__ */ jsx("div", {
65
+ ref,
60
66
  "data-slot": "card-description",
61
67
  className: cn("col-start-1 text-sm leading-5 text-muted-foreground", className),
62
68
  ...props
63
69
  });
64
- }
65
- function CardAction({ className, ...props }) {
70
+ });
71
+ var CardAction = React.forwardRef(function CardAction({ className, ...props }, ref) {
66
72
  return /* @__PURE__ */ jsx("div", {
73
+ ref,
67
74
  "data-slot": "card-action",
68
75
  className: cn("col-start-2 row-span-2 row-start-1 self-start", className),
69
76
  ...props
70
77
  });
71
- }
72
- function CardContent({ className, ...props }) {
78
+ });
79
+ var CardContent = React.forwardRef(function CardContent({ className, ...props }, ref) {
73
80
  return /* @__PURE__ */ jsx("div", {
81
+ ref,
74
82
  "data-slot": "card-content",
75
83
  className: cn("pb-5", className),
76
84
  ...props
77
85
  });
78
- }
79
- function CardFooter({ className, ...props }) {
86
+ });
87
+ var CardFooter = React.forwardRef(function CardFooter({ className, ...props }, ref) {
80
88
  return /* @__PURE__ */ jsx("div", {
89
+ ref,
81
90
  "data-slot": "card-footer",
82
91
  className: cn("mt-auto flex items-center gap-2 border-t pt-4", className),
83
92
  ...props
84
93
  });
85
- }
94
+ });
86
95
  //#endregion
87
96
  export { Card, CardAction, CardContent, CardDescription, CardEyebrow, CardFooter, CardHeader, CardTitle, cardVariants };
88
97
 
@@ -1 +1 @@
1
- {"version":3,"file":"card.js","names":[],"sources":["../../src/components/card.tsx"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nconst cardVariants = cva(\n 'group/card relative flex flex-col overflow-hidden rounded-lg border text-card-foreground transition-[border-color,background-color,box-shadow,transform] duration-150',\n {\n variants: {\n variant: {\n default: 'border-border bg-card shadow-xs',\n raised: 'border-border bg-surface-raised shadow-md',\n subtle: 'border-border/70 bg-surface-muted shadow-none',\n interactive:\n 'border-border bg-card shadow-xs hover:-translate-y-0.5 hover:border-brand/30 hover:shadow-md',\n terminal: 'border-border-strong bg-code text-code-foreground shadow-md',\n },\n density: {\n compact:\n '[&_[data-slot=card-header]]:p-4 [&_[data-slot=card-content]]:px-4 [&_[data-slot=card-footer]]:p-4',\n default:\n '[&_[data-slot=card-header]]:p-5 [&_[data-slot=card-content]]:px-5 [&_[data-slot=card-footer]]:p-5',\n roomy:\n '[&_[data-slot=card-header]]:p-6 [&_[data-slot=card-content]]:px-6 [&_[data-slot=card-footer]]:p-6',\n },\n },\n defaultVariants: { variant: 'default', density: 'default' },\n },\n);\n\nexport interface CardProps extends React.ComponentProps<'div'>, VariantProps<typeof cardVariants> {}\n\nfunction Card({ className, variant, density, ...props }: CardProps) {\n return (\n <div\n data-slot=\"card\"\n className={cn(cardVariants({ variant, density }), className)}\n {...props}\n />\n );\n}\n\nfunction CardHeader({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"card-header\"\n className={cn(\n 'grid grid-cols-[1fr_auto] items-start gap-x-4 gap-y-1 border-b border-transparent pb-3',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction CardEyebrow({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"card-eyebrow\"\n className={cn(\n 'col-span-full mb-0.5 text-[11px] font-semibold tracking-[0.12em] text-muted-foreground uppercase',\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction CardTitle({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"card-title\"\n className={cn('min-w-0 text-sm font-semibold tracking-[-0.015em]', className)}\n {...props}\n />\n );\n}\n\nfunction CardDescription({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"card-description\"\n className={cn('col-start-1 text-sm leading-5 text-muted-foreground', className)}\n {...props}\n />\n );\n}\n\nfunction CardAction({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"card-action\"\n className={cn('col-start-2 row-span-2 row-start-1 self-start', className)}\n {...props}\n />\n );\n}\n\nfunction CardContent({ className, ...props }: React.ComponentProps<'div'>) {\n return <div data-slot=\"card-content\" className={cn('pb-5', className)} {...props} />;\n}\n\nfunction CardFooter({ className, ...props }: React.ComponentProps<'div'>) {\n return (\n <div\n data-slot=\"card-footer\"\n className={cn('mt-auto flex items-center gap-2 border-t pt-4', className)}\n {...props}\n />\n );\n}\n\nexport {\n Card,\n CardAction,\n CardContent,\n CardDescription,\n CardEyebrow,\n CardFooter,\n CardHeader,\n CardTitle,\n cardVariants,\n};\n"],"mappings":";;;;;;AAKA,IAAM,eAAe,IACnB,yKACA;CACE,UAAU;EACR,SAAS;GACP,SAAS;GACT,QAAQ;GACR,QAAQ;GACR,aACE;GACF,UAAU;EACZ;EACA,SAAS;GACP,SACE;GACF,SACE;GACF,OACE;EACJ;CACF;CACA,iBAAiB;EAAE,SAAS;EAAW,SAAS;CAAU;AAC5D,CACF;AAIA,SAAS,KAAK,EAAE,WAAW,SAAS,SAAS,GAAG,SAAoB;CAClE,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,aAAa;GAAE;GAAS;EAAQ,CAAC,GAAG,SAAS;EAC3D,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,WAAW,EAAE,WAAW,GAAG,SAAsC;CACxE,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,0FACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,YAAY,EAAE,WAAW,GAAG,SAAsC;CACzE,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GACT,oGACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,UAAU,EAAE,WAAW,GAAG,SAAsC;CACvE,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,qDAAqD,SAAS;EAC5E,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,gBAAgB,EAAE,WAAW,GAAG,SAAsC;CAC7E,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,uDAAuD,SAAS;EAC9E,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,WAAW,EAAE,WAAW,GAAG,SAAsC;CACxE,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,iDAAiD,SAAS;EACxE,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,YAAY,EAAE,WAAW,GAAG,SAAsC;CACzE,OAAO,oBAAC,OAAD;EAAK,aAAU;EAAe,WAAW,GAAG,QAAQ,SAAS;EAAG,GAAI;CAAQ,CAAA;AACrF;AAEA,SAAS,WAAW,EAAE,WAAW,GAAG,SAAsC;CACxE,OACE,oBAAC,OAAD;EACE,aAAU;EACV,WAAW,GAAG,iDAAiD,SAAS;EACxE,GAAI;CACL,CAAA;AAEL"}
1
+ {"version":3,"file":"card.js","names":[],"sources":["../../src/components/card.tsx"],"sourcesContent":["import { cva, type VariantProps } from 'class-variance-authority';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nconst cardVariants = cva(\n 'group/card relative flex flex-col overflow-hidden rounded-lg border text-card-foreground transition-[border-color,background-color,box-shadow,transform]',\n {\n variants: {\n variant: {\n default: 'border-border bg-card shadow-xs',\n raised: 'border-border bg-surface-raised shadow-md',\n subtle: 'border-border/70 bg-surface-muted shadow-none',\n interactive:\n 'border-border bg-card shadow-xs hover:-translate-y-0.5 hover:border-brand/30 hover:shadow-md',\n // A dark panel in either theme. It re-points the text and rule tokens\n // at the code palette, so muted text, ghost buttons and dividers inside\n // it stay legible instead of using the page's colours.\n terminal:\n 'border-border-strong bg-code text-code-foreground shadow-md [--foreground:var(--code-foreground)] [--muted-foreground:color-mix(in_srgb,var(--code-foreground)_72%,var(--code))] [--muted:color-mix(in_srgb,var(--code-foreground)_10%,var(--code))] [--border:color-mix(in_srgb,var(--code-foreground)_16%,var(--code))]',\n },\n density: {\n compact:\n '[&_[data-slot=card-header]]:p-4 [&_[data-slot=card-content]]:px-4 [&_[data-slot=card-content]]:pb-4 [&_[data-slot=card-footer]]:p-4',\n default:\n '[&_[data-slot=card-header]]:p-5 [&_[data-slot=card-content]]:px-5 [&_[data-slot=card-content]]:pb-5 [&_[data-slot=card-footer]]:p-5',\n roomy:\n '[&_[data-slot=card-header]]:p-6 [&_[data-slot=card-content]]:px-6 [&_[data-slot=card-content]]:pb-6 [&_[data-slot=card-footer]]:p-6',\n },\n },\n defaultVariants: { variant: 'default', density: 'default' },\n },\n);\n\nexport interface CardProps extends React.ComponentProps<'div'>, VariantProps<typeof cardVariants> {}\n\nconst Card = React.forwardRef<HTMLDivElement, CardProps>(function Card(\n { className, variant, density, ...props },\n ref,\n) {\n return (\n <div\n ref={ref}\n data-slot=\"card\"\n data-variant={variant ?? 'default'}\n className={cn(cardVariants({ variant, density }), className)}\n {...props}\n />\n );\n});\n\nconst CardHeader = React.forwardRef<HTMLDivElement, React.ComponentProps<'div'>>(\n function CardHeader({ className, ...props }, ref) {\n return (\n <div\n ref={ref}\n data-slot=\"card-header\"\n className={cn('grid grid-cols-[1fr_auto] items-start gap-x-4 gap-y-1', className)}\n {...props}\n />\n );\n },\n);\n\nconst CardEyebrow = React.forwardRef<HTMLDivElement, React.ComponentProps<'div'>>(\n function CardEyebrow({ className, ...props }, ref) {\n return (\n <div\n ref={ref}\n data-slot=\"card-eyebrow\"\n className={cn(\n 'col-span-full mb-0.5 text-[11px] font-semibold tracking-[0.12em] text-muted-foreground uppercase',\n className,\n )}\n {...props}\n />\n );\n },\n);\n\nconst CardTitle = React.forwardRef<HTMLDivElement, React.ComponentProps<'div'>>(function CardTitle(\n { className, ...props },\n ref,\n) {\n return (\n <div\n ref={ref}\n data-slot=\"card-title\"\n className={cn('min-w-0 text-sm font-semibold tracking-[-0.015em]', className)}\n {...props}\n />\n );\n});\n\nconst CardDescription = React.forwardRef<HTMLDivElement, React.ComponentProps<'div'>>(\n function CardDescription({ className, ...props }, ref) {\n return (\n <div\n ref={ref}\n data-slot=\"card-description\"\n className={cn('col-start-1 text-sm leading-5 text-muted-foreground', className)}\n {...props}\n />\n );\n },\n);\n\nconst CardAction = React.forwardRef<HTMLDivElement, React.ComponentProps<'div'>>(\n function CardAction({ className, ...props }, ref) {\n return (\n <div\n ref={ref}\n data-slot=\"card-action\"\n className={cn('col-start-2 row-span-2 row-start-1 self-start', className)}\n {...props}\n />\n );\n },\n);\n\nconst CardContent = React.forwardRef<HTMLDivElement, React.ComponentProps<'div'>>(\n function CardContent({ className, ...props }, ref) {\n return <div ref={ref} data-slot=\"card-content\" className={cn('pb-5', className)} {...props} />;\n },\n);\n\nconst CardFooter = React.forwardRef<HTMLDivElement, React.ComponentProps<'div'>>(\n function CardFooter({ className, ...props }, ref) {\n return (\n <div\n ref={ref}\n data-slot=\"card-footer\"\n className={cn('mt-auto flex items-center gap-2 border-t pt-4', className)}\n {...props}\n />\n );\n },\n);\n\nexport {\n Card,\n CardAction,\n CardContent,\n CardDescription,\n CardEyebrow,\n CardFooter,\n CardHeader,\n CardTitle,\n cardVariants,\n};\n"],"mappings":";;;;;;AAKA,IAAM,eAAe,IACnB,4JACA;CACE,UAAU;EACR,SAAS;GACP,SAAS;GACT,QAAQ;GACR,QAAQ;GACR,aACE;GAIF,UACE;EACJ;EACA,SAAS;GACP,SACE;GACF,SACE;GACF,OACE;EACJ;CACF;CACA,iBAAiB;EAAE,SAAS;EAAW,SAAS;CAAU;AAC5D,CACF;AAIA,IAAM,OAAO,MAAM,WAAsC,SAAS,KAChE,EAAE,WAAW,SAAS,SAAS,GAAG,SAClC,KACA;CACA,OACE,oBAAC,OAAD;EACO;EACL,aAAU;EACV,gBAAc,WAAW;EACzB,WAAW,GAAG,aAAa;GAAE;GAAS;EAAQ,CAAC,GAAG,SAAS;EAC3D,GAAI;CACL,CAAA;AAEL,CAAC;AAED,IAAM,aAAa,MAAM,WACvB,SAAS,WAAW,EAAE,WAAW,GAAG,SAAS,KAAK;CAChD,OACE,oBAAC,OAAD;EACO;EACL,aAAU;EACV,WAAW,GAAG,yDAAyD,SAAS;EAChF,GAAI;CACL,CAAA;AAEL,CACF;AAEA,IAAM,cAAc,MAAM,WACxB,SAAS,YAAY,EAAE,WAAW,GAAG,SAAS,KAAK;CACjD,OACE,oBAAC,OAAD;EACO;EACL,aAAU;EACV,WAAW,GACT,oGACA,SACF;EACA,GAAI;CACL,CAAA;AAEL,CACF;AAEA,IAAM,YAAY,MAAM,WAAwD,SAAS,UACvF,EAAE,WAAW,GAAG,SAChB,KACA;CACA,OACE,oBAAC,OAAD;EACO;EACL,aAAU;EACV,WAAW,GAAG,qDAAqD,SAAS;EAC5E,GAAI;CACL,CAAA;AAEL,CAAC;AAED,IAAM,kBAAkB,MAAM,WAC5B,SAAS,gBAAgB,EAAE,WAAW,GAAG,SAAS,KAAK;CACrD,OACE,oBAAC,OAAD;EACO;EACL,aAAU;EACV,WAAW,GAAG,uDAAuD,SAAS;EAC9E,GAAI;CACL,CAAA;AAEL,CACF;AAEA,IAAM,aAAa,MAAM,WACvB,SAAS,WAAW,EAAE,WAAW,GAAG,SAAS,KAAK;CAChD,OACE,oBAAC,OAAD;EACO;EACL,aAAU;EACV,WAAW,GAAG,iDAAiD,SAAS;EACxE,GAAI;CACL,CAAA;AAEL,CACF;AAEA,IAAM,cAAc,MAAM,WACxB,SAAS,YAAY,EAAE,WAAW,GAAG,SAAS,KAAK;CACjD,OAAO,oBAAC,OAAD;EAAU;EAAK,aAAU;EAAe,WAAW,GAAG,QAAQ,SAAS;EAAG,GAAI;CAAQ,CAAA;AAC/F,CACF;AAEA,IAAM,aAAa,MAAM,WACvB,SAAS,WAAW,EAAE,WAAW,GAAG,SAAS,KAAK;CAChD,OACE,oBAAC,OAAD;EACO;EACL,aAAU;EACV,WAAW,GAAG,iDAAiD,SAAS;EACxE,GAAI;CACL,CAAA;AAEL,CACF"}
@@ -60,5 +60,5 @@ export interface ChatHistoryProps extends Omit<React.ComponentProps<'div'>, 'onS
60
60
  * rows, Home and End jump, Enter opens; each row has a menu for rename, pin
61
61
  * and delete. The app owns the data; this only reports what the person did.
62
62
  */
63
- declare function ChatHistory({ items, activeId, onSelect, onNewChat, onRename, onDelete, onPinChange, query: controlledQuery, onQueryChange, searchable, loading, error, onRetry, empty, now, renderItems, label, className, ...props }: ChatHistoryProps): React.JSX.Element;
63
+ declare const ChatHistory: React.ForwardRefExoticComponent<Omit<ChatHistoryProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
64
64
  export { ChatHistory };
@@ -1,8 +1,8 @@
1
1
  "use client";
2
- import { cn } from "../lib/utils.js";
2
+ import { cn, focusRingClasses, noOutlineClasses } from "../lib/utils.js";
3
3
  import { Button } from "./button.js";
4
4
  import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger } from "./dropdown-menu.js";
5
- import "./input.js";
5
+ import { fieldFocusClasses } from "./input.js";
6
6
  import * as React from "react";
7
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
8
  import AlertCircle from "@burtson-labs/icons/react/alert-circle";
@@ -62,7 +62,7 @@ function matchesConversation(item, query) {
62
62
  * rows, Home and End jump, Enter opens; each row has a menu for rename, pin
63
63
  * and delete. The app owns the data; this only reports what the person did.
64
64
  */
65
- function ChatHistory({ items, activeId, onSelect, onNewChat, onRename, onDelete, onPinChange, query: controlledQuery, onQueryChange, searchable = true, loading = false, error, onRetry, empty, now, renderItems, label = "Chat history", className, ...props }) {
65
+ var ChatHistory = React.forwardRef(function ChatHistory({ items, activeId, onSelect, onNewChat, onRename, onDelete, onPinChange, query: controlledQuery, onQueryChange, searchable = true, loading = false, error, onRetry, empty, now, renderItems, label = "Chat history", className, ...props }, ref) {
66
66
  const [ownQuery, setOwnQuery] = React.useState("");
67
67
  const query = controlledQuery ?? ownQuery;
68
68
  const setQuery = (q) => {
@@ -102,6 +102,7 @@ function ChatHistory({ items, activeId, onSelect, onNewChat, onRename, onDelete,
102
102
  onKeyDown: onRowKeyDown
103
103
  }, item.id);
104
104
  return /* @__PURE__ */ jsxs("div", {
105
+ ref,
105
106
  "data-slot": "chat-history",
106
107
  "aria-label": label,
107
108
  role: "navigation",
@@ -132,7 +133,7 @@ function ChatHistory({ items, activeId, onSelect, onNewChat, onRename, onDelete,
132
133
  value: query,
133
134
  onChange: (e) => setQuery(e.target.value),
134
135
  placeholder: "Search chats",
135
- className: cn("h-8 w-full rounded-md border border-input bg-surface pr-2 pl-8 text-base placeholder:text-muted-foreground sm:text-sm", "outline-hidden! focus-visible:border-ring focus-visible:inset-ring-1 focus-visible:inset-ring-ring aria-invalid:focus-visible:inset-ring-destructive")
136
+ className: cn("h-8 w-full rounded-md border border-input bg-surface pr-2 pl-8 text-base placeholder:text-muted-foreground sm:text-sm pointer-coarse:h-11", fieldFocusClasses)
136
137
  })
137
138
  ]
138
139
  })]
@@ -194,7 +195,7 @@ function ChatHistory({ items, activeId, onSelect, onNewChat, onRename, onDelete,
194
195
  "aria-label": g.label,
195
196
  className: "mt-2 first:mt-0",
196
197
  children: [/* @__PURE__ */ jsx("h3", {
197
- className: "px-2 pt-2 pb-1 text-[11px] font-semibold tracking-wide text-muted-foreground uppercase",
198
+ className: "px-2 pt-2 pb-1 text-[11px] font-semibold tracking-[0.06em] text-muted-foreground uppercase",
198
199
  children: g.label
199
200
  }), /* @__PURE__ */ jsx("ul", {
200
201
  className: "grid grid-cols-[minmax(0,1fr)] gap-0.5",
@@ -203,7 +204,7 @@ function ChatHistory({ items, activeId, onSelect, onNewChat, onRename, onDelete,
203
204
  }, g.key))
204
205
  })]
205
206
  });
206
- }
207
+ });
207
208
  function HistoryRow({ item, active, renaming, onSelect, onStartRename, onRename, onDelete, onPinChange, onKeyDown }) {
208
209
  const hasMenu = Boolean(onStartRename || onDelete || onPinChange);
209
210
  if (renaming) return /* @__PURE__ */ jsx(RenameRow, {
@@ -218,14 +219,14 @@ function HistoryRow({ item, active, renaming, onSelect, onStartRename, onRename,
218
219
  "aria-current": active ? "page" : void 0,
219
220
  onClick: onSelect,
220
221
  onKeyDown,
221
- className: cn("flex h-8 w-full items-center gap-2 rounded-md px-2 text-left text-sm outline-none transition-colors hover:bg-muted focus-visible:ring-[3px] focus-visible:ring-ring/20 pointer-coarse:h-11", hasMenu && "pr-9", active && "bg-accent font-medium text-accent-foreground hover:bg-accent"),
222
+ className: cn("flex h-8 w-full items-center gap-2 rounded-md px-2 text-left text-sm transition-colors hover:bg-muted pointer-coarse:h-11", focusRingClasses, "focus-visible:outline-offset-[-2px]", hasMenu && "pr-9", active && "bg-accent font-medium text-accent-foreground hover:bg-accent"),
222
223
  children: /* @__PURE__ */ jsx("span", {
223
224
  className: "min-w-0 flex-1 truncate",
224
225
  children: item.title || "Untitled chat"
225
226
  })
226
227
  }), hasMenu && /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
227
228
  "aria-label": `Actions for ${item.title || "chat"}`,
228
- className: cn("absolute top-1/2 right-1 grid size-7 -translate-y-1/2 place-items-center rounded-sm text-muted-foreground opacity-0 outline-none transition-opacity hover:bg-background hover:text-foreground focus-visible:opacity-100 focus-visible:ring-[3px] focus-visible:ring-ring/20 group-hover/row:opacity-100 data-[state=open]:opacity-100 pointer-coarse:size-9 pointer-coarse:opacity-100 [&_svg]:size-4", active && "opacity-100"),
229
+ className: cn("absolute top-1/2 right-1 grid size-7 -translate-y-1/2 place-items-center rounded-sm text-muted-foreground opacity-0 transition-opacity hover:bg-background hover:text-foreground focus-visible:opacity-100 group-hover/row:opacity-100 data-[state=open]:opacity-100 pointer-coarse:size-9 pointer-coarse:opacity-100 [&_svg]:size-4", "outline-none focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring", "relative pointer-coarse:before:absolute pointer-coarse:before:top-1/2 pointer-coarse:before:left-1/2 pointer-coarse:before:size-11 pointer-coarse:before:-translate-1/2 pointer-coarse:before:content-['']", "absolute", active && "opacity-100"),
229
230
  children: /* @__PURE__ */ jsx(MoreHorizontal, { "aria-hidden": true })
230
231
  }), /* @__PURE__ */ jsxs(DropdownMenuContent, {
231
232
  align: "end",
@@ -274,7 +275,7 @@ function RenameRow({ title, onDone }) {
274
275
  onDone(title);
275
276
  }
276
277
  },
277
- className: "h-8 w-full rounded-md border border-ring bg-surface px-2 text-base inset-ring-1 inset-ring-ring outline-hidden! sm:text-sm"
278
+ className: cn("h-8 w-full rounded-md border border-ring bg-surface px-2 text-base inset-ring-1 inset-ring-ring sm:text-sm", noOutlineClasses)
278
279
  })
279
280
  });
280
281
  }
@@ -1 +1 @@
1
- {"version":3,"file":"chat-history.js","names":["_Fragment"],"sources":["../../src/components/chat-history.tsx"],"sourcesContent":["import AlertCircle from '@burtson-labs/icons/react/alert-circle';\nimport Edit from '@burtson-labs/icons/react/edit';\nimport MessageSquarePlus from '@burtson-labs/icons/react/message-square-plus';\nimport MoreHorizontal from '@burtson-labs/icons/react/more-horizontal';\nimport Pin from '@burtson-labs/icons/react/pin';\nimport PinOff from '@burtson-labs/icons/react/pin-off';\nimport Search from '@burtson-labs/icons/react/search';\nimport Trash from '@burtson-labs/icons/react/trash';\nimport * as React from 'react';\n\nimport { cn } from '../lib/utils';\n\nimport { Button } from './button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from './dropdown-menu';\nimport { fieldFocusClasses } from './input';\n\nexport interface ChatHistoryItem {\n id: string;\n title: string;\n /** When the conversation last changed; decides its group. */\n updatedAt: Date | string | number;\n pinned?: boolean;\n /** A line of the latest message, searched along with the title. */\n preview?: string;\n}\n\nexport type ChatHistoryGroupKey = 'pinned' | 'today' | 'yesterday' | 'week' | 'older';\n\nexport interface ChatHistoryGroup {\n key: ChatHistoryGroupKey;\n label: string;\n items: ChatHistoryItem[];\n}\n\nconst LABELS: Record<ChatHistoryGroupKey, string> = {\n pinned: 'Pinned',\n today: 'Today',\n yesterday: 'Yesterday',\n week: 'Previous 7 days',\n older: 'Older',\n};\n\nconst time = (d: ChatHistoryItem['updatedAt']) => new Date(d).getTime();\nconst startOfDay = (d: Date) => new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();\n\n/**\n * Pinned first, then Today, Yesterday, Previous 7 days and Older by the\n * local calendar, newest first in each. Empty groups are left out.\n */\nexport function groupConversations(\n items: ChatHistoryItem[],\n now: Date = new Date(),\n): ChatHistoryGroup[] {\n const today = startOfDay(now);\n const day = 24 * 60 * 60 * 1000;\n const buckets: Record<ChatHistoryGroupKey, ChatHistoryItem[]> = {\n pinned: [],\n today: [],\n yesterday: [],\n week: [],\n older: [],\n };\n for (const item of [...items].sort((a, b) => time(b.updatedAt) - time(a.updatedAt))) {\n if (item.pinned) {\n buckets.pinned.push(item);\n continue;\n }\n const t = startOfDay(new Date(item.updatedAt));\n const key: ChatHistoryGroupKey =\n t >= today\n ? 'today'\n : t >= today - day\n ? 'yesterday'\n : t >= today - 7 * day\n ? 'week'\n : 'older';\n buckets[key].push(item);\n }\n return (Object.keys(buckets) as ChatHistoryGroupKey[])\n .filter((k) => buckets[k].length > 0)\n .map((k) => ({ key: k, label: LABELS[k], items: buckets[k] }));\n}\n\n/** Case-insensitive match on every word, across title and preview. */\nexport function matchesConversation(item: ChatHistoryItem, query: string): boolean {\n const hay = `${item.title} ${item.preview ?? ''}`.toLowerCase();\n return query\n .toLowerCase()\n .split(/\\s+/)\n .filter(Boolean)\n .every((w) => hay.includes(w));\n}\n\nexport interface ChatHistoryProps extends Omit<React.ComponentProps<'div'>, 'onSelect'> {\n items: ChatHistoryItem[];\n activeId?: string;\n onSelect: (id: string) => void;\n /** Shows a \"New chat\" button at the top. */\n onNewChat?: () => void;\n /** Adds Rename to the row menu; the title is edited in place. */\n onRename?: (id: string, title: string) => void;\n /** Adds Delete to the row menu. Confirm or offer undo in your app. */\n onDelete?: (id: string) => void;\n /** Adds Pin / Unpin to the row menu. */\n onPinChange?: (id: string, pinned: boolean) => void;\n /** Controlled search text; leave out to let the list keep its own. */\n query?: string;\n onQueryChange?: (query: string) => void;\n /** Hides the search box, e.g. when the app searches on the server. */\n searchable?: boolean;\n loading?: boolean;\n /** Why the list could not load. Shown with Retry when `onRetry` is set. */\n error?: React.ReactNode;\n onRetry?: () => void;\n /** Shown when there are no conversations at all. */\n empty?: React.ReactNode;\n /** The clock grouping uses; pass it in tests. */\n now?: Date;\n /**\n * Virtualisation hook for long histories: receives a group's items and the\n * row renderer, returns what to render (e.g. a windowed list). Default\n * renders every row.\n */\n renderItems?: (\n items: ChatHistoryItem[],\n renderItem: (item: ChatHistoryItem) => React.ReactNode,\n ) => React.ReactNode;\n label?: string;\n}\n\n/**\n * The conversation list beside a chat: a New chat action, search, and the\n * history grouped by day with pinned chats on top. Up and Down move between\n * rows, Home and End jump, Enter opens; each row has a menu for rename, pin\n * and delete. The app owns the data; this only reports what the person did.\n */\nfunction ChatHistory({\n items,\n activeId,\n onSelect,\n onNewChat,\n onRename,\n onDelete,\n onPinChange,\n query: controlledQuery,\n onQueryChange,\n searchable = true,\n loading = false,\n error,\n onRetry,\n empty,\n now,\n renderItems,\n label = 'Chat history',\n className,\n ...props\n}: ChatHistoryProps) {\n const [ownQuery, setOwnQuery] = React.useState('');\n const query = controlledQuery ?? ownQuery;\n const setQuery = (q: string) => {\n if (controlledQuery === undefined) setOwnQuery(q);\n onQueryChange?.(q);\n };\n const [renaming, setRenaming] = React.useState<string | null>(null);\n const list = React.useRef<HTMLDivElement>(null);\n const searchId = React.useId();\n\n const visible = query.trim() ? items.filter((i) => matchesConversation(i, query)) : items;\n const groups = groupConversations(visible, now);\n\n const onRowKeyDown = (e: React.KeyboardEvent) => {\n const rows = Array.from(\n list.current?.querySelectorAll<HTMLElement>('[data-slot=\"chat-history-row\"]') ?? [],\n );\n const i = rows.indexOf(document.activeElement as HTMLElement);\n let next = -1;\n if (e.key === 'ArrowDown') next = Math.min(rows.length - 1, i + 1);\n else if (e.key === 'ArrowUp') next = Math.max(0, i - 1);\n else if (e.key === 'Home') next = 0;\n else if (e.key === 'End') next = rows.length - 1;\n const row = next >= 0 ? rows[next] : undefined;\n if (row) {\n e.preventDefault();\n row.focus();\n }\n };\n\n const renderItem = (item: ChatHistoryItem) => (\n <HistoryRow\n key={item.id}\n item={item}\n active={item.id === activeId}\n renaming={renaming === item.id}\n onSelect={() => onSelect(item.id)}\n onStartRename={onRename ? () => setRenaming(item.id) : undefined}\n onRename={(title) => {\n setRenaming(null);\n if (onRename && title.trim() && title.trim() !== item.title)\n onRename(item.id, title.trim());\n }}\n onDelete={onDelete ? () => onDelete(item.id) : undefined}\n onPinChange={onPinChange ? (p) => onPinChange(item.id, p) : undefined}\n onKeyDown={onRowKeyDown}\n />\n );\n\n return (\n <div\n data-slot=\"chat-history\"\n aria-label={label}\n role=\"navigation\"\n className={cn('flex h-full min-h-0 flex-col', className)}\n {...props}\n >\n {(onNewChat || searchable) && (\n <div className=\"grid gap-2 p-2\">\n {onNewChat && (\n <Button variant=\"outline\" className=\"justify-start\" onClick={onNewChat}>\n <MessageSquarePlus /> New chat\n </Button>\n )}\n {searchable && (\n <label htmlFor={searchId} className=\"relative block\">\n <span className=\"sr-only\">Search chats</span>\n <Search\n aria-hidden\n className=\"pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground\"\n />\n <input\n id={searchId}\n type=\"search\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder=\"Search chats\"\n className={cn(\n 'h-8 w-full rounded-md border border-input bg-surface pr-2 pl-8 text-base placeholder:text-muted-foreground sm:text-sm',\n fieldFocusClasses,\n )}\n />\n </label>\n )}\n </div>\n )}\n <div ref={list} className=\"min-h-0 flex-1 overflow-y-auto px-2 pb-2\">\n {loading ? (\n <div role=\"status\" aria-label=\"Loading chats\" className=\"grid gap-1.5 pt-1\">\n {[72, 56, 64, 48, 60].map((w, i) => (\n <div key={i} className=\"h-8 rounded-md bg-muted/70 motion-safe:animate-pulse\">\n <span className=\"sr-only\">Loading</span>\n <span\n aria-hidden\n className=\"ml-2 inline-block h-2.5 translate-y-3 rounded bg-muted-foreground/15\"\n style={{ width: `${w}%` }}\n />\n </div>\n ))}\n </div>\n ) : error ? (\n <div role=\"alert\" className=\"grid justify-items-start gap-2 p-2 text-sm\">\n <span className=\"inline-flex items-center gap-1.5 font-medium text-destructive [&_svg]:size-4\">\n <AlertCircle aria-hidden /> Chats could not load\n </span>\n <span className=\"text-muted-foreground\">{error}</span>\n {onRetry && (\n <Button size=\"sm\" variant=\"outline\" onClick={onRetry}>\n Try again\n </Button>\n )}\n </div>\n ) : items.length === 0 ? (\n <div className=\"p-3 text-sm text-muted-foreground\">\n {empty ?? 'No chats yet. Start one and it will appear here.'}\n </div>\n ) : groups.length === 0 ? (\n <p role=\"status\" className=\"p-3 text-sm text-muted-foreground\">\n No chats match &ldquo;{query}&rdquo;.\n </p>\n ) : (\n groups.map((g) => (\n <section key={g.key} aria-label={g.label} className=\"mt-2 first:mt-0\">\n <h3 className=\"px-2 pt-2 pb-1 text-[11px] font-semibold tracking-wide text-muted-foreground uppercase\">\n {g.label}\n </h3>\n <ul className=\"grid grid-cols-[minmax(0,1fr)] gap-0.5\">\n {renderItems ? renderItems(g.items, renderItem) : g.items.map(renderItem)}\n </ul>\n </section>\n ))\n )}\n </div>\n </div>\n );\n}\n\nfunction HistoryRow({\n item,\n active,\n renaming,\n onSelect,\n onStartRename,\n onRename,\n onDelete,\n onPinChange,\n onKeyDown,\n}: {\n item: ChatHistoryItem;\n active: boolean;\n renaming: boolean;\n onSelect: () => void;\n onStartRename?: () => void;\n onRename: (title: string) => void;\n onDelete?: () => void;\n onPinChange?: (pinned: boolean) => void;\n onKeyDown: (e: React.KeyboardEvent) => void;\n}) {\n const hasMenu = Boolean(onStartRename || onDelete || onPinChange);\n if (renaming) return <RenameRow title={item.title} onDone={onRename} />;\n return (\n <li className=\"group/row relative min-w-0\">\n <button\n type=\"button\"\n data-slot=\"chat-history-row\"\n aria-current={active ? 'page' : undefined}\n onClick={onSelect}\n onKeyDown={onKeyDown}\n className={cn(\n 'flex h-8 w-full items-center gap-2 rounded-md px-2 text-left text-sm outline-none transition-colors hover:bg-muted focus-visible:ring-[3px] focus-visible:ring-ring/20 pointer-coarse:h-11',\n hasMenu && 'pr-9',\n active && 'bg-accent font-medium text-accent-foreground hover:bg-accent',\n )}\n >\n <span className=\"min-w-0 flex-1 truncate\">{item.title || 'Untitled chat'}</span>\n </button>\n {hasMenu && (\n <DropdownMenu>\n <DropdownMenuTrigger\n aria-label={`Actions for ${item.title || 'chat'}`}\n className={cn(\n 'absolute top-1/2 right-1 grid size-7 -translate-y-1/2 place-items-center rounded-sm text-muted-foreground opacity-0 outline-none transition-opacity hover:bg-background hover:text-foreground focus-visible:opacity-100 focus-visible:ring-[3px] focus-visible:ring-ring/20 group-hover/row:opacity-100 data-[state=open]:opacity-100 pointer-coarse:size-9 pointer-coarse:opacity-100 [&_svg]:size-4',\n active && 'opacity-100',\n )}\n >\n <MoreHorizontal aria-hidden />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-40\">\n {onStartRename && (\n <DropdownMenuItem onSelect={onStartRename}>\n <Edit aria-hidden /> Rename\n </DropdownMenuItem>\n )}\n {onPinChange && (\n <DropdownMenuItem onSelect={() => onPinChange(!item.pinned)}>\n {item.pinned ? <PinOff aria-hidden /> : <Pin aria-hidden />}\n {item.pinned ? 'Unpin' : 'Pin'}\n </DropdownMenuItem>\n )}\n {onDelete && (\n <>\n {(onStartRename || onPinChange) && <DropdownMenuSeparator />}\n <DropdownMenuItem variant=\"destructive\" onSelect={onDelete}>\n <Trash aria-hidden /> Delete\n </DropdownMenuItem>\n </>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n </li>\n );\n}\n\n/** Rename in place: Enter or leaving the field saves, Escape keeps the old title. */\nfunction RenameRow({ title, onDone }: { title: string; onDone: (title: string) => void }) {\n const [draft, setDraft] = React.useState(title);\n const input = React.useRef<HTMLInputElement>(null);\n React.useEffect(() => {\n input.current?.select();\n }, []);\n return (\n <li className=\"px-1 py-0.5\">\n <input\n ref={input}\n aria-label=\"Chat title\"\n value={draft}\n // eslint-disable-next-line jsx-a11y/no-autofocus -- rename was just asked for\n autoFocus\n onChange={(e) => setDraft(e.target.value)}\n onBlur={() => onDone(draft)}\n onKeyDown={(e) => {\n if (e.nativeEvent.isComposing || e.nativeEvent.keyCode === 229) return;\n if (e.key === 'Enter') {\n e.preventDefault();\n onDone(draft);\n } else if (e.key === 'Escape') {\n e.preventDefault();\n onDone(title);\n }\n }}\n className=\"h-8 w-full rounded-md border border-ring bg-surface px-2 text-base inset-ring-1 inset-ring-ring outline-hidden! sm:text-sm\"\n />\n </li>\n );\n}\n\nexport { ChatHistory };\n"],"mappings":"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"}
1
+ {"version":3,"file":"chat-history.js","names":["_Fragment"],"sources":["../../src/components/chat-history.tsx"],"sourcesContent":["import AlertCircle from '@burtson-labs/icons/react/alert-circle';\nimport Edit from '@burtson-labs/icons/react/edit';\nimport MessageSquarePlus from '@burtson-labs/icons/react/message-square-plus';\nimport MoreHorizontal from '@burtson-labs/icons/react/more-horizontal';\nimport Pin from '@burtson-labs/icons/react/pin';\nimport PinOff from '@burtson-labs/icons/react/pin-off';\nimport Search from '@burtson-labs/icons/react/search';\nimport Trash from '@burtson-labs/icons/react/trash';\nimport * as React from 'react';\n\nimport { cn, focusRingClasses, noOutlineClasses, touchTargetClasses } from '../lib/utils';\n\nimport { Button } from './button';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from './dropdown-menu';\nimport { fieldFocusClasses } from './input';\n\nexport interface ChatHistoryItem {\n id: string;\n title: string;\n /** When the conversation last changed; decides its group. */\n updatedAt: Date | string | number;\n pinned?: boolean;\n /** A line of the latest message, searched along with the title. */\n preview?: string;\n}\n\nexport type ChatHistoryGroupKey = 'pinned' | 'today' | 'yesterday' | 'week' | 'older';\n\nexport interface ChatHistoryGroup {\n key: ChatHistoryGroupKey;\n label: string;\n items: ChatHistoryItem[];\n}\n\nconst LABELS: Record<ChatHistoryGroupKey, string> = {\n pinned: 'Pinned',\n today: 'Today',\n yesterday: 'Yesterday',\n week: 'Previous 7 days',\n older: 'Older',\n};\n\nconst time = (d: ChatHistoryItem['updatedAt']) => new Date(d).getTime();\nconst startOfDay = (d: Date) => new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();\n\n/**\n * Pinned first, then Today, Yesterday, Previous 7 days and Older by the\n * local calendar, newest first in each. Empty groups are left out.\n */\nexport function groupConversations(\n items: ChatHistoryItem[],\n now: Date = new Date(),\n): ChatHistoryGroup[] {\n const today = startOfDay(now);\n const day = 24 * 60 * 60 * 1000;\n const buckets: Record<ChatHistoryGroupKey, ChatHistoryItem[]> = {\n pinned: [],\n today: [],\n yesterday: [],\n week: [],\n older: [],\n };\n for (const item of [...items].sort((a, b) => time(b.updatedAt) - time(a.updatedAt))) {\n if (item.pinned) {\n buckets.pinned.push(item);\n continue;\n }\n const t = startOfDay(new Date(item.updatedAt));\n const key: ChatHistoryGroupKey =\n t >= today\n ? 'today'\n : t >= today - day\n ? 'yesterday'\n : t >= today - 7 * day\n ? 'week'\n : 'older';\n buckets[key].push(item);\n }\n return (Object.keys(buckets) as ChatHistoryGroupKey[])\n .filter((k) => buckets[k].length > 0)\n .map((k) => ({ key: k, label: LABELS[k], items: buckets[k] }));\n}\n\n/** Case-insensitive match on every word, across title and preview. */\nexport function matchesConversation(item: ChatHistoryItem, query: string): boolean {\n const hay = `${item.title} ${item.preview ?? ''}`.toLowerCase();\n return query\n .toLowerCase()\n .split(/\\s+/)\n .filter(Boolean)\n .every((w) => hay.includes(w));\n}\n\nexport interface ChatHistoryProps extends Omit<React.ComponentProps<'div'>, 'onSelect'> {\n items: ChatHistoryItem[];\n activeId?: string;\n onSelect: (id: string) => void;\n /** Shows a \"New chat\" button at the top. */\n onNewChat?: () => void;\n /** Adds Rename to the row menu; the title is edited in place. */\n onRename?: (id: string, title: string) => void;\n /** Adds Delete to the row menu. Confirm or offer undo in your app. */\n onDelete?: (id: string) => void;\n /** Adds Pin / Unpin to the row menu. */\n onPinChange?: (id: string, pinned: boolean) => void;\n /** Controlled search text; leave out to let the list keep its own. */\n query?: string;\n onQueryChange?: (query: string) => void;\n /** Hides the search box, e.g. when the app searches on the server. */\n searchable?: boolean;\n loading?: boolean;\n /** Why the list could not load. Shown with Retry when `onRetry` is set. */\n error?: React.ReactNode;\n onRetry?: () => void;\n /** Shown when there are no conversations at all. */\n empty?: React.ReactNode;\n /** The clock grouping uses; pass it in tests. */\n now?: Date;\n /**\n * Virtualisation hook for long histories: receives a group's items and the\n * row renderer, returns what to render (e.g. a windowed list). Default\n * renders every row.\n */\n renderItems?: (\n items: ChatHistoryItem[],\n renderItem: (item: ChatHistoryItem) => React.ReactNode,\n ) => React.ReactNode;\n label?: string;\n}\n\n/**\n * The conversation list beside a chat: a New chat action, search, and the\n * history grouped by day with pinned chats on top. Up and Down move between\n * rows, Home and End jump, Enter opens; each row has a menu for rename, pin\n * and delete. The app owns the data; this only reports what the person did.\n */\nconst ChatHistory = React.forwardRef<HTMLDivElement, ChatHistoryProps>(function ChatHistory(\n {\n items,\n activeId,\n onSelect,\n onNewChat,\n onRename,\n onDelete,\n onPinChange,\n query: controlledQuery,\n onQueryChange,\n searchable = true,\n loading = false,\n error,\n onRetry,\n empty,\n now,\n renderItems,\n label = 'Chat history',\n className,\n ...props\n },\n ref,\n) {\n const [ownQuery, setOwnQuery] = React.useState('');\n const query = controlledQuery ?? ownQuery;\n const setQuery = (q: string) => {\n if (controlledQuery === undefined) setOwnQuery(q);\n onQueryChange?.(q);\n };\n const [renaming, setRenaming] = React.useState<string | null>(null);\n const list = React.useRef<HTMLDivElement>(null);\n const searchId = React.useId();\n\n const visible = query.trim() ? items.filter((i) => matchesConversation(i, query)) : items;\n const groups = groupConversations(visible, now);\n\n const onRowKeyDown = (e: React.KeyboardEvent) => {\n const rows = Array.from(\n list.current?.querySelectorAll<HTMLElement>('[data-slot=\"chat-history-row\"]') ?? [],\n );\n const i = rows.indexOf(document.activeElement as HTMLElement);\n let next = -1;\n if (e.key === 'ArrowDown') next = Math.min(rows.length - 1, i + 1);\n else if (e.key === 'ArrowUp') next = Math.max(0, i - 1);\n else if (e.key === 'Home') next = 0;\n else if (e.key === 'End') next = rows.length - 1;\n const row = next >= 0 ? rows[next] : undefined;\n if (row) {\n e.preventDefault();\n row.focus();\n }\n };\n\n const renderItem = (item: ChatHistoryItem) => (\n <HistoryRow\n key={item.id}\n item={item}\n active={item.id === activeId}\n renaming={renaming === item.id}\n onSelect={() => onSelect(item.id)}\n onStartRename={onRename ? () => setRenaming(item.id) : undefined}\n onRename={(title) => {\n setRenaming(null);\n if (onRename && title.trim() && title.trim() !== item.title)\n onRename(item.id, title.trim());\n }}\n onDelete={onDelete ? () => onDelete(item.id) : undefined}\n onPinChange={onPinChange ? (p) => onPinChange(item.id, p) : undefined}\n onKeyDown={onRowKeyDown}\n />\n );\n\n return (\n <div\n ref={ref}\n data-slot=\"chat-history\"\n aria-label={label}\n role=\"navigation\"\n className={cn('flex h-full min-h-0 flex-col', className)}\n {...props}\n >\n {(onNewChat || searchable) && (\n <div className=\"grid gap-2 p-2\">\n {onNewChat && (\n <Button variant=\"outline\" className=\"justify-start\" onClick={onNewChat}>\n <MessageSquarePlus /> New chat\n </Button>\n )}\n {searchable && (\n <label htmlFor={searchId} className=\"relative block\">\n <span className=\"sr-only\">Search chats</span>\n <Search\n aria-hidden\n className=\"pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2 text-muted-foreground\"\n />\n <input\n id={searchId}\n type=\"search\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n placeholder=\"Search chats\"\n className={cn(\n 'h-8 w-full rounded-md border border-input bg-surface pr-2 pl-8 text-base placeholder:text-muted-foreground sm:text-sm pointer-coarse:h-11',\n fieldFocusClasses,\n )}\n />\n </label>\n )}\n </div>\n )}\n <div ref={list} className=\"min-h-0 flex-1 overflow-y-auto px-2 pb-2\">\n {loading ? (\n <div role=\"status\" aria-label=\"Loading chats\" className=\"grid gap-1.5 pt-1\">\n {[72, 56, 64, 48, 60].map((w, i) => (\n <div key={i} className=\"h-8 rounded-md bg-muted/70 motion-safe:animate-pulse\">\n <span className=\"sr-only\">Loading</span>\n <span\n aria-hidden\n className=\"ml-2 inline-block h-2.5 translate-y-3 rounded bg-muted-foreground/15\"\n style={{ width: `${w}%` }}\n />\n </div>\n ))}\n </div>\n ) : error ? (\n <div role=\"alert\" className=\"grid justify-items-start gap-2 p-2 text-sm\">\n <span className=\"inline-flex items-center gap-1.5 font-medium text-destructive [&_svg]:size-4\">\n <AlertCircle aria-hidden /> Chats could not load\n </span>\n <span className=\"text-muted-foreground\">{error}</span>\n {onRetry && (\n <Button size=\"sm\" variant=\"outline\" onClick={onRetry}>\n Try again\n </Button>\n )}\n </div>\n ) : items.length === 0 ? (\n <div className=\"p-3 text-sm text-muted-foreground\">\n {empty ?? 'No chats yet. Start one and it will appear here.'}\n </div>\n ) : groups.length === 0 ? (\n <p role=\"status\" className=\"p-3 text-sm text-muted-foreground\">\n No chats match &ldquo;{query}&rdquo;.\n </p>\n ) : (\n groups.map((g) => (\n <section key={g.key} aria-label={g.label} className=\"mt-2 first:mt-0\">\n <h3 className=\"px-2 pt-2 pb-1 text-[11px] font-semibold tracking-[0.06em] text-muted-foreground uppercase\">\n {g.label}\n </h3>\n <ul className=\"grid grid-cols-[minmax(0,1fr)] gap-0.5\">\n {renderItems ? renderItems(g.items, renderItem) : g.items.map(renderItem)}\n </ul>\n </section>\n ))\n )}\n </div>\n </div>\n );\n});\n\nfunction HistoryRow({\n item,\n active,\n renaming,\n onSelect,\n onStartRename,\n onRename,\n onDelete,\n onPinChange,\n onKeyDown,\n}: {\n item: ChatHistoryItem;\n active: boolean;\n renaming: boolean;\n onSelect: () => void;\n onStartRename?: () => void;\n onRename: (title: string) => void;\n onDelete?: () => void;\n onPinChange?: (pinned: boolean) => void;\n onKeyDown: (e: React.KeyboardEvent) => void;\n}) {\n const hasMenu = Boolean(onStartRename || onDelete || onPinChange);\n if (renaming) return <RenameRow title={item.title} onDone={onRename} />;\n return (\n <li className=\"group/row relative min-w-0\">\n <button\n type=\"button\"\n data-slot=\"chat-history-row\"\n aria-current={active ? 'page' : undefined}\n onClick={onSelect}\n onKeyDown={onKeyDown}\n className={cn(\n 'flex h-8 w-full items-center gap-2 rounded-md px-2 text-left text-sm transition-colors hover:bg-muted pointer-coarse:h-11',\n focusRingClasses,\n 'focus-visible:outline-offset-[-2px]',\n hasMenu && 'pr-9',\n active && 'bg-accent font-medium text-accent-foreground hover:bg-accent',\n )}\n >\n <span className=\"min-w-0 flex-1 truncate\">{item.title || 'Untitled chat'}</span>\n </button>\n {hasMenu && (\n <DropdownMenu>\n <DropdownMenuTrigger\n aria-label={`Actions for ${item.title || 'chat'}`}\n className={cn(\n 'absolute top-1/2 right-1 grid size-7 -translate-y-1/2 place-items-center rounded-sm text-muted-foreground opacity-0 transition-opacity hover:bg-background hover:text-foreground focus-visible:opacity-100 group-hover/row:opacity-100 data-[state=open]:opacity-100 pointer-coarse:size-9 pointer-coarse:opacity-100 [&_svg]:size-4',\n focusRingClasses,\n touchTargetClasses,\n 'absolute',\n active && 'opacity-100',\n )}\n >\n <MoreHorizontal aria-hidden />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" className=\"w-40\">\n {onStartRename && (\n <DropdownMenuItem onSelect={onStartRename}>\n <Edit aria-hidden /> Rename\n </DropdownMenuItem>\n )}\n {onPinChange && (\n <DropdownMenuItem onSelect={() => onPinChange(!item.pinned)}>\n {item.pinned ? <PinOff aria-hidden /> : <Pin aria-hidden />}\n {item.pinned ? 'Unpin' : 'Pin'}\n </DropdownMenuItem>\n )}\n {onDelete && (\n <>\n {(onStartRename || onPinChange) && <DropdownMenuSeparator />}\n <DropdownMenuItem variant=\"destructive\" onSelect={onDelete}>\n <Trash aria-hidden /> Delete\n </DropdownMenuItem>\n </>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n </li>\n );\n}\n\n/** Rename in place: Enter or leaving the field saves, Escape keeps the old title. */\nfunction RenameRow({ title, onDone }: { title: string; onDone: (title: string) => void }) {\n const [draft, setDraft] = React.useState(title);\n const input = React.useRef<HTMLInputElement>(null);\n React.useEffect(() => {\n input.current?.select();\n }, []);\n return (\n <li className=\"px-1 py-0.5\">\n <input\n ref={input}\n aria-label=\"Chat title\"\n value={draft}\n // eslint-disable-next-line jsx-a11y/no-autofocus -- rename was just asked for\n autoFocus\n onChange={(e) => setDraft(e.target.value)}\n onBlur={() => onDone(draft)}\n onKeyDown={(e) => {\n if (e.nativeEvent.isComposing || e.nativeEvent.keyCode === 229) return;\n if (e.key === 'Enter') {\n e.preventDefault();\n onDone(draft);\n } else if (e.key === 'Escape') {\n e.preventDefault();\n onDone(title);\n }\n }}\n className={cn(\n 'h-8 w-full rounded-md border border-ring bg-surface px-2 text-base inset-ring-1 inset-ring-ring sm:text-sm',\n noOutlineClasses,\n )}\n />\n </li>\n );\n}\n\nexport { ChatHistory };\n"],"mappings":"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"}