cx 26.0.11 → 26.0.13

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 (366) hide show
  1. package/build/charts/ScatterGraph.d.ts +4 -4
  2. package/build/charts/ScatterGraph.js +2 -2
  3. package/build/data/ArrayElementView.spec.d.ts +1 -0
  4. package/build/data/ArrayElementView.spec.js +81 -0
  5. package/build/data/Binding.spec.d.ts +1 -0
  6. package/build/data/Binding.spec.js +61 -0
  7. package/build/data/Expression.spec.d.ts +1 -0
  8. package/build/data/Expression.spec.js +196 -0
  9. package/build/data/Grouper.spec.d.ts +1 -0
  10. package/build/data/Grouper.spec.js +48 -0
  11. package/build/data/Ref.spec.d.ts +1 -0
  12. package/build/data/Ref.spec.js +72 -0
  13. package/build/data/Selector.d.ts +1 -1
  14. package/build/data/Store.spec.d.ts +1 -0
  15. package/build/data/Store.spec.js +19 -0
  16. package/build/data/StoreRef.spec.d.ts +1 -0
  17. package/build/data/StoreRef.spec.js +22 -0
  18. package/build/data/StringTemplate.spec.d.ts +1 -0
  19. package/build/data/StringTemplate.spec.js +112 -0
  20. package/build/data/StructuredSelector.spec.d.ts +1 -0
  21. package/build/data/StructuredSelector.spec.js +102 -0
  22. package/build/data/View.spec.d.ts +1 -0
  23. package/build/data/View.spec.js +44 -0
  24. package/build/data/ZoomIntoPropertyView.spec.d.ts +1 -0
  25. package/build/data/ZoomIntoPropertyView.spec.js +54 -0
  26. package/build/data/comparer.spec.d.ts +1 -0
  27. package/build/data/comparer.spec.js +50 -0
  28. package/build/data/computable.d.ts +3 -6
  29. package/build/data/computable.spec.d.ts +1 -0
  30. package/build/data/computable.spec.js +56 -0
  31. package/build/data/createAccessorModelProxy.d.ts +5 -3
  32. package/build/data/createAccessorModelProxy.spec.d.ts +1 -0
  33. package/build/data/createAccessorModelProxy.spec.js +30 -0
  34. package/build/data/createStructuredSelector.spec.d.ts +1 -0
  35. package/build/data/createStructuredSelector.spec.js +42 -0
  36. package/build/data/diff/diffs.spec.d.ts +1 -0
  37. package/build/data/diff/diffs.spec.js +45 -0
  38. package/build/data/getAccessor.spec.d.ts +1 -0
  39. package/build/data/getAccessor.spec.js +10 -0
  40. package/build/data/getSelector.spec.d.ts +1 -0
  41. package/build/data/getSelector.spec.js +36 -0
  42. package/build/data/ops/append.spec.d.ts +1 -0
  43. package/build/data/ops/append.spec.js +24 -0
  44. package/build/data/ops/filter.spec.d.ts +1 -0
  45. package/build/data/ops/filter.spec.js +25 -0
  46. package/build/data/ops/findTreeNode.d.ts +1 -1
  47. package/build/data/ops/findTreeNode.js +1 -1
  48. package/build/data/ops/findTreeNode.spec.d.ts +1 -0
  49. package/build/data/ops/findTreeNode.spec.js +20 -0
  50. package/build/data/ops/findTreePath.d.ts +1 -1
  51. package/build/data/ops/merge.spec.d.ts +1 -0
  52. package/build/data/ops/merge.spec.js +23 -0
  53. package/build/data/ops/removeTreeNodes.d.ts +1 -1
  54. package/build/data/ops/removeTreeNodes.js +1 -1
  55. package/build/data/ops/removeTreeNodes.spec.d.ts +1 -0
  56. package/build/data/ops/removeTreeNodes.spec.js +35 -0
  57. package/build/data/ops/updateArray.spec.d.ts +1 -0
  58. package/build/data/ops/updateArray.spec.js +33 -0
  59. package/build/data/ops/updateTree.d.ts +1 -1
  60. package/build/data/ops/updateTree.spec.d.ts +1 -0
  61. package/build/data/ops/updateTree.spec.js +44 -0
  62. package/build/hooks/invokeCallback.spec.d.ts +1 -0
  63. package/build/hooks/invokeCallback.spec.js +44 -0
  64. package/build/hooks/resolveCallback.spec.d.ts +1 -0
  65. package/build/hooks/resolveCallback.spec.js +35 -0
  66. package/build/hooks/store.spec.d.ts +1 -0
  67. package/build/hooks/store.spec.js +48 -0
  68. package/build/hooks/useTrigger.spec.d.ts +1 -0
  69. package/build/hooks/useTrigger.spec.js +59 -0
  70. package/build/jsx-runtime.d.ts +10 -10
  71. package/build/jsx-runtime.js +6 -0
  72. package/build/svg/util/Rect.d.ts +1 -1
  73. package/build/ui/ContentResolver.d.ts +16 -6
  74. package/build/ui/Controller.d.ts +7 -0
  75. package/build/ui/Controller.js +2 -1
  76. package/build/ui/Controller.spec.d.ts +1 -0
  77. package/build/ui/Controller.spec.js +247 -0
  78. package/build/ui/Cx.spec.d.ts +1 -0
  79. package/build/ui/Cx.spec.js +153 -0
  80. package/build/ui/DataProxy.spec.d.ts +1 -0
  81. package/build/ui/DataProxy.spec.js +208 -0
  82. package/build/ui/Instance.d.ts +1 -1
  83. package/build/ui/Instance.js +10 -10
  84. package/build/ui/IsolatedScope.spec.d.ts +1 -0
  85. package/build/ui/IsolatedScope.spec.js +42 -0
  86. package/build/ui/Prop.d.ts +12 -1
  87. package/build/ui/PureContainer.spec.d.ts +1 -0
  88. package/build/ui/PureContainer.spec.js +149 -0
  89. package/build/ui/Repeater.d.ts +3 -3
  90. package/build/ui/Repeater.spec.d.ts +1 -0
  91. package/build/ui/Repeater.spec.js +109 -0
  92. package/build/ui/Rescope.spec.d.ts +1 -0
  93. package/build/ui/Rescope.spec.js +134 -0
  94. package/build/ui/Restate.spec.d.ts +1 -0
  95. package/build/ui/Restate.spec.js +257 -0
  96. package/build/ui/Text.d.ts +14 -2
  97. package/build/ui/Text.js +3 -0
  98. package/build/ui/adapter/ArrayAdapter.js +4 -1
  99. package/build/ui/adapter/ArrayAdapter.spec.d.ts +1 -0
  100. package/build/ui/adapter/ArrayAdapter.spec.js +44 -0
  101. package/build/ui/adapter/TreeAdapter.spec.d.ts +1 -0
  102. package/build/ui/adapter/TreeAdapter.spec.js +71 -0
  103. package/build/ui/app/Url.spec.d.ts +1 -0
  104. package/build/ui/app/Url.spec.js +43 -0
  105. package/build/ui/app/startHotAppLoop.js +1 -1
  106. package/build/ui/createFunctionalComponent.d.ts +14 -1
  107. package/build/ui/createFunctionalComponent.js +7 -4
  108. package/build/ui/createFunctionalComponent.spec.d.ts +1 -0
  109. package/build/ui/createFunctionalComponent.spec.js +272 -0
  110. package/build/ui/expr.d.ts +3 -1
  111. package/build/ui/exprHelpers.d.ts +32 -0
  112. package/build/ui/exprHelpers.js +61 -0
  113. package/build/ui/index.d.ts +1 -0
  114. package/build/ui/index.js +1 -0
  115. package/build/ui/layout/ContentPlaceholder.spec.d.ts +1 -0
  116. package/build/ui/layout/ContentPlaceholder.spec.js +333 -0
  117. package/build/ui/layout/FirstVisibleChildLayout.spec.d.ts +1 -0
  118. package/build/ui/layout/FirstVisibleChildLayout.spec.js +101 -0
  119. package/build/ui/selection/KeySelection.d.ts +0 -8
  120. package/build/ui/selection/Selection.d.ts +9 -3
  121. package/build/util/Console.d.ts +1 -0
  122. package/build/util/Console.js +7 -3
  123. package/build/util/Format.spec.d.ts +1 -0
  124. package/build/util/Format.spec.js +58 -0
  125. package/build/util/TraversalStack.spec.d.ts +1 -0
  126. package/build/util/TraversalStack.spec.js +43 -0
  127. package/build/util/date/upperBoundCheck.spec.d.ts +1 -0
  128. package/build/util/date/upperBoundCheck.spec.js +22 -0
  129. package/build/util/getSearchQueryPredicate.spec.d.ts +1 -0
  130. package/build/util/getSearchQueryPredicate.spec.js +33 -0
  131. package/build/util/isValidIdentifierName.spec.d.ts +1 -0
  132. package/build/util/isValidIdentifierName.spec.js +28 -0
  133. package/build/util/routeAppend.spec.d.ts +1 -0
  134. package/build/util/routeAppend.spec.js +14 -0
  135. package/build/widgets/AccessorBindings.spec.d.ts +1 -0
  136. package/build/widgets/AccessorBindings.spec.js +40 -0
  137. package/build/widgets/Button.d.ts +3 -6
  138. package/build/widgets/Button.js +1 -1
  139. package/build/widgets/DocumentTitle.d.ts +2 -0
  140. package/build/widgets/Heading.d.ts +2 -2
  141. package/build/widgets/HtmlElement.d.ts +33 -8
  142. package/build/widgets/HtmlElement.js +7 -9
  143. package/build/widgets/HtmlElement.spec.d.ts +1 -0
  144. package/build/widgets/HtmlElement.spec.js +38 -0
  145. package/build/widgets/Icon.d.ts +3 -13
  146. package/build/widgets/List.d.ts +4 -0
  147. package/build/widgets/ReactElementWrapper.d.ts +29 -0
  148. package/build/widgets/ReactElementWrapper.js +59 -0
  149. package/build/widgets/drag-drop/DragSource.d.ts +3 -3
  150. package/build/widgets/drag-drop/DragSource.js +2 -3
  151. package/build/widgets/drag-drop/DropZone.d.ts +3 -3
  152. package/build/widgets/drag-drop/DropZone.js +2 -3
  153. package/build/widgets/form/Checkbox.d.ts +2 -0
  154. package/build/widgets/form/ColorField.d.ts +2 -0
  155. package/build/widgets/form/DateTimeField.d.ts +2 -0
  156. package/build/widgets/form/Field.d.ts +0 -2
  157. package/build/widgets/form/LabeledContainer.d.ts +9 -8
  158. package/build/widgets/form/LabeledContainer.js +9 -9
  159. package/build/widgets/form/LookupField.d.ts +57 -9
  160. package/build/widgets/form/MonthField.d.ts +2 -0
  161. package/build/widgets/form/NumberField.d.ts +2 -0
  162. package/build/widgets/form/Radio.d.ts +2 -0
  163. package/build/widgets/form/Select.d.ts +2 -0
  164. package/build/widgets/form/Slider.d.ts +3 -0
  165. package/build/widgets/form/Switch.d.ts +2 -0
  166. package/build/widgets/form/TextField.d.ts +34 -0
  167. package/build/widgets/form/TimeList.d.ts +16 -1
  168. package/build/widgets/form/TimeList.js +34 -62
  169. package/build/widgets/form/UploadButton.d.ts +34 -2
  170. package/build/widgets/form/UploadButton.js +3 -1
  171. package/build/widgets/form/ValidationGroup.spec.d.ts +1 -0
  172. package/build/widgets/form/ValidationGroup.spec.js +62 -0
  173. package/build/widgets/form/Validator.d.ts +33 -2
  174. package/build/widgets/form/Validator.js +3 -0
  175. package/build/widgets/grid/Grid.d.ts +9 -9
  176. package/build/widgets/grid/TreeNode.d.ts +6 -0
  177. package/build/widgets/index.d.ts +1 -0
  178. package/build/widgets/index.js +1 -0
  179. package/build/widgets/nav/MenuItem.d.ts +3 -2
  180. package/build/widgets/nav/Route.spec.d.ts +1 -0
  181. package/build/widgets/nav/Route.spec.js +15 -0
  182. package/build/widgets/nav/Scroller.d.ts +4 -6
  183. package/build/widgets/nav/Scroller.js +6 -3
  184. package/build/widgets/nav/Tab.d.ts +2 -2
  185. package/build/widgets/overlay/ContextMenu.d.ts +3 -3
  186. package/build/widgets/overlay/Overlay.d.ts +2 -1
  187. package/build/widgets/overlay/Overlay.js +1 -1
  188. package/build.js +133 -133
  189. package/dist/data.js +2 -2
  190. package/dist/jsx-runtime.js +6 -1
  191. package/dist/manifest.d.ts +1443 -0
  192. package/dist/manifest.js +852 -804
  193. package/dist/ui.js +91 -5
  194. package/dist/util.js +3 -0
  195. package/dist/widgets.js +520 -161
  196. package/package.json +46 -20
  197. package/src/charts/Chart.ts +108 -108
  198. package/src/charts/ScatterGraph.tsx +6 -6
  199. package/src/data/ArrayElementView.ts +90 -90
  200. package/src/data/AugmentedViewBase.ts +88 -88
  201. package/src/data/Binding.ts +104 -104
  202. package/src/data/ExposedRecordView.ts +95 -95
  203. package/src/data/ExposedValueView.ts +89 -89
  204. package/src/data/Expression.spec.ts +229 -229
  205. package/src/data/Expression.ts +233 -233
  206. package/src/data/Grouper.spec.ts +57 -57
  207. package/src/data/Grouper.ts +158 -158
  208. package/src/data/NestedDataView.ts +43 -43
  209. package/src/data/ReadOnlyDataView.ts +39 -39
  210. package/src/data/Ref.ts +104 -104
  211. package/src/data/Selector.ts +10 -10
  212. package/src/data/Store.ts +52 -52
  213. package/src/data/StoreProxy.ts +19 -19
  214. package/src/data/StoreRef.ts +66 -66
  215. package/src/data/StringTemplate.spec.ts +132 -132
  216. package/src/data/StringTemplate.ts +93 -93
  217. package/src/data/StructuredSelector.spec.ts +113 -113
  218. package/src/data/StructuredSelector.ts +146 -146
  219. package/src/data/SubscribableView.ts +63 -63
  220. package/src/data/ZoomIntoPropertyView.spec.ts +64 -64
  221. package/src/data/ZoomIntoPropertyView.ts +45 -45
  222. package/src/data/computable.spec.ts +87 -62
  223. package/src/data/computable.ts +3 -6
  224. package/src/data/createAccessorModelProxy.spec.tsx +102 -1
  225. package/src/data/createAccessorModelProxy.ts +9 -3
  226. package/src/data/createStructuredSelector.ts +62 -62
  227. package/src/data/getAccessor.spec.ts +11 -11
  228. package/src/data/getAccessor.ts +74 -74
  229. package/src/data/getSelector.spec.ts +43 -43
  230. package/src/data/getSelector.ts +66 -66
  231. package/src/data/ops/filter.spec.ts +35 -35
  232. package/src/data/ops/filter.ts +9 -9
  233. package/src/data/ops/findTreeNode.ts +1 -5
  234. package/src/data/ops/findTreePath.ts +1 -1
  235. package/src/data/ops/merge.ts +13 -13
  236. package/src/data/ops/removeTreeNodes.spec.ts +37 -37
  237. package/src/data/ops/removeTreeNodes.ts +2 -2
  238. package/src/data/ops/updateArray.spec.ts +69 -69
  239. package/src/data/ops/updateArray.ts +31 -31
  240. package/src/data/ops/updateTree.ts +1 -1
  241. package/src/data/test-types.ts +7 -7
  242. package/src/hooks/resolveCallback.spec.tsx +30 -7
  243. package/src/hooks/useTrigger.ts +26 -26
  244. package/src/index.scss +6 -6
  245. package/src/jsx-dev-runtime.ts +4 -4
  246. package/src/jsx-runtime.spec.tsx +402 -0
  247. package/src/jsx-runtime.ts +26 -22
  248. package/src/svg/BoundedObject.ts +101 -101
  249. package/src/svg/util/Rect.ts +105 -105
  250. package/src/ui/CSSHelper.ts +17 -17
  251. package/src/ui/ContentResolver.spec.tsx +172 -19
  252. package/src/ui/ContentResolver.ts +16 -8
  253. package/src/ui/Controller.ts +15 -2
  254. package/src/ui/Culture.ts +159 -159
  255. package/src/ui/DataProxy.ts +55 -55
  256. package/src/ui/FocusManager.ts +171 -171
  257. package/src/ui/Instance.ts +866 -868
  258. package/src/ui/Prop.ts +140 -112
  259. package/src/ui/RenderingContext.ts +99 -99
  260. package/src/ui/Repeater.ts +3 -12
  261. package/src/ui/Rescope.ts +49 -49
  262. package/src/ui/StructuredInstanceDataAccessor.ts +32 -32
  263. package/src/ui/Text.ts +21 -2
  264. package/src/ui/VDOM.ts +34 -34
  265. package/src/ui/adapter/ArrayAdapter.spec.ts +55 -55
  266. package/src/ui/adapter/ArrayAdapter.ts +4 -1
  267. package/src/ui/adapter/TreeAdapter.spec.ts +76 -76
  268. package/src/ui/adapter/TreeAdapter.ts +185 -185
  269. package/src/ui/app/History.ts +133 -133
  270. package/src/ui/app/Url.spec.ts +50 -50
  271. package/src/ui/app/startHotAppLoop.ts +41 -41
  272. package/src/ui/createFunctionalComponent.spec.tsx +53 -0
  273. package/src/ui/createFunctionalComponent.ts +86 -65
  274. package/src/ui/expr.ts +4 -1
  275. package/src/ui/exprHelpers.spec.ts +379 -0
  276. package/src/ui/exprHelpers.ts +78 -0
  277. package/src/ui/index.ts +47 -46
  278. package/src/ui/layout/Content.ts +30 -30
  279. package/src/ui/layout/FirstVisibleChildLayout.spec.tsx +1 -1
  280. package/src/ui/layout/FirstVisibleChildLayout.ts +60 -60
  281. package/src/ui/selection/KeySelection.ts +0 -12
  282. package/src/ui/selection/PropertySelection.ts +87 -87
  283. package/src/ui/selection/Selection.ts +13 -3
  284. package/src/util/Console.ts +13 -11
  285. package/src/util/Format.ts +267 -267
  286. package/src/util/addEventListenerWithOptions.ts +41 -41
  287. package/src/util/browserSupportsPassiveEventHandlers.ts +20 -20
  288. package/src/util/color/rgbToHsl.ts +35 -35
  289. package/src/util/getActiveElement.ts +4 -4
  290. package/src/util/hasKey.ts +18 -18
  291. package/src/util/index.ts +55 -55
  292. package/src/util/innerTextTrim.ts +10 -10
  293. package/src/util/isArray.ts +3 -3
  294. package/src/util/isDataRecord.ts +5 -5
  295. package/src/util/isDefined.ts +3 -3
  296. package/src/util/isString.ts +3 -3
  297. package/src/widgets/AccessorBindings.spec.tsx +26 -0
  298. package/src/widgets/Button.tsx +5 -17
  299. package/src/widgets/DocumentTitle.ts +95 -92
  300. package/src/widgets/Heading.ts +2 -2
  301. package/src/widgets/HtmlElement.spec.helpers.tsx +108 -0
  302. package/src/widgets/HtmlElement.spec.tsx +20 -12
  303. package/src/widgets/HtmlElement.tsx +82 -24
  304. package/src/widgets/Icon.ts +3 -17
  305. package/src/widgets/List.tsx +6 -0
  306. package/src/widgets/ReactElementWrapper.spec.tsx +452 -0
  307. package/src/widgets/ReactElementWrapper.tsx +108 -0
  308. package/src/widgets/Sandbox.ts +103 -103
  309. package/src/widgets/autoFocus.ts +9 -9
  310. package/src/widgets/cx.ts +63 -63
  311. package/src/widgets/drag-drop/DragSource.tsx +3 -4
  312. package/src/widgets/drag-drop/DropZone.tsx +3 -4
  313. package/src/widgets/form/Checkbox.tsx +3 -0
  314. package/src/widgets/form/ColorField.tsx +3 -0
  315. package/src/widgets/form/DateTimeField.tsx +5 -0
  316. package/src/widgets/form/Field.tsx +0 -3
  317. package/src/widgets/form/Label.tsx +1 -0
  318. package/src/widgets/form/LabeledContainer.ts +22 -26
  319. package/src/widgets/form/LookupField.spec.tsx +93 -0
  320. package/src/widgets/form/LookupField.tsx +104 -9
  321. package/src/widgets/form/MonthField.tsx +5 -0
  322. package/src/widgets/form/NumberField.tsx +3 -0
  323. package/src/widgets/form/Radio.tsx +5 -0
  324. package/src/widgets/form/Select.tsx +5 -0
  325. package/src/widgets/form/Slider.tsx +4 -0
  326. package/src/widgets/form/Switch.tsx +3 -0
  327. package/src/widgets/form/TextField.tsx +62 -0
  328. package/src/widgets/form/TimeList.tsx +84 -73
  329. package/src/widgets/form/UploadButton.tsx +53 -2
  330. package/src/widgets/form/Validator.ts +40 -3
  331. package/src/widgets/grid/Grid.tsx +9 -12
  332. package/src/widgets/grid/GridCell.ts +143 -143
  333. package/src/widgets/grid/TreeNode.tsx +9 -0
  334. package/src/widgets/icons/calendar.tsx +17 -17
  335. package/src/widgets/icons/check.tsx +13 -13
  336. package/src/widgets/icons/clear.tsx +15 -15
  337. package/src/widgets/icons/close.tsx +20 -20
  338. package/src/widgets/icons/cx.tsx +38 -38
  339. package/src/widgets/icons/drop-down.tsx +15 -15
  340. package/src/widgets/icons/file.tsx +13 -13
  341. package/src/widgets/icons/folder-open.tsx +15 -15
  342. package/src/widgets/icons/folder.tsx +13 -13
  343. package/src/widgets/icons/forward.tsx +22 -22
  344. package/src/widgets/icons/loading.tsx +24 -24
  345. package/src/widgets/icons/menu.tsx +17 -17
  346. package/src/widgets/icons/pixel-picker.tsx +18 -18
  347. package/src/widgets/icons/search.tsx +13 -13
  348. package/src/widgets/icons/sort-asc.tsx +14 -14
  349. package/src/widgets/icons/square.tsx +18 -18
  350. package/src/widgets/index.ts +1 -0
  351. package/src/widgets/nav/MenuItem.tsx +3 -2
  352. package/src/widgets/nav/Route.ts +142 -142
  353. package/src/widgets/nav/Scroller.tsx +8 -9
  354. package/src/widgets/nav/Tab.ts +2 -2
  355. package/src/widgets/overlay/ContextMenu.ts +42 -42
  356. package/src/widgets/overlay/Dropdown.tsx +762 -762
  357. package/src/widgets/overlay/MsgBox.tsx +141 -141
  358. package/src/widgets/overlay/Overlay.tsx +5 -4
  359. package/src/widgets/overlay/Toast.ts +111 -111
  360. package/src/widgets/overlay/Window.tsx +299 -299
  361. package/src/widgets/overlay/alerts.ts +46 -46
  362. package/src/widgets/overlay/captureMouse.ts +195 -195
  363. package/src/widgets/overlay/createHotPromiseWindowFactory.ts +72 -72
  364. package/src/widgets/overlay/index.d.ts +11 -11
  365. package/src/widgets/overlay/index.ts +11 -11
  366. package/src/widgets/overlay/tooltip-ops.ts +173 -173
@@ -0,0 +1,93 @@
1
+ import { createAccessorModelProxy } from "../../data/createAccessorModelProxy";
2
+ import { LookupField } from "./LookupField";
3
+
4
+ interface User {
5
+ id: number;
6
+ name: string;
7
+ email: string;
8
+ }
9
+
10
+ interface SelectedUser {
11
+ id: number;
12
+ name: string;
13
+ }
14
+
15
+ interface Model {
16
+ users: User[];
17
+ selectedUsers: SelectedUser[];
18
+ selectedUserId: number;
19
+ }
20
+
21
+ describe("LookupField", () => {
22
+ it("infers TOption from AccessorChain<T[]> in options prop", () => {
23
+ const model = createAccessorModelProxy<Model>();
24
+
25
+ // TOption should be inferred as User from model.users (AccessorChain<User[]>)
26
+ let widget = (
27
+ <cx>
28
+ <LookupField
29
+ options={model.users}
30
+ onQuery={(query, instance) => {
31
+ // Should return User[]
32
+ return [] as User[];
33
+ }}
34
+ onCreateVisibleOptionsFilter={(params, instance) => (option) => {
35
+ // option should be typed as User
36
+ const id: number = option.id;
37
+ const name: string = option.name;
38
+ const email: string = option.email;
39
+ return true;
40
+ }}
41
+ />
42
+ </cx>
43
+ );
44
+ });
45
+
46
+ it("infers TRecord from AccessorChain<T[]> in records prop", () => {
47
+ const model = createAccessorModelProxy<Model>();
48
+
49
+ // TRecord should be inferred as SelectedUser from model.selectedUsers
50
+ let widget = (
51
+ <cx>
52
+ <LookupField
53
+ multiple
54
+ records={model.selectedUsers}
55
+ onGetRecordDisplayText={(record, instance) => {
56
+ // record should be typed as SelectedUser
57
+ const id: number = record.id;
58
+ const name: string = record.name;
59
+ return record.name;
60
+ }}
61
+ />
62
+ </cx>
63
+ );
64
+ });
65
+
66
+ it("infers both TOption and TRecord from accessor chains", () => {
67
+ const model = createAccessorModelProxy<Model>();
68
+
69
+ let widget = (
70
+ <cx>
71
+ <LookupField
72
+ multiple
73
+ options={model.users}
74
+ records={model.selectedUsers}
75
+ onQuery={(query) => {
76
+ // Should return User[]
77
+ return [] as User[];
78
+ }}
79
+ onCreateVisibleOptionsFilter={(params) => (option) => {
80
+ // option should be User
81
+ const email: string = option.email;
82
+ return true;
83
+ }}
84
+ onGetRecordDisplayText={(record) => {
85
+ // record should be SelectedUser
86
+ const name: string = record.name;
87
+ return name;
88
+ }}
89
+ />
90
+ </cx>
91
+ );
92
+ });
93
+ });
@@ -40,7 +40,7 @@ import { AccessorChain, isAccessorChain } from "../../data/createAccessorModelPr
40
40
  import type { CxChild, RenderingContext } from "../../ui/RenderingContext";
41
41
  import type { DropdownInstance, Instance } from "../../ui/Instance";
42
42
  import { FieldConfig } from "./Field";
43
- import { Prop, BooleanProp, StringProp, DataRecord } from "../../ui/Prop";
43
+ import { Prop, BooleanProp, StringProp, StructuredProp, DataRecord } from "../../ui/Prop";
44
44
 
45
45
  export interface LookupBinding {
46
46
  local: string;
@@ -48,60 +48,155 @@ export interface LookupBinding {
48
48
  key?: boolean;
49
49
  }
50
50
 
51
- export interface LookupFieldConfig extends FieldConfig {
51
+ export interface LookupFieldConfig<TOption = unknown, TRecord = unknown> extends FieldConfig {
52
+ /** Defaults to `false`. Set to `true` to enable multiple selection. */
52
53
  multiple?: BooleanProp;
54
+
55
+ /** Selected value. Used only if `multiple` is set to `false`. */
53
56
  value?: Prop<number | string>;
57
+
58
+ /** A list of selected ids. Used only if `multiple` is set to `true`. */
54
59
  values?: Prop<(number | string)[]>;
55
- records?: Prop<Record<string, any>[]>;
60
+
61
+ /** A list of selected records. Used only if `multiple` is set to `true`. */
62
+ records?: Prop<TRecord[]>;
63
+
64
+ /** Text associated with the selection. Used only if `multiple` is set to `false`. */
56
65
  text?: StringProp;
66
+
67
+ /** The opposite of `disabled`. */
57
68
  enabled?: BooleanProp;
69
+
70
+ /** Defaults to `false`. Used to make the field read-only. */
71
+ readOnly?: BooleanProp;
72
+
73
+ /** Default text displayed when the field is empty. */
58
74
  placeholder?: StringProp;
59
- options?: Prop<Record<string, any>[]>;
75
+
76
+ /** A list of available options. */
77
+ options?: Prop<TOption[]>;
78
+
79
+ /** Set to `true` to hide the clear button. Default value is `false`. */
60
80
  hideClear?: boolean;
81
+
82
+ /** Set to `false` to hide the clear button. Default value is `true`. */
61
83
  showClear?: boolean;
84
+
85
+ /** Set to `true` to display the clear button even if `required` is set. Default is `false`. */
62
86
  alwaysShowClear?: boolean;
87
+
88
+ /** Base CSS class to be applied to the field. Defaults to `lookupfield`. */
63
89
  baseClass?: string;
90
+
91
+ /** Name or configuration of the icon to be put on the left side of the input. */
92
+ icon?: StringProp | Record<string, any>;
93
+
94
+ /** Additional config to be applied to all items. */
64
95
  itemConfig?: any;
96
+
97
+ /** An array of objects describing the mapping of option data to store data. */
65
98
  bindings?: LookupBinding[];
99
+
100
+ /** A delay in milliseconds between typing stop and query. Default is `150`. */
66
101
  queryDelay?: number;
102
+
103
+ /** Minimal number of characters required before query is made. */
67
104
  minQueryLength?: number;
105
+
106
+ /** Set to `true` to hide the search field. */
68
107
  hideSearchField?: boolean;
108
+
109
+ /** Number of options required to show search field. Defaults to `7`. */
69
110
  minOptionsForSearchField?: number;
111
+
112
+ /** Text to display while data is being loaded. */
70
113
  loadingText?: string;
114
+
115
+ /** Error message displayed if server query throws an exception. */
71
116
  queryErrorText?: string;
117
+
118
+ /** Message to be displayed if no entries match the user query. */
72
119
  noResultsText?: string;
120
+
121
+ /** Name of the field which holds the id of the option. Default is `id`. */
73
122
  optionIdField?: string;
123
+
124
+ /** Name of the field which holds the display text of the option. Default is `text`. */
74
125
  optionTextField?: string;
126
+
127
+ /** Name of the field to store id of selected value in multiple mode. Default is `id`. */
75
128
  valueIdField?: string;
129
+
130
+ /** Name of the field to store display text of selected value. Default is `text`. */
76
131
  valueTextField?: string;
132
+
133
+ /** `onQuery` will be called once to fetch all options; filtering occurs client-side. */
77
134
  fetchAll?: boolean;
135
+
136
+ /** When set with `fetchAll`, fetched options are cached for widget lifetime. */
78
137
  cacheAll?: boolean;
138
+
139
+ /** Close the dropdown after selection. Default is `true`. */
79
140
  closeOnSelect?: boolean;
141
+
142
+ /** Message displayed if the entered search query is too short. */
80
143
  minQueryLengthMessageText?: string;
144
+
145
+ /** Query function called to fetch options. */
81
146
  onQuery?:
82
147
  | string
83
148
  | ((
84
149
  query: string | { query: string; page: number; pageSize: number },
85
150
  instance: Instance,
86
- ) => Record<string, any>[] | Promise<Record<string, any>[]>);
151
+ ) => TOption[] | Promise<TOption[]>);
152
+
153
+ /** Set to `true` to sort dropdown options. */
87
154
  sort?: boolean;
155
+
156
+ /** Additional list options, such as grouping configuration, custom sorting, etc. */
88
157
  listOptions?: Record<string, any>;
158
+
159
+ /** Show dropdown immediately after component mount; useful for cell editing. */
89
160
  autoOpen?: BooleanProp;
161
+
162
+ /** Allow enter key events to propagate; useful for forms or grid cell editors. */
90
163
  submitOnEnterKey?: BooleanProp;
164
+
165
+ /** Allow dropdown enter key events to propagate for form submission. */
91
166
  submitOnDropdownEnterKey?: BooleanProp;
167
+
168
+ /** Number of additional items loaded in `infinite` mode. Default is `100`. */
92
169
  pageSize?: number;
170
+
171
+ /** Set to `true` to enable loading additional options when scroll reaches end. */
93
172
  infinite?: boolean;
173
+
174
+ /** Allow quick selection of all displayed items on `Ctrl + A` key combination. */
94
175
  quickSelectAll?: boolean;
95
- onGetRecordDisplayText?: ((record: Record<string, any>, instance: Instance) => string) | null;
176
+
177
+ /** Parameters that affect filtering. */
178
+ filterParams?: StructuredProp;
179
+
180
+ /** Used in multiple selection lookups to construct display text from multiple fields. */
181
+ onGetRecordDisplayText?: ((record: TRecord, instance: Instance) => string) | null;
182
+
183
+ /** Callback to create a filter function for given filter params. */
96
184
  onCreateVisibleOptionsFilter?:
97
185
  | string
98
- | ((filterParams: unknown, instance: Instance) => (option: Record<string, any>) => boolean);
186
+ | ((filterParams: unknown, instance: Instance) => (option: TOption) => boolean);
99
187
 
100
- /** Additional configuration to be passed to the dropdown. */
188
+ /** Additional configuration to be passed to the dropdown, such as `style`, `positioning`, etc. */
101
189
  dropdownOptions?: Partial<DropdownConfig>;
190
+
191
+ /** Custom validation function. */
192
+ onValidate?:
193
+ | string
194
+ | ((value: number | string, instance: Instance, validationParams: Record<string, unknown>) => unknown);
102
195
  }
103
196
 
104
- export class LookupField<Config extends LookupFieldConfig = LookupFieldConfig> extends Field<Config> {
197
+ export class LookupField<TOption = unknown, TRecord = unknown> extends Field<
198
+ LookupFieldConfig<TOption, TRecord>
199
+ > {
105
200
  declare public baseClass: string;
106
201
  declare public multiple: boolean;
107
202
  declare public hideClear?: boolean;
@@ -122,6 +122,11 @@ export interface MonthFieldConfig extends FieldConfig {
122
122
 
123
123
  /** Optional configuration options for the MonthPicker component rendered within the dropdown. */
124
124
  monthPickerOptions?: Config;
125
+
126
+ /** Custom validation function. */
127
+ onValidate?:
128
+ | string
129
+ | ((value: string | Date, instance: Instance, validationParams: Record<string, unknown>) => unknown);
125
130
  }
126
131
 
127
132
  export class MonthField<Config extends MonthFieldConfig = MonthFieldConfig> extends Field<Config, MonthFieldInstance> {
@@ -57,6 +57,9 @@ export interface NumberFieldConfig extends FieldConfig {
57
57
  inputErrorText?: string;
58
58
  scale?: number;
59
59
  offset?: number;
60
+
61
+ /** Custom validation function. */
62
+ onValidate?: string | ((value: number, instance: Instance, validationParams: Record<string, unknown>) => unknown);
60
63
  }
61
64
 
62
65
  export class NumberField<Config extends NumberFieldConfig = NumberFieldConfig> extends Field<Config> {
@@ -34,6 +34,11 @@ export interface RadioConfig extends FieldConfig {
34
34
 
35
35
  /** Set to `true` to make the radio initially selected. */
36
36
  default?: boolean;
37
+
38
+ /** Custom validation function. */
39
+ onValidate?:
40
+ | string
41
+ | ((value: number | string | boolean, instance: Instance, validationParams: Record<string, unknown>) => unknown);
37
42
  }
38
43
 
39
44
  export class Radio extends Field<RadioConfig> {
@@ -34,6 +34,11 @@ export interface SelectConfig extends FieldConfig {
34
34
  multiple?: boolean;
35
35
  convertValues?: boolean;
36
36
  nullString?: string;
37
+
38
+ /** Custom validation function. */
39
+ onValidate?:
40
+ | string
41
+ | ((value: number | string, instance: Instance, validationParams: Record<string, unknown>) => unknown);
37
42
  }
38
43
 
39
44
  export class Select<Config extends SelectConfig = SelectConfig> extends Field<Config> {
@@ -17,6 +17,7 @@ import {
17
17
  type TooltipConfig,
18
18
  } from "../overlay/tooltip-ops";
19
19
  import { Field, FieldConfig, FieldInstance, getFieldTooltip } from "./Field";
20
+ import type { Instance } from "../../ui/Instance";
20
21
 
21
22
  export interface SliderConfig extends FieldConfig {
22
23
  /** Low value of the slider range. */
@@ -75,6 +76,9 @@ export interface SliderConfig extends FieldConfig {
75
76
 
76
77
  /** Set to `true` to make the slider read-only. */
77
78
  readOnly?: BooleanProp;
79
+
80
+ /** Custom validation function. */
81
+ onValidate?: string | ((value: number, instance: Instance, validationParams: Record<string, unknown>) => unknown);
78
82
  }
79
83
 
80
84
  export class Slider extends Field<SliderConfig, FieldInstance<Slider>> {
@@ -38,6 +38,9 @@ export interface SwitchConfig extends FieldConfig {
38
38
 
39
39
  /** Determines if button should receive focus on mousedown event. Default is `false`. */
40
40
  focusOnMouseDown?: boolean;
41
+
42
+ /** Custom validation function. */
43
+ onValidate?: string | ((value: boolean, instance: Instance, validationParams: Record<string, unknown>) => unknown);
41
44
  }
42
45
 
43
46
  export class Switch extends Field<SwitchConfig> {
@@ -6,30 +6,92 @@ import { BooleanProp, NumberProp, Prop, StringProp } from "../../ui/Prop";
6
6
  import { Instance } from "../../ui/Instance";
7
7
 
8
8
  export interface TextFieldConfig extends FieldConfig {
9
+ /** Textual value of the input field. */
9
10
  value?: Prop<any>;
11
+
12
+ /** Default text displayed when the field is empty. */
10
13
  placeholder?: StringProp;
14
+
15
+ /** Defaults to `false`. Set to `true` to disable the field. */
11
16
  disabled?: BooleanProp;
17
+
18
+ /** The opposite of `disabled`. */
19
+ enabled?: BooleanProp;
20
+
21
+ /** Defaults to `false`. Used to make the field read-only. */
12
22
  readOnly?: BooleanProp;
23
+
24
+ /** Defaults to `false`. Used to make the field required. */
13
25
  required?: BooleanProp;
26
+
27
+ /** Minimal length of the input text. */
14
28
  minLength?: NumberProp;
29
+
30
+ /** Maximal length of the input text. */
15
31
  maxLength?: NumberProp;
32
+
33
+ /** Regular expression used to validate the user's input. */
16
34
  validationRegExp?: Prop<RegExp>;
35
+
36
+ /** Error message displayed upon validation failure. */
17
37
  validationErrorText?: StringProp;
38
+
39
+ /** Error message displayed when input text is too short. */
18
40
  minLengthValidationErrorText?: StringProp;
41
+
42
+ /** Error message displayed when input text is too long. */
19
43
  maxLengthValidationErrorText?: StringProp;
44
+
45
+ /** Event triggering value updates. Possible values are `input` (default), `enter`, or `blur`. Multiple values can be separated by space. */
20
46
  reactOn?: StringProp;
47
+
48
+ /** Input type. Defaults to `text`. Other common value is `password`. */
21
49
  inputType?: StringProp;
50
+
51
+ /** Base CSS class to be applied to the field. Defaults to `textfield`. */
52
+ baseClass?: string;
53
+
54
+ /** Keyboard shortcut used to focus the field. */
22
55
  keyboardShortcut?: StringProp;
56
+
57
+ /** Set to `true` to remove leading and trailing whitespace. Default is `false`. */
23
58
  trim?: BooleanProp;
59
+
60
+ /** Set to `true` to hide the clear button. Default value is `false`. */
24
61
  hideClear?: BooleanProp;
62
+
63
+ /** Set to `false` to hide the clear button. Default value is `true`. */
25
64
  showClear?: BooleanProp;
65
+
66
+ /** Set to `true` to display the clear button even if `required` is set. Default is `false`. */
26
67
  alwaysShowClear?: BooleanProp;
68
+
69
+ /** Name or configuration of the icon to be put on the left side of the input. */
27
70
  icon?: Prop<any>;
71
+
72
+ /** Additional attributes to be passed to the input element. */
28
73
  inputAttrs?: Prop<any>;
74
+
75
+ /** If `trackFocus` is set, this value will be set when the field receives or loses focus. */
76
+ focused?: BooleanProp;
77
+
78
+ /** Callback invoked when the value changes. */
29
79
  onChange?: string | ((value: any, instance: Instance) => void);
80
+
81
+ /** Callback invoked on each input event. */
30
82
  onInput?: string | ((value: any, instance: Instance) => void);
83
+
84
+ /** Callback invoked when the field receives focus. */
31
85
  onFocus?: string | ((e: FocusEvent, instance: Instance) => void);
86
+
87
+ /** Callback invoked when the field loses focus. */
32
88
  onBlur?: string | ((e: FocusEvent, instance: Instance) => void);
89
+
90
+ /** Handler triggered on key down events. Return `false` to prevent default behavior. */
91
+ onKeyDown?: string | ((e: KeyboardEvent, instance: Instance) => boolean | void);
92
+
93
+ /** Custom validation function. */
94
+ onValidate?: string | ((value: string, instance: Instance, validationParams: any) => string | undefined | false);
33
95
  }
34
96
 
35
97
  // Legacy alias for backward compatibility
@@ -1,4 +1,3 @@
1
- /** @jsxImportSource react */
2
1
  import { ContentResolver } from "../../ui/ContentResolver";
3
2
  import { DataProxy } from "../../ui/DataProxy";
4
3
  import { List } from "../List";
@@ -10,85 +9,97 @@ import { Culture } from "../../ui/Culture";
10
9
  import { isString } from "../../util/isString";
11
10
  import { isFunction } from "../../util/isFunction";
12
11
  import { bind } from "../../ui/bind";
13
- import { Widget } from "../../ui/Widget";
14
12
  import type { Instance } from "../../ui/Instance";
15
- import { HtmlElement } from "../HtmlElement";
16
13
 
17
- interface TimeListProps {
14
+ export interface TimeListProps {
15
+ /** Selected time value. Should be a Date object or a valid date string. */
18
16
  value?: unknown;
17
+
18
+ /** Time step in minutes. Default is `15`. */
19
19
  step?: number;
20
+
21
+ /** Time format string. Default is `datetime;HHmm`. */
20
22
  format?: string;
23
+
24
+ /** Function to encode the Date object before storing. */
21
25
  encoding?: (date: Date) => unknown;
26
+
27
+ /** Callback invoked when a time is selected. */
22
28
  onSelect?: string | ((e: React.MouseEvent, instance: Instance, date: Date) => void);
29
+
30
+ /** Additional properties passed to the underlying component. */
23
31
  [key: string]: unknown;
24
32
  }
25
33
 
26
- export const TimeList = createFunctionalComponent(({ value, step, format, encoding, onSelect, ...props }: TimeListProps) => {
27
- return Widget.create({
28
- type: ContentResolver,
29
- params: { step, format, dummy: true },
30
- onResolve: ({ step, format }: { step?: number; format?: string }) => {
31
- let max = 24 * 60;
32
- if (!step) step = 15;
33
- if (step < 1) step = 1;
34
- let times = [];
35
- let today = zeroTime(new Date()).valueOf();
36
- for (let m = 0; m < max; m += step) {
37
- let time = m * 60 * 1000;
38
- times.push({
39
- id: m * 60 * 1000,
40
- text: Format.value(today + time, format || "datetime;HHmm"),
41
- });
42
- }
43
- let stepMs = step * 60 * 1000;
44
- return Widget.create({
45
- type: DataProxy,
46
- data: { $value: value },
47
- immutable: true,
48
- children: Widget.create({
49
- type: DataProxy,
50
- data: {
51
- $selection: {
52
- get: ({ $value }: { $value?: unknown }) => {
53
- if ($value == null) return null;
54
- let selectionDate = new Date($value as any);
55
- let selectionTime = selectionDate.valueOf() - zeroTime(selectionDate).valueOf();
56
- return (Math.round(selectionTime / stepMs) * stepMs) % 86400000;
57
- },
58
- set: (value: unknown, instance: Instance) => {
59
- let { store } = instance;
60
- let $value = store.get("$value");
61
- let copy = $value ? new Date($value as any) : new Date();
62
- let today = zeroTime(new Date()).valueOf();
63
- let date = new Date(today + (value as number));
64
- copy.setHours(date.getHours());
65
- copy.setMinutes(date.getMinutes());
66
- copy.setSeconds(date.getSeconds());
67
- copy.setMilliseconds(0);
68
- let encode = encoding || Culture.getDefaultDateEncoding();
69
- store.set("$value", encode(copy));
70
- },
71
- },
72
- },
73
- children: Widget.create({
74
- type: List,
75
- records: times,
76
- recordAlias: "$time",
77
- selection: {
78
- type: KeySelection,
79
- selection: { bind: "$selection" },
80
- },
81
- ...props,
82
- onItemClick: (e: React.MouseEvent, instance: Instance) => {
83
- if (!onSelect) return;
84
- let date = new Date(instance.store.get('$value') as any);
85
- if (isString(onSelect)) instance.invokeControllerMethod(onSelect, e, instance, date);
86
- else if (isFunction(onSelect)) onSelect(e, instance, date);
87
- },
88
- children: HtmlElement.create("div", { text: bind("$time.text") }),
89
- }),
90
- }),
91
- });
92
- },
93
- });
94
- });
34
+ export const TimeList = createFunctionalComponent(
35
+ ({ value, step, format, encoding, onSelect, ...props }: TimeListProps) => (
36
+ <cx>
37
+ <ContentResolver
38
+ params={{ step, format, dummy: true }}
39
+ onResolve={({ step, format }: { step?: number; format?: string }) => {
40
+ let max = 24 * 60;
41
+ if (!step) step = 15;
42
+ if (step < 1) step = 1;
43
+ let times = [];
44
+ let today = zeroTime(new Date()).valueOf();
45
+ for (let m = 0; m < max; m += step) {
46
+ let time = m * 60 * 1000;
47
+ times.push({
48
+ id: m * 60 * 1000,
49
+ text: Format.value(today + time, format || "datetime;HHmm"),
50
+ });
51
+ }
52
+ let stepMs = step * 60 * 1000;
53
+ return (
54
+ <cx>
55
+ <DataProxy data={{ $value: value }} immutable>
56
+ <DataProxy
57
+ data={{
58
+ $selection: {
59
+ get: ({ $value }: { $value?: unknown }) => {
60
+ if ($value == null) return null;
61
+ let selectionDate = new Date($value as any);
62
+ let selectionTime =
63
+ selectionDate.valueOf() - zeroTime(selectionDate).valueOf();
64
+ return (Math.round(selectionTime / stepMs) * stepMs) % 86400000;
65
+ },
66
+ set: (value: unknown, instance: Instance) => {
67
+ let { store } = instance;
68
+ let $value = store.get("$value");
69
+ let copy = $value ? new Date($value as any) : new Date();
70
+ let today = zeroTime(new Date()).valueOf();
71
+ let date = new Date(today + (value as number));
72
+ copy.setHours(date.getHours());
73
+ copy.setMinutes(date.getMinutes());
74
+ copy.setSeconds(date.getSeconds());
75
+ copy.setMilliseconds(0);
76
+ let encode = encoding || Culture.getDefaultDateEncoding();
77
+ store.set("$value", encode(copy));
78
+ },
79
+ },
80
+ }}
81
+ >
82
+ <List
83
+ records={times}
84
+ recordAlias="$time"
85
+ selection={{ type: KeySelection, selection: bind("$selection") }}
86
+ {...props}
87
+ onItemClick={(e, instance) => {
88
+ if (!onSelect) return;
89
+ let date = new Date(instance.store.get("$value") as any);
90
+ if (isString(onSelect))
91
+ instance.invokeControllerMethod(onSelect, e, instance, date);
92
+ else if (isFunction(onSelect)) onSelect(e, instance, date);
93
+ }}
94
+ >
95
+ <div text={bind("$time.text")} />
96
+ </List>
97
+ </DataProxy>
98
+ </DataProxy>
99
+ </cx>
100
+ );
101
+ }}
102
+ />
103
+ </cx>
104
+ ),
105
+ );