Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. import React, { useCallback } from 'react';
  2. import { Container } from '../../react/components/index';
  3. import { StyleType, styleTypeToObject } from '../../styles/functions';
  4. import { IIconProps } from './types';
  5. interface IProps extends IIconProps {
  6. /**
  7. * Optional label for screen reader users.
  8. *
  9. * If set, this is will add a `aria-label` attribute on the svg element,
  10. * contrary to the aria* props which set attributes on the container element.
  11. *
  12. * Use this if the icon conveys meaning and is not clickable.
  13. */
  14. alt?: string;
  15. /**
  16. * The id of the element this button icon controls.
  17. */
  18. ariaControls?: string;
  19. /**
  20. * Id of description label.
  21. */
  22. ariaDescribedBy?: string;
  23. /**
  24. * Aria disabled flag for the Icon.
  25. */
  26. ariaDisabled?: boolean;
  27. /**
  28. * Whether the element popup is expanded.
  29. */
  30. ariaExpanded?: boolean;
  31. /**
  32. * Whether the element has a popup.
  33. */
  34. ariaHasPopup?: boolean;
  35. /**
  36. * Aria label for the Icon.
  37. */
  38. ariaLabel?: string;
  39. /**
  40. * Whether the element has a pressed.
  41. */
  42. ariaPressed?: boolean;
  43. /**
  44. * Class name for the web platform, if any.
  45. */
  46. className?: string;
  47. /**
  48. * Color of the icon (if not provided by the style object).
  49. */
  50. color?: string;
  51. /**
  52. * Id of the icon container.
  53. */
  54. containerId?: string;
  55. /**
  56. * Id prop (mainly for autotests).
  57. */
  58. id?: string;
  59. /**
  60. * Keydown handler.
  61. */
  62. onKeyDown?: Function;
  63. /**
  64. * Keypress handler.
  65. */
  66. onKeyPress?: Function;
  67. /**
  68. * Role for the Icon.
  69. */
  70. role?: string;
  71. /**
  72. * The size of the icon (if not provided by the style object).
  73. */
  74. size?: number | string;
  75. /**
  76. * The preloaded icon component to render.
  77. */
  78. src: Function;
  79. /**
  80. * Style object to be applied.
  81. */
  82. style?: StyleType | StyleType[];
  83. /**
  84. * TabIndex for the Icon.
  85. */
  86. tabIndex?: number;
  87. /**
  88. * Test id for the icon.
  89. */
  90. testId?: string;
  91. }
  92. export const DEFAULT_COLOR = navigator.product === 'ReactNative' ? 'white' : undefined;
  93. export const DEFAULT_SIZE = navigator.product === 'ReactNative' ? 36 : 22;
  94. /**
  95. * Implements an Icon component that takes a loaded SVG file as prop and renders it as an icon.
  96. *
  97. * @param {IProps} props - The props of the component.
  98. * @returns {ReactElement}
  99. */
  100. export default function Icon(props: IProps) {
  101. const {
  102. alt,
  103. className,
  104. color,
  105. id,
  106. containerId,
  107. onClick,
  108. size,
  109. src: IconComponent,
  110. style,
  111. ariaHasPopup,
  112. ariaLabel,
  113. ariaDisabled,
  114. ariaExpanded,
  115. ariaControls,
  116. tabIndex,
  117. ariaPressed,
  118. ariaDescribedBy,
  119. role,
  120. onKeyPress,
  121. onKeyDown,
  122. testId,
  123. ...rest
  124. }: IProps = props;
  125. const {
  126. color: styleColor,
  127. fontSize: styleSize,
  128. ...restStyle
  129. } = styleTypeToObject(style ?? {});
  130. const calculatedColor = color ?? styleColor ?? DEFAULT_COLOR;
  131. const calculatedSize = size ?? styleSize ?? DEFAULT_SIZE;
  132. const onKeyPressHandler = useCallback(e => {
  133. if ((e.key === 'Enter' || e.key === ' ') && onClick) {
  134. e.preventDefault();
  135. onClick(e);
  136. } else if (onKeyPress) {
  137. onKeyPress(e);
  138. }
  139. }, [ onClick, onKeyPress ]);
  140. const jitsiIconClassName = calculatedColor ? 'jitsi-icon' : 'jitsi-icon jitsi-icon-default';
  141. const iconProps = alt ? {
  142. 'aria-label': alt,
  143. role: 'img'
  144. } : {
  145. 'aria-hidden': true
  146. };
  147. return (
  148. <Container
  149. { ...rest }
  150. aria-controls = { ariaControls }
  151. aria-describedby = { ariaDescribedBy }
  152. aria-disabled = { ariaDisabled }
  153. aria-expanded = { ariaExpanded }
  154. aria-haspopup = { ariaHasPopup }
  155. aria-label = { ariaLabel }
  156. aria-pressed = { ariaPressed }
  157. className = { `${jitsiIconClassName} ${className || ''}` }
  158. data-testid = { testId }
  159. id = { containerId }
  160. onClick = { onClick }
  161. onKeyDown = { onKeyDown }
  162. onKeyPress = { onKeyPressHandler }
  163. role = { role }
  164. style = { restStyle }
  165. tabIndex = { tabIndex }>
  166. <IconComponent
  167. { ...iconProps }
  168. fill = { calculatedColor }
  169. height = { calculatedSize }
  170. id = { id }
  171. width = { calculatedSize } />
  172. </Container>
  173. );
  174. }
  175. Icon.defaultProps = {
  176. className: ''
  177. };