@rtkelly-labs/design-system 0.0.0-bootstrap.0 → 0.16.0-dev.0.37dedac

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 (284) hide show
  1. package/CHANGELOG.md +347 -0
  2. package/LICENSE +21 -0
  3. package/README.md +317 -2
  4. package/dist/components/AlertDialog.js +95 -0
  5. package/dist/components/AlertDialog.js.map +1 -0
  6. package/dist/components/AppShell.js +261 -0
  7. package/dist/components/AppShell.js.map +1 -0
  8. package/dist/components/AsciiDivider.js +8 -0
  9. package/dist/components/AsciiDivider.js.map +1 -0
  10. package/dist/components/AsciiGauge.js +130 -0
  11. package/dist/components/AsciiGauge.js.map +1 -0
  12. package/dist/components/Avatar.js +87 -0
  13. package/dist/components/Avatar.js.map +1 -0
  14. package/dist/components/Badge.js +25 -0
  15. package/dist/components/Badge.js.map +1 -0
  16. package/dist/components/BarChart.js +288 -0
  17. package/dist/components/BarChart.js.map +1 -0
  18. package/dist/components/BracketText.js +23 -0
  19. package/dist/components/BracketText.js.map +1 -0
  20. package/dist/components/BulletChart.js +50 -0
  21. package/dist/components/BulletChart.js.map +1 -0
  22. package/dist/components/Button.js +130 -0
  23. package/dist/components/Button.js.map +1 -0
  24. package/dist/components/Card.js +181 -0
  25. package/dist/components/Card.js.map +1 -0
  26. package/dist/components/ChartTooltip.js +54 -0
  27. package/dist/components/ChartTooltip.js.map +1 -0
  28. package/dist/components/Checkbox.js +55 -0
  29. package/dist/components/Checkbox.js.map +1 -0
  30. package/dist/components/ColophonCard.js +122 -0
  31. package/dist/components/ColophonCard.js.map +1 -0
  32. package/dist/components/DataTable.js +299 -0
  33. package/dist/components/DataTable.js.map +1 -0
  34. package/dist/components/Divider.js +42 -0
  35. package/dist/components/Divider.js.map +1 -0
  36. package/dist/components/Drawer.js +81 -0
  37. package/dist/components/Drawer.js.map +1 -0
  38. package/dist/components/EmptyState.js +39 -0
  39. package/dist/components/EmptyState.js.map +1 -0
  40. package/dist/components/ErrorSummary.js +122 -0
  41. package/dist/components/ErrorSummary.js.map +1 -0
  42. package/dist/components/Fieldset.js +37 -0
  43. package/dist/components/Fieldset.js.map +1 -0
  44. package/dist/components/Glyph.js +60 -0
  45. package/dist/components/Glyph.js.map +1 -0
  46. package/dist/components/Input.js +111 -0
  47. package/dist/components/Input.js.map +1 -0
  48. package/dist/components/LinkProvider.js +76 -0
  49. package/dist/components/LinkProvider.js.map +1 -0
  50. package/dist/components/Menu.js +144 -0
  51. package/dist/components/Menu.js.map +1 -0
  52. package/dist/components/MetadataGrid.js +184 -0
  53. package/dist/components/MetadataGrid.js.map +1 -0
  54. package/dist/components/MobileNav.js +120 -0
  55. package/dist/components/MobileNav.js.map +1 -0
  56. package/dist/components/Modal.js +79 -0
  57. package/dist/components/Modal.js.map +1 -0
  58. package/dist/components/NerdIcon.js +177 -0
  59. package/dist/components/NerdIcon.js.map +1 -0
  60. package/dist/components/NoteBlock.js +84 -0
  61. package/dist/components/NoteBlock.js.map +1 -0
  62. package/dist/components/PageHeader.js +34 -0
  63. package/dist/components/PageHeader.js.map +1 -0
  64. package/dist/components/PageTitle.js +21 -0
  65. package/dist/components/PageTitle.js.map +1 -0
  66. package/dist/components/Pagination.js +96 -0
  67. package/dist/components/Pagination.js.map +1 -0
  68. package/dist/components/Popover.js +87 -0
  69. package/dist/components/Popover.js.map +1 -0
  70. package/dist/components/Progress.js +83 -0
  71. package/dist/components/Progress.js.map +1 -0
  72. package/dist/components/RadioGroup.js +74 -0
  73. package/dist/components/RadioGroup.js.map +1 -0
  74. package/dist/components/ReportDocument.js +75 -0
  75. package/dist/components/ReportDocument.js.map +1 -0
  76. package/dist/components/SectionContainer.js +18 -0
  77. package/dist/components/SectionContainer.js.map +1 -0
  78. package/dist/components/Select.js +199 -0
  79. package/dist/components/Select.js.map +1 -0
  80. package/dist/components/SiteFooter.js +29 -0
  81. package/dist/components/SiteFooter.js.map +1 -0
  82. package/dist/components/SiteHeader.js +59 -0
  83. package/dist/components/SiteHeader.js.map +1 -0
  84. package/dist/components/SiteNav.js +141 -0
  85. package/dist/components/SiteNav.js.map +1 -0
  86. package/dist/components/Skeleton.js +51 -0
  87. package/dist/components/Skeleton.js.map +1 -0
  88. package/dist/components/SocialIcon.js +77 -0
  89. package/dist/components/SocialIcon.js.map +1 -0
  90. package/dist/components/Sparkline.js +104 -0
  91. package/dist/components/Sparkline.js.map +1 -0
  92. package/dist/components/Spinner.js +65 -0
  93. package/dist/components/Spinner.js.map +1 -0
  94. package/dist/components/StatCard.js +53 -0
  95. package/dist/components/StatCard.js.map +1 -0
  96. package/dist/components/StatusPage.js +99 -0
  97. package/dist/components/StatusPage.js.map +1 -0
  98. package/dist/components/Swatch.js +55 -0
  99. package/dist/components/Swatch.js.map +1 -0
  100. package/dist/components/Switch.js +53 -0
  101. package/dist/components/Switch.js.map +1 -0
  102. package/dist/components/TLDR.js +53 -0
  103. package/dist/components/TLDR.js.map +1 -0
  104. package/dist/components/Table.js +155 -0
  105. package/dist/components/Table.js.map +1 -0
  106. package/dist/components/Tabs.js +325 -0
  107. package/dist/components/Tabs.js.map +1 -0
  108. package/dist/components/Tag.js +19 -0
  109. package/dist/components/Tag.js.map +1 -0
  110. package/dist/components/TelemetryGauge.js +112 -0
  111. package/dist/components/TelemetryGauge.js.map +1 -0
  112. package/dist/components/ThemeProvider.js +87 -0
  113. package/dist/components/ThemeProvider.js.map +1 -0
  114. package/dist/components/TickerTape.js +196 -0
  115. package/dist/components/TickerTape.js.map +1 -0
  116. package/dist/components/Toast.js +200 -0
  117. package/dist/components/Toast.js.map +1 -0
  118. package/dist/components/Tooltip.js +69 -0
  119. package/dist/components/Tooltip.js.map +1 -0
  120. package/dist/components/TrackCard.js +206 -0
  121. package/dist/components/TrackCard.js.map +1 -0
  122. package/dist/components/blog/BlogPost.js +116 -0
  123. package/dist/components/blog/BlogPost.js.map +1 -0
  124. package/dist/components/blog/LoremIpsumPost.js +62 -0
  125. package/dist/components/blog/LoremIpsumPost.js.map +1 -0
  126. package/dist/components/blog/author.js +25 -0
  127. package/dist/components/blog/author.js.map +1 -0
  128. package/dist/components/booleanControl.js +50 -0
  129. package/dist/components/booleanControl.js.map +1 -0
  130. package/dist/components/dialogPopupRef.js +28 -0
  131. package/dist/components/dialogPopupRef.js.map +1 -0
  132. package/dist/components/dialogSurface.js +75 -0
  133. package/dist/components/dialogSurface.js.map +1 -0
  134. package/dist/components/docs/AnchorHeading.js +80 -0
  135. package/dist/components/docs/AnchorHeading.js.map +1 -0
  136. package/dist/components/docs/Breadcrumbs.js +26 -0
  137. package/dist/components/docs/Breadcrumbs.js.map +1 -0
  138. package/dist/components/docs/CodeBlock.js +63 -0
  139. package/dist/components/docs/CodeBlock.js.map +1 -0
  140. package/dist/components/docs/CodeTabs.js +71 -0
  141. package/dist/components/docs/CodeTabs.js.map +1 -0
  142. package/dist/components/docs/DocPager.js +28 -0
  143. package/dist/components/docs/DocPager.js.map +1 -0
  144. package/dist/components/docs/DocsHeader.js +124 -0
  145. package/dist/components/docs/DocsHeader.js.map +1 -0
  146. package/dist/components/docs/DocsLayout.js +61 -0
  147. package/dist/components/docs/DocsLayout.js.map +1 -0
  148. package/dist/components/docs/DocsLinkProvider.js +25 -0
  149. package/dist/components/docs/DocsLinkProvider.js.map +1 -0
  150. package/dist/components/docs/DocsSidebar.js +147 -0
  151. package/dist/components/docs/DocsSidebar.js.map +1 -0
  152. package/dist/components/docs/Prose.js +56 -0
  153. package/dist/components/docs/Prose.js.map +1 -0
  154. package/dist/components/docs/TableOfContents.js +71 -0
  155. package/dist/components/docs/TableOfContents.js.map +1 -0
  156. package/dist/components/docs/codeTabsStore.js +75 -0
  157. package/dist/components/docs/codeTabsStore.js.map +1 -0
  158. package/dist/components/docs/figures/ActivityGrid.js +116 -0
  159. package/dist/components/docs/figures/ActivityGrid.js.map +1 -0
  160. package/dist/components/docs/figures/BeforeAfter.js +64 -0
  161. package/dist/components/docs/figures/BeforeAfter.js.map +1 -0
  162. package/dist/components/docs/figures/ChangeSummary.js +74 -0
  163. package/dist/components/docs/figures/ChangeSummary.js.map +1 -0
  164. package/dist/components/docs/figures/Decision.js +34 -0
  165. package/dist/components/docs/figures/Decision.js.map +1 -0
  166. package/dist/components/docs/figures/DrawingSheet.js +37 -0
  167. package/dist/components/docs/figures/DrawingSheet.js.map +1 -0
  168. package/dist/components/docs/figures/FigureFrame.js +226 -0
  169. package/dist/components/docs/figures/FigureFrame.js.map +1 -0
  170. package/dist/components/docs/figures/FileChangeTree.js +134 -0
  171. package/dist/components/docs/figures/FileChangeTree.js.map +1 -0
  172. package/dist/components/docs/figures/FlowDiagram.js +82 -0
  173. package/dist/components/docs/figures/FlowDiagram.js.map +1 -0
  174. package/dist/components/docs/figures/GanttChart.js +79 -0
  175. package/dist/components/docs/figures/GanttChart.js.map +1 -0
  176. package/dist/components/docs/figures/IndexedSection.js +45 -0
  177. package/dist/components/docs/figures/IndexedSection.js.map +1 -0
  178. package/dist/components/docs/figures/MetricStrip.js +23 -0
  179. package/dist/components/docs/figures/MetricStrip.js.map +1 -0
  180. package/dist/components/docs/figures/Steps.js +58 -0
  181. package/dist/components/docs/figures/Steps.js.map +1 -0
  182. package/dist/components/docs/figures/SwatchCompare.js +42 -0
  183. package/dist/components/docs/figures/SwatchCompare.js.map +1 -0
  184. package/dist/components/docs/figures/TermGrid.js +22 -0
  185. package/dist/components/docs/figures/TermGrid.js.map +1 -0
  186. package/dist/components/docs/figures/Terminal.js +37 -0
  187. package/dist/components/docs/figures/Terminal.js.map +1 -0
  188. package/dist/components/docs/figures/Timeline.js +61 -0
  189. package/dist/components/docs/figures/Timeline.js.map +1 -0
  190. package/dist/components/docs/figures/TokenTable.js +42 -0
  191. package/dist/components/docs/figures/TokenTable.js.map +1 -0
  192. package/dist/components/docs/figures/TreeDiagram.js +76 -0
  193. package/dist/components/docs/figures/TreeDiagram.js.map +1 -0
  194. package/dist/components/docs/figures/UptimeStrip.js +68 -0
  195. package/dist/components/docs/figures/UptimeStrip.js.map +1 -0
  196. package/dist/components/docs/figures/index.js +24 -0
  197. package/dist/components/docs/figures/index.js.map +1 -0
  198. package/dist/components/docs/index.js +15 -0
  199. package/dist/components/docs/index.js.map +1 -0
  200. package/dist/components/docs/mdxComponents.js +108 -0
  201. package/dist/components/docs/mdxComponents.js.map +1 -0
  202. package/dist/components/experiments/DesignSandbox.js +206 -0
  203. package/dist/components/experiments/DesignSandbox.js.map +1 -0
  204. package/dist/components/experiments/ExperimentsView.js +138 -0
  205. package/dist/components/experiments/ExperimentsView.js.map +1 -0
  206. package/dist/components/fieldFrame.js +200 -0
  207. package/dist/components/fieldFrame.js.map +1 -0
  208. package/dist/components/floatingSurface.js +35 -0
  209. package/dist/components/floatingSurface.js.map +1 -0
  210. package/dist/components/marketing/CTASection.js +47 -0
  211. package/dist/components/marketing/CTASection.js.map +1 -0
  212. package/dist/components/marketing/FeatureGrid.js +49 -0
  213. package/dist/components/marketing/FeatureGrid.js.map +1 -0
  214. package/dist/components/marketing/Hero.js +44 -0
  215. package/dist/components/marketing/Hero.js.map +1 -0
  216. package/dist/components/marketing/PricingGrid.js +65 -0
  217. package/dist/components/marketing/PricingGrid.js.map +1 -0
  218. package/dist/components/marketing/SectionGrid.js +51 -0
  219. package/dist/components/marketing/SectionGrid.js.map +1 -0
  220. package/dist/components/paginationRange.js +28 -0
  221. package/dist/components/paginationRange.js.map +1 -0
  222. package/dist/components/portalTheme.js +14 -0
  223. package/dist/components/portalTheme.js.map +1 -0
  224. package/dist/components/saas/SaasLandingPage.js +201 -0
  225. package/dist/components/saas/SaasLandingPage.js.map +1 -0
  226. package/dist/components/siteNavContext.js +24 -0
  227. package/dist/components/siteNavContext.js.map +1 -0
  228. package/dist/components/slides/Slide.js +84 -0
  229. package/dist/components/slides/Slide.js.map +1 -0
  230. package/dist/components/slides/SlideDeck.js +228 -0
  231. package/dist/components/slides/SlideDeck.js.map +1 -0
  232. package/dist/components/themeInitScript.js +16 -0
  233. package/dist/components/themeInitScript.js.map +1 -0
  234. package/dist/components/themeScope.js +9 -0
  235. package/dist/components/themeScope.js.map +1 -0
  236. package/dist/components/toastLifetime.js +21 -0
  237. package/dist/components/toastLifetime.js.map +1 -0
  238. package/dist/fonts/DSSymbols-OFL.txt +98 -0
  239. package/dist/fonts/DSSymbols-Regular.woff2 +0 -0
  240. package/dist/fonts/SymbolsNerdFontMono-Regular.woff2 +0 -0
  241. package/dist/hooks/useActiveHeading.js +59 -0
  242. package/dist/hooks/useActiveHeading.js.map +1 -0
  243. package/dist/hooks/useCopyToClipboard.js +58 -0
  244. package/dist/hooks/useCopyToClipboard.js.map +1 -0
  245. package/dist/index.d.ts +6394 -0
  246. package/dist/index.js +117 -0
  247. package/dist/index.js.map +1 -0
  248. package/dist/lib/accentClasses.js +87 -0
  249. package/dist/lib/accentClasses.js.map +1 -0
  250. package/dist/lib/recipe.js +33 -0
  251. package/dist/lib/recipe.js.map +1 -0
  252. package/dist/lib/slug.js +39 -0
  253. package/dist/lib/slug.js.map +1 -0
  254. package/dist/lib/theme.js +76 -0
  255. package/dist/lib/theme.js.map +1 -0
  256. package/dist/lib/tokenRules.js +51 -0
  257. package/dist/lib/tokenRules.js.map +1 -0
  258. package/dist/prose.css +766 -0
  259. package/dist/styles.css +203 -0
  260. package/dist/theme/ansi.js +77 -0
  261. package/dist/theme/ansi.js.map +1 -0
  262. package/dist/theme/contrast.js +342 -0
  263. package/dist/theme/contrast.js.map +1 -0
  264. package/dist/theme/levels.js +234 -0
  265. package/dist/theme/levels.js.map +1 -0
  266. package/dist/theme/media.js +115 -0
  267. package/dist/theme/media.js.map +1 -0
  268. package/dist/theme/recommended.js +105 -0
  269. package/dist/theme/recommended.js.map +1 -0
  270. package/dist/theme.css +538 -0
  271. package/dist/tokens.js +1 -0
  272. package/dist/tokens.js.map +1 -0
  273. package/package.json +209 -6
  274. package/skills/design-system-usage/SKILL.md +75 -0
  275. package/terminal/rtk-midnight.alacritty.toml +33 -0
  276. package/terminal/rtk-midnight.ghostty.conf +24 -0
  277. package/terminal/rtk-midnight.itermcolors +167 -0
  278. package/terminal/rtk-midnight.windows-terminal.json +23 -0
  279. package/terminal/rtk-sketch.alacritty.toml +33 -0
  280. package/terminal/rtk-sketch.ghostty.conf +24 -0
  281. package/terminal/rtk-sketch.itermcolors +167 -0
  282. package/terminal/rtk-sketch.windows-terminal.json +23 -0
  283. package/tokens/palette.midnight.tokens.json +477 -0
  284. package/tokens/palette.sketch.tokens.json +477 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/Swatch.tsx"],"sourcesContent":["import { forwardRef } from 'react';\nimport type { HTMLAttributes } from 'react';\nimport { cn } from '../lib/recipe';\n\n/**\n * Draws a colour and names it.\n *\n * This existed as a private `Swatch` inside `SemanticTokens.stories.tsx` —\n * declared there, exported nowhere, and therefore unavailable to the two places\n * that most need it: the docs portal, which #74 notes demonstrates chrome and\n * never the package's own integration, and the blog's design sandbox.\n *\n * A design system that cannot draw its own palette outside a story file is\n * asking every consumer to reimplement the one drawing it definitely owns.\n *\n * The story version used two dozen lines of inline `style` objects, which is the\n * third idiom #47 is about and is unreachable by a consumer's `className`. This\n * is utilities throughout.\n */\nexport interface SwatchProps extends Omit<HTMLAttributes<HTMLDivElement>, 'color'> {\n /** The colour to draw. Any CSS colour — usually a `var(--ds-*)` read. */\n value: string;\n /** What the colour is called. Rendered in mono beside the well. */\n name: string;\n /** Optional second line — a contrast ratio, a hex, a note. */\n detail?: string;\n /** `md` is the reference grid; `sm` suits a dense inline list. */\n size?: 'sm' | 'md';\n}\n\nexport const Swatch = forwardRef<HTMLDivElement, SwatchProps>(function Swatch(\n { value, name, detail, size = 'md', className, ...props },\n ref,\n) {\n return (\n <div\n ref={ref}\n data-slot=\"swatch\"\n className={cn('flex items-center gap-3 font-mono', className)}\n {...props}\n >\n <span\n data-slot=\"swatch-well\"\n aria-hidden=\"true\"\n className={cn(\n 'flex-none border-2 border-edge-strong',\n size === 'sm' ? 'h-6 w-6' : 'h-10 w-10',\n )}\n style={{ backgroundColor: value }}\n />\n <span data-slot=\"swatch-label\" className=\"flex min-w-0 flex-col\">\n <span className=\"truncate text-xs text-content-secondary\">{name}</span>\n {detail && <span className=\"truncate text-xs text-content-muted\">{detail}</span>}\n </span>\n </div>\n );\n});\n\nexport interface SwatchGroupProps extends HTMLAttributes<HTMLElement> {\n /** Bracketed and uppercased, matching the rest of the system's headings. */\n title: string;\n /** Name → colour. Insertion order is preserved, so declare it meaningfully. */\n entries: Record<string, string>;\n size?: SwatchProps['size'];\n}\n\n/**\n * A titled block of swatches.\n *\n * `entries` is a record rather than an array because every caller has one to\n * hand — `LEVELS[level].accent`, `semanticTokens.text`, a `palette` — and\n * turning it into an array at each call site is the kind of ceremony that gets\n * copy-pasted wrong.\n */\nexport const SwatchGroup = forwardRef<HTMLElement, SwatchGroupProps>(function SwatchGroup(\n { title, entries, size, className, ...props },\n ref,\n) {\n return (\n <section ref={ref} data-slot=\"swatch-group\" className={cn('mb-8', className)} {...props}>\n <h3\n data-slot=\"swatch-group-title\"\n className=\"mb-3 font-display text-xs font-extrabold uppercase tracking-widest text-accent-secondary\"\n >\n [ {title} ]\n </h3>\n <div data-slot=\"swatch-group-items\" className=\"grid gap-3 sm:grid-cols-2 lg:grid-cols-3\">\n {Object.entries(entries).map(([name, value]) => (\n <Swatch key={name} name={name} value={value} size={size} />\n ))}\n </div>\n </section>\n );\n});\n"],"mappings":";AAAA,SAAS,kBAAkB;AAE3B,SAAS,UAAU;AAuCb,cASA,YATA;AAXC,IAAM,SAAS,WAAwC,SAASA,QACrE,EAAE,OAAO,MAAM,QAAQ,OAAO,MAAM,WAAW,GAAG,MAAM,GACxD,KACA;AACA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,aAAU;AAAA,MACV,WAAW,GAAG,qCAAqC,SAAS;AAAA,MAC3D,GAAG;AAAA,MAEJ;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,aAAU;AAAA,YACV,eAAY;AAAA,YACZ,WAAW;AAAA,cACT;AAAA,cACA,SAAS,OAAO,YAAY;AAAA,YAC9B;AAAA,YACA,OAAO,EAAE,iBAAiB,MAAM;AAAA;AAAA,QAClC;AAAA,QACA,qBAAC,UAAK,aAAU,gBAAe,WAAU,yBACvC;AAAA,8BAAC,UAAK,WAAU,2CAA2C,gBAAK;AAAA,UAC/D,UAAU,oBAAC,UAAK,WAAU,uCAAuC,kBAAO;AAAA,WAC3E;AAAA;AAAA;AAAA,EACF;AAEJ,CAAC;AAkBM,IAAM,cAAc,WAA0C,SAASC,aAC5E,EAAE,OAAO,SAAS,MAAM,WAAW,GAAG,MAAM,GAC5C,KACA;AACA,SACE,qBAAC,aAAQ,KAAU,aAAU,gBAAe,WAAW,GAAG,QAAQ,SAAS,GAAI,GAAG,OAChF;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,aAAU;AAAA,QACV,WAAU;AAAA,QACX;AAAA;AAAA,UACI;AAAA,UAAM;AAAA;AAAA;AAAA,IACX;AAAA,IACA,oBAAC,SAAI,aAAU,sBAAqB,WAAU,4CAC3C,iBAAO,QAAQ,OAAO,EAAE,IAAI,CAAC,CAAC,MAAM,KAAK,MACxC,oBAAC,UAAkB,MAAY,OAAc,QAAhC,IAA4C,CAC1D,GACH;AAAA,KACF;AAEJ,CAAC;","names":["Swatch","SwatchGroup"]}
@@ -0,0 +1,53 @@
1
+ "use client";
2
+
3
+ // src/components/Switch.tsx
4
+ import { forwardRef } from "react";
5
+ import { Switch as BaseSwitch } from "@base-ui/react/switch";
6
+ import { cn } from "../lib/recipe.js";
7
+ import { booleanControl } from "./booleanControl.js";
8
+ import { FieldFrame, accentStyle } from "./fieldFrame.js";
9
+ import { jsx } from "react/jsx-runtime";
10
+ var Switch = forwardRef(function Switch2({
11
+ label,
12
+ error,
13
+ helperText,
14
+ accent = "primary",
15
+ className = "",
16
+ style,
17
+ checked,
18
+ defaultChecked,
19
+ onCheckedChange,
20
+ name,
21
+ value,
22
+ disabled,
23
+ readOnly,
24
+ required,
25
+ id,
26
+ ...props
27
+ }, ref) {
28
+ const styles = booleanControl({ shape: "track" });
29
+ return /* @__PURE__ */ jsx(FieldFrame, { label, error, helperText, disabled, layout: "inline", children: /* @__PURE__ */ jsx(
30
+ BaseSwitch.Root,
31
+ {
32
+ ref,
33
+ id,
34
+ name,
35
+ value,
36
+ checked,
37
+ defaultChecked,
38
+ disabled,
39
+ readOnly,
40
+ required,
41
+ onCheckedChange: (next) => onCheckedChange?.(next),
42
+ "data-slot": "switch",
43
+ style: accentStyle(accent, style),
44
+ className: cn(styles.control(), className),
45
+ ...props,
46
+ children: /* @__PURE__ */ jsx(BaseSwitch.Thumb, { "data-slot": "switch-thumb", className: styles.mark() })
47
+ }
48
+ ) });
49
+ });
50
+ export {
51
+ Switch
52
+ };
53
+ //# sourceMappingURL=Switch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/Switch.tsx"],"sourcesContent":["'use client';\n\nimport { forwardRef } from 'react';\nimport { Switch as BaseSwitch } from '@base-ui/react/switch';\nimport { cn } from '../lib/recipe';\nimport { booleanControl } from './booleanControl';\nimport { FieldFrame, accentStyle } from './fieldFrame';\nimport type { BooleanFieldProps } from './fieldFrame';\n\nexport interface SwitchProps extends BooleanFieldProps {}\n\n/**\n * A switch, with its label, description and error as one unit.\n *\n * The same boolean `Checkbox` carries, in the presentation that says *this\n * takes effect now*: a setting being turned on, not an answer being collected.\n * Pick by when the change lands, not by how it looks — a switch inside a form\n * that only applies on submit is a checkbox drawn misleadingly.\n *\n * There is no indeterminate switch, deliberately. A track has two ends and a\n * third state has nowhere to sit; a tri-state answer is a `Checkbox`.\n *\n * It composes the same `Field` as every other control here —\n * `SwitchRootState extends FieldRootState` — so `error`, `disabled`,\n * `required` and the description behave exactly as they do on `Input`, and\n * form participation is Base UI's hidden input rather than one written here.\n *\n * ```tsx\n * <Switch name=\"telemetry\" label=\"Send anonymous telemetry\" defaultChecked />\n * ```\n */\nexport const Switch = forwardRef<HTMLSpanElement, SwitchProps>(function Switch(\n {\n label,\n error,\n helperText,\n accent = 'primary',\n className = '',\n style,\n checked,\n defaultChecked,\n onCheckedChange,\n name,\n value,\n disabled,\n readOnly,\n required,\n id,\n ...props\n },\n ref,\n) {\n const styles = booleanControl({ shape: 'track' });\n\n return (\n <FieldFrame label={label} error={error} helperText={helperText} disabled={disabled} layout=\"inline\">\n <BaseSwitch.Root\n ref={ref}\n id={id}\n name={name}\n value={value}\n checked={checked}\n defaultChecked={defaultChecked}\n disabled={disabled}\n readOnly={readOnly}\n required={required}\n // The event details Base UI passes second are dropped here for the same\n // reason `Checkbox` drops them: they are a Base UI type, and the\n // published surface names none.\n onCheckedChange={(next) => onCheckedChange?.(next)}\n data-slot=\"switch\"\n style={accentStyle(accent, style)}\n // `cn`, for the reason `Checkbox` states: the merge is what makes a\n // caller's utility replace the recipe's rather than race it.\n className={cn(styles.control(), className)}\n {...props}\n >\n <BaseSwitch.Thumb data-slot=\"switch-thumb\" className={styles.mark()} />\n </BaseSwitch.Root>\n </FieldFrame>\n );\n});\n"],"mappings":";;;AAEA,SAAS,kBAAkB;AAC3B,SAAS,UAAU,kBAAkB;AACrC,SAAS,UAAU;AACnB,SAAS,sBAAsB;AAC/B,SAAS,YAAY,mBAAmB;AAuEhC;AA9CD,IAAM,SAAS,WAAyC,SAASA,QACtE;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA,SAAS;AAAA,EACT,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GACA,KACA;AACA,QAAM,SAAS,eAAe,EAAE,OAAO,QAAQ,CAAC;AAEhD,SACE,oBAAC,cAAW,OAAc,OAAc,YAAwB,UAAoB,QAAO,UACzF;AAAA,IAAC,WAAW;AAAA,IAAX;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MAIA,iBAAiB,CAAC,SAAS,kBAAkB,IAAI;AAAA,MACjD,aAAU;AAAA,MACV,OAAO,YAAY,QAAQ,KAAK;AAAA,MAGhC,WAAW,GAAG,OAAO,QAAQ,GAAG,SAAS;AAAA,MACxC,GAAG;AAAA,MAEJ,8BAAC,WAAW,OAAX,EAAiB,aAAU,gBAAe,WAAW,OAAO,KAAK,GAAG;AAAA;AAAA,EACvE,GACF;AAEJ,CAAC;","names":["Switch"]}
@@ -0,0 +1,53 @@
1
+ // src/components/TLDR.tsx
2
+ import { Zap } from "lucide-react";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ var TLDR = ({ children }) => {
5
+ return /* @__PURE__ */ jsxs(
6
+ "div",
7
+ {
8
+ "data-slot": "tldr",
9
+ style: {
10
+ margin: "2rem 0",
11
+ padding: "1.5rem",
12
+ border: "2px solid var(--ds-accent-secondary)",
13
+ backgroundColor: "var(--ds-surface-base)",
14
+ boxShadow: "6px 6px 0px 0px var(--ds-accent-secondary)"
15
+ },
16
+ children: [
17
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "0.5rem", marginBottom: "0.75rem" }, children: [
18
+ /* @__PURE__ */ jsx(Zap, { size: 20, color: "var(--ds-accent-secondary)" }),
19
+ /* @__PURE__ */ jsx(
20
+ "span",
21
+ {
22
+ style: {
23
+ fontFamily: "var(--ds-font-display)",
24
+ fontWeight: 800,
25
+ fontSize: "1rem",
26
+ textTransform: "uppercase",
27
+ color: "var(--ds-accent-secondary)"
28
+ },
29
+ children: "[ TL;DR ]"
30
+ }
31
+ )
32
+ ] }),
33
+ /* @__PURE__ */ jsx(
34
+ "div",
35
+ {
36
+ style: {
37
+ fontFamily: "var(--ds-font-body)",
38
+ fontSize: "1rem",
39
+ fontWeight: 500,
40
+ color: "var(--ds-text-primary)",
41
+ lineHeight: 1.6
42
+ },
43
+ children
44
+ }
45
+ )
46
+ ]
47
+ }
48
+ );
49
+ };
50
+ export {
51
+ TLDR
52
+ };
53
+ //# sourceMappingURL=TLDR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/TLDR.tsx"],"sourcesContent":["import type React from 'react';\nimport { Zap } from 'lucide-react';\n\nexport interface TLDRProps {\n children: React.ReactNode;\n}\n\nexport const TLDR: React.FC<TLDRProps> = ({ children }) => {\n return (\n <div\n data-slot=\"tldr\"\n style={{\n margin: '2rem 0',\n padding: '1.5rem',\n border: '2px solid var(--ds-accent-secondary)',\n backgroundColor: 'var(--ds-surface-base)',\n boxShadow: '6px 6px 0px 0px var(--ds-accent-secondary)',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem', marginBottom: '0.75rem' }}>\n <Zap size={20} color=\"var(--ds-accent-secondary)\" />\n <span\n style={{\n fontFamily: 'var(--ds-font-display)',\n fontWeight: 800,\n fontSize: '1rem',\n textTransform: 'uppercase',\n color: 'var(--ds-accent-secondary)',\n }}\n >\n [ TL;DR ]\n </span>\n </div>\n <div\n style={{\n fontFamily: 'var(--ds-font-body)',\n fontSize: '1rem',\n fontWeight: 500,\n color: 'var(--ds-text-primary)',\n lineHeight: 1.6,\n }}\n >\n {children}\n </div>\n </div>\n );\n};\n"],"mappings":";AACA,SAAS,WAAW;AAkBd,SACE,KADF;AAZC,IAAM,OAA4B,CAAC,EAAE,SAAS,MAAM;AACzD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,OAAO;AAAA,QACL,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,QAAQ;AAAA,QACR,iBAAiB;AAAA,QACjB,WAAW;AAAA,MACb;AAAA,MAEA;AAAA,6BAAC,SAAI,OAAO,EAAE,SAAS,QAAQ,YAAY,UAAU,KAAK,UAAU,cAAc,UAAU,GAC1F;AAAA,8BAAC,OAAI,MAAM,IAAI,OAAM,8BAA6B;AAAA,UAClD;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,gBACL,YAAY;AAAA,gBACZ,YAAY;AAAA,gBACZ,UAAU;AAAA,gBACV,eAAe;AAAA,gBACf,OAAO;AAAA,cACT;AAAA,cACD;AAAA;AAAA,UAED;AAAA,WACF;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,YAAY;AAAA,cACZ,UAAU;AAAA,cACV,YAAY;AAAA,cACZ,OAAO;AAAA,cACP,YAAY;AAAA,YACd;AAAA,YAEC;AAAA;AAAA,QACH;AAAA;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -0,0 +1,155 @@
1
+ "use client";
2
+
3
+ // src/components/Table.tsx
4
+ import {
5
+ createContext,
6
+ useContext
7
+ } from "react";
8
+ import { recipe } from "../lib/recipe.js";
9
+ import { jsx } from "react/jsx-runtime";
10
+ var DEFAULT_PRESENTATION = {
11
+ appearance: "grid",
12
+ density: "comfortable"
13
+ };
14
+ var TablePresentationContext = createContext(DEFAULT_PRESENTATION);
15
+ function useTablePresentation() {
16
+ return useContext(TablePresentationContext);
17
+ }
18
+ var tableStyles = recipe({
19
+ slots: {
20
+ container: "relative w-full overflow-x-auto border-2 border-edge-strong bg-surface-base",
21
+ table: "w-full caption-bottom text-left font-mono text-sm border-collapse",
22
+ header: "bg-surface-raised border-b-2 border-edge-strong",
23
+ head: "h-11 px-4 py-3 text-left align-middle font-display text-xs font-bold uppercase tracking-wider text-accent-primary border-r-2 border-edge-strong last:border-r-0",
24
+ rowHead: "px-4 py-3 text-left align-middle text-sm font-bold text-content-primary border-r-2 border-edge-strong last:border-r-0",
25
+ body: "divide-y-2 divide-edge-strong [&_tr:last-child]:border-0",
26
+ row: "border-b-2 border-edge-strong transition-colors hover:bg-surface-raised data-[state=selected]:bg-surface-raised",
27
+ cell: "px-4 py-3 align-middle text-sm text-content-primary border-r-2 border-edge-strong last:border-r-0",
28
+ footer: "bg-surface-raised border-t-2 border-edge-strong font-mono text-xs font-bold text-content-primary",
29
+ caption: "mt-3 text-xs font-mono text-content-muted text-center"
30
+ },
31
+ variants: {
32
+ appearance: {
33
+ grid: {},
34
+ quiet: {
35
+ container: "border-0 bg-transparent",
36
+ header: "bg-transparent border-b border-edge-subtle",
37
+ head: "text-content-secondary border-r-0",
38
+ rowHead: "border-r-0",
39
+ body: "divide-y divide-edge-subtle",
40
+ row: "border-b border-edge-subtle",
41
+ cell: "border-r-0",
42
+ footer: "bg-transparent border-t border-edge-subtle",
43
+ caption: "text-left"
44
+ },
45
+ index: {
46
+ container: "border-0 bg-transparent",
47
+ header: "bg-transparent border-b border-edge-subtle",
48
+ head: "text-content-secondary border-r-0",
49
+ rowHead: "border-l-2 border-accent-primary border-r-0 pl-3",
50
+ body: "divide-y divide-edge-subtle",
51
+ row: "border-b border-edge-subtle",
52
+ cell: "border-r-0",
53
+ footer: "bg-transparent border-t border-edge-subtle",
54
+ caption: "text-left"
55
+ }
56
+ },
57
+ density: {
58
+ comfortable: {},
59
+ compact: {
60
+ head: "h-9 px-3 py-2",
61
+ rowHead: "px-3 py-1.5",
62
+ cell: "px-3 py-1.5",
63
+ caption: "mt-2"
64
+ }
65
+ }
66
+ },
67
+ defaultVariants: {
68
+ appearance: "grid",
69
+ density: "comfortable"
70
+ }
71
+ });
72
+ function Table({
73
+ className,
74
+ containerClassName,
75
+ label = "Table",
76
+ appearance = "grid",
77
+ density = "comfortable",
78
+ ...props
79
+ }) {
80
+ const presentation = { appearance, density };
81
+ const styles = tableStyles(presentation);
82
+ return /* @__PURE__ */ jsx(TablePresentationContext.Provider, { value: presentation, children: /* @__PURE__ */ jsx(
83
+ "div",
84
+ {
85
+ "data-slot": "table-container",
86
+ tabIndex: 0,
87
+ role: "region",
88
+ "aria-label": label,
89
+ className: styles.container({ class: containerClassName }),
90
+ children: /* @__PURE__ */ jsx("table", { "data-slot": "table", className: styles.table({ class: className }), ...props })
91
+ }
92
+ ) });
93
+ }
94
+ function TableHeader({
95
+ className,
96
+ ...props
97
+ }) {
98
+ const styles = tableStyles(useTablePresentation());
99
+ return /* @__PURE__ */ jsx("thead", { "data-slot": "table-header", className: styles.header({ class: className }), ...props });
100
+ }
101
+ function TableBody({
102
+ className,
103
+ ...props
104
+ }) {
105
+ const styles = tableStyles(useTablePresentation());
106
+ return /* @__PURE__ */ jsx("tbody", { "data-slot": "table-body", className: styles.body({ class: className }), ...props });
107
+ }
108
+ function TableFooter({
109
+ className,
110
+ ...props
111
+ }) {
112
+ const styles = tableStyles(useTablePresentation());
113
+ return /* @__PURE__ */ jsx("tfoot", { "data-slot": "table-footer", className: styles.footer({ class: className }), ...props });
114
+ }
115
+ function TableRow({
116
+ className,
117
+ ...props
118
+ }) {
119
+ const styles = tableStyles(useTablePresentation());
120
+ return /* @__PURE__ */ jsx("tr", { "data-slot": "table-row", className: styles.row({ class: className }), ...props });
121
+ }
122
+ function TableHead({
123
+ className,
124
+ scope = "col",
125
+ ...props
126
+ }) {
127
+ const styles = tableStyles(useTablePresentation());
128
+ const slot = scope === "row" || scope === "rowgroup" ? styles.rowHead : styles.head;
129
+ return /* @__PURE__ */ jsx("th", { "data-slot": "table-head", scope, className: slot({ class: className }), ...props });
130
+ }
131
+ function TableCell({
132
+ className,
133
+ ...props
134
+ }) {
135
+ const styles = tableStyles(useTablePresentation());
136
+ return /* @__PURE__ */ jsx("td", { "data-slot": "table-cell", className: styles.cell({ class: className }), ...props });
137
+ }
138
+ function TableCaption({
139
+ className,
140
+ ...props
141
+ }) {
142
+ const styles = tableStyles(useTablePresentation());
143
+ return /* @__PURE__ */ jsx("caption", { "data-slot": "table-caption", className: styles.caption({ class: className }), ...props });
144
+ }
145
+ export {
146
+ Table,
147
+ TableBody,
148
+ TableCaption,
149
+ TableCell,
150
+ TableFooter,
151
+ TableHead,
152
+ TableHeader,
153
+ TableRow
154
+ };
155
+ //# sourceMappingURL=Table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/Table.tsx"],"sourcesContent":["'use client';\n\n\nimport {\n createContext,\n useContext,\n type HTMLAttributes,\n type TableHTMLAttributes,\n type TdHTMLAttributes,\n type ThHTMLAttributes,\n} from 'react';\nimport { cn, recipe } from '../lib/recipe';\n\n/** The visual treatment of a table. `grid` preserves the original framed style. */\nexport type TableAppearance = 'grid' | 'quiet' | 'index';\n\n/** Cell spacing for roomy reading or dense reference data. */\nexport type TableDensity = 'comfortable' | 'compact';\n\ninterface TablePresentation {\n appearance: TableAppearance;\n density: TableDensity;\n}\n\nconst DEFAULT_PRESENTATION: TablePresentation = {\n appearance: 'grid',\n density: 'comfortable',\n};\n\nconst TablePresentationContext = createContext<TablePresentation>(DEFAULT_PRESENTATION);\n\nfunction useTablePresentation() {\n return useContext(TablePresentationContext);\n}\n\nconst tableStyles = recipe({\n slots: {\n container: 'relative w-full overflow-x-auto border-2 border-edge-strong bg-surface-base',\n table: 'w-full caption-bottom text-left font-mono text-sm border-collapse',\n header: 'bg-surface-raised border-b-2 border-edge-strong',\n head: 'h-11 px-4 py-3 text-left align-middle font-display text-xs font-bold uppercase tracking-wider text-accent-primary border-r-2 border-edge-strong last:border-r-0',\n rowHead: 'px-4 py-3 text-left align-middle text-sm font-bold text-content-primary border-r-2 border-edge-strong last:border-r-0',\n body: 'divide-y-2 divide-edge-strong [&_tr:last-child]:border-0',\n row: 'border-b-2 border-edge-strong transition-colors hover:bg-surface-raised data-[state=selected]:bg-surface-raised',\n cell: 'px-4 py-3 align-middle text-sm text-content-primary border-r-2 border-edge-strong last:border-r-0',\n footer: 'bg-surface-raised border-t-2 border-edge-strong font-mono text-xs font-bold text-content-primary',\n caption: 'mt-3 text-xs font-mono text-content-muted text-center',\n },\n variants: {\n appearance: {\n grid: {},\n quiet: {\n container: 'border-0 bg-transparent',\n header: 'bg-transparent border-b border-edge-subtle',\n head: 'text-content-secondary border-r-0',\n rowHead: 'border-r-0',\n body: 'divide-y divide-edge-subtle',\n row: 'border-b border-edge-subtle',\n cell: 'border-r-0',\n footer: 'bg-transparent border-t border-edge-subtle',\n caption: 'text-left',\n },\n index: {\n container: 'border-0 bg-transparent',\n header: 'bg-transparent border-b border-edge-subtle',\n head: 'text-content-secondary border-r-0',\n rowHead: 'border-l-2 border-accent-primary border-r-0 pl-3',\n body: 'divide-y divide-edge-subtle',\n row: 'border-b border-edge-subtle',\n cell: 'border-r-0',\n footer: 'bg-transparent border-t border-edge-subtle',\n caption: 'text-left',\n },\n },\n density: {\n comfortable: {},\n compact: {\n head: 'h-9 px-3 py-2',\n rowHead: 'px-3 py-1.5',\n cell: 'px-3 py-1.5',\n caption: 'mt-2',\n },\n },\n },\n defaultVariants: {\n appearance: 'grid',\n density: 'comfortable',\n },\n});\n\nexport function Table({\n className,\n containerClassName,\n label = 'Table',\n appearance = 'grid',\n density = 'comfortable',\n ...props\n}: TableHTMLAttributes<HTMLTableElement> & {\n containerClassName?: string;\n /**\n * Names the scrollable region a keyboard user lands on before the table\n * itself. Defaults to `Table`, which is honest but uninformative — pass the\n * table's subject where it is known.\n */\n label?: string;\n /**\n * `grid` keeps the framed default, `quiet` removes the full cell grid, and\n * `index` adds a keyline to row headers for catalog-style scanning.\n */\n appearance?: TableAppearance;\n /**\n * `comfortable` preserves the existing cell spacing. `compact` reduces it\n * for reference tables with many rows.\n */\n density?: TableDensity;\n}) {\n const presentation = { appearance, density };\n const styles = tableStyles(presentation);\n /*\n * `tabIndex={0}` on the container because it is `overflow-x-auto`: any table\n * wider than its column becomes a scrollable region, and a scrollable region\n * that cannot take focus cannot be scrolled by keyboard at all — axe's\n * `scrollable-region-focusable`, and a real trap rather than a technicality,\n * since the columns off the right edge are then reachable only with a\n * pointer. `CodeBlock` carries the same attribute for the same reason.\n *\n * `role=\"region\"` and a name come with it, and not only to satisfy\n * `jsx-a11y/no-noninteractive-tabindex`, which is at budget 0. The two rules\n * are asking for the same thing from opposite ends: axe wants the scroll\n * container reachable, jsx-a11y wants anything focusable to be worth\n * landing on. A focus stop a screen reader announces as nothing is the\n * thing jsx-a11y is right about, so the region is named. `CodeBlock`\n * settled on exactly this pair for exactly this reason.\n *\n * `label` exists so the name can be the table's own — \"Failing checks\"\n * rather than \"Table\" — for the callers that know it.\n */\n return (\n <TablePresentationContext.Provider value={presentation}>\n <div\n data-slot=\"table-container\"\n tabIndex={0}\n role=\"region\"\n aria-label={label}\n className={styles.container({ class: containerClassName })}\n >\n <table data-slot=\"table\" className={styles.table({ class: className })} {...props} />\n </div>\n </TablePresentationContext.Provider>\n );\n}\n\nexport function TableHeader({\n className,\n ...props\n}: HTMLAttributes<HTMLTableSectionElement>) {\n const styles = tableStyles(useTablePresentation());\n return <thead data-slot=\"table-header\" className={styles.header({ class: className })} {...props} />;\n}\n\nexport function TableBody({\n className,\n ...props\n}: HTMLAttributes<HTMLTableSectionElement>) {\n const styles = tableStyles(useTablePresentation());\n return <tbody data-slot=\"table-body\" className={styles.body({ class: className })} {...props} />;\n}\n\nexport function TableFooter({\n className,\n ...props\n}: HTMLAttributes<HTMLTableSectionElement>) {\n const styles = tableStyles(useTablePresentation());\n return <tfoot data-slot=\"table-footer\" className={styles.footer({ class: className })} {...props} />;\n}\n\nexport function TableRow({\n className,\n ...props\n}: HTMLAttributes<HTMLTableRowElement>) {\n const styles = tableStyles(useTablePresentation());\n return <tr data-slot=\"table-row\" className={styles.row({ class: className })} {...props} />;\n}\n\n/**\n * A header cell. `scope` defaults to `col`, which is what a cell in\n * `TableHeader` is; pass `scope=\"row\"` for a row header in `TableBody`, which\n * also gives it the body cell's geometry rather than the column header's.\n */\nexport function TableHead({\n className,\n scope = 'col',\n ...props\n}: ThHTMLAttributes<HTMLTableCellElement>) {\n const styles = tableStyles(useTablePresentation());\n const slot = scope === 'row' || scope === 'rowgroup' ? styles.rowHead : styles.head;\n return <th data-slot=\"table-head\" scope={scope} className={slot({ class: className })} {...props} />;\n}\n\nexport function TableCell({\n className,\n ...props\n}: TdHTMLAttributes<HTMLTableCellElement>) {\n const styles = tableStyles(useTablePresentation());\n return <td data-slot=\"table-cell\" className={styles.cell({ class: className })} {...props} />;\n}\n\nexport function TableCaption({\n className,\n ...props\n}: HTMLAttributes<HTMLTableCaptionElement>) {\n const styles = tableStyles(useTablePresentation());\n return <caption data-slot=\"table-caption\" className={styles.caption({ class: className })} {...props} />;\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,325 @@
1
+ "use client";
2
+
3
+ // src/components/Tabs.tsx
4
+ import { createContext, forwardRef, useCallback, useContext, useId, useMemo, useState } from "react";
5
+ import { cn, recipe } from "../lib/recipe.js";
6
+ import { accentVar } from "../lib/theme.js";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ var tabs_ = recipe({
9
+ slots: {
10
+ // The root owns no spacing: a page margin is the caller's decision, and
11
+ // `CodeTabs` supplies its own `my-6`.
12
+ root: "",
13
+ strip: "relative z-10 flex border-2 border-edge-strong",
14
+ caption: "truncate text-xs text-content-secondary",
15
+ list: "flex items-end",
16
+ tab: "shrink-0 whitespace-nowrap transition-colors focus-visible:ring-2 focus-visible:ring-[var(--tabs-accent)] focus-visible:ring-inset"
17
+ },
18
+ variants: {
19
+ font: {
20
+ sans: {
21
+ tab: "font-sans text-sm font-semibold tracking-normal normal-case",
22
+ caption: "font-sans text-xs font-semibold uppercase tracking-wider"
23
+ },
24
+ mono: {
25
+ tab: "font-mono text-xs font-bold uppercase tracking-widest",
26
+ caption: "font-mono text-xs font-bold uppercase tracking-widest"
27
+ }
28
+ },
29
+ variant: {
30
+ // The loudest: a solid accent tab standing on the panel, its bottom rule
31
+ // dropped so the fill runs into what it labels.
32
+ merged: {
33
+ strip: "items-end overflow-x-auto bg-surface-raised px-1.5 pt-1.5",
34
+ list: "gap-1",
35
+ tab: "-mb-0.5 border-2 px-4 py-2"
36
+ },
37
+ // The quietest: no tab shapes, a 4px accent rule on the seam.
38
+ underline: {
39
+ strip: "items-end overflow-x-auto bg-surface-base px-3 pt-2",
40
+ list: "gap-1",
41
+ tab: "-mb-0.5 border-b-4 px-4 py-2.5"
42
+ },
43
+ // A title bar with a caption slot; the tabs are a segmented control.
44
+ segmented: {
45
+ strip: "items-center justify-between gap-4 bg-surface-raised px-3 py-2.5",
46
+ list: "gap-0 border-2 border-edge-strong",
47
+ tab: "border-r-2 border-edge-strong px-4 py-2 last:border-r-0"
48
+ }
49
+ },
50
+ /*
51
+ * `horizontal` adds nothing on purpose.
52
+ *
53
+ * Every class the horizontal strip renders is the class `CodeTabs` rendered
54
+ * before the extraction, which is what lets its committed baselines stay
55
+ * valid. The vertical set turns the strip on its side and moves each
56
+ * variant's edge treatment from the bottom of a tab to its trailing side.
57
+ */
58
+ orientation: {
59
+ horizontal: {},
60
+ vertical: {
61
+ root: "flex items-start",
62
+ strip: "flex-col items-stretch self-stretch overflow-x-visible",
63
+ list: "flex-col items-stretch",
64
+ tab: "w-full text-left"
65
+ }
66
+ },
67
+ selected: {
68
+ true: {},
69
+ false: {}
70
+ }
71
+ },
72
+ defaultVariants: {
73
+ font: "sans",
74
+ variant: "merged",
75
+ orientation: "horizontal",
76
+ selected: false
77
+ },
78
+ compoundVariants: [
79
+ {
80
+ variant: "merged",
81
+ selected: true,
82
+ class: {
83
+ tab: "relative z-10 border-edge-strong border-b-0 bg-[var(--tabs-accent)] text-content-inverse"
84
+ }
85
+ },
86
+ {
87
+ variant: "merged",
88
+ selected: false,
89
+ class: {
90
+ tab: "border-transparent text-content-muted hover:border-edge-strong hover:text-content-primary"
91
+ }
92
+ },
93
+ {
94
+ variant: "underline",
95
+ selected: true,
96
+ class: { tab: "border-b-[var(--tabs-accent)] text-content-primary" }
97
+ },
98
+ {
99
+ variant: "underline",
100
+ selected: false,
101
+ class: { tab: "border-b-transparent text-content-muted hover:text-content-primary" }
102
+ },
103
+ {
104
+ variant: "segmented",
105
+ selected: true,
106
+ class: { tab: "bg-[var(--tabs-accent)] text-content-inverse" }
107
+ },
108
+ {
109
+ variant: "segmented",
110
+ selected: false,
111
+ class: { tab: "bg-surface-base text-content-muted hover:text-content-primary" }
112
+ },
113
+ // Vertical: the seam a variant draws along the bottom of a tab moves to its
114
+ // trailing edge, so the strip reads as a column rather than a row that has
115
+ // been rotated and left with a dangling rule.
116
+ { variant: "merged", orientation: "vertical", class: { tab: "mb-0 -mr-0.5" } },
117
+ {
118
+ variant: "merged",
119
+ orientation: "vertical",
120
+ selected: true,
121
+ class: { tab: "border-b-2 border-r-0" }
122
+ },
123
+ {
124
+ variant: "underline",
125
+ orientation: "vertical",
126
+ class: { tab: "mb-0 border-b-0 border-r-4" }
127
+ },
128
+ {
129
+ variant: "underline",
130
+ orientation: "vertical",
131
+ selected: true,
132
+ class: { tab: "border-r-[var(--tabs-accent)]" }
133
+ },
134
+ {
135
+ variant: "underline",
136
+ orientation: "vertical",
137
+ selected: false,
138
+ class: { tab: "border-r-transparent" }
139
+ },
140
+ {
141
+ variant: "segmented",
142
+ orientation: "vertical",
143
+ class: { tab: "border-b-2 border-r-0 last:border-b-0" }
144
+ }
145
+ ]
146
+ });
147
+ var TabsContext = createContext(null);
148
+ function useTabsContext(part) {
149
+ const context = useContext(TabsContext);
150
+ if (!context) {
151
+ throw new Error(`<${part}> must be rendered inside <Tabs>.`);
152
+ }
153
+ return context;
154
+ }
155
+ function idPart(value) {
156
+ return encodeURIComponent(value);
157
+ }
158
+ var Tabs = forwardRef(function Tabs2({
159
+ value,
160
+ defaultValue,
161
+ onValueChange,
162
+ orientation = "horizontal",
163
+ variant = "merged",
164
+ font = "sans",
165
+ accent = "primary",
166
+ children,
167
+ className,
168
+ style,
169
+ ...props
170
+ }, ref) {
171
+ const uid = useId();
172
+ const [uncontrolled, setUncontrolled] = useState(defaultValue ?? "");
173
+ const selected = value ?? uncontrolled;
174
+ const select = useCallback(
175
+ (next) => {
176
+ if (value === void 0) setUncontrolled(next);
177
+ onValueChange?.(next);
178
+ },
179
+ [value, onValueChange]
180
+ );
181
+ const context = useMemo(
182
+ () => ({
183
+ value: selected,
184
+ select,
185
+ orientation,
186
+ variant,
187
+ font,
188
+ tabId: (v) => `${uid}-tab-${idPart(v)}`,
189
+ panelId: (v) => `${uid}-panel-${idPart(v)}`
190
+ }),
191
+ [selected, select, orientation, variant, font, uid]
192
+ );
193
+ const styles = tabs_({ variant, orientation, font });
194
+ const accented = { "--tabs-accent": accentVar(accent), ...style };
195
+ return /* @__PURE__ */ jsx(TabsContext.Provider, { value: context, children: /* @__PURE__ */ jsx(
196
+ "div",
197
+ {
198
+ ref,
199
+ ...props,
200
+ "data-slot": "tabs",
201
+ "data-orientation": orientation,
202
+ className: cn(styles.root(), className),
203
+ style: accented,
204
+ children
205
+ }
206
+ ) });
207
+ });
208
+ function moveBetweenTabs(event, orientation, select) {
209
+ const current = event.currentTarget;
210
+ const tablist = current.closest('[role="tablist"]');
211
+ if (!tablist) return;
212
+ const strip = tablist.querySelectorAll('[role="tab"]:not(:disabled)');
213
+ const list = Array.from(strip);
214
+ const index = list.indexOf(current);
215
+ if (index === -1) return;
216
+ const [back, forward] = orientation === "vertical" ? ["ArrowUp", "ArrowDown"] : ["ArrowLeft", "ArrowRight"];
217
+ const last = list.length - 1;
218
+ const next = event.key === forward ? index === last ? 0 : index + 1 : event.key === back ? index === 0 ? last : index - 1 : event.key === "Home" ? 0 : event.key === "End" ? last : null;
219
+ if (next === null) return;
220
+ event.preventDefault();
221
+ const target = list[next];
222
+ if (!target) return;
223
+ const value = target.dataset.value;
224
+ if (value !== void 0) select(value);
225
+ target.focus();
226
+ }
227
+ var TabsList = forwardRef(function TabsList2({
228
+ label,
229
+ caption,
230
+ children,
231
+ className,
232
+ "aria-label": ariaLabel,
233
+ "aria-labelledby": ariaLabelledBy,
234
+ ...props
235
+ }, ref) {
236
+ const { orientation, variant, font } = useTabsContext("TabsList");
237
+ const styles = tabs_({ variant, orientation, font });
238
+ return /* @__PURE__ */ jsxs(
239
+ "div",
240
+ {
241
+ ref,
242
+ ...props,
243
+ "data-slot": "tabs-list",
244
+ className: cn(styles.strip(), className),
245
+ children: [
246
+ caption ? /* @__PURE__ */ jsx("span", { "data-slot": "tabs-caption", className: styles.caption(), children: caption }) : null,
247
+ /* @__PURE__ */ jsx(
248
+ "div",
249
+ {
250
+ role: "tablist",
251
+ "aria-label": label ?? ariaLabel,
252
+ "aria-labelledby": ariaLabelledBy,
253
+ "aria-orientation": orientation === "vertical" ? "vertical" : void 0,
254
+ "data-orientation": orientation,
255
+ className: styles.list(),
256
+ children
257
+ }
258
+ )
259
+ ]
260
+ }
261
+ );
262
+ });
263
+ var TabsTab = forwardRef(function TabsTab2({ value, children, className, onClick, onKeyDown, ...props }, ref) {
264
+ const context = useTabsContext("TabsTab");
265
+ const selected = context.value === value;
266
+ const styles = tabs_({
267
+ variant: context.variant,
268
+ orientation: context.orientation,
269
+ font: context.font,
270
+ selected
271
+ });
272
+ return /* @__PURE__ */ jsx(
273
+ "button",
274
+ {
275
+ ref,
276
+ ...props,
277
+ type: "button",
278
+ role: "tab",
279
+ id: context.tabId(value),
280
+ "data-slot": "tabs-tab",
281
+ "data-value": value,
282
+ "aria-selected": selected,
283
+ "aria-controls": context.panelId(value),
284
+ tabIndex: selected ? 0 : -1,
285
+ onClick: (event) => {
286
+ onClick?.(event);
287
+ context.select(value);
288
+ },
289
+ onKeyDown: (event) => {
290
+ onKeyDown?.(event);
291
+ if (event.defaultPrevented) return;
292
+ moveBetweenTabs(event, context.orientation, context.select);
293
+ },
294
+ className: cn(styles.tab(), className),
295
+ children
296
+ }
297
+ );
298
+ });
299
+ var TabsPanel = forwardRef(function TabsPanel2({ value, keepMounted = false, children, className, ...props }, ref) {
300
+ const context = useTabsContext("TabsPanel");
301
+ const selected = context.value === value;
302
+ if (!selected && !keepMounted) return null;
303
+ const classes = cn(className);
304
+ return /* @__PURE__ */ jsx(
305
+ "div",
306
+ {
307
+ ref,
308
+ ...props,
309
+ role: "tabpanel",
310
+ id: context.panelId(value),
311
+ "data-slot": "tabs-panel",
312
+ "aria-labelledby": context.tabId(value),
313
+ hidden: !selected,
314
+ className: classes || void 0,
315
+ children
316
+ }
317
+ );
318
+ });
319
+ export {
320
+ Tabs,
321
+ TabsList,
322
+ TabsPanel,
323
+ TabsTab
324
+ };
325
+ //# sourceMappingURL=Tabs.js.map