@v-c/input-number 1.0.6 → 1.1.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/InputNumber.d.ts +7 -1
- package/dist/InputNumber.js +98 -7
- package/package.json +4 -4
package/dist/InputNumber.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ValueType } from '@v-c/mini-decimal';
|
|
2
2
|
import { InputFocusOptions } from '@v-c/util/dist/Dom/focus';
|
|
3
3
|
export type { ValueType };
|
|
4
|
-
type SemanticName = 'root' | 'actions' | 'input' | 'action' | 'prefix' | 'suffix';
|
|
4
|
+
type SemanticName = 'root' | 'actions' | 'input' | 'action' | 'prefix' | 'suffix' | 'clear';
|
|
5
5
|
export interface InputNumberProps<T extends ValueType = ValueType> {
|
|
6
6
|
mode?: 'input' | 'spinner';
|
|
7
7
|
prefixCls?: string;
|
|
@@ -19,6 +19,11 @@ export interface InputNumberProps<T extends ValueType = ValueType> {
|
|
|
19
19
|
readOnly?: boolean;
|
|
20
20
|
prefix?: any;
|
|
21
21
|
suffix?: any;
|
|
22
|
+
allowClear?: boolean | {
|
|
23
|
+
clearIcon?: any;
|
|
24
|
+
disabled?: boolean;
|
|
25
|
+
label?: string;
|
|
26
|
+
};
|
|
22
27
|
upHandler?: any;
|
|
23
28
|
downHandler?: any;
|
|
24
29
|
keyboard?: boolean;
|
|
@@ -33,6 +38,7 @@ export interface InputNumberProps<T extends ValueType = ValueType> {
|
|
|
33
38
|
decimalSeparator?: string;
|
|
34
39
|
onInput?: (text: string) => void;
|
|
35
40
|
onChange?: (value: T | null) => void;
|
|
41
|
+
onClear?: () => void;
|
|
36
42
|
onPressEnter?: (e: KeyboardEvent) => void;
|
|
37
43
|
onStep?: (value: T, info: {
|
|
38
44
|
offset: ValueType;
|
package/dist/InputNumber.js
CHANGED
|
@@ -4,7 +4,7 @@ import StepHandler_default from "./StepHandler.js";
|
|
|
4
4
|
import { getDecupleSteps } from "./utils/numberUtil.js";
|
|
5
5
|
import { computed, createVNode, defineComponent, isVNode, mergeDefaults, mergeProps, shallowRef, watch, watchEffect } from "vue";
|
|
6
6
|
import getMiniDecimal, { getNumberPrecision, num2str, toFixed, validateNumber } from "@v-c/mini-decimal";
|
|
7
|
-
import { clsx } from "@v-c/util";
|
|
7
|
+
import { clsx, isVueRenderable } from "@v-c/util";
|
|
8
8
|
import { triggerFocus } from "@v-c/util/dist/Dom/focus";
|
|
9
9
|
import { KeyCodeStr } from "@v-c/util/dist/KeyCode";
|
|
10
10
|
import omit from "@v-c/util/dist/omit";
|
|
@@ -12,6 +12,20 @@ import omit from "@v-c/util/dist/omit";
|
|
|
12
12
|
function _isSlot(s) {
|
|
13
13
|
return typeof s === "function" || Object.prototype.toString.call(s) === "[object Object]" && !isVNode(s);
|
|
14
14
|
}
|
|
15
|
+
/** Accumulated wheel distance that adds up to a single step. */
|
|
16
|
+
var WHEEL_STEP_DISTANCE = 100;
|
|
17
|
+
var WHEEL_LINE_HEIGHT = 40;
|
|
18
|
+
var WHEEL_PAGE_HEIGHT = 800;
|
|
19
|
+
/** Idle gap after which a new wheel gesture starts from scratch. */
|
|
20
|
+
var WHEEL_DELTA_RESET_INTERVAL = 200;
|
|
21
|
+
/** Normalize `deltaY` to pixels — browsers may report it in lines or pages. */
|
|
22
|
+
function getWheelDeltaY(event) {
|
|
23
|
+
switch (event.deltaMode) {
|
|
24
|
+
case 1: return event.deltaY * WHEEL_LINE_HEIGHT;
|
|
25
|
+
case 2: return event.deltaY * WHEEL_PAGE_HEIGHT;
|
|
26
|
+
default: return event.deltaY;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
15
29
|
var defaults = {
|
|
16
30
|
prefixCls: "vc-input-number",
|
|
17
31
|
step: 1,
|
|
@@ -63,6 +77,7 @@ var InputNumber = /* @__PURE__ */ defineComponent((props, { attrs, slots, expose
|
|
|
63
77
|
};
|
|
64
78
|
const inputValue = shallowRef("");
|
|
65
79
|
const inputValueRef = shallowRef("");
|
|
80
|
+
let inputValueUpdateId = 0;
|
|
66
81
|
const mergedFormatter = (number, userTyping) => {
|
|
67
82
|
if (props.formatter) return props.formatter(number, {
|
|
68
83
|
userTyping,
|
|
@@ -145,6 +160,8 @@ var InputNumber = /* @__PURE__ */ defineComponent((props, { attrs, slots, expose
|
|
|
145
160
|
};
|
|
146
161
|
const onNextPromise = useFrame_default();
|
|
147
162
|
const collectInputValue = (inputStr) => {
|
|
163
|
+
inputValueUpdateId += 1;
|
|
164
|
+
const currentUpdateId = inputValueUpdateId;
|
|
148
165
|
recordCursor();
|
|
149
166
|
inputValueRef.value = inputStr;
|
|
150
167
|
inputValue.value = inputStr;
|
|
@@ -154,6 +171,7 @@ var InputNumber = /* @__PURE__ */ defineComponent((props, { attrs, slots, expose
|
|
|
154
171
|
}
|
|
155
172
|
props.onInput?.(inputStr);
|
|
156
173
|
onNextPromise(() => {
|
|
174
|
+
if (currentUpdateId !== inputValueUpdateId) return;
|
|
157
175
|
let nextInputStr = inputStr;
|
|
158
176
|
if (!props.parser) nextInputStr = inputStr.replace(/。/g, ".");
|
|
159
177
|
if (nextInputStr !== inputStr) collectInputValue(nextInputStr);
|
|
@@ -227,20 +245,44 @@ var InputNumber = /* @__PURE__ */ defineComponent((props, { attrs, slots, expose
|
|
|
227
245
|
shiftKeyRef.value = false;
|
|
228
246
|
props.onKeyUp?.(event);
|
|
229
247
|
};
|
|
248
|
+
let wheelDelta = 0;
|
|
249
|
+
let wheelTimestamp = 0;
|
|
250
|
+
const resetWheel = () => {
|
|
251
|
+
wheelDelta = 0;
|
|
252
|
+
wheelTimestamp = 0;
|
|
253
|
+
};
|
|
254
|
+
const onInternalWheel = (event) => {
|
|
255
|
+
const delta = getWheelDeltaY(event);
|
|
256
|
+
if (!delta) return;
|
|
257
|
+
const eventTimestamp = event.timeStamp || Date.now();
|
|
258
|
+
if (eventTimestamp - wheelTimestamp > WHEEL_DELTA_RESET_INTERVAL) wheelDelta = 0;
|
|
259
|
+
wheelTimestamp = eventTimestamp;
|
|
260
|
+
if (wheelDelta && Math.sign(wheelDelta) !== Math.sign(delta)) wheelDelta = 0;
|
|
261
|
+
wheelDelta += delta;
|
|
262
|
+
if (Math.abs(wheelDelta) >= WHEEL_STEP_DISTANCE) {
|
|
263
|
+
onInternalStep(wheelDelta < 0, "wheel");
|
|
264
|
+
wheelDelta -= Math.sign(wheelDelta) * WHEEL_STEP_DISTANCE;
|
|
265
|
+
}
|
|
266
|
+
};
|
|
230
267
|
watchEffect((onCleanup) => {
|
|
231
268
|
if (props.changeOnWheel && focus.value && inputRef.value) {
|
|
232
269
|
const onWheel = (event) => {
|
|
233
|
-
|
|
270
|
+
onInternalWheel(event);
|
|
234
271
|
event.preventDefault();
|
|
235
272
|
};
|
|
236
273
|
inputRef.value.addEventListener("wheel", onWheel, { passive: false });
|
|
237
|
-
onCleanup(() =>
|
|
274
|
+
onCleanup(() => {
|
|
275
|
+
inputRef.value?.removeEventListener("wheel", onWheel);
|
|
276
|
+
resetWheel();
|
|
277
|
+
});
|
|
238
278
|
}
|
|
239
279
|
});
|
|
240
280
|
const onBlur = (e) => {
|
|
281
|
+
if (e.relatedTarget instanceof Node && rootRef.value?.contains(e.relatedTarget)) return;
|
|
241
282
|
if (props.changeOnBlur ?? true) flushInputValue(false);
|
|
242
283
|
focus.value = false;
|
|
243
284
|
userTypingRef.value = false;
|
|
285
|
+
resetWheel();
|
|
244
286
|
props.onBlur?.(e);
|
|
245
287
|
};
|
|
246
288
|
const onFocus = (e) => {
|
|
@@ -254,6 +296,26 @@ var InputNumber = /* @__PURE__ */ defineComponent((props, { attrs, slots, expose
|
|
|
254
296
|
}
|
|
255
297
|
props.onMouseDown?.(event);
|
|
256
298
|
};
|
|
299
|
+
const onClearKeyDown = (event) => {
|
|
300
|
+
const isStepKey = [
|
|
301
|
+
"Up",
|
|
302
|
+
"ArrowUp",
|
|
303
|
+
"Down",
|
|
304
|
+
"ArrowDown"
|
|
305
|
+
].includes(event.key);
|
|
306
|
+
if (event.key === KeyCodeStr.Enter || props.keyboard !== false && isStepKey) event.stopPropagation();
|
|
307
|
+
};
|
|
308
|
+
const onClearClick = () => {
|
|
309
|
+
userTypingRef.value = false;
|
|
310
|
+
inputValueRef.value = "";
|
|
311
|
+
inputValueUpdateId += 1;
|
|
312
|
+
const emptyValue = getMiniDecimal(null);
|
|
313
|
+
if (props.value !== void 0) setInputValue(decimalValue.value, false);
|
|
314
|
+
else if (decimalValue.value.isEmpty()) setInputValue(emptyValue, false);
|
|
315
|
+
inputRef.value?.focus();
|
|
316
|
+
triggerValueUpdate(emptyValue, false);
|
|
317
|
+
props.onClear?.();
|
|
318
|
+
};
|
|
257
319
|
watch([
|
|
258
320
|
() => props.precision,
|
|
259
321
|
() => props.formatter,
|
|
@@ -271,7 +333,7 @@ var InputNumber = /* @__PURE__ */ defineComponent((props, { attrs, slots, expose
|
|
|
271
333
|
if (props.formatter) restoreCursor();
|
|
272
334
|
}, { flush: "post" });
|
|
273
335
|
return () => {
|
|
274
|
-
const { prefixCls = defaults.prefixCls, classNames, styles, step = defaults.step, disabled, readOnly, controls = defaults.controls, mode = defaults.mode, placeholder } = props;
|
|
336
|
+
const { prefixCls = defaults.prefixCls, classNames, styles, step = defaults.step, disabled, readOnly, controls = defaults.controls, mode = defaults.mode, placeholder, allowClear } = props;
|
|
275
337
|
const mergedPrefixCls = prefixCls || defaults.prefixCls;
|
|
276
338
|
const { class: className, style, ...restAttrs } = attrs;
|
|
277
339
|
const mergedClassName = props.className || className;
|
|
@@ -284,6 +346,23 @@ var InputNumber = /* @__PURE__ */ defineComponent((props, { attrs, slots, expose
|
|
|
284
346
|
const suffixNode = slots.suffix?.() ?? props.suffix;
|
|
285
347
|
const upNode = slots.upHandler?.() ?? props.upHandler;
|
|
286
348
|
const downNode = slots.downHandler?.() ?? props.downHandler;
|
|
349
|
+
const clearConfig = allowClear && typeof allowClear === "object" ? allowClear : { disabled: allowClear !== true };
|
|
350
|
+
const showClear = !disabled && !readOnly && clearConfig.disabled !== true && String(inputValue.value).length > 0;
|
|
351
|
+
const hasSuffix = isVueRenderable(suffixNode);
|
|
352
|
+
const clearIconCls = `${mergedPrefixCls}-clear-icon`;
|
|
353
|
+
const clearNode = allowClear && createVNode("button", {
|
|
354
|
+
"type": "button",
|
|
355
|
+
"aria-label": clearConfig.label ?? "Clear",
|
|
356
|
+
"disabled": !showClear,
|
|
357
|
+
"class": clsx(clearIconCls, {
|
|
358
|
+
[`${clearIconCls}-hidden`]: !showClear,
|
|
359
|
+
[`${clearIconCls}-has-suffix`]: hasSuffix
|
|
360
|
+
}, classNames?.clear),
|
|
361
|
+
"style": styles?.clear,
|
|
362
|
+
"onMousedown": (event) => event.preventDefault(),
|
|
363
|
+
"onKeydown": onClearKeyDown,
|
|
364
|
+
"onClick": onClearClick
|
|
365
|
+
}, [slots.clearIcon?.() ?? clearConfig.clearIcon ?? "✖"]);
|
|
287
366
|
const upHandlerNode = createVNode(StepHandler_default, {
|
|
288
367
|
"prefixCls": mergedPrefixCls,
|
|
289
368
|
"action": "up",
|
|
@@ -308,6 +387,7 @@ var InputNumber = /* @__PURE__ */ defineComponent((props, { attrs, slots, expose
|
|
|
308
387
|
"value",
|
|
309
388
|
"prefix",
|
|
310
389
|
"suffix",
|
|
390
|
+
"allowClear",
|
|
311
391
|
"upHandler",
|
|
312
392
|
"downHandler",
|
|
313
393
|
"keyboard",
|
|
@@ -319,6 +399,7 @@ var InputNumber = /* @__PURE__ */ defineComponent((props, { attrs, slots, expose
|
|
|
319
399
|
"precision",
|
|
320
400
|
"decimalSeparator",
|
|
321
401
|
"onChange",
|
|
402
|
+
"onClear",
|
|
322
403
|
"onInput",
|
|
323
404
|
"onPressEnter",
|
|
324
405
|
"onStep",
|
|
@@ -371,7 +452,7 @@ var InputNumber = /* @__PURE__ */ defineComponent((props, { attrs, slots, expose
|
|
|
371
452
|
}
|
|
372
453
|
}, [
|
|
373
454
|
mode === "spinner" && controls && downHandlerNode,
|
|
374
|
-
|
|
455
|
+
isVueRenderable(prefixNode) && createVNode("div", {
|
|
375
456
|
"class": clsx(`${mergedPrefixCls}-prefix`, classNames?.prefix),
|
|
376
457
|
"style": styles?.prefix
|
|
377
458
|
}, [prefixNode]),
|
|
@@ -398,10 +479,10 @@ var InputNumber = /* @__PURE__ */ defineComponent((props, { attrs, slots, expose
|
|
|
398
479
|
"onCompositionend": onCompositionEnd,
|
|
399
480
|
"onBeforeinput": onBeforeInput
|
|
400
481
|
}, inputAttrs), null),
|
|
401
|
-
|
|
482
|
+
(allowClear || hasSuffix) && createVNode("div", {
|
|
402
483
|
"class": clsx(`${mergedPrefixCls}-suffix`, classNames?.suffix),
|
|
403
484
|
"style": styles?.suffix
|
|
404
|
-
}, [suffixNode]),
|
|
485
|
+
}, [clearNode, suffixNode]),
|
|
405
486
|
mode === "spinner" && controls && upHandlerNode,
|
|
406
487
|
mode === "input" && controls && createVNode("div", {
|
|
407
488
|
"class": clsx(`${mergedPrefixCls}-actions`, classNames?.actions),
|
|
@@ -482,6 +563,11 @@ var InputNumber = /* @__PURE__ */ defineComponent((props, { attrs, slots, expose
|
|
|
482
563
|
required: false,
|
|
483
564
|
default: void 0
|
|
484
565
|
},
|
|
566
|
+
allowClear: {
|
|
567
|
+
type: [Boolean, Object],
|
|
568
|
+
required: false,
|
|
569
|
+
default: void 0
|
|
570
|
+
},
|
|
485
571
|
upHandler: {
|
|
486
572
|
required: false,
|
|
487
573
|
default: void 0
|
|
@@ -535,6 +621,11 @@ var InputNumber = /* @__PURE__ */ defineComponent((props, { attrs, slots, expose
|
|
|
535
621
|
required: false,
|
|
536
622
|
default: void 0
|
|
537
623
|
},
|
|
624
|
+
onClear: {
|
|
625
|
+
type: Function,
|
|
626
|
+
required: false,
|
|
627
|
+
default: void 0
|
|
628
|
+
},
|
|
538
629
|
onPressEnter: {
|
|
539
630
|
type: Function,
|
|
540
631
|
required: false,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@v-c/input-number",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0
|
|
4
|
+
"version": "1.1.0",
|
|
5
5
|
"description": "",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://github.com/antdv-next/vue-components/tree/next/packages/input-number",
|
|
@@ -30,9 +30,9 @@
|
|
|
30
30
|
"vue": "^3.0.0"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@v-c/input": "^1.1.
|
|
34
|
-
"@v-c/
|
|
35
|
-
"@v-c/
|
|
33
|
+
"@v-c/input": "^1.1.2",
|
|
34
|
+
"@v-c/mini-decimal": "^1.0.1",
|
|
35
|
+
"@v-c/util": "^1.2.0"
|
|
36
36
|
},
|
|
37
37
|
"scripts": {
|
|
38
38
|
"build": "vite build",
|