UNPKG

4.38 kBJavaScriptView Raw
1import { useIsomorphicLayoutEffect } from 'ahooks';
2import { CloseCircleFill } from 'antd-mobile-icons';
3import classNames from 'classnames';
4import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
5import { withNativeProps } from '../../utils/native-props';
6import { usePropsValue } from '../../utils/use-props-value';
7import { mergeProp, mergeProps } from '../../utils/with-default-props';
8import { useConfig } from '../config-provider';
9const classPrefix = 'adm-virtual-input';
10const defaultProps = {
11 defaultValue: ''
12};
13export const VirtualInput = forwardRef((props, ref) => {
14 const {
15 locale,
16 input: componentConfig = {}
17 } = useConfig();
18 const mergedProps = mergeProps(defaultProps, componentConfig, props);
19 const [value, setValue] = usePropsValue(mergedProps);
20 const rootRef = useRef(null);
21 const contentRef = useRef(null);
22 const [hasFocus, setHasFocus] = useState(false);
23 const clearIcon = mergeProp(React.createElement(CloseCircleFill, null), componentConfig.clearIcon, props.clearIcon);
24 function scrollToEnd() {
25 const root = rootRef.current;
26 if (!root) return;
27 if (document.activeElement !== root) {
28 return;
29 }
30 const content = contentRef.current;
31 if (!content) return;
32 content.scrollLeft = content.clientWidth;
33 }
34 useIsomorphicLayoutEffect(() => {
35 scrollToEnd();
36 }, [value]);
37 useEffect(() => {
38 if (hasFocus) {
39 scrollToEnd();
40 }
41 }, [hasFocus]);
42 useImperativeHandle(ref, () => ({
43 focus: () => {
44 var _a;
45 (_a = rootRef.current) === null || _a === void 0 ? void 0 : _a.focus();
46 },
47 blur: () => {
48 var _a;
49 (_a = rootRef.current) === null || _a === void 0 ? void 0 : _a.blur();
50 }
51 }));
52 function onFocus() {
53 var _a;
54 setHasFocus(true);
55 (_a = mergedProps.onFocus) === null || _a === void 0 ? void 0 : _a.call(mergedProps);
56 }
57 function onBlur() {
58 var _a;
59 setHasFocus(false);
60 (_a = mergedProps.onBlur) === null || _a === void 0 ? void 0 : _a.call(mergedProps);
61 }
62 const keyboard = mergedProps.keyboard;
63 const keyboardElement = keyboard && React.cloneElement(keyboard, {
64 onInput: v => {
65 var _a, _b;
66 setValue(value + v);
67 (_b = (_a = keyboard.props).onInput) === null || _b === void 0 ? void 0 : _b.call(_a, v);
68 },
69 onDelete: () => {
70 var _a, _b;
71 setValue(value.slice(0, -1));
72 (_b = (_a = keyboard.props).onDelete) === null || _b === void 0 ? void 0 : _b.call(_a);
73 },
74 visible: hasFocus,
75 onClose: () => {
76 var _a, _b, _c, _d;
77 const activeElement = document.activeElement;
78 // Long press makes `activeElement` to be the child of rootRef
79 // We will trigger blur on the child element instead
80 if (activeElement && ((_a = rootRef.current) === null || _a === void 0 ? void 0 : _a.contains(activeElement))) {
81 activeElement.blur();
82 } else {
83 (_b = rootRef.current) === null || _b === void 0 ? void 0 : _b.blur();
84 }
85 (_d = (_c = keyboard.props).onClose) === null || _d === void 0 ? void 0 : _d.call(_c);
86 },
87 getContainer: null
88 });
89 return withNativeProps(mergedProps, React.createElement("div", {
90 ref: rootRef,
91 className: classNames(classPrefix, {
92 [`${classPrefix}-disabled`]: mergedProps.disabled
93 }),
94 tabIndex: mergedProps.disabled ? undefined : 0,
95 role: 'textbox',
96 onFocus: onFocus,
97 onBlur: onBlur,
98 onClick: mergedProps.onClick
99 }, React.createElement("div", {
100 className: `${classPrefix}-content`,
101 ref: contentRef,
102 "aria-disabled": mergedProps.disabled,
103 "aria-label": mergedProps.placeholder
104 }, value, React.createElement("div", {
105 className: `${classPrefix}-caret-container`
106 }, hasFocus && React.createElement("div", {
107 className: `${classPrefix}-caret`
108 }))), mergedProps.clearable && !!value && hasFocus && React.createElement("div", {
109 className: `${classPrefix}-clear`,
110 onClick: e => {
111 var _a;
112 e.stopPropagation();
113 setValue('');
114 (_a = mergedProps.onClear) === null || _a === void 0 ? void 0 : _a.call(mergedProps);
115 },
116 role: 'button',
117 "aria-label": locale.Input.clear
118 }, clearIcon), [undefined, null, ''].includes(value) && React.createElement("div", {
119 className: `${classPrefix}-placeholder`
120 }, mergedProps.placeholder), keyboardElement));
121});
\No newline at end of file