Avatar.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. "use client";
  2. var __rest = this && this.__rest || function (s, e) {
  3. var t = {};
  4. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
  5. if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
  6. if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];
  7. }
  8. return t;
  9. };
  10. import * as React from 'react';
  11. import classNames from 'classnames';
  12. import ResizeObserver from 'rc-resize-observer';
  13. import { composeRef } from "rc-util/es/ref";
  14. import { responsiveArray } from '../_util/responsiveObserver';
  15. import { devUseWarning } from '../_util/warning';
  16. import { ConfigContext } from '../config-provider';
  17. import useCSSVarCls from '../config-provider/hooks/useCSSVarCls';
  18. import useSize from '../config-provider/hooks/useSize';
  19. import useBreakpoint from '../grid/hooks/useBreakpoint';
  20. import AvatarContext from './AvatarContext';
  21. import useStyle from './style';
  22. const Avatar = /*#__PURE__*/React.forwardRef((props, ref) => {
  23. const {
  24. prefixCls: customizePrefixCls,
  25. shape,
  26. size: customSize,
  27. src,
  28. srcSet,
  29. icon,
  30. className,
  31. rootClassName,
  32. style,
  33. alt,
  34. draggable,
  35. children,
  36. crossOrigin,
  37. gap = 4,
  38. onError
  39. } = props,
  40. others = __rest(props, ["prefixCls", "shape", "size", "src", "srcSet", "icon", "className", "rootClassName", "style", "alt", "draggable", "children", "crossOrigin", "gap", "onError"]);
  41. const [scale, setScale] = React.useState(1);
  42. const [mounted, setMounted] = React.useState(false);
  43. const [isImgExist, setIsImgExist] = React.useState(true);
  44. const avatarNodeRef = React.useRef(null);
  45. const avatarChildrenRef = React.useRef(null);
  46. const avatarNodeMergedRef = composeRef(ref, avatarNodeRef);
  47. const {
  48. getPrefixCls,
  49. avatar
  50. } = React.useContext(ConfigContext);
  51. const avatarCtx = React.useContext(AvatarContext);
  52. const setScaleParam = () => {
  53. if (!avatarChildrenRef.current || !avatarNodeRef.current) {
  54. return;
  55. }
  56. const childrenWidth = avatarChildrenRef.current.offsetWidth; // offsetWidth avoid affecting be transform scale
  57. const nodeWidth = avatarNodeRef.current.offsetWidth;
  58. // denominator is 0 is no meaning
  59. if (childrenWidth !== 0 && nodeWidth !== 0) {
  60. if (gap * 2 < nodeWidth) {
  61. setScale(nodeWidth - gap * 2 < childrenWidth ? (nodeWidth - gap * 2) / childrenWidth : 1);
  62. }
  63. }
  64. };
  65. React.useEffect(() => {
  66. setMounted(true);
  67. }, []);
  68. React.useEffect(() => {
  69. setIsImgExist(true);
  70. setScale(1);
  71. }, [src]);
  72. React.useEffect(setScaleParam, [gap]);
  73. const handleImgLoadError = () => {
  74. const errorFlag = onError === null || onError === void 0 ? void 0 : onError();
  75. if (errorFlag !== false) {
  76. setIsImgExist(false);
  77. }
  78. };
  79. const size = useSize(ctxSize => {
  80. var _a, _b;
  81. return (_b = (_a = customSize !== null && customSize !== void 0 ? customSize : avatarCtx === null || avatarCtx === void 0 ? void 0 : avatarCtx.size) !== null && _a !== void 0 ? _a : ctxSize) !== null && _b !== void 0 ? _b : 'default';
  82. });
  83. const needResponsive = Object.keys(typeof size === 'object' ? size || {} : {}).some(key => ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'].includes(key));
  84. const screens = useBreakpoint(needResponsive);
  85. const responsiveSizeStyle = React.useMemo(() => {
  86. if (typeof size !== 'object') {
  87. return {};
  88. }
  89. const currentBreakpoint = responsiveArray.find(screen => screens[screen]);
  90. const currentSize = size[currentBreakpoint];
  91. return currentSize ? {
  92. width: currentSize,
  93. height: currentSize,
  94. fontSize: currentSize && (icon || children) ? currentSize / 2 : 18
  95. } : {};
  96. }, [screens, size]);
  97. if (process.env.NODE_ENV !== 'production') {
  98. const warning = devUseWarning('Avatar');
  99. process.env.NODE_ENV !== "production" ? warning(!(typeof icon === 'string' && icon.length > 2), 'breaking', `\`icon\` is using ReactNode instead of string naming in v4. Please check \`${icon}\` at https://ant.design/components/icon`) : void 0;
  100. }
  101. const prefixCls = getPrefixCls('avatar', customizePrefixCls);
  102. const rootCls = useCSSVarCls(prefixCls);
  103. const [wrapCSSVar, hashId, cssVarCls] = useStyle(prefixCls, rootCls);
  104. const sizeCls = classNames({
  105. [`${prefixCls}-lg`]: size === 'large',
  106. [`${prefixCls}-sm`]: size === 'small'
  107. });
  108. const hasImageElement = /*#__PURE__*/React.isValidElement(src);
  109. const mergedShape = shape || (avatarCtx === null || avatarCtx === void 0 ? void 0 : avatarCtx.shape) || 'circle';
  110. const classString = classNames(prefixCls, sizeCls, avatar === null || avatar === void 0 ? void 0 : avatar.className, `${prefixCls}-${mergedShape}`, {
  111. [`${prefixCls}-image`]: hasImageElement || src && isImgExist,
  112. [`${prefixCls}-icon`]: !!icon
  113. }, cssVarCls, rootCls, className, rootClassName, hashId);
  114. const sizeStyle = typeof size === 'number' ? {
  115. width: size,
  116. height: size,
  117. fontSize: icon ? size / 2 : 18
  118. } : {};
  119. let childrenToRender;
  120. if (typeof src === 'string' && isImgExist) {
  121. childrenToRender = /*#__PURE__*/React.createElement("img", {
  122. src: src,
  123. draggable: draggable,
  124. srcSet: srcSet,
  125. onError: handleImgLoadError,
  126. alt: alt,
  127. crossOrigin: crossOrigin
  128. });
  129. } else if (hasImageElement) {
  130. childrenToRender = src;
  131. } else if (icon) {
  132. childrenToRender = icon;
  133. } else if (mounted || scale !== 1) {
  134. const transformString = `scale(${scale})`;
  135. const childrenStyle = {
  136. msTransform: transformString,
  137. WebkitTransform: transformString,
  138. transform: transformString
  139. };
  140. childrenToRender = /*#__PURE__*/React.createElement(ResizeObserver, {
  141. onResize: setScaleParam
  142. }, /*#__PURE__*/React.createElement("span", {
  143. className: `${prefixCls}-string`,
  144. ref: avatarChildrenRef,
  145. style: Object.assign({}, childrenStyle)
  146. }, children));
  147. } else {
  148. childrenToRender = /*#__PURE__*/React.createElement("span", {
  149. className: `${prefixCls}-string`,
  150. style: {
  151. opacity: 0
  152. },
  153. ref: avatarChildrenRef
  154. }, children);
  155. }
  156. return wrapCSSVar(/*#__PURE__*/React.createElement("span", Object.assign({}, others, {
  157. style: Object.assign(Object.assign(Object.assign(Object.assign({}, sizeStyle), responsiveSizeStyle), avatar === null || avatar === void 0 ? void 0 : avatar.style), style),
  158. className: classString,
  159. ref: avatarNodeMergedRef
  160. }), childrenToRender));
  161. });
  162. if (process.env.NODE_ENV !== 'production') {
  163. Avatar.displayName = 'Avatar';
  164. }
  165. export default Avatar;