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.4KB

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