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.

ActionButton.tsx 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. import { withStyles } from '@material-ui/styles';
  2. import clsx from 'clsx';
  3. import React, { ReactNode, useCallback } from 'react';
  4. import Icon from '../../../icons/components/Icon';
  5. import { IconArrowDown } from '../../../icons/svg';
  6. import { withPixelLineHeight } from '../../../styles/functions.web';
  7. type Props = {
  8. /**
  9. * Icon to display in the options section.
  10. */
  11. OptionsIcon?: Function;
  12. /**
  13. * The Label of the child element.
  14. */
  15. ariaDropDownLabel?: string;
  16. /**
  17. * The Label of the current element.
  18. */
  19. ariaLabel?: string;
  20. /**
  21. * To give a aria-pressed to the icon.
  22. */
  23. ariaPressed?: boolean;
  24. /**
  25. * Text of the button.
  26. */
  27. children: ReactNode;
  28. /**
  29. * Text css class of the button.
  30. */
  31. className?: string;
  32. /**
  33. * An object containing the CSS classes.
  34. */
  35. classes: any;
  36. /**
  37. * If the button is disabled or not.
  38. */
  39. disabled?: boolean;
  40. /**
  41. * If the button has options.
  42. */
  43. hasOptions?: boolean;
  44. /**
  45. * OnClick button handler.
  46. */
  47. onClick?: (e?: React.MouseEvent) => void;
  48. /**
  49. * Click handler for options.
  50. */
  51. onOptionsClick?: (e?: React.KeyboardEvent | React.MouseEvent) => void;
  52. /**
  53. * To give a role to the icon.
  54. */
  55. role?: string;
  56. /**
  57. * To navigate with the keyboard.
  58. */
  59. tabIndex?: number;
  60. /**
  61. * TestId of the button. Can be used to locate element when testing UI.
  62. */
  63. testId?: string;
  64. /**
  65. * The type of th button: primary, secondary, text.
  66. */
  67. type: string;
  68. };
  69. /**
  70. * Creates the styles for the component.
  71. *
  72. * @param {Object} theme - The current UI theme.
  73. *
  74. * @returns {Object}
  75. */
  76. const styles = (theme: any) => {
  77. return {
  78. actionButton: {
  79. ...withPixelLineHeight(theme.typography.bodyLongBold),
  80. borderRadius: theme.shape.borderRadius,
  81. boxSizing: 'border-box',
  82. color: theme.palette.text01,
  83. cursor: 'pointer',
  84. display: 'inline-block',
  85. marginBottom: '16px',
  86. padding: '7px 16px',
  87. position: 'relative',
  88. textAlign: 'center',
  89. width: '100%',
  90. border: 0,
  91. '&.primary': {
  92. background: theme.palette.action01,
  93. color: theme.palette.text01,
  94. '&:hover': {
  95. backgroundColor: theme.palette.action01Hover
  96. }
  97. },
  98. '&.secondary': {
  99. background: theme.palette.action02,
  100. color: theme.palette.text04,
  101. '&:hover': {
  102. backgroundColor: theme.palette.action02Hover
  103. }
  104. },
  105. '&.text': {
  106. width: 'auto',
  107. fontSize: '13px',
  108. margin: '0',
  109. padding: '0'
  110. },
  111. '&.disabled': {
  112. background: theme.palette.disabled01,
  113. border: '1px solid #5E6D7A',
  114. color: '#AFB6BC',
  115. cursor: 'initial',
  116. '.icon': {
  117. '& > svg': {
  118. fill: '#AFB6BC'
  119. }
  120. }
  121. },
  122. [theme.breakpoints.down('400')]: {
  123. fontSize: 16,
  124. marginBottom: 8,
  125. padding: '11px 16px'
  126. }
  127. },
  128. options: {
  129. borderRadius: theme.shape.borderRadius / 2,
  130. alignItems: 'center',
  131. display: 'flex',
  132. height: '100%',
  133. justifyContent: 'center',
  134. position: 'absolute',
  135. right: 0,
  136. top: 0,
  137. width: 36,
  138. '&:hover': {
  139. backgroundColor: '#0262B6'
  140. },
  141. '& svg': {
  142. pointerEvents: 'none'
  143. }
  144. }
  145. };
  146. };
  147. /**
  148. * Button used for pre meeting actions.
  149. *
  150. * @returns {ReactElement}
  151. */
  152. function ActionButton({
  153. children,
  154. classes,
  155. className = '',
  156. disabled,
  157. hasOptions,
  158. OptionsIcon = IconArrowDown,
  159. testId,
  160. type = 'primary',
  161. onClick,
  162. onOptionsClick,
  163. tabIndex,
  164. role,
  165. ariaPressed,
  166. ariaLabel,
  167. ariaDropDownLabel
  168. }: Props) {
  169. const onKeyPressHandler = useCallback(e => {
  170. if (onClick && !disabled && (e.key === ' ' || e.key === 'Enter')) {
  171. e.preventDefault();
  172. onClick(e);
  173. }
  174. }, [ onClick, disabled ]);
  175. const onOptionsKeyPressHandler = useCallback(e => {
  176. if (onOptionsClick && !disabled && (e.key === ' ' || e.key === 'Enter')) {
  177. e.preventDefault();
  178. e.stopPropagation();
  179. onOptionsClick(e);
  180. }
  181. }, [ onOptionsClick, disabled ]);
  182. const containerClasses = clsx(
  183. classes.actionButton,
  184. className && className,
  185. type,
  186. disabled && 'disabled'
  187. );
  188. return (
  189. <div
  190. aria-disabled = { disabled }
  191. aria-label = { ariaLabel }
  192. className = { containerClasses }
  193. data-testid = { testId ? testId : undefined }
  194. onClick = { disabled ? undefined : onClick }
  195. onKeyPress = { onKeyPressHandler }
  196. role = 'button'
  197. tabIndex = { 0 } >
  198. {children}
  199. { hasOptions
  200. && <div
  201. aria-disabled = { disabled }
  202. aria-haspopup = 'true'
  203. aria-label = { ariaDropDownLabel }
  204. aria-pressed = { ariaPressed }
  205. className = { classes.options }
  206. data-testid = 'prejoin.joinOptions'
  207. onClick = { disabled ? undefined : onOptionsClick }
  208. onKeyPress = { onOptionsKeyPressHandler }
  209. role = { role }
  210. tabIndex = { tabIndex }>
  211. <Icon
  212. className = 'icon'
  213. size = { 14 }
  214. src = { OptionsIcon } />
  215. </div>
  216. }
  217. </div>
  218. );
  219. }
  220. // @ts-ignore
  221. export default withStyles(styles)(ActionButton);