@object-ui/components 3.3.0 → 3.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 (321) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +21 -1
  3. package/dist/index.css +6339 -2
  4. package/dist/index.js +17600 -17481
  5. package/dist/index.umd.cjs +36 -36
  6. package/dist/packages/components/src/custom/empty.d.ts +12 -1
  7. package/dist/packages/components/src/renderers/action/action-bar.d.ts +12 -1
  8. package/dist/packages/components/src/ui/chart.d.ts +10 -29
  9. package/package.json +65 -44
  10. package/.turbo/turbo-build.log +0 -84
  11. package/README_SHADCN_SYNC.md +0 -281
  12. package/TESTING.md +0 -335
  13. package/docs/FilterBuilder.md +0 -268
  14. package/metadata/Chart.component.yml +0 -30
  15. package/metadata/FilterBuilder.component.yml +0 -39
  16. package/metadata/GridLayout.component.yml +0 -27
  17. package/metadata/Menu.component.yml +0 -31
  18. package/metadata/ObjectForm.component.yml +0 -34
  19. package/metadata/ObjectGrid.component.yml +0 -72
  20. package/metadata/Page.component.yml +0 -24
  21. package/postcss.config.js +0 -14
  22. package/shadcn-components.json +0 -440
  23. package/src/SchemaRenderer.tsx +0 -28
  24. package/src/__tests__/PageRendererRegions.test.tsx +0 -668
  25. package/src/__tests__/README.md +0 -124
  26. package/src/__tests__/__snapshots__/snapshot-critical.test.tsx.snap +0 -811
  27. package/src/__tests__/__snapshots__/snapshot.test.tsx.snap +0 -327
  28. package/src/__tests__/accessibility.test.tsx +0 -137
  29. package/src/__tests__/action-bar.test.tsx +0 -206
  30. package/src/__tests__/api-consistency.test.tsx +0 -596
  31. package/src/__tests__/basic-renderers.test.tsx +0 -255
  32. package/src/__tests__/color-contrast.test.tsx +0 -212
  33. package/src/__tests__/complex-disclosure-renderers.test.tsx +0 -302
  34. package/src/__tests__/compliance.test.tsx +0 -72
  35. package/src/__tests__/config-field-renderer.test.tsx +0 -307
  36. package/src/__tests__/config-panel-renderer.test.tsx +0 -580
  37. package/src/__tests__/config-primitives.test.tsx +0 -106
  38. package/src/__tests__/edge-cases.test.tsx +0 -285
  39. package/src/__tests__/feedback-overlay-renderers.test.tsx +0 -349
  40. package/src/__tests__/filter-builder.test.tsx +0 -409
  41. package/src/__tests__/form-renderers.test.tsx +0 -364
  42. package/src/__tests__/layout-data-renderers.test.tsx +0 -340
  43. package/src/__tests__/mobile-accessibility.test.tsx +0 -120
  44. package/src/__tests__/navigation-overlay.test.tsx +0 -370
  45. package/src/__tests__/snapshot-critical.test.tsx +0 -317
  46. package/src/__tests__/snapshot.test.tsx +0 -205
  47. package/src/__tests__/test-utils.tsx +0 -190
  48. package/src/__tests__/use-config-draft.test.tsx +0 -295
  49. package/src/__tests__/view-compliance.test.tsx +0 -153
  50. package/src/__tests__/wcag-audit.test.tsx +0 -493
  51. package/src/custom/action-param-dialog.tsx +0 -264
  52. package/src/custom/button-group.tsx +0 -91
  53. package/src/custom/combobox.tsx +0 -104
  54. package/src/custom/config-field-renderer.tsx +0 -276
  55. package/src/custom/config-panel-renderer.tsx +0 -306
  56. package/src/custom/config-row.tsx +0 -50
  57. package/src/custom/date-picker.tsx +0 -61
  58. package/src/custom/empty.tsx +0 -112
  59. package/src/custom/field.tsx +0 -81
  60. package/src/custom/filter-builder.tsx +0 -418
  61. package/src/custom/index.ts +0 -21
  62. package/src/custom/input-group.tsx +0 -53
  63. package/src/custom/item.tsx +0 -201
  64. package/src/custom/kbd.tsx +0 -36
  65. package/src/custom/mobile-dialog-content.tsx +0 -67
  66. package/src/custom/native-select.tsx +0 -33
  67. package/src/custom/navigation-overlay.tsx +0 -334
  68. package/src/custom/section-header.tsx +0 -68
  69. package/src/custom/sort-builder.tsx +0 -129
  70. package/src/custom/spinner.tsx +0 -26
  71. package/src/custom/view-skeleton.tsx +0 -243
  72. package/src/custom/view-states.tsx +0 -153
  73. package/src/debug/DebugPanel.tsx +0 -313
  74. package/src/debug/__tests__/DebugPanel.test.tsx +0 -134
  75. package/src/debug/index.ts +0 -10
  76. package/src/hooks/use-config-draft.ts +0 -127
  77. package/src/hooks/use-mobile.tsx +0 -27
  78. package/src/index.css +0 -245
  79. package/src/index.ts +0 -47
  80. package/src/lib/use-sync-external-store-shim.ts +0 -10
  81. package/src/lib/use-sync-external-store-with-selector-shim.ts +0 -90
  82. package/src/lib/utils.tsx +0 -35
  83. package/src/new-components.test.ts +0 -73
  84. package/src/renderers/action/action-bar.tsx +0 -221
  85. package/src/renderers/action/action-button.tsx +0 -158
  86. package/src/renderers/action/action-group.tsx +0 -270
  87. package/src/renderers/action/action-icon.tsx +0 -150
  88. package/src/renderers/action/action-menu.tsx +0 -203
  89. package/src/renderers/action/index.ts +0 -19
  90. package/src/renderers/action/resolve-icon.ts +0 -35
  91. package/src/renderers/basic/button-group.tsx +0 -79
  92. package/src/renderers/basic/div.tsx +0 -60
  93. package/src/renderers/basic/html.tsx +0 -43
  94. package/src/renderers/basic/icon.tsx +0 -89
  95. package/src/renderers/basic/image.tsx +0 -49
  96. package/src/renderers/basic/index.ts +0 -18
  97. package/src/renderers/basic/navigation-menu.tsx +0 -81
  98. package/src/renderers/basic/pagination.tsx +0 -109
  99. package/src/renderers/basic/separator.tsx +0 -57
  100. package/src/renderers/basic/span.tsx +0 -63
  101. package/src/renderers/basic/text.tsx +0 -52
  102. package/src/renderers/complex/README-KANBAN.md +0 -208
  103. package/src/renderers/complex/TIMELINE.md +0 -353
  104. package/src/renderers/complex/__tests__/data-table-airtable-ux.test.tsx +0 -239
  105. package/src/renderers/complex/__tests__/data-table-batch-editing.test.tsx +0 -275
  106. package/src/renderers/complex/__tests__/data-table-cell-renderer.test.tsx +0 -120
  107. package/src/renderers/complex/__tests__/data-table-editing.test.tsx +0 -221
  108. package/src/renderers/complex/__tests__/data-table.test.ts +0 -76
  109. package/src/renderers/complex/carousel.tsx +0 -69
  110. package/src/renderers/complex/data-table.tsx +0 -1243
  111. package/src/renderers/complex/filter-builder.tsx +0 -77
  112. package/src/renderers/complex/index.ts +0 -16
  113. package/src/renderers/complex/resizable.tsx +0 -66
  114. package/src/renderers/complex/scroll-area.tsx +0 -58
  115. package/src/renderers/complex/table.tsx +0 -95
  116. package/src/renderers/data-display/alert.tsx +0 -46
  117. package/src/renderers/data-display/avatar.tsx +0 -38
  118. package/src/renderers/data-display/badge.tsx +0 -55
  119. package/src/renderers/data-display/breadcrumb.tsx +0 -61
  120. package/src/renderers/data-display/index.ts +0 -18
  121. package/src/renderers/data-display/kbd.tsx +0 -50
  122. package/src/renderers/data-display/list.tsx +0 -75
  123. package/src/renderers/data-display/statistic.tsx +0 -95
  124. package/src/renderers/data-display/table.tsx +0 -78
  125. package/src/renderers/data-display/tree-view.tsx +0 -176
  126. package/src/renderers/disclosure/accordion.tsx +0 -69
  127. package/src/renderers/disclosure/collapsible.tsx +0 -53
  128. package/src/renderers/disclosure/index.ts +0 -11
  129. package/src/renderers/disclosure/toggle-group.tsx +0 -79
  130. package/src/renderers/feedback/empty.tsx +0 -49
  131. package/src/renderers/feedback/index.ts +0 -16
  132. package/src/renderers/feedback/loading.tsx +0 -78
  133. package/src/renderers/feedback/progress.tsx +0 -29
  134. package/src/renderers/feedback/skeleton.tsx +0 -31
  135. package/src/renderers/feedback/sonner.tsx +0 -56
  136. package/src/renderers/feedback/spinner.tsx +0 -55
  137. package/src/renderers/feedback/toast.tsx +0 -59
  138. package/src/renderers/feedback/toaster.tsx +0 -23
  139. package/src/renderers/form/button.tsx +0 -103
  140. package/src/renderers/form/calendar.tsx +0 -34
  141. package/src/renderers/form/checkbox.tsx +0 -71
  142. package/src/renderers/form/combobox.tsx +0 -48
  143. package/src/renderers/form/command.tsx +0 -58
  144. package/src/renderers/form/date-picker.tsx +0 -84
  145. package/src/renderers/form/file-upload.tsx +0 -184
  146. package/src/renderers/form/form.tsx +0 -540
  147. package/src/renderers/form/index.ts +0 -26
  148. package/src/renderers/form/input-otp.tsx +0 -51
  149. package/src/renderers/form/input.tsx +0 -121
  150. package/src/renderers/form/label.tsx +0 -45
  151. package/src/renderers/form/radio-group.tsx +0 -63
  152. package/src/renderers/form/select.tsx +0 -94
  153. package/src/renderers/form/slider.tsx +0 -61
  154. package/src/renderers/form/switch.tsx +0 -48
  155. package/src/renderers/form/textarea.tsx +0 -76
  156. package/src/renderers/form/toggle.tsx +0 -42
  157. package/src/renderers/index.ts +0 -18
  158. package/src/renderers/layout/aspect-ratio.tsx +0 -51
  159. package/src/renderers/layout/card.tsx +0 -85
  160. package/src/renderers/layout/container.tsx +0 -122
  161. package/src/renderers/layout/flex.tsx +0 -132
  162. package/src/renderers/layout/grid.tsx +0 -178
  163. package/src/renderers/layout/index.ts +0 -19
  164. package/src/renderers/layout/page.tsx +0 -466
  165. package/src/renderers/layout/semantic.tsx +0 -48
  166. package/src/renderers/layout/stack.tsx +0 -132
  167. package/src/renderers/layout/tabs.tsx +0 -97
  168. package/src/renderers/navigation/header-bar.tsx +0 -118
  169. package/src/renderers/navigation/index.ts +0 -10
  170. package/src/renderers/navigation/sidebar.tsx +0 -208
  171. package/src/renderers/overlay/alert-dialog.tsx +0 -72
  172. package/src/renderers/overlay/context-menu.tsx +0 -100
  173. package/src/renderers/overlay/dialog.tsx +0 -77
  174. package/src/renderers/overlay/drawer.tsx +0 -77
  175. package/src/renderers/overlay/dropdown-menu.tsx +0 -99
  176. package/src/renderers/overlay/hover-card.tsx +0 -55
  177. package/src/renderers/overlay/index.ts +0 -18
  178. package/src/renderers/overlay/menubar.tsx +0 -76
  179. package/src/renderers/overlay/popover.tsx +0 -56
  180. package/src/renderers/overlay/sheet.tsx +0 -77
  181. package/src/renderers/overlay/tooltip.tsx +0 -67
  182. package/src/renderers/placeholders.tsx +0 -107
  183. package/src/stories/CRMApp.stories.tsx +0 -706
  184. package/src/stories/ConfigPanel.stories.tsx +0 -232
  185. package/src/stories/Guide.mdx +0 -55
  186. package/src/stories/MockedData.stories.tsx +0 -121
  187. package/src/stories/assets/accessibility.png +0 -0
  188. package/src/stories/assets/accessibility.svg +0 -1
  189. package/src/stories/assets/addon-library.png +0 -0
  190. package/src/stories/assets/assets.png +0 -0
  191. package/src/stories/assets/avif-test-image.avif +0 -0
  192. package/src/stories/assets/context.png +0 -0
  193. package/src/stories/assets/discord.svg +0 -1
  194. package/src/stories/assets/docs.png +0 -0
  195. package/src/stories/assets/figma-plugin.png +0 -0
  196. package/src/stories/assets/github.svg +0 -1
  197. package/src/stories/assets/share.png +0 -0
  198. package/src/stories/assets/styling.png +0 -0
  199. package/src/stories/assets/testing.png +0 -0
  200. package/src/stories/assets/theming.png +0 -0
  201. package/src/stories/assets/tutorials.svg +0 -1
  202. package/src/stories/assets/youtube.svg +0 -1
  203. package/src/stories/button.css +0 -30
  204. package/src/stories/header.css +0 -32
  205. package/src/stories/page.css +0 -68
  206. package/src/stories-json/Accessibility.mdx +0 -297
  207. package/src/stories-json/EdgeCases.stories.tsx +0 -160
  208. package/src/stories-json/GettingStarted.mdx +0 -89
  209. package/src/stories-json/Introduction.mdx +0 -127
  210. package/src/stories-json/accordion.stories.tsx +0 -43
  211. package/src/stories-json/aggrid.stories.tsx +0 -103
  212. package/src/stories-json/alert.stories.tsx +0 -39
  213. package/src/stories-json/aspect-ratio.stories.tsx +0 -34
  214. package/src/stories-json/avatar.stories.tsx +0 -38
  215. package/src/stories-json/badge.stories.tsx +0 -53
  216. package/src/stories-json/breadcrumb.stories.tsx +0 -30
  217. package/src/stories-json/button-group.stories.tsx +0 -43
  218. package/src/stories-json/button.stories.tsx +0 -73
  219. package/src/stories-json/calendar.stories.tsx +0 -85
  220. package/src/stories-json/card.stories.tsx +0 -48
  221. package/src/stories-json/carousel.stories.tsx +0 -33
  222. package/src/stories-json/charts.stories.tsx +0 -195
  223. package/src/stories-json/chatbot.stories.tsx +0 -349
  224. package/src/stories-json/code-editor.stories.tsx +0 -92
  225. package/src/stories-json/collapsible.stories.tsx +0 -40
  226. package/src/stories-json/controls.stories.tsx +0 -36
  227. package/src/stories-json/crm-live-data.stories.tsx +0 -154
  228. package/src/stories-json/dashboard.stories.tsx +0 -318
  229. package/src/stories-json/data-table.stories.tsx +0 -136
  230. package/src/stories-json/data_display_extras.stories.tsx +0 -102
  231. package/src/stories-json/date-picker.stories.tsx +0 -28
  232. package/src/stories-json/detail-view.stories.tsx +0 -258
  233. package/src/stories-json/dialog.stories.tsx +0 -43
  234. package/src/stories-json/feedback_extras.stories.tsx +0 -40
  235. package/src/stories-json/feedback_others.stories.tsx +0 -46
  236. package/src/stories-json/form-variants.stories.tsx +0 -210
  237. package/src/stories-json/form_advanced.stories.tsx +0 -117
  238. package/src/stories-json/form_extras.stories.tsx +0 -123
  239. package/src/stories-json/grid.stories.tsx +0 -56
  240. package/src/stories-json/icon.stories.tsx +0 -36
  241. package/src/stories-json/input.stories.tsx +0 -52
  242. package/src/stories-json/kanban.stories.tsx +0 -295
  243. package/src/stories-json/layout_extended.stories.tsx +0 -76
  244. package/src/stories-json/layout_flex.stories.tsx +0 -107
  245. package/src/stories-json/list-view.stories.tsx +0 -97
  246. package/src/stories-json/markdown.stories.tsx +0 -129
  247. package/src/stories-json/menus.stories.tsx +0 -63
  248. package/src/stories-json/metric-card.stories.tsx +0 -143
  249. package/src/stories-json/navigation-menu.stories.tsx +0 -37
  250. package/src/stories-json/object-aggrid-advanced.stories.tsx +0 -389
  251. package/src/stories-json/object-aggrid.stories.tsx +0 -252
  252. package/src/stories-json/object-form.stories.tsx +0 -130
  253. package/src/stories-json/object-gantt.stories.tsx +0 -114
  254. package/src/stories-json/object-grid.stories.tsx +0 -315
  255. package/src/stories-json/object-map.stories.tsx +0 -116
  256. package/src/stories-json/object-view.stories.tsx +0 -118
  257. package/src/stories-json/overlay_extras.stories.tsx +0 -113
  258. package/src/stories-json/overlay_others.stories.tsx +0 -76
  259. package/src/stories-json/page.stories.tsx +0 -55
  260. package/src/stories-json/reports.stories.tsx +0 -163
  261. package/src/stories-json/resizable.stories.tsx +0 -44
  262. package/src/stories-json/select.stories.tsx +0 -34
  263. package/src/stories-json/separator.stories.tsx +0 -41
  264. package/src/stories-json/sidebar.stories.tsx +0 -147
  265. package/src/stories-json/statistic.stories.tsx +0 -44
  266. package/src/stories-json/tabs.stories.tsx +0 -51
  267. package/src/stories-json/timeline.stories.tsx +0 -188
  268. package/src/stories-json/typography.stories.tsx +0 -45
  269. package/src/types/config-panel.ts +0 -101
  270. package/src/ui/accordion.tsx +0 -66
  271. package/src/ui/alert-dialog.tsx +0 -149
  272. package/src/ui/alert.tsx +0 -67
  273. package/src/ui/aspect-ratio.tsx +0 -15
  274. package/src/ui/avatar.tsx +0 -58
  275. package/src/ui/badge.tsx +0 -44
  276. package/src/ui/breadcrumb.tsx +0 -123
  277. package/src/ui/button.tsx +0 -64
  278. package/src/ui/calendar.tsx +0 -221
  279. package/src/ui/card.tsx +0 -87
  280. package/src/ui/carousel.tsx +0 -270
  281. package/src/ui/chart.tsx +0 -377
  282. package/src/ui/checkbox.tsx +0 -38
  283. package/src/ui/collapsible.tsx +0 -19
  284. package/src/ui/command.tsx +0 -161
  285. package/src/ui/context-menu.tsx +0 -208
  286. package/src/ui/dialog.tsx +0 -130
  287. package/src/ui/drawer.tsx +0 -126
  288. package/src/ui/dropdown-menu.tsx +0 -208
  289. package/src/ui/form.tsx +0 -186
  290. package/src/ui/hover-card.tsx +0 -37
  291. package/src/ui/index.ts +0 -56
  292. package/src/ui/input-otp.tsx +0 -79
  293. package/src/ui/input.tsx +0 -30
  294. package/src/ui/label.tsx +0 -34
  295. package/src/ui/menubar.tsx +0 -264
  296. package/src/ui/navigation-menu.tsx +0 -136
  297. package/src/ui/pagination.tsx +0 -125
  298. package/src/ui/popover.tsx +0 -39
  299. package/src/ui/progress.tsx +0 -36
  300. package/src/ui/radio-group.tsx +0 -52
  301. package/src/ui/resizable.tsx +0 -53
  302. package/src/ui/scroll-area.tsx +0 -56
  303. package/src/ui/select.tsx +0 -168
  304. package/src/ui/separator.tsx +0 -39
  305. package/src/ui/sheet.tsx +0 -150
  306. package/src/ui/sidebar.tsx +0 -781
  307. package/src/ui/skeleton.tsx +0 -23
  308. package/src/ui/slider.tsx +0 -39
  309. package/src/ui/sonner.tsx +0 -53
  310. package/src/ui/switch.tsx +0 -37
  311. package/src/ui/table.tsx +0 -125
  312. package/src/ui/tabs.tsx +0 -63
  313. package/src/ui/textarea.tsx +0 -30
  314. package/src/ui/toast.tsx +0 -137
  315. package/src/ui/toggle-group.tsx +0 -69
  316. package/src/ui/toggle.tsx +0 -53
  317. package/src/ui/tooltip.tsx +0 -38
  318. package/src/ui/typography.tsx +0 -85
  319. package/tsconfig.json +0 -19
  320. package/vite.config.ts +0 -71
  321. package/vitest.config.ts +0 -5
@@ -1,302 +0,0 @@
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 { describe, it, expect, beforeAll } from 'vitest';
10
- import { ComponentRegistry } from '@object-ui/core';
11
- import {
12
- renderComponent,
13
- validateComponentRegistration,
14
- checkDOMStructure,
15
- } from './test-utils';
16
-
17
- // Import renderers to ensure registration
18
- beforeAll(async () => {
19
- await import('../renderers');
20
- }, 30000); // Increase timeout to 30 seconds for heavy renderer imports
21
-
22
- /**
23
- * Comprehensive tests for disclosure renderer components
24
- */
25
- describe('Disclosure Renderers - Display Issue Detection', () => {
26
- describe('Accordion Renderer', () => {
27
- it('should be properly registered', () => {
28
- const validation = validateComponentRegistration('accordion');
29
- expect(validation.isRegistered).toBe(true);
30
- });
31
-
32
- it('should render accordion with items', () => {
33
- const { container } = renderComponent({
34
- type: 'accordion',
35
- items: [
36
- {
37
- title: 'Section 1',
38
- content: 'Content 1',
39
- },
40
- {
41
- title: 'Section 2',
42
- content: 'Content 2',
43
- },
44
- ],
45
- });
46
-
47
- expect(container.textContent).toContain('Section 1');
48
- expect(container.textContent).toContain('Section 2');
49
- });
50
-
51
- it('should not have structural issues', () => {
52
- const { container } = renderComponent({
53
- type: 'accordion',
54
- items: [{ title: 'Test', content: 'Content' }],
55
- });
56
-
57
- const domCheck = checkDOMStructure(container);
58
- expect(domCheck.hasContent).toBe(true);
59
- });
60
- });
61
-
62
- describe('Collapsible Renderer', () => {
63
- it('should be properly registered', () => {
64
- const validation = validateComponentRegistration('collapsible');
65
- expect(validation.isRegistered).toBe(true);
66
- });
67
-
68
- it('should render collapsible component', () => {
69
- const { container } = renderComponent({
70
- type: 'collapsible',
71
- trigger: { type: 'button', label: 'Toggle' },
72
- body: [{ type: 'text', content: 'Hidden content' }],
73
- });
74
-
75
- expect(container.textContent).toContain('Toggle');
76
- });
77
- });
78
-
79
- describe('Toggle Group Renderer', () => {
80
- it('should be properly registered', () => {
81
- const validation = validateComponentRegistration('toggle-group');
82
- expect(validation.isRegistered).toBe(true);
83
- });
84
-
85
- it('should render toggle group with items', () => {
86
- const { container } = renderComponent({
87
- type: 'toggle-group',
88
- selectionType: 'single',
89
- items: [
90
- { value: 'bold', label: 'Bold' },
91
- { value: 'italic', label: 'Italic' },
92
- ],
93
- });
94
-
95
- expect(container).toBeDefined();
96
- });
97
- });
98
- });
99
-
100
- /**
101
- * Comprehensive tests for complex renderer components
102
- */
103
- describe('Complex Renderers - Display Issue Detection', () => {
104
- describe('Data Table Renderer', () => {
105
- it('should be properly registered', () => {
106
- const validation = validateComponentRegistration('data-table');
107
- expect(validation.isRegistered).toBe(true);
108
- expect(validation.hasDefaultProps).toBe(true);
109
- });
110
-
111
- it('should render table with data', () => {
112
- const { container } = renderComponent({
113
- type: 'data-table',
114
- columns: [
115
- { id: 'name', header: 'Name' },
116
- { id: 'age', header: 'Age' },
117
- ],
118
- data: [
119
- { name: 'John', age: 30 },
120
- { name: 'Jane', age: 25 },
121
- ],
122
- });
123
-
124
- expect(container.textContent).toContain('Name');
125
- expect(container.textContent).toContain('Age');
126
- });
127
-
128
- it('should use table semantics', () => {
129
- const { container } = renderComponent({
130
- type: 'data-table',
131
- columns: [{ id: 'col1', header: 'Column 1' }],
132
- data: [{ col1: 'Data' }],
133
- });
134
-
135
- const table = container.querySelector('table');
136
- expect(table || container.querySelector('[role="table"]')).toBeTruthy();
137
- });
138
-
139
- it('should not have excessive nesting', () => {
140
- const { container } = renderComponent({
141
- type: 'data-table',
142
- columns: [{ id: 'col1', header: 'Test' }],
143
- data: [{ col1: 'Value' }],
144
- });
145
-
146
- const domCheck = checkDOMStructure(container);
147
- // Tables can be nested but not excessively
148
- expect(domCheck.nestedDepth).toBeLessThan(25);
149
- });
150
- });
151
-
152
- describe('Carousel Renderer', () => {
153
- it('should be properly registered', () => {
154
- const validation = validateComponentRegistration('carousel');
155
- expect(validation.isRegistered).toBe(true);
156
- });
157
-
158
- it('should render carousel with items', () => {
159
- const { container } = renderComponent({
160
- type: 'carousel',
161
- items: [
162
- { type: 'div', body: [{ type: 'text', content: 'Slide 1' }] },
163
- { type: 'div', body: [{ type: 'text', content: 'Slide 2' }] },
164
- ],
165
- });
166
-
167
- // Carousel should render
168
- expect(container).toBeDefined();
169
- });
170
- });
171
-
172
- describe('Scroll Area Renderer', () => {
173
- it('should be properly registered', () => {
174
- const validation = validateComponentRegistration('scroll-area');
175
- expect(validation.isRegistered).toBe(true);
176
- });
177
-
178
- it('should render scrollable area', () => {
179
- const { container } = renderComponent({
180
- type: 'scroll-area',
181
- children: [{ type: 'text', content: 'Scrollable content' }],
182
- });
183
-
184
- // ScrollArea renders content
185
-
186
- expect(container.textContent).toContain('Scrollable content');
187
- });
188
- });
189
-
190
- describe('Resizable Renderer', () => {
191
- it('should be properly registered', () => {
192
- const validation = validateComponentRegistration('resizable');
193
- expect(validation.isRegistered).toBe(true);
194
- });
195
-
196
- it('should render resizable panels', () => {
197
- const { container } = renderComponent({
198
- type: 'resizable',
199
- panels: [
200
- { content: { type: 'text', content: 'Panel 1' } },
201
- { content: { type: 'text', content: 'Panel 2' } },
202
- ],
203
- });
204
-
205
- expect(container).toBeDefined();
206
- });
207
- });
208
-
209
- describe('Filter Builder Renderer', () => {
210
- it('should be properly registered', () => {
211
- const validation = validateComponentRegistration('filter-builder');
212
- expect(validation.isRegistered).toBe(true);
213
- });
214
-
215
- it('should render filter builder', () => {
216
- const { container } = renderComponent({
217
- type: 'filter-builder',
218
- fields: [
219
- { name: 'name', label: 'Name', type: 'text' },
220
- { name: 'age', label: 'Age', type: 'number' },
221
- ],
222
- });
223
-
224
- expect(container).toBeDefined();
225
- });
226
- });
227
-
228
- describe('Table Renderer', () => {
229
- it('should be properly registered', () => {
230
- const validation = validateComponentRegistration('table');
231
- expect(validation.isRegistered).toBe(true);
232
- });
233
-
234
- it('should render basic table', () => {
235
- const { container } = renderComponent({
236
- type: 'table',
237
- head: {
238
- rows: [
239
- {
240
- cells: [
241
- { type: 'text', content: 'Header 1' },
242
- { type: 'text', content: 'Header 2' },
243
- ],
244
- },
245
- ],
246
- },
247
- body: {
248
- rows: [
249
- {
250
- cells: [
251
- { type: 'text', content: 'Cell 1' },
252
- { type: 'text', content: 'Cell 2' },
253
- ],
254
- },
255
- ],
256
- },
257
- });
258
-
259
- const table = container.querySelector('table');
260
- expect(table).toBeTruthy();
261
- });
262
- });
263
- });
264
-
265
- /**
266
- * Cross-cutting concerns: Tests that apply to all components
267
- */
268
- describe('All Renderers - Cross-Cutting Concerns', () => {
269
- it('should not render components with excessive DOM nesting', () => {
270
- const components = ['div', 'container', 'flex', 'grid'];
271
-
272
- components.forEach(type => {
273
- if (ComponentRegistry.has(type)) {
274
- const { container } = renderComponent({
275
- type,
276
- body: [{ type: 'text', content: 'Test' }],
277
- });
278
-
279
- const domCheck = checkDOMStructure(container);
280
- expect(domCheck.nestedDepth).toBeLessThan(20);
281
- }
282
- });
283
- });
284
-
285
- it('should handle className prop for custom styling', () => {
286
- const components = ['button', 'input', 'div', 'text'];
287
-
288
- components.forEach(type => {
289
- if (ComponentRegistry.has(type)) {
290
- const { container } = renderComponent({
291
- type,
292
- className: 'custom-class',
293
- label: 'Test',
294
- content: 'Test',
295
- });
296
-
297
- // Should render without errors
298
- expect(container).toBeDefined();
299
- }
300
- });
301
- });
302
- });
@@ -1,72 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { render } from '@testing-library/react';
3
- import React from 'react';
4
- import { ComponentRegistry } from '@object-ui/core';
5
-
6
- // Ensure all components are registered
7
- import '../index';
8
-
9
- describe('Component Compliance', () => {
10
- const components = ComponentRegistry.getAllConfigs();
11
-
12
- it('should have components registered', () => {
13
- expect(components.length).toBeGreaterThan(0);
14
- });
15
-
16
- components.forEach((config) => {
17
- describe(`Component: ${config.type}`, () => {
18
- it('should have valid metadata', () => {
19
- expect(config.type).toBeDefined();
20
- expect(config.component).toBeDefined();
21
- // namespace is optional but good practice
22
- // expect(config.namespace).toBeDefined();
23
- });
24
-
25
- it('should define inputs if it has any', () => {
26
- if (config.inputs) {
27
- expect(Array.isArray(config.inputs)).toBe(true);
28
- config.inputs?.forEach((input) => {
29
- expect(input.name).toBeDefined();
30
- expect(input.type).toBeDefined();
31
- });
32
- }
33
- });
34
-
35
- it('should render generic component without crashing', () => {
36
- const Cmp = config.component as React.ComponentType<any>;
37
-
38
- // Skip components that are known to require specific parents or context
39
- // for now, we just try to render them with a basic schema
40
- const schema = {
41
- type: config.type,
42
- id: 'test-id',
43
- className: 'test-class',
44
- props: {
45
- ...config.defaultProps
46
- }
47
- };
48
-
49
- try {
50
- // We wrap in a try-catch for now because some components might strictly require context
51
- // But ideally, renderers should be robust.
52
- // For now, we prefer to shallow render or just check it is a valid function/class
53
- expect(Cmp).toBeDefined();
54
-
55
- /*
56
- Full rendering is risky because of dependencies (e.g. Hooks, Context).
57
- So we will just verify the sanity of the registration for now.
58
- If we want to render, we need a wrapper provider.
59
- */
60
- } catch (e) {
61
- // console.warn(`Render failed for ${config.type}`, e);
62
- }
63
- });
64
-
65
- it('should accept className prop if rendered', () => {
66
- // This is a static check on the 'inputs' metadata to ensure className is exposed?
67
- // No, className is on the BaseSchema, not necessarily in 'inputs' array (which is for Designer).
68
- // But checks that component implementation uses 'cn' are hard to do at runtime without rendering.
69
- });
70
- });
71
- });
72
- });
@@ -1,307 +0,0 @@
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 { describe, it, expect, vi } from 'vitest';
10
- import { render, screen, fireEvent } from '@testing-library/react';
11
- import { ConfigFieldRenderer } from '../custom/config-field-renderer';
12
- import type { ConfigField } from '../types/config-panel';
13
-
14
- const defaultDraft = { name: 'Test', enabled: true, theme: 'dark', count: 5 };
15
-
16
- describe('ConfigFieldRenderer', () => {
17
- describe('input type', () => {
18
- const field: ConfigField = { key: 'name', label: 'Name', type: 'input', placeholder: 'Enter name' };
19
-
20
- it('should render input with label', () => {
21
- render(<ConfigFieldRenderer field={field} value="Test" onChange={vi.fn()} draft={defaultDraft} />);
22
- expect(screen.getByText('Name')).toBeDefined();
23
- expect(screen.getByTestId('config-field-name')).toBeDefined();
24
- });
25
-
26
- it('should display current value', () => {
27
- render(<ConfigFieldRenderer field={field} value="Hello" onChange={vi.fn()} draft={defaultDraft} />);
28
- expect((screen.getByTestId('config-field-name') as HTMLInputElement).value).toBe('Hello');
29
- });
30
-
31
- it('should call onChange on input', () => {
32
- const onChange = vi.fn();
33
- render(<ConfigFieldRenderer field={field} value="" onChange={onChange} draft={defaultDraft} />);
34
- fireEvent.change(screen.getByTestId('config-field-name'), { target: { value: 'New' } });
35
- expect(onChange).toHaveBeenCalledWith('New');
36
- });
37
-
38
- it('should use defaultValue when value is undefined', () => {
39
- const fieldWithDefault: ConfigField = { key: 'name', label: 'Name', type: 'input', defaultValue: 'Default' };
40
- render(<ConfigFieldRenderer field={fieldWithDefault} value={undefined} onChange={vi.fn()} draft={defaultDraft} />);
41
- expect((screen.getByTestId('config-field-name') as HTMLInputElement).value).toBe('Default');
42
- });
43
- });
44
-
45
- describe('switch type', () => {
46
- const field: ConfigField = { key: 'enabled', label: 'Enabled', type: 'switch' };
47
-
48
- it('should render switch with label', () => {
49
- render(<ConfigFieldRenderer field={field} value={true} onChange={vi.fn()} draft={defaultDraft} />);
50
- expect(screen.getByText('Enabled')).toBeDefined();
51
- expect(screen.getByTestId('config-field-enabled')).toBeDefined();
52
- });
53
-
54
- it('should toggle on click', () => {
55
- const onChange = vi.fn();
56
- render(<ConfigFieldRenderer field={field} value={false} onChange={onChange} draft={defaultDraft} />);
57
- fireEvent.click(screen.getByTestId('config-field-enabled'));
58
- expect(onChange).toHaveBeenCalledWith(true);
59
- });
60
- });
61
-
62
- describe('checkbox type', () => {
63
- const field: ConfigField = { key: 'checked', label: 'Active', type: 'checkbox' };
64
-
65
- it('should render checkbox with label', () => {
66
- render(<ConfigFieldRenderer field={field} value={false} onChange={vi.fn()} draft={defaultDraft} />);
67
- expect(screen.getByText('Active')).toBeDefined();
68
- expect(screen.getByTestId('config-field-checked')).toBeDefined();
69
- });
70
-
71
- it('should toggle on click', () => {
72
- const onChange = vi.fn();
73
- render(<ConfigFieldRenderer field={field} value={false} onChange={onChange} draft={defaultDraft} />);
74
- fireEvent.click(screen.getByTestId('config-field-checked'));
75
- expect(onChange).toHaveBeenCalledWith(true);
76
- });
77
- });
78
-
79
- describe('select type', () => {
80
- const field: ConfigField = {
81
- key: 'theme',
82
- label: 'Theme',
83
- type: 'select',
84
- options: [
85
- { value: 'light', label: 'Light' },
86
- { value: 'dark', label: 'Dark' },
87
- { value: 'auto', label: 'Auto' },
88
- ],
89
- };
90
-
91
- it('should render select trigger with label', () => {
92
- render(<ConfigFieldRenderer field={field} value="dark" onChange={vi.fn()} draft={defaultDraft} />);
93
- expect(screen.getByText('Theme')).toBeDefined();
94
- expect(screen.getByTestId('config-field-theme')).toBeDefined();
95
- });
96
- });
97
-
98
- describe('slider type', () => {
99
- const field: ConfigField = {
100
- key: 'count',
101
- label: 'Count',
102
- type: 'slider',
103
- min: 1,
104
- max: 10,
105
- step: 1,
106
- };
107
-
108
- it('should render slider with label and value display', () => {
109
- render(<ConfigFieldRenderer field={field} value={5} onChange={vi.fn()} draft={defaultDraft} />);
110
- expect(screen.getByText('Count')).toBeDefined();
111
- expect(screen.getByText('5')).toBeDefined();
112
- });
113
- });
114
-
115
- describe('color type', () => {
116
- const field: ConfigField = { key: 'bgColor', label: 'Background', type: 'color' };
117
-
118
- it('should render color picker', () => {
119
- render(<ConfigFieldRenderer field={field} value="#ff0000" onChange={vi.fn()} draft={defaultDraft} />);
120
- expect(screen.getByText('Background')).toBeDefined();
121
- const input = screen.getByTestId('config-field-bgColor') as HTMLInputElement;
122
- expect(input.type).toBe('color');
123
- expect(input.value).toBe('#ff0000');
124
- });
125
-
126
- it('should call onChange on color change', () => {
127
- const onChange = vi.fn();
128
- render(<ConfigFieldRenderer field={field} value="#ff0000" onChange={onChange} draft={defaultDraft} />);
129
- fireEvent.change(screen.getByTestId('config-field-bgColor'), { target: { value: '#00ff00' } });
130
- expect(onChange).toHaveBeenCalledWith('#00ff00');
131
- });
132
- });
133
-
134
- describe('icon-group type', () => {
135
- const field: ConfigField = {
136
- key: 'size',
137
- label: 'Size',
138
- type: 'icon-group',
139
- options: [
140
- { value: 'sm', label: 'Small' },
141
- { value: 'md', label: 'Medium' },
142
- { value: 'lg', label: 'Large' },
143
- ],
144
- };
145
-
146
- it('should render icon group buttons', () => {
147
- render(<ConfigFieldRenderer field={field} value="md" onChange={vi.fn()} draft={defaultDraft} />);
148
- expect(screen.getByText('Size')).toBeDefined();
149
- expect(screen.getByTitle('Small')).toBeDefined();
150
- expect(screen.getByTitle('Medium')).toBeDefined();
151
- expect(screen.getByTitle('Large')).toBeDefined();
152
- });
153
-
154
- it('should call onChange when button clicked', () => {
155
- const onChange = vi.fn();
156
- render(<ConfigFieldRenderer field={field} value="sm" onChange={onChange} draft={defaultDraft} />);
157
- fireEvent.click(screen.getByTitle('Large'));
158
- expect(onChange).toHaveBeenCalledWith('lg');
159
- });
160
- });
161
-
162
- describe('custom type', () => {
163
- it('should render custom content via render prop', () => {
164
- const field: ConfigField = {
165
- key: 'custom',
166
- label: 'Custom',
167
- type: 'custom',
168
- render: (value, onChange) => (
169
- <div data-testid="custom-render">
170
- <span>Custom: {value}</span>
171
- <button onClick={() => onChange('updated')}>Update</button>
172
- </div>
173
- ),
174
- };
175
- const onChange = vi.fn();
176
- render(<ConfigFieldRenderer field={field} value="initial" onChange={onChange} draft={defaultDraft} />);
177
- expect(screen.getByTestId('custom-render')).toBeDefined();
178
- expect(screen.getByText('Custom: initial')).toBeDefined();
179
- fireEvent.click(screen.getByText('Update'));
180
- expect(onChange).toHaveBeenCalledWith('updated');
181
- });
182
-
183
- it('should return null for custom type without render', () => {
184
- const field: ConfigField = { key: 'empty', label: 'Empty', type: 'custom' };
185
- const { container } = render(<ConfigFieldRenderer field={field} value={null} onChange={vi.fn()} draft={defaultDraft} />);
186
- expect(container.innerHTML).toBe('');
187
- });
188
- });
189
-
190
- describe('visibility', () => {
191
- it('should hide field when visibleWhen returns false', () => {
192
- const field: ConfigField = {
193
- key: 'hidden',
194
- label: 'Hidden',
195
- type: 'input',
196
- visibleWhen: () => false,
197
- };
198
- const { container } = render(<ConfigFieldRenderer field={field} value="" onChange={vi.fn()} draft={defaultDraft} />);
199
- expect(container.innerHTML).toBe('');
200
- });
201
-
202
- it('should show field when visibleWhen returns true', () => {
203
- const field: ConfigField = {
204
- key: 'visible',
205
- label: 'Visible',
206
- type: 'input',
207
- visibleWhen: (draft) => draft.enabled === true,
208
- };
209
- render(<ConfigFieldRenderer field={field} value="" onChange={vi.fn()} draft={defaultDraft} />);
210
- expect(screen.getByText('Visible')).toBeDefined();
211
- });
212
-
213
- it('should evaluate visibleWhen against draft', () => {
214
- const field: ConfigField = {
215
- key: 'conditional',
216
- label: 'Conditional',
217
- type: 'input',
218
- visibleWhen: (draft) => draft.theme === 'dark',
219
- };
220
- const { container: hidden } = render(
221
- <ConfigFieldRenderer field={field} value="" onChange={vi.fn()} draft={{ ...defaultDraft, theme: 'light' }} />,
222
- );
223
- expect(hidden.innerHTML).toBe('');
224
-
225
- render(<ConfigFieldRenderer field={field} value="" onChange={vi.fn()} draft={{ ...defaultDraft, theme: 'dark' }} />);
226
- expect(screen.getByText('Conditional')).toBeDefined();
227
- });
228
- });
229
-
230
- describe('field-picker type', () => {
231
- it('should render as clickable config row', () => {
232
- const field: ConfigField = { key: 'field', label: 'Select Field', type: 'field-picker', placeholder: 'Choose...' };
233
- render(<ConfigFieldRenderer field={field} value={undefined} onChange={vi.fn()} draft={defaultDraft} />);
234
- expect(screen.getByText('Select Field')).toBeDefined();
235
- expect(screen.getByText('Choose...')).toBeDefined();
236
- });
237
- });
238
-
239
- describe('filter/sort types', () => {
240
- it('should render filter with FilterBuilder', () => {
241
- const field: ConfigField = {
242
- key: 'filter',
243
- label: 'Filters',
244
- type: 'filter',
245
- fields: [
246
- { value: 'name', label: 'Name' },
247
- { value: 'status', label: 'Status' },
248
- ],
249
- };
250
- render(<ConfigFieldRenderer field={field} value={undefined} onChange={vi.fn()} draft={defaultDraft} />);
251
- expect(screen.getByText('Filters')).toBeDefined();
252
- expect(screen.getByTestId('config-field-filter')).toBeDefined();
253
- // FilterBuilder renders 'Where' label and 'Add filter' button
254
- expect(screen.getByText('Add filter')).toBeDefined();
255
- });
256
-
257
- it('should render sort with SortBuilder', () => {
258
- const field: ConfigField = {
259
- key: 'sort',
260
- label: 'Sorting',
261
- type: 'sort',
262
- fields: [
263
- { value: 'name', label: 'Name' },
264
- { value: 'date', label: 'Date' },
265
- ],
266
- };
267
- render(<ConfigFieldRenderer field={field} value={undefined} onChange={vi.fn()} draft={defaultDraft} />);
268
- expect(screen.getByText('Sorting')).toBeDefined();
269
- expect(screen.getByTestId('config-field-sort')).toBeDefined();
270
- // SortBuilder renders 'Add sort' button
271
- expect(screen.getByText('Add sort')).toBeDefined();
272
- });
273
- });
274
-
275
- describe('helpText rendering', () => {
276
- it('should render helpText below field when provided', () => {
277
- const field: ConfigField = {
278
- key: 'width',
279
- label: 'Width',
280
- type: 'input',
281
- helpText: 'Available for drawer, modal, and split modes',
282
- };
283
- render(<ConfigFieldRenderer field={field} value="" onChange={vi.fn()} draft={defaultDraft} />);
284
- expect(screen.getByText('Available for drawer, modal, and split modes')).toBeDefined();
285
- });
286
-
287
- it('should not render helpText paragraph when not provided', () => {
288
- const field: ConfigField = { key: 'name', label: 'Name', type: 'input' };
289
- const { container } = render(<ConfigFieldRenderer field={field} value="" onChange={vi.fn()} draft={defaultDraft} />);
290
- expect(container.querySelectorAll('p').length).toBe(0);
291
- });
292
-
293
- it('should render helpText for custom field type', () => {
294
- const React = require('react');
295
- const field: ConfigField = {
296
- key: 'custom',
297
- label: 'Custom',
298
- type: 'custom',
299
- helpText: 'Custom help text',
300
- render: (value, onChange) => React.createElement('div', { 'data-testid': 'custom-content' }, 'Custom'),
301
- };
302
- render(<ConfigFieldRenderer field={field} value="" onChange={vi.fn()} draft={defaultDraft} />);
303
- expect(screen.getByText('Custom help text')).toBeDefined();
304
- expect(screen.getByTestId('custom-content')).toBeDefined();
305
- });
306
- });
307
- });