cx 24.0.3 → 24.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/charts.js +61 -63
  2. package/dist/data.js +50 -70
  3. package/dist/manifest.js +719 -713
  4. package/dist/svg.js +70 -71
  5. package/dist/ui.js +104 -112
  6. package/dist/util.js +94 -13
  7. package/dist/widgets.js +273 -257
  8. package/package.json +1 -1
  9. package/src/charts/ColorMap.js +4 -6
  10. package/src/charts/axis/Axis.d.ts +96 -96
  11. package/src/charts/axis/Axis.js +252 -252
  12. package/src/charts/axis/TimeAxis.js +7 -6
  13. package/src/data/Expression.js +212 -212
  14. package/src/data/Expression.spec.js +174 -174
  15. package/src/data/StringTemplate.spec.js +105 -105
  16. package/src/ui/Controller.d.ts +182 -182
  17. package/src/ui/FocusManager.js +171 -171
  18. package/src/ui/Format.js +88 -87
  19. package/src/ui/Instance.d.ts +72 -72
  20. package/src/ui/keyboardShortcuts.js +4 -5
  21. package/src/ui/selection/KeySelection.d.ts +1 -1
  22. package/src/ui/selection/PropertySelection.d.ts +1 -1
  23. package/src/ui/selection/PropertySelection.js +2 -4
  24. package/src/ui/selection/Selection.d.ts +1 -1
  25. package/src/util/Format.js +73 -86
  26. package/src/util/date/index.d.ts +10 -9
  27. package/src/util/date/index.js +10 -9
  28. package/src/util/date/parseDateInvariant.d.ts +3 -0
  29. package/src/util/date/parseDateInvariant.js +20 -0
  30. package/src/widgets/form/Calendar.js +27 -26
  31. package/src/widgets/form/ColorField.js +14 -9
  32. package/src/widgets/form/ColorPicker.scss +275 -275
  33. package/src/widgets/form/ColorPicker.variables.scss +22 -22
  34. package/src/widgets/form/DateTimeField.js +18 -11
  35. package/src/widgets/form/DateTimePicker.js +9 -8
  36. package/src/widgets/form/Label.js +88 -88
  37. package/src/widgets/form/LookupField.d.ts +8 -9
  38. package/src/widgets/form/MonthField.js +17 -13
  39. package/src/widgets/form/MonthPicker.js +17 -16
  40. package/src/widgets/form/NumberField.js +8 -4
  41. package/src/widgets/form/TextArea.js +10 -6
  42. package/src/widgets/form/TextField.js +11 -9
  43. package/src/widgets/form/UploadButton.d.ts +34 -34
  44. package/src/widgets/form/index.js +1 -2
  45. package/src/widgets/grid/Grid.d.ts +11 -8
  46. package/src/widgets/grid/Grid.js +3277 -3277
@@ -5,6 +5,7 @@ import { WheelComponent } from "./Wheel";
5
5
  import { oneFocusOut, offFocusOut } from "../../ui/FocusManager";
6
6
 
7
7
  import { enableCultureSensitiveFormatting } from "../../ui/Format";
8
+ import { parseDateInvariant } from "../../util";
8
9
  enableCultureSensitiveFormatting();
9
10
 
10
11
  export class DateTimePicker extends Widget {
@@ -37,7 +38,7 @@ DateTimePicker.prototype.showSeconds = false;
37
38
  class DateTimePickerComponent extends VDOM.Component {
38
39
  constructor(props) {
39
40
  super(props);
40
- let date = props.data.value ? new Date(props.data.value) : new Date();
41
+ let date = props.data.value ? parseDateInvariant(props.data.value) : new Date();
41
42
  if (isNaN(date.getTime())) date = new Date();
42
43
  this.state = {
43
44
  date: date,
@@ -67,7 +68,7 @@ class DateTimePickerComponent extends VDOM.Component {
67
68
  }
68
69
 
69
70
  UNSAFE_componentWillReceiveProps(props) {
70
- let date = props.data.value ? new Date(props.data.value) : new Date();
71
+ let date = props.data.value ? parseDateInvariant(props.data.value) : new Date();
71
72
  if (isNaN(date.getTime())) date = new Date();
72
73
  this.setState({ date });
73
74
  }
@@ -160,7 +161,7 @@ class DateTimePickerComponent extends VDOM.Component {
160
161
  (state) => ({
161
162
  date: this.setDateComponent(this.state.date, "year", newIndex + 1970),
162
163
  }),
163
- this.handleChange
164
+ this.handleChange,
164
165
  );
165
166
  }}
166
167
  onPipeKeyDown={(kd) => {
@@ -186,7 +187,7 @@ class DateTimePickerComponent extends VDOM.Component {
186
187
  (state) => ({
187
188
  date: this.setDateComponent(this.state.date, "month", newIndex),
188
189
  }),
189
- this.handleChange
190
+ this.handleChange,
190
191
  );
191
192
  }}
192
193
  onPipeKeyDown={(kd) => {
@@ -214,7 +215,7 @@ class DateTimePickerComponent extends VDOM.Component {
214
215
  (state) => ({
215
216
  date: this.setDateComponent(this.state.date, "date", newIndex + 1),
216
217
  }),
217
- this.handleChange
218
+ this.handleChange,
218
219
  );
219
220
  }}
220
221
  onPipeKeyDown={(kd) => {
@@ -240,7 +241,7 @@ class DateTimePickerComponent extends VDOM.Component {
240
241
  (state) => ({
241
242
  date: this.setDateComponent(this.state.date, "hours", newIndex),
242
243
  }),
243
- this.handleChange
244
+ this.handleChange,
244
245
  );
245
246
  }}
246
247
  onPipeKeyDown={(kd) => {
@@ -266,7 +267,7 @@ class DateTimePickerComponent extends VDOM.Component {
266
267
  (state) => ({
267
268
  date: this.setDateComponent(this.state.date, "minutes", newIndex),
268
269
  }),
269
- this.handleChange
270
+ this.handleChange,
270
271
  );
271
272
  }}
272
273
  onPipeKeyDown={(kd) => {
@@ -292,7 +293,7 @@ class DateTimePickerComponent extends VDOM.Component {
292
293
  (state) => ({
293
294
  date: this.setDateComponent(this.state.date, "seconds", newIndex),
294
295
  }),
295
- this.handleChange
296
+ this.handleChange,
296
297
  );
297
298
  }}
298
299
  onPipeKeyDown={(kd) => {
@@ -1,88 +1,88 @@
1
- import { Widget, VDOM } from "../../ui/Widget";
2
- import { HtmlElement } from "../HtmlElement";
3
- import { FocusManager } from "../../ui/FocusManager";
4
- import { isArray } from "../../util/isArray";
5
- import { coalesce } from "../../util/coalesce";
6
-
7
- export class Label extends HtmlElement {
8
- declareData() {
9
- super.declareData(...arguments, {
10
- required: undefined,
11
- disabled: undefined,
12
- htmlFor: undefined,
13
- });
14
- }
15
-
16
- prepareData(context, instance) {
17
- let { data } = instance;
18
- data.stateMods = {
19
- ...data.stateMods,
20
- disabled: data.disabled,
21
- };
22
- data._disabled = data.disabled;
23
- super.prepareData(context, instance);
24
- }
25
-
26
- explore(context, instance) {
27
- let { data } = instance;
28
-
29
- if (!data.htmlFor) data.htmlFor = context.lastFieldId;
30
-
31
- data.disabled = data.stateMods.disabled = coalesce(
32
- context.parentStrict ? context.parentDisabled : null,
33
- data._disabled,
34
- context.parentDisabled
35
- );
36
-
37
- data.asterisk = context.parentAsterisk || this.asterisk;
38
-
39
- if (instance.cache("disabled", data.disabled) || instance.cache("asterisk", data.asterisk)) {
40
- instance.markShouldUpdate(context);
41
- this.prepareCSS(context, instance);
42
- }
43
-
44
- super.explore(context, instance);
45
- }
46
-
47
- isValidHtmlAttribute(attrName) {
48
- switch (attrName) {
49
- case "asterisk":
50
- case "required":
51
- return false;
52
- }
53
- return super.isValidHtmlAttribute(attrName);
54
- }
55
-
56
- attachProps(context, instance, props) {
57
- super.attachProps(context, instance, props);
58
-
59
- let { data } = instance;
60
-
61
- if (data.htmlFor) {
62
- props.htmlFor = data.htmlFor;
63
-
64
- if (!props.onClick)
65
- props.onClick = () => {
66
- //additional focus for LookupFields which are not input based
67
- let el = document.getElementById(instance.data.htmlFor);
68
- if (el) FocusManager.focusFirst(el);
69
- };
70
- }
71
-
72
- if (!props.id && data.htmlFor) props.id = `${data.htmlFor}-label`;
73
-
74
- if (data.required && data.asterisk) {
75
- if (!isArray(props.children)) props.children = [props.children];
76
- props.children.push(" ");
77
- props.children.push(
78
- <span key="asterisk" className={this.CSS.element(this.baseClass, "asterisk")}>
79
- *
80
- </span>
81
- );
82
- }
83
- }
84
- }
85
-
86
- Label.prototype.baseClass = "label";
87
- Label.prototype.tag = "label";
88
- Label.prototype.asterisk = false;
1
+ import { Widget, VDOM } from "../../ui/Widget";
2
+ import { HtmlElement } from "../HtmlElement";
3
+ import { FocusManager } from "../../ui/FocusManager";
4
+ import { isArray } from "../../util/isArray";
5
+ import { coalesce } from "../../util/coalesce";
6
+
7
+ export class Label extends HtmlElement {
8
+ declareData() {
9
+ super.declareData(...arguments, {
10
+ required: undefined,
11
+ disabled: undefined,
12
+ htmlFor: undefined,
13
+ });
14
+ }
15
+
16
+ prepareData(context, instance) {
17
+ let { data } = instance;
18
+ data.stateMods = {
19
+ ...data.stateMods,
20
+ disabled: data.disabled,
21
+ };
22
+ data._disabled = data.disabled;
23
+ super.prepareData(context, instance);
24
+ }
25
+
26
+ explore(context, instance) {
27
+ let { data } = instance;
28
+
29
+ if (!data.htmlFor) data.htmlFor = context.lastFieldId;
30
+
31
+ data.disabled = data.stateMods.disabled = coalesce(
32
+ context.parentStrict ? context.parentDisabled : null,
33
+ data._disabled,
34
+ context.parentDisabled
35
+ );
36
+
37
+ data.asterisk = context.parentAsterisk || this.asterisk;
38
+
39
+ if (instance.cache("disabled", data.disabled) || instance.cache("asterisk", data.asterisk)) {
40
+ instance.markShouldUpdate(context);
41
+ this.prepareCSS(context, instance);
42
+ }
43
+
44
+ super.explore(context, instance);
45
+ }
46
+
47
+ isValidHtmlAttribute(attrName) {
48
+ switch (attrName) {
49
+ case "asterisk":
50
+ case "required":
51
+ return false;
52
+ }
53
+ return super.isValidHtmlAttribute(attrName);
54
+ }
55
+
56
+ attachProps(context, instance, props) {
57
+ super.attachProps(context, instance, props);
58
+
59
+ let { data } = instance;
60
+
61
+ if (data.htmlFor) {
62
+ props.htmlFor = data.htmlFor;
63
+
64
+ if (!props.onClick)
65
+ props.onClick = () => {
66
+ //additional focus for LookupFields which are not input based
67
+ let el = document.getElementById(instance.data.htmlFor);
68
+ if (el) FocusManager.focusFirst(el);
69
+ };
70
+ }
71
+
72
+ if (!props.id && data.htmlFor) props.id = `${data.htmlFor}-label`;
73
+
74
+ if (data.required && data.asterisk) {
75
+ if (!isArray(props.children)) props.children = [props.children];
76
+ props.children.push(" ");
77
+ props.children.push(
78
+ <span key="asterisk" className={this.CSS.element(this.baseClass, "asterisk")}>
79
+ *
80
+ </span>
81
+ );
82
+ }
83
+ }
84
+ }
85
+
86
+ Label.prototype.baseClass = "label";
87
+ Label.prototype.tag = "label";
88
+ Label.prototype.asterisk = false;
@@ -8,7 +8,7 @@ export interface LookupBinding {
8
8
  key?: boolean;
9
9
  }
10
10
 
11
- interface LookupFieldProps extends FieldProps {
11
+ interface LookupFieldProps<T = unknown> extends FieldProps {
12
12
  /** Defaults to `false`. Set to `true` to enable multiple selection. */
13
13
  multiple?: Cx.BooleanProp;
14
14
 
@@ -31,7 +31,7 @@ interface LookupFieldProps extends FieldProps {
31
31
  placeholder?: Cx.StringProp;
32
32
 
33
33
  /** A list of available options. */
34
- options?: Cx.RecordsProp;
34
+ options?: Cx.Prop<T[]>;
35
35
 
36
36
  /**
37
37
  * Set to `true` to hide the clear button. It can be used interchangeably with the `showClear` property.
@@ -128,10 +128,9 @@ interface LookupFieldProps extends FieldProps {
128
128
  icon?: Cx.StringProp | Cx.Record;
129
129
 
130
130
  /** Query function. */
131
- onQuery?: (
132
- query: string | { query: string; page: number; pageSize: number },
133
- instance: Instance,
134
- ) => Cx.Record[] | Promise<Cx.Record>;
131
+ onQuery?:
132
+ | string
133
+ | ((query: string | { query: string; page: number; pageSize: number }, instance: Instance) => T[] | Promise<T[]>);
135
134
 
136
135
  /** Set to true to sort dropdown options. */
137
136
  sort?: boolean;
@@ -165,10 +164,10 @@ interface LookupFieldProps extends FieldProps {
165
164
  filterParams?: Cx.StructuredProp;
166
165
 
167
166
  /** Callback to create a filter function for given filter params. */
168
- onCreateVisibleOptionsFilter?: (filterParams: any, instance?: Instance) => (record: Record) => boolean;
167
+ onCreateVisibleOptionsFilter?: (filterParams: any, instance?: Instance) => (record: T) => boolean;
169
168
 
170
169
  /** Used in multiple selection lookups in combination with records, to construct the display text out of multiple fields or when additional formatting is needed. */
171
- onGetRecordDisplayText?: (record: any, instance?: Instance) => string;
170
+ onGetRecordDisplayText?: (record: T, instance?: Instance) => string;
172
171
  }
173
172
 
174
- export class LookupField extends Cx.Widget<LookupFieldProps> {}
173
+ export class LookupField<T = unknown> extends Cx.Widget<LookupFieldProps<T>> {}
@@ -13,7 +13,6 @@ import { stopPropagation } from "../../util/eventCallbacks";
13
13
  import { isDefined } from "../../util/isDefined";
14
14
  import { isTouchDevice } from "../../util/isTouchDevice";
15
15
  import { isTouchEvent } from "../../util/isTouchEvent";
16
- import { Icon } from "../Icon";
17
16
  import { autoFocus } from "../autoFocus";
18
17
  import ClearIcon from "../icons/clear";
19
18
  import DropdownIcon from "../icons/drop-down";
@@ -27,6 +26,8 @@ import {
27
26
  } from "../overlay/tooltip-ops";
28
27
  import { Field, getFieldTooltip } from "./Field";
29
28
  import { MonthPicker } from "./MonthPicker";
29
+ import { getActiveElement } from "../../util/getActiveElement";
30
+ import { parseDateInvariant } from "../../util";
30
31
 
31
32
  export class MonthField extends Field {
32
33
  declareData() {
@@ -92,11 +93,11 @@ export class MonthField extends Field {
92
93
  };
93
94
 
94
95
  if (!this.range && data.value) {
95
- data.date = new Date(data.value);
96
+ data.date = parseDateInvariant(data.value);
96
97
  data.formatted = this.culture.format(data.date, formatOptions);
97
98
  } else if (this.range && data.from && data.to) {
98
- data.from = new Date(data.from);
99
- data.to = new Date(data.to);
99
+ data.from = parseDateInvariant(data.from);
100
+ data.to = parseDateInvariant(data.to);
100
101
  data.to.setDate(data.to.getDate() - 1);
101
102
  let fromStr = this.culture.format(data.from, formatOptions);
102
103
  let toStr = this.culture.format(data.to, formatOptions);
@@ -104,11 +105,11 @@ export class MonthField extends Field {
104
105
  else data.formatted = fromStr;
105
106
  }
106
107
 
107
- if (data.refDate) data.refDate = monthStart(new Date(data.refDate));
108
+ if (data.refDate) data.refDate = monthStart(parseDateInvariant(data.refDate));
108
109
 
109
- if (data.maxValue) data.maxValue = monthStart(new Date(data.maxValue));
110
+ if (data.maxValue) data.maxValue = monthStart(parseDateInvariant(data.maxValue));
110
111
 
111
- if (data.minValue) data.minValue = monthStart(new Date(data.minValue));
112
+ if (data.minValue) data.minValue = monthStart(parseDateInvariant(data.minValue));
112
113
 
113
114
  instance.lastDropdown = context.lastDropdown;
114
115
  }
@@ -342,8 +343,8 @@ class MonthInput extends VDOM.Component {
342
343
  readOnly={data.readOnly}
343
344
  tabIndex={data.tabIndex}
344
345
  placeholder={data.placeholder}
345
- onInput={(e) => this.onChange(e, "input")}
346
- onChange={(e) => this.onChange(e, "change")}
346
+ onInput={(e) => this.onChange(e.target.value, "input")}
347
+ onChange={(e) => this.onChange(e.target.value, "change")}
347
348
  onKeyDown={(e) => this.onKeyDown(e)}
348
349
  onBlur={(e) => {
349
350
  this.onBlur(e);
@@ -397,7 +398,7 @@ class MonthInput extends VDOM.Component {
397
398
  switch (e.keyCode) {
398
399
  case KeyCode.enter:
399
400
  e.stopPropagation();
400
- this.onChange(e, "enter");
401
+ this.onChange(e.target.value, "enter");
401
402
  break;
402
403
 
403
404
  case KeyCode.esc:
@@ -429,7 +430,7 @@ class MonthInput extends VDOM.Component {
429
430
  this.setState({
430
431
  focus: false,
431
432
  });
432
- this.onChange(e, "blur");
433
+ this.onChange(e.target.value, "blur");
433
434
  }
434
435
 
435
436
  closeDropdown(e, callback) {
@@ -484,16 +485,19 @@ class MonthInput extends VDOM.Component {
484
485
  }
485
486
 
486
487
  componentWillUnmount() {
488
+ if (this.input == getActiveElement()) {
489
+ this.onChange(this.input.value, "blur");
490
+ }
487
491
  tooltipParentWillUnmount(this.props.instance);
488
492
  }
489
493
 
490
- onChange(e, eventType) {
494
+ onChange(inputValue, eventType) {
491
495
  var { instance } = this.props;
492
496
  var { widget } = instance;
493
497
 
494
498
  if (widget.reactOn.indexOf(eventType) == -1) return;
495
499
 
496
- var parts = e.target.value.split("-");
500
+ var parts = inputValue.split("-");
497
501
  var date1 = widget.parseDate(parts[0]);
498
502
  var date2 = widget.parseDate(parts[1]) || date1;
499
503
 
@@ -26,6 +26,7 @@ import { isTouchEvent } from "../../util/isTouchEvent";
26
26
  import { getCursorPos } from "../overlay/captureMouse";
27
27
 
28
28
  import { enableCultureSensitiveFormatting } from "../../ui/Format";
29
+ import { parseDateInvariant } from "../../util";
29
30
  enableCultureSensitiveFormatting();
30
31
 
31
32
  export class MonthPicker extends Field {
@@ -59,7 +60,7 @@ export class MonthPicker extends Field {
59
60
  maxValue: undefined,
60
61
  maxExclusive: undefined,
61
62
  },
62
- ...arguments
63
+ ...arguments,
63
64
  );
64
65
  }
65
66
 
@@ -72,19 +73,19 @@ export class MonthPicker extends Field {
72
73
  disabled: data.disabled,
73
74
  };
74
75
 
75
- if (!this.range && data.value) data.date = monthStart(new Date(data.value));
76
+ if (!this.range && data.value) data.date = monthStart(parseDateInvariant(data.value));
76
77
 
77
78
  if (this.range) {
78
- if (data.from) data.from = monthStart(new Date(data.from));
79
+ if (data.from) data.from = monthStart(parseDateInvariant(data.from));
79
80
 
80
- if (data.to) data.to = monthStart(new Date(data.to));
81
+ if (data.to) data.to = monthStart(parseDateInvariant(data.to));
81
82
  }
82
83
 
83
- if (data.refDate) data.refDate = monthStart(new Date(data.refDate));
84
+ if (data.refDate) data.refDate = monthStart(parseDateInvariant(data.refDate));
84
85
 
85
- if (data.maxValue) data.maxValue = monthStart(new Date(data.maxValue));
86
+ if (data.maxValue) data.maxValue = monthStart(parseDateInvariant(data.maxValue));
86
87
 
87
- if (data.minValue) data.minValue = monthStart(new Date(data.minValue));
88
+ if (data.minValue) data.minValue = monthStart(parseDateInvariant(data.minValue));
88
89
 
89
90
  super.prepareData(...arguments);
90
91
  }
@@ -272,7 +273,7 @@ export class MonthPickerComponent extends VDOM.Component {
272
273
  cursorQuarter: (cursorQuarter + 3) % 4,
273
274
  cursorYear: cursorQuarter == 0 ? cursorYear - 1 : cursorYear,
274
275
  },
275
- { ensureVisible: true }
276
+ { ensureVisible: true },
276
277
  );
277
278
  else if (column == "M")
278
279
  if (cursorMonth > 3) this.moveCursor(e, { cursorMonth: cursorMonth - 3 }, { ensureVisible: true });
@@ -280,7 +281,7 @@ export class MonthPickerComponent extends VDOM.Component {
280
281
  this.moveCursor(
281
282
  e,
282
283
  { cursorMonth: cursorMonth + 9, cursorYear: cursorYear - 1 },
283
- { ensureVisible: true }
284
+ { ensureVisible: true },
284
285
  );
285
286
  break;
286
287
 
@@ -293,7 +294,7 @@ export class MonthPickerComponent extends VDOM.Component {
293
294
  cursorQuarter: (cursorQuarter + 1) % 4,
294
295
  cursorYear: cursorQuarter == 3 ? cursorYear + 1 : cursorYear,
295
296
  },
296
- { ensureVisible: true }
297
+ { ensureVisible: true },
297
298
  );
298
299
  else if (column == "M")
299
300
  if (cursorMonth < 10) this.moveCursor(e, { cursorMonth: cursorMonth + 3 }, { ensureVisible: true });
@@ -301,7 +302,7 @@ export class MonthPickerComponent extends VDOM.Component {
301
302
  this.moveCursor(
302
303
  e,
303
304
  { cursorMonth: cursorMonth - 9, cursorYear: cursorYear + 1 },
304
- { ensureVisible: true }
305
+ { ensureVisible: true },
305
306
  );
306
307
  break;
307
308
 
@@ -470,7 +471,7 @@ export class MonthPickerComponent extends VDOM.Component {
470
471
  onMouseUp={this.handleMouseUp}
471
472
  >
472
473
  {y}
473
- </th>
474
+ </th>,
474
475
  );
475
476
 
476
477
  for (let i = 0; i < 3; i++) {
@@ -500,7 +501,7 @@ export class MonthPickerComponent extends VDOM.Component {
500
501
  onTouchEnd={this.handleMouseUp}
501
502
  >
502
503
  {monthNames[m - 1].substr(0, 3)}
503
- </td>
504
+ </td>,
504
505
  );
505
506
  }
506
507
  row.push(
@@ -519,7 +520,7 @@ export class MonthPickerComponent extends VDOM.Component {
519
520
  onMouseUp={this.handleMouseUp}
520
521
  >
521
522
  {`Q${q + 1}`}
522
- </th>
523
+ </th>,
523
524
  );
524
525
  rows.push(row);
525
526
  }
@@ -568,7 +569,7 @@ export class MonthPickerComponent extends VDOM.Component {
568
569
  let visibleItems = ceil5(Math.ceil(this.dom.el.offsetHeight / this.state.yearHeight));
569
570
  let start = Math.max(
570
571
  startYear,
571
- startYear + floor5(Math.floor(this.dom.el.scrollTop / this.state.yearHeight)) - visibleItems
572
+ startYear + floor5(Math.floor(this.dom.el.scrollTop / this.state.yearHeight)) - visibleItems,
572
573
  );
573
574
  if (start != this.state.start && start + bufferSize <= endYear) {
574
575
  this.setState({
@@ -606,7 +607,7 @@ export class MonthPickerComponent extends VDOM.Component {
606
607
  this.dom.el.scrollTop =
607
608
  (this.state.cursorYear - startYear + yearCount / 2) * this.state.yearHeight -
608
609
  this.dom.el.offsetHeight / 2;
609
- }
610
+ },
610
611
  );
611
612
  }
612
613
 
@@ -16,6 +16,7 @@ import ClearIcon from "../icons/clear";
16
16
  import { isString } from "../../util/isString";
17
17
  import { isNumber } from "../../util/isNumber";
18
18
  import { isDefined } from "../../util/isDefined";
19
+ import { getActiveElement } from "../../util/getActiveElement";
19
20
 
20
21
  import { enableCultureSensitiveFormatting } from "../../ui/Format";
21
22
  import { KeyCode } from "../../util/KeyCode";
@@ -248,6 +249,9 @@ class Input extends VDOM.Component {
248
249
  }
249
250
 
250
251
  componentWillUnmount() {
252
+ if (this.input == getActiveElement()) {
253
+ this.onChange({ target: { value: this.input.value } }, "blur");
254
+ }
251
255
  tooltipParentWillUnmount(this.props.instance);
252
256
  }
253
257
 
@@ -409,12 +413,12 @@ class Input extends VDOM.Component {
409
413
  let decimalSeparator = this.getDecimalSeparator(fmt) || Format.value(1.1, "n;1")[1];
410
414
 
411
415
  let formatted = Format.value(value, fmt);
412
- //re-parse to avoid differences between formatted value and value in the store
416
+ // Re-parse to avoid differences between formatted value and value in the store
413
417
 
414
418
  value = widget.parseValue(formatted, instance) * data.scale + data.offset;
415
419
 
416
- //allow users to type numbers like 100.0003 or -0.05 without interruptions
417
- //if the last typed in character is zero or dot (decimal separator) skip processing it
420
+ // Allow users to type numbers like 100.0003 or -0.05 without interruptions
421
+ // If the last typed character is zero or dot (decimal separator), skip processing it
418
422
  if (
419
423
  change == "change" &&
420
424
  this.input.selectionStart == this.input.selectionEnd &&
@@ -426,7 +430,7 @@ class Input extends VDOM.Component {
426
430
  return;
427
431
 
428
432
  if (change != "blur") {
429
- //format, but keep the correct cursor position
433
+ // Format, but keep the correct cursor position
430
434
  let preCursorText = this.getPreCursorDigits(this.input.value, this.input.selectionStart, decimalSeparator);
431
435
  this.input.value = formatted;
432
436
  this.updateCursorPosition(preCursorText);
@@ -11,6 +11,7 @@ import {
11
11
  import { stopPropagation } from "../../util/eventCallbacks";
12
12
  import { KeyCode } from "../../util/KeyCode";
13
13
  import { autoFocus } from "../autoFocus";
14
+ import { getActiveElement } from "../../util/getActiveElement";
14
15
 
15
16
  export class TextArea extends TextField {
16
17
  declareData() {
@@ -93,10 +94,10 @@ class Input extends VDOM.Component {
93
94
  tabIndex={data.tabIndex}
94
95
  placeholder={data.placeholder}
95
96
  {...data.inputAttrs}
96
- onInput={(e) => this.onChange(e, "input")}
97
- onChange={(e) => this.onChange(e, "change")}
97
+ onInput={(e) => this.onChange(e.target.value, "input")}
98
+ onChange={(e) => this.onChange(e.target.value, "change")}
98
99
  onBlur={(e) => {
99
- this.onChange(e, "blur");
100
+ this.onChange(e.target.value, "blur");
100
101
  }}
101
102
  onFocus={(e) => this.onFocus()}
102
103
  onClick={stopPropagation}
@@ -111,6 +112,9 @@ class Input extends VDOM.Component {
111
112
  }
112
113
 
113
114
  componentWillUnmount() {
115
+ if (this.input == getActiveElement()) {
116
+ this.onChange(this.input.value, "blur");
117
+ }
114
118
  tooltipParentWillUnmount(this.props.instance);
115
119
  }
116
120
 
@@ -144,7 +148,7 @@ class Input extends VDOM.Component {
144
148
  tooltipParentWillReceiveProps(this.input, ...getFieldTooltip(instance));
145
149
  }
146
150
 
147
- onChange(e, change) {
151
+ onChange(inputValue, change) {
148
152
  let { instance, data } = this.props;
149
153
  let { widget } = instance;
150
154
 
@@ -158,12 +162,12 @@ class Input extends VDOM.Component {
158
162
 
159
163
  if (data.required) {
160
164
  instance.setState({
161
- empty: !e.target.value,
165
+ empty: !inputValue,
162
166
  });
163
167
  }
164
168
 
165
169
  if (instance.widget.reactOn.indexOf(change) != -1) {
166
- let value = e.target.value || widget.emptyValue;
170
+ let value = inputValue || widget.emptyValue;
167
171
  instance.set("value", value);
168
172
  }
169
173
  }