Button.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /**
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. *
  7. * @format
  8. * @flow
  9. */
  10. 'use strict';
  11. const Platform = require('../Utilities/Platform');
  12. const React = require('react');
  13. const StyleSheet = require('../StyleSheet/StyleSheet');
  14. const Text = require('../Text/Text');
  15. const TouchableNativeFeedback = require('./Touchable/TouchableNativeFeedback');
  16. const TouchableOpacity = require('./Touchable/TouchableOpacity');
  17. const View = require('./View/View');
  18. const invariant = require('invariant');
  19. import type {PressEvent} from '../Types/CoreEventTypes';
  20. import type {ColorValue} from '../StyleSheet/StyleSheetTypes';
  21. type ButtonProps = $ReadOnly<{|
  22. /**
  23. * Text to display inside the button
  24. */
  25. title: string,
  26. /**
  27. * Handler to be called when the user taps the button
  28. */
  29. onPress: (event?: PressEvent) => mixed,
  30. /**
  31. * If true, doesn't play system sound on touch (Android Only)
  32. **/
  33. touchSoundDisabled?: ?boolean,
  34. /**
  35. * Color of the text (iOS), or background color of the button (Android)
  36. */
  37. color?: ?ColorValue,
  38. /**
  39. * TV preferred focus (see documentation for the View component).
  40. */
  41. hasTVPreferredFocus?: ?boolean,
  42. /**
  43. * TV next focus down (see documentation for the View component).
  44. *
  45. * @platform android
  46. */
  47. nextFocusDown?: ?number,
  48. /**
  49. * TV next focus forward (see documentation for the View component).
  50. *
  51. * @platform android
  52. */
  53. nextFocusForward?: ?number,
  54. /**
  55. * TV next focus left (see documentation for the View component).
  56. *
  57. * @platform android
  58. */
  59. nextFocusLeft?: ?number,
  60. /**
  61. * TV next focus right (see documentation for the View component).
  62. *
  63. * @platform android
  64. */
  65. nextFocusRight?: ?number,
  66. /**
  67. * TV next focus up (see documentation for the View component).
  68. *
  69. * @platform android
  70. */
  71. nextFocusUp?: ?number,
  72. /**
  73. * Text to display for blindness accessibility features
  74. */
  75. accessibilityLabel?: ?string,
  76. /**
  77. * If true, disable all interactions for this component.
  78. */
  79. disabled?: ?boolean,
  80. /**
  81. * Used to locate this view in end-to-end tests.
  82. */
  83. testID?: ?string,
  84. |}>;
  85. /**
  86. * A basic button component that should render nicely on any platform. Supports
  87. * a minimal level of customization.
  88. *
  89. * <center><img src="img/buttonExample.png"></img></center>
  90. *
  91. * If this button doesn't look right for your app, you can build your own
  92. * button using [TouchableOpacity](docs/touchableopacity.html)
  93. * or [TouchableNativeFeedback](docs/touchablenativefeedback.html).
  94. * For inspiration, look at the [source code for this button component](https://github.com/facebook/react-native/blob/master/Libraries/Components/Button.js).
  95. * Or, take a look at the [wide variety of button components built by the community](https://js.coach/react-native?search=button).
  96. *
  97. * Example usage:
  98. *
  99. * ```
  100. * import { Button } from 'react-native';
  101. * ...
  102. *
  103. * <Button
  104. * onPress={onPressLearnMore}
  105. * title="Learn More"
  106. * color="#841584"
  107. * accessibilityLabel="Learn more about this purple button"
  108. * />
  109. * ```
  110. *
  111. */
  112. class Button extends React.Component<ButtonProps> {
  113. render(): React.Node {
  114. const {
  115. accessibilityLabel,
  116. color,
  117. onPress,
  118. touchSoundDisabled,
  119. title,
  120. hasTVPreferredFocus,
  121. nextFocusDown,
  122. nextFocusForward,
  123. nextFocusLeft,
  124. nextFocusRight,
  125. nextFocusUp,
  126. disabled,
  127. testID,
  128. } = this.props;
  129. const buttonStyles = [styles.button];
  130. const textStyles = [styles.text];
  131. if (color) {
  132. if (Platform.OS === 'ios') {
  133. textStyles.push({color: color});
  134. } else {
  135. buttonStyles.push({backgroundColor: color});
  136. }
  137. }
  138. const accessibilityState = {};
  139. if (disabled) {
  140. buttonStyles.push(styles.buttonDisabled);
  141. textStyles.push(styles.textDisabled);
  142. accessibilityState.disabled = true;
  143. }
  144. invariant(
  145. typeof title === 'string',
  146. 'The title prop of a Button must be a string',
  147. );
  148. const formattedTitle =
  149. Platform.OS === 'android' ? title.toUpperCase() : title;
  150. const Touchable =
  151. Platform.OS === 'android' ? TouchableNativeFeedback : TouchableOpacity;
  152. return (
  153. <Touchable
  154. accessibilityLabel={accessibilityLabel}
  155. accessibilityRole="button"
  156. accessibilityState={accessibilityState}
  157. hasTVPreferredFocus={hasTVPreferredFocus}
  158. nextFocusDown={nextFocusDown}
  159. nextFocusForward={nextFocusForward}
  160. nextFocusLeft={nextFocusLeft}
  161. nextFocusRight={nextFocusRight}
  162. nextFocusUp={nextFocusUp}
  163. testID={testID}
  164. disabled={disabled}
  165. onPress={onPress}
  166. touchSoundDisabled={touchSoundDisabled}>
  167. <View style={buttonStyles}>
  168. <Text style={textStyles} disabled={disabled}>
  169. {formattedTitle}
  170. </Text>
  171. </View>
  172. </Touchable>
  173. );
  174. }
  175. }
  176. const styles = StyleSheet.create({
  177. button: Platform.select({
  178. ios: {},
  179. android: {
  180. elevation: 4,
  181. // Material design blue from https://material.google.com/style/color.html#color-color-palette
  182. backgroundColor: '#2196F3',
  183. borderRadius: 2,
  184. },
  185. }),
  186. text: {
  187. textAlign: 'center',
  188. margin: 8,
  189. ...Platform.select({
  190. ios: {
  191. // iOS blue from https://developer.apple.com/ios/human-interface-guidelines/visual-design/color/
  192. color: '#007AFF',
  193. fontSize: 18,
  194. },
  195. android: {
  196. color: 'white',
  197. fontWeight: '500',
  198. },
  199. }),
  200. },
  201. buttonDisabled: Platform.select({
  202. ios: {},
  203. android: {
  204. elevation: 0,
  205. backgroundColor: '#dfdfdf',
  206. },
  207. }),
  208. textDisabled: Platform.select({
  209. ios: {
  210. color: '#cdcdcd',
  211. },
  212. android: {
  213. color: '#a1a1a1',
  214. },
  215. }),
  216. });
  217. module.exports = Button;