@inui/design-system 0.0.0-stage → 1.22.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 (312) hide show
  1. package/README.md +360 -2
  2. package/dist/components/ui/accordion.d.ts +44 -0
  3. package/dist/components/ui/accordion.d.ts.map +1 -0
  4. package/dist/components/ui/accordion.js +86 -0
  5. package/dist/components/ui/accordion.js.map +1 -0
  6. package/dist/components/ui/ai-avatar.d.ts +46 -0
  7. package/dist/components/ui/ai-avatar.d.ts.map +1 -0
  8. package/dist/components/ui/ai-avatar.js +43 -0
  9. package/dist/components/ui/ai-avatar.js.map +1 -0
  10. package/dist/components/ui/ai-label.d.ts +118 -0
  11. package/dist/components/ui/ai-label.d.ts.map +1 -0
  12. package/dist/components/ui/ai-label.js +184 -0
  13. package/dist/components/ui/ai-label.js.map +1 -0
  14. package/dist/components/ui/ai-sparkle.d.ts +91 -0
  15. package/dist/components/ui/ai-sparkle.d.ts.map +1 -0
  16. package/dist/components/ui/ai-sparkle.js +200 -0
  17. package/dist/components/ui/ai-sparkle.js.map +1 -0
  18. package/dist/components/ui/alert-dialog.d.ts +79 -0
  19. package/dist/components/ui/alert-dialog.d.ts.map +1 -0
  20. package/dist/components/ui/alert-dialog.js +147 -0
  21. package/dist/components/ui/alert-dialog.js.map +1 -0
  22. package/dist/components/ui/alert.d.ts +71 -0
  23. package/dist/components/ui/alert.d.ts.map +1 -0
  24. package/dist/components/ui/alert.js +108 -0
  25. package/dist/components/ui/alert.js.map +1 -0
  26. package/dist/components/ui/aspect-ratio.d.ts +30 -0
  27. package/dist/components/ui/aspect-ratio.d.ts.map +1 -0
  28. package/dist/components/ui/aspect-ratio.js +40 -0
  29. package/dist/components/ui/aspect-ratio.js.map +1 -0
  30. package/dist/components/ui/attachment.d.ts +74 -0
  31. package/dist/components/ui/attachment.d.ts.map +1 -0
  32. package/dist/components/ui/attachment.js +142 -0
  33. package/dist/components/ui/attachment.js.map +1 -0
  34. package/dist/components/ui/avatar.d.ts +82 -0
  35. package/dist/components/ui/avatar.d.ts.map +1 -0
  36. package/dist/components/ui/avatar.js +123 -0
  37. package/dist/components/ui/avatar.js.map +1 -0
  38. package/dist/components/ui/badge.d.ts +130 -0
  39. package/dist/components/ui/badge.d.ts.map +1 -0
  40. package/dist/components/ui/badge.js +226 -0
  41. package/dist/components/ui/badge.js.map +1 -0
  42. package/dist/components/ui/breadcrumb.d.ts +43 -0
  43. package/dist/components/ui/breadcrumb.d.ts.map +1 -0
  44. package/dist/components/ui/breadcrumb.js +98 -0
  45. package/dist/components/ui/breadcrumb.js.map +1 -0
  46. package/dist/components/ui/browser-tabs.d.ts +218 -0
  47. package/dist/components/ui/browser-tabs.d.ts.map +1 -0
  48. package/dist/components/ui/browser-tabs.js +528 -0
  49. package/dist/components/ui/browser-tabs.js.map +1 -0
  50. package/dist/components/ui/bubble.d.ts +80 -0
  51. package/dist/components/ui/bubble.d.ts.map +1 -0
  52. package/dist/components/ui/bubble.js +235 -0
  53. package/dist/components/ui/bubble.js.map +1 -0
  54. package/dist/components/ui/button-group.d.ts +60 -0
  55. package/dist/components/ui/button-group.d.ts.map +1 -0
  56. package/dist/components/ui/button-group.js +89 -0
  57. package/dist/components/ui/button-group.js.map +1 -0
  58. package/dist/components/ui/button.d.ts +157 -0
  59. package/dist/components/ui/button.d.ts.map +1 -0
  60. package/dist/components/ui/button.js +144 -0
  61. package/dist/components/ui/button.js.map +1 -0
  62. package/dist/components/ui/calendar.d.ts +57 -0
  63. package/dist/components/ui/calendar.d.ts.map +1 -0
  64. package/dist/components/ui/calendar.js +163 -0
  65. package/dist/components/ui/calendar.js.map +1 -0
  66. package/dist/components/ui/card.d.ts +96 -0
  67. package/dist/components/ui/card.d.ts.map +1 -0
  68. package/dist/components/ui/card.js +131 -0
  69. package/dist/components/ui/card.js.map +1 -0
  70. package/dist/components/ui/carousel.d.ts +86 -0
  71. package/dist/components/ui/carousel.d.ts.map +1 -0
  72. package/dist/components/ui/carousel.js +207 -0
  73. package/dist/components/ui/carousel.js.map +1 -0
  74. package/dist/components/ui/checkbox.d.ts +54 -0
  75. package/dist/components/ui/checkbox.d.ts.map +1 -0
  76. package/dist/components/ui/checkbox.js +78 -0
  77. package/dist/components/ui/checkbox.js.map +1 -0
  78. package/dist/components/ui/collapsible.d.ts +45 -0
  79. package/dist/components/ui/collapsible.d.ts.map +1 -0
  80. package/dist/components/ui/collapsible.js +65 -0
  81. package/dist/components/ui/collapsible.js.map +1 -0
  82. package/dist/components/ui/combobox.d.ts +111 -0
  83. package/dist/components/ui/combobox.d.ts.map +1 -0
  84. package/dist/components/ui/combobox.js +264 -0
  85. package/dist/components/ui/combobox.js.map +1 -0
  86. package/dist/components/ui/command.d.ts +71 -0
  87. package/dist/components/ui/command.d.ts.map +1 -0
  88. package/dist/components/ui/command.js +133 -0
  89. package/dist/components/ui/command.js.map +1 -0
  90. package/dist/components/ui/context-menu.d.ts +70 -0
  91. package/dist/components/ui/context-menu.d.ts.map +1 -0
  92. package/dist/components/ui/context-menu.js +163 -0
  93. package/dist/components/ui/context-menu.js.map +1 -0
  94. package/dist/components/ui/count-badge.d.ts +40 -0
  95. package/dist/components/ui/count-badge.d.ts.map +1 -0
  96. package/dist/components/ui/count-badge.js +43 -0
  97. package/dist/components/ui/count-badge.js.map +1 -0
  98. package/dist/components/ui/data-table.d.ts +1026 -0
  99. package/dist/components/ui/data-table.d.ts.map +1 -0
  100. package/dist/components/ui/data-table.js +3423 -0
  101. package/dist/components/ui/data-table.js.map +1 -0
  102. package/dist/components/ui/dialog.d.ts +73 -0
  103. package/dist/components/ui/dialog.d.ts.map +1 -0
  104. package/dist/components/ui/dialog.js +145 -0
  105. package/dist/components/ui/dialog.js.map +1 -0
  106. package/dist/components/ui/direction.d.ts +35 -0
  107. package/dist/components/ui/direction.d.ts.map +1 -0
  108. package/dist/components/ui/direction.js +35 -0
  109. package/dist/components/ui/direction.js.map +1 -0
  110. package/dist/components/ui/drawer.d.ts +53 -0
  111. package/dist/components/ui/drawer.d.ts.map +1 -0
  112. package/dist/components/ui/drawer.js +115 -0
  113. package/dist/components/ui/drawer.js.map +1 -0
  114. package/dist/components/ui/dropdown-menu.d.ts +75 -0
  115. package/dist/components/ui/dropdown-menu.d.ts.map +1 -0
  116. package/dist/components/ui/dropdown-menu.js +173 -0
  117. package/dist/components/ui/dropdown-menu.js.map +1 -0
  118. package/dist/components/ui/dropzone.d.ts +141 -0
  119. package/dist/components/ui/dropzone.d.ts.map +1 -0
  120. package/dist/components/ui/dropzone.js +257 -0
  121. package/dist/components/ui/dropzone.js.map +1 -0
  122. package/dist/components/ui/empty.d.ts +94 -0
  123. package/dist/components/ui/empty.d.ts.map +1 -0
  124. package/dist/components/ui/empty.js +149 -0
  125. package/dist/components/ui/empty.js.map +1 -0
  126. package/dist/components/ui/field.d.ts +122 -0
  127. package/dist/components/ui/field.d.ts.map +1 -0
  128. package/dist/components/ui/field.js +254 -0
  129. package/dist/components/ui/field.js.map +1 -0
  130. package/dist/components/ui/hover-card.d.ts +51 -0
  131. package/dist/components/ui/hover-card.d.ts.map +1 -0
  132. package/dist/components/ui/hover-card.js +101 -0
  133. package/dist/components/ui/hover-card.js.map +1 -0
  134. package/dist/components/ui/input-group.d.ts +62 -0
  135. package/dist/components/ui/input-group.d.ts.map +1 -0
  136. package/dist/components/ui/input-group.js +115 -0
  137. package/dist/components/ui/input-group.js.map +1 -0
  138. package/dist/components/ui/input-otp.d.ts +52 -0
  139. package/dist/components/ui/input-otp.d.ts.map +1 -0
  140. package/dist/components/ui/input-otp.js +89 -0
  141. package/dist/components/ui/input-otp.js.map +1 -0
  142. package/dist/components/ui/input.d.ts +47 -0
  143. package/dist/components/ui/input.d.ts.map +1 -0
  144. package/dist/components/ui/input.js +47 -0
  145. package/dist/components/ui/input.js.map +1 -0
  146. package/dist/components/ui/item.d.ts +74 -0
  147. package/dist/components/ui/item.d.ts.map +1 -0
  148. package/dist/components/ui/item.js +176 -0
  149. package/dist/components/ui/item.js.map +1 -0
  150. package/dist/components/ui/kbd.d.ts +41 -0
  151. package/dist/components/ui/kbd.d.ts.map +1 -0
  152. package/dist/components/ui/kbd.js +58 -0
  153. package/dist/components/ui/kbd.js.map +1 -0
  154. package/dist/components/ui/key-value-pair.d.ts +56 -0
  155. package/dist/components/ui/key-value-pair.d.ts.map +1 -0
  156. package/dist/components/ui/key-value-pair.js +110 -0
  157. package/dist/components/ui/key-value-pair.js.map +1 -0
  158. package/dist/components/ui/label.d.ts +83 -0
  159. package/dist/components/ui/label.d.ts.map +1 -0
  160. package/dist/components/ui/label.js +85 -0
  161. package/dist/components/ui/label.js.map +1 -0
  162. package/dist/components/ui/marker.d.ts +54 -0
  163. package/dist/components/ui/marker.d.ts.map +1 -0
  164. package/dist/components/ui/marker.js +79 -0
  165. package/dist/components/ui/marker.js.map +1 -0
  166. package/dist/components/ui/menubar.d.ts +72 -0
  167. package/dist/components/ui/menubar.d.ts.map +1 -0
  168. package/dist/components/ui/menubar.js +174 -0
  169. package/dist/components/ui/menubar.js.map +1 -0
  170. package/dist/components/ui/message-scroller.d.ts +53 -0
  171. package/dist/components/ui/message-scroller.d.ts.map +1 -0
  172. package/dist/components/ui/message-scroller.js +95 -0
  173. package/dist/components/ui/message-scroller.js.map +1 -0
  174. package/dist/components/ui/message.d.ts +63 -0
  175. package/dist/components/ui/message.d.ts.map +1 -0
  176. package/dist/components/ui/message.js +92 -0
  177. package/dist/components/ui/message.js.map +1 -0
  178. package/dist/components/ui/meta-list.d.ts +55 -0
  179. package/dist/components/ui/meta-list.d.ts.map +1 -0
  180. package/dist/components/ui/meta-list.js +75 -0
  181. package/dist/components/ui/meta-list.js.map +1 -0
  182. package/dist/components/ui/native-select.d.ts +51 -0
  183. package/dist/components/ui/native-select.d.ts.map +1 -0
  184. package/dist/components/ui/native-select.js +75 -0
  185. package/dist/components/ui/native-select.js.map +1 -0
  186. package/dist/components/ui/navigation-menu.d.ts +56 -0
  187. package/dist/components/ui/navigation-menu.d.ts.map +1 -0
  188. package/dist/components/ui/navigation-menu.js +116 -0
  189. package/dist/components/ui/navigation-menu.js.map +1 -0
  190. package/dist/components/ui/page-header.d.ts +223 -0
  191. package/dist/components/ui/page-header.d.ts.map +1 -0
  192. package/dist/components/ui/page-header.js +233 -0
  193. package/dist/components/ui/page-header.js.map +1 -0
  194. package/dist/components/ui/pagination.d.ts +68 -0
  195. package/dist/components/ui/pagination.d.ts.map +1 -0
  196. package/dist/components/ui/pagination.js +145 -0
  197. package/dist/components/ui/pagination.js.map +1 -0
  198. package/dist/components/ui/popover.d.ts +61 -0
  199. package/dist/components/ui/popover.d.ts.map +1 -0
  200. package/dist/components/ui/popover.js +144 -0
  201. package/dist/components/ui/popover.js.map +1 -0
  202. package/dist/components/ui/progress.d.ts +35 -0
  203. package/dist/components/ui/progress.d.ts.map +1 -0
  204. package/dist/components/ui/progress.js +46 -0
  205. package/dist/components/ui/progress.js.map +1 -0
  206. package/dist/components/ui/questionnaire.d.ts +92 -0
  207. package/dist/components/ui/questionnaire.d.ts.map +1 -0
  208. package/dist/components/ui/questionnaire.js +277 -0
  209. package/dist/components/ui/questionnaire.js.map +1 -0
  210. package/dist/components/ui/radio-group.d.ts +50 -0
  211. package/dist/components/ui/radio-group.d.ts.map +1 -0
  212. package/dist/components/ui/radio-group.js +65 -0
  213. package/dist/components/ui/radio-group.js.map +1 -0
  214. package/dist/components/ui/resizable.d.ts +44 -0
  215. package/dist/components/ui/resizable.d.ts.map +1 -0
  216. package/dist/components/ui/resizable.js +73 -0
  217. package/dist/components/ui/resizable.js.map +1 -0
  218. package/dist/components/ui/scroll-area.d.ts +55 -0
  219. package/dist/components/ui/scroll-area.d.ts.map +1 -0
  220. package/dist/components/ui/scroll-area.js +72 -0
  221. package/dist/components/ui/scroll-area.js.map +1 -0
  222. package/dist/components/ui/select.d.ts +274 -0
  223. package/dist/components/ui/select.d.ts.map +1 -0
  224. package/dist/components/ui/select.js +609 -0
  225. package/dist/components/ui/select.js.map +1 -0
  226. package/dist/components/ui/separator.d.ts +31 -0
  227. package/dist/components/ui/separator.d.ts.map +1 -0
  228. package/dist/components/ui/separator.js +38 -0
  229. package/dist/components/ui/separator.js.map +1 -0
  230. package/dist/components/ui/sheet.d.ts +59 -0
  231. package/dist/components/ui/sheet.d.ts.map +1 -0
  232. package/dist/components/ui/sheet.js +128 -0
  233. package/dist/components/ui/sheet.js.map +1 -0
  234. package/dist/components/ui/sidebar.d.ts +166 -0
  235. package/dist/components/ui/sidebar.d.ts.map +1 -0
  236. package/dist/components/ui/sidebar.js +512 -0
  237. package/dist/components/ui/sidebar.js.map +1 -0
  238. package/dist/components/ui/skeleton.d.ts +35 -0
  239. package/dist/components/ui/skeleton.d.ts.map +1 -0
  240. package/dist/components/ui/skeleton.js +46 -0
  241. package/dist/components/ui/skeleton.js.map +1 -0
  242. package/dist/components/ui/slider.d.ts +39 -0
  243. package/dist/components/ui/slider.d.ts.map +1 -0
  244. package/dist/components/ui/slider.js +75 -0
  245. package/dist/components/ui/slider.js.map +1 -0
  246. package/dist/components/ui/sonner.d.ts +56 -0
  247. package/dist/components/ui/sonner.d.ts.map +1 -0
  248. package/dist/components/ui/sonner.js +96 -0
  249. package/dist/components/ui/sonner.js.map +1 -0
  250. package/dist/components/ui/spinner.d.ts +37 -0
  251. package/dist/components/ui/spinner.d.ts.map +1 -0
  252. package/dist/components/ui/spinner.js +51 -0
  253. package/dist/components/ui/spinner.js.map +1 -0
  254. package/dist/components/ui/stepper.d.ts +84 -0
  255. package/dist/components/ui/stepper.d.ts.map +1 -0
  256. package/dist/components/ui/stepper.js +145 -0
  257. package/dist/components/ui/stepper.js.map +1 -0
  258. package/dist/components/ui/switch.d.ts +36 -0
  259. package/dist/components/ui/switch.d.ts.map +1 -0
  260. package/dist/components/ui/switch.js +44 -0
  261. package/dist/components/ui/switch.js.map +1 -0
  262. package/dist/components/ui/table.d.ts +80 -0
  263. package/dist/components/ui/table.d.ts.map +1 -0
  264. package/dist/components/ui/table.js +130 -0
  265. package/dist/components/ui/table.js.map +1 -0
  266. package/dist/components/ui/tabs.d.ts +87 -0
  267. package/dist/components/ui/tabs.d.ts.map +1 -0
  268. package/dist/components/ui/tabs.js +128 -0
  269. package/dist/components/ui/tabs.js.map +1 -0
  270. package/dist/components/ui/textarea.d.ts +35 -0
  271. package/dist/components/ui/textarea.d.ts.map +1 -0
  272. package/dist/components/ui/textarea.js +38 -0
  273. package/dist/components/ui/textarea.js.map +1 -0
  274. package/dist/components/ui/time-picker.d.ts +58 -0
  275. package/dist/components/ui/time-picker.d.ts.map +1 -0
  276. package/dist/components/ui/time-picker.js +188 -0
  277. package/dist/components/ui/time-picker.js.map +1 -0
  278. package/dist/components/ui/toggle-group.d.ts +52 -0
  279. package/dist/components/ui/toggle-group.d.ts.map +1 -0
  280. package/dist/components/ui/toggle-group.js +94 -0
  281. package/dist/components/ui/toggle-group.js.map +1 -0
  282. package/dist/components/ui/toggle.d.ts +50 -0
  283. package/dist/components/ui/toggle.d.ts.map +1 -0
  284. package/dist/components/ui/toggle.js +70 -0
  285. package/dist/components/ui/toggle.js.map +1 -0
  286. package/dist/components/ui/tooltip.d.ts +51 -0
  287. package/dist/components/ui/tooltip.d.ts.map +1 -0
  288. package/dist/components/ui/tooltip.js +78 -0
  289. package/dist/components/ui/tooltip.js.map +1 -0
  290. package/dist/hooks/use-dark-mode.d.ts +2 -0
  291. package/dist/hooks/use-dark-mode.d.ts.map +1 -0
  292. package/dist/hooks/use-dark-mode.js +36 -0
  293. package/dist/hooks/use-dark-mode.js.map +1 -0
  294. package/dist/hooks/use-mobile.d.ts +2 -0
  295. package/dist/hooks/use-mobile.d.ts.map +1 -0
  296. package/dist/hooks/use-mobile.js +20 -0
  297. package/dist/hooks/use-mobile.js.map +1 -0
  298. package/dist/index.d.ts +88 -0
  299. package/dist/index.d.ts.map +1 -0
  300. package/dist/index.js +77 -0
  301. package/dist/lib/scope.d.ts +64 -0
  302. package/dist/lib/scope.d.ts.map +1 -0
  303. package/dist/lib/scope.js +74 -0
  304. package/dist/lib/scope.js.map +1 -0
  305. package/dist/lib/utils.d.ts +3 -0
  306. package/dist/lib/utils.d.ts.map +1 -0
  307. package/dist/lib/utils.js +11 -0
  308. package/dist/lib/utils.js.map +1 -0
  309. package/dist/styles.css +2 -0
  310. package/dist/theme-tokens.css +537 -0
  311. package/dist/theme.css +417 -0
  312. package/package.json +103 -3
@@ -0,0 +1,528 @@
1
+ "use client";
2
+ import { cn } from "../../lib/utils.js";
3
+ import { Button } from "./button.js";
4
+ import { Popover as Popover$1, PopoverContent, PopoverTrigger } from "./popover.js";
5
+ import { Input } from "./input.js";
6
+ import { ContextMenu as ContextMenu$1, ContextMenuContent, ContextMenuItem, ContextMenuSeparator, ContextMenuTrigger } from "./context-menu.js";
7
+ import { Tooltip as Tooltip$1, TooltipContent, TooltipTrigger } from "./tooltip.js";
8
+ import { TabsContent } from "./tabs.js";
9
+ import * as React from "react";
10
+ import { Tabs } from "radix-ui";
11
+ import { CopyXIcon, FileIcon, PinIcon, PinOffIcon, PlusIcon, XIcon } from "lucide-react";
12
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
13
+ //#region src/components/ui/browser-tabs.tsx
14
+ /**
15
+ * BrowserTabs — persistent, closable document tabs, browser-style.
16
+ *
17
+ * The same Radix Tabs primitive `tabs.tsx` wraps, plus Popover for the "+"
18
+ * menu, Tooltip for truncated names, and Button for the per-tab close
19
+ * action — a different visual/interaction language from Tabs, not a
20
+ * variant of it: Tabs switches between named views of one entity (2-6 fixed
21
+ * tabs); this is for many independent, closable documents/views open at
22
+ * once (an IDE's editor tabs, a browser's own tab strip) — always
23
+ * horizontal, and always the topmost chrome of whatever surface it sits on.
24
+ * Each tab floats as a rounded pill on the strip's own bg-secondary track,
25
+ * flush against its bottom edge — the active tab's bg-card fill then
26
+ * touches the card content's own bg-card directly beneath it with no grey
27
+ * left in between, merging the two Chrome-style, rather than reading as a
28
+ * colored/selected state the way Tabs' own default variant does. Pinned
29
+ * tabs render icon-only — a fixed favicon-size square, falling back to a
30
+ * generic FileIcon when the tab itself has none — same as a real browser's
31
+ * own pinned tabs, and never part of the overflow behavior below. Once
32
+ * unpinned tabs stop fitting, they shrink together down to a floor, then
33
+ * the strip scrolls that pool horizontally past that — the same overflow
34
+ * model a real browser's own tab strip uses, not a "More" menu hiding the
35
+ * rest.
36
+ * An optional "+" pill at the strip's end, outside the scrolling region
37
+ * (`addViews` on BrowserTabsList) opens a popover of product-defined views
38
+ * the user can open as new tabs — a worklist's saved filters, for
39
+ * instance. `addTrigger`/`renderAddContent` swap its trigger or its
40
+ * popover content for something fully custom.
41
+ */
42
+ var BrowserTabsActiveContext = React.createContext(void 0);
43
+ function BrowserTabs({ className, value, defaultValue, onValueChange, ...props }) {
44
+ const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue);
45
+ const activeValue = value ?? uncontrolledValue;
46
+ return /* @__PURE__ */ jsx(BrowserTabsActiveContext.Provider, {
47
+ value: activeValue,
48
+ children: /* @__PURE__ */ jsx(Tabs.Root, {
49
+ "data-slot": "browser-tabs",
50
+ className: cn("flex flex-col", className),
51
+ value,
52
+ defaultValue,
53
+ onValueChange: (next) => {
54
+ setUncontrolledValue(next);
55
+ onValueChange?.(next);
56
+ },
57
+ activationMode: "manual",
58
+ ...props
59
+ })
60
+ });
61
+ }
62
+ var BROWSER_TAB_PILL_CLASS = cn("group/browser-tab relative flex h-7 max-w-52 cursor-pointer items-center gap-1.5 rounded-md border border-transparent px-2.5 text-left text-sm font-medium text-muted-foreground transition-colors outline-none select-none", "hover:bg-muted hover:text-foreground dark:hover:text-foreground", "focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-inset");
63
+ var ADD_VIEWS_SEARCH_THRESHOLD = 6;
64
+ /** Children as a flat list of elements, looking through Fragments so tabs grouped in `<>…</>` still split into pinned/unpinned. */
65
+ function flattenTabChildren(children) {
66
+ return React.Children.toArray(children).flatMap((child) => {
67
+ if (!React.isValidElement(child)) return [];
68
+ if (child.type === React.Fragment) return flattenTabChildren(child.props.children).map((inner) => React.cloneElement(inner, { key: `${child.key}${inner.key}` }));
69
+ return [child];
70
+ });
71
+ }
72
+ function BrowserTabsList({ className, children, addViews, onAddView, addLabel = "Open a view in a new tab", addTrigger, renderAddContent, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, ...props }) {
73
+ const hasAdd = Boolean(addViews && addViews.length > 0 || renderAddContent);
74
+ const items = React.useMemo(() => flattenTabChildren(children), [children]);
75
+ const pinnedItems = React.useMemo(() => items.filter((item) => item.props.pin), [items]);
76
+ const restItems = React.useMemo(() => items.filter((item) => !item.props.pin), [items]);
77
+ const hasDivider = pinnedItems.length > 0 && restItems.length > 0;
78
+ const restScrollRef = React.useRef(null);
79
+ const activeValue = React.useContext(BrowserTabsActiveContext);
80
+ React.useEffect(() => {
81
+ const container = restScrollRef.current;
82
+ if (!container || activeValue === void 0) return;
83
+ container.querySelector(`[data-slot="browser-tab"][data-value="${CSS.escape(activeValue)}"]`)?.scrollIntoView({
84
+ block: "nearest",
85
+ inline: "nearest"
86
+ });
87
+ }, [activeValue]);
88
+ const [canScrollLeft, setCanScrollLeft] = React.useState(false);
89
+ const [canScrollRight, setCanScrollRight] = React.useState(false);
90
+ React.useEffect(() => {
91
+ const container = restScrollRef.current;
92
+ if (!container) return;
93
+ function measure() {
94
+ if (!container) return;
95
+ setCanScrollLeft(container.scrollLeft > 0);
96
+ setCanScrollRight(container.scrollLeft + container.clientWidth < container.scrollWidth);
97
+ }
98
+ measure();
99
+ container.addEventListener("scroll", measure);
100
+ const observer = new ResizeObserver(measure);
101
+ observer.observe(container);
102
+ return () => {
103
+ container.removeEventListener("scroll", measure);
104
+ observer.disconnect();
105
+ };
106
+ }, [restItems.length]);
107
+ const hasOverflow = canScrollLeft || canScrollRight;
108
+ return /* @__PURE__ */ jsxs(Tabs.List, {
109
+ "data-slot": "browser-tabs-list",
110
+ role: "presentation",
111
+ "aria-orientation": void 0,
112
+ className: cn("relative flex items-start gap-1 bg-secondary px-(--card-spacing,0.5rem) pt-[calc(var(--card-spacing,0.5rem)*0.5)]", className),
113
+ ...props,
114
+ children: [/* @__PURE__ */ jsxs("div", {
115
+ role: "tablist",
116
+ "aria-orientation": "horizontal",
117
+ "aria-label": ariaLabel,
118
+ "aria-labelledby": ariaLabelledBy,
119
+ "data-overflowing": hasOverflow || void 0,
120
+ className: "group/tablist flex min-h-8 min-w-0 items-start gap-1",
121
+ children: [
122
+ pinnedItems,
123
+ hasDivider && /* @__PURE__ */ jsx("div", {
124
+ "aria-hidden": "true",
125
+ className: "h-7 w-px shrink-0 bg-border"
126
+ }),
127
+ /* @__PURE__ */ jsx("div", {
128
+ ref: restScrollRef,
129
+ role: "presentation",
130
+ className: cn("-mt-[calc(var(--card-spacing,0.5rem)*0.5)] flex min-w-0 [scrollbar-width:thin] items-start gap-1 overflow-x-auto pt-[calc(var(--card-spacing,0.5rem)*0.5)] focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:outline-none focus-visible:ring-inset", pinnedItems.length === 0 && "-ml-(--card-spacing,0.5rem) pl-(--card-spacing,0.5rem)", !hasAdd && "-mr-(--card-spacing,0.5rem) pr-(--card-spacing,0.5rem)", pinnedItems.length > 0 && "-ml-2 pl-2", hasAdd && "-mr-2 pr-2"),
131
+ style: {
132
+ boxShadow: [canScrollLeft && "inset 8px 0 8px -8px color-mix(in srgb, var(--color-foreground) 20%, transparent)", canScrollRight && "inset -8px 0 8px -8px color-mix(in srgb, var(--color-foreground) 20%, transparent)"].filter(Boolean).join(", "),
133
+ ...hasOverflow && restItems.length > 0 ? {
134
+ flexGrow: restItems.length,
135
+ flexShrink: 1,
136
+ flexBasis: 0
137
+ } : void 0
138
+ },
139
+ children: restItems
140
+ })
141
+ ]
142
+ }), hasAdd && /* @__PURE__ */ jsx(BrowserTabsAdd, {
143
+ views: addViews ?? [],
144
+ onAddView,
145
+ label: addLabel,
146
+ trigger: addTrigger,
147
+ renderContent: renderAddContent,
148
+ className: hasOverflow ? "ml-auto" : void 0
149
+ })]
150
+ });
151
+ }
152
+ function BrowserTabsAdd({ views, onAddView, label, trigger, renderContent, className }) {
153
+ const [open, setOpen] = React.useState(false);
154
+ const [query, setQuery] = React.useState("");
155
+ const close = React.useCallback(() => {
156
+ setOpen(false);
157
+ setQuery("");
158
+ }, []);
159
+ const showSearch = views.length > ADD_VIEWS_SEARCH_THRESHOLD;
160
+ const visibleViews = React.useMemo(() => {
161
+ if (!showSearch || !query.trim()) return views;
162
+ const q = query.trim().toLowerCase();
163
+ return views.filter((view) => view.label.toLowerCase().includes(q) || view.description?.toLowerCase().includes(q));
164
+ }, [
165
+ views,
166
+ showSearch,
167
+ query
168
+ ]);
169
+ return /* @__PURE__ */ jsx("div", {
170
+ className: cn("shrink-0", className),
171
+ children: /* @__PURE__ */ jsxs(Popover$1, {
172
+ open,
173
+ onOpenChange: (next) => {
174
+ setOpen(next);
175
+ if (!next) setQuery("");
176
+ },
177
+ children: [/* @__PURE__ */ jsx(PopoverTrigger, {
178
+ asChild: true,
179
+ children: trigger ?? /* @__PURE__ */ jsx("button", {
180
+ type: "button",
181
+ "data-slot": "browser-tabs-add",
182
+ "aria-label": label,
183
+ className: cn("relative flex size-7 shrink-0 cursor-pointer items-center justify-center rounded-md border border-transparent text-muted-foreground transition-colors outline-none select-none", "hover:bg-muted hover:text-foreground dark:hover:text-foreground", "focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-inset", open && "bg-muted text-foreground"),
184
+ children: /* @__PURE__ */ jsx(PlusIcon, { className: "size-4 shrink-0" })
185
+ })
186
+ }), /* @__PURE__ */ jsx(PopoverContent, {
187
+ align: "start",
188
+ className: renderContent ? void 0 : "w-64 p-1.5",
189
+ children: renderContent ? renderContent(close) : /* @__PURE__ */ jsxs("div", {
190
+ className: "flex flex-col gap-1.5",
191
+ children: [showSearch && /* @__PURE__ */ jsx(Input, {
192
+ autoFocus: true,
193
+ placeholder: "Search...",
194
+ value: query,
195
+ onChange: (event) => setQuery(event.target.value)
196
+ }), /* @__PURE__ */ jsxs("div", {
197
+ className: "flex flex-col gap-0.5",
198
+ role: "menu",
199
+ children: [visibleViews.length === 0 && /* @__PURE__ */ jsx("p", {
200
+ className: "p-1.5 text-sm text-muted-foreground",
201
+ children: "No matches"
202
+ }), visibleViews.map((view) => {
203
+ const Icon = view.icon;
204
+ return /* @__PURE__ */ jsxs("button", {
205
+ type: "button",
206
+ role: "menuitem",
207
+ disabled: view.disabled,
208
+ onClick: () => {
209
+ onAddView?.(view);
210
+ close();
211
+ },
212
+ className: cn(BROWSER_TAB_PILL_CLASS, "w-full max-w-none justify-start", view.description && "h-auto py-1.5", "disabled:pointer-events-none disabled:opacity-50"),
213
+ children: [
214
+ Icon && /* @__PURE__ */ jsx(Icon, { className: "size-3.5 shrink-0" }),
215
+ /* @__PURE__ */ jsxs("span", {
216
+ className: "flex min-w-0 flex-1 flex-col",
217
+ children: [/* @__PURE__ */ jsx("span", {
218
+ className: "truncate",
219
+ children: view.label
220
+ }), view.description && /* @__PURE__ */ jsx("span", {
221
+ className: "truncate text-xs text-muted-foreground",
222
+ children: view.description
223
+ })]
224
+ }),
225
+ view.pin && /* @__PURE__ */ jsx(PinIcon, { className: "size-3.5 shrink-0 text-muted-foreground" })
226
+ ]
227
+ }, view.id);
228
+ })]
229
+ })]
230
+ })
231
+ })]
232
+ })
233
+ });
234
+ }
235
+ /** The truncating label — wraps itself in a Tooltip showing the full name, but only once its content actually overflows (`scrollWidth > clientWidth`), and only for the real interactive tab (never the invisible measuring copy). */
236
+ function BrowserTabLabel({ name, interactive, hoverReveal, children }) {
237
+ const labelRef = React.useRef(null);
238
+ const [truncated, setTruncated] = React.useState(false);
239
+ const [tooltipOpen, setTooltipOpen] = React.useState(false);
240
+ React.useLayoutEffect(() => {
241
+ if (!interactive) return;
242
+ const el = labelRef.current;
243
+ if (!el) return;
244
+ const check = () => {
245
+ if (el.clientWidth === 0) {
246
+ rafId = requestAnimationFrame(check);
247
+ return;
248
+ }
249
+ setTruncated(el.scrollWidth > el.clientWidth);
250
+ };
251
+ let rafId = requestAnimationFrame(check);
252
+ const observer = new ResizeObserver(check);
253
+ observer.observe(el);
254
+ return () => {
255
+ cancelAnimationFrame(rafId);
256
+ observer.disconnect();
257
+ };
258
+ }, [interactive, children]);
259
+ const label = /* @__PURE__ */ jsxs("span", {
260
+ className: "relative min-w-0 flex-1",
261
+ children: [/* @__PURE__ */ jsx("span", {
262
+ "aria-hidden": "true",
263
+ className: "invisible block truncate",
264
+ children
265
+ }), /* @__PURE__ */ jsx("span", {
266
+ ref: labelRef,
267
+ className: cn("absolute inset-0 truncate", hoverReveal && "transition-[padding] group-focus-within/browser-tab:pr-5 group-hover/browser-tab:pr-5"),
268
+ children
269
+ })]
270
+ });
271
+ if (!name) return label;
272
+ return /* @__PURE__ */ jsxs(Tooltip$1, {
273
+ open: truncated && tooltipOpen,
274
+ onOpenChange: setTooltipOpen,
275
+ children: [/* @__PURE__ */ jsx(TooltipTrigger, {
276
+ asChild: true,
277
+ children: label
278
+ }), /* @__PURE__ */ jsx(TooltipContent, { children: name })]
279
+ });
280
+ }
281
+ /** A pinned tab's entire visible content — icon only, no label, favicon-style
282
+ * like a real browser's own pinned tabs. Falls back to `FileIcon` — this
283
+ * design system's existing entity-agnostic "generic item" icon (Dropzone's
284
+ * own fallback for a file type it doesn't otherwise recognize, as opposed to
285
+ * `FileTextIcon`, which Dropzone reserves specifically for documents) — when
286
+ * the tab has no `icon`, so a pinned tab is never a blank square. A tab can
287
+ * represent any kind of view, not just documents, so the fallback shouldn't
288
+ * imply one. `PinIcon` itself would be the wrong fallback here: this same
289
+ * file already uses it for the "pin" *action* (the context menu's "Pin tab"
290
+ * item, and the `addViews` pin hint), so reusing it as a tab's identity icon
291
+ * would read as "pin this" rather than "generic tab." The name still
292
+ * surfaces on hover/focus via Tooltip (there's no visible text left to
293
+ * convey it), and unconditionally rather than only-when-truncated the way
294
+ * BrowserTabLabel's does — icon-only content is "truncated" by definition. */
295
+ function BrowserPinnedTabIcon({ icon: Icon }) {
296
+ return /* @__PURE__ */ jsx(Icon ?? FileIcon, { className: "size-3.5 shrink-0" });
297
+ }
298
+ var BrowserTabShell = React.forwardRef(function BrowserTabShell({ value, icon: Icon, pin, disabled, onClose, closeLabel, onPinToggle, onCloseOthers, className, children, interactive, ...rest }, ref) {
299
+ const activeValue = React.useContext(BrowserTabsActiveContext);
300
+ const isActive = interactive && value === activeValue;
301
+ const isPinned = Boolean(pin);
302
+ const canClose = Boolean(onClose);
303
+ const showHoverClose = canClose && !isPinned;
304
+ const canTogglePin = Boolean(onPinToggle) && pin !== "product";
305
+ const canCloseOthers = Boolean(onCloseOthers);
306
+ const hasMenu = interactive;
307
+ const name = typeof children === "string" ? children : void 0;
308
+ const pill = /* @__PURE__ */ jsxs("div", {
309
+ ref,
310
+ ...rest,
311
+ "data-slot": "browser-tab",
312
+ "data-value": value,
313
+ "aria-disabled": disabled || void 0,
314
+ onKeyDown: (event) => {
315
+ rest.onKeyDown?.(event);
316
+ if (event.defaultPrevented || !interactive || !canClose) return;
317
+ if (event.key === "Delete" || event.key === "Backspace") {
318
+ event.preventDefault();
319
+ onClose?.();
320
+ }
321
+ },
322
+ "aria-label": isPinned ? name ?? rest["aria-label"] : rest["aria-label"],
323
+ className: cn(BROWSER_TAB_PILL_CLASS, isPinned ? "size-7 shrink-0 justify-center px-0" : ["min-w-16", "group-data-overflowing/tablist:flex-1"], "data-disabled:pointer-events-none data-disabled:opacity-50", isActive && "h-8 rounded-b-none bg-card pb-1 text-card-foreground hover:bg-card hover:text-card-foreground", isActive && "before:absolute before:-bottom-px before:left-[calc(-0.5rem-1px)] before:size-2 before:bg-[radial-gradient(circle_at_0_0,transparent_0.5rem,var(--color-card)_calc(0.5rem+0.5px))] before:content-[''] after:absolute after:right-[calc(-0.5rem-1px)] after:-bottom-px after:size-2 after:bg-[radial-gradient(circle_at_100%_0,transparent_0.5rem,var(--color-card)_calc(0.5rem+0.5px))] after:content-['']", className),
324
+ children: [isPinned ? /* @__PURE__ */ jsx(BrowserPinnedTabIcon, { icon: Icon }) : /* @__PURE__ */ jsxs(Fragment, { children: [Icon && /* @__PURE__ */ jsx(Icon, { className: "size-3.5 shrink-0" }), /* @__PURE__ */ jsx(BrowserTabLabel, {
325
+ name,
326
+ interactive,
327
+ hoverReveal: showHoverClose,
328
+ children
329
+ })] }), showHoverClose && /* @__PURE__ */ jsx(Button, {
330
+ asChild: true,
331
+ variant: "secondary",
332
+ size: "xs",
333
+ iconOnly: true,
334
+ children: /* @__PURE__ */ jsx("span", {
335
+ "aria-hidden": "true",
336
+ title: closeLabel ?? `Close ${name ?? value}`,
337
+ className: "absolute inset-y-0 right-1 my-auto size-5 cursor-pointer opacity-0 transition-opacity group-hover/browser-tab:opacity-100",
338
+ onClick: interactive ? (event) => {
339
+ event.stopPropagation();
340
+ onClose?.();
341
+ } : void 0,
342
+ children: /* @__PURE__ */ jsx(XIcon, { className: "size-3" })
343
+ })
344
+ })]
345
+ });
346
+ const pinnedTooltip = isPinned && name;
347
+ const trigger = pinnedTooltip ? /* @__PURE__ */ jsx(TooltipTrigger, {
348
+ asChild: true,
349
+ children: pill
350
+ }) : pill;
351
+ const withTooltip = (node) => pinnedTooltip ? /* @__PURE__ */ jsxs(Tooltip$1, { children: [node, /* @__PURE__ */ jsx(TooltipContent, { children: name })] }) : node;
352
+ if (!hasMenu) return withTooltip(trigger);
353
+ return withTooltip(/* @__PURE__ */ jsxs(ContextMenu$1, { children: [/* @__PURE__ */ jsx(ContextMenuTrigger, {
354
+ asChild: true,
355
+ children: trigger
356
+ }), /* @__PURE__ */ jsxs(ContextMenuContent, { children: [
357
+ /* @__PURE__ */ jsxs(ContextMenuItem, {
358
+ disabled: !canTogglePin,
359
+ onSelect: () => onPinToggle?.(),
360
+ children: [pin ? /* @__PURE__ */ jsx(PinOffIcon, {}) : /* @__PURE__ */ jsx(PinIcon, {}), pin ? "Unpin tab" : "Pin tab"]
361
+ }),
362
+ /* @__PURE__ */ jsx(ContextMenuSeparator, {}),
363
+ /* @__PURE__ */ jsxs(ContextMenuItem, {
364
+ disabled: !canClose,
365
+ onSelect: () => onClose?.(),
366
+ children: [/* @__PURE__ */ jsx(XIcon, {}), "Close"]
367
+ }),
368
+ /* @__PURE__ */ jsxs(ContextMenuItem, {
369
+ disabled: !canCloseOthers,
370
+ onSelect: () => onCloseOthers?.(),
371
+ children: [/* @__PURE__ */ jsx(CopyXIcon, {}), "Close other tabs"]
372
+ })
373
+ ] })] }));
374
+ });
375
+ function BrowserTab(props) {
376
+ const { value, disabled } = props;
377
+ const canClose = Boolean(props.onClose) && props.pin !== "product";
378
+ return /* @__PURE__ */ jsx(Tabs.Trigger, {
379
+ value,
380
+ disabled,
381
+ asChild: true,
382
+ children: /* @__PURE__ */ jsx(BrowserTabShell, {
383
+ ...props,
384
+ onClose: canClose ? props.onClose : void 0,
385
+ interactive: true
386
+ })
387
+ });
388
+ }
389
+ /**
390
+ * WHEN TO USE
391
+ * - Many independent, addable/closable documents or views open at once —
392
+ * an IDE's editor tabs, a browser's own tab strip, a multi-record
393
+ * workspace where each record opens in its own tab.
394
+ * - Always as the topmost chrome of whatever surface hosts it (a Card,
395
+ * a page shell) — it's edge-to-edge and expects to sit flush at that
396
+ * surface's top.
397
+ *
398
+ * NOT WHEN
399
+ * - Switching between a fixed 2-6 named views of *one* entity (an
400
+ * Overview/History/Notes split) — use Tabs instead; it reads as
401
+ * neutral navigation, not as separate closable documents.
402
+ * - Vertical tab placement — not supported; always horizontal.
403
+ *
404
+ * KEY RULES
405
+ * - Composition mirrors Tabs: `BrowserTabs` (Root, controlled or
406
+ * uncontrolled via `value`/`onValueChange`/`defaultValue`) wraps
407
+ * `BrowserTabsList` (the strip) and one `BrowserTabsContent` per tab
408
+ * (re-exported directly from Tabs — same primitive, nothing about it
409
+ * is strip-specific).
410
+ * - `pin`: omit for a normal tab, `"user"` for one the user pinned
411
+ * (closable — closing is how they unpin it), `"product"` for one the
412
+ * product configured (never closable, no close button rendered even if
413
+ * `onClose` is passed). Pinned tabs of either kind render first, in a
414
+ * section separated from the rest by a divider, and are never subject
415
+ * to the overflow behavior below.
416
+ * - Pinned tabs render icon-only — a fixed favicon-size square, same as a
417
+ * real browser's own pinned tabs — falling back to `FileIcon`
418
+ * when the tab itself has no `icon`, so a pinned tab is never blank.
419
+ * The full name still surfaces via Tooltip on hover/focus; there's no
420
+ * hover-revealed close button at that width, so unpinning/closing goes
421
+ * through the right-click menu or Delete/Backspace on the focused tab.
422
+ * - Every tab has the same three-item right-click menu (ContextMenu):
423
+ * "Pin tab"/"Unpin tab", "Close", and "Close other tabs" — always
424
+ * visible, each disabled when the tab wasn't given the matching
425
+ * handler. `onPinToggle` drives the first (read the tab's current `pin`
426
+ * to know the direction, then move it into — or, unpinning, to the
427
+ * front of — the right section in your own list; always disabled on
428
+ * `pin="product"`), `onClose` the second, `onCloseOthers` the third
429
+ * (close every other UNPINNED tab yourself and keep this one active —
430
+ * "close others" never closes a pinned tab of either kind; pinning is
431
+ * exactly the promise that a tab survives bulk closing).
432
+ * No visible pin button on the tab; pinning is menu-only, and pinned
433
+ * tabs are identified by sitting in the pinned section ahead of the
434
+ * divider.
435
+ * - Each `BrowserTab` needs its own `onClose` to get a close button at
436
+ * all — omit it for a tab that can't be dismissed. A tab is exactly as
437
+ * wide as its name at rest (nothing reserved on the right); on hover
438
+ * the close button appears over the end of the name, which truncates
439
+ * underneath it, so the tab's width never changes between rest and
440
+ * hover. That button is pointer-only (a focusable control can't sit
441
+ * inside a `role="tab"`): keyboard users press Delete or Backspace on
442
+ * the focused tab, or use the right-click menu's "Close".
443
+ * - Closing a tab is entirely the consumer's responsibility: `onClose`
444
+ * only reports the intent. Removing it from whatever list backs your
445
+ * tabs, and deciding which tab becomes active next, is app logic this
446
+ * component has no way to know on its own.
447
+ * - Overflow is browser-style, not a "More" menu: once unpinned tabs stop
448
+ * fitting the available width, they shrink together (flex-shrink) down
449
+ * to `min-w-16` (64px) each; past that floor the strip scrolls that
450
+ * pool horizontally instead of shrinking further. Pinned tabs are
451
+ * already fixed-size icon-only squares (see above), so they never
452
+ * shrink, grow, or join the scrolling region. The active tab scrolls
453
+ * into view
454
+ * automatically whenever it changes, so switching tabs never leaves the
455
+ * newly-active one scrolled out of sight. Only the "+" pill is truly
456
+ * fixed-size, living outside the shrink pool entirely. A soft inset
457
+ * shadow fades in on
458
+ * whichever edge(s) still have more tabs scrolled past them (both at
459
+ * once, mid-strip) and disappears once there's nothing left that way —
460
+ * a direction-aware cue, not a static "this can scroll" marker.
461
+ * - A tab's name overflowing `max-w-52` is truncated in the strip but
462
+ * shown in full in a Tooltip on hover/focus.
463
+ * - `addViews` on `BrowserTabsList` adds a "+" pill that opens a popover of
464
+ * product-defined views the user can open as new tabs — a worklist's
465
+ * saved filters, a set of report layouts — `{ id, label, icon?,
466
+ * description?, disabled?, pin? }` each. Sits immediately after the
467
+ * last tab at rest; pins to the strip's own right edge once the tabs
468
+ * overflow into their shrink/scroll region instead, same as a real
469
+ * browser's "+" button. Each is the same full-width tab pill (icon +
470
+ * label) it will become as a tab; `description` grows that row to a
471
+ * second, muted line underneath (a filter's own scope, a last-modified
472
+ * date). Past `ADD_VIEWS_SEARCH_THRESHOLD` (6) views the popover grows
473
+ * a search box filtering by label and description. A `pin` hint renders
474
+ * a small pin icon trailing the label (purely visual — opening it
475
+ * pinned is still your own `onAddView` handler's job). `onAddView` only
476
+ * reports the pick: add a tab for that view to your own list and make
477
+ * it active — or, if that view is already open, just activate the
478
+ * existing tab instead of opening a duplicate. Icon-only by default;
479
+ * `addLabel` names it for assistive tech (default "Open a view in a new
480
+ * tab"). `addTrigger` swaps in a custom trigger node in place of the
481
+ * default "+" pill (still needs its own `aria-label`). `renderAddContent`
482
+ * replaces the *entire* popover body — search box, view list, and all —
483
+ * with something fully custom (a grouped menu, anything) — called with
484
+ * a `close` function to dismiss the popover
485
+ * from inside it; `addViews`/`onAddView` don't render alongside it.
486
+ * - Each `BrowserTab` floats as a rounded pill inset from the strip's
487
+ * `bg-secondary` track. Unlike Tabs' own default variant (a translucent
488
+ * `bg-primary/10` fill), the active tab here reads as merged into the
489
+ * card below it, Chrome-style: `bg-card`/`text-card-foreground` (matching
490
+ * the content surface exactly) plus squared-off bottom corners, sitting
491
+ * flush against the track's own bottom edge with nothing grey left
492
+ * between tab and content. Inactive tabs just fill `bg-muted` on hover
493
+ * and otherwise float clear of the track's edges.
494
+ * - A leading icon uses `icon`, not the `data-icon="inline-start"` slot
495
+ * convention Button/Tabs use — it needs to sit outside the label's own
496
+ * truncation, which a plain child node sharing that flex row wouldn't.
497
+ *
498
+ * USAGE
499
+ * <BrowserTabs value={activeId} onValueChange={setActiveId}>
500
+ * <BrowserTabsList
501
+ * addViews={worklistViews} // [{ id: "overdue", label: "Overdue", icon: ClockIcon }, ...]
502
+ * onAddView={(view) => openViewTab(view)} // add to openDocs (or activate if already open)
503
+ * >
504
+ * <BrowserTab value="home" pin="product">Home</BrowserTab>
505
+ * {openDocs.map((doc) => (
506
+ * <BrowserTab
507
+ * key={doc.id}
508
+ * value={doc.id}
509
+ * icon={doc.icon}
510
+ * pin={doc.pinnedByUser ? "user" : undefined}
511
+ * onClose={() => closeDoc(doc.id)}
512
+ * >
513
+ * {doc.title}
514
+ * </BrowserTab>
515
+ * ))}
516
+ * </BrowserTabsList>
517
+ * <BrowserTabsContent value="home">...</BrowserTabsContent>
518
+ * {openDocs.map((doc) => (
519
+ * <BrowserTabsContent key={doc.id} value={doc.id}>
520
+ * <DocView doc={doc} />
521
+ * </BrowserTabsContent>
522
+ * ))}
523
+ * </BrowserTabs>
524
+ */
525
+ //#endregion
526
+ export { BrowserTab, BrowserTabs, TabsContent as BrowserTabsContent, BrowserTabsList };
527
+
528
+ //# sourceMappingURL=browser-tabs.js.map