@treenity/react 3.0.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (369) hide show
  1. package/README.md +91 -0
  2. package/dist/AclEditor.d.ts +1 -1
  3. package/dist/AclEditor.d.ts.map +1 -1
  4. package/dist/AclEditor.js +5 -5
  5. package/dist/AclEditor.js.map +1 -1
  6. package/dist/ActionCards.d.ts +9 -0
  7. package/dist/ActionCards.d.ts.map +1 -0
  8. package/dist/ActionCards.js +96 -0
  9. package/dist/ActionCards.js.map +1 -0
  10. package/dist/App.d.ts.map +1 -1
  11. package/dist/App.js +71 -185
  12. package/dist/App.js.map +1 -1
  13. package/dist/ComponentSection.d.ts +15 -0
  14. package/dist/ComponentSection.d.ts.map +1 -0
  15. package/dist/ComponentSection.js +25 -0
  16. package/dist/ComponentSection.js.map +1 -0
  17. package/dist/ErrorBoundary.d.ts +18 -0
  18. package/dist/ErrorBoundary.d.ts.map +1 -0
  19. package/dist/ErrorBoundary.js +17 -0
  20. package/dist/ErrorBoundary.js.map +1 -0
  21. package/dist/Inspector.d.ts +1 -0
  22. package/dist/Inspector.d.ts.map +1 -1
  23. package/dist/Inspector.js +22 -347
  24. package/dist/Inspector.js.map +1 -1
  25. package/dist/Login.d.ts +8 -0
  26. package/dist/Login.d.ts.map +1 -0
  27. package/dist/Login.js +45 -0
  28. package/dist/Login.js.map +1 -0
  29. package/dist/NodeEditor.d.ts +11 -0
  30. package/dist/NodeEditor.d.ts.map +1 -0
  31. package/dist/NodeEditor.js +157 -0
  32. package/dist/NodeEditor.js.map +1 -0
  33. package/dist/Tree.d.ts +1 -0
  34. package/dist/Tree.d.ts.map +1 -1
  35. package/dist/Tree.js +8 -27
  36. package/dist/Tree.js.map +1 -1
  37. package/dist/bind/engine.js +1 -1
  38. package/dist/bind/engine.js.map +1 -1
  39. package/dist/bind/eval.d.ts +1 -1
  40. package/dist/bind/eval.d.ts.map +1 -1
  41. package/dist/bind/hook.d.ts +1 -1
  42. package/dist/bind/hook.d.ts.map +1 -1
  43. package/dist/bind/hook.js +1 -1
  44. package/dist/bind/hook.js.map +1 -1
  45. package/dist/cache.d.ts +1 -1
  46. package/dist/cache.d.ts.map +1 -1
  47. package/dist/cache.js +4 -0
  48. package/dist/cache.js.map +1 -1
  49. package/dist/client-tree.d.ts +1 -2
  50. package/dist/client-tree.d.ts.map +1 -1
  51. package/dist/client-tree.js +12 -5
  52. package/dist/client-tree.js.map +1 -1
  53. package/dist/client.d.ts +1 -1
  54. package/dist/client.d.ts.map +1 -1
  55. package/dist/client.js +2 -4
  56. package/dist/client.js.map +1 -1
  57. package/dist/components/ConfirmDialog.d.ts +9 -0
  58. package/dist/components/ConfirmDialog.d.ts.map +1 -0
  59. package/dist/components/ConfirmDialog.js +6 -0
  60. package/dist/components/ConfirmDialog.js.map +1 -0
  61. package/dist/components/ConfirmPopover.d.ts +8 -0
  62. package/dist/components/ConfirmPopover.d.ts.map +1 -0
  63. package/dist/components/ConfirmPopover.js +9 -0
  64. package/dist/components/ConfirmPopover.js.map +1 -0
  65. package/dist/components/PathBreadcrumb.d.ts +5 -0
  66. package/dist/components/PathBreadcrumb.d.ts.map +1 -0
  67. package/dist/components/PathBreadcrumb.js +16 -0
  68. package/dist/components/PathBreadcrumb.js.map +1 -0
  69. package/dist/components/lib/utils.d.ts +3 -0
  70. package/dist/components/lib/utils.d.ts.map +1 -0
  71. package/dist/components/lib/utils.js +6 -0
  72. package/dist/components/lib/utils.js.map +1 -0
  73. package/dist/components/ui/accordion.js +1 -1
  74. package/dist/components/ui/accordion.js.map +1 -1
  75. package/dist/components/ui/alert-dialog.d.ts +19 -0
  76. package/dist/components/ui/alert-dialog.d.ts.map +1 -0
  77. package/dist/components/ui/alert-dialog.js +42 -0
  78. package/dist/components/ui/alert-dialog.js.map +1 -0
  79. package/dist/components/ui/badge.js +1 -1
  80. package/dist/components/ui/badge.js.map +1 -1
  81. package/dist/components/ui/breadcrumb.d.ts +12 -0
  82. package/dist/components/ui/breadcrumb.d.ts.map +1 -0
  83. package/dist/components/ui/breadcrumb.js +28 -0
  84. package/dist/components/ui/breadcrumb.js.map +1 -0
  85. package/dist/components/ui/button.d.ts +9 -8
  86. package/dist/components/ui/button.d.ts.map +1 -1
  87. package/dist/components/ui/button.js +26 -21
  88. package/dist/components/ui/button.js.map +1 -1
  89. package/dist/components/ui/card.d.ts +10 -0
  90. package/dist/components/ui/card.d.ts.map +1 -0
  91. package/dist/components/ui/card.js +25 -0
  92. package/dist/components/ui/card.js.map +1 -0
  93. package/dist/components/ui/checkbox.js +1 -1
  94. package/dist/components/ui/checkbox.js.map +1 -1
  95. package/dist/components/ui/collapsible.d.ts +6 -0
  96. package/dist/components/ui/collapsible.d.ts.map +1 -0
  97. package/dist/components/ui/collapsible.js +13 -0
  98. package/dist/components/ui/collapsible.js.map +1 -0
  99. package/dist/components/ui/command.d.ts +19 -0
  100. package/dist/components/ui/command.d.ts.map +1 -0
  101. package/dist/components/ui/command.js +35 -0
  102. package/dist/components/ui/command.js.map +1 -0
  103. package/dist/components/ui/dialog.d.ts.map +1 -1
  104. package/dist/components/ui/dialog.js +1 -1
  105. package/dist/components/ui/dialog.js.map +1 -1
  106. package/dist/components/ui/drawer.js +1 -1
  107. package/dist/components/ui/drawer.js.map +1 -1
  108. package/dist/components/ui/dropdown-menu.d.ts +26 -0
  109. package/dist/components/ui/dropdown-menu.d.ts.map +1 -0
  110. package/dist/components/ui/dropdown-menu.js +52 -0
  111. package/dist/components/ui/dropdown-menu.js.map +1 -0
  112. package/dist/components/ui/form-field.d.ts +7 -0
  113. package/dist/components/ui/form-field.d.ts.map +1 -0
  114. package/dist/components/ui/form-field.js +17 -0
  115. package/dist/components/ui/form-field.js.map +1 -0
  116. package/dist/components/ui/input.js +1 -1
  117. package/dist/components/ui/input.js.map +1 -1
  118. package/dist/components/ui/label.js +1 -1
  119. package/dist/components/ui/label.js.map +1 -1
  120. package/dist/components/ui/pagination.d.ts +14 -0
  121. package/dist/components/ui/pagination.d.ts.map +1 -0
  122. package/dist/components/ui/pagination.js +30 -0
  123. package/dist/components/ui/pagination.js.map +1 -0
  124. package/dist/components/ui/popover.js +2 -2
  125. package/dist/components/ui/popover.js.map +1 -1
  126. package/dist/components/ui/progress.js +1 -1
  127. package/dist/components/ui/progress.js.map +1 -1
  128. package/dist/components/ui/resizable.d.ts +8 -0
  129. package/dist/components/ui/resizable.d.ts.map +1 -0
  130. package/dist/components/ui/resizable.js +14 -0
  131. package/dist/components/ui/resizable.js.map +1 -0
  132. package/dist/components/ui/scroll-area.d.ts +6 -0
  133. package/dist/components/ui/scroll-area.d.ts.map +1 -0
  134. package/dist/components/ui/scroll-area.js +13 -0
  135. package/dist/components/ui/scroll-area.js.map +1 -0
  136. package/dist/components/ui/select.js +1 -1
  137. package/dist/components/ui/select.js.map +1 -1
  138. package/dist/components/ui/separator.d.ts +5 -0
  139. package/dist/components/ui/separator.d.ts.map +1 -0
  140. package/dist/components/ui/separator.js +9 -0
  141. package/dist/components/ui/separator.js.map +1 -0
  142. package/dist/components/ui/sheet.d.ts +15 -0
  143. package/dist/components/ui/sheet.d.ts.map +1 -0
  144. package/dist/components/ui/sheet.js +40 -0
  145. package/dist/components/ui/sheet.js.map +1 -0
  146. package/dist/components/ui/skeleton.d.ts +3 -0
  147. package/dist/components/ui/skeleton.d.ts.map +1 -0
  148. package/dist/components/ui/skeleton.js +7 -0
  149. package/dist/components/ui/skeleton.js.map +1 -0
  150. package/dist/components/ui/slider.js +1 -1
  151. package/dist/components/ui/slider.js.map +1 -1
  152. package/dist/components/ui/switch.js +1 -1
  153. package/dist/components/ui/switch.js.map +1 -1
  154. package/dist/components/ui/table.d.ts +11 -0
  155. package/dist/components/ui/table.d.ts.map +1 -0
  156. package/dist/components/ui/table.js +29 -0
  157. package/dist/components/ui/table.js.map +1 -0
  158. package/dist/components/ui/tabs.d.ts +12 -0
  159. package/dist/components/ui/tabs.d.ts.map +1 -0
  160. package/dist/components/ui/tabs.js +29 -0
  161. package/dist/components/ui/tabs.js.map +1 -0
  162. package/dist/components/ui/textarea.js +1 -1
  163. package/dist/components/ui/textarea.js.map +1 -1
  164. package/dist/components/ui/toggle-group.d.ts +10 -0
  165. package/dist/components/ui/toggle-group.d.ts.map +1 -0
  166. package/dist/components/ui/toggle-group.js +23 -0
  167. package/dist/components/ui/toggle-group.js.map +1 -0
  168. package/dist/components/ui/toggle.d.ts +10 -0
  169. package/dist/components/ui/toggle.d.ts.map +1 -0
  170. package/dist/components/ui/toggle.js +27 -0
  171. package/dist/components/ui/toggle.js.map +1 -0
  172. package/dist/components/ui/tooltip.js +1 -1
  173. package/dist/components/ui/tooltip.js.map +1 -1
  174. package/dist/context/index.d.ts +27 -10
  175. package/dist/context/index.d.ts.map +1 -1
  176. package/dist/context/index.js +43 -36
  177. package/dist/context/index.js.map +1 -1
  178. package/dist/events.d.ts +10 -0
  179. package/dist/events.d.ts.map +1 -0
  180. package/dist/events.js +78 -0
  181. package/dist/events.js.map +1 -0
  182. package/dist/fiber-tree.d.ts +3 -0
  183. package/dist/fiber-tree.d.ts.map +1 -0
  184. package/dist/fiber-tree.js +93 -0
  185. package/dist/fiber-tree.js.map +1 -0
  186. package/dist/hooks.d.ts +5 -2
  187. package/dist/hooks.d.ts.map +1 -1
  188. package/dist/hooks.js +66 -6
  189. package/dist/hooks.js.map +1 -1
  190. package/dist/idb.d.ts +1 -1
  191. package/dist/idb.d.ts.map +1 -1
  192. package/dist/lib/to-plain.d.ts +2 -0
  193. package/dist/lib/to-plain.d.ts.map +1 -0
  194. package/dist/lib/to-plain.js +21 -0
  195. package/dist/lib/to-plain.js.map +1 -0
  196. package/dist/main.d.ts +1 -1
  197. package/dist/main.d.ts.map +1 -1
  198. package/dist/main.js +4 -3
  199. package/dist/main.js.map +1 -1
  200. package/dist/mods/clients.d.ts +3 -0
  201. package/dist/mods/clients.d.ts.map +1 -0
  202. package/dist/mods/clients.js +4 -0
  203. package/dist/mods/clients.js.map +1 -0
  204. package/dist/mods/editor-ui/FieldLabel.d.ts +15 -0
  205. package/dist/mods/editor-ui/FieldLabel.d.ts.map +1 -0
  206. package/dist/mods/editor-ui/FieldLabel.js +55 -0
  207. package/dist/mods/editor-ui/FieldLabel.js.map +1 -0
  208. package/dist/mods/editor-ui/client.d.ts +1 -1
  209. package/dist/mods/editor-ui/client.d.ts.map +1 -1
  210. package/dist/mods/editor-ui/client.js +1 -1
  211. package/dist/mods/editor-ui/client.js.map +1 -1
  212. package/dist/mods/editor-ui/default-edit.d.ts +2 -0
  213. package/dist/mods/editor-ui/default-edit.d.ts.map +1 -0
  214. package/dist/mods/editor-ui/default-edit.js +54 -0
  215. package/dist/mods/editor-ui/default-edit.js.map +1 -0
  216. package/dist/mods/editor-ui/default-view.d.ts +8 -1
  217. package/dist/mods/editor-ui/default-view.d.ts.map +1 -1
  218. package/dist/mods/editor-ui/default-view.js +8 -5
  219. package/dist/mods/editor-ui/default-view.js.map +1 -1
  220. package/dist/mods/editor-ui/dir-view.js +0 -2
  221. package/dist/mods/editor-ui/dir-view.js.map +1 -1
  222. package/dist/mods/editor-ui/empty-placeholder.d.ts +5 -0
  223. package/dist/mods/editor-ui/empty-placeholder.d.ts.map +1 -0
  224. package/dist/mods/editor-ui/empty-placeholder.js +14 -0
  225. package/dist/mods/editor-ui/empty-placeholder.js.map +1 -0
  226. package/dist/mods/editor-ui/form-field.d.ts +17 -0
  227. package/dist/mods/editor-ui/form-field.d.ts.map +1 -0
  228. package/dist/mods/editor-ui/form-field.js +68 -0
  229. package/dist/mods/editor-ui/form-field.js.map +1 -0
  230. package/dist/mods/editor-ui/form-fields.d.ts +1 -2
  231. package/dist/mods/editor-ui/form-fields.d.ts.map +1 -1
  232. package/dist/mods/editor-ui/form-fields.js +56 -60
  233. package/dist/mods/editor-ui/form-fields.js.map +1 -1
  234. package/dist/mods/editor-ui/layout-view.js +3 -2
  235. package/dist/mods/editor-ui/layout-view.js.map +1 -1
  236. package/dist/mods/editor-ui/list-items.js +1 -1
  237. package/dist/mods/editor-ui/list-items.js.map +1 -1
  238. package/dist/mods/editor-ui/node-utils.d.ts +2 -2
  239. package/dist/mods/editor-ui/node-utils.d.ts.map +1 -1
  240. package/dist/mods/editor-ui/node-utils.js +4 -5
  241. package/dist/mods/editor-ui/node-utils.js.map +1 -1
  242. package/dist/mods/editor-ui/type-picker.d.ts +15 -0
  243. package/dist/mods/editor-ui/type-picker.d.ts.map +1 -0
  244. package/dist/mods/editor-ui/type-picker.js +69 -0
  245. package/dist/mods/editor-ui/type-picker.js.map +1 -0
  246. package/dist/mods/editor-ui/user-view.js +1 -1
  247. package/dist/mods/editor-ui/user-view.js.map +1 -1
  248. package/dist/mods/servers.d.ts +1 -0
  249. package/dist/mods/servers.d.ts.map +1 -0
  250. package/dist/mods/servers.js +4 -0
  251. package/dist/mods/servers.js.map +1 -0
  252. package/dist/mods/treenity/groups/index.js +1 -1
  253. package/dist/mods/treenity/groups/index.js.map +1 -1
  254. package/dist/mods/treenity/preview.js +1 -1
  255. package/dist/mods/treenity/preview.js.map +1 -1
  256. package/dist/mods/treenity/ref-view.js +1 -1
  257. package/dist/mods/treenity/ref-view.js.map +1 -1
  258. package/dist/mods/treenity/schema-form.js +1 -1
  259. package/dist/mods/treenity/schema-form.js.map +1 -1
  260. package/dist/mods/treenity/seed.js +1 -1
  261. package/dist/mods/treenity/seed.js.map +1 -1
  262. package/dist/mods/treenity/type-view.js +1 -1
  263. package/dist/mods/treenity/type-view.js.map +1 -1
  264. package/dist/schema-loader.d.ts +1 -1
  265. package/dist/schema-loader.d.ts.map +1 -1
  266. package/dist/schema-loader.js +1 -1
  267. package/dist/schema-loader.js.map +1 -1
  268. package/dist/symbols.d.ts +5 -0
  269. package/dist/symbols.d.ts.map +1 -0
  270. package/dist/symbols.js +16 -0
  271. package/dist/symbols.js.map +1 -0
  272. package/dist/trpc.d.ts +10 -3
  273. package/dist/trpc.d.ts.map +1 -1
  274. package/package.json +74 -8
  275. package/src/AclEditor.tsx +11 -18
  276. package/src/ActionCards.tsx +224 -0
  277. package/src/App.tsx +204 -385
  278. package/src/ComponentSection.tsx +113 -0
  279. package/src/ErrorBoundary.tsx +37 -0
  280. package/src/Inspector.css +54 -0
  281. package/src/Inspector.tsx +73 -793
  282. package/src/Login.tsx +97 -0
  283. package/src/NodeEditor.tsx +300 -0
  284. package/src/Tree.css +91 -0
  285. package/src/Tree.tsx +40 -43
  286. package/src/bind/bind.test.ts +1 -1
  287. package/src/bind/engine.ts +1 -1
  288. package/src/bind/eval.ts +1 -1
  289. package/src/bind/hook.ts +1 -1
  290. package/src/bind/pipes.ts +1 -1
  291. package/src/cache.ts +5 -1
  292. package/src/client-tree.test.ts +1 -1
  293. package/src/client-tree.ts +22 -16
  294. package/src/client.ts +2 -4
  295. package/src/components/ConfirmDialog.tsx +34 -0
  296. package/src/components/ConfirmPopover.tsx +41 -0
  297. package/src/components/PathBreadcrumb.tsx +36 -0
  298. package/src/components/lib/utils.ts +6 -0
  299. package/src/components/lib/utils.ts.bak +6 -0
  300. package/src/components/ui/accordion.tsx +1 -1
  301. package/src/components/ui/alert-dialog.tsx +189 -0
  302. package/src/components/ui/badge.tsx +1 -1
  303. package/src/components/ui/breadcrumb.tsx +108 -0
  304. package/src/components/ui/button.tsx +53 -31
  305. package/src/components/ui/card.tsx +91 -0
  306. package/src/components/ui/checkbox.tsx +1 -1
  307. package/src/components/ui/collapsible.tsx +31 -0
  308. package/src/components/ui/command.tsx +177 -0
  309. package/src/components/ui/dialog.tsx +1 -2
  310. package/src/components/ui/drawer.tsx +1 -1
  311. package/src/components/ui/dropdown-menu.tsx +256 -0
  312. package/src/components/ui/form-field.tsx +37 -0
  313. package/src/components/ui/input.tsx +1 -1
  314. package/src/components/ui/label.tsx +1 -1
  315. package/src/components/ui/pagination.tsx +127 -0
  316. package/src/components/ui/popover.tsx +2 -2
  317. package/src/components/ui/progress.tsx +1 -1
  318. package/src/components/ui/resizable.tsx +47 -0
  319. package/src/components/ui/scroll-area.tsx +55 -0
  320. package/src/components/ui/select.tsx +1 -1
  321. package/src/components/ui/separator.tsx +27 -0
  322. package/src/components/ui/sheet.tsx +140 -0
  323. package/src/components/ui/skeleton.tsx +13 -0
  324. package/src/components/ui/slider.tsx +1 -1
  325. package/src/components/ui/switch.tsx +1 -1
  326. package/src/components/ui/table.tsx +115 -0
  327. package/src/components/ui/tabs.tsx +88 -0
  328. package/src/components/ui/textarea.tsx +1 -1
  329. package/src/components/ui/toggle-group.tsx +82 -0
  330. package/src/components/ui/toggle.tsx +46 -0
  331. package/src/components/ui/tooltip.tsx +1 -1
  332. package/src/context/index.tsx +75 -42
  333. package/src/events.ts +81 -0
  334. package/src/fiber-tree.ts +112 -0
  335. package/src/hooks.ts +88 -9
  336. package/src/idb.ts +1 -1
  337. package/src/lib/to-plain.ts +21 -0
  338. package/src/main.tsx +3 -1
  339. package/src/mods/clients.ts +3 -0
  340. package/src/mods/editor-ui/FieldLabel.tsx +124 -0
  341. package/src/mods/editor-ui/client.ts +1 -1
  342. package/src/mods/editor-ui/default-edit.tsx +99 -0
  343. package/src/mods/editor-ui/default-view.tsx +13 -8
  344. package/src/mods/editor-ui/dir-view.tsx +2 -2
  345. package/src/mods/editor-ui/editor-ui.css +174 -0
  346. package/src/mods/editor-ui/empty-placeholder.tsx +39 -0
  347. package/src/mods/editor-ui/form-field.tsx +144 -0
  348. package/src/mods/editor-ui/form-fields.tsx +132 -113
  349. package/src/mods/editor-ui/layout-view.tsx +4 -2
  350. package/src/mods/editor-ui/list-items.tsx +2 -2
  351. package/src/mods/editor-ui/node-utils.ts +4 -5
  352. package/src/mods/editor-ui/type-picker.tsx +147 -0
  353. package/src/mods/editor-ui/user-view.tsx +1 -1
  354. package/src/mods/servers.ts +2 -0
  355. package/src/mods/treenity/groups/index.tsx +1 -1
  356. package/src/mods/treenity/preview.tsx +1 -1
  357. package/src/mods/treenity/ref-view.tsx +1 -1
  358. package/src/mods/treenity/schema-form.tsx +1 -1
  359. package/src/mods/treenity/seed.ts +1 -1
  360. package/src/mods/treenity/type-view.tsx +1 -1
  361. package/src/optimistic.test.ts +111 -0
  362. package/src/remote-tree.test.ts +1 -1
  363. package/src/remote-tree.ts +1 -1
  364. package/src/root.css +117 -0
  365. package/src/schema-loader.ts +1 -1
  366. package/src/symbols.ts +18 -0
  367. package/src/index.html +0 -14
  368. package/src/style.css +0 -1269
  369. package/src/vite-env.d.ts +0 -3
@@ -1,24 +1,30 @@
1
1
  // Unified Client Tree — the browser as a peer node.
2
- // /local/* paths live in browser memory only (never hit the network).
3
- // Everything else routes through tRPC to the server.
4
- // Same Tree interface everywhere — components don't know where data lives.
2
+ // FilterTree: /local/* memory+mounts, everything else remote.
3
+ // Reads merge both /local visible alongside server nodes.
5
4
 
6
- import { createFilterTree, createMemoryTree } from '@treenity/core/tree';
7
- import { withCache } from '@treenity/core/tree/cache';
8
- import { createRemoteTree } from './remote-tree';
9
- import type { trpc } from './trpc';
5
+ import type { NodeData } from '@treenity/core'
6
+ import { createFilterTree, createMemoryTree } from '@treenity/core/tree'
7
+ import { withCache } from '@treenity/core/tree/cache'
8
+ import { withMounts } from '@treenity/core/server/mount'
9
+ import './fiber-tree' // registers t.mount.react
10
+ import { createRemoteTree } from './remote-tree'
11
+ import type { trpc } from './trpc'
10
12
 
11
- type TrpcClient = typeof trpc;
13
+ type TrpcClient = typeof trpc
12
14
 
13
15
  export function createClientTree(client: TrpcClient) {
14
- const local = createMemoryTree();
15
- const remote = withCache(createRemoteTree(client));
16
+ const memory = createMemoryTree()
17
+ const remote = withCache(createRemoteTree(client))
16
18
 
17
- const tree = createFilterTree(
18
- local,
19
- remote,
20
- (node) => node.$path.startsWith('/local'),
21
- );
19
+ // Seed local tree
20
+ memory.set({ $path: '/local', $type: 'dir' } as NodeData)
21
+ memory.set({ $path: '/local/react', $type: 'dir', mount: { $type: 't.mount.react' } } as NodeData)
22
22
 
23
- return { tree, local, remote };
23
+ const local = withMounts(memory)
24
+
25
+ // Writes: /local/* → memory, else → remote
26
+ // Reads: merge both — /local visible alongside server nodes
27
+ const tree = createFilterTree(local, remote, (node) => node.$path.startsWith('/local'))
28
+
29
+ return { tree }
24
30
  }
package/src/client.ts CHANGED
@@ -1,11 +1,9 @@
1
1
  /// <reference types="vite/client" />
2
- // The browser peer node — singleton client tree.
3
- // /local/* in memory, everything else via tRPC.
2
+ // The browser peer node — memory is root, server is mounted.
4
3
 
5
4
  import { createClientTree } from './client-tree';
6
5
  import { trpc } from './trpc';
7
6
 
8
- export const { tree, local, remote } = createClientTree(trpc);
7
+ export const { tree } = createClientTree(trpc);
9
8
 
10
- // Dev: expose tree for console debugging (e.g. __tree.get('/local/ui/theme'))
11
9
  if (import.meta.env?.DEV) (globalThis as any).__tree = tree;
@@ -0,0 +1,34 @@
1
+ import {
2
+ AlertDialog,
3
+ AlertDialogAction,
4
+ AlertDialogCancel,
5
+ AlertDialogContent,
6
+ AlertDialogDescription,
7
+ AlertDialogFooter,
8
+ AlertDialogHeader,
9
+ AlertDialogTitle,
10
+ } from '#components/ui/alert-dialog';
11
+
12
+ export function ConfirmDialog({ open, onOpenChange, title, description, onConfirm, variant = 'default' }: {
13
+ open: boolean;
14
+ onOpenChange: (open: boolean) => void;
15
+ title: string;
16
+ description?: string;
17
+ onConfirm: () => void;
18
+ variant?: 'default' | 'destructive';
19
+ }) {
20
+ return (
21
+ <AlertDialog open={open} onOpenChange={onOpenChange}>
22
+ <AlertDialogContent>
23
+ <AlertDialogHeader>
24
+ <AlertDialogTitle>{title}</AlertDialogTitle>
25
+ {description && <AlertDialogDescription>{description}</AlertDialogDescription>}
26
+ </AlertDialogHeader>
27
+ <AlertDialogFooter>
28
+ <AlertDialogCancel>Cancel</AlertDialogCancel>
29
+ <AlertDialogAction variant={variant} onClick={onConfirm}>Confirm</AlertDialogAction>
30
+ </AlertDialogFooter>
31
+ </AlertDialogContent>
32
+ </AlertDialog>
33
+ );
34
+ }
@@ -0,0 +1,41 @@
1
+ import { Button } from '#components/ui/button';
2
+ import { Popover, PopoverContent, PopoverTrigger } from '#components/ui/popover';
3
+ import { type ReactNode, useState } from 'react';
4
+
5
+ export function ConfirmPopover({
6
+ title,
7
+ onConfirm,
8
+ variant = 'default',
9
+ children,
10
+ }: {
11
+ title: string;
12
+ onConfirm: () => void;
13
+ variant?: 'default' | 'destructive';
14
+ children: ReactNode;
15
+ }) {
16
+ const [open, setOpen] = useState(false);
17
+
18
+ return (
19
+ <Popover open={open} onOpenChange={setOpen}>
20
+ <PopoverTrigger asChild>
21
+ {children}
22
+ </PopoverTrigger>
23
+ <PopoverContent
24
+ align="end"
25
+ side="bottom"
26
+ className="w-auto p-3 flex flex-col gap-2"
27
+ onClick={(e) => e.stopPropagation()}
28
+ >
29
+ <p className="text-xs text-muted-foreground">{title}</p>
30
+ <div className="flex gap-1.5 justify-end">
31
+ <Button variant="ghost" size="sm" className="h-7 text-xs" onClick={() => setOpen(false)}>
32
+ Cancel
33
+ </Button>
34
+ <Button variant={variant} size="sm" className="h-7 text-xs" onClick={() => { onConfirm(); setOpen(false); }}>
35
+ Confirm
36
+ </Button>
37
+ </div>
38
+ </PopoverContent>
39
+ </Popover>
40
+ );
41
+ }
@@ -0,0 +1,36 @@
1
+ import {
2
+ Breadcrumb,
3
+ BreadcrumbItem,
4
+ BreadcrumbLink,
5
+ BreadcrumbList,
6
+ BreadcrumbPage,
7
+ BreadcrumbSeparator,
8
+ } from '#components/ui/breadcrumb';
9
+
10
+ export function PathBreadcrumb({ path, onSelect }: { path: string; onSelect: (p: string) => void }) {
11
+ const parts = path.split('/').filter(Boolean);
12
+ const crumbs: { label: string; path: string }[] = [{ label: 'root', path: '/' }];
13
+ let cur = '';
14
+ for (const p of parts) {
15
+ cur += '/' + p;
16
+ crumbs.push({ label: p, path: cur });
17
+ }
18
+ const last = crumbs.length - 1;
19
+
20
+ return (
21
+ <Breadcrumb className="mb-2 text-xs">
22
+ <BreadcrumbList className="text-xs gap-1 sm:gap-1">
23
+ {crumbs.map((c, i) => (
24
+ <span key={c.path} className="contents">
25
+ {i > 0 && <BreadcrumbSeparator className="[&>svg]:size-3" />}
26
+ <BreadcrumbItem>
27
+ {i === last
28
+ ? <BreadcrumbPage>{c.label}</BreadcrumbPage>
29
+ : <BreadcrumbLink className="cursor-pointer" onClick={() => onSelect(c.path)}>{c.label}</BreadcrumbLink>}
30
+ </BreadcrumbItem>
31
+ </span>
32
+ ))}
33
+ </BreadcrumbList>
34
+ </Breadcrumb>
35
+ );
36
+ }
@@ -0,0 +1,6 @@
1
+ import { type ClassValue, clsx } from 'clsx';
2
+ import { twMerge } from 'tailwind-merge';
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs));
6
+ }
@@ -0,0 +1,6 @@
1
+ import { type ClassValue, clsx } from 'clsx';
2
+ import { twMerge } from 'tailwind-merge';
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs));
6
+ }
@@ -1,4 +1,4 @@
1
- import { cn } from '#lib/utils';
1
+ import { cn } from '#components/lib/utils';
2
2
  import { ChevronDownIcon } from 'lucide-react';
3
3
  import { Accordion as AccordionPrimitive } from 'radix-ui';
4
4
  import * as React from 'react';
@@ -0,0 +1,189 @@
1
+ import { cn } from '#components/lib/utils';
2
+ import { type ButtonProps, buttonVariants } from '#components/ui/button';
3
+ import { AlertDialog as AlertDialogPrimitive } from 'radix-ui';
4
+ import * as React from 'react';
5
+
6
+ function AlertDialog({
7
+ ...props
8
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Root>) {
9
+ return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />
10
+ }
11
+
12
+ function AlertDialogTrigger({
13
+ ...props
14
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Trigger>) {
15
+ return (
16
+ <AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
17
+ )
18
+ }
19
+
20
+ function AlertDialogPortal({
21
+ ...props
22
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Portal>) {
23
+ return (
24
+ <AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
25
+ )
26
+ }
27
+
28
+ function AlertDialogOverlay({
29
+ className,
30
+ ...props
31
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) {
32
+ return (
33
+ <AlertDialogPrimitive.Overlay
34
+ data-slot="alert-dialog-overlay"
35
+ className={cn(
36
+ "fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:animate-in data-[state=open]:fade-in-0",
37
+ className
38
+ )}
39
+ {...props}
40
+ />
41
+ )
42
+ }
43
+
44
+ function AlertDialogContent({
45
+ className,
46
+ size = "default",
47
+ ...props
48
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Content> & {
49
+ size?: "default" | "sm"
50
+ }) {
51
+ return (
52
+ <AlertDialogPortal>
53
+ <AlertDialogOverlay />
54
+ <AlertDialogPrimitive.Content
55
+ data-slot="alert-dialog-content"
56
+ data-size={size}
57
+ className={cn(
58
+ "group/alert-dialog-content fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border bg-background p-6 shadow-lg duration-200 data-[size=sm]:max-w-xs data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 data-[size=default]:sm:max-w-lg",
59
+ className
60
+ )}
61
+ {...props}
62
+ />
63
+ </AlertDialogPortal>
64
+ )
65
+ }
66
+
67
+ function AlertDialogHeader({
68
+ className,
69
+ ...props
70
+ }: React.ComponentProps<"div">) {
71
+ return (
72
+ <div
73
+ data-slot="alert-dialog-header"
74
+ className={cn(
75
+ "grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-6 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]",
76
+ className
77
+ )}
78
+ {...props}
79
+ />
80
+ )
81
+ }
82
+
83
+ function AlertDialogFooter({
84
+ className,
85
+ ...props
86
+ }: React.ComponentProps<"div">) {
87
+ return (
88
+ <div
89
+ data-slot="alert-dialog-footer"
90
+ className={cn(
91
+ "flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end",
92
+ className
93
+ )}
94
+ {...props}
95
+ />
96
+ )
97
+ }
98
+
99
+ function AlertDialogTitle({
100
+ className,
101
+ ...props
102
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
103
+ return (
104
+ <AlertDialogPrimitive.Title
105
+ data-slot="alert-dialog-title"
106
+ className={cn(
107
+ "text-lg font-semibold sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2",
108
+ className
109
+ )}
110
+ {...props}
111
+ />
112
+ )
113
+ }
114
+
115
+ function AlertDialogDescription({
116
+ className,
117
+ ...props
118
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
119
+ return (
120
+ <AlertDialogPrimitive.Description
121
+ data-slot="alert-dialog-description"
122
+ className={cn("text-sm text-muted-foreground", className)}
123
+ {...props}
124
+ />
125
+ )
126
+ }
127
+
128
+ function AlertDialogMedia({
129
+ className,
130
+ ...props
131
+ }: React.ComponentProps<"div">) {
132
+ return (
133
+ <div
134
+ data-slot="alert-dialog-media"
135
+ className={cn(
136
+ "mb-2 inline-flex size-16 items-center justify-center rounded-md bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-8",
137
+ className
138
+ )}
139
+ {...props}
140
+ />
141
+ )
142
+ }
143
+
144
+ function AlertDialogAction({
145
+ className,
146
+ variant = "default",
147
+ size = "default",
148
+ ...props
149
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Action> &
150
+ Pick<ButtonProps, 'variant' | 'size'>) {
151
+ return (
152
+ <AlertDialogPrimitive.Action
153
+ data-slot="alert-dialog-action"
154
+ className={cn(buttonVariants({ variant, size }), className)}
155
+ {...props}
156
+ />
157
+ )
158
+ }
159
+
160
+ function AlertDialogCancel({
161
+ className,
162
+ variant = "outline",
163
+ size = "default",
164
+ ...props
165
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Cancel> &
166
+ Pick<ButtonProps, 'variant' | 'size'>) {
167
+ return (
168
+ <AlertDialogPrimitive.Cancel
169
+ data-slot="alert-dialog-cancel"
170
+ className={cn(buttonVariants({ variant, size }), className)}
171
+ {...props}
172
+ />
173
+ )
174
+ }
175
+
176
+ export {
177
+ AlertDialog,
178
+ AlertDialogAction,
179
+ AlertDialogCancel,
180
+ AlertDialogContent,
181
+ AlertDialogDescription,
182
+ AlertDialogFooter,
183
+ AlertDialogHeader,
184
+ AlertDialogMedia,
185
+ AlertDialogOverlay,
186
+ AlertDialogPortal,
187
+ AlertDialogTitle,
188
+ AlertDialogTrigger,
189
+ }
@@ -1,4 +1,4 @@
1
- import { cn } from '#lib/utils';
1
+ import { cn } from '#components/lib/utils';
2
2
  import { cva, type VariantProps } from 'class-variance-authority';
3
3
  import { type HTMLAttributes } from 'react';
4
4
 
@@ -0,0 +1,108 @@
1
+ import { cn } from '#components/lib/utils';
2
+ import { ChevronRight, MoreHorizontal } from 'lucide-react';
3
+ import { Slot } from 'radix-ui';
4
+ import * as React from 'react';
5
+
6
+ function Breadcrumb({ ...props }: React.ComponentProps<"nav">) {
7
+ return <nav aria-label="breadcrumb" data-slot="breadcrumb" {...props} />
8
+ }
9
+
10
+ function BreadcrumbList({ className, ...props }: React.ComponentProps<"ol">) {
11
+ return (
12
+ <ol
13
+ data-slot="breadcrumb-list"
14
+ className={cn(
15
+ "flex flex-wrap items-center gap-1.5 text-sm break-words text-muted-foreground sm:gap-2.5",
16
+ className
17
+ )}
18
+ {...props}
19
+ />
20
+ )
21
+ }
22
+
23
+ function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
24
+ return (
25
+ <li
26
+ data-slot="breadcrumb-item"
27
+ className={cn("inline-flex items-center gap-1.5", className)}
28
+ {...props}
29
+ />
30
+ )
31
+ }
32
+
33
+ function BreadcrumbLink({
34
+ asChild,
35
+ className,
36
+ ...props
37
+ }: React.ComponentProps<"a"> & {
38
+ asChild?: boolean
39
+ }) {
40
+ const Comp = asChild ? Slot.Root : "a"
41
+
42
+ return (
43
+ <Comp
44
+ data-slot="breadcrumb-link"
45
+ className={cn("transition-colors hover:text-foreground", className)}
46
+ {...props}
47
+ />
48
+ )
49
+ }
50
+
51
+ function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
52
+ return (
53
+ <span
54
+ data-slot="breadcrumb-page"
55
+ role="link"
56
+ aria-disabled="true"
57
+ aria-current="page"
58
+ className={cn("font-normal text-foreground", className)}
59
+ {...props}
60
+ />
61
+ )
62
+ }
63
+
64
+ function BreadcrumbSeparator({
65
+ children,
66
+ className,
67
+ ...props
68
+ }: React.ComponentProps<"li">) {
69
+ return (
70
+ <li
71
+ data-slot="breadcrumb-separator"
72
+ role="presentation"
73
+ aria-hidden="true"
74
+ className={cn("[&>svg]:size-3.5", className)}
75
+ {...props}
76
+ >
77
+ {children ?? <ChevronRight />}
78
+ </li>
79
+ )
80
+ }
81
+
82
+ function BreadcrumbEllipsis({
83
+ className,
84
+ ...props
85
+ }: React.ComponentProps<"span">) {
86
+ return (
87
+ <span
88
+ data-slot="breadcrumb-ellipsis"
89
+ role="presentation"
90
+ aria-hidden="true"
91
+ className={cn("flex size-9 items-center justify-center", className)}
92
+ {...props}
93
+ >
94
+ <MoreHorizontal className="size-4" />
95
+ <span className="sr-only">More</span>
96
+ </span>
97
+ )
98
+ }
99
+
100
+ export {
101
+ Breadcrumb,
102
+ BreadcrumbList,
103
+ BreadcrumbItem,
104
+ BreadcrumbLink,
105
+ BreadcrumbPage,
106
+ BreadcrumbSeparator,
107
+ BreadcrumbEllipsis,
108
+ }
@@ -1,44 +1,66 @@
1
- import { cn } from '#lib/utils';
2
- import { cva, type VariantProps } from 'class-variance-authority';
3
- import { type ButtonHTMLAttributes, forwardRef } from 'react';
1
+ import * as React from "react"
2
+ import { cva, type VariantProps } from "class-variance-authority"
3
+ import { Slot } from "radix-ui"
4
+
5
+ import { cn } from "#components/lib/utils"
4
6
 
5
7
  const buttonVariants = cva(
6
- 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
8
+ "inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
7
9
  {
8
10
  variants: {
9
11
  variant: {
10
- default: 'bg-primary text-primary-foreground shadow hover:bg-primary/90',
11
- destructive: 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',
12
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
13
+ destructive:
14
+ "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:bg-destructive/60 dark:focus-visible:ring-destructive/40",
12
15
  outline:
13
- 'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
14
- outlined:
15
- 'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
16
- secondary: 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',
17
- ghost: 'hover:bg-accent hover:text-accent-foreground',
18
- link: 'text-primary underline-offset-4 hover:underline',
19
- primary: 'bg-primary text-primary-foreground shadow hover:bg-primary/90',
20
- transparent: 'bg-transparent hover:bg-accent hover:text-accent-foreground',
16
+ "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
17
+ secondary:
18
+ "bg-secondary text-secondary-foreground hover:bg-secondary/80",
19
+ ghost:
20
+ "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
21
+ link: "text-primary underline-offset-4 hover:underline",
21
22
  },
22
23
  size: {
23
- default: 'h-9 px-4 py-2',
24
- sm: 'h-8 rounded-md px-3 text-xs',
25
- lg: 'h-10 rounded-md px-8',
26
- icon: 'h-9 w-9',
27
- 'icon-sm': 'h-8 w-8',
24
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
25
+ xs: "h-6 gap-1 rounded-md px-2 text-xs has-[>svg]:px-1.5 [&_svg:not([class*='size-'])]:size-3",
26
+ sm: "h-8 gap-1.5 rounded-md px-3 has-[>svg]:px-2.5",
27
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
28
+ icon: "size-9",
29
+ "icon-xs": "size-6 rounded-md [&_svg:not([class*='size-'])]:size-3",
30
+ "icon-sm": "size-8",
31
+ "icon-lg": "size-10",
28
32
  },
29
33
  },
30
- defaultVariants: { variant: 'default', size: 'default' },
31
- },
32
- );
34
+ defaultVariants: {
35
+ variant: "default",
36
+ size: "default",
37
+ },
38
+ }
39
+ )
40
+
41
+ type ButtonProps = React.ComponentProps<"button"> &
42
+ VariantProps<typeof buttonVariants> & {
43
+ asChild?: boolean
44
+ }
33
45
 
34
- export interface ButtonProps
35
- extends ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {}
46
+ function Button({
47
+ className,
48
+ variant = "default",
49
+ size = "default",
50
+ asChild = false,
51
+ ...props
52
+ }: ButtonProps) {
53
+ const Comp = asChild ? Slot.Root : "button"
36
54
 
37
- const Button = forwardRef<HTMLButtonElement, ButtonProps>(
38
- ({ className, variant, size, ...props }, ref) => (
39
- <button className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />
40
- ),
41
- );
42
- Button.displayName = 'Button';
55
+ return (
56
+ <Comp
57
+ data-slot="button"
58
+ data-variant={variant}
59
+ data-size={size}
60
+ className={cn(buttonVariants({ variant, size, className }))}
61
+ {...props}
62
+ />
63
+ )
64
+ }
43
65
 
44
- export { Button, buttonVariants };
66
+ export { Button, buttonVariants, type ButtonProps }