@xsolla/xui-avatar 0.148.2 → 0.149.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -23
- package/native/index.d.mts +21 -10
- package/native/index.d.ts +21 -10
- package/native/index.js +52 -35
- package/native/index.js.map +1 -1
- package/native/index.mjs +52 -35
- package/native/index.mjs.map +1 -1
- package/package.json +6 -6
- package/web/index.d.mts +21 -10
- package/web/index.d.ts +21 -10
- package/web/index.js +56 -35
- package/web/index.js.map +1 -1
- package/web/index.mjs +56 -35
- package/web/index.mjs.map +1 -1
package/native/index.mjs
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// src/Avatar.tsx
|
|
2
|
+
import React2 from "react";
|
|
3
|
+
|
|
1
4
|
// ../../foundation/primitives-native/src/Box.tsx
|
|
2
5
|
import {
|
|
3
6
|
View,
|
|
@@ -277,10 +280,11 @@ var Avatar = ({
|
|
|
277
280
|
text,
|
|
278
281
|
size = "xl",
|
|
279
282
|
square = false,
|
|
283
|
+
tone = "mono",
|
|
280
284
|
badge = false,
|
|
281
285
|
badgeCount,
|
|
286
|
+
badgeIcon,
|
|
282
287
|
badgeTone = "alert",
|
|
283
|
-
stroke = false,
|
|
284
288
|
backgroundColor,
|
|
285
289
|
disableHover = true,
|
|
286
290
|
"aria-label": ariaLabel,
|
|
@@ -290,7 +294,15 @@ var Avatar = ({
|
|
|
290
294
|
themeProductContext
|
|
291
295
|
}) => {
|
|
292
296
|
const { theme } = useResolvedTheme({ themeMode, themeProductContext });
|
|
297
|
+
const [hasImageError, setHasImageError] = React2.useState(false);
|
|
298
|
+
React2.useEffect(() => {
|
|
299
|
+
setHasImageError(false);
|
|
300
|
+
}, [src]);
|
|
301
|
+
const useImage = !!src && !hasImageError;
|
|
293
302
|
const sizeStyles = theme.sizing.avatar(size);
|
|
303
|
+
const toneBackground = tone === "brand" ? theme.colors.background.brand.primary : theme.colors.overlay.mono;
|
|
304
|
+
const toneHoverBackground = tone === "brand" ? theme.colors.background.brand.secondary : theme.colors.overlay.monoHover;
|
|
305
|
+
const toneContent = tone === "brand" ? theme.colors.content.on.brand : theme.colors.content.primary;
|
|
294
306
|
const borderRadius = square ? sizeStyles.borderRadiusSquare : sizeStyles.borderRadiusCircle;
|
|
295
307
|
const countSizeMap = {
|
|
296
308
|
xl: "xl",
|
|
@@ -308,7 +320,9 @@ var Avatar = ({
|
|
|
308
320
|
xs: "sm",
|
|
309
321
|
xxs: "xs"
|
|
310
322
|
};
|
|
311
|
-
const
|
|
323
|
+
const hasBadgeContent = !!(badgeCount || badgeIcon);
|
|
324
|
+
const badgeSize = hasBadgeContent ? countSizeMap[size] : dotSizeMap[size];
|
|
325
|
+
const rendersAsDot = badgeSize === "sm" || badgeSize === "xs";
|
|
312
326
|
const getDotOffset = () => {
|
|
313
327
|
if (square) {
|
|
314
328
|
return size === "xxs" ? { right: -1, top: -1 } : { right: -3, top: -3 };
|
|
@@ -323,7 +337,7 @@ var Avatar = ({
|
|
|
323
337
|
};
|
|
324
338
|
return circleOffsets[size];
|
|
325
339
|
};
|
|
326
|
-
const badgeOffset =
|
|
340
|
+
const badgeOffset = hasBadgeContent && !rendersAsDot ? square ? sizeStyles.badgeOffsetSquare : sizeStyles.badgeOffsetCircle : getDotOffset();
|
|
327
341
|
const displayBadgeCount = badgeCount;
|
|
328
342
|
return /* @__PURE__ */ jsxs(
|
|
329
343
|
Box,
|
|
@@ -331,7 +345,7 @@ var Avatar = ({
|
|
|
331
345
|
width: sizeStyles.size,
|
|
332
346
|
height: sizeStyles.size,
|
|
333
347
|
position: "relative",
|
|
334
|
-
...!
|
|
348
|
+
...!useImage && { role: "img", "aria-label": ariaLabel },
|
|
335
349
|
...onClick && {
|
|
336
350
|
onPress: onClick,
|
|
337
351
|
onKeyDown: (e) => {
|
|
@@ -351,19 +365,19 @@ var Avatar = ({
|
|
|
351
365
|
width: sizeStyles.size,
|
|
352
366
|
height: sizeStyles.size,
|
|
353
367
|
borderRadius,
|
|
354
|
-
backgroundColor: backgroundColor ||
|
|
368
|
+
backgroundColor: backgroundColor || toneBackground,
|
|
355
369
|
alignItems: "center",
|
|
356
370
|
justifyContent: "center",
|
|
357
371
|
position: "relative",
|
|
358
372
|
overflow: "hidden",
|
|
359
|
-
borderWidth:
|
|
360
|
-
borderColor: theme.colors.
|
|
361
|
-
...!disableHover && !
|
|
373
|
+
borderWidth: 2,
|
|
374
|
+
borderColor: theme.colors.border.secondary,
|
|
375
|
+
...!disableHover && !useImage && {
|
|
362
376
|
hoverStyle: {
|
|
363
|
-
backgroundColor:
|
|
377
|
+
backgroundColor: toneHoverBackground
|
|
364
378
|
}
|
|
365
379
|
},
|
|
366
|
-
children:
|
|
380
|
+
children: useImage ? /* @__PURE__ */ jsx4(
|
|
367
381
|
Box,
|
|
368
382
|
{
|
|
369
383
|
as: "img",
|
|
@@ -372,15 +386,16 @@ var Avatar = ({
|
|
|
372
386
|
position: "absolute",
|
|
373
387
|
top: 0,
|
|
374
388
|
left: 0,
|
|
375
|
-
width:
|
|
376
|
-
height:
|
|
377
|
-
borderRadius
|
|
389
|
+
width: "100%",
|
|
390
|
+
height: "100%",
|
|
391
|
+
borderRadius,
|
|
392
|
+
onError: () => setHasImageError(true)
|
|
378
393
|
}
|
|
379
|
-
) : icon ? /* @__PURE__ */ jsx4(Icon, { size: sizeStyles.iconSize, color:
|
|
394
|
+
) : icon ? /* @__PURE__ */ jsx4(Icon, { size: sizeStyles.iconSize, color: toneContent, children: icon }) : text ? /* @__PURE__ */ jsx4(
|
|
380
395
|
Text,
|
|
381
396
|
{
|
|
382
397
|
fontSize: sizeStyles.fontSize,
|
|
383
|
-
color:
|
|
398
|
+
color: toneContent,
|
|
384
399
|
fontWeight: "400",
|
|
385
400
|
letterSpacing: 0.4,
|
|
386
401
|
children: text
|
|
@@ -388,8 +403,9 @@ var Avatar = ({
|
|
|
388
403
|
) : /* @__PURE__ */ jsx4(
|
|
389
404
|
User,
|
|
390
405
|
{
|
|
406
|
+
variant: "solid",
|
|
391
407
|
size: sizeStyles.iconSize,
|
|
392
|
-
color:
|
|
408
|
+
color: toneContent
|
|
393
409
|
}
|
|
394
410
|
)
|
|
395
411
|
}
|
|
@@ -405,6 +421,7 @@ var Avatar = ({
|
|
|
405
421
|
{
|
|
406
422
|
size: badgeSize,
|
|
407
423
|
tone: badgeTone,
|
|
424
|
+
icon: badgeIcon,
|
|
408
425
|
showStroke: size !== "xxs",
|
|
409
426
|
"aria-label": displayBadgeCount ? `${displayBadgeCount} notifications` : "Notification",
|
|
410
427
|
children: displayBadgeCount
|
|
@@ -421,26 +438,26 @@ var Avatar = ({
|
|
|
421
438
|
import { useResolvedTheme as useResolvedTheme2 } from "@xsolla/xui-core";
|
|
422
439
|
import { Tooltip } from "@xsolla/xui-tooltip";
|
|
423
440
|
import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
424
|
-
var
|
|
425
|
-
sm: "sm",
|
|
426
|
-
md: "md",
|
|
427
|
-
lg: "lg",
|
|
428
|
-
xl: "xl"
|
|
429
|
-
};
|
|
441
|
+
var DEFAULT_MAX_VISIBLE = 6;
|
|
430
442
|
var AvatarGroup = ({
|
|
431
443
|
list,
|
|
432
|
-
size = "
|
|
433
|
-
maxVisible =
|
|
434
|
-
stroke = true,
|
|
444
|
+
size = "sm",
|
|
445
|
+
maxVisible = DEFAULT_MAX_VISIBLE,
|
|
435
446
|
avatarBackgroundMode = "mixed",
|
|
436
447
|
"aria-label": ariaLabel,
|
|
437
448
|
themeMode,
|
|
438
449
|
themeProductContext
|
|
439
450
|
}) => {
|
|
440
451
|
const { theme } = useResolvedTheme2({ themeMode, themeProductContext });
|
|
441
|
-
|
|
452
|
+
if (maxVisible < 1) {
|
|
453
|
+
console.warn(
|
|
454
|
+
`[AvatarGroup] "maxVisible" must be a positive number. Received ${maxVisible}, falling back to default (${DEFAULT_MAX_VISIBLE}).`
|
|
455
|
+
);
|
|
456
|
+
}
|
|
457
|
+
const effectiveMaxVisible = maxVisible < 1 ? DEFAULT_MAX_VISIBLE : maxVisible;
|
|
442
458
|
const totalCount = list.length;
|
|
443
|
-
const
|
|
459
|
+
const overflows = totalCount > effectiveMaxVisible;
|
|
460
|
+
const visibleCount = overflows ? effectiveMaxVisible - 1 : totalCount;
|
|
444
461
|
const visibleListItems = list.slice(0, visibleCount);
|
|
445
462
|
const remainingCount = totalCount - visibleCount;
|
|
446
463
|
const overlap = -4;
|
|
@@ -488,7 +505,6 @@ var AvatarGroup = ({
|
|
|
488
505
|
visibleListItems.map((item, index) => {
|
|
489
506
|
const shouldApplyBackground = !item.src;
|
|
490
507
|
const backgroundColor = shouldApplyBackground ? getBackgroundColor(index) : void 0;
|
|
491
|
-
const shouldEnableHover = !!item.src && !!item.onClick;
|
|
492
508
|
const avatar = /* @__PURE__ */ jsx5(
|
|
493
509
|
Box,
|
|
494
510
|
{
|
|
@@ -499,11 +515,13 @@ var AvatarGroup = ({
|
|
|
499
515
|
{
|
|
500
516
|
src: item.src,
|
|
501
517
|
text: item.initials,
|
|
502
|
-
size
|
|
503
|
-
stroke,
|
|
518
|
+
size,
|
|
504
519
|
backgroundColor,
|
|
505
|
-
disableHover:
|
|
506
|
-
|
|
520
|
+
disableHover: true,
|
|
521
|
+
badge: item.badge,
|
|
522
|
+
badgeCount: item.badgeCount,
|
|
523
|
+
badgeIcon: item.badgeIcon,
|
|
524
|
+
badgeTone: item.badgeTone,
|
|
507
525
|
...item.tooltip ? { "aria-label": item.tooltip } : {}
|
|
508
526
|
}
|
|
509
527
|
)
|
|
@@ -515,9 +533,8 @@ var AvatarGroup = ({
|
|
|
515
533
|
remainingCount > 0 && /* @__PURE__ */ jsx5(Box, { marginLeft: overlap, zIndex: 0, children: /* @__PURE__ */ jsx5(
|
|
516
534
|
Avatar,
|
|
517
535
|
{
|
|
518
|
-
size
|
|
519
|
-
text: `+${remainingCount}`,
|
|
520
|
-
stroke,
|
|
536
|
+
size,
|
|
537
|
+
text: remainingCount > 99 ? "99+" : `+${remainingCount}`,
|
|
521
538
|
backgroundColor: theme.colors.background.secondary,
|
|
522
539
|
disableHover: true,
|
|
523
540
|
"aria-label": `${remainingCount} more ${remainingCount === 1 ? "user" : "users"}`
|
package/native/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../foundation/primitives-native/src/Box.tsx","../../../../foundation/primitives-native/src/Text.tsx","../../../../foundation/primitives-native/src/Icon.tsx","../../src/Avatar.tsx","../../src/AvatarGroup.tsx"],"sourcesContent":["import React from \"react\";\nimport {\n View,\n Pressable,\n Image,\n ViewStyle,\n ImageStyle,\n DimensionValue,\n AnimatableNumericValue,\n} from \"react-native\";\nimport { BoxProps } from \"@xsolla/xui-primitives-core\";\n\nexport const Box: React.FC<BoxProps> = ({\n children,\n onPress,\n onLayout,\n onMoveShouldSetResponder,\n onResponderGrant,\n onResponderMove,\n onResponderRelease,\n onResponderTerminate,\n backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius,\n borderStyle,\n height,\n padding,\n paddingHorizontal,\n paddingVertical,\n margin,\n marginTop,\n marginBottom,\n marginLeft,\n marginRight,\n flexDirection,\n alignItems,\n justifyContent,\n position,\n top,\n bottom,\n left,\n right,\n width,\n minWidth,\n minHeight,\n maxWidth,\n maxHeight,\n flex,\n overflow,\n zIndex,\n hoverStyle,\n pressStyle,\n style,\n \"data-testid\": dataTestId,\n testID,\n as,\n src,\n alt,\n ...rest\n}) => {\n const getContainerStyle = (pressed?: boolean): ViewStyle => ({\n backgroundColor:\n pressed && pressStyle?.backgroundColor\n ? pressStyle.backgroundColor\n : backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius: borderRadius as AnimatableNumericValue,\n borderStyle: borderStyle as ViewStyle[\"borderStyle\"],\n overflow,\n zIndex,\n height: height as DimensionValue,\n width: width as DimensionValue,\n minWidth: minWidth as DimensionValue,\n minHeight: minHeight as DimensionValue,\n maxWidth: maxWidth as DimensionValue,\n maxHeight: maxHeight as DimensionValue,\n padding: padding as DimensionValue,\n paddingHorizontal: paddingHorizontal as DimensionValue,\n paddingVertical: paddingVertical as DimensionValue,\n margin: margin as DimensionValue,\n marginTop: marginTop as DimensionValue,\n marginBottom: marginBottom as DimensionValue,\n marginLeft: marginLeft as DimensionValue,\n marginRight: marginRight as DimensionValue,\n flexDirection,\n alignItems,\n justifyContent,\n position: position as ViewStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n flex,\n ...(style as ViewStyle),\n });\n\n const finalTestID = dataTestId || testID;\n\n // Destructure and drop web-only props from rest before passing to RN components\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const {\n role,\n tabIndex,\n onKeyDown,\n onKeyUp,\n \"aria-label\": _ariaLabel,\n \"aria-labelledby\": _ariaLabelledBy,\n \"aria-current\": _ariaCurrent,\n \"aria-disabled\": _ariaDisabled,\n \"aria-live\": _ariaLive,\n className,\n \"data-testid\": _dataTestId,\n ...nativeRest\n } = rest as Record<string, unknown>;\n\n // Handle as=\"img\" for React Native\n if (as === \"img\" && src) {\n const imageStyle: ImageStyle = {\n width: width as DimensionValue,\n height: height as DimensionValue,\n borderRadius: borderRadius as number,\n position: position as ImageStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n ...(style as ImageStyle),\n };\n\n return (\n <Image\n source={{ uri: src }}\n style={imageStyle}\n testID={finalTestID}\n resizeMode=\"cover\"\n {...nativeRest}\n />\n );\n }\n\n if (onPress) {\n return (\n <Pressable\n onPress={onPress}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n style={({ pressed }) => getContainerStyle(pressed)}\n testID={finalTestID}\n {...nativeRest}\n >\n {children}\n </Pressable>\n );\n }\n\n return (\n <View\n style={getContainerStyle()}\n testID={finalTestID}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n {...nativeRest}\n >\n {children}\n </View>\n );\n};\n","import React from \"react\";\nimport {\n Text as RNText,\n TextStyle,\n AccessibilityRole,\n StyleSheet,\n} from \"react-native\";\nimport { TextProps } from \"@xsolla/xui-primitives-core\";\n\nconst roleMap: Record<string, AccessibilityRole> = {\n alert: \"alert\",\n heading: \"header\",\n button: \"button\",\n link: \"link\",\n text: \"text\",\n};\n\nconst parseNumericValue = (\n value: string | number | undefined\n): number | undefined => {\n if (value === undefined) return undefined;\n if (typeof value === \"number\") return value;\n const parsed = parseFloat(value);\n return isNaN(parsed) ? undefined : parsed;\n};\n\nexport const Text: React.FC<TextProps> = ({\n children,\n color,\n fontSize,\n fontWeight,\n fontFamily,\n textAlign,\n lineHeight,\n numberOfLines,\n id,\n role,\n style: styleProp,\n ...props\n}) => {\n let resolvedFontFamily = fontFamily\n ? fontFamily.split(\",\")[0].replace(/['\"]/g, \"\").trim()\n : undefined;\n\n if (\n resolvedFontFamily === \"Pilat Wide\" ||\n resolvedFontFamily === \"Pilat Wide Bold\" ||\n resolvedFontFamily === \"Aktiv Grotesk\"\n ) {\n resolvedFontFamily = undefined;\n }\n\n const incomingStyle = StyleSheet.flatten(styleProp) as TextStyle | undefined;\n\n const baseStyle: TextStyle = {\n color: color ?? incomingStyle?.color,\n fontSize: typeof fontSize === \"number\" ? fontSize : undefined,\n fontWeight: fontWeight as TextStyle[\"fontWeight\"],\n fontFamily: resolvedFontFamily,\n textDecorationLine: props.textDecoration as TextStyle[\"textDecorationLine\"],\n textAlign: textAlign ?? incomingStyle?.textAlign,\n lineHeight: parseNumericValue(lineHeight ?? incomingStyle?.lineHeight),\n marginTop: parseNumericValue(\n incomingStyle?.marginTop as number | string | undefined\n ),\n marginBottom: parseNumericValue(\n incomingStyle?.marginBottom as number | string | undefined\n ),\n };\n\n const accessibilityRole = role ? roleMap[role] : undefined;\n\n return (\n <RNText\n style={baseStyle}\n numberOfLines={numberOfLines}\n testID={id}\n accessibilityRole={accessibilityRole}\n >\n {children}\n </RNText>\n );\n};\n","import React from \"react\";\nimport { View, ViewStyle } from \"react-native\";\nimport { IconProps } from \"@xsolla/xui-primitives-core\";\n\nexport const Icon: React.FC<IconProps> = ({ children, color, size }) => {\n const style: ViewStyle = {\n width: typeof size === \"number\" ? size : undefined,\n height: typeof size === \"number\" ? size : undefined,\n alignItems: \"center\",\n justifyContent: \"center\",\n };\n\n // On native, we try to pass the color down to children (like Text primitives)\n // to mimic the CSS inheritance behavior of the web version.\n const childrenWithProps = React.Children.map(children, (child) => {\n if (React.isValidElement(child)) {\n return React.cloneElement(child, {\n color: child.props.color || color,\n // Also pass size if child seems to be an icon that needs it\n size: child.props.size || size,\n });\n }\n return child;\n });\n\n return <View style={style}>{childrenWithProps}</View>;\n};\n","import React from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box, Text, Icon } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme, type ThemeOverrideProps } from \"@xsolla/xui-core\";\nimport { Badge } from \"@xsolla/xui-badge\";\nimport { User } from \"@xsolla/xui-icons-base\";\n\nexport interface AvatarProps extends ThemeOverrideProps {\n /** Image source URL */\n src?: string;\n /** Icon component to display when no image is provided */\n icon?: React.ReactNode;\n /** Text/Initials to display when no image or icon is provided */\n text?: string;\n /** Size of the avatar */\n size?: \"xl\" | \"lg\" | \"md\" | \"sm\" | \"xs\" | \"xxs\";\n /** If true, the avatar will be square with small border radius. If false, it will be a circle. */\n square?: boolean;\n /** Whether to show an alert badge */\n badge?: boolean;\n /** Number or text to display in the badge notification */\n badgeCount?: React.ReactNode;\n /** If true, the avatar will have a border to separate it from other avatars in a group */\n stroke?: boolean;\n /** Background color for the avatar. Defaults to theme background secondary. */\n backgroundColor?: string;\n /** Disable hover effect. Used internally by AvatarGroup. */\n disableHover?: boolean;\n /** Accessible label for the avatar. Recommended for screen readers. */\n \"aria-label\"?: string;\n /** Alternative text for the avatar image */\n alt?: string;\n /** Click handler for the avatar */\n onClick?: () => void;\n /** Color tone for the badge */\n badgeTone?:\n | \"primary\"\n | \"secondary\"\n | \"brand\"\n | \"brandExtra\"\n | \"success\"\n | \"warning\"\n | \"alert\"\n | \"neutral\";\n}\n\nexport const Avatar: React.FC<AvatarProps> = ({\n src,\n icon,\n text,\n size = \"xl\",\n square = false,\n badge = false,\n badgeCount,\n badgeTone = \"alert\",\n stroke = false,\n backgroundColor,\n disableHover = true,\n \"aria-label\": ariaLabel,\n alt,\n onClick,\n themeMode,\n themeProductContext,\n}) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n\n const sizeStyles = theme.sizing.avatar(size);\n\n // Border radius based on square or circle variant\n const borderRadius = square\n ? sizeStyles.borderRadiusSquare\n : sizeStyles.borderRadiusCircle;\n\n const countSizeMap = {\n xl: \"xl\",\n lg: \"xl\",\n md: \"lg\",\n sm: \"lg\",\n xs: \"sm\",\n xxs: \"xs\",\n } as const;\n const dotSizeMap = {\n xl: \"md\",\n lg: \"md\",\n md: \"sm\",\n sm: \"sm\",\n xs: \"sm\",\n xxs: \"xs\",\n } as const;\n const badgeSize = badgeCount ? countSizeMap[size] : dotSizeMap[size];\n\n // Badge offset differs for circle vs square, and for dot vs count\n // Dot badge (8px) needs different offset per avatar size\n const getDotOffset = () => {\n if (square) {\n return size === \"xxs\" ? { right: -1, top: -1 } : { right: -3, top: -3 };\n }\n // Circle - position dot on the edge based on avatar size\n const circleOffsets = {\n xl: { right: 2, top: 2 },\n lg: { right: 2, top: 2 },\n md: { right: 2, top: 2 },\n sm: { right: 2, top: 2 },\n xs: { right: 0, top: 0 },\n xxs: { right: 1, top: 1 },\n };\n return circleOffsets[size];\n };\n\n const badgeOffset = badgeCount\n ? square\n ? sizeStyles.badgeOffsetSquare\n : sizeStyles.badgeOffsetCircle\n : getDotOffset();\n\n // Display badge count\n const displayBadgeCount = badgeCount;\n\n return (\n <Box\n width={sizeStyles.size}\n height={sizeStyles.size}\n position=\"relative\"\n {...(!src && { role: \"img\", \"aria-label\": ariaLabel })}\n {...(onClick && {\n onPress: onClick,\n onKeyDown: (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onClick();\n }\n },\n cursor: \"pointer\",\n role: \"button\",\n tabIndex: 0,\n })}\n >\n <Box\n width={sizeStyles.size}\n height={sizeStyles.size}\n borderRadius={borderRadius}\n backgroundColor={backgroundColor || theme.colors.overlay.mono}\n alignItems=\"center\"\n justifyContent=\"center\"\n position=\"relative\"\n overflow=\"hidden\"\n borderWidth={stroke ? 1 : 0}\n borderColor={theme.colors.background.primary}\n {...(!disableHover &&\n !src && {\n hoverStyle: {\n backgroundColor: theme.colors.overlay.monoHover,\n },\n })}\n >\n {src ? (\n <Box\n as=\"img\"\n src={src}\n alt={alt || ariaLabel || \"\"}\n position=\"absolute\"\n top={0}\n left={0}\n width={sizeStyles.size}\n height={sizeStyles.size}\n borderRadius={borderRadius}\n />\n ) : icon ? (\n <Icon size={sizeStyles.iconSize} color={theme.colors.content.primary}>\n {icon}\n </Icon>\n ) : text ? (\n <Text\n fontSize={sizeStyles.fontSize}\n color={theme.colors.content.primary}\n fontWeight=\"400\"\n letterSpacing={0.4}\n >\n {text}\n </Text>\n ) : (\n <User\n size={sizeStyles.iconSize}\n color={theme.colors.content.primary}\n />\n )}\n </Box>\n\n {badge && (\n <Box\n position=\"absolute\"\n right={badgeOffset.right}\n top={badgeOffset.top}\n >\n <Badge\n size={badgeSize}\n tone={badgeTone}\n showStroke={size !== \"xxs\"}\n aria-label={\n displayBadgeCount\n ? `${displayBadgeCount} notifications`\n : \"Notification\"\n }\n >\n {displayBadgeCount}\n </Badge>\n </Box>\n )}\n </Box>\n );\n};\n","import React from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme, type ThemeOverrideProps } from \"@xsolla/xui-core\";\nimport { Tooltip } from \"@xsolla/xui-tooltip\";\nimport { Avatar } from \"./Avatar\";\n\n/** Theme type from the design system */\ntype Theme = ReturnType<typeof useResolvedTheme>[\"theme\"];\n\n/** Item in the avatar group list */\nexport interface AvatarGroupItem {\n /** Image source URL */\n src?: string;\n /** Initials to display when no image is provided */\n initials?: string;\n /** Click handler for the avatar */\n onClick?: () => void;\n /** Tooltip text to display on hover */\n tooltip?: string;\n}\n\n/** Avatar background mode - preset colors, 'mixed' for cycling, or a theme function */\nexport type AvatarBackgroundMode =\n | \"mixed\"\n | \"brand\"\n | \"brandExtra\"\n | \"success\"\n | \"warning\"\n | \"alert\"\n | \"neutral\"\n | ((theme: Theme) => string);\n\nexport interface AvatarGroupProps extends ThemeOverrideProps {\n /**\n * List of avatars to display in the group.\n * `tooltip` property is text to be displayed in the tooltip when hovering over the avatar.\n */\n list: AvatarGroupItem[];\n /** Size of the avatars in the group */\n size?: \"sm\" | \"md\" | \"lg\" | \"xl\";\n /**\n * The maximum number of avatars to display before collapsing the rest into a \"+N\" counter.\n * If the number of avatars exceeds this value, the extra avatars will be hidden.\n */\n maxVisible?: number;\n /** Whether to show a stroke/border around each avatar */\n stroke?: boolean;\n /**\n * Controls the background color mode for avatars in the group.\n * - 'mixed' (default): Avatars cycle through different colors\n * - 'brand', 'brandExtra', 'success', 'warning', 'alert', 'neutral': Single color for all avatars\n * - Theme function: A function that receives theme and returns any color from the design system.\n * Example: (theme) => theme.colors.core.link.link\n */\n avatarBackgroundMode?: AvatarBackgroundMode;\n /** Accessible label for the avatar group. Defaults to \"Group of X users\". */\n \"aria-label\"?: string;\n}\n\n// Map external size values to internal Avatar size values\nconst sizeMap: Record<\n \"sm\" | \"md\" | \"lg\" | \"xl\",\n \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\"\n> = {\n sm: \"sm\",\n md: \"md\",\n lg: \"lg\",\n xl: \"xl\",\n};\n\nexport const AvatarGroup: React.FC<AvatarGroupProps> = ({\n list,\n size = \"md\",\n maxVisible = 6,\n stroke = true,\n avatarBackgroundMode = \"mixed\",\n \"aria-label\": ariaLabel,\n themeMode,\n themeProductContext,\n}) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n\n // Map external size to internal Avatar size\n const internalSize = sizeMap[size];\n\n const totalCount = list.length;\n\n // Determine which avatars to show\n // Ensure maxVisible is non-negative and doesn't exceed totalCount\n const visibleCount = Math.min(totalCount, Math.max(0, maxVisible));\n const visibleListItems = list.slice(0, visibleCount);\n const remainingCount = totalCount - visibleCount;\n\n // Overlap amount: 4px in Figma\n const overlap = -4;\n\n // Background colors for text/icon avatars (cycling through theme colors)\n const mixedBackgrounds = [\n theme.colors.background.alert.secondary,\n theme.colors.background.warning.secondary,\n theme.colors.background.brandExtra.secondary,\n theme.colors.background.neutral.secondary,\n theme.colors.background.brand.secondary,\n theme.colors.background.success.secondary,\n theme.colors.background.success.primary,\n ];\n\n // Preset color mapping\n const presetColors: Record<string, string> = {\n brand: theme.colors.background.brand.secondary,\n brandExtra: theme.colors.background.brandExtra.secondary,\n success: theme.colors.background.success.secondary,\n warning: theme.colors.background.warning.secondary,\n alert: theme.colors.background.alert.secondary,\n neutral: theme.colors.background.neutral.secondary,\n };\n\n // Get background color based on avatarBackgroundMode\n const getBackgroundColor = (index: number): string => {\n if (typeof avatarBackgroundMode === \"function\") {\n return avatarBackgroundMode(theme);\n }\n if (avatarBackgroundMode === \"mixed\") {\n return mixedBackgrounds[index % mixedBackgrounds.length];\n }\n // Preset color mode\n return (\n presetColors[avatarBackgroundMode] || theme.colors.background.secondary\n );\n };\n\n // Default accessible label for the group\n const defaultAriaLabel =\n totalCount === 1\n ? \"1 user\"\n : totalCount === visibleCount\n ? `${totalCount} users`\n : `${visibleCount} of ${totalCount} users`;\n\n // Render an avatar with optional tooltip wrapper\n const renderAvatarWithTooltip = (\n avatar: React.ReactNode,\n tooltip: string | undefined,\n key: number\n ) => {\n if (tooltip) {\n return (\n <Tooltip key={key} content={tooltip} placement=\"top\">\n {avatar}\n </Tooltip>\n );\n }\n return avatar;\n };\n\n return (\n <Box\n flexDirection=\"row\"\n alignItems=\"center\"\n role=\"group\"\n aria-label={ariaLabel || defaultAriaLabel}\n >\n {visibleListItems.map((item, index) => {\n const shouldApplyBackground = !item.src;\n const backgroundColor = shouldApplyBackground\n ? getBackgroundColor(index)\n : undefined;\n\n // Only enable hover for image avatars with onClick\n const shouldEnableHover = !!item.src && !!item.onClick;\n\n const avatar = (\n <Box\n key={index}\n marginLeft={index === 0 ? 0 : overlap}\n zIndex={totalCount - index}\n >\n <Avatar\n src={item.src}\n text={item.initials}\n size={internalSize}\n stroke={stroke}\n backgroundColor={backgroundColor}\n disableHover={!shouldEnableHover}\n onClick={item.onClick}\n {...(item.tooltip ? { \"aria-label\": item.tooltip } : {})}\n />\n </Box>\n );\n\n return renderAvatarWithTooltip(avatar, item.tooltip, index);\n })}\n\n {remainingCount > 0 && (\n <Box marginLeft={overlap} zIndex={0}>\n <Avatar\n size={internalSize}\n text={`+${remainingCount}`}\n stroke={stroke}\n backgroundColor={theme.colors.background.secondary}\n disableHover={true}\n aria-label={`${remainingCount} more ${remainingCount === 1 ? \"user\" : \"users\"}`}\n />\n </Box>\n )}\n </Box>\n );\n};\n"],"mappings":"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","names":["jsx","View","jsx","jsx","useResolvedTheme","jsx","jsxs","useResolvedTheme"]}
|
|
1
|
+
{"version":3,"sources":["../../src/Avatar.tsx","../../../../foundation/primitives-native/src/Box.tsx","../../../../foundation/primitives-native/src/Text.tsx","../../../../foundation/primitives-native/src/Icon.tsx","../../src/AvatarGroup.tsx"],"sourcesContent":["import React from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box, Text, Icon } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme, type ThemeOverrideProps } from \"@xsolla/xui-core\";\nimport { Badge } from \"@xsolla/xui-badge\";\nimport { User } from \"@xsolla/xui-icons-base\";\n\nexport interface AvatarProps extends ThemeOverrideProps {\n /** Image source URL */\n src?: string;\n /** Icon component to display when no image is provided */\n icon?: React.ReactNode;\n /** Text/Initials to display when no image or icon is provided */\n text?: string;\n /** Size of the avatar */\n size?: \"xl\" | \"lg\" | \"md\" | \"sm\" | \"xs\" | \"xxs\";\n /** If true, the avatar will be square with small border radius. If false, it will be a circle. */\n square?: boolean;\n /** Visual tone — 'mono' (default) or 'brand'. */\n tone?: \"mono\" | \"brand\";\n /** Whether to show an alert badge */\n badge?: boolean;\n /** Number or text to display in the badge notification */\n badgeCount?: React.ReactNode;\n /** Icon to display in the badge */\n badgeIcon?: React.ReactNode;\n /**\n * Background colour override. Intended for internal use by AvatarGroup to\n * drive its `avatarBackgroundMode` cycling; not part of the public API.\n * @internal\n */\n backgroundColor?: string;\n /** Disable hover effect. Used internally by AvatarGroup. */\n disableHover?: boolean;\n /** Accessible label for the avatar. Recommended for screen readers. */\n \"aria-label\"?: string;\n /** Alternative text for the avatar image */\n alt?: string;\n /** Click handler for the avatar */\n onClick?: () => void;\n /** Color tone for the badge */\n badgeTone?:\n | \"primary\"\n | \"secondary\"\n | \"brand\"\n | \"brandExtra\"\n | \"success\"\n | \"warning\"\n | \"alert\"\n | \"neutral\";\n}\n\nexport const Avatar: React.FC<AvatarProps> = ({\n src,\n icon,\n text,\n size = \"xl\",\n square = false,\n tone = \"mono\",\n badge = false,\n badgeCount,\n badgeIcon,\n badgeTone = \"alert\",\n backgroundColor,\n disableHover = true,\n \"aria-label\": ariaLabel,\n alt,\n onClick,\n themeMode,\n themeProductContext,\n}) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n\n const [hasImageError, setHasImageError] = React.useState(false);\n\n React.useEffect(() => {\n setHasImageError(false);\n }, [src]);\n\n const useImage = !!src && !hasImageError;\n\n const sizeStyles = theme.sizing.avatar(size);\n\n const toneBackground =\n tone === \"brand\"\n ? theme.colors.background.brand.primary\n : theme.colors.overlay.mono;\n const toneHoverBackground =\n tone === \"brand\"\n ? theme.colors.background.brand.secondary\n : theme.colors.overlay.monoHover;\n const toneContent =\n tone === \"brand\"\n ? theme.colors.content.on.brand\n : theme.colors.content.primary;\n\n // Border radius based on square or circle variant\n const borderRadius = square\n ? sizeStyles.borderRadiusSquare\n : sizeStyles.borderRadiusCircle;\n\n const countSizeMap = {\n xl: \"xl\",\n lg: \"xl\",\n md: \"lg\",\n sm: \"lg\",\n xs: \"sm\",\n xxs: \"xs\",\n } as const;\n const dotSizeMap = {\n xl: \"md\",\n lg: \"md\",\n md: \"sm\",\n sm: \"sm\",\n xs: \"sm\",\n xxs: \"xs\",\n } as const;\n const hasBadgeContent = !!(badgeCount || badgeIcon);\n const badgeSize = hasBadgeContent ? countSizeMap[size] : dotSizeMap[size];\n // Badge sizes sm/xs are dot-only — content is dropped, so position as a dot.\n const rendersAsDot = badgeSize === \"sm\" || badgeSize === \"xs\";\n\n // Badge offset differs for circle vs square, and for dot vs count\n // Dot badge (8px) needs different offset per avatar size\n const getDotOffset = () => {\n if (square) {\n return size === \"xxs\" ? { right: -1, top: -1 } : { right: -3, top: -3 };\n }\n // Circle - position dot on the edge based on avatar size\n const circleOffsets = {\n xl: { right: 2, top: 2 },\n lg: { right: 2, top: 2 },\n md: { right: 2, top: 2 },\n sm: { right: 2, top: 2 },\n xs: { right: 0, top: 0 },\n xxs: { right: 1, top: 1 },\n };\n return circleOffsets[size];\n };\n\n const badgeOffset =\n hasBadgeContent && !rendersAsDot\n ? square\n ? sizeStyles.badgeOffsetSquare\n : sizeStyles.badgeOffsetCircle\n : getDotOffset();\n\n // Display badge count\n const displayBadgeCount = badgeCount;\n\n return (\n <Box\n width={sizeStyles.size}\n height={sizeStyles.size}\n position=\"relative\"\n {...(!useImage && { role: \"img\", \"aria-label\": ariaLabel })}\n {...(onClick && {\n onPress: onClick,\n onKeyDown: (e: React.KeyboardEvent) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n onClick();\n }\n },\n cursor: \"pointer\",\n role: \"button\",\n tabIndex: 0,\n })}\n >\n <Box\n width={sizeStyles.size}\n height={sizeStyles.size}\n borderRadius={borderRadius}\n backgroundColor={backgroundColor || toneBackground}\n alignItems=\"center\"\n justifyContent=\"center\"\n position=\"relative\"\n overflow=\"hidden\"\n borderWidth={2}\n borderColor={theme.colors.border.secondary}\n {...(!disableHover &&\n !useImage && {\n hoverStyle: {\n backgroundColor: toneHoverBackground,\n },\n })}\n >\n {useImage ? (\n <Box\n as=\"img\"\n src={src}\n alt={alt || ariaLabel || \"\"}\n position=\"absolute\"\n top={0}\n left={0}\n width=\"100%\"\n height=\"100%\"\n borderRadius={borderRadius}\n onError={() => setHasImageError(true)}\n />\n ) : icon ? (\n <Icon size={sizeStyles.iconSize} color={toneContent}>\n {icon}\n </Icon>\n ) : text ? (\n <Text\n fontSize={sizeStyles.fontSize}\n color={toneContent}\n fontWeight=\"400\"\n letterSpacing={0.4}\n >\n {text}\n </Text>\n ) : (\n <User\n variant=\"solid\"\n size={sizeStyles.iconSize}\n color={toneContent}\n />\n )}\n </Box>\n\n {badge && (\n <Box\n position=\"absolute\"\n right={badgeOffset.right}\n top={badgeOffset.top}\n >\n <Badge\n size={badgeSize}\n tone={badgeTone}\n icon={badgeIcon}\n showStroke={size !== \"xxs\"}\n aria-label={\n displayBadgeCount\n ? `${displayBadgeCount} notifications`\n : \"Notification\"\n }\n >\n {displayBadgeCount}\n </Badge>\n </Box>\n )}\n </Box>\n );\n};\n","import React from \"react\";\nimport {\n View,\n Pressable,\n Image,\n ViewStyle,\n ImageStyle,\n DimensionValue,\n AnimatableNumericValue,\n} from \"react-native\";\nimport { BoxProps } from \"@xsolla/xui-primitives-core\";\n\nexport const Box: React.FC<BoxProps> = ({\n children,\n onPress,\n onLayout,\n onMoveShouldSetResponder,\n onResponderGrant,\n onResponderMove,\n onResponderRelease,\n onResponderTerminate,\n backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius,\n borderStyle,\n height,\n padding,\n paddingHorizontal,\n paddingVertical,\n margin,\n marginTop,\n marginBottom,\n marginLeft,\n marginRight,\n flexDirection,\n alignItems,\n justifyContent,\n position,\n top,\n bottom,\n left,\n right,\n width,\n minWidth,\n minHeight,\n maxWidth,\n maxHeight,\n flex,\n overflow,\n zIndex,\n hoverStyle,\n pressStyle,\n style,\n \"data-testid\": dataTestId,\n testID,\n as,\n src,\n alt,\n ...rest\n}) => {\n const getContainerStyle = (pressed?: boolean): ViewStyle => ({\n backgroundColor:\n pressed && pressStyle?.backgroundColor\n ? pressStyle.backgroundColor\n : backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius: borderRadius as AnimatableNumericValue,\n borderStyle: borderStyle as ViewStyle[\"borderStyle\"],\n overflow,\n zIndex,\n height: height as DimensionValue,\n width: width as DimensionValue,\n minWidth: minWidth as DimensionValue,\n minHeight: minHeight as DimensionValue,\n maxWidth: maxWidth as DimensionValue,\n maxHeight: maxHeight as DimensionValue,\n padding: padding as DimensionValue,\n paddingHorizontal: paddingHorizontal as DimensionValue,\n paddingVertical: paddingVertical as DimensionValue,\n margin: margin as DimensionValue,\n marginTop: marginTop as DimensionValue,\n marginBottom: marginBottom as DimensionValue,\n marginLeft: marginLeft as DimensionValue,\n marginRight: marginRight as DimensionValue,\n flexDirection,\n alignItems,\n justifyContent,\n position: position as ViewStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n flex,\n ...(style as ViewStyle),\n });\n\n const finalTestID = dataTestId || testID;\n\n // Destructure and drop web-only props from rest before passing to RN components\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const {\n role,\n tabIndex,\n onKeyDown,\n onKeyUp,\n \"aria-label\": _ariaLabel,\n \"aria-labelledby\": _ariaLabelledBy,\n \"aria-current\": _ariaCurrent,\n \"aria-disabled\": _ariaDisabled,\n \"aria-live\": _ariaLive,\n className,\n \"data-testid\": _dataTestId,\n ...nativeRest\n } = rest as Record<string, unknown>;\n\n // Handle as=\"img\" for React Native\n if (as === \"img\" && src) {\n const imageStyle: ImageStyle = {\n width: width as DimensionValue,\n height: height as DimensionValue,\n borderRadius: borderRadius as number,\n position: position as ImageStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n ...(style as ImageStyle),\n };\n\n return (\n <Image\n source={{ uri: src }}\n style={imageStyle}\n testID={finalTestID}\n resizeMode=\"cover\"\n {...nativeRest}\n />\n );\n }\n\n if (onPress) {\n return (\n <Pressable\n onPress={onPress}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n style={({ pressed }) => getContainerStyle(pressed)}\n testID={finalTestID}\n {...nativeRest}\n >\n {children}\n </Pressable>\n );\n }\n\n return (\n <View\n style={getContainerStyle()}\n testID={finalTestID}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n {...nativeRest}\n >\n {children}\n </View>\n );\n};\n","import React from \"react\";\nimport {\n Text as RNText,\n TextStyle,\n AccessibilityRole,\n StyleSheet,\n} from \"react-native\";\nimport { TextProps } from \"@xsolla/xui-primitives-core\";\n\nconst roleMap: Record<string, AccessibilityRole> = {\n alert: \"alert\",\n heading: \"header\",\n button: \"button\",\n link: \"link\",\n text: \"text\",\n};\n\nconst parseNumericValue = (\n value: string | number | undefined\n): number | undefined => {\n if (value === undefined) return undefined;\n if (typeof value === \"number\") return value;\n const parsed = parseFloat(value);\n return isNaN(parsed) ? undefined : parsed;\n};\n\nexport const Text: React.FC<TextProps> = ({\n children,\n color,\n fontSize,\n fontWeight,\n fontFamily,\n textAlign,\n lineHeight,\n numberOfLines,\n id,\n role,\n style: styleProp,\n ...props\n}) => {\n let resolvedFontFamily = fontFamily\n ? fontFamily.split(\",\")[0].replace(/['\"]/g, \"\").trim()\n : undefined;\n\n if (\n resolvedFontFamily === \"Pilat Wide\" ||\n resolvedFontFamily === \"Pilat Wide Bold\" ||\n resolvedFontFamily === \"Aktiv Grotesk\"\n ) {\n resolvedFontFamily = undefined;\n }\n\n const incomingStyle = StyleSheet.flatten(styleProp) as TextStyle | undefined;\n\n const baseStyle: TextStyle = {\n color: color ?? incomingStyle?.color,\n fontSize: typeof fontSize === \"number\" ? fontSize : undefined,\n fontWeight: fontWeight as TextStyle[\"fontWeight\"],\n fontFamily: resolvedFontFamily,\n textDecorationLine: props.textDecoration as TextStyle[\"textDecorationLine\"],\n textAlign: textAlign ?? incomingStyle?.textAlign,\n lineHeight: parseNumericValue(lineHeight ?? incomingStyle?.lineHeight),\n marginTop: parseNumericValue(\n incomingStyle?.marginTop as number | string | undefined\n ),\n marginBottom: parseNumericValue(\n incomingStyle?.marginBottom as number | string | undefined\n ),\n };\n\n const accessibilityRole = role ? roleMap[role] : undefined;\n\n return (\n <RNText\n style={baseStyle}\n numberOfLines={numberOfLines}\n testID={id}\n accessibilityRole={accessibilityRole}\n >\n {children}\n </RNText>\n );\n};\n","import React from \"react\";\nimport { View, ViewStyle } from \"react-native\";\nimport { IconProps } from \"@xsolla/xui-primitives-core\";\n\nexport const Icon: React.FC<IconProps> = ({ children, color, size }) => {\n const style: ViewStyle = {\n width: typeof size === \"number\" ? size : undefined,\n height: typeof size === \"number\" ? size : undefined,\n alignItems: \"center\",\n justifyContent: \"center\",\n };\n\n // On native, we try to pass the color down to children (like Text primitives)\n // to mimic the CSS inheritance behavior of the web version.\n const childrenWithProps = React.Children.map(children, (child) => {\n if (React.isValidElement(child)) {\n return React.cloneElement(child, {\n color: child.props.color || color,\n // Also pass size if child seems to be an icon that needs it\n size: child.props.size || size,\n });\n }\n return child;\n });\n\n return <View style={style}>{childrenWithProps}</View>;\n};\n","import React from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme, type ThemeOverrideProps } from \"@xsolla/xui-core\";\nimport { Tooltip } from \"@xsolla/xui-tooltip\";\nimport { Avatar, AvatarProps } from \"./Avatar\";\n\n/** Theme type from the design system */\ntype Theme = ReturnType<typeof useResolvedTheme>[\"theme\"];\n\n/** Item in the avatar group list */\nexport interface AvatarGroupItem {\n /** Image source URL */\n src?: string;\n /** Initials to display when no image is provided */\n initials?: string;\n /** Tooltip text to display on hover */\n tooltip?: string;\n /** Whether to show a badge on the avatar */\n badge?: boolean;\n /** Number or text to display in the badge notification */\n badgeCount?: React.ReactNode;\n /** Icon to display in the badge */\n badgeIcon?: React.ReactNode;\n /** Color tone for the badge */\n badgeTone?: AvatarProps[\"badgeTone\"];\n}\n\n/** Avatar background mode - preset colors, 'mixed' for cycling, or a theme function */\nexport type AvatarBackgroundMode =\n | \"mixed\"\n | \"brand\"\n | \"brandExtra\"\n | \"success\"\n | \"warning\"\n | \"alert\"\n | \"neutral\"\n | ((theme: Theme) => string);\n\nexport interface AvatarGroupProps extends ThemeOverrideProps {\n /**\n * List of avatars to display in the group.\n * `tooltip` property is text to be displayed in the tooltip when hovering over the avatar.\n */\n list: AvatarGroupItem[];\n /** Size of the avatars in the group */\n size?: \"xxs\" | \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\n /**\n * Maximum number of slots rendered, including the \"+N\" overflow counter.\n * When the list exceeds this, (maxVisible - 1) avatars are shown plus a \"+N\" indicator.\n * When the list fits, all avatars are shown and no \"+N\" is rendered.\n */\n maxVisible?: number;\n /**\n * Controls the background color mode for avatars in the group.\n * - 'mixed' (default): Avatars cycle through different colors\n * - 'brand', 'brandExtra', 'success', 'warning', 'alert', 'neutral': Single color for all avatars\n * - Theme function: A function that receives theme and returns any color from the design system.\n * Example: (theme) => theme.colors.core.link.link\n */\n avatarBackgroundMode?: AvatarBackgroundMode;\n /** Accessible label for the avatar group. Defaults to \"Group of X users\". */\n \"aria-label\"?: string;\n}\n\nconst DEFAULT_MAX_VISIBLE = 6;\n\nexport const AvatarGroup: React.FC<AvatarGroupProps> = ({\n list,\n size = \"sm\",\n maxVisible = DEFAULT_MAX_VISIBLE,\n avatarBackgroundMode = \"mixed\",\n \"aria-label\": ariaLabel,\n themeMode,\n themeProductContext,\n}) => {\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n\n if (maxVisible < 1) {\n console.warn(\n `[AvatarGroup] \"maxVisible\" must be a positive number. Received ${maxVisible}, falling back to default (${DEFAULT_MAX_VISIBLE}).`\n );\n }\n const effectiveMaxVisible = maxVisible < 1 ? DEFAULT_MAX_VISIBLE : maxVisible;\n\n const totalCount = list.length;\n const overflows = totalCount > effectiveMaxVisible;\n const visibleCount = overflows ? effectiveMaxVisible - 1 : totalCount;\n const visibleListItems = list.slice(0, visibleCount);\n const remainingCount = totalCount - visibleCount;\n\n // Overlap amount: 4px in Figma\n const overlap = -4;\n\n // Background colors for text/icon avatars (cycling through theme colors)\n const mixedBackgrounds = [\n theme.colors.background.alert.secondary,\n theme.colors.background.warning.secondary,\n theme.colors.background.brandExtra.secondary,\n theme.colors.background.neutral.secondary,\n theme.colors.background.brand.secondary,\n theme.colors.background.success.secondary,\n theme.colors.background.success.primary,\n ];\n\n // Preset color mapping\n const presetColors: Record<string, string> = {\n brand: theme.colors.background.brand.secondary,\n brandExtra: theme.colors.background.brandExtra.secondary,\n success: theme.colors.background.success.secondary,\n warning: theme.colors.background.warning.secondary,\n alert: theme.colors.background.alert.secondary,\n neutral: theme.colors.background.neutral.secondary,\n };\n\n // Get background color based on avatarBackgroundMode\n const getBackgroundColor = (index: number): string => {\n if (typeof avatarBackgroundMode === \"function\") {\n return avatarBackgroundMode(theme);\n }\n if (avatarBackgroundMode === \"mixed\") {\n return mixedBackgrounds[index % mixedBackgrounds.length];\n }\n // Preset color mode\n return (\n presetColors[avatarBackgroundMode] || theme.colors.background.secondary\n );\n };\n\n // Default accessible label for the group\n const defaultAriaLabel =\n totalCount === 1\n ? \"1 user\"\n : totalCount === visibleCount\n ? `${totalCount} users`\n : `${visibleCount} of ${totalCount} users`;\n\n // Render an avatar with optional tooltip wrapper\n const renderAvatarWithTooltip = (\n avatar: React.ReactNode,\n tooltip: string | undefined,\n key: number\n ) => {\n if (tooltip) {\n return (\n <Tooltip key={key} content={tooltip} placement=\"top\">\n {avatar}\n </Tooltip>\n );\n }\n return avatar;\n };\n\n return (\n <Box\n flexDirection=\"row\"\n alignItems=\"center\"\n role=\"group\"\n aria-label={ariaLabel || defaultAriaLabel}\n >\n {visibleListItems.map((item, index) => {\n const shouldApplyBackground = !item.src;\n const backgroundColor = shouldApplyBackground\n ? getBackgroundColor(index)\n : undefined;\n\n const avatar = (\n <Box\n key={index}\n marginLeft={index === 0 ? 0 : overlap}\n zIndex={totalCount - index}\n >\n <Avatar\n src={item.src}\n text={item.initials}\n size={size}\n backgroundColor={backgroundColor}\n disableHover={true}\n badge={item.badge}\n badgeCount={item.badgeCount}\n badgeIcon={item.badgeIcon}\n badgeTone={item.badgeTone}\n {...(item.tooltip ? { \"aria-label\": item.tooltip } : {})}\n />\n </Box>\n );\n\n return renderAvatarWithTooltip(avatar, item.tooltip, index);\n })}\n\n {remainingCount > 0 && (\n <Box marginLeft={overlap} zIndex={0}>\n <Avatar\n size={size}\n text={remainingCount > 99 ? \"99+\" : `+${remainingCount}`}\n backgroundColor={theme.colors.background.secondary}\n disableHover={true}\n aria-label={`${remainingCount} more ${remainingCount === 1 ? \"user\" : \"users\"}`}\n />\n </Box>\n )}\n </Box>\n );\n};\n"],"mappings":"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","names":["React","jsx","View","jsx","jsx","React","useResolvedTheme","jsx","jsxs","useResolvedTheme"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xsolla/xui-avatar",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.149.1",
|
|
4
4
|
"main": "./web/index.js",
|
|
5
5
|
"module": "./web/index.mjs",
|
|
6
6
|
"types": "./web/index.d.ts",
|
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
"build:native": "PLATFORM=native tsup"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@xsolla/xui-badge": "0.
|
|
14
|
-
"@xsolla/xui-core": "0.
|
|
15
|
-
"@xsolla/xui-icons-base": "0.
|
|
16
|
-
"@xsolla/xui-primitives-core": "0.
|
|
17
|
-
"@xsolla/xui-tooltip": "0.
|
|
13
|
+
"@xsolla/xui-badge": "0.149.1",
|
|
14
|
+
"@xsolla/xui-core": "0.149.1",
|
|
15
|
+
"@xsolla/xui-icons-base": "0.149.1",
|
|
16
|
+
"@xsolla/xui-primitives-core": "0.149.1",
|
|
17
|
+
"@xsolla/xui-tooltip": "0.149.1"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
20
|
"react": ">=16.8.0",
|
package/web/index.d.mts
CHANGED
|
@@ -12,13 +12,19 @@ interface AvatarProps extends ThemeOverrideProps {
|
|
|
12
12
|
size?: "xl" | "lg" | "md" | "sm" | "xs" | "xxs";
|
|
13
13
|
/** If true, the avatar will be square with small border radius. If false, it will be a circle. */
|
|
14
14
|
square?: boolean;
|
|
15
|
+
/** Visual tone — 'mono' (default) or 'brand'. */
|
|
16
|
+
tone?: "mono" | "brand";
|
|
15
17
|
/** Whether to show an alert badge */
|
|
16
18
|
badge?: boolean;
|
|
17
19
|
/** Number or text to display in the badge notification */
|
|
18
20
|
badgeCount?: React.ReactNode;
|
|
19
|
-
/**
|
|
20
|
-
|
|
21
|
-
/**
|
|
21
|
+
/** Icon to display in the badge */
|
|
22
|
+
badgeIcon?: React.ReactNode;
|
|
23
|
+
/**
|
|
24
|
+
* Background colour override. Intended for internal use by AvatarGroup to
|
|
25
|
+
* drive its `avatarBackgroundMode` cycling; not part of the public API.
|
|
26
|
+
* @internal
|
|
27
|
+
*/
|
|
22
28
|
backgroundColor?: string;
|
|
23
29
|
/** Disable hover effect. Used internally by AvatarGroup. */
|
|
24
30
|
disableHover?: boolean;
|
|
@@ -41,10 +47,16 @@ interface AvatarGroupItem {
|
|
|
41
47
|
src?: string;
|
|
42
48
|
/** Initials to display when no image is provided */
|
|
43
49
|
initials?: string;
|
|
44
|
-
/** Click handler for the avatar */
|
|
45
|
-
onClick?: () => void;
|
|
46
50
|
/** Tooltip text to display on hover */
|
|
47
51
|
tooltip?: string;
|
|
52
|
+
/** Whether to show a badge on the avatar */
|
|
53
|
+
badge?: boolean;
|
|
54
|
+
/** Number or text to display in the badge notification */
|
|
55
|
+
badgeCount?: React.ReactNode;
|
|
56
|
+
/** Icon to display in the badge */
|
|
57
|
+
badgeIcon?: React.ReactNode;
|
|
58
|
+
/** Color tone for the badge */
|
|
59
|
+
badgeTone?: AvatarProps["badgeTone"];
|
|
48
60
|
}
|
|
49
61
|
/** Avatar background mode - preset colors, 'mixed' for cycling, or a theme function */
|
|
50
62
|
type AvatarBackgroundMode = "mixed" | "brand" | "brandExtra" | "success" | "warning" | "alert" | "neutral" | ((theme: Theme) => string);
|
|
@@ -55,14 +67,13 @@ interface AvatarGroupProps extends ThemeOverrideProps {
|
|
|
55
67
|
*/
|
|
56
68
|
list: AvatarGroupItem[];
|
|
57
69
|
/** Size of the avatars in the group */
|
|
58
|
-
size?: "sm" | "md" | "lg" | "xl";
|
|
70
|
+
size?: "xxs" | "xs" | "sm" | "md" | "lg" | "xl";
|
|
59
71
|
/**
|
|
60
|
-
*
|
|
61
|
-
*
|
|
72
|
+
* Maximum number of slots rendered, including the "+N" overflow counter.
|
|
73
|
+
* When the list exceeds this, (maxVisible - 1) avatars are shown plus a "+N" indicator.
|
|
74
|
+
* When the list fits, all avatars are shown and no "+N" is rendered.
|
|
62
75
|
*/
|
|
63
76
|
maxVisible?: number;
|
|
64
|
-
/** Whether to show a stroke/border around each avatar */
|
|
65
|
-
stroke?: boolean;
|
|
66
77
|
/**
|
|
67
78
|
* Controls the background color mode for avatars in the group.
|
|
68
79
|
* - 'mixed' (default): Avatars cycle through different colors
|
package/web/index.d.ts
CHANGED
|
@@ -12,13 +12,19 @@ interface AvatarProps extends ThemeOverrideProps {
|
|
|
12
12
|
size?: "xl" | "lg" | "md" | "sm" | "xs" | "xxs";
|
|
13
13
|
/** If true, the avatar will be square with small border radius. If false, it will be a circle. */
|
|
14
14
|
square?: boolean;
|
|
15
|
+
/** Visual tone — 'mono' (default) or 'brand'. */
|
|
16
|
+
tone?: "mono" | "brand";
|
|
15
17
|
/** Whether to show an alert badge */
|
|
16
18
|
badge?: boolean;
|
|
17
19
|
/** Number or text to display in the badge notification */
|
|
18
20
|
badgeCount?: React.ReactNode;
|
|
19
|
-
/**
|
|
20
|
-
|
|
21
|
-
/**
|
|
21
|
+
/** Icon to display in the badge */
|
|
22
|
+
badgeIcon?: React.ReactNode;
|
|
23
|
+
/**
|
|
24
|
+
* Background colour override. Intended for internal use by AvatarGroup to
|
|
25
|
+
* drive its `avatarBackgroundMode` cycling; not part of the public API.
|
|
26
|
+
* @internal
|
|
27
|
+
*/
|
|
22
28
|
backgroundColor?: string;
|
|
23
29
|
/** Disable hover effect. Used internally by AvatarGroup. */
|
|
24
30
|
disableHover?: boolean;
|
|
@@ -41,10 +47,16 @@ interface AvatarGroupItem {
|
|
|
41
47
|
src?: string;
|
|
42
48
|
/** Initials to display when no image is provided */
|
|
43
49
|
initials?: string;
|
|
44
|
-
/** Click handler for the avatar */
|
|
45
|
-
onClick?: () => void;
|
|
46
50
|
/** Tooltip text to display on hover */
|
|
47
51
|
tooltip?: string;
|
|
52
|
+
/** Whether to show a badge on the avatar */
|
|
53
|
+
badge?: boolean;
|
|
54
|
+
/** Number or text to display in the badge notification */
|
|
55
|
+
badgeCount?: React.ReactNode;
|
|
56
|
+
/** Icon to display in the badge */
|
|
57
|
+
badgeIcon?: React.ReactNode;
|
|
58
|
+
/** Color tone for the badge */
|
|
59
|
+
badgeTone?: AvatarProps["badgeTone"];
|
|
48
60
|
}
|
|
49
61
|
/** Avatar background mode - preset colors, 'mixed' for cycling, or a theme function */
|
|
50
62
|
type AvatarBackgroundMode = "mixed" | "brand" | "brandExtra" | "success" | "warning" | "alert" | "neutral" | ((theme: Theme) => string);
|
|
@@ -55,14 +67,13 @@ interface AvatarGroupProps extends ThemeOverrideProps {
|
|
|
55
67
|
*/
|
|
56
68
|
list: AvatarGroupItem[];
|
|
57
69
|
/** Size of the avatars in the group */
|
|
58
|
-
size?: "sm" | "md" | "lg" | "xl";
|
|
70
|
+
size?: "xxs" | "xs" | "sm" | "md" | "lg" | "xl";
|
|
59
71
|
/**
|
|
60
|
-
*
|
|
61
|
-
*
|
|
72
|
+
* Maximum number of slots rendered, including the "+N" overflow counter.
|
|
73
|
+
* When the list exceeds this, (maxVisible - 1) avatars are shown plus a "+N" indicator.
|
|
74
|
+
* When the list fits, all avatars are shown and no "+N" is rendered.
|
|
62
75
|
*/
|
|
63
76
|
maxVisible?: number;
|
|
64
|
-
/** Whether to show a stroke/border around each avatar */
|
|
65
|
-
stroke?: boolean;
|
|
66
77
|
/**
|
|
67
78
|
* Controls the background color mode for avatars in the group.
|
|
68
79
|
* - 'mixed' (default): Avatars cycle through different colors
|