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.js 3.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. // @flow
  2. import React, { useCallback } from 'react';
  3. import { Icon, IconArrowDown } from '../../../icons';
  4. type Props = {
  5. /**
  6. * Text of the button.
  7. */
  8. children: React$Node,
  9. /**
  10. * Text css class of the button.
  11. */
  12. className?: string,
  13. /**
  14. * If the button is disabled or not.
  15. */
  16. disabled?: boolean,
  17. /**
  18. * If the button has options.
  19. */
  20. hasOptions?: boolean,
  21. /**
  22. * Icon to display in the options section.
  23. */
  24. OptionsIcon?: React$Node,
  25. /**
  26. * TestId of the button. Can be used to locate element when testing UI.
  27. */
  28. testId?: string,
  29. /**
  30. * The type of th button: primary, secondary, text.
  31. */
  32. type: string,
  33. /**
  34. * OnClick button handler.
  35. */
  36. onClick: Function,
  37. /**
  38. * Click handler for options.
  39. */
  40. onOptionsClick?: Function,
  41. /**
  42. * to navigate with the keyboard.
  43. */
  44. tabIndex?: number,
  45. /**
  46. * to give a role to the icon.
  47. */
  48. role?: string,
  49. /**
  50. * to give a aria-pressed to the icon.
  51. */
  52. ariaPressed?: boolean,
  53. /**
  54. * The Label of the current element
  55. */
  56. ariaLabel?: string,
  57. /**
  58. * The Label of the child element
  59. */
  60. ariaDropDownLabel?: string
  61. };
  62. /**
  63. * Button used for pre meeting actions.
  64. *
  65. * @returns {ReactElement}
  66. */
  67. function ActionButton({
  68. children,
  69. className = '',
  70. disabled,
  71. hasOptions,
  72. OptionsIcon = IconArrowDown,
  73. testId,
  74. type = 'primary',
  75. onClick,
  76. onOptionsClick,
  77. tabIndex,
  78. role,
  79. ariaPressed,
  80. ariaLabel,
  81. ariaDropDownLabel
  82. }: Props) {
  83. const onKeyPressHandler = useCallback(e => {
  84. if (onClick && !disabled && (e.key === ' ' || e.key === 'Enter')) {
  85. e.preventDefault();
  86. onClick(e);
  87. }
  88. }, [ onClick, disabled ]);
  89. const onOptionsKeyPressHandler = useCallback(e => {
  90. if (onOptionsClick && !disabled && (e.key === ' ' || e.key === 'Enter')) {
  91. e.preventDefault();
  92. e.stopPropagation();
  93. onOptionsClick(e);
  94. }
  95. }, [ onOptionsClick, disabled ]);
  96. return (
  97. <div
  98. aria-disabled = { disabled }
  99. aria-label = { ariaLabel }
  100. className = { `action-btn ${className} ${type} ${disabled ? 'disabled' : ''}` }
  101. data-testid = { testId ? testId : undefined }
  102. onClick = { disabled ? undefined : onClick }
  103. onKeyPress = { onKeyPressHandler }
  104. role = 'button'
  105. tabIndex = { 0 } >
  106. {children}
  107. { hasOptions
  108. && <div
  109. aria-disabled = { disabled }
  110. aria-haspopup = 'true'
  111. aria-label = { ariaDropDownLabel }
  112. aria-pressed = { ariaPressed }
  113. className = 'options'
  114. data-testid = 'prejoin.joinOptions'
  115. onClick = { disabled ? undefined : onOptionsClick }
  116. onKeyPress = { onOptionsKeyPressHandler }
  117. role = { role }
  118. tabIndex = { tabIndex }>
  119. <Icon
  120. className = 'icon'
  121. size = { 14 }
  122. src = { OptionsIcon } />
  123. </div>
  124. }
  125. </div>
  126. );
  127. }
  128. export default ActionButton;