@object-ui/components 0.3.0 → 0.3.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 (317) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/ISSUES_FOUND.md +128 -0
  3. package/README.md +19 -1
  4. package/README_SHADCN_SYNC.md +281 -0
  5. package/TESTING.md +335 -0
  6. package/dist/index.css +1 -1
  7. package/dist/index.js +30981 -30027
  8. package/dist/index.umd.cjs +30 -39
  9. package/dist/src/hooks/use-mobile.d.ts +7 -0
  10. package/dist/src/index.d.ts +4 -1
  11. package/dist/src/renderers/basic/button-group.d.ts +8 -0
  12. package/dist/src/renderers/basic/div.d.ts +7 -0
  13. package/dist/src/renderers/basic/html.d.ts +7 -0
  14. package/dist/src/renderers/basic/icon.d.ts +7 -0
  15. package/dist/src/renderers/basic/image.d.ts +7 -0
  16. package/dist/src/renderers/basic/navigation-menu.d.ts +8 -0
  17. package/dist/src/renderers/basic/pagination.d.ts +8 -0
  18. package/dist/src/renderers/basic/separator.d.ts +7 -0
  19. package/dist/src/renderers/basic/span.d.ts +7 -0
  20. package/dist/src/renderers/basic/text.d.ts +7 -0
  21. package/dist/src/renderers/complex/carousel.d.ts +7 -0
  22. package/dist/src/renderers/complex/data-table.d.ts +7 -0
  23. package/dist/src/renderers/complex/filter-builder.d.ts +7 -0
  24. package/dist/src/renderers/complex/resizable.d.ts +7 -0
  25. package/dist/src/renderers/complex/scroll-area.d.ts +7 -0
  26. package/dist/src/renderers/complex/table.d.ts +7 -0
  27. package/dist/src/renderers/data-display/alert.d.ts +7 -0
  28. package/dist/src/renderers/data-display/avatar.d.ts +7 -0
  29. package/dist/src/renderers/data-display/badge.d.ts +7 -0
  30. package/dist/src/renderers/data-display/breadcrumb.d.ts +8 -0
  31. package/dist/src/renderers/data-display/kbd.d.ts +8 -0
  32. package/dist/src/renderers/data-display/list.d.ts +7 -0
  33. package/dist/src/renderers/data-display/statistic.d.ts +7 -0
  34. package/dist/src/renderers/data-display/table.d.ts +8 -0
  35. package/dist/src/renderers/data-display/tree-view.d.ts +7 -0
  36. package/dist/src/renderers/disclosure/accordion.d.ts +7 -0
  37. package/dist/src/renderers/disclosure/collapsible.d.ts +7 -0
  38. package/dist/src/renderers/disclosure/toggle-group.d.ts +8 -0
  39. package/dist/src/renderers/feedback/empty.d.ts +8 -0
  40. package/dist/src/renderers/feedback/loading.d.ts +7 -0
  41. package/dist/src/renderers/feedback/progress.d.ts +7 -0
  42. package/dist/src/renderers/feedback/skeleton.d.ts +7 -0
  43. package/dist/src/renderers/feedback/sonner.d.ts +8 -0
  44. package/dist/src/renderers/feedback/spinner.d.ts +8 -0
  45. package/dist/src/renderers/feedback/toast.d.ts +8 -0
  46. package/dist/src/renderers/feedback/toaster.d.ts +7 -0
  47. package/dist/src/renderers/form/button.d.ts +7 -0
  48. package/dist/src/renderers/form/calendar.d.ts +7 -0
  49. package/dist/src/renderers/form/checkbox.d.ts +7 -0
  50. package/dist/src/renderers/form/combobox.d.ts +8 -0
  51. package/dist/src/renderers/form/command.d.ts +8 -0
  52. package/dist/src/renderers/form/date-picker.d.ts +7 -0
  53. package/dist/src/renderers/form/file-upload.d.ts +7 -0
  54. package/dist/src/renderers/form/form.d.ts +7 -0
  55. package/dist/src/renderers/form/input-otp.d.ts +7 -0
  56. package/dist/src/renderers/form/input.d.ts +7 -0
  57. package/dist/src/renderers/form/label.d.ts +7 -0
  58. package/dist/src/renderers/form/radio-group.d.ts +7 -0
  59. package/dist/src/renderers/form/select.d.ts +7 -0
  60. package/dist/src/renderers/form/slider.d.ts +7 -0
  61. package/dist/src/renderers/form/switch.d.ts +7 -0
  62. package/dist/src/renderers/form/textarea.d.ts +7 -0
  63. package/dist/src/renderers/form/toggle.d.ts +7 -0
  64. package/dist/src/renderers/layout/aspect-ratio.d.ts +8 -0
  65. package/dist/src/renderers/layout/card.d.ts +7 -0
  66. package/dist/src/renderers/layout/container.d.ts +7 -0
  67. package/dist/src/renderers/layout/flex.d.ts +7 -0
  68. package/dist/src/renderers/layout/grid.d.ts +7 -0
  69. package/dist/src/renderers/layout/semantic.d.ts +7 -0
  70. package/dist/src/renderers/layout/stack.d.ts +7 -0
  71. package/dist/src/renderers/layout/tabs.d.ts +7 -0
  72. package/dist/src/renderers/navigation/header-bar.d.ts +7 -0
  73. package/dist/src/renderers/navigation/sidebar.d.ts +7 -0
  74. package/dist/src/renderers/overlay/alert-dialog.d.ts +7 -0
  75. package/dist/src/renderers/overlay/context-menu.d.ts +7 -0
  76. package/dist/src/renderers/overlay/dialog.d.ts +7 -0
  77. package/dist/src/renderers/overlay/drawer.d.ts +7 -0
  78. package/dist/src/renderers/overlay/dropdown-menu.d.ts +7 -0
  79. package/dist/src/renderers/overlay/hover-card.d.ts +7 -0
  80. package/dist/src/renderers/overlay/menubar.d.ts +8 -0
  81. package/dist/src/renderers/overlay/popover.d.ts +7 -0
  82. package/dist/src/renderers/overlay/sheet.d.ts +7 -0
  83. package/dist/src/renderers/overlay/tooltip.d.ts +7 -0
  84. package/dist/src/renderers/placeholders.d.ts +9 -0
  85. package/dist/src/ui/accordion.d.ts +7 -0
  86. package/dist/src/ui/alert-dialog.d.ts +7 -0
  87. package/dist/src/ui/alert.d.ts +7 -0
  88. package/dist/src/ui/aspect-ratio.d.ts +7 -0
  89. package/dist/src/ui/avatar.d.ts +7 -0
  90. package/dist/src/ui/badge.d.ts +7 -0
  91. package/dist/src/ui/breadcrumb.d.ts +7 -0
  92. package/dist/src/ui/button.d.ts +10 -5
  93. package/dist/src/ui/calendar.d.ts +14 -7
  94. package/dist/src/ui/card.d.ts +7 -0
  95. package/dist/src/ui/carousel.d.ts +7 -0
  96. package/dist/src/ui/checkbox.d.ts +7 -0
  97. package/dist/src/ui/collapsible.d.ts +7 -0
  98. package/dist/src/ui/combobox.d.ts +22 -0
  99. package/dist/src/ui/command.d.ts +7 -0
  100. package/dist/src/ui/context-menu.d.ts +7 -0
  101. package/dist/src/ui/date-picker.d.ts +15 -0
  102. package/dist/src/ui/dialog.d.ts +7 -0
  103. package/dist/src/ui/drawer.d.ts +7 -0
  104. package/dist/src/ui/dropdown-menu.d.ts +7 -0
  105. package/dist/src/ui/filter-builder.d.ts +7 -0
  106. package/dist/src/ui/form.d.ts +7 -0
  107. package/dist/src/ui/hover-card.d.ts +7 -0
  108. package/dist/src/ui/index.d.ts +10 -5
  109. package/dist/src/ui/input-otp.d.ts +7 -0
  110. package/dist/src/ui/input.d.ts +7 -0
  111. package/dist/src/ui/item.d.ts +7 -0
  112. package/dist/src/ui/kbd.d.ts +7 -0
  113. package/dist/src/ui/label.d.ts +7 -0
  114. package/dist/src/ui/menubar.d.ts +7 -0
  115. package/dist/src/ui/navigation-menu.d.ts +7 -0
  116. package/dist/src/ui/pagination.d.ts +7 -0
  117. package/dist/src/ui/popover.d.ts +7 -0
  118. package/dist/src/ui/progress.d.ts +7 -0
  119. package/dist/src/ui/radio-group.d.ts +7 -0
  120. package/dist/src/ui/resizable.d.ts +7 -0
  121. package/dist/src/ui/scroll-area.d.ts +7 -0
  122. package/dist/src/ui/select.d.ts +9 -2
  123. package/dist/src/ui/separator.d.ts +7 -0
  124. package/dist/src/ui/sheet.d.ts +7 -0
  125. package/dist/src/ui/sidebar.d.ts +14 -9
  126. package/dist/src/ui/skeleton.d.ts +7 -0
  127. package/dist/src/ui/slider.d.ts +7 -0
  128. package/dist/src/ui/spinner.d.ts +7 -0
  129. package/dist/src/ui/switch.d.ts +7 -0
  130. package/dist/src/ui/table.d.ts +15 -8
  131. package/dist/src/ui/tabs.d.ts +7 -0
  132. package/dist/src/ui/textarea.d.ts +7 -0
  133. package/dist/src/ui/toggle-group.d.ts +8 -3
  134. package/dist/src/ui/toggle.d.ts +7 -0
  135. package/dist/src/ui/tooltip.d.ts +7 -0
  136. package/metadata/ObjectGrid.component.yml +72 -0
  137. package/package.json +23 -11
  138. package/postcss.config.js +9 -1
  139. package/shadcn-components.json +310 -0
  140. package/src/__tests__/README.md +124 -0
  141. package/src/__tests__/basic-renderers.test.tsx +255 -0
  142. package/src/__tests__/complex-disclosure-renderers.test.tsx +301 -0
  143. package/src/__tests__/feedback-overlay-renderers.test.tsx +349 -0
  144. package/src/__tests__/form-renderers.test.tsx +364 -0
  145. package/src/__tests__/layout-data-renderers.test.tsx +340 -0
  146. package/src/__tests__/test-utils.tsx +190 -0
  147. package/src/hooks/use-mobile.tsx +8 -0
  148. package/src/index.css +86 -54
  149. package/src/index.test.ts +8 -0
  150. package/src/index.ts +21 -1
  151. package/src/lib/utils.tsx +8 -0
  152. package/src/new-components.test.ts +8 -9
  153. package/src/renderers/basic/button-group.tsx +78 -0
  154. package/src/renderers/basic/div.tsx +9 -1
  155. package/src/renderers/basic/html.tsx +8 -0
  156. package/src/renderers/basic/icon.tsx +66 -3
  157. package/src/renderers/basic/image.tsx +12 -1
  158. package/src/renderers/basic/index.ts +11 -0
  159. package/src/renderers/basic/navigation-menu.tsx +80 -0
  160. package/src/renderers/basic/pagination.tsx +82 -0
  161. package/src/renderers/basic/separator.tsx +9 -1
  162. package/src/renderers/basic/span.tsx +9 -1
  163. package/src/renderers/basic/text.tsx +8 -0
  164. package/src/renderers/complex/__tests__/data-table.test.ts +8 -0
  165. package/src/renderers/complex/carousel.tsx +11 -3
  166. package/src/renderers/complex/data-table.tsx +19 -4
  167. package/src/renderers/complex/filter-builder.tsx +8 -0
  168. package/src/renderers/complex/index.ts +9 -3
  169. package/src/renderers/complex/resizable.tsx +8 -0
  170. package/src/renderers/complex/scroll-area.tsx +8 -0
  171. package/src/renderers/complex/table.tsx +10 -2
  172. package/src/renderers/data-display/alert.tsx +8 -0
  173. package/src/renderers/data-display/avatar.tsx +8 -0
  174. package/src/renderers/data-display/badge.tsx +8 -0
  175. package/src/renderers/data-display/breadcrumb.tsx +59 -0
  176. package/src/renderers/data-display/index.ts +12 -0
  177. package/src/renderers/data-display/kbd.tsx +49 -0
  178. package/src/renderers/data-display/list.tsx +8 -0
  179. package/src/renderers/data-display/statistic.tsx +24 -43
  180. package/src/renderers/data-display/table.tsx +68 -0
  181. package/src/renderers/data-display/tree-view.tsx +26 -37
  182. package/src/renderers/disclosure/accordion.tsx +8 -0
  183. package/src/renderers/disclosure/collapsible.tsx +8 -0
  184. package/src/renderers/disclosure/index.ts +9 -0
  185. package/src/renderers/disclosure/toggle-group.tsx +77 -0
  186. package/src/renderers/feedback/empty.tsx +48 -0
  187. package/src/renderers/feedback/index.ts +12 -0
  188. package/src/renderers/feedback/loading.tsx +8 -0
  189. package/src/renderers/feedback/progress.tsx +8 -0
  190. package/src/renderers/feedback/skeleton.tsx +8 -0
  191. package/src/renderers/feedback/sonner.tsx +55 -0
  192. package/src/renderers/feedback/spinner.tsx +54 -0
  193. package/src/renderers/feedback/toast.tsx +58 -0
  194. package/src/renderers/feedback/toaster.tsx +13 -17
  195. package/src/renderers/form/button.tsx +8 -0
  196. package/src/renderers/form/calendar.tsx +8 -0
  197. package/src/renderers/form/checkbox.tsx +8 -0
  198. package/src/renderers/form/combobox.tsx +47 -0
  199. package/src/renderers/form/command.tsx +57 -0
  200. package/src/renderers/form/date-picker.tsx +10 -2
  201. package/src/renderers/form/file-upload.tsx +10 -2
  202. package/src/renderers/form/form.tsx +12 -3
  203. package/src/renderers/form/index.ts +10 -0
  204. package/src/renderers/form/input-otp.tsx +34 -15
  205. package/src/renderers/form/input.tsx +89 -50
  206. package/src/renderers/form/label.tsx +8 -0
  207. package/src/renderers/form/radio-group.tsx +8 -0
  208. package/src/renderers/form/select.tsx +8 -0
  209. package/src/renderers/form/slider.tsx +16 -1
  210. package/src/renderers/form/switch.tsx +8 -0
  211. package/src/renderers/form/textarea.tsx +8 -0
  212. package/src/renderers/form/toggle.tsx +8 -0
  213. package/src/renderers/index.ts +8 -0
  214. package/src/renderers/layout/aspect-ratio.tsx +50 -0
  215. package/src/renderers/layout/card.tsx +8 -0
  216. package/src/renderers/layout/container.tsx +20 -12
  217. package/src/renderers/layout/flex.tsx +16 -8
  218. package/src/renderers/layout/grid.tsx +8 -0
  219. package/src/renderers/layout/index.ts +9 -0
  220. package/src/renderers/layout/page.tsx +9 -1
  221. package/src/renderers/layout/semantic.tsx +8 -0
  222. package/src/renderers/layout/stack.tsx +16 -8
  223. package/src/renderers/layout/tabs.tsx +8 -0
  224. package/src/renderers/navigation/header-bar.tsx +9 -1
  225. package/src/renderers/navigation/index.ts +8 -0
  226. package/src/renderers/navigation/sidebar.tsx +8 -0
  227. package/src/renderers/overlay/alert-dialog.tsx +8 -0
  228. package/src/renderers/overlay/context-menu.tsx +9 -1
  229. package/src/renderers/overlay/dialog.tsx +8 -0
  230. package/src/renderers/overlay/drawer.tsx +8 -0
  231. package/src/renderers/overlay/dropdown-menu.tsx +8 -0
  232. package/src/renderers/overlay/hover-card.tsx +8 -0
  233. package/src/renderers/overlay/index.ts +9 -0
  234. package/src/renderers/overlay/menubar.tsx +75 -0
  235. package/src/renderers/overlay/popover.tsx +8 -0
  236. package/src/renderers/overlay/sheet.tsx +8 -0
  237. package/src/renderers/overlay/tooltip.tsx +8 -0
  238. package/src/renderers/placeholders.tsx +107 -0
  239. package/src/ui/accordion.tsx +8 -0
  240. package/src/ui/alert-dialog.tsx +8 -0
  241. package/src/ui/alert.tsx +14 -24
  242. package/src/ui/aspect-ratio.tsx +8 -0
  243. package/src/ui/avatar.tsx +8 -0
  244. package/src/ui/badge.tsx +13 -6
  245. package/src/ui/breadcrumb.tsx +8 -0
  246. package/src/ui/button-group.tsx +8 -0
  247. package/src/ui/button.tsx +38 -36
  248. package/src/ui/calendar.tsx +57 -200
  249. package/src/ui/card.tsx +8 -0
  250. package/src/ui/carousel.tsx +8 -0
  251. package/src/ui/checkbox.tsx +8 -0
  252. package/src/ui/collapsible.tsx +8 -0
  253. package/src/ui/combobox.tsx +104 -0
  254. package/src/ui/command.tsx +8 -0
  255. package/src/ui/context-menu.tsx +8 -0
  256. package/src/ui/date-picker.tsx +61 -0
  257. package/src/ui/dialog.tsx +8 -0
  258. package/src/ui/drawer.tsx +8 -0
  259. package/src/ui/dropdown-menu.tsx +8 -0
  260. package/src/ui/empty.tsx +8 -0
  261. package/src/ui/filter-builder.tsx +8 -0
  262. package/src/ui/form.tsx +8 -0
  263. package/src/ui/hover-card.tsx +8 -0
  264. package/src/ui/index.ts +11 -5
  265. package/src/ui/input-otp.tsx +20 -12
  266. package/src/ui/input.tsx +8 -0
  267. package/src/ui/item.tsx +8 -0
  268. package/src/ui/kbd.tsx +8 -0
  269. package/src/ui/label.tsx +8 -0
  270. package/src/ui/menubar.tsx +8 -0
  271. package/src/ui/navigation-menu.tsx +8 -0
  272. package/src/ui/pagination.tsx +8 -0
  273. package/src/ui/popover.tsx +9 -1
  274. package/src/ui/progress.tsx +11 -15
  275. package/src/ui/radio-group.tsx +8 -0
  276. package/src/ui/resizable.tsx +8 -0
  277. package/src/ui/scroll-area.tsx +9 -1
  278. package/src/ui/select.tsx +17 -9
  279. package/src/ui/separator.tsx +8 -0
  280. package/src/ui/sheet.tsx +8 -0
  281. package/src/ui/sidebar.tsx +34 -15
  282. package/src/ui/skeleton.tsx +8 -0
  283. package/src/ui/slider.tsx +8 -0
  284. package/src/ui/sonner.tsx +12 -20
  285. package/src/ui/spinner.tsx +11 -23
  286. package/src/ui/switch.tsx +8 -0
  287. package/src/ui/table.tsx +102 -97
  288. package/src/ui/tabs.tsx +8 -0
  289. package/src/ui/textarea.tsx +8 -0
  290. package/src/ui/toggle-group.tsx +12 -21
  291. package/src/ui/toggle.tsx +15 -12
  292. package/src/ui/tooltip.tsx +8 -0
  293. package/tsconfig.json +2 -1
  294. package/vite.config.ts +11 -1
  295. package/dist/src/index.test.d.ts +0 -1
  296. package/dist/src/new-components.test.d.ts +0 -1
  297. package/dist/src/renderers/complex/__tests__/data-table.test.d.ts +0 -0
  298. package/dist/src/renderers/complex/calendar-view.d.ts +0 -1
  299. package/dist/src/renderers/complex/chatbot.d.ts +0 -1
  300. package/dist/src/renderers/complex/chatbot.test.d.ts +0 -1
  301. package/dist/src/renderers/complex/timeline.d.ts +0 -1
  302. package/dist/src/ui/calendar-view.d.ts +0 -21
  303. package/dist/src/ui/chatbot.d.ts +0 -36
  304. package/dist/src/ui/field.d.ts +0 -24
  305. package/dist/src/ui/input-group.d.ts +0 -16
  306. package/dist/src/ui/timeline.d.ts +0 -25
  307. package/metadata/ObjectTable.component.yml +0 -41
  308. package/src/renderers/complex/calendar-view.tsx +0 -219
  309. package/src/renderers/complex/chatbot.test.ts +0 -44
  310. package/src/renderers/complex/chatbot.tsx +0 -185
  311. package/src/renderers/complex/timeline.tsx +0 -466
  312. package/src/ui/calendar-view.tsx +0 -503
  313. package/src/ui/chatbot.tsx +0 -240
  314. package/src/ui/field.tsx +0 -246
  315. package/src/ui/input-group.tsx +0 -170
  316. package/src/ui/timeline.tsx +0 -266
  317. package/tailwind.config.js +0 -75
@@ -0,0 +1,190 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+
9
+ import { render, RenderOptions } from '@testing-library/react';
10
+ import { ComponentRegistry } from '@object-ui/core';
11
+ import type { SchemaNode } from '@object-ui/types';
12
+
13
+ /**
14
+ * Test utility for rendering components from schema
15
+ */
16
+ export function renderComponent(schema: SchemaNode, options?: RenderOptions) {
17
+ const Component = ComponentRegistry.get(schema.type);
18
+
19
+ if (!Component) {
20
+ throw new Error(`Component "${schema.type}" is not registered`);
21
+ }
22
+
23
+ return render(<Component schema={schema} />, options);
24
+ }
25
+
26
+ /**
27
+ * Check if a component has proper accessibility attributes
28
+ */
29
+ export function checkAccessibility(element: HTMLElement): {
30
+ hasRole: boolean;
31
+ hasAriaLabel: boolean;
32
+ hasAriaDescribedBy: boolean;
33
+ issues: string[];
34
+ } {
35
+ const issues: string[] = [];
36
+ const hasRole = element.hasAttribute('role');
37
+ const hasAriaLabel = element.hasAttribute('aria-label') || element.hasAttribute('aria-labelledby');
38
+ const hasAriaDescribedBy = element.hasAttribute('aria-describedby');
39
+
40
+ // Check for interactive elements without labels
41
+ if (
42
+ element.tagName === 'BUTTON' ||
43
+ element.tagName === 'A' ||
44
+ element.getAttribute('role') === 'button'
45
+ ) {
46
+ if (!element.textContent?.trim() && !hasAriaLabel) {
47
+ issues.push('Interactive element missing accessible label');
48
+ }
49
+ }
50
+
51
+ // Check for form inputs without labels
52
+ if (element.tagName === 'INPUT' || element.tagName === 'TEXTAREA' || element.tagName === 'SELECT') {
53
+ const id = element.getAttribute('id');
54
+ const doc = element.ownerDocument || document;
55
+ const hasAssociatedLabel =
56
+ !!element.closest('label') ||
57
+ (!!id && !!doc.querySelector(`label[for="${id}"]`));
58
+ const hasLabel = hasAriaLabel || hasAssociatedLabel;
59
+ if (!hasLabel) {
60
+ issues.push('Form element missing label association');
61
+ }
62
+ }
63
+
64
+ return {
65
+ hasRole,
66
+ hasAriaLabel,
67
+ hasAriaDescribedBy,
68
+ issues,
69
+ };
70
+ }
71
+
72
+ /**
73
+ * Check DOM structure for common issues
74
+ */
75
+ export function checkDOMStructure(container: HTMLElement): {
76
+ hasContent: boolean;
77
+ isEmpty: boolean;
78
+ hasChildren: boolean;
79
+ nestedDepth: number;
80
+ issues: string[];
81
+ } {
82
+ const issues: string[] = [];
83
+ const hasContent = container.textContent !== null && container.textContent.trim().length > 0;
84
+ const isEmpty = container.children.length === 0 && !hasContent;
85
+ const hasChildren = container.children.length > 0;
86
+
87
+ // Calculate nesting depth
88
+ let maxDepth = 0;
89
+ function getDepth(el: Element, depth = 0): number {
90
+ if (el.children.length === 0) return depth;
91
+ let max = depth;
92
+ for (const child of Array.from(el.children)) {
93
+ max = Math.max(max, getDepth(child, depth + 1));
94
+ }
95
+ return max;
96
+ }
97
+ maxDepth = getDepth(container);
98
+
99
+ // Check for excessive nesting (potential performance issue)
100
+ if (maxDepth > 20) {
101
+ issues.push(`Excessive DOM nesting detected: ${maxDepth} levels`);
102
+ }
103
+
104
+ // Check for empty elements
105
+ if (isEmpty) {
106
+ issues.push('Component renders empty content');
107
+ }
108
+
109
+ return {
110
+ hasContent,
111
+ isEmpty,
112
+ hasChildren,
113
+ nestedDepth: maxDepth,
114
+ issues,
115
+ };
116
+ }
117
+
118
+ /**
119
+ * Validate component registration
120
+ */
121
+ export function validateComponentRegistration(componentType: string): {
122
+ isRegistered: boolean;
123
+ hasConfig: boolean;
124
+ hasRenderer: boolean;
125
+ hasLabel: boolean;
126
+ hasInputs: boolean;
127
+ hasDefaultProps: boolean;
128
+ config: ReturnType<typeof ComponentRegistry.getConfig>;
129
+ } {
130
+ const isRegistered = ComponentRegistry.has(componentType);
131
+ const renderer = ComponentRegistry.get(componentType);
132
+ const config = ComponentRegistry.getConfig(componentType);
133
+
134
+ return {
135
+ isRegistered,
136
+ hasConfig: !!config,
137
+ hasRenderer: !!renderer,
138
+ hasLabel: !!config?.label,
139
+ hasInputs: !!config?.inputs && config.inputs.length > 0,
140
+ hasDefaultProps: !!config?.defaultProps,
141
+ config,
142
+ };
143
+ }
144
+
145
+ /**
146
+ * Get all display issues for a rendered component
147
+ */
148
+ export function getAllDisplayIssues(container: HTMLElement): string[] {
149
+ const issues: string[] = [];
150
+
151
+ // Check DOM structure
152
+ const domCheck = checkDOMStructure(container);
153
+ issues.push(...domCheck.issues);
154
+
155
+ // Check accessibility for all interactive elements
156
+ const buttons = container.querySelectorAll('button, a, [role="button"], input, textarea, select');
157
+ buttons.forEach((element) => {
158
+ const a11yCheck = checkAccessibility(element as HTMLElement);
159
+ issues.push(...a11yCheck.issues);
160
+ });
161
+
162
+ // Check for missing keys in lists
163
+ const lists = container.querySelectorAll('[role="list"], ul, ol');
164
+ lists.forEach((list) => {
165
+ const items = list.children;
166
+ if (items.length > 0) {
167
+ // This is a simplified check - in React, keys are not in the DOM
168
+ // but we can check for duplicate content which might indicate missing keys
169
+ const contents = Array.from(items).map(item => item.textContent);
170
+ const contentCounts = new Map<string, number>();
171
+ contents.forEach(content => {
172
+ contentCounts.set(content || '', (contentCounts.get(content || '') || 0) + 1);
173
+ });
174
+ const hasDuplicates = Array.from(contentCounts.values()).some(count => count > 1);
175
+ if (hasDuplicates) {
176
+ issues.push(`Potential duplicate list items detected`);
177
+ }
178
+ }
179
+ });
180
+
181
+ // Check for images without alt text
182
+ const images = container.querySelectorAll('img');
183
+ images.forEach((img) => {
184
+ if (!img.hasAttribute('alt')) {
185
+ issues.push('Image missing alt attribute');
186
+ }
187
+ });
188
+
189
+ return issues;
190
+ }
@@ -1,3 +1,11 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+
1
9
  import * as React from "react"
2
10
 
3
11
  const MOBILE_BREAKPOINT = 768
package/src/index.css CHANGED
@@ -1,76 +1,108 @@
1
- @tailwind base;
2
- @tailwind components;
3
- @tailwind utilities;
1
+ @import 'tailwindcss';
2
+
3
+ /* Scan sources for Tailwind classes */
4
+ @source './src/**/*.{ts,tsx}';
5
+
6
+ /* Tailwind plugin for animations */
7
+ @plugin 'tailwindcss-animate';
8
+
9
+ /* Define theme colors for Tailwind 4 */
10
+ @theme {
11
+ /* Border radius tokens */
12
+ --radius-lg: var(--radius);
13
+ --radius-md: calc(var(--radius) - 2px);
14
+ --radius-sm: calc(var(--radius) - 4px);
15
+
16
+ /* Color tokens mapped to CSS variables */
17
+ --color-border: hsl(var(--border));
18
+ --color-input: hsl(var(--input));
19
+ --color-ring: hsl(var(--ring));
20
+ --color-background: hsl(var(--background));
21
+ --color-foreground: hsl(var(--foreground));
22
+ --color-primary: hsl(var(--primary));
23
+ --color-primary-foreground: hsl(var(--primary-foreground));
24
+ --color-secondary: hsl(var(--secondary));
25
+ --color-secondary-foreground: hsl(var(--secondary-foreground));
26
+ --color-destructive: hsl(var(--destructive));
27
+ --color-destructive-foreground: hsl(var(--destructive-foreground));
28
+ --color-muted: hsl(var(--muted));
29
+ --color-muted-foreground: hsl(var(--muted-foreground));
30
+ --color-accent: hsl(var(--accent));
31
+ --color-accent-foreground: hsl(var(--accent-foreground));
32
+ --color-popover: hsl(var(--popover));
33
+ --color-popover-foreground: hsl(var(--popover-foreground));
34
+ --color-card: hsl(var(--card));
35
+ --color-card-foreground: hsl(var(--card-foreground));
36
+ }
37
+
38
+ /* CSS custom properties for theme */
39
+ :root {
40
+ --background: 0 0% 100%;
41
+ --foreground: 222.2 84% 4.9%;
4
42
 
5
- @layer base {
6
- :root {
7
- --background: 0 0% 100%;
8
- --foreground: 222.2 84% 4.9%;
43
+ --card: 0 0% 100%;
44
+ --card-foreground: 222.2 84% 4.9%;
9
45
 
10
- --card: 0 0% 100%;
11
- --card-foreground: 222.2 84% 4.9%;
46
+ --popover: 0 0% 100%;
47
+ --popover-foreground: 222.2 84% 4.9%;
12
48
 
13
- --popover: 0 0% 100%;
14
- --popover-foreground: 222.2 84% 4.9%;
49
+ --primary: 222.2 47.4% 11.2%;
50
+ --primary-foreground: 210 40% 98%;
15
51
 
16
- --primary: 222.2 47.4% 11.2%;
17
- --primary-foreground: 210 40% 98%;
52
+ --secondary: 210 40% 96.1%;
53
+ --secondary-foreground: 222.2 47.4% 11.2%;
18
54
 
19
- --secondary: 210 40% 96.1%;
20
- --secondary-foreground: 222.2 47.4% 11.2%;
55
+ --muted: 210 40% 96.1%;
56
+ --muted-foreground: 215.4 16.3% 46.9%;
21
57
 
22
- --muted: 210 40% 96.1%;
23
- --muted-foreground: 215.4 16.3% 46.9%;
58
+ --accent: 210 40% 96.1%;
59
+ --accent-foreground: 222.2 47.4% 11.2%;
24
60
 
25
- --accent: 210 40% 96.1%;
26
- --accent-foreground: 222.2 47.4% 11.2%;
61
+ --destructive: 0 84.2% 60.2%;
62
+ --destructive-foreground: 210 40% 98%;
27
63
 
28
- --destructive: 0 84.2% 60.2%;
29
- --destructive-foreground: 210 40% 98%;
64
+ --border: 214.3 31.8% 91.4%;
65
+ --input: 214.3 31.8% 91.4%;
66
+ --ring: 222.2 84% 4.9%;
30
67
 
31
- --border: 214.3 31.8% 91.4%;
32
- --input: 214.3 31.8% 91.4%;
33
- --ring: 222.2 84% 4.9%;
68
+ --radius: 0.5rem;
69
+ }
34
70
 
35
- --radius: 0.5rem;
36
- }
71
+ .dark {
72
+ --background: 222.2 84% 4.9%;
73
+ --foreground: 210 40% 98%;
37
74
 
38
- .dark {
39
- --background: 222.2 84% 4.9%;
40
- --foreground: 210 40% 98%;
75
+ --card: 222.2 84% 4.9%;
76
+ --card-foreground: 210 40% 98%;
41
77
 
42
- --card: 222.2 84% 4.9%;
43
- --card-foreground: 210 40% 98%;
78
+ --popover: 222.2 84% 4.9%;
79
+ --popover-foreground: 210 40% 98%;
44
80
 
45
- --popover: 222.2 84% 4.9%;
46
- --popover-foreground: 210 40% 98%;
81
+ --primary: 210 40% 98%;
82
+ --primary-foreground: 222.2 47.4% 11.2%;
47
83
 
48
- --primary: 210 40% 98%;
49
- --primary-foreground: 222.2 47.4% 11.2%;
84
+ --secondary: 217.2 32.6% 17.5%;
85
+ --secondary-foreground: 210 40% 98%;
50
86
 
51
- --secondary: 217.2 32.6% 17.5%;
52
- --secondary-foreground: 210 40% 98%;
87
+ --muted: 217.2 32.6% 17.5%;
88
+ --muted-foreground: 215 20.2% 65.1%;
53
89
 
54
- --muted: 217.2 32.6% 17.5%;
55
- --muted-foreground: 215 20.2% 65.1%;
90
+ --accent: 217.2 32.6% 17.5%;
91
+ --accent-foreground: 210 40% 98%;
56
92
 
57
- --accent: 217.2 32.6% 17.5%;
58
- --accent-foreground: 210 40% 98%;
93
+ --destructive: 0 62.8% 30.6%;
94
+ --destructive-foreground: 210 40% 98%;
59
95
 
60
- --destructive: 0 62.8% 30.6%;
61
- --destructive-foreground: 210 40% 98%;
96
+ --border: 217.2 32.6% 17.5%;
97
+ --input: 217.2 32.6% 17.5%;
98
+ --ring: 212.7 26.8% 83.9%;
99
+ }
62
100
 
63
- --border: 217.2 32.6% 17.5%;
64
- --input: 217.2 32.6% 17.5%;
65
- --ring: 212.7 26.8% 83.9%;
66
- }
101
+ * {
102
+ border-color: hsl(var(--border));
67
103
  }
68
104
 
69
- @layer base {
70
- * {
71
- @apply border-border;
72
- }
73
- body {
74
- @apply bg-background text-foreground;
75
- }
105
+ body {
106
+ background-color: hsl(var(--background));
107
+ color: hsl(var(--foreground));
76
108
  }
package/src/index.test.ts CHANGED
@@ -1,3 +1,11 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+
1
9
  import { describe, it, expect } from 'vitest';
2
10
 
3
11
  describe('components', () => {
package/src/index.ts CHANGED
@@ -1,10 +1,30 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+
1
9
  import './index.css';
2
10
 
3
11
  // Register all ObjectUI renderers (side-effects)
4
12
  import './renderers';
5
13
 
6
14
  // Export utils
7
- export * from './lib/utils';
15
+ export { cn } from './lib/utils';
16
+ export { renderChildren } from './lib/utils';
17
+
18
+ // Export placeholder registration
19
+ export { registerPlaceholders } from './renderers/placeholders';
8
20
 
9
21
  // Export raw Shadcn UI components
10
22
  export * from './ui';
23
+
24
+ // Export an init function to ensure components are registered
25
+ // This is a workaround for bundlers that might tree-shake side-effect imports
26
+ export function initializeComponents() {
27
+ // This function exists to ensure the import side-effects above are executed
28
+ // Simply importing this module should register all components
29
+ return true;
30
+ }
package/src/lib/utils.tsx CHANGED
@@ -1,3 +1,11 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+
1
9
  import { clsx, type ClassValue } from "clsx"
2
10
  import { twMerge } from "tailwind-merge"
3
11
  import { SchemaRenderer } from "@object-ui/react"
@@ -1,3 +1,11 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+
1
9
  import { describe, it, expect, beforeAll } from 'vitest';
2
10
  import { ComponentRegistry } from '@object-ui/core';
3
11
 
@@ -62,13 +70,4 @@ describe('New Components Registration', () => {
62
70
  expect(component?.label).toBe('Loading');
63
71
  });
64
72
  });
65
-
66
- describe('Complex Components', () => {
67
- it('should register timeline component', () => {
68
- const component = ComponentRegistry.getConfig('timeline');
69
- expect(component).toBeDefined();
70
- expect(component?.label).toBe('Timeline');
71
- expect(component?.category).toBe('data-display');
72
- });
73
- });
74
73
  });
@@ -0,0 +1,78 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+
9
+ import { ComponentRegistry } from '@object-ui/core';
10
+ import type { ButtonGroupSchema } from '@object-ui/types';
11
+ import { Button } from '../../ui';
12
+ import { cn } from '../../lib/utils';
13
+
14
+ ComponentRegistry.register('button-group',
15
+ ({ schema, ...props }: { schema: ButtonGroupSchema; [key: string]: any }) => {
16
+ const {
17
+ 'data-obj-id': dataObjId,
18
+ 'data-obj-type': dataObjType,
19
+ style,
20
+ ...buttonGroupProps
21
+ } = props;
22
+
23
+ return (
24
+ <div
25
+ className={cn('flex flex-wrap sm:inline-flex rounded-md shadow-sm', schema.className)}
26
+ role="group"
27
+ {...buttonGroupProps}
28
+ {...{ 'data-obj-id': dataObjId, 'data-obj-type': dataObjType, style }}
29
+ >
30
+ {schema.buttons?.map((button, idx) => (
31
+ <Button
32
+ key={idx}
33
+ variant={button.variant || schema.variant}
34
+ size={button.size || schema.size}
35
+ className={cn(
36
+ 'rounded-none',
37
+ idx === 0 && 'rounded-l-md',
38
+ idx === (schema.buttons?.length || 0) - 1 && 'rounded-r-md',
39
+ idx > 0 && '-ml-px',
40
+ button.className
41
+ )}
42
+ >
43
+ {button.label}
44
+ </Button>
45
+ ))}
46
+ </div>
47
+ );
48
+ },
49
+ {
50
+ label: 'Button Group',
51
+ inputs: [
52
+ {
53
+ name: 'variant',
54
+ type: 'enum',
55
+ enum: ['default', 'destructive', 'outline', 'secondary', 'ghost', 'link'],
56
+ defaultValue: 'default',
57
+ label: 'Variant'
58
+ },
59
+ {
60
+ name: 'size',
61
+ type: 'enum',
62
+ enum: ['default', 'sm', 'lg', 'icon'],
63
+ defaultValue: 'default',
64
+ label: 'Size'
65
+ },
66
+ { name: 'className', type: 'string', label: 'CSS Class' }
67
+ ],
68
+ defaultProps: {
69
+ variant: 'default',
70
+ size: 'default',
71
+ buttons: [
72
+ { label: 'Left' },
73
+ { label: 'Middle' },
74
+ { label: 'Right' }
75
+ ]
76
+ }
77
+ }
78
+ );
@@ -1,3 +1,11 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+
1
9
  import { ComponentRegistry } from '@object-ui/core';
2
10
  import type { DivSchema } from '@object-ui/types';
3
11
  import { renderChildren } from '../../lib/utils';
@@ -35,7 +43,7 @@ ComponentRegistry.register('div',
35
43
  { name: 'className', type: 'string', label: 'CSS Class' }
36
44
  ],
37
45
  defaultProps: {
38
- className: 'p-4 border border-dashed border-gray-300 rounded min-h-[100px]'
46
+ className: 'p-2 sm:p-4 border border-dashed border-gray-300 rounded min-h-[100px]'
39
47
  }
40
48
  }
41
49
  );
@@ -1,3 +1,11 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+
1
9
  import React from 'react';
2
10
  import { ComponentRegistry } from '@object-ui/core';
3
11
  import type { HtmlSchema } from '@object-ui/types';
@@ -1,16 +1,77 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+
1
9
  import { ComponentRegistry } from '@object-ui/core';
2
10
  import type { IconSchema } from '@object-ui/types';
3
11
  import { icons } from 'lucide-react';
4
12
  import React, { forwardRef } from 'react';
13
+ import { cn } from '../../lib/utils';
14
+
15
+ // Convert kebab-case to PascalCase for Lucide icon names
16
+ // e.g., "arrow-right" -> "ArrowRight", "home" -> "Home"
17
+ function toPascalCase(str: string): string {
18
+ return str
19
+ .split('-')
20
+ .map(word => word.charAt(0).toUpperCase() + word.slice(1))
21
+ .join('');
22
+ }
23
+
24
+ // Map of renamed icons in lucide-react (from old name to new name)
25
+ const iconNameMap: Record<string, string> = {
26
+ 'Home': 'House', // "Home" was renamed to "House" in lucide-react's icons object
27
+ };
5
28
 
6
29
  const IconRenderer = forwardRef<SVGSVGElement, { schema: IconSchema; className?: string; [key: string]: any }>(
7
30
  ({ schema, className, ...props }, ref) => {
8
- const Icon = (icons as any)[schema.name || schema.icon];
9
- if (!Icon) return null;
10
- return <Icon ref={ref} className={className} {...props} />;
31
+ // Extract designer-related props
32
+ const {
33
+ 'data-obj-id': dataObjId,
34
+ 'data-obj-type': dataObjType,
35
+ style,
36
+ ...iconProps
37
+ } = props;
38
+
39
+ // Convert icon name to PascalCase for Lucide lookup
40
+ const iconName = toPascalCase(schema.name);
41
+ // Apply icon name mapping for renamed icons
42
+ const mappedIconName = iconNameMap[iconName] || iconName;
43
+ const Icon = (icons as any)[mappedIconName];
44
+
45
+ if (!Icon) {
46
+ console.warn(`Icon "${schema.name}" (lookup: "${iconName}"${mappedIconName !== iconName ? ` -> "${mappedIconName}"` : ''}) not found in lucide-react`);
47
+ return null;
48
+ }
49
+
50
+ // Build size style
51
+ const sizeStyle = schema.size ? { width: schema.size, height: schema.size } : undefined;
52
+
53
+ // Merge classNames: schema color, schema className, prop className
54
+ const mergedClassName = cn(
55
+ schema.color,
56
+ schema.className,
57
+ className
58
+ );
59
+
60
+ return (
61
+ <Icon
62
+ ref={ref}
63
+ className={mergedClassName}
64
+ style={{ ...sizeStyle, ...style }}
65
+ {...iconProps}
66
+ // Apply designer props
67
+ {...{ 'data-obj-id': dataObjId, 'data-obj-type': dataObjType }}
68
+ />
69
+ );
11
70
  }
12
71
  );
13
72
 
73
+ IconRenderer.displayName = 'IconRenderer';
74
+
14
75
  ComponentRegistry.register('icon',
15
76
  IconRenderer,
16
77
  {
@@ -19,6 +80,8 @@ ComponentRegistry.register('icon',
19
80
  category: 'basic',
20
81
  inputs: [
21
82
  { name: 'name', type: 'string', label: 'Icon Name', defaultValue: 'smile' },
83
+ { name: 'size', type: 'number', label: 'Size (px)' },
84
+ { name: 'color', type: 'string', label: 'Color Class' },
22
85
  { name: 'className', type: 'string', label: 'CSS Class' }
23
86
  ]
24
87
  }
@@ -1,3 +1,11 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+
1
9
  import { ComponentRegistry } from '@object-ui/core';
2
10
  import type { ImageSchema } from '@object-ui/types';
3
11
 
@@ -32,6 +40,9 @@ ComponentRegistry.register('image',
32
40
  { name: 'src', type: 'string', label: 'Source URL' },
33
41
  { name: 'alt', type: 'string', label: 'Alt Text' },
34
42
  { name: 'className', type: 'string', label: 'Classes' }
35
- ]
43
+ ],
44
+ defaultProps: {
45
+ className: 'max-w-full h-auto'
46
+ }
36
47
  }
37
48
  );