@usetheo/ui 0.13.0 → 0.13.2

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 (1235) hide show
  1. package/CHANGELOG.md +541 -69
  2. package/DESIGN.md +18 -18
  3. package/NOTICE +2 -2
  4. package/README.md +54 -52
  5. package/dist/chunk-23YEYNDS.js +89 -0
  6. package/dist/chunk-23YEYNDS.js.map +1 -0
  7. package/dist/chunk-25KBUQEQ.js +95 -0
  8. package/dist/chunk-25KBUQEQ.js.map +1 -0
  9. package/dist/chunk-2NTEJRPA.js +212 -0
  10. package/dist/chunk-2NTEJRPA.js.map +1 -0
  11. package/dist/chunk-2NZYMQKT.js +56 -0
  12. package/dist/chunk-2NZYMQKT.js.map +1 -0
  13. package/dist/chunk-2OVFVPSZ.js +26 -0
  14. package/dist/chunk-2OVFVPSZ.js.map +1 -0
  15. package/dist/chunk-2UP7SECE.js +78 -0
  16. package/dist/chunk-2UP7SECE.js.map +1 -0
  17. package/dist/chunk-33ETHPT7.js +112 -0
  18. package/dist/chunk-33ETHPT7.js.map +1 -0
  19. package/dist/chunk-33IIDFSM.js +43 -0
  20. package/dist/chunk-33IIDFSM.js.map +1 -0
  21. package/dist/chunk-345HYADQ.js +88 -0
  22. package/dist/chunk-345HYADQ.js.map +1 -0
  23. package/dist/chunk-357XIC2N.js +98 -0
  24. package/dist/chunk-357XIC2N.js.map +1 -0
  25. package/dist/chunk-3YOPTHZH.js +31 -0
  26. package/dist/chunk-3YOPTHZH.js.map +1 -0
  27. package/dist/chunk-44ZNZZUS.js +111 -0
  28. package/dist/chunk-44ZNZZUS.js.map +1 -0
  29. package/dist/chunk-45FWKR23.js +62 -0
  30. package/dist/chunk-45FWKR23.js.map +1 -0
  31. package/dist/chunk-47IPOYLQ.js +116 -0
  32. package/dist/chunk-47IPOYLQ.js.map +1 -0
  33. package/dist/chunk-4EH6F54D.js +69 -0
  34. package/dist/chunk-4EH6F54D.js.map +1 -0
  35. package/dist/chunk-4EKF4EIE.js +140 -0
  36. package/dist/chunk-4EKF4EIE.js.map +1 -0
  37. package/dist/chunk-4XYFJIRC.js +65 -0
  38. package/dist/chunk-4XYFJIRC.js.map +1 -0
  39. package/dist/chunk-52J7SDYH.js +48 -0
  40. package/dist/chunk-52J7SDYH.js.map +1 -0
  41. package/dist/chunk-5YX76GH6.js +70 -0
  42. package/dist/chunk-5YX76GH6.js.map +1 -0
  43. package/dist/chunk-624AATQZ.js +77 -0
  44. package/dist/chunk-624AATQZ.js.map +1 -0
  45. package/dist/chunk-65YSFZAN.js +192 -0
  46. package/dist/chunk-65YSFZAN.js.map +1 -0
  47. package/dist/chunk-6IODJQWC.js +47 -0
  48. package/dist/chunk-6IODJQWC.js.map +1 -0
  49. package/dist/chunk-6ORS6XOE.js +57 -0
  50. package/dist/chunk-6ORS6XOE.js.map +1 -0
  51. package/dist/chunk-6V2LQEPT.js +165 -0
  52. package/dist/chunk-6V2LQEPT.js.map +1 -0
  53. package/dist/chunk-75IDWFYX.js +134 -0
  54. package/dist/chunk-75IDWFYX.js.map +1 -0
  55. package/dist/chunk-7BQXMG2A.js +93 -0
  56. package/dist/chunk-7BQXMG2A.js.map +1 -0
  57. package/dist/chunk-7RFWVNQA.js +47 -0
  58. package/dist/chunk-7RFWVNQA.js.map +1 -0
  59. package/dist/chunk-ABBXLAJW.js +74 -0
  60. package/dist/chunk-ABBXLAJW.js.map +1 -0
  61. package/dist/chunk-ACZNFEOZ.js +180 -0
  62. package/dist/chunk-ACZNFEOZ.js.map +1 -0
  63. package/dist/chunk-AJ2LNQUQ.js +108 -0
  64. package/dist/chunk-AJ2LNQUQ.js.map +1 -0
  65. package/dist/chunk-AX6P3SDS.js +89 -0
  66. package/dist/chunk-AX6P3SDS.js.map +1 -0
  67. package/dist/chunk-AXUAQM45.js +154 -0
  68. package/dist/chunk-AXUAQM45.js.map +1 -0
  69. package/dist/chunk-B2FL7KBJ.js +65 -0
  70. package/dist/chunk-B2FL7KBJ.js.map +1 -0
  71. package/dist/chunk-B42EOFRD.js +106 -0
  72. package/dist/chunk-B42EOFRD.js.map +1 -0
  73. package/dist/chunk-BE232OKN.js +42 -0
  74. package/dist/chunk-BE232OKN.js.map +1 -0
  75. package/dist/chunk-BSF4Y4UT.js +77 -0
  76. package/dist/chunk-BSF4Y4UT.js.map +1 -0
  77. package/dist/chunk-BYUWQ6OP.js +45 -0
  78. package/dist/chunk-BYUWQ6OP.js.map +1 -0
  79. package/dist/chunk-C5ULP2P5.js +140 -0
  80. package/dist/chunk-C5ULP2P5.js.map +1 -0
  81. package/dist/chunk-CCG7PXLX.js +24 -0
  82. package/dist/chunk-CCG7PXLX.js.map +1 -0
  83. package/dist/chunk-CFVSXYVT.js +59 -0
  84. package/dist/chunk-CFVSXYVT.js.map +1 -0
  85. package/dist/chunk-CGWIOIEO.js +27 -0
  86. package/dist/chunk-CGWIOIEO.js.map +1 -0
  87. package/dist/chunk-CVFSNA4K.js +716 -0
  88. package/dist/chunk-CVFSNA4K.js.map +1 -0
  89. package/dist/chunk-CX54TUTT.js +144 -0
  90. package/dist/chunk-CX54TUTT.js.map +1 -0
  91. package/dist/chunk-DJK6H3FD.js +200 -0
  92. package/dist/chunk-DJK6H3FD.js.map +1 -0
  93. package/dist/chunk-E26M7ATD.js +61 -0
  94. package/dist/chunk-E26M7ATD.js.map +1 -0
  95. package/dist/chunk-E63IRXZZ.js +78 -0
  96. package/dist/chunk-E63IRXZZ.js.map +1 -0
  97. package/dist/chunk-EOTSD2GL.js +83 -0
  98. package/dist/chunk-EOTSD2GL.js.map +1 -0
  99. package/dist/chunk-ESJUISWY.js +45 -0
  100. package/dist/chunk-ESJUISWY.js.map +1 -0
  101. package/dist/chunk-ET7A3TQZ.js +158 -0
  102. package/dist/chunk-ET7A3TQZ.js.map +1 -0
  103. package/dist/chunk-ETTL6XGU.js +139 -0
  104. package/dist/chunk-ETTL6XGU.js.map +1 -0
  105. package/dist/chunk-EWDN56AS.js +24 -0
  106. package/dist/chunk-EWDN56AS.js.map +1 -0
  107. package/dist/chunk-FELH4AAQ.js +90 -0
  108. package/dist/chunk-FELH4AAQ.js.map +1 -0
  109. package/dist/chunk-FJZKA2LV.js +165 -0
  110. package/dist/chunk-FJZKA2LV.js.map +1 -0
  111. package/dist/chunk-FM72LBCJ.js +102 -0
  112. package/dist/chunk-FM72LBCJ.js.map +1 -0
  113. package/dist/chunk-FNQASFTK.js +53 -0
  114. package/dist/chunk-FNQASFTK.js.map +1 -0
  115. package/dist/chunk-FOE3XXBJ.js +965 -0
  116. package/dist/chunk-FOE3XXBJ.js.map +1 -0
  117. package/dist/chunk-GC52HWIL.js +41 -0
  118. package/dist/chunk-GC52HWIL.js.map +1 -0
  119. package/dist/chunk-GCKFA7X7.js +83 -0
  120. package/dist/chunk-GCKFA7X7.js.map +1 -0
  121. package/dist/chunk-GDMCDW66.js +19 -0
  122. package/dist/chunk-GDMCDW66.js.map +1 -0
  123. package/dist/chunk-GLRUM43F.js +121 -0
  124. package/dist/chunk-GLRUM43F.js.map +1 -0
  125. package/dist/chunk-H3L7WZDZ.js +74 -0
  126. package/dist/chunk-H3L7WZDZ.js.map +1 -0
  127. package/dist/chunk-H55WXDME.js +45 -0
  128. package/dist/chunk-H55WXDME.js.map +1 -0
  129. package/dist/chunk-HB45JHMM.js +43 -0
  130. package/dist/chunk-HB45JHMM.js.map +1 -0
  131. package/dist/chunk-HETHTYEZ.js +80 -0
  132. package/dist/chunk-HETHTYEZ.js.map +1 -0
  133. package/dist/chunk-HHSKNB32.js +55 -0
  134. package/dist/chunk-HHSKNB32.js.map +1 -0
  135. package/dist/chunk-HILOUYES.js +151 -0
  136. package/dist/chunk-HILOUYES.js.map +1 -0
  137. package/dist/chunk-HKVOCYTN.js +113 -0
  138. package/dist/chunk-HKVOCYTN.js.map +1 -0
  139. package/dist/chunk-HNRFBJ25.js +129 -0
  140. package/dist/chunk-HNRFBJ25.js.map +1 -0
  141. package/dist/chunk-HTJVHFNW.js +178 -0
  142. package/dist/chunk-HTJVHFNW.js.map +1 -0
  143. package/dist/chunk-HZ7Z22VW.js +130 -0
  144. package/dist/chunk-HZ7Z22VW.js.map +1 -0
  145. package/dist/chunk-II5Q5RIO.js +236 -0
  146. package/dist/chunk-II5Q5RIO.js.map +1 -0
  147. package/dist/chunk-ITEIRMSH.js +121 -0
  148. package/dist/chunk-ITEIRMSH.js.map +1 -0
  149. package/dist/chunk-JIZKW3WC.js +74 -0
  150. package/dist/chunk-JIZKW3WC.js.map +1 -0
  151. package/dist/chunk-JP3SHERK.js +154 -0
  152. package/dist/chunk-JP3SHERK.js.map +1 -0
  153. package/dist/chunk-JR4H3FJ2.js +74 -0
  154. package/dist/chunk-JR4H3FJ2.js.map +1 -0
  155. package/dist/chunk-JRW53TVG.js +53 -0
  156. package/dist/chunk-JRW53TVG.js.map +1 -0
  157. package/dist/chunk-JS5T2CRO.js +86 -0
  158. package/dist/chunk-JS5T2CRO.js.map +1 -0
  159. package/dist/chunk-JXOCE27Z.js +82 -0
  160. package/dist/chunk-JXOCE27Z.js.map +1 -0
  161. package/dist/chunk-JYW5YNF7.js +188 -0
  162. package/dist/chunk-JYW5YNF7.js.map +1 -0
  163. package/dist/chunk-KHBXI6AV.js +149 -0
  164. package/dist/chunk-KHBXI6AV.js.map +1 -0
  165. package/dist/chunk-KXZH7BTX.js +92 -0
  166. package/dist/chunk-KXZH7BTX.js.map +1 -0
  167. package/dist/chunk-LB4PMLCX.js +57 -0
  168. package/dist/chunk-LB4PMLCX.js.map +1 -0
  169. package/dist/chunk-LMGE2QEO.js +117 -0
  170. package/dist/chunk-LMGE2QEO.js.map +1 -0
  171. package/dist/chunk-M74ZYBOK.js +93 -0
  172. package/dist/chunk-M74ZYBOK.js.map +1 -0
  173. package/dist/chunk-ML7WLNIK.js +11 -0
  174. package/dist/chunk-ML7WLNIK.js.map +1 -0
  175. package/dist/chunk-MLEPCMTF.js +147 -0
  176. package/dist/chunk-MLEPCMTF.js.map +1 -0
  177. package/dist/chunk-NSZEZTDO.js +98 -0
  178. package/dist/chunk-NSZEZTDO.js.map +1 -0
  179. package/dist/chunk-OMR6ZGME.js +63 -0
  180. package/dist/chunk-OMR6ZGME.js.map +1 -0
  181. package/dist/chunk-ORVYP73T.js +223 -0
  182. package/dist/chunk-ORVYP73T.js.map +1 -0
  183. package/dist/chunk-OZFUUO2Q.js +50 -0
  184. package/dist/chunk-OZFUUO2Q.js.map +1 -0
  185. package/dist/chunk-PJWYIOY4.js +3 -0
  186. package/dist/chunk-PJWYIOY4.js.map +1 -0
  187. package/dist/chunk-PXT47DRZ.js +59 -0
  188. package/dist/chunk-PXT47DRZ.js.map +1 -0
  189. package/dist/chunk-QBSJM4XI.js +83 -0
  190. package/dist/chunk-QBSJM4XI.js.map +1 -0
  191. package/dist/chunk-QBUTRD2M.js +58 -0
  192. package/dist/chunk-QBUTRD2M.js.map +1 -0
  193. package/dist/chunk-QCSMJTA6.js +68 -0
  194. package/dist/chunk-QCSMJTA6.js.map +1 -0
  195. package/dist/chunk-QNYOIVQ4.js +36 -0
  196. package/dist/chunk-QNYOIVQ4.js.map +1 -0
  197. package/dist/chunk-QPURZJJM.js +88 -0
  198. package/dist/chunk-QPURZJJM.js.map +1 -0
  199. package/dist/chunk-QTG266XU.js +69 -0
  200. package/dist/chunk-QTG266XU.js.map +1 -0
  201. package/dist/chunk-QV4BQRNH.js +29 -0
  202. package/dist/chunk-QV4BQRNH.js.map +1 -0
  203. package/dist/chunk-RJ6RAMKH.js +89 -0
  204. package/dist/chunk-RJ6RAMKH.js.map +1 -0
  205. package/dist/chunk-RJBCTMVW.js +59 -0
  206. package/dist/chunk-RJBCTMVW.js.map +1 -0
  207. package/dist/chunk-RMJYXHBX.js +113 -0
  208. package/dist/chunk-RMJYXHBX.js.map +1 -0
  209. package/dist/chunk-RQT5DWGG.js +34 -0
  210. package/dist/chunk-RQT5DWGG.js.map +1 -0
  211. package/dist/chunk-SPGNNN4R.js +115 -0
  212. package/dist/chunk-SPGNNN4R.js.map +1 -0
  213. package/dist/chunk-SQ66DCXY.js +35 -0
  214. package/dist/chunk-SQ66DCXY.js.map +1 -0
  215. package/dist/chunk-SXKGWHAM.js +179 -0
  216. package/dist/chunk-SXKGWHAM.js.map +1 -0
  217. package/dist/chunk-T2OKGV6M.js +13 -0
  218. package/dist/chunk-T2OKGV6M.js.map +1 -0
  219. package/dist/chunk-T4Z7HBZR.js +110 -0
  220. package/dist/chunk-T4Z7HBZR.js.map +1 -0
  221. package/dist/chunk-TW5I37AE.js +142 -0
  222. package/dist/chunk-TW5I37AE.js.map +1 -0
  223. package/dist/chunk-TY6NTWN5.js +29 -0
  224. package/dist/chunk-TY6NTWN5.js.map +1 -0
  225. package/dist/chunk-UJAWV6LM.js +136 -0
  226. package/dist/chunk-UJAWV6LM.js.map +1 -0
  227. package/dist/chunk-V2WCZBVE.js +122 -0
  228. package/dist/chunk-V2WCZBVE.js.map +1 -0
  229. package/dist/chunk-V4LRBYOD.js +55 -0
  230. package/dist/chunk-V4LRBYOD.js.map +1 -0
  231. package/dist/chunk-V6H2RUVP.js +77 -0
  232. package/dist/chunk-V6H2RUVP.js.map +1 -0
  233. package/dist/chunk-VFRFUU7A.js +35 -0
  234. package/dist/chunk-VFRFUU7A.js.map +1 -0
  235. package/dist/chunk-VHK2OUCW.js +38 -0
  236. package/dist/chunk-VHK2OUCW.js.map +1 -0
  237. package/dist/chunk-VLNFUEOR.js +86 -0
  238. package/dist/chunk-VLNFUEOR.js.map +1 -0
  239. package/dist/chunk-VU7XKD4G.js +66 -0
  240. package/dist/chunk-VU7XKD4G.js.map +1 -0
  241. package/dist/chunk-VZX4HLBM.js +84 -0
  242. package/dist/chunk-VZX4HLBM.js.map +1 -0
  243. package/dist/chunk-W24RR5OD.js +102 -0
  244. package/dist/chunk-W24RR5OD.js.map +1 -0
  245. package/dist/chunk-W47V2F3Q.js +115 -0
  246. package/dist/chunk-W47V2F3Q.js.map +1 -0
  247. package/dist/chunk-W743ORLA.js +91 -0
  248. package/dist/chunk-W743ORLA.js.map +1 -0
  249. package/dist/chunk-W7I3ZX66.js +76 -0
  250. package/dist/chunk-W7I3ZX66.js.map +1 -0
  251. package/dist/chunk-WD42UBGR.js +64 -0
  252. package/dist/chunk-WD42UBGR.js.map +1 -0
  253. package/dist/chunk-WQVEJJV7.js +108 -0
  254. package/dist/chunk-WQVEJJV7.js.map +1 -0
  255. package/dist/chunk-WX4Q4DTX.js +121 -0
  256. package/dist/chunk-WX4Q4DTX.js.map +1 -0
  257. package/dist/chunk-XC7SYZYR.js +86 -0
  258. package/dist/chunk-XC7SYZYR.js.map +1 -0
  259. package/dist/chunk-XSENM65D.js +128 -0
  260. package/dist/chunk-XSENM65D.js.map +1 -0
  261. package/dist/chunk-Y7JTBQUQ.js +152 -0
  262. package/dist/chunk-Y7JTBQUQ.js.map +1 -0
  263. package/dist/chunk-YD2QEVHO.js +68 -0
  264. package/dist/chunk-YD2QEVHO.js.map +1 -0
  265. package/dist/chunk-YDKRUSB5.js +35 -0
  266. package/dist/chunk-YDKRUSB5.js.map +1 -0
  267. package/dist/chunk-YNDHYMPI.js +46 -0
  268. package/dist/chunk-YNDHYMPI.js.map +1 -0
  269. package/dist/chunk-YO3WEMOH.js +130 -0
  270. package/dist/chunk-YO3WEMOH.js.map +1 -0
  271. package/dist/chunk-YVXMWUWD.js +118 -0
  272. package/dist/chunk-YVXMWUWD.js.map +1 -0
  273. package/dist/chunk-Z6HZMGO2.js +106 -0
  274. package/dist/chunk-Z6HZMGO2.js.map +1 -0
  275. package/dist/chunk-ZAP4RIUL.js +81 -0
  276. package/dist/chunk-ZAP4RIUL.js.map +1 -0
  277. package/dist/chunk-ZEDDWVBB.js +112 -0
  278. package/dist/chunk-ZEDDWVBB.js.map +1 -0
  279. package/dist/chunk-ZEFOXF2I.js +87 -0
  280. package/dist/chunk-ZEFOXF2I.js.map +1 -0
  281. package/dist/chunk-ZPURFK4C.js +203 -0
  282. package/dist/chunk-ZPURFK4C.js.map +1 -0
  283. package/dist/chunk-ZZZIOTLC.js +89 -0
  284. package/dist/chunk-ZZZIOTLC.js.map +1 -0
  285. package/dist/components/composites/account-menu/account-menu.d.ts +43 -0
  286. package/dist/components/composites/account-menu/index.d.ts +1 -0
  287. package/dist/components/composites/agent-composer/agent-composer.d.ts +41 -0
  288. package/dist/components/composites/agent-composer/index.d.ts +1 -0
  289. package/dist/components/composites/agent-editor/agent-editor.d.ts +31 -0
  290. package/dist/components/composites/agent-editor/index.d.ts +1 -0
  291. package/dist/components/composites/agent-stream/agent-stream.d.ts +72 -0
  292. package/dist/components/composites/agent-stream/index.d.ts +2 -0
  293. package/dist/components/composites/agent-stream/to-agent-stream-items.d.ts +32 -0
  294. package/dist/components/composites/agent-timeline/agent-timeline.d.ts +22 -0
  295. package/dist/components/composites/agent-timeline/index.d.ts +1 -0
  296. package/dist/components/composites/agent-tool-renderer/agent-tool-renderer.d.ts +60 -0
  297. package/dist/components/composites/agent-tool-renderer/index.d.ts +1 -0
  298. package/dist/components/composites/agent-tool-renderer/tool-call-part.d.ts +5 -0
  299. package/dist/components/composites/approval-card/approval-card.d.ts +35 -0
  300. package/dist/components/composites/approval-card/index.d.ts +1 -0
  301. package/dist/components/composites/chat-composer/chat-composer.d.ts +68 -0
  302. package/dist/components/composites/chat-composer/index.d.ts +1 -0
  303. package/dist/components/composites/chat-message/chat-message-actions.d.ts +22 -0
  304. package/dist/components/composites/chat-message/chat-message-branch.d.ts +17 -0
  305. package/dist/components/composites/chat-message/chat-message-response.d.ts +15 -0
  306. package/dist/components/composites/chat-message/chat-message-toolbar.d.ts +7 -0
  307. package/dist/components/composites/chat-message/chat-message.d.ts +94 -0
  308. package/dist/components/composites/chat-message/index.d.ts +23 -0
  309. package/dist/components/composites/chat-message/parts/data-part.d.ts +9 -0
  310. package/dist/components/composites/chat-message/parts/file-part.d.ts +5 -0
  311. package/dist/components/composites/chat-message/parts/reasoning-part.d.ts +7 -0
  312. package/dist/components/composites/chat-message/parts/source-part.d.ts +9 -0
  313. package/dist/components/composites/chat-message/parts/text-part.d.ts +11 -0
  314. package/dist/components/composites/choice-prompt/choice-prompt.d.ts +65 -0
  315. package/dist/components/composites/choice-prompt/index.d.ts +2 -0
  316. package/dist/components/composites/code-block/code-block.d.ts +29 -0
  317. package/dist/components/composites/code-block/index.d.ts +1 -0
  318. package/dist/components/composites/command-palette/command-palette.d.ts +41 -0
  319. package/dist/components/composites/command-palette/index.d.ts +1 -0
  320. package/dist/components/composites/confirm-dialog/confirm-dialog.d.ts +41 -0
  321. package/dist/components/composites/confirm-dialog/index.d.ts +1 -0
  322. package/dist/components/composites/confirm-prompt/confirm-prompt.d.ts +31 -0
  323. package/dist/components/composites/confirm-prompt/index.d.ts +1 -0
  324. package/dist/components/composites/cron-jobs-list/cron-jobs-list.d.ts +15 -0
  325. package/dist/components/composites/cron-jobs-list/index.d.ts +1 -0
  326. package/dist/components/composites/data-table/data-table.d.ts +63 -0
  327. package/dist/components/composites/data-table/index.d.ts +1 -0
  328. package/dist/components/composites/deployment-row/deployment-row.d.ts +28 -0
  329. package/dist/components/composites/deployment-row/index.d.ts +1 -0
  330. package/dist/components/composites/domain-config/domain-config.d.ts +34 -0
  331. package/dist/components/composites/domain-config/index.d.ts +1 -0
  332. package/dist/components/composites/env-var-editor/env-var-editor.d.ts +35 -0
  333. package/dist/components/composites/env-var-editor/index.d.ts +1 -0
  334. package/dist/components/composites/mcp-server-list/index.d.ts +1 -0
  335. package/dist/components/composites/mcp-server-list/mcp-server-list.d.ts +15 -0
  336. package/dist/components/composites/metric-card/index.d.ts +2 -0
  337. package/dist/components/composites/metric-card/metric-card.d.ts +46 -0
  338. package/dist/components/composites/multi-select-prompt/index.d.ts +1 -0
  339. package/dist/components/composites/multi-select-prompt/multi-select-prompt.d.ts +61 -0
  340. package/dist/components/composites/page-shell/index.d.ts +1 -0
  341. package/dist/components/composites/page-shell/page-shell.d.ts +68 -0
  342. package/dist/components/composites/permission-modal/index.d.ts +1 -0
  343. package/dist/components/composites/permission-modal/permission-modal.d.ts +48 -0
  344. package/dist/components/composites/preview-env-card/index.d.ts +1 -0
  345. package/dist/components/composites/preview-env-card/preview-env-card.d.ts +36 -0
  346. package/dist/components/composites/preview-panel/index.d.ts +1 -0
  347. package/dist/components/composites/preview-panel/preview-panel.d.ts +24 -0
  348. package/dist/components/composites/project-card/index.d.ts +1 -0
  349. package/dist/components/composites/project-card/project-card.d.ts +32 -0
  350. package/dist/components/composites/rollback-ui/index.d.ts +1 -0
  351. package/dist/components/composites/rollback-ui/rollback-ui.d.ts +32 -0
  352. package/dist/components/composites/rule-editor/index.d.ts +1 -0
  353. package/dist/components/composites/rule-editor/rule-editor.d.ts +18 -0
  354. package/dist/components/composites/skill-editor/index.d.ts +1 -0
  355. package/dist/components/composites/skill-editor/skill-editor.d.ts +19 -0
  356. package/dist/components/composites/skills-list/index.d.ts +1 -0
  357. package/dist/components/composites/skills-list/skills-list.d.ts +15 -0
  358. package/dist/components/composites/slide-deck/context.d.ts +23 -0
  359. package/dist/components/composites/slide-deck/controls.d.ts +8 -0
  360. package/dist/components/composites/slide-deck/fragments.d.ts +20 -0
  361. package/dist/components/composites/slide-deck/index.d.ts +21 -0
  362. package/dist/components/composites/slide-deck/notes.d.ts +14 -0
  363. package/dist/components/composites/slide-deck/presenter-view.d.ts +15 -0
  364. package/dist/components/composites/slide-deck/print-styles.d.ts +21 -0
  365. package/dist/components/composites/slide-deck/progress-bar.d.ts +8 -0
  366. package/dist/components/composites/slide-deck/schema.d.ts +31 -0
  367. package/dist/components/composites/slide-deck/slide-deck.d.ts +78 -0
  368. package/dist/components/composites/slide-deck/slide-number.d.ts +11 -0
  369. package/dist/components/composites/slide-deck/split-deck.d.ts +2 -0
  370. package/dist/components/composites/slide-deck/thumbnails.d.ts +19 -0
  371. package/dist/components/composites/slide-deck/use-deck-hash-routing.d.ts +23 -0
  372. package/dist/components/composites/slide-deck/use-deck-keyboard.d.ts +25 -0
  373. package/dist/components/composites/slide-deck/use-deck-state.d.ts +57 -0
  374. package/dist/components/composites/slide-deck/use-deck-swipe.d.ts +20 -0
  375. package/dist/components/composites/slide-deck/use-fullscreen.d.ts +18 -0
  376. package/dist/components/composites/stability-bundle-viewer/index.d.ts +1 -0
  377. package/dist/components/composites/stability-bundle-viewer/stability-bundle-viewer.d.ts +28 -0
  378. package/dist/components/composites/status-indicator/index.d.ts +2 -0
  379. package/dist/components/composites/status-indicator/status-indicator.d.ts +31 -0
  380. package/dist/components/composites/task-header/index.d.ts +1 -0
  381. package/dist/components/composites/task-header/task-header.d.ts +20 -0
  382. package/dist/components/composites/text-prompt/index.d.ts +1 -0
  383. package/dist/components/composites/text-prompt/text-prompt.d.ts +48 -0
  384. package/dist/components/composites/usage-meter/index.d.ts +1 -0
  385. package/dist/components/composites/usage-meter/usage-meter.d.ts +56 -0
  386. package/dist/components/primitives/action-bar/action-bar.d.ts +34 -0
  387. package/dist/components/primitives/action-bar/index.d.ts +1 -0
  388. package/dist/components/primitives/agent-error-card/agent-error-card.d.ts +47 -0
  389. package/dist/components/primitives/agent-error-card/index.d.ts +1 -0
  390. package/dist/components/primitives/agent-event/agent-event.d.ts +25 -0
  391. package/dist/components/primitives/agent-event/index.d.ts +1 -0
  392. package/dist/components/primitives/agent-handoff/agent-handoff.d.ts +24 -0
  393. package/dist/components/primitives/agent-handoff/index.d.ts +1 -0
  394. package/dist/components/primitives/agent-profile/agent-profile.d.ts +28 -0
  395. package/dist/components/primitives/agent-profile/index.d.ts +1 -0
  396. package/dist/components/primitives/agent-starting-state/agent-starting-state.d.ts +15 -0
  397. package/dist/components/primitives/agent-starting-state/index.d.ts +1 -0
  398. package/dist/components/primitives/agent-streaming/agent-streaming.d.ts +16 -0
  399. package/dist/components/primitives/agent-streaming/index.d.ts +1 -0
  400. package/dist/components/primitives/alert/alert.d.ts +31 -0
  401. package/dist/components/primitives/alert/index.d.ts +1 -0
  402. package/dist/components/primitives/artifact-preview/artifact-preview.d.ts +25 -0
  403. package/dist/components/primitives/artifact-preview/index.d.ts +1 -0
  404. package/dist/components/primitives/attachment-chip/attachment-chip.d.ts +14 -0
  405. package/dist/components/primitives/attachment-chip/index.d.ts +1 -0
  406. package/dist/components/primitives/audit-log-entry/audit-log-entry.d.ts +29 -0
  407. package/dist/components/primitives/audit-log-entry/index.d.ts +1 -0
  408. package/dist/components/primitives/auto-compact-notice/auto-compact-notice.d.ts +24 -0
  409. package/dist/components/primitives/auto-compact-notice/index.d.ts +1 -0
  410. package/dist/components/primitives/avatar/avatar.d.ts +26 -0
  411. package/dist/components/primitives/avatar/index.d.ts +1 -0
  412. package/dist/components/primitives/badge/badge.d.ts +33 -0
  413. package/dist/components/primitives/badge/index.d.ts +1 -0
  414. package/dist/components/primitives/branch-indicator/branch-indicator.d.ts +13 -0
  415. package/dist/components/primitives/branch-indicator/index.d.ts +1 -0
  416. package/dist/components/primitives/browser-controls/browser-controls.d.ts +19 -0
  417. package/dist/components/primitives/browser-controls/index.d.ts +1 -0
  418. package/dist/components/primitives/build-log-stream/build-log-stream.d.ts +51 -0
  419. package/dist/components/primitives/build-log-stream/index.d.ts +1 -0
  420. package/dist/components/primitives/button/button.d.ts +26 -0
  421. package/dist/components/primitives/button/index.d.ts +1 -0
  422. package/dist/components/primitives/capability-indicator/capability-indicator.d.ts +57 -0
  423. package/dist/components/primitives/capability-indicator/index.d.ts +1 -0
  424. package/dist/components/primitives/card/card.d.ts +40 -0
  425. package/dist/components/primitives/card/index.d.ts +1 -0
  426. package/dist/components/primitives/channel-card/channel-card.d.ts +28 -0
  427. package/dist/components/primitives/channel-card/index.d.ts +1 -0
  428. package/dist/components/primitives/chat-thread/chat-thread.d.ts +12 -0
  429. package/dist/components/primitives/chat-thread/index.d.ts +1 -0
  430. package/dist/components/primitives/checkbox/checkbox.d.ts +20 -0
  431. package/dist/components/primitives/checkbox/index.d.ts +1 -0
  432. package/dist/components/primitives/context-card/context-card.d.ts +18 -0
  433. package/dist/components/primitives/context-card/index.d.ts +1 -0
  434. package/dist/components/primitives/context-window-bar/context-window-bar.d.ts +27 -0
  435. package/dist/components/primitives/context-window-bar/index.d.ts +1 -0
  436. package/dist/components/primitives/copy-button/copy-button.d.ts +17 -0
  437. package/dist/components/primitives/copy-button/index.d.ts +1 -0
  438. package/dist/components/primitives/cost-meter/cost-meter.d.ts +23 -0
  439. package/dist/components/primitives/cost-meter/index.d.ts +1 -0
  440. package/dist/components/primitives/created-files-card/created-files-card.d.ts +30 -0
  441. package/dist/components/primitives/created-files-card/index.d.ts +1 -0
  442. package/dist/components/primitives/cron-job-card/cron-job-card.d.ts +30 -0
  443. package/dist/components/primitives/cron-job-card/index.d.ts +1 -0
  444. package/dist/components/primitives/danger-zone/danger-zone.d.ts +40 -0
  445. package/dist/components/primitives/danger-zone/index.d.ts +1 -0
  446. package/dist/components/primitives/dialog/dialog.d.ts +26 -0
  447. package/dist/components/primitives/dialog/index.d.ts +1 -0
  448. package/dist/components/primitives/diff-viewer/diff-viewer.d.ts +45 -0
  449. package/dist/components/primitives/diff-viewer/index.d.ts +1 -0
  450. package/dist/components/primitives/dropdown-menu/dropdown-menu.d.ts +68 -0
  451. package/dist/components/primitives/dropdown-menu/index.d.ts +1 -0
  452. package/dist/components/primitives/empty-state/empty-state.d.ts +22 -0
  453. package/dist/components/primitives/empty-state/index.d.ts +1 -0
  454. package/dist/components/primitives/export-chat-dialog/export-chat-dialog.d.ts +18 -0
  455. package/dist/components/primitives/export-chat-dialog/index.d.ts +1 -0
  456. package/dist/components/primitives/folder-context-card/folder-context-card.d.ts +40 -0
  457. package/dist/components/primitives/folder-context-card/index.d.ts +1 -0
  458. package/dist/components/primitives/folder-selector/folder-selector.d.ts +18 -0
  459. package/dist/components/primitives/folder-selector/index.d.ts +1 -0
  460. package/dist/components/primitives/form-field/form-field.d.ts +44 -0
  461. package/dist/components/primitives/form-field/index.d.ts +1 -0
  462. package/dist/components/primitives/gateway-status-indicator/gateway-status-indicator.d.ts +19 -0
  463. package/dist/components/primitives/gateway-status-indicator/index.d.ts +1 -0
  464. package/dist/components/primitives/hook-config/hook-config.d.ts +27 -0
  465. package/dist/components/primitives/hook-config/index.d.ts +1 -0
  466. package/dist/components/primitives/hook-event-log/hook-event-log.d.ts +27 -0
  467. package/dist/components/primitives/hook-event-log/index.d.ts +1 -0
  468. package/dist/components/primitives/input/index.d.ts +1 -0
  469. package/dist/components/primitives/input/input.d.ts +24 -0
  470. package/dist/components/primitives/intent-selector/index.d.ts +1 -0
  471. package/dist/components/primitives/intent-selector/intent-selector.d.ts +22 -0
  472. package/dist/components/primitives/label/index.d.ts +1 -0
  473. package/dist/components/primitives/label/label.d.ts +15 -0
  474. package/dist/components/primitives/lane-board/index.d.ts +1 -0
  475. package/dist/components/primitives/lane-board/lane-board.d.ts +26 -0
  476. package/dist/components/primitives/login-split/index.d.ts +1 -0
  477. package/dist/components/primitives/login-split/login-split.d.ts +24 -0
  478. package/dist/components/primitives/mcp-server-card/index.d.ts +1 -0
  479. package/dist/components/primitives/mcp-server-card/mcp-server-card.d.ts +32 -0
  480. package/dist/components/primitives/memory-editor/index.d.ts +1 -0
  481. package/dist/components/primitives/memory-editor/memory-editor.d.ts +29 -0
  482. package/dist/components/primitives/mention-menu/index.d.ts +1 -0
  483. package/dist/components/primitives/mention-menu/mention-menu.d.ts +44 -0
  484. package/dist/components/primitives/metrics-panel/index.d.ts +1 -0
  485. package/dist/components/primitives/metrics-panel/metrics-panel.d.ts +62 -0
  486. package/dist/components/primitives/model-card/index.d.ts +1 -0
  487. package/dist/components/primitives/model-card/model-card.d.ts +72 -0
  488. package/dist/components/primitives/model-selector/index.d.ts +1 -0
  489. package/dist/components/primitives/model-selector/model-selector.d.ts +21 -0
  490. package/dist/components/primitives/pagination/index.d.ts +1 -0
  491. package/dist/components/primitives/pagination/pagination.d.ts +44 -0
  492. package/dist/components/primitives/permission-matrix/index.d.ts +1 -0
  493. package/dist/components/primitives/permission-matrix/permission-matrix.d.ts +43 -0
  494. package/dist/components/primitives/pin-input/index.d.ts +1 -0
  495. package/dist/components/primitives/pin-input/pin-input.d.ts +41 -0
  496. package/dist/components/primitives/plan-badge/index.d.ts +1 -0
  497. package/dist/components/primitives/plan-badge/plan-badge.d.ts +35 -0
  498. package/dist/components/primitives/progress/index.d.ts +1 -0
  499. package/dist/components/primitives/progress/progress.d.ts +44 -0
  500. package/dist/components/primitives/progress-checklist/index.d.ts +1 -0
  501. package/dist/components/primitives/progress-checklist/progress-checklist.d.ts +18 -0
  502. package/dist/components/primitives/project-switcher/index.d.ts +1 -0
  503. package/dist/components/primitives/project-switcher/project-switcher.d.ts +32 -0
  504. package/dist/components/primitives/quick-action-chips/index.d.ts +1 -0
  505. package/dist/components/primitives/quick-action-chips/quick-action-chips.d.ts +22 -0
  506. package/dist/components/primitives/radio-group/index.d.ts +1 -0
  507. package/dist/components/primitives/radio-group/radio-group.d.ts +5 -0
  508. package/dist/components/primitives/recent-folders-list/index.d.ts +1 -0
  509. package/dist/components/primitives/recent-folders-list/recent-folders-list.d.ts +21 -0
  510. package/dist/components/primitives/rule-card/index.d.ts +1 -0
  511. package/dist/components/primitives/rule-card/rule-card.d.ts +15 -0
  512. package/dist/components/primitives/run-stats/index.d.ts +1 -0
  513. package/dist/components/primitives/run-stats/run-stats.d.ts +16 -0
  514. package/dist/components/primitives/run-status-pill/index.d.ts +1 -0
  515. package/dist/components/primitives/run-status-pill/run-status-pill.d.ts +13 -0
  516. package/dist/components/primitives/running-tasks-panel/index.d.ts +1 -0
  517. package/dist/components/primitives/running-tasks-panel/running-tasks-panel.d.ts +20 -0
  518. package/dist/components/primitives/scroll-area/index.d.ts +2 -0
  519. package/dist/components/primitives/scroll-area/scroll-area.d.ts +40 -0
  520. package/dist/components/primitives/scroll-area/use-stick-to-bottom.d.ts +20 -0
  521. package/dist/components/primitives/select/index.d.ts +1 -0
  522. package/dist/components/primitives/select/select.d.ts +50 -0
  523. package/dist/components/primitives/session-list-item/index.d.ts +1 -0
  524. package/dist/components/primitives/session-list-item/session-list-item.d.ts +35 -0
  525. package/dist/components/primitives/session-timeline/index.d.ts +1 -0
  526. package/dist/components/primitives/session-timeline/session-timeline.d.ts +32 -0
  527. package/dist/components/primitives/sheet/index.d.ts +1 -0
  528. package/dist/components/primitives/sheet/sheet.d.ts +57 -0
  529. package/dist/components/primitives/sidebar/index.d.ts +1 -0
  530. package/dist/components/primitives/sidebar/sidebar.d.ts +18 -0
  531. package/dist/components/primitives/skeleton/index.d.ts +1 -0
  532. package/dist/components/primitives/skeleton/skeleton.d.ts +21 -0
  533. package/dist/components/primitives/skill-card/index.d.ts +1 -0
  534. package/dist/components/primitives/skill-card/skill-card.d.ts +28 -0
  535. package/dist/components/primitives/slide/alerts.d.ts +31 -0
  536. package/dist/components/primitives/slide/frontmatter.d.ts +23 -0
  537. package/dist/components/primitives/slide/index.d.ts +16 -0
  538. package/dist/components/primitives/slide/json-schema.d.ts +9 -0
  539. package/dist/components/primitives/slide/marpit-bg.d.ts +36 -0
  540. package/dist/components/primitives/slide/parse.d.ts +59 -0
  541. package/dist/components/primitives/slide/plugin.d.ts +79 -0
  542. package/dist/components/primitives/slide/plugins/emoji/index.d.ts +8 -0
  543. package/dist/components/primitives/slide/plugins/emoji/map.d.ts +15 -0
  544. package/dist/components/primitives/slide/plugins/math/index.d.ts +6 -0
  545. package/dist/components/primitives/slide/plugins/mermaid/index.d.ts +48 -0
  546. package/dist/components/primitives/slide/plugins/shiki/index.d.ts +11 -0
  547. package/dist/components/primitives/slide/sanitize.d.ts +33 -0
  548. package/dist/components/primitives/slide/schema.d.ts +109 -0
  549. package/dist/components/primitives/slide/slide.d.ts +53 -0
  550. package/dist/components/primitives/slide/themes/index.d.ts +9 -0
  551. package/dist/components/primitives/slide/use-slide-fit.d.ts +21 -0
  552. package/dist/components/primitives/slide/validate.d.ts +33 -0
  553. package/dist/components/primitives/social-auth-row/index.d.ts +1 -0
  554. package/dist/components/primitives/social-auth-row/social-auth-row.d.ts +24 -0
  555. package/dist/components/primitives/stat-tile/index.d.ts +1 -0
  556. package/dist/components/primitives/stat-tile/stat-tile.d.ts +28 -0
  557. package/dist/components/primitives/status-dot/index.d.ts +1 -0
  558. package/dist/components/primitives/status-dot/status-dot.d.ts +31 -0
  559. package/dist/components/primitives/steps-rail/index.d.ts +1 -0
  560. package/dist/components/primitives/steps-rail/steps-rail.d.ts +24 -0
  561. package/dist/components/primitives/sub-agent-dispatch/index.d.ts +1 -0
  562. package/dist/components/primitives/sub-agent-dispatch/sub-agent-dispatch.d.ts +30 -0
  563. package/dist/components/primitives/switch/index.d.ts +1 -0
  564. package/dist/components/primitives/switch/switch.d.ts +20 -0
  565. package/dist/components/primitives/system-prompt-editor/index.d.ts +1 -0
  566. package/dist/components/primitives/system-prompt-editor/system-prompt-editor.d.ts +25 -0
  567. package/dist/components/primitives/table/index.d.ts +1 -0
  568. package/dist/components/primitives/table/table.d.ts +61 -0
  569. package/dist/components/primitives/tabs/index.d.ts +1 -0
  570. package/dist/components/primitives/tabs/tabs.d.ts +7 -0
  571. package/dist/components/primitives/task-plan/index.d.ts +1 -0
  572. package/dist/components/primitives/task-plan/task-plan.d.ts +36 -0
  573. package/dist/components/primitives/terminal-panel/index.d.ts +1 -0
  574. package/dist/components/primitives/terminal-panel/terminal-panel.d.ts +32 -0
  575. package/dist/components/primitives/textarea/index.d.ts +1 -0
  576. package/dist/components/primitives/textarea/textarea.d.ts +20 -0
  577. package/dist/components/primitives/thinking-level-selector/index.d.ts +1 -0
  578. package/dist/components/primitives/thinking-level-selector/thinking-level-selector.d.ts +24 -0
  579. package/dist/components/primitives/timestamp/index.d.ts +1 -0
  580. package/dist/components/primitives/timestamp/timestamp.d.ts +34 -0
  581. package/dist/components/primitives/toast/index.d.ts +2 -0
  582. package/dist/components/primitives/toast/toast.d.ts +34 -0
  583. package/dist/components/primitives/toast/toaster.d.ts +38 -0
  584. package/dist/components/primitives/token-usage-chart/index.d.ts +2 -0
  585. package/dist/components/primitives/token-usage-chart/token-usage-chart.d.ts +44 -0
  586. package/dist/components/primitives/token-usage-chart/usage-metrics.d.ts +23 -0
  587. package/dist/components/primitives/tool-call/index.d.ts +1 -0
  588. package/dist/components/primitives/tool-call/tool-call.d.ts +30 -0
  589. package/dist/components/primitives/tool-call-card/index.d.ts +1 -0
  590. package/dist/components/primitives/tool-call-card/tool-call-card.d.ts +30 -0
  591. package/dist/components/primitives/tool-result/index.d.ts +1 -0
  592. package/dist/components/primitives/tool-result/tool-result.d.ts +19 -0
  593. package/dist/components/primitives/tools-list/index.d.ts +1 -0
  594. package/dist/components/primitives/tools-list/tools-list.d.ts +32 -0
  595. package/dist/components/primitives/tooltip/index.d.ts +1 -0
  596. package/dist/components/primitives/tooltip/tooltip.d.ts +33 -0
  597. package/dist/components/primitives/topnav/index.d.ts +1 -0
  598. package/dist/components/primitives/topnav/topnav.d.ts +29 -0
  599. package/dist/components/primitives/update-banner/index.d.ts +1 -0
  600. package/dist/components/primitives/update-banner/update-banner.d.ts +16 -0
  601. package/dist/components/primitives/whiteboard/index.d.ts +2 -0
  602. package/dist/components/primitives/whiteboard/render/freedraw.d.ts +2 -0
  603. package/dist/components/primitives/whiteboard/render/line.d.ts +4 -0
  604. package/dist/components/primitives/whiteboard/render/rough-paths.d.ts +16 -0
  605. package/dist/components/primitives/whiteboard/render/scene.d.ts +3 -0
  606. package/dist/components/primitives/whiteboard/render/shape.d.ts +5 -0
  607. package/dist/components/primitives/whiteboard/render/style.d.ts +24 -0
  608. package/dist/components/primitives/whiteboard/render/text.d.ts +2 -0
  609. package/dist/components/primitives/whiteboard/schema.d.ts +596 -0
  610. package/dist/components/primitives/whiteboard/seed.d.ts +22 -0
  611. package/dist/components/primitives/whiteboard/validate.d.ts +26 -0
  612. package/dist/components/primitives/whiteboard/viewport/use-pointer-pan.d.ts +11 -0
  613. package/dist/components/primitives/whiteboard/viewport/use-viewport.d.ts +33 -0
  614. package/dist/components/primitives/whiteboard/whiteboard.d.ts +21 -0
  615. package/dist/components.css +1 -1
  616. package/dist/composites/account-menu/index.js +4 -4
  617. package/dist/composites/agent-composer/index.js +6 -5
  618. package/dist/composites/agent-editor/index.js +8 -7
  619. package/dist/composites/agent-stream/index.js +21 -9
  620. package/dist/composites/agent-timeline/index.js +3 -3
  621. package/dist/composites/agent-tool-renderer/index.js +17 -0
  622. package/dist/composites/agent-tool-renderer/index.js.map +1 -0
  623. package/dist/composites/approval-card/index.js +3 -3
  624. package/dist/composites/chat-composer/index.js +3 -3
  625. package/dist/composites/chat-message/index.js +18 -4
  626. package/dist/composites/choice-prompt/index.js +11 -0
  627. package/dist/composites/choice-prompt/index.js.map +1 -0
  628. package/dist/composites/code-block/index.js +3 -3
  629. package/dist/composites/command-palette/index.js +4 -3
  630. package/dist/composites/confirm-dialog/index.js +6 -5
  631. package/dist/composites/confirm-prompt/index.js +7 -0
  632. package/dist/composites/confirm-prompt/index.js.map +1 -0
  633. package/dist/composites/cron-jobs-list/index.js +3 -3
  634. package/dist/composites/data-table/index.js +8 -7
  635. package/dist/composites/deployment-row/index.js +3 -3
  636. package/dist/composites/domain-config/index.js +6 -5
  637. package/dist/composites/env-var-editor/index.js +7 -5
  638. package/dist/composites/mcp-server-list/index.js +4 -3
  639. package/dist/composites/metric-card/index.js +5 -0
  640. package/dist/composites/metric-card/index.js.map +1 -0
  641. package/dist/composites/multi-select-prompt/index.js +11 -0
  642. package/dist/composites/multi-select-prompt/index.js.map +1 -0
  643. package/dist/composites/page-shell/index.js +6 -5
  644. package/dist/composites/permission-modal/index.js +5 -4
  645. package/dist/composites/preview-env-card/index.js +4 -4
  646. package/dist/composites/preview-panel/index.js +3 -3
  647. package/dist/composites/project-card/index.js +4 -4
  648. package/dist/composites/rollback-ui/index.js +5 -4
  649. package/dist/composites/rule-editor/index.js +9 -8
  650. package/dist/composites/skill-editor/index.js +9 -8
  651. package/dist/composites/skills-list/index.js +4 -3
  652. package/dist/composites/stability-bundle-viewer/index.js +3 -2
  653. package/dist/composites/status-indicator/index.js +4 -0
  654. package/dist/composites/status-indicator/index.js.map +1 -0
  655. package/dist/composites/task-header/index.js +3 -3
  656. package/dist/composites/text-prompt/index.js +10 -0
  657. package/dist/composites/text-prompt/index.js.map +1 -0
  658. package/dist/composites/usage-meter/index.js +3 -3
  659. package/dist/fonts-cdn.css +4 -4
  660. package/dist/fonts.css +2 -2
  661. package/dist/index.d.ts +144 -4622
  662. package/dist/index.js +999 -739
  663. package/dist/index.js.map +1 -1
  664. package/dist/lib/cn.d.ts +6 -0
  665. package/dist/lib/env.d.ts +55 -0
  666. package/dist/lib/live-region-context.d.ts +2 -0
  667. package/dist/lib/markdown/code-block.d.ts +14 -0
  668. package/dist/lib/markdown/inline-code.d.ts +10 -0
  669. package/dist/lib/markdown/math.d.ts +12 -0
  670. package/dist/lib/markdown/mermaid.d.ts +6 -0
  671. package/dist/lib/markdown/parser.d.ts +47 -0
  672. package/dist/lib/markdown/streaming-preprocess.d.ts +39 -0
  673. package/dist/lib/prompt.d.ts +40 -0
  674. package/dist/lib/safe-href.d.ts +27 -0
  675. package/dist/lib/sdk-tools-adapters/index.d.ts +1 -0
  676. package/dist/lib/sdk-tools-adapters/index.js +3 -0
  677. package/dist/lib/sdk-tools-adapters/index.js.map +1 -0
  678. package/dist/lib/sdk-tools-adapters/sdk-tools-adapters.d.ts +60 -0
  679. package/dist/lib/types.d.ts +10 -0
  680. package/dist/preset-v3-legacy.d.ts +7 -10
  681. package/dist/preset-v3-legacy.js +23 -3
  682. package/dist/preset-v3-legacy.js.map +1 -1
  683. package/dist/preset.css +2 -2
  684. package/dist/primitives/action-bar/index.js +2 -2
  685. package/dist/primitives/agent-error-card/index.js +2 -2
  686. package/dist/primitives/agent-event/index.js +3 -2
  687. package/dist/primitives/agent-handoff/index.js +2 -2
  688. package/dist/primitives/agent-profile/index.js +2 -2
  689. package/dist/primitives/agent-starting-state/index.js +2 -2
  690. package/dist/primitives/agent-streaming/index.js +2 -2
  691. package/dist/primitives/alert/index.js +2 -2
  692. package/dist/primitives/artifact-preview/index.js +2 -2
  693. package/dist/primitives/attachment-chip/index.js +2 -2
  694. package/dist/primitives/audit-log-entry/index.js +2 -2
  695. package/dist/primitives/auto-compact-notice/index.js +2 -2
  696. package/dist/primitives/avatar/index.js +2 -2
  697. package/dist/primitives/badge/index.js +2 -2
  698. package/dist/primitives/branch-indicator/index.js +2 -2
  699. package/dist/primitives/browser-controls/index.js +2 -2
  700. package/dist/primitives/build-log-stream/index.js +4 -2
  701. package/dist/primitives/button/index.js +2 -2
  702. package/dist/primitives/capability-indicator/index.js +2 -2
  703. package/dist/primitives/card/index.js +3 -2
  704. package/dist/primitives/channel-card/index.js +2 -2
  705. package/dist/primitives/chat-thread/index.js +2 -2
  706. package/dist/primitives/checkbox/index.js +2 -2
  707. package/dist/primitives/context-card/index.js +2 -2
  708. package/dist/primitives/context-window-bar/index.js +2 -2
  709. package/dist/primitives/copy-button/index.js +3 -2
  710. package/dist/primitives/cost-meter/index.js +2 -2
  711. package/dist/primitives/created-files-card/index.js +2 -2
  712. package/dist/primitives/cron-job-card/index.js +2 -2
  713. package/dist/primitives/danger-zone/index.js +2 -2
  714. package/dist/primitives/dialog/index.js +2 -2
  715. package/dist/primitives/diff-viewer/index.js +2 -2
  716. package/dist/primitives/dropdown-menu/index.js +2 -2
  717. package/dist/primitives/empty-state/index.js +2 -2
  718. package/dist/primitives/export-chat-dialog/index.js +3 -2
  719. package/dist/primitives/folder-context-card/index.js +2 -2
  720. package/dist/primitives/folder-selector/index.js +2 -2
  721. package/dist/primitives/form-field/index.js +3 -2
  722. package/dist/primitives/gateway-status-indicator/index.js +2 -2
  723. package/dist/primitives/hook-config/index.js +3 -2
  724. package/dist/primitives/hook-event-log/index.js +2 -2
  725. package/dist/primitives/input/index.js +2 -2
  726. package/dist/primitives/intent-selector/index.js +2 -2
  727. package/dist/primitives/label/index.js +2 -2
  728. package/dist/primitives/lane-board/index.js +2 -2
  729. package/dist/primitives/login-split/index.js +2 -2
  730. package/dist/primitives/mcp-server-card/index.js +2 -2
  731. package/dist/primitives/memory-editor/index.js +2 -2
  732. package/dist/primitives/mention-menu/index.js +3 -2
  733. package/dist/primitives/metrics-panel/index.js +2 -2
  734. package/dist/primitives/model-card/index.js +2 -2
  735. package/dist/primitives/model-selector/index.js +2 -2
  736. package/dist/primitives/pagination/index.js +2 -2
  737. package/dist/primitives/permission-matrix/index.js +3 -2
  738. package/dist/primitives/pin-input/index.js +3 -2
  739. package/dist/primitives/plan-badge/index.js +2 -2
  740. package/dist/primitives/progress/index.js +2 -2
  741. package/dist/primitives/progress-checklist/index.js +2 -2
  742. package/dist/primitives/project-switcher/index.js +2 -2
  743. package/dist/primitives/quick-action-chips/index.js +2 -2
  744. package/dist/primitives/radio-group/index.js +2 -2
  745. package/dist/primitives/recent-folders-list/index.js +2 -2
  746. package/dist/primitives/rule-card/index.js +2 -2
  747. package/dist/primitives/run-stats/index.js +2 -2
  748. package/dist/primitives/run-status-pill/index.js +2 -2
  749. package/dist/primitives/running-tasks-panel/index.js +2 -2
  750. package/dist/primitives/scroll-area/index.js +3 -2
  751. package/dist/primitives/select/index.js +2 -2
  752. package/dist/primitives/session-list-item/index.js +2 -2
  753. package/dist/primitives/session-timeline/index.js +2 -2
  754. package/dist/primitives/sheet/index.js +2 -2
  755. package/dist/primitives/sidebar/index.js +2 -2
  756. package/dist/primitives/skeleton/index.js +2 -2
  757. package/dist/primitives/skill-card/index.js +2 -2
  758. package/dist/primitives/social-auth-row/index.js +2 -2
  759. package/dist/primitives/stat-tile/index.js +2 -2
  760. package/dist/primitives/status-dot/index.js +4 -2
  761. package/dist/primitives/steps-rail/index.js +2 -2
  762. package/dist/primitives/sub-agent-dispatch/index.js +2 -2
  763. package/dist/primitives/switch/index.js +2 -2
  764. package/dist/primitives/system-prompt-editor/index.js +3 -2
  765. package/dist/primitives/table/index.js +3 -2
  766. package/dist/primitives/tabs/index.js +2 -2
  767. package/dist/primitives/task-plan/index.js +2 -2
  768. package/dist/primitives/terminal-panel/index.js +2 -2
  769. package/dist/primitives/textarea/index.js +2 -2
  770. package/dist/primitives/thinking-level-selector/index.js +3 -2
  771. package/dist/primitives/timestamp/index.js +4 -2
  772. package/dist/primitives/toast/index.js +3 -2
  773. package/dist/primitives/token-usage-chart/index.js +2 -2
  774. package/dist/primitives/tool-call/index.js +3 -2
  775. package/dist/primitives/tool-call-card/index.js +3 -2
  776. package/dist/primitives/tool-result/index.js +2 -2
  777. package/dist/primitives/tools-list/index.js +2 -2
  778. package/dist/primitives/tooltip/index.js +2 -2
  779. package/dist/primitives/topnav/index.js +2 -2
  780. package/dist/primitives/update-banner/index.js +2 -2
  781. package/dist/screens/theo-code-shell.d.ts +9 -0
  782. package/dist/screens/theo-code-shell.data.d.ts +147 -0
  783. package/dist/slide/index.js +2 -1
  784. package/dist/slide/plugins/mermaid/index.js +1 -1
  785. package/dist/slide/plugins/mermaid/index.js.map +1 -1
  786. package/dist/slide/plugins/shiki/index.js.map +1 -1
  787. package/dist/slide/themes/violet-forge.css +1 -1
  788. package/dist/slide-deck/index.js +13 -2
  789. package/dist/slide-deck/index.js.map +1 -1
  790. package/dist/styles/tailwind-preset.d.ts +29 -0
  791. package/dist/styles.css +3 -3
  792. package/dist/test/a11y.d.ts +13 -0
  793. package/dist/test/setup.d.ts +1 -0
  794. package/dist/themes/anthropic-style.d.ts +11 -0
  795. package/dist/themes/aurora-terminal.d.ts +9 -0
  796. package/dist/themes/classic-paper.d.ts +17 -0
  797. package/dist/themes/color-value-pattern.d.ts +22 -0
  798. package/dist/themes/color.d.ts +62 -0
  799. package/dist/themes/define.d.ts +65 -0
  800. package/dist/themes/density.d.ts +17 -0
  801. package/dist/themes/dracula.d.ts +14 -0
  802. package/dist/themes/github-dark.d.ts +11 -0
  803. package/dist/themes/index.d.ts +26 -0
  804. package/dist/themes/linear-glass.d.ts +11 -0
  805. package/dist/themes/one-dark.d.ts +11 -0
  806. package/dist/themes/openai-style.d.ts +10 -0
  807. package/dist/themes/schema.d.ts +112 -0
  808. package/dist/themes/theme-provider.d.ts +82 -0
  809. package/dist/themes/theme-script.d.ts +48 -0
  810. package/dist/themes/theme-switcher.d.ts +17 -0
  811. package/dist/themes/types.d.ts +88 -0
  812. package/dist/themes/vercel-mono.d.ts +11 -0
  813. package/dist/themes/violet-forge.d.ts +12 -0
  814. package/dist/theo-ui-provider.d.ts +50 -0
  815. package/dist/tokens-v4.css +77 -41
  816. package/dist/tokens.css +159 -74
  817. package/dist/types/agent.d.ts +19 -0
  818. package/dist/types/chat.d.ts +173 -0
  819. package/dist/types/mode.d.ts +16 -0
  820. package/dist/types/permission.d.ts +8 -0
  821. package/dist/types/rule.d.ts +28 -0
  822. package/dist/types/task.d.ts +9 -0
  823. package/dist/vite-plugin.d.ts +7 -11
  824. package/dist/vite-plugin.js +4 -4
  825. package/dist/vite-plugin.js.map +1 -1
  826. package/dist/whiteboard/index.js +3 -0
  827. package/dist/whiteboard/index.js.map +1 -1
  828. package/llms.txt +39 -39
  829. package/package.json +236 -188
  830. package/registry/index.json +58 -4
  831. package/registry/r/account-menu.json +1 -1
  832. package/registry/r/action-bar.json +1 -1
  833. package/registry/r/agent-composer.json +1 -1
  834. package/registry/r/agent-editor.json +1 -1
  835. package/registry/r/agent-error-card.json +1 -1
  836. package/registry/r/agent-event.json +1 -1
  837. package/registry/r/agent-handoff.json +1 -1
  838. package/registry/r/agent-profile.json +1 -1
  839. package/registry/r/agent-starting-state.json +1 -1
  840. package/registry/r/agent-stream.json +1 -1
  841. package/registry/r/agent-streaming.json +1 -1
  842. package/registry/r/agent-timeline.json +1 -1
  843. package/registry/r/agent-tool-renderer.json +40 -0
  844. package/registry/r/alert.json +1 -1
  845. package/registry/r/approval-card.json +1 -1
  846. package/registry/r/artifact-preview.json +1 -1
  847. package/registry/r/attachment-chip.json +1 -1
  848. package/registry/r/audit-log-entry.json +1 -1
  849. package/registry/r/auto-compact-notice.json +1 -1
  850. package/registry/r/avatar.json +1 -1
  851. package/registry/r/badge.json +1 -1
  852. package/registry/r/browser-controls.json +1 -1
  853. package/registry/r/build-log-stream.json +2 -1
  854. package/registry/r/button.json +1 -1
  855. package/registry/r/capability-indicator.json +1 -1
  856. package/registry/r/card.json +1 -1
  857. package/registry/r/chat-composer.json +1 -1
  858. package/registry/r/chat-message.json +11 -16
  859. package/registry/r/chat-thread.json +1 -1
  860. package/registry/r/chat-types.json +1 -1
  861. package/registry/r/checkbox.json +1 -1
  862. package/registry/r/choice-prompt.json +25 -0
  863. package/registry/r/cn.json +1 -1
  864. package/registry/r/code-block.json +1 -1
  865. package/registry/r/command-palette.json +1 -1
  866. package/registry/r/confirm-dialog.json +1 -1
  867. package/registry/r/confirm-prompt.json +21 -0
  868. package/registry/r/context-card.json +1 -1
  869. package/registry/r/context-window-bar.json +1 -1
  870. package/registry/r/copy-button.json +1 -1
  871. package/registry/r/cost-meter.json +1 -1
  872. package/registry/r/created-files-card.json +1 -1
  873. package/registry/r/cron-job-card.json +1 -1
  874. package/registry/r/cron-jobs-list.json +1 -1
  875. package/registry/r/danger-zone.json +1 -1
  876. package/registry/r/data-table.json +1 -1
  877. package/registry/r/deployment-row.json +1 -1
  878. package/registry/r/dialog.json +1 -1
  879. package/registry/r/diff-viewer.json +1 -1
  880. package/registry/r/domain-config.json +1 -1
  881. package/registry/r/dropdown-menu.json +2 -2
  882. package/registry/r/empty-state.json +1 -1
  883. package/registry/r/env-var-editor.json +2 -1
  884. package/registry/r/env.json +15 -0
  885. package/registry/r/folder-context-card.json +1 -1
  886. package/registry/r/folder-selector.json +1 -1
  887. package/registry/r/form-field.json +1 -1
  888. package/registry/r/hook-config.json +1 -1
  889. package/registry/r/hook-event-log.json +1 -1
  890. package/registry/r/input.json +1 -1
  891. package/registry/r/intent-selector.json +1 -1
  892. package/registry/r/label.json +1 -1
  893. package/registry/r/lane-board.json +1 -1
  894. package/registry/r/login-split.json +1 -1
  895. package/registry/r/mcp-server-card.json +1 -1
  896. package/registry/r/mcp-server-list.json +1 -1
  897. package/registry/r/memory-editor.json +1 -1
  898. package/registry/r/mention-menu.json +1 -1
  899. package/registry/r/metric-card.json +23 -0
  900. package/registry/r/metrics-panel.json +1 -1
  901. package/registry/r/model-card.json +1 -1
  902. package/registry/r/model-selector.json +1 -1
  903. package/registry/r/multi-select-prompt.json +25 -0
  904. package/registry/r/page-shell.json +1 -1
  905. package/registry/r/pagination.json +1 -1
  906. package/registry/r/permission-matrix.json +1 -1
  907. package/registry/r/permission-modal.json +1 -1
  908. package/registry/r/pin-input.json +1 -1
  909. package/registry/r/plan-badge.json +1 -1
  910. package/registry/r/preview-env-card.json +1 -1
  911. package/registry/r/preview-panel.json +1 -1
  912. package/registry/r/progress-checklist.json +1 -1
  913. package/registry/r/progress.json +1 -1
  914. package/registry/r/project-card.json +1 -1
  915. package/registry/r/project-switcher.json +1 -1
  916. package/registry/r/prompt.json +15 -0
  917. package/registry/r/quick-action-chips.json +1 -1
  918. package/registry/r/radio-group.json +1 -1
  919. package/registry/r/recent-folders-list.json +1 -1
  920. package/registry/r/rollback-ui.json +1 -1
  921. package/registry/r/rule-card.json +1 -1
  922. package/registry/r/rule-editor.json +1 -1
  923. package/registry/r/run-stats.json +1 -1
  924. package/registry/r/running-tasks-panel.json +1 -1
  925. package/registry/r/safe-href.json +1 -1
  926. package/registry/r/scroll-area.json +1 -1
  927. package/registry/r/select.json +1 -1
  928. package/registry/r/session-list-item.json +1 -1
  929. package/registry/r/session-timeline.json +1 -1
  930. package/registry/r/sheet.json +1 -1
  931. package/registry/r/sidebar.json +1 -1
  932. package/registry/r/skeleton.json +1 -1
  933. package/registry/r/skill-card.json +1 -1
  934. package/registry/r/skill-editor.json +1 -1
  935. package/registry/r/skills-list.json +1 -1
  936. package/registry/r/slide-deck.json +8 -8
  937. package/registry/r/slide-plugin-mermaid.json +1 -1
  938. package/registry/r/slide-plugin-shiki.json +1 -1
  939. package/registry/r/slide.json +6 -6
  940. package/registry/r/social-auth-row.json +1 -1
  941. package/registry/r/stat-tile.json +1 -1
  942. package/registry/r/status-dot.json +2 -1
  943. package/registry/r/status-indicator.json +20 -0
  944. package/registry/r/steps-rail.json +1 -1
  945. package/registry/r/sub-agent-dispatch.json +1 -1
  946. package/registry/r/switch.json +1 -1
  947. package/registry/r/system-prompt-editor.json +1 -1
  948. package/registry/r/table.json +1 -1
  949. package/registry/r/tabs.json +1 -1
  950. package/registry/r/tailwind-preset.json +1 -1
  951. package/registry/r/task-header.json +1 -1
  952. package/registry/r/task-plan.json +1 -1
  953. package/registry/r/terminal-panel.json +1 -1
  954. package/registry/r/text-prompt.json +24 -0
  955. package/registry/r/textarea.json +1 -1
  956. package/registry/r/theme-provider.json +7 -6
  957. package/registry/r/theo-ui-provider.json +1 -1
  958. package/registry/r/timestamp.json +2 -1
  959. package/registry/r/toast.json +2 -2
  960. package/registry/r/token-usage-chart.json +1 -1
  961. package/registry/r/tokens.json +2 -2
  962. package/registry/r/tool-call-card.json +1 -1
  963. package/registry/r/tool-call.json +1 -1
  964. package/registry/r/tool-result.json +1 -1
  965. package/registry/r/tools-list.json +1 -1
  966. package/registry/r/tooltip.json +1 -1
  967. package/registry/r/topnav.json +1 -1
  968. package/registry/r/usage-meter.json +1 -1
  969. package/registry/r/whiteboard.json +3 -3
  970. package/dist/chunk-2UJROWAG.js +0 -106
  971. package/dist/chunk-2UJROWAG.js.map +0 -1
  972. package/dist/chunk-2XPWOUEH.js +0 -68
  973. package/dist/chunk-2XPWOUEH.js.map +0 -1
  974. package/dist/chunk-3GHLNCM3.js +0 -42
  975. package/dist/chunk-3GHLNCM3.js.map +0 -1
  976. package/dist/chunk-3HOXC25T.js +0 -48
  977. package/dist/chunk-3HOXC25T.js.map +0 -1
  978. package/dist/chunk-3QGO5SB3.js +0 -46
  979. package/dist/chunk-3QGO5SB3.js.map +0 -1
  980. package/dist/chunk-47QJVWW2.js +0 -85
  981. package/dist/chunk-47QJVWW2.js.map +0 -1
  982. package/dist/chunk-4L63UW3I.js +0 -35
  983. package/dist/chunk-4L63UW3I.js.map +0 -1
  984. package/dist/chunk-4UUSJJFZ.js +0 -25
  985. package/dist/chunk-4UUSJJFZ.js.map +0 -1
  986. package/dist/chunk-4ZBZBRG5.js +0 -127
  987. package/dist/chunk-4ZBZBRG5.js.map +0 -1
  988. package/dist/chunk-57NXT3OX.js +0 -92
  989. package/dist/chunk-57NXT3OX.js.map +0 -1
  990. package/dist/chunk-5FF5EUZP.js +0 -44
  991. package/dist/chunk-5FF5EUZP.js.map +0 -1
  992. package/dist/chunk-5UGQXB2P.js +0 -714
  993. package/dist/chunk-5UGQXB2P.js.map +0 -1
  994. package/dist/chunk-62FT22CI.js +0 -85
  995. package/dist/chunk-62FT22CI.js.map +0 -1
  996. package/dist/chunk-673R3GSK.js +0 -19
  997. package/dist/chunk-673R3GSK.js.map +0 -1
  998. package/dist/chunk-6VINZJBV.js +0 -128
  999. package/dist/chunk-6VINZJBV.js.map +0 -1
  1000. package/dist/chunk-6ZQKEY54.js +0 -149
  1001. package/dist/chunk-6ZQKEY54.js.map +0 -1
  1002. package/dist/chunk-74NZ5U3E.js +0 -145
  1003. package/dist/chunk-74NZ5U3E.js.map +0 -1
  1004. package/dist/chunk-755NWSNW.js +0 -36
  1005. package/dist/chunk-755NWSNW.js.map +0 -1
  1006. package/dist/chunk-7GLBWWMW.js +0 -70
  1007. package/dist/chunk-7GLBWWMW.js.map +0 -1
  1008. package/dist/chunk-7RXYW5VM.js +0 -88
  1009. package/dist/chunk-7RXYW5VM.js.map +0 -1
  1010. package/dist/chunk-AC4MGCXI.js +0 -92
  1011. package/dist/chunk-AC4MGCXI.js.map +0 -1
  1012. package/dist/chunk-AEVSVDT6.js +0 -67
  1013. package/dist/chunk-AEVSVDT6.js.map +0 -1
  1014. package/dist/chunk-AODIMN2N.js +0 -68
  1015. package/dist/chunk-AODIMN2N.js.map +0 -1
  1016. package/dist/chunk-ATHOPBCA.js +0 -61
  1017. package/dist/chunk-ATHOPBCA.js.map +0 -1
  1018. package/dist/chunk-AVPHVQZS.js +0 -73
  1019. package/dist/chunk-AVPHVQZS.js.map +0 -1
  1020. package/dist/chunk-AXKBNRZW.js +0 -173
  1021. package/dist/chunk-AXKBNRZW.js.map +0 -1
  1022. package/dist/chunk-B75MEYNR.js +0 -106
  1023. package/dist/chunk-B75MEYNR.js.map +0 -1
  1024. package/dist/chunk-BGKA6DI6.js +0 -34
  1025. package/dist/chunk-BGKA6DI6.js.map +0 -1
  1026. package/dist/chunk-BNQAJGEN.js +0 -88
  1027. package/dist/chunk-BNQAJGEN.js.map +0 -1
  1028. package/dist/chunk-BP2SETUC.js +0 -101
  1029. package/dist/chunk-BP2SETUC.js.map +0 -1
  1030. package/dist/chunk-BPUQWMBD.js +0 -79
  1031. package/dist/chunk-BPUQWMBD.js.map +0 -1
  1032. package/dist/chunk-BVDASR3Y.js +0 -74
  1033. package/dist/chunk-BVDASR3Y.js.map +0 -1
  1034. package/dist/chunk-BX7A5GUV.js +0 -78
  1035. package/dist/chunk-BX7A5GUV.js.map +0 -1
  1036. package/dist/chunk-CDA6RYOX.js +0 -115
  1037. package/dist/chunk-CDA6RYOX.js.map +0 -1
  1038. package/dist/chunk-CG7O3A42.js +0 -80
  1039. package/dist/chunk-CG7O3A42.js.map +0 -1
  1040. package/dist/chunk-CIYGNPKT.js +0 -76
  1041. package/dist/chunk-CIYGNPKT.js.map +0 -1
  1042. package/dist/chunk-CKXY4FTV.js +0 -59
  1043. package/dist/chunk-CKXY4FTV.js.map +0 -1
  1044. package/dist/chunk-CVOKZITR.js +0 -82
  1045. package/dist/chunk-CVOKZITR.js.map +0 -1
  1046. package/dist/chunk-CWFMFKDI.js +0 -82
  1047. package/dist/chunk-CWFMFKDI.js.map +0 -1
  1048. package/dist/chunk-CWVKSV7S.js +0 -124
  1049. package/dist/chunk-CWVKSV7S.js.map +0 -1
  1050. package/dist/chunk-CYOLRWOX.js +0 -63
  1051. package/dist/chunk-CYOLRWOX.js.map +0 -1
  1052. package/dist/chunk-D23LRJT6.js +0 -116
  1053. package/dist/chunk-D23LRJT6.js.map +0 -1
  1054. package/dist/chunk-DFADMEJK.js +0 -127
  1055. package/dist/chunk-DFADMEJK.js.map +0 -1
  1056. package/dist/chunk-DKQAHZG2.js +0 -83
  1057. package/dist/chunk-DKQAHZG2.js.map +0 -1
  1058. package/dist/chunk-DW247T3Q.js +0 -199
  1059. package/dist/chunk-DW247T3Q.js.map +0 -1
  1060. package/dist/chunk-E5A7HN6H.js +0 -32
  1061. package/dist/chunk-E5A7HN6H.js.map +0 -1
  1062. package/dist/chunk-EI63GTN7.js +0 -57
  1063. package/dist/chunk-EI63GTN7.js.map +0 -1
  1064. package/dist/chunk-EP25QJ4N.js +0 -146
  1065. package/dist/chunk-EP25QJ4N.js.map +0 -1
  1066. package/dist/chunk-ET44426Q.js +0 -80
  1067. package/dist/chunk-ET44426Q.js.map +0 -1
  1068. package/dist/chunk-ETEIDY34.js +0 -67
  1069. package/dist/chunk-ETEIDY34.js.map +0 -1
  1070. package/dist/chunk-EU55O4P7.js +0 -76
  1071. package/dist/chunk-EU55O4P7.js.map +0 -1
  1072. package/dist/chunk-F436537E.js +0 -104
  1073. package/dist/chunk-F436537E.js.map +0 -1
  1074. package/dist/chunk-FLBTGNQI.js +0 -86
  1075. package/dist/chunk-FLBTGNQI.js.map +0 -1
  1076. package/dist/chunk-FUT45NFW.js +0 -46
  1077. package/dist/chunk-FUT45NFW.js.map +0 -1
  1078. package/dist/chunk-G3LWNTVZ.js +0 -51
  1079. package/dist/chunk-G3LWNTVZ.js.map +0 -1
  1080. package/dist/chunk-GBJB5WLT.js +0 -58
  1081. package/dist/chunk-GBJB5WLT.js.map +0 -1
  1082. package/dist/chunk-GIEPEFRX.js +0 -110
  1083. package/dist/chunk-GIEPEFRX.js.map +0 -1
  1084. package/dist/chunk-GSO7MISR.js +0 -58
  1085. package/dist/chunk-GSO7MISR.js.map +0 -1
  1086. package/dist/chunk-GUQFYUIC.js +0 -61
  1087. package/dist/chunk-GUQFYUIC.js.map +0 -1
  1088. package/dist/chunk-GXBFGWQN.js +0 -81
  1089. package/dist/chunk-GXBFGWQN.js.map +0 -1
  1090. package/dist/chunk-H3VJMFJQ.js +0 -35
  1091. package/dist/chunk-H3VJMFJQ.js.map +0 -1
  1092. package/dist/chunk-HG4WEERE.js +0 -26
  1093. package/dist/chunk-HG4WEERE.js.map +0 -1
  1094. package/dist/chunk-HGPBGLNP.js +0 -51
  1095. package/dist/chunk-HGPBGLNP.js.map +0 -1
  1096. package/dist/chunk-HQFTW7SF.js +0 -141
  1097. package/dist/chunk-HQFTW7SF.js.map +0 -1
  1098. package/dist/chunk-I32I36LW.js +0 -113
  1099. package/dist/chunk-I32I36LW.js.map +0 -1
  1100. package/dist/chunk-I7WYM63C.js +0 -170
  1101. package/dist/chunk-I7WYM63C.js.map +0 -1
  1102. package/dist/chunk-JPTPIZ5V.js +0 -120
  1103. package/dist/chunk-JPTPIZ5V.js.map +0 -1
  1104. package/dist/chunk-JQXLPVWP.js +0 -74
  1105. package/dist/chunk-JQXLPVWP.js.map +0 -1
  1106. package/dist/chunk-K5ARID4S.js +0 -26
  1107. package/dist/chunk-K5ARID4S.js.map +0 -1
  1108. package/dist/chunk-K6RTLPIJ.js +0 -41
  1109. package/dist/chunk-K6RTLPIJ.js.map +0 -1
  1110. package/dist/chunk-K7PYLTMP.js +0 -221
  1111. package/dist/chunk-K7PYLTMP.js.map +0 -1
  1112. package/dist/chunk-KQNKKV2C.js +0 -56
  1113. package/dist/chunk-KQNKKV2C.js.map +0 -1
  1114. package/dist/chunk-KRN4NE4U.js +0 -155
  1115. package/dist/chunk-KRN4NE4U.js.map +0 -1
  1116. package/dist/chunk-L2BI762I.js +0 -82
  1117. package/dist/chunk-L2BI762I.js.map +0 -1
  1118. package/dist/chunk-LEEH63B2.js +0 -56
  1119. package/dist/chunk-LEEH63B2.js.map +0 -1
  1120. package/dist/chunk-LHRWVM3G.js +0 -42
  1121. package/dist/chunk-LHRWVM3G.js.map +0 -1
  1122. package/dist/chunk-LIGWMGXM.js +0 -117
  1123. package/dist/chunk-LIGWMGXM.js.map +0 -1
  1124. package/dist/chunk-LKYSX3QF.js +0 -104
  1125. package/dist/chunk-LKYSX3QF.js.map +0 -1
  1126. package/dist/chunk-MCIFB6VS.js +0 -54
  1127. package/dist/chunk-MCIFB6VS.js.map +0 -1
  1128. package/dist/chunk-MI5CXMZU.js +0 -171
  1129. package/dist/chunk-MI5CXMZU.js.map +0 -1
  1130. package/dist/chunk-MYEHGDC2.js +0 -152
  1131. package/dist/chunk-MYEHGDC2.js.map +0 -1
  1132. package/dist/chunk-NQZYY4LR.js +0 -84
  1133. package/dist/chunk-NQZYY4LR.js.map +0 -1
  1134. package/dist/chunk-O23LKHUR.js +0 -66
  1135. package/dist/chunk-O23LKHUR.js.map +0 -1
  1136. package/dist/chunk-PASI2U2R.js +0 -23
  1137. package/dist/chunk-PASI2U2R.js.map +0 -1
  1138. package/dist/chunk-PPH5NTHV.js +0 -34
  1139. package/dist/chunk-PPH5NTHV.js.map +0 -1
  1140. package/dist/chunk-PR6OZF6D.js +0 -28
  1141. package/dist/chunk-PR6OZF6D.js.map +0 -1
  1142. package/dist/chunk-PTHRL242.js +0 -186
  1143. package/dist/chunk-PTHRL242.js.map +0 -1
  1144. package/dist/chunk-PWXOXPFT.js +0 -142
  1145. package/dist/chunk-PWXOXPFT.js.map +0 -1
  1146. package/dist/chunk-QB6BNHO3.js +0 -112
  1147. package/dist/chunk-QB6BNHO3.js.map +0 -1
  1148. package/dist/chunk-QJGGTIUN.js +0 -110
  1149. package/dist/chunk-QJGGTIUN.js.map +0 -1
  1150. package/dist/chunk-QSOIJ6J3.js +0 -91
  1151. package/dist/chunk-QSOIJ6J3.js.map +0 -1
  1152. package/dist/chunk-R63ZKLQM.js +0 -45
  1153. package/dist/chunk-R63ZKLQM.js.map +0 -1
  1154. package/dist/chunk-RC5XME4T.js +0 -33
  1155. package/dist/chunk-RC5XME4T.js.map +0 -1
  1156. package/dist/chunk-RTYYJPPE.js +0 -77
  1157. package/dist/chunk-RTYYJPPE.js.map +0 -1
  1158. package/dist/chunk-RVOBP7PO.js +0 -116
  1159. package/dist/chunk-RVOBP7PO.js.map +0 -1
  1160. package/dist/chunk-SF6R5VMQ.js +0 -97
  1161. package/dist/chunk-SF6R5VMQ.js.map +0 -1
  1162. package/dist/chunk-SP4CP5HY.js +0 -57
  1163. package/dist/chunk-SP4CP5HY.js.map +0 -1
  1164. package/dist/chunk-SWJ4EUOI.js +0 -30
  1165. package/dist/chunk-SWJ4EUOI.js.map +0 -1
  1166. package/dist/chunk-TK24HQJJ.js +0 -128
  1167. package/dist/chunk-TK24HQJJ.js.map +0 -1
  1168. package/dist/chunk-UAYOOTRR.js +0 -77
  1169. package/dist/chunk-UAYOOTRR.js.map +0 -1
  1170. package/dist/chunk-UDTAMHXW.js +0 -55
  1171. package/dist/chunk-UDTAMHXW.js.map +0 -1
  1172. package/dist/chunk-UK27KR35.js +0 -73
  1173. package/dist/chunk-UK27KR35.js.map +0 -1
  1174. package/dist/chunk-UOMQPIB4.js +0 -48
  1175. package/dist/chunk-UOMQPIB4.js.map +0 -1
  1176. package/dist/chunk-UOXU7NDY.js +0 -120
  1177. package/dist/chunk-UOXU7NDY.js.map +0 -1
  1178. package/dist/chunk-V7OOTVK3.js +0 -106
  1179. package/dist/chunk-V7OOTVK3.js.map +0 -1
  1180. package/dist/chunk-VI5M7KJ2.js +0 -1022
  1181. package/dist/chunk-VI5M7KJ2.js.map +0 -1
  1182. package/dist/chunk-VMMATOPE.js +0 -64
  1183. package/dist/chunk-VMMATOPE.js.map +0 -1
  1184. package/dist/chunk-W2PVSIW3.js +0 -89
  1185. package/dist/chunk-W2PVSIW3.js.map +0 -1
  1186. package/dist/chunk-W3DUDZDU.js +0 -88
  1187. package/dist/chunk-W3DUDZDU.js.map +0 -1
  1188. package/dist/chunk-WKEUU2FU.js +0 -114
  1189. package/dist/chunk-WKEUU2FU.js.map +0 -1
  1190. package/dist/chunk-WKLW7RC6.js +0 -28
  1191. package/dist/chunk-WKLW7RC6.js.map +0 -1
  1192. package/dist/chunk-WSJGZNUH.js +0 -111
  1193. package/dist/chunk-WSJGZNUH.js.map +0 -1
  1194. package/dist/chunk-WVPDQMC2.js +0 -144
  1195. package/dist/chunk-WVPDQMC2.js.map +0 -1
  1196. package/dist/chunk-WWNH5ENT.js +0 -43
  1197. package/dist/chunk-WWNH5ENT.js.map +0 -1
  1198. package/dist/chunk-X5L62PXY.js +0 -112
  1199. package/dist/chunk-X5L62PXY.js.map +0 -1
  1200. package/dist/chunk-XGCV5E6W.js +0 -133
  1201. package/dist/chunk-XGCV5E6W.js.map +0 -1
  1202. package/dist/chunk-XRKIEL5M.js +0 -72
  1203. package/dist/chunk-XRKIEL5M.js.map +0 -1
  1204. package/dist/chunk-XUJYEADU.js +0 -80
  1205. package/dist/chunk-XUJYEADU.js.map +0 -1
  1206. package/dist/chunk-XVYNSIQC.js +0 -116
  1207. package/dist/chunk-XVYNSIQC.js.map +0 -1
  1208. package/dist/chunk-XWTISHXO.js +0 -54
  1209. package/dist/chunk-XWTISHXO.js.map +0 -1
  1210. package/dist/chunk-XZKEGEPT.js +0 -156
  1211. package/dist/chunk-XZKEGEPT.js.map +0 -1
  1212. package/dist/chunk-YOGHS4UU.js +0 -202
  1213. package/dist/chunk-YOGHS4UU.js.map +0 -1
  1214. package/dist/chunk-YRSKXEOD.js +0 -135
  1215. package/dist/chunk-YRSKXEOD.js.map +0 -1
  1216. package/dist/chunk-ZALLCR7X.js +0 -108
  1217. package/dist/chunk-ZALLCR7X.js.map +0 -1
  1218. package/dist/chunk-ZDAOHMCW.js +0 -46
  1219. package/dist/chunk-ZDAOHMCW.js.map +0 -1
  1220. package/dist/chunk-ZESICCKK.js +0 -37
  1221. package/dist/chunk-ZESICCKK.js.map +0 -1
  1222. package/dist/chunk-ZIKFOD6N.js +0 -87
  1223. package/dist/chunk-ZIKFOD6N.js.map +0 -1
  1224. package/dist/chunk-ZJRWCQEN.js +0 -76
  1225. package/dist/chunk-ZJRWCQEN.js.map +0 -1
  1226. package/dist/chunk-ZSRJCIWF.js +0 -24
  1227. package/dist/chunk-ZSRJCIWF.js.map +0 -1
  1228. package/dist/plugin-Atb0VKtr.d.ts +0 -172
  1229. package/dist/slide/index.d.ts +0 -212
  1230. package/dist/slide/plugins/emoji/index.d.ts +0 -29
  1231. package/dist/slide/plugins/math/index.d.ts +0 -13
  1232. package/dist/slide/plugins/mermaid/index.d.ts +0 -55
  1233. package/dist/slide/plugins/shiki/index.d.ts +0 -18
  1234. package/dist/slide-deck/index.d.ts +0 -377
  1235. package/dist/whiteboard/index.d.ts +0 -258
@@ -14,7 +14,7 @@
14
14
  "path": "components/primitives/context-window-bar/context-window-bar.tsx",
15
15
  "type": "registry:ui",
16
16
  "target": "components/ui/context-window-bar.tsx",
17
- "content": "import { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\ninterface ContextWindowBarProps extends HTMLAttributes<HTMLDivElement> {\n /** Tokens currently used in the context window. */\n used: number;\n /** Model's total context capacity (e.g. 200_000, 1_000_000). */\n total: number;\n /** Optional secondary label rendered on the right (e.g. model name). */\n trailing?: ReactNode;\n /** Optional title shown above the bar. */\n label?: ReactNode;\n /** Compact mode hides numbers and label; just the bar. */\n compact?: boolean;\n /**\n * Override warning thresholds (0..1). Defaults: warn 0.7, danger 0.9.\n */\n warnAt?: number;\n dangerAt?: number;\n}\n\nconst formatTokens = (n: number) => {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${(n / 1_000).toFixed(1)}k`;\n return `${n}`;\n};\n\n/**\n * ContextWindowBar — shows how much of the model's context window has been\n * consumed. Color transitions: success → warning → destructive past thresholds.\n *\n * Critical for transparency: a user should always be able to glance at this\n * and know if the conversation is about to hit the cap.\n */\nconst ContextWindowBar = forwardRef<HTMLDivElement, ContextWindowBarProps>(\n (\n {\n className,\n used,\n total,\n trailing,\n label = \"Context\",\n compact,\n warnAt = 0.7,\n dangerAt = 0.9,\n ...props\n },\n ref,\n ) => {\n const ratio = Math.max(0, Math.min(1, used / total));\n const tone = ratio >= dangerAt ? \"destructive\" : ratio >= warnAt ? \"warning\" : \"primary\";\n const percent = Math.round(ratio * 100);\n\n const barColor = {\n primary: \"bg-primary\",\n warning: \"bg-warning\",\n destructive: \"bg-destructive\",\n }[tone];\n\n const textColor = {\n primary: \"text-foreground\",\n warning: \"text-warning\",\n destructive: \"text-destructive\",\n }[tone];\n\n return (\n <div ref={ref} className={cn(\"grid gap-1.5\", className)} {...props}>\n {!compact ? (\n <div className=\"flex items-baseline justify-between gap-2\">\n <span className=\"font-mono text-label-caps text-muted-foreground uppercase tracking-wider\">\n {label}\n </span>\n <span className={cn(\"font-mono text-body-sm tabular-nums\", textColor)}>\n {formatTokens(used)} / {formatTokens(total)}{\" \"}\n <span className=\"opacity-60\">({percent}%)</span>\n </span>\n </div>\n ) : null}\n <div\n className=\"h-1.5 w-full overflow-hidden rounded-full bg-muted\"\n role=\"progressbar\"\n tabIndex={-1}\n aria-valuenow={used}\n aria-valuemin={0}\n aria-valuemax={total}\n aria-label={`${percent}% of context window used`}\n >\n <div\n className={cn(\n \"h-full rounded-full transition-[width,background-color] duration-base ease-out-soft\",\n barColor,\n )}\n style={{ width: `${percent}%` }}\n />\n </div>\n {trailing ? (\n <div className=\"font-mono text-label text-muted-foreground\">{trailing}</div>\n ) : null}\n </div>\n );\n },\n);\nContextWindowBar.displayName = \"ContextWindowBar\";\n\nexport { ContextWindowBar };\n"
17
+ "content": "import { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\ninterface ContextWindowBarProps extends HTMLAttributes<HTMLDivElement> {\n /** Tokens currently used in the context window. */\n used: number;\n /** Model's total context capacity (e.g. 200_000, 1_000_000). */\n total: number;\n /** Optional secondary label rendered on the right (e.g. model name). */\n trailing?: ReactNode;\n /** Optional title shown above the bar. */\n label?: ReactNode;\n /** Compact mode hides numbers and label; just the bar. */\n compact?: boolean;\n /**\n * Override warning thresholds (0..1). Defaults: warn 0.7, danger 0.9.\n */\n warnAt?: number;\n dangerAt?: number;\n}\n\nconst formatTokens = (n: number) => {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${(n / 1_000).toFixed(1)}k`;\n return `${n}`;\n};\n\n/**\n * ContextWindowBar — shows how much of the model's context window has been\n * consumed. Color transitions: success → warning → destructive past thresholds.\n *\n * Critical for transparency: a user should always be able to glance at this\n * and know if the conversation is about to hit the cap.\n */\nconst ContextWindowBar = forwardRef<HTMLDivElement, ContextWindowBarProps>(\n (\n {\n className,\n used,\n total,\n trailing,\n label = \"Context\",\n compact,\n warnAt = 0.7,\n dangerAt = 0.9,\n ...props\n },\n ref,\n ) => {\n const ratio = Math.max(0, Math.min(1, used / total));\n const tone = ratio >= dangerAt ? \"destructive\" : ratio >= warnAt ? \"warning\" : \"primary\";\n const percent = Math.round(ratio * 100);\n\n const barColor = {\n primary: \"bg-primary\",\n warning: \"bg-warning\",\n destructive: \"bg-destructive\",\n }[tone];\n\n const textColor = {\n primary: \"text-foreground\",\n warning: \"text-warning\",\n destructive: \"text-destructive\",\n }[tone];\n\n return (\n <div\n data-slot=\"context-window-bar\"\n ref={ref}\n className={cn(\"grid gap-1.5\", className)}\n {...props}\n >\n {!compact ? (\n <div className=\"flex items-baseline justify-between gap-2\">\n <span className=\"font-mono text-label-caps text-muted-foreground uppercase tracking-wider\">\n {label}\n </span>\n <span className={cn(\"font-mono text-body-sm tabular-nums\", textColor)}>\n {formatTokens(used)} / {formatTokens(total)}{\" \"}\n <span className=\"opacity-60\">({percent}%)</span>\n </span>\n </div>\n ) : null}\n <div\n className=\"h-1.5 w-full overflow-hidden rounded-full bg-muted\"\n role=\"progressbar\"\n tabIndex={-1}\n aria-valuenow={used}\n aria-valuemin={0}\n aria-valuemax={total}\n aria-label={`${percent}% of context window used`}\n >\n <div\n className={cn(\n \"h-full rounded-full transition-[width,background-color] duration-base ease-out-soft\",\n barColor,\n )}\n style={{ width: `${percent}%` }}\n />\n </div>\n {trailing ? (\n <div className=\"font-mono text-label text-muted-foreground\">{trailing}</div>\n ) : null}\n </div>\n );\n },\n);\nContextWindowBar.displayName = \"ContextWindowBar\";\n\nexport { ContextWindowBar };\n"
18
18
  }
19
19
  ]
20
20
  }
@@ -16,7 +16,7 @@
16
16
  "path": "components/primitives/copy-button/copy-button.tsx",
17
17
  "type": "registry:ui",
18
18
  "target": "components/ui/copy-button.tsx",
19
- "content": "import { Check, Copy, X } from \"lucide-react\";\nimport { forwardRef, useCallback, useEffect, useRef, useState } from \"react\";\nimport type { ButtonHTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\n/**\n * CopyButton — click-to-copy primitive for PaaS surfaces.\n *\n * Wraps the Clipboard API behind a button that:\n * - Calls `navigator.clipboard.writeText(value)` on click\n * - Swaps the icon (Copy → Check on success, Copy → X on failure)\n * - Optionally swaps the visible `label` to \"Copied!\" / \"Failed\"\n * - Announces the state change via an `aria-live=\"polite\"` sr-only region\n * - Reverts to idle after `feedbackDuration` ms (default 1500)\n *\n * SSR-safe (guards `navigator?.clipboard?.writeText`). Debounces double-clicks\n * by ignoring clicks while not in the `idle` state. Cleans up the revert timer\n * on unmount so no `setState` happens on unmounted components.\n *\n * @example\n * <CopyButton value={envVar.value} /> // icon-only ghost\n * <CopyButton value={token} label=\"Copy token\" variant=\"outline\" />\n */\ntype CopyState = \"idle\" | \"copied\" | \"failed\";\n\nexport interface CopyButtonProps\n extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, \"type\" | \"onClick\" | \"children\"> {\n /** String to copy when clicked. */\n value: string;\n /** Optional button label. Default: just the icon. */\n label?: ReactNode;\n /** Visual style. */\n variant?: \"ghost\" | \"outline\";\n /** Size. */\n size?: \"sm\" | \"md\";\n /** Callback after successful copy (e.g. analytics). */\n onCopied?: (value: string) => void;\n /** Duration of the feedback state in ms. Default 1500. */\n feedbackDuration?: number;\n}\n\nconst VARIANT: Record<NonNullable<CopyButtonProps[\"variant\"]>, string> = {\n ghost: \"hover:bg-muted\",\n outline: \"border border-border/60 rounded-md\",\n};\n\nconst SIZE: Record<NonNullable<CopyButtonProps[\"size\"]>, string> = {\n sm: \"px-2 py-1 text-label\",\n md: \"px-2.5 py-1.5 text-body-sm\",\n};\n\nconst CopyButton = forwardRef<HTMLButtonElement, CopyButtonProps>(\n (\n {\n className,\n value,\n label,\n variant = \"ghost\",\n size = \"sm\",\n onCopied,\n feedbackDuration = 1500,\n ...props\n },\n ref,\n ) => {\n const [state, setState] = useState<CopyState>(\"idle\");\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n return () => {\n if (timerRef.current !== null) {\n clearTimeout(timerRef.current);\n }\n };\n }, []);\n\n const scheduleRevert = useCallback(() => {\n if (timerRef.current !== null) {\n clearTimeout(timerRef.current);\n }\n timerRef.current = setTimeout(() => {\n setState(\"idle\");\n timerRef.current = null;\n }, feedbackDuration);\n }, [feedbackDuration]);\n\n const handleClick = useCallback(() => {\n if (state !== \"idle\") return;\n\n if (typeof navigator === \"undefined\" || !navigator.clipboard?.writeText) {\n setState(\"failed\");\n scheduleRevert();\n return;\n }\n\n navigator.clipboard.writeText(value).then(\n () => {\n setState(\"copied\");\n onCopied?.(value);\n scheduleRevert();\n },\n () => {\n setState(\"failed\");\n scheduleRevert();\n },\n );\n }, [state, value, onCopied, scheduleRevert]);\n\n const Icon = state === \"copied\" ? Check : state === \"failed\" ? X : Copy;\n const liveMessage =\n state === \"copied\" ? \"Copied to clipboard\" : state === \"failed\" ? \"Copy failed\" : \"\";\n\n const labelText =\n label !== undefined\n ? state === \"copied\"\n ? \"Copied!\"\n : state === \"failed\"\n ? \"Failed\"\n : label\n : null;\n\n return (\n <button\n ref={ref}\n type=\"button\"\n onClick={handleClick}\n data-state={state}\n className={cn(\n \"inline-flex items-center gap-1.5\",\n \"font-sans transition-colors\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card\",\n VARIANT[variant],\n SIZE[size],\n className,\n )}\n {...props}\n >\n <Icon\n aria-hidden=\"true\"\n className={cn(\n \"size-3.5 shrink-0 transition-opacity duration-200\",\n state === \"copied\" && \"text-success\",\n state === \"failed\" && \"text-destructive\",\n )}\n />\n {labelText !== null ? <span>{labelText}</span> : null}\n <span className=\"sr-only\" aria-live=\"polite\">\n {liveMessage}\n </span>\n </button>\n );\n },\n);\nCopyButton.displayName = \"CopyButton\";\n\nexport { CopyButton };\n"
19
+ "content": "\"use client\";\n\nimport { Check, Copy, X } from \"lucide-react\";\nimport { forwardRef, useCallback, useEffect, useRef, useState } from \"react\";\nimport type { ButtonHTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\n/**\n * CopyButton — click-to-copy primitive for PaaS surfaces.\n *\n * Wraps the Clipboard API behind a button that:\n * - Calls `navigator.clipboard.writeText(value)` on click\n * - Swaps the icon (Copy → Check on success, Copy → X on failure)\n * - Optionally swaps the visible `label` to \"Copied!\" / \"Failed\"\n * - Announces the state change via an `aria-live=\"polite\"` sr-only region\n * - Reverts to idle after `feedbackDuration` ms (default 1500)\n *\n * SSR-safe (guards `navigator?.clipboard?.writeText`). Debounces double-clicks\n * by ignoring clicks while not in the `idle` state. Cleans up the revert timer\n * on unmount so no `setState` happens on unmounted components.\n *\n * @example\n * <CopyButton value={envVar.value} /> // icon-only ghost\n * <CopyButton value={token} label=\"Copy token\" variant=\"outline\" />\n */\ntype CopyState = \"idle\" | \"copied\" | \"failed\";\n\nexport interface CopyButtonProps\n extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, \"type\" | \"onClick\" | \"children\"> {\n /** String to copy when clicked. */\n value: string;\n /** Optional button label. Default: just the icon. */\n label?: ReactNode;\n /** Visual style. */\n variant?: \"ghost\" | \"outline\";\n /** Size. */\n size?: \"sm\" | \"md\";\n /** Callback after successful copy (e.g. analytics). */\n onCopied?: (value: string) => void;\n /** Duration of the feedback state in ms. Default 1500. */\n feedbackDuration?: number;\n}\n\nconst VARIANT: Record<NonNullable<CopyButtonProps[\"variant\"]>, string> = {\n ghost: \"hover:bg-muted\",\n outline: \"border border-border/60 rounded-md\",\n};\n\nconst SIZE: Record<NonNullable<CopyButtonProps[\"size\"]>, string> = {\n sm: \"px-2 py-1 text-label\",\n md: \"px-2.5 py-1.5 text-body-sm\",\n};\n\nconst CopyButton = forwardRef<HTMLButtonElement, CopyButtonProps>(\n (\n {\n className,\n value,\n label,\n variant = \"ghost\",\n size = \"sm\",\n onCopied,\n feedbackDuration = 1500,\n ...props\n },\n ref,\n ) => {\n const [state, setState] = useState<CopyState>(\"idle\");\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n return () => {\n if (timerRef.current !== null) {\n clearTimeout(timerRef.current);\n }\n };\n }, []);\n\n const scheduleRevert = useCallback(() => {\n if (timerRef.current !== null) {\n clearTimeout(timerRef.current);\n }\n timerRef.current = setTimeout(() => {\n setState(\"idle\");\n timerRef.current = null;\n }, feedbackDuration);\n }, [feedbackDuration]);\n\n const handleClick = useCallback(() => {\n if (state !== \"idle\") return;\n\n if (typeof navigator === \"undefined\" || !navigator.clipboard?.writeText) {\n setState(\"failed\");\n scheduleRevert();\n return;\n }\n\n navigator.clipboard.writeText(value).then(\n () => {\n setState(\"copied\");\n onCopied?.(value);\n scheduleRevert();\n },\n () => {\n setState(\"failed\");\n scheduleRevert();\n },\n );\n }, [state, value, onCopied, scheduleRevert]);\n\n const Icon = state === \"copied\" ? Check : state === \"failed\" ? X : Copy;\n const liveMessage =\n state === \"copied\" ? \"Copied to clipboard\" : state === \"failed\" ? \"Copy failed\" : \"\";\n\n const labelText =\n label !== undefined\n ? state === \"copied\"\n ? \"Copied!\"\n : state === \"failed\"\n ? \"Failed\"\n : label\n : null;\n\n return (\n <button\n data-slot=\"copy-button\"\n ref={ref}\n type=\"button\"\n onClick={handleClick}\n data-state={state}\n className={cn(\n \"inline-flex items-center gap-1.5\",\n \"font-sans transition-colors\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card\",\n VARIANT[variant],\n SIZE[size],\n className,\n )}\n {...props}\n >\n <Icon\n aria-hidden=\"true\"\n className={cn(\n \"size-3.5 shrink-0 transition-opacity duration-200\",\n state === \"copied\" && \"text-success\",\n state === \"failed\" && \"text-destructive\",\n )}\n />\n {labelText !== null ? <span>{labelText}</span> : null}\n <span className=\"sr-only\" aria-live=\"polite\">\n {liveMessage}\n </span>\n </button>\n );\n },\n);\nCopyButton.displayName = \"CopyButton\";\n\nexport { CopyButton };\n"
20
20
  }
21
21
  ]
22
22
  }
@@ -16,7 +16,7 @@
16
16
  "path": "components/primitives/cost-meter/cost-meter.tsx",
17
17
  "type": "registry:ui",
18
18
  "target": "components/ui/cost-meter.tsx",
19
- "content": "import { Coins, TrendingDown, TrendingUp } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\ninterface CostMeterProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n /** Current cost in USD. */\n cost: number;\n /** Optional monthly budget; renders progress bar when present. */\n budget?: number;\n /** Optional title (e.g. \"This session\", \"Monthly\"). */\n title?: ReactNode;\n /** Optional delta vs previous period. */\n delta?: { value: number; period: string };\n /** Compact mode — single-line summary. */\n compact?: boolean;\n}\n\nconst formatUsd = (n: number) =>\n n >= 100 ? `$${n.toFixed(0)}` : n >= 10 ? `$${n.toFixed(1)}` : `$${n.toFixed(2)}`;\n\n/**\n * CostMeter — gauge for token spend. Two visuals:\n * - card: title + big number + optional progress bar + optional delta.\n * - compact: chip \"Coins $4.20\" for nav bars.\n */\nconst CostMeter = forwardRef<HTMLDivElement, CostMeterProps>(\n ({ className, cost, budget, title = \"Spend\", delta, compact, ...props }, ref) => {\n if (compact) {\n return (\n <div\n ref={ref}\n className={cn(\n \"inline-flex items-center gap-1.5 rounded-full border border-border/60 bg-card px-2.5 py-1\",\n \"font-mono text-label\",\n className,\n )}\n {...props}\n >\n <Coins className=\"size-3 text-primary\" aria-hidden=\"true\" />\n <span className=\"text-foreground tabular-nums\">{formatUsd(cost)}</span>\n {budget ? <span className=\"text-muted-foreground\">/ {formatUsd(budget)}</span> : null}\n </div>\n );\n }\n\n const ratio = budget ? Math.max(0, Math.min(1, cost / budget)) : 0;\n const percent = Math.round(ratio * 100);\n const overBudget = budget !== undefined && cost > budget;\n\n return (\n <div\n ref={ref}\n className={cn(\"grid gap-2 rounded-xl border bg-card p-4\", className)}\n {...props}\n >\n <header className=\"flex items-baseline justify-between\">\n <span className=\"font-mono text-label-caps text-muted-foreground uppercase tracking-wider\">\n {title}\n </span>\n {delta ? (\n <span\n className={cn(\n \"inline-flex items-center gap-1 font-mono text-body-sm tabular-nums\",\n delta.value >= 0 ? \"text-warning\" : \"text-success\",\n )}\n >\n {delta.value >= 0 ? (\n <TrendingUp className=\"size-3\" aria-hidden=\"true\" />\n ) : (\n <TrendingDown className=\"size-3\" aria-hidden=\"true\" />\n )}\n {delta.value >= 0 ? \"+\" : \"\"}\n {formatUsd(Math.abs(delta.value))}{\" \"}\n <span className=\"text-muted-foreground\">{delta.period}</span>\n </span>\n ) : null}\n </header>\n <div className=\"flex items-baseline gap-1.5\">\n <span className=\"font-bold font-display text-display-md text-foreground tabular-nums leading-none\">\n {formatUsd(cost)}\n </span>\n {budget !== undefined ? (\n <span className=\"font-mono text-body-sm text-muted-foreground\">\n of {formatUsd(budget)}\n </span>\n ) : null}\n </div>\n {budget !== undefined ? (\n <div className=\"grid gap-1\">\n <div\n className=\"h-1.5 w-full overflow-hidden rounded-full bg-muted\"\n role=\"progressbar\"\n tabIndex={-1}\n aria-valuenow={percent}\n aria-valuemin={0}\n aria-valuemax={100}\n >\n <div\n className={cn(\n \"h-full rounded-full transition-[width,background-color]\",\n overBudget ? \"bg-destructive\" : ratio > 0.75 ? \"bg-warning\" : \"bg-primary\",\n )}\n style={{ width: `${Math.min(100, percent)}%` }}\n />\n </div>\n <span className=\"font-mono text-label text-muted-foreground tabular-nums\">\n {percent}% of budget {overBudget ? \"· over!\" : \"used\"}\n </span>\n </div>\n ) : null}\n </div>\n );\n },\n);\nCostMeter.displayName = \"CostMeter\";\n\nexport { CostMeter };\n"
19
+ "content": "import { Coins, TrendingDown, TrendingUp } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\ninterface CostMeterProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n /** Current cost in USD. */\n cost: number;\n /** Optional monthly budget; renders progress bar when present. */\n budget?: number;\n /** Optional title (e.g. \"This session\", \"Monthly\"). */\n title?: ReactNode;\n /** Optional delta vs previous period. */\n delta?: { value: number; period: string };\n /** Compact mode — single-line summary. */\n compact?: boolean;\n}\n\nconst formatUsd = (n: number) =>\n n >= 100 ? `$${n.toFixed(0)}` : n >= 10 ? `$${n.toFixed(1)}` : `$${n.toFixed(2)}`;\n\n/**\n * CostMeter — gauge for token spend. Two visuals:\n * - card: title + big number + optional progress bar + optional delta.\n * - compact: chip \"Coins $4.20\" for nav bars.\n */\nconst CostMeter = forwardRef<HTMLDivElement, CostMeterProps>(\n ({ className, cost, budget, title = \"Spend\", delta, compact, ...props }, ref) => {\n if (compact) {\n return (\n <div\n data-slot=\"cost-meter\"\n ref={ref}\n className={cn(\n \"inline-flex items-center gap-1.5 rounded-full border border-border/60 bg-card px-2.5 py-1\",\n \"font-mono text-label\",\n className,\n )}\n {...props}\n >\n <Coins className=\"size-3 text-primary\" aria-hidden=\"true\" />\n <span className=\"text-foreground tabular-nums\">{formatUsd(cost)}</span>\n {budget ? <span className=\"text-muted-foreground\">/ {formatUsd(budget)}</span> : null}\n </div>\n );\n }\n\n const ratio = budget ? Math.max(0, Math.min(1, cost / budget)) : 0;\n const percent = Math.round(ratio * 100);\n const overBudget = budget !== undefined && cost > budget;\n\n return (\n <div\n data-slot=\"cost-meter\"\n ref={ref}\n className={cn(\"grid gap-2 rounded-xl border bg-card p-4\", className)}\n {...props}\n >\n <header className=\"flex items-baseline justify-between\">\n <span className=\"font-mono text-label-caps text-muted-foreground uppercase tracking-wider\">\n {title}\n </span>\n {delta ? (\n <span\n className={cn(\n \"inline-flex items-center gap-1 font-mono text-body-sm tabular-nums\",\n delta.value >= 0 ? \"text-warning\" : \"text-success\",\n )}\n >\n {delta.value >= 0 ? (\n <TrendingUp className=\"size-3\" aria-hidden=\"true\" />\n ) : (\n <TrendingDown className=\"size-3\" aria-hidden=\"true\" />\n )}\n {delta.value >= 0 ? \"+\" : \"\"}\n {formatUsd(Math.abs(delta.value))}{\" \"}\n <span className=\"text-muted-foreground\">{delta.period}</span>\n </span>\n ) : null}\n </header>\n <div className=\"flex items-baseline gap-1.5\">\n <span className=\"font-bold font-display text-display-md text-foreground tabular-nums leading-none\">\n {formatUsd(cost)}\n </span>\n {budget !== undefined ? (\n <span className=\"font-mono text-body-sm text-muted-foreground\">\n of {formatUsd(budget)}\n </span>\n ) : null}\n </div>\n {budget !== undefined ? (\n <div className=\"grid gap-1\">\n <div\n className=\"h-1.5 w-full overflow-hidden rounded-full bg-muted\"\n role=\"progressbar\"\n tabIndex={-1}\n aria-valuenow={percent}\n aria-valuemin={0}\n aria-valuemax={100}\n >\n <div\n className={cn(\n \"h-full rounded-full transition-[width,background-color]\",\n overBudget ? \"bg-destructive\" : ratio > 0.75 ? \"bg-warning\" : \"bg-primary\",\n )}\n style={{ width: `${Math.min(100, percent)}%` }}\n />\n </div>\n <span className=\"font-mono text-label text-muted-foreground tabular-nums\">\n {percent}% of budget {overBudget ? \"· over!\" : \"used\"}\n </span>\n </div>\n ) : null}\n </div>\n );\n },\n);\nCostMeter.displayName = \"CostMeter\";\n\nexport { CostMeter };\n"
20
20
  }
21
21
  ]
22
22
  }
@@ -17,7 +17,7 @@
17
17
  "path": "components/primitives/created-files-card/created-files-card.tsx",
18
18
  "type": "registry:ui",
19
19
  "target": "components/ui/created-files-card.tsx",
20
- "content": "import { Cloud, FileSpreadsheet, Folder } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport type { IconComponent } from \"@/lib/types\";\n\nexport interface CreatedFile {\n id: string;\n name: string;\n /** Optional size for display, e.g. \"42 KB\". */\n size?: string;\n /** Icon override. */\n icon?: IconComponent;\n /** Optional destination metadata (e.g. \"Google Drive · /Reports\"). */\n destination?: ReactNode;\n /** Optional URL to open the file. */\n href?: string;\n}\n\ninterface CreatedFilesCardProps extends Omit<HTMLAttributes<HTMLElement>, \"title\"> {\n title?: ReactNode;\n files: CreatedFile[];\n /**\n * Optional CTA shown at the bottom (e.g. \"Move to Google Drive\").\n */\n cta?: ReactNode;\n}\n\n/**\n * CreatedFilesCard — surfaces files produced by a completed task.\n *\n * From WIREMOCKS §2: each file is a card-like row with icon + name + destination.\n * Used as social proof of delivery in Task Completed views.\n */\nconst CreatedFilesCard = forwardRef<HTMLElement, CreatedFilesCardProps>(\n ({ className, title = \"Files created\", files, cta, ...props }, ref) => (\n <section\n ref={ref}\n className={cn(\"rounded-xl border border-primary/40 bg-primary/5 p-4\", className)}\n {...props}\n >\n <header className=\"mb-3 flex items-center gap-2\">\n <Cloud className=\"size-4 text-primary\" aria-hidden=\"true\" />\n <h3 className=\"font-display text-title-md tracking-tight\">{title}</h3>\n </header>\n <ul className=\"grid gap-2\">\n {files.map((file) => {\n const Icon = file.icon ?? FileSpreadsheet;\n const RowTag = file.href ? \"a\" : \"div\";\n return (\n <li key={file.id}>\n <RowTag\n href={file.href}\n target={file.href ? \"_blank\" : undefined}\n rel={file.href ? \"noreferrer\" : undefined}\n className={cn(\n \"flex items-center gap-3 rounded-md border border-border/40 bg-card px-3 py-2\",\n file.href &&\n \"transition-colors hover:border-primary/40 hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n )}\n >\n <Icon className=\"size-5 shrink-0 text-primary\" aria-hidden=\"true\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate font-mono text-code-md text-foreground\">{file.name}</p>\n {file.destination ? (\n <p className=\"flex items-center gap-1 truncate text-body-sm text-muted-foreground\">\n <Folder className=\"size-3 shrink-0\" aria-hidden=\"true\" /> {file.destination}\n </p>\n ) : null}\n </div>\n {file.size ? (\n <span className=\"font-mono text-code-sm text-muted-foreground\">{file.size}</span>\n ) : null}\n </RowTag>\n </li>\n );\n })}\n </ul>\n {cta ? <div className=\"mt-3 flex justify-end\">{cta}</div> : null}\n </section>\n ),\n);\nCreatedFilesCard.displayName = \"CreatedFilesCard\";\n\nexport { CreatedFilesCard };\n"
20
+ "content": "import { Cloud, FileSpreadsheet, Folder } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport type { IconComponent } from \"@/lib/types\";\n\nexport interface CreatedFile {\n id: string;\n name: string;\n /** Optional size for display, e.g. \"42 KB\". */\n size?: string;\n /** Icon override. */\n icon?: IconComponent;\n /** Optional destination metadata (e.g. \"Google Drive · /Reports\"). */\n destination?: ReactNode;\n /** Optional URL to open the file. */\n href?: string;\n}\n\ninterface CreatedFilesCardProps extends Omit<HTMLAttributes<HTMLElement>, \"title\"> {\n title?: ReactNode;\n files: CreatedFile[];\n /**\n * Optional CTA shown at the bottom (e.g. \"Move to Google Drive\").\n */\n cta?: ReactNode;\n}\n\n/**\n * CreatedFilesCard — surfaces files produced by a completed task.\n *\n * From WIREMOCKS §2: each file is a card-like row with icon + name + destination.\n * Used as social proof of delivery in Task Completed views.\n */\nconst CreatedFilesCard = forwardRef<HTMLElement, CreatedFilesCardProps>(\n ({ className, title = \"Files created\", files, cta, ...props }, ref) => (\n <section\n data-slot=\"created-files-card\"\n ref={ref}\n className={cn(\"rounded-xl border border-primary/40 bg-primary/5 p-4\", className)}\n {...props}\n >\n <header className=\"mb-3 flex items-center gap-2\">\n <Cloud className=\"size-4 text-primary\" aria-hidden=\"true\" />\n <h3 className=\"font-display text-title-md tracking-tight\">{title}</h3>\n </header>\n <ul className=\"grid gap-2\">\n {files.map((file) => {\n const Icon = file.icon ?? FileSpreadsheet;\n const RowTag = file.href ? \"a\" : \"div\";\n return (\n <li key={file.id}>\n <RowTag\n href={file.href}\n target={file.href ? \"_blank\" : undefined}\n rel={file.href ? \"noreferrer\" : undefined}\n className={cn(\n \"flex items-center gap-3 rounded-md border border-border/40 bg-card px-3 py-2\",\n file.href &&\n \"transition-colors hover:border-primary/40 hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n )}\n >\n <Icon className=\"size-5 shrink-0 text-primary\" aria-hidden=\"true\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate font-mono text-code-md text-foreground\">{file.name}</p>\n {file.destination ? (\n <p className=\"flex items-center gap-1 truncate text-body-sm text-muted-foreground\">\n <Folder className=\"size-3 shrink-0\" aria-hidden=\"true\" /> {file.destination}\n </p>\n ) : null}\n </div>\n {file.size ? (\n <span className=\"font-mono text-code-sm text-muted-foreground\">{file.size}</span>\n ) : null}\n </RowTag>\n </li>\n );\n })}\n </ul>\n {cta ? <div className=\"mt-3 flex justify-end\">{cta}</div> : null}\n </section>\n ),\n);\nCreatedFilesCard.displayName = \"CreatedFilesCard\";\n\nexport { CreatedFilesCard };\n"
21
21
  }
22
22
  ]
23
23
  }
@@ -16,7 +16,7 @@
16
16
  "path": "components/primitives/cron-job-card/cron-job-card.tsx",
17
17
  "type": "registry:ui",
18
18
  "target": "components/ui/cron-job-card.tsx",
19
- "content": "import { Clock, Play, Square, Trash2 } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\nexport type CronJobStatus = \"idle\" | \"running\" | \"failed\" | \"disabled\";\n\nexport interface CronJob {\n id: string;\n /** Human-readable job name. */\n name: string;\n /** Cron expression — e.g. every 4 hours. */\n schedule: string;\n /** What gets run (prompt or command). */\n prompt: string;\n status: CronJobStatus;\n /** ISO/string timestamp of last run. */\n lastRun?: string;\n /** ISO/string timestamp of next run. */\n nextRun?: string;\n /** Optional last-run result line. */\n lastResult?: ReactNode;\n}\n\ninterface CronJobCardProps extends Omit<HTMLAttributes<HTMLElement>, \"onToggle\"> {\n job: CronJob;\n onRunNow?: (id: string) => void;\n onToggle?: (id: string, enabled: boolean) => void;\n onRemove?: (id: string) => void;\n}\n\nconst STATUS_CONFIG: Record<CronJobStatus, { label: string; class: string }> = {\n idle: { label: \"Scheduled\", class: \"border-success/40 bg-success/10 text-success\" },\n running: {\n label: \"Running\",\n class: \"border-primary/40 bg-primary/10 text-primary animate-pulse\",\n },\n failed: {\n label: \"Last run failed\",\n class: \"border-destructive/40 bg-destructive/10 text-destructive\",\n },\n disabled: { label: \"Disabled\", class: \"border-border/40 bg-muted text-muted-foreground\" },\n};\n\n/**\n * CronJobCard — one scheduled agent job. Shows cron expression, prompt,\n * status, last/next run. Inline actions: run now, pause, delete.\n */\nconst CronJobCard = forwardRef<HTMLElement, CronJobCardProps>(\n ({ className, job, onRunNow, onToggle, onRemove, ...props }, ref) => {\n const cfg = STATUS_CONFIG[job.status];\n const enabled = job.status !== \"disabled\";\n return (\n <article\n ref={ref}\n className={cn(\n \"grid gap-3 rounded-xl border bg-card p-4\",\n job.status === \"disabled\" && \"opacity-70\",\n className,\n )}\n {...props}\n >\n <header className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <h4 className=\"font-display text-title-md tracking-tight\">{job.name}</h4>\n <p className=\"mt-0.5 inline-flex items-center gap-2 font-mono text-code-sm text-muted-foreground\">\n <Clock className=\"size-3\" aria-hidden=\"true\" /> {job.schedule}\n </p>\n </div>\n <span\n className={cn(\n \"inline-flex items-center rounded-full border px-2.5 py-0.5\",\n \"font-mono text-label uppercase tracking-wider\",\n cfg.class,\n )}\n >\n {cfg.label}\n </span>\n </header>\n\n <p className=\"line-clamp-2 rounded-md bg-muted/60 px-3 py-2 font-mono text-code-sm text-foreground\">\n {job.prompt}\n </p>\n\n <div className=\"grid grid-cols-2 gap-3 font-mono text-label text-muted-foreground\">\n <span>\n <span className=\"text-muted-foreground/60\">last:</span> {job.lastRun ?? \"never\"}\n </span>\n <span>\n <span className=\"text-muted-foreground/60\">next:</span> {job.nextRun ?? \"—\"}\n </span>\n </div>\n\n {job.lastResult ? (\n <p className=\"text-body-sm text-muted-foreground\">{job.lastResult}</p>\n ) : null}\n\n <footer className=\"flex items-center justify-end gap-1.5\">\n {onRunNow ? (\n <button\n type=\"button\"\n onClick={() => onRunNow(job.id)}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border/60 bg-card px-2.5 py-1 font-mono text-label hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <Play className=\"size-3\" /> Run now\n </button>\n ) : null}\n {onToggle ? (\n <button\n type=\"button\"\n onClick={() => onToggle(job.id, !enabled)}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border/60 bg-card px-2.5 py-1 font-mono text-label hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <Square className=\"size-3\" /> {enabled ? \"Pause\" : \"Enable\"}\n </button>\n ) : null}\n {onRemove ? (\n <button\n type=\"button\"\n onClick={() => onRemove(job.id)}\n aria-label={`Remove ${job.name}`}\n className=\"rounded-md p-1.5 text-muted-foreground hover:bg-muted hover:text-destructive focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <Trash2 className=\"size-3.5\" />\n </button>\n ) : null}\n </footer>\n </article>\n );\n },\n);\nCronJobCard.displayName = \"CronJobCard\";\n\nexport { CronJobCard };\n"
19
+ "content": "import { Clock, Play, Square, Trash2 } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\nexport type CronJobStatus = \"idle\" | \"running\" | \"failed\" | \"disabled\";\n\nexport interface CronJob {\n id: string;\n /** Human-readable job name. */\n name: string;\n /** Cron expression — e.g. every 4 hours. */\n schedule: string;\n /** What gets run (prompt or command). */\n prompt: string;\n status: CronJobStatus;\n /** ISO/string timestamp of last run. */\n lastRun?: string;\n /** ISO/string timestamp of next run. */\n nextRun?: string;\n /** Optional last-run result line. */\n lastResult?: ReactNode;\n}\n\ninterface CronJobCardProps extends Omit<HTMLAttributes<HTMLElement>, \"onToggle\"> {\n job: CronJob;\n onRunNow?: (id: string) => void;\n onToggle?: (id: string, enabled: boolean) => void;\n onRemove?: (id: string) => void;\n}\n\nconst STATUS_CONFIG: Record<CronJobStatus, { label: string; class: string }> = {\n idle: { label: \"Scheduled\", class: \"border-success/40 bg-success/10 text-success\" },\n running: {\n label: \"Running\",\n class: \"border-primary/40 bg-primary/10 text-primary animate-pulse\",\n },\n failed: {\n label: \"Last run failed\",\n class: \"border-destructive/40 bg-destructive/10 text-destructive\",\n },\n disabled: { label: \"Disabled\", class: \"border-border/40 bg-muted text-muted-foreground\" },\n};\n\n/**\n * CronJobCard — one scheduled agent job. Shows cron expression, prompt,\n * status, last/next run. Inline actions: run now, pause, delete.\n */\nconst CronJobCard = forwardRef<HTMLElement, CronJobCardProps>(\n ({ className, job, onRunNow, onToggle, onRemove, ...props }, ref) => {\n const cfg = STATUS_CONFIG[job.status];\n const enabled = job.status !== \"disabled\";\n return (\n <article\n data-slot=\"cron-job-card\"\n ref={ref}\n className={cn(\n \"grid gap-3 rounded-xl border bg-card p-4\",\n job.status === \"disabled\" && \"opacity-70\",\n className,\n )}\n {...props}\n >\n <header className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <h4 className=\"font-display text-title-md tracking-tight\">{job.name}</h4>\n <p className=\"mt-0.5 inline-flex items-center gap-2 font-mono text-code-sm text-muted-foreground\">\n <Clock className=\"size-3\" aria-hidden=\"true\" /> {job.schedule}\n </p>\n </div>\n <span\n className={cn(\n \"inline-flex items-center rounded-full border px-2.5 py-0.5\",\n \"font-mono text-label uppercase tracking-wider\",\n cfg.class,\n )}\n >\n {cfg.label}\n </span>\n </header>\n\n <p className=\"line-clamp-2 rounded-md bg-muted/60 px-3 py-2 font-mono text-code-sm text-foreground\">\n {job.prompt}\n </p>\n\n <div className=\"grid grid-cols-2 gap-3 font-mono text-label text-muted-foreground\">\n <span>\n <span className=\"text-muted-foreground/60\">last:</span> {job.lastRun ?? \"never\"}\n </span>\n <span>\n <span className=\"text-muted-foreground/60\">next:</span> {job.nextRun ?? \"—\"}\n </span>\n </div>\n\n {job.lastResult ? (\n <p className=\"text-body-sm text-muted-foreground\">{job.lastResult}</p>\n ) : null}\n\n <footer className=\"flex items-center justify-end gap-1.5\">\n {onRunNow ? (\n <button\n type=\"button\"\n onClick={() => onRunNow(job.id)}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border/60 bg-card px-2.5 py-1 font-mono text-label hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <Play className=\"size-3\" /> Run now\n </button>\n ) : null}\n {onToggle ? (\n <button\n type=\"button\"\n onClick={() => onToggle(job.id, !enabled)}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border/60 bg-card px-2.5 py-1 font-mono text-label hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <Square className=\"size-3\" /> {enabled ? \"Pause\" : \"Enable\"}\n </button>\n ) : null}\n {onRemove ? (\n <button\n type=\"button\"\n onClick={() => onRemove(job.id)}\n aria-label={`Remove ${job.name}`}\n className=\"rounded-md p-1.5 text-muted-foreground hover:bg-muted hover:text-destructive focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <Trash2 className=\"size-3.5\" />\n </button>\n ) : null}\n </footer>\n </article>\n );\n },\n);\nCronJobCard.displayName = \"CronJobCard\";\n\nexport { CronJobCard };\n"
20
20
  }
21
21
  ]
22
22
  }
@@ -17,7 +17,7 @@
17
17
  "path": "components/composites/cron-jobs-list/cron-jobs-list.tsx",
18
18
  "type": "registry:block",
19
19
  "target": "components/blocks/cron-jobs-list.tsx",
20
- "content": "import { Plus } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport { type CronJob, CronJobCard } from \"@/components/ui/cron-job-card\";\n\ninterface CronJobsListProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\" | \"onToggle\"> {\n jobs: CronJob[];\n title?: ReactNode;\n onAdd?: () => void;\n onRunNow?: (id: string) => void;\n onToggle?: (id: string, enabled: boolean) => void;\n onRemove?: (id: string) => void;\n}\n\n/**\n * CronJobsList — grid of CronJobCards with a sticky \"new job\" action.\n */\nconst CronJobsList = forwardRef<HTMLDivElement, CronJobsListProps>(\n (\n { className, jobs, title = \"Scheduled jobs\", onAdd, onRunNow, onToggle, onRemove, ...props },\n ref,\n ) => (\n <section\n ref={ref}\n className={cn(\"grid gap-3\", className)}\n aria-label=\"Scheduled agent jobs\"\n {...props}\n >\n <header className=\"flex items-baseline justify-between\">\n {title ? <h3 className=\"font-display text-title-md tracking-tight\">{title}</h3> : <span />}\n <div className=\"flex items-center gap-3\">\n <span className=\"font-mono text-label text-muted-foreground\">\n {jobs.length} {jobs.length === 1 ? \"job\" : \"jobs\"}\n </span>\n {onAdd ? (\n <button\n type=\"button\"\n onClick={onAdd}\n className=\"inline-flex items-center gap-1 rounded-md bg-primary px-2.5 py-1 font-sans text-label text-primary-foreground hover:shadow-glow focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <Plus className=\"size-3.5\" /> New job\n </button>\n ) : null}\n </div>\n </header>\n {jobs.length === 0 ? (\n <p className=\"rounded-xl border border-border/60 border-dashed bg-muted/30 px-4 py-8 text-center font-sans text-body-sm text-muted-foreground\">\n No scheduled jobs yet.\n </p>\n ) : (\n <div className=\"grid grid-cols-1 gap-3 md:grid-cols-2\">\n {jobs.map((job) => (\n <CronJobCard\n key={job.id}\n job={job}\n {...(onRunNow ? { onRunNow } : {})}\n {...(onToggle ? { onToggle } : {})}\n {...(onRemove ? { onRemove } : {})}\n />\n ))}\n </div>\n )}\n </section>\n ),\n);\nCronJobsList.displayName = \"CronJobsList\";\n\nexport { CronJobsList };\n"
20
+ "content": "import { Plus } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport { type CronJob, CronJobCard } from \"@/components/ui/cron-job-card\";\n\ninterface CronJobsListProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\" | \"onToggle\"> {\n jobs: CronJob[];\n title?: ReactNode;\n onAdd?: () => void;\n onRunNow?: (id: string) => void;\n onToggle?: (id: string, enabled: boolean) => void;\n onRemove?: (id: string) => void;\n}\n\n/**\n * CronJobsList — grid of CronJobCards with a sticky \"new job\" action.\n */\nconst CronJobsList = forwardRef<HTMLDivElement, CronJobsListProps>(\n (\n { className, jobs, title = \"Scheduled jobs\", onAdd, onRunNow, onToggle, onRemove, ...props },\n ref,\n ) => (\n <section\n data-slot=\"cron-jobs-list\"\n ref={ref}\n className={cn(\"grid gap-3\", className)}\n aria-label=\"Scheduled agent jobs\"\n {...props}\n >\n <header className=\"flex items-baseline justify-between\">\n {title ? <h3 className=\"font-display text-title-md tracking-tight\">{title}</h3> : <span />}\n <div className=\"flex items-center gap-3\">\n <span className=\"font-mono text-label text-muted-foreground\">\n {jobs.length} {jobs.length === 1 ? \"job\" : \"jobs\"}\n </span>\n {onAdd ? (\n <button\n type=\"button\"\n onClick={onAdd}\n className=\"inline-flex items-center gap-1 rounded-md bg-primary px-2.5 py-1 font-sans text-label text-primary-foreground hover:shadow-glow focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\"\n >\n <Plus className=\"size-3.5\" /> New job\n </button>\n ) : null}\n </div>\n </header>\n {jobs.length === 0 ? (\n <p className=\"rounded-xl border border-border/60 border-dashed bg-muted/30 px-4 py-8 text-center font-sans text-body-sm text-muted-foreground\">\n No scheduled jobs yet.\n </p>\n ) : (\n <div className=\"grid grid-cols-1 gap-3 md:grid-cols-2\">\n {jobs.map((job) => (\n <CronJobCard\n key={job.id}\n job={job}\n {...(onRunNow ? { onRunNow } : {})}\n {...(onToggle ? { onToggle } : {})}\n {...(onRemove ? { onRemove } : {})}\n />\n ))}\n </div>\n )}\n </section>\n ),\n);\nCronJobsList.displayName = \"CronJobsList\";\n\nexport { CronJobsList };\n"
21
21
  }
22
22
  ]
23
23
  }
@@ -14,7 +14,7 @@
14
14
  "path": "components/primitives/danger-zone/danger-zone.tsx",
15
15
  "type": "registry:ui",
16
16
  "target": "components/ui/danger-zone.tsx",
17
- "content": "import { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\n/**\n * DangerZone — destructive-actions section primitive.\n *\n * Red-bordered container with a title bar and `DangerZone.Action` rows.\n * Each Action is laid out as title + description on the left, with a\n * consumer-provided action slot (typically a destructive Button) on\n * the right. Rows are separated by hairline dividers; the last row\n * has no bottom border via `last:border-b-0`.\n *\n * The consumer supplies the destructive button — this primitive never\n * imports `<Button>`, keeping it free of internal `@usetheo/ui` deps\n * (true primitive).\n *\n * @example\n * <DangerZone>\n * <DangerZone.Action\n * title=\"Delete project\"\n * description=\"Permanently delete this project.\"\n * action={<Button variant=\"destructive\">Delete</Button>}\n * />\n * </DangerZone>\n */\nexport interface DangerZoneProps extends Omit<HTMLAttributes<HTMLElement>, \"title\"> {\n /** Section title. Default \"Danger Zone\". */\n title?: ReactNode;\n}\n\nconst Root = forwardRef<HTMLElement, DangerZoneProps>(\n ({ className, title = \"Danger Zone\", children, ...props }, ref) => (\n <section\n ref={ref}\n aria-label={typeof title === \"string\" ? title : \"Danger Zone\"}\n className={cn(\"rounded-xl border border-destructive/30 bg-destructive/[0.02]\", className)}\n {...props}\n >\n <div className=\"border-destructive/20 border-b px-5 py-3 font-sans text-destructive text-label-caps uppercase tracking-wider\">\n {title}\n </div>\n {children}\n </section>\n ),\n);\nRoot.displayName = \"DangerZone\";\n\nexport interface DangerZoneActionProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n title: ReactNode;\n description: ReactNode;\n /** Consumer-provided destructive button (or any ReactNode). */\n action: ReactNode;\n}\n\nconst Action = forwardRef<HTMLDivElement, DangerZoneActionProps>(\n ({ className, title, description, action, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\n \"flex items-center justify-between gap-4 border-destructive/10 border-b px-5 py-4 last:border-b-0\",\n className,\n )}\n {...props}\n >\n <div className=\"flex flex-col\">\n <span className=\"font-medium font-sans text-body-sm text-foreground\">{title}</span>\n <span className=\"mt-0.5 font-sans text-label text-muted-foreground\">{description}</span>\n </div>\n <div className=\"shrink-0\">{action}</div>\n </div>\n ),\n);\nAction.displayName = \"DangerZone.Action\";\n\ntype DangerZoneRoot = typeof Root & { Action: typeof Action };\nconst DangerZone: DangerZoneRoot = Object.assign(Root, { Action });\n\nexport { DangerZone };\n"
17
+ "content": "import { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\n/**\n * DangerZone — destructive-actions section primitive.\n *\n * Red-bordered container with a title bar and `DangerZone.Action` rows.\n * Each Action is laid out as title + description on the left, with a\n * consumer-provided action slot (typically a destructive Button) on\n * the right. Rows are separated by hairline dividers; the last row\n * has no bottom border via `last:border-b-0`.\n *\n * The consumer supplies the destructive button — this primitive never\n * imports `<Button>`, keeping it free of internal `@theokit/ui` deps\n * (true primitive).\n *\n * @example\n * <DangerZone>\n * <DangerZone.Action\n * title=\"Delete project\"\n * description=\"Permanently delete this project.\"\n * action={<Button variant=\"destructive\">Delete</Button>}\n * />\n * </DangerZone>\n */\nexport interface DangerZoneProps extends Omit<HTMLAttributes<HTMLElement>, \"title\"> {\n /** Section title. Default \"Danger Zone\". */\n title?: ReactNode;\n}\n\nconst Root = forwardRef<HTMLElement, DangerZoneProps>(\n ({ className, title = \"Danger Zone\", children, ...props }, ref) => (\n <section\n data-slot=\"danger-zone\"\n ref={ref}\n aria-label={typeof title === \"string\" ? title : \"Danger Zone\"}\n className={cn(\"rounded-xl border border-destructive/30 bg-destructive/[0.02]\", className)}\n {...props}\n >\n <div className=\"border-destructive/20 border-b px-5 py-3 font-sans text-destructive text-label-caps uppercase tracking-wider\">\n {title}\n </div>\n {children}\n </section>\n ),\n);\nRoot.displayName = \"DangerZone\";\n\nexport interface DangerZoneActionProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n title: ReactNode;\n description: ReactNode;\n /** Consumer-provided destructive button (or any ReactNode). */\n action: ReactNode;\n}\n\nconst Action = forwardRef<HTMLDivElement, DangerZoneActionProps>(\n ({ className, title, description, action, ...props }, ref) => (\n <div\n data-slot=\"danger-zone-action\"\n ref={ref}\n className={cn(\n \"flex items-center justify-between gap-4 border-destructive/10 border-b px-5 py-4 last:border-b-0\",\n className,\n )}\n {...props}\n >\n <div className=\"flex flex-col\">\n <span className=\"font-medium font-sans text-body-sm text-foreground\">{title}</span>\n <span className=\"mt-0.5 font-sans text-label text-muted-foreground\">{description}</span>\n </div>\n <div className=\"shrink-0\">{action}</div>\n </div>\n ),\n);\nAction.displayName = \"DangerZone.Action\";\n\ntype DangerZoneRoot = typeof Root & { Action: typeof Action };\nconst DangerZone: DangerZoneRoot = Object.assign(Root, { Action });\n\nexport { DangerZone };\n"
18
18
  }
19
19
  ]
20
20
  }
@@ -21,7 +21,7 @@
21
21
  "path": "components/composites/data-table/data-table.tsx",
22
22
  "type": "registry:ui",
23
23
  "target": "components/ui/data-table.tsx",
24
- "content": "import { ChevronDown, ChevronRight, MoreHorizontal } from \"lucide-react\";\nimport { Fragment, useMemo, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport { DropdownMenu } from \"@/components/ui/dropdown-menu\";\nimport { EmptyState } from \"@/components/ui/empty-state\";\nimport { Pagination } from \"@/components/ui/pagination\";\nimport { Skeleton } from \"@/components/ui/skeleton\";\nimport { Table } from \"@/components/ui/table\";\n\n/**\n * DataTable — generic, sortable, expandable composite over `<Table>`.\n *\n * Adds operator-grade entity-list patterns on top of the plain Table\n * primitive: sortable headers, sticky header, expandable rows\n * (multi-row by default), row action menus (Dropdown), client-side\n * pagination, loading skeleton rows, empty state. Both sort and\n * pagination support controlled OR uncontrolled mode (consumer\n * passes onSortChange / onPageChange to take over state).\n *\n * @example\n * <DataTable\n * columns={[\n * { key: \"name\", label: \"Name\", sortable: true },\n * { key: \"status\", label: \"Status\" },\n * ]}\n * data={domains}\n * rowKey={(d) => d.id}\n * expandable={(d) => d.status === \"pending\" ? <DnsRecords domain={d} /> : null}\n * rowActions={(d) => (\n * <>\n * <DropdownMenu.Item onSelect={() => editDomain(d)}>Edit</DropdownMenu.Item>\n * <DropdownMenu.Item onSelect={() => deleteDomain(d)}>Delete</DropdownMenu.Item>\n * </>\n * )}\n * />\n */\nexport interface DataTableColumn<T> {\n key: string;\n label: ReactNode;\n align?: \"left\" | \"center\" | \"right\";\n sortable?: boolean;\n width?: string;\n render?: (row: T) => ReactNode;\n className?: string;\n}\n\nexport interface DataTableSort {\n key: string;\n direction: \"asc\" | \"desc\";\n}\n\nexport interface DataTableProps<T> {\n data: T[];\n columns: DataTableColumn<T>[];\n rowKey: (row: T) => string;\n stickyHeader?: boolean;\n expandable?: (row: T) => ReactNode | null;\n expandMode?: \"single\" | \"multiple\";\n rowActions?: (row: T) => ReactNode;\n pagination?: {\n pageSize: number;\n controlledPage?: number;\n onPageChange?: (page: number) => void;\n } | null;\n defaultSort?: DataTableSort;\n sort?: DataTableSort | null;\n onSortChange?: (sort: DataTableSort | null) => void;\n loading?: boolean;\n emptyState?: ReactNode;\n className?: string;\n}\n\nfunction compareValues(a: unknown, b: unknown): number {\n if (a === b) return 0;\n if (a === null || a === undefined) return -1;\n if (b === null || b === undefined) return 1;\n if (typeof a === \"number\" && typeof b === \"number\") return a - b;\n return String(a).localeCompare(String(b));\n}\n\nfunction DataTable<T>(props: DataTableProps<T>): ReactNode {\n const {\n data,\n columns,\n rowKey,\n stickyHeader = true,\n expandable,\n expandMode = \"multiple\",\n rowActions,\n pagination,\n defaultSort,\n sort: controlledSort,\n onSortChange,\n loading = false,\n emptyState,\n className,\n } = props;\n\n const isControlledSort = onSortChange !== undefined;\n const [uncontrolledSort, setUncontrolledSort] = useState<DataTableSort | null>(\n defaultSort ?? null,\n );\n const sort = isControlledSort ? (controlledSort ?? null) : uncontrolledSort;\n\n const isControlledPage = pagination?.controlledPage !== undefined;\n const [uncontrolledPage, setUncontrolledPage] = useState(0);\n const currentPage = isControlledPage ? (pagination?.controlledPage ?? 0) : uncontrolledPage;\n\n // EC-9: clamp pageSize to >= 1 to avoid divide-by-zero / infinite render\n const effectivePageSize = Math.max(1, pagination?.pageSize ?? 10);\n\n const [expanded, setExpanded] = useState<Set<string>>(new Set());\n\n function handleSort(columnKey: string) {\n // Cycle: none → asc → desc → none\n let nextSort: DataTableSort | null;\n if (sort?.key !== columnKey) {\n nextSort = { key: columnKey, direction: \"asc\" };\n } else if (sort.direction === \"asc\") {\n nextSort = { key: columnKey, direction: \"desc\" };\n } else {\n nextSort = null;\n }\n if (isControlledSort) {\n onSortChange?.(nextSort);\n } else {\n setUncontrolledSort(nextSort);\n // EC-8: sort change resets pagination to page 0\n if (!isControlledPage) setUncontrolledPage(0);\n }\n }\n\n function handlePageChange(page: number) {\n // Pagination uses 1-indexed; internal state 0-indexed\n const zeroIdx = page - 1;\n if (isControlledPage) {\n pagination?.onPageChange?.(zeroIdx);\n } else {\n setUncontrolledPage(zeroIdx);\n }\n }\n\n function toggleExpand(key: string) {\n if (expandMode === \"single\") {\n setExpanded((prev) => (prev.has(key) ? new Set() : new Set([key])));\n } else {\n setExpanded((prev) => {\n const next = new Set(prev);\n if (next.has(key)) {\n next.delete(key);\n } else {\n next.add(key);\n }\n return next;\n });\n }\n }\n\n // Apply client-side sort in uncontrolled mode\n const sortedData = useMemo(() => {\n if (isControlledSort || sort === null) return data;\n const col = columns.find((c) => c.key === sort.key);\n if (!col) return data;\n const sorted = [...data].sort((a, b) => {\n const aVal = col.render\n ? null\n : (a as Record<string, unknown>)[sort.key as keyof T as string];\n const bVal = col.render\n ? null\n : (b as Record<string, unknown>)[sort.key as keyof T as string];\n const cmp = compareValues(aVal, bVal);\n return sort.direction === \"asc\" ? cmp : -cmp;\n });\n return sorted;\n }, [data, sort, isControlledSort, columns]);\n\n // Apply client-side pagination in uncontrolled mode\n const visibleData = useMemo(() => {\n if (!pagination) return sortedData;\n if (isControlledPage) return sortedData; // consumer pre-sliced\n const start = currentPage * effectivePageSize;\n return sortedData.slice(start, start + effectivePageSize);\n }, [sortedData, pagination, isControlledPage, currentPage, effectivePageSize]);\n\n // EC-1 fix: compute colSpan accounting for chevron + actions columns\n const extraCols = (expandable ? 1 : 0) + (rowActions ? 1 : 0);\n const expandedColSpan = columns.length + extraCols;\n const totalCols = columns.length + extraCols;\n\n // Loading state (EC-7: loading > empty)\n if (loading) {\n return (\n <div className={cn(\"w-full\", className)}>\n <Table>\n <Table.Header className={stickyHeader ? \"sticky top-0 bg-card\" : undefined}>\n <Table.Row>\n {expandable ? (\n <Table.HeaderCell>\n <span className=\"sr-only\">Expand</span>\n </Table.HeaderCell>\n ) : null}\n {columns.map((col) => (\n <Table.HeaderCell key={col.key} align={col.align}>\n {col.label}\n </Table.HeaderCell>\n ))}\n {rowActions ? (\n <Table.HeaderCell>\n <span className=\"sr-only\">Actions</span>\n </Table.HeaderCell>\n ) : null}\n </Table.Row>\n </Table.Header>\n <Table.Body>\n {Array.from({ length: 5 }, (_, i) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: skeleton rows are positional placeholders\n <Table.Row key={`skeleton-${i}`}>\n {Array.from({ length: totalCols }, (_, j) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: skeleton cells are positional placeholders\n <Table.Cell key={`s-${i}-${j}`}>\n <Skeleton className=\"h-4 w-full\" />\n </Table.Cell>\n ))}\n </Table.Row>\n ))}\n </Table.Body>\n </Table>\n </div>\n );\n }\n\n // Empty state (after loading check)\n if (sortedData.length === 0) {\n return (\n <div className={cn(\"w-full\", className)}>\n {emptyState ?? <EmptyState title=\"No data\" description=\"There's nothing here yet.\" />}\n </div>\n );\n }\n\n const totalPages = pagination ? Math.ceil(sortedData.length / effectivePageSize) : 1;\n\n return (\n <div className={cn(\"w-full\", className)}>\n <Table>\n <Table.Header className={stickyHeader ? \"sticky top-0 z-10 bg-card\" : undefined}>\n <Table.Row>\n {expandable ? (\n <Table.HeaderCell>\n <span className=\"sr-only\">Expand</span>\n </Table.HeaderCell>\n ) : null}\n {columns.map((col) => {\n const isSortable = col.sortable === true;\n const isActive = sort?.key === col.key;\n return (\n <Table.HeaderCell\n key={col.key}\n align={col.align}\n onSort={isSortable ? () => handleSort(col.key) : undefined}\n sortDirection={isSortable ? (isActive ? sort?.direction : \"none\") : undefined}\n style={col.width ? { width: col.width } : undefined}\n >\n {col.label}\n </Table.HeaderCell>\n );\n })}\n {rowActions ? (\n <Table.HeaderCell>\n <span className=\"sr-only\">Actions</span>\n </Table.HeaderCell>\n ) : null}\n </Table.Row>\n </Table.Header>\n <Table.Body>\n {visibleData.map((row) => {\n const key = rowKey(row);\n const expandedContent = expandable ? expandable(row) : null;\n const isExpandable = expandedContent !== null && expandedContent !== undefined;\n const isExpanded = expanded.has(key);\n return (\n <Fragment key={key}>\n <Table.Row>\n {expandable ? (\n <Table.Cell>\n {isExpandable ? (\n <button\n type=\"button\"\n onClick={() => toggleExpand(key)}\n aria-expanded={isExpanded}\n aria-controls={`expanded-${key}`}\n aria-label={isExpanded ? \"Collapse row\" : \"Expand row\"}\n className=\"inline-flex items-center justify-center rounded-md p-0.5 hover:bg-muted\"\n >\n {isExpanded ? (\n <ChevronDown aria-hidden=\"true\" className=\"size-4\" />\n ) : (\n <ChevronRight aria-hidden=\"true\" className=\"size-4\" />\n )}\n </button>\n ) : null}\n </Table.Cell>\n ) : null}\n {columns.map((col) => (\n <Table.Cell key={col.key} align={col.align} className={col.className}>\n {col.render\n ? col.render(row)\n : String((row as Record<string, unknown>)[col.key] ?? \"\")}\n </Table.Cell>\n ))}\n {rowActions ? (\n <Table.Cell align=\"right\">\n <DropdownMenu>\n <DropdownMenu.Trigger\n aria-label=\"Row actions\"\n className={cn(\n \"inline-flex size-7 items-center justify-center rounded-md\",\n \"text-muted-foreground hover:bg-muted hover:text-foreground\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n )}\n >\n <MoreHorizontal aria-hidden=\"true\" className=\"size-4\" />\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"end\">{rowActions(row)}</DropdownMenu.Content>\n </DropdownMenu>\n </Table.Cell>\n ) : null}\n </Table.Row>\n {isExpanded && isExpandable ? (\n <tr id={`expanded-${key}`}>\n <td colSpan={expandedColSpan} className=\"bg-muted/30 p-4\">\n {expandedContent}\n </td>\n </tr>\n ) : null}\n </Fragment>\n );\n })}\n </Table.Body>\n </Table>\n {pagination && totalPages > 1 ? (\n <div className=\"mt-4 flex items-center justify-end\">\n <Pagination\n currentPage={currentPage + 1}\n totalPages={totalPages}\n onPageChange={handlePageChange}\n />\n </div>\n ) : null}\n </div>\n );\n}\n\nexport { DataTable };\n"
24
+ "content": "\"use client\";\n\nimport { ChevronDown, ChevronRight, MoreHorizontal } from \"lucide-react\";\nimport { Fragment, useMemo, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport { DropdownMenu } from \"@/components/ui/dropdown-menu\";\nimport { EmptyState } from \"@/components/ui/empty-state\";\nimport { Pagination } from \"@/components/ui/pagination\";\nimport { Skeleton } from \"@/components/ui/skeleton\";\nimport { Table } from \"@/components/ui/table\";\n\n/**\n * DataTable — generic, sortable, expandable composite over `<Table>`.\n *\n * Adds operator-grade entity-list patterns on top of the plain Table\n * primitive: sortable headers, sticky header, expandable rows\n * (multi-row by default), row action menus (Dropdown), client-side\n * pagination, loading skeleton rows, empty state. Both sort and\n * pagination support controlled OR uncontrolled mode (consumer\n * passes onSortChange / onPageChange to take over state).\n *\n * @example\n * <DataTable\n * columns={[\n * { key: \"name\", label: \"Name\", sortable: true },\n * { key: \"status\", label: \"Status\" },\n * ]}\n * data={domains}\n * rowKey={(d) => d.id}\n * expandable={(d) => d.status === \"pending\" ? <DnsRecords domain={d} /> : null}\n * rowActions={(d) => (\n * <>\n * <DropdownMenu.Item onSelect={() => editDomain(d)}>Edit</DropdownMenu.Item>\n * <DropdownMenu.Item onSelect={() => deleteDomain(d)}>Delete</DropdownMenu.Item>\n * </>\n * )}\n * />\n */\nexport interface DataTableColumn<T> {\n key: string;\n label: ReactNode;\n align?: \"left\" | \"center\" | \"right\";\n sortable?: boolean;\n width?: string;\n render?: (row: T) => ReactNode;\n className?: string;\n}\n\nexport interface DataTableSort {\n key: string;\n direction: \"asc\" | \"desc\";\n}\n\nexport interface DataTableProps<T> {\n data: T[];\n columns: DataTableColumn<T>[];\n rowKey: (row: T) => string;\n stickyHeader?: boolean;\n expandable?: (row: T) => ReactNode | null;\n expandMode?: \"single\" | \"multiple\";\n rowActions?: (row: T) => ReactNode;\n pagination?: {\n pageSize: number;\n controlledPage?: number;\n onPageChange?: (page: number) => void;\n } | null;\n defaultSort?: DataTableSort;\n sort?: DataTableSort | null;\n onSortChange?: (sort: DataTableSort | null) => void;\n loading?: boolean;\n emptyState?: ReactNode;\n className?: string;\n}\n\nfunction compareValues(a: unknown, b: unknown): number {\n if (a === b) return 0;\n if (a === null || a === undefined) return -1;\n if (b === null || b === undefined) return 1;\n if (typeof a === \"number\" && typeof b === \"number\") return a - b;\n return String(a).localeCompare(String(b));\n}\n\nfunction DataTable<T>(props: DataTableProps<T>): ReactNode {\n const {\n data,\n columns,\n rowKey,\n stickyHeader = true,\n expandable,\n expandMode = \"multiple\",\n rowActions,\n pagination,\n defaultSort,\n sort: controlledSort,\n onSortChange,\n loading = false,\n emptyState,\n className,\n } = props;\n\n const isControlledSort = onSortChange !== undefined;\n const [uncontrolledSort, setUncontrolledSort] = useState<DataTableSort | null>(\n defaultSort ?? null,\n );\n const sort = isControlledSort ? (controlledSort ?? null) : uncontrolledSort;\n\n const isControlledPage = pagination?.controlledPage !== undefined;\n const [uncontrolledPage, setUncontrolledPage] = useState(0);\n const currentPage = isControlledPage ? (pagination?.controlledPage ?? 0) : uncontrolledPage;\n\n // EC-9: clamp pageSize to >= 1 to avoid divide-by-zero / infinite render\n const effectivePageSize = Math.max(1, pagination?.pageSize ?? 10);\n\n const [expanded, setExpanded] = useState<Set<string>>(new Set());\n\n function handleSort(columnKey: string) {\n // Cycle: none → asc → desc → none\n let nextSort: DataTableSort | null;\n if (sort?.key !== columnKey) {\n nextSort = { key: columnKey, direction: \"asc\" };\n } else if (sort.direction === \"asc\") {\n nextSort = { key: columnKey, direction: \"desc\" };\n } else {\n nextSort = null;\n }\n if (isControlledSort) {\n onSortChange?.(nextSort);\n } else {\n setUncontrolledSort(nextSort);\n // EC-8: sort change resets pagination to page 0\n if (!isControlledPage) setUncontrolledPage(0);\n }\n }\n\n function handlePageChange(page: number) {\n // Pagination uses 1-indexed; internal state 0-indexed\n const zeroIdx = page - 1;\n if (isControlledPage) {\n pagination?.onPageChange?.(zeroIdx);\n } else {\n setUncontrolledPage(zeroIdx);\n }\n }\n\n function toggleExpand(key: string) {\n if (expandMode === \"single\") {\n setExpanded((prev) => (prev.has(key) ? new Set() : new Set([key])));\n } else {\n setExpanded((prev) => {\n const next = new Set(prev);\n if (next.has(key)) {\n next.delete(key);\n } else {\n next.add(key);\n }\n return next;\n });\n }\n }\n\n // Apply client-side sort in uncontrolled mode\n const sortedData = useMemo(() => {\n if (isControlledSort || sort === null) return data;\n const col = columns.find((c) => c.key === sort.key);\n if (!col) return data;\n const sorted = [...data].sort((a, b) => {\n const aVal = col.render\n ? null\n : (a as Record<string, unknown>)[sort.key as keyof T as string];\n const bVal = col.render\n ? null\n : (b as Record<string, unknown>)[sort.key as keyof T as string];\n const cmp = compareValues(aVal, bVal);\n return sort.direction === \"asc\" ? cmp : -cmp;\n });\n return sorted;\n }, [data, sort, isControlledSort, columns]);\n\n // Apply client-side pagination in uncontrolled mode\n const visibleData = useMemo(() => {\n if (!pagination) return sortedData;\n if (isControlledPage) return sortedData; // consumer pre-sliced\n const start = currentPage * effectivePageSize;\n return sortedData.slice(start, start + effectivePageSize);\n }, [sortedData, pagination, isControlledPage, currentPage, effectivePageSize]);\n\n // EC-1 fix: compute colSpan accounting for chevron + actions columns\n const extraCols = (expandable ? 1 : 0) + (rowActions ? 1 : 0);\n const expandedColSpan = columns.length + extraCols;\n const totalCols = columns.length + extraCols;\n\n // Loading state (EC-7: loading > empty)\n if (loading) {\n return (\n <div data-slot=\"data-table\" className={cn(\"w-full\", className)}>\n <Table>\n <Table.Header className={stickyHeader ? \"sticky top-0 bg-card\" : undefined}>\n <Table.Row>\n {expandable ? (\n <Table.HeaderCell>\n <span className=\"sr-only\">Expand</span>\n </Table.HeaderCell>\n ) : null}\n {columns.map((col) => (\n <Table.HeaderCell key={col.key} align={col.align}>\n {col.label}\n </Table.HeaderCell>\n ))}\n {rowActions ? (\n <Table.HeaderCell>\n <span className=\"sr-only\">Actions</span>\n </Table.HeaderCell>\n ) : null}\n </Table.Row>\n </Table.Header>\n <Table.Body>\n {Array.from({ length: 5 }, (_, i) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: skeleton rows are positional placeholders\n <Table.Row key={`skeleton-${i}`}>\n {Array.from({ length: totalCols }, (_, j) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: skeleton cells are positional placeholders\n <Table.Cell key={`s-${i}-${j}`}>\n <Skeleton className=\"h-4 w-full\" />\n </Table.Cell>\n ))}\n </Table.Row>\n ))}\n </Table.Body>\n </Table>\n </div>\n );\n }\n\n // Empty state (after loading check)\n if (sortedData.length === 0) {\n return (\n <div className={cn(\"w-full\", className)}>\n {emptyState ?? <EmptyState title=\"No data\" description=\"There's nothing here yet.\" />}\n </div>\n );\n }\n\n const totalPages = pagination ? Math.ceil(sortedData.length / effectivePageSize) : 1;\n\n return (\n <div className={cn(\"w-full\", className)}>\n <Table>\n <Table.Header className={stickyHeader ? \"sticky top-0 z-10 bg-card\" : undefined}>\n <Table.Row>\n {expandable ? (\n <Table.HeaderCell>\n <span className=\"sr-only\">Expand</span>\n </Table.HeaderCell>\n ) : null}\n {columns.map((col) => {\n const isSortable = col.sortable === true;\n const isActive = sort?.key === col.key;\n return (\n <Table.HeaderCell\n key={col.key}\n align={col.align}\n onSort={isSortable ? () => handleSort(col.key) : undefined}\n sortDirection={isSortable ? (isActive ? sort?.direction : \"none\") : undefined}\n style={col.width ? { width: col.width } : undefined}\n >\n {col.label}\n </Table.HeaderCell>\n );\n })}\n {rowActions ? (\n <Table.HeaderCell>\n <span className=\"sr-only\">Actions</span>\n </Table.HeaderCell>\n ) : null}\n </Table.Row>\n </Table.Header>\n <Table.Body>\n {visibleData.map((row) => {\n const key = rowKey(row);\n const expandedContent = expandable ? expandable(row) : null;\n const isExpandable = expandedContent !== null && expandedContent !== undefined;\n const isExpanded = expanded.has(key);\n return (\n <Fragment key={key}>\n <Table.Row>\n {expandable ? (\n <Table.Cell>\n {isExpandable ? (\n <button\n type=\"button\"\n onClick={() => toggleExpand(key)}\n aria-expanded={isExpanded}\n aria-controls={`expanded-${key}`}\n aria-label={isExpanded ? \"Collapse row\" : \"Expand row\"}\n className=\"inline-flex items-center justify-center rounded-md p-0.5 hover:bg-muted\"\n >\n {isExpanded ? (\n <ChevronDown aria-hidden=\"true\" className=\"size-4\" />\n ) : (\n <ChevronRight aria-hidden=\"true\" className=\"size-4\" />\n )}\n </button>\n ) : null}\n </Table.Cell>\n ) : null}\n {columns.map((col) => (\n <Table.Cell key={col.key} align={col.align} className={col.className}>\n {col.render\n ? col.render(row)\n : String((row as Record<string, unknown>)[col.key] ?? \"\")}\n </Table.Cell>\n ))}\n {rowActions ? (\n <Table.Cell align=\"right\">\n <DropdownMenu>\n <DropdownMenu.Trigger\n aria-label=\"Row actions\"\n className={cn(\n \"inline-flex size-7 items-center justify-center rounded-md\",\n \"text-muted-foreground hover:bg-muted hover:text-foreground\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n )}\n >\n <MoreHorizontal aria-hidden=\"true\" className=\"size-4\" />\n </DropdownMenu.Trigger>\n <DropdownMenu.Content align=\"end\">{rowActions(row)}</DropdownMenu.Content>\n </DropdownMenu>\n </Table.Cell>\n ) : null}\n </Table.Row>\n {isExpanded && isExpandable ? (\n <tr id={`expanded-${key}`}>\n <td colSpan={expandedColSpan} className=\"bg-muted/30 p-4\">\n {expandedContent}\n </td>\n </tr>\n ) : null}\n </Fragment>\n );\n })}\n </Table.Body>\n </Table>\n {pagination && totalPages > 1 ? (\n <div className=\"mt-4 flex items-center justify-end\">\n <Pagination\n currentPage={currentPage + 1}\n totalPages={totalPages}\n onPageChange={handlePageChange}\n />\n </div>\n ) : null}\n </div>\n );\n}\n\nexport { DataTable };\n"
25
25
  }
26
26
  ]
27
27
  }
@@ -17,7 +17,7 @@
17
17
  "path": "components/composites/deployment-row/deployment-row.tsx",
18
18
  "type": "registry:block",
19
19
  "target": "components/blocks/deployment-row.tsx",
20
- "content": "import { GitCommit } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport { Badge } from \"@/components/ui/badge\";\n\nexport type DeploymentStatus =\n | \"queued\"\n | \"building\"\n | \"deploying\"\n | \"live\"\n | \"failed\"\n | \"cancelled\";\n\nconst statusToVariant: Record<\n DeploymentStatus,\n \"default\" | \"primary\" | \"success\" | \"warning\" | \"destructive\"\n> = {\n queued: \"warning\",\n building: \"primary\",\n deploying: \"primary\",\n live: \"success\",\n failed: \"destructive\",\n cancelled: \"default\",\n};\n\nconst statusToDotTone: Record<\n DeploymentStatus,\n \"primary\" | \"success\" | \"warning\" | \"destructive\" | \"muted\"\n> = {\n queued: \"warning\",\n building: \"primary\",\n deploying: \"primary\",\n live: \"success\",\n failed: \"destructive\",\n cancelled: \"muted\",\n};\n\nconst statusLabels: Record<DeploymentStatus, string> = {\n queued: \"Queued\",\n building: \"Building\",\n deploying: \"Deploying\",\n live: \"Live\",\n failed: \"Failed\",\n cancelled: \"Cancelled\",\n};\n\nconst isAnimated = (status: DeploymentStatus) =>\n status === \"building\" || status === \"deploying\" || status === \"queued\";\n\nexport interface Deployment {\n id: string;\n status: DeploymentStatus;\n environment: string;\n branch: string;\n commitSha: string;\n commitMessage: string;\n author?: { name: string; avatarUrl?: string };\n duration?: string;\n timeAgo: string;\n}\n\ninterface DeploymentRowProps extends HTMLAttributes<HTMLDivElement> {\n deployment: Deployment;\n actions?: ReactNode;\n}\n\n/**\n * DeploymentRow — one row in a deployment list (table-ish layout).\n *\n * Inspired by Vercel/Railway deployment lists. Composes Badge + Badge.Dot for status,\n * mono font for SHA/branch, muted-foreground for metadata.\n */\nconst DeploymentRow = forwardRef<HTMLDivElement, DeploymentRowProps>(\n ({ className, deployment, actions, ...props }, ref) => {\n const variant = statusToVariant[deployment.status];\n const tone = statusToDotTone[deployment.status];\n return (\n <div\n ref={ref}\n className={cn(\n \"grid grid-cols-[auto_1fr_auto] items-center gap-4 border-border/40 border-b px-4 py-3\",\n \"last:border-b-0\",\n \"transition-colors hover:bg-muted/40\",\n className,\n )}\n {...props}\n >\n <Badge variant={variant} className=\"min-w-[88px] justify-center\">\n <Badge.Dot tone={tone} pulse={isAnimated(deployment.status)} />\n {statusLabels[deployment.status]}\n </Badge>\n\n <div className=\"min-w-0\">\n <p className=\"truncate font-medium text-body-sm text-foreground\">\n {deployment.commitMessage}\n </p>\n <p className=\"mt-0.5 flex flex-wrap items-center gap-2 text-body-sm text-muted-foreground\">\n <span className=\"font-mono text-code-sm\">{deployment.environment}</span>\n <span aria-hidden=\"true\">·</span>\n <span className=\"inline-flex items-center gap-1 font-mono text-code-sm\">\n <GitCommit className=\"size-3\" /> {deployment.commitSha.slice(0, 7)}\n </span>\n <span aria-hidden=\"true\">·</span>\n <span className=\"font-mono text-code-sm\">{deployment.branch}</span>\n {deployment.author ? (\n <>\n <span aria-hidden=\"true\">·</span>\n <span>by {deployment.author.name}</span>\n </>\n ) : null}\n {deployment.duration ? (\n <>\n <span aria-hidden=\"true\">·</span>\n <span className=\"font-mono text-code-sm\">{deployment.duration}</span>\n </>\n ) : null}\n <span aria-hidden=\"true\">·</span>\n <span>{deployment.timeAgo}</span>\n </p>\n </div>\n\n {actions ? <div className=\"flex items-center gap-1\">{actions}</div> : null}\n </div>\n );\n },\n);\nDeploymentRow.displayName = \"DeploymentRow\";\n\nexport { DeploymentRow };\n"
20
+ "content": "import { GitCommit } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport { Badge } from \"@/components/ui/badge\";\n\nexport type DeploymentStatus =\n | \"queued\"\n | \"building\"\n | \"deploying\"\n | \"live\"\n | \"failed\"\n | \"cancelled\";\n\nconst statusToVariant: Record<\n DeploymentStatus,\n \"default\" | \"primary\" | \"success\" | \"warning\" | \"destructive\"\n> = {\n queued: \"warning\",\n building: \"primary\",\n deploying: \"primary\",\n live: \"success\",\n failed: \"destructive\",\n cancelled: \"default\",\n};\n\nconst statusToDotTone: Record<\n DeploymentStatus,\n \"primary\" | \"success\" | \"warning\" | \"destructive\" | \"muted\"\n> = {\n queued: \"warning\",\n building: \"primary\",\n deploying: \"primary\",\n live: \"success\",\n failed: \"destructive\",\n cancelled: \"muted\",\n};\n\nconst statusLabels: Record<DeploymentStatus, string> = {\n queued: \"Queued\",\n building: \"Building\",\n deploying: \"Deploying\",\n live: \"Live\",\n failed: \"Failed\",\n cancelled: \"Cancelled\",\n};\n\nconst isAnimated = (status: DeploymentStatus) =>\n status === \"building\" || status === \"deploying\" || status === \"queued\";\n\nexport interface Deployment {\n id: string;\n status: DeploymentStatus;\n environment: string;\n branch: string;\n commitSha: string;\n commitMessage: string;\n author?: { name: string; avatarUrl?: string };\n duration?: string;\n timeAgo: string;\n}\n\ninterface DeploymentRowProps extends HTMLAttributes<HTMLDivElement> {\n deployment: Deployment;\n actions?: ReactNode;\n}\n\n/**\n * DeploymentRow — one row in a deployment list (table-ish layout).\n *\n * Inspired by Vercel/Railway deployment lists. Composes Badge + Badge.Dot for status,\n * mono font for SHA/branch, muted-foreground for metadata.\n */\nconst DeploymentRow = forwardRef<HTMLDivElement, DeploymentRowProps>(\n ({ className, deployment, actions, ...props }, ref) => {\n const variant = statusToVariant[deployment.status];\n const tone = statusToDotTone[deployment.status];\n return (\n <div\n data-slot=\"deployment-row\"\n ref={ref}\n className={cn(\n \"grid grid-cols-[auto_1fr_auto] items-center gap-4 border-border/40 border-b px-4 py-3\",\n \"last:border-b-0\",\n \"transition-colors hover:bg-muted/40\",\n className,\n )}\n {...props}\n >\n <Badge variant={variant} className=\"min-w-[88px] justify-center\">\n <Badge.Dot tone={tone} pulse={isAnimated(deployment.status)} />\n {statusLabels[deployment.status]}\n </Badge>\n\n <div className=\"min-w-0\">\n <p className=\"truncate font-medium text-body-sm text-foreground\">\n {deployment.commitMessage}\n </p>\n <p className=\"mt-0.5 flex flex-wrap items-center gap-2 text-body-sm text-muted-foreground\">\n <span className=\"font-mono text-code-sm\">{deployment.environment}</span>\n <span aria-hidden=\"true\">·</span>\n <span className=\"inline-flex items-center gap-1 font-mono text-code-sm\">\n <GitCommit className=\"size-3\" /> {deployment.commitSha.slice(0, 7)}\n </span>\n <span aria-hidden=\"true\">·</span>\n <span className=\"font-mono text-code-sm\">{deployment.branch}</span>\n {deployment.author ? (\n <>\n <span aria-hidden=\"true\">·</span>\n <span>by {deployment.author.name}</span>\n </>\n ) : null}\n {deployment.duration ? (\n <>\n <span aria-hidden=\"true\">·</span>\n <span className=\"font-mono text-code-sm\">{deployment.duration}</span>\n </>\n ) : null}\n <span aria-hidden=\"true\">·</span>\n <span>{deployment.timeAgo}</span>\n </p>\n </div>\n\n {actions ? <div className=\"flex items-center gap-1\">{actions}</div> : null}\n </div>\n );\n },\n);\nDeploymentRow.displayName = \"DeploymentRow\";\n\nexport { DeploymentRow };\n"
21
21
  }
22
22
  ]
23
23
  }
@@ -17,7 +17,7 @@
17
17
  "path": "components/primitives/dialog/dialog.tsx",
18
18
  "type": "registry:ui",
19
19
  "target": "components/ui/dialog.tsx",
20
- "content": "import * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport { X } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { ComponentPropsWithoutRef, ElementRef, HTMLAttributes } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\n/**\n * Dialog — modal overlay built on Radix Dialog.\n *\n * Composition:\n * <Dialog>\n * <Dialog.Trigger>Open</Dialog.Trigger>\n * <Dialog.Content>\n * <Dialog.Header>\n * <Dialog.Title>…</Dialog.Title>\n * <Dialog.Description>…</Dialog.Description>\n * </Dialog.Header>\n * <Dialog.Body>…</Dialog.Body>\n * <Dialog.Footer>…</Dialog.Footer>\n * </Dialog.Content>\n * </Dialog>\n *\n * Overlay is a theme-neutral backdrop (`bg-background/80`) with no glass blur\n * (anti-glass guideline). Content uses card surface, rounded-2xl, shadow-lg\n * + slight glow on enter.\n */\n\nconst Overlay = forwardRef<\n ElementRef<typeof DialogPrimitive.Overlay>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n className={cn(\n \"fixed inset-0 z-50 bg-background/80\",\n \"data-[state=open]:fade-in-0 data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=closed]:animate-out\",\n className,\n )}\n {...props}\n />\n));\nOverlay.displayName = \"Dialog.Overlay\";\n\ninterface ContentProps extends ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {\n hideCloseButton?: boolean;\n}\n\nconst Content = forwardRef<ElementRef<typeof DialogPrimitive.Content>, ContentProps>(\n ({ className, children, hideCloseButton, ...props }, ref) => (\n <DialogPrimitive.Portal>\n <Overlay />\n <DialogPrimitive.Content\n ref={ref}\n className={cn(\n \"-translate-x-1/2 -translate-y-1/2 fixed top-1/2 left-1/2 z-50 w-full max-w-lg\",\n \"rounded-2xl border bg-card text-card-foreground shadow-lg\",\n \"data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=closed]:animate-out\",\n \"duration-base\",\n className,\n )}\n {...props}\n >\n {children}\n {!hideCloseButton ? (\n <DialogPrimitive.Close\n className={cn(\n \"absolute top-4 right-4 rounded-md p-1 opacity-70\",\n \"transition-opacity hover:opacity-100\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card\",\n \"disabled:pointer-events-none\",\n )}\n >\n <X className=\"size-4\" />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n ) : null}\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n ),\n);\nContent.displayName = \"Dialog.Content\";\n\nconst Header = ({ className, ...props }: HTMLAttributes<HTMLDivElement>) => (\n <div className={cn(\"flex flex-col gap-1.5 p-6 pb-3 text-left\", className)} {...props} />\n);\nHeader.displayName = \"Dialog.Header\";\n\nconst Body = ({ className, ...props }: HTMLAttributes<HTMLDivElement>) => (\n <div className={cn(\"px-6 pb-6 text-body-md text-muted-foreground\", className)} {...props} />\n);\nBody.displayName = \"Dialog.Body\";\n\nconst Footer = ({ className, ...props }: HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\"flex flex-col-reverse gap-2 p-6 pt-3 sm:flex-row sm:justify-end\", className)}\n {...props}\n />\n);\nFooter.displayName = \"Dialog.Footer\";\n\ntype TitleProps = ComponentPropsWithoutRef<typeof DialogPrimitive.Title>;\n\nconst Title = forwardRef<ElementRef<typeof DialogPrimitive.Title>, TitleProps>(\n ({ className, ...props }, ref) => (\n <DialogPrimitive.Title\n ref={ref}\n className={cn(\"font-display text-foreground text-title-lg tracking-tight\", className)}\n {...props}\n />\n ),\n);\nTitle.displayName = \"Dialog.Title\";\n\nconst Description = forwardRef<\n ElementRef<typeof DialogPrimitive.Description>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn(\"text-body-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nDescription.displayName = \"Dialog.Description\";\n\nconst Dialog = /*#__PURE__*/ Object.assign(DialogPrimitive.Root, {\n Trigger: DialogPrimitive.Trigger,\n Close: DialogPrimitive.Close,\n Content,\n Overlay,\n Header,\n Body,\n Footer,\n Title,\n Description,\n});\n\nexport { Dialog };\n"
20
+ "content": "import * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport { X } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { ComponentPropsWithoutRef, ElementRef, HTMLAttributes } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\n/**\n * Dialog — modal overlay built on Radix Dialog.\n *\n * Composition:\n * <Dialog>\n * <Dialog.Trigger>Open</Dialog.Trigger>\n * <Dialog.Content>\n * <Dialog.Header>\n * <Dialog.Title>…</Dialog.Title>\n * <Dialog.Description>…</Dialog.Description>\n * </Dialog.Header>\n * <Dialog.Body>…</Dialog.Body>\n * <Dialog.Footer>…</Dialog.Footer>\n * </Dialog.Content>\n * </Dialog>\n *\n * Overlay is a theme-neutral backdrop (`bg-background/80`) with no glass blur\n * (anti-glass guideline). Content uses card surface, rounded-2xl, shadow-lg\n * + slight glow on enter.\n */\n\nconst Overlay = forwardRef<\n ElementRef<typeof DialogPrimitive.Overlay>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Overlay\n data-slot=\"dialog-overlay\"\n ref={ref}\n className={cn(\n \"fixed inset-0 z-50 bg-background/80\",\n \"data-[state=open]:fade-in-0 data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=closed]:animate-out\",\n className,\n )}\n {...props}\n />\n));\nOverlay.displayName = \"Dialog.Overlay\";\n\ninterface ContentProps extends ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {\n hideCloseButton?: boolean;\n}\n\nconst Content = forwardRef<ElementRef<typeof DialogPrimitive.Content>, ContentProps>(\n ({ className, children, hideCloseButton, ...props }, ref) => (\n <DialogPrimitive.Portal>\n <Overlay />\n <DialogPrimitive.Content\n data-slot=\"dialog-content\"\n ref={ref}\n className={cn(\n \"-translate-x-1/2 -translate-y-1/2 fixed top-1/2 left-1/2 z-50 w-full max-w-lg\",\n \"rounded-2xl border bg-card text-card-foreground shadow-lg\",\n \"data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=closed]:animate-out\",\n \"duration-base\",\n className,\n )}\n {...props}\n >\n {children}\n {!hideCloseButton ? (\n <DialogPrimitive.Close\n className={cn(\n \"absolute top-4 right-4 rounded-md p-1 opacity-70\",\n \"transition-opacity hover:opacity-100\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card\",\n \"disabled:pointer-events-none\",\n )}\n >\n <X className=\"size-4\" />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n ) : null}\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n ),\n);\nContent.displayName = \"Dialog.Content\";\n\nconst Header = ({ className, ...props }: HTMLAttributes<HTMLDivElement>) => (\n <div className={cn(\"flex flex-col gap-1.5 p-6 pb-3 text-left\", className)} {...props} />\n);\nHeader.displayName = \"Dialog.Header\";\n\nconst Body = ({ className, ...props }: HTMLAttributes<HTMLDivElement>) => (\n <div className={cn(\"px-6 pb-6 text-body-md text-muted-foreground\", className)} {...props} />\n);\nBody.displayName = \"Dialog.Body\";\n\nconst Footer = ({ className, ...props }: HTMLAttributes<HTMLDivElement>) => (\n <div\n className={cn(\"flex flex-col-reverse gap-2 p-6 pt-3 sm:flex-row sm:justify-end\", className)}\n {...props}\n />\n);\nFooter.displayName = \"Dialog.Footer\";\n\ntype TitleProps = ComponentPropsWithoutRef<typeof DialogPrimitive.Title>;\n\nconst Title = forwardRef<ElementRef<typeof DialogPrimitive.Title>, TitleProps>(\n ({ className, ...props }, ref) => (\n <DialogPrimitive.Title\n data-slot=\"dialog-title\"\n ref={ref}\n className={cn(\"font-display text-foreground text-title-lg tracking-tight\", className)}\n {...props}\n />\n ),\n);\nTitle.displayName = \"Dialog.Title\";\n\nconst Description = forwardRef<\n ElementRef<typeof DialogPrimitive.Description>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n data-slot=\"dialog-description\"\n ref={ref}\n className={cn(\"text-body-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nDescription.displayName = \"Dialog.Description\";\n\nconst Dialog = /*#__PURE__*/ Object.assign(DialogPrimitive.Root, {\n Trigger: DialogPrimitive.Trigger,\n Close: DialogPrimitive.Close,\n Content,\n Overlay,\n Header,\n Body,\n Footer,\n Title,\n Description,\n});\n\nexport { Dialog };\n"
21
21
  }
22
22
  ]
23
23
  }
@@ -14,7 +14,7 @@
14
14
  "path": "components/primitives/diff-viewer/diff-viewer.tsx",
15
15
  "type": "registry:ui",
16
16
  "target": "components/ui/diff-viewer.tsx",
17
- "content": "import { forwardRef } from \"react\";\nimport type { HTMLAttributes } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\nexport type DiffLineKind = \"added\" | \"removed\" | \"unchanged\" | \"meta\";\n\nexport interface DiffLine {\n kind: DiffLineKind;\n /** Original line number (left side); undefined for added lines. */\n oldNumber?: number;\n /** New line number (right side); undefined for removed lines. */\n newNumber?: number;\n content: string;\n}\n\nexport interface DiffHunk {\n id: string;\n /**\n * Optional header (e.g. \"@@ -42,7 +42,12 @@\"). Caller usually formats this.\n */\n header?: string;\n lines: DiffLine[];\n /**\n * If true, the hunk is rendered as a collapsed \"N unmodified lines\" placeholder.\n */\n collapsed?: boolean;\n}\n\ninterface DiffViewerProps extends HTMLAttributes<HTMLDivElement> {\n /** Path of the file being diffed. */\n path: string;\n /** Diff stats summary. */\n stats?: { added: number; removed: number };\n hunks: DiffHunk[];\n}\n\nconst lineBg: Record<DiffLineKind, string> = {\n added: \"bg-success/10\",\n removed: \"bg-destructive/10\",\n unchanged: \"\",\n meta: \"bg-muted/60 text-primary\",\n};\n\nconst sign: Record<DiffLineKind, string> = {\n added: \"+\",\n removed: \"-\",\n unchanged: \" \",\n meta: \"@\",\n};\n\n/**\n * DiffViewer — unified diff rendering, no external dep.\n *\n * Visual: two gutter columns (old/new line numbers) + sign + monospaced content.\n * Added/removed rows tinted in success/destructive. Collapsed hunks render as\n * a single muted row \"N unmodified lines\".\n *\n * For syntax highlighting, the consumer can render `content` via their own\n * highlighter and pass `unchanged` lines with already-highlighted strings (not\n * common; usually plain text is enough for the brutalist console aesthetic).\n */\nconst DiffViewer = forwardRef<HTMLDivElement, DiffViewerProps>(\n ({ className, path, stats, hunks, ...props }, ref) => (\n <div\n ref={ref}\n className={cn(\"overflow-hidden rounded-xl border bg-card font-mono\", className)}\n {...props}\n >\n <header className=\"flex items-center justify-between gap-3 border-border/40 border-b bg-muted/30 px-3 py-2\">\n <span className=\"truncate text-code-sm text-foreground\">{path}</span>\n {stats ? (\n <span className=\"font-mono text-code-sm\">\n <span className=\"text-success\">+{stats.added}</span>{\" \"}\n <span className=\"text-destructive\">-{stats.removed}</span>\n </span>\n ) : null}\n </header>\n <ol className=\"text-code-sm\">\n {hunks.map((hunk) => (\n <li key={hunk.id}>\n {hunk.collapsed ? (\n <div className=\"px-3 py-1 text-muted-foreground italic\">\n {hunk.lines.length} unmodified lines\n </div>\n ) : (\n <>\n {hunk.header ? (\n <div className=\"bg-muted/60 px-3 py-1 text-primary\">{hunk.header}</div>\n ) : null}\n <table className=\"w-full border-collapse\" aria-label={`Diff hunk for ${path}`}>\n <tbody>\n {hunk.lines.map((line, idx) => (\n <tr key={`${hunk.id}-${idx}`} className={lineBg[line.kind]}>\n <td className=\"select-none px-2 text-right text-muted-foreground/60 tabular-nums\">\n {line.oldNumber ?? \"\"}\n </td>\n <td className=\"select-none px-2 text-right text-muted-foreground/60 tabular-nums\">\n {line.newNumber ?? \"\"}\n </td>\n <td\n className={cn(\n \"select-none pr-1 pl-2\",\n line.kind === \"added\" && \"text-success\",\n line.kind === \"removed\" && \"text-destructive\",\n line.kind === \"meta\" && \"text-primary\",\n )}\n >\n {sign[line.kind]}\n </td>\n <td\n className={cn(\n \"w-full whitespace-pre\",\n line.kind === \"added\" && \"text-success\",\n line.kind === \"removed\" && \"text-destructive\",\n )}\n >\n {line.content}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </>\n )}\n </li>\n ))}\n </ol>\n </div>\n ),\n);\nDiffViewer.displayName = \"DiffViewer\";\n\nexport { DiffViewer };\n"
17
+ "content": "import { forwardRef } from \"react\";\nimport type { HTMLAttributes } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\nexport type DiffLineKind = \"added\" | \"removed\" | \"unchanged\" | \"meta\";\n\nexport interface DiffLine {\n kind: DiffLineKind;\n /** Original line number (left side); undefined for added lines. */\n oldNumber?: number;\n /** New line number (right side); undefined for removed lines. */\n newNumber?: number;\n content: string;\n}\n\nexport interface DiffHunk {\n id: string;\n /**\n * Optional header (e.g. \"@@ -42,7 +42,12 @@\"). Caller usually formats this.\n */\n header?: string;\n lines: DiffLine[];\n /**\n * If true, the hunk is rendered as a collapsed \"N unmodified lines\" placeholder.\n */\n collapsed?: boolean;\n}\n\ninterface DiffViewerProps extends HTMLAttributes<HTMLDivElement> {\n /** Path of the file being diffed. */\n path: string;\n /** Diff stats summary. */\n stats?: { added: number; removed: number };\n hunks: DiffHunk[];\n}\n\nconst lineBg: Record<DiffLineKind, string> = {\n added: \"bg-success/10\",\n removed: \"bg-destructive/10\",\n unchanged: \"\",\n meta: \"bg-muted/60 text-primary\",\n};\n\nconst sign: Record<DiffLineKind, string> = {\n added: \"+\",\n removed: \"-\",\n unchanged: \" \",\n meta: \"@\",\n};\n\n/**\n * DiffViewer — unified diff rendering, no external dep.\n *\n * Visual: two gutter columns (old/new line numbers) + sign + monospaced content.\n * Added/removed rows tinted in success/destructive. Collapsed hunks render as\n * a single muted row \"N unmodified lines\".\n *\n * For syntax highlighting, the consumer can render `content` via their own\n * highlighter and pass `unchanged` lines with already-highlighted strings (not\n * common; usually plain text is enough for the brutalist console aesthetic).\n */\nconst DiffViewer = forwardRef<HTMLDivElement, DiffViewerProps>(\n ({ className, path, stats, hunks, ...props }, ref) => (\n <div\n data-slot=\"diff-viewer\"\n ref={ref}\n className={cn(\"overflow-hidden rounded-xl border bg-card font-mono\", className)}\n {...props}\n >\n <header className=\"flex items-center justify-between gap-3 border-border/40 border-b bg-muted/30 px-3 py-2\">\n <span className=\"truncate text-code-sm text-foreground\">{path}</span>\n {stats ? (\n <span className=\"font-mono text-code-sm\">\n <span className=\"text-success\">+{stats.added}</span>{\" \"}\n <span className=\"text-destructive\">-{stats.removed}</span>\n </span>\n ) : null}\n </header>\n <ol className=\"text-code-sm\">\n {hunks.map((hunk) => (\n <li key={hunk.id}>\n {hunk.collapsed ? (\n <div className=\"px-3 py-1 text-muted-foreground italic\">\n {hunk.lines.length} unmodified lines\n </div>\n ) : (\n <>\n {hunk.header ? (\n <div className=\"bg-muted/60 px-3 py-1 text-primary\">{hunk.header}</div>\n ) : null}\n <table className=\"w-full border-collapse\" aria-label={`Diff hunk for ${path}`}>\n <tbody>\n {hunk.lines.map((line, idx) => (\n <tr key={`${hunk.id}-${idx}`} className={lineBg[line.kind]}>\n <td className=\"select-none px-2 text-right text-muted-foreground/60 tabular-nums\">\n {line.oldNumber ?? \"\"}\n </td>\n <td className=\"select-none px-2 text-right text-muted-foreground/60 tabular-nums\">\n {line.newNumber ?? \"\"}\n </td>\n <td\n className={cn(\n \"select-none pr-1 pl-2\",\n line.kind === \"added\" && \"text-success\",\n line.kind === \"removed\" && \"text-destructive\",\n line.kind === \"meta\" && \"text-primary\",\n )}\n >\n {sign[line.kind]}\n </td>\n <td\n className={cn(\n \"w-full whitespace-pre\",\n line.kind === \"added\" && \"text-success\",\n line.kind === \"removed\" && \"text-destructive\",\n )}\n >\n {line.content}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </>\n )}\n </li>\n ))}\n </ol>\n </div>\n ),\n);\nDiffViewer.displayName = \"DiffViewer\";\n\nexport { DiffViewer };\n"
18
18
  }
19
19
  ]
20
20
  }
@@ -19,7 +19,7 @@
19
19
  "path": "components/composites/domain-config/domain-config.tsx",
20
20
  "type": "registry:block",
21
21
  "target": "components/blocks/domain-config.tsx",
22
- "content": "import { Check, Globe, Plus, ShieldCheck, ShieldX, Trash2 } from \"lucide-react\";\nimport { forwardRef, useState } from \"react\";\nimport type { HTMLAttributes } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\n\nexport type DomainStatus = \"verified\" | \"pending\" | \"invalid\";\n\nexport interface Domain {\n id: string;\n hostname: string;\n status: DomainStatus;\n primary?: boolean;\n /**\n * TLS state. If true, certificate is provisioned & valid.\n */\n tls?: boolean;\n /**\n * DNS record the user must add to verify ownership.\n */\n verificationRecord?: {\n type: \"TXT\" | \"CNAME\" | \"A\";\n name: string;\n value: string;\n };\n}\n\nconst statusVariant: Record<DomainStatus, \"success\" | \"warning\" | \"destructive\"> = {\n verified: \"success\",\n pending: \"warning\",\n invalid: \"destructive\",\n};\nconst statusDot: Record<DomainStatus, \"success\" | \"warning\" | \"destructive\"> = {\n verified: \"success\",\n pending: \"warning\",\n invalid: \"destructive\",\n};\nconst statusLabel: Record<DomainStatus, string> = {\n verified: \"Verified\",\n pending: \"Pending DNS\",\n invalid: \"Invalid\",\n};\n\ninterface DomainConfigProps extends HTMLAttributes<HTMLDivElement> {\n domains: Domain[];\n onAdd?: (hostname: string) => void;\n onRemove?: (id: string) => void;\n onSetPrimary?: (id: string) => void;\n}\n\n/**\n * DomainConfig — manage custom domains for a project.\n *\n * Shows: hostname, status, TLS, primary flag, and verification DNS record when pending.\n * Common in every cloud dashboard (Vercel, Railway, Render).\n */\nconst DomainConfig = forwardRef<HTMLDivElement, DomainConfigProps>(\n ({ className, domains, onAdd, onRemove, onSetPrimary, ...props }, ref) => {\n const [hostname, setHostname] = useState(\"\");\n\n return (\n <div\n ref={ref}\n className={cn(\"rounded-xl border bg-card p-5 shadow-sm\", className)}\n {...props}\n >\n <header className=\"mb-4 flex items-baseline justify-between gap-3\">\n <div>\n <h3 className=\"font-display text-title-md tracking-tight\">Domains</h3>\n <p className=\"text-body-sm text-muted-foreground\">{domains.length} configured</p>\n </div>\n </header>\n\n {onAdd ? (\n <form\n className=\"mb-4 grid grid-cols-[1fr_auto] gap-2\"\n onSubmit={(e) => {\n e.preventDefault();\n const v = hostname.trim();\n if (!v) return;\n onAdd(v);\n setHostname(\"\");\n }}\n >\n <Input\n placeholder=\"api.acme.com\"\n value={hostname}\n onChange={(e) => setHostname(e.target.value)}\n aria-label=\"Hostname\"\n className=\"font-mono\"\n />\n <Button type=\"submit\">\n <Plus /> Add domain\n </Button>\n </form>\n ) : null}\n\n <ul className=\"grid gap-3\">\n {domains.map((d) => (\n <li key={d.id} className=\"grid gap-3 rounded-lg border border-border/40 p-4\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <Globe className=\"size-4 text-muted-foreground\" aria-hidden=\"true\" />\n <span className=\"font-mono text-code-md text-foreground\">{d.hostname}</span>\n <Badge variant={statusVariant[d.status]}>\n <Badge.Dot tone={statusDot[d.status]} pulse={d.status === \"pending\"} />\n {statusLabel[d.status]}\n </Badge>\n {d.tls === true ? (\n <Badge variant=\"primary\">\n <ShieldCheck className=\"size-3\" /> TLS\n </Badge>\n ) : d.tls === false ? (\n <Badge variant=\"destructive\">\n <ShieldX className=\"size-3\" /> No TLS\n </Badge>\n ) : null}\n {d.primary ? (\n <Badge variant=\"accent\">\n <Check className=\"size-3\" /> Primary\n </Badge>\n ) : null}\n <div className=\"ml-auto flex items-center gap-1\">\n {!d.primary && onSetPrimary ? (\n <Button size=\"sm\" variant=\"ghost\" onClick={() => onSetPrimary(d.id)}>\n Set primary\n </Button>\n ) : null}\n {onRemove ? (\n <Button\n size=\"icon\"\n variant=\"ghost\"\n onClick={() => onRemove(d.id)}\n aria-label={`Remove ${d.hostname}`}\n >\n <Trash2 />\n </Button>\n ) : null}\n </div>\n </div>\n {d.status === \"pending\" && d.verificationRecord ? (\n <div className=\"rounded-md border border-border/60 border-dashed bg-muted/30 p-3 font-mono text-code-sm\">\n <p className=\"mb-2 font-sans text-label-caps text-muted-foreground uppercase\">\n Add this DNS record to verify\n </p>\n <div className=\"grid grid-cols-[auto_1fr] gap-x-3 gap-y-1\">\n <span className=\"text-muted-foreground\">type</span>\n <span>{d.verificationRecord.type}</span>\n <span className=\"text-muted-foreground\">name</span>\n <span>{d.verificationRecord.name}</span>\n <span className=\"text-muted-foreground\">value</span>\n <span className=\"break-all\">{d.verificationRecord.value}</span>\n </div>\n </div>\n ) : null}\n </li>\n ))}\n {domains.length === 0 ? (\n <li className=\"rounded-lg border border-border/40 border-dashed p-8 text-center text-body-sm text-muted-foreground\">\n No domains yet. Add one to route traffic to this project.\n </li>\n ) : null}\n </ul>\n </div>\n );\n },\n);\nDomainConfig.displayName = \"DomainConfig\";\n\nexport { DomainConfig };\n"
22
+ "content": "\"use client\";\n\nimport { Check, Globe, Plus, ShieldCheck, ShieldX, Trash2 } from \"lucide-react\";\nimport { forwardRef, useState } from \"react\";\nimport type { HTMLAttributes } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\n\nexport type DomainStatus = \"verified\" | \"pending\" | \"invalid\";\n\nexport interface Domain {\n id: string;\n hostname: string;\n status: DomainStatus;\n primary?: boolean;\n /**\n * TLS state. If true, certificate is provisioned & valid.\n */\n tls?: boolean;\n /**\n * DNS record the user must add to verify ownership.\n */\n verificationRecord?: {\n type: \"TXT\" | \"CNAME\" | \"A\";\n name: string;\n value: string;\n };\n}\n\nconst statusVariant: Record<DomainStatus, \"success\" | \"warning\" | \"destructive\"> = {\n verified: \"success\",\n pending: \"warning\",\n invalid: \"destructive\",\n};\nconst statusDot: Record<DomainStatus, \"success\" | \"warning\" | \"destructive\"> = {\n verified: \"success\",\n pending: \"warning\",\n invalid: \"destructive\",\n};\nconst statusLabel: Record<DomainStatus, string> = {\n verified: \"Verified\",\n pending: \"Pending DNS\",\n invalid: \"Invalid\",\n};\n\ninterface DomainConfigProps extends HTMLAttributes<HTMLDivElement> {\n domains: Domain[];\n onAdd?: (hostname: string) => void;\n onRemove?: (id: string) => void;\n onSetPrimary?: (id: string) => void;\n}\n\n/**\n * DomainConfig — manage custom domains for a project.\n *\n * Shows: hostname, status, TLS, primary flag, and verification DNS record when pending.\n * Common in every cloud dashboard (Vercel, Railway, Render).\n */\nconst DomainConfig = forwardRef<HTMLDivElement, DomainConfigProps>(\n ({ className, domains, onAdd, onRemove, onSetPrimary, ...props }, ref) => {\n const [hostname, setHostname] = useState(\"\");\n\n return (\n <div\n data-slot=\"domain-config\"\n ref={ref}\n className={cn(\"rounded-xl border bg-card p-5 shadow-sm\", className)}\n {...props}\n >\n <header className=\"mb-4 flex items-baseline justify-between gap-3\">\n <div>\n <h3 className=\"font-display text-title-md tracking-tight\">Domains</h3>\n <p className=\"text-body-sm text-muted-foreground\">{domains.length} configured</p>\n </div>\n </header>\n\n {onAdd ? (\n <form\n className=\"mb-4 grid grid-cols-[1fr_auto] gap-2\"\n onSubmit={(e) => {\n e.preventDefault();\n const v = hostname.trim();\n if (!v) return;\n onAdd(v);\n setHostname(\"\");\n }}\n >\n <Input\n placeholder=\"api.acme.com\"\n value={hostname}\n onChange={(e) => setHostname(e.target.value)}\n aria-label=\"Hostname\"\n className=\"font-mono\"\n />\n <Button type=\"submit\">\n <Plus /> Add domain\n </Button>\n </form>\n ) : null}\n\n <ul className=\"grid gap-3\">\n {domains.map((d) => (\n <li key={d.id} className=\"grid gap-3 rounded-lg border border-border/40 p-4\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <Globe className=\"size-4 text-muted-foreground\" aria-hidden=\"true\" />\n <span className=\"font-mono text-code-md text-foreground\">{d.hostname}</span>\n <Badge variant={statusVariant[d.status]}>\n <Badge.Dot tone={statusDot[d.status]} pulse={d.status === \"pending\"} />\n {statusLabel[d.status]}\n </Badge>\n {d.tls === true ? (\n <Badge variant=\"primary\">\n <ShieldCheck className=\"size-3\" /> TLS\n </Badge>\n ) : d.tls === false ? (\n <Badge variant=\"destructive\">\n <ShieldX className=\"size-3\" /> No TLS\n </Badge>\n ) : null}\n {d.primary ? (\n <Badge variant=\"accent\">\n <Check className=\"size-3\" /> Primary\n </Badge>\n ) : null}\n <div className=\"ml-auto flex items-center gap-1\">\n {!d.primary && onSetPrimary ? (\n <Button size=\"sm\" variant=\"ghost\" onClick={() => onSetPrimary(d.id)}>\n Set primary\n </Button>\n ) : null}\n {onRemove ? (\n <Button\n size=\"icon\"\n variant=\"ghost\"\n onClick={() => onRemove(d.id)}\n aria-label={`Remove ${d.hostname}`}\n >\n <Trash2 />\n </Button>\n ) : null}\n </div>\n </div>\n {d.status === \"pending\" && d.verificationRecord ? (\n <div className=\"rounded-md border border-border/60 border-dashed bg-muted/30 p-3 font-mono text-code-sm\">\n <p className=\"mb-2 font-sans text-label-caps text-muted-foreground uppercase\">\n Add this DNS record to verify\n </p>\n <div className=\"grid grid-cols-[auto_1fr] gap-x-3 gap-y-1\">\n <span className=\"text-muted-foreground\">type</span>\n <span>{d.verificationRecord.type}</span>\n <span className=\"text-muted-foreground\">name</span>\n <span>{d.verificationRecord.name}</span>\n <span className=\"text-muted-foreground\">value</span>\n <span className=\"break-all\">{d.verificationRecord.value}</span>\n </div>\n </div>\n ) : null}\n </li>\n ))}\n {domains.length === 0 ? (\n <li className=\"rounded-lg border border-border/40 border-dashed p-8 text-center text-body-sm text-muted-foreground\">\n No domains yet. Add one to route traffic to this project.\n </li>\n ) : null}\n </ul>\n </div>\n );\n },\n);\nDomainConfig.displayName = \"DomainConfig\";\n\nexport { DomainConfig };\n"
23
23
  }
24
24
  ]
25
25
  }
@@ -3,7 +3,7 @@
3
3
  "name": "dropdown-menu",
4
4
  "type": "registry:ui",
5
5
  "title": "DropdownMenu",
6
- "description": "Accessible dropdown menu primitive built on @radix-ui/react-dropdown-menu. Sub-components attached via Object.assign (Trigger, Content, Item, CheckboxItem, RadioItem, Label, Separator, Shortcut, Group, Sub, SubTrigger, SubContent, RadioGroup). Styled with @usetheo/ui design tokens. Consolidates the 5 prior direct-Radix usages under a single wrapper.",
6
+ "description": "Accessible dropdown menu primitive built on @radix-ui/react-dropdown-menu. Sub-components attached via Object.assign (Trigger, Content, Item, CheckboxItem, RadioItem, Label, Separator, Shortcut, Group, Sub, SubTrigger, SubContent, RadioGroup). Styled with @theokit/ui design tokens. Consolidates the 5 prior direct-Radix usages under a single wrapper.",
7
7
  "dependencies": [
8
8
  "@radix-ui/react-dropdown-menu",
9
9
  "lucide-react"
@@ -17,7 +17,7 @@
17
17
  "path": "components/primitives/dropdown-menu/dropdown-menu.tsx",
18
18
  "type": "registry:ui",
19
19
  "target": "components/ui/dropdown-menu.tsx",
20
- "content": "import * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport { Check, ChevronRight, Circle } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { ComponentPropsWithoutRef, ElementRef, HTMLAttributes } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\n/**\n * DropdownMenu — accessible menu primitive built on Radix.\n *\n * Composition (single import surface):\n * <DropdownMenu>\n * <DropdownMenu.Trigger>…</DropdownMenu.Trigger>\n * <DropdownMenu.Content>\n * <DropdownMenu.Label>Section</DropdownMenu.Label>\n * <DropdownMenu.Item onSelect={…}>Edit</DropdownMenu.Item>\n * <DropdownMenu.Separator />\n * <DropdownMenu.Item disabled>Delete</DropdownMenu.Item>\n * </DropdownMenu.Content>\n * </DropdownMenu>\n *\n * The primitive consolidates 5 prior direct-Radix usages\n * (`model-selector`, `intent-selector`, `agent-profile`,\n * `theme-switcher`, `theo-code-shell`) under a single styled\n * wrapper so consumers get consistent visuals + the design tokens.\n *\n * a11y note for tests: Radix's focus-guard spans intentionally\n * violate `aria-hidden-focus`. Tests should pass\n * `{ rules: { \"aria-hidden-focus\": { enabled: false } } }` to axe.\n */\n\nconst Trigger = DropdownMenuPrimitive.Trigger;\nconst Portal = DropdownMenuPrimitive.Portal;\nconst Group = DropdownMenuPrimitive.Group;\nconst Sub = DropdownMenuPrimitive.Sub;\nconst RadioGroup = DropdownMenuPrimitive.RadioGroup;\n\nconst Content = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.Content>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n \"z-50 min-w-32 overflow-hidden rounded-lg border border-border/40 bg-card p-1\",\n \"text-card-foreground shadow-md\",\n \"data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=closed]:animate-out\",\n className,\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n));\nContent.displayName = \"DropdownMenu.Content\";\n\ninterface ItemProps extends ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> {\n inset?: boolean;\n}\n\nconst Item = forwardRef<ElementRef<typeof DropdownMenuPrimitive.Item>, ItemProps>(\n ({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Item\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center gap-2 rounded-md px-2 py-1.5\",\n \"font-sans text-body-sm text-foreground outline-none\",\n \"transition-colors\",\n \"focus:bg-muted focus:text-foreground\",\n \"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n inset && \"pl-8\",\n className,\n )}\n {...props}\n />\n ),\n);\nItem.displayName = \"DropdownMenu.Item\";\n\nconst CheckboxItem = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n <DropdownMenuPrimitive.CheckboxItem\n ref={ref}\n checked={checked}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-md py-1.5 pr-2 pl-8\",\n \"font-sans text-body-sm text-foreground outline-none\",\n \"transition-colors focus:bg-muted focus:text-foreground\",\n \"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className,\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex size-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Check aria-hidden=\"true\" className=\"size-4\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n));\nCheckboxItem.displayName = \"DropdownMenu.CheckboxItem\";\n\nconst RadioItem = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.RadioItem>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n <DropdownMenuPrimitive.RadioItem\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-md py-1.5 pr-2 pl-8\",\n \"font-sans text-body-sm text-foreground outline-none\",\n \"transition-colors focus:bg-muted focus:text-foreground\",\n \"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className,\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex size-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Circle aria-hidden=\"true\" className=\"size-2 fill-current\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n));\nRadioItem.displayName = \"DropdownMenu.RadioItem\";\n\ninterface LabelProps extends ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> {\n inset?: boolean;\n}\n\nconst Label = forwardRef<ElementRef<typeof DropdownMenuPrimitive.Label>, LabelProps>(\n ({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Label\n ref={ref}\n className={cn(\n \"px-2 py-1.5 font-medium font-sans text-label-caps text-muted-foreground uppercase tracking-wider\",\n inset && \"pl-8\",\n className,\n )}\n {...props}\n />\n ),\n);\nLabel.displayName = \"DropdownMenu.Label\";\n\nconst Separator = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.Separator>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Separator\n ref={ref}\n className={cn(\"-mx-1 my-1 h-px bg-border/40\", className)}\n {...props}\n />\n));\nSeparator.displayName = \"DropdownMenu.Separator\";\n\nconst Shortcut = ({ className, ...props }: HTMLAttributes<HTMLSpanElement>) => (\n <span\n className={cn(\"ml-auto font-mono text-label text-muted-foreground\", className)}\n {...props}\n />\n);\nShortcut.displayName = \"DropdownMenu.Shortcut\";\n\nconst SubTrigger = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & { inset?: boolean }\n>(({ className, inset, children, ...props }, ref) => (\n <DropdownMenuPrimitive.SubTrigger\n ref={ref}\n className={cn(\n \"flex cursor-default select-none items-center gap-2 rounded-md px-2 py-1.5\",\n \"font-sans text-body-sm text-foreground outline-none\",\n \"focus:bg-muted data-[state=open]:bg-muted\",\n inset && \"pl-8\",\n className,\n )}\n {...props}\n >\n {children}\n <ChevronRight aria-hidden=\"true\" className=\"ml-auto size-3.5\" />\n </DropdownMenuPrimitive.SubTrigger>\n));\nSubTrigger.displayName = \"DropdownMenu.SubTrigger\";\n\nconst SubContent = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.SubContent>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.SubContent\n ref={ref}\n className={cn(\n \"z-50 min-w-32 overflow-hidden rounded-lg border border-border/40 bg-card p-1\",\n \"text-card-foreground shadow-md\",\n \"data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=closed]:animate-out\",\n className,\n )}\n {...props}\n />\n));\nSubContent.displayName = \"DropdownMenu.SubContent\";\n\ntype DropdownMenuRoot = typeof DropdownMenuPrimitive.Root & {\n Trigger: typeof Trigger;\n Portal: typeof Portal;\n Content: typeof Content;\n Item: typeof Item;\n CheckboxItem: typeof CheckboxItem;\n RadioItem: typeof RadioItem;\n Label: typeof Label;\n Separator: typeof Separator;\n Shortcut: typeof Shortcut;\n Group: typeof Group;\n Sub: typeof Sub;\n SubTrigger: typeof SubTrigger;\n SubContent: typeof SubContent;\n RadioGroup: typeof RadioGroup;\n};\n\nconst DropdownMenu: DropdownMenuRoot = Object.assign(DropdownMenuPrimitive.Root, {\n Trigger,\n Portal,\n Content,\n Item,\n CheckboxItem,\n RadioItem,\n Label,\n Separator,\n Shortcut,\n Group,\n Sub,\n SubTrigger,\n SubContent,\n RadioGroup,\n});\n\nexport { DropdownMenu };\n"
20
+ "content": "import * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport { Check, ChevronRight, Circle } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport type { ComponentPropsWithoutRef, ElementRef, HTMLAttributes } from \"react\";\nimport { cn } from \"@/lib/cn\";\n\n/**\n * DropdownMenu — accessible menu primitive built on Radix.\n *\n * Composition (single import surface):\n * <DropdownMenu>\n * <DropdownMenu.Trigger>…</DropdownMenu.Trigger>\n * <DropdownMenu.Content>\n * <DropdownMenu.Label>Section</DropdownMenu.Label>\n * <DropdownMenu.Item onSelect={…}>Edit</DropdownMenu.Item>\n * <DropdownMenu.Separator />\n * <DropdownMenu.Item disabled>Delete</DropdownMenu.Item>\n * </DropdownMenu.Content>\n * </DropdownMenu>\n *\n * The primitive consolidates 5 prior direct-Radix usages\n * (`model-selector`, `intent-selector`, `agent-profile`,\n * `theme-switcher`, `theo-code-shell`) under a single styled\n * wrapper so consumers get consistent visuals + the design tokens.\n *\n * a11y note for tests: Radix's focus-guard spans intentionally\n * violate `aria-hidden-focus`. Tests should pass\n * `{ rules: { \"aria-hidden-focus\": { enabled: false } } }` to axe.\n */\n\nconst Trigger = DropdownMenuPrimitive.Trigger;\nconst Portal = DropdownMenuPrimitive.Portal;\nconst Group = DropdownMenuPrimitive.Group;\nconst Sub = DropdownMenuPrimitive.Sub;\nconst RadioGroup = DropdownMenuPrimitive.RadioGroup;\n\nconst Content = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.Content>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n data-slot=\"dropdown-menu-content\"\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n \"z-50 min-w-32 overflow-hidden rounded-lg border border-border/40 bg-card p-1\",\n \"text-card-foreground shadow-md\",\n \"data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=closed]:animate-out\",\n className,\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n));\nContent.displayName = \"DropdownMenu.Content\";\n\ninterface ItemProps extends ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> {\n inset?: boolean;\n}\n\nconst Item = forwardRef<ElementRef<typeof DropdownMenuPrimitive.Item>, ItemProps>(\n ({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Item\n data-slot=\"dropdown-menu-item\"\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center gap-2 rounded-md px-2 py-1.5\",\n \"font-sans text-body-sm text-foreground outline-none\",\n \"transition-colors\",\n \"focus:bg-muted focus:text-foreground\",\n \"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n inset && \"pl-8\",\n className,\n )}\n {...props}\n />\n ),\n);\nItem.displayName = \"DropdownMenu.Item\";\n\nconst CheckboxItem = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n <DropdownMenuPrimitive.CheckboxItem\n data-slot=\"dropdown-menu-checkbox-item\"\n ref={ref}\n checked={checked}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-md py-1.5 pr-2 pl-8\",\n \"font-sans text-body-sm text-foreground outline-none\",\n \"transition-colors focus:bg-muted focus:text-foreground\",\n \"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className,\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex size-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Check aria-hidden=\"true\" className=\"size-4\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n));\nCheckboxItem.displayName = \"DropdownMenu.CheckboxItem\";\n\nconst RadioItem = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.RadioItem>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n <DropdownMenuPrimitive.RadioItem\n data-slot=\"dropdown-menu-radio-item\"\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center rounded-md py-1.5 pr-2 pl-8\",\n \"font-sans text-body-sm text-foreground outline-none\",\n \"transition-colors focus:bg-muted focus:text-foreground\",\n \"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className,\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex size-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Circle aria-hidden=\"true\" className=\"size-2 fill-current\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n));\nRadioItem.displayName = \"DropdownMenu.RadioItem\";\n\ninterface LabelProps extends ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> {\n inset?: boolean;\n}\n\nconst Label = forwardRef<ElementRef<typeof DropdownMenuPrimitive.Label>, LabelProps>(\n ({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Label\n data-slot=\"dropdown-menu-label\"\n ref={ref}\n className={cn(\n \"px-2 py-1.5 font-medium font-sans text-label-caps text-muted-foreground uppercase tracking-wider\",\n inset && \"pl-8\",\n className,\n )}\n {...props}\n />\n ),\n);\nLabel.displayName = \"DropdownMenu.Label\";\n\nconst Separator = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.Separator>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Separator\n data-slot=\"dropdown-menu-separator\"\n ref={ref}\n className={cn(\"-mx-1 my-1 h-px bg-border/40\", className)}\n {...props}\n />\n));\nSeparator.displayName = \"DropdownMenu.Separator\";\n\nconst Shortcut = ({ className, ...props }: HTMLAttributes<HTMLSpanElement>) => (\n <span\n className={cn(\"ml-auto font-mono text-label text-muted-foreground\", className)}\n {...props}\n />\n);\nShortcut.displayName = \"DropdownMenu.Shortcut\";\n\nconst SubTrigger = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & { inset?: boolean }\n>(({ className, inset, children, ...props }, ref) => (\n <DropdownMenuPrimitive.SubTrigger\n data-slot=\"dropdown-menu-sub-trigger\"\n ref={ref}\n className={cn(\n \"flex cursor-default select-none items-center gap-2 rounded-md px-2 py-1.5\",\n \"font-sans text-body-sm text-foreground outline-none\",\n \"focus:bg-muted data-[state=open]:bg-muted\",\n inset && \"pl-8\",\n className,\n )}\n {...props}\n >\n {children}\n <ChevronRight aria-hidden=\"true\" className=\"ml-auto size-3.5\" />\n </DropdownMenuPrimitive.SubTrigger>\n));\nSubTrigger.displayName = \"DropdownMenu.SubTrigger\";\n\nconst SubContent = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.SubContent>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.SubContent\n data-slot=\"dropdown-menu-sub-content\"\n ref={ref}\n className={cn(\n \"z-50 min-w-32 overflow-hidden rounded-lg border border-border/40 bg-card p-1\",\n \"text-card-foreground shadow-md\",\n \"data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[state=open]:animate-in\",\n \"data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=closed]:animate-out\",\n className,\n )}\n {...props}\n />\n));\nSubContent.displayName = \"DropdownMenu.SubContent\";\n\ntype DropdownMenuRoot = typeof DropdownMenuPrimitive.Root & {\n Trigger: typeof Trigger;\n Portal: typeof Portal;\n Content: typeof Content;\n Item: typeof Item;\n CheckboxItem: typeof CheckboxItem;\n RadioItem: typeof RadioItem;\n Label: typeof Label;\n Separator: typeof Separator;\n Shortcut: typeof Shortcut;\n Group: typeof Group;\n Sub: typeof Sub;\n SubTrigger: typeof SubTrigger;\n SubContent: typeof SubContent;\n RadioGroup: typeof RadioGroup;\n};\n\nconst DropdownMenu: DropdownMenuRoot = Object.assign(DropdownMenuPrimitive.Root, {\n Trigger,\n Portal,\n Content,\n Item,\n CheckboxItem,\n RadioItem,\n Label,\n Separator,\n Shortcut,\n Group,\n Sub,\n SubTrigger,\n SubContent,\n RadioGroup,\n});\n\nexport { DropdownMenu };\n"
21
21
  }
22
22
  ]
23
23
  }
@@ -14,7 +14,7 @@
14
14
  "path": "components/primitives/empty-state/empty-state.tsx",
15
15
  "type": "registry:ui",
16
16
  "target": "components/ui/empty-state.tsx",
17
- "content": "import { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport type { IconComponent } from \"@/lib/types\";\n\ninterface EmptyStateProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n /** Icon shown above the title. */\n icon?: IconComponent;\n title: ReactNode;\n description?: ReactNode;\n /** Optional action slot (typically <Button>). */\n action?: ReactNode;\n /** Hint shown above the title (e.g. uppercase eyebrow). */\n eyebrow?: ReactNode;\n /** Bordered dashed surface (placeholder vibe). Default true. */\n dashed?: boolean;\n}\n\n/**\n * EmptyState — visual placeholder for empty lists / first-run screens.\n *\n * Composition: icon + eyebrow + title + description + action. All slots are\n * optional except title.\n */\nconst EmptyState = forwardRef<HTMLDivElement, EmptyStateProps>(\n (\n { className, icon: Icon, title, description, action, eyebrow, dashed = true, ...props },\n ref,\n ) => (\n <div\n ref={ref}\n className={cn(\n \"grid place-items-center gap-3 rounded-2xl border bg-card px-6 py-12 text-center\",\n dashed ? \"border-border/60 border-dashed\" : \"border-border/40\",\n className,\n )}\n {...props}\n >\n {Icon ? (\n <span className=\"grid size-12 place-items-center rounded-2xl bg-primary/10 text-primary\">\n <Icon className=\"size-6\" aria-hidden=\"true\" />\n </span>\n ) : null}\n {eyebrow ? (\n <p className=\"font-mono text-label-caps text-muted-foreground uppercase\">{eyebrow}</p>\n ) : null}\n <h3 className=\"font-display text-foreground text-title-md\">{title}</h3>\n {description ? (\n <p className=\"max-w-md text-body-sm text-muted-foreground\">{description}</p>\n ) : null}\n {action ? <div className=\"mt-2\">{action}</div> : null}\n </div>\n ),\n);\nEmptyState.displayName = \"EmptyState\";\n\nexport { EmptyState };\n"
17
+ "content": "import { forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport type { IconComponent } from \"@/lib/types\";\n\ninterface EmptyStateProps extends Omit<HTMLAttributes<HTMLDivElement>, \"title\"> {\n /** Icon shown above the title. */\n icon?: IconComponent;\n title: ReactNode;\n description?: ReactNode;\n /** Optional action slot (typically <Button>). */\n action?: ReactNode;\n /** Hint shown above the title (e.g. uppercase eyebrow). */\n eyebrow?: ReactNode;\n /** Bordered dashed surface (placeholder vibe). Default true. */\n dashed?: boolean;\n}\n\n/**\n * EmptyState — visual placeholder for empty lists / first-run screens.\n *\n * Composition: icon + eyebrow + title + description + action. All slots are\n * optional except title.\n */\nconst EmptyState = forwardRef<HTMLDivElement, EmptyStateProps>(\n (\n { className, icon: Icon, title, description, action, eyebrow, dashed = true, ...props },\n ref,\n ) => (\n <div\n data-slot=\"empty-state\"\n ref={ref}\n className={cn(\n \"grid place-items-center gap-3 rounded-2xl border bg-card px-6 py-12 text-center\",\n dashed ? \"border-border/60 border-dashed\" : \"border-border/40\",\n className,\n )}\n {...props}\n >\n {Icon ? (\n <span className=\"grid size-12 place-items-center rounded-2xl bg-primary/10 text-primary\">\n <Icon className=\"size-6\" aria-hidden=\"true\" />\n </span>\n ) : null}\n {eyebrow ? (\n <p className=\"font-mono text-label-caps text-muted-foreground uppercase\">{eyebrow}</p>\n ) : null}\n <h3 className=\"font-display text-foreground text-title-md\">{title}</h3>\n {description ? (\n <p className=\"max-w-md text-body-sm text-muted-foreground\">{description}</p>\n ) : null}\n {action ? <div className=\"mt-2\">{action}</div> : null}\n </div>\n ),\n);\nEmptyState.displayName = \"EmptyState\";\n\nexport { EmptyState };\n"
18
18
  }
19
19
  ]
20
20
  }
@@ -11,6 +11,7 @@
11
11
  "https://usetheodev.github.io/theo-ui/r/badge.json",
12
12
  "https://usetheodev.github.io/theo-ui/r/button.json",
13
13
  "https://usetheodev.github.io/theo-ui/r/cn.json",
14
+ "https://usetheodev.github.io/theo-ui/r/env.json",
14
15
  "https://usetheodev.github.io/theo-ui/r/input.json",
15
16
  "https://usetheodev.github.io/theo-ui/r/tailwind-preset.json"
16
17
  ],
@@ -19,7 +20,7 @@
19
20
  "path": "components/composites/env-var-editor/env-var-editor.tsx",
20
21
  "type": "registry:block",
21
22
  "target": "components/blocks/env-var-editor.tsx",
22
- "content": "import { Copy, Eye, EyeOff, Lock, Plus, Trash2 } from \"lucide-react\";\nimport { forwardRef, useState } from \"react\";\nimport type { HTMLAttributes } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\n\nexport type EnvScope = \"production\" | \"staging\" | \"preview\" | \"all\" | string;\n\nexport interface EnvVar {\n id: string;\n key: string;\n /**\n * Secret value. If `masked` is true, value is hidden by default.\n */\n value: string;\n masked?: boolean;\n scope?: EnvScope;\n /**\n * Read-only marker (e.g. system-managed vars like THEO_DEPLOY_ID).\n */\n readonly?: boolean;\n}\n\ninterface EnvVarEditorProps extends HTMLAttributes<HTMLDivElement> {\n vars: EnvVar[];\n onAdd?: (entry: Omit<EnvVar, \"id\">) => void;\n onRemove?: (id: string) => void;\n /**\n * Available scope options for the add form. Defaults to a sensible PaaS set.\n */\n scopeOptions?: EnvScope[];\n}\n\nconst DEFAULT_SCOPES: EnvScope[] = [\"production\", \"staging\", \"preview\", \"all\"];\n\n/**\n * EnvVarEditor — table-like editor for environment variables.\n *\n * Mono font on keys/values, mask toggle on secret values, scope badge,\n * remove + copy actions. Add form sits above the list.\n *\n * Stateless: caller controls the list and reacts to onAdd / onRemove.\n */\nconst EnvVarEditor = forwardRef<HTMLDivElement, EnvVarEditorProps>(\n ({ className, vars, onAdd, onRemove, scopeOptions = DEFAULT_SCOPES, ...props }, ref) => {\n const [newKey, setNewKey] = useState(\"\");\n const [newValue, setNewValue] = useState(\"\");\n const [newScope, setNewScope] = useState<EnvScope>(scopeOptions[0] ?? \"production\");\n\n const submit = () => {\n const trimmedKey = newKey.trim();\n if (!trimmedKey) return;\n onAdd?.({ key: trimmedKey, value: newValue, scope: newScope, masked: true });\n setNewKey(\"\");\n setNewValue(\"\");\n };\n\n return (\n <div\n ref={ref}\n className={cn(\"rounded-xl border bg-card p-5 shadow-sm\", className)}\n {...props}\n >\n <header className=\"mb-4 flex items-baseline justify-between gap-3\">\n <div>\n <h3 className=\"font-display text-title-md tracking-tight\">Environment variables</h3>\n <p className=\"text-body-sm text-muted-foreground\">\n {vars.length} {vars.length === 1 ? \"variable\" : \"variables\"}\n </p>\n </div>\n </header>\n\n {onAdd ? (\n <form\n className=\"mb-4 grid grid-cols-[2fr_3fr_auto_auto] gap-2\"\n onSubmit={(e) => {\n e.preventDefault();\n submit();\n }}\n >\n <Input\n placeholder=\"DATABASE_URL\"\n value={newKey}\n onChange={(e) => setNewKey(e.target.value)}\n className=\"font-mono\"\n aria-label=\"Variable name\"\n />\n <Input\n placeholder=\"postgresql://…\"\n value={newValue}\n onChange={(e) => setNewValue(e.target.value)}\n className=\"font-mono\"\n aria-label=\"Variable value\"\n />\n <select\n value={newScope}\n onChange={(e) => setNewScope(e.target.value)}\n aria-label=\"Variable scope\"\n className={cn(\n \"h-10 rounded-md border border-input bg-card px-3\",\n \"font-sans text-body-sm\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card\",\n )}\n >\n {scopeOptions.map((s) => (\n <option key={s} value={s}>\n {s}\n </option>\n ))}\n </select>\n <Button type=\"submit\">\n <Plus /> Add\n </Button>\n </form>\n ) : null}\n\n <ul className=\"divide-y divide-border/30\">\n {vars.map((v) => (\n <Row key={v.id} entry={v} {...(onRemove ? { onRemove } : {})} />\n ))}\n {vars.length === 0 ? (\n <li className=\"py-8 text-center text-body-sm text-muted-foreground\">\n No environment variables yet.\n </li>\n ) : null}\n </ul>\n </div>\n );\n },\n);\nEnvVarEditor.displayName = \"EnvVarEditor\";\n\ninterface RowProps {\n entry: EnvVar;\n onRemove?: (id: string) => void;\n}\n\nfunction Row({ entry, onRemove }: RowProps) {\n const [revealed, setRevealed] = useState(!entry.masked);\n\n const value = revealed ? entry.value : \"•\".repeat(Math.min(entry.value.length, 12) || 8);\n\n const copy = () => {\n if (typeof navigator !== \"undefined\" && navigator.clipboard) {\n navigator.clipboard.writeText(entry.value).catch((err: unknown) => {\n // T7.6: dev-only warning so engineers see something when clipboard\n // fails (Safari/Firefox iframe sandbox, document not focused,\n // Permissions-Policy block). Production stays silent — behavior is\n // fail-safe (user can still copy manually).\n if (typeof process !== \"undefined\" && process.env.NODE_ENV !== \"production\") {\n // biome-ignore lint/suspicious/noConsole: dev-only clipboard diagnostic (T7.6)\n console.warn(\"[@usetheo/ui] EnvVarEditor clipboard write failed:\", err);\n }\n });\n }\n };\n\n return (\n <li className=\"grid grid-cols-[2fr_3fr_auto_auto] items-center gap-3 py-3\">\n <span className=\"truncate font-mono text-code-sm text-foreground\">{entry.key}</span>\n <span className=\"flex items-center gap-2 truncate font-mono text-code-sm text-muted-foreground\">\n {entry.readonly ? <Lock className=\"size-3\" aria-hidden=\"true\" /> : null}\n {value}\n </span>\n <Badge variant={entry.scope === \"production\" ? \"primary\" : \"default\"}>\n {entry.scope ?? \"all\"}\n </Badge>\n <div className=\"flex items-center gap-0.5\">\n {entry.masked ? (\n <Button\n size=\"icon\"\n variant=\"ghost\"\n onClick={() => setRevealed((r) => !r)}\n aria-label={revealed ? \"Hide value\" : \"Reveal value\"}\n >\n {revealed ? <EyeOff /> : <Eye />}\n </Button>\n ) : null}\n <Button size=\"icon\" variant=\"ghost\" onClick={copy} aria-label=\"Copy value\">\n <Copy />\n </Button>\n {onRemove && !entry.readonly ? (\n <Button\n size=\"icon\"\n variant=\"ghost\"\n onClick={() => onRemove(entry.id)}\n aria-label={`Remove ${entry.key}`}\n >\n <Trash2 />\n </Button>\n ) : null}\n </div>\n </li>\n );\n}\n\nexport { EnvVarEditor };\n"
23
+ "content": "\"use client\";\n\nimport { Copy, Eye, EyeOff, Lock, Plus, Trash2 } from \"lucide-react\";\nimport { forwardRef, useState } from \"react\";\nimport type { HTMLAttributes } from \"react\";\nimport { cn } from \"@/lib/cn\";\nimport { isDev } from \"@/lib/env\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\n\nexport type EnvScope = \"production\" | \"staging\" | \"preview\" | \"all\" | string;\n\nexport interface EnvVar {\n id: string;\n key: string;\n /**\n * Secret value. If `masked` is true, value is hidden by default.\n */\n value: string;\n masked?: boolean;\n scope?: EnvScope;\n /**\n * Read-only marker (e.g. system-managed vars like THEO_DEPLOY_ID).\n */\n readonly?: boolean;\n}\n\ninterface EnvVarEditorProps extends HTMLAttributes<HTMLDivElement> {\n vars: EnvVar[];\n onAdd?: (entry: Omit<EnvVar, \"id\">) => void;\n onRemove?: (id: string) => void;\n /**\n * Available scope options for the add form. Defaults to a sensible PaaS set.\n */\n scopeOptions?: EnvScope[];\n}\n\nconst DEFAULT_SCOPES: EnvScope[] = [\"production\", \"staging\", \"preview\", \"all\"];\n\n/**\n * EnvVarEditor — table-like editor for environment variables.\n *\n * Mono font on keys/values, mask toggle on secret values, scope badge,\n * remove + copy actions. Add form sits above the list.\n *\n * Stateless: caller controls the list and reacts to onAdd / onRemove.\n */\nconst EnvVarEditor = forwardRef<HTMLDivElement, EnvVarEditorProps>(\n ({ className, vars, onAdd, onRemove, scopeOptions = DEFAULT_SCOPES, ...props }, ref) => {\n const [newKey, setNewKey] = useState(\"\");\n const [newValue, setNewValue] = useState(\"\");\n const [newScope, setNewScope] = useState<EnvScope>(scopeOptions[0] ?? \"production\");\n\n const submit = () => {\n const trimmedKey = newKey.trim();\n if (!trimmedKey) return;\n onAdd?.({ key: trimmedKey, value: newValue, scope: newScope, masked: true });\n setNewKey(\"\");\n setNewValue(\"\");\n };\n\n return (\n <div\n data-slot=\"env-var-editor\"\n ref={ref}\n className={cn(\"rounded-xl border bg-card p-5 shadow-sm\", className)}\n {...props}\n >\n <header className=\"mb-4 flex items-baseline justify-between gap-3\">\n <div>\n <h3 className=\"font-display text-title-md tracking-tight\">Environment variables</h3>\n <p className=\"text-body-sm text-muted-foreground\">\n {vars.length} {vars.length === 1 ? \"variable\" : \"variables\"}\n </p>\n </div>\n </header>\n\n {onAdd ? (\n <form\n className=\"mb-4 grid grid-cols-[2fr_3fr_auto_auto] gap-2\"\n onSubmit={(e) => {\n e.preventDefault();\n submit();\n }}\n >\n <Input\n placeholder=\"DATABASE_URL\"\n value={newKey}\n onChange={(e) => setNewKey(e.target.value)}\n className=\"font-mono\"\n aria-label=\"Variable name\"\n />\n <Input\n placeholder=\"postgresql://…\"\n value={newValue}\n onChange={(e) => setNewValue(e.target.value)}\n className=\"font-mono\"\n aria-label=\"Variable value\"\n />\n <select\n value={newScope}\n onChange={(e) => setNewScope(e.target.value)}\n aria-label=\"Variable scope\"\n className={cn(\n \"h-10 rounded-md border border-input bg-card px-3\",\n \"font-sans text-body-sm\",\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-card\",\n )}\n >\n {scopeOptions.map((s) => (\n <option key={s} value={s}>\n {s}\n </option>\n ))}\n </select>\n <Button type=\"submit\">\n <Plus /> Add\n </Button>\n </form>\n ) : null}\n\n <ul className=\"divide-y divide-border/30\">\n {vars.map((v) => (\n <Row key={v.id} entry={v} {...(onRemove ? { onRemove } : {})} />\n ))}\n {vars.length === 0 ? (\n <li className=\"py-8 text-center text-body-sm text-muted-foreground\">\n No environment variables yet.\n </li>\n ) : null}\n </ul>\n </div>\n );\n },\n);\nEnvVarEditor.displayName = \"EnvVarEditor\";\n\ninterface RowProps {\n entry: EnvVar;\n onRemove?: (id: string) => void;\n}\n\nfunction Row({ entry, onRemove }: RowProps) {\n const [revealed, setRevealed] = useState(!entry.masked);\n\n const value = revealed ? entry.value : \"•\".repeat(Math.min(entry.value.length, 12) || 8);\n\n const copy = () => {\n if (typeof navigator !== \"undefined\" && navigator.clipboard) {\n navigator.clipboard.writeText(entry.value).catch((err: unknown) => {\n // T7.6: dev-only warning so engineers see something when clipboard\n // fails (Safari/Firefox iframe sandbox, document not focused,\n // Permissions-Policy block). Production stays silent — behavior is\n // fail-safe (user can still copy manually).\n if (isDev()) {\n // biome-ignore lint/suspicious/noConsole: dev-only clipboard diagnostic (T7.6)\n console.warn(\"[@theokit/ui] EnvVarEditor clipboard write failed:\", err);\n }\n });\n }\n };\n\n return (\n <li className=\"grid grid-cols-[2fr_3fr_auto_auto] items-center gap-3 py-3\">\n <span className=\"truncate font-mono text-code-sm text-foreground\">{entry.key}</span>\n <span className=\"flex items-center gap-2 truncate font-mono text-code-sm text-muted-foreground\">\n {entry.readonly ? <Lock className=\"size-3\" aria-hidden=\"true\" /> : null}\n {value}\n </span>\n <Badge variant={entry.scope === \"production\" ? \"primary\" : \"default\"}>\n {entry.scope ?? \"all\"}\n </Badge>\n <div className=\"flex items-center gap-0.5\">\n {entry.masked ? (\n <Button\n size=\"icon\"\n variant=\"ghost\"\n onClick={() => setRevealed((r) => !r)}\n aria-label={revealed ? \"Hide value\" : \"Reveal value\"}\n >\n {revealed ? <EyeOff /> : <Eye />}\n </Button>\n ) : null}\n <Button size=\"icon\" variant=\"ghost\" onClick={copy} aria-label=\"Copy value\">\n <Copy />\n </Button>\n {onRemove && !entry.readonly ? (\n <Button\n size=\"icon\"\n variant=\"ghost\"\n onClick={() => onRemove(entry.id)}\n aria-label={`Remove ${entry.key}`}\n >\n <Trash2 />\n </Button>\n ) : null}\n </div>\n </li>\n );\n}\n\nexport { EnvVarEditor };\n"
23
24
  }
24
25
  ]
25
26
  }