@treenity/react 3.0.0 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (379) 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 +97 -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 +18 -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 +9 -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 +8 -7
  86. package/dist/components/ui/button.d.ts.map +1 -1
  87. package/dist/components/ui/button.js +25 -20
  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 +2 -2
  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 +12 -0
  179. package/dist/events.d.ts.map +1 -0
  180. package/dist/events.js +123 -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 +14 -2
  187. package/dist/hooks.d.ts.map +1 -1
  188. package/dist/hooks.js +146 -11
  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/minimd.d.ts.map +1 -1
  193. package/dist/lib/minimd.js +8 -1
  194. package/dist/lib/minimd.js.map +1 -1
  195. package/dist/lib/sanitize-href.d.ts +3 -0
  196. package/dist/lib/sanitize-href.d.ts.map +1 -0
  197. package/dist/lib/sanitize-href.js +14 -0
  198. package/dist/lib/sanitize-href.js.map +1 -0
  199. package/dist/lib/to-plain.d.ts +2 -0
  200. package/dist/lib/to-plain.d.ts.map +1 -0
  201. package/dist/lib/to-plain.js +21 -0
  202. package/dist/lib/to-plain.js.map +1 -0
  203. package/dist/main.d.ts +1 -1
  204. package/dist/main.d.ts.map +1 -1
  205. package/dist/main.js +11 -4
  206. package/dist/main.js.map +1 -1
  207. package/dist/mods/clients.d.ts +3 -0
  208. package/dist/mods/clients.d.ts.map +1 -0
  209. package/dist/mods/clients.js +4 -0
  210. package/dist/mods/clients.js.map +1 -0
  211. package/dist/mods/editor-ui/FieldLabel.d.ts +15 -0
  212. package/dist/mods/editor-ui/FieldLabel.d.ts.map +1 -0
  213. package/dist/mods/editor-ui/FieldLabel.js +56 -0
  214. package/dist/mods/editor-ui/FieldLabel.js.map +1 -0
  215. package/dist/mods/editor-ui/client.d.ts +1 -1
  216. package/dist/mods/editor-ui/client.d.ts.map +1 -1
  217. package/dist/mods/editor-ui/client.js +1 -1
  218. package/dist/mods/editor-ui/client.js.map +1 -1
  219. package/dist/mods/editor-ui/default-edit.d.ts +2 -0
  220. package/dist/mods/editor-ui/default-edit.d.ts.map +1 -0
  221. package/dist/mods/editor-ui/default-edit.js +56 -0
  222. package/dist/mods/editor-ui/default-edit.js.map +1 -0
  223. package/dist/mods/editor-ui/default-view.d.ts +8 -1
  224. package/dist/mods/editor-ui/default-view.d.ts.map +1 -1
  225. package/dist/mods/editor-ui/default-view.js +8 -5
  226. package/dist/mods/editor-ui/default-view.js.map +1 -1
  227. package/dist/mods/editor-ui/dir-view.js +0 -2
  228. package/dist/mods/editor-ui/dir-view.js.map +1 -1
  229. package/dist/mods/editor-ui/empty-placeholder.d.ts +5 -0
  230. package/dist/mods/editor-ui/empty-placeholder.d.ts.map +1 -0
  231. package/dist/mods/editor-ui/empty-placeholder.js +14 -0
  232. package/dist/mods/editor-ui/empty-placeholder.js.map +1 -0
  233. package/dist/mods/editor-ui/form-field.d.ts +17 -0
  234. package/dist/mods/editor-ui/form-field.d.ts.map +1 -0
  235. package/dist/mods/editor-ui/form-field.js +69 -0
  236. package/dist/mods/editor-ui/form-field.js.map +1 -0
  237. package/dist/mods/editor-ui/form-fields.d.ts +1 -2
  238. package/dist/mods/editor-ui/form-fields.d.ts.map +1 -1
  239. package/dist/mods/editor-ui/form-fields.js +56 -60
  240. package/dist/mods/editor-ui/form-fields.js.map +1 -1
  241. package/dist/mods/editor-ui/layout-view.js +3 -2
  242. package/dist/mods/editor-ui/layout-view.js.map +1 -1
  243. package/dist/mods/editor-ui/list-items.js +1 -1
  244. package/dist/mods/editor-ui/list-items.js.map +1 -1
  245. package/dist/mods/editor-ui/node-utils.d.ts +2 -2
  246. package/dist/mods/editor-ui/node-utils.d.ts.map +1 -1
  247. package/dist/mods/editor-ui/node-utils.js +4 -5
  248. package/dist/mods/editor-ui/node-utils.js.map +1 -1
  249. package/dist/mods/editor-ui/type-picker.d.ts +15 -0
  250. package/dist/mods/editor-ui/type-picker.d.ts.map +1 -0
  251. package/dist/mods/editor-ui/type-picker.js +70 -0
  252. package/dist/mods/editor-ui/type-picker.js.map +1 -0
  253. package/dist/mods/editor-ui/user-view.js +1 -1
  254. package/dist/mods/editor-ui/user-view.js.map +1 -1
  255. package/dist/mods/servers.d.ts +1 -0
  256. package/dist/mods/servers.d.ts.map +1 -0
  257. package/dist/mods/servers.js +4 -0
  258. package/dist/mods/servers.js.map +1 -0
  259. package/dist/mods/treenity/groups/index.js +1 -1
  260. package/dist/mods/treenity/groups/index.js.map +1 -1
  261. package/dist/mods/treenity/preview.d.ts.map +1 -1
  262. package/dist/mods/treenity/preview.js +3 -4
  263. package/dist/mods/treenity/preview.js.map +1 -1
  264. package/dist/mods/treenity/ref-view.js +3 -2
  265. package/dist/mods/treenity/ref-view.js.map +1 -1
  266. package/dist/mods/treenity/schema-form.js +1 -1
  267. package/dist/mods/treenity/schema-form.js.map +1 -1
  268. package/dist/mods/treenity/seed.js +3 -2
  269. package/dist/mods/treenity/seed.js.map +1 -1
  270. package/dist/mods/treenity/type-view.js +1 -1
  271. package/dist/mods/treenity/type-view.js.map +1 -1
  272. package/dist/schema-loader.d.ts +1 -1
  273. package/dist/schema-loader.d.ts.map +1 -1
  274. package/dist/schema-loader.js +1 -1
  275. package/dist/schema-loader.js.map +1 -1
  276. package/dist/symbols.d.ts +5 -0
  277. package/dist/symbols.d.ts.map +1 -0
  278. package/dist/symbols.js +22 -0
  279. package/dist/symbols.js.map +1 -0
  280. package/dist/trpc.d.ts +10 -3
  281. package/dist/trpc.d.ts.map +1 -1
  282. package/package.json +76 -8
  283. package/src/AclEditor.tsx +11 -18
  284. package/src/ActionCards.tsx +224 -0
  285. package/src/App.tsx +232 -385
  286. package/src/ComponentSection.tsx +113 -0
  287. package/src/ErrorBoundary.tsx +40 -0
  288. package/src/Inspector.css +54 -0
  289. package/src/Inspector.tsx +73 -793
  290. package/src/Login.tsx +97 -0
  291. package/src/NodeEditor.tsx +300 -0
  292. package/src/Tree.css +91 -0
  293. package/src/Tree.tsx +40 -43
  294. package/src/bind/engine.ts +1 -1
  295. package/src/bind/eval.ts +1 -1
  296. package/src/bind/hook.ts +1 -1
  297. package/src/bind/pipes.ts +1 -1
  298. package/src/cache.ts +12 -1
  299. package/src/client-tree.ts +18 -12
  300. package/src/client.ts +2 -4
  301. package/src/components/ConfirmDialog.tsx +34 -0
  302. package/src/components/ConfirmPopover.tsx +41 -0
  303. package/src/components/PathBreadcrumb.tsx +36 -0
  304. package/src/components/lib/utils.ts +6 -0
  305. package/src/components/lib/utils.ts.bak +6 -0
  306. package/src/components/ui/accordion.tsx +1 -1
  307. package/src/components/ui/alert-dialog.tsx +189 -0
  308. package/src/components/ui/badge.tsx +1 -1
  309. package/src/components/ui/breadcrumb.tsx +108 -0
  310. package/src/components/ui/button.tsx +51 -30
  311. package/src/components/ui/card.tsx +91 -0
  312. package/src/components/ui/checkbox.tsx +1 -1
  313. package/src/components/ui/collapsible.tsx +31 -0
  314. package/src/components/ui/command.tsx +177 -0
  315. package/src/components/ui/dialog.tsx +1 -2
  316. package/src/components/ui/drawer.tsx +1 -1
  317. package/src/components/ui/dropdown-menu.tsx +256 -0
  318. package/src/components/ui/form-field.tsx +37 -0
  319. package/src/components/ui/input.tsx +1 -1
  320. package/src/components/ui/label.tsx +1 -1
  321. package/src/components/ui/pagination.tsx +122 -0
  322. package/src/components/ui/popover.tsx +2 -2
  323. package/src/components/ui/progress.tsx +1 -1
  324. package/src/components/ui/resizable.tsx +47 -0
  325. package/src/components/ui/scroll-area.tsx +55 -0
  326. package/src/components/ui/select.tsx +1 -1
  327. package/src/components/ui/separator.tsx +27 -0
  328. package/src/components/ui/sheet.tsx +140 -0
  329. package/src/components/ui/skeleton.tsx +13 -0
  330. package/src/components/ui/slider.tsx +1 -1
  331. package/src/components/ui/switch.tsx +1 -1
  332. package/src/components/ui/table.tsx +115 -0
  333. package/src/components/ui/tabs.tsx +88 -0
  334. package/src/components/ui/textarea.tsx +2 -2
  335. package/src/components/ui/toggle-group.tsx +82 -0
  336. package/src/components/ui/toggle.tsx +46 -0
  337. package/src/components/ui/tooltip.tsx +1 -1
  338. package/src/context/index.tsx +75 -42
  339. package/src/events.ts +121 -0
  340. package/src/fiber-tree.ts +112 -0
  341. package/src/hooks.ts +161 -13
  342. package/src/idb.ts +1 -1
  343. package/src/lib/minimd.ts +7 -1
  344. package/src/lib/sanitize-href.ts +13 -0
  345. package/src/lib/to-plain.ts +21 -0
  346. package/src/main.tsx +14 -4
  347. package/src/mods/clients.ts +3 -0
  348. package/src/mods/editor-ui/FieldLabel.tsx +125 -0
  349. package/src/mods/editor-ui/client.ts +1 -1
  350. package/src/mods/editor-ui/default-edit.tsx +101 -0
  351. package/src/mods/editor-ui/default-view.tsx +13 -8
  352. package/src/mods/editor-ui/dir-view.tsx +2 -2
  353. package/src/mods/editor-ui/editor-ui.css +174 -0
  354. package/src/mods/editor-ui/empty-placeholder.tsx +39 -0
  355. package/src/mods/editor-ui/form-field.tsx +146 -0
  356. package/src/mods/editor-ui/form-fields.tsx +132 -113
  357. package/src/mods/editor-ui/layout-view.tsx +4 -2
  358. package/src/mods/editor-ui/list-items.tsx +2 -2
  359. package/src/mods/editor-ui/node-utils.ts +4 -5
  360. package/src/mods/editor-ui/type-picker.tsx +148 -0
  361. package/src/mods/editor-ui/user-view.tsx +1 -1
  362. package/src/mods/servers.ts +2 -0
  363. package/src/mods/treenity/groups/index.tsx +1 -1
  364. package/src/mods/treenity/preview.tsx +7 -8
  365. package/src/mods/treenity/ref-view.tsx +12 -7
  366. package/src/mods/treenity/schema-form.tsx +1 -1
  367. package/src/mods/treenity/seed.ts +3 -2
  368. package/src/mods/treenity/type-view.tsx +1 -1
  369. package/src/remote-tree.ts +1 -1
  370. package/src/root.css +117 -0
  371. package/src/schema-loader.ts +1 -1
  372. package/src/symbols.ts +25 -0
  373. package/src/bind/bind.test.ts +0 -316
  374. package/src/cache.test.ts +0 -139
  375. package/src/client-tree.test.ts +0 -116
  376. package/src/index.html +0 -14
  377. package/src/remote-tree.test.ts +0 -142
  378. package/src/style.css +0 -1269
  379. package/src/vite-env.d.ts +0 -3
@@ -0,0 +1,82 @@
1
+ 'use client';
2
+
3
+ import { cn } from '#components/lib/utils';
4
+ import { toggleVariants } from '#components/ui/toggle';
5
+ import { type VariantProps } from 'class-variance-authority';
6
+ import { ToggleGroup as ToggleGroupPrimitive } from 'radix-ui';
7
+ import * as React from 'react';
8
+
9
+ const ToggleGroupContext = React.createContext<
10
+ VariantProps<typeof toggleVariants> & {
11
+ spacing?: number
12
+ }
13
+ >({
14
+ size: "default",
15
+ variant: "default",
16
+ spacing: 0,
17
+ })
18
+
19
+ function ToggleGroup({
20
+ className,
21
+ variant,
22
+ size,
23
+ spacing = 0,
24
+ children,
25
+ ...props
26
+ }: React.ComponentProps<typeof ToggleGroupPrimitive.Root> &
27
+ VariantProps<typeof toggleVariants> & {
28
+ spacing?: number
29
+ }) {
30
+ return (
31
+ <ToggleGroupPrimitive.Root
32
+ data-slot="toggle-group"
33
+ data-variant={variant}
34
+ data-size={size}
35
+ data-spacing={spacing}
36
+ style={{ "--gap": spacing } as React.CSSProperties}
37
+ className={cn(
38
+ "group/toggle-group flex w-fit items-center gap-[--spacing(var(--gap))] rounded-md data-[spacing=default]:data-[variant=outline]:shadow-xs",
39
+ className
40
+ )}
41
+ {...props}
42
+ >
43
+ <ToggleGroupContext.Provider value={{ variant, size, spacing }}>
44
+ {children}
45
+ </ToggleGroupContext.Provider>
46
+ </ToggleGroupPrimitive.Root>
47
+ )
48
+ }
49
+
50
+ function ToggleGroupItem({
51
+ className,
52
+ children,
53
+ variant,
54
+ size,
55
+ ...props
56
+ }: React.ComponentProps<typeof ToggleGroupPrimitive.Item> &
57
+ VariantProps<typeof toggleVariants>) {
58
+ const context = React.useContext(ToggleGroupContext)
59
+
60
+ return (
61
+ <ToggleGroupPrimitive.Item
62
+ data-slot="toggle-group-item"
63
+ data-variant={context.variant || variant}
64
+ data-size={context.size || size}
65
+ data-spacing={context.spacing}
66
+ className={cn(
67
+ toggleVariants({
68
+ variant: context.variant || variant,
69
+ size: context.size || size,
70
+ }),
71
+ "w-auto min-w-0 shrink-0 px-3 focus:z-10 focus-visible:z-10",
72
+ "data-[spacing=0]:rounded-none data-[spacing=0]:shadow-none data-[spacing=0]:first:rounded-l-md data-[spacing=0]:last:rounded-r-md data-[spacing=0]:data-[variant=outline]:border-l-0 data-[spacing=0]:data-[variant=outline]:first:border-l",
73
+ className
74
+ )}
75
+ {...props}
76
+ >
77
+ {children}
78
+ </ToggleGroupPrimitive.Item>
79
+ )
80
+ }
81
+
82
+ export { ToggleGroup, ToggleGroupItem }
@@ -0,0 +1,46 @@
1
+ 'use client';
2
+
3
+ import { cn } from '#components/lib/utils';
4
+ import { cva, type VariantProps } from 'class-variance-authority';
5
+ import { Toggle as TogglePrimitive } from 'radix-ui';
6
+ import * as React from 'react';
7
+
8
+ const toggleVariants = cva(
9
+ "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-[color,box-shadow] outline-none hover:bg-muted hover:text-muted-foreground 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 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
10
+ {
11
+ variants: {
12
+ variant: {
13
+ default: "bg-transparent",
14
+ outline:
15
+ "border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground",
16
+ },
17
+ size: {
18
+ default: "h-9 min-w-9 px-2",
19
+ sm: "h-8 min-w-8 px-1.5",
20
+ lg: "h-10 min-w-10 px-2.5",
21
+ },
22
+ },
23
+ defaultVariants: {
24
+ variant: "default",
25
+ size: "default",
26
+ },
27
+ }
28
+ )
29
+
30
+ function Toggle({
31
+ className,
32
+ variant,
33
+ size,
34
+ ...props
35
+ }: React.ComponentProps<typeof TogglePrimitive.Root> &
36
+ VariantProps<typeof toggleVariants>) {
37
+ return (
38
+ <TogglePrimitive.Root
39
+ data-slot="toggle"
40
+ className={cn(toggleVariants({ variant, size, className }))}
41
+ {...props}
42
+ />
43
+ )
44
+ }
45
+
46
+ export { Toggle, toggleVariants }
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { cn } from '#lib/utils';
3
+ import { cn } from '#components/lib/utils';
4
4
  import { Tooltip as TooltipPrimitive } from 'radix-ui';
5
5
  import * as React from 'react';
6
6
 
@@ -2,6 +2,8 @@
2
2
  // <Render> + <RenderContext> + <NodeProvider>
3
3
  // Depends on: core (resolve), React
4
4
 
5
+ import { execute } from '#hooks';
6
+ import { $key, $node } from '#symbols';
5
7
  import {
6
8
  type ComponentData,
7
9
  hasMissResolver,
@@ -9,8 +11,8 @@ import {
9
11
  resolve,
10
12
  resolveExact,
11
13
  subscribeRegistry,
12
- } from '@treenity/core/core';
13
- import { createContext, createElement, type FC, type ReactNode, useContext, useEffect, useState } from 'react';
14
+ } from '@treenity/core';
15
+ import { createContext, createElement, type FC, type ReactNode, useContext, useEffect, useMemo, useState } from 'react';
14
16
 
15
17
  // ── Tree context (rendering context string) ──
16
18
 
@@ -28,7 +30,7 @@ export function RenderContext({ name, children }: { name: string; children: Reac
28
30
 
29
31
  const NodeCtx = createContext<NodeData | null>(null);
30
32
 
31
- export function NodeProvider({ value, children }: { value: NodeData | null; children: ReactNode }) {
33
+ export function NodeProvider({ value, children }: { value: NodeData | null; children?: ReactNode }) {
32
34
  if (!value?.$path) return null;
33
35
  return <NodeCtx.Provider value={value}>{children}</NodeCtx.Provider>;
34
36
  }
@@ -39,32 +41,67 @@ export function useCurrentNode(): NodeData {
39
41
  return n;
40
42
  }
41
43
 
44
+ // ── viewCtx — derive location context from value's symbol metadata ──
45
+
46
+ export type ViewCtx = {
47
+ node: NodeData;
48
+ path: string;
49
+ execute(action: string, data?: unknown): Promise<unknown>;
50
+ };
51
+
52
+ export function viewCtx(value: ComponentData): ViewCtx | null {
53
+ const node: NodeData | undefined = (value as any)[$node];
54
+ if (!node) return null;
55
+ const key: string = (value as any)[$key] ?? '';
56
+ const path = key ? `${node.$path}#${key}` : node.$path;
57
+ return { node, path, execute: (action, data?) => execute(path, action, data) };
58
+ }
59
+
42
60
  // ── Handler type for React context ──
43
61
  // value is ComponentData (base type). NodeData IS ComponentData.
44
- // Renderers that need $path use usePath().
45
62
 
46
- export type RenderProps = {
47
- value: ComponentData;
48
- onChange?: (next: ComponentData) => void;
63
+ export type RenderProps<T = ComponentData> = {
64
+ value: T;
65
+ onChange?: (next: T) => void;
66
+ ctx?: ViewCtx | null;
67
+ };
68
+
69
+ export type ReactHandler = FC<RenderProps<any>>;
70
+
71
+ /** Typed view component. Use: `const MyView: View<MyType> = ({ value, ctx }) => ...` */
72
+ export type View<T> = FC<RenderProps<T>>;
73
+
74
+ // ── useActions — proxy that turns value's symbol metadata into action calls ──
75
+
76
+ type Actions<T> = {
77
+ [K in keyof T as T[K] extends (...args: any[]) => any ? K : never]:
78
+ T[K] extends (data: infer D) => any
79
+ ? (data: D) => Promise<unknown>
80
+ : () => Promise<unknown>;
49
81
  };
50
82
 
51
- export type ReactHandler = FC<RenderProps>;
83
+ export function useActions<T extends ComponentData>(value: T): Actions<T> {
84
+ const ctx = viewCtx(value);
85
+ if (!ctx) throw new Error('useActions: value has no node context (missing $node symbol)');
86
+
87
+ return useMemo(() => new Proxy({} as Actions<T>, {
88
+ get: (_target, prop: string) => (data?: unknown) => ctx.execute(prop, data),
89
+ }), [ctx.path]);
90
+ }
52
91
 
53
92
  declare module '@treenity/core/core/context' {
54
- interface ContextHandlers {
55
- react: ReactHandler;
93
+ interface ContextHandlers<T> {
94
+ react: FC<RenderProps<T>>;
56
95
  }
57
96
  }
58
97
 
59
- // ── SystemFallbackView — registered by UIX when a type has no custom view ──
98
+ // ── UixNoView — registered by UIX when a type has no custom view yet ──
60
99
  // Renders default@context without going through type-specific resolve (avoids infinite loop).
61
- export const SystemFallbackView: FC<RenderProps> = ({ value, onChange }) => {
100
+ export const UixNoView: FC<RenderProps> = ({ value, onChange }) => {
62
101
  const context = useTreeContext();
63
102
  const def = resolve('default', context, false) as FC<RenderProps> | null;
64
103
  if (!def) return null;
65
- const el = createElement(def, { value, onChange });
66
- if ('$path' in value) return <NodeProvider value={value as NodeData}>{el}</NodeProvider>;
67
- return el;
104
+ return createElement(def, { value, onChange });
68
105
  };
69
106
 
70
107
  // ── <Render> — component/node-level rendering ──
@@ -73,40 +110,36 @@ export function Render({ value, onChange }: RenderProps) {
73
110
  const context = useTreeContext();
74
111
  const type = value.$type;
75
112
 
76
- // Tree actual handler in state so React Compiler can't optimize away the update
77
- // (a dummy tick counter gets eliminated because its value is never read in render output)
78
- const [Handler, setHandler] = useState<ReactHandler | null>(
79
- () => resolveExact(type, context) as ReactHandler | null,
80
- );
113
+ const ctx_ = context as 'react';
114
+ const sync = useMemo(() => resolveExact(type, ctx_), [type, ctx_]);
115
+ const [async_, setAsync] = useState<ReactHandler | null>(null);
81
116
 
82
- // Subscribe to registry bumps. When handler is registered async (UIX lazy load),
83
- // the callback fires and stores the resolved handler → triggers re-render.
84
117
  useEffect(() => {
85
- const found = resolveExact(type, context) as ReactHandler | null;
86
- if (found) { setHandler(() => found); return; }
87
- setHandler(null); // Clear stale handler when type/context changes
88
- if (hasMissResolver(context)) resolve(type, context);
89
- const unsub = subscribeRegistry(() => {
90
- const h = resolveExact(type, context) as ReactHandler | null;
91
- if (h) setHandler(() => h);
118
+ if (sync) return;
119
+ setAsync(null);
120
+ if (hasMissResolver(ctx_)) resolve(type, ctx_);
121
+
122
+ return subscribeRegistry(() => {
123
+ const h = resolveExact(type, ctx_);
124
+ if (h) setAsync(() => h);
92
125
  });
93
- return unsub;
94
- }, [type, context]);
95
-
96
- // Fallback: if no exact handler, try default/parent context resolution
97
- let Final = Handler;
98
- if (!Final) {
99
- if (hasMissResolver(context)) {
100
- resolve(type, context);
126
+ }, [type, ctx_, sync]);
127
+
128
+ let Handler = sync ?? async_;
129
+
130
+ if (!Handler) {
131
+ if (hasMissResolver(ctx_)) {
132
+ resolve(type, ctx_);
101
133
  return null;
102
134
  }
103
- Final = resolve(type, context, false) as ReactHandler | null;
135
+ Handler = resolve(type, ctx_, false);
104
136
  }
105
137
 
106
- if (!Final) return null;
107
- const el = createElement(Final, { value, onChange });
108
- if ('$path' in value) return <NodeProvider value={value as NodeData}>{el}</NodeProvider>;
109
- return el;
138
+ if (!Handler) return null;
139
+
140
+ const ctx = viewCtx(value);
141
+ const el = createElement(Handler, { value, onChange, ctx });
142
+ return ctx?.node ? createElement(NodeProvider, { value: ctx.node }, el) : el;
110
143
  }
111
144
 
112
145
  // ── <RenderField> — field-level rendering by type name ──
package/src/events.ts ADDED
@@ -0,0 +1,121 @@
1
+ // Server event subscription — module-level, not tied to any React component.
2
+ // Listens to trpc.events SSE and updates the cache.
3
+
4
+ import type { NodeData } from '@treenity/core';
5
+ import { applyPatch, type Operation } from 'fast-json-patch';
6
+ import * as cache from './cache';
7
+ import { trpc } from './trpc';
8
+
9
+ type LoadChildren = (path: string) => Promise<void>;
10
+
11
+ interface EventsConfig {
12
+ loadChildren: LoadChildren;
13
+ getExpanded: () => Set<string>;
14
+ getSelected: () => string | null;
15
+ }
16
+
17
+ // ── SSE connection events (consumed by App.tsx) ──
18
+
19
+ export const SSE_CONNECTED = 'sse-connected';
20
+ export const SSE_DISCONNECTED = 'sse-disconnected';
21
+
22
+ let unsub: (() => void) | null = null;
23
+ let reconnectTimer: ReturnType<typeof setTimeout> | null = null;
24
+ let lastConfig: EventsConfig | null = null;
25
+
26
+ export function startEvents(config: EventsConfig) {
27
+ stopEvents();
28
+ lastConfig = config;
29
+
30
+ const { loadChildren, getExpanded, getSelected } = config;
31
+
32
+ const sub = trpc.events.subscribe(undefined as void, {
33
+ onStarted() {
34
+ window.dispatchEvent(new Event(SSE_CONNECTED));
35
+ },
36
+ onConnectionStateChange(state: { state: string }) {
37
+ if (state.state === 'connecting') {
38
+ window.dispatchEvent(new Event(SSE_DISCONNECTED));
39
+ } else if (state.state === 'pending') {
40
+ // 'pending' = connected and waiting for data — SSE is alive
41
+ window.dispatchEvent(new Event(SSE_CONNECTED));
42
+ }
43
+ },
44
+ onError(err: unknown) {
45
+ console.error('[sse] subscription error (non-retryable):', err);
46
+ window.dispatchEvent(new Event(SSE_DISCONNECTED));
47
+ // tRPC exhausted retries — schedule a single delayed re-subscribe
48
+ scheduleResubscribe();
49
+ },
50
+ onStopped() {
51
+ // Server closed the stream — schedule re-subscribe
52
+ window.dispatchEvent(new Event(SSE_DISCONNECTED));
53
+ scheduleResubscribe();
54
+ },
55
+ onData(event) {
56
+ if (event.type === 'reconnect') {
57
+ if (!event.preserved) {
58
+ cache.signalReconnect();
59
+ for (const path of getExpanded()) loadChildren(path);
60
+ const sel = getSelected();
61
+ if (sel) {
62
+ trpc.get.query({ path: sel, watch: true }).then(n => {
63
+ if (n) cache.put(n as NodeData);
64
+ });
65
+ }
66
+ }
67
+ return;
68
+ }
69
+
70
+ if (event.type === 'set') {
71
+ cache.put({ $path: event.path, ...event.node } as NodeData);
72
+ if (event.addVps) event.addVps.forEach((vp: string) => cache.addToParent(event.path, vp));
73
+ if (event.rmVps) event.rmVps.forEach((vp: string) => cache.removeFromParent(event.path, vp));
74
+ } else if (event.type === 'patch') {
75
+ const existing = cache.get(event.path);
76
+ if (existing && event.patches) {
77
+ try {
78
+ const patched = structuredClone(existing);
79
+ applyPatch(patched, event.patches as Operation[]);
80
+ cache.put(patched);
81
+ } catch (e) {
82
+ console.error('Failed to apply patches, fetching full node:', e);
83
+ trpc.get.query({ path: event.path }).then((n) => {
84
+ if (n) cache.put(n as NodeData);
85
+ });
86
+ }
87
+ } else {
88
+ trpc.get.query({ path: event.path }).then((n) => {
89
+ if (n) cache.put(n as NodeData);
90
+ });
91
+ }
92
+ if (event.addVps) event.addVps.forEach((vp: string) => cache.addToParent(event.path, vp));
93
+ if (event.rmVps) event.rmVps.forEach((vp: string) => cache.removeFromParent(event.path, vp));
94
+ } else if (event.type === 'remove') {
95
+ if (event.rmVps && event.rmVps.length > 0) {
96
+ event.rmVps.forEach((vp: string) => cache.removeFromParent(event.path, vp));
97
+ } else {
98
+ cache.remove(event.path);
99
+ }
100
+ }
101
+ },
102
+ });
103
+
104
+ unsub = () => sub.unsubscribe();
105
+ }
106
+
107
+ const RESUBSCRIBE_DELAY = 5_000;
108
+
109
+ function scheduleResubscribe() {
110
+ if (reconnectTimer || !lastConfig) return;
111
+ console.log(`[sse] will re-subscribe in ${RESUBSCRIBE_DELAY}ms`);
112
+ reconnectTimer = setTimeout(() => {
113
+ reconnectTimer = null;
114
+ if (lastConfig) startEvents(lastConfig);
115
+ }, RESUBSCRIBE_DELAY);
116
+ }
117
+
118
+ export function stopEvents() {
119
+ if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; }
120
+ if (unsub) { unsub(); unsub = null; }
121
+ }
@@ -0,0 +1,112 @@
1
+ // Virtual read-only Tree over React Fiber.
2
+ // Walks the live Fiber tree on each query — no state, no tracking.
3
+ // Registered as t.mount.react — isomorphic mount, same as server-side mounts.
4
+
5
+ import type { NodeData } from '@treenity/core';
6
+ import { register } from '@treenity/core';
7
+ import type { Tree } from '@treenity/core/tree';
8
+
9
+ const PREFIX = '/local/react'
10
+
11
+ interface FiberNode {
12
+ $path: string
13
+ $type: string
14
+ sourcePath?: string
15
+ children?: FiberNode[]
16
+ }
17
+
18
+ // Detect <Render> by name + props shape (resilient to HMR wrappers)
19
+ function isRenderFiber(f: any): boolean {
20
+ if (!f.memoizedProps?.value?.$type) return false
21
+ const name = f.type?.name || f.type?.displayName || ''
22
+ return name === 'Render'
23
+ }
24
+
25
+ function getRootFiber() {
26
+ const el = document.getElementById('root')
27
+ if (!el) return null
28
+
29
+ // React 19 createRoot: __reactContainer$ on the container element
30
+ const containerKey = Object.keys(el).find(k => k.startsWith('__reactContainer$'))
31
+ if (containerKey) return (el as any)[containerKey]
32
+
33
+ // React 18 fallback: __reactFiber$ on first child
34
+ const fiberKey = Object.keys(el).find(k => k.startsWith('__reactFiber$'))
35
+ return fiberKey ? (el as any)[fiberKey] : null
36
+ }
37
+
38
+ function walk(fiber: any, parentPath: string, maxDepth: number, depth = 0): FiberNode[] {
39
+ if (depth >= maxDepth) return []
40
+
41
+ const result: FiberNode[] = []
42
+ let f = fiber?.child
43
+ let i = 0
44
+
45
+ while (f) {
46
+ if (isRenderFiber(f)) {
47
+ const v = f.memoizedProps.value
48
+ const path = `${parentPath}/${i}`
49
+ result.push({
50
+ $path: path,
51
+ $type: v.$type,
52
+ sourcePath: v.$path,
53
+ children: depth + 1 < maxDepth ? walk(f, path, maxDepth, depth + 1) : undefined,
54
+ })
55
+ i++
56
+ } else {
57
+ result.push(...walk(f, parentPath, maxDepth, depth))
58
+ }
59
+ f = f.sibling
60
+ }
61
+
62
+ return result
63
+ }
64
+
65
+ function scan(depth = 1): FiberNode[] {
66
+ const root = getRootFiber()
67
+ return root ? walk(root, PREFIX, depth) : []
68
+ }
69
+
70
+ function findByPath(nodes: FiberNode[], path: string): FiberNode | undefined {
71
+ for (const n of nodes) {
72
+ if (n.$path === path) return n
73
+ if (n.children) {
74
+ const found = findByPath(n.children, path)
75
+ if (found) return found
76
+ }
77
+ }
78
+ }
79
+
80
+ function toNode(n: FiberNode): NodeData {
81
+ return { $path: n.$path, $type: n.$type, sourcePath: n.sourcePath } as NodeData
82
+ }
83
+
84
+ export function createFiberTree(): Tree {
85
+ return {
86
+ async get(path) {
87
+ if (path === PREFIX) return { $path: PREFIX, $type: 'dir' } as NodeData
88
+ const node = findByPath(scan(100), path)
89
+ return node ? toNode(node) : undefined
90
+ },
91
+
92
+ async getChildren(path, opts?) {
93
+ const depth = opts?.depth ?? 1
94
+
95
+ if (path === PREFIX) {
96
+ const nodes = scan(depth)
97
+ return { items: nodes.map(toNode), total: nodes.length }
98
+ }
99
+
100
+ const parent = findByPath(scan(100), path)
101
+ const children = parent?.children ?? []
102
+ return { items: children.map(toNode), total: children.length }
103
+ },
104
+
105
+ async set() { throw new Error('fiber tree is read-only') },
106
+ async remove() { throw new Error('fiber tree is read-only') },
107
+ async patch() { throw new Error('fiber tree is read-only') },
108
+ }
109
+ }
110
+
111
+ // Mount adapter — same pattern as t.mount.fs, t.mount.mongo
112
+ register('t.mount.react', 'mount', () => createFiberTree())