rn-material-ui-textfield
Version:
736 lines (637 loc) • 18.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _propTypes = _interopRequireDefault(require("prop-types"));
var _react = _interopRequireWildcard(require("react"));
var _reactNative = require("react-native");
var _deprecatedReactNativePropTypes = require("deprecated-react-native-prop-types");
var _line = _interopRequireDefault(require("../line"));
var _label = _interopRequireDefault(require("../label"));
var _affix = _interopRequireDefault(require("../affix"));
var _helper = _interopRequireDefault(require("../helper"));
var _counter = _interopRequireDefault(require("../counter"));
var _styles = _interopRequireDefault(require("./styles"));
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function startAnimation(animation, options, callback) {
_reactNative.Animated.timing(animation, options).start(callback);
}
function labelStateFromProps(props, state) {
let {
placeholder,
defaultValue
} = props;
let {
value,
receivedFocus
} = state;
return !!(placeholder || value || !receivedFocus && defaultValue);
}
function errorStateFromProps(props, state) {
let {
error
} = props;
return !!error;
}
class TextField extends _react.PureComponent {
static getDerivedStateFromProps(_ref, state) {
let {
error,
value
} = _ref;
let newState = {};
/* Keep last received error in state */
if (error && error !== state.error) {
newState.error = error;
}
if (value !== undefined && value !== state.value) {
newState.value = value;
}
return newState;
}
constructor(props) {
super(props);
this.onBlur = this.onBlur.bind(this);
this.onFocus = this.onFocus.bind(this);
this.onPress = this.focus.bind(this);
this.onChange = this.onChange.bind(this);
this.onChangeText = this.onChangeText.bind(this);
this.onContentSizeChange = this.onContentSizeChange.bind(this);
this.onFocusAnimationEnd = this.onFocusAnimationEnd.bind(this);
this.createGetter('contentInset');
this.createGetter('labelOffset');
this.inputRef = this.props.inputRef ?? /*#__PURE__*/_react.default.createRef();
this.mounted = false;
this.focused = false;
let {
value,
error,
fontSize
} = this.props;
let labelState = labelStateFromProps(this.props, {
value
}) ? 1 : 0;
let focusState = errorStateFromProps(this.props) ? -1 : 0;
this.state = {
value,
error,
focusAnimation: new _reactNative.Animated.Value(focusState),
labelAnimation: new _reactNative.Animated.Value(labelState),
receivedFocus: false,
height: fontSize * 1.5
};
}
createGetter(name) {
this[name] = () => {
let {
[name]: value
} = this.props;
let {
[name]: defaultValue
} = this.constructor;
return { ...defaultValue,
...value
};
};
}
componentDidMount() {
this.mounted = true;
}
componentWillUnmount() {
this.mounted = false;
}
componentDidUpdate(prevProps, prevState) {
let errorState = errorStateFromProps(this.props);
let prevErrorState = errorStateFromProps(prevProps);
if (errorState ^ prevErrorState) {
this.startFocusAnimation();
}
let labelState = labelStateFromProps(this.props, this.state);
let prevLabelState = labelStateFromProps(prevProps, prevState);
if (labelState ^ prevLabelState) {
this.startLabelAnimation();
}
}
startFocusAnimation() {
let {
focusAnimation
} = this.state;
let {
animationDuration: duration
} = this.props;
let options = {
toValue: this.focusState(),
duration,
useNativeDriver: false
};
startAnimation(focusAnimation, options, this.onFocusAnimationEnd);
}
startLabelAnimation() {
let {
labelAnimation
} = this.state;
let {
animationDuration: duration
} = this.props;
let options = {
toValue: this.labelState(),
useNativeDriver: true,
duration
};
startAnimation(labelAnimation, options);
}
setNativeProps(props) {
let {
current: input
} = this.inputRef;
input.setNativeProps(props);
}
focusState() {
if (errorStateFromProps(this.props)) {
return -1;
}
return this.focused ? 1 : 0;
}
labelState() {
if (labelStateFromProps(this.props, this.state)) {
return 1;
}
return this.focused ? 1 : 0;
}
focus() {
let {
disabled,
editable
} = this.props;
let {
current: input
} = this.inputRef;
if (!disabled && editable) {
input.focus();
}
}
blur() {
let {
current: input
} = this.inputRef;
input.blur();
}
clear() {
let {
current: input
} = this.inputRef;
input.clear();
/* onChangeText is not triggered by .clear() */
this.onChangeText('');
}
value() {
const {
defaultValue
} = this.props;
const value = this.isDefaultVisible() ? defaultValue : this.state.value;
if (value == null) {
return '';
}
return typeof value === 'string' ? value : String(value);
}
setValue(value) {
this.setState({
value
});
}
isFocused() {
let {
current: input
} = this.inputRef;
return input.isFocused();
}
isRestricted() {
let {
characterRestriction: limit
} = this.props;
let {
length: count
} = this.value();
return limit < count;
}
isErrored() {
return errorStateFromProps(this.props);
}
isDefaultVisible() {
let {
value,
receivedFocus
} = this.state;
let {
defaultValue
} = this.props;
return !receivedFocus && value == null && defaultValue != null;
}
isPlaceholderVisible() {
let {
placeholder
} = this.props;
return placeholder && !this.focused && !this.value();
}
isLabelActive() {
return this.labelState() === 1;
}
onFocus(event) {
let {
onFocus,
clearTextOnFocus
} = this.props;
let {
receivedFocus
} = this.state;
if (typeof onFocus === 'function') {
onFocus(event);
}
if (clearTextOnFocus) {
this.clear();
}
this.focused = true;
this.startFocusAnimation();
this.startLabelAnimation();
if (!receivedFocus) {
this.setState({
receivedFocus: true,
value: this.value()
});
}
}
onBlur(event) {
let {
onBlur
} = this.props;
if (typeof onBlur === 'function') {
onBlur(event);
}
this.focused = false;
this.startFocusAnimation();
this.startLabelAnimation();
}
onChange(event) {
let {
onChange
} = this.props;
if (typeof onChange === 'function') {
onChange(event);
}
}
onChangeText(text) {
let {
onChangeText,
formatText
} = this.props;
if (typeof formatText === 'function') {
text = formatText(text);
}
this.setState({
value: text
});
if (typeof onChangeText === 'function') {
onChangeText(text);
}
}
onContentSizeChange(event) {
let {
onContentSizeChange,
fontSize
} = this.props;
let {
height
} = event.nativeEvent.contentSize;
if (typeof onContentSizeChange === 'function') {
onContentSizeChange(event);
}
this.setState({
height: Math.max(fontSize * 1.5, Math.ceil(height) + _reactNative.Platform.select({
ios: 4,
android: 1
}))
});
}
onFocusAnimationEnd() {
let {
error
} = this.props;
let {
error: retainedError
} = this.state;
if (this.mounted && !error && retainedError) {
this.setState({
error: null
});
}
}
inputHeight() {
let {
height: computedHeight
} = this.state;
let {
multiline,
fontSize,
height = computedHeight
} = this.props;
return multiline ? height : fontSize * 1.5;
}
inputContainerHeight() {
let {
labelFontSize,
multiline
} = this.props;
let contentInset = this.contentInset();
if (_reactNative.Platform.OS === 'web' && multiline) {
return 'auto';
}
return contentInset.top + labelFontSize + contentInset.label + this.inputHeight() + contentInset.input;
}
inputProps() {
let store = {};
for (let key in _deprecatedReactNativePropTypes.TextInputPropTypes) {
if (key === 'defaultValue') {
continue;
}
if (key in this.props) {
store[key] = this.props[key];
}
}
return store;
}
inputStyle() {
let {
fontSize,
baseColor,
textColor,
disabled,
multiline
} = this.props;
let color = disabled || this.isDefaultVisible() ? baseColor : textColor;
let style = {
fontSize,
color,
height: this.inputHeight()
};
if (multiline) {
let lineHeight = fontSize * 1.5;
let offset = _reactNative.Platform.OS === 'ios' ? 2 : 0;
style.height += lineHeight;
style.transform = [{
translateY: lineHeight + offset
}];
}
return style;
}
renderLabel(props) {
let offset = this.labelOffset();
let {
label,
fontSize,
labelFontSize,
labelTextStyle
} = this.props;
return /*#__PURE__*/_react.default.createElement(_label.default, _extends({}, props, {
fontSize: fontSize,
activeFontSize: labelFontSize,
offset: offset,
label: label,
style: labelTextStyle
}));
}
renderLine(props) {
return /*#__PURE__*/_react.default.createElement(_line.default, props);
}
renderAccessory(prop) {
let {
[prop]: renderAccessory
} = this.props;
return typeof renderAccessory === 'function' ? renderAccessory() : null;
}
renderAffix(type) {
let {
labelAnimation
} = this.state;
let {
[type]: affix,
fontSize,
baseColor: color,
affixTextStyle: style
} = this.props;
if (affix == null) {
return null;
}
let props = {
type,
style,
color,
fontSize,
labelAnimation
};
return /*#__PURE__*/_react.default.createElement(_affix.default, props, affix);
}
renderHelper() {
let {
focusAnimation,
error
} = this.state;
let {
title,
disabled,
baseColor,
errorColor,
titleTextStyle: style,
characterRestriction: limit
} = this.props;
let {
length: count
} = this.value();
let contentInset = this.contentInset();
let containerStyle = {
paddingLeft: contentInset.left,
paddingRight: contentInset.right,
minHeight: contentInset.bottom
};
let styleProps = {
style,
baseColor,
errorColor
};
let counterProps = { ...styleProps,
limit,
count
};
let helperProps = { ...styleProps,
title,
error,
disabled,
focusAnimation
};
return /*#__PURE__*/_react.default.createElement(_reactNative.View, {
style: [_styles.default.helperContainer, containerStyle]
}, /*#__PURE__*/_react.default.createElement(_helper.default, helperProps), /*#__PURE__*/_react.default.createElement(_counter.default, counterProps));
}
renderInput() {
let {
disabled,
editable,
tintColor,
style: inputStyleOverrides
} = this.props;
let props = this.inputProps();
let inputStyle = this.inputStyle();
return /*#__PURE__*/_react.default.createElement(_reactNative.TextInput, _extends({
selectionColor: tintColor
}, props, {
style: [_styles.default.input, inputStyle, inputStyleOverrides],
editable: !disabled && editable,
onChange: this.onChange,
onChangeText: this.onChangeText,
onContentSizeChange: this.onContentSizeChange,
onFocus: this.onFocus,
onBlur: this.onBlur,
value: this.value(),
ref: this.inputRef
}));
}
render() {
let {
labelAnimation,
focusAnimation
} = this.state;
let {
editable,
disabled,
lineType,
disabledLineType,
lineWidth,
activeLineWidth,
disabledLineWidth,
tintColor,
baseColor,
errorColor,
containerStyle,
inputContainerStyle: inputContainerStyleOverrides
} = this.props;
let restricted = this.isRestricted();
let contentInset = this.contentInset();
let inputContainerStyle = {
paddingTop: contentInset.top,
paddingRight: contentInset.right,
paddingBottom: contentInset.input,
paddingLeft: contentInset.left,
height: this.inputContainerHeight()
};
let containerProps = {
style: containerStyle,
onStartShouldSetResponder: () => true,
onResponderRelease: this.onPress,
pointerEvents: !disabled ? 'auto' : 'none'
};
let inputContainerProps = {
style: [this.constructor.inputContainerStyle, inputContainerStyle, inputContainerStyleOverrides]
};
let styleProps = {
disabled,
restricted,
baseColor,
tintColor,
errorColor,
contentInset,
focusAnimation,
labelAnimation
};
let lineProps = { ...styleProps,
lineWidth,
activeLineWidth,
disabledLineWidth,
lineType,
disabledLineType
};
return /*#__PURE__*/_react.default.createElement(_reactNative.View, containerProps, /*#__PURE__*/_react.default.createElement(_reactNative.Animated.View, inputContainerProps, this.renderLine(lineProps), this.renderAccessory('renderLeftAccessory'), /*#__PURE__*/_react.default.createElement(_reactNative.View, {
style: _styles.default.stack,
pointerEvents: editable ? 'auto' : 'none'
}, this.renderLabel(styleProps), /*#__PURE__*/_react.default.createElement(_reactNative.View, {
style: _styles.default.row
}, this.renderAffix('prefix'), this.renderInput(), this.renderAffix('suffix'))), this.renderAccessory('renderRightAccessory')), this.renderHelper());
}
}
exports.default = TextField;
_defineProperty(TextField, "defaultProps", {
underlineColorAndroid: 'transparent',
disableFullscreenUI: true,
autoCapitalize: 'sentences',
editable: true,
animationDuration: 225,
fontSize: 16,
labelFontSize: 12,
tintColor: 'rgb(0, 145, 234)',
textColor: 'rgba(0, 0, 0, .87)',
baseColor: 'rgba(0, 0, 0, .38)',
errorColor: 'rgb(213, 0, 0)',
lineWidth: _reactNative.StyleSheet.hairlineWidth,
activeLineWidth: 2,
disabledLineWidth: 1,
lineType: 'solid',
disabledLineType: 'dotted',
disabled: false
});
_defineProperty(TextField, "propTypes", { ..._deprecatedReactNativePropTypes.TextInputPropTypes,
animationDuration: _propTypes.default.number,
fontSize: _propTypes.default.number,
labelFontSize: _propTypes.default.number,
contentInset: _propTypes.default.shape({
top: _propTypes.default.number,
label: _propTypes.default.number,
input: _propTypes.default.number,
left: _propTypes.default.number,
right: _propTypes.default.number,
bottom: _propTypes.default.number
}),
labelOffset: _label.default.propTypes.offset,
labelTextStyle: _deprecatedReactNativePropTypes.TextPropTypes.style,
titleTextStyle: _deprecatedReactNativePropTypes.TextPropTypes.style,
affixTextStyle: _deprecatedReactNativePropTypes.TextPropTypes.style,
tintColor: _propTypes.default.string,
textColor: _propTypes.default.string,
baseColor: _propTypes.default.string,
label: _propTypes.default.string,
title: _propTypes.default.string,
characterRestriction: _propTypes.default.number,
error: _propTypes.default.string,
errorColor: _propTypes.default.string,
lineWidth: _propTypes.default.number,
activeLineWidth: _propTypes.default.number,
disabledLineWidth: _propTypes.default.number,
lineType: _line.default.propTypes.lineType,
disabledLineType: _line.default.propTypes.lineType,
disabled: _propTypes.default.bool,
formatText: _propTypes.default.func,
renderLeftAccessory: _propTypes.default.func,
renderRightAccessory: _propTypes.default.func,
prefix: _propTypes.default.string,
suffix: _propTypes.default.string,
containerStyle: _deprecatedReactNativePropTypes.ViewPropTypes.style,
inputContainerStyle: _deprecatedReactNativePropTypes.ViewPropTypes.style
});
_defineProperty(TextField, "inputContainerStyle", _styles.default.inputContainer);
_defineProperty(TextField, "contentInset", {
top: 16,
label: 4,
input: 8,
left: 0,
right: 0,
bottom: 8
});
_defineProperty(TextField, "labelOffset", {
x0: 0,
y0: 0,
x1: 0,
y1: 0
});
//# sourceMappingURL=index.js.map