Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 42 additions & 1 deletion docs/6.x/docs/components/Avatar/AvatarImage.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,36 @@ import * as React from 'react';
import { Avatar } from 'react-native-paper';

const MyComponent = () => (
<Avatar.Image size={24} source={require('../assets/avatar.png')} />
<Avatar.Image size={24} source={require('../assets/avatar.png')} alt="Jane Doe" />
);
export default MyComponent
```

Pass `alt` to describe the image to assistive technology. Avatars without it
are treated as decorative and skipped by screen readers.

Show another avatar when the image fails to load:
```js
<Avatar.Image
size={64}
source={{ uri: user.avatarUrl }}
alt="Jane Doe"
fallback={({ size }) => <Avatar.Text size={size} label="JD" />}
/>
```

Custom image components should apply the host `style`, `onError` and `alt`:
```js
<Avatar.Image
size={64}
alt="Jane Doe"
source={({ style, onError, alt }) => (
<CustomImage source={{ uri }} style={style} onError={onError} alt={alt} />
)}
fallback={({ size }) => <Avatar.Text size={size} label="JD" />}
/>
```


## Props
<span />
Expand All @@ -51,6 +76,22 @@ export default MyComponent

<div>

### alt

</div>

<PropTable componentLink="Avatar/AvatarImage" prop="alt" />

<div>

### fallback

</div>

<PropTable componentLink="Avatar/AvatarImage" prop="fallback" />

<div>

### style

</div>
Expand Down
71 changes: 57 additions & 14 deletions docs/src/data/componentDocs6x.json
Original file line number Diff line number Diff line change
Expand Up @@ -751,16 +751,16 @@
},
"description": "Size of the avatar.",
"defaultValue": {
"value": "64",
"computed": false
"value": "DEFAULT_SIZE",
"computed": true
}
},
"color": {
"required": false,
"tsType": {
"name": "string"
},
"description": "Custom color for the icon."
"description": "Custom color for the icon. Takes precedence over the automatic contrast\ncolor below."
},
"style": {
"required": false,
Expand All @@ -773,7 +773,7 @@
],
"raw": "StyleProp<ViewStyle>"
},
"description": ""
"description": "Style for the icon container. A custom `backgroundColor` is\nautomatically paired with a contrasting icon color when `color` is not\nset: string values use a luminance heuristic, while opaque/dynamic\nvalues (`PlatformColor` / `DynamicColorIOS`) are paired with a theme\nrole's `on-` color, falling back to `onSurface`."
},
"theme": {
"required": false,
Expand All @@ -793,10 +793,10 @@
"Avatar/AvatarImage": {
"filepath": "Avatar/AvatarImage.tsx",
"title": "Avatar.Image",
"description": "Avatars can be used to represent people in a graphical way.\n\n## Usage\n```js\nimport * as React from 'react';\nimport { Avatar } from 'react-native-paper';\n\nconst MyComponent = () => (\n <Avatar.Image size={24} source={require('../assets/avatar.png')} />\n);\nexport default MyComponent\n```",
"description": "Avatars can be used to represent people in a graphical way.\n\n## Usage\n```js\nimport * as React from 'react';\nimport { Avatar } from 'react-native-paper';\n\nconst MyComponent = () => (\n <Avatar.Image size={24} source={require('../assets/avatar.png')} alt=\"Jane Doe\" />\n);\nexport default MyComponent\n```\n\nPass `alt` to describe the image to assistive technology. Avatars without it\nare treated as decorative and skipped by screen readers.\n\nShow another avatar when the image fails to load:\n```js\n<Avatar.Image\n size={64}\n source={{ uri: user.avatarUrl }}\n alt=\"Jane Doe\"\n fallback={({ size }) => <Avatar.Text size={size} label=\"JD\" />}\n/>\n```\n\nCustom image components should apply the host `style`, `onError` and `alt`:\n```js\n<Avatar.Image\n size={64}\n alt=\"Jane Doe\"\n source={({ style, onError, alt }) => (\n <CustomImage source={{ uri }} style={style} onError={onError} alt={alt} />\n )}\n fallback={({ size }) => <Avatar.Text size={size} label=\"JD\" />}\n/>\n```",
"link": "avatar-image",
"data": {
"description": "Avatars can be used to represent people in a graphical way.\n\n## Usage\n```js\nimport * as React from 'react';\nimport { Avatar } from 'react-native-paper';\n\nconst MyComponent = () => (\n <Avatar.Image size={24} source={require('../assets/avatar.png')} />\n);\nexport default MyComponent\n```",
"description": "Avatars can be used to represent people in a graphical way.\n\n## Usage\n```js\nimport * as React from 'react';\nimport { Avatar } from 'react-native-paper';\n\nconst MyComponent = () => (\n <Avatar.Image size={24} source={require('../assets/avatar.png')} alt=\"Jane Doe\" />\n);\nexport default MyComponent\n```\n\nPass `alt` to describe the image to assistive technology. Avatars without it\nare treated as decorative and skipped by screen readers.\n\nShow another avatar when the image fails to load:\n```js\n<Avatar.Image\n size={64}\n source={{ uri: user.avatarUrl }}\n alt=\"Jane Doe\"\n fallback={({ size }) => <Avatar.Text size={size} label=\"JD\" />}\n/>\n```\n\nCustom image components should apply the host `style`, `onError` and `alt`:\n```js\n<Avatar.Image\n size={64}\n alt=\"Jane Doe\"\n source={({ style, onError, alt }) => (\n <CustomImage source={{ uri }} style={style} onError={onError} alt={alt} />\n )}\n fallback={({ size }) => <Avatar.Text size={size} label=\"JD\" />}\n/>\n```",
"displayName": "Avatar.Image",
"methods": [],
"statics": [],
Expand All @@ -805,7 +805,7 @@
"required": true,
"tsType": {
"name": "union",
"raw": "| ImageSourcePropType\n| ((props: { size: number }) => React.ReactNode)",
"raw": "| ImageSourcePropType\n| ((props: AvatarImageSourceProps) => React.ReactNode)",
"elements": [
{
"name": "ImageSourcePropType"
Expand All @@ -815,7 +815,7 @@
}
]
},
"description": "Image to display for the `Avatar`.\nIt accepts a standard React Native Image `source` prop\nOr a function that returns an `Image`."
"description": "Image to display for the `Avatar`.\nIt accepts a standard React Native Image `source` prop\nor a function that returns an image component.\nFunction sources receive `{ size, style, onError, alt }` matching the host avatar.\nApply `style` so the image fills the circle, pass `alt` on for assistive\ntechnology, and call `onError` to trigger `fallback`."
},
"size": {
"required": false,
Expand All @@ -824,10 +824,53 @@
},
"description": "Size of the avatar.",
"defaultValue": {
"value": "64",
"computed": false
"value": "DEFAULT_SIZE",
"computed": true
}
},
"alt": {
"required": false,
"tsType": {
"name": "string"
},
"description": "Text describing the image for assistive technology."
},
"fallback": {
"required": false,
"tsType": {
"name": "signature",
"type": "function",
"raw": "(props: { size: number }) => React.ReactNode",
"signature": {
"arguments": [
{
"name": "props",
"type": {
"name": "signature",
"type": "object",
"raw": "{ size: number }",
"signature": {
"properties": [
{
"key": "size",
"value": {
"name": "number",
"required": true
}
}
]
}
}
}
],
"return": {
"name": "ReactReactNode",
"raw": "React.ReactNode"
}
}
},
"description": "Content shown when the image fails to load.\nReceives host `size` so custom content can match the avatar."
},
"style": {
"required": false,
"tsType": {
Expand Down Expand Up @@ -929,16 +972,16 @@
},
"description": "Size of the avatar.",
"defaultValue": {
"value": "64",
"computed": false
"value": "DEFAULT_SIZE",
"computed": true
}
},
"color": {
"required": false,
"tsType": {
"name": "string"
},
"description": "Custom color for the text."
"description": "Custom color for the text. Takes precedence over the automatic contrast\ncolor below."
},
"style": {
"required": false,
Expand All @@ -951,7 +994,7 @@
],
"raw": "StyleProp<ViewStyle>"
},
"description": "Style for text container"
"description": "Style for text container. A custom `backgroundColor` is automatically\npaired with a contrasting text color when `color` is not set: string\nvalues use a luminance heuristic, while opaque/dynamic values\n(`PlatformColor` / `DynamicColorIOS`) are paired with a theme role's\n`on-` color, falling back to `onSurface`."
},
"labelStyle": {
"required": false,
Expand Down
39 changes: 25 additions & 14 deletions src/components/Avatar/AvatarIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { StyleSheet, View } from 'react-native';
import type { StyleProp, ViewProps, ViewStyle } from 'react-native';

import { DEFAULT_SIZE, ICON_SIZE_RATIO, resolveAvatarColors } from './utils';
import { useInternalTheme } from '../../core/theming';
import { white } from '../../theme/colors';
import { cornerFull } from '../../theme/tokens/sys/shape';
import type { ThemeProp } from '../../types';
import getContrastingColor from '../../utils/getContrastingColor';
import Icon from '../Icon';
import type { IconSource } from '../Icon';

const defaultSize = 64;

export type Props = ViewProps & {
/**
* Icon to display for the `Avatar`.
Expand All @@ -20,9 +18,17 @@ export type Props = ViewProps & {
*/
size?: number;
/**
* Custom color for the icon.
* Custom color for the icon. Takes precedence over the automatic contrast
* color below.
*/
color?: string;
/**
* Style for the icon container. A custom `backgroundColor` is
* automatically paired with a contrasting icon color when `color` is not
* set: string values use a luminance heuristic, while opaque/dynamic
* values (`PlatformColor` / `DynamicColorIOS`) are paired with a theme
* role's `on-` color, falling back to `onSurface`.
*/
style?: StyleProp<ViewStyle>;
/**
* @optional
Expand All @@ -45,33 +51,38 @@ export type Props = ViewProps & {
*/
const Avatar = ({
icon,
size = defaultSize,
size = DEFAULT_SIZE,
style,
theme: themeOverrides,
color: customColor,
...rest
}: Props) => {
const theme = useInternalTheme(themeOverrides);
const { backgroundColor = theme.colors?.primary, ...restStyle } =
StyleSheet.flatten(style) || {};
const textColor =
rest.color ??
getContrastingColor(backgroundColor, white, 'rgba(0, 0, 0, .54)');
const { backgroundColor, ...restStyle } = StyleSheet.flatten(style) || {};
const { background, textColor } = resolveAvatarColors({
theme,
backgroundColor,
color: customColor,
});
const hasLabel =
rest.accessibilityLabel !== undefined || rest['aria-label'] !== undefined;

return (
<View
style={[
{
width: size,
height: size,
borderRadius: size / 2,
backgroundColor,
borderRadius: cornerFull,
backgroundColor: background,
},
styles.container,
restStyle,
]}
{...(hasLabel && { accessible: true })}
{...rest}
>
<Icon source={icon} color={textColor} size={size * 0.6} />
<Icon source={icon} color={textColor} size={size * ICON_SIZE_RATIO} />
</View>
);
};
Expand Down
Loading