Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

ListItem.tsx 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. import { makeStyles } from '@material-ui/styles';
  2. import clsx from 'clsx';
  3. import React, { ReactNode } from 'react';
  4. import { ACTION_TRIGGER } from '../../../participants-pane/constants';
  5. import { isMobileBrowser } from '../../environment/utils';
  6. import participantsPaneTheme from '../themes/participantsPaneTheme.json';
  7. type Props = {
  8. /**
  9. * List item actions.
  10. */
  11. actions: ReactNode;
  12. /**
  13. * List item container class name.
  14. */
  15. className?: string;
  16. /**
  17. * Whether or not the actions should be hidden.
  18. */
  19. hideActions?: boolean;
  20. /**
  21. * Icon to be displayed on the list item. (Avatar for participants).
  22. */
  23. icon: ReactNode;
  24. /**
  25. * Id of the container.
  26. */
  27. id?: string;
  28. /**
  29. * Indicators to be displayed on the list item.
  30. */
  31. indicators?: ReactNode;
  32. /**
  33. * Whether or not the item is highlighted.
  34. */
  35. isHighlighted?: boolean;
  36. /**
  37. * Click handler.
  38. */
  39. onClick?: (e?: React.MouseEvent) => void;
  40. /**
  41. * Long press handler.
  42. */
  43. onLongPress?: (e?: EventTarget) => void;
  44. /**
  45. * Mouse leave handler.
  46. */
  47. onMouseLeave?: (e?: React.MouseEvent) => void;
  48. /**
  49. * Data test id.
  50. */
  51. testId?: string;
  52. /**
  53. * Text children to be displayed on the list item.
  54. */
  55. textChildren: ReactNode | string;
  56. /**
  57. * The actions trigger. Can be Hover or Permanent.
  58. */
  59. trigger: string;
  60. };
  61. const useStyles = makeStyles((theme: any) => {
  62. return {
  63. container: {
  64. alignItems: 'center',
  65. color: theme.palette.text01,
  66. display: 'flex',
  67. ...theme.typography.bodyShortRegular,
  68. lineHeight: `${theme.typography.bodyShortRegular.lineHeight}px`,
  69. margin: `0 -${participantsPaneTheme.panePadding}px`,
  70. padding: `0 ${participantsPaneTheme.panePadding}px`,
  71. position: 'relative',
  72. boxShadow: 'inset 0px -1px 0px rgba(255, 255, 255, 0.15)',
  73. minHeight: '40px',
  74. '&:hover': {
  75. backgroundColor: theme.palette.ui02,
  76. '& .indicators': {
  77. display: 'none'
  78. },
  79. '& .actions': {
  80. display: 'flex',
  81. boxShadow: `-15px 0px 10px -5px ${theme.palette.ui02}`,
  82. backgroundColor: theme.palette.ui02
  83. }
  84. },
  85. [`@media(max-width: ${participantsPaneTheme.MD_BREAKPOINT})`]: {
  86. ...theme.typography.bodyShortRegularLarge,
  87. lineHeight: `${theme.typography.bodyShortRegularLarge.lineHeight}px`,
  88. padding: `${theme.spacing(2)}px ${participantsPaneTheme.panePadding}px`
  89. }
  90. },
  91. highlighted: {
  92. backgroundColor: theme.palette.ui02
  93. },
  94. detailsContainer: {
  95. display: 'flex',
  96. alignItems: 'center',
  97. flex: 1,
  98. height: '100%',
  99. overflow: 'hidden',
  100. position: 'relative'
  101. },
  102. name: {
  103. display: 'flex',
  104. flex: 1,
  105. marginRight: `${theme.spacing(2)}px`,
  106. overflow: 'hidden',
  107. flexDirection: 'column',
  108. justifyContent: 'flex-start'
  109. },
  110. indicators: {
  111. display: 'flex',
  112. justifyContent: 'flex-end',
  113. '& > *': {
  114. alignItems: 'center',
  115. display: 'flex',
  116. justifyContent: 'center'
  117. },
  118. '& > *:not(:last-child)': {
  119. marginRight: `${theme.spacing(2)}px`
  120. },
  121. '& .jitsi-icon': {
  122. padding: '3px'
  123. }
  124. },
  125. indicatorsHidden: {
  126. display: 'none'
  127. },
  128. actionsContainer: {
  129. display: 'none',
  130. boxShadow: `-15px 0px 10px -5px ${theme.palette.ui02}`,
  131. backgroundColor: theme.palette.ui02
  132. },
  133. actionsPermanent: {
  134. display: 'flex',
  135. boxShadow: `-15px 0px 10px -5px ${theme.palette.ui01}`,
  136. backgroundColor: theme.palette.ui01
  137. },
  138. actionsVisible: {
  139. display: 'flex',
  140. boxShadow: `-15px 0px 10px -5px ${theme.palette.ui02}`,
  141. backgroundColor: theme.palette.ui02
  142. }
  143. };
  144. });
  145. const ListItem = ({
  146. actions,
  147. className,
  148. icon,
  149. id,
  150. hideActions = false,
  151. indicators,
  152. isHighlighted,
  153. onClick,
  154. onLongPress,
  155. onMouseLeave,
  156. testId,
  157. textChildren,
  158. trigger
  159. }: Props) => {
  160. const styles = useStyles();
  161. const _isMobile = isMobileBrowser();
  162. let timeoutHandler: number;
  163. /**
  164. * Set calling long press handler after x milliseconds.
  165. *
  166. * @param {TouchEvent} e - Touch start event.
  167. * @returns {void}
  168. */
  169. function _onTouchStart(e: React.TouchEvent) {
  170. const target = e.touches[0].target;
  171. timeoutHandler = window.setTimeout(() => onLongPress?.(target), 600);
  172. }
  173. /**
  174. * Cancel calling on long press after x milliseconds if the number of milliseconds is not reached
  175. * before a touch move(drag), or just clears the timeout.
  176. *
  177. * @returns {void}
  178. */
  179. function _onTouchMove() {
  180. clearTimeout(timeoutHandler);
  181. }
  182. /**
  183. * Cancel calling on long press after x milliseconds if the number of milliseconds is not reached yet,
  184. * or just clears the timeout.
  185. *
  186. * @returns {void}
  187. */
  188. function _onTouchEnd() {
  189. clearTimeout(timeoutHandler);
  190. }
  191. return (
  192. <div
  193. className = { clsx('list-item-container',
  194. styles.container,
  195. isHighlighted && styles.highlighted,
  196. className
  197. ) }
  198. data-testid = { testId }
  199. id = { id }
  200. onClick = { onClick }
  201. { ...(_isMobile
  202. ? {
  203. onTouchEnd: _onTouchEnd,
  204. onTouchMove: _onTouchMove,
  205. onTouchStart: _onTouchStart
  206. }
  207. : {
  208. onMouseLeave
  209. }
  210. ) }>
  211. <div> {icon} </div>
  212. <div className = { styles.detailsContainer }>
  213. <div className = { styles.name }>
  214. {textChildren}
  215. </div>
  216. {indicators && (
  217. <div
  218. className = { clsx('indicators',
  219. styles.indicators,
  220. (isHighlighted || trigger === ACTION_TRIGGER.PERMANENT) && styles.indicatorsHidden
  221. ) }>
  222. {indicators}
  223. </div>
  224. )}
  225. {!hideActions && (
  226. <div
  227. className = { clsx('actions',
  228. styles.actionsContainer,
  229. trigger === ACTION_TRIGGER.PERMANENT && styles.actionsPermanent,
  230. isHighlighted && styles.actionsVisible
  231. ) }>
  232. {actions}
  233. </div>
  234. )}
  235. </div>
  236. </div>
  237. );
  238. };
  239. export default ListItem;