@gitlab/ui 107.7.1 → 108.0.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/CHANGELOG.md +13 -0
- package/dist/components/base/form/form_input/form_input.js +605 -36
- package/dist/utils/utils.js +1 -0
- package/package.json +1 -1
- package/src/components/base/form/form_input/form_input.md +306 -1
- package/src/components/base/form/form_input/form_input.vue +579 -34
- package/src/utils/utils.js +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
# [108.0.0](https://gitlab.com/gitlab-org/gitlab-ui/compare/v107.7.1...v108.0.0) (2025-02-03)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* remove BFormInput from GlFormInput ([f71e397](https://gitlab.com/gitlab-org/gitlab-ui/commit/f71e397e62bc04b6163bf585bbcaad94d332eece))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### BREAKING CHANGES
|
|
10
|
+
|
|
11
|
+
* Remove support for `size` prop which does not have
|
|
12
|
+
any effect anyway.
|
|
13
|
+
|
|
1
14
|
## [107.7.1](https://gitlab.com/gitlab-org/gitlab-ui/compare/v107.7.0...v107.7.1) (2025-01-31)
|
|
2
15
|
|
|
3
16
|
|
|
@@ -1,21 +1,41 @@
|
|
|
1
1
|
import isObject from 'lodash/isObject';
|
|
2
|
-
import
|
|
2
|
+
import uniqueId from 'lodash/uniqueId';
|
|
3
|
+
import isBoolean from 'lodash/isBoolean';
|
|
4
|
+
import toInteger from 'lodash/toInteger';
|
|
5
|
+
import toString from 'lodash/toString';
|
|
6
|
+
import { toFloat } from '../../../../utils/number_utils';
|
|
7
|
+
import { stopEvent, isVisible } from '../../../../utils/utils';
|
|
3
8
|
import { formInputWidths } from '../../../../utils/constants';
|
|
4
9
|
import __vue_normalize__ from 'vue-runtime-helpers/dist/normalize-component.js';
|
|
5
10
|
|
|
11
|
+
// Valid supported input types
|
|
12
|
+
const TYPES = ['text', 'password', 'email', 'number', 'url', 'tel', 'search', 'range', 'color', 'date', 'time', 'datetime', 'datetime-local', 'month', 'week'];
|
|
6
13
|
const MODEL_PROP = 'value';
|
|
7
14
|
const MODEL_EVENT = 'input';
|
|
8
15
|
var script = {
|
|
9
16
|
name: 'GlFormInput',
|
|
10
|
-
components: {
|
|
11
|
-
BFormInput
|
|
12
|
-
},
|
|
13
|
-
inheritAttrs: false,
|
|
14
17
|
model: {
|
|
15
18
|
prop: MODEL_PROP,
|
|
16
19
|
event: MODEL_EVENT
|
|
17
20
|
},
|
|
18
21
|
props: {
|
|
22
|
+
/**
|
|
23
|
+
* The current value of the input. Result will always be a string, except when the `number` prop is used
|
|
24
|
+
*/
|
|
25
|
+
value: {
|
|
26
|
+
type: [Number, String],
|
|
27
|
+
required: false,
|
|
28
|
+
default: ''
|
|
29
|
+
},
|
|
30
|
+
/**
|
|
31
|
+
* The type of input to render.
|
|
32
|
+
*/
|
|
33
|
+
type: {
|
|
34
|
+
type: String,
|
|
35
|
+
required: false,
|
|
36
|
+
default: 'text',
|
|
37
|
+
validator: value => TYPES.includes(value)
|
|
38
|
+
},
|
|
19
39
|
/**
|
|
20
40
|
* Maximum width of the input
|
|
21
41
|
*/
|
|
@@ -27,10 +47,251 @@ var script = {
|
|
|
27
47
|
const widths = isObject(value) ? Object.values(value) : [value];
|
|
28
48
|
return widths.every(width => Object.values(formInputWidths).includes(width));
|
|
29
49
|
}
|
|
50
|
+
},
|
|
51
|
+
/**
|
|
52
|
+
* Used to set the `id` attribute on the rendered content, and used as the base to generate any additional element IDs as needed
|
|
53
|
+
*/
|
|
54
|
+
id: {
|
|
55
|
+
type: String,
|
|
56
|
+
required: false,
|
|
57
|
+
default: undefined
|
|
58
|
+
},
|
|
59
|
+
/**
|
|
60
|
+
* When set to `true`, attempts to auto-focus the control when it is mounted, or re-activated when in a keep-alive. Does not set the `autofocus` attribute on the control
|
|
61
|
+
*/
|
|
62
|
+
autofocus: {
|
|
63
|
+
type: Boolean,
|
|
64
|
+
required: false,
|
|
65
|
+
default: false
|
|
66
|
+
},
|
|
67
|
+
/**
|
|
68
|
+
* When set to `true`, disables the component's functionality and places it in a disabled state
|
|
69
|
+
*/
|
|
70
|
+
disabled: {
|
|
71
|
+
type: Boolean,
|
|
72
|
+
required: false,
|
|
73
|
+
default: false
|
|
74
|
+
},
|
|
75
|
+
/**
|
|
76
|
+
* ID of the form that the form control belongs to. Sets the `form` attribute on the control
|
|
77
|
+
*/
|
|
78
|
+
form: {
|
|
79
|
+
type: String,
|
|
80
|
+
required: false,
|
|
81
|
+
default: undefined
|
|
82
|
+
},
|
|
83
|
+
/**
|
|
84
|
+
* Sets the value of the `name` attribute on the form control
|
|
85
|
+
*/
|
|
86
|
+
name: {
|
|
87
|
+
type: String,
|
|
88
|
+
required: false,
|
|
89
|
+
default: undefined
|
|
90
|
+
},
|
|
91
|
+
/**
|
|
92
|
+
* Adds the `required` attribute to the form control
|
|
93
|
+
*/
|
|
94
|
+
required: {
|
|
95
|
+
type: Boolean,
|
|
96
|
+
required: false,
|
|
97
|
+
default: false
|
|
98
|
+
},
|
|
99
|
+
/**
|
|
100
|
+
* Controls the validation state appearance of the component. `true` for valid, `false` for invalid, or `null` for no validation state
|
|
101
|
+
*/
|
|
102
|
+
state: {
|
|
103
|
+
type: Boolean,
|
|
104
|
+
required: false,
|
|
105
|
+
default: null
|
|
106
|
+
},
|
|
107
|
+
/**
|
|
108
|
+
* Sets the `placeholder` attribute value on the form control
|
|
109
|
+
*/
|
|
110
|
+
placeholder: {
|
|
111
|
+
type: String,
|
|
112
|
+
required: false,
|
|
113
|
+
default: undefined
|
|
114
|
+
},
|
|
115
|
+
/**
|
|
116
|
+
* Optional value to set for the 'aria-invalid' attribute. Supported values are 'true' and 'false'. If not set, the 'state' prop will dictate the value
|
|
117
|
+
*/
|
|
118
|
+
ariaInvalid: {
|
|
119
|
+
type: [Boolean, String],
|
|
120
|
+
required: false,
|
|
121
|
+
default: false
|
|
122
|
+
},
|
|
123
|
+
/**
|
|
124
|
+
* Sets the 'autocomplete' attribute value on the form control
|
|
125
|
+
*/
|
|
126
|
+
autocomplete: {
|
|
127
|
+
type: String,
|
|
128
|
+
required: false,
|
|
129
|
+
default: undefined
|
|
130
|
+
},
|
|
131
|
+
/**
|
|
132
|
+
* When set to a number of milliseconds greater than zero, will debounce the user input. Has no effect if prop 'lazy' is set
|
|
133
|
+
*/
|
|
134
|
+
debounce: {
|
|
135
|
+
type: [Number, String],
|
|
136
|
+
required: false,
|
|
137
|
+
default: undefined
|
|
138
|
+
},
|
|
139
|
+
/**
|
|
140
|
+
* Reference to a function for formatting the input
|
|
141
|
+
*/
|
|
142
|
+
formatter: {
|
|
143
|
+
type: Function,
|
|
144
|
+
required: false,
|
|
145
|
+
default: undefined
|
|
146
|
+
},
|
|
147
|
+
/**
|
|
148
|
+
* When set, updates the v-model on 'change'/'blur' events instead of 'input'. Emulates the Vue '.lazy' v-model modifier
|
|
149
|
+
*/
|
|
150
|
+
lazy: {
|
|
151
|
+
type: Boolean,
|
|
152
|
+
required: false,
|
|
153
|
+
default: false
|
|
154
|
+
},
|
|
155
|
+
/**
|
|
156
|
+
* When set, the input is formatted on blur instead of each keystroke (if there is a formatter specified)
|
|
157
|
+
*/
|
|
158
|
+
lazyFormatter: {
|
|
159
|
+
type: Boolean,
|
|
160
|
+
required: false,
|
|
161
|
+
default: false
|
|
162
|
+
},
|
|
163
|
+
/**
|
|
164
|
+
* When set attempts to convert the input value to a native number. Emulates the Vue '.number' v-model modifier
|
|
165
|
+
*/
|
|
166
|
+
number: {
|
|
167
|
+
type: Boolean,
|
|
168
|
+
required: false,
|
|
169
|
+
default: false
|
|
170
|
+
},
|
|
171
|
+
/**
|
|
172
|
+
* Set the form control as readonly and renders the control to look like plain text (no borders)
|
|
173
|
+
*/
|
|
174
|
+
plaintext: {
|
|
175
|
+
type: Boolean,
|
|
176
|
+
required: false,
|
|
177
|
+
default: false
|
|
178
|
+
},
|
|
179
|
+
/**
|
|
180
|
+
* Sets the `readonly` attribute on the form control
|
|
181
|
+
*/
|
|
182
|
+
readonly: {
|
|
183
|
+
type: Boolean,
|
|
184
|
+
required: false,
|
|
185
|
+
default: false
|
|
186
|
+
},
|
|
187
|
+
/**
|
|
188
|
+
* When set, trims any leading and trailing white space from the input value. Emulates the Vue '.trim' v-model modifier
|
|
189
|
+
*/
|
|
190
|
+
trim: {
|
|
191
|
+
type: Boolean,
|
|
192
|
+
required: false,
|
|
193
|
+
default: false
|
|
194
|
+
},
|
|
195
|
+
/**
|
|
196
|
+
* The ID of the associated datalist element or component
|
|
197
|
+
*/
|
|
198
|
+
list: {
|
|
199
|
+
type: String,
|
|
200
|
+
required: false,
|
|
201
|
+
default: undefined
|
|
202
|
+
},
|
|
203
|
+
/**
|
|
204
|
+
* Value to set in the 'max' attribute on the input. Used by number-like inputs
|
|
205
|
+
*/
|
|
206
|
+
max: {
|
|
207
|
+
type: [Number, String],
|
|
208
|
+
required: false,
|
|
209
|
+
default: undefined
|
|
210
|
+
},
|
|
211
|
+
/**
|
|
212
|
+
* Value to set in the 'min' attribute on the input. Used by number-like inputs
|
|
213
|
+
*/
|
|
214
|
+
min: {
|
|
215
|
+
type: [Number, String],
|
|
216
|
+
required: false,
|
|
217
|
+
default: undefined
|
|
218
|
+
},
|
|
219
|
+
/**
|
|
220
|
+
* Value to set in the 'step' attribute on the input. Used by number-like inputs
|
|
221
|
+
*/
|
|
222
|
+
step: {
|
|
223
|
+
type: [Number, String],
|
|
224
|
+
required: false,
|
|
225
|
+
default: undefined
|
|
30
226
|
}
|
|
31
227
|
},
|
|
228
|
+
data() {
|
|
229
|
+
return {
|
|
230
|
+
localValue: toString(this.value),
|
|
231
|
+
vModelValue: this.modifyValue(this.value),
|
|
232
|
+
localId: null
|
|
233
|
+
};
|
|
234
|
+
},
|
|
32
235
|
computed: {
|
|
33
|
-
|
|
236
|
+
computedId() {
|
|
237
|
+
return this.id || this.localId;
|
|
238
|
+
},
|
|
239
|
+
localType() {
|
|
240
|
+
// We only allow certain types
|
|
241
|
+
const {
|
|
242
|
+
type
|
|
243
|
+
} = this;
|
|
244
|
+
return TYPES.includes(type) ? type : 'text';
|
|
245
|
+
},
|
|
246
|
+
computedAriaInvalid() {
|
|
247
|
+
const {
|
|
248
|
+
ariaInvalid
|
|
249
|
+
} = this;
|
|
250
|
+
if (ariaInvalid === true || ariaInvalid === 'true' || ariaInvalid === '') {
|
|
251
|
+
return 'true';
|
|
252
|
+
}
|
|
253
|
+
return this.computedState === false ? 'true' : ariaInvalid;
|
|
254
|
+
},
|
|
255
|
+
computedAttrs() {
|
|
256
|
+
const {
|
|
257
|
+
localType: type,
|
|
258
|
+
name,
|
|
259
|
+
form,
|
|
260
|
+
disabled,
|
|
261
|
+
placeholder,
|
|
262
|
+
required,
|
|
263
|
+
min,
|
|
264
|
+
max,
|
|
265
|
+
step
|
|
266
|
+
} = this;
|
|
267
|
+
return {
|
|
268
|
+
id: this.computedId,
|
|
269
|
+
name,
|
|
270
|
+
form,
|
|
271
|
+
type,
|
|
272
|
+
disabled,
|
|
273
|
+
placeholder,
|
|
274
|
+
required,
|
|
275
|
+
autocomplete: this.autocomplete || null,
|
|
276
|
+
readonly: this.readonly || this.plaintext,
|
|
277
|
+
min,
|
|
278
|
+
max,
|
|
279
|
+
step,
|
|
280
|
+
list: type !== 'password' ? this.list : null,
|
|
281
|
+
'aria-required': required ? 'true' : null,
|
|
282
|
+
'aria-invalid': this.computedAriaInvalid
|
|
283
|
+
};
|
|
284
|
+
},
|
|
285
|
+
computedState() {
|
|
286
|
+
// If not a boolean, ensure that value is null
|
|
287
|
+
return isBoolean(this.state) ? this.state : null;
|
|
288
|
+
},
|
|
289
|
+
stateClass() {
|
|
290
|
+
if (this.computedState === true) return 'is-valid';
|
|
291
|
+
if (this.computedState === false) return 'is-invalid';
|
|
292
|
+
return null;
|
|
293
|
+
},
|
|
294
|
+
widthClasses() {
|
|
34
295
|
if (this.width === null) {
|
|
35
296
|
return [];
|
|
36
297
|
}
|
|
@@ -52,41 +313,349 @@ var script = {
|
|
|
52
313
|
// eslint-disable-next-line @gitlab/tailwind-no-interpolation -- Not a CSS utility
|
|
53
314
|
return [`gl-form-input-${this.width}`];
|
|
54
315
|
},
|
|
55
|
-
|
|
56
|
-
|
|
316
|
+
computedClass() {
|
|
317
|
+
const {
|
|
318
|
+
plaintext,
|
|
319
|
+
type
|
|
320
|
+
} = this;
|
|
321
|
+
const isRange = type === 'range';
|
|
322
|
+
const isColor = type === 'color';
|
|
323
|
+
return [...this.widthClasses, {
|
|
324
|
+
// Range input needs class `custom-range`
|
|
325
|
+
'custom-range': isRange,
|
|
326
|
+
// `plaintext` not supported by `type="range"` or `type="color"`
|
|
327
|
+
'form-control-plaintext': plaintext && !isRange && !isColor,
|
|
328
|
+
// `form-control` not used by `type="range"` or `plaintext`
|
|
329
|
+
// Always used by `type="color"`
|
|
330
|
+
'form-control': isColor || !plaintext && !isRange
|
|
331
|
+
}, this.stateClass];
|
|
332
|
+
},
|
|
333
|
+
computedListeners() {
|
|
57
334
|
return {
|
|
58
335
|
...this.$listeners,
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
336
|
+
input: this.onInput,
|
|
337
|
+
change: this.onChange,
|
|
338
|
+
blur: this.onBlur
|
|
339
|
+
};
|
|
340
|
+
},
|
|
341
|
+
computedDebounce() {
|
|
342
|
+
// Ensure we have a positive number equal to or greater than 0
|
|
343
|
+
return Math.max(toInteger(this.debounce), 0);
|
|
344
|
+
},
|
|
345
|
+
hasFormatter() {
|
|
346
|
+
return typeof this.formatter === 'function';
|
|
347
|
+
},
|
|
348
|
+
noWheel() {
|
|
349
|
+
return this.type === 'number';
|
|
350
|
+
},
|
|
351
|
+
selectionStart: {
|
|
352
|
+
// Expose selectionStart for formatters, etc
|
|
353
|
+
cache: false,
|
|
354
|
+
get() {
|
|
355
|
+
return this.$refs.input.selectionStart;
|
|
356
|
+
},
|
|
357
|
+
set(val) {
|
|
358
|
+
this.$refs.input.selectionStart = val;
|
|
359
|
+
}
|
|
360
|
+
},
|
|
361
|
+
selectionEnd: {
|
|
362
|
+
// Expose selectionEnd for formatters, etc
|
|
363
|
+
cache: false,
|
|
364
|
+
get() {
|
|
365
|
+
return this.$refs.input.selectionEnd;
|
|
366
|
+
},
|
|
367
|
+
set(val) {
|
|
368
|
+
this.$refs.input.selectionEnd = val;
|
|
369
|
+
}
|
|
370
|
+
},
|
|
371
|
+
selectionDirection: {
|
|
372
|
+
// Expose selectionDirection for formatters, etc
|
|
373
|
+
cache: false,
|
|
374
|
+
get() {
|
|
375
|
+
return this.$refs.input.selectionDirection;
|
|
376
|
+
},
|
|
377
|
+
set(val) {
|
|
378
|
+
this.$refs.input.selectionDirection = val;
|
|
379
|
+
}
|
|
380
|
+
},
|
|
381
|
+
validity: {
|
|
382
|
+
// Expose validity property
|
|
383
|
+
cache: false,
|
|
384
|
+
get() {
|
|
385
|
+
return this.$refs.input.validity;
|
|
386
|
+
}
|
|
387
|
+
},
|
|
388
|
+
validationMessage: {
|
|
389
|
+
// Expose validationMessage property
|
|
390
|
+
cache: false,
|
|
391
|
+
get() {
|
|
392
|
+
return this.$refs.input.validationMessage;
|
|
393
|
+
}
|
|
394
|
+
},
|
|
395
|
+
willValidate: {
|
|
396
|
+
// Expose willValidate property
|
|
397
|
+
cache: false,
|
|
398
|
+
get() {
|
|
399
|
+
return this.$refs.input.willValidate;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
watch: {
|
|
404
|
+
value(newValue) {
|
|
405
|
+
const stringifyValue = toString(newValue);
|
|
406
|
+
const modifiedValue = this.modifyValue(newValue);
|
|
407
|
+
if (stringifyValue !== this.localValue || modifiedValue !== this.vModelValue) {
|
|
408
|
+
// Clear any pending debounce timeout, as we are overwriting the user input
|
|
409
|
+
this.clearDebounce();
|
|
410
|
+
// Update the local values
|
|
411
|
+
this.localValue = stringifyValue;
|
|
412
|
+
this.vModelValue = modifiedValue;
|
|
413
|
+
}
|
|
414
|
+
},
|
|
415
|
+
noWheel(newValue) {
|
|
416
|
+
this.setWheelStopper(newValue);
|
|
417
|
+
}
|
|
418
|
+
},
|
|
419
|
+
created() {
|
|
420
|
+
// Create private non-reactive props
|
|
421
|
+
this.$_inputDebounceTimer = null;
|
|
422
|
+
},
|
|
423
|
+
mounted() {
|
|
424
|
+
this.setWheelStopper(this.noWheel);
|
|
425
|
+
this.handleAutofocus();
|
|
426
|
+
this.$nextTick(() => {
|
|
427
|
+
// Update DOM with auto-generated ID after mount
|
|
428
|
+
// to prevent SSR hydration errors
|
|
429
|
+
this.localId = uniqueId('gl-form-input-');
|
|
430
|
+
});
|
|
431
|
+
},
|
|
432
|
+
deactivated() {
|
|
433
|
+
// Turn off listeners when keep-alive component deactivated
|
|
434
|
+
this.setWheelStopper(false);
|
|
435
|
+
},
|
|
436
|
+
activated() {
|
|
437
|
+
// Turn on listeners (if no-wheel) when keep-alive component activated
|
|
438
|
+
this.setWheelStopper(this.noWheel);
|
|
439
|
+
this.handleAutofocus();
|
|
440
|
+
},
|
|
441
|
+
beforeDestroy() {
|
|
442
|
+
this.setWheelStopper(false);
|
|
443
|
+
this.clearDebounce();
|
|
444
|
+
},
|
|
445
|
+
methods: {
|
|
446
|
+
focus() {
|
|
447
|
+
if (!this.disabled) {
|
|
448
|
+
var _this$$refs$input;
|
|
449
|
+
(_this$$refs$input = this.$refs.input) === null || _this$$refs$input === void 0 ? void 0 : _this$$refs$input.focus();
|
|
450
|
+
}
|
|
451
|
+
},
|
|
452
|
+
blur() {
|
|
453
|
+
if (!this.disabled) {
|
|
454
|
+
var _this$$refs$input2;
|
|
455
|
+
(_this$$refs$input2 = this.$refs.input) === null || _this$$refs$input2 === void 0 ? void 0 : _this$$refs$input2.blur();
|
|
456
|
+
}
|
|
457
|
+
},
|
|
458
|
+
clearDebounce() {
|
|
459
|
+
clearTimeout(this.$_inputDebounceTimer);
|
|
460
|
+
this.$_inputDebounceTimer = null;
|
|
461
|
+
},
|
|
462
|
+
formatValue(value, event) {
|
|
463
|
+
let force = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
|
|
464
|
+
let newValue = toString(value);
|
|
465
|
+
if (this.hasFormatter && (!this.lazyFormatter || force)) {
|
|
466
|
+
newValue = this.formatter(value, event);
|
|
467
|
+
}
|
|
468
|
+
return newValue;
|
|
469
|
+
},
|
|
470
|
+
modifyValue(value) {
|
|
471
|
+
let newValue = toString(value);
|
|
472
|
+
// Emulate `.trim` modifier behaviour
|
|
473
|
+
if (this.trim) {
|
|
474
|
+
newValue = newValue.trim();
|
|
475
|
+
}
|
|
476
|
+
// Emulate `.number` modifier behaviour
|
|
477
|
+
if (this.number) {
|
|
478
|
+
newValue = toFloat(newValue, newValue);
|
|
479
|
+
}
|
|
480
|
+
return newValue;
|
|
481
|
+
},
|
|
482
|
+
updateValue(value) {
|
|
483
|
+
let force = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
|
|
484
|
+
const {
|
|
485
|
+
lazy
|
|
486
|
+
} = this;
|
|
487
|
+
if (lazy && !force) {
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
// Make sure to always clear the debounce when `updateValue()`
|
|
491
|
+
// is called, even when the v-model hasn't changed
|
|
492
|
+
this.clearDebounce();
|
|
493
|
+
// Define the shared update logic in a method to be able to use
|
|
494
|
+
// it for immediate and debounced value changes
|
|
495
|
+
const doUpdate = () => {
|
|
496
|
+
const newValue = this.modifyValue(value);
|
|
497
|
+
if (newValue !== this.vModelValue) {
|
|
498
|
+
this.vModelValue = newValue;
|
|
499
|
+
this.$emit(MODEL_EVENT, newValue);
|
|
500
|
+
} else if (this.hasFormatter) {
|
|
501
|
+
// When the `vModelValue` hasn't changed but the actual input value
|
|
502
|
+
// is out of sync, make sure to change it to the given one
|
|
503
|
+
// Usually caused by browser autocomplete and how it triggers the
|
|
504
|
+
// change or input event, or depending on the formatter function
|
|
505
|
+
// https://github.com/bootstrap-vue/bootstrap-vue/issues/2657
|
|
506
|
+
// https://github.com/bootstrap-vue/bootstrap-vue/issues/3498
|
|
507
|
+
const $input = this.$refs.input;
|
|
508
|
+
if ($input && newValue !== $input.value) {
|
|
509
|
+
$input.value = newValue;
|
|
76
510
|
}
|
|
77
|
-
/**
|
|
78
|
-
* Triggered by user interaction. Emitted after any formatting (not including 'trim' or 'number' props).
|
|
79
|
-
* Useful for getting the currently entered value when the 'debounce' or 'lazy' props are set.
|
|
80
|
-
*
|
|
81
|
-
* @event input
|
|
82
|
-
* @property {string} value new value
|
|
83
|
-
*/
|
|
84
|
-
_this.$emit(MODEL_EVENT, ...args);
|
|
85
511
|
}
|
|
86
512
|
};
|
|
513
|
+
// Only debounce the value update when a value greater than `0`
|
|
514
|
+
// is set and we are not in lazy mode or this is a forced update
|
|
515
|
+
const debounce = this.computedDebounce;
|
|
516
|
+
if (debounce > 0 && !lazy && !force) {
|
|
517
|
+
this.$_inputDebounceTimer = setTimeout(doUpdate, debounce);
|
|
518
|
+
} else {
|
|
519
|
+
// Immediately update the v-model
|
|
520
|
+
doUpdate();
|
|
521
|
+
}
|
|
87
522
|
},
|
|
88
|
-
|
|
89
|
-
|
|
523
|
+
onInput(event) {
|
|
524
|
+
// `event.target.composing` is set by Vue
|
|
525
|
+
// https://github.com/vuejs/vue/blob/dev/src/platforms/web/runtime/directives/model.js
|
|
526
|
+
// TODO: Is this needed now with the latest Vue?
|
|
527
|
+
if (event.target.composing) {
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
const {
|
|
531
|
+
value
|
|
532
|
+
} = event.target;
|
|
533
|
+
const formattedValue = this.formatValue(value, event);
|
|
534
|
+
// Exit when the `formatter` function strictly returned `false`
|
|
535
|
+
// or prevented the input event
|
|
536
|
+
if (formattedValue === false || event.defaultPrevented) {
|
|
537
|
+
stopEvent(event, {
|
|
538
|
+
propagation: false
|
|
539
|
+
});
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
this.localValue = formattedValue;
|
|
543
|
+
this.updateValue(formattedValue);
|
|
544
|
+
/**
|
|
545
|
+
* The `input` and `update` events are swapped
|
|
546
|
+
* see https://gitlab.com/gitlab-org/gitlab-ui/-/merge_requests/1628
|
|
547
|
+
*/
|
|
548
|
+
this.$emit('update', formattedValue);
|
|
549
|
+
},
|
|
550
|
+
onChange(event) {
|
|
551
|
+
const {
|
|
552
|
+
value
|
|
553
|
+
} = event.target;
|
|
554
|
+
const formattedValue = this.formatValue(value, event);
|
|
555
|
+
// Exit when the `formatter` function strictly returned `false`
|
|
556
|
+
// or prevented the input event
|
|
557
|
+
if (formattedValue === false || event.defaultPrevented) {
|
|
558
|
+
stopEvent(event, {
|
|
559
|
+
propagation: false
|
|
560
|
+
});
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
this.localValue = formattedValue;
|
|
564
|
+
this.updateValue(formattedValue, true);
|
|
565
|
+
this.$emit('change', formattedValue);
|
|
566
|
+
},
|
|
567
|
+
onBlur(event) {
|
|
568
|
+
// Apply the `localValue` on blur to prevent cursor jumps
|
|
569
|
+
// on mobile browsers (e.g. caused by autocomplete)
|
|
570
|
+
const {
|
|
571
|
+
value
|
|
572
|
+
} = event.target;
|
|
573
|
+
const formattedValue = this.formatValue(value, event, true);
|
|
574
|
+
if (formattedValue !== false) {
|
|
575
|
+
// We need to use the modified value here to apply the
|
|
576
|
+
// `.trim` and `.number` modifiers properly
|
|
577
|
+
this.localValue = toString(this.modifyValue(formattedValue));
|
|
578
|
+
// We pass the formatted value here since the `updateValue` method
|
|
579
|
+
// handles the modifiers itself
|
|
580
|
+
this.updateValue(formattedValue, true);
|
|
581
|
+
}
|
|
582
|
+
// Emit native blur event
|
|
583
|
+
this.$emit('blur', event);
|
|
584
|
+
},
|
|
585
|
+
setWheelStopper(on) {
|
|
586
|
+
const {
|
|
587
|
+
input
|
|
588
|
+
} = this.$refs;
|
|
589
|
+
// We use native events, so that we don't interfere with propagation
|
|
590
|
+
if (on) {
|
|
591
|
+
input.addEventListener('focus', this.onWheelFocus);
|
|
592
|
+
input.addEventListener('blur', this.onWheelBlur);
|
|
593
|
+
} else {
|
|
594
|
+
input.removeEventListener('focus', this.onWheelFocus);
|
|
595
|
+
input.removeEventListener('blur', this.onWheelBlur);
|
|
596
|
+
document.removeEventListener('wheel', this.stopWheel);
|
|
597
|
+
}
|
|
598
|
+
},
|
|
599
|
+
onWheelFocus() {
|
|
600
|
+
document.addEventListener('wheel', this.stopWheel);
|
|
601
|
+
},
|
|
602
|
+
onWheelBlur() {
|
|
603
|
+
document.removeEventListener('wheel', this.stopWheel);
|
|
604
|
+
},
|
|
605
|
+
stopWheel(event) {
|
|
606
|
+
stopEvent(event, {
|
|
607
|
+
propagation: false
|
|
608
|
+
});
|
|
609
|
+
this.blur();
|
|
610
|
+
},
|
|
611
|
+
handleAutofocus() {
|
|
612
|
+
this.$nextTick(() => {
|
|
613
|
+
window.requestAnimationFrame(() => {
|
|
614
|
+
if (this.autofocus && isVisible(this.$refs.input)) this.focus();
|
|
615
|
+
});
|
|
616
|
+
});
|
|
617
|
+
},
|
|
618
|
+
select() {
|
|
619
|
+
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
620
|
+
args[_key] = arguments[_key];
|
|
621
|
+
}
|
|
622
|
+
// For external handler that may want a select() method
|
|
623
|
+
this.$refs.input.select(args);
|
|
624
|
+
},
|
|
625
|
+
setSelectionRange() {
|
|
626
|
+
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
|
627
|
+
args[_key2] = arguments[_key2];
|
|
628
|
+
}
|
|
629
|
+
// For external handler that may want a setSelectionRange(a,b,c) method
|
|
630
|
+
this.$refs.input.setSelectionRange(args);
|
|
631
|
+
},
|
|
632
|
+
setRangeText() {
|
|
633
|
+
for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
|
|
634
|
+
args[_key3] = arguments[_key3];
|
|
635
|
+
}
|
|
636
|
+
// For external handler that may want a setRangeText(a,b,c) method
|
|
637
|
+
this.$refs.input.setRangeText(args);
|
|
638
|
+
},
|
|
639
|
+
setCustomValidity() {
|
|
640
|
+
for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
|
|
641
|
+
args[_key4] = arguments[_key4];
|
|
642
|
+
}
|
|
643
|
+
// For external handler that may want a setCustomValidity(...) method
|
|
644
|
+
return this.$refs.input.setCustomValidity(args);
|
|
645
|
+
},
|
|
646
|
+
checkValidity() {
|
|
647
|
+
for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {
|
|
648
|
+
args[_key5] = arguments[_key5];
|
|
649
|
+
}
|
|
650
|
+
// For external handler that may want a checkValidity(...) method
|
|
651
|
+
return this.$refs.input.checkValidity(args);
|
|
652
|
+
},
|
|
653
|
+
reportValidity() {
|
|
654
|
+
for (var _len6 = arguments.length, args = new Array(_len6), _key6 = 0; _key6 < _len6; _key6++) {
|
|
655
|
+
args[_key6] = arguments[_key6];
|
|
656
|
+
}
|
|
657
|
+
// For external handler that may want a reportValidity(...) method
|
|
658
|
+
return this.$refs.input.reportValidity(args);
|
|
90
659
|
}
|
|
91
660
|
}
|
|
92
661
|
};
|
|
@@ -95,7 +664,7 @@ var script = {
|
|
|
95
664
|
const __vue_script__ = script;
|
|
96
665
|
|
|
97
666
|
/* template */
|
|
98
|
-
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('
|
|
667
|
+
var __vue_render__ = function () {var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;return _c('input',_vm._g(_vm._b({ref:"input",staticClass:"gl-form-input",class:_vm.computedClass,domProps:{"value":_vm.localValue}},'input',_vm.computedAttrs,false),_vm.computedListeners))};
|
|
99
668
|
var __vue_staticRenderFns__ = [];
|
|
100
669
|
|
|
101
670
|
/* style */
|
package/dist/utils/utils.js
CHANGED