7a1872c3d017606556d4a32c49463d3f129b56f5001b649fb0d5ec4ef20ad6a49d8919933a3110341696a7aa45c9d0f47ccdf0421bf82b86137575fc89f87f 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. import { defineComponent, useAttrs, useSlots, computed, shallowRef, ref, watch, nextTick, onMounted, toRef, openBlock, createElementBlock, normalizeClass, unref, normalizeStyle, createCommentVNode, Fragment, renderSlot, createElementVNode, createBlock, withCtx, resolveDynamicComponent, mergeProps, withModifiers, toDisplayString } from 'vue';
  2. import { useResizeObserver, isClient } from '@vueuse/core';
  3. import { isNil } from 'lodash-unified';
  4. import { ElIcon } from '../../icon/index.mjs';
  5. import { View, Hide } from '@element-plus/icons-vue';
  6. import { calcTextareaHeight } from './utils.mjs';
  7. import { inputProps, inputEmits } from './input.mjs';
  8. import _export_sfc from '../../../_virtual/plugin-vue_export-helper.mjs';
  9. import { useAttrs as useAttrs$1 } from '../../../hooks/use-attrs/index.mjs';
  10. import { useFormItem, useFormItemInputId } from '../../form/src/hooks/use-form-item.mjs';
  11. import { useFormSize, useFormDisabled } from '../../form/src/hooks/use-form-common-props.mjs';
  12. import { useFocusController } from '../../../hooks/use-focus-controller/index.mjs';
  13. import { ValidateComponentsMap } from '../../../utils/vue/icon.mjs';
  14. import { useComposition } from '../../../hooks/use-composition/index.mjs';
  15. import { UPDATE_MODEL_EVENT, INPUT_EVENT, CHANGE_EVENT } from '../../../constants/event.mjs';
  16. import { useCursor } from '../../../hooks/use-cursor/index.mjs';
  17. import { useNamespace } from '../../../hooks/use-namespace/index.mjs';
  18. import { debugWarn } from '../../../utils/error.mjs';
  19. import { NOOP, isObject } from '@vue/shared';
  20. const COMPONENT_NAME = "ElInput";
  21. const __default__ = defineComponent({
  22. name: COMPONENT_NAME,
  23. inheritAttrs: false
  24. });
  25. const _sfc_main = /* @__PURE__ */ defineComponent({
  26. ...__default__,
  27. props: inputProps,
  28. emits: inputEmits,
  29. setup(__props, { expose, emit }) {
  30. const props = __props;
  31. const rawAttrs = useAttrs();
  32. const attrs = useAttrs$1();
  33. const slots = useSlots();
  34. const containerKls = computed(() => [
  35. props.type === "textarea" ? nsTextarea.b() : nsInput.b(),
  36. nsInput.m(inputSize.value),
  37. nsInput.is("disabled", inputDisabled.value),
  38. nsInput.is("exceed", inputExceed.value),
  39. {
  40. [nsInput.b("group")]: slots.prepend || slots.append,
  41. [nsInput.m("prefix")]: slots.prefix || props.prefixIcon,
  42. [nsInput.m("suffix")]: slots.suffix || props.suffixIcon || props.clearable || props.showPassword,
  43. [nsInput.bm("suffix", "password-clear")]: showClear.value && showPwdVisible.value,
  44. [nsInput.b("hidden")]: props.type === "hidden"
  45. },
  46. rawAttrs.class
  47. ]);
  48. const wrapperKls = computed(() => [
  49. nsInput.e("wrapper"),
  50. nsInput.is("focus", isFocused.value)
  51. ]);
  52. const { form: elForm, formItem: elFormItem } = useFormItem();
  53. const { inputId } = useFormItemInputId(props, {
  54. formItemContext: elFormItem
  55. });
  56. const inputSize = useFormSize();
  57. const inputDisabled = useFormDisabled();
  58. const nsInput = useNamespace("input");
  59. const nsTextarea = useNamespace("textarea");
  60. const input = shallowRef();
  61. const textarea = shallowRef();
  62. const hovering = ref(false);
  63. const passwordVisible = ref(false);
  64. const countStyle = ref();
  65. const textareaCalcStyle = shallowRef(props.inputStyle);
  66. const _ref = computed(() => input.value || textarea.value);
  67. const { wrapperRef, isFocused, handleFocus, handleBlur } = useFocusController(_ref, {
  68. disabled: inputDisabled,
  69. afterBlur() {
  70. var _a;
  71. if (props.validateEvent) {
  72. (_a = elFormItem == null ? void 0 : elFormItem.validate) == null ? void 0 : _a.call(elFormItem, "blur").catch((err) => debugWarn());
  73. }
  74. }
  75. });
  76. const needStatusIcon = computed(() => {
  77. var _a;
  78. return (_a = elForm == null ? void 0 : elForm.statusIcon) != null ? _a : false;
  79. });
  80. const validateState = computed(() => (elFormItem == null ? void 0 : elFormItem.validateState) || "");
  81. const validateIcon = computed(() => validateState.value && ValidateComponentsMap[validateState.value]);
  82. const passwordIcon = computed(() => passwordVisible.value ? View : Hide);
  83. const containerStyle = computed(() => [
  84. rawAttrs.style
  85. ]);
  86. const textareaStyle = computed(() => [
  87. props.inputStyle,
  88. textareaCalcStyle.value,
  89. { resize: props.resize }
  90. ]);
  91. const nativeInputValue = computed(() => isNil(props.modelValue) ? "" : String(props.modelValue));
  92. const showClear = computed(() => props.clearable && !inputDisabled.value && !props.readonly && !!nativeInputValue.value && (isFocused.value || hovering.value));
  93. const showPwdVisible = computed(() => props.showPassword && !inputDisabled.value && !!nativeInputValue.value);
  94. const isWordLimitVisible = computed(() => props.showWordLimit && !!props.maxlength && (props.type === "text" || props.type === "textarea") && !inputDisabled.value && !props.readonly && !props.showPassword);
  95. const textLength = computed(() => nativeInputValue.value.length);
  96. const inputExceed = computed(() => !!isWordLimitVisible.value && textLength.value > Number(props.maxlength));
  97. const suffixVisible = computed(() => !!slots.suffix || !!props.suffixIcon || showClear.value || props.showPassword || isWordLimitVisible.value || !!validateState.value && needStatusIcon.value);
  98. const [recordCursor, setCursor] = useCursor(input);
  99. useResizeObserver(textarea, (entries) => {
  100. onceInitSizeTextarea();
  101. if (!isWordLimitVisible.value || props.resize !== "both")
  102. return;
  103. const entry = entries[0];
  104. const { width } = entry.contentRect;
  105. countStyle.value = {
  106. right: `calc(100% - ${width + 15 + 6}px)`
  107. };
  108. });
  109. const resizeTextarea = () => {
  110. const { type, autosize } = props;
  111. if (!isClient || type !== "textarea" || !textarea.value)
  112. return;
  113. if (autosize) {
  114. const minRows = isObject(autosize) ? autosize.minRows : void 0;
  115. const maxRows = isObject(autosize) ? autosize.maxRows : void 0;
  116. const textareaStyle2 = calcTextareaHeight(textarea.value, minRows, maxRows);
  117. textareaCalcStyle.value = {
  118. overflowY: "hidden",
  119. ...textareaStyle2
  120. };
  121. nextTick(() => {
  122. textarea.value.offsetHeight;
  123. textareaCalcStyle.value = textareaStyle2;
  124. });
  125. } else {
  126. textareaCalcStyle.value = {
  127. minHeight: calcTextareaHeight(textarea.value).minHeight
  128. };
  129. }
  130. };
  131. const createOnceInitResize = (resizeTextarea2) => {
  132. let isInit = false;
  133. return () => {
  134. var _a;
  135. if (isInit || !props.autosize)
  136. return;
  137. const isElHidden = ((_a = textarea.value) == null ? void 0 : _a.offsetParent) === null;
  138. if (!isElHidden) {
  139. setTimeout(resizeTextarea2);
  140. isInit = true;
  141. }
  142. };
  143. };
  144. const onceInitSizeTextarea = createOnceInitResize(resizeTextarea);
  145. const setNativeInputValue = () => {
  146. const input2 = _ref.value;
  147. const formatterValue = props.formatter ? props.formatter(nativeInputValue.value) : nativeInputValue.value;
  148. if (!input2 || input2.value === formatterValue)
  149. return;
  150. input2.value = formatterValue;
  151. };
  152. const handleInput = async (event) => {
  153. recordCursor();
  154. let { value } = event.target;
  155. if (props.formatter && props.parser) {
  156. value = props.parser(value);
  157. }
  158. if (isComposing.value)
  159. return;
  160. if (value === nativeInputValue.value) {
  161. setNativeInputValue();
  162. return;
  163. }
  164. emit(UPDATE_MODEL_EVENT, value);
  165. emit(INPUT_EVENT, value);
  166. await nextTick();
  167. setNativeInputValue();
  168. setCursor();
  169. };
  170. const handleChange = (event) => {
  171. let { value } = event.target;
  172. if (props.formatter && props.parser) {
  173. value = props.parser(value);
  174. }
  175. emit(CHANGE_EVENT, value);
  176. };
  177. const {
  178. isComposing,
  179. handleCompositionStart,
  180. handleCompositionUpdate,
  181. handleCompositionEnd
  182. } = useComposition({ emit, afterComposition: handleInput });
  183. const handlePasswordVisible = () => {
  184. recordCursor();
  185. passwordVisible.value = !passwordVisible.value;
  186. setTimeout(setCursor);
  187. };
  188. const focus = () => {
  189. var _a;
  190. return (_a = _ref.value) == null ? void 0 : _a.focus();
  191. };
  192. const blur = () => {
  193. var _a;
  194. return (_a = _ref.value) == null ? void 0 : _a.blur();
  195. };
  196. const handleMouseLeave = (evt) => {
  197. hovering.value = false;
  198. emit("mouseleave", evt);
  199. };
  200. const handleMouseEnter = (evt) => {
  201. hovering.value = true;
  202. emit("mouseenter", evt);
  203. };
  204. const handleKeydown = (evt) => {
  205. emit("keydown", evt);
  206. };
  207. const select = () => {
  208. var _a;
  209. (_a = _ref.value) == null ? void 0 : _a.select();
  210. };
  211. const clear = () => {
  212. emit(UPDATE_MODEL_EVENT, "");
  213. emit(CHANGE_EVENT, "");
  214. emit("clear");
  215. emit(INPUT_EVENT, "");
  216. };
  217. watch(() => props.modelValue, () => {
  218. var _a;
  219. nextTick(() => resizeTextarea());
  220. if (props.validateEvent) {
  221. (_a = elFormItem == null ? void 0 : elFormItem.validate) == null ? void 0 : _a.call(elFormItem, "change").catch((err) => debugWarn());
  222. }
  223. });
  224. watch(nativeInputValue, () => setNativeInputValue());
  225. watch(() => props.type, async () => {
  226. await nextTick();
  227. setNativeInputValue();
  228. resizeTextarea();
  229. });
  230. onMounted(() => {
  231. if (!props.formatter && props.parser) ;
  232. setNativeInputValue();
  233. nextTick(resizeTextarea);
  234. });
  235. expose({
  236. input,
  237. textarea,
  238. ref: _ref,
  239. textareaStyle,
  240. autosize: toRef(props, "autosize"),
  241. isComposing,
  242. focus,
  243. blur,
  244. select,
  245. clear,
  246. resizeTextarea
  247. });
  248. return (_ctx, _cache) => {
  249. return openBlock(), createElementBlock("div", {
  250. class: normalizeClass([
  251. unref(containerKls),
  252. {
  253. [unref(nsInput).bm("group", "append")]: _ctx.$slots.append,
  254. [unref(nsInput).bm("group", "prepend")]: _ctx.$slots.prepend
  255. }
  256. ]),
  257. style: normalizeStyle(unref(containerStyle)),
  258. onMouseenter: handleMouseEnter,
  259. onMouseleave: handleMouseLeave
  260. }, [
  261. createCommentVNode(" input "),
  262. _ctx.type !== "textarea" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
  263. createCommentVNode(" prepend slot "),
  264. _ctx.$slots.prepend ? (openBlock(), createElementBlock("div", {
  265. key: 0,
  266. class: normalizeClass(unref(nsInput).be("group", "prepend"))
  267. }, [
  268. renderSlot(_ctx.$slots, "prepend")
  269. ], 2)) : createCommentVNode("v-if", true),
  270. createElementVNode("div", {
  271. ref_key: "wrapperRef",
  272. ref: wrapperRef,
  273. class: normalizeClass(unref(wrapperKls))
  274. }, [
  275. createCommentVNode(" prefix slot "),
  276. _ctx.$slots.prefix || _ctx.prefixIcon ? (openBlock(), createElementBlock("span", {
  277. key: 0,
  278. class: normalizeClass(unref(nsInput).e("prefix"))
  279. }, [
  280. createElementVNode("span", {
  281. class: normalizeClass(unref(nsInput).e("prefix-inner"))
  282. }, [
  283. renderSlot(_ctx.$slots, "prefix"),
  284. _ctx.prefixIcon ? (openBlock(), createBlock(unref(ElIcon), {
  285. key: 0,
  286. class: normalizeClass(unref(nsInput).e("icon"))
  287. }, {
  288. default: withCtx(() => [
  289. (openBlock(), createBlock(resolveDynamicComponent(_ctx.prefixIcon)))
  290. ]),
  291. _: 1
  292. }, 8, ["class"])) : createCommentVNode("v-if", true)
  293. ], 2)
  294. ], 2)) : createCommentVNode("v-if", true),
  295. createElementVNode("input", mergeProps({
  296. id: unref(inputId),
  297. ref_key: "input",
  298. ref: input,
  299. class: unref(nsInput).e("inner")
  300. }, unref(attrs), {
  301. name: _ctx.name,
  302. minlength: _ctx.minlength,
  303. maxlength: _ctx.maxlength,
  304. type: _ctx.showPassword ? passwordVisible.value ? "text" : "password" : _ctx.type,
  305. disabled: unref(inputDisabled),
  306. readonly: _ctx.readonly,
  307. autocomplete: _ctx.autocomplete,
  308. tabindex: _ctx.tabindex,
  309. "aria-label": _ctx.ariaLabel,
  310. placeholder: _ctx.placeholder,
  311. style: _ctx.inputStyle,
  312. form: _ctx.form,
  313. autofocus: _ctx.autofocus,
  314. role: _ctx.containerRole,
  315. inputmode: _ctx.inputmode,
  316. onCompositionstart: unref(handleCompositionStart),
  317. onCompositionupdate: unref(handleCompositionUpdate),
  318. onCompositionend: unref(handleCompositionEnd),
  319. onInput: handleInput,
  320. onChange: handleChange,
  321. onKeydown: handleKeydown
  322. }), null, 16, ["id", "name", "minlength", "maxlength", "type", "disabled", "readonly", "autocomplete", "tabindex", "aria-label", "placeholder", "form", "autofocus", "role", "inputmode", "onCompositionstart", "onCompositionupdate", "onCompositionend"]),
  323. createCommentVNode(" suffix slot "),
  324. unref(suffixVisible) ? (openBlock(), createElementBlock("span", {
  325. key: 1,
  326. class: normalizeClass(unref(nsInput).e("suffix"))
  327. }, [
  328. createElementVNode("span", {
  329. class: normalizeClass(unref(nsInput).e("suffix-inner"))
  330. }, [
  331. !unref(showClear) || !unref(showPwdVisible) || !unref(isWordLimitVisible) ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
  332. renderSlot(_ctx.$slots, "suffix"),
  333. _ctx.suffixIcon ? (openBlock(), createBlock(unref(ElIcon), {
  334. key: 0,
  335. class: normalizeClass(unref(nsInput).e("icon"))
  336. }, {
  337. default: withCtx(() => [
  338. (openBlock(), createBlock(resolveDynamicComponent(_ctx.suffixIcon)))
  339. ]),
  340. _: 1
  341. }, 8, ["class"])) : createCommentVNode("v-if", true)
  342. ], 64)) : createCommentVNode("v-if", true),
  343. unref(showClear) ? (openBlock(), createBlock(unref(ElIcon), {
  344. key: 1,
  345. class: normalizeClass([unref(nsInput).e("icon"), unref(nsInput).e("clear")]),
  346. onMousedown: withModifiers(unref(NOOP), ["prevent"]),
  347. onClick: clear
  348. }, {
  349. default: withCtx(() => [
  350. (openBlock(), createBlock(resolveDynamicComponent(_ctx.clearIcon)))
  351. ]),
  352. _: 1
  353. }, 8, ["class", "onMousedown"])) : createCommentVNode("v-if", true),
  354. unref(showPwdVisible) ? (openBlock(), createBlock(unref(ElIcon), {
  355. key: 2,
  356. class: normalizeClass([unref(nsInput).e("icon"), unref(nsInput).e("password")]),
  357. onClick: handlePasswordVisible
  358. }, {
  359. default: withCtx(() => [
  360. (openBlock(), createBlock(resolveDynamicComponent(unref(passwordIcon))))
  361. ]),
  362. _: 1
  363. }, 8, ["class"])) : createCommentVNode("v-if", true),
  364. unref(isWordLimitVisible) ? (openBlock(), createElementBlock("span", {
  365. key: 3,
  366. class: normalizeClass(unref(nsInput).e("count"))
  367. }, [
  368. createElementVNode("span", {
  369. class: normalizeClass(unref(nsInput).e("count-inner"))
  370. }, toDisplayString(unref(textLength)) + " / " + toDisplayString(_ctx.maxlength), 3)
  371. ], 2)) : createCommentVNode("v-if", true),
  372. unref(validateState) && unref(validateIcon) && unref(needStatusIcon) ? (openBlock(), createBlock(unref(ElIcon), {
  373. key: 4,
  374. class: normalizeClass([
  375. unref(nsInput).e("icon"),
  376. unref(nsInput).e("validateIcon"),
  377. unref(nsInput).is("loading", unref(validateState) === "validating")
  378. ])
  379. }, {
  380. default: withCtx(() => [
  381. (openBlock(), createBlock(resolveDynamicComponent(unref(validateIcon))))
  382. ]),
  383. _: 1
  384. }, 8, ["class"])) : createCommentVNode("v-if", true)
  385. ], 2)
  386. ], 2)) : createCommentVNode("v-if", true)
  387. ], 2),
  388. createCommentVNode(" append slot "),
  389. _ctx.$slots.append ? (openBlock(), createElementBlock("div", {
  390. key: 1,
  391. class: normalizeClass(unref(nsInput).be("group", "append"))
  392. }, [
  393. renderSlot(_ctx.$slots, "append")
  394. ], 2)) : createCommentVNode("v-if", true)
  395. ], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
  396. createCommentVNode(" textarea "),
  397. createElementVNode("textarea", mergeProps({
  398. id: unref(inputId),
  399. ref_key: "textarea",
  400. ref: textarea,
  401. class: [unref(nsTextarea).e("inner"), unref(nsInput).is("focus", unref(isFocused))]
  402. }, unref(attrs), {
  403. minlength: _ctx.minlength,
  404. maxlength: _ctx.maxlength,
  405. tabindex: _ctx.tabindex,
  406. disabled: unref(inputDisabled),
  407. readonly: _ctx.readonly,
  408. autocomplete: _ctx.autocomplete,
  409. style: unref(textareaStyle),
  410. "aria-label": _ctx.ariaLabel,
  411. placeholder: _ctx.placeholder,
  412. form: _ctx.form,
  413. autofocus: _ctx.autofocus,
  414. rows: _ctx.rows,
  415. role: _ctx.containerRole,
  416. onCompositionstart: unref(handleCompositionStart),
  417. onCompositionupdate: unref(handleCompositionUpdate),
  418. onCompositionend: unref(handleCompositionEnd),
  419. onInput: handleInput,
  420. onFocus: unref(handleFocus),
  421. onBlur: unref(handleBlur),
  422. onChange: handleChange,
  423. onKeydown: handleKeydown
  424. }), null, 16, ["id", "minlength", "maxlength", "tabindex", "disabled", "readonly", "autocomplete", "aria-label", "placeholder", "form", "autofocus", "rows", "role", "onCompositionstart", "onCompositionupdate", "onCompositionend", "onFocus", "onBlur"]),
  425. unref(isWordLimitVisible) ? (openBlock(), createElementBlock("span", {
  426. key: 0,
  427. style: normalizeStyle(countStyle.value),
  428. class: normalizeClass(unref(nsInput).e("count"))
  429. }, toDisplayString(unref(textLength)) + " / " + toDisplayString(_ctx.maxlength), 7)) : createCommentVNode("v-if", true)
  430. ], 64))
  431. ], 38);
  432. };
  433. }
  434. });
  435. var Input = /* @__PURE__ */ _export_sfc(_sfc_main, [["__file", "input.vue"]]);
  436. export { Input as default };
  437. //# sourceMappingURL=input2.mjs.map