antd-mobile
Version:
<div align="center">
121 lines • 4.38 kB
JavaScript
import { useIsomorphicLayoutEffect } from 'ahooks';
import { CloseCircleFill } from 'antd-mobile-icons';
import classNames from 'classnames';
import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
import { withNativeProps } from '../../utils/native-props';
import { usePropsValue } from '../../utils/use-props-value';
import { mergeProp, mergeProps } from '../../utils/with-default-props';
import { useConfig } from '../config-provider';
const classPrefix = 'adm-virtual-input';
const defaultProps = {
defaultValue: ''
};
export const VirtualInput = forwardRef((props, ref) => {
const {
locale,
input: componentConfig = {}
} = useConfig();
const mergedProps = mergeProps(defaultProps, componentConfig, props);
const [value, setValue] = usePropsValue(mergedProps);
const rootRef = useRef(null);
const contentRef = useRef(null);
const [hasFocus, setHasFocus] = useState(false);
const clearIcon = mergeProp(React.createElement(CloseCircleFill, null), componentConfig.clearIcon, props.clearIcon);
function scrollToEnd() {
const root = rootRef.current;
if (!root) return;
if (document.activeElement !== root) {
return;
}
const content = contentRef.current;
if (!content) return;
content.scrollLeft = content.clientWidth;
}
useIsomorphicLayoutEffect(() => {
scrollToEnd();
}, [value]);
useEffect(() => {
if (hasFocus) {
scrollToEnd();
}
}, [hasFocus]);
useImperativeHandle(ref, () => ({
focus: () => {
var _a;
(_a = rootRef.current) === null || _a === void 0 ? void 0 : _a.focus();
},
blur: () => {
var _a;
(_a = rootRef.current) === null || _a === void 0 ? void 0 : _a.blur();
}
}));
function onFocus() {
var _a;
setHasFocus(true);
(_a = mergedProps.onFocus) === null || _a === void 0 ? void 0 : _a.call(mergedProps);
}
function onBlur() {
var _a;
setHasFocus(false);
(_a = mergedProps.onBlur) === null || _a === void 0 ? void 0 : _a.call(mergedProps);
}
const keyboard = mergedProps.keyboard;
const keyboardElement = keyboard && React.cloneElement(keyboard, {
onInput: v => {
var _a, _b;
setValue(value + v);
(_b = (_a = keyboard.props).onInput) === null || _b === void 0 ? void 0 : _b.call(_a, v);
},
onDelete: () => {
var _a, _b;
setValue(value.slice(0, -1));
(_b = (_a = keyboard.props).onDelete) === null || _b === void 0 ? void 0 : _b.call(_a);
},
visible: hasFocus,
onClose: () => {
var _a, _b, _c, _d;
const activeElement = document.activeElement;
// Long press makes `activeElement` to be the child of rootRef
// We will trigger blur on the child element instead
if (activeElement && ((_a = rootRef.current) === null || _a === void 0 ? void 0 : _a.contains(activeElement))) {
activeElement.blur();
} else {
(_b = rootRef.current) === null || _b === void 0 ? void 0 : _b.blur();
}
(_d = (_c = keyboard.props).onClose) === null || _d === void 0 ? void 0 : _d.call(_c);
},
getContainer: null
});
return withNativeProps(mergedProps, React.createElement("div", {
ref: rootRef,
className: classNames(classPrefix, {
[`${classPrefix}-disabled`]: mergedProps.disabled
}),
tabIndex: mergedProps.disabled ? undefined : 0,
role: 'textbox',
onFocus: onFocus,
onBlur: onBlur,
onClick: mergedProps.onClick
}, React.createElement("div", {
className: `${classPrefix}-content`,
ref: contentRef,
"aria-disabled": mergedProps.disabled,
"aria-label": mergedProps.placeholder
}, value, React.createElement("div", {
className: `${classPrefix}-caret-container`
}, hasFocus && React.createElement("div", {
className: `${classPrefix}-caret`
}))), mergedProps.clearable && !!value && hasFocus && React.createElement("div", {
className: `${classPrefix}-clear`,
onClick: e => {
var _a;
e.stopPropagation();
setValue('');
(_a = mergedProps.onClear) === null || _a === void 0 ? void 0 : _a.call(mergedProps);
},
role: 'button',
"aria-label": locale.Input.clear
}, clearIcon), [undefined, null, ''].includes(value) && React.createElement("div", {
className: `${classPrefix}-placeholder`
}, mergedProps.placeholder), keyboardElement));
});