@rangka/client 0.1.0 → 0.1.2

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 (352) hide show
  1. package/dist/App.d.ts.map +1 -1
  2. package/dist/App.js +7 -1
  3. package/dist/App.js.map +1 -1
  4. package/dist/components/ui/input-group.d.ts +1 -1
  5. package/dist/index.d.ts +2 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +2 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/main.d.ts.map +1 -1
  10. package/dist/main.js +20 -0
  11. package/dist/main.js.map +1 -1
  12. package/dist/shell/assets/AttachmentWidget-BTTGroHP.js +1 -0
  13. package/dist/shell/assets/AttachmentsWidget-DZgvmO9P.js +1 -0
  14. package/dist/shell/assets/BadgeWidget-DN6GsAAG.js +1 -0
  15. package/dist/shell/assets/CardWidget-qX-UvqJh.js +1 -0
  16. package/dist/shell/assets/CheckboxWidget-CYPZ85ih.js +1 -0
  17. package/dist/shell/assets/CodeWidget-DnVtHG1d.js +1 -0
  18. package/dist/shell/assets/ColumnWidget-CYmFCVOf.js +1 -0
  19. package/dist/shell/assets/ComputedWidget-BQApkfir.js +1 -0
  20. package/dist/shell/assets/DatePickerWidget-pEusSy9D.js +1 -0
  21. package/dist/shell/assets/DatetimeWidget-M0fEGDTD.js +1 -0
  22. package/dist/shell/assets/DividerWidget-hXVGhIKC.js +1 -0
  23. package/dist/shell/assets/DrawerWidget-DynL7EIy.js +1 -0
  24. package/dist/shell/assets/DynamicLinkWidget-ChMJ5DAf.js +1 -0
  25. package/dist/shell/assets/IconWidget-Cgo9txq1.js +1 -0
  26. package/dist/shell/assets/ImageWidget-YUv1_OQK.js +1 -0
  27. package/dist/shell/assets/JsonWidget-RHUHhXHJ.js +1 -0
  28. package/dist/shell/assets/LinkWidget-CIu7qmb2.js +1 -0
  29. package/dist/shell/assets/ManyToManyWidget-DCQnygvZ.js +1 -0
  30. package/dist/shell/assets/ModalWidget-FggzYaS2.js +1 -0
  31. package/dist/shell/assets/MoneyWidget-CKjOSucD.js +1 -0
  32. package/dist/shell/assets/RepeatWidget-Dfp4zW4d.js +1 -0
  33. package/dist/shell/assets/ScrollAreaWidget-CdFdf4rv.js +1 -0
  34. package/dist/shell/assets/SequenceWidget-DIXHZslz.js +1 -0
  35. package/dist/shell/assets/SpacerWidget-BgM4dC6x.js +1 -0
  36. package/dist/shell/assets/SplitWidget-_mcQkjQk.js +1 -0
  37. package/dist/shell/assets/StackWidget-BI_VIreo.js +1 -0
  38. package/dist/shell/assets/TableWidget-DuIvd6qR.js +1 -0
  39. package/dist/shell/assets/TextareaWidget-CATua7Ls.js +1 -0
  40. package/dist/shell/assets/TreeWidget-BoHlhfza.js +1 -0
  41. package/dist/shell/assets/calendar-DqckiKt1.js +1 -0
  42. package/dist/shell/assets/index-63v1sBS3.css +1 -0
  43. package/dist/shell/assets/index-D1wStSrO.js +8635 -0
  44. package/dist/shell/assets/popover-DywIKFaQ.js +1 -0
  45. package/dist/shell/assets/textarea-BVCZevA6.js +1 -0
  46. package/dist/shell/assets/useSurfaceContext-kzu9770H.js +1 -0
  47. package/dist/shell/assets/vendor-query-dRdWN_eK.js +1 -0
  48. package/dist/shell/assets/vendor-radix-D-Trh8JA.js +69 -0
  49. package/dist/shell/assets/vendor-router-B1WM9yRc.js +17 -0
  50. package/dist/shell/index.html +5 -2
  51. package/dist/theme.css +82 -0
  52. package/dist/widgets/components/lazy-manifest.d.ts +11 -0
  53. package/dist/widgets/components/lazy-manifest.d.ts.map +1 -0
  54. package/dist/widgets/components/lazy-manifest.js +32 -0
  55. package/dist/widgets/components/lazy-manifest.js.map +1 -0
  56. package/dist/widgets/components/register.d.ts.map +1 -1
  57. package/dist/widgets/components/register.js +0 -58
  58. package/dist/widgets/components/register.js.map +1 -1
  59. package/dist/widgets/loader.d.ts +3 -0
  60. package/dist/widgets/loader.d.ts.map +1 -0
  61. package/dist/widgets/loader.js +99 -0
  62. package/dist/widgets/loader.js.map +1 -0
  63. package/dist/widgets/renderer/LazyWidget.d.ts +8 -0
  64. package/dist/widgets/renderer/LazyWidget.d.ts.map +1 -0
  65. package/dist/widgets/renderer/LazyWidget.js +31 -0
  66. package/dist/widgets/renderer/LazyWidget.js.map +1 -0
  67. package/dist/widgets/renderer/WidgetErrorBoundary.d.ts +17 -0
  68. package/dist/widgets/renderer/WidgetErrorBoundary.d.ts.map +1 -0
  69. package/dist/widgets/renderer/WidgetErrorBoundary.js +18 -0
  70. package/dist/widgets/renderer/WidgetErrorBoundary.js.map +1 -0
  71. package/dist/widgets/renderer/WidgetRenderer.d.ts.map +1 -1
  72. package/dist/widgets/renderer/WidgetRenderer.js +8 -6
  73. package/dist/widgets/renderer/WidgetRenderer.js.map +1 -1
  74. package/package.json +7 -4
  75. package/.claude/skills/add-widget/SKILL.md +0 -101
  76. package/.turbo/turbo-build.log +0 -29
  77. package/CHANGELOG.md +0 -18
  78. package/CLAUDE.md +0 -236
  79. package/components.json +0 -25
  80. package/dist/components/ui/chart.d.ts +0 -45
  81. package/dist/components/ui/chart.d.ts.map +0 -1
  82. package/dist/components/ui/chart.js +0 -119
  83. package/dist/components/ui/chart.js.map +0 -1
  84. package/dist/shell/assets/index--35CAvcP.js +0 -8715
  85. package/dist/shell/assets/index-COLmoPYo.css +0 -1
  86. package/index.html +0 -12
  87. package/src/App.tsx +0 -44
  88. package/src/__tests__/setup.ts +0 -1
  89. package/src/api/auth.ts +0 -41
  90. package/src/api/boot.ts +0 -10
  91. package/src/api/client.ts +0 -26
  92. package/src/api/paths.ts +0 -3
  93. package/src/api/token.ts +0 -13
  94. package/src/auth/LoginForm.tsx +0 -67
  95. package/src/auth/SessionExpired.tsx +0 -24
  96. package/src/auth/SetupForm.tsx +0 -76
  97. package/src/boot/BootGate.tsx +0 -35
  98. package/src/boot/BootProvider.tsx +0 -28
  99. package/src/boot/types.ts +0 -9
  100. package/src/boot/useBoot.ts +0 -111
  101. package/src/components/Icon.tsx +0 -17
  102. package/src/components/ui/accordion.tsx +0 -82
  103. package/src/components/ui/alert-dialog.tsx +0 -180
  104. package/src/components/ui/alert.tsx +0 -76
  105. package/src/components/ui/aspect-ratio.tsx +0 -9
  106. package/src/components/ui/avatar.tsx +0 -94
  107. package/src/components/ui/badge.tsx +0 -45
  108. package/src/components/ui/breadcrumb.tsx +0 -104
  109. package/src/components/ui/button-group.tsx +0 -78
  110. package/src/components/ui/button.tsx +0 -65
  111. package/src/components/ui/calendar.tsx +0 -187
  112. package/src/components/ui/card.tsx +0 -85
  113. package/src/components/ui/carousel.tsx +0 -229
  114. package/src/components/ui/chart.tsx +0 -339
  115. package/src/components/ui/checkbox.tsx +0 -27
  116. package/src/components/ui/collapsible.tsx +0 -21
  117. package/src/components/ui/combobox.tsx +0 -275
  118. package/src/components/ui/command.tsx +0 -178
  119. package/src/components/ui/context-menu.tsx +0 -242
  120. package/src/components/ui/dialog.tsx +0 -146
  121. package/src/components/ui/direction.tsx +0 -20
  122. package/src/components/ui/drawer.tsx +0 -118
  123. package/src/components/ui/dropdown-menu.tsx +0 -247
  124. package/src/components/ui/empty.tsx +0 -94
  125. package/src/components/ui/field.tsx +0 -224
  126. package/src/components/ui/hover-card.tsx +0 -36
  127. package/src/components/ui/input-group.tsx +0 -142
  128. package/src/components/ui/input-otp.tsx +0 -86
  129. package/src/components/ui/input.tsx +0 -19
  130. package/src/components/ui/item.tsx +0 -182
  131. package/src/components/ui/kbd.tsx +0 -26
  132. package/src/components/ui/label.tsx +0 -19
  133. package/src/components/ui/menubar.tsx +0 -260
  134. package/src/components/ui/native-select.tsx +0 -55
  135. package/src/components/ui/navigation-menu.tsx +0 -160
  136. package/src/components/ui/pagination.tsx +0 -112
  137. package/src/components/ui/popover.tsx +0 -74
  138. package/src/components/ui/progress.tsx +0 -31
  139. package/src/components/ui/radio-group.tsx +0 -42
  140. package/src/components/ui/resizable.tsx +0 -42
  141. package/src/components/ui/scroll-area.tsx +0 -53
  142. package/src/components/ui/select.tsx +0 -185
  143. package/src/components/ui/separator.tsx +0 -26
  144. package/src/components/ui/sheet.tsx +0 -128
  145. package/src/components/ui/sidebar.tsx +0 -669
  146. package/src/components/ui/skeleton.tsx +0 -13
  147. package/src/components/ui/slider.tsx +0 -54
  148. package/src/components/ui/sonner.tsx +0 -43
  149. package/src/components/ui/spinner.tsx +0 -16
  150. package/src/components/ui/switch.tsx +0 -33
  151. package/src/components/ui/table.tsx +0 -87
  152. package/src/components/ui/tabs.tsx +0 -80
  153. package/src/components/ui/textarea.tsx +0 -18
  154. package/src/components/ui/toggle-group.tsx +0 -86
  155. package/src/components/ui/toggle.tsx +0 -44
  156. package/src/components/ui/tooltip.tsx +0 -53
  157. package/src/context/MetaContext.tsx +0 -22
  158. package/src/context/ModuleContext.tsx +0 -62
  159. package/src/context/PermissionsContext.tsx +0 -39
  160. package/src/context/ShellProviders.tsx +0 -33
  161. package/src/context/UserContext.tsx +0 -16
  162. package/src/data/QueryProvider.tsx +0 -7
  163. package/src/data/queryClient.ts +0 -18
  164. package/src/data/useModelMeta.ts +0 -17
  165. package/src/data/useMutation.ts +0 -60
  166. package/src/data/useRecord.ts +0 -29
  167. package/src/data/useSource.ts +0 -112
  168. package/src/hooks/use-mobile.ts +0 -19
  169. package/src/index.css +0 -260
  170. package/src/index.ts +0 -16
  171. package/src/lib/utils.ts +0 -6
  172. package/src/main.tsx +0 -17
  173. package/src/router/NotFound.tsx +0 -8
  174. package/src/router/RouterProvider.tsx +0 -7
  175. package/src/router/buildRouteTree.tsx +0 -63
  176. package/src/router/createShellRouter.ts +0 -9
  177. package/src/router/hooks.ts +0 -43
  178. package/src/shell/CommandPalette.tsx +0 -76
  179. package/src/shell/ConfirmDialog.tsx +0 -34
  180. package/src/shell/ConfirmProvider.tsx +0 -56
  181. package/src/shell/DrawerContext.tsx +0 -44
  182. package/src/shell/HeaderActions.tsx +0 -31
  183. package/src/shell/ModuleSelectorPage.tsx +0 -149
  184. package/src/shell/PageOutlet.tsx +0 -21
  185. package/src/shell/ShellContext.tsx +0 -45
  186. package/src/shell/ShellDevTools.tsx +0 -153
  187. package/src/shell/ShellLayout.tsx +0 -231
  188. package/src/shell/Toast.tsx +0 -58
  189. package/src/shell/ToastProvider.tsx +0 -60
  190. package/src/shell/app-sidebar/AppSidebar.tsx +0 -44
  191. package/src/shell/app-sidebar/ModuleSwitcher.tsx +0 -87
  192. package/src/shell/app-sidebar/NavMain.tsx +0 -64
  193. package/src/shell/app-sidebar/NavUser.tsx +0 -97
  194. package/src/shell/app-sidebar/SearchMenu.tsx +0 -22
  195. package/src/shell/app-sidebar/index.ts +0 -8
  196. package/src/shell/app-sidebar/types.ts +0 -38
  197. package/src/shell/types.ts +0 -6
  198. package/src/shell/useBreadcrumbs.ts +0 -42
  199. package/src/studio/bridge.ts +0 -125
  200. package/src/studio/index.ts +0 -3
  201. package/src/studio/overlay.ts +0 -47
  202. package/src/studio/types.ts +0 -32
  203. package/src/studio/walker.ts +0 -48
  204. package/src/vite-env.d.ts +0 -1
  205. package/src/widgets/__tests__/action-edge-cases.test.ts +0 -281
  206. package/src/widgets/__tests__/action.test.ts +0 -236
  207. package/src/widgets/__tests__/attachment-widget.test.tsx +0 -85
  208. package/src/widgets/__tests__/attachments-widget.test.tsx +0 -109
  209. package/src/widgets/__tests__/binding.test.ts +0 -76
  210. package/src/widgets/__tests__/button-widget.test.tsx +0 -145
  211. package/src/widgets/__tests__/checkbox-widget.test.tsx +0 -158
  212. package/src/widgets/__tests__/code-widget.test.tsx +0 -64
  213. package/src/widgets/__tests__/computed-widget.test.tsx +0 -62
  214. package/src/widgets/__tests__/condition-edge-cases.test.ts +0 -120
  215. package/src/widgets/__tests__/condition.test.ts +0 -221
  216. package/src/widgets/__tests__/context.test.ts +0 -99
  217. package/src/widgets/__tests__/data-widget.test.tsx +0 -204
  218. package/src/widgets/__tests__/datepicker-widget.test.tsx +0 -66
  219. package/src/widgets/__tests__/datetime-widget.test.tsx +0 -67
  220. package/src/widgets/__tests__/drawer-widget.test.tsx +0 -149
  221. package/src/widgets/__tests__/dynamic-link-widget.test.tsx +0 -52
  222. package/src/widgets/__tests__/edge-cases.test.ts +0 -232
  223. package/src/widgets/__tests__/evaluator.test.ts +0 -107
  224. package/src/widgets/__tests__/functions.test.ts +0 -147
  225. package/src/widgets/__tests__/grid-widget.test.tsx +0 -137
  226. package/src/widgets/__tests__/hooks.test.tsx +0 -249
  227. package/src/widgets/__tests__/icon-widget.test.tsx +0 -129
  228. package/src/widgets/__tests__/input-widget.test.tsx +0 -264
  229. package/src/widgets/__tests__/integration.test.ts +0 -116
  230. package/src/widgets/__tests__/json-widget.test.tsx +0 -70
  231. package/src/widgets/__tests__/link-widget.test.tsx +0 -92
  232. package/src/widgets/__tests__/many-to-many-widget.test.tsx +0 -93
  233. package/src/widgets/__tests__/modal-widget.test.tsx +0 -148
  234. package/src/widgets/__tests__/money-widget.test.tsx +0 -97
  235. package/src/widgets/__tests__/parser.test.ts +0 -171
  236. package/src/widgets/__tests__/reactive-variables.test.ts +0 -383
  237. package/src/widgets/__tests__/renderer.test.tsx +0 -300
  238. package/src/widgets/__tests__/repeat-widget.test.tsx +0 -229
  239. package/src/widgets/__tests__/select-widget.test.tsx +0 -231
  240. package/src/widgets/__tests__/sequence-widget.test.tsx +0 -58
  241. package/src/widgets/__tests__/shell-integration.test.tsx +0 -1343
  242. package/src/widgets/__tests__/split-widget.test.tsx +0 -133
  243. package/src/widgets/__tests__/state-edge-cases.test.ts +0 -118
  244. package/src/widgets/__tests__/state.test.ts +0 -106
  245. package/src/widgets/__tests__/table-data-binding.test.tsx +0 -482
  246. package/src/widgets/__tests__/table-filter-popover.test.tsx +0 -486
  247. package/src/widgets/__tests__/table-search.test.tsx +0 -305
  248. package/src/widgets/__tests__/table-widget.test.tsx +0 -509
  249. package/src/widgets/__tests__/textarea-widget.test.tsx +0 -105
  250. package/src/widgets/__tests__/tracker-validator-edge-cases.test.ts +0 -242
  251. package/src/widgets/__tests__/tracker.test.ts +0 -133
  252. package/src/widgets/__tests__/tree-widget.test.tsx +0 -97
  253. package/src/widgets/__tests__/use-model-source.test.ts +0 -67
  254. package/src/widgets/__tests__/validator.test.ts +0 -208
  255. package/src/widgets/action/dispatcher.ts +0 -334
  256. package/src/widgets/action/index.ts +0 -2
  257. package/src/widgets/binding/index.ts +0 -2
  258. package/src/widgets/binding/resolver.ts +0 -61
  259. package/src/widgets/components/AttachmentWidget.tsx +0 -111
  260. package/src/widgets/components/AttachmentsWidget.tsx +0 -121
  261. package/src/widgets/components/BadgeWidget.tsx +0 -35
  262. package/src/widgets/components/ButtonWidget.tsx +0 -43
  263. package/src/widgets/components/CardWidget.tsx +0 -68
  264. package/src/widgets/components/CheckboxWidget.tsx +0 -39
  265. package/src/widgets/components/CodeWidget.tsx +0 -44
  266. package/src/widgets/components/ColumnWidget.tsx +0 -22
  267. package/src/widgets/components/ComputedWidget.tsx +0 -49
  268. package/src/widgets/components/DataWidget.tsx +0 -189
  269. package/src/widgets/components/DatePickerWidget.tsx +0 -73
  270. package/src/widgets/components/DatetimeWidget.tsx +0 -160
  271. package/src/widgets/components/DividerWidget.tsx +0 -37
  272. package/src/widgets/components/DrawerWidget.tsx +0 -52
  273. package/src/widgets/components/DynamicLinkWidget.tsx +0 -130
  274. package/src/widgets/components/GridWidget.tsx +0 -134
  275. package/src/widgets/components/GroupWidget.tsx +0 -111
  276. package/src/widgets/components/IconWidget.tsx +0 -29
  277. package/src/widgets/components/ImageWidget.tsx +0 -28
  278. package/src/widgets/components/InputWidget.tsx +0 -70
  279. package/src/widgets/components/JsonWidget.tsx +0 -78
  280. package/src/widgets/components/LinkWidget.tsx +0 -99
  281. package/src/widgets/components/ManyToManyWidget.tsx +0 -125
  282. package/src/widgets/components/ModalWidget.tsx +0 -52
  283. package/src/widgets/components/MoneyWidget.tsx +0 -80
  284. package/src/widgets/components/RepeatWidget.tsx +0 -66
  285. package/src/widgets/components/ScrollAreaWidget.tsx +0 -40
  286. package/src/widgets/components/SectionWidget.tsx +0 -78
  287. package/src/widgets/components/SelectWidget.tsx +0 -63
  288. package/src/widgets/components/SequenceWidget.tsx +0 -32
  289. package/src/widgets/components/SpacerWidget.tsx +0 -29
  290. package/src/widgets/components/SplitWidget.tsx +0 -60
  291. package/src/widgets/components/StackWidget.tsx +0 -44
  292. package/src/widgets/components/TableWidget.tsx +0 -366
  293. package/src/widgets/components/TextWidget.tsx +0 -44
  294. package/src/widgets/components/TextareaWidget.tsx +0 -49
  295. package/src/widgets/components/TreeWidget.tsx +0 -109
  296. package/src/widgets/components/index.ts +0 -30
  297. package/src/widgets/components/register.ts +0 -93
  298. package/src/widgets/components/table/CellRenderers.tsx +0 -83
  299. package/src/widgets/components/table/TablePagination.tsx +0 -45
  300. package/src/widgets/components/table/TableToolbar.tsx +0 -285
  301. package/src/widgets/components/table/filter-operators.ts +0 -134
  302. package/src/widgets/components/table/index.ts +0 -11
  303. package/src/widgets/condition/evaluator.ts +0 -57
  304. package/src/widgets/condition/index.ts +0 -1
  305. package/src/widgets/context/builder.ts +0 -99
  306. package/src/widgets/context/index.ts +0 -8
  307. package/src/widgets/context/types.ts +0 -37
  308. package/src/widgets/data/index.ts +0 -5
  309. package/src/widgets/data/useModelQuery.ts +0 -116
  310. package/src/widgets/data/useModelRecord.ts +0 -37
  311. package/src/widgets/expression/evaluator.ts +0 -100
  312. package/src/widgets/expression/functions.ts +0 -131
  313. package/src/widgets/expression/index.ts +0 -13
  314. package/src/widgets/expression/parser.ts +0 -229
  315. package/src/widgets/expression/types.ts +0 -45
  316. package/src/widgets/form/FormContext.ts +0 -29
  317. package/src/widgets/form/FormProvider.tsx +0 -84
  318. package/src/widgets/form/FormWidget.tsx +0 -42
  319. package/src/widgets/form/index.ts +0 -4
  320. package/src/widgets/form/useFormState.ts +0 -127
  321. package/src/widgets/form/useFormSubmit.ts +0 -90
  322. package/src/widgets/form/useFormValidation.ts +0 -62
  323. package/src/widgets/hooks/index.ts +0 -8
  324. package/src/widgets/hooks/useAction.ts +0 -83
  325. package/src/widgets/hooks/useBind.ts +0 -34
  326. package/src/widgets/hooks/useCondition.ts +0 -21
  327. package/src/widgets/hooks/useDataQuery.ts +0 -48
  328. package/src/widgets/hooks/useExpression.ts +0 -14
  329. package/src/widgets/hooks/usePageState.ts +0 -21
  330. package/src/widgets/hooks/useSurfaceContext.ts +0 -11
  331. package/src/widgets/hooks/useWidgetContext.ts +0 -14
  332. package/src/widgets/index.ts +0 -80
  333. package/src/widgets/lib/layout-props.ts +0 -135
  334. package/src/widgets/reactivity/index.ts +0 -11
  335. package/src/widgets/reactivity/tracker.ts +0 -139
  336. package/src/widgets/reactivity/variables.ts +0 -213
  337. package/src/widgets/registry.ts +0 -41
  338. package/src/widgets/renderer/SlotRenderer.tsx +0 -47
  339. package/src/widgets/renderer/WidgetRenderer.tsx +0 -191
  340. package/src/widgets/renderer/index.ts +0 -4
  341. package/src/widgets/shell/WidgetSlotRenderer.tsx +0 -73
  342. package/src/widgets/shell/index.ts +0 -4
  343. package/src/widgets/shell/useActionHandlers.ts +0 -170
  344. package/src/widgets/state/index.ts +0 -2
  345. package/src/widgets/state/store.ts +0 -96
  346. package/src/widgets/types.ts +0 -28
  347. package/src/widgets/validation/index.ts +0 -2
  348. package/src/widgets/validation/validator.ts +0 -140
  349. package/tsconfig.json +0 -27
  350. package/tsconfig.tsbuildinfo +0 -1
  351. package/vite.config.ts +0 -21
  352. package/vitest.config.ts +0 -16
@@ -1,158 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
- import React from 'react';
3
- import { render, screen, fireEvent } from '@testing-library/react';
4
- import { CheckboxWidget } from '../components/CheckboxWidget.js';
5
-
6
- describe('CheckboxWidget', () => {
7
- it('renders label text from props', () => {
8
- render(
9
- <CheckboxWidget
10
- props={{ label: 'Accept terms' }}
11
- bind={{ value: false }}
12
- on={{}}
13
- context={{ record: {}, model: '', mode: 'view' }}
14
- />,
15
- );
16
-
17
- expect(screen.getByText('Accept terms')).toBeInTheDocument();
18
- });
19
-
20
- it('renders label from bind.meta.label as fallback', () => {
21
- render(
22
- <CheckboxWidget
23
- props={{}}
24
- bind={{
25
- value: false,
26
- meta: { type: 'boolean', label: 'Meta Label', required: false, readOnly: false },
27
- }}
28
- on={{}}
29
- context={{ record: {}, model: '', mode: 'view' }}
30
- />,
31
- );
32
-
33
- expect(screen.getByText('Meta Label')).toBeInTheDocument();
34
- });
35
-
36
- it('does not render label when label is empty', () => {
37
- const { container } = render(
38
- <CheckboxWidget
39
- props={{ label: '' }}
40
- bind={{ value: false }}
41
- on={{}}
42
- context={{ record: {}, model: '', mode: 'view' }}
43
- />,
44
- );
45
-
46
- expect(container.querySelector('span')).toBeNull();
47
- });
48
-
49
- it('renders checked state when bind.value is true', () => {
50
- render(
51
- <CheckboxWidget
52
- props={{}}
53
- bind={{ value: true }}
54
- on={{}}
55
- context={{ record: {}, model: '', mode: 'view' }}
56
- />,
57
- );
58
-
59
- const checkbox = screen.getByRole('checkbox');
60
- expect(checkbox).toHaveAttribute('aria-checked', 'true');
61
- });
62
-
63
- it('renders unchecked state when bind.value is false', () => {
64
- render(
65
- <CheckboxWidget
66
- props={{}}
67
- bind={{ value: false }}
68
- on={{}}
69
- context={{ record: {}, model: '', mode: 'view' }}
70
- />,
71
- );
72
-
73
- const checkbox = screen.getByRole('checkbox');
74
- expect(checkbox).toHaveAttribute('aria-checked', 'false');
75
- });
76
-
77
- it('defaults to unchecked when bind.value is undefined', () => {
78
- render(
79
- <CheckboxWidget
80
- props={{}}
81
- bind={{ value: undefined }}
82
- on={{}}
83
- context={{ record: {}, model: '', mode: 'view' }}
84
- />,
85
- );
86
-
87
- const checkbox = screen.getByRole('checkbox');
88
- expect(checkbox).toHaveAttribute('aria-checked', 'false');
89
- });
90
-
91
- it('disables checkbox when props.disabled is true', () => {
92
- render(
93
- <CheckboxWidget
94
- props={{ disabled: true }}
95
- bind={{ value: false }}
96
- on={{}}
97
- context={{ record: {}, model: '', mode: 'view' }}
98
- />,
99
- );
100
-
101
- const checkbox = screen.getByRole('checkbox');
102
- expect(checkbox).toBeDisabled();
103
- expect(checkbox).toHaveAttribute('data-disabled', '');
104
- });
105
-
106
- it('disables checkbox from bind.meta.readOnly as fallback', () => {
107
- render(
108
- <CheckboxWidget
109
- props={{}}
110
- bind={{
111
- value: false,
112
- meta: { type: 'boolean', label: 'Read Only', required: false, readOnly: true },
113
- }}
114
- on={{}}
115
- context={{ record: {}, model: '', mode: 'view' }}
116
- />,
117
- );
118
-
119
- const checkbox = screen.getByRole('checkbox');
120
- expect(checkbox).toBeDisabled();
121
- expect(checkbox).toHaveAttribute('data-disabled', '');
122
- });
123
-
124
- it('calls bind.setValue and on.change when clicked', () => {
125
- const setValue = vi.fn();
126
- const onChange = vi.fn();
127
-
128
- render(
129
- <CheckboxWidget
130
- props={{}}
131
- bind={{ value: false, setValue }}
132
- on={{ change: onChange }}
133
- context={{ record: {}, model: '', mode: 'edit' }}
134
- />,
135
- );
136
-
137
- const checkbox = screen.getByRole('checkbox');
138
- fireEvent.click(checkbox);
139
-
140
- expect(setValue).toHaveBeenCalledWith(true);
141
- expect(onChange).toHaveBeenCalledWith(true);
142
- });
143
-
144
- it('has correct widgetMeta', () => {
145
- expect(CheckboxWidget.widgetMeta).toEqual({
146
- name: 'checkbox',
147
- label: 'Checkbox',
148
- category: 'input',
149
- schema: {
150
- label: { type: 'string' },
151
- disabled: { type: 'boolean', default: false },
152
- },
153
- binding: 'field',
154
- triggers: ['change'],
155
- container: false,
156
- });
157
- });
158
- });
@@ -1,64 +0,0 @@
1
- import { describe, it, expect, vi, afterEach } from 'vitest';
2
- import React from 'react';
3
- import { render, screen, fireEvent, cleanup } from '@testing-library/react';
4
- import { CodeWidget } from '../components/CodeWidget.js';
5
-
6
- const defaultProps = {
7
- props: {},
8
- bind: { value: '' },
9
- on: {},
10
- context: { record: {}, model: '', mode: 'view' as const },
11
- };
12
-
13
- afterEach(() => cleanup());
14
-
15
- describe('CodeWidget', () => {
16
- it('renders a textarea', () => {
17
- const { container } = render(<CodeWidget {...defaultProps} />);
18
- expect(container.querySelector('textarea')).toBeInTheDocument();
19
- });
20
-
21
- it('has monospace font', () => {
22
- const { container } = render(<CodeWidget {...defaultProps} />);
23
- expect(container.querySelector('textarea')?.className).toContain('font-mono');
24
- });
25
-
26
- it('displays label from props', () => {
27
- render(<CodeWidget {...defaultProps} props={{ label: 'Expression' }} />);
28
- expect(screen.getByText('Expression')).toBeInTheDocument();
29
- });
30
-
31
- it('renders current value', () => {
32
- const { container } = render(
33
- <CodeWidget {...defaultProps} bind={{ value: 'return x + 1;' }} />,
34
- );
35
- expect(container.querySelector('textarea')?.value).toBe('return x + 1;');
36
- });
37
-
38
- it('fires on.change when typing', () => {
39
- const onChange = vi.fn();
40
- const { container } = render(<CodeWidget {...defaultProps} on={{ change: onChange }} />);
41
- fireEvent.change(container.querySelector('textarea')!, { target: { value: 'new code' } });
42
- expect(onChange).toHaveBeenCalledWith('new code');
43
- });
44
-
45
- it('sets rows from props', () => {
46
- const { container } = render(<CodeWidget {...defaultProps} props={{ rows: 10 }} />);
47
- expect(container.querySelector('textarea')?.rows).toBe(10);
48
- });
49
-
50
- it('handles disabled state', () => {
51
- const { container } = render(<CodeWidget {...defaultProps} props={{ disabled: true }} />);
52
- expect(container.querySelector('textarea')?.disabled).toBe(true);
53
- });
54
-
55
- it('handles null bind.value gracefully', () => {
56
- const { container } = render(<CodeWidget {...defaultProps} bind={{ value: null }} />);
57
- expect(container.querySelector('textarea')?.value).toBe('');
58
- });
59
-
60
- it('has spellCheck disabled', () => {
61
- const { container } = render(<CodeWidget {...defaultProps} />);
62
- expect(container.querySelector('textarea')?.getAttribute('spellcheck')).toBe('false');
63
- });
64
- });
@@ -1,62 +0,0 @@
1
- import { describe, it, expect, afterEach } from 'vitest';
2
- import React from 'react';
3
- import { render, screen, cleanup } from '@testing-library/react';
4
- import { ComputedWidget } from '../components/ComputedWidget.js';
5
-
6
- const defaultProps = {
7
- props: {},
8
- bind: { value: null },
9
- on: {},
10
- context: { record: {}, model: '', mode: 'view' as const },
11
- };
12
-
13
- afterEach(() => cleanup());
14
-
15
- describe('ComputedWidget', () => {
16
- it('renders dash for null value', () => {
17
- render(<ComputedWidget {...defaultProps} />);
18
- expect(screen.getByTestId('computed-value').textContent).toBe('—');
19
- });
20
-
21
- it('renders string value', () => {
22
- render(<ComputedWidget {...defaultProps} bind={{ value: 'hello' }} />);
23
- expect(screen.getByTestId('computed-value').textContent).toBe('hello');
24
- });
25
-
26
- it('renders number with locale formatting', () => {
27
- render(
28
- <ComputedWidget {...defaultProps} props={{ format: 'number' }} bind={{ value: 1234567 }} />,
29
- );
30
- expect(screen.getByTestId('computed-value').textContent).toContain('1,234,567');
31
- });
32
-
33
- it('renders currency with 2 decimals', () => {
34
- render(
35
- <ComputedWidget {...defaultProps} props={{ format: 'currency' }} bind={{ value: 99.5 }} />,
36
- );
37
- expect(screen.getByTestId('computed-value').textContent).toBe('99.50');
38
- });
39
-
40
- it('displays label from props', () => {
41
- render(<ComputedWidget {...defaultProps} props={{ label: 'Total' }} />);
42
- expect(screen.getByText('Total')).toBeInTheDocument();
43
- });
44
-
45
- it('falls back to bind.meta.label', () => {
46
- render(
47
- <ComputedWidget
48
- {...defaultProps}
49
- bind={{
50
- value: 0,
51
- meta: { type: 'computed', label: 'Outstanding', required: false, readOnly: true },
52
- }}
53
- />,
54
- );
55
- expect(screen.getByText('Outstanding')).toBeInTheDocument();
56
- });
57
-
58
- it('handles undefined value gracefully', () => {
59
- render(<ComputedWidget {...defaultProps} bind={{ value: undefined }} />);
60
- expect(screen.getByTestId('computed-value').textContent).toBe('—');
61
- });
62
- });
@@ -1,120 +0,0 @@
1
- import { describe, test, expect } from 'vitest';
2
- import { evaluateCondition, evaluateConditions } from '../condition/evaluator.js';
3
-
4
- describe('Condition Edge Cases', () => {
5
- test('eq with null value matches null field', () => {
6
- expect(evaluateCondition({ field: 'x', operator: 'eq', value: null }, { x: null })).toBe(true);
7
- });
8
-
9
- test('eq with undefined field matches null (loose)', () => {
10
- expect(evaluateCondition({ field: 'x', operator: 'eq', value: null }, {})).toBe(true);
11
- });
12
-
13
- test('neq null vs undefined is false (loose equality)', () => {
14
- expect(evaluateCondition({ field: 'x', operator: 'neq', value: null }, {})).toBe(false);
15
- });
16
-
17
- test('gt with string numbers coerces', () => {
18
- expect(evaluateCondition({ field: 'x', operator: 'gt', value: '5' }, { x: '10' })).toBe(true);
19
- });
20
-
21
- test('lt with null field (NaN comparison)', () => {
22
- expect(evaluateCondition({ field: 'x', operator: 'lt', value: 5 }, { x: null })).toBe(true);
23
- });
24
-
25
- test('in with empty array always false', () => {
26
- expect(evaluateCondition({ field: 'x', operator: 'in', value: [] }, { x: 'anything' })).toBe(
27
- false,
28
- );
29
- });
30
-
31
- test('notIn with empty array always true', () => {
32
- expect(evaluateCondition({ field: 'x', operator: 'notIn', value: [] }, { x: 'anything' })).toBe(
33
- true,
34
- );
35
- });
36
-
37
- test('empty with 0 is not empty', () => {
38
- expect(evaluateCondition({ field: 'x', operator: 'empty' }, { x: 0 })).toBe(false);
39
- });
40
-
41
- test('empty with false is not empty', () => {
42
- expect(evaluateCondition({ field: 'x', operator: 'empty' }, { x: false })).toBe(false);
43
- });
44
-
45
- test('notEmpty with 0 is true', () => {
46
- expect(evaluateCondition({ field: 'x', operator: 'notEmpty' }, { x: 0 })).toBe(true);
47
- });
48
-
49
- test('deeply nested field resolution', () => {
50
- expect(
51
- evaluateCondition(
52
- { field: '$state.wizard.currentStep', operator: 'eq', value: 3 },
53
- { $state: { wizard: { currentStep: 3 } } },
54
- ),
55
- ).toBe(true);
56
- });
57
-
58
- test('multiple conditions with all passing', () => {
59
- expect(
60
- evaluateConditions(
61
- [
62
- { field: 'a', operator: 'gt', value: 0 },
63
- { field: 'b', operator: 'notEmpty' },
64
- { field: 'c', operator: 'in', value: ['x', 'y'] },
65
- ],
66
- { a: 5, b: 'hello', c: 'x' },
67
- ),
68
- ).toBe(true);
69
- });
70
-
71
- test('multiple conditions short-circuits on first false', () => {
72
- expect(
73
- evaluateConditions(
74
- [
75
- { field: 'a', operator: 'eq', value: 'wrong' },
76
- { field: 'b', operator: 'notEmpty' },
77
- ],
78
- { a: 'right', b: 'hello' },
79
- ),
80
- ).toBe(false);
81
- });
82
-
83
- test('gte with equal values', () => {
84
- expect(evaluateCondition({ field: 'x', operator: 'gte', value: 10 }, { x: 10 })).toBe(true);
85
- });
86
-
87
- test('lte with equal values', () => {
88
- expect(evaluateCondition({ field: 'x', operator: 'lte', value: 10 }, { x: 10 })).toBe(true);
89
- });
90
-
91
- test('in operator with numeric values', () => {
92
- expect(evaluateCondition({ field: 'x', operator: 'in', value: [1, 2, 3] }, { x: 2 })).toBe(
93
- true,
94
- );
95
- });
96
-
97
- test('notIn operator with numeric values', () => {
98
- expect(evaluateCondition({ field: 'x', operator: 'notIn', value: [1, 2, 3] }, { x: 5 })).toBe(
99
- true,
100
- );
101
- });
102
-
103
- test('expression value resolves against context', () => {
104
- expect(
105
- evaluateCondition(
106
- { field: 'total', operator: 'gte', value: '{{min_total}}' },
107
- { total: 100, min_total: 50 },
108
- ),
109
- ).toBe(true);
110
- });
111
-
112
- test('expression value with function call', () => {
113
- expect(
114
- evaluateCondition(
115
- { field: 'count', operator: 'gt', value: '{{count(items)}}' },
116
- { count: 5, items: [1, 2, 3] },
117
- ),
118
- ).toBe(true);
119
- });
120
- });
@@ -1,221 +0,0 @@
1
- import { describe, test, expect } from 'vitest';
2
- import { evaluateCondition, evaluateConditions } from '../condition/evaluator.js';
3
-
4
- describe('Condition Evaluator', () => {
5
- describe('eq operator', () => {
6
- test('matches equal values', () => {
7
- expect(
8
- evaluateCondition({ field: 'status', operator: 'eq', value: 'draft' }, { status: 'draft' }),
9
- ).toBe(true);
10
- });
11
-
12
- test('fails on unequal values', () => {
13
- expect(
14
- evaluateCondition(
15
- { field: 'status', operator: 'eq', value: 'draft' },
16
- { status: 'submitted' },
17
- ),
18
- ).toBe(false);
19
- });
20
-
21
- test('loose equality (number vs string)', () => {
22
- expect(evaluateCondition({ field: 'count', operator: 'eq', value: '5' }, { count: 5 })).toBe(
23
- true,
24
- );
25
- });
26
- });
27
-
28
- describe('neq operator', () => {
29
- test('passes when not equal', () => {
30
- expect(
31
- evaluateCondition(
32
- { field: 'status', operator: 'neq', value: 'draft' },
33
- { status: 'submitted' },
34
- ),
35
- ).toBe(true);
36
- });
37
-
38
- test('fails when equal', () => {
39
- expect(
40
- evaluateCondition(
41
- { field: 'status', operator: 'neq', value: 'draft' },
42
- { status: 'draft' },
43
- ),
44
- ).toBe(false);
45
- });
46
- });
47
-
48
- describe('in operator', () => {
49
- test('passes when value in array', () => {
50
- expect(
51
- evaluateCondition(
52
- { field: 'status', operator: 'in', value: ['draft', 'pending'] },
53
- { status: 'draft' },
54
- ),
55
- ).toBe(true);
56
- });
57
-
58
- test('fails when value not in array', () => {
59
- expect(
60
- evaluateCondition(
61
- { field: 'status', operator: 'in', value: ['draft', 'pending'] },
62
- { status: 'submitted' },
63
- ),
64
- ).toBe(false);
65
- });
66
- });
67
-
68
- describe('notIn operator', () => {
69
- test('passes when value not in array', () => {
70
- expect(
71
- evaluateCondition(
72
- { field: 'status', operator: 'notIn', value: ['draft', 'pending'] },
73
- { status: 'submitted' },
74
- ),
75
- ).toBe(true);
76
- });
77
-
78
- test('fails when value in array', () => {
79
- expect(
80
- evaluateCondition(
81
- { field: 'status', operator: 'notIn', value: ['draft', 'pending'] },
82
- { status: 'draft' },
83
- ),
84
- ).toBe(false);
85
- });
86
- });
87
-
88
- describe('empty operator', () => {
89
- test('passes for null', () => {
90
- expect(evaluateCondition({ field: 'name', operator: 'empty' }, { name: null })).toBe(true);
91
- });
92
-
93
- test('passes for undefined', () => {
94
- expect(evaluateCondition({ field: 'name', operator: 'empty' }, {})).toBe(true);
95
- });
96
-
97
- test('passes for empty string', () => {
98
- expect(evaluateCondition({ field: 'name', operator: 'empty' }, { name: '' })).toBe(true);
99
- });
100
-
101
- test('fails for non-empty value', () => {
102
- expect(evaluateCondition({ field: 'name', operator: 'empty' }, { name: 'test' })).toBe(false);
103
- });
104
- });
105
-
106
- describe('notEmpty operator', () => {
107
- test('passes for non-empty value', () => {
108
- expect(evaluateCondition({ field: 'name', operator: 'notEmpty' }, { name: 'test' })).toBe(
109
- true,
110
- );
111
- });
112
-
113
- test('fails for null', () => {
114
- expect(evaluateCondition({ field: 'name', operator: 'notEmpty' }, { name: null })).toBe(
115
- false,
116
- );
117
- });
118
-
119
- test('fails for empty string', () => {
120
- expect(evaluateCondition({ field: 'name', operator: 'notEmpty' }, { name: '' })).toBe(false);
121
- });
122
- });
123
-
124
- describe('gt/lt/gte/lte operators', () => {
125
- test('gt passes', () => {
126
- expect(
127
- evaluateCondition({ field: 'total', operator: 'gt', value: 100 }, { total: 150 }),
128
- ).toBe(true);
129
- });
130
-
131
- test('gt fails', () => {
132
- expect(evaluateCondition({ field: 'total', operator: 'gt', value: 100 }, { total: 50 })).toBe(
133
- false,
134
- );
135
- });
136
-
137
- test('lt passes', () => {
138
- expect(evaluateCondition({ field: 'total', operator: 'lt', value: 100 }, { total: 50 })).toBe(
139
- true,
140
- );
141
- });
142
-
143
- test('gte passes on equal', () => {
144
- expect(
145
- evaluateCondition({ field: 'total', operator: 'gte', value: 100 }, { total: 100 }),
146
- ).toBe(true);
147
- });
148
-
149
- test('lte passes on equal', () => {
150
- expect(
151
- evaluateCondition({ field: 'total', operator: 'lte', value: 100 }, { total: 100 }),
152
- ).toBe(true);
153
- });
154
- });
155
-
156
- describe('scope references', () => {
157
- test('resolves $state field', () => {
158
- expect(
159
- evaluateCondition(
160
- { field: '$state.step', operator: 'eq', value: 2 },
161
- { $state: { step: 2 } },
162
- ),
163
- ).toBe(true);
164
- });
165
-
166
- test('resolves $parent field', () => {
167
- expect(
168
- evaluateCondition(
169
- { field: '$parent.status', operator: 'eq', value: 'active' },
170
- { $parent: { status: 'active' } },
171
- ),
172
- ).toBe(true);
173
- });
174
- });
175
-
176
- describe('expression values', () => {
177
- test('resolves expression in value field', () => {
178
- expect(
179
- evaluateCondition(
180
- { field: 'total', operator: 'gt', value: '{{$state.threshold}}' },
181
- { total: 150, $state: { threshold: 100 } },
182
- ),
183
- ).toBe(true);
184
- });
185
- });
186
-
187
- describe('evaluateConditions (AND logic)', () => {
188
- test('all conditions pass', () => {
189
- expect(
190
- evaluateConditions(
191
- [
192
- { field: 'status', operator: 'eq', value: 'draft' },
193
- { field: 'total', operator: 'gt', value: 0 },
194
- ],
195
- { status: 'draft', total: 100 },
196
- ),
197
- ).toBe(true);
198
- });
199
-
200
- test('one condition fails', () => {
201
- expect(
202
- evaluateConditions(
203
- [
204
- { field: 'status', operator: 'eq', value: 'draft' },
205
- { field: 'total', operator: 'gt', value: 0 },
206
- ],
207
- { status: 'draft', total: 0 },
208
- ),
209
- ).toBe(false);
210
- });
211
-
212
- test('single condition (not array)', () => {
213
- expect(
214
- evaluateConditions(
215
- { field: 'status', operator: 'eq', value: 'draft' },
216
- { status: 'draft' },
217
- ),
218
- ).toBe(true);
219
- });
220
- });
221
- });