input-number2.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', { value: true });
  3. var vue = require('vue');
  4. var lodashUnified = require('lodash-unified');
  5. var index$4 = require('../../input/index.js');
  6. var index$2 = require('../../icon/index.js');
  7. var iconsVue = require('@element-plus/icons-vue');
  8. var inputNumber = require('./input-number.js');
  9. var pluginVue_exportHelper = require('../../../_virtual/plugin-vue_export-helper.js');
  10. var index$3 = require('../../../directives/repeat-click/index.js');
  11. var index = require('../../../hooks/use-locale/index.js');
  12. var index$1 = require('../../../hooks/use-namespace/index.js');
  13. var useFormItem = require('../../form/src/hooks/use-form-item.js');
  14. var types = require('../../../utils/types.js');
  15. var error = require('../../../utils/error.js');
  16. var useFormCommonProps = require('../../form/src/hooks/use-form-common-props.js');
  17. var event = require('../../../constants/event.js');
  18. var shared = require('@vue/shared');
  19. var browser = require('../../../utils/browser.js');
  20. const __default__ = vue.defineComponent({
  21. name: "ElInputNumber"
  22. });
  23. const _sfc_main = /* @__PURE__ */ vue.defineComponent({
  24. ...__default__,
  25. props: inputNumber.inputNumberProps,
  26. emits: inputNumber.inputNumberEmits,
  27. setup(__props, { expose, emit }) {
  28. const props = __props;
  29. const { t } = index.useLocale();
  30. const ns = index$1.useNamespace("input-number");
  31. const input = vue.ref();
  32. const data = vue.reactive({
  33. currentValue: props.modelValue,
  34. userInput: null
  35. });
  36. const { formItem } = useFormItem.useFormItem();
  37. const minDisabled = vue.computed(() => types.isNumber(props.modelValue) && props.modelValue <= props.min);
  38. const maxDisabled = vue.computed(() => types.isNumber(props.modelValue) && props.modelValue >= props.max);
  39. const numPrecision = vue.computed(() => {
  40. const stepPrecision = getPrecision(props.step);
  41. if (!types.isUndefined(props.precision)) {
  42. if (stepPrecision > props.precision) {
  43. error.debugWarn("InputNumber", "precision should not be less than the decimal places of step");
  44. }
  45. return props.precision;
  46. } else {
  47. return Math.max(getPrecision(props.modelValue), stepPrecision);
  48. }
  49. });
  50. const controlsAtRight = vue.computed(() => {
  51. return props.controls && props.controlsPosition === "right";
  52. });
  53. const inputNumberSize = useFormCommonProps.useFormSize();
  54. const inputNumberDisabled = useFormCommonProps.useFormDisabled();
  55. const displayValue = vue.computed(() => {
  56. if (data.userInput !== null) {
  57. return data.userInput;
  58. }
  59. let currentValue = data.currentValue;
  60. if (lodashUnified.isNil(currentValue))
  61. return "";
  62. if (types.isNumber(currentValue)) {
  63. if (Number.isNaN(currentValue))
  64. return "";
  65. if (!types.isUndefined(props.precision)) {
  66. currentValue = currentValue.toFixed(props.precision);
  67. }
  68. }
  69. return currentValue;
  70. });
  71. const toPrecision = (num, pre) => {
  72. if (types.isUndefined(pre))
  73. pre = numPrecision.value;
  74. if (pre === 0)
  75. return Math.round(num);
  76. let snum = String(num);
  77. const pointPos = snum.indexOf(".");
  78. if (pointPos === -1)
  79. return num;
  80. const nums = snum.replace(".", "").split("");
  81. const datum = nums[pointPos + pre];
  82. if (!datum)
  83. return num;
  84. const length = snum.length;
  85. if (snum.charAt(length - 1) === "5") {
  86. snum = `${snum.slice(0, Math.max(0, length - 1))}6`;
  87. }
  88. return Number.parseFloat(Number(snum).toFixed(pre));
  89. };
  90. const getPrecision = (value) => {
  91. if (lodashUnified.isNil(value))
  92. return 0;
  93. const valueString = value.toString();
  94. const dotPosition = valueString.indexOf(".");
  95. let precision = 0;
  96. if (dotPosition !== -1) {
  97. precision = valueString.length - dotPosition - 1;
  98. }
  99. return precision;
  100. };
  101. const ensurePrecision = (val, coefficient = 1) => {
  102. if (!types.isNumber(val))
  103. return data.currentValue;
  104. return toPrecision(val + props.step * coefficient);
  105. };
  106. const increase = () => {
  107. if (props.readonly || inputNumberDisabled.value || maxDisabled.value)
  108. return;
  109. const value = Number(displayValue.value) || 0;
  110. const newVal = ensurePrecision(value);
  111. setCurrentValue(newVal);
  112. emit(event.INPUT_EVENT, data.currentValue);
  113. setCurrentValueToModelValue();
  114. };
  115. const decrease = () => {
  116. if (props.readonly || inputNumberDisabled.value || minDisabled.value)
  117. return;
  118. const value = Number(displayValue.value) || 0;
  119. const newVal = ensurePrecision(value, -1);
  120. setCurrentValue(newVal);
  121. emit(event.INPUT_EVENT, data.currentValue);
  122. setCurrentValueToModelValue();
  123. };
  124. const verifyValue = (value, update) => {
  125. const { max, min, step, precision, stepStrictly, valueOnClear } = props;
  126. if (max < min) {
  127. error.throwError("InputNumber", "min should not be greater than max.");
  128. }
  129. let newVal = Number(value);
  130. if (lodashUnified.isNil(value) || Number.isNaN(newVal)) {
  131. return null;
  132. }
  133. if (value === "") {
  134. if (valueOnClear === null) {
  135. return null;
  136. }
  137. newVal = shared.isString(valueOnClear) ? { min, max }[valueOnClear] : valueOnClear;
  138. }
  139. if (stepStrictly) {
  140. newVal = toPrecision(Math.round(newVal / step) * step, precision);
  141. if (newVal !== value) {
  142. update && emit(event.UPDATE_MODEL_EVENT, newVal);
  143. }
  144. }
  145. if (!types.isUndefined(precision)) {
  146. newVal = toPrecision(newVal, precision);
  147. }
  148. if (newVal > max || newVal < min) {
  149. newVal = newVal > max ? max : min;
  150. update && emit(event.UPDATE_MODEL_EVENT, newVal);
  151. }
  152. return newVal;
  153. };
  154. const setCurrentValue = (value, emitChange = true) => {
  155. var _a;
  156. const oldVal = data.currentValue;
  157. const newVal = verifyValue(value);
  158. if (!emitChange) {
  159. emit(event.UPDATE_MODEL_EVENT, newVal);
  160. return;
  161. }
  162. if (oldVal === newVal && value)
  163. return;
  164. data.userInput = null;
  165. emit(event.UPDATE_MODEL_EVENT, newVal);
  166. if (oldVal !== newVal) {
  167. emit(event.CHANGE_EVENT, newVal, oldVal);
  168. }
  169. if (props.validateEvent) {
  170. (_a = formItem == null ? void 0 : formItem.validate) == null ? void 0 : _a.call(formItem, "change").catch((err) => error.debugWarn(err));
  171. }
  172. data.currentValue = newVal;
  173. };
  174. const handleInput = (value) => {
  175. data.userInput = value;
  176. const newVal = value === "" ? null : Number(value);
  177. emit(event.INPUT_EVENT, newVal);
  178. setCurrentValue(newVal, false);
  179. };
  180. const handleInputChange = (value) => {
  181. const newVal = value !== "" ? Number(value) : "";
  182. if (types.isNumber(newVal) && !Number.isNaN(newVal) || value === "") {
  183. setCurrentValue(newVal);
  184. }
  185. setCurrentValueToModelValue();
  186. data.userInput = null;
  187. };
  188. const focus = () => {
  189. var _a, _b;
  190. (_b = (_a = input.value) == null ? void 0 : _a.focus) == null ? void 0 : _b.call(_a);
  191. };
  192. const blur = () => {
  193. var _a, _b;
  194. (_b = (_a = input.value) == null ? void 0 : _a.blur) == null ? void 0 : _b.call(_a);
  195. };
  196. const handleFocus = (event) => {
  197. emit("focus", event);
  198. };
  199. const handleBlur = (event) => {
  200. var _a, _b;
  201. data.userInput = null;
  202. if (browser.isFirefox() && data.currentValue === null && ((_a = input.value) == null ? void 0 : _a.input)) {
  203. input.value.input.value = "";
  204. }
  205. emit("blur", event);
  206. if (props.validateEvent) {
  207. (_b = formItem == null ? void 0 : formItem.validate) == null ? void 0 : _b.call(formItem, "blur").catch((err) => error.debugWarn(err));
  208. }
  209. };
  210. const setCurrentValueToModelValue = () => {
  211. if (data.currentValue !== props.modelValue) {
  212. data.currentValue = props.modelValue;
  213. }
  214. };
  215. const handleWheel = (e) => {
  216. if (document.activeElement === e.target)
  217. e.preventDefault();
  218. };
  219. vue.watch(() => props.modelValue, (value, oldValue) => {
  220. const newValue = verifyValue(value, true);
  221. if (data.userInput === null && newValue !== oldValue) {
  222. data.currentValue = newValue;
  223. }
  224. }, { immediate: true });
  225. vue.onMounted(() => {
  226. var _a;
  227. const { min, max, modelValue } = props;
  228. const innerInput = (_a = input.value) == null ? void 0 : _a.input;
  229. innerInput.setAttribute("role", "spinbutton");
  230. if (Number.isFinite(max)) {
  231. innerInput.setAttribute("aria-valuemax", String(max));
  232. } else {
  233. innerInput.removeAttribute("aria-valuemax");
  234. }
  235. if (Number.isFinite(min)) {
  236. innerInput.setAttribute("aria-valuemin", String(min));
  237. } else {
  238. innerInput.removeAttribute("aria-valuemin");
  239. }
  240. innerInput.setAttribute("aria-valuenow", data.currentValue || data.currentValue === 0 ? String(data.currentValue) : "");
  241. innerInput.setAttribute("aria-disabled", String(inputNumberDisabled.value));
  242. if (!types.isNumber(modelValue) && modelValue != null) {
  243. let val = Number(modelValue);
  244. if (Number.isNaN(val)) {
  245. val = null;
  246. }
  247. emit(event.UPDATE_MODEL_EVENT, val);
  248. }
  249. innerInput.addEventListener("wheel", handleWheel, { passive: false });
  250. });
  251. vue.onUpdated(() => {
  252. var _a, _b;
  253. const innerInput = (_a = input.value) == null ? void 0 : _a.input;
  254. innerInput == null ? void 0 : innerInput.setAttribute("aria-valuenow", `${(_b = data.currentValue) != null ? _b : ""}`);
  255. });
  256. expose({
  257. focus,
  258. blur
  259. });
  260. return (_ctx, _cache) => {
  261. return vue.openBlock(), vue.createElementBlock("div", {
  262. class: vue.normalizeClass([
  263. vue.unref(ns).b(),
  264. vue.unref(ns).m(vue.unref(inputNumberSize)),
  265. vue.unref(ns).is("disabled", vue.unref(inputNumberDisabled)),
  266. vue.unref(ns).is("without-controls", !_ctx.controls),
  267. vue.unref(ns).is("controls-right", vue.unref(controlsAtRight))
  268. ]),
  269. onDragstart: vue.withModifiers(() => {
  270. }, ["prevent"])
  271. }, [
  272. _ctx.controls ? vue.withDirectives((vue.openBlock(), vue.createElementBlock("span", {
  273. key: 0,
  274. role: "button",
  275. "aria-label": vue.unref(t)("el.inputNumber.decrease"),
  276. class: vue.normalizeClass([vue.unref(ns).e("decrease"), vue.unref(ns).is("disabled", vue.unref(minDisabled))]),
  277. onKeydown: vue.withKeys(decrease, ["enter"])
  278. }, [
  279. vue.renderSlot(_ctx.$slots, "decrease-icon", {}, () => [
  280. vue.createVNode(vue.unref(index$2.ElIcon), null, {
  281. default: vue.withCtx(() => [
  282. vue.unref(controlsAtRight) ? (vue.openBlock(), vue.createBlock(vue.unref(iconsVue.ArrowDown), { key: 0 })) : (vue.openBlock(), vue.createBlock(vue.unref(iconsVue.Minus), { key: 1 }))
  283. ]),
  284. _: 1
  285. })
  286. ])
  287. ], 42, ["aria-label", "onKeydown"])), [
  288. [vue.unref(index$3.vRepeatClick), decrease]
  289. ]) : vue.createCommentVNode("v-if", true),
  290. _ctx.controls ? vue.withDirectives((vue.openBlock(), vue.createElementBlock("span", {
  291. key: 1,
  292. role: "button",
  293. "aria-label": vue.unref(t)("el.inputNumber.increase"),
  294. class: vue.normalizeClass([vue.unref(ns).e("increase"), vue.unref(ns).is("disabled", vue.unref(maxDisabled))]),
  295. onKeydown: vue.withKeys(increase, ["enter"])
  296. }, [
  297. vue.renderSlot(_ctx.$slots, "increase-icon", {}, () => [
  298. vue.createVNode(vue.unref(index$2.ElIcon), null, {
  299. default: vue.withCtx(() => [
  300. vue.unref(controlsAtRight) ? (vue.openBlock(), vue.createBlock(vue.unref(iconsVue.ArrowUp), { key: 0 })) : (vue.openBlock(), vue.createBlock(vue.unref(iconsVue.Plus), { key: 1 }))
  301. ]),
  302. _: 1
  303. })
  304. ])
  305. ], 42, ["aria-label", "onKeydown"])), [
  306. [vue.unref(index$3.vRepeatClick), increase]
  307. ]) : vue.createCommentVNode("v-if", true),
  308. vue.createVNode(vue.unref(index$4.ElInput), {
  309. id: _ctx.id,
  310. ref_key: "input",
  311. ref: input,
  312. type: "number",
  313. step: _ctx.step,
  314. "model-value": vue.unref(displayValue),
  315. placeholder: _ctx.placeholder,
  316. readonly: _ctx.readonly,
  317. disabled: vue.unref(inputNumberDisabled),
  318. size: vue.unref(inputNumberSize),
  319. max: _ctx.max,
  320. min: _ctx.min,
  321. name: _ctx.name,
  322. "aria-label": _ctx.ariaLabel,
  323. "validate-event": false,
  324. onKeydown: [
  325. vue.withKeys(vue.withModifiers(increase, ["prevent"]), ["up"]),
  326. vue.withKeys(vue.withModifiers(decrease, ["prevent"]), ["down"])
  327. ],
  328. onBlur: handleBlur,
  329. onFocus: handleFocus,
  330. onInput: handleInput,
  331. onChange: handleInputChange
  332. }, vue.createSlots({
  333. _: 2
  334. }, [
  335. _ctx.$slots.prefix ? {
  336. name: "prefix",
  337. fn: vue.withCtx(() => [
  338. vue.renderSlot(_ctx.$slots, "prefix")
  339. ])
  340. } : void 0,
  341. _ctx.$slots.suffix ? {
  342. name: "suffix",
  343. fn: vue.withCtx(() => [
  344. vue.renderSlot(_ctx.$slots, "suffix")
  345. ])
  346. } : void 0
  347. ]), 1032, ["id", "step", "model-value", "placeholder", "readonly", "disabled", "size", "max", "min", "name", "aria-label", "onKeydown"])
  348. ], 42, ["onDragstart"]);
  349. };
  350. }
  351. });
  352. var InputNumber = /* @__PURE__ */ pluginVue_exportHelper["default"](_sfc_main, [["__file", "input-number.vue"]]);
  353. exports["default"] = InputNumber;
  354. //# sourceMappingURL=input-number2.js.map