cx 24.0.3 → 24.2.0
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.
- package/dist/data.js +15 -26
- package/dist/manifest.js +738 -738
- package/dist/ui.js +1 -1
- package/dist/widgets.js +64 -40
- package/package.json +1 -1
- package/src/charts/ColorMap.js +4 -6
- package/src/charts/axis/Axis.d.ts +96 -96
- package/src/charts/axis/Axis.js +252 -252
- package/src/data/Expression.js +212 -212
- package/src/data/Expression.spec.js +174 -174
- package/src/data/StringTemplate.spec.js +105 -105
- package/src/ui/Controller.d.ts +182 -182
- package/src/ui/FocusManager.js +171 -171
- package/src/ui/Format.js +87 -87
- package/src/ui/Instance.d.ts +72 -72
- package/src/ui/keyboardShortcuts.js +4 -5
- package/src/ui/selection/KeySelection.d.ts +1 -1
- package/src/ui/selection/PropertySelection.d.ts +1 -1
- package/src/ui/selection/PropertySelection.js +2 -4
- package/src/ui/selection/Selection.d.ts +1 -1
- package/src/widgets/form/ColorField.js +14 -9
- package/src/widgets/form/ColorPicker.scss +275 -275
- package/src/widgets/form/ColorPicker.variables.scss +22 -22
- package/src/widgets/form/DateTimeField.js +10 -6
- package/src/widgets/form/Label.js +88 -88
- package/src/widgets/form/LookupField.d.ts +8 -9
- package/src/widgets/form/MonthField.js +10 -6
- package/src/widgets/form/NumberField.js +8 -4
- package/src/widgets/form/TextArea.js +10 -6
- package/src/widgets/form/TextField.js +11 -9
- package/src/widgets/form/UploadButton.d.ts +34 -34
- package/src/widgets/form/index.js +1 -2
- package/src/widgets/grid/Grid.d.ts +11 -8
- package/src/widgets/grid/Grid.js +3277 -3277
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
$cx-default-colorpicker-font-family: "Consolas", monospace !default;
|
|
2
|
-
$cx-default-colorpicker-font-size: 11px !default;
|
|
3
|
-
$cx-default-colorpicker-background-color: $cx-default-input-background-color !default;
|
|
4
|
-
$cx-default-colorpicker-border-width: $cx-default-box-border-width !default;
|
|
5
|
-
$cx-default-colorpicker-border-color: $cx-default-input-border-color !default;
|
|
6
|
-
$cx-default-colorpicker-box-shadow: none !default;
|
|
7
|
-
|
|
8
|
-
$cx-colorpicker-state-style-map: cx-deep-map-merge(
|
|
9
|
-
$cx-input-state-style-map,
|
|
10
|
-
(
|
|
11
|
-
default: (
|
|
12
|
-
font-family: $cx-default-colorpicker-font-family,
|
|
13
|
-
font-size: $cx-default-colorpicker-font-size,
|
|
14
|
-
background-color: $cx-default-colorpicker-background-color,
|
|
15
|
-
border-width: $cx-default-colorpicker-border-width,
|
|
16
|
-
border-color: $cx-default-colorpicker-border-color,
|
|
17
|
-
box-shadow: $cx-default-colorpicker-box-shadow,
|
|
18
|
-
padding: 2px,
|
|
19
|
-
),
|
|
20
|
-
hover: (),
|
|
21
|
-
)
|
|
22
|
-
) !default;
|
|
1
|
+
$cx-default-colorpicker-font-family: "Consolas", monospace !default;
|
|
2
|
+
$cx-default-colorpicker-font-size: 11px !default;
|
|
3
|
+
$cx-default-colorpicker-background-color: $cx-default-input-background-color !default;
|
|
4
|
+
$cx-default-colorpicker-border-width: $cx-default-box-border-width !default;
|
|
5
|
+
$cx-default-colorpicker-border-color: $cx-default-input-border-color !default;
|
|
6
|
+
$cx-default-colorpicker-box-shadow: none !default;
|
|
7
|
+
|
|
8
|
+
$cx-colorpicker-state-style-map: cx-deep-map-merge(
|
|
9
|
+
$cx-input-state-style-map,
|
|
10
|
+
(
|
|
11
|
+
default: (
|
|
12
|
+
font-family: $cx-default-colorpicker-font-family,
|
|
13
|
+
font-size: $cx-default-colorpicker-font-size,
|
|
14
|
+
background-color: $cx-default-colorpicker-background-color,
|
|
15
|
+
border-width: $cx-default-colorpicker-border-width,
|
|
16
|
+
border-color: $cx-default-colorpicker-border-color,
|
|
17
|
+
box-shadow: $cx-default-colorpicker-box-shadow,
|
|
18
|
+
padding: 2px,
|
|
19
|
+
),
|
|
20
|
+
hover: (),
|
|
21
|
+
)
|
|
22
|
+
) !default;
|
|
@@ -26,6 +26,7 @@ import { stopPropagation } from "../../util/eventCallbacks";
|
|
|
26
26
|
import { Format } from "../../util/Format";
|
|
27
27
|
import { TimeList } from "./TimeList";
|
|
28
28
|
import { autoFocus } from "../autoFocus";
|
|
29
|
+
import { getActiveElement } from "../../util";
|
|
29
30
|
|
|
30
31
|
export class DateTimeField extends Field {
|
|
31
32
|
declareData() {
|
|
@@ -362,8 +363,8 @@ class DateTimeInput extends VDOM.Component {
|
|
|
362
363
|
tabIndex={data.tabIndex}
|
|
363
364
|
placeholder={data.placeholder}
|
|
364
365
|
{...data.inputAttrs}
|
|
365
|
-
onInput={(e) => this.onChange(e, "input")}
|
|
366
|
-
onChange={(e) => this.onChange(e, "change")}
|
|
366
|
+
onInput={(e) => this.onChange(e.target.value, "input")}
|
|
367
|
+
onChange={(e) => this.onChange(e.target.value, "change")}
|
|
367
368
|
onKeyDown={(e) => this.onKeyDown(e)}
|
|
368
369
|
onBlur={(e) => {
|
|
369
370
|
this.onBlur(e);
|
|
@@ -421,7 +422,7 @@ class DateTimeInput extends VDOM.Component {
|
|
|
421
422
|
|
|
422
423
|
switch (e.keyCode) {
|
|
423
424
|
case KeyCode.enter:
|
|
424
|
-
this.onChange(e, "enter");
|
|
425
|
+
this.onChange(e.target.value, "enter");
|
|
425
426
|
break;
|
|
426
427
|
|
|
427
428
|
case KeyCode.esc:
|
|
@@ -453,7 +454,7 @@ class DateTimeInput extends VDOM.Component {
|
|
|
453
454
|
this.setState({
|
|
454
455
|
focus: false,
|
|
455
456
|
});
|
|
456
|
-
this.onChange(e, "blur");
|
|
457
|
+
this.onChange(e.target.value, "blur");
|
|
457
458
|
}
|
|
458
459
|
|
|
459
460
|
closeDropdown(e, callback) {
|
|
@@ -509,10 +510,13 @@ class DateTimeInput extends VDOM.Component {
|
|
|
509
510
|
}
|
|
510
511
|
|
|
511
512
|
componentWillUnmount() {
|
|
513
|
+
if (this.input == getActiveElement()) {
|
|
514
|
+
this.onChange(this.input.value, "blur");
|
|
515
|
+
}
|
|
512
516
|
tooltipParentWillUnmount(this.props.instance);
|
|
513
517
|
}
|
|
514
518
|
|
|
515
|
-
onChange(
|
|
519
|
+
onChange(inputValue, eventType) {
|
|
516
520
|
let { instance, data } = this.props;
|
|
517
521
|
let { widget } = instance;
|
|
518
522
|
|
|
@@ -522,7 +526,7 @@ class DateTimeInput extends VDOM.Component {
|
|
|
522
526
|
|
|
523
527
|
if (eventType == "enter") instance.setState({ visited: true });
|
|
524
528
|
|
|
525
|
-
this.setValue(
|
|
529
|
+
this.setValue(inputValue, data.value);
|
|
526
530
|
}
|
|
527
531
|
|
|
528
532
|
setValue(text, baseValue) {
|
|
@@ -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.
|
|
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
|
-
|
|
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:
|
|
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:
|
|
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>> {}
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
} from "../overlay/tooltip-ops";
|
|
28
28
|
import { Field, getFieldTooltip } from "./Field";
|
|
29
29
|
import { MonthPicker } from "./MonthPicker";
|
|
30
|
+
import { getActiveElement } from "../../util/getActiveElement";
|
|
30
31
|
|
|
31
32
|
export class MonthField extends Field {
|
|
32
33
|
declareData() {
|
|
@@ -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(
|
|
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 =
|
|
500
|
+
var parts = inputValue.split("-");
|
|
497
501
|
var date1 = widget.parseDate(parts[0]);
|
|
498
502
|
var date2 = widget.parseDate(parts[1]) || date1;
|
|
499
503
|
|
|
@@ -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
|
-
//
|
|
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
|
-
//
|
|
417
|
-
//
|
|
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
|
-
//
|
|
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(
|
|
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: !
|
|
165
|
+
empty: !inputValue,
|
|
162
166
|
});
|
|
163
167
|
}
|
|
164
168
|
|
|
165
169
|
if (instance.widget.reactOn.indexOf(change) != -1) {
|
|
166
|
-
let value =
|
|
170
|
+
let value = inputValue || widget.emptyValue;
|
|
167
171
|
instance.set("value", value);
|
|
168
172
|
}
|
|
169
173
|
}
|
|
@@ -15,6 +15,7 @@ import { Localization } from "../../ui/Localization";
|
|
|
15
15
|
import ClearIcon from "../icons/clear";
|
|
16
16
|
import { autoFocus } from "../autoFocus";
|
|
17
17
|
import { isString } from "../../util/isString";
|
|
18
|
+
import { getActiveElement } from "../../util/getActiveElement";
|
|
18
19
|
|
|
19
20
|
export class TextField extends Field {
|
|
20
21
|
init() {
|
|
@@ -104,7 +105,7 @@ class Input extends VDOM.Component {
|
|
|
104
105
|
<div
|
|
105
106
|
className={CSS.element(baseClass, "left-icon")}
|
|
106
107
|
onMouseDown={preventDefault}
|
|
107
|
-
onClick={(e) => this.onChange(e, "enter")}
|
|
108
|
+
onClick={(e) => this.onChange(e.target.value, "enter")}
|
|
108
109
|
>
|
|
109
110
|
{iconVDOM}
|
|
110
111
|
</div>
|
|
@@ -164,8 +165,8 @@ class Input extends VDOM.Component {
|
|
|
164
165
|
{...data.inputAttrs}
|
|
165
166
|
onMouseMove={this.onMouseMove.bind(this)}
|
|
166
167
|
onMouseLeave={this.onMouseLeave.bind(this)}
|
|
167
|
-
onInput={(e) => this.onChange(e, "input")}
|
|
168
|
-
onChange={(e) => this.onChange(e, "change")}
|
|
168
|
+
onInput={(e) => this.onChange(e.target.value, "input")}
|
|
169
|
+
onChange={(e) => this.onChange(e.target.value, "change")}
|
|
169
170
|
onKeyDown={this.onKeyDown.bind(this)}
|
|
170
171
|
onFocus={this.onFocus.bind(this)}
|
|
171
172
|
onBlur={this.onBlur.bind(this)}
|
|
@@ -198,7 +199,7 @@ class Input extends VDOM.Component {
|
|
|
198
199
|
});
|
|
199
200
|
this.props.instance.set("focused", false);
|
|
200
201
|
}
|
|
201
|
-
this.onChange(e, "blur");
|
|
202
|
+
this.onChange(e.target.value, "blur");
|
|
202
203
|
}
|
|
203
204
|
|
|
204
205
|
onClearClick(e) {
|
|
@@ -223,6 +224,7 @@ class Input extends VDOM.Component {
|
|
|
223
224
|
}
|
|
224
225
|
|
|
225
226
|
componentWillUnmount() {
|
|
227
|
+
if (this.input == getActiveElement()) this.onChange(this.input.value, "blur");
|
|
226
228
|
tooltipParentWillUnmount(this.props.instance);
|
|
227
229
|
}
|
|
228
230
|
|
|
@@ -232,7 +234,7 @@ class Input extends VDOM.Component {
|
|
|
232
234
|
|
|
233
235
|
switch (e.keyCode) {
|
|
234
236
|
case KeyCode.enter:
|
|
235
|
-
this.onChange(e, "enter");
|
|
237
|
+
this.onChange(e.target.value, "enter");
|
|
236
238
|
break;
|
|
237
239
|
|
|
238
240
|
case KeyCode.left:
|
|
@@ -244,13 +246,13 @@ class Input extends VDOM.Component {
|
|
|
244
246
|
|
|
245
247
|
UNSAFE_componentWillReceiveProps(props) {
|
|
246
248
|
let { data } = props;
|
|
247
|
-
//
|
|
248
|
-
//and update may be caused by some other property, i.e. visited
|
|
249
|
+
// The second check is required for debouncing, sometimes the value in the store lags after the input
|
|
250
|
+
// and update may be caused by some other property, i.e. visited
|
|
249
251
|
if (data.value != this.input.value && data.value != this.props.data.value) this.input.value = data.value || "";
|
|
250
252
|
tooltipParentWillReceiveProps(this.input, ...getFieldTooltip(props.instance));
|
|
251
253
|
}
|
|
252
254
|
|
|
253
|
-
onChange(
|
|
255
|
+
onChange(textValue, change) {
|
|
254
256
|
let { instance, data } = this.props;
|
|
255
257
|
|
|
256
258
|
let immediate = change == "blur" || change == "enter";
|
|
@@ -262,7 +264,7 @@ class Input extends VDOM.Component {
|
|
|
262
264
|
let { widget } = instance;
|
|
263
265
|
|
|
264
266
|
if (widget.reactOn.indexOf(change) != -1) {
|
|
265
|
-
let text = this.trimmed(
|
|
267
|
+
let text = this.trimmed(textValue);
|
|
266
268
|
if (data.maxLength != null && text.length > data.maxLength) {
|
|
267
269
|
text = text.substring(0, data.maxLength);
|
|
268
270
|
this.input.value = text;
|
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
import * as Cx from "../../core";
|
|
2
|
-
import { FieldProps } from "./Field";
|
|
3
|
-
|
|
4
|
-
interface UploadButtonProps extends FieldProps {
|
|
5
|
-
/** Text description. */
|
|
6
|
-
text?: Cx.StringProp;
|
|
7
|
-
|
|
8
|
-
url?: Cx.StringProp;
|
|
9
|
-
|
|
10
|
-
/** Base CSS class to be applied to the element. Default is 'uploadbutton'. */
|
|
11
|
-
baseClass?: string;
|
|
12
|
-
|
|
13
|
-
/** Defaults to `false`. Set to `true` to enable multiple selection. */
|
|
14
|
-
multiple?: boolean;
|
|
15
|
-
|
|
16
|
-
method?: string;
|
|
17
|
-
uploadInProgressText?: string;
|
|
18
|
-
|
|
19
|
-
/** Defaults to `false`. Set to `true` to abort uploads if the button is destroyed (unmounted). */
|
|
20
|
-
abortOnDestroy?: boolean;
|
|
21
|
-
|
|
22
|
-
/** Defines file types that are accepted for upload. */
|
|
23
|
-
accept?: Cx.StringProp;
|
|
24
|
-
|
|
25
|
-
/** Name of the icon to be put on the left side of the button. */
|
|
26
|
-
icon?: Cx.StringProp;
|
|
27
|
-
|
|
28
|
-
onUploadStarting?: ((xhr: XMLHttpRequest, instance: any, file: File, formData: FormData) => boolean) | string;
|
|
29
|
-
onUploadComplete?: ((xhr: XMLHttpRequest, instance: any, file: File, formData: FormData) => void) | string;
|
|
30
|
-
onUploadProgress?: ((event: ProgressEvent, instance: any, file: File, formData: FormData) => void) | string;
|
|
31
|
-
onUploadError?: ((event: ProgressEvent, instance: any, file: File, formData: FormData) => void) | string;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export class UploadButton extends Cx.Widget<UploadButtonProps> {}
|
|
1
|
+
import * as Cx from "../../core";
|
|
2
|
+
import { FieldProps } from "./Field";
|
|
3
|
+
|
|
4
|
+
interface UploadButtonProps extends FieldProps {
|
|
5
|
+
/** Text description. */
|
|
6
|
+
text?: Cx.StringProp;
|
|
7
|
+
|
|
8
|
+
url?: Cx.StringProp;
|
|
9
|
+
|
|
10
|
+
/** Base CSS class to be applied to the element. Default is 'uploadbutton'. */
|
|
11
|
+
baseClass?: string;
|
|
12
|
+
|
|
13
|
+
/** Defaults to `false`. Set to `true` to enable multiple selection. */
|
|
14
|
+
multiple?: boolean;
|
|
15
|
+
|
|
16
|
+
method?: string;
|
|
17
|
+
uploadInProgressText?: string;
|
|
18
|
+
|
|
19
|
+
/** Defaults to `false`. Set to `true` to abort uploads if the button is destroyed (unmounted). */
|
|
20
|
+
abortOnDestroy?: boolean;
|
|
21
|
+
|
|
22
|
+
/** Defines file types that are accepted for upload. */
|
|
23
|
+
accept?: Cx.StringProp;
|
|
24
|
+
|
|
25
|
+
/** Name of the icon to be put on the left side of the button. */
|
|
26
|
+
icon?: Cx.StringProp;
|
|
27
|
+
|
|
28
|
+
onUploadStarting?: ((xhr: XMLHttpRequest, instance: any, file: File, formData: FormData) => boolean) | string;
|
|
29
|
+
onUploadComplete?: ((xhr: XMLHttpRequest, instance: any, file: File, formData: FormData) => void) | string;
|
|
30
|
+
onUploadProgress?: ((event: ProgressEvent, instance: any, file: File, formData: FormData) => void) | string;
|
|
31
|
+
onUploadError?: ((event: ProgressEvent, instance: any, file: File, formData: FormData) => void) | string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export class UploadButton extends Cx.Widget<UploadButtonProps> {}
|