cx 24.6.4 → 24.7.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.
@@ -1,289 +1,289 @@
1
- import { Widget, VDOM, getContent } from "../../ui/Widget";
2
- import { Field, getFieldTooltip } from "./Field";
3
- import {
4
- tooltipParentWillReceiveProps,
5
- tooltipParentWillUnmount,
6
- tooltipMouseMove,
7
- tooltipMouseLeave,
8
- tooltipParentDidMount,
9
- } from "../overlay/tooltip-ops";
10
- import { stopPropagation, preventDefault } from "../../util/eventCallbacks";
11
- import { StringTemplate } from "../../data/StringTemplate";
12
- import { Icon } from "../Icon";
13
- import { KeyCode } from "../../util/KeyCode";
14
- import { Localization } from "../../ui/Localization";
15
- import ClearIcon from "../icons/clear";
16
- import { autoFocus } from "../autoFocus";
17
- import { isString } from "../../util/isString";
18
- import { getActiveElement } from "../../util/getActiveElement";
19
-
20
- export class TextField extends Field {
21
- init() {
22
- if (typeof this.hideClear !== "undefined") this.showClear = !this.hideClear;
23
-
24
- if (this.alwaysShowClear) this.showClear = true;
25
-
26
- super.init();
27
- }
28
-
29
- declareData() {
30
- super.declareData(
31
- {
32
- value: this.emptyValue,
33
- disabled: undefined,
34
- readOnly: undefined,
35
- enabled: undefined,
36
- placeholder: undefined,
37
- required: undefined,
38
- minLength: undefined,
39
- maxLength: undefined,
40
- icon: undefined,
41
- trim: undefined,
42
- },
43
- ...arguments,
44
- );
45
- }
46
-
47
- renderInput(context, instance, key) {
48
- return (
49
- <Input
50
- key={key}
51
- instance={instance}
52
- data={instance.data}
53
- label={this.labelPlacement && getContent(this.renderLabel(context, instance, "label"))}
54
- help={this.helpPlacement && getContent(this.renderHelp(context, instance, "help"))}
55
- icon={this.renderIcon(context, instance, "icon")}
56
- />
57
- );
58
- }
59
-
60
- validate(context, instance) {
61
- super.validate(context, instance);
62
-
63
- let { data } = instance;
64
-
65
- if (!data.error && data.value) {
66
- if (this.validationRegExp) this.validationRegExp.lastIndex = 0;
67
- if (this.validationRegExp && !this.validationRegExp.test(data.value)) data.error = this.validationErrorText;
68
- else if (typeof data.value === "string" && data.minLength != null && data.value.length < data.minLength)
69
- data.error = StringTemplate.format(this.minLengthValidationErrorText, data.minLength, data.value.length);
70
- else if (typeof data.value === "string" && data.maxLength != null && data.value.length > data.maxLength)
71
- data.error = StringTemplate.format(this.maxLengthValidationErrorText, data.maxLength, data.value.length);
72
- }
73
- }
74
- }
75
-
76
- TextField.prototype.baseClass = "textfield";
77
- TextField.prototype.reactOn = "change input blur enter";
78
- TextField.prototype.inputType = "text";
79
- TextField.prototype.validationErrorText = "The entered value is not valid.";
80
- TextField.prototype.minLengthValidationErrorText = "Enter {[{0}-{1}]} more character(s).";
81
- TextField.prototype.maxLengthValidationErrorText = "Use {0} characters or fewer.";
82
- TextField.prototype.suppressErrorsUntilVisited = true;
83
- TextField.prototype.icon = null;
84
- TextField.prototype.showClear = false;
85
- TextField.prototype.alwaysShowClear = false;
86
- TextField.prototype.keyboardShortcut = false;
87
- TextField.prototype.trim = false;
88
-
89
- Localization.registerPrototype("cx/widgets/TextField", TextField);
90
-
91
- class Input extends VDOM.Component {
92
- constructor(props) {
93
- super(props);
94
- this.state = {
95
- focus: false,
96
- };
97
- }
98
-
99
- render() {
100
- let { instance, data, label, help, icon: iconVDOM } = this.props;
101
- let { widget, state } = instance;
102
- let { CSS, baseClass, suppressErrorsUntilVisited } = widget;
103
-
104
- let icon = iconVDOM && (
105
- <div
106
- className={CSS.element(baseClass, "left-icon")}
107
- onMouseDown={preventDefault}
108
- onClick={(e) => this.onChange(e.target.value, "enter")}
109
- >
110
- {iconVDOM}
111
- </div>
112
- );
113
-
114
- let insideButton;
115
- if (
116
- widget.showClear &&
117
- !data.empty &&
118
- !data.readOnly &&
119
- !data.disabled &&
120
- (widget.alwaysShowClear || !data.required)
121
- ) {
122
- insideButton = (
123
- <div
124
- className={CSS.element(baseClass, "clear")}
125
- onMouseDown={(e) => e.preventDefault()}
126
- onClick={(e) => this.onClearClick(e)}
127
- >
128
- <ClearIcon className={CSS.element(baseClass, "icon")} />
129
- </div>
130
- );
131
- }
132
-
133
- let empty = this.input ? !this.trimmed(this.input.value) : data.empty;
134
-
135
- return (
136
- <div
137
- className={CSS.expand(
138
- data.classNames,
139
- CSS.state({
140
- visited: state.visited,
141
- focus: this.state.focus,
142
- icon: !!icon,
143
- clear: insideButton != null,
144
- empty: empty && !data.placeholder,
145
- error: data.error && (state.visited || !suppressErrorsUntilVisited || !empty),
146
- }),
147
- )}
148
- style={data.style}
149
- onMouseDown={stopPropagation}
150
- onTouchStart={stopPropagation}
151
- >
152
- <input
153
- ref={(el) => {
154
- this.input = el;
155
- }}
156
- className={CSS.expand(CSS.element(baseClass, "input"), data.inputClass)}
157
- defaultValue={data.value}
158
- id={data.id}
159
- style={data.inputStyle}
160
- type={widget.inputType}
161
- disabled={data.disabled}
162
- readOnly={data.readOnly}
163
- tabIndex={data.tabIndex}
164
- placeholder={data.placeholder}
165
- {...data.inputAttrs}
166
- onMouseMove={this.onMouseMove.bind(this)}
167
- onMouseLeave={this.onMouseLeave.bind(this)}
168
- onInput={(e) => this.onChange(e.target.value, "input")}
169
- onChange={(e) => this.onChange(e.target.value, "change")}
170
- onKeyDown={this.onKeyDown.bind(this)}
171
- onFocus={this.onFocus.bind(this)}
172
- onBlur={this.onBlur.bind(this)}
173
- onClick={stopPropagation}
174
- />
175
- {insideButton}
176
- {icon}
177
- {label}
178
- {help}
179
- </div>
180
- );
181
- }
182
-
183
- onFocus() {
184
- let { instance, data } = this.props;
185
- let { widget } = instance;
186
- if (widget.trackFocus) {
187
- this.setState({
188
- focus: true,
189
- });
190
- instance.set("focused", true);
191
- }
192
- if (data.error && data.value) instance.setState({ visited: true });
193
- }
194
-
195
- onBlur(e) {
196
- if (this.state.focus) {
197
- this.setState({
198
- focus: false,
199
- });
200
- this.props.instance.set("focused", false);
201
- }
202
- this.onChange(e.target.value, "blur");
203
- }
204
-
205
- onClearClick(e) {
206
- this.input.value = ""; // prevent onChange call with old text value on blur or component unmount
207
- this.props.instance.set("value", this.props.instance.widget.emptyValue, { immediate: true });
208
- }
209
-
210
- onMouseMove(e) {
211
- tooltipMouseMove(e, ...getFieldTooltip(this.props.instance));
212
- }
213
-
214
- onMouseLeave(e) {
215
- tooltipMouseLeave(e, ...getFieldTooltip(this.props.instance));
216
- }
217
-
218
- componentDidMount() {
219
- tooltipParentDidMount(this.input, ...getFieldTooltip(this.props.instance));
220
- autoFocus(this.input, this);
221
- }
222
-
223
- componentDidUpdate() {
224
- autoFocus(this.input, this);
225
- }
226
-
227
- componentWillUnmount() {
228
- if (this.input == getActiveElement()) this.onChange(this.input.value, "blur");
229
- tooltipParentWillUnmount(this.props.instance);
230
- }
231
-
232
- onKeyDown(e) {
233
- let { instance } = this.props;
234
- if (instance.widget.handleKeyDown(e, instance) === false) return;
235
-
236
- switch (e.keyCode) {
237
- case KeyCode.enter:
238
- this.onChange(e.target.value, "enter");
239
- break;
240
-
241
- case KeyCode.left:
242
- case KeyCode.right:
243
- e.stopPropagation();
244
- break;
245
- }
246
- }
247
-
248
- UNSAFE_componentWillReceiveProps(props) {
249
- let { data } = props;
250
- // The second check is required for debouncing, sometimes the value in the store lags after the input
251
- // and update may be caused by some other property, i.e. visited
252
- if (data.value != this.input.value && data.value != this.props.data.value) this.input.value = data.value || "";
253
- tooltipParentWillReceiveProps(this.input, ...getFieldTooltip(props.instance));
254
- }
255
-
256
- onChange(textValue, change) {
257
- let { instance, data } = this.props;
258
-
259
- let immediate = change == "blur" || change == "enter";
260
-
261
- if (immediate) {
262
- instance.setState({ visited: true });
263
- }
264
-
265
- let { widget } = instance;
266
-
267
- if (widget.reactOn.indexOf(change) != -1) {
268
- let text = this.trimmed(textValue);
269
- if (data.maxLength != null && text.length > data.maxLength) {
270
- text = text.substring(0, data.maxLength);
271
- this.input.value = text;
272
- }
273
-
274
- let value = text || widget.emptyValue;
275
- if (!instance.set("value", value, { immediate })) {
276
- if (text != this.input.value && immediate) this.input.value = text;
277
- } else {
278
- if (value) instance.setState({ visited: true });
279
- }
280
- }
281
- }
282
-
283
- trimmed(value) {
284
- if (this.props.data.trim && isString(value)) return value.trim();
285
- return value;
286
- }
287
- }
288
-
289
- Widget.alias("textfield", TextField);
1
+ import { Widget, VDOM, getContent } from "../../ui/Widget";
2
+ import { Field, getFieldTooltip } from "./Field";
3
+ import {
4
+ tooltipParentWillReceiveProps,
5
+ tooltipParentWillUnmount,
6
+ tooltipMouseMove,
7
+ tooltipMouseLeave,
8
+ tooltipParentDidMount,
9
+ } from "../overlay/tooltip-ops";
10
+ import { stopPropagation, preventDefault } from "../../util/eventCallbacks";
11
+ import { StringTemplate } from "../../data/StringTemplate";
12
+ import { Icon } from "../Icon";
13
+ import { KeyCode } from "../../util/KeyCode";
14
+ import { Localization } from "../../ui/Localization";
15
+ import ClearIcon from "../icons/clear";
16
+ import { autoFocus } from "../autoFocus";
17
+ import { isString } from "../../util/isString";
18
+ import { getActiveElement } from "../../util/getActiveElement";
19
+
20
+ export class TextField extends Field {
21
+ init() {
22
+ if (typeof this.hideClear !== "undefined") this.showClear = !this.hideClear;
23
+
24
+ if (this.alwaysShowClear) this.showClear = true;
25
+
26
+ super.init();
27
+ }
28
+
29
+ declareData() {
30
+ super.declareData(
31
+ {
32
+ value: this.emptyValue,
33
+ disabled: undefined,
34
+ readOnly: undefined,
35
+ enabled: undefined,
36
+ placeholder: undefined,
37
+ required: undefined,
38
+ minLength: undefined,
39
+ maxLength: undefined,
40
+ icon: undefined,
41
+ trim: undefined,
42
+ },
43
+ ...arguments,
44
+ );
45
+ }
46
+
47
+ renderInput(context, instance, key) {
48
+ return (
49
+ <Input
50
+ key={key}
51
+ instance={instance}
52
+ data={instance.data}
53
+ label={this.labelPlacement && getContent(this.renderLabel(context, instance, "label"))}
54
+ help={this.helpPlacement && getContent(this.renderHelp(context, instance, "help"))}
55
+ icon={this.renderIcon(context, instance, "icon")}
56
+ />
57
+ );
58
+ }
59
+
60
+ validate(context, instance) {
61
+ super.validate(context, instance);
62
+
63
+ let { data } = instance;
64
+
65
+ if (!data.error && data.value) {
66
+ if (this.validationRegExp) this.validationRegExp.lastIndex = 0;
67
+ if (this.validationRegExp && !this.validationRegExp.test(data.value)) data.error = this.validationErrorText;
68
+ else if (typeof data.value === "string" && data.minLength != null && data.value.length < data.minLength)
69
+ data.error = StringTemplate.format(this.minLengthValidationErrorText, data.minLength, data.value.length);
70
+ else if (typeof data.value === "string" && data.maxLength != null && data.value.length > data.maxLength)
71
+ data.error = StringTemplate.format(this.maxLengthValidationErrorText, data.maxLength, data.value.length);
72
+ }
73
+ }
74
+ }
75
+
76
+ TextField.prototype.baseClass = "textfield";
77
+ TextField.prototype.reactOn = "change input blur enter";
78
+ TextField.prototype.inputType = "text";
79
+ TextField.prototype.validationErrorText = "The entered value is not valid.";
80
+ TextField.prototype.minLengthValidationErrorText = "Enter {[{0}-{1}]} more character(s).";
81
+ TextField.prototype.maxLengthValidationErrorText = "Use {0} characters or fewer.";
82
+ TextField.prototype.suppressErrorsUntilVisited = true;
83
+ TextField.prototype.icon = null;
84
+ TextField.prototype.showClear = false;
85
+ TextField.prototype.alwaysShowClear = false;
86
+ TextField.prototype.keyboardShortcut = false;
87
+ TextField.prototype.trim = false;
88
+
89
+ Localization.registerPrototype("cx/widgets/TextField", TextField);
90
+
91
+ class Input extends VDOM.Component {
92
+ constructor(props) {
93
+ super(props);
94
+ this.state = {
95
+ focus: false,
96
+ };
97
+ }
98
+
99
+ render() {
100
+ let { instance, data, label, help, icon: iconVDOM } = this.props;
101
+ let { widget, state } = instance;
102
+ let { CSS, baseClass, suppressErrorsUntilVisited } = widget;
103
+
104
+ let icon = iconVDOM && (
105
+ <div
106
+ className={CSS.element(baseClass, "left-icon")}
107
+ onMouseDown={preventDefault}
108
+ onClick={(e) => this.onChange(e.target.value, "enter")}
109
+ >
110
+ {iconVDOM}
111
+ </div>
112
+ );
113
+
114
+ let insideButton;
115
+ if (
116
+ widget.showClear &&
117
+ !data.empty &&
118
+ !data.readOnly &&
119
+ !data.disabled &&
120
+ (widget.alwaysShowClear || !data.required)
121
+ ) {
122
+ insideButton = (
123
+ <div
124
+ className={CSS.element(baseClass, "clear")}
125
+ onMouseDown={(e) => e.preventDefault()}
126
+ onClick={(e) => this.onClearClick(e)}
127
+ >
128
+ <ClearIcon className={CSS.element(baseClass, "icon")} />
129
+ </div>
130
+ );
131
+ }
132
+
133
+ let empty = this.input ? !this.trimmed(this.input.value) : data.empty;
134
+
135
+ return (
136
+ <div
137
+ className={CSS.expand(
138
+ data.classNames,
139
+ CSS.state({
140
+ visited: state.visited,
141
+ focus: this.state.focus,
142
+ icon: !!icon,
143
+ clear: insideButton != null,
144
+ empty: empty && !data.placeholder,
145
+ error: data.error && (state.visited || !suppressErrorsUntilVisited || !empty),
146
+ }),
147
+ )}
148
+ style={data.style}
149
+ onMouseDown={stopPropagation}
150
+ onTouchStart={stopPropagation}
151
+ >
152
+ <input
153
+ ref={(el) => {
154
+ this.input = el;
155
+ }}
156
+ className={CSS.expand(CSS.element(baseClass, "input"), data.inputClass)}
157
+ defaultValue={data.value}
158
+ id={data.id}
159
+ style={data.inputStyle}
160
+ type={widget.inputType}
161
+ disabled={data.disabled}
162
+ readOnly={data.readOnly}
163
+ tabIndex={data.tabIndex}
164
+ placeholder={data.placeholder}
165
+ {...data.inputAttrs}
166
+ onMouseMove={this.onMouseMove.bind(this)}
167
+ onMouseLeave={this.onMouseLeave.bind(this)}
168
+ onInput={(e) => this.onChange(e.target.value, "input")}
169
+ onChange={(e) => this.onChange(e.target.value, "change")}
170
+ onKeyDown={this.onKeyDown.bind(this)}
171
+ onFocus={this.onFocus.bind(this)}
172
+ onBlur={this.onBlur.bind(this)}
173
+ onClick={stopPropagation}
174
+ />
175
+ {insideButton}
176
+ {icon}
177
+ {label}
178
+ {help}
179
+ </div>
180
+ );
181
+ }
182
+
183
+ onFocus() {
184
+ let { instance, data } = this.props;
185
+ let { widget } = instance;
186
+ if (widget.trackFocus) {
187
+ this.setState({
188
+ focus: true,
189
+ });
190
+ instance.set("focused", true);
191
+ }
192
+ if (data.error && data.value) instance.setState({ visited: true });
193
+ }
194
+
195
+ onBlur(e) {
196
+ if (this.state.focus) {
197
+ this.setState({
198
+ focus: false,
199
+ });
200
+ this.props.instance.set("focused", false);
201
+ }
202
+ this.onChange(e.target.value, "blur");
203
+ }
204
+
205
+ onClearClick(e) {
206
+ this.input.value = ""; // prevent onChange call with old text value on blur or component unmount
207
+ this.props.instance.set("value", this.props.instance.widget.emptyValue, { immediate: true });
208
+ }
209
+
210
+ onMouseMove(e) {
211
+ tooltipMouseMove(e, ...getFieldTooltip(this.props.instance));
212
+ }
213
+
214
+ onMouseLeave(e) {
215
+ tooltipMouseLeave(e, ...getFieldTooltip(this.props.instance));
216
+ }
217
+
218
+ componentDidMount() {
219
+ tooltipParentDidMount(this.input, ...getFieldTooltip(this.props.instance));
220
+ autoFocus(this.input, this);
221
+ }
222
+
223
+ componentDidUpdate() {
224
+ autoFocus(this.input, this);
225
+ }
226
+
227
+ componentWillUnmount() {
228
+ if (this.input == getActiveElement()) this.onChange(this.input.value, "blur");
229
+ tooltipParentWillUnmount(this.props.instance);
230
+ }
231
+
232
+ onKeyDown(e) {
233
+ let { instance } = this.props;
234
+ if (instance.widget.handleKeyDown(e, instance) === false) return;
235
+
236
+ switch (e.keyCode) {
237
+ case KeyCode.enter:
238
+ this.onChange(e.target.value, "enter");
239
+ break;
240
+
241
+ case KeyCode.left:
242
+ case KeyCode.right:
243
+ e.stopPropagation();
244
+ break;
245
+ }
246
+ }
247
+
248
+ UNSAFE_componentWillReceiveProps(props) {
249
+ let { data } = props;
250
+ // The second check is required for debouncing, sometimes the value in the store lags after the input
251
+ // and update may be caused by some other property, i.e. visited
252
+ if (data.value != this.input.value && data.value != this.props.data.value) this.input.value = data.value || "";
253
+ tooltipParentWillReceiveProps(this.input, ...getFieldTooltip(props.instance));
254
+ }
255
+
256
+ onChange(textValue, change) {
257
+ let { instance, data } = this.props;
258
+
259
+ let immediate = change == "blur" || change == "enter";
260
+
261
+ if (immediate) {
262
+ instance.setState({ visited: true });
263
+ }
264
+
265
+ let { widget } = instance;
266
+
267
+ if (widget.reactOn.indexOf(change) != -1) {
268
+ let text = this.trimmed(textValue);
269
+ if (data.maxLength != null && text.length > data.maxLength) {
270
+ text = text.substring(0, data.maxLength);
271
+ this.input.value = text;
272
+ }
273
+
274
+ let value = text || widget.emptyValue;
275
+ if (!instance.set("value", value, { immediate })) {
276
+ if (text != this.input.value && immediate) this.input.value = text;
277
+ } else {
278
+ if (value) instance.setState({ visited: true });
279
+ }
280
+ }
281
+ }
282
+
283
+ trimmed(value) {
284
+ if (this.props.data.trim && isString(value)) return value.trim();
285
+ return value;
286
+ }
287
+ }
288
+
289
+ Widget.alias("textfield", TextField);
@@ -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> {}