UNPKG

5.36 kBJavaScriptView Raw
1function _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); }
2
3import color from 'color';
4import * as React from 'react';
5import { Animated, View, StyleSheet } from 'react-native';
6import ActivityIndicator from '../ActivityIndicator';
7import Surface from '../Surface';
8import CrossFadeIcon from '../CrossFadeIcon';
9import Icon from '../Icon';
10import Text from '../Typography/Text';
11import TouchableRipple from '../TouchableRipple/TouchableRipple';
12import { black, white } from '../../styles/colors';
13import { withTheme } from '../../core/theming';
14import getContrastingColor from '../../utils/getContrastingColor';
15getContrastingColor;
16
17/**
18 * A floating action button represents the primary action in an application.
19 *
20 * <div class="screenshots">
21 * <img src="screenshots/fab-1.png" />
22 * <img src="screenshots/fab-2.png" />
23 * </div>
24 *
25 * ## Usage
26 * ```js
27 * import * as React from 'react';
28 * import { StyleSheet } from 'react-native';
29 * import { FAB } from 'react-native-paper';
30 *
31 * const MyComponent = () => (
32 * <FAB
33 * style={styles.fab}
34 * small
35 * icon="plus"
36 * onPress={() => console.log('Pressed')}
37 * />
38 * );
39 *
40 * const styles = StyleSheet.create({
41 * fab: {
42 * position: 'absolute',
43 * margin: 16,
44 * right: 0,
45 * bottom: 0,
46 * },
47 * })
48 *
49 * export default MyComponent;
50 * ```
51 */
52const FAB = _ref => {
53 let {
54 small,
55 icon,
56 label,
57 accessibilityLabel = label,
58 accessibilityState,
59 animated = true,
60 color: customColor,
61 disabled,
62 onPress,
63 onLongPress,
64 theme,
65 style,
66 visible = true,
67 uppercase = true,
68 loading,
69 testID,
70 ...rest
71 } = _ref;
72 const {
73 current: visibility
74 } = React.useRef(new Animated.Value(visible ? 1 : 0));
75 const {
76 scale
77 } = theme.animation;
78 React.useEffect(() => {
79 if (visible) {
80 Animated.timing(visibility, {
81 toValue: 1,
82 duration: 200 * scale,
83 useNativeDriver: true
84 }).start();
85 } else {
86 Animated.timing(visibility, {
87 toValue: 0,
88 duration: 150 * scale,
89 useNativeDriver: true
90 }).start();
91 }
92 }, [visible, scale, visibility]);
93 const IconComponent = animated ? CrossFadeIcon : Icon;
94 const disabledColor = color(theme.dark ? white : black).alpha(0.12).rgb().string();
95 const {
96 backgroundColor = disabled ? disabledColor : theme.colors.accent
97 } = StyleSheet.flatten(style) || {};
98 let foregroundColor;
99
100 if (typeof customColor !== 'undefined') {
101 foregroundColor = customColor;
102 } else if (disabled) {
103 foregroundColor = color(theme.dark ? white : black).alpha(0.32).rgb().string();
104 } else {
105 foregroundColor = getContrastingColor(backgroundColor, white, 'rgba(0, 0, 0, .54)');
106 }
107
108 const rippleColor = color(foregroundColor).alpha(0.32).rgb().string();
109 return /*#__PURE__*/React.createElement(Surface, _extends({}, rest, {
110 style: [{
111 backgroundColor,
112 opacity: visibility,
113 transform: [{
114 scale: visibility
115 }]
116 }, styles.container, disabled && styles.disabled, style],
117 pointerEvents: visible ? 'auto' : 'none'
118 }), /*#__PURE__*/React.createElement(TouchableRipple, {
119 borderless: true,
120 onPress: onPress,
121 onLongPress: onLongPress,
122 rippleColor: rippleColor,
123 disabled: disabled,
124 accessibilityLabel: accessibilityLabel // @ts-expect-error We keep old a11y props for backwards compat with old RN versions
125 ,
126 accessibilityTraits: disabled ? ['button', 'disabled'] : 'button',
127 accessibilityComponentType: "button",
128 accessibilityRole: "button",
129 accessibilityState: { ...accessibilityState,
130 disabled
131 },
132 style: styles.touchable,
133 testID: testID
134 }, /*#__PURE__*/React.createElement(View, {
135 style: [styles.content, label ? styles.extended : small ? styles.small : styles.standard],
136 pointerEvents: "none"
137 }, icon && loading !== true ? /*#__PURE__*/React.createElement(IconComponent, {
138 source: icon,
139 size: 24,
140 color: foregroundColor
141 }) : null, loading ? /*#__PURE__*/React.createElement(ActivityIndicator, {
142 size: 18,
143 color: foregroundColor
144 }) : null, label ? /*#__PURE__*/React.createElement(Text, {
145 selectable: false,
146 style: [styles.label, uppercase && styles.uppercaseLabel, {
147 color: foregroundColor,
148 ...theme.fonts.medium
149 }]
150 }, label) : null)));
151};
152
153const styles = StyleSheet.create({
154 container: {
155 borderRadius: 28,
156 elevation: 6
157 },
158 touchable: {
159 borderRadius: 28
160 },
161 standard: {
162 height: 56,
163 width: 56
164 },
165 small: {
166 height: 40,
167 width: 40
168 },
169 extended: {
170 height: 48,
171 paddingHorizontal: 16
172 },
173 content: {
174 flexDirection: 'row',
175 alignItems: 'center',
176 justifyContent: 'center'
177 },
178 label: {
179 marginHorizontal: 8
180 },
181 uppercaseLabel: {
182 textTransform: 'uppercase'
183 },
184 disabled: {
185 elevation: 0
186 }
187});
188export default withTheme(FAB); // @component-docs ignore-next-line
189
190const FABWithTheme = withTheme(FAB); // @component-docs ignore-next-line
191
192export { FABWithTheme as FAB };
193//# sourceMappingURL=FAB.js.map
\No newline at end of file