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.

ContextMenuItem.tsx 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. import React, { ReactNode } from 'react';
  2. import { useSelector } from 'react-redux';
  3. import { makeStyles } from 'tss-react/mui';
  4. import { showOverflowDrawer } from '../../../../toolbox/functions.web';
  5. import Icon from '../../../icons/components/Icon';
  6. import { withPixelLineHeight } from '../../../styles/functions.web';
  7. import { TEXT_OVERFLOW_TYPES } from '../../constants.any';
  8. import TextWithOverflow from './TextWithOverflow';
  9. export interface IProps {
  10. /**
  11. * Label used for accessibility.
  12. */
  13. accessibilityLabel: string;
  14. /**
  15. * Component children.
  16. */
  17. children?: ReactNode;
  18. /**
  19. * CSS class name used for custom styles.
  20. */
  21. className?: string;
  22. /**
  23. * Custom icon. If used, the icon prop is ignored.
  24. * Used to allow custom children instead of just the default icons.
  25. */
  26. customIcon?: ReactNode;
  27. /**
  28. * Whether or not the action is disabled.
  29. */
  30. disabled?: boolean;
  31. /**
  32. * Default icon for action.
  33. */
  34. icon?: Function;
  35. /**
  36. * Id of the action container.
  37. */
  38. id?: string;
  39. /**
  40. * Click handler.
  41. */
  42. onClick?: (e?: React.MouseEvent) => void;
  43. /**
  44. * Keydown handler.
  45. */
  46. onKeyDown?: (e?: React.KeyboardEvent) => void;
  47. /**
  48. * Keypress handler.
  49. */
  50. onKeyPress?: (e?: React.KeyboardEvent) => void;
  51. /**
  52. * Overflow type for item text.
  53. */
  54. overflowType?: TEXT_OVERFLOW_TYPES;
  55. /**
  56. * Whether the item is marked as selected.
  57. */
  58. selected?: boolean;
  59. /**
  60. * TestId of the element, if any.
  61. */
  62. testId?: string;
  63. /**
  64. * Action text.
  65. */
  66. text?: string;
  67. /**
  68. * Class name for the text.
  69. */
  70. textClassName?: string;
  71. }
  72. const useStyles = makeStyles()(theme => {
  73. return {
  74. contextMenuItem: {
  75. alignItems: 'center',
  76. cursor: 'pointer',
  77. display: 'flex',
  78. minHeight: '40px',
  79. padding: '10px 16px',
  80. boxSizing: 'border-box',
  81. '& > *:not(:last-child)': {
  82. marginRight: theme.spacing(3)
  83. },
  84. '&:hover': {
  85. backgroundColor: theme.palette.ui02
  86. },
  87. '&:active': {
  88. backgroundColor: theme.palette.ui03
  89. },
  90. '&.focus-visible': {
  91. boxShadow: `inset 0 0 0 2px ${theme.palette.action01Hover}`
  92. }
  93. },
  94. selected: {
  95. borderLeft: `3px solid ${theme.palette.action01Hover}`,
  96. paddingLeft: '13px',
  97. backgroundColor: theme.palette.ui02
  98. },
  99. contextMenuItemDisabled: {
  100. pointerEvents: 'none'
  101. },
  102. contextMenuItemDrawer: {
  103. padding: '13px 16px'
  104. },
  105. contextMenuItemIcon: {
  106. '& svg': {
  107. fill: theme.palette.icon01
  108. }
  109. },
  110. text: {
  111. ...withPixelLineHeight(theme.typography.bodyShortRegular),
  112. color: theme.palette.text01
  113. },
  114. drawerText: {
  115. ...withPixelLineHeight(theme.typography.bodyShortRegularLarge)
  116. }
  117. };
  118. });
  119. const ContextMenuItem = ({
  120. accessibilityLabel,
  121. children,
  122. className,
  123. customIcon,
  124. disabled,
  125. id,
  126. icon,
  127. onClick,
  128. onKeyDown,
  129. onKeyPress,
  130. overflowType,
  131. selected,
  132. testId,
  133. text,
  134. textClassName }: IProps) => {
  135. const { classes: styles, cx } = useStyles();
  136. const _overflowDrawer: boolean = useSelector(showOverflowDrawer);
  137. return (
  138. <div
  139. aria-disabled = { disabled }
  140. aria-label = { accessibilityLabel }
  141. className = { cx(styles.contextMenuItem,
  142. _overflowDrawer && styles.contextMenuItemDrawer,
  143. disabled && styles.contextMenuItemDisabled,
  144. selected && styles.selected,
  145. className
  146. ) }
  147. data-testid = { testId }
  148. id = { id }
  149. key = { text }
  150. onClick = { disabled ? undefined : onClick }
  151. onKeyDown = { disabled ? undefined : onKeyDown }
  152. onKeyPress = { disabled ? undefined : onKeyPress }
  153. role = 'button'
  154. tabIndex = { disabled ? undefined : 0 }>
  155. {customIcon ? customIcon
  156. : icon && <Icon
  157. className = { styles.contextMenuItemIcon }
  158. size = { 20 }
  159. src = { icon } />}
  160. {text && (
  161. <TextWithOverflow
  162. className = { cx(styles.text,
  163. _overflowDrawer && styles.drawerText,
  164. textClassName) }
  165. overflowType = { overflowType } >
  166. {text}
  167. </TextWithOverflow>
  168. )}
  169. {children}
  170. </div>
  171. );
  172. };
  173. export default ContextMenuItem;