react-native-paper
Version:
Material design for React Native
362 lines (318 loc) • 12 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var React = _interopRequireWildcard(require("react"));
var _reactNative = require("react-native");
var _TextInputOutlined = _interopRequireDefault(require("./TextInputOutlined"));
var _TextInputFlat = _interopRequireDefault(require("./TextInputFlat"));
var _TextInputIcon = _interopRequireDefault(require("./Adornment/TextInputIcon"));
var _TextInputAffix = _interopRequireDefault(require("./Adornment/TextInputAffix"));
var _theming = require("../../core/theming");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
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 _extends() { _extends = Object.assign || 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); }
const BLUR_ANIMATION_DURATION = 180;
const FOCUS_ANIMATION_DURATION = 150;
/**
* A component to allow users to input text.
*
* <div class="screenshots">
* <figure>
* <img class="medium" src="screenshots/textinput-flat.focused.png" />
* <figcaption>Flat (focused)</figcaption>
* </figure>
* <figure>
* <img class="medium" src="screenshots/textinput-flat.disabled.png" />
* <figcaption>Flat (disabled)</figcaption>
* </figure>
* <figure>
* <img class="medium" src="screenshots/textinput-outlined.focused.png" />
* <figcaption>Outlined (focused)</figcaption>
* </figure>
* <figure>
* <img class="medium" src="screenshots/textinput-outlined.disabled.png" />
* <figcaption>Outlined (disabled)</figcaption>
* </figure>
* </div>
*
* ## Usage
* ```js
* import * as React from 'react';
* import { TextInput } from 'react-native-paper';
*
* const MyComponent = () => {
* const [text, setText] = React.useState("");
*
* return (
* <TextInput
* label="Email"
* value={text}
* onChangeText={text => setText(text)}
* />
* );
* };
*
* export default MyComponent;
* ```
*
* @extends TextInput props https://reactnative.dev/docs/textinput#props
*/
const TextInput = /*#__PURE__*/React.forwardRef((_ref, ref) => {
let {
mode = 'flat',
dense = false,
disabled = false,
error: errorProp = false,
multiline = false,
editable = true,
render = props => /*#__PURE__*/React.createElement(_reactNative.TextInput, props),
...rest
} = _ref;
const isControlled = rest.value !== undefined;
const validInputValue = isControlled ? rest.value : rest.defaultValue;
const {
current: labeled
} = React.useRef(new _reactNative.Animated.Value(validInputValue ? 0 : 1));
const {
current: error
} = React.useRef(new _reactNative.Animated.Value(errorProp ? 1 : 0));
const [focused, setFocused] = React.useState(false);
const [placeholder, setPlaceholder] = React.useState('');
const [uncontrolledValue, setUncontrolledValue] = React.useState(validInputValue); // Use value from props instead of local state when input is controlled
const value = isControlled ? rest.value : uncontrolledValue;
const [labelLayout, setLabelLayout] = React.useState({
measured: false,
width: 0,
height: 0
});
const [leftLayout, setLeftLayout] = React.useState({
width: null,
height: null
});
const [rightLayout, setRightLayout] = React.useState({
width: null,
height: null
});
const timer = React.useRef();
const root = React.useRef();
const {
scale
} = rest.theme.animation;
React.useImperativeHandle(ref, () => ({
focus: () => {
var _root$current;
return (_root$current = root.current) === null || _root$current === void 0 ? void 0 : _root$current.focus();
},
clear: () => {
var _root$current2;
return (_root$current2 = root.current) === null || _root$current2 === void 0 ? void 0 : _root$current2.clear();
},
setNativeProps: args => {
var _root$current3;
return (_root$current3 = root.current) === null || _root$current3 === void 0 ? void 0 : _root$current3.setNativeProps(args);
},
isFocused: () => {
var _root$current4;
return ((_root$current4 = root.current) === null || _root$current4 === void 0 ? void 0 : _root$current4.isFocused()) || false;
},
blur: () => {
var _root$current5;
return (_root$current5 = root.current) === null || _root$current5 === void 0 ? void 0 : _root$current5.blur();
},
forceFocus: () => {
var _root$current6;
return (_root$current6 = root.current) === null || _root$current6 === void 0 ? void 0 : _root$current6.focus();
}
}));
React.useEffect(() => {
// When the input has an error, we wiggle the label and apply error styles
if (errorProp) {
// show error
_reactNative.Animated.timing(error, {
toValue: 1,
duration: FOCUS_ANIMATION_DURATION * scale,
// To prevent this - https://github.com/callstack/react-native-paper/issues/941
useNativeDriver: true
}).start();
} else {
// hide error
{
_reactNative.Animated.timing(error, {
toValue: 0,
duration: BLUR_ANIMATION_DURATION * scale,
// To prevent this - https://github.com/callstack/react-native-paper/issues/941
useNativeDriver: true
}).start();
}
}
}, [errorProp, scale, error]);
React.useEffect(() => {
// Show placeholder text only if the input is focused, or there's no label
// We don't show placeholder if there's a label because the label acts as placeholder
// When focused, the label moves up, so we can show a placeholder
if (focused || !rest.label) {
// Set the placeholder in a delay to offset the label animation
// If we show it immediately, they'll overlap and look ugly
timer.current = setTimeout(() => setPlaceholder(rest.placeholder), 50);
} else {
// hidePlaceholder
setPlaceholder('');
}
return () => {
if (timer.current) {
clearTimeout(timer.current);
}
};
}, [focused, rest.label, rest.placeholder]);
React.useEffect(() => {
// The label should be minimized if the text input is focused, or has text
// In minimized mode, the label moves up and becomes small
// workaround for animated regression for react native > 0.61
// https://github.com/callstack/react-native-paper/pull/1440
if (value || focused) {
// minimize label
_reactNative.Animated.timing(labeled, {
toValue: 0,
duration: BLUR_ANIMATION_DURATION * scale,
// To prevent this - https://github.com/callstack/react-native-paper/issues/941
useNativeDriver: true
}).start();
} else {
// restore label
{
_reactNative.Animated.timing(labeled, {
toValue: 1,
duration: FOCUS_ANIMATION_DURATION * scale,
// To prevent this - https://github.com/callstack/react-native-paper/issues/941
useNativeDriver: true
}).start();
}
}
}, [focused, value, labeled, scale]);
const onLeftAffixLayoutChange = event => {
setLeftLayout({
height: event.nativeEvent.layout.height,
width: event.nativeEvent.layout.width
});
};
const onRightAffixLayoutChange = event => {
setRightLayout({
width: event.nativeEvent.layout.width,
height: event.nativeEvent.layout.height
});
};
const handleFocus = args => {
var _rest$onFocus;
if (disabled || !editable) {
return;
}
setFocused(true);
(_rest$onFocus = rest.onFocus) === null || _rest$onFocus === void 0 ? void 0 : _rest$onFocus.call(rest, args);
};
const handleBlur = args => {
var _rest$onBlur;
if (!editable) {
return;
}
setFocused(false);
(_rest$onBlur = rest.onBlur) === null || _rest$onBlur === void 0 ? void 0 : _rest$onBlur.call(rest, args);
};
const handleChangeText = value => {
var _rest$onChangeText;
if (!editable || disabled) {
return;
}
if (!isControlled) {
// Keep track of value in local state when input is not controlled
setUncontrolledValue(value);
}
(_rest$onChangeText = rest.onChangeText) === null || _rest$onChangeText === void 0 ? void 0 : _rest$onChangeText.call(rest, value);
};
const handleLayoutAnimatedText = e => {
setLabelLayout({
width: e.nativeEvent.layout.width,
height: e.nativeEvent.layout.height,
measured: true
});
};
const forceFocus = () => {
var _root$current7;
return (_root$current7 = root.current) === null || _root$current7 === void 0 ? void 0 : _root$current7.focus();
};
const {
maxFontSizeMultiplier = 1.5
} = rest;
if (mode === 'outlined') {
return /*#__PURE__*/React.createElement(_TextInputOutlined.default, _extends({
dense: dense,
disabled: disabled,
error: errorProp,
multiline: multiline,
editable: editable,
render: render
}, rest, {
value: value,
parentState: {
labeled,
error,
focused,
placeholder,
value,
labelLayout,
leftLayout,
rightLayout
},
innerRef: ref => {
root.current = ref;
},
onFocus: handleFocus,
forceFocus: forceFocus,
onBlur: handleBlur,
onChangeText: handleChangeText,
onLayoutAnimatedText: handleLayoutAnimatedText,
onLeftAffixLayoutChange: onLeftAffixLayoutChange,
onRightAffixLayoutChange: onRightAffixLayoutChange,
maxFontSizeMultiplier: maxFontSizeMultiplier
}));
}
return /*#__PURE__*/React.createElement(_TextInputFlat.default, _extends({
dense: dense,
disabled: disabled,
error: errorProp,
multiline: multiline,
editable: editable,
render: render
}, rest, {
value: value,
parentState: {
labeled,
error,
focused,
placeholder,
value,
labelLayout,
leftLayout,
rightLayout
},
innerRef: ref => {
root.current = ref;
},
onFocus: handleFocus,
forceFocus: forceFocus,
onBlur: handleBlur,
onChangeText: handleChangeText,
onLayoutAnimatedText: handleLayoutAnimatedText,
onLeftAffixLayoutChange: onLeftAffixLayoutChange,
onRightAffixLayoutChange: onRightAffixLayoutChange,
maxFontSizeMultiplier: maxFontSizeMultiplier
}));
}); // @component ./Adornment/TextInputIcon.tsx
TextInput.Icon = _TextInputIcon.default; // @component ./Adornment/TextInputAffix.tsx
// @ts-ignore Types of property 'theme' are incompatible.
TextInput.Affix = _TextInputAffix.default;
var _default = (0, _theming.withTheme)(TextInput);
exports.default = _default;
//# sourceMappingURL=TextInput.js.map