UNPKG

6.93 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 * as React from 'react';
4import { Animated, View, StyleSheet } from 'react-native';
5import color from 'color';
6import ActivityIndicator from './ActivityIndicator';
7import Icon from './Icon';
8import Surface from './Surface';
9import Text from './Typography/Text';
10import TouchableRipple from './TouchableRipple/TouchableRipple';
11import { black, white } from '../styles/colors';
12import { withTheme } from '../core/theming';
13
14/**
15 * A button is component that the user can press to trigger an action.
16 *
17 * <div class="screenshots">
18 * <figure>
19 * <img src="screenshots/button-1.png" />
20 * <figcaption>Text button</figcaption>
21 * </figure>
22 * <figure>
23 * <img src="screenshots/button-2.png" />
24 * <figcaption>Outlined button</figcaption>
25 * </figure>
26 * <figure>
27 * <img src="screenshots/button-3.png" />
28 * <figcaption>Contained button</figcaption>
29 * </figure>
30 * </div>
31 *
32 * ## Usage
33 * ```js
34 * import * as React from 'react';
35 * import { Button } from 'react-native-paper';
36 *
37 * const MyComponent = () => (
38 * <Button icon="camera" mode="contained" onPress={() => console.log('Pressed')}>
39 * Press me
40 * </Button>
41 * );
42 *
43 * export default MyComponent;
44 * ```
45 */
46const Button = ({
47 disabled,
48 compact,
49 mode = 'text',
50 dark,
51 loading,
52 icon,
53 color: buttonColor,
54 children,
55 uppercase = true,
56 accessibilityLabel,
57 onPress,
58 onLongPress,
59 style,
60 theme,
61 contentStyle,
62 labelStyle,
63 testID,
64 accessible,
65 ...rest
66}) => {
67 var _StyleSheet$flatten;
68
69 const {
70 current: elevation
71 } = React.useRef(new Animated.Value(mode === 'contained' ? 2 : 0));
72 React.useEffect(() => {
73 elevation.setValue(mode === 'contained' ? 2 : 0);
74 }, [mode, elevation]);
75
76 const handlePressIn = () => {
77 if (mode === 'contained') {
78 const {
79 scale
80 } = theme.animation;
81 Animated.timing(elevation, {
82 toValue: 8,
83 duration: 200 * scale,
84 useNativeDriver: true
85 }).start();
86 }
87 };
88
89 const handlePressOut = () => {
90 if (mode === 'contained') {
91 const {
92 scale
93 } = theme.animation;
94 Animated.timing(elevation, {
95 toValue: 2,
96 duration: 150 * scale,
97 useNativeDriver: true
98 }).start();
99 }
100 };
101
102 const {
103 colors,
104 roundness
105 } = theme;
106 const font = theme.fonts.medium;
107 let backgroundColor, borderColor, textColor, borderWidth;
108
109 if (mode === 'contained') {
110 if (disabled) {
111 backgroundColor = color(theme.dark ? white : black).alpha(0.12).rgb().string();
112 } else if (buttonColor) {
113 backgroundColor = buttonColor;
114 } else {
115 backgroundColor = colors.primary;
116 }
117 } else {
118 backgroundColor = 'transparent';
119 }
120
121 if (mode === 'outlined') {
122 borderColor = color(theme.dark ? white : black).alpha(0.29).rgb().string();
123 borderWidth = StyleSheet.hairlineWidth;
124 } else {
125 borderColor = 'transparent';
126 borderWidth = 0;
127 }
128
129 if (disabled) {
130 textColor = color(theme.dark ? white : black).alpha(0.32).rgb().string();
131 } else if (mode === 'contained') {
132 let isDark;
133
134 if (typeof dark === 'boolean') {
135 isDark = dark;
136 } else {
137 isDark = backgroundColor === 'transparent' ? false : !color(backgroundColor).isLight();
138 }
139
140 textColor = isDark ? white : black;
141 } else if (buttonColor) {
142 textColor = buttonColor;
143 } else {
144 textColor = colors.primary;
145 }
146
147 const rippleColor = color(textColor).alpha(0.32).rgb().string();
148 const buttonStyle = {
149 backgroundColor,
150 borderColor,
151 borderWidth,
152 borderRadius: roundness
153 };
154 const touchableStyle = {
155 borderRadius: style ? (StyleSheet.flatten(style) || {}).borderRadius || roundness : roundness
156 };
157 const {
158 color: customLabelColor,
159 fontSize: customLabelSize
160 } = StyleSheet.flatten(labelStyle) || {};
161 const textStyle = {
162 color: textColor,
163 ...font
164 };
165 const elevationRes = disabled || mode !== 'contained' ? 0 : elevation;
166 const iconStyle = ((_StyleSheet$flatten = StyleSheet.flatten(contentStyle)) === null || _StyleSheet$flatten === void 0 ? void 0 : _StyleSheet$flatten.flexDirection) === 'row-reverse' ? styles.iconReverse : styles.icon;
167 return /*#__PURE__*/React.createElement(Surface, _extends({}, rest, {
168 style: [styles.button, compact && styles.compact, {
169 elevation: elevationRes
170 }, buttonStyle, style]
171 }), /*#__PURE__*/React.createElement(TouchableRipple, {
172 borderless: true,
173 delayPressIn: 0,
174 onPress: onPress,
175 onLongPress: onLongPress,
176 onPressIn: handlePressIn,
177 onPressOut: handlePressOut,
178 accessibilityLabel: accessibilityLabel // @ts-expect-error We keep old a11y props for backwards compat with old RN versions
179 ,
180 accessibilityTraits: disabled ? ['button', 'disabled'] : 'button',
181 accessibilityComponentType: "button",
182 accessibilityRole: "button",
183 accessibilityState: {
184 disabled
185 },
186 accessible: accessible,
187 disabled: disabled,
188 rippleColor: rippleColor,
189 style: touchableStyle,
190 testID: testID
191 }, /*#__PURE__*/React.createElement(View, {
192 style: [styles.content, contentStyle]
193 }, icon && loading !== true ? /*#__PURE__*/React.createElement(View, {
194 style: iconStyle
195 }, /*#__PURE__*/React.createElement(Icon, {
196 source: icon,
197 size: customLabelSize !== null && customLabelSize !== void 0 ? customLabelSize : 16,
198 color: typeof customLabelColor === 'string' ? customLabelColor : textColor
199 })) : null, loading ? /*#__PURE__*/React.createElement(ActivityIndicator, {
200 size: customLabelSize !== null && customLabelSize !== void 0 ? customLabelSize : 16,
201 color: typeof customLabelColor === 'string' ? customLabelColor : textColor,
202 style: iconStyle
203 }) : null, /*#__PURE__*/React.createElement(Text, {
204 selectable: false,
205 numberOfLines: 1,
206 style: [styles.label, compact && styles.compactLabel, uppercase && styles.uppercaseLabel, textStyle, font, labelStyle]
207 }, children))));
208};
209
210const styles = StyleSheet.create({
211 button: {
212 minWidth: 64,
213 borderStyle: 'solid'
214 },
215 compact: {
216 minWidth: 'auto'
217 },
218 content: {
219 flexDirection: 'row',
220 alignItems: 'center',
221 justifyContent: 'center'
222 },
223 icon: {
224 marginLeft: 12,
225 marginRight: -4
226 },
227 iconReverse: {
228 marginRight: 12,
229 marginLeft: -4
230 },
231 label: {
232 textAlign: 'center',
233 letterSpacing: 1,
234 marginVertical: 9,
235 marginHorizontal: 16
236 },
237 compactLabel: {
238 marginHorizontal: 8
239 },
240 uppercaseLabel: {
241 textTransform: 'uppercase'
242 }
243});
244export default withTheme(Button);
245//# sourceMappingURL=Button.js.map
\No newline at end of file