@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,10 +1,16 @@
1
1
  // react:form handlers — editable fields for inspector panel
2
2
  import * as cache from '#cache';
3
3
  import { tree as clientStore } from '#client';
4
- import { useSchema } from '#schema-loader';
5
4
  // react view handlers — readOnly display for same types
6
5
  // Covers: string, text, textarea, number, integer, boolean, array, object, image, uri, url, select, timestamp, path
7
- import { register, resolve as resolveHandler } from '@treenity/core/core';
6
+ import { Button } from '#components/ui/button';
7
+ import { Input } from '#components/ui/input';
8
+ import { Popover, PopoverContent, PopoverTrigger } from '#components/ui/popover';
9
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '#components/ui/select';
10
+ import { Switch } from '#components/ui/switch';
11
+ import { Textarea } from '#components/ui/textarea';
12
+ import { useSchema } from '#schema-loader';
13
+ import { register, resolve as resolveHandler } from '@treenity/core';
8
14
  import dayjs from 'dayjs';
9
15
  import { X } from 'lucide-react';
10
16
  import { createElement, useCallback, useEffect, useRef, useState, useSyncExternalStore } from 'react';
@@ -97,20 +103,22 @@ function StringForm({ value, onChange }: FP) {
97
103
  // enum → select dropdown
98
104
  if (value.enum && value.enum.length > 0) {
99
105
  return (
100
- <select
101
- value={String(value.value ?? '')}
102
- onChange={(e) => onChange?.({ ...value, value: e.target.value })}
103
- >
104
- <option value="">—</option>
105
- {value.enum.map((v) => (
106
- <option key={v} value={v}>{v}</option>
107
- ))}
108
- </select>
106
+ <Select value={String(value.value ?? '')} onValueChange={(v) => onChange?.({ ...value, value: v })}>
107
+ <SelectTrigger className="h-7 text-xs font-mono">
108
+ <SelectValue placeholder="—" />
109
+ </SelectTrigger>
110
+ <SelectContent>
111
+ {value.enum.map((v) => (
112
+ <SelectItem key={v} value={v}>{v}</SelectItem>
113
+ ))}
114
+ </SelectContent>
115
+ </Select>
109
116
  );
110
117
  }
111
118
 
112
119
  return (
113
- <input
120
+ <Input
121
+ className="h-7 text-xs"
114
122
  value={String(value.value ?? '')}
115
123
  placeholder={value.placeholder}
116
124
  onChange={(e) => onChange?.({ ...value, value: e.target.value })}
@@ -120,7 +128,8 @@ function StringForm({ value, onChange }: FP) {
120
128
 
121
129
  function TextForm({ value, onChange }: FP) {
122
130
  return (
123
- <textarea
131
+ <Textarea
132
+ className="text-xs"
124
133
  value={String(value.value ?? '')}
125
134
  placeholder={value.placeholder}
126
135
  onChange={(e) => onChange?.({ ...value, value: e.target.value })}
@@ -130,8 +139,9 @@ function TextForm({ value, onChange }: FP) {
130
139
 
131
140
  function NumberForm({ value, onChange }: FP) {
132
141
  return (
133
- <input
142
+ <Input
134
143
  type="number"
144
+ className="h-7 text-xs"
135
145
  value={String(value.value ?? 0)}
136
146
  onChange={(e) => onChange?.({ ...value, value: Number(e.target.value) })}
137
147
  />
@@ -140,9 +150,10 @@ function NumberForm({ value, onChange }: FP) {
140
150
 
141
151
  function IntegerForm({ value, onChange }: FP) {
142
152
  return (
143
- <input
153
+ <Input
144
154
  type="number"
145
155
  step="1"
156
+ className="h-7 text-xs"
146
157
  value={String(value.value ?? 0)}
147
158
  onChange={(e) => onChange?.({ ...value, value: Math.round(Number(e.target.value)) })}
148
159
  />
@@ -152,11 +163,9 @@ function IntegerForm({ value, onChange }: FP) {
152
163
  function BooleanForm({ value, onChange }: FP) {
153
164
  return (
154
165
  <label className="flex items-center gap-2 cursor-pointer">
155
- <input
156
- type="checkbox"
157
- className="w-auto"
166
+ <Switch
158
167
  checked={!!value.value}
159
- onChange={(e) => onChange?.({ ...value, value: e.target.checked })}
168
+ onCheckedChange={(checked) => onChange?.({ ...value, value: checked })}
160
169
  />
161
170
  <span className="text-xs text-muted-foreground">{value.label}</span>
162
171
  </label>
@@ -167,7 +176,8 @@ function ImageForm({ value, onChange }: FP) {
167
176
  const src = typeof value.value === 'string' ? value.value : '';
168
177
  return (
169
178
  <div className="space-y-2">
170
- <input
179
+ <Input
180
+ className="h-7 text-xs"
171
181
  value={src}
172
182
  placeholder="Image URL"
173
183
  onChange={(e) => onChange?.({ ...value, value: e.target.value })}
@@ -181,7 +191,8 @@ function UriForm({ value, onChange }: FP) {
181
191
  const url = String(value.value ?? '');
182
192
  return (
183
193
  <div className="space-y-1">
184
- <input
194
+ <Input
195
+ className="h-7 text-xs"
185
196
  value={url}
186
197
  placeholder={value.placeholder ?? 'https://...'}
187
198
  onChange={(e) => onChange?.({ ...value, value: e.target.value })}
@@ -200,9 +211,9 @@ function TimestampForm({ value, onChange }: FP) {
200
211
  const formatted = ts ? dayjs(ts > 1e12 ? ts : ts * 1000).format('YYYY-MM-DD HH:mm:ss') : '—';
201
212
  return (
202
213
  <div className="flex items-center gap-2">
203
- <input
214
+ <Input
204
215
  type="number"
205
- className="flex-1"
216
+ className="h-7 text-xs flex-1"
206
217
  value={String(ts)}
207
218
  onChange={(e) => onChange?.({ ...value, value: Number(e.target.value) })}
208
219
  />
@@ -214,15 +225,16 @@ function TimestampForm({ value, onChange }: FP) {
214
225
  function SelectForm({ value, onChange }: FP) {
215
226
  const opts = value.enum ?? [];
216
227
  return (
217
- <select
218
- value={String(value.value ?? '')}
219
- onChange={(e) => onChange?.({ ...value, value: e.target.value })}
220
- >
221
- <option value="">—</option>
222
- {opts.map((v) => (
223
- <option key={v} value={v}>{v}</option>
224
- ))}
225
- </select>
228
+ <Select value={String(value.value ?? '')} onValueChange={(v) => onChange?.({ ...value, value: v })}>
229
+ <SelectTrigger className="h-7 text-xs font-mono">
230
+ <SelectValue placeholder="—" />
231
+ </SelectTrigger>
232
+ <SelectContent>
233
+ {opts.map((v) => (
234
+ <SelectItem key={v} value={v}>{v}</SelectItem>
235
+ ))}
236
+ </SelectContent>
237
+ </Select>
226
238
  );
227
239
  }
228
240
 
@@ -240,16 +252,20 @@ function ObjectForm({ value, onChange }: FP) {
240
252
 
241
253
  const modeToggle = (
242
254
  <div className="flex gap-1 mb-1">
243
- <button
255
+ <Button
256
+ variant="ghost"
257
+ size="sm"
244
258
  type="button"
245
- className={`border-0 px-2 py-0.5 text-[10px] rounded ${mode === 'fields' ? 'bg-muted text-foreground' : 'bg-transparent text-muted-foreground hover:text-foreground'}`}
259
+ className={`h-6 px-2 text-[10px] ${mode === 'fields' ? 'bg-muted text-foreground' : 'text-muted-foreground hover:text-foreground'}`}
246
260
  onClick={() => setMode('fields')}
247
261
  >
248
262
  Fields
249
- </button>
250
- <button
263
+ </Button>
264
+ <Button
265
+ variant="ghost"
266
+ size="sm"
251
267
  type="button"
252
- className={`border-0 px-2 py-0.5 text-[10px] rounded ${mode === 'json' ? 'bg-muted text-foreground' : 'bg-transparent text-muted-foreground hover:text-foreground'}`}
268
+ className={`h-6 px-2 text-[10px] ${mode === 'json' ? 'bg-muted text-foreground' : 'text-muted-foreground hover:text-foreground'}`}
253
269
  onClick={() => {
254
270
  setJsonDraft(JSON.stringify(obj, null, 2));
255
271
  setJsonError(false);
@@ -257,7 +273,7 @@ function ObjectForm({ value, onChange }: FP) {
257
273
  }}
258
274
  >
259
275
  JSON
260
- </button>
276
+ </Button>
261
277
  </div>
262
278
  );
263
279
 
@@ -265,7 +281,7 @@ function ObjectForm({ value, onChange }: FP) {
265
281
  return (
266
282
  <div className="rounded border border-border/50 bg-muted/30 p-2">
267
283
  {modeToggle}
268
- <textarea
284
+ <Textarea
269
285
  className={`text-[11px] min-h-[60px] ${jsonError ? 'border-destructive' : ''}`}
270
286
  value={jsonDraft}
271
287
  onChange={(e) => {
@@ -299,27 +315,26 @@ function ObjectForm({ value, onChange }: FP) {
299
315
  {k}
300
316
  </span>
301
317
  {typeof v === 'boolean' ? (
302
- <input
303
- type="checkbox"
304
- className="w-auto mt-1.5"
318
+ <Switch
319
+ className="mt-1"
305
320
  checked={v}
306
- onChange={(e) => emit({ ...obj, [k]: e.target.checked })}
321
+ onCheckedChange={(checked) => emit({ ...obj, [k]: checked })}
307
322
  />
308
323
  ) : typeof v === 'number' ? (
309
- <input
324
+ <Input
310
325
  type="number"
311
- className="flex-1 min-w-0 text-[11px]"
326
+ className="h-7 text-[11px] flex-1 min-w-0"
312
327
  value={String(v)}
313
328
  onChange={(e) => emit({ ...obj, [k]: Number(e.target.value) })}
314
329
  />
315
330
  ) : typeof v === 'string' ? (
316
- <input
317
- className="flex-1 min-w-0 text-[11px]"
331
+ <Input
332
+ className="h-7 text-[11px] flex-1 min-w-0"
318
333
  value={v}
319
334
  onChange={(e) => emit({ ...obj, [k]: e.target.value })}
320
335
  />
321
336
  ) : (
322
- <textarea
337
+ <Textarea
323
338
  className="flex-1 min-w-0 text-[11px] font-mono min-h-[40px]"
324
339
  value={JSON.stringify(v, null, 2)}
325
340
  onChange={(e) => {
@@ -331,9 +346,11 @@ function ObjectForm({ value, onChange }: FP) {
331
346
  }}
332
347
  />
333
348
  )}
334
- <button
349
+ <Button
350
+ variant="ghost"
351
+ size="icon"
335
352
  type="button"
336
- className="border-0 bg-transparent p-0 mt-1 text-muted-foreground/30 opacity-0 group-hover:opacity-100 hover:text-destructive shrink-0 cursor-pointer transition-opacity"
353
+ className="h-5 w-5 p-0 mt-1 text-muted-foreground/30 opacity-0 group-hover:opacity-100 hover:text-destructive shrink-0 transition-opacity"
337
354
  onClick={() => {
338
355
  const next = { ...obj };
339
356
  delete next[k];
@@ -341,15 +358,15 @@ function ObjectForm({ value, onChange }: FP) {
341
358
  }}
342
359
  >
343
360
  <X className="h-3 w-3" />
344
- </button>
361
+ </Button>
345
362
  </div>
346
363
  ))}
347
364
  </div>
348
365
  )}
349
366
 
350
367
  <div className="flex gap-1 items-center border-t border-border/30 pt-1.5">
351
- <input
352
- className="flex-1 min-w-0 text-[11px] bg-transparent border-dashed"
368
+ <Input
369
+ className="h-7 text-[11px] flex-1 min-w-0 bg-transparent border-dashed"
353
370
  placeholder="new key..."
354
371
  value={newKey}
355
372
  onChange={(e) => setNewKey(e.target.value)}
@@ -363,9 +380,11 @@ function ObjectForm({ value, onChange }: FP) {
363
380
  }
364
381
  }}
365
382
  />
366
- <button
383
+ <Button
384
+ variant="ghost"
385
+ size="sm"
367
386
  type="button"
368
- className="border-0 bg-transparent p-0 text-[11px] text-muted-foreground hover:text-foreground shrink-0 cursor-pointer"
387
+ className="h-6 px-2 text-[10px] text-muted-foreground hover:text-foreground shrink-0"
369
388
  onClick={() => {
370
389
  const k = newKey.trim();
371
390
  if (k && !(k in obj)) {
@@ -375,7 +394,7 @@ function ObjectForm({ value, onChange }: FP) {
375
394
  }}
376
395
  >
377
396
  +
378
- </button>
397
+ </Button>
379
398
  </div>
380
399
  </div>
381
400
  );
@@ -398,19 +417,21 @@ function ArrayForm({ value, onChange }: FP) {
398
417
  className="inline-flex items-center gap-0.5 text-[11px] font-mono bg-muted text-foreground/70 px-1.5 py-0.5 rounded"
399
418
  >
400
419
  {tag}
401
- <button
420
+ <Button
421
+ variant="ghost"
422
+ size="icon"
402
423
  type="button"
403
- className="ml-0.5 border-0 bg-transparent p-0 text-muted-foreground/40 hover:text-foreground leading-none cursor-pointer"
424
+ className="h-5 w-5 p-0 ml-0.5 text-muted-foreground/40 hover:text-foreground leading-none"
404
425
  onClick={() => emit(arr.filter((_, j) => j !== i))}
405
426
  >
406
427
  ×
407
- </button>
428
+ </Button>
408
429
  </span>
409
430
  ))}
410
431
  </div>
411
432
  )}
412
- <input
413
- className="text-[11px] bg-transparent border-dashed"
433
+ <Input
434
+ className="h-7 text-[11px] bg-transparent border-dashed"
414
435
  placeholder="add item..."
415
436
  value={input}
416
437
  onChange={(e) => setInput(e.target.value)}
@@ -431,35 +452,39 @@ function ArrayForm({ value, onChange }: FP) {
431
452
  <div className="rounded border border-border/50 bg-muted/30 p-2 space-y-1">
432
453
  {arr.map((item, i) => (
433
454
  <div key={i} className="flex gap-1 items-center group">
434
- <input
455
+ <Input
435
456
  type="number"
436
- className="flex-1 text-[11px]"
457
+ className="h-7 text-[11px] flex-1"
437
458
  value={String(item ?? 0)}
438
459
  onChange={(e) => emit(arr.map((v, j) => (j === i ? Number(e.target.value) : v)))}
439
460
  />
440
- <button
461
+ <Button
462
+ variant="ghost"
463
+ size="icon"
441
464
  type="button"
442
- className="border-0 bg-transparent p-0 text-muted-foreground/30 opacity-0 group-hover:opacity-100 hover:text-destructive cursor-pointer transition-opacity"
465
+ className="h-5 w-5 p-0 text-muted-foreground/30 opacity-0 group-hover:opacity-100 hover:text-destructive transition-opacity"
443
466
  onClick={() => emit(arr.filter((_, j) => j !== i))}
444
467
  >
445
468
  <X className="h-3 w-3" />
446
- </button>
469
+ </Button>
447
470
  </div>
448
471
  ))}
449
- <button
472
+ <Button
473
+ variant="ghost"
474
+ size="sm"
450
475
  type="button"
451
- className="border-0 bg-transparent p-0 text-[11px] text-muted-foreground hover:text-foreground cursor-pointer"
476
+ className="h-6 px-2 text-[10px] text-muted-foreground hover:text-foreground"
452
477
  onClick={() => emit([...arr, 0])}
453
478
  >
454
479
  + add
455
- </button>
480
+ </Button>
456
481
  </div>
457
482
  );
458
483
  }
459
484
 
460
485
  // object/other — textarea fallback
461
486
  return (
462
- <textarea
487
+ <Textarea
463
488
  value={JSON.stringify(arr, null, 2)}
464
489
  onChange={(e) => {
465
490
  try {
@@ -482,8 +507,7 @@ function PathView({ value }: FP) {
482
507
 
483
508
  // Compact tree picker dropdown for selecting a node path
484
509
  // Lazy-loads children via trpc on expand, caches into front/cache
485
- export function MiniTree({ onSelect, onClose }: { onSelect: (path: string) => void; onClose: () => void }) {
486
- const ref = useRef<HTMLDivElement>(null);
510
+ export function MiniTree({ onSelect }: { onSelect: (path: string) => void }) {
487
511
  const [expanded, setExpanded] = useState<Set<string>>(new Set(['/']));
488
512
  const [loaded, setLoaded] = useState<Set<string>>(new Set());
489
513
  const [filter, setFilter] = useState('');
@@ -499,15 +523,6 @@ export function MiniTree({ onSelect, onClose }: { onSelect: (path: string) => vo
499
523
  fetchChildren('/');
500
524
  }, []);
501
525
 
502
- // Close on outside click
503
- useEffect(() => {
504
- const handler = (e: MouseEvent) => {
505
- if (ref.current && !ref.current.contains(e.target as Node)) onClose();
506
- };
507
- document.addEventListener('mousedown', handler);
508
- return () => document.removeEventListener('mousedown', handler);
509
- }, [onClose]);
510
-
511
526
  async function fetchChildren(path: string) {
512
527
  if (loaded.has(path)) return;
513
528
  const { items } = await clientStore.getChildren(path);
@@ -594,13 +609,10 @@ export function MiniTree({ onSelect, onClose }: { onSelect: (path: string) => vo
594
609
  const rootNode = nodes.get('/');
595
610
 
596
611
  return (
597
- <div
598
- ref={ref}
599
- className="absolute z-50 mt-1 w-64 max-h-60 overflow-auto bg-popover border border-border rounded-lg shadow-lg"
600
- >
612
+ <>
601
613
  <div className="p-1.5 border-b border-border">
602
- <input
603
- className="text-[11px] w-full"
614
+ <Input
615
+ className="h-7 text-[11px] w-full"
604
616
  placeholder="Filter..."
605
617
  value={filter}
606
618
  onChange={(e) => setFilter(e.target.value)}
@@ -611,7 +623,7 @@ export function MiniTree({ onSelect, onClose }: { onSelect: (path: string) => vo
611
623
  {rootNode && renderNode('/', 0)}
612
624
  {!rootNode && rootKids.map((r) => renderNode(r, 0))}
613
625
  </div>
614
- </div>
626
+ </>
615
627
  );
616
628
  }
617
629
 
@@ -668,8 +680,8 @@ function EmbeddedFields({ data, type, setData }: {
668
680
  {entries.map(([k, v]) => (
669
681
  <div key={k} className="field">
670
682
  <label>{k}</label>
671
- <input
672
- className="text-[11px]"
683
+ <Input
684
+ className="h-7 text-[11px]"
673
685
  value={typeof v === 'string' ? v : JSON.stringify(v)}
674
686
  onChange={(e) => setData((prev) => ({ ...prev, [k]: e.target.value }))}
675
687
  />
@@ -749,9 +761,11 @@ function PathForm({ value, onChange }: FP) {
749
761
  {/* Header row: mode switch + input + controls */}
750
762
  <div className="flex items-center gap-1">
751
763
  {/* Mode toggle — always visible */}
752
- <button
764
+ <Button
765
+ variant="ghost"
766
+ size="sm"
753
767
  type="button"
754
- className={`border-0 bg-transparent p-0 px-1 cursor-pointer shrink-0 text-[10px] font-bold font-mono ${
768
+ className={`h-6 px-1 text-[10px] font-bold font-mono shrink-0 ${
755
769
  mode === 'val' ? 'text-amber-500' : 'text-primary'
756
770
  }`}
757
771
  onClick={() => {
@@ -767,7 +781,7 @@ function PathForm({ value, onChange }: FP) {
767
781
  title={mode === 'val' ? 'Value mode — embeds node data' : 'Ref mode — stores path'}
768
782
  >
769
783
  {mode}
770
- </button>
784
+ </Button>
771
785
 
772
786
  {/* Type badge when refType is known */}
773
787
  {refType && (
@@ -784,8 +798,8 @@ function PathForm({ value, onChange }: FP) {
784
798
  )}
785
799
  </span>
786
800
  ) : (
787
- <input
788
- className="flex-1 min-w-0 text-[11px] font-mono border-0 bg-transparent"
801
+ <Input
802
+ className="h-7 text-[11px] font-mono flex-1 min-w-0 border-0 bg-transparent"
789
803
  value={refPath}
790
804
  placeholder="drop or pick a node"
791
805
  onChange={(e) => setRef(e.target.value)}
@@ -793,22 +807,34 @@ function PathForm({ value, onChange }: FP) {
793
807
  )}
794
808
 
795
809
  {hasValue && (
796
- <button
810
+ <Button
811
+ variant="ghost"
812
+ size="icon"
797
813
  type="button"
798
- className="border-0 bg-transparent p-0 px-0.5 text-muted-foreground/40 hover:text-foreground cursor-pointer shrink-0"
814
+ className="h-5 w-5 p-0 text-muted-foreground/40 hover:text-foreground shrink-0"
799
815
  onClick={() => { onChange?.({ ...value, value: '' }); setMode('ref'); }}
800
816
  >
801
817
  <X className="h-3 w-3" />
802
- </button>
818
+ </Button>
803
819
  )}
804
- <button
805
- type="button"
806
- className="border-0 bg-transparent p-0 px-1 text-muted-foreground hover:text-foreground cursor-pointer shrink-0 text-[11px]"
807
- onClick={() => setPickerOpen((v) => !v)}
808
- title="Browse tree"
809
- >
810
- &#9776;
811
- </button>
820
+ <Popover open={pickerOpen} onOpenChange={setPickerOpen}>
821
+ <PopoverTrigger asChild>
822
+ <Button
823
+ variant="ghost"
824
+ size="icon"
825
+ type="button"
826
+ className="h-5 w-5 p-0 text-muted-foreground hover:text-foreground shrink-0 text-[11px]"
827
+ title="Browse tree"
828
+ >
829
+ &#9776;
830
+ </Button>
831
+ </PopoverTrigger>
832
+ <PopoverContent align="end" className="w-64 max-h-60 overflow-auto p-0">
833
+ <MiniTree
834
+ onSelect={(p) => { applyNode(p); setPickerOpen(false); }}
835
+ />
836
+ </PopoverContent>
837
+ </Popover>
812
838
  </div>
813
839
 
814
840
  {/* Inline typed editor for embedded value */}
@@ -822,13 +848,6 @@ function PathForm({ value, onChange }: FP) {
822
848
  </div>
823
849
  )}
824
850
  </div>
825
-
826
- {pickerOpen && (
827
- <MiniTree
828
- onSelect={(p) => { applyNode(p); setPickerOpen(false); }}
829
- onClose={() => setPickerOpen(false)}
830
- />
831
- )}
832
851
  </div>
833
852
  );
834
853
  }
@@ -3,7 +3,8 @@
3
3
 
4
4
  import { Render, RenderContext } from '#context';
5
5
  import { useChildren } from '#hooks';
6
- import { type ComponentData, type NodeData, register } from '@treenity/core/core';
6
+ import { type ComponentData, type NodeData, register } from '@treenity/core';
7
+ import { EmptyNodePlaceholder } from './empty-placeholder';
7
8
  import { getComponents, getPlainFields } from './node-utils';
8
9
 
9
10
  function DefaultLayout({ value }: { value: ComponentData }) {
@@ -54,9 +55,10 @@ function DefaultLayout({ value }: { value: ComponentData }) {
54
55
  </RenderContext>
55
56
  )}
56
57
 
57
- {children.length === 0 && !hasInfo && <div className="node-empty">Empty node</div>}
58
+ {children.length === 0 && !hasInfo && <EmptyNodePlaceholder value={node} />}
58
59
  </div>
59
60
  );
60
61
  }
61
62
 
63
+
62
64
  register('default', 'react:layout', DefaultLayout as any);
@@ -2,8 +2,8 @@
2
2
  // Self-contained: include card styling, click navigation, chevron
3
3
 
4
4
  import { useNavigate } from '#hooks';
5
- import type { NodeData } from '@treenity/core/core';
6
- import { register } from '@treenity/core/core';
5
+ import type { NodeData } from '@treenity/core';
6
+ import { register } from '@treenity/core';
7
7
 
8
8
  const TYPE_ICONS: Record<string, string> = {
9
9
  root: '/',
@@ -1,9 +1,9 @@
1
- import { getContextsForType, type NodeData, resolve } from '@treenity/core/core';
1
+ import { getContextsForType, isComponent, type NodeData, resolve } from '@treenity/core';
2
2
  import type { PropertySchema, TypeSchema } from '@treenity/core/schema/types';
3
3
 
4
4
  export function getComponents(node: NodeData): [string, Record<string, unknown>][] {
5
5
  return Object.entries(node).filter(
6
- ([k, v]) => !k.startsWith('$') && typeof v === 'object' && v !== null && '$type' in v,
6
+ ([k, v]) => !k.startsWith('$') && isComponent(v),
7
7
  ) as [string, Record<string, unknown>][];
8
8
  }
9
9
 
@@ -78,7 +78,6 @@ export function getActionSchema(type: string, action: string): TypeSchema | null
78
78
  };
79
79
  }
80
80
 
81
- export function pickDefaultContext(type: string): string {
82
- const ctxs = getViewContexts(type);
83
- return ctxs.includes('react') ? 'react' : ctxs[0] ?? 'react';
81
+ export function pickDefaultContext(_type: string): string {
82
+ return 'react';
84
83
  }