UNPKG

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