cx 26.2.2 → 26.2.3

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 (324) hide show
  1. package/build/charts/Chart.d.ts.map +1 -1
  2. package/build/charts/Chart.js +5 -4
  3. package/build/charts/ColumnBarBase.d.ts +3 -3
  4. package/build/charts/ColumnBarBase.d.ts.map +1 -1
  5. package/build/charts/ColumnBarBase.js +1 -1
  6. package/build/charts/Legend.d.ts.map +1 -1
  7. package/build/charts/Legend.js +11 -4
  8. package/build/charts/Marker.d.ts +3 -3
  9. package/build/charts/Marker.d.ts.map +1 -1
  10. package/build/charts/MarkerLine.d.ts +7 -7
  11. package/build/charts/MarkerLine.d.ts.map +1 -1
  12. package/build/charts/MarkerLine.js +14 -10
  13. package/build/charts/PieChart.d.ts +4 -4
  14. package/build/charts/PieChart.d.ts.map +1 -1
  15. package/build/charts/PieChart.js +36 -14
  16. package/build/charts/PieLabel.d.ts.map +1 -1
  17. package/build/charts/PieLabel.js +2 -1
  18. package/build/charts/RangeMarker.d.ts +3 -3
  19. package/build/charts/RangeMarker.d.ts.map +1 -1
  20. package/build/charts/RangeMarker.js +1 -1
  21. package/build/charts/axis/TimeAxis.d.ts +3 -3
  22. package/build/charts/axis/TimeAxis.d.ts.map +1 -1
  23. package/build/charts/axis/TimeAxis.js +70 -21
  24. package/build/charts/helpers/ValueAtFinder.d.ts +1 -1
  25. package/build/charts/helpers/ValueAtFinder.d.ts.map +1 -1
  26. package/build/charts/helpers/ValueAtFinder.js +5 -2
  27. package/build/data/StructuredSelector.js +3 -4
  28. package/build/data/createAccessorModelProxy.d.ts +6 -11
  29. package/build/data/createAccessorModelProxy.d.ts.map +1 -1
  30. package/build/data/createAccessorModelProxy.js +1 -3
  31. package/build/svg/Ellipse.d.ts +5 -4
  32. package/build/svg/Ellipse.d.ts.map +1 -1
  33. package/build/svg/Ellipse.js +9 -6
  34. package/build/svg/Line.d.ts +1 -0
  35. package/build/svg/Line.d.ts.map +1 -1
  36. package/build/svg/Line.js +4 -1
  37. package/build/svg/Text.d.ts +12 -6
  38. package/build/svg/Text.d.ts.map +1 -1
  39. package/build/svg/Text.js +12 -4
  40. package/build/ui/Controller.d.ts +2 -0
  41. package/build/ui/Controller.d.ts.map +1 -1
  42. package/build/ui/Controller.js +3 -0
  43. package/build/ui/HoverSync.d.ts.map +1 -1
  44. package/build/ui/HoverSync.js +7 -2
  45. package/build/ui/Prop.d.ts +1 -1
  46. package/build/ui/Prop.d.ts.map +1 -1
  47. package/build/ui/Text.d.ts +3 -3
  48. package/build/ui/Text.d.ts.map +1 -1
  49. package/build/ui/Text.js +5 -5
  50. package/build/ui/adapter/GroupAdapter.d.ts.map +1 -1
  51. package/build/ui/adapter/GroupAdapter.js +20 -10
  52. package/build/ui/app/History.js +1 -1
  53. package/build/widgets/List.d.ts.map +1 -1
  54. package/build/widgets/List.js +6 -7
  55. package/build/widgets/drag-drop/DropZone.d.ts +3 -3
  56. package/build/widgets/drag-drop/DropZone.d.ts.map +1 -1
  57. package/build/widgets/form/Calendar.d.ts.map +1 -1
  58. package/build/widgets/form/Calendar.js +30 -11
  59. package/build/widgets/form/ColorField.d.ts.map +1 -1
  60. package/build/widgets/form/ColorField.js +16 -7
  61. package/build/widgets/form/DateTimeField.d.ts.map +1 -1
  62. package/build/widgets/form/DateTimeField.js +23 -10
  63. package/build/widgets/form/Field.d.ts +2 -0
  64. package/build/widgets/form/Field.d.ts.map +1 -1
  65. package/build/widgets/form/Field.js +11 -5
  66. package/build/widgets/form/LookupField.d.ts +1 -1
  67. package/build/widgets/form/LookupField.d.ts.map +1 -1
  68. package/build/widgets/form/LookupField.js +6 -6
  69. package/build/widgets/form/MonthField.d.ts.map +1 -1
  70. package/build/widgets/form/MonthField.js +15 -7
  71. package/build/widgets/form/MonthPicker.d.ts +1 -2
  72. package/build/widgets/form/MonthPicker.d.ts.map +1 -1
  73. package/build/widgets/form/MonthPicker.js +84 -41
  74. package/build/widgets/form/NumberField.d.ts +2 -0
  75. package/build/widgets/form/NumberField.d.ts.map +1 -1
  76. package/build/widgets/form/NumberField.js +45 -15
  77. package/build/widgets/form/TextField.d.ts +1 -9
  78. package/build/widgets/form/TextField.d.ts.map +1 -1
  79. package/build/widgets/form/TextField.js +1 -1
  80. package/build/widgets/grid/Grid.d.ts +2 -2
  81. package/build/widgets/grid/Grid.d.ts.map +1 -1
  82. package/build/widgets/grid/Grid.js +14 -11
  83. package/build/widgets/grid/Pagination.d.ts.map +1 -1
  84. package/build/widgets/grid/Pagination.js +4 -4
  85. package/build/widgets/grid/TreeNode.d.ts.map +1 -1
  86. package/build/widgets/grid/TreeNode.js +10 -2
  87. package/build/widgets/icons/folder.d.ts.map +1 -1
  88. package/build/widgets/icons/folder.js +1 -0
  89. package/build/widgets/icons/forward.d.ts.map +1 -1
  90. package/build/widgets/icons/forward.js +4 -3
  91. package/build/widgets/icons/loading.d.ts.map +1 -1
  92. package/build/widgets/icons/loading.js +6 -5
  93. package/build/widgets/icons/square.d.ts.map +1 -1
  94. package/build/widgets/icons/square.js +3 -3
  95. package/build/widgets/index.d.ts +3 -1
  96. package/build/widgets/index.d.ts.map +1 -1
  97. package/build/widgets/index.js +3 -1
  98. package/build/widgets/overlay/ContextMenu.d.ts.map +1 -1
  99. package/build/widgets/overlay/ContextMenu.js +2 -0
  100. package/build/widgets/overlay/Dropdown.d.ts +2 -1
  101. package/build/widgets/overlay/Dropdown.d.ts.map +1 -1
  102. package/build/widgets/overlay/Dropdown.js +75 -20
  103. package/build/widgets/overlay/MsgBox.d.ts +1 -0
  104. package/build/widgets/overlay/MsgBox.d.ts.map +1 -1
  105. package/build/widgets/overlay/MsgBox.js +2 -2
  106. package/build/widgets/overlay/Overlay.d.ts +32 -2
  107. package/build/widgets/overlay/Overlay.d.ts.map +1 -1
  108. package/build/widgets/overlay/Overlay.js +47 -16
  109. package/build/widgets/overlay/Toast.d.ts +1 -1
  110. package/build/widgets/overlay/Toast.d.ts.map +1 -1
  111. package/build/widgets/overlay/Toast.js +4 -1
  112. package/build/widgets/overlay/Tooltip.d.ts +6 -0
  113. package/build/widgets/overlay/Tooltip.d.ts.map +1 -1
  114. package/build/widgets/overlay/Tooltip.js +24 -9
  115. package/build/widgets/overlay/Window.d.ts.map +1 -1
  116. package/build/widgets/overlay/Window.js +24 -9
  117. package/dist/charts.css +325 -272
  118. package/dist/charts.js +11 -5
  119. package/dist/data.js +2 -2
  120. package/dist/manifest.js +821 -809
  121. package/dist/svg.css +14 -8
  122. package/dist/svg.js +9 -1
  123. package/dist/ui.js +29 -16
  124. package/dist/widgets.css +997 -294
  125. package/dist/widgets.js +319 -126
  126. package/package.json +1 -1
  127. package/src/charts/Bar.scss +13 -10
  128. package/src/charts/BarGraph.scss +31 -29
  129. package/src/charts/BubbleGraph.scss +11 -8
  130. package/src/charts/Chart.ts +5 -3
  131. package/src/charts/Column.scss +13 -10
  132. package/src/charts/ColumnBarBase.tsx +255 -230
  133. package/src/charts/ColumnGraph.scss +13 -11
  134. package/src/charts/Gridlines.scss +10 -8
  135. package/src/charts/Legend.scss +57 -50
  136. package/src/charts/Legend.tsx +257 -213
  137. package/src/charts/LegendEntry.scss +35 -29
  138. package/src/charts/LineGraph.scss +28 -25
  139. package/src/charts/Marker.scss +12 -10
  140. package/src/charts/Marker.tsx +3 -2
  141. package/src/charts/MarkerLine.scss +11 -8
  142. package/src/charts/MarkerLine.tsx +196 -177
  143. package/src/charts/PieChart.scss +12 -9
  144. package/src/charts/PieChart.tsx +717 -591
  145. package/src/charts/PieLabel.tsx +99 -81
  146. package/src/charts/Range.scss +11 -8
  147. package/src/charts/RangeMarker.tsx +204 -187
  148. package/src/charts/ScatterGraph.scss +12 -9
  149. package/src/charts/axis/Axis.scss +6 -5
  150. package/src/charts/axis/CategoryAxis.scss +10 -8
  151. package/src/charts/axis/NumericAxis.scss +9 -6
  152. package/src/charts/axis/TimeAxis.scss +9 -6
  153. package/src/charts/axis/TimeAxis.tsx +753 -637
  154. package/src/charts/axis/index.scss +4 -5
  155. package/src/charts/axis/variables.scss +4 -2
  156. package/src/charts/helpers/ValueAtFinder.ts +19 -5
  157. package/src/charts/index.scss +16 -19
  158. package/src/charts/maps.scss +0 -0
  159. package/src/charts/palette.scss +11 -31
  160. package/src/charts/palette.variables.scss +23 -0
  161. package/src/charts/variables.scss +35 -3
  162. package/src/data/StructuredSelector.ts +2 -2
  163. package/src/data/createAccessorModelProxy.ts +66 -74
  164. package/src/index.scss +5 -6
  165. package/src/maps.scss +5 -0
  166. package/src/svg/Ellipse.tsx +62 -55
  167. package/src/svg/Line.tsx +57 -42
  168. package/src/svg/Svg.scss +6 -6
  169. package/src/svg/Text.scss +19 -0
  170. package/src/svg/Text.tsx +172 -116
  171. package/src/svg/index.scss +3 -2
  172. package/src/svg/maps.scss +0 -0
  173. package/src/svg/variables.scss +0 -0
  174. package/src/ui/Container.spec.ts +59 -0
  175. package/src/ui/Controller.spec.tsx +30 -0
  176. package/src/ui/Controller.ts +5 -0
  177. package/src/ui/HoverSync.tsx +179 -147
  178. package/src/ui/Prop.ts +1 -1
  179. package/src/ui/Text.ts +12 -9
  180. package/src/ui/adapter/GroupAdapter.spec.ts +42 -0
  181. package/src/ui/adapter/GroupAdapter.ts +25 -14
  182. package/src/ui/app/History.ts +1 -1
  183. package/src/ui/index.scss +1 -1
  184. package/src/ui/layout/LabelsLeftLayout.scss +5 -7
  185. package/src/ui/layout/LabelsTopLayout.scss +4 -6
  186. package/src/ui/layout/index.scss +2 -3
  187. package/src/ui/maps.scss +0 -0
  188. package/src/ui/variables.scss +1 -2
  189. package/src/util/index.scss +4 -2
  190. package/src/util/maps.scss +1 -0
  191. package/src/util/scss/besm.scss +15 -0
  192. package/src/util/scss/calc.scss +103 -11
  193. package/src/util/scss/defaults.scss +24 -0
  194. package/src/util/scss/elements.scss +78 -0
  195. package/src/util/scss/global.scss +15 -0
  196. package/src/util/scss/include.scss +17 -9
  197. package/src/util/scss/index.scss +1 -9
  198. package/src/util/scss/maps.scss +2 -0
  199. package/src/util/scss/pad-size.scss +9 -0
  200. package/src/util/scss/padding.scss +6 -0
  201. package/src/util/scss/screen-size.scss +5 -0
  202. package/src/util/scss/variables.scss +6 -0
  203. package/src/util/variables.scss +1 -0
  204. package/src/variables.scss +5 -217
  205. package/src/widgets/Button.maps.scss +103 -0
  206. package/src/widgets/Button.scss +33 -9
  207. package/src/widgets/Button.variables.scss +8 -104
  208. package/src/widgets/CxCredit.scss +2 -0
  209. package/src/widgets/FlexBox.scss +16 -11
  210. package/src/widgets/Heading.scss +6 -0
  211. package/src/widgets/HighlightedSearchText.scss +8 -1
  212. package/src/widgets/Icon.scss +6 -0
  213. package/src/widgets/List.scss +7 -0
  214. package/src/widgets/List.tsx +6 -7
  215. package/src/widgets/ProgressBar.scss +9 -0
  216. package/src/widgets/Resizer.scss +9 -7
  217. package/src/widgets/Section.scss +53 -56
  218. package/src/widgets/animations.scss +4 -2
  219. package/src/widgets/box.scss +47 -0
  220. package/src/widgets/drag-drop/DragClone.scss +12 -4
  221. package/src/widgets/drag-drop/DragHandle.scss +12 -6
  222. package/src/widgets/drag-drop/DragSource.scss +12 -6
  223. package/src/widgets/drag-drop/DropZone.scss +9 -0
  224. package/src/widgets/drag-drop/DropZone.tsx +3 -3
  225. package/src/widgets/drag-drop/index.scss +4 -4
  226. package/src/widgets/drag-drop/maps.scss +7 -0
  227. package/src/widgets/drag-drop/variables.scss +8 -5
  228. package/src/widgets/form/Calendar.maps.scss +54 -0
  229. package/src/widgets/form/Calendar.scss +49 -11
  230. package/src/widgets/form/Calendar.tsx +755 -653
  231. package/src/widgets/form/Calendar.variables.scss +3 -46
  232. package/src/widgets/form/Checkbox.maps.scss +34 -0
  233. package/src/widgets/form/Checkbox.scss +14 -3
  234. package/src/widgets/form/Checkbox.variables.scss +4 -36
  235. package/src/widgets/form/ColorField.scss +21 -2
  236. package/src/widgets/form/ColorField.tsx +485 -431
  237. package/src/widgets/form/ColorPicker.maps.scss +21 -0
  238. package/src/widgets/form/ColorPicker.scss +26 -9
  239. package/src/widgets/form/ColorPicker.variables.scss +3 -16
  240. package/src/widgets/form/DateTimeField.scss +54 -21
  241. package/src/widgets/form/DateTimeField.tsx +697 -615
  242. package/src/widgets/form/DateTimePicker.scss +14 -4
  243. package/src/widgets/form/Field.maps.scss +122 -0
  244. package/src/widgets/form/Field.scss +54 -18
  245. package/src/widgets/form/Field.tsx +611 -504
  246. package/src/widgets/form/Field.variables.scss +46 -0
  247. package/src/widgets/form/HelpText.scss +8 -5
  248. package/src/widgets/form/Label.scss +10 -3
  249. package/src/widgets/form/LookupField.maps.scss +26 -0
  250. package/src/widgets/form/LookupField.scss +54 -24
  251. package/src/widgets/form/LookupField.tsx +25 -21
  252. package/src/widgets/form/MonthField.scss +48 -26
  253. package/src/widgets/form/MonthField.tsx +645 -567
  254. package/src/widgets/form/MonthPicker.maps.scss +50 -0
  255. package/src/widgets/form/MonthPicker.scss +44 -35
  256. package/src/widgets/form/MonthPicker.tsx +954 -724
  257. package/src/widgets/form/MonthPicker.variables.scss +24 -0
  258. package/src/widgets/form/NumberField.scss +19 -2
  259. package/src/widgets/form/NumberField.tsx +576 -466
  260. package/src/widgets/form/Radio.maps.scss +36 -0
  261. package/src/widgets/form/Radio.scss +12 -2
  262. package/src/widgets/form/Radio.variables.scss +3 -42
  263. package/src/widgets/form/Select.scss +25 -9
  264. package/src/widgets/form/Slider.scss +23 -14
  265. package/src/widgets/form/Switch.scss +18 -8
  266. package/src/widgets/form/TextArea.scss +14 -1
  267. package/src/widgets/form/TextField.scss +24 -3
  268. package/src/widgets/form/TextField.tsx +9 -21
  269. package/src/widgets/form/UploadButton.scss +14 -6
  270. package/src/widgets/form/ValidationError.scss +10 -6
  271. package/src/widgets/form/Wheel.scss +14 -4
  272. package/src/widgets/form/index.scss +22 -24
  273. package/src/widgets/form/maps.scss +81 -0
  274. package/src/widgets/form/variables.scss +111 -355
  275. package/src/widgets/grid/Grid.scss +19 -2
  276. package/src/widgets/grid/Grid.spec.ts +42 -0
  277. package/src/widgets/grid/Grid.tsx +18 -13
  278. package/src/widgets/grid/Pagination.scss +11 -2
  279. package/src/widgets/grid/Pagination.tsx +110 -102
  280. package/src/widgets/grid/TreeNode.scss +25 -8
  281. package/src/widgets/grid/TreeNode.tsx +127 -116
  282. package/src/widgets/grid/index.scss +3 -4
  283. package/src/widgets/grid/maps.scss +110 -0
  284. package/src/widgets/grid/variables.scss +48 -137
  285. package/src/widgets/icons/folder.tsx +1 -2
  286. package/src/widgets/icons/forward.tsx +23 -20
  287. package/src/widgets/icons/loading.tsx +22 -19
  288. package/src/widgets/icons/square.tsx +20 -17
  289. package/src/widgets/index.scss +16 -16
  290. package/src/widgets/index.ts +63 -58
  291. package/src/widgets/lists.scss +42 -0
  292. package/src/widgets/maps.scss +139 -0
  293. package/src/widgets/nav/Link.scss +14 -1
  294. package/src/widgets/nav/Menu.scss +13 -7
  295. package/src/widgets/nav/Menu.variables.scss +1 -12
  296. package/src/widgets/nav/MenuItem.scss +21 -6
  297. package/src/widgets/nav/Scroller.scss +11 -2
  298. package/src/widgets/nav/Tab.maps.scss +78 -0
  299. package/src/widgets/nav/Tab.scss +12 -6
  300. package/src/widgets/nav/Tab.variables.scss +7 -76
  301. package/src/widgets/nav/cover.scss +6 -4
  302. package/src/widgets/nav/index.scss +6 -6
  303. package/src/widgets/nav/maps.scss +32 -0
  304. package/src/widgets/nav/variables.scss +4 -11
  305. package/src/widgets/overlay/ContextMenu.ts +3 -0
  306. package/src/widgets/overlay/Dropdown.scss +47 -16
  307. package/src/widgets/overlay/Dropdown.tsx +851 -676
  308. package/src/widgets/overlay/MsgBox.tsx +125 -111
  309. package/src/widgets/overlay/Overlay.scss +60 -40
  310. package/src/widgets/overlay/Overlay.tsx +948 -800
  311. package/src/widgets/overlay/Toast.scss +42 -34
  312. package/src/widgets/overlay/Toast.ts +11 -1
  313. package/src/widgets/overlay/Tooltip.scss +27 -96
  314. package/src/widgets/overlay/Tooltip.tsx +376 -309
  315. package/src/widgets/overlay/Window.maps.scss +51 -0
  316. package/src/widgets/overlay/Window.scss +17 -17
  317. package/src/widgets/overlay/Window.tsx +291 -236
  318. package/src/widgets/overlay/Window.variables.scss +2 -43
  319. package/src/widgets/overlay/index.d.ts +11 -11
  320. package/src/widgets/overlay/index.scss +6 -15
  321. package/src/widgets/overlay/maps.scss +44 -0
  322. package/src/widgets/overlay/variables.scss +11 -42
  323. package/src/widgets/variables.scss +33 -117
  324. package/src/global.scss +0 -14
@@ -20,11 +20,11 @@ import ClearIcon from "../icons/clear";
20
20
  import DropdownIcon from "../icons/drop-down";
21
21
  import { Dropdown, DropdownConfig } from "../overlay/Dropdown";
22
22
  import {
23
- tooltipMouseLeave,
24
- tooltipMouseMove,
25
- tooltipParentDidMount,
26
- tooltipParentWillReceiveProps,
27
- tooltipParentWillUnmount,
23
+ tooltipMouseLeave,
24
+ tooltipMouseMove,
25
+ tooltipParentDidMount,
26
+ tooltipParentWillReceiveProps,
27
+ tooltipParentWillUnmount,
28
28
  } from "../overlay/tooltip-ops";
29
29
  import { Calendar } from "./Calendar";
30
30
  import { DateTimePicker } from "./DateTimePicker";
@@ -33,273 +33,311 @@ import { TimeList } from "./TimeList";
33
33
  import { BooleanProp, Config, Prop, StringProp } from "../../ui/Prop";
34
34
 
35
35
  export interface DateTimeFieldConfig extends FieldConfig {
36
- /** Selected date. This should be a Date object or a valid date string consumable by Date.parse function. */
37
- value?: Prop<string | Date>;
36
+ /** Selected date. This should be a Date object or a valid date string consumable by Date.parse function. */
37
+ value?: Prop<string | Date>;
38
38
 
39
- /** Defaults to false. Used to make the field read-only. */
40
- readOnly?: BooleanProp;
39
+ /** Defaults to false. Used to make the field read-only. */
40
+ readOnly?: BooleanProp;
41
41
 
42
- /** The opposite of `disabled`. */
43
- enabled?: BooleanProp;
42
+ /** The opposite of `disabled`. */
43
+ enabled?: BooleanProp;
44
44
 
45
- /** Default text displayed when the field is empty. */
46
- placeholder?: StringProp;
45
+ /** Default text displayed when the field is empty. */
46
+ placeholder?: StringProp;
47
47
 
48
- /** Minimum date value. This should be a Date object or a valid date string consumable by Date.parse function. */
49
- minValue?: Prop<string | Date>;
48
+ /** Minimum date value. This should be a Date object or a valid date string consumable by Date.parse function. */
49
+ minValue?: Prop<string | Date>;
50
50
 
51
- /** Set to `true` to disallow the `minValue`. Default value is `false`. */
52
- minExclusive?: BooleanProp;
51
+ /** Set to `true` to disallow the `minValue`. Default value is `false`. */
52
+ minExclusive?: BooleanProp;
53
53
 
54
- /** Maximum date value. This should be a Date object or a valid date string consumable by Date.parse function. */
55
- maxValue?: Prop<string | Date>;
54
+ /** Maximum date value. This should be a Date object or a valid date string consumable by Date.parse function. */
55
+ maxValue?: Prop<string | Date>;
56
56
 
57
- /** Set to `true` to disallow the `maxValue`. Default value is `false`. */
58
- maxExclusive?: BooleanProp;
57
+ /** Set to `true` to disallow the `maxValue`. Default value is `false`. */
58
+ maxExclusive?: BooleanProp;
59
59
 
60
- /** Date format used to display the selected date. */
61
- format?: StringProp;
60
+ /** Date format used to display the selected date. */
61
+ format?: StringProp;
62
62
 
63
- /** Base CSS class to be applied to the field. Defaults to `datefield`. */
64
- baseClass?: string;
63
+ /** Base CSS class to be applied to the field. Defaults to `datefield`. */
64
+ baseClass?: string;
65
65
 
66
- /** Maximum value error text. */
67
- maxValueErrorText?: string;
66
+ /** Maximum value error text. */
67
+ maxValueErrorText?: string;
68
68
 
69
- /** Maximum exclusive value error text. */
70
- maxExclusiveErrorText?: string;
69
+ /** Maximum exclusive value error text. */
70
+ maxExclusiveErrorText?: string;
71
71
 
72
- /** Minimum value error text. */
73
- minValueErrorText?: string;
72
+ /** Minimum value error text. */
73
+ minValueErrorText?: string;
74
74
 
75
- /** Minimum exclusive value error text. */
76
- minExclusiveErrorText?: string;
75
+ /** Minimum exclusive value error text. */
76
+ minExclusiveErrorText?: string;
77
77
 
78
- /** Error message used to indicate wrong user input. */
79
- inputErrorText?: string;
78
+ /** Error message used to indicate wrong user input. */
79
+ inputErrorText?: string;
80
80
 
81
- /** Name or configuration of the icon to be put on the left side of the input. */
82
- icon?: StringProp | Config;
81
+ /** Name or configuration of the icon to be put on the left side of the input. */
82
+ icon?: StringProp | Config;
83
83
 
84
- /** Set to false to hide the clear button. Default value is true. */
85
- showClear?: boolean;
84
+ /** Set to false to hide the clear button. Default value is true. */
85
+ showClear?: boolean;
86
86
 
87
- /** Set to `true` to display the clear button even if `required` is set. Default is `false`. */
88
- alwaysShowClear?: boolean;
87
+ /** Set to `true` to display the clear button even if `required` is set. Default is `false`. */
88
+ alwaysShowClear?: boolean;
89
89
 
90
- /** Set to true to hide the clear button. Default value is false. */
91
- hideClear?: boolean;
90
+ /** Set to true to hide the clear button. Default value is false. */
91
+ hideClear?: boolean;
92
92
 
93
- /** Determines which segment of date/time is used. Default value is `datetime`. */
94
- segment?: "date" | "time" | "datetime";
93
+ /** Determines which segment of date/time is used. Default value is `datetime`. */
94
+ segment?: "date" | "time" | "datetime";
95
95
 
96
- /** Set to `true` to indicate that only one segment of the selected date is affected. */
97
- partial?: boolean;
96
+ /** Set to `true` to indicate that only one segment of the selected date is affected. */
97
+ partial?: boolean;
98
98
 
99
- /** The function that will be used to convert Date objects before writing data to the store. */
100
- encoding?: (date: Date) => any;
99
+ /** The function that will be used to convert Date objects before writing data to the store. */
100
+ encoding?: (date: Date) => any;
101
101
 
102
- /** Defines which days of week should be displayed as disabled. */
103
- disabledDaysOfWeek?: number[];
102
+ /** Defines which days of week should be displayed as disabled. */
103
+ disabledDaysOfWeek?: number[];
104
104
 
105
- /** Set to true to focus the input field instead of the picker first. */
106
- focusInputFirst?: boolean;
105
+ /** Set to true to focus the input field instead of the picker first. */
106
+ focusInputFirst?: boolean;
107
107
 
108
- /** Set to true to enable seconds segment in the picker. */
109
- showSeconds?: boolean;
108
+ /** Set to true to enable seconds segment in the picker. */
109
+ showSeconds?: boolean;
110
110
 
111
- /** Additional configuration to be passed to the dropdown. */
112
- dropdownOptions?: Partial<DropdownConfig>;
111
+ /** Additional configuration to be passed to the dropdown. */
112
+ dropdownOptions?: Partial<DropdownConfig>;
113
113
 
114
- /** Type of picker to show. Can be `calendar`, `time`, `list`, or `auto`. Default is `auto`. */
115
- picker?: "calendar" | "time" | "list" | "auto";
114
+ /** Type of picker to show. Can be `calendar`, `time`, `list`, or `auto`. Default is `auto`. */
115
+ picker?: "calendar" | "time" | "list" | "auto";
116
116
 
117
- /** Time step in minutes for the time picker. */
118
- step?: number;
117
+ /** Time step in minutes for the time picker. */
118
+ step?: number;
119
119
 
120
- /** Custom validation function. */
121
- onValidate?:
122
- | string
123
- | ((value: string | Date, instance: Instance, validationParams: Record<string, unknown>) => unknown);
120
+ /** Custom validation function. */
121
+ onValidate?:
122
+ | string
123
+ | ((
124
+ value: string | Date,
125
+ instance: Instance,
126
+ validationParams: Record<string, unknown>,
127
+ ) => unknown);
124
128
  }
125
129
 
126
130
  export class DateTimeField extends Field<DateTimeFieldConfig> {
127
- declare public showClear?: boolean;
128
- declare public alwaysShowClear?: boolean;
129
- declare public hideClear?: boolean;
130
- declare public format?: string;
131
- declare public segment?: string;
132
- declare public maxValueErrorText?: string;
133
- declare public maxExclusiveErrorText?: string;
134
- declare public minValueErrorText?: string;
135
- declare public minExclusiveErrorText?: string;
136
- declare public inputErrorText?: string;
137
- declare public disabledDaysOfWeekErrorText?: string;
138
- declare public value?: unknown;
139
- declare public minValue?: unknown;
140
- declare public maxValue?: unknown;
141
- declare public minExclusive?: boolean;
142
- declare public maxExclusive?: boolean;
143
- declare public picker?: string;
144
- declare public partial?: boolean;
145
- declare public encoding?: (date: Date) => string;
146
- declare public disabledDaysOfWeek?: number[] | null;
147
- declare public reactOn?: string;
148
- declare public focusInputFirst?: boolean;
149
- declare public dropdownOptions?: Partial<DropdownConfig>;
150
- declare public onParseInput?: string | ((date: unknown, instance: Instance) => Date | undefined);
151
- declare public showSeconds?: boolean;
152
- declare public step?: number;
153
-
154
- constructor(config?: DateTimeFieldConfig) {
155
- super(config);
156
- }
157
-
158
- declareData(...args: Record<string, unknown>[]): void {
159
- super.declareData(
160
- {
161
- value: this.emptyValue,
162
- disabled: undefined,
163
- readOnly: undefined,
164
- enabled: undefined,
165
- placeholder: undefined,
166
- required: undefined,
167
- minValue: undefined,
168
- minExclusive: undefined,
169
- maxValue: undefined,
170
- maxExclusive: undefined,
171
- format: undefined,
172
- icon: undefined,
173
- autoOpen: undefined,
174
- },
175
- ...args,
176
- );
177
- }
178
-
179
- init(): void {
180
- if (typeof this.hideClear !== "undefined") this.showClear = !this.hideClear;
181
-
182
- if (this.alwaysShowClear) this.showClear = true;
183
-
184
- if (!this.format) {
185
- switch (this.segment) {
186
- case "datetime":
187
- this.format = "datetime;YYYYMMddhhmm";
188
- break;
189
-
190
- case "time":
191
- this.format = "time;hhmm";
192
- break;
193
-
194
- case "date":
195
- this.format = "date;yyyyMMMdd";
196
- break;
197
- }
131
+ declare public showClear?: boolean;
132
+ declare public alwaysShowClear?: boolean;
133
+ declare public hideClear?: boolean;
134
+ declare public format?: string;
135
+ declare public segment?: string;
136
+ declare public maxValueErrorText?: string;
137
+ declare public maxExclusiveErrorText?: string;
138
+ declare public minValueErrorText?: string;
139
+ declare public minExclusiveErrorText?: string;
140
+ declare public inputErrorText?: string;
141
+ declare public disabledDaysOfWeekErrorText?: string;
142
+ declare public value?: unknown;
143
+ declare public minValue?: unknown;
144
+ declare public maxValue?: unknown;
145
+ declare public minExclusive?: boolean;
146
+ declare public maxExclusive?: boolean;
147
+ declare public picker?: string;
148
+ declare public partial?: boolean;
149
+ declare public encoding?: (date: Date) => string;
150
+ declare public disabledDaysOfWeek?: number[] | null;
151
+ declare public reactOn?: string;
152
+ declare public focusInputFirst?: boolean;
153
+ declare public dropdownOptions?: Partial<DropdownConfig>;
154
+ declare public onParseInput?:
155
+ | string
156
+ | ((date: unknown, instance: Instance) => Date | undefined);
157
+ declare public showSeconds?: boolean;
158
+ declare public step?: number;
159
+
160
+ constructor(config?: DateTimeFieldConfig) {
161
+ super(config);
162
+ }
163
+
164
+ declareData(...args: Record<string, unknown>[]): void {
165
+ super.declareData(
166
+ {
167
+ value: this.emptyValue,
168
+ disabled: undefined,
169
+ readOnly: undefined,
170
+ enabled: undefined,
171
+ placeholder: undefined,
172
+ required: undefined,
173
+ minValue: undefined,
174
+ minExclusive: undefined,
175
+ maxValue: undefined,
176
+ maxExclusive: undefined,
177
+ format: undefined,
178
+ icon: undefined,
179
+ autoOpen: undefined,
180
+ },
181
+ ...args,
182
+ );
183
+ }
184
+
185
+ init(): void {
186
+ if (typeof this.hideClear !== "undefined") this.showClear = !this.hideClear;
187
+
188
+ if (this.alwaysShowClear) this.showClear = true;
189
+
190
+ if (!this.format) {
191
+ switch (this.segment) {
192
+ case "datetime":
193
+ this.format = "datetime;YYYYMMddhhmm";
194
+ break;
195
+
196
+ case "time":
197
+ this.format = "time;hhmm";
198
+ break;
199
+
200
+ case "date":
201
+ this.format = "date;yyyyMMMdd";
202
+ break;
203
+ }
204
+ }
205
+ super.init();
206
+ }
207
+
208
+ prepareData(
209
+ context: RenderingContext,
210
+ instance: FieldInstance<DateTimeField>,
211
+ ): void {
212
+ let { data } = instance;
213
+ let dropdownInstance = instance as DropdownInstance;
214
+
215
+ if (data.value) {
216
+ let date = parseDateInvariant(data.value);
217
+ // let date = new Date(data.value);
218
+
219
+ if (isNaN(date.getTime())) data.formatted = String(data.value);
220
+ else {
221
+ // handle utc edge cases
222
+ if (this.segment == "date") date = zeroTime(date);
223
+ data.formatted = Format.value(date, data.format);
198
224
  }
199
- super.init();
200
- }
225
+ data.date = date;
226
+ } else data.formatted = "";
201
227
 
202
- prepareData(context: RenderingContext, instance: FieldInstance<DateTimeField>): void {
203
- let { data } = instance;
204
- let dropdownInstance = instance as DropdownInstance;
228
+ if (data.refDate) data.refDate = zeroTime(parseDateInvariant(data.refDate));
205
229
 
206
- if (data.value) {
207
- let date = parseDateInvariant(data.value);
208
- // let date = new Date(data.value);
230
+ if (data.maxValue) data.maxValue = parseDateInvariant(data.maxValue);
209
231
 
210
- if (isNaN(date.getTime())) data.formatted = String(data.value);
211
- else {
212
- // handle utc edge cases
213
- if (this.segment == "date") date = zeroTime(date);
214
- data.formatted = Format.value(date, data.format);
215
- }
216
- data.date = date;
217
- } else data.formatted = "";
232
+ if (data.minValue) data.minValue = parseDateInvariant(data.minValue);
218
233
 
219
- if (data.refDate) data.refDate = zeroTime(parseDateInvariant(data.refDate));
234
+ if (this.segment == "date") {
235
+ if (data.minValue) data.minValue = zeroTime(data.minValue);
220
236
 
221
- if (data.maxValue) data.maxValue = parseDateInvariant(data.maxValue);
237
+ if (data.maxValue) data.maxValue = zeroTime(data.maxValue);
238
+ }
222
239
 
223
- if (data.minValue) data.minValue = parseDateInvariant(data.minValue);
240
+ dropdownInstance.lastDropdown = context.lastDropdown;
224
241
 
225
- if (this.segment == "date") {
226
- if (data.minValue) data.minValue = zeroTime(data.minValue);
242
+ super.prepareData(context, instance);
243
+ }
227
244
 
228
- if (data.maxValue) data.maxValue = zeroTime(data.maxValue);
229
- }
245
+ validate(
246
+ context: RenderingContext,
247
+ instance: FieldInstance<DateTimeField>,
248
+ ): void {
249
+ super.validate(context, instance);
250
+ let { data, widget } = instance;
251
+ let dateTimeWidget = widget as DateTimeField;
230
252
 
231
- dropdownInstance.lastDropdown = context.lastDropdown;
232
-
233
- super.prepareData(context, instance);
234
- }
235
-
236
- validate(context: RenderingContext, instance: FieldInstance<DateTimeField>): void {
237
- super.validate(context, instance);
238
- let { data, widget } = instance;
239
- let dateTimeWidget = widget as DateTimeField;
240
-
241
- if (!data.error && data.date) {
242
- if (isNaN(data.date)) data.error = this.inputErrorText;
243
- else {
244
- let d;
245
- if (data.maxValue) {
246
- d = dateDiff(data.date, data.maxValue);
247
- if (d > 0) data.error = StringTemplate.format(this.maxValueErrorText!, data.maxValue);
248
- else if (d == 0 && data.maxExclusive)
249
- data.error = StringTemplate.format(this.maxExclusiveErrorText!, data.maxValue);
250
- }
251
- if (data.minValue) {
252
- d = dateDiff(data.date, data.minValue);
253
- if (d < 0) data.error = StringTemplate.format(this.minValueErrorText!, data.minValue);
254
- else if (d == 0 && data.minExclusive)
255
- data.error = StringTemplate.format(this.minExclusiveErrorText!, data.minValue);
256
- }
257
- if (dateTimeWidget.disabledDaysOfWeek) {
258
- if (dateTimeWidget.disabledDaysOfWeek.includes(data.date.getDay()))
259
- data.error = this.disabledDaysOfWeekErrorText;
260
- }
261
- }
262
- }
263
- }
264
-
265
- renderInput(context: RenderingContext, instance: FieldInstance<DateTimeField>, key: string): React.ReactNode {
266
- return (
267
- <DateTimeInput
268
- key={key}
269
- instance={instance}
270
- data={instance.data}
271
- picker={{
272
- value: this.value,
273
- minValue: this.minValue,
274
- maxValue: this.maxValue,
275
- minExclusive: this.minExclusive,
276
- maxExclusive: this.maxExclusive,
277
- maxValueErrorText: this.maxValueErrorText,
278
- maxExclusiveErrorText: this.maxExclusiveErrorText,
279
- minValueErrorText: this.minValueErrorText,
280
- minExclusiveErrorText: this.minExclusiveErrorText,
281
- }}
282
- label={this.labelPlacement && getContent(this.renderLabel(context, instance, "label"))}
283
- help={this.helpPlacement && getContent(this.renderHelp(context, instance, "help"))}
284
- icon={getContent(this.renderIcon(context, instance, "icon"))}
285
- />
286
- );
287
- }
288
-
289
- formatValue(context: RenderingContext, { data }: Instance): React.ReactNode {
290
- return data.value ? data.formatted : null;
291
- }
292
-
293
- parseDate(date: unknown, instance: Instance): Date | null {
294
- if (!date) return null;
295
- if (date instanceof Date) return date;
296
- if (this.onParseInput) {
297
- let result = instance.invoke("onParseInput", date, instance);
298
- if (result !== undefined) return result;
253
+ if (!data.error && data.date) {
254
+ if (isNaN(data.date)) data.error = this.inputErrorText;
255
+ else {
256
+ let d;
257
+ if (data.maxValue) {
258
+ d = dateDiff(data.date, data.maxValue);
259
+ if (d > 0)
260
+ data.error = StringTemplate.format(
261
+ this.maxValueErrorText!,
262
+ data.maxValue,
263
+ );
264
+ else if (d == 0 && data.maxExclusive)
265
+ data.error = StringTemplate.format(
266
+ this.maxExclusiveErrorText!,
267
+ data.maxValue,
268
+ );
269
+ }
270
+ if (data.minValue) {
271
+ d = dateDiff(data.date, data.minValue);
272
+ if (d < 0)
273
+ data.error = StringTemplate.format(
274
+ this.minValueErrorText!,
275
+ data.minValue,
276
+ );
277
+ else if (d == 0 && data.minExclusive)
278
+ data.error = StringTemplate.format(
279
+ this.minExclusiveErrorText!,
280
+ data.minValue,
281
+ );
282
+ }
283
+ if (dateTimeWidget.disabledDaysOfWeek) {
284
+ if (dateTimeWidget.disabledDaysOfWeek.includes(data.date.getDay()))
285
+ data.error = this.disabledDaysOfWeekErrorText;
286
+ }
299
287
  }
300
- date = Culture.getDateTimeCulture().parse(date, { useCurrentDateForDefaults: true }) as Date;
301
- return date as Date | null;
302
- }
288
+ }
289
+ }
290
+
291
+ renderInput(
292
+ context: RenderingContext,
293
+ instance: FieldInstance<DateTimeField>,
294
+ key: string,
295
+ ): React.ReactNode {
296
+ return (
297
+ <DateTimeInput
298
+ key={key}
299
+ instance={instance}
300
+ data={instance.data}
301
+ picker={{
302
+ value: this.value,
303
+ minValue: this.minValue,
304
+ maxValue: this.maxValue,
305
+ minExclusive: this.minExclusive,
306
+ maxExclusive: this.maxExclusive,
307
+ maxValueErrorText: this.maxValueErrorText,
308
+ maxExclusiveErrorText: this.maxExclusiveErrorText,
309
+ minValueErrorText: this.minValueErrorText,
310
+ minExclusiveErrorText: this.minExclusiveErrorText,
311
+ }}
312
+ label={
313
+ this.labelPlacement &&
314
+ getContent(this.renderLabel(context, instance, "label"))
315
+ }
316
+ help={
317
+ this.helpPlacement &&
318
+ getContent(this.renderHelp(context, instance, "help"))
319
+ }
320
+ icon={getContent(this.renderIcon(context, instance, "icon"))}
321
+ />
322
+ );
323
+ }
324
+
325
+ formatValue(context: RenderingContext, { data }: Instance): React.ReactNode {
326
+ return data.value ? data.formatted : null;
327
+ }
328
+
329
+ parseDate(date: unknown, instance: Instance): Date | null {
330
+ if (!date) return null;
331
+ if (date instanceof Date) return date;
332
+ if (this.onParseInput) {
333
+ let result = instance.invoke("onParseInput", date, instance);
334
+ if (result !== undefined) return result;
335
+ }
336
+ date = Culture.getDateTimeCulture().parse(date, {
337
+ useCurrentDateForDefaults: true,
338
+ }) as Date;
339
+ return date as Date | null;
340
+ }
303
341
  }
304
342
 
305
343
  DateTimeField.prototype.baseClass = "datetimefield";
@@ -308,7 +346,8 @@ DateTimeField.prototype.maxExclusiveErrorText = "Select a date before {0:d}.";
308
346
  DateTimeField.prototype.minValueErrorText = "Select {0:d} or later.";
309
347
  DateTimeField.prototype.minExclusiveErrorText = "Select a date after {0:d}.";
310
348
  DateTimeField.prototype.inputErrorText = "Invalid date entered.";
311
- DateTimeField.prototype.disabledDaysOfWeekErrorText = "Selected day of week is not allowed.";
349
+ DateTimeField.prototype.disabledDaysOfWeekErrorText =
350
+ "Selected day of week is not allowed.";
312
351
 
313
352
  DateTimeField.prototype.suppressErrorsUntilVisited = true;
314
353
  DateTimeField.prototype.icon = "calendar";
@@ -324,409 +363,452 @@ Widget.alias("datetimefield", DateTimeField);
324
363
  Localization.registerPrototype("cx/widgets/DateTimeField", DateTimeField);
325
364
 
326
365
  interface DateTimeInputProps {
327
- instance: FieldInstance<DateTimeField>;
328
- data: Record<string, unknown>;
329
- picker: Record<string, unknown>;
330
- label?: React.ReactNode;
331
- help?: React.ReactNode;
332
- icon?: React.ReactNode;
366
+ instance: FieldInstance<DateTimeField>;
367
+ data: Record<string, unknown>;
368
+ picker: Record<string, unknown>;
369
+ label?: React.ReactNode;
370
+ help?: React.ReactNode;
371
+ icon?: React.ReactNode;
333
372
  }
334
373
 
335
374
  interface DateTimeInputState {
336
- dropdownOpen: boolean;
337
- focus: boolean;
338
- dropdownOpenTime?: number;
375
+ dropdownOpen: boolean;
376
+ focus: boolean;
377
+ dropdownOpenTime?: number;
339
378
  }
340
379
 
341
- class DateTimeInput extends VDOM.Component<DateTimeInputProps, DateTimeInputState> {
342
- input!: HTMLInputElement;
343
- dropdown?: Widget;
344
- scrollableParents?: Element[];
345
- openDropdownOnFocus: boolean = false;
346
- updateDropdownPosition: () => void;
347
- scrolling?: boolean;
348
-
349
- constructor(props: DateTimeInputProps) {
350
- super(props);
351
- (props.instance as any).component = this;
352
- this.state = {
353
- dropdownOpen: false,
354
- focus: false,
355
- };
356
- this.updateDropdownPosition = () => {};
357
- }
358
-
359
- getDropdown(): Widget {
360
- if (this.dropdown) return this.dropdown;
361
-
362
- let { widget, lastDropdown } = this.props.instance as DropdownInstance;
363
- let dateTimeWidget = widget as DateTimeField;
364
-
365
- let pickerConfig;
366
-
367
- switch (dateTimeWidget.picker) {
368
- case "calendar":
369
- pickerConfig = {
370
- type: Calendar,
371
- partial: dateTimeWidget.partial,
372
- encoding: dateTimeWidget.encoding,
373
- disabledDaysOfWeek: dateTimeWidget.disabledDaysOfWeek,
374
- focusable: !dateTimeWidget.focusInputFirst,
375
- };
376
- break;
377
-
378
- case "list":
379
- pickerConfig = {
380
- type: TimeList,
381
- style: "height: 300px",
382
- encoding: dateTimeWidget.encoding,
383
- step: dateTimeWidget.step,
384
- format: dateTimeWidget.format,
385
- scrollSelectionIntoView: true,
386
- };
387
- break;
388
-
389
- default:
390
- pickerConfig = {
391
- type: DateTimePicker,
392
- segment: dateTimeWidget.segment,
393
- encoding: dateTimeWidget.encoding,
394
- showSeconds: dateTimeWidget.showSeconds,
395
- };
396
- break;
397
- }
398
-
399
- let dropdown = {
400
- scrollTracking: true,
401
- inline: !isTouchDevice() || !!lastDropdown,
402
- matchWidth: false,
403
- placementOrder: "down down-right down-left up up-right up-left",
404
- touchFriendly: true,
405
- firstChildDefinesHeight: true,
406
- firstChildDefinesWidth: true,
407
- ...dateTimeWidget.dropdownOptions,
408
- type: Dropdown,
409
- relatedElement: this.input,
410
- onFocusOut: (e: unknown) => {
411
- this.closeDropdown(e);
412
- },
413
- onMouseDown: stopPropagation,
414
- items: {
415
- ...pickerConfig,
416
- ...this.props.picker,
417
- autoFocus: !dateTimeWidget.focusInputFirst,
418
- tabIndex: dateTimeWidget.focusInputFirst ? -1 : 0,
419
- onKeyDown: (e: React.KeyboardEvent) => this.onKeyDown(e),
420
- onSelect: (e: React.MouseEvent, calendar: any, date: Date) => {
421
- e.stopPropagation();
422
- e.preventDefault();
423
- let touch = isTouchEvent();
424
- this.closeDropdown(e, () => {
425
- if (date) {
426
- // If a blur event occurs before we re-render the input,
427
- // the old input value is parsed and written to the store.
428
- // We want to prevent that by eagerly updating the input value.
429
- // This can happen if the date field is within a menu.
430
- let newFormattedValue = Format.value(date, this.props.data.format as string);
431
- this.input.value = newFormattedValue;
432
- }
433
- if (!touch) this.input.focus();
434
- });
435
- },
436
- },
437
- };
438
-
439
- return (this.dropdown = Widget.create(dropdown));
440
- }
441
-
442
- render(): React.ReactNode {
443
- let { instance, label, help, icon: iconVDOM } = this.props;
444
- let { data, widget, state } = instance;
445
- let { CSS, baseClass, suppressErrorsUntilVisited, showClear, alwaysShowClear } = widget;
446
-
447
- let insideButton, icon;
448
-
449
- if (!data.readOnly && !data.disabled) {
450
- if (showClear && (((alwaysShowClear || !data.required) && !data.empty) || instance.state?.inputError))
451
- insideButton = (
452
- <div
453
- className={CSS.element(baseClass, "clear")}
454
- onMouseDown={(e) => {
455
- e.preventDefault();
456
- e.stopPropagation();
457
- }}
458
- onClick={(e) => this.onClearClick(e)}
459
- >
460
- <ClearIcon className={CSS.element(baseClass, "icon")} />
461
- </div>
462
- );
463
- else
464
- insideButton = (
465
- <div className={CSS.element(baseClass, "right-icon")}>
466
- <DropdownIcon className={CSS.element(baseClass, "icon")} />
467
- </div>
468
- );
469
- }
470
-
471
- if (iconVDOM) {
472
- icon = <div className={CSS.element(baseClass, "left-icon")}>{iconVDOM}</div>;
473
- }
474
-
475
- let dropdown: React.ReactNode | undefined;
476
- if (this.state.dropdownOpen)
477
- dropdown = (
478
- <Cx
479
- widget={this.getDropdown()}
480
- parentInstance={instance}
481
- options={{ name: "datefield-dropdown" }}
482
- subscribe
483
- />
484
- );
485
-
486
- let empty = this.input ? !this.input.value : data.empty;
487
-
488
- return (
489
- <div
490
- className={CSS.expand(
491
- data.classNames,
492
- CSS.state({
493
- visited: state?.visited,
494
- focus: this.state.focus || this.state.dropdownOpen,
495
- icon: !!icon,
496
- empty: empty && !data.placeholder,
497
- error: data.error && (state?.visited || !suppressErrorsUntilVisited || !empty),
498
- }),
499
- )}
500
- style={data.style as React.CSSProperties}
501
- onMouseDown={this.onMouseDown.bind(this)}
502
- onTouchStart={stopPropagation}
503
- >
504
- <input
505
- id={data.id as string}
506
- ref={(el) => {
507
- this.input = el!;
508
- }}
509
- type="text"
510
- className={CSS.expand(CSS.element(baseClass, "input"), data.inputClass)}
511
- style={data.inputStyle as React.CSSProperties}
512
- defaultValue={data.formatted as string}
513
- disabled={data.disabled as boolean}
514
- readOnly={data.readOnly as boolean}
515
- tabIndex={data.tabIndex as number}
516
- placeholder={data.placeholder as string}
517
- {...(data.inputAttrs as Record<string, any>)}
518
- onInput={(e) => this.onChange((e.target as HTMLInputElement).value, "input")}
519
- onChange={(e) => this.onChange(e.target.value, "change")}
520
- onKeyDown={(e) => this.onKeyDown(e)}
521
- onBlur={(e) => {
522
- this.onBlur(e);
523
- }}
524
- onFocus={(e) => {
525
- this.onFocus(e);
526
- }}
527
- onMouseMove={(e) => tooltipMouseMove(e, ...getFieldTooltip(this.props.instance))}
528
- onMouseLeave={(e) => tooltipMouseLeave(e, ...getFieldTooltip(this.props.instance))}
529
- />
530
- {icon}
531
- {insideButton}
532
- {dropdown}
533
- {label}
534
- {help}
535
- </div>
380
+ class DateTimeInput extends VDOM.Component<
381
+ DateTimeInputProps,
382
+ DateTimeInputState
383
+ > {
384
+ input!: HTMLInputElement;
385
+ dropdown?: Widget;
386
+ scrollableParents?: Element[];
387
+ openDropdownOnFocus: boolean = false;
388
+ updateDropdownPosition: () => void;
389
+ scrolling?: boolean;
390
+
391
+ constructor(props: DateTimeInputProps) {
392
+ super(props);
393
+ (props.instance as any).component = this;
394
+ this.state = {
395
+ dropdownOpen: false,
396
+ focus: false,
397
+ };
398
+ this.updateDropdownPosition = () => {};
399
+ }
400
+
401
+ getDropdown(): Widget {
402
+ if (this.dropdown) return this.dropdown;
403
+
404
+ let { widget, lastDropdown } = this.props.instance as DropdownInstance;
405
+ let dateTimeWidget = widget as DateTimeField;
406
+
407
+ let pickerConfig;
408
+
409
+ switch (dateTimeWidget.picker) {
410
+ case "calendar":
411
+ pickerConfig = {
412
+ type: Calendar,
413
+ partial: dateTimeWidget.partial,
414
+ encoding: dateTimeWidget.encoding,
415
+ disabledDaysOfWeek: dateTimeWidget.disabledDaysOfWeek,
416
+ focusable: !dateTimeWidget.focusInputFirst,
417
+ };
418
+ break;
419
+
420
+ case "list":
421
+ pickerConfig = {
422
+ type: TimeList,
423
+ style: "height: 300px",
424
+ encoding: dateTimeWidget.encoding,
425
+ step: dateTimeWidget.step,
426
+ format: dateTimeWidget.format,
427
+ scrollSelectionIntoView: true,
428
+ };
429
+ break;
430
+
431
+ default:
432
+ pickerConfig = {
433
+ type: DateTimePicker,
434
+ segment: dateTimeWidget.segment,
435
+ encoding: dateTimeWidget.encoding,
436
+ showSeconds: dateTimeWidget.showSeconds,
437
+ };
438
+ break;
439
+ }
440
+
441
+ let dropdown = {
442
+ scrollTracking: true,
443
+ inline: !isTouchDevice() || !!lastDropdown,
444
+ matchWidth: false,
445
+ placementOrder: "down down-right down-left up up-right up-left",
446
+ touchFriendly: true,
447
+ firstChildDefinesHeight: true,
448
+ firstChildDefinesWidth: true,
449
+ ...dateTimeWidget.dropdownOptions,
450
+ type: Dropdown,
451
+ relatedElement: this.input,
452
+ onFocusOut: (e: unknown) => {
453
+ this.closeDropdown(e);
454
+ },
455
+ onMouseDown: stopPropagation,
456
+ items: {
457
+ mod: "dropdown",
458
+ ...pickerConfig,
459
+ ...this.props.picker,
460
+ autoFocus: !dateTimeWidget.focusInputFirst,
461
+ tabIndex: dateTimeWidget.focusInputFirst ? -1 : 0,
462
+ onKeyDown: (e: React.KeyboardEvent) => this.onKeyDown(e),
463
+ onSelect: (e: React.MouseEvent, calendar: any, date: Date) => {
464
+ e.stopPropagation();
465
+ e.preventDefault();
466
+ let touch = isTouchEvent();
467
+ this.closeDropdown(e, () => {
468
+ if (date) {
469
+ // If a blur event occurs before we re-render the input,
470
+ // the old input value is parsed and written to the store.
471
+ // We want to prevent that by eagerly updating the input value.
472
+ // This can happen if the date field is within a menu.
473
+ let newFormattedValue = Format.value(
474
+ date,
475
+ this.props.data.format as string,
476
+ );
477
+ this.input.value = newFormattedValue;
478
+ }
479
+ if (!touch) this.input.focus();
480
+ });
481
+ },
482
+ },
483
+ };
484
+
485
+ return (this.dropdown = Widget.create(dropdown));
486
+ }
487
+
488
+ render(): React.ReactNode {
489
+ let { instance, label, help, icon: iconVDOM } = this.props;
490
+ let { data, widget, state } = instance;
491
+ let {
492
+ CSS,
493
+ baseClass,
494
+ suppressErrorsUntilVisited,
495
+ showClear,
496
+ alwaysShowClear,
497
+ } = widget;
498
+
499
+ let insideButton, icon;
500
+
501
+ if (!data.readOnly && !data.disabled) {
502
+ if (
503
+ showClear &&
504
+ (((alwaysShowClear || !data.required) && !data.empty) ||
505
+ instance.state?.inputError)
506
+ )
507
+ insideButton = (
508
+ <div
509
+ className={CSS.element(baseClass, "clear")}
510
+ onMouseDown={(e) => {
511
+ e.preventDefault();
512
+ e.stopPropagation();
513
+ }}
514
+ onClick={(e) => this.onClearClick(e)}
515
+ >
516
+ <ClearIcon className={CSS.element(baseClass, "icon")} />
517
+ </div>
518
+ );
519
+ else
520
+ insideButton = (
521
+ <div className={CSS.element(baseClass, "right-icon")}>
522
+ <DropdownIcon className={CSS.element(baseClass, "icon")} />
523
+ </div>
524
+ );
525
+ }
526
+
527
+ if (iconVDOM) {
528
+ icon = (
529
+ <div className={CSS.element(baseClass, "left-icon")}>{iconVDOM}</div>
530
+ );
531
+ }
532
+
533
+ let dropdown: React.ReactNode | undefined;
534
+ if (this.state.dropdownOpen)
535
+ dropdown = (
536
+ <Cx
537
+ widget={this.getDropdown()}
538
+ parentInstance={instance}
539
+ options={{ name: "datefield-dropdown" }}
540
+ subscribe
541
+ />
536
542
  );
537
- }
538
-
539
- onMouseDown(e: React.MouseEvent): void {
540
- e.stopPropagation();
541
- let { widget } = this.props.instance;
542
-
543
- if (this.state.dropdownOpen) {
544
- this.closeDropdown(e);
545
- } else {
546
- this.openDropdownOnFocus = true;
547
- }
548
-
549
- //icon click
550
- if (e.target !== this.input) {
551
- e.preventDefault();
552
-
553
- //the field should not focus only in case when dropdown will open and autofocus
554
- if (widget.focusInputFirst || this.state.dropdownOpen) this.input.focus();
555
-
556
- if (this.state.dropdownOpen) this.closeDropdown(e);
557
- else this.openDropdown();
558
- }
559
- }
560
543
 
561
- onFocus(e: React.FocusEvent): void {
562
- let { instance } = this.props;
563
- let { widget } = instance;
544
+ let empty = this.input ? !this.input.value : data.empty;
545
+
546
+ return (
547
+ <div
548
+ className={CSS.expand(
549
+ data.classNames,
550
+ CSS.state({
551
+ visited: state?.visited,
552
+ focus: this.state.focus || this.state.dropdownOpen,
553
+ icon: !!icon,
554
+ empty: empty && !data.placeholder,
555
+ error:
556
+ data.error &&
557
+ (state?.visited || !suppressErrorsUntilVisited || !empty),
558
+ }),
559
+ )}
560
+ style={data.style as React.CSSProperties}
561
+ onMouseDown={this.onMouseDown.bind(this)}
562
+ onTouchStart={stopPropagation}
563
+ >
564
+ <input
565
+ id={data.id as string}
566
+ ref={(el) => {
567
+ this.input = el!;
568
+ }}
569
+ type="text"
570
+ className={CSS.expand(
571
+ CSS.element(baseClass, "input"),
572
+ data.inputClass,
573
+ )}
574
+ style={data.inputStyle as React.CSSProperties}
575
+ defaultValue={data.formatted as string}
576
+ disabled={data.disabled as boolean}
577
+ readOnly={data.readOnly as boolean}
578
+ tabIndex={data.tabIndex as number}
579
+ placeholder={data.placeholder as string}
580
+ {...(data.inputAttrs as Record<string, any>)}
581
+ onInput={(e) =>
582
+ this.onChange((e.target as HTMLInputElement).value, "input")
583
+ }
584
+ onChange={(e) => this.onChange(e.target.value, "change")}
585
+ onKeyDown={(e) => this.onKeyDown(e)}
586
+ onBlur={(e) => {
587
+ this.onBlur(e);
588
+ }}
589
+ onFocus={(e) => {
590
+ this.onFocus(e);
591
+ }}
592
+ onMouseMove={(e) =>
593
+ tooltipMouseMove(e, ...getFieldTooltip(this.props.instance))
594
+ }
595
+ onMouseLeave={(e) =>
596
+ tooltipMouseLeave(e, ...getFieldTooltip(this.props.instance))
597
+ }
598
+ />
599
+ {icon}
600
+ {insideButton}
601
+ {dropdown}
602
+ {label}
603
+ {help}
604
+ </div>
605
+ );
606
+ }
607
+
608
+ onMouseDown(e: React.MouseEvent): void {
609
+ e.stopPropagation();
610
+ let { widget } = this.props.instance;
611
+
612
+ if (this.state.dropdownOpen) {
613
+ this.closeDropdown(e);
614
+ } else {
615
+ this.openDropdownOnFocus = true;
616
+ }
617
+
618
+ //icon click
619
+ if (e.target !== this.input) {
620
+ e.preventDefault();
564
621
 
565
- if (widget.trackFocus) {
566
- this.setState({
567
- focus: true,
568
- });
569
- }
570
- if (this.openDropdownOnFocus || widget.focusInputFirst) this.openDropdown();
571
- }
622
+ //the field should not focus only in case when dropdown will open and autofocus
623
+ if (widget.focusInputFirst || this.state.dropdownOpen) this.input.focus();
572
624
 
573
- onKeyDown(e: React.KeyboardEvent): void {
574
- let { instance } = this.props;
575
- if (instance.widget.handleKeyDown(e, instance) === false) return;
625
+ if (this.state.dropdownOpen) this.closeDropdown(e);
626
+ else this.openDropdown();
627
+ }
628
+ }
576
629
 
577
- switch (e.keyCode) {
578
- case KeyCode.enter:
579
- this.onChange((e.target as HTMLInputElement).value, "enter");
580
- break;
630
+ onFocus(e: React.FocusEvent): void {
631
+ let { instance } = this.props;
632
+ let { widget } = instance;
581
633
 
582
- case KeyCode.esc:
583
- if (this.state.dropdownOpen) {
584
- e.stopPropagation();
585
- this.closeDropdown(e, () => {
586
- this.input.focus();
587
- });
588
- }
634
+ if (widget.trackFocus) {
635
+ this.setState({
636
+ focus: true,
637
+ });
638
+ }
639
+ if (this.openDropdownOnFocus || widget.focusInputFirst) this.openDropdown();
640
+ }
641
+
642
+ onKeyDown(e: React.KeyboardEvent): void {
643
+ let { instance } = this.props;
644
+ if (instance.widget.handleKeyDown(e, instance) === false) return;
645
+
646
+ switch (e.keyCode) {
647
+ case KeyCode.enter:
648
+ this.onChange((e.target as HTMLInputElement).value, "enter");
649
+ break;
650
+
651
+ case KeyCode.esc:
652
+ if (this.state.dropdownOpen) {
653
+ e.stopPropagation();
654
+ this.closeDropdown(e, () => {
655
+ this.input.focus();
656
+ });
657
+ }
658
+ break;
659
+
660
+ case KeyCode.left:
661
+ case KeyCode.right:
662
+ e.stopPropagation();
663
+ break;
664
+
665
+ case KeyCode.down:
666
+ this.openDropdown();
667
+ e.stopPropagation();
668
+ e.preventDefault();
669
+ break;
670
+ }
671
+ }
672
+
673
+ onBlur(e: React.FocusEvent<HTMLInputElement>): void {
674
+ let { widget } = this.props.instance;
675
+ let dateTimeWidget = widget as DateTimeField;
676
+
677
+ if (!this.state.dropdownOpen)
678
+ this.props.instance.setState({ visited: true });
679
+ else if (dateTimeWidget.focusInputFirst) this.closeDropdown(e);
680
+ if (this.state.focus)
681
+ this.setState({
682
+ focus: false,
683
+ });
684
+ this.onChange(e.target.value, "blur");
685
+ }
686
+
687
+ closeDropdown(e: unknown, callback?: () => void): void {
688
+ if (this.state.dropdownOpen) {
689
+ if (this.scrollableParents)
690
+ this.scrollableParents.forEach((el) => {
691
+ el.removeEventListener("scroll", this.updateDropdownPosition);
692
+ });
693
+
694
+ this.setState({ dropdownOpen: false }, callback);
695
+ this.props.instance.setState({ visited: true });
696
+ } else if (callback) callback();
697
+ }
698
+
699
+ openDropdown(): void {
700
+ let { data } = this.props.instance;
701
+ this.openDropdownOnFocus = false;
702
+
703
+ if (!this.state.dropdownOpen && !(data.disabled || data.readOnly)) {
704
+ this.setState({
705
+ dropdownOpen: true,
706
+ dropdownOpenTime: Date.now(),
707
+ });
708
+ }
709
+ }
710
+
711
+ onClearClick(e: React.MouseEvent): void {
712
+ this.setValue(null);
713
+ e.stopPropagation();
714
+ e.preventDefault();
715
+ }
716
+
717
+ UNSAFE_componentWillReceiveProps(props: DateTimeInputProps): void {
718
+ let { data, state } = props.instance;
719
+ if (
720
+ data.formatted !== this.input.value &&
721
+ (data.formatted !== this.props.data.formatted || !state?.inputError)
722
+ ) {
723
+ this.input.value = data.formatted || "";
724
+ props.instance.setState({
725
+ inputError: false,
726
+ });
727
+ }
728
+
729
+ tooltipParentWillReceiveProps(
730
+ this.input,
731
+ ...getFieldTooltip(this.props.instance),
732
+ );
733
+ }
734
+
735
+ componentDidMount(): void {
736
+ tooltipParentDidMount(this.input, ...getFieldTooltip(this.props.instance));
737
+ autoFocus(this.input, this);
738
+ if (this.props.data.autoOpen) this.openDropdown();
739
+ }
740
+
741
+ componentDidUpdate(): void {
742
+ autoFocus(this.input, this);
743
+ }
744
+
745
+ componentWillUnmount(): void {
746
+ if (
747
+ this.input == getActiveElement() &&
748
+ this.input.value != this.props.data.formatted
749
+ ) {
750
+ this.onChange(this.input.value, "blur");
751
+ }
752
+ tooltipParentWillUnmount(this.props.instance);
753
+ }
754
+
755
+ onChange(inputValue: string, eventType: string): void {
756
+ let { instance, data } = this.props;
757
+ let { widget } = instance;
758
+ let dateTimeWidget = widget as DateTimeField;
759
+
760
+ if (data.disabled || data.readOnly) return;
761
+
762
+ if (dateTimeWidget.reactOn!.indexOf(eventType) === -1) return;
763
+
764
+ if (eventType == "enter") instance.setState({ visited: true });
765
+
766
+ this.setValue(inputValue, data.value);
767
+ }
768
+
769
+ setValue(text: string | null, baseValue?: unknown): void {
770
+ let { instance, data } = this.props;
771
+ let { widget } = instance;
772
+ let dateTimeWidget = widget as DateTimeField;
773
+
774
+ let date = dateTimeWidget.parseDate(text, instance);
775
+
776
+ instance.setState({
777
+ inputError: isNaN(date as any) && dateTimeWidget.inputErrorText,
778
+ });
779
+
780
+ if (!isNaN(date as any)) {
781
+ let mixed = parseDateInvariant(baseValue as string);
782
+ if (date && baseValue && !isNaN(mixed as any) && dateTimeWidget.partial) {
783
+ switch (dateTimeWidget.segment) {
784
+ case "date":
785
+ mixed.setFullYear(date!.getFullYear());
786
+ mixed.setMonth(date!.getMonth());
787
+ mixed.setDate(date!.getDate());
589
788
  break;
590
789
 
591
- case KeyCode.left:
592
- case KeyCode.right:
593
- e.stopPropagation();
790
+ case "time":
791
+ mixed.setHours(date!.getHours());
792
+ mixed.setMinutes(date!.getMinutes());
793
+ mixed.setSeconds(date!.getSeconds());
594
794
  break;
595
795
 
596
- case KeyCode.down:
597
- this.openDropdown();
598
- e.stopPropagation();
599
- e.preventDefault();
796
+ default:
797
+ mixed = date;
600
798
  break;
601
- }
602
- }
603
-
604
- onBlur(e: React.FocusEvent<HTMLInputElement>): void {
605
- let { widget } = this.props.instance;
606
- let dateTimeWidget = widget as DateTimeField;
607
-
608
- if (!this.state.dropdownOpen) this.props.instance.setState({ visited: true });
609
- else if (dateTimeWidget.focusInputFirst) this.closeDropdown(e);
610
- if (this.state.focus)
611
- this.setState({
612
- focus: false,
613
- });
614
- this.onChange(e.target.value, "blur");
615
- }
616
-
617
- closeDropdown(e: unknown, callback?: () => void): void {
618
- if (this.state.dropdownOpen) {
619
- if (this.scrollableParents)
620
- this.scrollableParents.forEach((el) => {
621
- el.removeEventListener("scroll", this.updateDropdownPosition);
622
- });
623
-
624
- this.setState({ dropdownOpen: false }, callback);
625
- this.props.instance.setState({ visited: true });
626
- } else if (callback) callback();
627
- }
628
-
629
- openDropdown(): void {
630
- let { data } = this.props.instance;
631
- this.openDropdownOnFocus = false;
632
-
633
- if (!this.state.dropdownOpen && !(data.disabled || data.readOnly)) {
634
- this.setState({
635
- dropdownOpen: true,
636
- dropdownOpenTime: Date.now(),
637
- });
638
- }
639
- }
799
+ }
640
800
 
641
- onClearClick(e: React.MouseEvent): void {
642
- this.setValue(null);
643
- e.stopPropagation();
644
- e.preventDefault();
645
- }
646
-
647
- UNSAFE_componentWillReceiveProps(props: DateTimeInputProps): void {
648
- let { data, state } = props.instance;
649
- if (data.formatted !== this.input.value && (data.formatted !== this.props.data.formatted || !state?.inputError)) {
650
- this.input.value = data.formatted || "";
651
- props.instance.setState({
652
- inputError: false,
653
- });
801
+ date = mixed;
654
802
  }
655
803
 
656
- tooltipParentWillReceiveProps(this.input, ...getFieldTooltip(this.props.instance));
657
- }
658
-
659
- componentDidMount(): void {
660
- tooltipParentDidMount(this.input, ...getFieldTooltip(this.props.instance));
661
- autoFocus(this.input, this);
662
- if (this.props.data.autoOpen) this.openDropdown();
663
- }
804
+ let encode = dateTimeWidget.encoding || Culture.getDefaultDateEncoding();
664
805
 
665
- componentDidUpdate(): void {
666
- autoFocus(this.input, this);
667
- }
806
+ let value = date ? encode!(date!) : dateTimeWidget.emptyValue;
668
807
 
669
- componentWillUnmount(): void {
670
- if (this.input == getActiveElement() && this.input.value != this.props.data.formatted) {
671
- this.onChange(this.input.value, "blur");
672
- }
673
- tooltipParentWillUnmount(this.props.instance);
674
- }
675
-
676
- onChange(inputValue: string, eventType: string): void {
677
- let { instance, data } = this.props;
678
- let { widget } = instance;
679
- let dateTimeWidget = widget as DateTimeField;
680
-
681
- if (data.disabled || data.readOnly) return;
682
-
683
- if (dateTimeWidget.reactOn!.indexOf(eventType) === -1) return;
684
-
685
- if (eventType == "enter") instance.setState({ visited: true });
686
-
687
- this.setValue(inputValue, data.value);
688
- }
689
-
690
- setValue(text: string | null, baseValue?: unknown): void {
691
- let { instance, data } = this.props;
692
- let { widget } = instance;
693
- let dateTimeWidget = widget as DateTimeField;
694
-
695
- let date = dateTimeWidget.parseDate(text, instance);
696
-
697
- instance.setState({
698
- inputError: isNaN(date as any) && dateTimeWidget.inputErrorText,
699
- });
700
-
701
- if (!isNaN(date as any)) {
702
- let mixed = parseDateInvariant(baseValue as string);
703
- if (date && baseValue && !isNaN(mixed as any) && dateTimeWidget.partial) {
704
- switch (dateTimeWidget.segment) {
705
- case "date":
706
- mixed.setFullYear(date!.getFullYear());
707
- mixed.setMonth(date!.getMonth());
708
- mixed.setDate(date!.getDate());
709
- break;
710
-
711
- case "time":
712
- mixed.setHours(date!.getHours());
713
- mixed.setMinutes(date!.getMinutes());
714
- mixed.setSeconds(date!.getSeconds());
715
- break;
716
-
717
- default:
718
- mixed = date;
719
- break;
720
- }
721
-
722
- date = mixed;
723
- }
724
-
725
- let encode = dateTimeWidget.encoding || Culture.getDefaultDateEncoding();
726
-
727
- let value = date ? encode!(date!) : dateTimeWidget.emptyValue;
728
-
729
- if (!instance.set("value", value)) this.input.value = value ? Format.value(date!, data.format as string) : "";
730
- }
731
- }
808
+ if (!instance.set("value", value))
809
+ this.input.value = value
810
+ ? Format.value(date!, data.format as string)
811
+ : "";
812
+ }
813
+ }
732
814
  }