@nikala-ui/docs 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (463) hide show
  1. package/README.md +22 -0
  2. package/dist/cli/commands/build.d.ts +5 -0
  3. package/dist/cli/commands/build.d.ts.map +1 -0
  4. package/dist/cli/commands/build.js +27 -0
  5. package/dist/cli/commands/build.js.map +1 -0
  6. package/dist/cli/commands/dev.d.ts +7 -0
  7. package/dist/cli/commands/dev.d.ts.map +1 -0
  8. package/dist/cli/commands/dev.js +32 -0
  9. package/dist/cli/commands/dev.js.map +1 -0
  10. package/dist/cli/commands/init.d.ts +2 -0
  11. package/dist/cli/commands/init.d.ts.map +1 -0
  12. package/dist/cli/commands/init.js +308 -0
  13. package/dist/cli/commands/init.js.map +1 -0
  14. package/dist/cli/commands/preview.d.ts +7 -0
  15. package/dist/cli/commands/preview.d.ts.map +1 -0
  16. package/dist/cli/commands/preview.js +24 -0
  17. package/dist/cli/commands/preview.js.map +1 -0
  18. package/dist/cli/commands/serve.d.ts +7 -0
  19. package/dist/cli/commands/serve.d.ts.map +1 -0
  20. package/dist/cli/commands/serve.js +33 -0
  21. package/dist/cli/commands/serve.js.map +1 -0
  22. package/dist/cli/index.d.ts +3 -0
  23. package/dist/cli/index.d.ts.map +1 -0
  24. package/dist/cli/index.js +53 -0
  25. package/dist/cli/index.js.map +1 -0
  26. package/dist/client/App.d.ts +5 -0
  27. package/dist/client/App.d.ts.map +1 -0
  28. package/dist/client/App.jsx +31 -0
  29. package/dist/client/App.jsx.map +1 -0
  30. package/dist/client/app-types.d.ts +14 -0
  31. package/dist/client/app-types.d.ts.map +1 -0
  32. package/dist/client/app-types.js +2 -0
  33. package/dist/client/app-types.js.map +1 -0
  34. package/dist/client/components/DocsLayoutShell.d.ts +21 -0
  35. package/dist/client/components/DocsLayoutShell.d.ts.map +1 -0
  36. package/dist/client/components/DocsLayoutShell.jsx +14 -0
  37. package/dist/client/components/DocsLayoutShell.jsx.map +1 -0
  38. package/dist/client/components/DocsPageContent.d.ts +9 -0
  39. package/dist/client/components/DocsPageContent.d.ts.map +1 -0
  40. package/dist/client/components/DocsPageContent.jsx +10 -0
  41. package/dist/client/components/DocsPageContent.jsx.map +1 -0
  42. package/dist/client/entry.d.ts +2 -0
  43. package/dist/client/entry.d.ts.map +1 -0
  44. package/dist/client/entry.jsx +28 -0
  45. package/dist/client/entry.jsx.map +1 -0
  46. package/dist/client/index.html +21 -0
  47. package/dist/client/navigation/page-navigation.d.ts +9 -0
  48. package/dist/client/navigation/page-navigation.d.ts.map +1 -0
  49. package/dist/client/navigation/page-navigation.js +51 -0
  50. package/dist/client/navigation/page-navigation.js.map +1 -0
  51. package/dist/client/routing/use-docs-router.d.ts +17 -0
  52. package/dist/client/routing/use-docs-router.d.ts.map +1 -0
  53. package/dist/client/routing/use-docs-router.js +71 -0
  54. package/dist/client/routing/use-docs-router.js.map +1 -0
  55. package/dist/client/ssr-entry.d.ts +3 -0
  56. package/dist/client/ssr-entry.d.ts.map +1 -0
  57. package/dist/client/ssr-entry.jsx +13 -0
  58. package/dist/client/ssr-entry.jsx.map +1 -0
  59. package/dist/client/style.css +183 -0
  60. package/dist/client/utils/sidebar.d.ts +2 -0
  61. package/dist/client/utils/sidebar.d.ts.map +1 -0
  62. package/dist/client/utils/sidebar.js +2 -0
  63. package/dist/client/utils/sidebar.js.map +1 -0
  64. package/dist/components/mdx-components.d.ts +34 -0
  65. package/dist/components/mdx-components.d.ts.map +1 -0
  66. package/dist/components/mdx-components.jsx +131 -0
  67. package/dist/components/mdx-components.jsx.map +1 -0
  68. package/dist/config.d.ts +6 -0
  69. package/dist/config.d.ts.map +1 -0
  70. package/dist/config.js +105 -0
  71. package/dist/config.js.map +1 -0
  72. package/dist/core/content-scanner.d.ts +10 -0
  73. package/dist/core/content-scanner.d.ts.map +1 -0
  74. package/dist/core/content-scanner.js +153 -0
  75. package/dist/core/content-scanner.js.map +1 -0
  76. package/dist/core/route-tree.d.ts +19 -0
  77. package/dist/core/route-tree.d.ts.map +1 -0
  78. package/dist/core/route-tree.js +176 -0
  79. package/dist/core/route-tree.js.map +1 -0
  80. package/dist/index.d.ts +13 -0
  81. package/dist/index.d.ts.map +1 -0
  82. package/dist/index.js +14 -0
  83. package/dist/index.js.map +1 -0
  84. package/dist/lib/cn.d.ts +6 -0
  85. package/dist/lib/cn.d.ts.map +1 -0
  86. package/dist/lib/cn.js +9 -0
  87. package/dist/lib/cn.js.map +1 -0
  88. package/dist/mdx/compiler.d.ts +13 -0
  89. package/dist/mdx/compiler.d.ts.map +1 -0
  90. package/dist/mdx/compiler.js +38 -0
  91. package/dist/mdx/compiler.js.map +1 -0
  92. package/dist/mdx/highlighter.d.ts +22 -0
  93. package/dist/mdx/highlighter.d.ts.map +1 -0
  94. package/dist/mdx/highlighter.js +139 -0
  95. package/dist/mdx/highlighter.js.map +1 -0
  96. package/dist/mdx/rehype-shiki.d.ts +3 -0
  97. package/dist/mdx/rehype-shiki.d.ts.map +1 -0
  98. package/dist/mdx/rehype-shiki.js +83 -0
  99. package/dist/mdx/rehype-shiki.js.map +1 -0
  100. package/dist/navigation/index.d.ts +2 -0
  101. package/dist/navigation/index.d.ts.map +1 -0
  102. package/dist/navigation/index.js +2 -0
  103. package/dist/navigation/index.js.map +1 -0
  104. package/dist/navigation/sidebar-state.d.ts +6 -0
  105. package/dist/navigation/sidebar-state.d.ts.map +1 -0
  106. package/dist/navigation/sidebar-state.js +20 -0
  107. package/dist/navigation/sidebar-state.js.map +1 -0
  108. package/dist/navigation/sidebar-tree.d.ts +7 -0
  109. package/dist/navigation/sidebar-tree.d.ts.map +1 -0
  110. package/dist/navigation/sidebar-tree.js +11 -0
  111. package/dist/navigation/sidebar-tree.js.map +1 -0
  112. package/dist/registry/accordion.json +18 -0
  113. package/dist/registry/alert.json +18 -0
  114. package/dist/registry/api-table.json +21 -0
  115. package/dist/registry/aspect-ratio.json +17 -0
  116. package/dist/registry/avatar.json +17 -0
  117. package/dist/registry/badge.json +18 -0
  118. package/dist/registry/banner.json +19 -0
  119. package/dist/registry/breadcrumb.json +17 -0
  120. package/dist/registry/bubble.json +18 -0
  121. package/dist/registry/button-group.json +20 -0
  122. package/dist/registry/button.json +21 -0
  123. package/dist/registry/callout.json +19 -0
  124. package/dist/registry/card.json +17 -0
  125. package/dist/registry/checkbox.json +20 -0
  126. package/dist/registry/code-block.json +26 -0
  127. package/dist/registry/code-group.json +20 -0
  128. package/dist/registry/collapsible.json +18 -0
  129. package/dist/registry/combobox.json +21 -0
  130. package/dist/registry/command.json +27 -0
  131. package/dist/registry/component-viewer.json +25 -0
  132. package/dist/registry/container.json +18 -0
  133. package/dist/registry/context-menu.json +24 -0
  134. package/dist/registry/create-active-element.json +13 -0
  135. package/dist/registry/create-app-updater.json +13 -0
  136. package/dist/registry/create-audio.json +7 -0
  137. package/dist/registry/create-battery.json +13 -0
  138. package/dist/registry/create-chat-scroll.json +13 -0
  139. package/dist/registry/create-click-outside.json +13 -0
  140. package/dist/registry/create-clipboard.json +13 -0
  141. package/dist/registry/create-color-mode.json +13 -0
  142. package/dist/registry/create-controllable-signal.json +13 -0
  143. package/dist/registry/create-debounce.json +13 -0
  144. package/dist/registry/create-disclosure.json +13 -0
  145. package/dist/registry/create-document-tabs.json +13 -0
  146. package/dist/registry/create-document-title.json +13 -0
  147. package/dist/registry/create-drop-zone.json +13 -0
  148. package/dist/registry/create-event-source.json +13 -0
  149. package/dist/registry/create-favicon.json +13 -0
  150. package/dist/registry/create-fetch.json +13 -0
  151. package/dist/registry/create-focus-trap.json +13 -0
  152. package/dist/registry/create-form.json +13 -0
  153. package/dist/registry/create-fullscreen.json +13 -0
  154. package/dist/registry/create-geolocation.json +13 -0
  155. package/dist/registry/create-global-shortcut.json +13 -0
  156. package/dist/registry/create-hover.json +13 -0
  157. package/dist/registry/create-idle.json +13 -0
  158. package/dist/registry/create-infinite-scroll.json +13 -0
  159. package/dist/registry/create-input-mask.json +13 -0
  160. package/dist/registry/create-intersection-observer.json +13 -0
  161. package/dist/registry/create-keybindings.json +13 -0
  162. package/dist/registry/create-lock-scroll.json +13 -0
  163. package/dist/registry/create-long-press.json +13 -0
  164. package/dist/registry/create-media-query.json +13 -0
  165. package/dist/registry/create-mouse-position.json +13 -0
  166. package/dist/registry/create-network-status.json +13 -0
  167. package/dist/registry/create-orientation.json +13 -0
  168. package/dist/registry/create-pagination.json +13 -0
  169. package/dist/registry/create-permission.json +13 -0
  170. package/dist/registry/create-previous.json +13 -0
  171. package/dist/registry/create-resize-observer.json +13 -0
  172. package/dist/registry/create-scroll-into-view.json +13 -0
  173. package/dist/registry/create-scroll-position.json +13 -0
  174. package/dist/registry/create-storage.json +13 -0
  175. package/dist/registry/create-tauri-window.json +13 -0
  176. package/dist/registry/create-timer.json +13 -0
  177. package/dist/registry/create-tiptap-editor.json +34 -0
  178. package/dist/registry/create-undo-redo.json +13 -0
  179. package/dist/registry/create-web-notification.json +13 -0
  180. package/dist/registry/create-websocket.json +13 -0
  181. package/dist/registry/create-window-size.json +13 -0
  182. package/dist/registry/dialog.json +21 -0
  183. package/dist/registry/dropdown-menu.json +22 -0
  184. package/dist/registry/dropzone.json +21 -0
  185. package/dist/registry/empty.json +17 -0
  186. package/dist/registry/field.json +20 -0
  187. package/dist/registry/file-tree.json +21 -0
  188. package/dist/registry/footer.json +18 -0
  189. package/dist/registry/forgot-password-01.json +28 -0
  190. package/dist/registry/form-message.json +17 -0
  191. package/dist/registry/form.json +17 -0
  192. package/dist/registry/hero-01.json +22 -0
  193. package/dist/registry/hover-card.json +18 -0
  194. package/dist/registry/icon-button.json +20 -0
  195. package/dist/registry/index.json +1489 -0
  196. package/dist/registry/input-group.json +21 -0
  197. package/dist/registry/input.json +17 -0
  198. package/dist/registry/kbd.json +18 -0
  199. package/dist/registry/label.json +18 -0
  200. package/dist/registry/list.json +20 -0
  201. package/dist/registry/login-01.json +28 -0
  202. package/dist/registry/logo.json +17 -0
  203. package/dist/registry/marker.json +17 -0
  204. package/dist/registry/marquee.json +17 -0
  205. package/dist/registry/message.json +17 -0
  206. package/dist/registry/navbar.json +19 -0
  207. package/dist/registry/navigation-menu.json +22 -0
  208. package/dist/registry/number-input.json +24 -0
  209. package/dist/registry/otp-verification-01.json +26 -0
  210. package/dist/registry/package-manager-tabs.json +24 -0
  211. package/dist/registry/pager.json +21 -0
  212. package/dist/registry/pagination.json +22 -0
  213. package/dist/registry/pin-input.json +17 -0
  214. package/dist/registry/popover.json +22 -0
  215. package/dist/registry/progress.json +18 -0
  216. package/dist/registry/radio-group.json +18 -0
  217. package/dist/registry/rating.json +19 -0
  218. package/dist/registry/register-01.json +31 -0
  219. package/dist/registry/resizable.json +21 -0
  220. package/dist/registry/review-card.json +23 -0
  221. package/dist/registry/rich-text-editor.json +95 -0
  222. package/dist/registry/scroll-area.json +21 -0
  223. package/dist/registry/section-heading.json +21 -0
  224. package/dist/registry/select.json +22 -0
  225. package/dist/registry/separator.json +17 -0
  226. package/dist/registry/sheet.json +22 -0
  227. package/dist/registry/sidebar.json +24 -0
  228. package/dist/registry/skeleton.json +17 -0
  229. package/dist/registry/slider.json +18 -0
  230. package/dist/registry/spinner.json +18 -0
  231. package/dist/registry/stat.json +19 -0
  232. package/dist/registry/status.json +18 -0
  233. package/dist/registry/steps.json +20 -0
  234. package/dist/registry/switch.json +20 -0
  235. package/dist/registry/table-of-contents.json +23 -0
  236. package/dist/registry/table.json +17 -0
  237. package/dist/registry/tabs.json +20 -0
  238. package/dist/registry/textarea.json +17 -0
  239. package/dist/registry/theme-manager.json +39 -0
  240. package/dist/registry/timeline.json +18 -0
  241. package/dist/registry/titlebar-tabs.json +24 -0
  242. package/dist/registry/titlebar.json +26 -0
  243. package/dist/registry/toast.json +20 -0
  244. package/dist/registry/toggle-group.json +21 -0
  245. package/dist/registry/toggle.json +18 -0
  246. package/dist/registry/tooltip.json +18 -0
  247. package/dist/registry/updater-modal.json +26 -0
  248. package/dist/server/index.d.ts +18 -0
  249. package/dist/server/index.d.ts.map +1 -0
  250. package/dist/server/index.js +526 -0
  251. package/dist/server/index.js.map +1 -0
  252. package/dist/server/plugin.d.ts +10 -0
  253. package/dist/server/plugin.d.ts.map +1 -0
  254. package/dist/server/plugin.js +271 -0
  255. package/dist/server/plugin.js.map +1 -0
  256. package/dist/themes/default/content/breadcrumbs.d.ts +4 -0
  257. package/dist/themes/default/content/breadcrumbs.d.ts.map +1 -0
  258. package/dist/themes/default/content/breadcrumbs.jsx +31 -0
  259. package/dist/themes/default/content/breadcrumbs.jsx.map +1 -0
  260. package/dist/themes/default/content/pager.d.ts +5 -0
  261. package/dist/themes/default/content/pager.d.ts.map +1 -0
  262. package/dist/themes/default/content/pager.jsx +9 -0
  263. package/dist/themes/default/content/pager.jsx.map +1 -0
  264. package/dist/themes/default/content/table-of-contents.d.ts +4 -0
  265. package/dist/themes/default/content/table-of-contents.d.ts.map +1 -0
  266. package/dist/themes/default/content/table-of-contents.jsx +19 -0
  267. package/dist/themes/default/content/table-of-contents.jsx.map +1 -0
  268. package/dist/themes/default/index.d.ts +11 -0
  269. package/dist/themes/default/index.d.ts.map +1 -0
  270. package/dist/themes/default/index.js +30 -0
  271. package/dist/themes/default/index.js.map +1 -0
  272. package/dist/themes/default/layout.d.ts +4 -0
  273. package/dist/themes/default/layout.d.ts.map +1 -0
  274. package/dist/themes/default/layout.jsx +75 -0
  275. package/dist/themes/default/layout.jsx.map +1 -0
  276. package/dist/themes/default/navbar.d.ts +4 -0
  277. package/dist/themes/default/navbar.d.ts.map +1 -0
  278. package/dist/themes/default/navbar.jsx +74 -0
  279. package/dist/themes/default/navbar.jsx.map +1 -0
  280. package/dist/themes/default/navigation/mobile-table-of-contents.d.ts +4 -0
  281. package/dist/themes/default/navigation/mobile-table-of-contents.d.ts.map +1 -0
  282. package/dist/themes/default/navigation/mobile-table-of-contents.jsx +22 -0
  283. package/dist/themes/default/navigation/mobile-table-of-contents.jsx.map +1 -0
  284. package/dist/themes/default/navigation/sidebar-tree.d.ts +8 -0
  285. package/dist/themes/default/navigation/sidebar-tree.d.ts.map +1 -0
  286. package/dist/themes/default/navigation/sidebar-tree.jsx +100 -0
  287. package/dist/themes/default/navigation/sidebar-tree.jsx.map +1 -0
  288. package/dist/themes/default/overlays/search-dialog.d.ts +4 -0
  289. package/dist/themes/default/overlays/search-dialog.d.ts.map +1 -0
  290. package/dist/themes/default/overlays/search-dialog.jsx +34 -0
  291. package/dist/themes/default/overlays/search-dialog.jsx.map +1 -0
  292. package/dist/themes/default/sidebar.d.ts +4 -0
  293. package/dist/themes/default/sidebar.d.ts.map +1 -0
  294. package/dist/themes/default/sidebar.jsx +60 -0
  295. package/dist/themes/default/sidebar.jsx.map +1 -0
  296. package/dist/themes/index.d.ts +4 -0
  297. package/dist/themes/index.d.ts.map +1 -0
  298. package/dist/themes/index.js +5 -0
  299. package/dist/themes/index.js.map +1 -0
  300. package/dist/themes/types.d.ts +83 -0
  301. package/dist/themes/types.d.ts.map +1 -0
  302. package/dist/themes/types.js +2 -0
  303. package/dist/themes/types.js.map +1 -0
  304. package/dist/types.d.ts +97 -0
  305. package/dist/types.d.ts.map +1 -0
  306. package/dist/types.js +3 -0
  307. package/dist/types.js.map +1 -0
  308. package/dist/vendor/core-src/index.css +11 -0
  309. package/dist/vendor/core-src/index.ts +48 -0
  310. package/dist/vendor/core-src/lib/cn.ts +9 -0
  311. package/dist/vendor/core-src/registry/blocks/forgot-password-01.tsx +141 -0
  312. package/dist/vendor/core-src/registry/blocks/hero-01.tsx +28 -0
  313. package/dist/vendor/core-src/registry/blocks/login-01.tsx +231 -0
  314. package/dist/vendor/core-src/registry/blocks/otp-verification-01.tsx +170 -0
  315. package/dist/vendor/core-src/registry/blocks/register-01.tsx +318 -0
  316. package/dist/vendor/core-src/registry/components/ui/accordion.tsx +128 -0
  317. package/dist/vendor/core-src/registry/components/ui/alert.tsx +155 -0
  318. package/dist/vendor/core-src/registry/components/ui/api-table.tsx +117 -0
  319. package/dist/vendor/core-src/registry/components/ui/aspect-ratio.tsx +31 -0
  320. package/dist/vendor/core-src/registry/components/ui/avatar.tsx +114 -0
  321. package/dist/vendor/core-src/registry/components/ui/badge.tsx +56 -0
  322. package/dist/vendor/core-src/registry/components/ui/banner.tsx +187 -0
  323. package/dist/vendor/core-src/registry/components/ui/breadcrumb.tsx +136 -0
  324. package/dist/vendor/core-src/registry/components/ui/bubble.tsx +142 -0
  325. package/dist/vendor/core-src/registry/components/ui/button-group.tsx +42 -0
  326. package/dist/vendor/core-src/registry/components/ui/button.tsx +82 -0
  327. package/dist/vendor/core-src/registry/components/ui/callout.tsx +137 -0
  328. package/dist/vendor/core-src/registry/components/ui/card.tsx +113 -0
  329. package/dist/vendor/core-src/registry/components/ui/checkbox.tsx +74 -0
  330. package/dist/vendor/core-src/registry/components/ui/code-block.tsx +326 -0
  331. package/dist/vendor/core-src/registry/components/ui/code-group.tsx +105 -0
  332. package/dist/vendor/core-src/registry/components/ui/collapsible.tsx +73 -0
  333. package/dist/vendor/core-src/registry/components/ui/combobox.tsx +299 -0
  334. package/dist/vendor/core-src/registry/components/ui/command.tsx +378 -0
  335. package/dist/vendor/core-src/registry/components/ui/component-viewer.tsx +363 -0
  336. package/dist/vendor/core-src/registry/components/ui/container.tsx +45 -0
  337. package/dist/vendor/core-src/registry/components/ui/context-menu.tsx +237 -0
  338. package/dist/vendor/core-src/registry/components/ui/dialog.tsx +200 -0
  339. package/dist/vendor/core-src/registry/components/ui/dropdown-menu.tsx +298 -0
  340. package/dist/vendor/core-src/registry/components/ui/dropzone.tsx +189 -0
  341. package/dist/vendor/core-src/registry/components/ui/empty.tsx +83 -0
  342. package/dist/vendor/core-src/registry/components/ui/field.tsx +71 -0
  343. package/dist/vendor/core-src/registry/components/ui/file-tree.tsx +181 -0
  344. package/dist/vendor/core-src/registry/components/ui/footer.tsx +247 -0
  345. package/dist/vendor/core-src/registry/components/ui/form-message.tsx +36 -0
  346. package/dist/vendor/core-src/registry/components/ui/form.tsx +21 -0
  347. package/dist/vendor/core-src/registry/components/ui/hover-card.tsx +105 -0
  348. package/dist/vendor/core-src/registry/components/ui/icon-button.tsx +34 -0
  349. package/dist/vendor/core-src/registry/components/ui/input-group.tsx +80 -0
  350. package/dist/vendor/core-src/registry/components/ui/input.tsx +28 -0
  351. package/dist/vendor/core-src/registry/components/ui/kbd.tsx +73 -0
  352. package/dist/vendor/core-src/registry/components/ui/label.tsx +30 -0
  353. package/dist/vendor/core-src/registry/components/ui/list.tsx +222 -0
  354. package/dist/vendor/core-src/registry/components/ui/logo.tsx +68 -0
  355. package/dist/vendor/core-src/registry/components/ui/marker.tsx +102 -0
  356. package/dist/vendor/core-src/registry/components/ui/marquee.tsx +118 -0
  357. package/dist/vendor/core-src/registry/components/ui/message.tsx +168 -0
  358. package/dist/vendor/core-src/registry/components/ui/navbar.tsx +375 -0
  359. package/dist/vendor/core-src/registry/components/ui/navigation-menu.tsx +358 -0
  360. package/dist/vendor/core-src/registry/components/ui/number-input.tsx +150 -0
  361. package/dist/vendor/core-src/registry/components/ui/package-manager-tabs.tsx +226 -0
  362. package/dist/vendor/core-src/registry/components/ui/pager.tsx +102 -0
  363. package/dist/vendor/core-src/registry/components/ui/pagination.tsx +258 -0
  364. package/dist/vendor/core-src/registry/components/ui/pin-input.tsx +198 -0
  365. package/dist/vendor/core-src/registry/components/ui/popover.tsx +90 -0
  366. package/dist/vendor/core-src/registry/components/ui/progress.tsx +66 -0
  367. package/dist/vendor/core-src/registry/components/ui/radio-group.tsx +95 -0
  368. package/dist/vendor/core-src/registry/components/ui/rating.tsx +185 -0
  369. package/dist/vendor/core-src/registry/components/ui/resizable.tsx +195 -0
  370. package/dist/vendor/core-src/registry/components/ui/review-card.tsx +195 -0
  371. package/dist/vendor/core-src/registry/components/ui/rich-text-editor/bubble-menu.tsx +236 -0
  372. package/dist/vendor/core-src/registry/components/ui/rich-text-editor/editor.tsx +308 -0
  373. package/dist/vendor/core-src/registry/components/ui/rich-text-editor/extensions.ts +116 -0
  374. package/dist/vendor/core-src/registry/components/ui/rich-text-editor/footer.tsx +36 -0
  375. package/dist/vendor/core-src/registry/components/ui/rich-text-editor/image-dialog.tsx +75 -0
  376. package/dist/vendor/core-src/registry/components/ui/rich-text-editor/index.ts +11 -0
  377. package/dist/vendor/core-src/registry/components/ui/rich-text-editor/link-dialog.tsx +48 -0
  378. package/dist/vendor/core-src/registry/components/ui/rich-text-editor/markdown.ts +170 -0
  379. package/dist/vendor/core-src/registry/components/ui/rich-text-editor/slash-command.tsx +301 -0
  380. package/dist/vendor/core-src/registry/components/ui/rich-text-editor/table-controls.tsx +68 -0
  381. package/dist/vendor/core-src/registry/components/ui/rich-text-editor/toolbar.tsx +465 -0
  382. package/dist/vendor/core-src/registry/components/ui/rich-text-editor/use-editor.ts +231 -0
  383. package/dist/vendor/core-src/registry/components/ui/scroll-area.tsx +228 -0
  384. package/dist/vendor/core-src/registry/components/ui/section-heading.tsx +108 -0
  385. package/dist/vendor/core-src/registry/components/ui/select.tsx +156 -0
  386. package/dist/vendor/core-src/registry/components/ui/separator.tsx +37 -0
  387. package/dist/vendor/core-src/registry/components/ui/sheet.tsx +220 -0
  388. package/dist/vendor/core-src/registry/components/ui/sidebar.tsx +692 -0
  389. package/dist/vendor/core-src/registry/components/ui/skeleton.tsx +24 -0
  390. package/dist/vendor/core-src/registry/components/ui/slider.tsx +153 -0
  391. package/dist/vendor/core-src/registry/components/ui/spinner.tsx +41 -0
  392. package/dist/vendor/core-src/registry/components/ui/stat.tsx +245 -0
  393. package/dist/vendor/core-src/registry/components/ui/status.tsx +121 -0
  394. package/dist/vendor/core-src/registry/components/ui/steps.tsx +198 -0
  395. package/dist/vendor/core-src/registry/components/ui/switch.tsx +68 -0
  396. package/dist/vendor/core-src/registry/components/ui/table-of-contents.tsx +131 -0
  397. package/dist/vendor/core-src/registry/components/ui/table.tsx +160 -0
  398. package/dist/vendor/core-src/registry/components/ui/tabs.tsx +204 -0
  399. package/dist/vendor/core-src/registry/components/ui/textarea.tsx +82 -0
  400. package/dist/vendor/core-src/registry/components/ui/theme-toggle.tsx +238 -0
  401. package/dist/vendor/core-src/registry/components/ui/timeline.tsx +350 -0
  402. package/dist/vendor/core-src/registry/components/ui/titlebar-tabs.tsx +773 -0
  403. package/dist/vendor/core-src/registry/components/ui/titlebar.tsx +468 -0
  404. package/dist/vendor/core-src/registry/components/ui/toast.tsx +124 -0
  405. package/dist/vendor/core-src/registry/components/ui/toggle-group.tsx +203 -0
  406. package/dist/vendor/core-src/registry/components/ui/toggle.tsx +101 -0
  407. package/dist/vendor/core-src/registry/components/ui/tooltip.tsx +41 -0
  408. package/dist/vendor/core-src/registry/components/ui/updater-modal.tsx +254 -0
  409. package/dist/vendor/core-src/registry/index.ts +50 -0
  410. package/dist/vendor/core-src/registry/metadata.ts +742 -0
  411. package/dist/vendor/core-src/registry/providers/theme-provider.tsx +216 -0
  412. package/dist/vendor/core-src/registry/providers/theme-script.tsx +78 -0
  413. package/dist/vendor/core-src/registry/providers/theme-transitions.ts +139 -0
  414. package/dist/vendor/hooks-src/create-active-element.ts +51 -0
  415. package/dist/vendor/hooks-src/create-app-updater.ts +272 -0
  416. package/dist/vendor/hooks-src/create-audio-video.ts +444 -0
  417. package/dist/vendor/hooks-src/create-battery.ts +78 -0
  418. package/dist/vendor/hooks-src/create-chat-scroll.ts +113 -0
  419. package/dist/vendor/hooks-src/create-click-outside.ts +82 -0
  420. package/dist/vendor/hooks-src/create-clipboard.ts +69 -0
  421. package/dist/vendor/hooks-src/create-color-mode.ts +115 -0
  422. package/dist/vendor/hooks-src/create-controllable-signal.ts +56 -0
  423. package/dist/vendor/hooks-src/create-debounce.ts +90 -0
  424. package/dist/vendor/hooks-src/create-disclosure.ts +82 -0
  425. package/dist/vendor/hooks-src/create-document-tabs.ts +267 -0
  426. package/dist/vendor/hooks-src/create-document-title.ts +33 -0
  427. package/dist/vendor/hooks-src/create-drop-zone.ts +317 -0
  428. package/dist/vendor/hooks-src/create-event-source.ts +126 -0
  429. package/dist/vendor/hooks-src/create-favicon.ts +52 -0
  430. package/dist/vendor/hooks-src/create-fetch.ts +93 -0
  431. package/dist/vendor/hooks-src/create-focus-trap.ts +94 -0
  432. package/dist/vendor/hooks-src/create-form.ts +200 -0
  433. package/dist/vendor/hooks-src/create-fullscreen.ts +105 -0
  434. package/dist/vendor/hooks-src/create-geolocation.ts +140 -0
  435. package/dist/vendor/hooks-src/create-global-shortcut.ts +140 -0
  436. package/dist/vendor/hooks-src/create-hover.ts +88 -0
  437. package/dist/vendor/hooks-src/create-idle.ts +109 -0
  438. package/dist/vendor/hooks-src/create-infinite-scroll.ts +90 -0
  439. package/dist/vendor/hooks-src/create-input-mask.ts +109 -0
  440. package/dist/vendor/hooks-src/create-intersection-observer.ts +82 -0
  441. package/dist/vendor/hooks-src/create-keybindings.ts +148 -0
  442. package/dist/vendor/hooks-src/create-lock-scroll.ts +97 -0
  443. package/dist/vendor/hooks-src/create-long-press.ts +85 -0
  444. package/dist/vendor/hooks-src/create-media-query.ts +94 -0
  445. package/dist/vendor/hooks-src/create-mouse-position.ts +87 -0
  446. package/dist/vendor/hooks-src/create-network-status.ts +100 -0
  447. package/dist/vendor/hooks-src/create-orientation.ts +129 -0
  448. package/dist/vendor/hooks-src/create-pagination.ts +208 -0
  449. package/dist/vendor/hooks-src/create-permission.ts +91 -0
  450. package/dist/vendor/hooks-src/create-previous.ts +21 -0
  451. package/dist/vendor/hooks-src/create-resize-observer.ts +89 -0
  452. package/dist/vendor/hooks-src/create-scroll-into-view.ts +57 -0
  453. package/dist/vendor/hooks-src/create-scroll-position.ts +129 -0
  454. package/dist/vendor/hooks-src/create-storage.ts +106 -0
  455. package/dist/vendor/hooks-src/create-tauri-window.ts +628 -0
  456. package/dist/vendor/hooks-src/create-timer.ts +150 -0
  457. package/dist/vendor/hooks-src/create-tiptap-editor.ts +326 -0
  458. package/dist/vendor/hooks-src/create-undo-redo.ts +100 -0
  459. package/dist/vendor/hooks-src/create-web-notification.ts +111 -0
  460. package/dist/vendor/hooks-src/create-websocket.ts +179 -0
  461. package/dist/vendor/hooks-src/create-window-size.ts +41 -0
  462. package/dist/vendor/hooks-src/index.ts +48 -0
  463. package/package.json +87 -0
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "theme-manager",
3
+ "title": "Theme Manager",
4
+ "description": "Zero-dependency ThemeProvider and ThemeToggle component for switching light, dark, and system themes.",
5
+ "type": "registry:ui",
6
+ "dependencies": [
7
+ "clsx",
8
+ "tailwind-merge",
9
+ "@kobalte/core",
10
+ "lucide-solid"
11
+ ],
12
+ "registryDependencies": [
13
+ "button",
14
+ "dropdown-menu",
15
+ "create-color-mode"
16
+ ],
17
+ "files": [
18
+ {
19
+ "path": "providers/theme-provider.tsx",
20
+ "content": "import {\n createContext,\n createEffect,\n createSignal,\n onCleanup,\n onMount,\n useContext,\n type ParentComponent,\n type Accessor,\n} from \"solid-js\";\n\nexport type Theme = \"light\" | \"dark\" | \"system\";\nexport type AccentColor = \"yellow\" | \"red\" | \"violet\" | \"sky\" | \"emerald\" | \"zinc\";\nexport type Radius = \"0\" | \"0.3\" | \"0.5\" | \"0.75\" | \"1.0\";\n\nexport interface ThemeProviderProps {\n /** Initial default theme mode if no saved preference is found in localStorage */\n defaultTheme?: Theme;\n /** Initial default accent color override if needed */\n defaultAccent?: AccentColor;\n /** Initial default border radius override if needed */\n defaultRadius?: Radius;\n /** Key used to store theme preferences in localStorage */\n storageKey?: string;\n}\n\nconst ACCENT_COLORS: Record<\n AccentColor,\n { light: string; dark: string; lightFg: string; darkFg: string }\n> = {\n yellow: { light: \"oklch(0.795 0.184 86.047)\", dark: \"oklch(0.852 0.199 91.936)\", lightFg: \"oklch(0.145 0 0)\", darkFg: \"oklch(0.145 0 0)\" },\n red: { light: \"oklch(0.577 0.245 27.325)\", dark: \"oklch(0.637 0.237 25.331)\", lightFg: \"oklch(0.985 0 0)\", darkFg: \"oklch(0.985 0 0)\" },\n violet: { light: \"oklch(0.541 0.281 293.009)\", dark: \"oklch(0.606 0.25 292.717)\", lightFg: \"oklch(0.985 0 0)\", darkFg: \"oklch(0.985 0 0)\" },\n sky: { light: \"oklch(0.588 0.158 241.966)\", dark: \"oklch(0.672 0.154 238.29)\", lightFg: \"oklch(0.985 0 0)\", darkFg: \"oklch(0.145 0 0)\" },\n emerald: { light: \"oklch(0.596 0.145 163.225)\", dark: \"oklch(0.696 0.17 162.48)\", lightFg: \"oklch(0.985 0 0)\", darkFg: \"oklch(0.145 0 0)\" },\n zinc: { light: \"oklch(0.205 0 0)\", dark: \"oklch(0.985 0 0)\", lightFg: \"oklch(0.985 0 0)\", darkFg: \"oklch(0.205 0 0)\" },\n};\n\ninterface ThemeProviderContextValue {\n theme: Accessor<Theme>;\n setTheme: (theme: Theme) => void;\n accent: Accessor<AccentColor | undefined>;\n setAccent: (accent: AccentColor) => void;\n radius: Accessor<Radius | undefined>;\n setRadius: (radius: Radius) => void;\n}\n\nconst ThemeProviderContext = createContext<ThemeProviderContextValue>();\n\n/**\n * Context provider managing application theme state (light/dark/system), accent colors, and border radius.\n */\nexport const ThemeProvider: ParentComponent<ThemeProviderProps> = (props) => {\n const storageKey = props.storageKey || \"nikala-theme\";\n const defaultTheme = props.defaultTheme || \"system\";\n\n // Safely read saved values from localStorage without forcing unnecessary fallbacks\n const getInitialTheme = (): Theme => {\n if (typeof window === \"undefined\") return defaultTheme;\n try {\n const saved = localStorage.getItem(`${storageKey}-mode`);\n if (saved === \"light\" || saved === \"dark\" || saved === \"system\") return saved;\n } catch { }\n return defaultTheme;\n };\n\n const getInitialAccent = (): AccentColor | undefined => {\n if (typeof window === \"undefined\") return props.defaultAccent;\n try {\n const saved = localStorage.getItem(`${storageKey}-accent`);\n if (saved && ACCENT_COLORS[saved as AccentColor]) return saved as AccentColor;\n } catch { }\n return props.defaultAccent;\n };\n\n const getInitialRadius = (): Radius | undefined => {\n if (typeof window === \"undefined\") return props.defaultRadius;\n try {\n const saved = localStorage.getItem(`${storageKey}-radius`);\n if (saved) return saved as Radius;\n } catch { }\n return props.defaultRadius;\n };\n\n const [theme, setThemeSignal] = createSignal<Theme>(getInitialTheme());\n const [accent, setAccentSignal] = createSignal<AccentColor | undefined>(getInitialAccent());\n const [radius, setRadiusSignal] = createSignal<Radius | undefined>(getInitialRadius());\n\n // Applies classes and CSS custom properties when custom overrides are explicitly set\n const applyTheme = (\n targetTheme: Theme,\n currentAccent: AccentColor | undefined,\n currentRadius: Radius | undefined\n ) => {\n if (typeof window === \"undefined\") return;\n\n const root = document.documentElement;\n root.classList.remove(\"light\", \"dark\");\n\n let resolvedDark = false;\n if (targetTheme === \"system\") {\n resolvedDark = window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n root.classList.add(resolvedDark ? \"dark\" : \"light\");\n } else {\n resolvedDark = targetTheme === \"dark\";\n root.classList.add(targetTheme);\n }\n root.style.colorScheme = resolvedDark ? \"dark\" : \"light\";\n\n // Override --primary CSS variables ONLY if explicitly chosen\n if (currentAccent && ACCENT_COLORS[currentAccent]) {\n const accentData = ACCENT_COLORS[currentAccent];\n const primaryHex = resolvedDark ? accentData.dark : accentData.light;\n const primaryFgHex = resolvedDark ? accentData.darkFg : accentData.lightFg;\n\n root.style.setProperty(\"--primary\", primaryHex);\n root.style.setProperty(\"--primary-foreground\", primaryFgHex);\n } else {\n root.style.removeProperty(\"--primary\");\n root.style.removeProperty(\"--primary-foreground\");\n }\n\n // Override --radius CSS variable ONLY if explicitly chosen\n if (currentRadius) {\n root.style.setProperty(\"--radius\", `${currentRadius}rem`);\n } else {\n root.style.removeProperty(\"--radius\");\n }\n };\n\n // Reactively apply theme updates and store preferences in localStorage\n createEffect(() => {\n const t = theme();\n const a = accent();\n const r = radius();\n\n applyTheme(t, a, r);\n\n if (typeof window !== \"undefined\") {\n try {\n localStorage.setItem(`${storageKey}-mode`, t);\n if (a) localStorage.setItem(`${storageKey}-accent`, a);\n else localStorage.removeItem(`${storageKey}-accent`);\n if (r) localStorage.setItem(`${storageKey}-radius`, r);\n else localStorage.removeItem(`${storageKey}-radius`);\n } catch { }\n }\n });\n\n onMount(() => {\n if (typeof window === \"undefined\") return;\n\n const mediaQuery = window.matchMedia(\"(prefers-color-scheme: dark)\");\n\n const handleSystemChange = (e: MediaQueryListEvent) => {\n if (theme() === \"system\") {\n const root = document.documentElement;\n root.classList.remove(\"light\", \"dark\");\n root.classList.add(e.matches ? \"dark\" : \"light\");\n root.style.colorScheme = e.matches ? \"dark\" : \"light\";\n\n const currentAccent = accent();\n if (currentAccent && ACCENT_COLORS[currentAccent]) {\n const accentData = ACCENT_COLORS[currentAccent];\n const primaryHex = e.matches ? accentData.dark : accentData.light;\n const primaryFgHex = e.matches ? accentData.darkFg : accentData.lightFg;\n\n root.style.setProperty(\"--primary\", primaryHex);\n root.style.setProperty(\"--primary-foreground\", primaryFgHex);\n }\n }\n };\n\n if (mediaQuery.addEventListener) {\n mediaQuery.addEventListener(\"change\", handleSystemChange);\n } else if (\"addListener\" in mediaQuery) {\n (mediaQuery as any).addListener(handleSystemChange);\n }\n\n onCleanup(() => {\n if (mediaQuery.removeEventListener) {\n mediaQuery.removeEventListener(\"change\", handleSystemChange);\n } else if (\"removeListener\" in mediaQuery) {\n (mediaQuery as any).removeListener(handleSystemChange);\n }\n });\n });\n\n const value: ThemeProviderContextValue = {\n theme,\n setTheme: (newTheme: Theme) => setThemeSignal(newTheme),\n accent,\n setAccent: (newAccent: AccentColor) => setAccentSignal(newAccent),\n radius,\n setRadius: (newRadius: Radius) => setRadiusSignal(newRadius),\n };\n\n return (\n <ThemeProviderContext.Provider value={value}>\n {props.children}\n </ThemeProviderContext.Provider>\n );\n};\n\n/**\n * Accesses Nikala UI theme state, accent colors, border radius, and update functions.\n */\nexport function useTheme(): ThemeProviderContextValue {\n const context = useContext(ThemeProviderContext);\n if (!context) {\n throw new Error(\"useTheme must be used within a ThemeProvider\");\n }\n return context;\n}\n\nexport { ThemeScript, type ThemeScriptProps } from \"./theme-script\";",
21
+ "type": "registry:ui"
22
+ },
23
+ {
24
+ "path": "providers/theme-transitions.ts",
25
+ "content": "export type ThemeEffect = \"none\" | \"circular\" | \"fade\";\n\n/**\n * Injects required CSS view-transition pseudo-element styles to prevent browser mix-blend artifacts.\n */\nfunction ensureTransitionStyles() {\n if (typeof document === \"undefined\") return;\n const styleId = \"nikala-view-transition-styles\";\n if (!document.getElementById(styleId)) {\n const style = document.createElement(\"style\");\n style.id = styleId;\n style.textContent = `\n ::view-transition-old(root),\n ::view-transition-new(root) {\n animation: none;\n mix-blend-mode: normal;\n }\n ::view-transition-old(root) {\n z-index: 1;\n }\n ::view-transition-new(root) {\n z-index: 9999;\n }\n `;\n document.head.appendChild(style);\n }\n}\n\n/**\n * Checks whether the current environment is Linux WebKitGTK (e.g. Tauri on Linux)\n * where CSS View Transitions pseudo-element animations trigger known WebProcess crashes.\n */\nfunction isLinuxWebKit(): boolean {\n if (typeof navigator === \"undefined\") return false;\n const ua = navigator.userAgent || \"\";\n const isLinux = /linux/i.test(ua);\n const isWebKit = /applewebkit/i.test(ua);\n const isChrome = /chrome|chromium|edg/i.test(ua);\n const isTauri = typeof window !== \"undefined\" && typeof (window as any).__TAURI_INTERNALS__ !== \"undefined\";\n\n return isLinux && ((isWebKit && !isChrome) || isTauri);\n}\n\n/**\n * Executes a theme change with the specified transition effect using the Web View Transitions API.\n * Supported on modern browsers, Windows (Tauri WebView2), and macOS (Tauri WKWebView).\n * Automatically falls back to safe instant transitions on Linux WebKitGTK.\n *\n * @param effect - Desired transition animation (\"none\", \"circular\", \"fade\")\n * @param event - Mouse or Pointer event to calculate transition center coordinates\n * @param updateThemeCallback - Callback function performing the actual theme state change\n */\nexport function runThemeTransition(\n effect: ThemeEffect = \"none\",\n event: MouseEvent | undefined,\n updateThemeCallback: () => void\n) {\n // Safe fallback if View Transitions API is unsupported, reduced motion is preferred,\n // or on Linux WebKitGTK where pseudo-element clipping transitions trigger WebProcess faults\n if (\n effect === \"none\" ||\n typeof document === \"undefined\" ||\n !(document as any).startViewTransition ||\n window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches ||\n isLinuxWebKit()\n ) {\n updateThemeCallback();\n return;\n }\n\n ensureTransitionStyles();\n\n try {\n // Circular expanding ripple transition originating from click coordinates\n if (effect === \"circular\" && event) {\n const x = event.clientX;\n const y = event.clientY;\n\n const endRadius = Math.hypot(\n Math.max(x, window.innerWidth - x),\n Math.max(y, window.innerHeight - y)\n );\n\n const transition = (document as any).startViewTransition(() => {\n updateThemeCallback();\n });\n\n transition.ready\n ?.then(() => {\n document.documentElement.animate(\n {\n clipPath: [\n `circle(0px at ${x}px ${y}px)`,\n `circle(${endRadius}px at ${x}px ${y}px)`,\n ],\n },\n {\n duration: 500,\n easing: \"ease-in-out\",\n pseudoElement: \"::view-transition-new(root)\",\n }\n );\n })\n ?.catch(() => {\n // Graceful fallback\n });\n return;\n }\n\n // Smooth opacity fade view transition\n if (effect === \"fade\") {\n const transition = (document as any).startViewTransition(() => {\n updateThemeCallback();\n });\n\n transition.ready\n ?.then(() => {\n document.documentElement.animate(\n {\n opacity: [0, 1],\n },\n {\n duration: 350,\n easing: \"ease-in-out\",\n pseudoElement: \"::view-transition-new(root)\",\n }\n );\n })\n ?.catch(() => {\n // Graceful fallback\n });\n return;\n }\n\n updateThemeCallback();\n } catch {\n updateThemeCallback();\n }\n}",
26
+ "type": "registry:ui"
27
+ },
28
+ {
29
+ "path": "providers/theme-script.tsx",
30
+ "content": "import { isServer } from \"solid-js/web\";\nimport type { Component } from \"solid-js\";\n\nexport interface ThemeScriptProps {\n /** Storage key namespace used in localStorage (default: \"nikala-theme\") */\n storageKey?: string;\n /** Initial default theme mode if no saved preference exists (default: \"system\") */\n defaultTheme?: \"light\" | \"dark\" | \"system\";\n /** Initial default primary accent color if no saved preference exists */\n defaultAccent?: string;\n /** Initial default border radius if no saved preference exists */\n defaultRadius?: string;\n}\n\n/**\n * Pre-hydration inline script executed synchronously before DOM paint to prevent theme flickering (anti-FOUC).\n */\nexport const ThemeScript: Component<ThemeScriptProps> = (props) => {\n if (!isServer) return null;\n const key = props.storageKey || \"nikala-theme\";\n const defTheme = props.defaultTheme || \"system\";\n const defAccent = props.defaultAccent || \"\";\n const defRadius = props.defaultRadius || \"\";\n\n const scriptText = `(function(){try{\n var key = '${key}';\n var mode = localStorage.getItem(key + '-mode') || '${defTheme}';\n var accent = localStorage.getItem(key + '-accent') || '${defAccent}';\n var radius = localStorage.getItem(key + '-radius') || '${defRadius}';\n\n var isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;\n var resolvedDark = mode === 'dark' || (mode === 'system' && isDark);\n\n var root = document.documentElement;\n root.classList.remove('light', 'dark');\n root.classList.add(resolvedDark ? 'dark' : 'light');\n root.style.colorScheme = resolvedDark ? 'dark' : 'light';\n\n var colorMap = {\n yellow: {\n primary: resolvedDark ? 'oklch(0.852 0.199 91.936)' : 'oklch(0.795 0.184 86.047)',\n foreground: 'oklch(0.145 0 0)'\n },\n red: {\n primary: resolvedDark ? 'oklch(0.637 0.237 25.331)' : 'oklch(0.577 0.245 27.325)',\n foreground: 'oklch(0.985 0 0)'\n },\n violet: {\n primary: resolvedDark ? 'oklch(0.606 0.25 292.717)' : 'oklch(0.541 0.281 293.009)',\n foreground: 'oklch(0.985 0 0)'\n },\n sky: {\n primary: resolvedDark ? 'oklch(0.672 0.154 238.29)' : 'oklch(0.588 0.158 241.966)',\n foreground: resolvedDark ? 'oklch(0.145 0 0)' : 'oklch(0.985 0 0)'\n },\n emerald: {\n primary: resolvedDark ? 'oklch(0.696 0.17 162.48)' : 'oklch(0.596 0.145 163.225)',\n foreground: resolvedDark ? 'oklch(0.145 0 0)' : 'oklch(0.985 0 0)'\n },\n zinc: {\n primary: resolvedDark ? 'oklch(0.985 0 0)' : 'oklch(0.205 0 0)',\n foreground: resolvedDark ? 'oklch(0.205 0 0)' : 'oklch(0.985 0 0)'\n }\n };\n\n if (accent && colorMap[accent]) {\n root.style.setProperty('--primary', colorMap[accent].primary);\n root.style.setProperty('--primary-foreground', colorMap[accent].foreground);\n }\n\n if (radius) {\n var radVal = radius.endsWith('rem') ? radius : radius + 'rem';\n root.style.setProperty('--radius', radVal);\n }\n}catch(e){}})();`;\n\n return <script innerHTML={scriptText} />;\n};",
31
+ "type": "registry:ui"
32
+ },
33
+ {
34
+ "path": "ui/theme-toggle.tsx",
35
+ "content": "import { splitProps, type Component, For, Show, type JSX } from \"solid-js\";\nimport { Sun, Moon, Monitor } from \"lucide-solid\";\nimport {\n useTheme,\n type AccentColor,\n type Radius,\n type Theme,\n} from \"../../providers/theme-provider\";\nimport {\n runThemeTransition,\n type ThemeEffect,\n} from \"../../providers/theme-transitions\";\nimport { Button, type ButtonProps } from \"./button\";\nimport {\n DropdownMenu,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuGroup,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n} from \"./dropdown-menu\";\nimport { cn } from \"@/lib/cn\";\n\nexport interface ThemeToggleProps\n extends Omit<JSX.ButtonHTMLAttributes<HTMLButtonElement>, \"onClick\"> {\n /** Display mode: \"button\" (direct 1-click toggle), \"mini\" (compact dropdown), \"max\" (full customizer panel). Defaults to \"mini\". */\n mode?: \"button\" | \"mini\" | \"max\";\n /** Transition animation effect when changing themes (\"none\", \"circular\", \"fade\") */\n effect?: ThemeEffect;\n /** Button visual style variant when rendered as a button or dropdown trigger */\n variant?: ButtonProps[\"variant\"];\n /** Button size */\n size?: ButtonProps[\"size\"];\n class?: string;\n}\n\nconst ACCENT_OPTIONS: { name: AccentColor; label: string; color: string }[] = [\n { name: \"yellow\", label: \"Yellow\", color: \"bg-yellow-500\" },\n { name: \"red\", label: \"Red\", color: \"bg-red-500\" },\n { name: \"violet\", label: \"Violet\", color: \"bg-violet-500\" },\n { name: \"sky\", label: \"Sky\", color: \"bg-sky-500\" },\n { name: \"emerald\", label: \"Emerald\", color: \"bg-emerald-500\" },\n { name: \"zinc\", label: \"Zinc\", color: \"bg-zinc-800 dark:bg-zinc-200\" },\n];\n\nconst RADIUS_OPTIONS: { value: Radius; label: string }[] = [\n { value: \"0\", label: \"0\" },\n { value: \"0.3\", label: \"0.3\" },\n { value: \"0.5\", label: \"0.5\" },\n { value: \"0.75\", label: \"0.75\" },\n { value: \"1.0\", label: \"1.0\" },\n];\n\n/**\n * Interactive UI theme switcher supporting button, mini (dropdown), and max (customizer panel) modes with View Transition animations.\n */\nexport const ThemeToggle: Component<ThemeToggleProps> = (props) => {\n const [local, rest] = splitProps(props, [\"mode\", \"effect\", \"variant\", \"size\", \"class\"]);\n const { theme, setTheme, accent, setAccent, radius, setRadius } = useTheme();\n\n const mode = () => local.mode || \"mini\";\n const effect = () => local.effect || \"none\";\n\n /* Reactive accessor determining whether dark mode is active */\n const isDarkMode = () => {\n const currentTheme = theme();\n if (currentTheme === \"dark\") return true;\n if (currentTheme === \"light\") return false;\n if (typeof window !== \"undefined\") {\n return window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n }\n return false;\n };\n\n const changeThemeWithEffect = (newTheme: Theme, e: MouseEvent) => {\n runThemeTransition(effect(), e, () => {\n setTheme(newTheme);\n });\n };\n\n const handleToggleClick = (e: MouseEvent) => {\n const nextTheme: Theme = isDarkMode() ? \"light\" : \"dark\";\n changeThemeWithEffect(nextTheme, e);\n };\n\n return (\n <Show\n when={mode() !== \"button\"}\n fallback={\n /* Button Mode: Direct 1-click Dark/Light switcher without dropdown */\n <Button\n variant={local.variant || \"ghost\"}\n size={local.size || \"icon\"}\n onClick={handleToggleClick}\n class={cn(\"relative cursor-pointer\", local.class)}\n aria-label=\"Toggle theme\"\n {...rest}\n >\n <Show\n when={isDarkMode()}\n fallback={<Sun class=\"h-4 w-4 text-foreground transition-transform\" />}\n >\n <Moon class=\"h-4 w-4 text-foreground transition-transform\" />\n </Show>\n <span class=\"sr-only\">Toggle theme</span>\n </Button>\n }\n >\n <DropdownMenu placement=\"bottom-end\">\n <DropdownMenuTrigger\n as={Button}\n variant={local.variant || \"ghost\"}\n size={local.size || \"icon\"}\n class={cn(\"relative cursor-pointer\", local.class)}\n {...rest}\n >\n {/* Reactive Sun / Moon Icon Toggle */}\n <Show\n when={isDarkMode()}\n fallback={<Sun class=\"h-4 w-4 text-foreground transition-transform\" />}\n >\n <Moon class=\"h-4 w-4 text-foreground transition-transform\" />\n </Show>\n <span class=\"sr-only\">Toggle theme</span>\n </DropdownMenuTrigger>\n\n <Show\n when={mode() === \"max\"}\n fallback={\n /* Mini Mode: Compact Dropdown */\n <DropdownMenuContent>\n <DropdownMenuItem onClick={(e: MouseEvent) => changeThemeWithEffect(\"light\", e)}>\n <Sun class=\"mr-2 h-4 w-4 text-muted-foreground\" />\n Light\n </DropdownMenuItem>\n\n <DropdownMenuItem onClick={(e: MouseEvent) => changeThemeWithEffect(\"dark\", e)}>\n <Moon class=\"mr-2 h-4 w-4 text-muted-foreground\" />\n Dark\n </DropdownMenuItem>\n\n <DropdownMenuItem onClick={(e: MouseEvent) => changeThemeWithEffect(\"system\", e)}>\n <Monitor class=\"mr-2 h-4 w-4 text-muted-foreground\" />\n System\n </DropdownMenuItem>\n </DropdownMenuContent>\n }\n >\n {/* Max Mode: Full Theme Customizer Panel */}\n <DropdownMenuContent class=\"w-64\">\n <div class=\"p-2 space-y-2\">\n <DropdownMenuGroup>\n <DropdownMenuLabel class=\"px-0 pt-0 text-xs font-semibold uppercase tracking-wider text-muted-foreground\">\n Theme Mode\n </DropdownMenuLabel>\n <div class=\"grid grid-cols-3 gap-1 my-1.5\">\n <Button\n variant={theme() === \"light\" ? \"default\" : \"outline\"}\n size=\"sm\"\n onClick={(e: MouseEvent) => changeThemeWithEffect(\"light\", e)}\n class=\"h-8 text-xs cursor-pointer\"\n >\n Light\n </Button>\n <Button\n variant={theme() === \"dark\" ? \"default\" : \"outline\"}\n size=\"sm\"\n onClick={(e: MouseEvent) => changeThemeWithEffect(\"dark\", e)}\n class=\"h-8 text-xs cursor-pointer\"\n >\n Dark\n </Button>\n <Button\n variant={theme() === \"system\" ? \"default\" : \"outline\"}\n size=\"sm\"\n onClick={(e: MouseEvent) => changeThemeWithEffect(\"system\", e)}\n class=\"h-8 text-xs cursor-pointer\"\n >\n System\n </Button>\n </div>\n </DropdownMenuGroup>\n\n <DropdownMenuSeparator class=\"my-2\" />\n\n <DropdownMenuGroup>\n <DropdownMenuLabel class=\"px-0 text-xs font-semibold uppercase tracking-wider text-muted-foreground\">\n Brand Accent Color\n </DropdownMenuLabel>\n <div class=\"flex flex-wrap gap-1.5 my-1.5\">\n <For each={ACCENT_OPTIONS}>\n {(opt) => (\n <button\n type=\"button\"\n title={opt.label}\n onClick={() => setAccent(opt.name)}\n class={cn(\n \"h-6 w-6 rounded-md transition-all cursor-pointer border border-border flex items-center justify-center\",\n opt.color,\n accent() === opt.name\n ? \"ring-2 ring-primary ring-offset-2 ring-offset-background scale-110\"\n : \"hover:scale-105\"\n )}\n />\n )}\n </For>\n </div>\n </DropdownMenuGroup>\n\n <DropdownMenuSeparator class=\"my-2\" />\n\n <DropdownMenuGroup>\n <DropdownMenuLabel class=\"px-0 text-xs font-semibold uppercase tracking-wider text-muted-foreground\">\n Border Radius\n </DropdownMenuLabel>\n <div class=\"grid grid-cols-5 gap-1 my-1.5\">\n <For each={RADIUS_OPTIONS}>\n {(r) => (\n <Button\n variant={radius() === r.value ? \"default\" : \"outline\"}\n size=\"sm\"\n onClick={() => setRadius(r.value)}\n class=\"h-7 text-xs px-1 cursor-pointer\"\n >\n {r.label}\n </Button>\n )}\n </For>\n </div>\n </DropdownMenuGroup>\n </div>\n </DropdownMenuContent>\n </Show>\n </DropdownMenu>\n </Show>\n );\n};",
36
+ "type": "registry:ui"
37
+ }
38
+ ]
39
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "timeline",
3
+ "title": "Timeline",
4
+ "description": "A responsive chronological display for event streams, activity logs, order tracking, and multi-step workflows.",
5
+ "type": "registry:ui",
6
+ "dependencies": [
7
+ "clsx",
8
+ "tailwind-merge",
9
+ "class-variance-authority"
10
+ ],
11
+ "files": [
12
+ {
13
+ "path": "ui/timeline.tsx",
14
+ "content": "import {\n createContext,\n useContext,\n splitProps,\n type Component,\n type JSX,\n type Accessor,\n} from \"solid-js\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"@/lib/cn\";\n\n/* --- Timeline Context --- */\ninterface TimelineContextValue {\n orientation: Accessor<\"vertical\" | \"horizontal\">;\n align: Accessor<\"left\" | \"right\" | \"alternate\">;\n size: Accessor<\"sm\" | \"default\" | \"lg\">;\n}\n\nconst TimelineContext = createContext<TimelineContextValue>();\n\nexport interface TimelineProps extends JSX.HTMLAttributes<HTMLOListElement> {\n /** Layout orientation of the timeline */\n orientation?: \"vertical\" | \"horizontal\";\n /** Alignment of content relative to the timeline line */\n align?: \"left\" | \"right\" | \"alternate\";\n /** Sizing of dots and spacing */\n size?: \"sm\" | \"default\" | \"lg\";\n class?: string;\n children?: JSX.Element;\n}\n\n/**\n * Root container for chronological timeline event sequences.\n */\nexport const Timeline: Component<TimelineProps> = (props) => {\n const [local, rest] = splitProps(props, [\n \"orientation\",\n \"align\",\n \"size\",\n \"class\",\n \"children\",\n ]);\n\n const orientation = () => local.orientation ?? \"vertical\";\n const align = () => local.align ?? \"left\";\n const size = () => local.size ?? \"default\";\n\n const contextValue: TimelineContextValue = {\n orientation,\n align,\n size,\n };\n\n return (\n <TimelineContext.Provider value={contextValue}>\n <ol\n role=\"list\"\n data-orientation={orientation()}\n data-align={align()}\n class={cn(\n \"relative flex\",\n orientation() === \"vertical\"\n ? \"flex-col w-full\"\n : \"flex-row w-full items-start\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </ol>\n </TimelineContext.Provider>\n );\n};\n\n/* --- Timeline Item --- */\nexport interface TimelineItemProps extends JSX.HTMLAttributes<HTMLLIElement> {\n class?: string;\n children?: JSX.Element;\n}\n\n/**\n * Individual event row container in the timeline.\n */\nexport const TimelineItem: Component<TimelineItemProps> = (props) => {\n const context = useContext(TimelineContext);\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n const isVertical = () => !context || context.orientation() === \"vertical\";\n const align = () => context?.align() ?? \"left\";\n\n return (\n <li\n class={cn(\n \"group relative flex\",\n isVertical()\n ? \"min-h-[3.5rem] w-full items-start\"\n : \"flex-1 min-w-0 flex-col items-start\",\n isVertical() && align() === \"right\" && \"flex-row-reverse\",\n isVertical() && align() === \"alternate\" && \"[&:nth-child(even)]:flex-row-reverse\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </li>\n );\n};\n\n/* --- Timeline Separator (Dot + Connector wrapper) --- */\nexport interface TimelineSeparatorProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const TimelineSeparator: Component<TimelineSeparatorProps> = (props) => {\n const context = useContext(TimelineContext);\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n const isVertical = () => !context || context.orientation() === \"vertical\";\n\n return (\n <div\n aria-hidden=\"true\"\n class={cn(\n \"flex shrink-0 relative\",\n isVertical()\n ? \"flex-col items-center self-stretch\"\n : \"flex-row items-center w-full\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </div>\n );\n};\n\n/* --- Timeline Point / Dot --- */\nexport const timelinePointVariants = cva(\n \"relative z-10 flex shrink-0 items-center justify-center rounded-lg font-medium transition-all shadow-xs\",\n {\n variants: {\n variant: {\n default: \"border-2 bg-background\",\n solid: \"text-primary-foreground\",\n subtle: \"bg-muted text-muted-foreground\",\n outline: \"border-2 border-border bg-card text-foreground\",\n },\n status: {\n default: \"border-border text-foreground bg-card\",\n primary: \"border-primary bg-primary text-primary-foreground\",\n success: \"border-emerald-500 bg-emerald-500 text-white dark:border-emerald-400 dark:bg-emerald-400\",\n warning: \"border-amber-500 bg-amber-500 text-white dark:border-amber-400 dark:bg-amber-400\",\n destructive: \"border-destructive bg-destructive text-destructive-foreground\",\n muted: \"border-border/60 bg-muted text-muted-foreground\",\n },\n size: {\n sm: \"size-5 text-[10px] [&_svg]:size-3\",\n default: \"size-8 text-xs [&_svg]:size-4\",\n lg: \"size-10 text-sm [&_svg]:size-5\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n status: \"default\",\n size: \"default\",\n },\n }\n);\n\nexport interface TimelinePointProps\n extends JSX.HTMLAttributes<HTMLDivElement>,\n VariantProps<typeof timelinePointVariants> {\n class?: string;\n children?: JSX.Element;\n}\n\n/**\n * Status indicator node or icon container in the timeline separator.\n */\nexport const TimelinePoint: Component<TimelinePointProps> = (props) => {\n const context = useContext(TimelineContext);\n const [local, rest] = splitProps(props, [\n \"variant\",\n \"status\",\n \"size\",\n \"class\",\n \"children\",\n ]);\n\n const size = () => local.size || context?.size() || \"default\";\n\n return (\n <div\n class={cn(\n timelinePointVariants({\n variant: local.variant,\n status: local.status,\n size: size(),\n }),\n local.class\n )}\n {...rest}\n >\n {local.children}\n </div>\n );\n};\n\n/* --- Timeline Connector (Line track) --- */\nexport interface TimelineConnectorProps extends JSX.HTMLAttributes<HTMLDivElement> {\n dashed?: boolean;\n class?: string;\n}\n\n/**\n * Line track connecting sequential timeline items.\n */\nexport const TimelineConnector: Component<TimelineConnectorProps> = (props) => {\n const context = useContext(TimelineContext);\n const [local, rest] = splitProps(props, [\"dashed\", \"class\"]);\n\n const isVertical = () => !context || context.orientation() === \"vertical\";\n\n return (\n <div\n aria-hidden=\"true\"\n class={cn(\n \"transition-colors group-last:hidden\",\n isVertical()\n ? \"w-0.5 flex-1 min-h-6 my-1 bg-border\"\n : \"h-0.5 flex-1 min-w-4 mx-2 bg-border\",\n local.dashed && (\n isVertical()\n ? \"border-l-2 border-dashed border-border bg-transparent w-0\"\n : \"border-t-2 border-dashed border-border bg-transparent h-0\"\n ),\n local.class\n )}\n {...rest}\n />\n );\n};\n\n/* --- Timeline Content (Event Details) --- */\nexport interface TimelineContentProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\n/**\n * Primary container holding the description, title, and body for a timeline event.\n */\nexport const TimelineContent: Component<TimelineContentProps> = (props) => {\n const context = useContext(TimelineContext);\n const [local, rest] = splitProps(props, [\"class\"]);\n\n const isVertical = () => !context || context.orientation() === \"vertical\";\n const align = () => context?.align() ?? \"left\";\n\n return (\n <div\n class={cn(\n \"flex flex-col\",\n isVertical() ? \"flex-1 pb-6 pt-0.5\" : \"pt-2 pr-2 text-left\",\n isVertical() && align() === \"left\" && \"text-left pl-3.5 pr-0\",\n isVertical() && align() === \"right\" && \"text-right pr-3.5 pl-0\",\n isVertical() && align() === \"alternate\" && \"text-left pl-3.5 group-even:text-right group-even:pr-3.5 group-even:pl-0\",\n local.class\n )}\n {...rest}\n />\n );\n};\n\n/* --- Timeline Opposite Content --- */\nexport interface TimelineOppositeContentProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\n/**\n * Content placed on the opposite side of the timeline separator (e.g. timestamps in alternate layouts).\n */\nexport const TimelineOppositeContent: Component<TimelineOppositeContentProps> = (props) => {\n const context = useContext(TimelineContext);\n const [local, rest] = splitProps(props, [\"class\"]);\n\n const isVertical = () => !context || context.orientation() === \"vertical\";\n const align = () => context?.align() ?? \"left\";\n\n return (\n <div\n class={cn(\n \"flex flex-col text-xs text-muted-foreground\",\n align() !== \"alternate\" && \"hidden\",\n isVertical()\n ? \"flex-1 pb-6 pt-1 text-right pr-3.5 group-even:text-left group-even:pl-3.5 group-even:pr-0\"\n : \"pb-1 pr-2\",\n local.class\n )}\n {...rest}\n />\n );\n};\n\n/* --- Timeline Title --- */\nexport interface TimelineTitleProps extends JSX.HTMLAttributes<HTMLHeadingElement> {\n class?: string;\n}\n\nexport const TimelineTitle: Component<TimelineTitleProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n\n return (\n <h4\n class={cn(\"text-sm font-semibold tracking-tight text-foreground\", local.class)}\n {...rest}\n />\n );\n};\n\n/* --- Timeline Description --- */\nexport interface TimelineDescriptionProps extends JSX.HTMLAttributes<HTMLParagraphElement> {\n class?: string;\n}\n\nexport const TimelineDescription: Component<TimelineDescriptionProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n\n return (\n <p\n class={cn(\"mt-1 text-sm text-muted-foreground\", local.class)}\n {...rest}\n />\n );\n};\n\n/* --- Timeline Time --- */\nexport interface TimelineTimeProps extends JSX.HTMLAttributes<HTMLTimeElement> {\n class?: string;\n}\n\nexport const TimelineTime: Component<TimelineTimeProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n\n return (\n <time\n class={cn(\"text-xs font-medium text-muted-foreground/80\", local.class)}\n {...rest}\n />\n );\n};\n",
15
+ "type": "registry:ui"
16
+ }
17
+ ]
18
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "titlebar-tabs",
3
+ "title": "Titlebar Tabs",
4
+ "description": "Native draggable tab bar integrated directly inside desktop titlebars for multi-document applications.",
5
+ "type": "registry:ui",
6
+ "dependencies": [
7
+ "clsx",
8
+ "tailwind-merge",
9
+ "class-variance-authority",
10
+ "lucide-solid"
11
+ ],
12
+ "registryDependencies": [
13
+ "button",
14
+ "tooltip",
15
+ "create-document-tabs"
16
+ ],
17
+ "files": [
18
+ {
19
+ "path": "ui/titlebar-tabs.tsx",
20
+ "content": "import {\n createContext,\n useContext,\n splitProps,\n createSignal,\n createEffect,\n onMount,\n onCleanup,\n Show,\n For,\n type Component,\n type JSX,\n type ParentComponent,\n type Accessor,\n} from \"solid-js\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { Plus, X, Pin, XCircle, CircleX } from \"lucide-solid\";\nimport * as ContextMenuPrimitive from \"@kobalte/core/context-menu\";\nimport { Button } from \"@/components/ui/button\";\nimport { Tooltip, TooltipTrigger, TooltipContent } from \"@/components/ui/tooltip\";\nimport {\n type CreateDocumentTabsReturn,\n type TabItem,\n} from \"@/hooks/create-document-tabs\";\nimport { cn } from \"@/lib/cn\";\n\n/* --- 1. Context & Variants --- */\n\nexport type TitlebarTabsVariant = \"editor\" | \"chrome\" | \"pills\";\n\ninterface TitlebarTabsContextValue {\n value: Accessor<string | undefined>;\n setValue: (value: string) => void;\n variant: Accessor<TitlebarTabsVariant>;\n manager?: CreateDocumentTabsReturn<any>;\n reorderable?: boolean;\n enableContextMenu?: boolean;\n draggedTabId: Accessor<string | null>;\n dropTargetId: Accessor<string | null>;\n dropPosition: Accessor<\"left\" | \"right\" | null>;\n setDragState: (draggedId: string | null, targetId: string | null, position: \"left\" | \"right\" | null) => void;\n handleDropReorder: (sourceId: string, targetId: string, position: \"left\" | \"right\") => void;\n}\n\nconst TitlebarTabsContext = createContext<TitlebarTabsContextValue>();\n\nexport function useTitlebarTabs() {\n const ctx = useContext(TitlebarTabsContext);\n if (!ctx) {\n throw new Error(\"useTitlebarTabs must be used within a <TitlebarTabs /> container\");\n }\n return ctx;\n}\n\nexport const titlebarTabVariants = cva(\n \"group relative inline-flex items-center gap-1.5 px-3 text-xs font-medium select-none cursor-pointer transition-colors shrink-0 max-w-[180px] min-w-[80px]\",\n {\n variants: {\n variant: {\n editor:\n \"h-full py-1 border-r border-border/40 border-t-2 border-t-transparent hover:bg-muted/40 data-[active=true]:bg-background data-[active=true]:border-t-primary data-[active=true]:text-foreground data-[active=false]:text-muted-foreground\",\n chrome:\n \"h-[calc(100%-2px)] py-1 rounded-t-lg border-t border-x border-transparent hover:bg-muted/60 data-[active=true]:border-border/70 data-[active=true]:bg-background data-[active=true]:text-foreground data-[active=true]:-mb-px data-[active=true]:shadow-xs data-[active=false]:text-muted-foreground\",\n pills:\n \"h-7 py-0.5 rounded-md mx-0.5 hover:bg-muted/50 data-[active=true]:bg-primary/10 data-[active=true]:text-primary data-[active=true]:font-semibold data-[active=false]:text-muted-foreground\",\n },\n },\n defaultVariants: {\n variant: \"editor\",\n },\n }\n);\n\n/* --- 2. TitlebarTabs Root Container --- */\n\nexport interface TitlebarTabsProps extends JSX.HTMLAttributes<HTMLElement> {\n /** Reactive tabs manager instance from createDocumentTabs(). */\n manager?: CreateDocumentTabsReturn<any>;\n /** Controlled active tab identifier value (when not using manager). */\n value?: string;\n /** Uncontrolled default active tab identifier value. */\n defaultValue?: string;\n /** Callback triggered when active tab changes. */\n onValueChange?: (value: string) => void;\n /** Callback triggered when the \"+\" add tab button is clicked. */\n onAddTab?: () => void;\n /** Whether tabs can be reordered via Drag & Drop. Defaults to true when manager is present. */\n reorderable?: boolean;\n /** Whether right-click context menu is enabled on tabs and empty space. Defaults to true. */\n enableContextMenu?: boolean;\n /** Custom render function for the empty tabstrip context menu. */\n renderEmptyContextMenu?: () => JSX.Element;\n /** Visual chrome styling variant. */\n variant?: TitlebarTabsVariant;\n class?: string;\n}\n\nexport const TitlebarTabs: ParentComponent<TitlebarTabsProps> = (props) => {\n const [local, rest] = splitProps(props, [\n \"manager\",\n \"value\",\n \"defaultValue\",\n \"onValueChange\",\n \"onAddTab\",\n \"reorderable\",\n \"enableContextMenu\",\n \"renderEmptyContextMenu\",\n \"variant\",\n \"class\",\n \"children\",\n ]);\n\n let scrollContainerRef: HTMLDivElement | undefined;\n\n const [internalValue, setInternalValue] = createSignal(local.defaultValue || local.value);\n const [draggedTabId, setDraggedTabId] = createSignal<string | null>(null);\n const [dropTargetId, setDropTargetId] = createSignal<string | null>(null);\n const [dropPosition, setDropPosition] = createSignal<\"left\" | \"right\" | null>(null);\n\n const activeValue = () => {\n if (local.manager) return local.manager.activeTabId();\n return local.value !== undefined ? local.value : internalValue();\n };\n\n const variant = () => local.variant || \"editor\";\n\n const setValue = (val: string) => {\n if (local.manager) {\n local.manager.setActiveTab(val);\n } else {\n setInternalValue(val);\n local.onValueChange?.(val);\n }\n };\n\n const setDragState = (\n draggedId: string | null,\n targetId: string | null,\n pos: \"left\" | \"right\" | null\n ) => {\n setDraggedTabId(draggedId);\n setDropTargetId(targetId);\n setDropPosition(pos);\n };\n\n const handleDropReorder = (sourceId: string, targetId: string, pos: \"left\" | \"right\") => {\n if (!local.manager) return;\n const list = local.manager.tabs();\n const fromIndex = list.findIndex((t) => t.id === sourceId);\n const targetIndex = list.findIndex((t) => t.id === targetId);\n if (fromIndex === -1 || targetIndex === -1 || fromIndex === targetIndex) return;\n\n let finalIndex = targetIndex;\n if (fromIndex < targetIndex && pos === \"left\") {\n finalIndex = targetIndex - 1;\n } else if (fromIndex > targetIndex && pos === \"right\") {\n finalIndex = targetIndex + 1;\n }\n\n if (fromIndex !== finalIndex && finalIndex >= 0 && finalIndex < list.length) {\n local.manager.reorderTabs(fromIndex, finalIndex);\n }\n };\n\n // Mouse wheel horizontal scroll listener (converts vertical wheel deltaY to horizontal scroll)\n onMount(() => {\n if (!scrollContainerRef) return;\n\n const handleWheel = (e: WheelEvent) => {\n if (e.deltaY !== 0) {\n e.preventDefault();\n scrollContainerRef!.scrollLeft += e.deltaY;\n }\n };\n\n scrollContainerRef.addEventListener(\"wheel\", handleWheel, { passive: false });\n onCleanup(() => {\n scrollContainerRef?.removeEventListener(\"wheel\", handleWheel);\n });\n });\n\n // Auto-scroll to end when tabs are added\n createEffect(() => {\n if (local.manager?.count() && scrollContainerRef) {\n scrollContainerRef.scrollTo({\n left: scrollContainerRef.scrollWidth,\n behavior: \"smooth\",\n });\n }\n });\n\n const contextValue: TitlebarTabsContextValue = {\n value: activeValue,\n setValue,\n variant,\n manager: local.manager,\n reorderable: local.reorderable ?? Boolean(local.manager),\n enableContextMenu: local.enableContextMenu ?? true,\n draggedTabId,\n dropTargetId,\n dropPosition,\n setDragState,\n handleDropReorder,\n };\n\n const hasEmptyContextMenu = () =>\n (local.enableContextMenu ?? true) &&\n (Boolean(local.onAddTab) || Boolean(local.manager) || Boolean(local.renderEmptyContextMenu));\n\n const renderNavContent = () => (\n <nav\n aria-label=\"Window Tabs\"\n class={cn(\n \"flex flex-1 h-full overflow-hidden z-10 min-w-0 pointer-events-auto [app-region:drag] [-webkit-app-region:drag]\",\n variant() === \"chrome\" ? \"items-end\" : \"items-center\",\n local.class\n )}\n {...rest}\n >\n <Show\n when={local.children}\n fallback={\n /* Automatic Declarative Mode: Tab List with Mouse Wheel Scroll + Anchored Add Button */\n <>\n <div\n ref={scrollContainerRef}\n class={cn(\n \"flex h-full overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] gap-0 items-center min-w-0 flex-1 scroll-smooth [app-region:drag] [-webkit-app-region:drag]\",\n variant() === \"chrome\" && \"items-end pt-1.5\"\n )}\n >\n <Show when={local.manager}>\n <For each={local.manager!.tabs()}>\n {(tab) => <TitlebarTab tab={tab} />}\n </For>\n </Show>\n </div>\n\n {/* Anchored Add Tab Button (Always visible outside scroll container) */}\n <Show when={local.onAddTab}>\n <div class={cn(\"shrink-0 px-1 z-20 flex items-center\", variant() === \"chrome\" ? \"mb-1\" : \"my-auto\")}>\n <TitlebarTabAddButton onClick={local.onAddTab} />\n </div>\n </Show>\n </>\n }\n >\n {local.children}\n </Show>\n </nav>\n );\n\n return (\n <TitlebarTabsContext.Provider value={contextValue}>\n <Show when={hasEmptyContextMenu()} fallback={renderNavContent()}>\n <ContextMenuPrimitive.Root>\n <ContextMenuPrimitive.Trigger\n as=\"div\"\n style={(\"-webkit-app-region: no-drag; app-region: no-drag; outline: none !important; -webkit-focus-ring-color: transparent !important;\") as any}\n class=\"flex flex-1 h-full min-w-0 outline-none ring-0 focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0\"\n >\n {renderNavContent()}\n </ContextMenuPrimitive.Trigger>\n <ContextMenuPrimitive.Portal>\n <ContextMenuPrimitive.Content\n data-no-drag\n data-tauri-drag-region=\"false\"\n style=\"-webkit-app-region: no-drag; app-region: no-drag; outline: none !important; -webkit-focus-ring-color: transparent !important;\"\n onMouseDown={(e) => e.stopPropagation()}\n onPointerDown={(e) => e.stopPropagation()}\n class={cn(\n \"z-50 min-w-[160px] overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md\",\n \"animate-in fade-in-80 slide-in-from-top-1 text-xs pointer-events-auto [app-region:no-drag] [-webkit-app-region:no-drag]\",\n \"outline-none ring-0 focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0\"\n )}\n >\n <Show\n when={local.renderEmptyContextMenu}\n fallback={\n <>\n <Show when={local.onAddTab}>\n <ContextMenuPrimitive.Item\n data-no-drag\n data-tauri-drag-region=\"false\"\n style=\"-webkit-app-region: no-drag; app-region: no-drag;\"\n onMouseDown={(e) => e.stopPropagation()}\n onPointerDown={(e) => e.stopPropagation()}\n onSelect={() => {\n setTimeout(() => local.onAddTab?.(), 0);\n }}\n class=\"relative flex cursor-pointer select-none items-center justify-between gap-2 rounded-xs px-2 py-1.5 text-xs outline-none transition-colors hover:bg-accent hover:text-accent-foreground pointer-events-auto [app-region:no-drag] [-webkit-app-region:no-drag]\"\n >\n <span class=\"flex items-center gap-2\">\n <Plus class=\"size-3.5 text-muted-foreground\" />\n New Tab\n </span>\n <span class=\"ml-auto text-[10px] text-muted-foreground font-mono\">Ctrl+T</span>\n </ContextMenuPrimitive.Item>\n </Show>\n\n <Show when={local.manager && local.manager.tabs().length > 0}>\n <Show when={local.onAddTab}>\n <ContextMenuPrimitive.Separator class=\"my-1 h-px bg-border/60\" />\n </Show>\n <ContextMenuPrimitive.Item\n data-no-drag\n data-tauri-drag-region=\"false\"\n style=\"-webkit-app-region: no-drag; app-region: no-drag;\"\n onMouseDown={(e) => e.stopPropagation()}\n onPointerDown={(e) => e.stopPropagation()}\n onSelect={() => {\n setTimeout(() => local.manager?.closeAll(), 0);\n }}\n class=\"relative flex cursor-pointer select-none items-center gap-2 rounded-xs px-2 py-1.5 text-xs outline-none transition-colors hover:bg-accent hover:text-accent-foreground pointer-events-auto [app-region:no-drag] [-webkit-app-region:no-drag]\"\n >\n <CircleX class=\"size-3.5 text-muted-foreground\" />\n <span>Close All Tabs</span>\n </ContextMenuPrimitive.Item>\n </Show>\n </>\n }\n >\n {local.renderEmptyContextMenu!()}\n </Show>\n </ContextMenuPrimitive.Content>\n </ContextMenuPrimitive.Portal>\n </ContextMenuPrimitive.Root>\n </Show>\n </TitlebarTabsContext.Provider>\n );\n};\n\n/* --- 3. TitlebarTabList --- */\n\nexport interface TitlebarTabListProps extends JSX.HTMLAttributes<HTMLDivElement> {\n class?: string;\n}\n\nexport const TitlebarTabList: ParentComponent<TitlebarTabListProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n const ctx = useTitlebarTabs();\n let listRef: HTMLDivElement | undefined;\n\n onMount(() => {\n if (!listRef) return;\n const handleWheel = (e: WheelEvent) => {\n if (e.deltaY !== 0) {\n e.preventDefault();\n listRef!.scrollLeft += e.deltaY;\n }\n };\n listRef.addEventListener(\"wheel\", handleWheel, { passive: false });\n onCleanup(() => listRef?.removeEventListener(\"wheel\", handleWheel));\n });\n\n return (\n <div\n ref={listRef}\n class={cn(\n \"flex h-full overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] gap-0 items-center min-w-0 flex-1 scroll-smooth [app-region:drag] [-webkit-app-region:drag]\",\n ctx.variant() === \"chrome\" && \"items-end pt-1.5\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </div>\n );\n};\n\n/* --- 4. TitlebarTab Individual Item --- */\n\nexport interface TitlebarTabProps extends Omit<JSX.HTMLAttributes<HTMLDivElement>, \"onClose\"> {\n /** Tab data object from createDocumentTabs(). Automatically wires all properties. */\n tab?: TabItem<any>;\n value?: string;\n isDirty?: boolean;\n isPinned?: boolean;\n closable?: boolean;\n reorderable?: boolean;\n /** Whether right-click context menu is enabled on this tab. Defaults to true. */\n enableContextMenu?: boolean;\n /** Custom render function for context menu content. */\n renderContextMenu?: (tab: TabItem<any>) => JSX.Element;\n onClose?: (e: MouseEvent) => void;\n class?: string;\n}\n\nexport const TitlebarTab: ParentComponent<TitlebarTabProps> = (props) => {\n const [local, rest] = splitProps(props, [\n \"tab\",\n \"value\",\n \"isDirty\",\n \"isPinned\",\n \"closable\",\n \"reorderable\",\n \"enableContextMenu\",\n \"renderContextMenu\",\n \"onClose\",\n \"class\",\n \"style\",\n \"children\",\n \"onClick\",\n \"onKeyDown\",\n \"onDragStart\",\n \"onDragOver\",\n \"onDragLeave\",\n \"onDragEnd\",\n \"onDrop\",\n ]);\n\n const ctx = useTitlebarTabs();\n let tabRef: HTMLDivElement | undefined;\n\n const tabId = () => local.tab?.id || local.value || \"\";\n const isPinned = () => local.tab?.isPinned ?? local.isPinned ?? false;\n const isDirty = () => local.tab?.isDirty ?? local.isDirty ?? false;\n const closable = () => local.tab?.closable ?? local.closable ?? true;\n const title = () => local.tab?.title || \"\";\n const IconComp = () => local.tab?.icon;\n\n const isActive = () => ctx.value() === tabId();\n const isDragging = () => ctx.draggedTabId() === tabId();\n const isDropTarget = () => ctx.dropTargetId() === tabId() && ctx.draggedTabId() !== tabId();\n const dropPosition = () => (isDropTarget() ? ctx.dropPosition() : null);\n\n const canDrag = () => !isPinned() && (local.reorderable ?? ctx.reorderable ?? true);\n const hasContextMenu = () =>\n (local.enableContextMenu ?? ctx.enableContextMenu ?? true) &&\n (Boolean(ctx.manager) || Boolean(local.renderContextMenu));\n\n // Scroll active tab horizontally inside its tablist container\n createEffect(() => {\n if (typeof window !== \"undefined\" && isActive() && tabRef && tabRef.parentElement) {\n try {\n const container = tabRef.parentElement;\n const tabLeft = tabRef.offsetLeft;\n const tabRight = tabLeft + tabRef.offsetWidth;\n const containerLeft = container.scrollLeft;\n const containerRight = containerLeft + container.clientWidth;\n\n if (tabLeft < containerLeft) {\n container.scrollTo({ left: tabLeft, behavior: \"smooth\" });\n } else if (tabRight > containerRight) {\n container.scrollTo({ left: tabRight - container.clientWidth, behavior: \"smooth\" });\n }\n } catch {\n // Safe fallback\n }\n }\n });\n\n const handleClick = (e: MouseEvent) => {\n ctx.setValue(tabId());\n if (typeof local.onClick === \"function\") {\n (local.onClick as any)(e);\n }\n };\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n ctx.setValue(tabId());\n }\n if (typeof (local as any).onKeyDown === \"function\") {\n ((local as any).onKeyDown)(e);\n }\n };\n\n const handleClose = (e: MouseEvent) => {\n e.stopPropagation();\n if (local.onClose) {\n local.onClose(e);\n } else if (ctx.manager) {\n ctx.manager.closeTab(tabId());\n }\n };\n\n const handleDragStart: JSX.EventHandlerUnion<HTMLDivElement, DragEvent> = (e) => {\n if (!canDrag()) {\n e.preventDefault();\n return;\n }\n if (e.dataTransfer) {\n e.dataTransfer.setData(\"text/plain\", tabId());\n e.dataTransfer.effectAllowed = \"move\";\n }\n ctx.setDragState(tabId(), null, null);\n if (typeof local.onDragStart === \"function\") {\n (local.onDragStart as any)(e);\n }\n };\n\n const handleDragOver: JSX.EventHandlerUnion<HTMLDivElement, DragEvent> = (e) => {\n const currentDragged = ctx.draggedTabId();\n if (!currentDragged || currentDragged === tabId() || isPinned()) return;\n\n e.preventDefault();\n if (e.dataTransfer) {\n e.dataTransfer.dropEffect = \"move\";\n }\n\n if (tabRef) {\n const rect = tabRef.getBoundingClientRect();\n const midpoint = rect.left + rect.width / 2;\n const pos: \"left\" | \"right\" = e.clientX < midpoint ? \"left\" : \"right\";\n ctx.setDragState(currentDragged, tabId(), pos);\n }\n\n if (typeof local.onDragOver === \"function\") {\n (local.onDragOver as any)(e);\n }\n };\n\n const handleDragLeave: JSX.EventHandlerUnion<HTMLDivElement, DragEvent> = (e) => {\n if (tabRef && !tabRef.contains(e.relatedTarget as Node)) {\n if (ctx.dropTargetId() === tabId()) {\n ctx.setDragState(ctx.draggedTabId(), null, null);\n }\n }\n if (typeof local.onDragLeave === \"function\") {\n (local.onDragLeave as any)(e);\n }\n };\n\n const handleDragEnd: JSX.EventHandlerUnion<HTMLDivElement, DragEvent> = (e) => {\n ctx.setDragState(null, null, null);\n if (typeof local.onDragEnd === \"function\") {\n (local.onDragEnd as any)(e);\n }\n };\n\n const handleDrop: JSX.EventHandlerUnion<HTMLDivElement, DragEvent> = (e) => {\n e.preventDefault();\n const sourceId = e.dataTransfer?.getData(\"text/plain\") || ctx.draggedTabId();\n const pos = ctx.dropPosition();\n if (sourceId && pos && sourceId !== tabId()) {\n ctx.handleDropReorder(sourceId, tabId(), pos);\n }\n ctx.setDragState(null, null, null);\n if (typeof local.onDrop === \"function\") {\n (local.onDrop as any)(e);\n }\n };\n\n const renderTabElement = () => (\n <div\n ref={tabRef}\n role=\"tab\"\n tabindex=\"0\"\n aria-selected={isActive()}\n draggable={canDrag()}\n onDragStart={handleDragStart}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onDragEnd={handleDragEnd}\n onDrop={handleDrop}\n data-no-drag\n data-tauri-drag-region=\"false\"\n style={(\"-webkit-app-region: no-drag; app-region: no-drag;\" + (typeof local.style === \"string\" ? ` ${local.style}` : \"\")) as any}\n data-active={isActive() ? \"true\" : \"false\"}\n data-dragging={isDragging() ? \"true\" : undefined}\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n class={cn(\n titlebarTabVariants({ variant: ctx.variant() }),\n isPinned() && \"min-w-fit px-2 max-w-fit\",\n isDragging() && \"opacity-40 scale-95\",\n dropPosition() === \"left\" &&\n \"before:absolute before:left-0 before:top-1 before:bottom-1 before:w-0.5 before:bg-primary before:z-30 before:rouded-lg\",\n dropPosition() === \"right\" &&\n \"after:absolute after:right-0 after:top-1 after:bottom-1 after:w-0.5 after:bg-primary after:z-30 after:rouded-lg\",\n \"cursor-pointer outline-none ring-0 focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0 [app-region:no-drag] [-webkit-app-region:no-drag] pointer-events-auto transition-all duration-150\",\n local.class\n )}\n {...rest}\n >\n {/* Tab Icon & Title Slot */}\n <span class=\"flex items-center gap-1.5 truncate flex-1 pointer-events-none\">\n <Show when={IconComp()}>\n {(() => {\n const Comp = IconComp()!;\n return <Comp class=\"size-3.5 shrink-0 text-primary\" />;\n })()}\n </Show>\n <Show when={local.children} fallback={<span class=\"truncate\">{title()}</span>}>\n {local.children}\n </Show>\n </span>\n\n {/* Pinned Tab Badge */}\n <Show when={isPinned()}>\n <Pin class=\"size-2.5 text-muted-foreground rotate-45 shrink-0\" />\n </Show>\n\n {/* Close Button / Dirty Dot Indicator using Nikala UI Button */}\n <Show when={!isPinned() && closable()}>\n <Tooltip>\n <TooltipTrigger\n as={Button}\n variant=\"ghost\"\n size=\"icon\"\n onClick={handleClose}\n aria-label={`Close ${tabId()} tab`}\n class=\"size-4 p-0 rounded-xs text-muted-foreground hover:bg-muted hover:text-foreground shrink-0 ml-0.5 cursor-pointer outline-none ring-0 focus:ring-0 focus-visible:ring-0\"\n >\n <Show\n when={isDirty()}\n fallback={<X class=\"size-3 opacity-60 hover:opacity-100\" />}\n >\n <span class=\"size-1.5 rouded-lg bg-primary group-hover:hidden\" />\n <X class=\"size-3 hidden group-hover:block\" />\n </Show>\n </TooltipTrigger>\n <TooltipContent class=\"text-[10px] py-1 px-2\">\n Close tab (Ctrl+W)\n </TooltipContent>\n </Tooltip>\n </Show>\n </div>\n );\n\n return (\n <Show when={hasContextMenu()} fallback={renderTabElement()}>\n <ContextMenuPrimitive.Root>\n <ContextMenuPrimitive.Trigger\n as=\"div\"\n data-no-drag\n data-tauri-drag-region=\"false\"\n style={(\"-webkit-app-region: no-drag; app-region: no-drag; outline: none !important; -webkit-focus-ring-color: transparent !important;\" + (typeof local.style === \"string\" ? ` ${local.style}` : \"\")) as any}\n class=\"h-full flex items-center shrink-0 pointer-events-auto [app-region:no-drag] [-webkit-app-region:no-drag] outline-none ring-0 focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0\"\n >\n {renderTabElement()}\n </ContextMenuPrimitive.Trigger>\n <ContextMenuPrimitive.Portal>\n <ContextMenuPrimitive.Content\n data-no-drag\n data-tauri-drag-region=\"false\"\n style=\"-webkit-app-region: no-drag; app-region: no-drag; outline: none !important; -webkit-focus-ring-color: transparent !important;\"\n onMouseDown={(e) => e.stopPropagation()}\n onPointerDown={(e) => e.stopPropagation()}\n class={cn(\n \"z-50 min-w-[170px] overflow-hidden rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md\",\n \"animate-in fade-in-80 slide-in-from-top-1 text-xs pointer-events-auto [app-region:no-drag] [-webkit-app-region:no-drag]\",\n \"outline-none ring-0 focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0\"\n )}\n >\n <Show\n when={local.renderContextMenu}\n fallback={\n <>\n <Show when={ctx.manager}>\n <ContextMenuPrimitive.Item\n data-no-drag\n data-tauri-drag-region=\"false\"\n style=\"-webkit-app-region: no-drag; app-region: no-drag;\"\n onMouseDown={(e) => e.stopPropagation()}\n onPointerDown={(e) => e.stopPropagation()}\n onSelect={() => {\n setTimeout(() => ctx.manager?.togglePin(tabId()), 0);\n }}\n class=\"relative flex cursor-pointer select-none items-center gap-2 rounded-xs px-2 py-1.5 text-xs outline-none transition-colors hover:bg-accent hover:text-accent-foreground pointer-events-auto [app-region:no-drag] [-webkit-app-region:no-drag]\"\n >\n <Pin class=\"size-3.5 text-muted-foreground\" />\n <span>{isPinned() ? \"Unpin Tab\" : \"Pin Tab\"}</span>\n </ContextMenuPrimitive.Item>\n <ContextMenuPrimitive.Separator class=\"my-1 h-px bg-border/60\" />\n </Show>\n\n <ContextMenuPrimitive.Item\n data-no-drag\n data-tauri-drag-region=\"false\"\n style=\"-webkit-app-region: no-drag; app-region: no-drag;\"\n onMouseDown={(e) => e.stopPropagation()}\n onPointerDown={(e) => e.stopPropagation()}\n disabled={isPinned() || !closable()}\n onSelect={() => {\n setTimeout(() => {\n if (local.onClose) local.onClose(new MouseEvent(\"click\"));\n else ctx.manager?.closeTab(tabId());\n }, 0);\n }}\n class=\"relative flex cursor-pointer select-none items-center justify-between gap-2 rounded-xs px-2 py-1.5 text-xs outline-none transition-colors hover:bg-accent hover:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 pointer-events-auto [app-region:no-drag] [-webkit-app-region:no-drag]\"\n >\n <span class=\"flex items-center gap-2\">\n <X class=\"size-3.5 text-muted-foreground\" />\n Close Tab\n </span>\n <span class=\"ml-auto text-[10px] text-muted-foreground font-mono\">Ctrl+W</span>\n </ContextMenuPrimitive.Item>\n\n <Show when={ctx.manager && ctx.manager.tabs().length > 1}>\n <ContextMenuPrimitive.Item\n data-no-drag\n data-tauri-drag-region=\"false\"\n style=\"-webkit-app-region: no-drag; app-region: no-drag;\"\n onMouseDown={(e) => e.stopPropagation()}\n onPointerDown={(e) => e.stopPropagation()}\n onSelect={() => {\n setTimeout(() => ctx.manager?.closeOthers(tabId()), 0);\n }}\n class=\"relative flex cursor-pointer select-none items-center gap-2 rounded-xs px-2 py-1.5 text-xs outline-none transition-colors hover:bg-accent hover:text-accent-foreground pointer-events-auto [app-region:no-drag] [-webkit-app-region:no-drag]\"\n >\n <CircleX class=\"size-3.5 text-muted-foreground\" />\n Close Other Tabs\n </ContextMenuPrimitive.Item>\n <ContextMenuPrimitive.Item\n data-no-drag\n data-tauri-drag-region=\"false\"\n style=\"-webkit-app-region: no-drag; app-region: no-drag;\"\n onMouseDown={(e) => e.stopPropagation()}\n onPointerDown={(e) => e.stopPropagation()}\n onSelect={() => {\n setTimeout(() => ctx.manager?.closeAll(), 0);\n }}\n class=\"relative flex cursor-pointer select-none items-center gap-2 rounded-xs px-2 py-1.5 text-xs outline-none transition-colors hover:bg-accent hover:text-accent-foreground pointer-events-auto [app-region:no-drag] [-webkit-app-region:no-drag]\"\n >\n <CircleX class=\"size-3.5 text-muted-foreground\" />\n <span>Close All Tabs</span>\n </ContextMenuPrimitive.Item>\n </Show>\n </>\n }\n >\n {local.renderContextMenu!(local.tab || { id: tabId(), title: title() })}\n </Show>\n </ContextMenuPrimitive.Content>\n </ContextMenuPrimitive.Portal>\n </ContextMenuPrimitive.Root>\n </Show>\n );\n};\n\n/* --- 5. TitlebarTabAddButton using Nikala UI Button & Tooltip --- */\n\nexport interface TitlebarTabAddButtonProps extends JSX.HTMLAttributes<HTMLButtonElement> {\n class?: string;\n}\n\nexport const TitlebarTabAddButton: Component<TitlebarTabAddButtonProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"style\"]);\n\n return (\n <div\n data-no-drag\n data-tauri-drag-region=\"false\"\n style={(\"-webkit-app-region: no-drag; app-region: no-drag;\" + (typeof local.style === \"string\" ? ` ${local.style}` : \"\")) as any}\n class=\"shrink-0 flex items-center z-20 pointer-events-auto [app-region:no-drag] [-webkit-app-region:no-drag]\"\n >\n <Tooltip>\n <TooltipTrigger\n as={Button}\n variant=\"ghost\"\n size=\"icon\"\n data-no-drag\n data-tauri-drag-region=\"false\"\n aria-label=\"Add new tab\"\n class={cn(\n \"size-6 rounded-md text-muted-foreground hover:bg-muted/80 hover:text-foreground cursor-pointer shrink-0\",\n local.class\n )}\n {...rest}\n >\n <Plus class=\"size-3.5\" />\n </TooltipTrigger>\n <TooltipContent class=\"text-[10px] py-1 px-2\">\n New tab (Ctrl+T)\n </TooltipContent>\n </Tooltip>\n </div>\n );\n};\n\n",
21
+ "type": "registry:ui"
22
+ }
23
+ ]
24
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "titlebar",
3
+ "title": "Titlebar",
4
+ "description": "A native-feeling custom titlebar for frameless desktop windows supporting macOS Traffic Lights and Windows 11 controls.",
5
+ "type": "registry:ui",
6
+ "dependencies": [
7
+ "clsx",
8
+ "tailwind-merge",
9
+ "class-variance-authority",
10
+ "lucide-solid"
11
+ ],
12
+ "registryDependencies": [
13
+ "titlebar-tabs",
14
+ "button",
15
+ "tooltip",
16
+ "create-tauri-window",
17
+ "create-document-tabs"
18
+ ],
19
+ "files": [
20
+ {
21
+ "path": "ui/titlebar.tsx",
22
+ "content": "import {\n createContext,\n useContext,\n splitProps,\n createMemo,\n Show,\n type Component,\n type JSX,\n type ParentComponent,\n type Accessor,\n} from \"solid-js\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { createTauriWindow, type TauriPlatform, detectPlatform } from \"@/hooks/create-tauri-window\";\nimport { cn } from \"@/lib/cn\";\n\n/* --- 1. Context & Types --- */\nexport type TitlebarPlatform = \"macos\" | \"windows\" | \"auto\";\n\nexport interface TitlebarContextValue {\n platform: Accessor<\"macos\" | \"windows\">;\n isMaximized: Accessor<boolean>;\n minimize: () => Promise<void> | void;\n toggleMaximize: () => Promise<void> | void;\n close: () => Promise<void> | void;\n destroy?: () => Promise<void> | void;\n}\n\nconst TitlebarContext = createContext<TitlebarContextValue>();\n\nexport function useTitlebar() {\n const context = useContext(TitlebarContext);\n if (!context) {\n throw new Error(\"useTitlebar must be used within a <Titlebar />\");\n }\n return context;\n}\n\n/* --- 2. Titlebar Variants --- */\nexport const titlebarVariants = cva(\n \"relative flex w-full select-none items-center justify-between border-b transition-colors shrink-0 sticky top-0 z-50\",\n {\n variants: {\n variant: {\n default: \"border-border/50 bg-background text-foreground\",\n translucent: \"border-border/40 bg-background/80 backdrop-blur-md text-foreground\",\n floating: \"m-2 rounded-lg border border-border bg-card shadow-sm text-card-foreground\",\n transparent: \"border-transparent bg-transparent text-foreground\",\n },\n size: {\n sm: \"h-8 text-xs px-2.5\",\n default: \"h-9 text-xs px-3\",\n lg: \"h-11 text-sm px-4\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n);\n\n/* --- 3. Root Titlebar Component --- */\nexport interface TitlebarProps\n extends JSX.HTMLAttributes<HTMLElement>,\n VariantProps<typeof titlebarVariants> {\n /** Explicit platform style, or 'auto' to detect host OS. */\n platform?: TitlebarPlatform;\n /** Optional controlled maximize state override. */\n isMaximized?: boolean;\n /** Optional minimize callback override. */\n onMinimize?: () => void | Promise<void>;\n /** Optional maximize callback override. */\n onToggleMaximize?: () => void | Promise<void>;\n /** Optional close callback override. */\n onClose?: () => void | Promise<void>;\n /** Whether double-clicking the titlebar toggles window maximize state. Defaults to true. */\n doubleClickToMaximize?: boolean;\n}\n\nexport const Titlebar: ParentComponent<TitlebarProps> = (props) => {\n const [local, rest] = splitProps(props, [\n \"platform\",\n \"isMaximized\",\n \"onMinimize\",\n \"onToggleMaximize\",\n \"onClose\",\n \"variant\",\n \"size\",\n \"class\",\n \"children\",\n \"doubleClickToMaximize\",\n \"onMouseDown\",\n \"onDblClick\",\n ]);\n\n const windowCtrl = createTauriWindow();\n\n const resolvedPlatform = createMemo<\"macos\" | \"windows\">(() => {\n if (local.platform && local.platform !== \"auto\") {\n return local.platform;\n }\n const detected = detectPlatform();\n return detected === \"macos\" ? \"macos\" : \"windows\";\n });\n\n const isMaximized = () =>\n local.isMaximized !== undefined ? local.isMaximized : windowCtrl.isMaximized();\n\n const minimize = () => (local.onMinimize ? local.onMinimize() : windowCtrl.minimize());\n const toggleMaximize = () =>\n local.onToggleMaximize ? local.onToggleMaximize() : windowCtrl.toggleMaximize();\n const close = () => (local.onClose ? local.onClose() : windowCtrl.close());\n const destroy = () => windowCtrl.destroy();\n\n const handleMouseDown: JSX.EventHandlerUnion<HTMLElement, MouseEvent> = (e) => {\n if (e.button === 0) {\n const target = e.target as HTMLElement;\n if (!target.closest(\"button, a, input, select, textarea, [data-no-drag], [data-tauri-drag-region='false']\")) {\n if (e.detail === 2 && local.doubleClickToMaximize !== false) {\n // Double-click detected on mousedown detail - toggles maximize immediately without initiating a drag\n toggleMaximize();\n } else if (e.detail === 1) {\n // Single-click: initiate window drag\n windowCtrl.startDragging(e);\n }\n }\n }\n if (typeof local.onMouseDown === \"function\") {\n (local.onMouseDown as any)(e);\n }\n };\n\n let lastDblClickTime = 0;\n const handleDoubleClick: JSX.EventHandlerUnion<HTMLElement, MouseEvent> = (e) => {\n const now = Date.now();\n if (now - lastDblClickTime < 350) {\n return; // Deduplicate rapid triggers\n }\n lastDblClickTime = now;\n\n if (local.doubleClickToMaximize !== false) {\n // Don't maximize if user double-clicked an interactive control\n const target = e.target as HTMLElement;\n if (!target.closest(\"button, a, input, select, textarea, [data-no-drag], [data-tauri-drag-region='false']\")) {\n toggleMaximize();\n }\n }\n if (typeof local.onDblClick === \"function\") {\n (local.onDblClick as any)(e);\n }\n };\n\n const contextValue: TitlebarContextValue = {\n platform: resolvedPlatform,\n isMaximized,\n minimize,\n toggleMaximize,\n close,\n destroy,\n };\n\n return (\n <TitlebarContext.Provider value={contextValue}>\n <header\n onMouseDown={handleMouseDown}\n onDblClick={handleDoubleClick}\n class={cn(\n titlebarVariants({ variant: local.variant, size: local.size }),\n \"select-none cursor-default\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </header>\n </TitlebarContext.Provider>\n );\n};\n\n/* --- 4. Subcomponents --- */\n\n/**\n * Traffic light buttons for macOS or Fluent control buttons for Windows.\n */\nexport interface TitlebarControlsProps extends JSX.HTMLAttributes<HTMLDivElement> {\n /** Optional override platform style. Defaults to Titlebar context or detected OS. */\n platform?: \"macos\" | \"windows\";\n /** Optional controlled maximize state override. */\n isMaximized?: boolean;\n /** Optional minimize callback override. */\n onMinimize?: () => void | Promise<void>;\n /** Optional maximize callback override. */\n onToggleMaximize?: () => void | Promise<void>;\n /** Optional close callback override. */\n onClose?: () => void | Promise<void>;\n}\n\nexport const TitlebarControls: Component<TitlebarControlsProps> = (props) => {\n const [local, rest] = splitProps(props, [\n \"platform\",\n \"class\",\n \"style\",\n \"isMaximized\",\n \"onMinimize\",\n \"onToggleMaximize\",\n \"onClose\",\n ]);\n const ctx = useContext(TitlebarContext);\n let fallbackCtrl: ReturnType<typeof createTauriWindow> | null = null;\n if (!ctx) {\n fallbackCtrl = createTauriWindow();\n }\n\n const activePlatform = createMemo<\"macos\" | \"windows\">(() => {\n if (local.platform) return local.platform;\n if (ctx?.platform) return ctx.platform();\n const detected = detectPlatform();\n return detected === \"macos\" ? \"macos\" : \"windows\";\n });\n\n const isMaximized = () => {\n if (local.isMaximized !== undefined) return local.isMaximized;\n if (ctx?.isMaximized) return ctx.isMaximized();\n return fallbackCtrl ? fallbackCtrl.isMaximized() : false;\n };\n\n const handleMinimize = (e: MouseEvent) => {\n e.stopPropagation();\n if (local.onMinimize) return local.onMinimize();\n if (ctx?.minimize) return ctx.minimize();\n return fallbackCtrl?.minimize();\n };\n\n const handleToggleMaximize = (e: MouseEvent) => {\n e.stopPropagation();\n if (local.onToggleMaximize) return local.onToggleMaximize();\n if (ctx?.toggleMaximize) return ctx.toggleMaximize();\n return fallbackCtrl?.toggleMaximize();\n };\n\n const handleClose = (e: MouseEvent) => {\n e.stopPropagation();\n if (local.onClose) return local.onClose();\n if (ctx?.close) return ctx.close();\n return fallbackCtrl?.close();\n };\n\n return (\n <div\n data-no-drag\n data-tauri-drag-region=\"false\"\n style={(\"-webkit-app-region: no-drag; app-region: no-drag;\" + (typeof local.style === \"string\" ? ` ${local.style}` : \"\")) as any}\n class={cn(\n \"flex items-center z-10 self-stretch shrink-0 pointer-events-auto [app-region:no-drag] [-webkit-app-region:no-drag]\",\n activePlatform() === \"macos\"\n ? \"gap-2 px-1 order-first\"\n : \"gap-0 -mr-3 h-full order-last ml-auto\",\n local.class\n )}\n {...rest}\n >\n <Show\n when={activePlatform() === \"macos\"}\n fallback={\n /* Windows 11 Fluent Window Controls */\n <div class=\"flex items-center h-full self-stretch\">\n {/* Minimize */}\n <button\n type=\"button\"\n onClick={handleMinimize}\n class=\"inline-flex h-full w-11 items-center justify-center text-muted-foreground hover:bg-muted hover:text-foreground transition-colors cursor-pointer\"\n aria-label=\"Minimize Window\"\n >\n <svg class=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 12 12\">\n <path stroke=\"currentColor\" stroke-width=\"1\" d=\"M1.5 6h9\" />\n </svg>\n </button>\n\n {/* Maximize / Restore */}\n <button\n type=\"button\"\n onClick={handleToggleMaximize}\n class=\"inline-flex h-full w-11 items-center justify-center text-muted-foreground hover:bg-muted hover:text-foreground transition-colors cursor-pointer\"\n aria-label={isMaximized() ? \"Restore Window\" : \"Maximize Window\"}\n >\n <Show\n when={isMaximized()}\n fallback={\n <svg class=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 12 12\">\n <rect width=\"8\" height=\"8\" x=\"2\" y=\"2\" stroke=\"currentColor\" stroke-width=\"1\" rx=\"0.5\" />\n </svg>\n }\n >\n <svg class=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 12 12\">\n <path stroke=\"currentColor\" stroke-width=\"1\" d=\"M3.5 3.5v-1.5h6v6h-1.5M2 4.5h6v6h-6z\" />\n </svg>\n </Show>\n </button>\n\n {/* Close */}\n <button\n type=\"button\"\n onClick={handleClose}\n class=\"inline-flex h-full w-11 items-center justify-center text-muted-foreground hover:bg-destructive hover:text-destructive-foreground transition-colors cursor-pointer\"\n aria-label=\"Close Window\"\n >\n <svg class=\"h-3 w-3\" fill=\"none\" viewBox=\"0 0 12 12\">\n <path stroke=\"currentColor\" stroke-width=\"1\" d=\"M2.5 2.5l7 7M9.5 2.5l-7 7\" />\n </svg>\n </button>\n </div>\n }\n >\n {/* macOS Traffic Lights */}\n <div class=\"group/traffic flex items-center gap-2\">\n {/* Close */}\n <button\n type=\"button\"\n onClick={handleClose}\n class=\"flex size-3 items-center justify-center rouded-lg bg-[#ff5f57] border border-[#e0443e] cursor-pointer\"\n aria-label=\"Close Window\"\n >\n <svg\n class=\"size-1.5 text-[#4c0000] opacity-0 group-hover/traffic:opacity-100 transition-opacity\"\n viewBox=\"0 0 6 6\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.2\"\n >\n <path d=\"M1 1l4 4M5 1L1 5\" />\n </svg>\n </button>\n\n {/* Minimize */}\n <button\n type=\"button\"\n onClick={handleMinimize}\n class=\"flex size-3 items-center justify-center rouded-lg bg-[#febc2e] border border-[#d89e24] cursor-pointer\"\n aria-label=\"Minimize Window\"\n >\n <svg\n class=\"size-1.5 text-[#5c3e00] opacity-0 group-hover/traffic:opacity-100 transition-opacity\"\n viewBox=\"0 0 6 6\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.2\"\n >\n <path d=\"M1 3h4\" />\n </svg>\n </button>\n\n {/* Maximize */}\n <button\n type=\"button\"\n onClick={handleToggleMaximize}\n class=\"flex size-3 items-center justify-center rouded-lg bg-[#28c840] border border-[#1aab29] cursor-pointer\"\n aria-label=\"Maximize Window\"\n >\n <svg\n class=\"size-1.5 text-[#003d07] opacity-0 group-hover/traffic:opacity-100 transition-opacity\"\n viewBox=\"0 0 6 6\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.2\"\n >\n <path d=\"M1 4.5l3.5-3.5M4.5 1h-3M4.5 1v3\" />\n </svg>\n </button>\n </div>\n </Show>\n </div>\n );\n};\n\n/**\n * Title text container. Placed naturally in JSX flow by default, or centered with align=\"center\".\n */\nexport interface TitlebarTitleProps extends JSX.HTMLAttributes<HTMLDivElement> {\n align?: \"center\" | \"start\";\n}\n\nexport const TitlebarTitle: ParentComponent<TitlebarTitleProps> = (props) => {\n const [local, rest] = splitProps(props, [\"align\", \"class\", \"children\"]);\n\n const isCentered = () => local.align === \"center\";\n\n return (\n <div\n class={cn(\n \"flex items-center gap-2 font-medium truncate text-xs text-foreground\",\n isCentered()\n ? \"absolute left-1/2 -translate-x-1/2 pointer-events-none text-center justify-center max-w-[calc(100%-160px)]\"\n : \"shrink-0\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </div>\n );\n};\n\n/**\n * App icon slot within Titlebar.\n */\nexport const TitlebarIcon: ParentComponent<JSX.HTMLAttributes<HTMLDivElement>> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n return (\n <div\n data-no-drag\n data-tauri-drag-region=\"false\"\n class={cn(\n \"flex shrink-0 items-center justify-center size-4 text-muted-foreground pointer-events-auto [app-region:no-drag] [-webkit-app-region:no-drag]\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </div>\n );\n};\n\n/**\n * Action buttons container (Search, Settings, ThemeToggle, Navigation) placed in the titlebar.\n * Supports start, end, center, or natural flow alignment.\n */\nexport interface TitlebarActionsProps extends JSX.HTMLAttributes<HTMLDivElement> {\n /** Alignment of the actions container within the titlebar. Defaults to 'end'. */\n align?: \"start\" | \"end\" | \"center\" | \"none\";\n}\n\nexport const TitlebarActions: ParentComponent<TitlebarActionsProps> = (props) => {\n const [local, rest] = splitProps(props, [\"align\", \"class\", \"children\", \"style\"]);\n\n const alignClass = () => {\n switch (local.align) {\n case \"start\":\n return \"mr-auto\";\n case \"center\":\n return \"mx-auto\";\n case \"none\":\n return \"\";\n case \"end\":\n default:\n return \"ml-auto\";\n }\n };\n\n return (\n <div\n data-no-drag\n data-tauri-drag-region=\"false\"\n style={(\"-webkit-app-region: no-drag; app-region: no-drag;\" + (typeof local.style === \"string\" ? ` ${local.style}` : \"\")) as any}\n class={cn(\n \"flex items-center gap-1 shrink-0 z-10 px-1 pointer-events-auto [app-region:no-drag] [-webkit-app-region:no-drag]\",\n alignClass(),\n local.class\n )}\n {...rest}\n >\n {local.children}\n </div>\n );\n};\n\n/* --- 6. Re-export TitlebarTabs Suite --- */\nexport * from \"./titlebar-tabs\";\n\n",
23
+ "type": "registry:ui"
24
+ }
25
+ ]
26
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "toast",
3
+ "title": "Toast / Sonner",
4
+ "description": "A succinct message displayed temporarily in a toast region, built on Kobalte primitives.",
5
+ "type": "registry:ui",
6
+ "dependencies": [
7
+ "clsx",
8
+ "tailwind-merge",
9
+ "class-variance-authority",
10
+ "lucide-solid",
11
+ "@kobalte/core"
12
+ ],
13
+ "files": [
14
+ {
15
+ "path": "ui/toast.tsx",
16
+ "content": "import { splitProps, type Component, type JSX, type ComponentProps } from \"solid-js\";\nimport { Toast as KobalteToast, toaster } from \"@kobalte/core/toast\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { X, CircleCheck, Info, CircleAlert, TriangleAlert } from \"lucide-solid\";\nimport { cn } from \"@/lib/cn\";\n\nexport const toastVariants = cva(\n \"group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-lg border p-4 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--kb-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--kb-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[opened]:animate-in data-[closed]:animate-out data-[swipe=end]:animate-out data-[closed]:fade-out-80 data-[closed]:slide-out-to-right-full data-[opened]:slide-in-from-top-full data-[opened]:sm:slide-in-from-bottom-full\",\n {\n variants: {\n variant: {\n default: \"border-border bg-background text-foreground\",\n success: \"border-emerald-500/20 bg-emerald-500/10 text-emerald-900 dark:text-emerald-200 border-emerald-500/30\",\n destructive: \"border-destructive/30 bg-destructive/10 text-destructive dark:text-red-300\",\n warning: \"border-amber-500/20 bg-amber-500/10 text-amber-900 dark:text-amber-200 border-amber-500/30\",\n info: \"border-sky-500/20 bg-sky-500/10 text-sky-900 dark:text-sky-200 border-sky-500/30\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\nexport interface ToastProps\n extends ComponentProps<typeof KobalteToast>,\n VariantProps<typeof toastVariants> {\n class?: string;\n}\n\nexport const Toast: Component<ToastProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"variant\"]);\n\n return (\n <KobalteToast\n class={cn(toastVariants({ variant: local.variant }), local.class)}\n {...rest}\n />\n );\n};\n\nexport const ToastTitle: Component<ComponentProps<typeof KobalteToast.Title>> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n\n return (\n <KobalteToast.Title\n class={cn(\"text-sm font-semibold [&+div]:text-xs\", local.class)}\n {...rest}\n />\n );\n};\n\nexport const ToastDescription: Component<ComponentProps<typeof KobalteToast.Description>> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n\n return (\n <KobalteToast.Description\n class={cn(\"text-sm opacity-90\", local.class)}\n {...rest}\n />\n );\n};\n\nexport const ToastCloseButton: Component<ComponentProps<typeof KobalteToast.CloseButton>> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <KobalteToast.CloseButton\n class={cn(\n \"absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-1 group-hover:opacity-100\",\n local.class\n )}\n {...rest}\n >\n {local.children || <X class=\"h-4 w-4\" />}\n </KobalteToast.CloseButton>\n );\n};\n\nexport const ToastRegion: Component<ComponentProps<typeof KobalteToast.Region>> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n\n return (\n <KobalteToast.Region\n class={cn(\n \"fixed top-0 z-100 flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-105\",\n local.class\n )}\n {...rest}\n />\n );\n};\n\nexport const ToastList: Component<ComponentProps<typeof KobalteToast.List>> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n\n return <KobalteToast.List class={cn(\"flex flex-col gap-2\", local.class)} {...rest} />;\n};\n\n/* --- Helper Function to Trigger Toast Notifications --- */\nexport interface ShowToastOptions {\n title: string;\n description?: string;\n variant?: \"default\" | \"success\" | \"destructive\" | \"warning\" | \"info\";\n duration?: number;\n}\n\nexport const showToast = (options: ShowToastOptions) => {\n return toaster.show((props) => (\n <Toast toastId={props.toastId} variant={options.variant || \"default\"}>\n <div class=\"flex items-start gap-3\">\n {options.variant === \"success\" && <CircleCheck class=\"h-5 w-5 text-emerald-500 shrink-0 mt-0.5\" />}\n {options.variant === \"destructive\" && <CircleAlert class=\"h-5 w-5 text-red-500 shrink-0 mt-0.5\" />}\n {options.variant === \"warning\" && <TriangleAlert class=\"h-5 w-5 text-amber-500 shrink-0 mt-0.5\" />}\n {options.variant === \"info\" && <Info class=\"h-5 w-5 text-sky-500 shrink-0 mt-0.5\" />}\n <div class=\"grid gap-1\">\n <ToastTitle>{options.title}</ToastTitle>\n {options.description && <ToastDescription>{options.description}</ToastDescription>}\n </div>\n </div>\n <ToastCloseButton />\n </Toast>\n ));\n};",
17
+ "type": "registry:ui"
18
+ }
19
+ ]
20
+ }
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "toggle-group",
3
+ "title": "Toggle Group",
4
+ "description": "A set of two-state buttons that can be toggled on or off with single or multiple selection modes.",
5
+ "type": "registry:ui",
6
+ "dependencies": [
7
+ "clsx",
8
+ "tailwind-merge",
9
+ "class-variance-authority"
10
+ ],
11
+ "registryDependencies": [
12
+ "create-controllable-signal"
13
+ ],
14
+ "files": [
15
+ {
16
+ "path": "ui/toggle-group.tsx",
17
+ "content": "import {\n createContext,\n useContext,\n splitProps,\n type Component,\n type JSX,\n type Accessor,\n} from \"solid-js\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { createControllableSignal } from \"@/hooks/create-controllable-signal\";\nimport { cn } from \"@/lib/cn\";\n\nexport const toggleGroupItemVariants = cva(\n \"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 cursor-pointer\",\n {\n variants: {\n variant: {\n default: \"bg-transparent\",\n outline:\n \"border border-border bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground data-[state=on]:bg-accent data-[state=on]:text-accent-foreground\",\n },\n size: {\n default: \"h-9 px-3 min-w-9\",\n sm: \"h-8 px-2 text-xs min-w-8\",\n lg: \"h-10 px-3 min-w-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n);\n\ninterface ToggleGroupContextValue {\n type: \"single\" | \"multiple\";\n value: Accessor<any>;\n onItemSelect: (itemValue: string) => void;\n variant: Accessor<\"default\" | \"outline\">;\n size: Accessor<\"default\" | \"sm\" | \"lg\">;\n disabled: Accessor<boolean>;\n}\n\nconst ToggleGroupContext = createContext<ToggleGroupContextValue>();\n\nexport interface ToggleGroupProps<T extends \"single\" | \"multiple\" = \"single\">\n extends Omit<JSX.HTMLAttributes<HTMLDivElement>, \"onChange\">,\n VariantProps<typeof toggleGroupItemVariants> {\n /** Mode of selection: single choice or multiple choices */\n type?: T;\n /** Controlled value: string for 'single', string[] for 'multiple' */\n value?: T extends \"multiple\" ? string[] : string;\n /** Uncontrolled default value */\n defaultValue?: T extends \"multiple\" ? string[] : string;\n /** Callback fired when selection changes */\n onChange?: (value: T extends \"multiple\" ? string[] : string) => void;\n /** Layout orientation */\n orientation?: \"horizontal\" | \"vertical\";\n /** Disables all buttons in the group */\n disabled?: boolean;\n class?: string;\n children?: JSX.Element;\n}\n\n/**\n * Root container for grouping connected toggle items with shared single/multiple selection state.\n */\nexport const ToggleGroup = <T extends \"single\" | \"multiple\" = \"single\">(\n props: ToggleGroupProps<T>\n) => {\n const [local, rest] = splitProps(props, [\n \"type\",\n \"value\",\n \"defaultValue\",\n \"onChange\",\n \"orientation\",\n \"variant\",\n \"size\",\n \"disabled\",\n \"class\",\n \"children\",\n ]);\n\n const type = () => local.type ?? (\"single\" as T);\n const variant = () => local.variant ?? \"default\";\n const size = () => local.size ?? \"default\";\n const disabled = () => local.disabled ?? false;\n const orientation = () => local.orientation ?? \"horizontal\";\n\n const [currentValue, setCurrentValue] = createControllableSignal<any>({\n value: () => local.value,\n defaultValue: local.defaultValue ?? (type() === \"multiple\" ? [] : undefined),\n onChange: (val) => local.onChange?.(val),\n });\n\n const onItemSelect = (itemValue: string) => {\n if (disabled()) return;\n\n if (type() === \"multiple\") {\n const currentList = Array.isArray(currentValue()) ? currentValue() : [];\n if (currentList.includes(itemValue)) {\n setCurrentValue(currentList.filter((v: string) => v !== itemValue));\n } else {\n setCurrentValue([...currentList, itemValue]);\n }\n } else {\n const current = currentValue();\n if (current === itemValue) {\n setCurrentValue(undefined);\n } else {\n setCurrentValue(itemValue);\n }\n }\n };\n\n const contextValue: ToggleGroupContextValue = {\n type: type(),\n value: currentValue,\n onItemSelect,\n variant,\n size,\n disabled,\n };\n\n return (\n <ToggleGroupContext.Provider value={contextValue}>\n <div\n role=\"group\"\n data-orientation={orientation()}\n class={cn(\n \"flex items-center justify-center gap-1 rounded-lg\",\n orientation() === \"vertical\" ? \"flex-col\" : \"flex-row\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </div>\n </ToggleGroupContext.Provider>\n );\n};\n\nexport interface ToggleGroupItemProps\n extends JSX.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof toggleGroupItemVariants> {\n /** Unique value representing this toggle item within the group */\n value: string;\n class?: string;\n children?: JSX.Element;\n}\n\n/**\n * Individual toggle button item within a ToggleGroup.\n */\nexport const ToggleGroupItem: Component<ToggleGroupItemProps> = (props) => {\n const context = useContext(ToggleGroupContext);\n\n if (!context) {\n throw new Error(\"ToggleGroupItem must be used within a ToggleGroup\");\n }\n\n const [local, rest] = splitProps(props, [\n \"value\",\n \"variant\",\n \"size\",\n \"disabled\",\n \"class\",\n \"children\",\n ]);\n\n const isSelected = () => {\n const groupValue = context.value();\n if (context.type === \"multiple\") {\n return Array.isArray(groupValue) && groupValue.includes(local.value);\n }\n return groupValue === local.value;\n };\n\n const isDisabled = () => local.disabled || context.disabled();\n const itemVariant = () => local.variant || context.variant();\n const itemSize = () => local.size || context.size();\n\n return (\n <button\n type=\"button\"\n role={context.type === \"single\" ? \"radio\" : \"checkbox\"}\n aria-checked={isSelected()}\n data-state={isSelected() ? \"on\" : \"off\"}\n disabled={isDisabled()}\n onClick={() => context.onItemSelect(local.value)}\n class={cn(\n toggleGroupItemVariants({\n variant: itemVariant(),\n size: itemSize(),\n }),\n local.class\n )}\n {...rest}\n >\n {local.children}\n </button>\n );\n};\n",
18
+ "type": "registry:ui"
19
+ }
20
+ ]
21
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "toggle",
3
+ "title": "Toggle",
4
+ "description": "A two-state interactive button component built on Kobalte primitives.",
5
+ "type": "registry:ui",
6
+ "dependencies": [
7
+ "clsx",
8
+ "tailwind-merge",
9
+ "@kobalte/core"
10
+ ],
11
+ "files": [
12
+ {
13
+ "path": "ui/toggle.tsx",
14
+ "content": "import { splitProps, type Component, type JSX } from \"solid-js\";\nimport { ToggleButton as KobalteToggle } from \"@kobalte/core/toggle-button\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"@/lib/cn\";\n\nexport const toggleVariants = cva(\n \"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[pressed]:bg-accent data-[pressed]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 cursor-pointer\",\n {\n variants: {\n variant: {\n default: \"bg-transparent\",\n outline:\n \"border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground data-[pressed]:bg-accent data-[pressed]:text-accent-foreground\",\n },\n size: {\n default: \"h-9 px-3 min-w-9\",\n sm: \"h-8 px-2 text-xs min-w-8\",\n lg: \"h-10 px-3 min-w-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n);\n\nexport interface ToggleProps\n extends JSX.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof toggleVariants> {\n pressed?: boolean;\n defaultPressed?: boolean;\n onPressedChange?: (pressed: boolean) => void;\n disabled?: boolean;\n class?: string;\n children?: JSX.Element;\n}\n\nexport const Toggle: Component<ToggleProps> = (props) => {\n const [local, rest] = splitProps(props, [\n \"variant\",\n \"size\",\n \"class\",\n \"children\",\n \"pressed\",\n \"defaultPressed\",\n \"onPressedChange\",\n \"disabled\",\n \"onChange\",\n ]);\n\n return (\n <KobalteToggle\n isPressed={local.pressed}\n defaultIsPressed={local.defaultPressed}\n onChange={local.onPressedChange}\n disabled={local.disabled}\n class={cn(\n toggleVariants({ variant: local.variant, size: local.size }),\n local.class\n )}\n {...rest}\n >\n {local.children}\n </KobalteToggle>\n );\n};\n\nexport interface ToggleGroupProps extends JSX.HTMLAttributes<HTMLDivElement> {\n type?: \"single\" | \"multiple\";\n value?: string | string[];\n defaultValue?: string | string[];\n onChange?: (value: any) => void;\n disabled?: boolean;\n class?: string;\n children?: JSX.Element;\n}\n\nexport const ToggleGroup: Component<ToggleGroupProps> = (props) => {\n const [local, rest] = splitProps(props, [\n \"type\",\n \"value\",\n \"defaultValue\",\n \"onChange\",\n \"disabled\",\n \"class\",\n \"children\",\n ]);\n\n return (\n <div\n class={cn(\n \"flex items-center justify-center gap-1 rounded-md border border-border/40 p-1 bg-background\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </div>\n );\n};\n",
15
+ "type": "registry:ui"
16
+ }
17
+ ]
18
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "tooltip",
3
+ "title": "Tooltip",
4
+ "description": "A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it, built on Kobalte primitives.",
5
+ "type": "registry:ui",
6
+ "dependencies": [
7
+ "clsx",
8
+ "tailwind-merge",
9
+ "@kobalte/core"
10
+ ],
11
+ "files": [
12
+ {
13
+ "path": "ui/tooltip.tsx",
14
+ "content": "import { splitProps, type Component, type ComponentProps } from \"solid-js\";\nimport { Tooltip as KobalteTooltip } from \"@kobalte/core/tooltip\";\nimport { cn } from \"@/lib/cn\";\n\nexport const Tooltip = KobalteTooltip;\n\nexport const TooltipTrigger = KobalteTooltip.Trigger;\n\nexport const TooltipArrow: Component<ComponentProps<typeof KobalteTooltip.Arrow>> = (props) => {\n const [local, rest] = splitProps(props, [\"class\"]);\n\n return (\n <KobalteTooltip.Arrow\n size={8}\n class={cn(\"fill-popover stroke-border\", local.class)}\n {...rest}\n />\n );\n};\n\nexport interface TooltipContentProps extends ComponentProps<typeof KobalteTooltip.Content> {\n class?: string;\n}\n\nexport const TooltipContent: Component<TooltipContentProps> = (props) => {\n const [local, rest] = splitProps(props, [\"class\", \"children\"]);\n\n return (\n <KobalteTooltip.Portal>\n <KobalteTooltip.Content\n class={cn(\n \"z-50 rounded-md border border-border bg-popover px-3 py-1.5 text-xs text-popover-foreground shadow-md transition-all animate-in fade-in-0 zoom-in-95 data-closed:animate-out data-[closed]:fade-out-0 data-closed:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2\",\n local.class\n )}\n {...rest}\n >\n {local.children}\n </KobalteTooltip.Content>\n </KobalteTooltip.Portal>\n );\n};",
15
+ "type": "registry:ui"
16
+ }
17
+ ]
18
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "updater-modal",
3
+ "title": "Updater Modal",
4
+ "description": "An automated application auto-updater dialog for Tauri v2 with release notes preview, download progress bar, and relaunch actions.",
5
+ "type": "registry:ui",
6
+ "dependencies": [
7
+ "clsx",
8
+ "tailwind-merge",
9
+ "lucide-solid"
10
+ ],
11
+ "registryDependencies": [
12
+ "dialog",
13
+ "button",
14
+ "badge",
15
+ "progress",
16
+ "alert",
17
+ "create-app-updater"
18
+ ],
19
+ "files": [
20
+ {
21
+ "path": "ui/updater-modal.tsx",
22
+ "content": "import {\n Show,\n splitProps,\n type Component,\n type ParentComponent,\n type JSX,\n} from \"solid-js\";\nimport {\n Dialog,\n DialogContent,\n DialogHeader,\n DialogTitle,\n DialogDescription,\n DialogFooter,\n} from \"@/components/ui/dialog\";\nimport { Button } from \"@/components/ui/button\";\nimport { Badge } from \"@/components/ui/badge\";\nimport { Progress } from \"@/components/ui/progress\";\nimport { Alert, AlertTitle, AlertDescription } from \"@/components/ui/alert\";\nimport type {\n CreateAppUpdaterReturn,\n UpdateManifestInfo,\n UpdateProgressInfo,\n} from \"@/hooks/create-app-updater\";\nimport {\n Download,\n RotateCcw,\n CheckCircle2,\n AlertTriangle,\n ArrowRight,\n Package,\n} from \"lucide-solid\";\nimport { cn } from \"@/lib/cn\";\n\nfunction formatBytes(bytes: number): string {\n if (!bytes || bytes === 0) return \"0 MB\";\n const mb = bytes / (1024 * 1024);\n return `${mb.toFixed(1)} MB`;\n}\n\n/* --- 1. Sub-components for Clean Modularity & Zero Repetition --- */\n\nexport interface UpdaterHeaderProps {\n appName: string;\n status: string;\n info?: UpdateManifestInfo | null;\n}\n\nexport const UpdaterHeader: Component<UpdaterHeaderProps> = (props) => (\n <DialogHeader class=\"space-y-1.5 text-left\">\n <div class=\"flex items-center justify-between\">\n <div class=\"size-8 rounded-lg bg-primary/10 text-primary flex items-center justify-center\">\n <Package class=\"size-4\" />\n </div>\n <Show when={props.info?.version}>\n <div class=\"flex items-center gap-1.5 text-xs font-mono\">\n <span class=\"text-muted-foreground\">{props.info?.currentVersion || \"v1.0.0\"}</span>\n <ArrowRight class=\"size-3 text-muted-foreground\" />\n <Badge variant=\"default\" class=\"text-xs px-1.5 py-0 bg-primary text-primary-foreground font-semibold\">\n {props.info?.version}\n </Badge>\n </div>\n </Show>\n </div>\n\n <DialogTitle class=\"text-base font-bold tracking-tight text-foreground\">\n {props.status === \"downloaded\"\n ? \"Update Ready to Install\"\n : props.status === \"downloading\"\n ? \"Downloading Update...\"\n : props.status === \"up-to-date\"\n ? \"Up to Date\"\n : `New Update Available for ${props.appName}`}\n </DialogTitle>\n\n <DialogDescription class=\"text-xs text-muted-foreground leading-relaxed\">\n {props.status === \"downloaded\"\n ? \"The update has been downloaded and verified. Restart to apply changes.\"\n : props.status === \"downloading\"\n ? \"Please wait while update packages are being downloaded.\"\n : props.status === \"up-to-date\"\n ? `${props.appName} is running on the latest version.`\n : \"A new version with features and bug fixes is ready to install.\"}\n </DialogDescription>\n </DialogHeader>\n);\n\nexport interface UpdaterReleaseNotesProps {\n body?: string;\n date?: string;\n}\n\nexport const UpdaterReleaseNotes: Component<UpdaterReleaseNotesProps> = (props) => (\n <div class=\"space-y-1\">\n <div class=\"flex items-center justify-between text-xs text-muted-foreground font-medium\">\n <span>Release Notes</span>\n <Show when={props.date}>\n <span class=\"text-[11px] font-mono\">{props.date}</span>\n </Show>\n </div>\n <pre class=\"max-h-28 overflow-y-auto rounded-md border border-border bg-black/5 dark:bg-black/50 p-2.5 text-xs text-foreground font-mono whitespace-pre-wrap leading-relaxed select-text shadow-inner\">\n {props.body}\n </pre>\n </div>\n);\n\nexport interface UpdaterProgressBarProps {\n progress: UpdateProgressInfo;\n}\n\nexport const UpdaterProgressBar: Component<UpdaterProgressBarProps> = (props) => (\n <div class=\"space-y-1.5 py-1\">\n <div class=\"flex items-center justify-between text-xs font-mono\">\n <span class=\"text-muted-foreground font-sans\">Progress</span>\n <span class=\"font-semibold text-primary\">{props.progress.percentage}%</span>\n </div>\n <Progress value={props.progress.percentage} class=\"h-1.5\" />\n <div class=\"flex items-center justify-between text-[11px] font-mono text-muted-foreground\">\n <span>{formatBytes(props.progress.downloaded)}</span>\n <span>{formatBytes(props.progress.total)}</span>\n </div>\n </div>\n);\n\n/* --- 2. Main UpdaterModal Compound Component --- */\n\nexport interface UpdaterModalProps {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n updater: CreateAppUpdaterReturn;\n appName?: string;\n class?: string;\n}\n\nexport const UpdaterModal: Component<UpdaterModalProps> = (props) => {\n const [local, rest] = splitProps(props, [\n \"open\",\n \"onOpenChange\",\n \"updater\",\n \"appName\",\n \"class\",\n ]);\n\n const appName = () => local.appName || \"Nikala Desktop\";\n const status = () => local.updater.status();\n const info = () => local.updater.updateInfo();\n const progress = () => local.updater.progress();\n const error = () => local.updater.error();\n\n return (\n <Dialog open={local.open} onOpenChange={local.onOpenChange}>\n <DialogContent class={cn(\"sm:max-w-sm\", local.class)}>\n {/* Header */}\n <UpdaterHeader\n appName={appName()}\n status={status()}\n info={info()}\n />\n\n {/* Error Alert */}\n <Show when={error()}>\n <Alert variant=\"destructive\" class=\"py-2 text-xs\">\n <AlertTriangle class=\"size-3.5\" />\n <AlertTitle class=\"font-semibold text-xs\">Update Failed</AlertTitle>\n <AlertDescription class=\"text-[11px]\">{error()}</AlertDescription>\n </Alert>\n </Show>\n\n {/* Release Notes */}\n <Show when={info()?.body && (status() === \"available\" || status() === \"downloading\")}>\n <UpdaterReleaseNotes body={info()?.body} date={info()?.date} />\n </Show>\n\n {/* Progress Bar */}\n <Show when={status() === \"downloading\"}>\n <UpdaterProgressBar progress={progress()} />\n </Show>\n\n {/* Success Callout */}\n <Show when={status() === \"downloaded\"}>\n <div class=\"flex items-center gap-2.5 p-2.5 rounded-md border border-primary/30 bg-primary/5 text-xs text-foreground\">\n <CheckCircle2 class=\"size-4 text-primary shrink-0\" />\n <p class=\"font-medium text-foreground text-xs\">Package downloaded & verified.</p>\n </div>\n </Show>\n\n {/* Actions Footer */}\n <DialogFooter class=\"flex-row items-center justify-end gap-1.5 pt-1\">\n <Show when={status() === \"available\" || status() === \"error\"}>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => local.onOpenChange(false)}\n class=\"text-xs h-7.5 px-3 cursor-pointer\"\n >\n Later\n </Button>\n <Button\n variant=\"default\"\n size=\"sm\"\n onClick={() => local.updater.downloadAndInstall()}\n class=\"text-xs h-7.5 px-3 gap-1.5 cursor-pointer font-medium\"\n >\n <Download class=\"size-3.5\" />\n <span>Update Now</span>\n </Button>\n </Show>\n\n <Show when={status() === \"downloading\"}>\n <Button\n variant=\"outline\"\n size=\"sm\"\n disabled\n class=\"text-xs h-7.5 w-full opacity-70 justify-center\"\n >\n Downloading ({progress().percentage}%)\n </Button>\n </Show>\n\n <Show when={status() === \"downloaded\"}>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => local.onOpenChange(false)}\n class=\"text-xs h-7.5 px-3 cursor-pointer\"\n >\n Later\n </Button>\n <Button\n variant=\"default\"\n size=\"sm\"\n onClick={() => local.updater.relaunch()}\n class=\"text-xs h-7.5 px-3 gap-1.5 cursor-pointer font-semibold shadow-xs\"\n >\n <RotateCcw class=\"size-3.5\" />\n <span>Relaunch</span>\n </Button>\n </Show>\n\n <Show when={status() === \"up-to-date\" || status() === \"idle\"}>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => local.onOpenChange(false)}\n class=\"text-xs h-7.5 px-3 cursor-pointer\"\n >\n Close\n </Button>\n </Show>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n};\n",
23
+ "type": "registry:ui"
24
+ }
25
+ ]
26
+ }
@@ -0,0 +1,18 @@
1
+ import { type ViteDevServer } from "vite";
2
+ import type { DocsConfig } from "../types.js";
3
+ export interface DocsServerOptions {
4
+ root?: string;
5
+ docsDir?: string;
6
+ port?: number;
7
+ host?: string | boolean;
8
+ open?: boolean;
9
+ config?: DocsConfig;
10
+ outDir?: string;
11
+ }
12
+ export declare function getClientDir(): string;
13
+ export declare function createDocsServer(options?: DocsServerOptions): Promise<ViteDevServer>;
14
+ export declare function buildDocs(options?: DocsServerOptions): Promise<void>;
15
+ export declare function createDocsRequestHandler(options?: DocsServerOptions): Promise<(request: Request) => Promise<Response>>;
16
+ export declare function previewDocs(options?: DocsServerOptions): Promise<void>;
17
+ export * from "./plugin.js";
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAuB,KAAK,aAAa,EAAqB,MAAM,MAAM,CAAC;AAMlF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAI9C,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAKD,wBAAgB,YAAY,IAAI,MAAM,CAIrC;AA+VD,wBAAsB,gBAAgB,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,aAAa,CAAC,CA+D9F;AAED,wBAAsB,SAAS,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgB9E;AAwBD,wBAAsB,wBAAwB,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC,CAkDhI;AAED,wBAAsB,WAAW,CAAC,OAAO,GAAE,iBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBhF;AAsBD,cAAc,aAAa,CAAC"}