Stepper.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. var __defProp = Object.defineProperty;
  2. var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
  3. var __getOwnPropNames = Object.getOwnPropertyNames;
  4. var __hasOwnProp = Object.prototype.hasOwnProperty;
  5. var __export = (target, all) => {
  6. for (var name2 in all)
  7. __defProp(target, name2, { get: all[name2], enumerable: true });
  8. };
  9. var __copyProps = (to, from, except, desc) => {
  10. if (from && typeof from === "object" || typeof from === "function") {
  11. for (let key of __getOwnPropNames(from))
  12. if (!__hasOwnProp.call(to, key) && key !== except)
  13. __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  14. }
  15. return to;
  16. };
  17. var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
  18. var stdin_exports = {};
  19. __export(stdin_exports, {
  20. default: () => stdin_default,
  21. stepperProps: () => stepperProps
  22. });
  23. module.exports = __toCommonJS(stdin_exports);
  24. var import_vue = require("vue");
  25. var import_vue2 = require("vue");
  26. var import_utils = require("../utils");
  27. var import_use = require("@vant/use");
  28. const [name, bem] = (0, import_utils.createNamespace)("stepper");
  29. const LONG_PRESS_INTERVAL = 200;
  30. const isEqual = (value1, value2) => String(value1) === String(value2);
  31. const stepperProps = {
  32. min: (0, import_utils.makeNumericProp)(1),
  33. max: (0, import_utils.makeNumericProp)(Infinity),
  34. name: (0, import_utils.makeNumericProp)(""),
  35. step: (0, import_utils.makeNumericProp)(1),
  36. theme: String,
  37. integer: Boolean,
  38. disabled: Boolean,
  39. showPlus: import_utils.truthProp,
  40. showMinus: import_utils.truthProp,
  41. showInput: import_utils.truthProp,
  42. longPress: import_utils.truthProp,
  43. autoFixed: import_utils.truthProp,
  44. allowEmpty: Boolean,
  45. modelValue: import_utils.numericProp,
  46. inputWidth: import_utils.numericProp,
  47. buttonSize: import_utils.numericProp,
  48. placeholder: String,
  49. disablePlus: Boolean,
  50. disableMinus: Boolean,
  51. disableInput: Boolean,
  52. beforeChange: Function,
  53. defaultValue: (0, import_utils.makeNumericProp)(1),
  54. decimalLength: import_utils.numericProp
  55. };
  56. var stdin_default = (0, import_vue2.defineComponent)({
  57. name,
  58. props: stepperProps,
  59. emits: ["plus", "blur", "minus", "focus", "change", "overlimit", "update:modelValue"],
  60. setup(props, {
  61. emit
  62. }) {
  63. const format = (value, autoFixed = true) => {
  64. const {
  65. min,
  66. max,
  67. allowEmpty,
  68. decimalLength
  69. } = props;
  70. if (allowEmpty && value === "") {
  71. return value;
  72. }
  73. value = (0, import_utils.formatNumber)(String(value), !props.integer);
  74. value = value === "" ? 0 : +value;
  75. value = Number.isNaN(value) ? +min : value;
  76. value = autoFixed ? Math.max(Math.min(+max, value), +min) : value;
  77. if ((0, import_utils.isDef)(decimalLength)) {
  78. value = value.toFixed(+decimalLength);
  79. }
  80. return value;
  81. };
  82. const getInitialValue = () => {
  83. var _a;
  84. const defaultValue = (_a = props.modelValue) != null ? _a : props.defaultValue;
  85. const value = format(defaultValue);
  86. if (!isEqual(value, props.modelValue)) {
  87. emit("update:modelValue", value);
  88. }
  89. return value;
  90. };
  91. let actionType;
  92. const inputRef = (0, import_vue2.ref)();
  93. const current = (0, import_vue2.ref)(getInitialValue());
  94. const minusDisabled = (0, import_vue2.computed)(() => props.disabled || props.disableMinus || current.value <= +props.min);
  95. const plusDisabled = (0, import_vue2.computed)(() => props.disabled || props.disablePlus || current.value >= +props.max);
  96. const inputStyle = (0, import_vue2.computed)(() => ({
  97. width: (0, import_utils.addUnit)(props.inputWidth),
  98. height: (0, import_utils.addUnit)(props.buttonSize)
  99. }));
  100. const buttonStyle = (0, import_vue2.computed)(() => (0, import_utils.getSizeStyle)(props.buttonSize));
  101. const check = () => {
  102. const value = format(current.value);
  103. if (!isEqual(value, current.value)) {
  104. current.value = value;
  105. }
  106. };
  107. const setValue = (value) => {
  108. if (props.beforeChange) {
  109. (0, import_utils.callInterceptor)(props.beforeChange, {
  110. args: [value],
  111. done() {
  112. current.value = value;
  113. }
  114. });
  115. } else {
  116. current.value = value;
  117. }
  118. };
  119. const onChange = () => {
  120. if (actionType === "plus" && plusDisabled.value || actionType === "minus" && minusDisabled.value) {
  121. emit("overlimit", actionType);
  122. return;
  123. }
  124. const diff = actionType === "minus" ? -props.step : +props.step;
  125. const value = format((0, import_utils.addNumber)(+current.value, diff));
  126. setValue(value);
  127. emit(actionType);
  128. };
  129. const onInput = (event) => {
  130. const input = event.target;
  131. const {
  132. value
  133. } = input;
  134. const {
  135. decimalLength
  136. } = props;
  137. let formatted = (0, import_utils.formatNumber)(String(value), !props.integer);
  138. if ((0, import_utils.isDef)(decimalLength) && formatted.includes(".")) {
  139. const pair = formatted.split(".");
  140. formatted = `${pair[0]}.${pair[1].slice(0, +decimalLength)}`;
  141. }
  142. if (props.beforeChange) {
  143. input.value = String(current.value);
  144. } else if (!isEqual(value, formatted)) {
  145. input.value = formatted;
  146. }
  147. const isNumeric = formatted === String(+formatted);
  148. setValue(isNumeric ? +formatted : formatted);
  149. };
  150. const onFocus = (event) => {
  151. var _a;
  152. if (props.disableInput) {
  153. (_a = inputRef.value) == null ? void 0 : _a.blur();
  154. } else {
  155. emit("focus", event);
  156. }
  157. };
  158. const onBlur = (event) => {
  159. const input = event.target;
  160. const value = format(input.value, props.autoFixed);
  161. input.value = String(value);
  162. current.value = value;
  163. (0, import_vue2.nextTick)(() => {
  164. emit("blur", event);
  165. (0, import_utils.resetScroll)();
  166. });
  167. };
  168. let isLongPress;
  169. let longPressTimer;
  170. const longPressStep = () => {
  171. longPressTimer = setTimeout(() => {
  172. onChange();
  173. longPressStep();
  174. }, LONG_PRESS_INTERVAL);
  175. };
  176. const onTouchStart = () => {
  177. if (props.longPress) {
  178. isLongPress = false;
  179. clearTimeout(longPressTimer);
  180. longPressTimer = setTimeout(() => {
  181. isLongPress = true;
  182. onChange();
  183. longPressStep();
  184. }, import_utils.LONG_PRESS_START_TIME);
  185. }
  186. };
  187. const onTouchEnd = (event) => {
  188. if (props.longPress) {
  189. clearTimeout(longPressTimer);
  190. if (isLongPress) {
  191. (0, import_utils.preventDefault)(event);
  192. }
  193. }
  194. };
  195. const onMousedown = (event) => {
  196. if (props.disableInput) {
  197. (0, import_utils.preventDefault)(event);
  198. }
  199. };
  200. const createListeners = (type) => ({
  201. onClick: (event) => {
  202. (0, import_utils.preventDefault)(event);
  203. actionType = type;
  204. onChange();
  205. },
  206. onTouchstartPassive: () => {
  207. actionType = type;
  208. onTouchStart();
  209. },
  210. onTouchend: onTouchEnd,
  211. onTouchcancel: onTouchEnd
  212. });
  213. (0, import_vue2.watch)(() => [props.max, props.min, props.integer, props.decimalLength], check);
  214. (0, import_vue2.watch)(() => props.modelValue, (value) => {
  215. if (!isEqual(value, current.value)) {
  216. current.value = format(value);
  217. }
  218. });
  219. (0, import_vue2.watch)(current, (value) => {
  220. emit("update:modelValue", value);
  221. emit("change", value, {
  222. name: props.name
  223. });
  224. });
  225. (0, import_use.useCustomFieldValue)(() => props.modelValue);
  226. return () => (0, import_vue.createVNode)("div", {
  227. "role": "group",
  228. "class": bem([props.theme])
  229. }, [(0, import_vue.withDirectives)((0, import_vue.createVNode)("button", (0, import_vue.mergeProps)({
  230. "type": "button",
  231. "style": buttonStyle.value,
  232. "class": [bem("minus", {
  233. disabled: minusDisabled.value
  234. }), {
  235. [import_utils.HAPTICS_FEEDBACK]: !minusDisabled.value
  236. }],
  237. "aria-disabled": minusDisabled.value || void 0
  238. }, createListeners("minus")), null), [[import_vue.vShow, props.showMinus]]), (0, import_vue.withDirectives)((0, import_vue.createVNode)("input", {
  239. "ref": inputRef,
  240. "type": props.integer ? "tel" : "text",
  241. "role": "spinbutton",
  242. "class": bem("input"),
  243. "value": current.value,
  244. "style": inputStyle.value,
  245. "disabled": props.disabled,
  246. "readonly": props.disableInput,
  247. "inputmode": props.integer ? "numeric" : "decimal",
  248. "placeholder": props.placeholder,
  249. "aria-valuemax": props.max,
  250. "aria-valuemin": props.min,
  251. "aria-valuenow": current.value,
  252. "onBlur": onBlur,
  253. "onInput": onInput,
  254. "onFocus": onFocus,
  255. "onMousedown": onMousedown
  256. }, null), [[import_vue.vShow, props.showInput]]), (0, import_vue.withDirectives)((0, import_vue.createVNode)("button", (0, import_vue.mergeProps)({
  257. "type": "button",
  258. "style": buttonStyle.value,
  259. "class": [bem("plus", {
  260. disabled: plusDisabled.value
  261. }), {
  262. [import_utils.HAPTICS_FEEDBACK]: !plusDisabled.value
  263. }],
  264. "aria-disabled": plusDisabled.value || void 0
  265. }, createListeners("plus")), null), [[import_vue.vShow, props.showPlus]])]);
  266. }
  267. });