UNPKG

3.77 kBTypeScriptView Raw
1import * as React from 'react';
2import {
3 View,
4 ViewStyle,
5 StyleSheet,
6 StyleProp,
7 GestureResponderEvent,
8 TouchableWithoutFeedback,
9} from 'react-native';
10import color from 'color';
11
12import TouchableRipple from './TouchableRipple/TouchableRipple';
13import Icon, { IconSource } from './Icon';
14import CrossFadeIcon from './CrossFadeIcon';
15import { withTheme } from '../core/theming';
16
17import type { $RemoveChildren } from '../types';
18
19type Props = $RemoveChildren<typeof TouchableRipple> & {
20 /**
21 * Icon to display.
22 */
23 icon: IconSource;
24 /**
25 * Color of the icon.
26 */
27 color?: string;
28 /**
29 * Size of the icon.
30 */
31 size?: number;
32 /**
33 * Whether the button is disabled. A disabled button is greyed out and `onPress` is not called on touch.
34 */
35 disabled?: boolean;
36 /**
37 * Whether an icon change is animated.
38 */
39 animated?: boolean;
40 /**
41 * Accessibility label for the button. This is read by the screen reader when the user taps the button.
42 */
43 accessibilityLabel?: string;
44 /**
45 * Function to execute on press.
46 */
47 onPress?: (e: GestureResponderEvent) => void;
48 style?: StyleProp<ViewStyle>;
49 ref?: React.RefObject<TouchableWithoutFeedback>;
50 /**
51 * @optional
52 */
53 theme: ReactNativePaper.Theme;
54};
55
56/**
57 * An icon button is a button which displays only an icon without a label.
58 * By default button has 150% size of the icon.
59 *
60 * <div class="screenshots">
61 * <figure>
62 * <img src="screenshots/icon-button-1.png" />
63 * <figcaption>Icon button</figcaption>
64 * </figure>
65 * <figure>
66 * <img src="screenshots/icon-button-2.png" />
67 * <figcaption>Pressed icon button</figcaption>
68 * </figure>
69 * </div>
70 *
71 * ## Usage
72 * ```js
73 * import * as React from 'react';
74 * import { IconButton, Colors } from 'react-native-paper';
75 *
76 * const MyComponent = () => (
77 * <IconButton
78 * icon="camera"
79 * color={Colors.red500}
80 * size={20}
81 * onPress={() => console.log('Pressed')}
82 * />
83 * );
84 *
85 * export default MyComponent;
86 * ```
87 *
88 * @extends TouchableRipple props https://callstack.github.io/react-native-paper/touchable-ripple.html
89 */
90const IconButton = ({
91 icon,
92 color: customColor,
93 size = 24,
94 accessibilityLabel,
95 disabled,
96 onPress,
97 animated = false,
98 theme,
99 style,
100 ...rest
101}: Props) => {
102 const iconColor =
103 typeof customColor !== 'undefined' ? customColor : theme.colors.text;
104 const rippleColor = color(iconColor).alpha(0.32).rgb().string();
105 const IconComponent = animated ? CrossFadeIcon : Icon;
106 const buttonSize = size * 1.5;
107 return (
108 <TouchableRipple
109 borderless
110 centered
111 onPress={onPress}
112 rippleColor={rippleColor}
113 style={[
114 styles.container,
115 { width: buttonSize, height: buttonSize, borderRadius: buttonSize / 2 },
116 disabled && styles.disabled,
117 style,
118 ]}
119 accessibilityLabel={accessibilityLabel}
120 // @ts-expect-error We keep old a11y props for backwards compat with old RN versions
121 accessibilityTraits={disabled ? ['button', 'disabled'] : 'button'}
122 accessibilityComponentType="button"
123 accessibilityRole="button"
124 accessibilityState={{ disabled }}
125 disabled={disabled}
126 hitSlop={
127 TouchableRipple.supported
128 ? { top: 10, left: 10, bottom: 10, right: 10 }
129 : { top: 6, left: 6, bottom: 6, right: 6 }
130 }
131 {...rest}
132 >
133 <View>
134 <IconComponent color={iconColor} source={icon} size={size} />
135 </View>
136 </TouchableRipple>
137 );
138};
139
140const styles = StyleSheet.create({
141 container: {
142 alignItems: 'center',
143 justifyContent: 'center',
144 overflow: 'hidden',
145 margin: 6,
146 },
147 disabled: {
148 opacity: 0.32,
149 },
150});
151
152export default withTheme(IconButton);