@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,327 +0,0 @@
1
- // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
-
3
- exports[`Badge snapshots > renders variant="default" 1`] = `
4
- <div
5
- class="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 border-transparent bg-primary text-primary-foreground hover:bg-primary/80"
6
- >
7
- Label
8
- </div>
9
- `;
10
-
11
- exports[`Badge snapshots > renders variant="destructive" 1`] = `
12
- <div
13
- class="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80"
14
- >
15
- Label
16
- </div>
17
- `;
18
-
19
- exports[`Badge snapshots > renders variant="outline" 1`] = `
20
- <div
21
- class="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 text-foreground"
22
- >
23
- Label
24
- </div>
25
- `;
26
-
27
- exports[`Badge snapshots > renders variant="secondary" 1`] = `
28
- <div
29
- class="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80"
30
- >
31
- Label
32
- </div>
33
- `;
34
-
35
- exports[`Badge snapshots > renders with custom className 1`] = `
36
- <div
37
- class="inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 border-transparent bg-primary text-primary-foreground hover:bg-primary/80 custom-class"
38
- >
39
- Custom
40
- </div>
41
- `;
42
-
43
- exports[`Button snapshots > renders disabled state 1`] = `
44
- <button
45
- class="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2"
46
- disabled=""
47
- >
48
- Disabled
49
- </button>
50
- `;
51
-
52
- exports[`Button snapshots > renders size="icon" 1`] = `
53
- <button
54
- aria-label="Icon button"
55
- class="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-primary text-primary-foreground hover:bg-primary/90 h-10 w-10"
56
- >
57
-
58
- </button>
59
- `;
60
-
61
- exports[`Button snapshots > renders size="lg" 1`] = `
62
- <button
63
- class="inline-flex items-center justify-center gap-2 whitespace-nowrap text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-primary text-primary-foreground hover:bg-primary/90 h-11 rounded-md px-8"
64
- >
65
- Large
66
- </button>
67
- `;
68
-
69
- exports[`Button snapshots > renders size="sm" 1`] = `
70
- <button
71
- class="inline-flex items-center justify-center gap-2 whitespace-nowrap text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-primary text-primary-foreground hover:bg-primary/90 h-9 rounded-md px-3"
72
- >
73
- Small
74
- </button>
75
- `;
76
-
77
- exports[`Button snapshots > renders variant="default" 1`] = `
78
- <button
79
- class="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2"
80
- >
81
- Click me
82
- </button>
83
- `;
84
-
85
- exports[`Button snapshots > renders variant="destructive" 1`] = `
86
- <button
87
- class="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-destructive text-destructive-foreground hover:bg-destructive/90 h-10 px-4 py-2"
88
- >
89
- Click me
90
- </button>
91
- `;
92
-
93
- exports[`Button snapshots > renders variant="ghost" 1`] = `
94
- <button
95
- class="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 hover:bg-accent hover:text-accent-foreground h-10 px-4 py-2"
96
- >
97
- Click me
98
- </button>
99
- `;
100
-
101
- exports[`Button snapshots > renders variant="link" 1`] = `
102
- <button
103
- class="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 text-primary underline-offset-4 hover:underline h-10 px-4 py-2"
104
- >
105
- Click me
106
- </button>
107
- `;
108
-
109
- exports[`Button snapshots > renders variant="outline" 1`] = `
110
- <button
111
- class="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 border border-input bg-background hover:bg-accent hover:text-accent-foreground h-10 px-4 py-2"
112
- >
113
- Click me
114
- </button>
115
- `;
116
-
117
- exports[`Button snapshots > renders variant="secondary" 1`] = `
118
- <button
119
- class="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-secondary text-secondary-foreground hover:bg-secondary/80 h-10 px-4 py-2"
120
- >
121
- Click me
122
- </button>
123
- `;
124
-
125
- exports[`Card snapshots > renders content-only card 1`] = `
126
- <div
127
- class="rounded-lg border bg-card text-card-foreground shadow-sm"
128
- >
129
- <div
130
- class="p-6 pt-0"
131
- >
132
- Just content
133
- </div>
134
- </div>
135
- `;
136
-
137
- exports[`Card snapshots > renders header-only card 1`] = `
138
- <div
139
- class="rounded-lg border bg-card text-card-foreground shadow-sm"
140
- >
141
- <div
142
- class="flex flex-col space-y-1.5 p-6"
143
- >
144
- <div
145
- class="text-2xl font-semibold leading-none tracking-tight"
146
- >
147
- Minimal Card
148
- </div>
149
- </div>
150
- </div>
151
- `;
152
-
153
- exports[`Card snapshots > renders with custom className 1`] = `
154
- <div
155
- class="rounded-lg border bg-card text-card-foreground w-96 shadow-lg"
156
- >
157
- <div
158
- class="p-6 pt-0"
159
- >
160
- Styled card
161
- </div>
162
- </div>
163
- `;
164
-
165
- exports[`Card snapshots > renders with header, content, and footer 1`] = `
166
- <div
167
- class="rounded-lg border bg-card text-card-foreground shadow-sm"
168
- >
169
- <div
170
- class="flex flex-col space-y-1.5 p-6"
171
- >
172
- <div
173
- class="text-2xl font-semibold leading-none tracking-tight"
174
- >
175
- Card Title
176
- </div>
177
- <div
178
- class="text-sm text-muted-foreground"
179
- >
180
- A brief description
181
- </div>
182
- </div>
183
- <div
184
- class="p-6 pt-0"
185
- >
186
- <p>
187
- Card body content
188
- </p>
189
- </div>
190
- <div
191
- class="flex items-center p-6 pt-0"
192
- >
193
- <button
194
- class="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-primary text-primary-foreground hover:bg-primary/90 h-10 px-4 py-2"
195
- >
196
- Action
197
- </button>
198
- </div>
199
- </div>
200
- `;
201
-
202
- exports[`Empty state snapshots > renders empty media with default variant 1`] = `
203
- <div
204
- class="flex shrink-0 items-center justify-center mb-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 bg-transparent"
205
- data-slot="empty-icon"
206
- data-variant="default"
207
- >
208
- <span>
209
- 🔍
210
- </span>
211
- </div>
212
- `;
213
-
214
- exports[`Empty state snapshots > renders full empty state with media, title, description, and content 1`] = `
215
- <div
216
- class="flex min-w-0 flex-1 flex-col items-center justify-center gap-6 rounded-lg border-dashed p-6 text-center text-balance md:p-12"
217
- data-slot="empty"
218
- >
219
- <div
220
- class="flex max-w-sm flex-col items-center gap-2 text-center"
221
- data-slot="empty-header"
222
- >
223
- <div
224
- class="mb-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 bg-muted text-foreground flex size-10 shrink-0 items-center justify-center rounded-lg [&_svg:not([class*='size-'])]:size-6"
225
- data-slot="empty-icon"
226
- data-variant="icon"
227
- >
228
- <span>
229
- 📭
230
- </span>
231
- </div>
232
- <div
233
- class="text-lg font-medium tracking-tight"
234
- data-slot="empty-title"
235
- >
236
- No results found
237
- </div>
238
- <div
239
- class="text-muted-foreground [&>a:hover]:text-primary text-sm/relaxed [&>a]:underline [&>a]:underline-offset-4"
240
- data-slot="empty-description"
241
- >
242
- Try adjusting your search or filter criteria.
243
- </div>
244
- </div>
245
- <div
246
- class="flex w-full max-w-sm min-w-0 flex-col items-center gap-4 text-sm text-balance"
247
- data-slot="empty-content"
248
- >
249
- <button
250
- class="inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 border border-input bg-background hover:bg-accent hover:text-accent-foreground h-10 px-4 py-2"
251
- >
252
- Clear filters
253
- </button>
254
- </div>
255
- </div>
256
- `;
257
-
258
- exports[`Empty state snapshots > renders minimal empty state with title only 1`] = `
259
- <div
260
- class="flex min-w-0 flex-1 flex-col items-center justify-center gap-6 rounded-lg border-dashed p-6 text-center text-balance md:p-12"
261
- data-slot="empty"
262
- >
263
- <div
264
- class="flex max-w-sm flex-col items-center gap-2 text-center"
265
- data-slot="empty-header"
266
- >
267
- <div
268
- class="text-lg font-medium tracking-tight"
269
- data-slot="empty-title"
270
- >
271
- Nothing here yet
272
- </div>
273
- </div>
274
- </div>
275
- `;
276
-
277
- exports[`Spinner snapshots > renders default spinner 1`] = `
278
- <div
279
- aria-label="Loading"
280
- class="flex items-center justify-center"
281
- role="status"
282
- >
283
- <svg
284
- aria-hidden="true"
285
- class="lucide lucide-loader-circle animate-spin text-muted-foreground w-full h-full min-w-4 min-h-4"
286
- fill="none"
287
- height="24"
288
- stroke="currentColor"
289
- stroke-linecap="round"
290
- stroke-linejoin="round"
291
- stroke-width="2"
292
- viewBox="0 0 24 24"
293
- width="24"
294
- xmlns="http://www.w3.org/2000/svg"
295
- >
296
- <path
297
- d="M21 12a9 9 0 1 1-6.219-8.56"
298
- />
299
- </svg>
300
- </div>
301
- `;
302
-
303
- exports[`Spinner snapshots > renders with custom className 1`] = `
304
- <div
305
- aria-label="Loading"
306
- class="flex items-center justify-center h-8 w-8"
307
- role="status"
308
- >
309
- <svg
310
- aria-hidden="true"
311
- class="lucide lucide-loader-circle animate-spin text-muted-foreground w-full h-full min-w-4 min-h-4"
312
- fill="none"
313
- height="24"
314
- stroke="currentColor"
315
- stroke-linecap="round"
316
- stroke-linejoin="round"
317
- stroke-width="2"
318
- viewBox="0 0 24 24"
319
- width="24"
320
- xmlns="http://www.w3.org/2000/svg"
321
- >
322
- <path
323
- d="M21 12a9 9 0 1 1-6.219-8.56"
324
- />
325
- </svg>
326
- </div>
327
- `;
@@ -1,137 +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
- /**
10
- * Axe-core accessibility test suite for ObjectUI Shadcn components.
11
- *
12
- * Tests core UI primitives against WCAG 2.1 AA standards using axe-core.
13
- * Part of Q1 2026 roadmap §1.4 Test Coverage Improvement.
14
- */
15
-
16
- import { describe, it, expect } from 'vitest';
17
- import { render } from '@testing-library/react';
18
- import { axe } from 'vitest-axe';
19
- import React from 'react';
20
- import {
21
- Button,
22
- Badge,
23
- Card,
24
- CardContent,
25
- CardHeader,
26
- CardTitle,
27
- CardDescription,
28
- Input,
29
- Label,
30
- Skeleton,
31
- } from '@object-ui/components';
32
-
33
- /**
34
- * Helper to assert no axe violations.
35
- * Works with vitest-axe's AxeResults format.
36
- */
37
- async function expectNoViolations(container: HTMLElement) {
38
- const results = await axe(container);
39
- const violations = results.violations || [];
40
- if (violations.length > 0) {
41
- const messages = violations.map(
42
- (v: any) => `[${v.impact}] ${v.id}: ${v.description} (${v.nodes.length} instance(s))`
43
- );
44
- throw new Error(`Expected no accessibility violations, but found ${violations.length}:\n${messages.join('\n')}`);
45
- }
46
- }
47
-
48
- describe('Accessibility — axe-core (WCAG 2.1 AA)', () => {
49
- it('Button should have no a11y violations', async () => {
50
- const { container } = render(<Button>Click me</Button>);
51
- await expectNoViolations(container);
52
- });
53
-
54
- it('Icon-only Button with aria-label should have no violations', async () => {
55
- const { container } = render(
56
- <Button aria-label="Close" size="icon">
57
-
58
- </Button>
59
- );
60
- await expectNoViolations(container);
61
- });
62
-
63
- it('Badge should have no a11y violations', async () => {
64
- const { container } = render(<Badge>Status</Badge>);
65
- await expectNoViolations(container);
66
- });
67
-
68
- it('Card with proper heading hierarchy should have no violations', async () => {
69
- const { container } = render(
70
- <Card>
71
- <CardHeader>
72
- <CardTitle>Card Title</CardTitle>
73
- <CardDescription>Card description text</CardDescription>
74
- </CardHeader>
75
- <CardContent>
76
- <p>Card content</p>
77
- </CardContent>
78
- </Card>
79
- );
80
- await expectNoViolations(container);
81
- });
82
-
83
- it('Input with associated Label should have no violations', async () => {
84
- const { container } = render(
85
- <div>
86
- <Label htmlFor="email">Email</Label>
87
- <Input id="email" type="email" placeholder="Enter email" />
88
- </div>
89
- );
90
- await expectNoViolations(container);
91
- });
92
-
93
- it('Input with aria-label should have no violations', async () => {
94
- const { container } = render(
95
- <Input aria-label="Search" type="search" placeholder="Search..." />
96
- );
97
- await expectNoViolations(container);
98
- });
99
-
100
- it('Skeleton should have no a11y violations', async () => {
101
- const { container } = render(
102
- <div role="status" aria-label="Loading">
103
- <Skeleton className="h-10 w-full" />
104
- <Skeleton className="h-4 w-3/4" />
105
- </div>
106
- );
107
- await expectNoViolations(container);
108
- });
109
-
110
- it('Multiple Buttons in a group should have no violations', async () => {
111
- const { container } = render(
112
- <div role="group" aria-label="Actions">
113
- <Button variant="default">Save</Button>
114
- <Button variant="outline">Cancel</Button>
115
- <Button variant="destructive">Delete</Button>
116
- </div>
117
- );
118
- await expectNoViolations(container);
119
- });
120
-
121
- it('Form with proper labels should have no violations', async () => {
122
- const { container } = render(
123
- <form aria-label="Login form">
124
- <div>
125
- <Label htmlFor="username">Username</Label>
126
- <Input id="username" type="text" />
127
- </div>
128
- <div>
129
- <Label htmlFor="password">Password</Label>
130
- <Input id="password" type="password" />
131
- </div>
132
- <Button type="submit">Sign In</Button>
133
- </form>
134
- );
135
- await expectNoViolations(container);
136
- });
137
- });
@@ -1,206 +0,0 @@
1
- /**
2
- * Tests for ActionBar (action:bar) renderer
3
- */
4
-
5
- import { describe, it, expect } from 'vitest';
6
- import { render, screen } from '@testing-library/react';
7
- import { ComponentRegistry } from '@object-ui/core';
8
- import { renderComponent, validateComponentRegistration } from './test-utils';
9
-
10
- // Ensure action renderers are loaded (side-effect imports via vitest.setup.tsx)
11
-
12
- describe('ActionBar (action:bar)', () => {
13
- describe('registration', () => {
14
- it('is registered in ComponentRegistry', () => {
15
- const reg = validateComponentRegistration('action:bar');
16
- expect(reg.isRegistered).toBe(true);
17
- expect(reg.hasRenderer).toBe(true);
18
- expect(reg.hasLabel).toBe(true);
19
- expect(reg.hasInputs).toBe(true);
20
- expect(reg.hasDefaultProps).toBe(true);
21
- });
22
- });
23
-
24
- describe('rendering', () => {
25
- it('renders nothing when actions array is empty', () => {
26
- const { container } = renderComponent({
27
- type: 'action:bar',
28
- actions: [],
29
- });
30
- expect(container.innerHTML).toBe('');
31
- });
32
-
33
- it('renders action buttons for provided actions', () => {
34
- const { container } = renderComponent({
35
- type: 'action:bar',
36
- actions: [
37
- { name: 'save', label: 'Save', type: 'script', component: 'action:button' },
38
- { name: 'cancel', label: 'Cancel', type: 'script', component: 'action:button' },
39
- ],
40
- });
41
- expect(container.textContent).toContain('Save');
42
- expect(container.textContent).toContain('Cancel');
43
- });
44
-
45
- it('renders with role="toolbar" and aria-label', () => {
46
- const { container } = renderComponent({
47
- type: 'action:bar',
48
- actions: [
49
- { name: 'test', label: 'Test', type: 'script' },
50
- ],
51
- });
52
- const toolbar = container.querySelector('[role="toolbar"]');
53
- expect(toolbar).toBeTruthy();
54
- expect(toolbar?.getAttribute('aria-label')).toBe('Actions');
55
- });
56
-
57
- it('filters actions by location', () => {
58
- const { container } = renderComponent({
59
- type: 'action:bar',
60
- location: 'list_toolbar',
61
- actions: [
62
- { name: 'toolbar_action', label: 'Toolbar Action', type: 'script', locations: ['list_toolbar'] },
63
- { name: 'header_action', label: 'Header Action', type: 'script', locations: ['record_header'] },
64
- { name: 'both_action', label: 'Both Action', type: 'script', locations: ['list_toolbar', 'record_header'] },
65
- ],
66
- });
67
- expect(container.textContent).toContain('Toolbar Action');
68
- expect(container.textContent).not.toContain('Header Action');
69
- expect(container.textContent).toContain('Both Action');
70
- });
71
-
72
- it('shows actions without locations when filtering by location', () => {
73
- const { container } = renderComponent({
74
- type: 'action:bar',
75
- location: 'record_header',
76
- actions: [
77
- { name: 'no_loc', label: 'No Location', type: 'script' },
78
- { name: 'has_loc', label: 'Has Location', type: 'script', locations: ['list_toolbar'] },
79
- ],
80
- });
81
- // Action without locations should show in any location
82
- expect(container.textContent).toContain('No Location');
83
- expect(container.textContent).not.toContain('Has Location');
84
- });
85
-
86
- it('renders all actions when no location filter is set', () => {
87
- const { container } = renderComponent({
88
- type: 'action:bar',
89
- actions: [
90
- { name: 'a1', label: 'Action 1', type: 'script', locations: ['list_toolbar'] },
91
- { name: 'a2', label: 'Action 2', type: 'script', locations: ['record_header'] },
92
- ],
93
- });
94
- expect(container.textContent).toContain('Action 1');
95
- expect(container.textContent).toContain('Action 2');
96
- });
97
-
98
- it('deduplicates actions by name', () => {
99
- const { container } = renderComponent({
100
- type: 'action:bar',
101
- actions: [
102
- { name: 'change_status', label: 'Change Status', type: 'script', component: 'action:button' },
103
- { name: 'assign_user', label: 'Assign User', type: 'script', component: 'action:button' },
104
- { name: 'change_status', label: 'Change Status', type: 'script', component: 'action:button' },
105
- ],
106
- });
107
- const toolbar = container.querySelector('[role="toolbar"]');
108
- expect(toolbar).toBeTruthy();
109
- // Should only render 2 actions (duplicates removed)
110
- expect(toolbar!.children.length).toBe(2);
111
- expect(container.textContent).toContain('Change Status');
112
- expect(container.textContent).toContain('Assign User');
113
- });
114
-
115
- it('deduplicates actions after location filtering', () => {
116
- const { container } = renderComponent({
117
- type: 'action:bar',
118
- location: 'record_header',
119
- actions: [
120
- { name: 'change_status', label: 'Change Status', type: 'script', locations: ['record_header'] },
121
- { name: 'assign_user', label: 'Assign User', type: 'script', locations: ['record_header'] },
122
- { name: 'change_status', label: 'Change Status', type: 'script', locations: ['record_header', 'record_more'] },
123
- { name: 'assign_user', label: 'Assign User', type: 'script', locations: ['record_header'] },
124
- ],
125
- });
126
- const toolbar = container.querySelector('[role="toolbar"]');
127
- expect(toolbar).toBeTruthy();
128
- // Should only render 2 unique actions
129
- expect(toolbar!.children.length).toBe(2);
130
- });
131
- });
132
-
133
- describe('overflow', () => {
134
- it('groups excess actions into overflow menu when maxVisible is exceeded', () => {
135
- const { container } = renderComponent({
136
- type: 'action:bar',
137
- maxVisible: 2,
138
- actions: [
139
- { name: 'a1', label: 'Action 1', type: 'script' },
140
- { name: 'a2', label: 'Action 2', type: 'script' },
141
- { name: 'a3', label: 'Action 3', type: 'script' },
142
- { name: 'a4', label: 'Action 4', type: 'script' },
143
- ],
144
- });
145
- // First 2 should be visible as buttons
146
- expect(container.textContent).toContain('Action 1');
147
- expect(container.textContent).toContain('Action 2');
148
- // Remaining 2 should be in a dropdown (rendered as action:menu trigger)
149
- const toolbar = container.querySelector('[role="toolbar"]');
150
- expect(toolbar).toBeTruthy();
151
- // There should be 3 children: 2 inline buttons + 1 menu trigger
152
- const children = toolbar!.children;
153
- expect(children.length).toBe(3);
154
- });
155
-
156
- it('does not show overflow when actions fit within maxVisible', () => {
157
- const { container } = renderComponent({
158
- type: 'action:bar',
159
- maxVisible: 5,
160
- actions: [
161
- { name: 'a1', label: 'Action 1', type: 'script' },
162
- { name: 'a2', label: 'Action 2', type: 'script' },
163
- ],
164
- });
165
- const toolbar = container.querySelector('[role="toolbar"]');
166
- expect(toolbar!.children.length).toBe(2);
167
- });
168
- });
169
-
170
- describe('styling', () => {
171
- it('applies custom className', () => {
172
- const { container } = renderComponent({
173
- type: 'action:bar',
174
- className: 'my-custom-bar',
175
- actions: [
176
- { name: 'test', label: 'Test', type: 'script' },
177
- ],
178
- });
179
- const toolbar = container.querySelector('[role="toolbar"]');
180
- expect(toolbar?.className).toContain('my-custom-bar');
181
- });
182
-
183
- it('supports vertical direction', () => {
184
- const { container } = renderComponent({
185
- type: 'action:bar',
186
- direction: 'vertical',
187
- actions: [
188
- { name: 'test', label: 'Test', type: 'script' },
189
- ],
190
- });
191
- const toolbar = container.querySelector('[role="toolbar"]');
192
- expect(toolbar?.className).toContain('flex-col');
193
- });
194
-
195
- it('defaults to horizontal direction', () => {
196
- const { container } = renderComponent({
197
- type: 'action:bar',
198
- actions: [
199
- { name: 'test', label: 'Test', type: 'script' },
200
- ],
201
- });
202
- const toolbar = container.querySelector('[role="toolbar"]');
203
- expect(toolbar?.className).toContain('flex-row');
204
- });
205
- });
206
- });