選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

StatelessAvatar.js 5.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. // @flow
  2. import React from 'react';
  3. import { Icon } from '../../../icons';
  4. import AbstractStatelessAvatar, { type Props as AbstractProps } from '../AbstractStatelessAvatar';
  5. type Props = AbstractProps & {
  6. /**
  7. * External class name passed through props.
  8. */
  9. className?: string,
  10. /**
  11. * The default avatar URL if we want to override the app bundled one (e.g. AlwaysOnTop).
  12. */
  13. defaultAvatar?: string,
  14. /**
  15. * ID of the component to be rendered.
  16. */
  17. id?: string,
  18. /**
  19. * One of the expected status strings (e.g. 'available') to render a badge on the avatar, if necessary.
  20. */
  21. status?: ?string,
  22. /**
  23. * TestId of the element, if any.
  24. */
  25. testId?: string,
  26. /**
  27. * Indicates whether to load the avatar using CORS or not.
  28. */
  29. useCORS?: ?boolean
  30. };
  31. /**
  32. * Implements a stateless avatar component that renders an avatar purely from what gets passed through
  33. * props.
  34. */
  35. export default class StatelessAvatar extends AbstractStatelessAvatar<Props> {
  36. /**
  37. * Instantiates a new {@code Component}.
  38. *
  39. * @inheritdoc
  40. */
  41. constructor(props: Props) {
  42. super(props);
  43. this._onAvatarLoadError = this._onAvatarLoadError.bind(this);
  44. }
  45. /**
  46. * Implements {@code Component#render}.
  47. *
  48. * @inheritdoc
  49. */
  50. render() {
  51. const { initials, url, useCORS } = this.props;
  52. if (this._isIcon(url)) {
  53. return (
  54. <div
  55. className = { `${this._getAvatarClassName()} ${this._getBadgeClassName()}` }
  56. data-testid = { this.props.testId }
  57. id = { this.props.id }
  58. style = { this._getAvatarStyle(this.props.color) }>
  59. <Icon
  60. size = '50%'
  61. src = { url } />
  62. </div>
  63. );
  64. }
  65. if (url) {
  66. return (
  67. <div className = { this._getBadgeClassName() }>
  68. <img
  69. alt = 'avatar'
  70. className = { this._getAvatarClassName() }
  71. crossOrigin = { useCORS ? '' : undefined }
  72. data-testid = { this.props.testId }
  73. id = { this.props.id }
  74. onError = { this._onAvatarLoadError }
  75. src = { url }
  76. style = { this._getAvatarStyle() } />
  77. </div>
  78. );
  79. }
  80. if (initials) {
  81. return (
  82. <div
  83. className = { `${this._getAvatarClassName()} ${this._getBadgeClassName()}` }
  84. data-testid = { this.props.testId }
  85. id = { this.props.id }
  86. style = { this._getAvatarStyle(this.props.color) }>
  87. <svg
  88. className = 'avatar-svg'
  89. viewBox = '0 0 100 100'
  90. xmlns = 'http://www.w3.org/2000/svg'
  91. xmlnsXlink = 'http://www.w3.org/1999/xlink'>
  92. <text
  93. dominantBaseline = 'central'
  94. fill = 'rgba(255,255,255,1)'
  95. fontSize = '40pt'
  96. textAnchor = 'middle'
  97. x = '50'
  98. y = '50'>
  99. { initials }
  100. </text>
  101. </svg>
  102. </div>
  103. );
  104. }
  105. // default avatar
  106. return (
  107. <div className = { this._getBadgeClassName() }>
  108. <img
  109. alt = 'avatar'
  110. className = { this._getAvatarClassName('defaultAvatar') }
  111. data-testid = { this.props.testId }
  112. id = { this.props.id }
  113. src = { this.props.defaultAvatar || 'images/avatar.png' }
  114. style = { this._getAvatarStyle() } />
  115. </div>
  116. );
  117. }
  118. /**
  119. * Constructs a style object to be used on the avatars.
  120. *
  121. * @param {string?} color - The desired background color.
  122. * @returns {Object}
  123. */
  124. _getAvatarStyle(color) {
  125. const { size } = this.props;
  126. return {
  127. background: color || undefined,
  128. fontSize: size ? size * 0.5 : '180%',
  129. height: size || '100%',
  130. width: size || '100%'
  131. };
  132. }
  133. /**
  134. * Constructs a list of class names required for the avatar component.
  135. *
  136. * @param {string} additional - Any additional class to add.
  137. * @returns {string}
  138. */
  139. _getAvatarClassName(additional) {
  140. return `avatar ${additional || ''} ${this.props.className || ''}`;
  141. }
  142. /**
  143. * Generates a class name to render a badge on the avatar, if necessary.
  144. *
  145. * @returns {string}
  146. */
  147. _getBadgeClassName() {
  148. const { status } = this.props;
  149. if (status) {
  150. return `avatar-badge avatar-badge-${status}`;
  151. }
  152. return '';
  153. }
  154. _isIcon: (?string | ?Object) => boolean;
  155. _onAvatarLoadError: () => void;
  156. /**
  157. * Handles avatar load errors.
  158. *
  159. * @returns {void}
  160. */
  161. _onAvatarLoadError() {
  162. const { onAvatarLoadError, onAvatarLoadErrorParams } = this.props;
  163. if (typeof onAvatarLoadError === 'function') {
  164. onAvatarLoadError(onAvatarLoadErrorParams);
  165. }
  166. }
  167. }