UNPKG

react-native-paper

Version:
314 lines (285 loc) 10.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var React = _interopRequireWildcard(require("react")); var _color = _interopRequireDefault(require("color")); var _reactNative = require("react-native"); var _Surface = _interopRequireDefault(require("../../Surface")); var _Icon = _interopRequireDefault(require("../../Icon")); var _TouchableRipple = _interopRequireDefault(require("../../TouchableRipple/TouchableRipple")); var _theming = require("../../../core/theming"); var _colors = require("../../../styles/colors"); var _AnimatedText = _interopRequireDefault(require("../../Typography/AnimatedText")); var _utils = require("./utils"); 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 SIZE = 56; const BORDER_RADIUS = SIZE / 2; const SCALE = 0.9; const AnimatedFAB = _ref => { let { icon, label, accessibilityLabel = label, accessibilityState, color: customColor, disabled, onPress, onLongPress, theme, style, visible = true, uppercase = true, testID, animateFrom = 'right', extended = false, iconMode = 'dynamic', ...rest } = _ref; const isIOS = _reactNative.Platform.OS === 'ios'; const isAnimatedFromRight = animateFrom === 'right'; const isIconStatic = iconMode === 'static'; const { isRTL } = _reactNative.I18nManager; const { current: visibility } = React.useRef(new _reactNative.Animated.Value(visible ? 1 : 0)); const { current: animFAB } = React.useRef(new _reactNative.Animated.Value(0)); const { scale } = theme.animation; const [textWidth, setTextWidth] = React.useState(0); const [textHeight, setTextHeight] = React.useState(0); React.useEffect(() => { if (visible) { _reactNative.Animated.timing(visibility, { toValue: 1, duration: 200 * scale, useNativeDriver: true }).start(); } else { _reactNative.Animated.timing(visibility, { toValue: 0, duration: 150 * scale, useNativeDriver: true }).start(); } }, [visible, scale, visibility]); const disabledColor = (0, _color.default)(theme.dark ? _colors.white : _colors.black).alpha(0.12).rgb().string(); const { backgroundColor = disabled ? disabledColor : theme.colors.accent } = _reactNative.StyleSheet.flatten(style) || {}; let foregroundColor; if (typeof customColor !== 'undefined') { foregroundColor = customColor; } else if (disabled) { foregroundColor = (0, _color.default)(theme.dark ? _colors.white : _colors.black).alpha(0.32).rgb().string(); } else { foregroundColor = !(0, _color.default)(backgroundColor).isLight() ? _colors.white : 'rgba(0, 0, 0, .54)'; } const rippleColor = (0, _color.default)(foregroundColor).alpha(0.32).rgb().string(); const extendedWidth = textWidth + 1.5 * SIZE; const distance = isAnimatedFromRight ? -textWidth - BORDER_RADIUS : textWidth + BORDER_RADIUS; React.useEffect(() => { _reactNative.Animated.timing(animFAB, { toValue: !extended ? 0 : distance, duration: 150 * scale, useNativeDriver: true, easing: _reactNative.Easing.linear }).start(); }, [animFAB, scale, distance, extended]); const onTextLayout = _ref2 => { let { nativeEvent } = _ref2; const currentWidth = Math.ceil(nativeEvent.lines[0].width); const currentHeight = Math.ceil(nativeEvent.lines[0].height); if (currentWidth !== textWidth || currentHeight !== textHeight) { setTextHeight(currentHeight); if (isIOS) { return setTextWidth(currentWidth - 12); } setTextWidth(currentWidth); } }; const propForDirection = right => { if (isAnimatedFromRight) { return right; } return right.reverse(); }; const combinedStyles = (0, _utils.getCombinedStyles)({ isAnimatedFromRight, isIconStatic, distance, animFAB }); return /*#__PURE__*/React.createElement(_Surface.default, _extends({}, rest, { style: [{ opacity: visibility, transform: [{ scale: visibility }], elevation: isIOS ? 6 : 0 }, styles.container, disabled && styles.disabled, style] }), /*#__PURE__*/React.createElement(_reactNative.Animated.View, { style: [{ transform: [{ scaleY: animFAB.interpolate({ inputRange: propForDirection([distance, 0]), outputRange: propForDirection([SCALE, 1]) }) }] }, styles.standard] }, /*#__PURE__*/React.createElement(_reactNative.View, { style: [_reactNative.StyleSheet.absoluteFill, styles.shadowWrapper] }, /*#__PURE__*/React.createElement(_reactNative.Animated.View, { pointerEvents: "none", style: [_reactNative.StyleSheet.absoluteFill, styles.shadow, { width: extendedWidth, opacity: animFAB.interpolate({ inputRange: propForDirection([distance, 0.9 * distance, 0]), outputRange: propForDirection([1, 0.15, 0]) }) }] }), /*#__PURE__*/React.createElement(_reactNative.Animated.View, { pointerEvents: "none", style: [_reactNative.StyleSheet.absoluteFill, styles.shadow, { opacity: animFAB.interpolate({ inputRange: propForDirection([distance, 0.9 * distance, 0]), outputRange: propForDirection([0, 0.85, 1]) }), width: SIZE, borderRadius: animFAB.interpolate({ inputRange: propForDirection([distance, 0]), outputRange: propForDirection([SIZE / (extendedWidth / SIZE), BORDER_RADIUS]) }) }, combinedStyles.absoluteFill] })), /*#__PURE__*/React.createElement(_reactNative.Animated.View, { pointerEvents: "box-none", style: [styles.innerWrapper] }, /*#__PURE__*/React.createElement(_reactNative.Animated.View, { style: [styles.standard, { width: extendedWidth, backgroundColor }, combinedStyles.innerWrapper] }, /*#__PURE__*/React.createElement(_TouchableRipple.default, { borderless: true, onPress: onPress, onLongPress: onLongPress, rippleColor: rippleColor, disabled: disabled, accessibilityLabel: accessibilityLabel // @ts-expect-error We keep old a11y props for backwards compat with old RN versions , accessibilityTraits: disabled ? ['button', 'disabled'] : 'button', accessibilityComponentType: "button", accessibilityRole: "button", accessibilityState: { ...accessibilityState, disabled }, testID: testID, style: styles.touchable }, /*#__PURE__*/React.createElement(_reactNative.View, { style: [styles.standard, { width: extendedWidth }] }))))), /*#__PURE__*/React.createElement(_reactNative.Animated.View, { style: [styles.iconWrapper, combinedStyles.iconWrapper], pointerEvents: "none" }, /*#__PURE__*/React.createElement(_Icon.default, { source: icon, size: 24, color: foregroundColor })), /*#__PURE__*/React.createElement(_reactNative.View, { pointerEvents: "none" }, /*#__PURE__*/React.createElement(_AnimatedText.default, { numberOfLines: 1, onTextLayout: isIOS ? onTextLayout : undefined, ellipsizeMode: 'tail', style: [{ [isAnimatedFromRight || isRTL ? 'right' : 'left']: isIconStatic ? isIOS ? SIZE - 10 : SIZE - 12 : BORDER_RADIUS }, { minWidth: textWidth, top: -BORDER_RADIUS - textHeight / 2, opacity: animFAB.interpolate({ inputRange: propForDirection([distance, 0.7 * distance, 0]), outputRange: propForDirection([1, 0, 0]) }), transform: [{ translateX: animFAB.interpolate({ inputRange: propForDirection([distance, 0]), outputRange: propForDirection([0, SIZE]) }) }] }, styles.label, uppercase && styles.uppercaseLabel, { color: foregroundColor, ...theme.fonts.medium }] }, label)), !isIOS && /*#__PURE__*/ // Method `onTextLayout` on Android returns sizes of text visible on the screen, // however during render the text in `FAB` isn't fully visible. In order to get // proper text measurements there is a need to additionaly render that text, but // wrapped in absolutely positioned `ScrollView` which height is 0. React.createElement(_reactNative.ScrollView, { style: styles.textPlaceholderContainer }, /*#__PURE__*/React.createElement(_reactNative.Text, { onTextLayout: onTextLayout }, label))); }; const styles = _reactNative.StyleSheet.create({ standard: { height: SIZE, borderRadius: BORDER_RADIUS }, disabled: { elevation: 0 }, container: { position: 'absolute', backgroundColor: 'transparent', borderRadius: BORDER_RADIUS }, innerWrapper: { flexDirection: 'row', overflow: 'hidden', borderRadius: BORDER_RADIUS }, shadowWrapper: { elevation: 0 }, shadow: { elevation: 6, borderRadius: BORDER_RADIUS }, touchable: { borderRadius: BORDER_RADIUS }, iconWrapper: { alignItems: 'center', justifyContent: 'center', position: 'absolute', height: SIZE, width: SIZE }, label: { position: 'absolute' }, uppercaseLabel: { textTransform: 'uppercase' }, textPlaceholderContainer: { height: 0, position: 'absolute' } }); var _default = (0, _theming.withTheme)(AnimatedFAB); exports.default = _default; //# sourceMappingURL=AnimatedFAB.js.map