@fungi.computer/caps 0.0.0-stage → 0.0.1

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 (387) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1125 -2
  3. package/dist/blocks/app-bar.d.ts +43 -0
  4. package/dist/blocks/app-bar.js +244 -0
  5. package/dist/blocks/app-status-bar.d.ts +93 -0
  6. package/dist/blocks/app-status-bar.js +42 -0
  7. package/dist/blocks/async-state.d.ts +21 -0
  8. package/dist/blocks/async-state.js +8 -0
  9. package/dist/blocks/card-grid.d.ts +11 -0
  10. package/dist/blocks/card-grid.js +21 -0
  11. package/dist/blocks/command-menu.d.ts +26 -0
  12. package/dist/blocks/command-menu.js +70 -0
  13. package/dist/blocks/composer.d.ts +23 -0
  14. package/dist/blocks/composer.js +13 -0
  15. package/dist/blocks/empty-state.d.ts +59 -0
  16. package/dist/blocks/empty-state.js +35 -0
  17. package/dist/blocks/faq-chat.d.ts +62 -0
  18. package/dist/blocks/faq-chat.js +77 -0
  19. package/dist/blocks/game-share-card.d.ts +17 -0
  20. package/dist/blocks/game-share-card.js +9 -0
  21. package/dist/blocks/launcher-grid.d.ts +50 -0
  22. package/dist/blocks/launcher-grid.js +11 -0
  23. package/dist/blocks/listing-detail.d.ts +23 -0
  24. package/dist/blocks/listing-detail.js +12 -0
  25. package/dist/blocks/loading-state.d.ts +5 -0
  26. package/dist/blocks/loading-state.js +8 -0
  27. package/dist/blocks/mosaic.d.ts +29 -0
  28. package/dist/blocks/mosaic.js +19 -0
  29. package/dist/blocks/permission-grid.d.ts +45 -0
  30. package/dist/blocks/permission-grid.js +14 -0
  31. package/dist/blocks/pricing-card.d.ts +53 -0
  32. package/dist/blocks/pricing-card.js +12 -0
  33. package/dist/blocks/release-tag.d.ts +20 -0
  34. package/dist/blocks/release-tag.js +10 -0
  35. package/dist/blocks/resource-select.d.ts +22 -0
  36. package/dist/blocks/resource-select.js +16 -0
  37. package/dist/blocks/result-state.d.ts +15 -0
  38. package/dist/blocks/result-state.js +8 -0
  39. package/dist/blocks/section-card.d.ts +31 -0
  40. package/dist/blocks/section-card.js +7 -0
  41. package/dist/blocks/section-heading.d.ts +13 -0
  42. package/dist/blocks/section-heading.js +11 -0
  43. package/dist/blocks/spec-sheet.d.ts +125 -0
  44. package/dist/blocks/spec-sheet.js +47 -0
  45. package/dist/blocks/status-tray.d.ts +83 -0
  46. package/dist/blocks/status-tray.js +79 -0
  47. package/dist/blocks/upload-queue.d.ts +48 -0
  48. package/dist/blocks/upload-queue.js +24 -0
  49. package/dist/components/action-row.d.ts +16 -0
  50. package/dist/components/action-row.js +11 -0
  51. package/dist/components/activity-line.d.ts +33 -0
  52. package/dist/components/activity-line.js +69 -0
  53. package/dist/components/alert.d.ts +17 -0
  54. package/dist/components/alert.js +17 -0
  55. package/dist/components/badge.d.ts +19 -0
  56. package/dist/components/badge.js +24 -0
  57. package/dist/components/button.d.ts +55 -0
  58. package/dist/components/button.js +230 -0
  59. package/dist/components/card.d.ts +61 -0
  60. package/dist/components/card.js +48 -0
  61. package/dist/components/chat-bubble.d.ts +34 -0
  62. package/dist/components/chat-bubble.js +10 -0
  63. package/dist/components/checkbox-bead.d.ts +6 -0
  64. package/dist/components/checkbox-bead.js +67 -0
  65. package/dist/components/checkbox.d.ts +21 -0
  66. package/dist/components/checkbox.js +46 -0
  67. package/dist/components/code-input.d.ts +35 -0
  68. package/dist/components/code-input.js +126 -0
  69. package/dist/components/combobox.d.ts +86 -0
  70. package/dist/components/combobox.js +218 -0
  71. package/dist/components/confirm-action.d.ts +23 -0
  72. package/dist/components/confirm-action.js +64 -0
  73. package/dist/components/copy-field.d.ts +53 -0
  74. package/dist/components/copy-field.js +49 -0
  75. package/dist/components/count-badge.d.ts +15 -0
  76. package/dist/components/count-badge.js +9 -0
  77. package/dist/components/cover-pattern.d.ts +19 -0
  78. package/dist/components/cover-pattern.js +74 -0
  79. package/dist/components/data-list.d.ts +25 -0
  80. package/dist/components/data-list.js +16 -0
  81. package/dist/components/dialog.d.ts +39 -0
  82. package/dist/components/dialog.js +73 -0
  83. package/dist/components/diff-view.d.ts +14 -0
  84. package/dist/components/diff-view.js +13 -0
  85. package/dist/components/disclosure.d.ts +29 -0
  86. package/dist/components/disclosure.js +19 -0
  87. package/dist/components/dropdown-menu.d.ts +49 -0
  88. package/dist/components/dropdown-menu.js +98 -0
  89. package/dist/components/field-guide.d.ts +41 -0
  90. package/dist/components/field-guide.js +18 -0
  91. package/dist/components/field.d.ts +164 -0
  92. package/dist/components/field.js +228 -0
  93. package/dist/components/game-feedback.d.ts +84 -0
  94. package/dist/components/game-feedback.js +48 -0
  95. package/dist/components/game-hud.d.ts +126 -0
  96. package/dist/components/game-hud.js +136 -0
  97. package/dist/components/generation-frame.d.ts +36 -0
  98. package/dist/components/generation-frame.js +97 -0
  99. package/dist/components/gooey.d.ts +32 -0
  100. package/dist/components/gooey.js +25 -0
  101. package/dist/components/hold-button.d.ts +26 -0
  102. package/dist/components/hold-button.js +115 -0
  103. package/dist/components/icon-button.d.ts +24 -0
  104. package/dist/components/icon-button.js +18 -0
  105. package/dist/components/icon-checkbox.d.ts +20 -0
  106. package/dist/components/icon-checkbox.js +9 -0
  107. package/dist/components/icon-choice-mark.d.ts +6 -0
  108. package/dist/components/icon-choice-mark.js +5 -0
  109. package/dist/components/icon-lamp.d.ts +42 -0
  110. package/dist/components/icon-lamp.js +15 -0
  111. package/dist/components/icon-radio.d.ts +16 -0
  112. package/dist/components/icon-radio.js +9 -0
  113. package/dist/components/inline-code.d.ts +3 -0
  114. package/dist/components/inline-code.js +7 -0
  115. package/dist/components/input-group.d.ts +9 -0
  116. package/dist/components/input-group.js +15 -0
  117. package/dist/components/input.d.ts +15 -0
  118. package/dist/components/input.js +15 -0
  119. package/dist/components/item-grid.d.ts +110 -0
  120. package/dist/components/item-grid.js +136 -0
  121. package/dist/components/keycap.d.ts +80 -0
  122. package/dist/components/keycap.js +18 -0
  123. package/dist/components/label.d.ts +13 -0
  124. package/dist/components/label.js +7 -0
  125. package/dist/components/listbox.d.ts +50 -0
  126. package/dist/components/listbox.js +134 -0
  127. package/dist/components/loader-blobs.d.ts +5 -0
  128. package/dist/components/loader-blobs.js +128 -0
  129. package/dist/components/loader.d.ts +21 -0
  130. package/dist/components/loader.js +25 -0
  131. package/dist/components/markdown.d.ts +23 -0
  132. package/dist/components/markdown.js +70 -0
  133. package/dist/components/minimap-labels.d.ts +39 -0
  134. package/dist/components/minimap-labels.js +113 -0
  135. package/dist/components/monogram.d.ts +32 -0
  136. package/dist/components/monogram.js +24 -0
  137. package/dist/components/motion-visibility.d.ts +2 -0
  138. package/dist/components/motion-visibility.js +25 -0
  139. package/dist/components/navigation-rail.d.ts +11 -0
  140. package/dist/components/navigation-rail.js +55 -0
  141. package/dist/components/overlay-root.d.ts +16 -0
  142. package/dist/components/overlay-root.js +24 -0
  143. package/dist/components/pixel-number.d.ts +50 -0
  144. package/dist/components/pixel-number.js +113 -0
  145. package/dist/components/popover.d.ts +31 -0
  146. package/dist/components/popover.js +24 -0
  147. package/dist/components/presence.d.ts +59 -0
  148. package/dist/components/presence.js +232 -0
  149. package/dist/components/price-tag.d.ts +11 -0
  150. package/dist/components/price-tag.js +6 -0
  151. package/dist/components/progress.d.ts +25 -0
  152. package/dist/components/progress.js +24 -0
  153. package/dist/components/prose.d.ts +14 -0
  154. package/dist/components/prose.js +10 -0
  155. package/dist/components/quota-meter.d.ts +24 -0
  156. package/dist/components/quota-meter.js +11 -0
  157. package/dist/components/radio-bead.d.ts +4 -0
  158. package/dist/components/radio-bead.js +53 -0
  159. package/dist/components/radio-group.d.ts +54 -0
  160. package/dist/components/radio-group.js +64 -0
  161. package/dist/components/resize-handle.d.ts +23 -0
  162. package/dist/components/resize-handle.js +31 -0
  163. package/dist/components/rough-drawing.d.ts +42 -0
  164. package/dist/components/rough-drawing.js +231 -0
  165. package/dist/components/rough.d.ts +68 -0
  166. package/dist/components/rough.js +33 -0
  167. package/dist/components/scroll-area.d.ts +12 -0
  168. package/dist/components/scroll-area.js +96 -0
  169. package/dist/components/scroll-motion.d.ts +12 -0
  170. package/dist/components/scroll-motion.js +31 -0
  171. package/dist/components/scroll-to-bottom-blob-state.d.ts +40 -0
  172. package/dist/components/scroll-to-bottom-blob-state.js +109 -0
  173. package/dist/components/scroll-to-bottom-blob.d.ts +16 -0
  174. package/dist/components/scroll-to-bottom-blob.js +174 -0
  175. package/dist/components/select.d.ts +9 -0
  176. package/dist/components/select.js +12 -0
  177. package/dist/components/selectable.d.ts +13 -0
  178. package/dist/components/selectable.js +45 -0
  179. package/dist/components/send-action.d.ts +33 -0
  180. package/dist/components/send-action.js +96 -0
  181. package/dist/components/separator.d.ts +11 -0
  182. package/dist/components/separator.js +7 -0
  183. package/dist/components/skeleton.d.ts +5 -0
  184. package/dist/components/skeleton.js +7 -0
  185. package/dist/components/slider.d.ts +18 -0
  186. package/dist/components/slider.js +31 -0
  187. package/dist/components/stat.d.ts +17 -0
  188. package/dist/components/stat.js +7 -0
  189. package/dist/components/status-bead.d.ts +9 -0
  190. package/dist/components/status-bead.js +107 -0
  191. package/dist/components/status-mark.d.ts +12 -0
  192. package/dist/components/status-mark.js +177 -0
  193. package/dist/components/status.d.ts +38 -0
  194. package/dist/components/status.js +28 -0
  195. package/dist/components/store-card.d.ts +21 -0
  196. package/dist/components/store-card.js +10 -0
  197. package/dist/components/surface.d.ts +89 -0
  198. package/dist/components/surface.js +31 -0
  199. package/dist/components/switch-bead.d.ts +4 -0
  200. package/dist/components/switch-bead.js +62 -0
  201. package/dist/components/switch.d.ts +11 -0
  202. package/dist/components/switch.js +36 -0
  203. package/dist/components/tabs.d.ts +55 -0
  204. package/dist/components/tabs.js +81 -0
  205. package/dist/components/technonomicon.d.ts +192 -0
  206. package/dist/components/technonomicon.js +121 -0
  207. package/dist/components/textarea.d.ts +9 -0
  208. package/dist/components/textarea.js +11 -0
  209. package/dist/components/toaster.d.ts +4 -0
  210. package/dist/components/toaster.js +13 -0
  211. package/dist/components/tool-call-chip.d.ts +22 -0
  212. package/dist/components/tool-call-chip.js +100 -0
  213. package/dist/components/tooltip.d.ts +41 -0
  214. package/dist/components/tooltip.js +169 -0
  215. package/dist/components/trading-card.d.ts +60 -0
  216. package/dist/components/trading-card.js +13 -0
  217. package/dist/components/undo-action.d.ts +52 -0
  218. package/dist/components/undo-action.js +100 -0
  219. package/dist/components/undo-toast.d.ts +21 -0
  220. package/dist/components/undo-toast.js +58 -0
  221. package/dist/components/visually-hidden.d.ts +9 -0
  222. package/dist/components/visually-hidden.js +11 -0
  223. package/dist/components/window.d.ts +65 -0
  224. package/dist/components/window.js +31 -0
  225. package/dist/components/wizard.d.ts +17 -0
  226. package/dist/components/wizard.js +19 -0
  227. package/dist/enhance/cigarette-card.d.ts +8 -0
  228. package/dist/enhance/cigarette-card.js +33 -0
  229. package/dist/enhance/sketch.d.ts +16 -0
  230. package/dist/enhance/sketch.js +130 -0
  231. package/dist/form-error.d.ts +7 -0
  232. package/dist/form-error.js +14 -0
  233. package/dist/form-fields.d.ts +15 -0
  234. package/dist/form-fields.js +250 -0
  235. package/dist/form-schema.d.ts +166 -0
  236. package/dist/form-schema.js +398 -0
  237. package/dist/form.d.ts +30 -0
  238. package/dist/form.js +20 -0
  239. package/dist/lib/cn.d.ts +8 -0
  240. package/dist/lib/cn.js +12 -0
  241. package/dist/lib/format-money.d.ts +2 -0
  242. package/dist/lib/format-money.js +22 -0
  243. package/dist/lib/glide.d.ts +12 -0
  244. package/dist/lib/glide.js +143 -0
  245. package/dist/lib/ime.d.ts +3 -0
  246. package/dist/lib/ime.js +8 -0
  247. package/dist/lib/motion-spring.d.ts +27 -0
  248. package/dist/lib/motion-spring.js +36 -0
  249. package/dist/lib/motion.d.ts +51 -0
  250. package/dist/lib/motion.js +161 -0
  251. package/dist/lib/reorder-motion.d.ts +13 -0
  252. package/dist/lib/reorder-motion.js +201 -0
  253. package/dist/lib/seed-hash.d.ts +6 -0
  254. package/dist/lib/seed-hash.js +13 -0
  255. package/dist/lib/tanstack-highlight.d.ts +4 -0
  256. package/dist/lib/tanstack-highlight.js +41 -0
  257. package/dist/schema-form.d.ts +120 -0
  258. package/dist/schema-form.js +129 -0
  259. package/dist/styles.css +18814 -0
  260. package/docs/api/README.md +134 -0
  261. package/docs/api/blocks/app-bar.md +227 -0
  262. package/docs/api/blocks/app-status-bar.md +257 -0
  263. package/docs/api/blocks/async-state.md +53 -0
  264. package/docs/api/blocks/card-grid.md +31 -0
  265. package/docs/api/blocks/command-menu.md +89 -0
  266. package/docs/api/blocks/composer.md +40 -0
  267. package/docs/api/blocks/empty-state.md +97 -0
  268. package/docs/api/blocks/faq-chat.md +147 -0
  269. package/docs/api/blocks/game-share-card.md +40 -0
  270. package/docs/api/blocks/launcher-grid.md +86 -0
  271. package/docs/api/blocks/listing-detail.md +51 -0
  272. package/docs/api/blocks/loading-state.md +21 -0
  273. package/docs/api/blocks/mosaic.md +94 -0
  274. package/docs/api/blocks/permission-grid.md +79 -0
  275. package/docs/api/blocks/pricing-card.md +90 -0
  276. package/docs/api/blocks/release-tag.md +62 -0
  277. package/docs/api/blocks/resource-select.md +126 -0
  278. package/docs/api/blocks/result-state.md +42 -0
  279. package/docs/api/blocks/section-card.md +42 -0
  280. package/docs/api/blocks/section-heading.md +61 -0
  281. package/docs/api/blocks/spec-sheet.md +400 -0
  282. package/docs/api/blocks/status-tray.md +141 -0
  283. package/docs/api/blocks/upload-queue.md +110 -0
  284. package/docs/api/components/action-row.md +51 -0
  285. package/docs/api/components/activity-line.md +103 -0
  286. package/docs/api/components/alert.md +60 -0
  287. package/docs/api/components/badge.md +77 -0
  288. package/docs/api/components/button.md +94 -0
  289. package/docs/api/components/card.md +165 -0
  290. package/docs/api/components/chat-bubble.md +66 -0
  291. package/docs/api/components/checkbox-bead.md +20 -0
  292. package/docs/api/components/checkbox.md +42 -0
  293. package/docs/api/components/code-input.md +61 -0
  294. package/docs/api/components/combobox.md +303 -0
  295. package/docs/api/components/confirm-action.md +58 -0
  296. package/docs/api/components/copy-field.md +106 -0
  297. package/docs/api/components/count-badge.md +39 -0
  298. package/docs/api/components/cover-pattern.md +43 -0
  299. package/docs/api/components/data-list.md +80 -0
  300. package/docs/api/components/dialog.md +235 -0
  301. package/docs/api/components/diff-view.md +59 -0
  302. package/docs/api/components/disclosure.md +71 -0
  303. package/docs/api/components/dropdown-menu.md +269 -0
  304. package/docs/api/components/field-guide.md +174 -0
  305. package/docs/api/components/field.md +252 -0
  306. package/docs/api/components/game-feedback.md +157 -0
  307. package/docs/api/components/game-hud.md +359 -0
  308. package/docs/api/components/generation-frame.md +59 -0
  309. package/docs/api/components/hold-button.md +44 -0
  310. package/docs/api/components/icon-button.md +56 -0
  311. package/docs/api/components/icon-checkbox.md +42 -0
  312. package/docs/api/components/icon-choice-mark.md +31 -0
  313. package/docs/api/components/icon-lamp.md +92 -0
  314. package/docs/api/components/icon-radio.md +42 -0
  315. package/docs/api/components/inline-code.md +21 -0
  316. package/docs/api/components/input-group.md +53 -0
  317. package/docs/api/components/input.md +54 -0
  318. package/docs/api/components/item-grid.md +262 -0
  319. package/docs/api/components/keycap.md +102 -0
  320. package/docs/api/components/label.md +40 -0
  321. package/docs/api/components/listbox.md +131 -0
  322. package/docs/api/components/loader-blobs.md +9 -0
  323. package/docs/api/components/loader.md +51 -0
  324. package/docs/api/components/markdown.md +91 -0
  325. package/docs/api/components/minimap-labels.md +84 -0
  326. package/docs/api/components/monogram.md +96 -0
  327. package/docs/api/components/motion-visibility.md +9 -0
  328. package/docs/api/components/navigation-rail.md +37 -0
  329. package/docs/api/components/overlay-root.md +92 -0
  330. package/docs/api/components/pixel-number.md +120 -0
  331. package/docs/api/components/popover.md +80 -0
  332. package/docs/api/components/presence.md +106 -0
  333. package/docs/api/components/price-tag.md +48 -0
  334. package/docs/api/components/progress.md +90 -0
  335. package/docs/api/components/prose.md +48 -0
  336. package/docs/api/components/quota-meter.md +47 -0
  337. package/docs/api/components/radio-bead.md +9 -0
  338. package/docs/api/components/radio-group.md +126 -0
  339. package/docs/api/components/resize-handle.md +46 -0
  340. package/docs/api/components/rough-drawing.md +122 -0
  341. package/docs/api/components/rough.md +66 -0
  342. package/docs/api/components/scroll-area.md +22 -0
  343. package/docs/api/components/scroll-motion.md +9 -0
  344. package/docs/api/components/scroll-to-bottom-blob-state.md +162 -0
  345. package/docs/api/components/scroll-to-bottom-blob.md +73 -0
  346. package/docs/api/components/select.md +39 -0
  347. package/docs/api/components/send-action.md +58 -0
  348. package/docs/api/components/separator.md +38 -0
  349. package/docs/api/components/skeleton.md +31 -0
  350. package/docs/api/components/slider.md +70 -0
  351. package/docs/api/components/stat.md +42 -0
  352. package/docs/api/components/status-bead.md +19 -0
  353. package/docs/api/components/status-mark.md +19 -0
  354. package/docs/api/components/status.md +105 -0
  355. package/docs/api/components/store-card.md +53 -0
  356. package/docs/api/components/surface.md +161 -0
  357. package/docs/api/components/switch-bead.md +9 -0
  358. package/docs/api/components/switch.md +40 -0
  359. package/docs/api/components/tabs.md +138 -0
  360. package/docs/api/components/technonomicon.md +773 -0
  361. package/docs/api/components/textarea.md +40 -0
  362. package/docs/api/components/toaster.md +29 -0
  363. package/docs/api/components/tool-call-chip.md +68 -0
  364. package/docs/api/components/tooltip.md +113 -0
  365. package/docs/api/components/trading-card.md +95 -0
  366. package/docs/api/components/undo-action.md +117 -0
  367. package/docs/api/components/undo-toast.md +49 -0
  368. package/docs/api/components/visually-hidden.md +37 -0
  369. package/docs/api/components/window.md +291 -0
  370. package/docs/api/components/wizard.md +65 -0
  371. package/docs/api/enhance/cigarette-card.md +52 -0
  372. package/docs/api/enhance/sketch.md +42 -0
  373. package/docs/api/form.md +1623 -0
  374. package/docs/api/lib/cn.md +46 -0
  375. package/docs/api/lib/format-money.md +30 -0
  376. package/docs/api/lib/glide.md +36 -0
  377. package/docs/api/lib/ime.md +29 -0
  378. package/docs/api/lib/motion-spring.md +91 -0
  379. package/docs/api/lib/motion.md +212 -0
  380. package/docs/api/lib/reorder-motion.md +46 -0
  381. package/docs/api/lib/seed-hash.md +31 -0
  382. package/docs/api/lib/tanstack-highlight.md +40 -0
  383. package/package.json +597 -3
  384. package/src/app-status-bar.css +158 -0
  385. package/src/fonts.css +1 -0
  386. package/src/status-tray.css +282 -0
  387. package/src/styles.css +10177 -0
@@ -0,0 +1,81 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, forwardRef, useContext, useId, useState, } from "react";
3
+ import { cn } from "../lib/cn.js";
4
+ const TabsContext = createContext(null);
5
+ /** A tab-list controller with explicit controlled or uncontrolled value state. */
6
+ export const Tabs = forwardRef(function Tabs({ children, defaultValue, onValueChange, value: controlledValue, ...props }, ref) {
7
+ const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);
8
+ const selectedValue = controlledValue ?? uncontrolledValue;
9
+ const rootId = useId();
10
+ const setValue = (next) => {
11
+ if (controlledValue === undefined)
12
+ setUncontrolledValue(next);
13
+ onValueChange?.(next);
14
+ };
15
+ const idFor = (prefix, value) => `${rootId}-${prefix}-${encodeURIComponent(value)}`;
16
+ return (_jsx(TabsContext.Provider, { value: {
17
+ onValueChange: setValue,
18
+ panelId: (value) => idFor("panel", value),
19
+ selectedValue,
20
+ tabId: (value) => idFor("tab", value),
21
+ }, children: _jsx("div", { ...props, className: cn("w-full", props.className), ref: ref, children: children }) }));
22
+ });
23
+ function useTabsContext() {
24
+ const context = useContext(TabsContext);
25
+ if (!context)
26
+ throw new Error("Tabs parts must be used inside <Tabs>");
27
+ return context;
28
+ }
29
+ /** The tab-list layout for a Tabs controller. */
30
+ export const TabsList = forwardRef(function TabsList({ className, variant = "bordered", ...props }, ref) {
31
+ return (_jsx("div", { ...props, "aria-orientation": props["aria-orientation"] ?? "horizontal", className: cn(variant === "segmented"
32
+ ? "tabs caps-tabs-segmented w-full"
33
+ : "tabs tabs-border flex w-full items-center gap-xs", className), "data-variant": variant, ref: ref, role: "tablist" }));
34
+ });
35
+ /** A selectable tab in a Tabs controller. */
36
+ export const TabsTrigger = forwardRef(function TabsTrigger({ className, disabled, onClick, onKeyDown, value, ...props }, ref) {
37
+ const tabs = useTabsContext();
38
+ const selected = tabs.selectedValue === value;
39
+ const focusTab = (event) => {
40
+ const list = event.currentTarget.closest('[role="tablist"]');
41
+ if (!(list instanceof HTMLElement))
42
+ return;
43
+ const tabsInList = Array.from(list.querySelectorAll('[role="tab"]')).filter((tab) => !tab.disabled && tab.getAttribute("aria-disabled") !== "true");
44
+ const currentIndex = tabsInList.indexOf(event.currentTarget);
45
+ if (currentIndex < 0 || tabsInList.length === 0)
46
+ return;
47
+ let nextIndex;
48
+ if (event.key === "ArrowRight")
49
+ nextIndex = (currentIndex + 1) % tabsInList.length;
50
+ else if (event.key === "ArrowLeft")
51
+ nextIndex = (currentIndex - 1 + tabsInList.length) % tabsInList.length;
52
+ else if (event.key === "Home")
53
+ nextIndex = 0;
54
+ else if (event.key === "End")
55
+ nextIndex = tabsInList.length - 1;
56
+ else
57
+ return;
58
+ event.preventDefault();
59
+ const next = tabsInList[nextIndex];
60
+ next?.focus();
61
+ if (next)
62
+ tabs.onValueChange(next.dataset.tabValue ?? value);
63
+ };
64
+ return (_jsx("button", { ...props, "aria-controls": tabs.panelId(value), "aria-disabled": disabled ? true : undefined, "aria-selected": selected, className: cn("tab whitespace-nowrap text-base-content transition-colors focus-visible:outline-none focus-visible:ring-2 caps-focus-color", selected && "tab-active", className), "data-tab-value": value, disabled: disabled, id: tabs.tabId(value), onClick: (event) => {
65
+ onClick?.(event);
66
+ if (!event.defaultPrevented && !disabled)
67
+ tabs.onValueChange(value);
68
+ }, onKeyDown: (event) => {
69
+ onKeyDown?.(event);
70
+ if (!event.defaultPrevented)
71
+ focusTab(event);
72
+ }, ref: ref, role: "tab", tabIndex: disabled ? -1 : selected ? 0 : -1, type: props.type ?? "button" }));
73
+ });
74
+ /** The content panel associated with a Tabs value. */
75
+ export const TabsContent = forwardRef(function TabsContent({ children, className, forceMount = false, value, ...props }, ref) {
76
+ const tabs = useTabsContext();
77
+ const selected = tabs.selectedValue === value;
78
+ if (!selected && !forceMount)
79
+ return null;
80
+ return (_jsx("div", { ...props, "aria-labelledby": tabs.tabId(value), className: cn("mt-md focus-visible:outline-none", className), hidden: !selected, id: tabs.panelId(value), ref: ref, role: "tabpanel", tabIndex: 0, children: children }));
81
+ });
@@ -0,0 +1,192 @@
1
+ import { type CSSProperties, type HTMLAttributes, type ReactNode } from "react";
2
+ /** Props accepted by Plate. */
3
+ export type PlateProps = {
4
+ caption: ReactNode;
5
+ image: ReactNode;
6
+ label: string;
7
+ } & HTMLAttributes<HTMLElement>;
8
+ /** A labelled graphite illustration plate. */
9
+ export declare function Plate({ caption, className, image, label, ...props }: PlateProps): import("react/jsx-runtime").JSX.Element;
10
+ /** Props accepted by StagePlate. */
11
+ export type StagePlateProps = {
12
+ caption: ReactNode;
13
+ /** The live drawing: an element with the `caps-stage-plate-viewport` class. */
14
+ children: ReactNode;
15
+ /** How to handle the drawing, shown under the caption. */
16
+ hint?: ReactNode;
17
+ /** Id for the hint, so the drawing can name it with aria-describedby. */
18
+ hintId?: string;
19
+ label: string;
20
+ /** A numbered key to what the drawing shows. */
21
+ specimenKey?: ReactNode;
22
+ } & HTMLAttributes<HTMLElement>;
23
+ /**
24
+ * A plate whose illustration is a live pixel-art stage rather than an image.
25
+ * Its drawing reads `--specimen-ink`, `--specimen-paper` and
26
+ * `--specimen-accent`, which follow the theme.
27
+ */
28
+ export declare function StagePlate({ caption, children, className, hint, hintId, label, specimenKey, ...props }: StagePlateProps): import("react/jsx-runtime").JSX.Element;
29
+ /** Props accepted by CompactPlate. */
30
+ export type CompactPlateProps = Omit<PlateProps, "className">;
31
+ /** A compact plate for editorial teasers. */
32
+ export declare function CompactPlate(props: CompactPlateProps): import("react/jsx-runtime").JSX.Element;
33
+ /** Props accepted by MarginNote. */
34
+ export type MarginNoteProps = {
35
+ children: ReactNode;
36
+ } & HTMLAttributes<HTMLSpanElement>;
37
+ /** An inline note styled for the page margin. */
38
+ export declare function MarginNote({ children, className, ...props }: MarginNoteProps): import("react/jsx-runtime").JSX.Element;
39
+ /** Supported editorial callout kinds. */
40
+ export type CalloutKind = "lesson" | "status" | "plan" | "warning";
41
+ /** Props accepted by Callout. */
42
+ export type CalloutProps = {
43
+ kind: CalloutKind;
44
+ title?: ReactNode;
45
+ children: ReactNode;
46
+ } & HTMLAttributes<HTMLElement>;
47
+ /** A labelled editorial aside. */
48
+ export declare function Callout({ children, className, kind, title, ...props }: CalloutProps): import("react/jsx-runtime").JSX.Element;
49
+ /** Supported lifecycle stages. */
50
+ export type GrowthStage = "spore" | "mycelium" | "fruiting";
51
+ /** Props accepted by GrowthBadge. */
52
+ export type GrowthBadgeProps = {
53
+ stage: GrowthStage;
54
+ } & HTMLAttributes<HTMLSpanElement>;
55
+ /** An outlined Badge in the selected growth-stage color. */
56
+ export declare function GrowthBadge({ className, stage, ...props }: GrowthBadgeProps): import("react/jsx-runtime").JSX.Element;
57
+ /** Props accepted by IssueMasthead. */
58
+ export type IssueMastheadProps = {
59
+ date: string;
60
+ dek: ReactNode;
61
+ number: string;
62
+ /** The publication the Issue belongs to, printed in the kicker. */
63
+ publication: string;
64
+ title: string;
65
+ } & HTMLAttributes<HTMLElement>;
66
+ /** The title, number, date, and dek for an Issue. */
67
+ export declare function IssueMasthead({ className, date, dek, number, publication, title, ...props }: IssueMastheadProps): import("react/jsx-runtime").JSX.Element;
68
+ /** A newspaper nameplate: the front page's large head or a running head. */
69
+ export type MastheadSize = "front" | "running";
70
+ /** Props accepted by Masthead. */
71
+ export type MastheadProps = {
72
+ /** The publication name, set large in the nameplate face. */
73
+ wordmark: string;
74
+ /** Where the nameplate links, normally the front page. */
75
+ href: string;
76
+ /** A small printed mark beside the wordmark, such as a logo drawing. */
77
+ mark?: ReactNode;
78
+ /** One line under the wordmark in the publication's voice. */
79
+ tagline?: ReactNode;
80
+ /** The ruled edition line: date, issue, editor and similar items. */
81
+ edition?: readonly ReactNode[];
82
+ /** The left ear box beside the nameplate, such as a weather note. */
83
+ startEar?: ReactNode;
84
+ /** The right ear box beside the nameplate, such as the editor's portrait. */
85
+ endEar?: ReactNode;
86
+ /** The section bar under the edition line, normally a SectionBar. */
87
+ sections?: ReactNode;
88
+ size?: MastheadSize;
89
+ } & HTMLAttributes<HTMLElement>;
90
+ /**
91
+ * A print masthead. Ears flank the nameplate on wide pages and sit under it
92
+ * on phones; the edition line runs between a thin and a heavy rule.
93
+ */
94
+ export declare function Masthead({ className, edition, endEar, href, mark, sections, size, startEar, tagline, wordmark, ...props }: MastheadProps): import("react/jsx-runtime").JSX.Element;
95
+ /** One section of a publication. */
96
+ export type SectionLink = {
97
+ href: string;
98
+ label: string;
99
+ /** Printed before the label, such as a section letter. */
100
+ marker?: string;
101
+ current?: boolean;
102
+ /** A keyboard shortcut announced through aria-keyshortcuts. */
103
+ shortcut?: string;
104
+ };
105
+ /** Props accepted by SectionBar. */
106
+ export type SectionBarProps = {
107
+ sections: readonly SectionLink[];
108
+ /** Controls set at the end of the bar, such as theme and help buttons. */
109
+ tools?: ReactNode;
110
+ } & HTMLAttributes<HTMLElement>;
111
+ /**
112
+ * A newspaper section bar: small capitals between hairline rules, the
113
+ * current section printed in reverse. It scrolls sideways on narrow pages
114
+ * instead of wrapping. Name it with aria-label.
115
+ */
116
+ export declare function SectionBar({ className, sections, tools, ...props }: SectionBarProps): import("react/jsx-runtime").JSX.Element;
117
+ /** Props accepted by Folio. */
118
+ export type FolioProps = {
119
+ /** Running items, such as the publication, page number and date. */
120
+ items: readonly ReactNode[];
121
+ } & HTMLAttributes<HTMLElement>;
122
+ /** A running foot: the page's folio line between rules. */
123
+ export declare function Folio({ className, items, ...props }: FolioProps): import("react/jsx-runtime").JSX.Element;
124
+ /** Supported editorial spread arrangements. */
125
+ export type SpreadLayout = "lead" | "columns" | "grid";
126
+ /** Props accepted by Spread. */
127
+ export type SpreadProps = {
128
+ layout: SpreadLayout;
129
+ children: ReactNode;
130
+ } & HTMLAttributes<HTMLElement>;
131
+ /** A responsive editorial region with an explicit layout. */
132
+ export declare function Spread({ children, className, layout, ...props }: SpreadProps): import("react/jsx-runtime").JSX.Element;
133
+ /** One supplied card measurement and its provenance. `null` means not measured. */
134
+ export type CardStat = {
135
+ key: string;
136
+ label: string;
137
+ value: string | number | null;
138
+ unit?: string;
139
+ source: string;
140
+ asOf: string;
141
+ };
142
+ /** Print finish: the rarer full-art card lets the drawing run under the text. */
143
+ export type CigaretteCardFinish = "standard" | "full-art";
144
+ /** Props accepted by CigaretteCard. */
145
+ export type CigaretteCardProps = {
146
+ number: number;
147
+ /** The series numeral printed on both faces and in the series mark, such as "I". */
148
+ seriesNumeral: string;
149
+ series: string;
150
+ title: string;
151
+ /** The type line beside the title, such as "Machine of the Burrow". */
152
+ typeLine?: string | undefined;
153
+ image: ReactNode;
154
+ stats: readonly CardStat[];
155
+ note: string;
156
+ finish?: CigaretteCardFinish;
157
+ /** A small set symbol printed in the collector line. */
158
+ setMark?: ReactNode;
159
+ defaultFlipped?: boolean;
160
+ /**
161
+ * Makes the card a preview: a link to the card's own page showing its
162
+ * face, instead of a pressed button that turns over in place.
163
+ */
164
+ href?: string;
165
+ /** "large" prints the card bigger, for its own page. */
166
+ size?: "standard" | "large";
167
+ className?: string;
168
+ /** Inline style on the card, such as a shared view-transition name. */
169
+ style?: CSSProperties;
170
+ };
171
+ /**
172
+ * A two-sided collector card: a framed front with an inset drawing, a stat
173
+ * plate and a flavor line, and a ruled measurement ledger on the back. Both
174
+ * faces live inside one native pressed button, so the reverse stays in the
175
+ * DOM; the visible face names the button. Hydrated hosts flip through React
176
+ * state. Static hosts load the Caps `enhance/cigarette-card` module, which
177
+ * ignores clicks this component already handled. With `href` the card is a
178
+ * preview instead: a link to the card's own page that shows only its face.
179
+ */
180
+ export declare function CigaretteCard({ className, defaultFlipped, finish, href, image, note, number, series, seriesNumeral, setMark, size, stats, style, title, typeLine, }: CigaretteCardProps): import("react/jsx-runtime").JSX.Element;
181
+ /** One numbered album position, optionally occupied by a card. */
182
+ export type AlbumSlot = {
183
+ number: number;
184
+ card?: CigaretteCardProps;
185
+ };
186
+ /** Props accepted by CardAlbum. */
187
+ export type CardAlbumProps = {
188
+ title: string;
189
+ slots: readonly AlbumSlot[];
190
+ } & HTMLAttributes<HTMLElement>;
191
+ /** A numbered checklist of supplied cards and ruled spaces for missing ones. */
192
+ export declare function CardAlbum({ className, slots, title, ...props }: CardAlbumProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,121 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useState, } from "react";
3
+ import { cn } from "../lib/cn.js";
4
+ import { Badge } from "./badge.js";
5
+ /** A labelled graphite illustration plate. */
6
+ export function Plate({ caption, className, image, label, ...props }) {
7
+ return (_jsxs("figure", { ...props, className: cn("caps-plate", className), children: [_jsx("div", { className: "caps-plate-image", children: image }), _jsxs("figcaption", { children: [_jsx("span", { children: label }), _jsx("span", { children: caption })] })] }));
8
+ }
9
+ /**
10
+ * A plate whose illustration is a live pixel-art stage rather than an image.
11
+ * Its drawing reads `--specimen-ink`, `--specimen-paper` and
12
+ * `--specimen-accent`, which follow the theme.
13
+ */
14
+ export function StagePlate({ caption, children, className, hint, hintId, label, specimenKey, ...props }) {
15
+ return (_jsxs("figure", { ...props, className: cn("caps-stage-plate", className), children: [children, _jsxs("figcaption", { children: [_jsx("span", { children: label }), _jsx("span", { className: "caps-stage-plate-caption", children: caption })] }), hint ? (_jsx("p", { className: "caps-stage-plate-hint", id: hintId, children: hint })) : null, specimenKey] }));
16
+ }
17
+ /** A compact plate for editorial teasers. */
18
+ export function CompactPlate(props) {
19
+ return _jsx(Plate, { ...props, className: "caps-compact-plate" });
20
+ }
21
+ /** An inline note styled for the page margin. */
22
+ export function MarginNote({ children, className, ...props }) {
23
+ return (_jsx("span", { ...props, className: cn("caps-margin-note", className), children: children }));
24
+ }
25
+ /** A labelled editorial aside. */
26
+ export function Callout({ children, className, kind, title, ...props }) {
27
+ return (_jsxs("aside", { ...props, className: cn("caps-callout", className), "data-kind": kind, children: [title ? _jsx("h2", { children: title }) : null, children] }));
28
+ }
29
+ /** An outlined Badge in the selected growth-stage color. */
30
+ export function GrowthBadge({ className, stage, ...props }) {
31
+ const tone = stage === "spore"
32
+ ? "secondary"
33
+ : stage === "mycelium"
34
+ ? "primary"
35
+ : "accent";
36
+ return (_jsx(Badge, { ...props, className: cn("caps-growth-badge badge-outline", className), "data-stage": stage, size: "sm", tone: tone, children: stage }));
37
+ }
38
+ /** The title, number, date, and dek for an Issue. */
39
+ export function IssueMasthead({ className, date, dek, number, publication, title, ...props }) {
40
+ return (_jsxs("header", { ...props, className: cn("caps-issue-masthead", className), children: [_jsxs("p", { className: "caps-issue-kicker", children: [publication, " \u00B7 Issue ", number, " \u00B7 ", date] }), _jsx("h1", { children: title }), _jsx("p", { children: dek })] }));
41
+ }
42
+ /**
43
+ * A print masthead. Ears flank the nameplate on wide pages and sit under it
44
+ * on phones; the edition line runs between a thin and a heavy rule.
45
+ */
46
+ export function Masthead({ className, edition, endEar, href, mark, sections, size = "front", startEar, tagline, wordmark, ...props }) {
47
+ return (_jsxs("header", { ...props, className: cn("caps-masthead", className), "data-size": size, children: [_jsxs("div", { className: "caps-masthead-plate", children: [startEar ? (_jsx("div", { className: "caps-masthead-ear", "data-side": "start", children: startEar })) : null, _jsxs("a", { className: "caps-masthead-nameplate", href: href, children: [mark ? (_jsx("span", { "aria-hidden": "true", className: "caps-masthead-mark", children: mark })) : null, _jsx("span", { className: "caps-masthead-wordmark", children: wordmark })] }), endEar ? (_jsx("div", { className: "caps-masthead-ear", "data-side": "end", children: endEar })) : null] }), tagline ? _jsx("p", { className: "caps-masthead-tagline", children: tagline }) : null, edition && edition.length > 0 ? (_jsx("ul", { className: "caps-masthead-edition", children: edition.map((item, index) => (_jsx("li", { children: item }, index))) })) : null, sections] }));
48
+ }
49
+ /**
50
+ * A newspaper section bar: small capitals between hairline rules, the
51
+ * current section printed in reverse. It scrolls sideways on narrow pages
52
+ * instead of wrapping. Name it with aria-label.
53
+ */
54
+ export function SectionBar({ className, sections, tools, ...props }) {
55
+ return (_jsxs("nav", { ...props, className: cn("caps-section-bar", className), children: [_jsx("ul", { children: sections.map((section) => (_jsx("li", { children: _jsxs("a", { "aria-current": section.current ? "page" : undefined, "aria-keyshortcuts": section.shortcut, className: "caps-section-bar-link", href: section.href, children: [section.marker ? (_jsx("span", { "aria-hidden": "true", className: "caps-section-bar-marker", children: section.marker })) : null, _jsx("span", { children: section.label })] }) }, section.href))) }), tools ? _jsx("div", { className: "caps-section-bar-tools", children: tools }) : null] }));
56
+ }
57
+ /** A running foot: the page's folio line between rules. */
58
+ export function Folio({ className, items, ...props }) {
59
+ return (_jsx("footer", { ...props, className: cn("caps-folio", className), children: _jsx("ul", { children: items.map((item, index) => (_jsx("li", { children: item }, index))) }) }));
60
+ }
61
+ /** A responsive editorial region with an explicit layout. */
62
+ export function Spread({ children, className, layout, ...props }) {
63
+ return (_jsx("section", { ...props, className: cn("caps-spread", className), "data-layout": layout, children: children }));
64
+ }
65
+ /** Print an observation date as a calendar day when it carries a time. */
66
+ function calendarDay(asOf) {
67
+ return /^\d{4}-\d{2}-\d{2}T/.test(asOf) ? asOf.slice(0, 10) : asOf;
68
+ }
69
+ function groupCardSources(stats) {
70
+ const grouped = new Map();
71
+ for (const { source, asOf } of stats) {
72
+ const dates = grouped.get(source) ?? new Set();
73
+ dates.add(calendarDay(asOf));
74
+ grouped.set(source, dates);
75
+ }
76
+ return Array.from(grouped, ([source, dates]) => ({
77
+ source,
78
+ asOf: Array.from(dates),
79
+ }));
80
+ }
81
+ function StatFigure({ stat }) {
82
+ if (stat.value === null)
83
+ return (_jsx("span", { className: "caps-cigarette-card-not-measured", children: "not measured" }));
84
+ return (_jsxs(_Fragment, { children: [_jsx("span", { className: "caps-cigarette-card-numeral", children: String(stat.value) }), stat.unit ? (_jsx("span", { className: "caps-cigarette-card-unit", children: stat.unit })) : null] }));
85
+ }
86
+ function CardHead({ seriesNumeral, title, typeLine, }) {
87
+ return (_jsxs(_Fragment, { children: [_jsxs("span", { className: "caps-cigarette-card-head", children: [_jsx("span", { className: "caps-cigarette-card-title", children: title }), typeLine ? (_jsx("span", { className: "caps-cigarette-card-type", children: typeLine })) : null] }), _jsx("span", { "aria-hidden": "true", className: "caps-cigarette-card-mark", children: _jsx("span", { children: seriesNumeral }) })] }));
88
+ }
89
+ function CollectorLine({ number, series, seriesNumeral, setMark, }) {
90
+ return (_jsxs("span", { className: "caps-cigarette-card-collector", children: [_jsxs("span", { children: ["No. ", number, " \u00B7 Series ", seriesNumeral, ": ", series] }), setMark ? (_jsx("span", { "aria-hidden": "true", className: "caps-cigarette-card-set", children: setMark })) : null] }));
91
+ }
92
+ /**
93
+ * A two-sided collector card: a framed front with an inset drawing, a stat
94
+ * plate and a flavor line, and a ruled measurement ledger on the back. Both
95
+ * faces live inside one native pressed button, so the reverse stays in the
96
+ * DOM; the visible face names the button. Hydrated hosts flip through React
97
+ * state. Static hosts load the Caps `enhance/cigarette-card` module, which
98
+ * ignores clicks this component already handled. With `href` the card is a
99
+ * preview instead: a link to the card's own page that shows only its face.
100
+ */
101
+ export function CigaretteCard({ className, defaultFlipped = false, finish = "standard", href, image, note, number, series, seriesNumeral, setMark, size = "standard", stats, style, title, typeLine, }) {
102
+ const [flipped, setFlipped] = useState(defaultFlipped);
103
+ const sources = groupCardSources(stats);
104
+ const headline = stats.find((stat) => stat.value !== null) ?? stats[0];
105
+ const others = stats.filter((stat) => stat !== headline).slice(0, 2);
106
+ const head = { seriesNumeral, title, typeLine };
107
+ const collector = { number, series, seriesNumeral, setMark };
108
+ const front = (_jsxs("span", { className: "caps-cigarette-card-face caps-cigarette-card-front", "aria-hidden": href ? undefined : flipped, children: [_jsx(CardHead, { ...head }), _jsx("span", { className: "caps-cigarette-card-window", children: image }), headline ? (_jsxs("span", { className: "caps-cigarette-card-plate", children: [_jsxs("span", { className: "caps-cigarette-card-headline", children: [_jsx("span", { className: "caps-cigarette-card-label", children: headline.label }), _jsx("span", { className: "caps-cigarette-card-figure", children: _jsx(StatFigure, { stat: headline }) })] }), others.length > 0 ? (_jsx("span", { className: "caps-cigarette-card-plate-list", children: others.map((stat) => (_jsxs("span", { children: [_jsx("span", { className: "caps-cigarette-card-label", children: stat.label }), _jsx("span", { children: _jsx(StatFigure, { stat: stat }) })] }, stat.key))) })) : null] })) : null, _jsx("span", { className: "caps-cigarette-card-flavor", children: note }), _jsx(CollectorLine, { ...collector })] }));
109
+ const back = (_jsxs("span", { className: "caps-cigarette-card-face caps-cigarette-card-back", "aria-hidden": !flipped, children: [_jsx(CardHead, { ...head }), _jsxs("span", { className: "caps-cigarette-card-ledger", children: [_jsx("span", { className: "caps-cigarette-card-ledger-title", children: "Field measurements" }), _jsx("span", { className: "caps-cigarette-card-stats", children: stats.map((stat) => (_jsxs("span", { className: "caps-cigarette-card-stat", children: [_jsx("span", { className: "caps-cigarette-card-stat-label", children: stat.label }), _jsx("span", { "aria-hidden": "true", className: "caps-cigarette-card-leader" }), _jsx("span", { className: "caps-cigarette-card-stat-value", children: _jsx(StatFigure, { stat: stat }) })] }, stat.key))) }), _jsx("span", { "aria-hidden": "true", className: "caps-cigarette-card-cameo", children: image }), _jsx("span", { className: "caps-cigarette-card-note", children: note }), _jsx("span", { className: "caps-cigarette-card-sources", children: sources.map(({ source, asOf }) => (_jsxs("span", { className: "caps-cigarette-card-source", children: [source, " \u00B7 ", asOf.join(", ")] }, source))) })] }), _jsx(CollectorLine, { ...collector })] }));
110
+ if (href)
111
+ return (_jsx("a", { className: cn("caps-cigarette-card", className), "data-finish": finish, "data-flipped": false, "data-size": size, href: href, style: style, children: _jsx("span", { className: "caps-cigarette-card-inner", children: front }) }));
112
+ return (_jsx("button", { type: "button", "aria-pressed": flipped, className: cn("caps-cigarette-card", className), onClick: (event) => {
113
+ event.preventDefault();
114
+ setFlipped((current) => !current);
115
+ }, "data-finish": finish, "data-flipped": flipped, "data-size": size, style: style, children: _jsxs("span", { className: "caps-cigarette-card-inner", children: [front, back] }) }));
116
+ }
117
+ /** A numbered checklist of supplied cards and ruled spaces for missing ones. */
118
+ export function CardAlbum({ className, slots, title, ...props }) {
119
+ const collected = slots.filter((slot) => slot.card !== undefined).length;
120
+ return (_jsxs("section", { ...props, className: cn("caps-album", className), children: [_jsxs("header", { className: "caps-album-head", children: [_jsx("h2", { children: title }), _jsxs("p", { children: [collected, " of ", slots.length, " collected"] })] }), _jsx("ol", { children: slots.map(({ card, number }) => (_jsx("li", { "data-collected": card !== undefined, children: card ? (_jsx(CigaretteCard, { ...card })) : (_jsxs("span", { className: "caps-album-empty", children: [_jsxs("span", { children: ["No. ", number] }), _jsx("span", { children: "not yet collected" })] })) }, number))) })] }));
121
+ }
@@ -0,0 +1,9 @@
1
+ import { type TextareaHTMLAttributes } from "react";
2
+ /** Props accepted by Textarea. */
3
+ export type TextareaProps = {
4
+ invalid?: boolean;
5
+ } & TextareaHTMLAttributes<HTMLTextAreaElement>;
6
+ /** A styled multiline text input that preserves caller-owned value and event behavior. */
7
+ export declare const Textarea: import("react").ForwardRefExoticComponent<{
8
+ invalid?: boolean;
9
+ } & TextareaHTMLAttributes<HTMLTextAreaElement> & import("react").RefAttributes<HTMLTextAreaElement>>;
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { forwardRef } from "react";
3
+ import { cn } from "../lib/cn.js";
4
+ /** A styled multiline text input that preserves caller-owned value and event behavior. */
5
+ export const Textarea = forwardRef(function Textarea({ className, invalid, ...props }, ref) {
6
+ return (_jsx("textarea", { ...props, "aria-invalid": invalid
7
+ ? true
8
+ : props["aria-invalid"] === false
9
+ ? undefined
10
+ : props["aria-invalid"], className: cn("textarea textarea-bordered w-full", invalid && "textarea-error", className), ref: ref }));
11
+ });
@@ -0,0 +1,4 @@
1
+ import { type ToasterProps } from "sonner";
2
+ export { toast } from "sonner";
3
+ /** Sonner owns gestures, stacking, focus and lifetime; Caps owns the surface. */
4
+ export declare function Toaster({ className, ...props }: ToasterProps): import("react").ReactPortal | null;
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Toaster as Sonner } from "sonner";
3
+ import { cn } from "../lib/cn.js";
4
+ import { createPortal } from "react-dom";
5
+ import { useOverlayRoot } from "./overlay-root.js";
6
+ export { toast } from "sonner";
7
+ /** Sonner owns gestures, stacking, focus and lifetime; Caps owns the surface. */
8
+ export function Toaster({ className, ...props }) {
9
+ const root = useOverlayRoot("toast");
10
+ if (!root)
11
+ return null;
12
+ return createPortal(_jsx(Sonner, { position: "top-right", swipeDirections: ["right", "top"], offset: 16, gap: 8, className: cn("caps-toaster", className), ...props }), root);
13
+ }
@@ -0,0 +1,22 @@
1
+ import { type ActivityState } from "./activity-line.js";
2
+ /** A tool call's time: milliseconds under a second, then the activity clock. */
3
+ export declare function formatCallTime(milliseconds: number): string;
4
+ /** Props accepted by ToolCallChip. */
5
+ export type ToolCallChipProps = Readonly<{
6
+ /** The tool's name, such as `read_file`. */
7
+ name: string;
8
+ state: ActivityState;
9
+ /** When the call started (epoch ms). */
10
+ startedAt: number;
11
+ /** When it ended (epoch ms). */
12
+ finishedAt?: number | undefined;
13
+ /** Offered after a failure. */
14
+ onRetry?: (() => void) | undefined;
15
+ className?: string;
16
+ }>;
17
+ /**
18
+ * One tool call as a chip. While it runs a quiet fill wipes across and a
19
+ * live clock counts; when it lands the fill completes and washes away; when
20
+ * it fails the chip shakes and offers a retry.
21
+ */
22
+ export declare function ToolCallChip({ name, state, startedAt, finishedAt, onRetry, className, }: ToolCallChipProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,100 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { RotateCcw } from "lucide-react";
3
+ import { useLayoutEffect, useRef } from "react";
4
+ import { cn } from "../lib/cn.js";
5
+ import { canAnimate, motionEasing, readMotion } from "../lib/motion.js";
6
+ import { formatElapsed, useElapsed, } from "./activity-line.js";
7
+ import { IconButton } from "./icon-button.js";
8
+ import { Presence } from "./presence.js";
9
+ import { Status } from "./status.js";
10
+ /** A tool call's time: milliseconds under a second, then the activity clock. */
11
+ export function formatCallTime(milliseconds) {
12
+ return milliseconds < 1_000
13
+ ? `${String(Math.max(0, Math.round(milliseconds)))}ms`
14
+ : formatElapsed(milliseconds);
15
+ }
16
+ const glyphFor = {
17
+ running: "arc",
18
+ done: "check",
19
+ failed: "cross",
20
+ };
21
+ /** How long a running fill takes to approach (never reach) the far edge. */
22
+ const fillPatienceMs = 6_000;
23
+ /**
24
+ * One tool call as a chip. While it runs a quiet fill wipes across and a
25
+ * live clock counts; when it lands the fill completes and washes away; when
26
+ * it fails the chip shakes and offers a retry.
27
+ */
28
+ export function ToolCallChip({ name, state, startedAt, finishedAt, onRetry, className, }) {
29
+ const chip = useRef(null);
30
+ const fill = useRef(null);
31
+ const previous = useRef(null);
32
+ const elapsed = useElapsed(startedAt, finishedAt, state === "running");
33
+ useLayoutEffect(() => {
34
+ const element = chip.current;
35
+ const bar = fill.current;
36
+ const before = previous.current;
37
+ previous.current = state;
38
+ if (!element || !bar || !canAnimate(bar))
39
+ return;
40
+ const motion = readMotion(element);
41
+ const animations = [];
42
+ if (motion.reduced) {
43
+ // No wipe: the finished tint arrives and leaves as a fade.
44
+ if (before === "running" && state !== "running")
45
+ animations.push(bar.animate([
46
+ { transform: "none", opacity: 0 },
47
+ { transform: "none", opacity: 1, offset: 0.3 },
48
+ { transform: "none", opacity: 0 },
49
+ ], { duration: motion.slow * 4, easing: motion.ease }));
50
+ }
51
+ else if (state === "running") {
52
+ animations.push(bar.animate([{ transform: "scaleX(0)" }, { transform: "scaleX(0.9)" }], {
53
+ duration: fillPatienceMs,
54
+ easing: motionEasing(motion, "cubic-bezier(0.1, 0.6, 0.3, 1)"),
55
+ fill: "forwards",
56
+ }));
57
+ }
58
+ else if (before === "running") {
59
+ // Land from wherever the wipe had reached.
60
+ const reached = getComputedStyle(bar).transform;
61
+ for (const running of bar.getAnimations())
62
+ running.cancel();
63
+ const from = reached === "none" ? "scaleX(0)" : reached;
64
+ animations.push(bar.animate(state === "done"
65
+ ? [
66
+ { transform: from, opacity: 1 },
67
+ { transform: "scaleX(1)", opacity: 1, offset: 0.25 },
68
+ { transform: "scaleX(1)", opacity: 1, offset: 0.55 },
69
+ { transform: "scaleX(1)", opacity: 0 },
70
+ ]
71
+ : [
72
+ { transform: from, opacity: 1 },
73
+ { transform: from, opacity: 1, offset: 0.5 },
74
+ { transform: from, opacity: 0 },
75
+ ], {
76
+ duration: motion.slow * 4,
77
+ easing: motionEasing(motion, motion.ease),
78
+ fill: "forwards",
79
+ }));
80
+ if (state === "failed" && motion.shake > 0) {
81
+ const x = motion.shake;
82
+ animations.push(element.animate([
83
+ { transform: "none" },
84
+ { transform: `translateX(${String(-x)}px)` },
85
+ { transform: `translateX(${String(x)}px)` },
86
+ { transform: `translateX(${String(-x / 2)}px)` },
87
+ { transform: "none" },
88
+ ], {
89
+ duration: motion.slow * 1.2,
90
+ easing: motionEasing(motion, "linear"),
91
+ }));
92
+ }
93
+ }
94
+ return () => {
95
+ for (const animation of animations)
96
+ animation.cancel();
97
+ };
98
+ }, [state]);
99
+ return (_jsxs("span", { ref: chip, className: cn("caps-tool-call", className), "data-state": state, children: [_jsx("span", { ref: fill, className: "caps-tool-call-fill", "aria-hidden": "true" }), _jsx(Status, { glyph: glyphFor[state], size: "compact", tone: state === "failed" ? "error" : "neutral" }), _jsx("span", { className: "caps-tool-call-name", children: name }), _jsx("span", { className: "caps-tool-call-time", children: formatCallTime(elapsed) }), onRetry === undefined ? null : (_jsx(Presence, { show: state === "failed", appear: true, children: _jsx(IconButton, { "aria-label": `Retry ${name}`, icon: _jsx(RotateCcw, {}), onClick: onRetry, size: "xs", variant: "ghost" }) }))] }));
100
+ }
@@ -0,0 +1,41 @@
1
+ import { type ButtonHTMLAttributes, type HTMLAttributes, type ReactNode } from "react";
2
+ /** Supported TooltipSide values. */
3
+ export type TooltipSide = "bottom" | "left" | "right" | "top";
4
+ /** Props accepted by Tooltip. */
5
+ export type TooltipProps = {
6
+ children: ReactNode;
7
+ defaultOpen?: boolean;
8
+ delayDuration?: number;
9
+ /** Called after the tooltip open state changes. */
10
+ onOpenChange?: (open: boolean) => void;
11
+ open?: boolean;
12
+ side?: TooltipSide;
13
+ } & Omit<HTMLAttributes<HTMLSpanElement>, "children">;
14
+ /** A tooltip controller with explicit controlled or uncontrolled open state. */
15
+ export declare const Tooltip: import("react").ForwardRefExoticComponent<{
16
+ children: ReactNode;
17
+ defaultOpen?: boolean;
18
+ delayDuration?: number;
19
+ /** Called after the tooltip open state changes. */
20
+ onOpenChange?: (open: boolean) => void;
21
+ open?: boolean;
22
+ side?: TooltipSide;
23
+ } & Omit<HTMLAttributes<HTMLSpanElement>, "children"> & import("react").RefAttributes<HTMLSpanElement>>;
24
+ /** Props accepted by TooltipTrigger. */
25
+ export type TooltipTriggerProps = {
26
+ asChild?: boolean;
27
+ children?: ReactNode;
28
+ } & ButtonHTMLAttributes<HTMLButtonElement>;
29
+ /** The trigger control for a Tooltip. */
30
+ export declare const TooltipTrigger: import("react").ForwardRefExoticComponent<{
31
+ asChild?: boolean;
32
+ children?: ReactNode;
33
+ } & ButtonHTMLAttributes<HTMLButtonElement> & import("react").RefAttributes<HTMLButtonElement>>;
34
+ /** Props accepted by TooltipContent. */
35
+ export type TooltipContentProps = {
36
+ children: ReactNode;
37
+ } & HTMLAttributes<HTMLDivElement>;
38
+ /** The positioned content region for a Tooltip. */
39
+ export declare const TooltipContent: import("react").ForwardRefExoticComponent<{
40
+ children: ReactNode;
41
+ } & HTMLAttributes<HTMLDivElement> & import("react").RefAttributes<HTMLDivElement>>;