You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Button.tsx 5.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. import React from 'react';
  2. import { useTranslation } from 'react-i18next';
  3. import { makeStyles } from 'tss-react/mui';
  4. import Icon from '../../../icons/components/Icon';
  5. import { withPixelLineHeight } from '../../../styles/functions.web';
  6. import { BUTTON_TYPES } from '../../constants.web';
  7. import { IButtonProps } from '../types';
  8. interface IProps extends IButtonProps {
  9. /**
  10. * Class name used for additional styles.
  11. */
  12. className?: string;
  13. /**
  14. * Whether or not the button should be full width.
  15. */
  16. fullWidth?: boolean;
  17. /**
  18. * The id of the button.
  19. */
  20. id?: string;
  21. /**
  22. * Whether or not the button is a submit form button.
  23. */
  24. isSubmit?: boolean;
  25. /**
  26. * Text to be displayed on the component.
  27. * Used when there's no labelKey.
  28. */
  29. label?: string;
  30. /**
  31. * Which size the button should be.
  32. */
  33. size?: 'small' | 'medium' | 'large';
  34. /**
  35. * Data test id.
  36. */
  37. testId?: string;
  38. }
  39. const useStyles = makeStyles()(theme => {
  40. return {
  41. button: {
  42. backgroundColor: theme.palette.action01,
  43. color: theme.palette.text01,
  44. borderRadius: theme.shape.borderRadius,
  45. padding: '10px 16px',
  46. display: 'flex',
  47. alignItems: 'center',
  48. justifyContent: 'center',
  49. border: 0,
  50. ...withPixelLineHeight(theme.typography.bodyShortBold),
  51. transition: 'background .2s',
  52. cursor: 'pointer',
  53. '&:hover': {
  54. backgroundColor: theme.palette.action01Hover
  55. },
  56. '&:active': {
  57. backgroundColor: theme.palette.action01Active
  58. },
  59. '&.focus-visible': {
  60. outline: 0,
  61. boxShadow: `0px 0px 0px 2px ${theme.palette.focus01}`
  62. },
  63. '& div > svg': {
  64. fill: theme.palette.icon01
  65. }
  66. },
  67. primary: {},
  68. secondary: {
  69. backgroundColor: theme.palette.action02,
  70. color: theme.palette.text04,
  71. '&:hover': {
  72. backgroundColor: theme.palette.action02Hover
  73. },
  74. '&:active': {
  75. backgroundColor: theme.palette.action02Active
  76. },
  77. '& div > svg': {
  78. fill: theme.palette.icon04
  79. }
  80. },
  81. tertiary: {
  82. backgroundColor: theme.palette.action03,
  83. '&:hover': {
  84. backgroundColor: theme.palette.action03Hover
  85. },
  86. '&:active': {
  87. backgroundColor: theme.palette.action03Active
  88. }
  89. },
  90. destructive: {
  91. backgroundColor: theme.palette.actionDanger,
  92. '&:hover': {
  93. backgroundColor: theme.palette.actionDangerHover
  94. },
  95. '&:active': {
  96. backgroundColor: theme.palette.actionDangerActive
  97. }
  98. },
  99. disabled: {
  100. backgroundColor: theme.palette.disabled01,
  101. color: theme.palette.text03,
  102. '&:hover': {
  103. backgroundColor: theme.palette.disabled01,
  104. color: theme.palette.text03
  105. },
  106. '&:active': {
  107. backgroundColor: theme.palette.disabled01,
  108. color: theme.palette.text03
  109. },
  110. '& div > svg': {
  111. fill: theme.palette.icon03
  112. }
  113. },
  114. iconButton: {
  115. padding: theme.spacing(2)
  116. },
  117. textWithIcon: {
  118. marginLeft: theme.spacing(2)
  119. },
  120. small: {
  121. padding: '8px 16px',
  122. ...withPixelLineHeight(theme.typography.labelBold),
  123. '&.iconButton': {
  124. padding: theme.spacing(1)
  125. }
  126. },
  127. medium: {},
  128. large: {
  129. padding: '13px 16px',
  130. ...withPixelLineHeight(theme.typography.bodyShortBoldLarge),
  131. '&.iconButton': {
  132. padding: '12px'
  133. }
  134. },
  135. fullWidth: {
  136. width: '100%'
  137. }
  138. };
  139. });
  140. const Button = React.forwardRef<any, any>(({
  141. accessibilityLabel,
  142. autoFocus = false,
  143. className,
  144. disabled,
  145. fullWidth,
  146. icon,
  147. id,
  148. isSubmit,
  149. label,
  150. labelKey,
  151. onClick = () => null,
  152. onKeyPress = () => null,
  153. size = 'medium',
  154. testId,
  155. type = BUTTON_TYPES.PRIMARY
  156. }: IProps, ref) => {
  157. const { classes: styles, cx } = useStyles();
  158. const { t } = useTranslation();
  159. return (
  160. <button
  161. aria-label = { accessibilityLabel }
  162. autoFocus = { autoFocus }
  163. className = { cx(styles.button, styles[type],
  164. disabled && styles.disabled,
  165. icon && !(labelKey || label) && `${styles.iconButton} iconButton`,
  166. styles[size], fullWidth && styles.fullWidth, className) }
  167. data-testid = { testId }
  168. disabled = { disabled }
  169. { ...(id ? { id } : {}) }
  170. onClick = { onClick }
  171. onKeyPress = { onKeyPress }
  172. ref = { ref }
  173. title = { accessibilityLabel }
  174. type = { isSubmit ? 'submit' : 'button' }>
  175. {icon && <Icon
  176. size = { 24 }
  177. src = { icon } />}
  178. {(labelKey || label) && <span className = { icon ? styles.textWithIcon : '' }>
  179. {labelKey ? t(labelKey) : label}
  180. </span>}
  181. </button>
  182. );
  183. });
  184. export default Button;