cx 26.2.1 → 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 +9 -4
  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 +892 -880
  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 +317 -121
  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 +15 -7
  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
@@ -21,11 +21,11 @@ import ClearIcon from "../icons/clear";
21
21
  import DropdownIcon from "../icons/drop-down";
22
22
  import { Dropdown, DropdownConfig } from "../overlay/Dropdown";
23
23
  import {
24
- tooltipMouseLeave,
25
- tooltipMouseMove,
26
- tooltipParentDidMount,
27
- tooltipParentWillReceiveProps,
28
- tooltipParentWillUnmount,
24
+ tooltipMouseLeave,
25
+ tooltipMouseMove,
26
+ tooltipParentDidMount,
27
+ tooltipParentWillReceiveProps,
28
+ tooltipParentWillUnmount,
29
29
  } from "../overlay/tooltip-ops";
30
30
  import { Field, getFieldTooltip, FieldInstance, FieldConfig } from "./Field";
31
31
  import { MonthPicker } from "./MonthPicker";
@@ -35,299 +35,343 @@ import type { Instance, DropdownWidgetProps } from "../../ui/Instance";
35
35
  import type { Config, Prop, BooleanProp, StringProp } from "../../ui/Prop";
36
36
 
37
37
  export class MonthFieldInstance<F extends MonthField = MonthField>
38
- extends FieldInstance<F>
39
- implements DropdownWidgetProps
38
+ extends FieldInstance<F>
39
+ implements DropdownWidgetProps
40
40
  {
41
- lastDropdown?: Instance;
42
- dropdownOpen?: boolean;
43
- selectedIndex?: number;
44
- component?: any;
41
+ lastDropdown?: Instance;
42
+ dropdownOpen?: boolean;
43
+ selectedIndex?: number;
44
+ component?: any;
45
45
  }
46
46
 
47
47
  export interface MonthFieldConfig extends FieldConfig {
48
- /** Selected month. This should be a Date object or a valid date string consumable by Date.parse function. */
49
- value?: Prop<string | Date>;
48
+ /** Selected month. This should be a Date object or a valid date string consumable by Date.parse function. */
49
+ value?: Prop<string | Date>;
50
50
 
51
- /** Set to `true` to allow range select. */
52
- range?: BooleanProp;
51
+ /** Set to `true` to allow range select. */
52
+ range?: BooleanProp;
53
53
 
54
- /** Start of the selected month range. Used only if `range` is set to `true`. */
55
- from?: Prop<string | Date>;
54
+ /** Start of the selected month range. Used only if `range` is set to `true`. */
55
+ from?: Prop<string | Date>;
56
56
 
57
- /** End of the selected month range. Used only if `range` is set to `true`. */
58
- to?: Prop<string | Date>;
57
+ /** End of the selected month range. Used only if `range` is set to `true`. */
58
+ to?: Prop<string | Date>;
59
59
 
60
- /** Defaults to `false`. Used to make the field read-only. */
61
- readOnly?: BooleanProp;
60
+ /** Defaults to `false`. Used to make the field read-only. */
61
+ readOnly?: BooleanProp;
62
62
 
63
- /** The opposite of `disabled`. */
64
- enabled?: BooleanProp;
63
+ /** The opposite of `disabled`. */
64
+ enabled?: BooleanProp;
65
65
 
66
- /** Default text displayed when the field is empty. */
67
- placeholder?: StringProp;
66
+ /** Default text displayed when the field is empty. */
67
+ placeholder?: StringProp;
68
68
 
69
- /** Minimum date value. */
70
- minValue?: Prop<string | Date>;
69
+ /** Minimum date value. */
70
+ minValue?: Prop<string | Date>;
71
71
 
72
- /** Set to `true` to disallow the `minValue`. Default value is `false`. */
73
- minExclusive?: BooleanProp;
72
+ /** Set to `true` to disallow the `minValue`. Default value is `false`. */
73
+ minExclusive?: BooleanProp;
74
74
 
75
- /** Maximum date value. */
76
- maxValue?: Prop<string | Date>;
75
+ /** Maximum date value. */
76
+ maxValue?: Prop<string | Date>;
77
77
 
78
- /** Set to `true` to disallow the `maxValue`. Default value is `false`. */
79
- maxExclusive?: BooleanProp;
78
+ /** Set to `true` to disallow the `maxValue`. Default value is `false`. */
79
+ maxExclusive?: BooleanProp;
80
80
 
81
- /** String representing culture. Default is `en`. */
82
- culture?: string;
81
+ /** String representing culture. Default is `en`. */
82
+ culture?: string;
83
83
 
84
- /** Set to `true` to hide the clear button. Default value is `false`. */
85
- hideClear?: boolean;
84
+ /** Set to `true` to hide the clear button. Default value is `false`. */
85
+ hideClear?: boolean;
86
86
 
87
- /** Base CSS class to be applied on the field. Defaults to `monthfield`. */
88
- baseClass?: string;
87
+ /** Base CSS class to be applied on the field. Defaults to `monthfield`. */
88
+ baseClass?: string;
89
89
 
90
- /** Maximum value error text. */
91
- maxValueErrorText?: string;
90
+ /** Maximum value error text. */
91
+ maxValueErrorText?: string;
92
92
 
93
- /** Maximum exclusive value error text. */
94
- maxExclusiveErrorText?: string;
93
+ /** Maximum exclusive value error text. */
94
+ maxExclusiveErrorText?: string;
95
95
 
96
- /** Minimum value error text. */
97
- minValueErrorText?: string;
96
+ /** Minimum value error text. */
97
+ minValueErrorText?: string;
98
98
 
99
- /** Minimum exclusive value error text. */
100
- minExclusiveErrorText?: string;
99
+ /** Minimum exclusive value error text. */
100
+ minExclusiveErrorText?: string;
101
101
 
102
- /** Invalid input error text. */
103
- inputErrorText?: string;
102
+ /** Invalid input error text. */
103
+ inputErrorText?: string;
104
104
 
105
- /** Name or configuration of the icon to be put on the left side of the input. */
106
- icon?: StringProp | Config;
105
+ /** Name or configuration of the icon to be put on the left side of the input. */
106
+ icon?: StringProp | Config;
107
107
 
108
- /** Set to `false` to hide the clear button. Default value is `true`. */
109
- showClear?: boolean;
108
+ /** Set to `false` to hide the clear button. Default value is `true`. */
109
+ showClear?: boolean;
110
110
 
111
- /** Set to `true` to display the clear button even if `required` is set. Default is `false`. */
112
- alwaysShowClear?: boolean;
111
+ /** Set to `true` to display the clear button even if `required` is set. Default is `false`. */
112
+ alwaysShowClear?: boolean;
113
113
 
114
- /** The function that will be used to convert Date objects before writing data to the store. */
115
- encoding?: (date: Date) => any;
114
+ /** The function that will be used to convert Date objects before writing data to the store. */
115
+ encoding?: (date: Date) => any;
116
116
 
117
- /** Additional configuration to be passed to the dropdown. */
118
- dropdownOptions?: Partial<DropdownConfig>;
117
+ /** Additional configuration to be passed to the dropdown. */
118
+ dropdownOptions?: Partial<DropdownConfig>;
119
119
 
120
- /** A boolean flag that determines whether the `to` date is included in the range. */
121
- inclusiveTo?: boolean;
120
+ /** A boolean flag that determines whether the `to` date is included in the range. */
121
+ inclusiveTo?: boolean;
122
122
 
123
- /** Optional configuration options for the MonthPicker component rendered within the dropdown. */
124
- monthPickerOptions?: Config;
123
+ /** Optional configuration options for the MonthPicker component rendered within the dropdown. */
124
+ monthPickerOptions?: Config;
125
125
 
126
- /** Custom validation function. */
127
- onValidate?:
128
- | string
129
- | ((value: string | Date, instance: Instance, validationParams: Record<string, unknown>) => unknown);
126
+ /** Custom validation function. */
127
+ onValidate?:
128
+ | string
129
+ | ((
130
+ value: string | Date,
131
+ instance: Instance,
132
+ validationParams: Record<string, unknown>,
133
+ ) => unknown);
130
134
  }
131
135
 
132
- export class MonthField<Config extends MonthFieldConfig = MonthFieldConfig> extends Field<Config, MonthFieldInstance> {
133
- declare public baseClass: string;
134
- declare public mode?: string;
135
- declare public range?: BooleanProp;
136
- declare public from?: Prop<string | Date>;
137
- declare public to?: Prop<string | Date>;
138
- declare public value?: Prop<string | Date>;
139
- declare public culture: DateTimeCulture;
140
- declare public hideClear?: boolean;
141
- declare public showClear?: boolean;
142
- declare public alwaysShowClear?: boolean;
143
- declare public encoding?: (date: Date) => string;
144
- declare public dropdownOptions?: Partial<DropdownConfig>;
145
- declare public inclusiveTo?: boolean;
146
- declare public monthPickerOptions?: Record<string, any>;
147
- declare public maxValueErrorText: string;
148
- declare public maxExclusiveErrorText: string;
149
- declare public minValueErrorText: string;
150
- declare public minExclusiveErrorText: string;
151
- declare public inputErrorText?: string;
152
- declare public minExclusive?: BooleanProp;
153
- declare public maxExclusive?: BooleanProp;
154
- declare public minValue?: Prop<string | Date>;
155
- declare public maxValue?: Prop<string | Date>;
156
- declare public placeholder?: StringProp;
157
- declare public reactOn: string;
158
-
159
- declareData(...args: Record<string, unknown>[]): void {
160
- if (this.mode == "range") {
161
- this.range = true;
162
- this.mode = "edit";
163
- Console.warn('Please use the range flag on MonthFields. Syntax mode="range" is deprecated.', this);
164
- }
165
-
166
- let values: Record<string, unknown> = {};
167
-
168
- if (this.range) {
169
- values = {
170
- from: null,
171
- to: null,
172
- };
173
- } else {
174
- values = {
175
- value: this.emptyValue,
176
- };
177
- }
178
-
179
- super.declareData(
180
- values,
181
- {
182
- disabled: undefined,
183
- readOnly: undefined,
184
- enabled: undefined,
185
- placeholder: undefined,
186
- required: undefined,
187
- minValue: undefined,
188
- minExclusive: undefined,
189
- maxValue: undefined,
190
- maxExclusive: undefined,
191
- icon: undefined,
192
- },
193
- ...args,
136
+ export class MonthField<
137
+ Config extends MonthFieldConfig = MonthFieldConfig,
138
+ > extends Field<Config, MonthFieldInstance> {
139
+ declare public baseClass: string;
140
+ declare public mode?: string;
141
+ declare public range?: BooleanProp;
142
+ declare public from?: Prop<string | Date>;
143
+ declare public to?: Prop<string | Date>;
144
+ declare public value?: Prop<string | Date>;
145
+ declare public culture: DateTimeCulture;
146
+ declare public hideClear?: boolean;
147
+ declare public showClear?: boolean;
148
+ declare public alwaysShowClear?: boolean;
149
+ declare public encoding?: (date: Date) => string;
150
+ declare public dropdownOptions?: Partial<DropdownConfig>;
151
+ declare public inclusiveTo?: boolean;
152
+ declare public monthPickerOptions?: Record<string, any>;
153
+ declare public maxValueErrorText: string;
154
+ declare public maxExclusiveErrorText: string;
155
+ declare public minValueErrorText: string;
156
+ declare public minExclusiveErrorText: string;
157
+ declare public inputErrorText?: string;
158
+ declare public minExclusive?: BooleanProp;
159
+ declare public maxExclusive?: BooleanProp;
160
+ declare public minValue?: Prop<string | Date>;
161
+ declare public maxValue?: Prop<string | Date>;
162
+ declare public placeholder?: StringProp;
163
+ declare public reactOn: string;
164
+
165
+ declareData(...args: Record<string, unknown>[]): void {
166
+ if (this.mode == "range") {
167
+ this.range = true;
168
+ this.mode = "edit";
169
+ Console.warn(
170
+ 'Please use the range flag on MonthFields. Syntax mode="range" is deprecated.',
171
+ this,
194
172
  );
195
- }
196
-
197
- isEmpty(data: Record<string, unknown>): boolean {
198
- return this.range ? data.from == null : data.value == null;
199
- }
200
-
201
- init(): void {
202
- if (!this.culture) this.culture = Culture.getDateTimeCulture();
203
-
204
- if (isDefined(this.hideClear)) this.showClear = !this.hideClear;
173
+ }
205
174
 
206
- if (this.alwaysShowClear) this.showClear = true;
175
+ let values: Record<string, unknown> = {};
207
176
 
208
- super.init();
209
- }
210
-
211
- prepareData(context: RenderingContext, instance: MonthFieldInstance): void {
212
- super.prepareData(context, instance);
213
-
214
- let { data } = instance;
215
-
216
- let formatOptions = {
217
- year: "numeric",
218
- month: "short",
177
+ if (this.range) {
178
+ values = {
179
+ from: null,
180
+ to: null,
219
181
  };
220
-
221
- if (!this.range && data.value) {
222
- data.date = parseDateInvariant(data.value);
223
- data.formatted = this.culture.format(data.date, formatOptions);
224
- } else if (this.range && data.from && data.to) {
225
- data.from = parseDateInvariant(data.from);
226
- data.to = parseDateInvariant(data.to);
227
- if (!this.inclusiveTo) data.to.setDate(data.to.getDate() - 1);
228
- let fromStr = this.culture.format(data.from, formatOptions);
229
- let toStr = this.culture.format(data.to, formatOptions);
230
- if (fromStr != toStr) data.formatted = fromStr + " - " + toStr;
231
- else data.formatted = fromStr;
182
+ } else {
183
+ values = {
184
+ value: this.emptyValue,
185
+ };
186
+ }
187
+
188
+ super.declareData(
189
+ values,
190
+ {
191
+ disabled: undefined,
192
+ readOnly: undefined,
193
+ enabled: undefined,
194
+ placeholder: undefined,
195
+ required: undefined,
196
+ minValue: undefined,
197
+ minExclusive: undefined,
198
+ maxValue: undefined,
199
+ maxExclusive: undefined,
200
+ icon: undefined,
201
+ },
202
+ ...args,
203
+ );
204
+ }
205
+
206
+ isEmpty(data: Record<string, unknown>): boolean {
207
+ return this.range ? data.from == null : data.value == null;
208
+ }
209
+
210
+ init(): void {
211
+ if (!this.culture) this.culture = Culture.getDateTimeCulture();
212
+
213
+ if (isDefined(this.hideClear)) this.showClear = !this.hideClear;
214
+
215
+ if (this.alwaysShowClear) this.showClear = true;
216
+
217
+ super.init();
218
+ }
219
+
220
+ prepareData(context: RenderingContext, instance: MonthFieldInstance): void {
221
+ super.prepareData(context, instance);
222
+
223
+ let { data } = instance;
224
+
225
+ let formatOptions = {
226
+ year: "numeric",
227
+ month: "short",
228
+ };
229
+
230
+ if (!this.range && data.value) {
231
+ data.date = parseDateInvariant(data.value);
232
+ data.formatted = this.culture.format(data.date, formatOptions);
233
+ } else if (this.range && data.from && data.to) {
234
+ data.from = parseDateInvariant(data.from);
235
+ data.to = parseDateInvariant(data.to);
236
+ if (!this.inclusiveTo) data.to.setDate(data.to.getDate() - 1);
237
+ let fromStr = this.culture.format(data.from, formatOptions);
238
+ let toStr = this.culture.format(data.to, formatOptions);
239
+ if (fromStr != toStr) data.formatted = fromStr + " - " + toStr;
240
+ else data.formatted = fromStr;
241
+ }
242
+
243
+ if (data.refDate)
244
+ data.refDate = monthStart(parseDateInvariant(data.refDate));
245
+
246
+ if (data.maxValue)
247
+ data.maxValue = monthStart(parseDateInvariant(data.maxValue));
248
+
249
+ if (data.minValue)
250
+ data.minValue = monthStart(parseDateInvariant(data.minValue));
251
+
252
+ instance.lastDropdown = context.lastDropdown;
253
+ }
254
+
255
+ validateRequired(
256
+ context: RenderingContext,
257
+ instance: MonthFieldInstance,
258
+ ): string | undefined {
259
+ const { data } = instance;
260
+ if (this.range) {
261
+ if (!data.from || !data.to) return this.requiredText;
262
+ } else return super.validateRequired(context, instance);
263
+ }
264
+
265
+ validate(context: RenderingContext, instance: MonthFieldInstance): void {
266
+ super.validate(context, instance);
267
+ var { data } = instance;
268
+ if (!data.error && data.date) {
269
+ var d;
270
+ if (data.maxValue) {
271
+ d = dateDiff(data.date, data.maxValue);
272
+ if (d > 0)
273
+ data.error = StringTemplate.format(
274
+ this.maxValueErrorText,
275
+ data.maxValue,
276
+ );
277
+ else if (d == 0 && data.maxExclusive)
278
+ data.error = StringTemplate.format(
279
+ this.maxExclusiveErrorText,
280
+ data.maxValue,
281
+ );
232
282
  }
233
283
 
234
- if (data.refDate) data.refDate = monthStart(parseDateInvariant(data.refDate));
235
-
236
- if (data.maxValue) data.maxValue = monthStart(parseDateInvariant(data.maxValue));
237
-
238
- if (data.minValue) data.minValue = monthStart(parseDateInvariant(data.minValue));
239
-
240
- instance.lastDropdown = context.lastDropdown;
241
- }
242
-
243
- validateRequired(context: RenderingContext, instance: MonthFieldInstance): string | undefined {
244
- const { data } = instance;
245
- if (this.range) {
246
- if (!data.from || !data.to) return this.requiredText;
247
- } else return super.validateRequired(context, instance);
248
- }
249
-
250
- validate(context: RenderingContext, instance: MonthFieldInstance): void {
251
- super.validate(context, instance);
252
- var { data } = instance;
253
- if (!data.error && data.date) {
254
- var d;
255
- if (data.maxValue) {
256
- d = dateDiff(data.date, data.maxValue);
257
- if (d > 0) data.error = StringTemplate.format(this.maxValueErrorText, data.maxValue);
258
- else if (d == 0 && data.maxExclusive)
259
- data.error = StringTemplate.format(this.maxExclusiveErrorText, data.maxValue);
260
- }
261
-
262
- if (data.minValue) {
263
- d = dateDiff(data.date, data.minValue);
264
- if (d < 0) data.error = StringTemplate.format(this.minValueErrorText, data.minValue);
265
- else if (d == 0 && data.minExclusive)
266
- data.error = StringTemplate.format(this.minExclusiveErrorText, data.minValue);
267
- }
284
+ if (data.minValue) {
285
+ d = dateDiff(data.date, data.minValue);
286
+ if (d < 0)
287
+ data.error = StringTemplate.format(
288
+ this.minValueErrorText,
289
+ data.minValue,
290
+ );
291
+ else if (d == 0 && data.minExclusive)
292
+ data.error = StringTemplate.format(
293
+ this.minExclusiveErrorText,
294
+ data.minValue,
295
+ );
268
296
  }
269
- }
270
-
271
- renderInput(context: RenderingContext, instance: MonthFieldInstance, key: string): React.ReactNode {
272
- return (
273
- <MonthInput
274
- key={key}
275
- data={instance.data}
276
- instance={instance}
277
- monthPicker={{
278
- ...this.monthPickerOptions,
279
- value: this.value,
280
- from: this.from,
281
- to: this.to,
282
- range: this.range,
283
- minValue: this.minValue,
284
- maxValue: this.maxValue,
285
- minExclusive: this.minExclusive,
286
- maxExclusive: this.maxExclusive,
287
- maxValueErrorText: this.maxValueErrorText,
288
- maxExclusiveErrorText: this.maxExclusiveErrorText,
289
- minValueErrorText: this.minValueErrorText,
290
- minExclusiveErrorText: this.minExclusiveErrorText,
291
- }}
292
- label={this.labelPlacement && getContent(this.renderLabel(context, instance, "label"))}
293
- help={this.helpPlacement && getContent(this.renderHelp(context, instance, "help"))}
294
- icon={this.renderIcon(context, instance, "icon")}
295
- />
296
- );
297
- }
298
-
299
- formatValue(context: RenderingContext, instance: Instance): string {
300
- return instance.data.formatted || "";
301
- }
302
-
303
- parseDate(date: string | Date | null): Date | null {
304
- if (!date) return null;
305
- if (date instanceof Date) return date;
306
- let parsed = this.culture.parse(date, { useCurrentDateForDefaults: true });
307
- return parsed;
308
- }
309
-
310
- handleSelect(instance: MonthFieldInstance, date1: Date | null, date2: Date | null): void {
311
- let { widget } = instance;
312
- let encode = widget.encoding ?? Culture.getDefaultDateEncoding();
313
- instance.setState({
314
- inputError: false,
315
- });
316
- if (this.range) {
317
- let d1 = date1 ? encode(date1) : this.emptyValue;
318
- let toDate = date2;
319
- if (date2 && this.inclusiveTo) {
320
- toDate = new Date(date2);
321
- toDate.setDate(toDate.getDate() - 1);
322
- }
323
- let d2 = toDate ? encode(toDate) : this.emptyValue;
324
- instance.set("from", d1);
325
- instance.set("to", d2);
326
- } else {
327
- let value = date1 ? encode(date1) : this.emptyValue;
328
- instance.set("value", value);
297
+ }
298
+ }
299
+
300
+ renderInput(
301
+ context: RenderingContext,
302
+ instance: MonthFieldInstance,
303
+ key: string,
304
+ ): React.ReactNode {
305
+ return (
306
+ <MonthInput
307
+ key={key}
308
+ data={instance.data}
309
+ instance={instance}
310
+ monthPicker={{
311
+ mod: "dropdown",
312
+ ...this.monthPickerOptions,
313
+ value: this.value,
314
+ from: this.from,
315
+ to: this.to,
316
+ range: this.range,
317
+ minValue: this.minValue,
318
+ maxValue: this.maxValue,
319
+ minExclusive: this.minExclusive,
320
+ maxExclusive: this.maxExclusive,
321
+ maxValueErrorText: this.maxValueErrorText,
322
+ maxExclusiveErrorText: this.maxExclusiveErrorText,
323
+ minValueErrorText: this.minValueErrorText,
324
+ minExclusiveErrorText: this.minExclusiveErrorText,
325
+ }}
326
+ label={
327
+ this.labelPlacement &&
328
+ getContent(this.renderLabel(context, instance, "label"))
329
+ }
330
+ help={
331
+ this.helpPlacement &&
332
+ getContent(this.renderHelp(context, instance, "help"))
333
+ }
334
+ icon={this.renderIcon(context, instance, "icon")}
335
+ />
336
+ );
337
+ }
338
+
339
+ formatValue(context: RenderingContext, instance: Instance): string {
340
+ return instance.data.formatted || "";
341
+ }
342
+
343
+ parseDate(date: string | Date | null): Date | null {
344
+ if (!date) return null;
345
+ if (date instanceof Date) return date;
346
+ let parsed = this.culture.parse(date, { useCurrentDateForDefaults: true });
347
+ return parsed;
348
+ }
349
+
350
+ handleSelect(
351
+ instance: MonthFieldInstance,
352
+ date1: Date | null,
353
+ date2: Date | null,
354
+ ): void {
355
+ let { widget } = instance;
356
+ let encode = widget.encoding ?? Culture.getDefaultDateEncoding();
357
+ instance.setState({
358
+ inputError: false,
359
+ });
360
+ if (this.range) {
361
+ let d1 = date1 ? encode(date1) : this.emptyValue;
362
+ let toDate = date2;
363
+ if (date2 && this.inclusiveTo) {
364
+ toDate = new Date(date2);
365
+ toDate.setDate(toDate.getDate() - 1);
329
366
  }
330
- }
367
+ let d2 = toDate ? encode(toDate) : this.emptyValue;
368
+ instance.set("from", d1);
369
+ instance.set("to", d2);
370
+ } else {
371
+ let value = date1 ? encode(date1) : this.emptyValue;
372
+ instance.set("value", value);
373
+ }
374
+ }
331
375
  }
332
376
 
333
377
  MonthField.prototype.baseClass = "monthfield";
@@ -349,322 +393,356 @@ Localization.registerPrototype("cx/widgets/MonthField", MonthField);
349
393
  Widget.alias("monthfield", MonthField);
350
394
 
351
395
  interface MonthInputProps {
352
- instance: MonthFieldInstance;
353
- data: Record<string, any>;
354
- monthPicker: Record<string, any>;
355
- label?: React.ReactNode;
356
- help?: React.ReactNode;
357
- icon?: React.ReactNode;
396
+ instance: MonthFieldInstance;
397
+ data: Record<string, any>;
398
+ monthPicker: Record<string, any>;
399
+ label?: React.ReactNode;
400
+ help?: React.ReactNode;
401
+ icon?: React.ReactNode;
358
402
  }
359
403
 
360
404
  interface MonthInputState {
361
- dropdownOpen: boolean;
362
- focus: boolean;
405
+ dropdownOpen: boolean;
406
+ focus: boolean;
363
407
  }
364
408
 
365
409
  class MonthInput extends VDOM.Component<MonthInputProps, MonthInputState> {
366
- input?: HTMLInputElement | null;
367
- dropdown?: Widget;
368
- openDropdownOnFocus: boolean = false;
369
- scrollableParents?: Element[];
370
- updateDropdownPosition: () => void = () => {};
371
-
372
- constructor(props: MonthInputProps) {
373
- super(props);
374
- this.props.instance.component = this;
375
- this.state = {
376
- dropdownOpen: false,
377
- focus: false,
378
- };
379
- }
380
-
381
- getDropdown(): Widget {
382
- if (this.dropdown) return this.dropdown;
383
-
384
- let { widget, lastDropdown } = this.props.instance;
385
-
386
- var dropdown = {
387
- scrollTracking: true,
388
- inline: !isTouchDevice() || !!lastDropdown,
389
- placementOrder:
390
- "down down-left down-right up up-left up-right right right-up right-down left left-up left-down",
391
- touchFriendly: true,
392
- ...widget.dropdownOptions,
393
- type: Dropdown,
394
- relatedElement: this.input,
395
- items: {
396
- type: MonthPicker,
397
- ...this.props.monthPicker,
398
- encoding: widget.encoding,
399
- inclusiveTo: widget.inclusiveTo,
400
- autoFocus: true,
401
- onFocusOut: (e: React.MouseEvent) => {
402
- this.closeDropdown(e);
403
- },
404
- onKeyDown: (e: React.KeyboardEvent) => this.onKeyDown(e),
405
- onSelect: (e: React.MouseEvent) => {
406
- let touch = isTouchEvent();
407
- this.closeDropdown(e, () => {
408
- if (!touch) this.input!.focus();
409
- });
410
- },
411
- },
412
- constrain: true,
413
- firstChildDefinesWidth: true,
414
- };
415
-
416
- return (this.dropdown = Widget.create(dropdown));
417
- }
418
-
419
- render(): React.ReactNode {
420
- const { instance, label, help, data, icon: iconVDOM } = this.props;
421
- const { widget, state } = instance;
422
- var { CSS, baseClass, suppressErrorsUntilVisited } = widget;
423
-
424
- let insideButton, icon;
425
-
426
- if (!data.readOnly && !data.disabled) {
427
- if (
428
- widget.showClear &&
429
- (((widget.alwaysShowClear || !data.required) && !data.empty) || instance.state.inputError)
430
- )
431
- insideButton = (
432
- <div
433
- className={CSS.element(baseClass, "clear")}
434
- onMouseDown={(e) => {
435
- e.preventDefault();
436
- e.stopPropagation();
437
- }}
438
- onClick={(e) => {
439
- this.onClearClick(e);
440
- }}
441
- >
442
- <ClearIcon className={CSS.element(baseClass, "icon")} />
443
- </div>
444
- );
445
- else
446
- insideButton = (
447
- <div className={CSS.element(baseClass, "right-icon")}>
448
- <DropdownIcon className={CSS.element(baseClass, "icon")} />
449
- </div>
450
- );
451
- }
452
-
453
- if (iconVDOM) {
454
- icon = <div className={CSS.element(baseClass, "left-icon")}>{iconVDOM}</div>;
455
- }
456
-
457
- var dropdown: React.ReactElement | false = false;
458
- if (this.state.dropdownOpen)
459
- dropdown = (
460
- <Cx
461
- widget={this.getDropdown()}
462
- parentInstance={instance}
463
- options={{ name: "monthfield-dropdown" }}
464
- subscribe
465
- />
466
- );
467
-
468
- let empty = this.input ? !this.input.value : data.empty;
469
-
470
- return (
471
- <div
472
- className={CSS.expand(
473
- data.classNames,
474
- CSS.state({
475
- visited: state.visited,
476
- focus: this.state.focus || this.state.dropdownOpen,
477
- icon: !!icon,
478
- empty: empty && !data.placeholder,
479
- error: data.error && (state.visited || !suppressErrorsUntilVisited || !empty),
480
- }),
481
- )}
482
- style={data.style}
483
- onMouseDown={this.onMouseDown.bind(this)}
484
- onTouchStart={stopPropagation}
485
- onClick={stopPropagation}
486
- >
487
- <input
488
- id={data.id}
489
- ref={(el) => {
490
- this.input = el;
491
- }}
492
- type="text"
493
- className={CSS.expand(CSS.element(baseClass, "input"), data.inputClass)}
494
- style={data.inputStyle}
495
- defaultValue={data.formatted}
496
- disabled={data.disabled}
497
- readOnly={data.readOnly}
498
- tabIndex={data.tabIndex}
499
- placeholder={data.placeholder}
500
- onInput={(e) => this.onChange((e.target as HTMLInputElement).value, "input")}
501
- onChange={(e) => this.onChange((e.target as HTMLInputElement).value, "change")}
502
- onKeyDown={(e) => this.onKeyDown(e)}
503
- onBlur={(e) => {
504
- this.onBlur(e);
505
- }}
506
- onFocus={(e) => {
507
- this.onFocus(e);
508
- }}
509
- onMouseMove={(e) => tooltipMouseMove(e, ...getFieldTooltip(this.props.instance))}
510
- onMouseLeave={(e) => tooltipMouseLeave(e, ...getFieldTooltip(this.props.instance))}
511
- />
512
- {icon}
513
- {insideButton}
514
- {dropdown}
515
- {label}
516
- {help}
517
- </div>
410
+ input?: HTMLInputElement | null;
411
+ dropdown?: Widget;
412
+ openDropdownOnFocus: boolean = false;
413
+ scrollableParents?: Element[];
414
+ updateDropdownPosition: () => void = () => {};
415
+
416
+ constructor(props: MonthInputProps) {
417
+ super(props);
418
+ this.props.instance.component = this;
419
+ this.state = {
420
+ dropdownOpen: false,
421
+ focus: false,
422
+ };
423
+ }
424
+
425
+ getDropdown(): Widget {
426
+ if (this.dropdown) return this.dropdown;
427
+
428
+ let { widget, lastDropdown } = this.props.instance;
429
+
430
+ var dropdown = {
431
+ scrollTracking: true,
432
+ inline: !isTouchDevice() || !!lastDropdown,
433
+ placementOrder:
434
+ "down down-left down-right up up-left up-right right right-up right-down left left-up left-down",
435
+ touchFriendly: true,
436
+ ...widget.dropdownOptions,
437
+ type: Dropdown,
438
+ relatedElement: this.input,
439
+ items: {
440
+ type: MonthPicker,
441
+ ...this.props.monthPicker,
442
+ encoding: widget.encoding,
443
+ inclusiveTo: widget.inclusiveTo,
444
+ autoFocus: true,
445
+ onFocusOut: (e: React.MouseEvent) => {
446
+ this.closeDropdown(e);
447
+ },
448
+ onKeyDown: (e: React.KeyboardEvent) => this.onKeyDown(e),
449
+ onSelect: (e: React.MouseEvent) => {
450
+ let touch = isTouchEvent();
451
+ this.closeDropdown(e, () => {
452
+ if (!touch) this.input!.focus();
453
+ });
454
+ },
455
+ },
456
+ constrain: true,
457
+ firstChildDefinesWidth: true,
458
+ };
459
+
460
+ return (this.dropdown = Widget.create(dropdown));
461
+ }
462
+
463
+ render(): React.ReactNode {
464
+ const { instance, label, help, data, icon: iconVDOM } = this.props;
465
+ const { widget, state } = instance;
466
+ var { CSS, baseClass, suppressErrorsUntilVisited } = widget;
467
+
468
+ let insideButton, icon;
469
+
470
+ if (!data.readOnly && !data.disabled) {
471
+ if (
472
+ widget.showClear &&
473
+ (((widget.alwaysShowClear || !data.required) && !data.empty) ||
474
+ instance.state.inputError)
475
+ )
476
+ insideButton = (
477
+ <div
478
+ className={CSS.element(baseClass, "clear")}
479
+ onMouseDown={(e) => {
480
+ e.preventDefault();
481
+ e.stopPropagation();
482
+ }}
483
+ onClick={(e) => {
484
+ this.onClearClick(e);
485
+ }}
486
+ >
487
+ <ClearIcon className={CSS.element(baseClass, "icon")} />
488
+ </div>
489
+ );
490
+ else
491
+ insideButton = (
492
+ <div className={CSS.element(baseClass, "right-icon")}>
493
+ <DropdownIcon className={CSS.element(baseClass, "icon")} />
494
+ </div>
495
+ );
496
+ }
497
+
498
+ if (iconVDOM) {
499
+ icon = (
500
+ <div className={CSS.element(baseClass, "left-icon")}>{iconVDOM}</div>
501
+ );
502
+ }
503
+
504
+ var dropdown: React.ReactElement | false = false;
505
+ if (this.state.dropdownOpen)
506
+ dropdown = (
507
+ <Cx
508
+ widget={this.getDropdown()}
509
+ parentInstance={instance}
510
+ options={{ name: "monthfield-dropdown" }}
511
+ subscribe
512
+ />
518
513
  );
519
- }
520
-
521
- onMouseDown(e: React.MouseEvent): void {
522
- e.stopPropagation();
523
-
524
- if (this.state.dropdownOpen) this.closeDropdown(e);
525
- else {
526
- this.openDropdownOnFocus = true;
527
- }
528
-
529
- //icon click
530
- if (e.target != this.input) {
531
- e.preventDefault();
532
- if (!this.state.dropdownOpen) this.openDropdown(e);
533
- else this.input!.focus();
534
- }
535
- }
536
-
537
- onFocus(e: React.FocusEvent): void {
538
- let { instance } = this.props;
539
- let { widget } = instance;
540
- if (widget.trackFocus) {
541
- this.setState({
542
- focus: true,
543
- });
544
- }
545
- if (this.openDropdownOnFocus) this.openDropdown(e);
546
- }
547
-
548
- onKeyDown(e: React.KeyboardEvent): void {
549
- let { instance } = this.props;
550
- if (instance.widget.handleKeyDown(e, instance) === false) return;
551
-
552
- switch (e.keyCode) {
553
- case KeyCode.enter:
554
- e.stopPropagation();
555
- this.onChange((e.target as HTMLInputElement).value, "enter");
556
- break;
557
-
558
- case KeyCode.esc:
559
- if (this.state.dropdownOpen) {
560
- e.stopPropagation();
561
- this.closeDropdown(e, () => {
562
- this.input!.focus();
563
- });
564
- }
565
- break;
566
-
567
- case KeyCode.left:
568
- case KeyCode.right:
569
- e.stopPropagation();
570
- break;
571
-
572
- case KeyCode.down:
573
- this.openDropdown(e);
574
- e.stopPropagation();
575
- e.preventDefault();
576
- break;
577
- }
578
- }
579
-
580
- onBlur(e: React.FocusEvent): void {
581
- if (!this.state.dropdownOpen) this.props.instance.setState({ visited: true });
582
-
583
- if (this.state.focus)
584
- this.setState({
585
- focus: false,
586
- });
587
- this.onChange((e.target as HTMLInputElement).value, "blur");
588
- }
589
-
590
- closeDropdown(e?: React.KeyboardEvent | React.MouseEvent, callback?: () => void): void {
591
- if (this.state.dropdownOpen) {
592
- if (this.scrollableParents)
593
- this.scrollableParents.forEach((el) => {
594
- el.removeEventListener("scroll", this.updateDropdownPosition);
595
- });
596
-
597
- this.props.instance.setState({ visited: true });
598
- this.setState({ dropdownOpen: false }, callback);
599
- } else if (callback) callback();
600
- }
601
-
602
- openDropdown(e?: React.KeyboardEvent | React.MouseEvent | React.FocusEvent): void {
603
- const { data } = this.props.instance;
604
- this.openDropdownOnFocus = false;
605
-
606
- if (!this.state.dropdownOpen && !(data.disabled || data.readOnly)) {
607
- this.setState({ dropdownOpen: true });
608
- }
609
- }
610
514
 
611
- onClearClick(e: React.MouseEvent): void {
612
- e.stopPropagation();
515
+ let empty = this.input ? !this.input.value : data.empty;
516
+
517
+ return (
518
+ <div
519
+ className={CSS.expand(
520
+ data.classNames,
521
+ CSS.state({
522
+ visited: state.visited,
523
+ focus: this.state.focus || this.state.dropdownOpen,
524
+ icon: !!icon,
525
+ empty: empty && !data.placeholder,
526
+ error:
527
+ data.error &&
528
+ (state.visited || !suppressErrorsUntilVisited || !empty),
529
+ }),
530
+ )}
531
+ style={data.style}
532
+ onMouseDown={this.onMouseDown.bind(this)}
533
+ onTouchStart={stopPropagation}
534
+ onClick={stopPropagation}
535
+ >
536
+ <input
537
+ id={data.id}
538
+ ref={(el) => {
539
+ this.input = el;
540
+ }}
541
+ type="text"
542
+ className={CSS.expand(
543
+ CSS.element(baseClass, "input"),
544
+ data.inputClass,
545
+ )}
546
+ style={data.inputStyle}
547
+ defaultValue={data.formatted}
548
+ disabled={data.disabled}
549
+ readOnly={data.readOnly}
550
+ tabIndex={data.tabIndex}
551
+ placeholder={data.placeholder}
552
+ onInput={(e) =>
553
+ this.onChange((e.target as HTMLInputElement).value, "input")
554
+ }
555
+ onChange={(e) =>
556
+ this.onChange((e.target as HTMLInputElement).value, "change")
557
+ }
558
+ onKeyDown={(e) => this.onKeyDown(e)}
559
+ onBlur={(e) => {
560
+ this.onBlur(e);
561
+ }}
562
+ onFocus={(e) => {
563
+ this.onFocus(e);
564
+ }}
565
+ onMouseMove={(e) =>
566
+ tooltipMouseMove(e, ...getFieldTooltip(this.props.instance))
567
+ }
568
+ onMouseLeave={(e) =>
569
+ tooltipMouseLeave(e, ...getFieldTooltip(this.props.instance))
570
+ }
571
+ />
572
+ {icon}
573
+ {insideButton}
574
+ {dropdown}
575
+ {label}
576
+ {help}
577
+ </div>
578
+ );
579
+ }
580
+
581
+ onMouseDown(e: React.MouseEvent): void {
582
+ e.stopPropagation();
583
+
584
+ if (this.state.dropdownOpen) this.closeDropdown(e);
585
+ else {
586
+ this.openDropdownOnFocus = true;
587
+ }
588
+
589
+ //icon click
590
+ if (e.target != this.input) {
613
591
  e.preventDefault();
614
-
615
- const { instance } = this.props;
616
- const { widget } = instance;
617
-
618
- widget.handleSelect(instance, null, null);
619
- }
620
-
621
- UNSAFE_componentWillReceiveProps(props: MonthInputProps): void {
622
- const { data, state } = props.instance;
623
- if (data.formatted != this.input!.value && (data.formatted != this.props.data.formatted || !state.inputError)) {
624
- this.input!.value = data.formatted || "";
625
- props.instance.setState({
626
- inputError: false,
627
- });
628
- }
629
- tooltipParentWillReceiveProps(this.input!, ...getFieldTooltip(this.props.instance));
630
- }
631
-
632
- componentDidMount(): void {
633
- tooltipParentDidMount(this.input!, ...getFieldTooltip(this.props.instance));
634
- autoFocus(this.input, this);
635
- }
636
-
637
- componentDidUpdate(): void {
638
- autoFocus(this.input, this);
639
- }
640
-
641
- componentWillUnmount(): void {
642
- if (this.input == getActiveElement() && this.input.value != this.props.data.formatted) {
643
- this.onChange(this.input.value, "blur");
644
- }
645
- tooltipParentWillUnmount(this.props.instance);
646
- }
647
-
648
- onChange(inputValue: string, eventType: string): void {
649
- const { instance } = this.props;
650
- const { widget } = instance;
651
-
652
- if (widget.reactOn.indexOf(eventType) == -1) return;
653
-
654
- var parts = inputValue.split("-");
655
- var date1 = widget.parseDate(parts[0]);
656
- var date2 = widget.parseDate(parts[1]) || date1;
657
-
658
- if ((date1 != null && isNaN(date1.getTime())) || (date2 != null && isNaN(date2.getTime()))) {
659
- instance.setState({
660
- inputError: widget.inputErrorText,
661
- });
662
- } else if (eventType == "blur" || eventType == "enter") {
663
- if (date2) date2 = new Date(date2.getFullYear(), date2.getMonth() + 1, 1);
664
- instance.setState({
665
- visited: true,
666
- });
667
- widget.handleSelect(instance, date1, date2);
668
- }
669
- }
592
+ if (!this.state.dropdownOpen) this.openDropdown(e);
593
+ else this.input!.focus();
594
+ }
595
+ }
596
+
597
+ onFocus(e: React.FocusEvent): void {
598
+ let { instance } = this.props;
599
+ let { widget } = instance;
600
+ if (widget.trackFocus) {
601
+ this.setState({
602
+ focus: true,
603
+ });
604
+ }
605
+ if (this.openDropdownOnFocus) this.openDropdown(e);
606
+ }
607
+
608
+ onKeyDown(e: React.KeyboardEvent): void {
609
+ let { instance } = this.props;
610
+ if (instance.widget.handleKeyDown(e, instance) === false) return;
611
+
612
+ switch (e.keyCode) {
613
+ case KeyCode.enter:
614
+ e.stopPropagation();
615
+ this.onChange((e.target as HTMLInputElement).value, "enter");
616
+ break;
617
+
618
+ case KeyCode.esc:
619
+ if (this.state.dropdownOpen) {
620
+ e.stopPropagation();
621
+ this.closeDropdown(e, () => {
622
+ this.input!.focus();
623
+ });
624
+ }
625
+ break;
626
+
627
+ case KeyCode.left:
628
+ case KeyCode.right:
629
+ e.stopPropagation();
630
+ break;
631
+
632
+ case KeyCode.down:
633
+ this.openDropdown(e);
634
+ e.stopPropagation();
635
+ e.preventDefault();
636
+ break;
637
+ }
638
+ }
639
+
640
+ onBlur(e: React.FocusEvent): void {
641
+ if (!this.state.dropdownOpen)
642
+ this.props.instance.setState({ visited: true });
643
+
644
+ if (this.state.focus)
645
+ this.setState({
646
+ focus: false,
647
+ });
648
+ this.onChange((e.target as HTMLInputElement).value, "blur");
649
+ }
650
+
651
+ closeDropdown(
652
+ e?: React.KeyboardEvent | React.MouseEvent,
653
+ callback?: () => void,
654
+ ): void {
655
+ if (this.state.dropdownOpen) {
656
+ if (this.scrollableParents)
657
+ this.scrollableParents.forEach((el) => {
658
+ el.removeEventListener("scroll", this.updateDropdownPosition);
659
+ });
660
+
661
+ this.props.instance.setState({ visited: true });
662
+ this.setState({ dropdownOpen: false }, callback);
663
+ } else if (callback) callback();
664
+ }
665
+
666
+ openDropdown(
667
+ e?: React.KeyboardEvent | React.MouseEvent | React.FocusEvent,
668
+ ): void {
669
+ const { data } = this.props.instance;
670
+ this.openDropdownOnFocus = false;
671
+
672
+ if (!this.state.dropdownOpen && !(data.disabled || data.readOnly)) {
673
+ this.setState({ dropdownOpen: true });
674
+ }
675
+ }
676
+
677
+ onClearClick(e: React.MouseEvent): void {
678
+ e.stopPropagation();
679
+ e.preventDefault();
680
+
681
+ const { instance } = this.props;
682
+ const { widget } = instance;
683
+
684
+ widget.handleSelect(instance, null, null);
685
+ }
686
+
687
+ UNSAFE_componentWillReceiveProps(props: MonthInputProps): void {
688
+ const { data, state } = props.instance;
689
+ if (
690
+ data.formatted != this.input!.value &&
691
+ (data.formatted != this.props.data.formatted || !state.inputError)
692
+ ) {
693
+ this.input!.value = data.formatted || "";
694
+ props.instance.setState({
695
+ inputError: false,
696
+ });
697
+ }
698
+ tooltipParentWillReceiveProps(
699
+ this.input!,
700
+ ...getFieldTooltip(this.props.instance),
701
+ );
702
+ }
703
+
704
+ componentDidMount(): void {
705
+ tooltipParentDidMount(this.input!, ...getFieldTooltip(this.props.instance));
706
+ autoFocus(this.input, this);
707
+ }
708
+
709
+ componentDidUpdate(): void {
710
+ autoFocus(this.input, this);
711
+ }
712
+
713
+ componentWillUnmount(): void {
714
+ if (
715
+ this.input == getActiveElement() &&
716
+ this.input.value != this.props.data.formatted
717
+ ) {
718
+ this.onChange(this.input.value, "blur");
719
+ }
720
+ tooltipParentWillUnmount(this.props.instance);
721
+ }
722
+
723
+ onChange(inputValue: string, eventType: string): void {
724
+ const { instance } = this.props;
725
+ const { widget } = instance;
726
+
727
+ if (widget.reactOn.indexOf(eventType) == -1) return;
728
+
729
+ var parts = inputValue.split("-");
730
+ var date1 = widget.parseDate(parts[0]);
731
+ var date2 = widget.parseDate(parts[1]) || date1;
732
+
733
+ if (
734
+ (date1 != null && isNaN(date1.getTime())) ||
735
+ (date2 != null && isNaN(date2.getTime()))
736
+ ) {
737
+ instance.setState({
738
+ inputError: widget.inputErrorText,
739
+ });
740
+ } else if (eventType == "blur" || eventType == "enter") {
741
+ if (date2) date2 = new Date(date2.getFullYear(), date2.getMonth() + 1, 1);
742
+ instance.setState({
743
+ visited: true,
744
+ });
745
+ widget.handleSelect(instance, date1, date2);
746
+ }
747
+ }
670
748
  }