@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,16 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { forwardRef } from "react";
3
+ import { Combobox } from "../components/combobox.js";
4
+ /** A resource-selection block with caller-owned options and selected value. */
5
+ export const ResourceSelect = forwardRef(function ResourceSelect({ onSelect, options, placeholder = "Select an option", triggerProps, value, }, ref) {
6
+ const { className, ...nativeTriggerProps } = triggerProps ?? {};
7
+ return (_jsx(Combobox, { triggerRef: ref, getKey: (item) => item.id, getLabel: (item) => item.label, getSearchText: (item) => item.searchText ?? item.label, isDisabled: (item) => item.disabled === true, items: options, onValueChange: (_next, item) => {
8
+ if (item)
9
+ onSelect(item);
10
+ }, placeholder: placeholder, renderItem: (item) => _jsx("span", { children: item.label }), value: value ?? null, trigger: _jsx("button", { ...nativeTriggerProps, className: [
11
+ "btn btn-xs btn-ghost w-full justify-between text-left font-normal",
12
+ className,
13
+ ]
14
+ .filter(Boolean)
15
+ .join(" "), type: "button", children: options.find((item) => item.id === value)?.label ?? placeholder }) }));
16
+ });
@@ -0,0 +1,15 @@
1
+ import { type HTMLAttributes, type ReactNode } from "react";
2
+ /** Props accepted by ResultState. */
3
+ export type ResultStateProps = Omit<HTMLAttributes<HTMLElement>, "title"> & {
4
+ actions?: ReactNode;
5
+ description: ReactNode;
6
+ icon?: ReactNode;
7
+ title: ReactNode;
8
+ };
9
+ /** A labelled result presentation; hosts own its meaning and next actions. */
10
+ export declare const ResultState: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLElement>, "title"> & {
11
+ actions?: ReactNode;
12
+ description: ReactNode;
13
+ icon?: ReactNode;
14
+ title: ReactNode;
15
+ } & import("react").RefAttributes<HTMLElement>>;
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef, useId } from "react";
3
+ import { cn } from "../lib/cn.js";
4
+ /** A labelled result presentation; hosts own its meaning and next actions. */
5
+ export const ResultState = forwardRef(function ResultState({ actions, className, description, icon, title, ...props }, ref) {
6
+ const titleId = useId();
7
+ return (_jsxs("section", { ...props, "aria-labelledby": props["aria-labelledby"] ?? titleId, className: cn("result-state", className), ref: ref, children: [icon ? _jsx("div", { "aria-hidden": "true", children: icon }) : null, _jsx("h2", { id: props["aria-labelledby"] ? undefined : titleId, children: title }), _jsx("p", { children: description }), actions ? _jsx("div", { className: "result-state-actions", children: actions }) : null] }));
8
+ });
@@ -0,0 +1,31 @@
1
+ import { type HTMLAttributes, type ReactNode } from "react";
2
+ /** Props accepted by SectionCard. */
3
+ export type SectionCardProps = HTMLAttributes<HTMLDivElement> & {
4
+ /** The host-provided section heading. */
5
+ heading: ReactNode;
6
+ /** Optional host-provided supporting copy. */
7
+ description?: ReactNode;
8
+ /** Optional host-provided controls or status content. */
9
+ actions?: ReactNode;
10
+ /** The section body, supplied by the host through normal composition. */
11
+ children?: ReactNode;
12
+ /** Inside a SectionGrid, `full` spans every column; `auto` takes one. */
13
+ span?: "auto" | "full";
14
+ /** Heading level; the host keeps its document outline. Defaults to 3. */
15
+ headingLevel?: 2 | 3;
16
+ };
17
+ /** A presentational card shell. It does not assign behavior to action content. */
18
+ export declare const SectionCard: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & {
19
+ /** The host-provided section heading. */
20
+ heading: ReactNode;
21
+ /** Optional host-provided supporting copy. */
22
+ description?: ReactNode;
23
+ /** Optional host-provided controls or status content. */
24
+ actions?: ReactNode;
25
+ /** The section body, supplied by the host through normal composition. */
26
+ children?: ReactNode;
27
+ /** Inside a SectionGrid, `full` spans every column; `auto` takes one. */
28
+ span?: "auto" | "full";
29
+ /** Heading level; the host keeps its document outline. Defaults to 3. */
30
+ headingLevel?: 2 | 3;
31
+ } & import("react").RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef } from "react";
3
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "../components/card.js";
4
+ /** A presentational card shell. It does not assign behavior to action content. */
5
+ export const SectionCard = forwardRef(function SectionCard({ actions, children, className, description, heading, headingLevel = 3, span = "auto", ...rootProps }, ref) {
6
+ return (_jsxs(Card, { ...rootProps, className: className, "data-span": span === "full" ? "full" : undefined, ref: ref, variant: "outline", children: [_jsxs(CardHeader, { children: [_jsxs("div", { className: "caps-section-card-heading-row", children: [_jsx(CardTitle, { level: headingLevel, children: heading }), actions ? (_jsx("div", { className: "caps-section-card-actions", children: actions })) : null] }), description ? (_jsx(CardDescription, { children: description })) : null] }), children !== undefined ? _jsx(CardContent, { children: children }) : null] }));
7
+ });
@@ -0,0 +1,13 @@
1
+ import { type HTMLAttributes } from "react";
2
+ /** A shelf or section title with shared case and tracking. */
3
+ export declare const SectionHeading: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLHeadingElement> & import("react").RefAttributes<HTMLHeadingElement>>;
4
+ /** Supported Eyebrow tones. `live` marks something happening right now. */
5
+ export type EyebrowTone = "quiet" | "primary" | "secondary" | "live";
6
+ /** Props accepted by Eyebrow. */
7
+ export type EyebrowProps = HTMLAttributes<HTMLParagraphElement> & {
8
+ tone?: EyebrowTone;
9
+ };
10
+ /** A small contextual label with shared case and tracking. */
11
+ export declare const Eyebrow: import("react").ForwardRefExoticComponent<HTMLAttributes<HTMLParagraphElement> & {
12
+ tone?: EyebrowTone;
13
+ } & import("react").RefAttributes<HTMLParagraphElement>>;
@@ -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 shelf or section title with shared case and tracking. */
5
+ export const SectionHeading = forwardRef(function SectionHeading({ className, ...props }, ref) {
6
+ return (_jsx("h2", { ...props, ref: ref, className: cn("caps-section-heading", className) }));
7
+ });
8
+ /** A small contextual label with shared case and tracking. */
9
+ export const Eyebrow = forwardRef(function Eyebrow({ className, tone = "quiet", ...props }, ref) {
10
+ return (_jsx("p", { ...props, ref: ref, className: cn("caps-eyebrow", className), "data-tone": tone }));
11
+ });
@@ -0,0 +1,125 @@
1
+ import { type HTMLAttributes, type ReactNode } from "react";
2
+ /** Props accepted by SpecRuler. */
3
+ export type SpecRulerProps = Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
4
+ /** A short section label, such as `01 · Plans`. */
5
+ label: ReactNode;
6
+ };
7
+ /**
8
+ * A tick-marked rule that separates sections, with crosshairs at both ends.
9
+ * It is decorative: the section heading carries the accessible name.
10
+ */
11
+ export declare const SpecRuler: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
12
+ /** A short section label, such as `01 · Plans`. */
13
+ label: ReactNode;
14
+ } & import("react").RefAttributes<HTMLDivElement>>;
15
+ /** Props accepted by SpecFrame. */
16
+ export type SpecFrameProps = Omit<HTMLAttributes<HTMLElement>, "children"> & {
17
+ /** Caller-owned media, such as an `img` with its own alt text. */
18
+ children: ReactNode;
19
+ /** A short printed caption under the frame. */
20
+ caption?: ReactNode;
21
+ /** `inverse` seats dark media, such as a terminal readout, in the frame. */
22
+ surface?: "default" | "inverse";
23
+ };
24
+ /** A figure seated in a hatched band, like a plate in a printed manual. */
25
+ export declare const SpecFrame: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLElement>, "children"> & {
26
+ /** Caller-owned media, such as an `img` with its own alt text. */
27
+ children: ReactNode;
28
+ /** A short printed caption under the frame. */
29
+ caption?: ReactNode;
30
+ /** `inverse` seats dark media, such as a terminal readout, in the frame. */
31
+ surface?: "default" | "inverse";
32
+ } & import("react").RefAttributes<HTMLElement>>;
33
+ /** One fact in a SpecFacts strip. */
34
+ export type SpecFact = {
35
+ id: string;
36
+ value: ReactNode;
37
+ label: ReactNode;
38
+ };
39
+ /** Props accepted by SpecFacts. */
40
+ export type SpecFactsProps = Omit<HTMLAttributes<HTMLDListElement>, "children"> & {
41
+ facts: readonly SpecFact[];
42
+ };
43
+ /** A ruled strip of short facts: a big value over a small label. */
44
+ export declare const SpecFacts: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLDListElement>, "children"> & {
45
+ facts: readonly SpecFact[];
46
+ } & import("react").RefAttributes<HTMLDListElement>>;
47
+ /** One step in a SpecSteps list. */
48
+ export type SpecStep = {
49
+ id: string;
50
+ title: ReactNode;
51
+ body: ReactNode;
52
+ };
53
+ /** Props accepted by SpecSteps. */
54
+ export type SpecStepsProps = Omit<HTMLAttributes<HTMLOListElement>, "children"> & {
55
+ steps: readonly SpecStep[];
56
+ };
57
+ /** A numbered row of steps in ruled cells, numbered 01, 02 and on. */
58
+ export declare const SpecSteps: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLOListElement>, "children"> & {
59
+ steps: readonly SpecStep[];
60
+ } & import("react").RefAttributes<HTMLOListElement>>;
61
+ /** One question in a SpecFaq list. */
62
+ export type SpecFaqItem = {
63
+ id: string;
64
+ question: ReactNode;
65
+ /** Caller-reviewed answer content. */
66
+ answer: ReactNode;
67
+ };
68
+ /** Props accepted by SpecFaq. */
69
+ export type SpecFaqProps = Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
70
+ items: readonly SpecFaqItem[];
71
+ /** Ids of the items that start open. */
72
+ defaultOpen?: readonly string[];
73
+ };
74
+ /**
75
+ * Questions and answers as native disclosures. It works without JavaScript,
76
+ * and every answer stays in the document for search and find-in-page.
77
+ */
78
+ export declare const SpecFaq: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
79
+ items: readonly SpecFaqItem[];
80
+ /** Ids of the items that start open. */
81
+ defaultOpen?: readonly string[];
82
+ } & import("react").RefAttributes<HTMLDivElement>>;
83
+ /** One labelled part of a SpecDiagram, placed in percent of the art. */
84
+ export type SpecDiagramMarker = {
85
+ id: string;
86
+ /** A short tag drawn on the art, such as `A`. */
87
+ tag: string;
88
+ /** Distance from the art's left edge, 0 to 100. */
89
+ x: number;
90
+ /** Distance from the art's top edge, 0 to 100. */
91
+ y: number;
92
+ label: ReactNode;
93
+ note?: ReactNode;
94
+ };
95
+ /** Props accepted by SpecDiagram. */
96
+ export type SpecDiagramProps = Omit<HTMLAttributes<HTMLElement>, "children"> & {
97
+ /** Caller-owned art, such as an `img` with its own alt text. */
98
+ art: ReactNode;
99
+ markers: readonly SpecDiagramMarker[];
100
+ };
101
+ /**
102
+ * A manual-style parts diagram: tags drawn on the art and a legend that
103
+ * names each part. The legend is the accessible text; tags are decorative.
104
+ */
105
+ export declare const SpecDiagram: import("react").ForwardRefExoticComponent<Omit<HTMLAttributes<HTMLElement>, "children"> & {
106
+ /** Caller-owned art, such as an `img` with its own alt text. */
107
+ art: ReactNode;
108
+ markers: readonly SpecDiagramMarker[];
109
+ } & import("react").RefAttributes<HTMLElement>>;
110
+ /** Props accepted by SpecPrintFilter. */
111
+ export type SpecPrintFilterProps = {
112
+ /** Misregistration of the second ink, in CSS pixels. Defaults to 2, 1. */
113
+ offset?: {
114
+ x: number;
115
+ y: number;
116
+ };
117
+ };
118
+ /**
119
+ * The `#caps-print` SVG filter, rendered once per page. It turns 1-bit art
120
+ * (dark ink on light paper) into the theme's ink on a transparent ground,
121
+ * with a second ink printed slightly off register underneath, like a two-drum
122
+ * risograph. Art opts in through the theme's `--caps-print-filter`; the inks
123
+ * come from `--caps-print-ink` and `--caps-print-offset`.
124
+ */
125
+ export declare function SpecPrintFilter({ offset, }: SpecPrintFilterProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,47 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef } from "react";
3
+ import { cn } from "../lib/cn.js";
4
+ /**
5
+ * A tick-marked rule that separates sections, with crosshairs at both ends.
6
+ * It is decorative: the section heading carries the accessible name.
7
+ */
8
+ export const SpecRuler = forwardRef(function SpecRuler({ className, label, ...props }, ref) {
9
+ return (_jsx("div", { "aria-hidden": "true", ...props, className: cn("caps-spec-ruler", className), ref: ref, children: _jsx("span", { className: "caps-spec-ruler-label", children: label }) }));
10
+ });
11
+ /** A figure seated in a hatched band, like a plate in a printed manual. */
12
+ export const SpecFrame = forwardRef(function SpecFrame({ caption, children, className, surface = "default", ...props }, ref) {
13
+ return (_jsxs("figure", { ...props, className: cn("caps-spec-frame", className), "data-surface": surface, ref: ref, children: [_jsx("div", { className: "caps-spec-frame-window", children: children }), caption !== undefined ? (_jsx("figcaption", { className: "caps-spec-frame-caption", children: caption })) : null] }));
14
+ });
15
+ /** A ruled strip of short facts: a big value over a small label. */
16
+ export const SpecFacts = forwardRef(function SpecFacts({ className, facts, ...props }, ref) {
17
+ return (_jsx("dl", { ...props, className: cn("caps-spec-facts", className), ref: ref, children: facts.map((fact) => (_jsxs("div", { className: "caps-spec-fact", children: [_jsx("dt", { className: "caps-spec-fact-label", children: fact.label }), _jsx("dd", { className: "caps-spec-fact-value", children: fact.value })] }, fact.id))) }));
18
+ });
19
+ /** A numbered row of steps in ruled cells, numbered 01, 02 and on. */
20
+ export const SpecSteps = forwardRef(function SpecSteps({ className, steps, ...props }, ref) {
21
+ return (_jsx("ol", { ...props, className: cn("caps-spec-steps", className), ref: ref, children: steps.map((step, index) => (_jsxs("li", { className: "caps-spec-step", children: [_jsx("span", { "aria-hidden": "true", className: "caps-spec-step-number", children: String(index + 1).padStart(2, "0") }), _jsx("h3", { className: "caps-spec-step-title", children: step.title }), _jsx("div", { className: "caps-spec-step-body", children: step.body })] }, step.id))) }));
22
+ });
23
+ /**
24
+ * Questions and answers as native disclosures. It works without JavaScript,
25
+ * and every answer stays in the document for search and find-in-page.
26
+ */
27
+ export const SpecFaq = forwardRef(function SpecFaq({ className, defaultOpen = [], items, ...props }, ref) {
28
+ return (_jsx("div", { ...props, className: cn("caps-spec-faq", className), ref: ref, children: items.map((item, index) => (_jsxs("details", { className: "caps-spec-faq-item", open: defaultOpen.includes(item.id) || undefined, children: [_jsxs("summary", { className: "caps-spec-faq-question", children: [_jsx("span", { "aria-hidden": "true", className: "caps-spec-faq-number", children: String(index + 1).padStart(2, "0") }), _jsx("span", { className: "caps-spec-faq-text", children: item.question }), _jsx("span", { "aria-hidden": "true", className: "caps-spec-faq-mark" })] }), _jsx("div", { className: "caps-spec-faq-answer", children: item.answer })] }, item.id))) }));
29
+ });
30
+ const percent = (value) => `${String(Math.min(100, Math.max(0, value)))}%`;
31
+ /**
32
+ * A manual-style parts diagram: tags drawn on the art and a legend that
33
+ * names each part. The legend is the accessible text; tags are decorative.
34
+ */
35
+ export const SpecDiagram = forwardRef(function SpecDiagram({ art, className, markers, ...props }, ref) {
36
+ return (_jsxs("figure", { ...props, className: cn("caps-spec-diagram", className), ref: ref, children: [_jsxs("div", { className: "caps-spec-diagram-art", children: [art, markers.map((marker) => (_jsx("span", { "aria-hidden": "true", className: "caps-spec-diagram-tag", style: { left: percent(marker.x), top: percent(marker.y) }, children: marker.tag }, marker.id)))] }), _jsx("figcaption", { className: "caps-spec-diagram-legend", children: _jsx("ul", { children: markers.map((marker) => (_jsxs("li", { children: [_jsx("span", { "aria-hidden": "true", className: "caps-spec-diagram-key", children: marker.tag }), _jsx("span", { className: "caps-spec-diagram-label", children: marker.label }), marker.note !== undefined ? (_jsx("span", { className: "caps-spec-diagram-note", children: marker.note })) : null] }, marker.id))) }) })] }));
37
+ });
38
+ /**
39
+ * The `#caps-print` SVG filter, rendered once per page. It turns 1-bit art
40
+ * (dark ink on light paper) into the theme's ink on a transparent ground,
41
+ * with a second ink printed slightly off register underneath, like a two-drum
42
+ * risograph. Art opts in through the theme's `--caps-print-filter`; the inks
43
+ * come from `--caps-print-ink` and `--caps-print-offset`.
44
+ */
45
+ export function SpecPrintFilter({ offset = { x: 2, y: 1 }, }) {
46
+ return (_jsx("svg", { "aria-hidden": "true", className: "caps-print-filter", focusable: "false", children: _jsxs("filter", { colorInterpolationFilters: "sRGB", height: "100%", id: "caps-print", width: "100%", x: "0", y: "0", children: [_jsx("feColorMatrix", { in: "SourceGraphic", result: "darkness", type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -0.2976 -1.0013 -0.1011 0 1.3" }), _jsx("feComposite", { in: "darkness", in2: "SourceAlpha", operator: "in", result: "coverage" }), _jsx("feFlood", { className: "caps-print-filter-offset", result: "offsetInk" }), _jsx("feComposite", { in: "offsetInk", in2: "coverage", operator: "in", result: "offsetPrint" }), _jsx("feOffset", { dx: offset.x, dy: offset.y, in: "offsetPrint", result: "offsetShifted" }), _jsx("feFlood", { className: "caps-print-filter-ink", result: "ink" }), _jsx("feComposite", { in: "ink", in2: "coverage", operator: "in", result: "inkPrint" }), _jsxs("feMerge", { children: [_jsx("feMergeNode", { in: "offsetShifted" }), _jsx("feMergeNode", { in: "inkPrint" })] })] }) }));
47
+ }
@@ -0,0 +1,83 @@
1
+ import { type HTMLAttributes, type ReactNode } from "react";
2
+ import { type StatusGlyph, type StatusMotion, type StatusTone } from "../components/status.js";
3
+ /**
4
+ * One footer readout and the small tray it opens. Semantic data only: the
5
+ * chip's finish, the tray's material and the seam between them come from
6
+ * theme tokens (`--caps-status-tray-*`), never from a prop.
7
+ */
8
+ export type StatusTrayItem = Readonly<{
9
+ id: string;
10
+ /** Short readout, e.g. "Ports". */
11
+ label: ReactNode;
12
+ /** Positive counts render after the label; zero is hidden. */
13
+ count?: number;
14
+ /** A live-state bead before the label. Omit for none. */
15
+ tone?: StatusTone;
16
+ glyph?: StatusGlyph;
17
+ motion?: StatusMotion;
18
+ /** Accessible name when the label alone is ambiguous. */
19
+ accessibleLabel?: string;
20
+ /** Tray heading; defaults to the label. */
21
+ title?: ReactNode;
22
+ /** Tray header actions such as Refresh. */
23
+ actions?: ReactNode;
24
+ /** Tray body. */
25
+ content: ReactNode;
26
+ /** Keep the chip but disable opening, e.g. no Computer. */
27
+ disabled?: boolean;
28
+ /**
29
+ * Controls placed right after this chip, in DOM and keyboard order, so a
30
+ * host can interleave its own controls between chips.
31
+ */
32
+ after?: ReactNode;
33
+ }>;
34
+ /** Controlled selection and structural slots for a row of footer trays. */
35
+ export type StatusTrayProps = Omit<HTMLAttributes<HTMLDivElement>, "title"> & {
36
+ /** Readouts and their tray contents in display order. */
37
+ items: readonly StatusTrayItem[];
38
+ /** Which tray is open. The host owns this state. */
39
+ openId: string | null;
40
+ /** Requests a selection change or dismissal. */
41
+ onOpenChange: (id: string | null) => void;
42
+ /** Leading readouts that never open a tray (connection state, etc.). */
43
+ leading?: ReactNode;
44
+ /** Trailing controls after the chips (Send, Expand, …). */
45
+ trailing?: ReactNode;
46
+ /**
47
+ * Structural seat. `housing` sits on the plastic below a screen; `screen`
48
+ * sits inside a Display as flat, screen-native text (the wiki's screen
49
+ * material rule); `host` means a host's own chrome draws the chips, so
50
+ * only the open tray renders here. The look of each seat is theme-owned.
51
+ */
52
+ placement?: "housing" | "screen" | "host";
53
+ /** Which edge the tray aligns to. */
54
+ align?: "start" | "end";
55
+ /**
56
+ * For `host` placement: where the host's trigger starts, in CSS pixels from
57
+ * this tray's inline start, so the open tray sits above it.
58
+ */
59
+ hostInset?: number;
60
+ };
61
+ /** A footer row of readout chips; one opens its tray above the row at a time. */
62
+ export declare function StatusTray({ items, openId, onOpenChange, leading, trailing, placement, align, hostInset, className, ...props }: StatusTrayProps): import("react/jsx-runtime").JSX.Element;
63
+ /** A group of tray rows. Precede it with a DataListHeading to label it. */
64
+ export declare function StatusTrayList({ children, className, ...props }: HTMLAttributes<HTMLDivElement>): import("react/jsx-runtime").JSX.Element;
65
+ /**
66
+ * One line: the host's icon, a title, a muted detail that truncates, and a
67
+ * quiet text action (a ghost Button) at the end.
68
+ */
69
+ export declare function StatusTrayRow({ icon, primary, secondary, actions, className, ...props }: Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
70
+ /** The App's own icon for this kind of row, e.g. a Sigil or a Status. */
71
+ icon?: ReactNode;
72
+ primary: ReactNode;
73
+ secondary?: ReactNode;
74
+ actions?: ReactNode;
75
+ }): import("react/jsx-runtime").JSX.Element;
76
+ /**
77
+ * A quiet sentence for an empty or unavailable feed. Empty reads "All caught
78
+ * up." unless the host says otherwise; unavailable takes a `title`.
79
+ */
80
+ export declare function StatusTrayNote({ children, title, }: {
81
+ children?: ReactNode;
82
+ title?: string;
83
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,79 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { X } from "lucide-react";
3
+ import { Fragment, useEffect, useId, useRef, } from "react";
4
+ import { IconButton } from "../components/icon-button.js";
5
+ import { Popover, PopoverAnchor } from "../components/popover.js";
6
+ import { Status, } from "../components/status.js";
7
+ import { cn } from "../lib/cn.js";
8
+ /** A footer row of readout chips; one opens its tray above the row at a time. */
9
+ export function StatusTray({ items, openId, onOpenChange, leading, trailing, placement = "housing", align = "end", hostInset, className, ...props }) {
10
+ const scope = useId();
11
+ const root = useRef(null);
12
+ const panel = useRef(null);
13
+ const triggers = useRef(new Map());
14
+ const open = items.find((item) => item.id === openId && !item.disabled);
15
+ const activeId = open?.id;
16
+ const close = () => {
17
+ if (activeId)
18
+ triggers.current.get(activeId)?.focus();
19
+ onOpenChange(null);
20
+ };
21
+ useEffect(() => {
22
+ if (activeId)
23
+ panel.current?.focus();
24
+ }, [activeId]);
25
+ useEffect(() => {
26
+ // A dynamic position is a custom property; the stylesheet clamps it.
27
+ if (hostInset === undefined)
28
+ root.current?.style.removeProperty("--caps-status-tray-host-inset");
29
+ else
30
+ root.current?.style.setProperty("--caps-status-tray-host-inset", `${String(Math.max(0, hostInset))}px`);
31
+ }, [hostInset]);
32
+ useEffect(() => {
33
+ if (!activeId)
34
+ return;
35
+ const onKey = (event) => {
36
+ if (event.key !== "Escape" || event.defaultPrevented)
37
+ return;
38
+ event.preventDefault();
39
+ triggers.current.get(activeId)?.focus();
40
+ onOpenChange(null);
41
+ };
42
+ const onPointer = (event) => {
43
+ if (event.target instanceof Node && !root.current?.contains(event.target))
44
+ onOpenChange(null);
45
+ };
46
+ document.addEventListener("keydown", onKey);
47
+ document.addEventListener("pointerdown", onPointer);
48
+ return () => {
49
+ document.removeEventListener("keydown", onKey);
50
+ document.removeEventListener("pointerdown", onPointer);
51
+ };
52
+ }, [activeId, onOpenChange]);
53
+ return (_jsxs(PopoverAnchor, { ...props, ref: root, className: cn("caps-status-tray", className), "data-placement": placement, "data-align": align, children: [open ? (_jsxs(Popover, { open: true, ref: panel, tabIndex: -1, side: "top", id: `${scope}-${open.id}`, role: "dialog", "aria-labelledby": `${scope}-title`, className: "caps-status-tray-panel", "data-status-tray-panel": open.id, children: [_jsxs("div", { className: "caps-status-tray-head", children: [open.tone ? (_jsx(Status, { size: "compact", tone: open.tone, glyph: open.glyph ?? "dot" })) : null, _jsx("span", { id: `${scope}-title`, className: "caps-status-tray-title", children: open.title ?? open.label }), open.actions, _jsx(IconButton, { "aria-label": "Close tray", icon: _jsx(X, { "aria-hidden": "true" }), onClick: close })] }), _jsx("div", { className: "caps-status-tray-body", children: open.content })] })) : null, placement === "host" ? null : (_jsxs("div", { className: "caps-status-tray-row", children: [leading, _jsx("div", { className: "caps-status-tray-chips", children: items.map((item) => (_jsxs(Fragment, { children: [_jsxs("button", { ref: (node) => {
54
+ if (node)
55
+ triggers.current.set(item.id, node);
56
+ else
57
+ triggers.current.delete(item.id);
58
+ }, type: "button", className: "caps-status-tray-chip", "aria-expanded": activeId === item.id, "aria-controls": activeId === item.id ? `${scope}-${item.id}` : undefined, "aria-label": item.accessibleLabel, disabled: item.disabled, title: item.disabled ? item.accessibleLabel : undefined, "aria-haspopup": "dialog", "data-status-tray-chip": item.id, onClick: () => {
59
+ onOpenChange(openId === item.id ? null : item.id);
60
+ }, children: [item.tone ? (_jsx(Status, { size: "compact", glyph: item.glyph ?? "dot", motion: item.motion ?? "none", tone: item.tone })) : null, _jsx("span", { className: "caps-status-tray-label", children: item.label }), item.count !== undefined && item.count > 0 ? (_jsx("span", { className: "caps-status-tray-count", children: item.count })) : null] }), item.after] }, item.id))) }), trailing] }))] }));
61
+ }
62
+ /** A group of tray rows. Precede it with a DataListHeading to label it. */
63
+ export function StatusTrayList({ children, className, ...props }) {
64
+ return (_jsx("div", { ...props, className: cn("caps-status-tray-list", className), children: children }));
65
+ }
66
+ /**
67
+ * One line: the host's icon, a title, a muted detail that truncates, and a
68
+ * quiet text action (a ghost Button) at the end.
69
+ */
70
+ export function StatusTrayRow({ icon, primary, secondary, actions, className, ...props }) {
71
+ return (_jsxs("div", { ...props, className: cn("caps-status-tray-item", className), children: [icon ? _jsx("span", { className: "caps-status-tray-icon", children: icon }) : null, _jsxs("span", { className: "caps-status-tray-text", children: [_jsx("span", { className: "caps-status-tray-primary", children: primary }), secondary ? (_jsx("span", { className: "caps-status-tray-secondary", children: secondary })) : null] }), actions ? (_jsx("span", { className: "caps-status-tray-actions", children: actions })) : null] }));
72
+ }
73
+ /**
74
+ * A quiet sentence for an empty or unavailable feed. Empty reads "All caught
75
+ * up." unless the host says otherwise; unavailable takes a `title`.
76
+ */
77
+ export function StatusTrayNote({ children = "All caught up.", title, }) {
78
+ return (_jsxs("div", { className: "caps-status-tray-note", children: [title ? (_jsx("strong", { className: "caps-status-tray-note-title", children: title })) : null, _jsx("p", { children: children })] }));
79
+ }
@@ -0,0 +1,48 @@
1
+ import type { JSX } from "react";
2
+ /**
3
+ * LAW — queue thumbnails are decorative. The adjacent filename is the row's
4
+ * accessible file fact; lifecycle status, progress, and actions remain named.
5
+ */
6
+ export type UploadQueueAction = Readonly<{
7
+ accessibleLabel: string;
8
+ label: string;
9
+ }>;
10
+ /** Caller-owned labels for the row actions that may be shown. */
11
+ export type UploadQueueActions = Readonly<{
12
+ cancel?: UploadQueueAction;
13
+ remove?: UploadQueueAction;
14
+ retry?: UploadQueueAction;
15
+ }>;
16
+ /** Caller-provided upload queue item data. */
17
+ export type UploadQueueItem = Readonly<{
18
+ actions: UploadQueueActions;
19
+ alert?: string;
20
+ id: string;
21
+ name: string;
22
+ preview: UploadQueuePreview;
23
+ /** Null means the transport does not report byte progress. */
24
+ progress: number | null;
25
+ progressLabel: string;
26
+ statusLabel: string;
27
+ }>;
28
+ /** A caller-provided file or image preview for one upload row. */
29
+ export type UploadQueuePreview = Readonly<{
30
+ kind: "file";
31
+ }> | Readonly<{
32
+ kind: "image";
33
+ url: string;
34
+ }>;
35
+ /** Props accepted by UploadQueue. */
36
+ export type UploadQueueProps = Readonly<{
37
+ className?: string;
38
+ items: readonly UploadQueueItem[];
39
+ /** Handles a caller-requested cancellation. */
40
+ onCancel: (id: string) => Promise<void> | void;
41
+ /** Handles removal of a completed or failed row. */
42
+ onRemove: (id: string) => void;
43
+ /** Handles a caller-requested retry. */
44
+ onRetry: (id: string) => Promise<void> | void;
45
+ rowClassName?: string;
46
+ }>;
47
+ /** Product-neutral upload facts and affordances; lifecycle stays with the host. */
48
+ export declare function UploadQueue({ className, items, onCancel, onRemove, onRetry, rowClassName, }: UploadQueueProps): JSX.Element | null;
@@ -0,0 +1,24 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { FileImage, RotateCcw, X } from "lucide-react";
3
+ import { IconButton } from "../components/icon-button.js";
4
+ import { Progress } from "../components/progress.js";
5
+ /** Product-neutral upload facts and affordances; lifecycle stays with the host. */
6
+ export function UploadQueue({ className, items, onCancel, onRemove, onRetry, rowClassName, }) {
7
+ if (!items.length)
8
+ return null;
9
+ return (_jsx("div", { "aria-live": "polite", className: `caps-upload-queue flex w-full min-w-0 flex-col gap-sm ${className ?? ""}`, "data-upload-rows": true, children: items.map((item) => (_jsx(UploadQueueRow, { item: item, onCancel: onCancel, onRemove: onRemove, onRetry: onRetry, ...(rowClassName === undefined ? {} : { rowClassName }) }, item.id))) }));
10
+ }
11
+ function UploadQueueAction({ action, id, onAction, retry = false, }) {
12
+ if (!action)
13
+ return null;
14
+ return (_jsx(IconButton, { "aria-label": action.accessibleLabel, title: action.label, variant: "ghost", size: "xs", className: "motion-reduce:transition-none", icon: retry ? _jsx(RotateCcw, {}) : _jsx(X, {}), onClick: () => void onAction(id), type: "button" }));
15
+ }
16
+ function UploadQueueDetails({ item }) {
17
+ return (_jsxs("div", { className: "min-w-0", children: [_jsx("span", { className: "block min-w-0 truncate", title: item.name, children: item.name }), _jsx("div", { className: "caps-upload-details", children: _jsxs("span", { "aria-live": item.alert ? "assertive" : undefined, className: "caps-upload-status min-w-0 break-words", "data-upload-status": true, role: item.alert ? "alert" : undefined, children: [item.alert ?? item.statusLabel, " ", item.progressLabel] }) })] }));
18
+ }
19
+ function UploadQueueRow({ item, onCancel, onRemove, onRetry, rowClassName, }) {
20
+ return (_jsxs("div", { className: `caps-upload-row grid w-full min-w-0 max-w-full grid-cols-[2rem_minmax(0,1fr)_auto] items-center gap-sm p-sm text-xs ${rowClassName ?? ""}`, children: [item.preview.kind === "image" ? (_jsx("img", { alt: "", className: "caps-upload-preview mask mask-squircle size-8 shrink-0 object-cover", src: item.preview.url })) : (_jsx("span", { "aria-hidden": "true", className: "caps-upload-preview mask mask-squircle flex size-8 shrink-0 items-center justify-center bg-base-300", children: _jsx(FileImage, { className: "size-4" }) })), _jsx(UploadQueueDetails, { item: item }), _jsx(UploadQueueRowActions, { actions: item.actions, id: item.id, onCancel: onCancel, onRemove: onRemove, onRetry: onRetry }), _jsx(Progress, { "aria-label": `${item.name} progress`, className: "caps-upload-progress", tone: item.alert ? "error" : item.progress === 100 ? "success" : "accent", max: 100, value: item.progress ?? (item.alert ? 0 : undefined) })] }));
21
+ }
22
+ function UploadQueueRowActions({ actions, id, onCancel, onRemove, onRetry, }) {
23
+ return (_jsxs("div", { className: "caps-upload-actions flex min-w-0 flex-wrap justify-end gap-xs", children: [_jsx(UploadQueueAction, { action: actions.retry, id: id, onAction: onRetry, retry: true }), _jsx(UploadQueueAction, { action: actions.cancel, id: id, onAction: onCancel }), _jsx(UploadQueueAction, { action: actions.remove, id: id, onAction: onRemove })] }));
24
+ }
@@ -0,0 +1,16 @@
1
+ import type { ReactNode } from "react";
2
+ import { type ButtonProps } from "./button.js";
3
+ /** A full-width, structured action for a data list. */
4
+ export type ActionRowProps = Omit<ButtonProps, "children"> & {
5
+ icon?: ReactNode;
6
+ label: ReactNode;
7
+ description?: ReactNode;
8
+ trailing?: ReactNode;
9
+ density?: "regular" | "compact";
10
+ /** `lg` gives a character-sized mark (a sprite head) more room than an icon. */
11
+ iconSize?: "default" | "lg";
12
+ /** `card` molds the row into its own raised plastic card. */
13
+ appearance?: "plain" | "card";
14
+ };
15
+ /** Render a clear label, supporting detail, and optional trailing status. */
16
+ export declare function ActionRow({ description, icon, label, density, appearance, iconSize, size, trailing, ...buttonProps }: ActionRowProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button } from "./button.js";
3
+ import { cn } from "../lib/cn.js";
4
+ /** Render a clear label, supporting detail, and optional trailing status. */
5
+ export function ActionRow({ description, icon, label, density = "regular", appearance = "plain", iconSize = "default", size, trailing, ...buttonProps }) {
6
+ return (_jsxs(Button, { ...buttonProps, className: cn("caps-action-row", appearance === "card" && "caps-action-row-card", density === "compact"
7
+ ? "h-auto min-h-10 w-full justify-start gap-xs px-xs py-2xs text-left"
8
+ : "h-auto min-h-14 w-full justify-start gap-sm px-sm py-xs text-left", buttonProps.className), size: size ?? (density === "compact" ? "default" : "lg"), variant: buttonProps.variant ?? "ghost", children: [icon ? (_jsx("span", { className: density === "compact"
9
+ ? `grid ${iconSize === "lg" ? "size-8" : "size-7"} shrink-0 place-items-center [&_:is(svg,.caps-monogram)]:size-5`
10
+ : `grid ${iconSize === "lg" ? "size-12" : "size-10"} shrink-0 place-items-center [&_:is(svg,.caps-monogram)]:size-7`, children: icon })) : null, _jsxs("span", { className: "caps-action-row-copy", children: [_jsx("span", { className: "caps-action-row-label max-w-full truncate", children: label }), description ? (_jsx("span", { className: "caps-action-row-description max-w-full truncate", children: description })) : null] }), trailing ? (_jsx("span", { className: "caps-action-row-trailing", children: trailing })) : null] }));
11
+ }
@@ -0,0 +1,33 @@
1
+ import { type ReactNode } from "react";
2
+ /** Where a piece of agent work stands. */
3
+ export type ActivityState = "running" | "done" | "failed";
4
+ /** Short elapsed time: `0.4s`, `4.2s`, `42s`, `3m 05s`. */
5
+ export declare function formatElapsed(milliseconds: number): string;
6
+ /**
7
+ * A clock that ticks while `running` and holds still otherwise. Times are
8
+ * epoch milliseconds (`Date.now()`), owned by the caller.
9
+ */
10
+ export declare function useElapsed(startedAt: number, finishedAt: number | undefined, running: boolean): number;
11
+ /** Props accepted by ActivityLine. */
12
+ export type ActivityLineProps = Readonly<{
13
+ state: ActivityState;
14
+ /** When the work started (epoch ms). */
15
+ startedAt: number;
16
+ /** When it ended (epoch ms); otherwise the moment it stopped running. */
17
+ finishedAt?: number | undefined;
18
+ /** What is happening, such as "Thinking". */
19
+ label: string;
20
+ /** How finished work reads before its time, such as "Thought for". */
21
+ doneLabel: string;
22
+ /** How stopped work reads before its time, such as "Stopped after". */
23
+ failedLabel?: string;
24
+ /** The trace: shown while running, folded away once done. */
25
+ children?: ReactNode;
26
+ className?: string;
27
+ }>;
28
+ /**
29
+ * One line of agent activity. While running it says what is happening with
30
+ * a live clock and shows its trace; when done it settles into "Thought for
31
+ * 4.2s" and folds the trace away, one click from reopening.
32
+ */
33
+ export declare function ActivityLine({ state, startedAt, finishedAt, label, doneLabel, failedLabel, children, className, }: ActivityLineProps): import("react/jsx-runtime").JSX.Element;