@object-ui/components 0.3.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (326) hide show
  1. package/.turbo/turbo-build.log +34 -0
  2. package/CHANGELOG.md +13 -0
  3. package/README.md +13 -0
  4. package/dist/index.css +1 -1
  5. package/dist/index.js +36430 -25529
  6. package/dist/index.umd.cjs +53 -32
  7. package/dist/src/SchemaRenderer.d.ts +3 -0
  8. package/dist/src/custom/action-param-dialog.d.ts +21 -0
  9. package/dist/src/{ui → custom}/button-group.d.ts +1 -1
  10. package/dist/src/custom/field.d.ts +19 -0
  11. package/dist/src/custom/index.d.ts +14 -0
  12. package/dist/src/custom/input-group.d.ts +14 -0
  13. package/dist/src/{ui → custom}/item.d.ts +1 -1
  14. package/dist/src/custom/native-select.d.ts +12 -0
  15. package/dist/src/custom/navigation-overlay.d.ts +50 -0
  16. package/dist/src/custom/sort-builder.d.ts +22 -0
  17. package/dist/src/index.d.ts +2 -0
  18. package/dist/src/renderers/action/action-button.d.ts +11 -0
  19. package/dist/src/renderers/action/action-group.d.ts +25 -0
  20. package/dist/src/renderers/action/action-icon.d.ts +10 -0
  21. package/dist/src/renderers/action/action-menu.d.ts +19 -0
  22. package/dist/src/renderers/action/index.d.ts +0 -0
  23. package/dist/src/renderers/action/resolve-icon.d.ts +6 -0
  24. package/dist/src/renderers/data-display/table.d.ts +1 -1
  25. package/dist/src/renderers/layout/page.d.ts +1 -1
  26. package/dist/src/renderers/placeholders.d.ts +1 -1
  27. package/dist/src/ui/accordion.d.ts +4 -4
  28. package/dist/src/ui/alert-dialog.d.ts +17 -11
  29. package/dist/src/ui/alert.d.ts +4 -5
  30. package/dist/src/ui/aspect-ratio.d.ts +1 -1
  31. package/dist/src/ui/avatar.d.ts +3 -3
  32. package/dist/src/ui/badge.d.ts +3 -3
  33. package/dist/src/ui/breadcrumb.d.ts +16 -8
  34. package/dist/src/ui/calendar.d.ts +7 -7
  35. package/dist/src/ui/card.d.ts +7 -8
  36. package/dist/src/ui/carousel.d.ts +5 -6
  37. package/dist/src/ui/chart.d.ts +62 -0
  38. package/dist/src/ui/checkbox.d.ts +1 -1
  39. package/dist/src/ui/collapsible.d.ts +3 -3
  40. package/dist/src/ui/command.d.ts +78 -16
  41. package/dist/src/ui/context-menu.d.ts +14 -12
  42. package/dist/src/ui/dialog.d.ts +17 -13
  43. package/dist/src/ui/drawer.d.ts +19 -10
  44. package/dist/src/ui/dropdown-menu.d.ts +20 -18
  45. package/dist/src/ui/form.d.ts +6 -7
  46. package/dist/src/ui/hover-card.d.ts +3 -3
  47. package/dist/src/ui/index.d.ts +2 -8
  48. package/dist/src/ui/input-otp.d.ts +30 -7
  49. package/dist/src/ui/label.d.ts +2 -1
  50. package/dist/src/ui/menubar.d.ts +19 -17
  51. package/dist/src/ui/navigation-menu.d.ts +9 -11
  52. package/dist/src/ui/pagination.d.ts +25 -10
  53. package/dist/src/ui/popover.d.ts +4 -5
  54. package/dist/src/ui/progress.d.ts +1 -1
  55. package/dist/src/ui/radio-group.d.ts +2 -2
  56. package/dist/src/ui/resizable.d.ts +5 -8
  57. package/dist/src/ui/scroll-area.d.ts +2 -2
  58. package/dist/src/ui/select.d.ts +11 -13
  59. package/dist/src/ui/sheet.d.ts +23 -11
  60. package/dist/src/ui/sidebar.d.ts +27 -29
  61. package/dist/src/ui/skeleton.d.ts +1 -1
  62. package/dist/src/ui/slider.d.ts +1 -1
  63. package/dist/src/ui/sonner.d.ts +2 -1
  64. package/dist/src/ui/switch.d.ts +2 -2
  65. package/dist/src/ui/tabs.d.ts +1 -1
  66. package/dist/src/ui/textarea.d.ts +1 -1
  67. package/dist/src/ui/toast.d.ts +22 -0
  68. package/dist/src/ui/toggle-group.d.ts +8 -3
  69. package/dist/src/ui/toggle.d.ts +4 -1
  70. package/dist/src/ui/tooltip.d.ts +4 -4
  71. package/dist/src/ui/typography.d.ts +21 -0
  72. package/package.json +20 -9
  73. package/shadcn-components.json +52 -47
  74. package/src/SchemaRenderer.tsx +28 -0
  75. package/src/__tests__/PageRendererRegions.test.tsx +668 -0
  76. package/src/__tests__/Registry.test.ts +21 -0
  77. package/src/__tests__/basic-renderers.test.tsx +1 -1
  78. package/src/__tests__/complex-disclosure-renderers.test.tsx +3 -2
  79. package/src/__tests__/compliance.test.tsx +72 -0
  80. package/src/__tests__/feedback-overlay-renderers.test.tsx +1 -1
  81. package/src/__tests__/form-renderers.test.tsx +1 -1
  82. package/src/__tests__/layout-data-renderers.test.tsx +1 -1
  83. package/src/__tests__/navigation-overlay.test.tsx +273 -0
  84. package/src/__tests__/view-compliance.test.tsx +153 -0
  85. package/src/custom/action-param-dialog.tsx +264 -0
  86. package/src/{ui → custom}/button-group.tsx +1 -1
  87. package/src/{ui → custom}/combobox.tsx +3 -3
  88. package/src/{ui → custom}/date-picker.tsx +3 -3
  89. package/src/custom/field.tsx +81 -0
  90. package/src/{ui → custom}/filter-builder.tsx +3 -3
  91. package/src/custom/index.ts +14 -0
  92. package/src/custom/input-group.tsx +53 -0
  93. package/src/{ui → custom}/item.tsx +1 -1
  94. package/src/custom/native-select.tsx +33 -0
  95. package/src/custom/navigation-overlay.tsx +296 -0
  96. package/src/custom/sort-builder.tsx +129 -0
  97. package/src/index.css +20 -1
  98. package/src/index.ts +2 -0
  99. package/src/renderers/action/action-button.tsx +147 -0
  100. package/src/renderers/action/action-group.tsx +270 -0
  101. package/src/renderers/action/action-icon.tsx +150 -0
  102. package/src/renderers/action/action-menu.tsx +203 -0
  103. package/src/renderers/action/index.ts +18 -0
  104. package/src/renderers/action/resolve-icon.ts +35 -0
  105. package/src/renderers/basic/button-group.tsx +1 -0
  106. package/src/renderers/basic/div.tsx +12 -1
  107. package/src/renderers/basic/html.tsx +1 -0
  108. package/src/renderers/basic/icon.tsx +1 -0
  109. package/src/renderers/basic/image.tsx +1 -0
  110. package/src/renderers/basic/navigation-menu.tsx +1 -0
  111. package/src/renderers/basic/pagination.tsx +31 -4
  112. package/src/renderers/basic/separator.tsx +1 -0
  113. package/src/renderers/basic/span.tsx +12 -1
  114. package/src/renderers/basic/text.tsx +4 -2
  115. package/src/renderers/complex/__tests__/data-table-batch-editing.test.tsx +275 -0
  116. package/src/renderers/complex/__tests__/data-table-cell-renderer.test.tsx +120 -0
  117. package/src/renderers/complex/__tests__/data-table-editing.test.tsx +221 -0
  118. package/src/renderers/complex/carousel.tsx +1 -0
  119. package/src/renderers/complex/data-table.tsx +355 -95
  120. package/src/renderers/complex/filter-builder.tsx +2 -1
  121. package/src/renderers/complex/resizable.tsx +2 -1
  122. package/src/renderers/complex/scroll-area.tsx +25 -7
  123. package/src/renderers/complex/table.tsx +1 -0
  124. package/src/renderers/data-display/alert.tsx +1 -0
  125. package/src/renderers/data-display/avatar.tsx +1 -0
  126. package/src/renderers/data-display/badge.tsx +1 -0
  127. package/src/renderers/data-display/breadcrumb.tsx +1 -0
  128. package/src/renderers/data-display/kbd.tsx +1 -0
  129. package/src/renderers/data-display/list.tsx +21 -49
  130. package/src/renderers/data-display/statistic.tsx +21 -5
  131. package/src/renderers/data-display/table.tsx +21 -11
  132. package/src/renderers/data-display/tree-view.tsx +7 -1
  133. package/src/renderers/disclosure/accordion.tsx +1 -0
  134. package/src/renderers/disclosure/collapsible.tsx +1 -0
  135. package/src/renderers/disclosure/toggle-group.tsx +2 -0
  136. package/src/renderers/feedback/empty.tsx +1 -0
  137. package/src/renderers/feedback/loading.tsx +2 -1
  138. package/src/renderers/feedback/progress.tsx +1 -0
  139. package/src/renderers/feedback/skeleton.tsx +1 -0
  140. package/src/renderers/feedback/sonner.tsx +1 -0
  141. package/src/renderers/feedback/spinner.tsx +1 -0
  142. package/src/renderers/feedback/toast.tsx +1 -0
  143. package/src/renderers/feedback/toaster.tsx +1 -0
  144. package/src/renderers/form/button.tsx +35 -1
  145. package/src/renderers/form/calendar.tsx +1 -0
  146. package/src/renderers/form/checkbox.tsx +38 -16
  147. package/src/renderers/form/combobox.tsx +2 -1
  148. package/src/renderers/form/command.tsx +1 -0
  149. package/src/renderers/form/date-picker.tsx +1 -0
  150. package/src/renderers/form/file-upload.tsx +1 -0
  151. package/src/renderers/form/form.tsx +115 -19
  152. package/src/renderers/form/input-otp.tsx +1 -0
  153. package/src/renderers/form/input.tsx +3 -0
  154. package/src/renderers/form/label.tsx +1 -0
  155. package/src/renderers/form/radio-group.tsx +1 -0
  156. package/src/renderers/form/select.tsx +35 -15
  157. package/src/renderers/form/slider.tsx +1 -0
  158. package/src/renderers/form/switch.tsx +1 -0
  159. package/src/renderers/form/textarea.tsx +50 -27
  160. package/src/renderers/form/toggle.tsx +3 -45
  161. package/src/renderers/index.ts +1 -0
  162. package/src/renderers/layout/aspect-ratio.tsx +2 -1
  163. package/src/renderers/layout/card.tsx +10 -2
  164. package/src/renderers/layout/container.tsx +1 -0
  165. package/src/renderers/layout/flex.tsx +1 -0
  166. package/src/renderers/layout/grid.tsx +23 -8
  167. package/src/renderers/layout/page.tsx +433 -57
  168. package/src/renderers/layout/semantic.tsx +1 -0
  169. package/src/renderers/layout/stack.tsx +2 -1
  170. package/src/renderers/layout/tabs.tsx +43 -17
  171. package/src/renderers/navigation/header-bar.tsx +1 -0
  172. package/src/renderers/navigation/sidebar.tsx +11 -0
  173. package/src/renderers/overlay/alert-dialog.tsx +1 -0
  174. package/src/renderers/overlay/context-menu.tsx +1 -0
  175. package/src/renderers/overlay/dialog.tsx +1 -0
  176. package/src/renderers/overlay/drawer.tsx +1 -0
  177. package/src/renderers/overlay/dropdown-menu.tsx +1 -0
  178. package/src/renderers/overlay/hover-card.tsx +1 -0
  179. package/src/renderers/overlay/menubar.tsx +1 -0
  180. package/src/renderers/overlay/popover.tsx +1 -0
  181. package/src/renderers/overlay/sheet.tsx +1 -0
  182. package/src/renderers/overlay/tooltip.tsx +1 -0
  183. package/src/renderers/placeholders.tsx +4 -4
  184. package/src/stories/CRMApp.stories.tsx +706 -0
  185. package/src/stories/Guide.mdx +55 -0
  186. package/src/stories/Introduction.mdx +61 -0
  187. package/src/stories/MockedData.stories.tsx +121 -0
  188. package/src/stories/assets/accessibility.png +0 -0
  189. package/src/stories/assets/accessibility.svg +1 -0
  190. package/src/stories/assets/addon-library.png +0 -0
  191. package/src/stories/assets/assets.png +0 -0
  192. package/src/stories/assets/avif-test-image.avif +0 -0
  193. package/src/stories/assets/context.png +0 -0
  194. package/src/stories/assets/discord.svg +1 -0
  195. package/src/stories/assets/docs.png +0 -0
  196. package/src/stories/assets/figma-plugin.png +0 -0
  197. package/src/stories/assets/github.svg +1 -0
  198. package/src/stories/assets/share.png +0 -0
  199. package/src/stories/assets/styling.png +0 -0
  200. package/src/stories/assets/testing.png +0 -0
  201. package/src/stories/assets/theming.png +0 -0
  202. package/src/stories/assets/tutorials.svg +1 -0
  203. package/src/stories/assets/youtube.svg +1 -0
  204. package/src/stories/button.css +30 -0
  205. package/src/stories/header.css +32 -0
  206. package/src/stories/page.css +68 -0
  207. package/src/stories-json/accordion.stories.tsx +43 -0
  208. package/src/stories-json/aggrid.stories.tsx +103 -0
  209. package/src/stories-json/alert.stories.tsx +39 -0
  210. package/src/stories-json/aspect-ratio.stories.tsx +34 -0
  211. package/src/stories-json/avatar.stories.tsx +38 -0
  212. package/src/stories-json/badge.stories.tsx +53 -0
  213. package/src/stories-json/breadcrumb.stories.tsx +30 -0
  214. package/src/stories-json/button-group.stories.tsx +43 -0
  215. package/src/stories-json/button.stories.tsx +73 -0
  216. package/src/stories-json/calendar.stories.tsx +85 -0
  217. package/src/stories-json/card.stories.tsx +48 -0
  218. package/src/stories-json/carousel.stories.tsx +33 -0
  219. package/src/stories-json/charts.stories.tsx +195 -0
  220. package/src/stories-json/chatbot.stories.tsx +248 -0
  221. package/src/stories-json/code-editor.stories.tsx +92 -0
  222. package/src/stories-json/collapsible.stories.tsx +40 -0
  223. package/src/stories-json/controls.stories.tsx +36 -0
  224. package/src/stories-json/crm-live-data.stories.tsx +154 -0
  225. package/src/stories-json/dashboard.stories.tsx +318 -0
  226. package/src/stories-json/data-table.stories.tsx +136 -0
  227. package/src/stories-json/data_display_extras.stories.tsx +102 -0
  228. package/src/stories-json/date-picker.stories.tsx +28 -0
  229. package/src/stories-json/detail-view.stories.tsx +258 -0
  230. package/src/stories-json/dialog.stories.tsx +43 -0
  231. package/src/stories-json/feedback_extras.stories.tsx +40 -0
  232. package/src/stories-json/feedback_others.stories.tsx +46 -0
  233. package/src/stories-json/form-variants.stories.tsx +210 -0
  234. package/src/stories-json/form_advanced.stories.tsx +117 -0
  235. package/src/stories-json/form_extras.stories.tsx +123 -0
  236. package/src/stories-json/grid.stories.tsx +56 -0
  237. package/src/stories-json/icon.stories.tsx +36 -0
  238. package/src/stories-json/input.stories.tsx +52 -0
  239. package/src/stories-json/kanban.stories.tsx +295 -0
  240. package/src/stories-json/layout_extended.stories.tsx +76 -0
  241. package/src/stories-json/layout_flex.stories.tsx +107 -0
  242. package/src/stories-json/list-view.stories.tsx +97 -0
  243. package/src/stories-json/markdown.stories.tsx +129 -0
  244. package/src/stories-json/menus.stories.tsx +63 -0
  245. package/src/stories-json/metric-card.stories.tsx +143 -0
  246. package/src/stories-json/navigation-menu.stories.tsx +37 -0
  247. package/src/stories-json/object-aggrid-advanced.stories.tsx +389 -0
  248. package/src/stories-json/object-aggrid.stories.tsx +252 -0
  249. package/src/stories-json/object-form.stories.tsx +130 -0
  250. package/src/stories-json/object-gantt.stories.tsx +114 -0
  251. package/src/stories-json/object-grid.stories.tsx +315 -0
  252. package/src/stories-json/object-map.stories.tsx +116 -0
  253. package/src/stories-json/object-view.stories.tsx +118 -0
  254. package/src/stories-json/overlay_extras.stories.tsx +113 -0
  255. package/src/stories-json/overlay_others.stories.tsx +76 -0
  256. package/src/stories-json/page.stories.tsx +55 -0
  257. package/src/stories-json/reports.stories.tsx +163 -0
  258. package/src/stories-json/resizable.stories.tsx +44 -0
  259. package/src/stories-json/select.stories.tsx +34 -0
  260. package/src/stories-json/separator.stories.tsx +41 -0
  261. package/src/stories-json/sidebar.stories.tsx +147 -0
  262. package/src/stories-json/statistic.stories.tsx +44 -0
  263. package/src/stories-json/tabs.stories.tsx +51 -0
  264. package/src/stories-json/timeline.stories.tsx +188 -0
  265. package/src/stories-json/typography.stories.tsx +45 -0
  266. package/src/ui/accordion.tsx +47 -53
  267. package/src/ui/alert-dialog.tsx +103 -117
  268. package/src/ui/alert.tsx +35 -36
  269. package/src/ui/aspect-ratio.tsx +1 -5
  270. package/src/ui/avatar.tsx +41 -42
  271. package/src/ui/badge.tsx +6 -15
  272. package/src/ui/breadcrumb.tsx +81 -75
  273. package/src/ui/button.tsx +10 -11
  274. package/src/ui/calendar.tsx +178 -51
  275. package/src/ui/card.tsx +51 -110
  276. package/src/ui/carousel.tsx +136 -113
  277. package/src/ui/chart.tsx +367 -0
  278. package/src/ui/checkbox.tsx +20 -22
  279. package/src/ui/collapsible.tsx +5 -25
  280. package/src/ui/command.tsx +106 -135
  281. package/src/ui/context-menu.tsx +69 -116
  282. package/src/ui/dialog.tsx +94 -113
  283. package/src/ui/drawer.tsx +82 -99
  284. package/src/ui/dropdown-menu.tsx +134 -188
  285. package/src/ui/form.tsx +51 -40
  286. package/src/ui/hover-card.tsx +18 -33
  287. package/src/ui/index.ts +2 -8
  288. package/src/ui/input-otp.tsx +42 -52
  289. package/src/ui/input.tsx +13 -15
  290. package/src/ui/label.tsx +17 -15
  291. package/src/ui/menubar.tsx +188 -206
  292. package/src/ui/navigation-menu.tsx +96 -136
  293. package/src/ui/pagination.tsx +86 -96
  294. package/src/ui/popover.tsx +24 -41
  295. package/src/ui/progress.tsx +21 -22
  296. package/src/ui/radio-group.tsx +19 -20
  297. package/src/ui/resizable.tsx +32 -42
  298. package/src/ui/scroll-area.tsx +38 -48
  299. package/src/ui/select.tsx +129 -157
  300. package/src/ui/separator.tsx +2 -2
  301. package/src/ui/sheet.tsx +110 -107
  302. package/src/ui/sidebar.tsx +442 -408
  303. package/src/ui/skeleton.tsx +6 -11
  304. package/src/ui/slider.tsx +19 -54
  305. package/src/ui/sonner.tsx +19 -1
  306. package/src/ui/switch.tsx +19 -21
  307. package/src/ui/tabs.tsx +6 -37
  308. package/src/ui/textarea.tsx +8 -4
  309. package/src/ui/toast.tsx +137 -0
  310. package/src/ui/toggle-group.tsx +28 -37
  311. package/src/ui/toggle.tsx +19 -19
  312. package/src/ui/tooltip.tsx +21 -52
  313. package/src/ui/typography.tsx +85 -0
  314. package/tsconfig.json +1 -1
  315. package/vite.config.ts +9 -1
  316. package/vitest.config.ts +5 -0
  317. package/ISSUES_FOUND.md +0 -128
  318. /package/dist/src/{ui → custom}/combobox.d.ts +0 -0
  319. /package/dist/src/{ui → custom}/date-picker.d.ts +0 -0
  320. /package/dist/src/{ui → custom}/empty.d.ts +0 -0
  321. /package/dist/src/{ui → custom}/filter-builder.d.ts +0 -0
  322. /package/dist/src/{ui → custom}/kbd.d.ts +0 -0
  323. /package/dist/src/{ui → custom}/spinner.d.ts +0 -0
  324. /package/src/{ui → custom}/empty.tsx +0 -0
  325. /package/src/{ui → custom}/kbd.tsx +0 -0
  326. /package/src/{ui → custom}/spinner.tsx +0 -0
@@ -14,6 +14,7 @@ import { Button } from '../../ui/button';
14
14
  import { Input } from '../../ui/input';
15
15
  import { Textarea } from '../../ui/textarea';
16
16
  import { Checkbox } from '../../ui/checkbox';
17
+ import { Switch } from '../../ui/switch';
17
18
  import {
18
19
  Select,
19
20
  SelectTrigger,
@@ -36,10 +37,12 @@ ComponentRegistry.register('form',
36
37
  submitLabel = 'Submit',
37
38
  cancelLabel = 'Cancel',
38
39
  showCancel = false,
40
+ showSubmit = true,
39
41
  layout = 'vertical',
40
42
  columns = 1,
41
43
  onSubmit: onSubmitProp,
42
44
  onChange: onChangeProp,
45
+ onCancel: onCancelProp,
43
46
  resetOnSubmit = false,
44
47
  validationMode = 'onSubmit',
45
48
  disabled = false,
@@ -54,6 +57,11 @@ ComponentRegistry.register('form',
54
57
  const [isSubmitting, setIsSubmitting] = React.useState(false);
55
58
  const [submitError, setSubmitError] = React.useState<string | null>(null);
56
59
 
60
+ // React to defaultValues changes
61
+ React.useEffect(() => {
62
+ form.reset(defaultValues);
63
+ }, [defaultValues]);
64
+
57
65
  // Watch for form changes - only track changes when onAction is available
58
66
  React.useEffect(() => {
59
67
  if (onAction) {
@@ -73,12 +81,34 @@ ComponentRegistry.register('form',
73
81
  setIsSubmitting(true);
74
82
  setSubmitError(null);
75
83
 
84
+ // Defensive check: If data is an Event, use getValues()
85
+ let formData = data;
86
+ // Check for Event-like properties
87
+ const isEvent = data && (
88
+ (data as any).nativeEvent ||
89
+ typeof (data as any).preventDefault === 'function' ||
90
+ typeof (data as any).stopPropagation === 'function' ||
91
+ (data as any).target ||
92
+ (data as any).bubbles
93
+ );
94
+
95
+ if (isEvent) {
96
+ // This should not happen with RHF handleSubmit, but just in case
97
+ formData = form.getValues();
98
+ } else if (!formData || Object.keys(formData).length === 0) {
99
+ // Fallback: if data is empty check getValues(), in case RHF failed to pass it for some reason
100
+ const values = form.getValues();
101
+ if (values && Object.keys(values).length > 0) {
102
+ formData = values;
103
+ }
104
+ }
105
+
76
106
  try {
77
107
  if (onAction) {
78
108
  const result = await onAction({
79
109
  type: 'form_submit',
80
- data,
81
- formData: data,
110
+ data: formData,
111
+ formData: formData,
82
112
  }) as any;
83
113
 
84
114
  // Check if submission returned an error
@@ -89,7 +119,7 @@ ComponentRegistry.register('form',
89
119
  }
90
120
 
91
121
  if (onSubmitProp && typeof onSubmitProp === 'function') {
92
- await onSubmitProp(data);
122
+ await onSubmitProp(formData);
93
123
  }
94
124
 
95
125
  if (resetOnSubmit) {
@@ -117,6 +147,11 @@ ComponentRegistry.register('form',
117
147
  // Handle cancel
118
148
  const handleCancel = () => {
119
149
  form.reset();
150
+
151
+ if (onCancelProp && typeof onCancelProp === 'function') {
152
+ onCancelProp();
153
+ }
154
+
120
155
  if (onAction) {
121
156
  onAction({
122
157
  type: 'form_cancel',
@@ -137,11 +172,21 @@ ComponentRegistry.register('form',
137
172
  ? cn('grid gap-4', gridColsClass)
138
173
  : 'space-y-4';
139
174
 
140
- // Extract designer-related props
175
+ // Extract designer-related props and conflicting handlers
141
176
  const {
142
177
  'data-obj-id': dataObjId,
143
178
  'data-obj-type': dataObjType,
144
- style,
179
+ style,
180
+ onSubmit: _ignoredOnSubmit, // Prevent overwriting our handleSubmit
181
+ onChange: _ignoredOnChange, // Prevent overwriting our onChange
182
+ // Extract schema props that should not be spread to DOM (handled separately by schema destructuring above)
183
+ submitLabel: _submitLabel,
184
+ cancelLabel: _cancelLabel,
185
+ showSubmit: _showSubmit,
186
+ showCancel: _showCancel,
187
+ resetOnSubmit: _resetOnSubmit,
188
+ defaultValues: _defaultValues,
189
+ inputType: _inputType,
145
190
  ...formProps
146
191
  } = props;
147
192
 
@@ -183,9 +228,17 @@ ComponentRegistry.register('form',
183
228
  disabled: fieldDisabled = false,
184
229
  validation = {},
185
230
  condition,
231
+ colSpan,
232
+ hidden,
233
+ widget,
234
+ visibleOn,
235
+ readonly,
186
236
  ...fieldProps
187
237
  } = field;
188
238
 
239
+ // Skip hidden fields
240
+ if (hidden) return null;
241
+
189
242
  // Handle conditional rendering with null/undefined safety
190
243
  if (condition) {
191
244
  const watchField = condition.field;
@@ -219,6 +272,17 @@ ComponentRegistry.register('form',
219
272
  // Use field.id or field.name for stable keys (never use index alone)
220
273
  const fieldKey = field.id ?? name;
221
274
 
275
+ // Resolve the component type: prefer widget override, fallback to field type
276
+ const resolvedType = widget || type;
277
+
278
+ // colSpan classes for grid layout
279
+ const colSpanClass = colSpan && colSpan > 1
280
+ ? colSpan === 2 ? 'col-span-2'
281
+ : colSpan === 3 ? 'col-span-3'
282
+ : colSpan >= 4 ? 'col-span-4'
283
+ : ''
284
+ : '';
285
+
222
286
  return (
223
287
  <FormField
224
288
  key={fieldKey}
@@ -226,7 +290,7 @@ ComponentRegistry.register('form',
226
290
  name={name}
227
291
  rules={rules}
228
292
  render={({ field: formField }) => (
229
- <FormItem>
293
+ <FormItem className={colSpanClass || undefined}>
230
294
  {label && (
231
295
  <FormLabel>
232
296
  {label}
@@ -238,14 +302,17 @@ ComponentRegistry.register('form',
238
302
  </FormLabel>
239
303
  )}
240
304
  <FormControl>
241
- {/* Render the actual field component based on type */}
242
- {renderFieldComponent(type, {
305
+ {/* Render the actual field component based on resolved type */}
306
+ {renderFieldComponent(resolvedType, {
243
307
  ...fieldProps,
308
+ // specialized fields needs raw metadata, but we should traverse down if it exists
309
+ // field is the field configuration loop variable
310
+ field: (field as any).field || field,
244
311
  ...formField,
245
312
  inputType: fieldProps.inputType,
246
313
  options: fieldProps.options,
247
314
  placeholder: fieldProps.placeholder,
248
- disabled: disabled || fieldDisabled || isSubmitting,
315
+ disabled: disabled || fieldDisabled || readonly || isSubmitting,
249
316
  })}
250
317
  </FormControl>
251
318
  {description && (
@@ -273,6 +340,7 @@ ComponentRegistry.register('form',
273
340
  {cancelLabel}
274
341
  </Button>
275
342
  )}
343
+ {showSubmit && (
276
344
  <Button
277
345
  type="submit"
278
346
  disabled={isSubmitting || disabled}
@@ -280,6 +348,7 @@ ComponentRegistry.register('form',
280
348
  {isSubmitting && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
281
349
  {submitLabel}
282
350
  </Button>
351
+ )}
283
352
  </div>
284
353
  )}
285
354
  </form>
@@ -287,6 +356,7 @@ ComponentRegistry.register('form',
287
356
  );
288
357
  },
289
358
  {
359
+ namespace: 'ui',
290
360
  label: 'Form',
291
361
  inputs: [
292
362
  {
@@ -372,26 +442,52 @@ interface RenderFieldProps {
372
442
  }
373
443
 
374
444
  function renderFieldComponent(type: string, props: RenderFieldProps) {
445
+ // 1. Try to resolve specialized field widget from registry first
446
+ // We prioritize registry components (e.g., 'field.currency', 'field.date')
447
+ const RegisteredComponent = ComponentRegistry.get(type);
448
+
449
+ if (RegisteredComponent) {
450
+ // For specialized fields (e.g. fields package), they expect 'field' prop.
451
+ // Ensure we pass all props.
452
+ // Also pass 'schema' for standard renderers that expect it
453
+ return <RegisteredComponent schema={props} {...props} />;
454
+ }
455
+
375
456
  const { inputType, options = [], placeholder, ...fieldProps } = props;
376
457
 
377
458
  switch (type) {
378
459
  case 'input':
379
- return <Input type={inputType || 'text'} placeholder={placeholder} {...fieldProps} />;
380
-
460
+ if (inputType === 'file') {
461
+ // File inputs cannot be controlled with value prop
462
+ const { value, ...fileProps } = fieldProps;
463
+ return <Input type="file" placeholder={placeholder} {...fileProps} />;
464
+ }
465
+ return <Input type={inputType || 'text'} placeholder={placeholder} {...fieldProps} value={fieldProps.value ?? ''} />;
466
+
381
467
  case 'textarea':
382
- return <Textarea placeholder={placeholder} {...fieldProps} />;
468
+ return <Textarea placeholder={placeholder} {...fieldProps} value={fieldProps.value ?? ''} />;
383
469
 
384
470
  case 'checkbox': {
385
471
  // For checkbox, we need to handle the value differently
386
472
  const { value, onChange, ...checkboxProps } = fieldProps;
387
473
  return (
388
- <div className="flex items-center space-x-2">
389
- <Checkbox
390
- checked={value}
391
- onCheckedChange={onChange}
392
- {...checkboxProps}
393
- />
394
- </div>
474
+ <Checkbox
475
+ checked={value}
476
+ onCheckedChange={onChange}
477
+ {...checkboxProps}
478
+ />
479
+ );
480
+ }
481
+
482
+ case 'switch': {
483
+ // For switch, we need to handle the value differently (same as checkbox)
484
+ const { value, onChange, ...switchProps } = fieldProps;
485
+ return (
486
+ <Switch
487
+ checked={value}
488
+ onCheckedChange={onChange}
489
+ {...switchProps}
490
+ />
395
491
  );
396
492
  }
397
493
 
@@ -38,6 +38,7 @@ ComponentRegistry.register('input-otp',
38
38
  );
39
39
  },
40
40
  {
41
+ namespace: 'ui',
41
42
  label: 'Input OTP',
42
43
  inputs: [
43
44
  { name: 'maxLength', type: 'number', label: 'Max Length', defaultValue: 6 },
@@ -63,6 +63,7 @@ const InputRenderer = ({ schema, className, onChange, value, ...props }: { schem
63
63
  };
64
64
 
65
65
  ComponentRegistry.register('input', InputRenderer, {
66
+ namespace: 'ui',
66
67
  label: 'Input Field',
67
68
  inputs: [
68
69
  { name: 'label', type: 'string', label: 'Label' },
@@ -88,6 +89,7 @@ ComponentRegistry.register('input', InputRenderer, {
88
89
  ComponentRegistry.register('email',
89
90
  (props: any) => <InputRenderer {...props} schema={{ ...props.schema, inputType: 'email' }} />,
90
91
  {
92
+ namespace: 'ui',
91
93
  label: 'Email Input',
92
94
  icon: 'mail',
93
95
  inputs: [
@@ -104,6 +106,7 @@ ComponentRegistry.register('email',
104
106
  ComponentRegistry.register('password',
105
107
  (props: any) => <InputRenderer {...props} schema={{ ...props.schema, inputType: 'password' }} />,
106
108
  {
109
+ namespace: 'ui',
107
110
  label: 'Password Input',
108
111
  icon: 'lock',
109
112
  inputs: [
@@ -32,6 +32,7 @@ ComponentRegistry.register('label',
32
32
  );
33
33
  },
34
34
  {
35
+ namespace: 'ui',
35
36
  label: 'Label',
36
37
  inputs: [
37
38
  { name: 'text', type: 'string', label: 'Text', required: true },
@@ -38,6 +38,7 @@ ComponentRegistry.register('radio-group',
38
38
  );
39
39
  },
40
40
  {
41
+ namespace: 'ui',
41
42
  label: 'Radio Group',
42
43
  inputs: [
43
44
  { name: 'defaultValue', type: 'string', label: 'Default Value' },
@@ -16,44 +16,64 @@ import {
16
16
  SelectItem,
17
17
  Label
18
18
  } from '../../ui';
19
+ import { cn } from '../../lib/utils';
20
+ import React from 'react';
19
21
 
20
- ComponentRegistry.register('select',
21
- ({ schema, className, ...props }: { schema: SelectSchema; className?: string; [key: string]: any }) => {
22
- // Extract designer-related props
23
- const {
24
- 'data-obj-id': dataObjId,
25
- 'data-obj-type': dataObjType,
26
- style,
27
- ...selectProps
28
- } = props;
22
+ const SelectRenderer = ({ schema, className, onChange, value, ...props }: { schema: SelectSchema; className?: string; onChange?: (val: any) => void; value?: any; [key: string]: any }) => {
23
+ // Extract designer-related props
24
+ const {
25
+ 'data-obj-id': dataObjId,
26
+ 'data-obj-type': dataObjType,
27
+ style,
28
+ ...selectProps
29
+ } = props;
29
30
 
30
- return (
31
+ const handleValueChange = (newValue: string) => {
32
+ if (onChange) {
33
+ onChange(newValue);
34
+ }
35
+ };
36
+
37
+ return (
31
38
  <div
32
- className={`grid w-full max-w-sm items-center gap-1.5 ${schema.wrapperClass || ''}`}
39
+ className={cn("grid w-full items-center gap-1.5", schema.wrapperClass)}
33
40
  data-obj-id={dataObjId}
34
41
  data-obj-type={dataObjType}
35
42
  style={style}
36
43
  >
37
- {schema.label && <Label>{schema.label}</Label>}
38
- <Select defaultValue={schema.defaultValue} {...selectProps}>
44
+ {schema.label && <Label className={cn(schema.required && "text-destructive after:content-['*'] after:ml-0.5")}>{schema.label}</Label>}
45
+ <Select
46
+ defaultValue={value === undefined ? schema.defaultValue : undefined}
47
+ value={value ?? schema.value}
48
+ onValueChange={handleValueChange}
49
+ disabled={schema.disabled}
50
+ required={schema.required}
51
+ name={schema.name}
52
+ {...selectProps}
53
+ >
39
54
  <SelectTrigger className={className}>
40
55
  <SelectValue placeholder={schema.placeholder} />
41
56
  </SelectTrigger>
42
57
  <SelectContent>
43
58
  {schema.options?.map((opt) => (
44
- <SelectItem key={opt.value} value={opt.value}>{opt.label}</SelectItem>
59
+ <SelectItem key={opt.value} value={opt.value} disabled={opt.disabled}>{opt.label}</SelectItem>
45
60
  ))}
46
61
  </SelectContent>
47
62
  </Select>
48
63
  </div>
49
64
  );
50
- },
65
+ };
66
+
67
+ ComponentRegistry.register('select', SelectRenderer,
51
68
  {
69
+ namespace: 'ui',
52
70
  label: 'Select',
53
71
  inputs: [
54
72
  { name: 'label', type: 'string', label: 'Label' },
55
73
  { name: 'placeholder', type: 'string', label: 'Placeholder' },
56
74
  { name: 'defaultValue', type: 'string', label: 'Default Value' },
75
+ { name: 'required', type: 'boolean', label: 'Required' },
76
+ { name: 'disabled', type: 'boolean', label: 'Disabled' },
57
77
  {
58
78
  name: 'options',
59
79
  type: 'array',
@@ -41,6 +41,7 @@ ComponentRegistry.register('slider',
41
41
  );
42
42
  },
43
43
  {
44
+ namespace: 'ui',
44
45
  label: 'Slider',
45
46
  inputs: [
46
47
  { name: 'defaultValue', type: 'array', label: 'Default Value', defaultValue: [50] },
@@ -33,6 +33,7 @@ ComponentRegistry.register('switch',
33
33
  );
34
34
  },
35
35
  {
36
+ namespace: 'ui',
36
37
  label: 'Switch',
37
38
  inputs: [
38
39
  { name: 'label', type: 'string', label: 'Label', required: true },
@@ -9,45 +9,68 @@
9
9
  import { ComponentRegistry } from '@object-ui/core';
10
10
  import type { TextareaSchema } from '@object-ui/types';
11
11
  import { Textarea, Label } from '../../ui';
12
+ import { cn } from '../../lib/utils';
13
+ import React from 'react';
12
14
 
13
- ComponentRegistry.register('textarea',
14
- ({ schema, className, ...props }: { schema: TextareaSchema; className?: string; [key: string]: any }) => {
15
- // Extract designer-related props
16
- const {
17
- 'data-obj-id': dataObjId,
18
- 'data-obj-type': dataObjType,
19
- style,
20
- ...inputProps
21
- } = props;
15
+ const TextareaRenderer = ({ schema, className, onChange, value, ...props }: { schema: TextareaSchema; className?: string; onChange?: (val: any) => void; value?: any; [key: string]: any }) => {
16
+ // Handle change for both raw inputs and form-bound inputs
17
+ const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
18
+ if (onChange) {
19
+ onChange(e.target.value);
20
+ }
21
+ };
22
+
23
+ // Extract designer-related props
24
+ const {
25
+ 'data-obj-id': dataObjId,
26
+ 'data-obj-type': dataObjType,
27
+ style,
28
+ ...inputProps
29
+ } = props;
30
+
31
+ return (
32
+ <div
33
+ className={cn("grid w-full gap-1.5", schema.wrapperClass)}
34
+ data-obj-id={dataObjId}
35
+ data-obj-type={dataObjType}
36
+ style={style}
37
+ >
38
+ {schema.label && <Label htmlFor={schema.id} className={cn(schema.required && "text-destructive after:content-['*'] after:ml-0.5")}>{schema.label}</Label>}
39
+ <Textarea
40
+ id={schema.id}
41
+ name={schema.name}
42
+ placeholder={schema.placeholder}
43
+ className={className}
44
+ disabled={schema.disabled}
45
+ readOnly={schema.readOnly}
46
+ required={schema.required}
47
+ rows={schema.rows}
48
+ value={value ?? schema.value ?? ''}
49
+ defaultValue={value === undefined ? schema.defaultValue : undefined}
50
+ onChange={handleChange}
51
+ {...inputProps}
52
+ />
53
+ </div>
54
+ );
55
+ };
22
56
 
23
- return (
24
- <div
25
- className={`grid w-full gap-1.5 ${schema.wrapperClass || ''}`}
26
- data-obj-id={dataObjId}
27
- data-obj-type={dataObjType}
28
- style={style}
29
- >
30
- {schema.label && <Label htmlFor={schema.id}>{schema.label}</Label>}
31
- <Textarea
32
- id={schema.id}
33
- placeholder={schema.placeholder}
34
- className={className}
35
- {...inputProps}
36
- />
37
- </div>
38
- );
39
- },
57
+ ComponentRegistry.register('textarea', TextareaRenderer,
40
58
  {
59
+ namespace: 'ui',
41
60
  label: 'Textarea',
42
61
  inputs: [
43
62
  { name: 'label', type: 'string', label: 'Label' },
44
63
  { name: 'placeholder', type: 'string', label: 'Placeholder' },
64
+ { name: 'rows', type: 'number', label: 'Rows' },
65
+ { name: 'required', type: 'boolean', label: 'Required' },
66
+ { name: 'disabled', type: 'boolean', label: 'Disabled' },
45
67
  { name: 'id', type: 'string', label: 'ID', required: true }
46
68
  ],
47
69
  defaultProps: {
48
70
  label: 'Textarea label',
49
71
  placeholder: 'Enter text here...',
50
- id: 'textarea-field' // Will be made unique by designer's ensureNodeIds
72
+ rows: 3,
73
+ id: 'textarea-field'
51
74
  }
52
75
  }
53
76
  );
@@ -8,7 +8,7 @@
8
8
 
9
9
  import { ComponentRegistry } from '@object-ui/core';
10
10
  import type { ToggleSchema } from '@object-ui/types';
11
- import { Toggle, ToggleGroup, ToggleGroupItem } from '../../ui';
11
+ import { Toggle } from '../../ui';
12
12
  import { renderChildren } from '../../lib/utils';
13
13
 
14
14
  ComponentRegistry.register('toggle',
@@ -24,13 +24,14 @@ ComponentRegistry.register('toggle',
24
24
  </Toggle>
25
25
  ),
26
26
  {
27
+ namespace: 'ui',
27
28
  label: 'Toggle',
28
29
  inputs: [
29
30
  { name: 'label', type: 'string', label: 'Label' },
30
31
  { name: 'pressed', type: 'boolean', label: 'Pressed' },
31
32
  { name: 'variant', type: 'enum', enum: ['default', 'outline'], defaultValue: 'default', label: 'Variant' },
32
33
  { name: 'size', type: 'enum', enum: ['default', 'sm', 'lg'], defaultValue: 'default', label: 'Size' },
33
- { name: 'ariaLabel', type: 'string', label: 'Aria Label' }
34
+ { name: 'ariaLabel', type: 'string', label: 'Aria Label' }
34
35
  ],
35
36
  defaultProps: {
36
37
  label: 'Toggle',
@@ -39,46 +40,3 @@ ComponentRegistry.register('toggle',
39
40
  }
40
41
  }
41
42
  );
42
-
43
- ComponentRegistry.register('toggle-group',
44
- ({ schema, className, ...props }) => (
45
- <ToggleGroup
46
- type={schema.groupType || 'single'}
47
- variant={schema.variant}
48
- size={schema.size}
49
- className={className}
50
- {...props}
51
- >
52
- {schema.items?.map((item: any) => (
53
- <ToggleGroupItem key={item.value} value={item.value} aria-label={item.label}>
54
- {item.icon || item.label}
55
- </ToggleGroupItem>
56
- ))}
57
- </ToggleGroup>
58
- ),
59
- {
60
- label: 'Toggle Group',
61
- inputs: [
62
- { name: 'groupType', type: 'enum', enum: ['single', 'multiple'], defaultValue: 'single', label: 'Type' },
63
- { name: 'variant', type: 'enum', enum: ['default', 'outline'], defaultValue: 'default', label: 'Variant' },
64
- { name: 'size', type: 'enum', enum: ['default', 'sm', 'lg'], defaultValue: 'default', label: 'Size' },
65
- {
66
- name: 'items',
67
- type: 'array',
68
- label: 'Items',
69
- description: 'Array of {label, value, icon?} objects'
70
- },
71
- { name: 'className', type: 'string', label: 'CSS Class' }
72
- ],
73
- defaultProps: {
74
- groupType: 'single',
75
- variant: 'default',
76
- size: 'default',
77
- items: [
78
- { label: 'A', value: 'a' },
79
- { label: 'B', value: 'b' },
80
- { label: 'C', value: 'c' }
81
- ]
82
- }
83
- }
84
- );
@@ -15,3 +15,4 @@ import './feedback';
15
15
  import './overlay';
16
16
  import './disclosure';
17
17
  import './complex';
18
+ import './action';
@@ -30,12 +30,13 @@ ComponentRegistry.register('aspect-ratio',
30
30
  {schema.image ? (
31
31
  <img src={schema.image} alt={schema.alt || ''} className="rounded-md object-cover w-full h-full" />
32
32
  ) : (
33
- renderChildren(schema.body)
33
+ renderChildren(schema.children || schema.body)
34
34
  )}
35
35
  </AspectRatio>
36
36
  );
37
37
  },
38
38
  {
39
+ namespace: 'ui',
39
40
  label: 'Aspect Ratio',
40
41
  inputs: [
41
42
  { name: 'ratio', type: 'number', label: 'Ratio', defaultValue: 16/9 },
@@ -8,7 +8,7 @@
8
8
 
9
9
  import { ComponentRegistry } from '@object-ui/core';
10
10
  import type { CardSchema } from '@object-ui/types';
11
- import { renderChildren } from '../../lib/utils';
11
+ import { renderChildren, cn } from '../../lib/utils';
12
12
  import {
13
13
  Card,
14
14
  CardHeader,
@@ -28,11 +28,18 @@ const CardRenderer = forwardRef<HTMLDivElement, { schema: CardSchema; className?
28
28
  style,
29
29
  ...cardProps
30
30
  } = props;
31
+
32
+ const isClickable = schema.clickable || !!props.onClick;
33
+ const isHoverable = schema.hoverable || isClickable;
31
34
 
32
35
  return (
33
36
  <Card
34
37
  ref={ref}
35
- className={className}
38
+ className={cn(
39
+ className,
40
+ isHoverable && "transition-colors hover:bg-muted/50",
41
+ isClickable && "cursor-pointer active:bg-muted"
42
+ )}
36
43
  {...cardProps}
37
44
  // Apply designer props
38
45
  {...{ 'data-obj-id': dataObjId, 'data-obj-type': dataObjType, style }}
@@ -54,6 +61,7 @@ const CardRenderer = forwardRef<HTMLDivElement, { schema: CardSchema; className?
54
61
  ComponentRegistry.register('card',
55
62
  CardRenderer,
56
63
  {
64
+ namespace: 'ui',
57
65
  label: 'Card',
58
66
  inputs: [
59
67
  { name: 'title', type: 'string', label: 'Title' },
@@ -77,6 +77,7 @@ const ContainerRenderer = forwardRef<HTMLDivElement, { schema: ContainerSchema;
77
77
  ComponentRegistry.register('container',
78
78
  ContainerRenderer,
79
79
  {
80
+ namespace: 'ui',
80
81
  label: 'Container',
81
82
  inputs: [
82
83
  {
@@ -76,6 +76,7 @@ ComponentRegistry.register('flex',
76
76
  );
77
77
  },
78
78
  {
79
+ namespace: 'ui',
79
80
  label: 'Flex Layout',
80
81
  inputs: [
81
82
  {