Skip to content

Commit

Permalink
Merge pull request #3 from TDesignOteam/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
yatessss authored Feb 5, 2024
2 parents 046bddd + 9b4fb8c commit 225ce96
Show file tree
Hide file tree
Showing 19 changed files with 737 additions and 12 deletions.
2 changes: 1 addition & 1 deletion example/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ function ExampleList() {
return (
<ListItem
key={childIndex}
hideBorder={index === endIndex}
hideBorder={childIndex === endIndex}
label={child.title}
onPressItem={() => {
navigation.navigate(child.key as never);
Expand Down
2 changes: 1 addition & 1 deletion example/src/components/Element.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ export const H5 = (props: PropsWithChildren<any>) => {

export const P = (props: PropsWithChildren<any>) => {
const { children } = props;
return <Text>{children}</Text>;
return <Text className="mt4">{children}</Text>;
};
8 changes: 8 additions & 0 deletions example/src/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
{
"title": "数据展示",
"children": [
{
"title": "Avatar 头像",
"key": "Avatar"
},
{
"title": "Badge 徽标",
"key": "Badge"
Expand All @@ -47,6 +51,10 @@
"title": "Highlight 高亮",
"key": "Highlight"
},
{
"title": "Image 图片",
"key": "Image"
},
{
"title": "Tag 标签",
"key": "Tag"
Expand Down
2 changes: 1 addition & 1 deletion site/plugin-tdoc/md-to-react.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export default function mdToReact(options) {
<div style={isShow('demo')} name="DEMO">
${mdSegment.demoMd.replace(/class=/g, 'className=')}
<td-doc-phone ref={tdDocPhone}>
<td-doc-phone ref={tdDocPhone} style={{position: 'relative', zIndex: 999}}>
<iframe src="${
mdSegment.mobileUrl
}" frameBorder="0" width="100%" height="100%" style={{ borderRadius: '0 0 6px 6px' }}></iframe>
Expand Down
7 changes: 7 additions & 0 deletions src/components/Avatar/Avatar.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
:: BASE_DOC ::

## API
### Base Props

临时md,后期会自动生成

87 changes: 87 additions & 0 deletions src/components/Avatar/Avatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React, { useMemo } from 'react';
import { View, StyleSheet } from 'react-native';
import { isString } from 'lodash';
import { Text } from '../Base';
import { Image } from '../Image';
import { useTheme, ThemeType } from '../../theme';
import type { AvatarProps } from './types';
import { SizeEnum, ShapeEnum } from '../common';

export const AVATAR_SIZE_MAP = {
small: 32,
normal: 48,
large: 64,
};

export const AVATAR_ICON_SIZE_MAP = {
small: 16,
normal: 24,
large: 32,
};

const createStyles = (theme: ThemeType, size: SizeEnum, shape: ShapeEnum) => {
const height = AVATAR_SIZE_MAP[size];
const width = AVATAR_SIZE_MAP[size];
const textSize = AVATAR_ICON_SIZE_MAP[size];
const radius = {
circle: theme.spacers.spacer999,
round: theme.spacers.spacer4,
square: theme.spacers.spacer0,
};

return StyleSheet.create({
avatar: {
height,
width,
borderRadius: radius[shape],
overflow: 'hidden',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: theme.colors.brand2,
fontSize: textSize,
color: theme.colors.brand7,
},
image: {
width: '100%',
height: '100%',
},
});
};

export const Avatar: React.FunctionComponent<AvatarProps> = (props) => {
const { shape = 'circle', url, size = 'normal', style, icon, onError, onLoad, children } = props;
const { theme } = useTheme();
const styles = createStyles(theme, size, shape);

const avatarElement = useMemo(() => {
if (url) {
return (
<Image
source={{ uri: url }}
style={styles.image}
backgroundColor={theme.colors.brand2}
onError={(e) => onError?.(e)}
onLoad={(e) => onLoad?.(e)}
/>
);
}

if (React.isValidElement(icon)) {
return icon;
}

if (isString(children)) {
return <Text style={[styles.avatar, style]}>{children}</Text>;
}

return children;
}, [children, icon, onError, onLoad, style, styles.avatar, styles.image, theme.colors.brand2, url]);

return <View style={[styles.avatar, style]}>{avatarElement}</View>;
};

Avatar.defaultProps = {
shape: 'circle',
size: 'normal',
};
97 changes: 97 additions & 0 deletions src/components/Avatar/AvatarGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import React, { Children, cloneElement, ReactNode, useMemo } from 'react';
import { View, StyleSheet } from 'react-native';
import { Text } from '../Base';
import { useTheme, ThemeType } from '../../theme';
import { AVATAR_SIZE_MAP, AVATAR_ICON_SIZE_MAP } from './Avatar';
import type { AvatarGroupProps } from './types';
import { SizeEnum } from '../common';

const createStyles = (theme: ThemeType, size: SizeEnum) => {
const height = AVATAR_SIZE_MAP[size];
const width = AVATAR_SIZE_MAP[size];
const textSize = AVATAR_ICON_SIZE_MAP[size];
return StyleSheet.create({
group: {
display: 'flex',
flexDirection: 'row',
},
offsetRight: {
marginRight: -(theme.spacers.spacer10 ?? 10),
borderColor: theme.colors.white,
borderWidth: theme.spacers.spacer2,
},
numberWrap: {
height,
width,
borderRadius: 999,
overflow: 'hidden',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: theme.colors.brand2,
fontSize: textSize,
marginRight: -(theme.spacers.spacer10 ?? 10),
borderColor: theme.colors.white,
borderWidth: theme.spacers.spacer2,
},
numberText: {
color: theme.colors.brand7,
},
});
};

export const AvatarGroup: React.FunctionComponent<AvatarGroupProps> = (props) => {
const { style, children, size = 'normal', max, collapseAvatar, cascading } = props;
const { theme } = useTheme();
const styles = createStyles(theme, size);
const childrens = Children.toArray(children);

const childrenList = useMemo(() => {
const result: ReactNode[] = [];
childrens?.forEach((child, index) => {
if (React.isValidElement(child)) {
const cloneChild = cloneElement(child, {
...child.props,
style: [
styles.offsetRight,
child?.props?.style || {},
{ zIndex: cascading === 'left-up' ? childrens.length - index : 0 },
],
size,
});
if (max) {
if (index < max) {
result.push(cloneChild);
}
} else {
result.push(cloneChild);
}
}
});
return result;
}, [cascading, childrens, max, size, styles.offsetRight]);

const hiddenNumber = useMemo(() => {
if (max && childrens.length > max) {
return childrens.length - max;
}
return false;
}, [childrens, max]);

const collapseElement = (
<View style={styles.numberWrap}>
{collapseAvatar ? collapseAvatar : <Text style={styles.numberText}>{`+${hiddenNumber}`}</Text>}
</View>
);

return (
<View style={[styles.group, style]}>
{childrenList}
{hiddenNumber ? collapseElement : null}
</View>
);
};

AvatarGroup.defaultProps = {
cascading: 'right-up',
};
127 changes: 127 additions & 0 deletions src/components/Avatar/_example/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/**
* title: Avatar 头像
* description: 用图标、图片、字符的形式展示用户或事物信息
* spline: base
* isComponent: true
* toc: false
*/
import { View, Avatar, AvatarGroup, Touchable, Badge } from 'tdesign-react-native/components';
import { UserIcon, UserAddIcon } from 'tdesign-icons-react-native/src';
import { Section, CodeSpace, H3, P } from '@src/../example/src/components';
import { useState } from 'react';

const TypeDemo1 = () => {
const [list, setList] = useState([1, 2, 3, 4, 5, 6]);
const handleAdd = () => {
const test = [list.length + 1, ...list];
setList(test);
};
return (
<AvatarGroup
max={5}
collapseAvatar={
<Touchable onPress={handleAdd}>
<UserAddIcon />
</Touchable>
}
>
{list.map((item, i) => (
<Avatar size="large" key={i}>
{item}
</Avatar>
))}
</AvatarGroup>
);
};

const Demo = () => {
return (
<>
<Section>
<P>用于展示用户头像信息,除了纯展示也可点击进入个人详情等操作。</P>
<H3>1.类型</H3>
<P>图片头像</P>
<CodeSpace>
<View className="flexRow gapX10">
<Avatar url={'https://tdesign.gtimg.com/mobile/demos/avatar1.png'} />
<Avatar shape="round" url={'https://tdesign.gtimg.com/mobile/demos/avatar1.png'} />
<Avatar shape="square" url={'https://tdesign.gtimg.com/mobile/demos/avatar1.png'} />
</View>
</CodeSpace>
<P>图标头像</P>
<CodeSpace>
<View className="flexRow gapX10">
<Avatar icon={<UserIcon />} />
<Avatar shape="round" icon={<UserIcon />} />
<Avatar shape="square" icon={<UserIcon />} />
</View>
</CodeSpace>
<P>字符头像</P>
<CodeSpace>
<View className="flexRow gapX10">
<Avatar>A</Avatar>
<Avatar shape="round">A</Avatar>
<Avatar shape="square">A</Avatar>
</View>
</CodeSpace>
</Section>
<Section>
<H3>2.组件样式</H3>
<P>向上堆叠</P>
<CodeSpace>
<AvatarGroup max={5}>
<Avatar url={'https://tdesign.gtimg.com/mobile/demos/avatar1.png'} />
<Avatar url={'https://tdesign.gtimg.com/mobile/demos/avatar1.png'} />
<Avatar url={'https://tdesign.gtimg.com/mobile/demos/avatar1.png'} />
<Avatar url={'https://tdesign.gtimg.com/mobile/demos/avatar1.png'} />
<Avatar url={'https://tdesign.gtimg.com/mobile/demos/avatar1.png'} />
<Avatar url={'https://tdesign.gtimg.com/mobile/demos/avatar1.png'} />
<Avatar url={'https://tdesign.gtimg.com/mobile/demos/avatar1.png'} />
</AvatarGroup>
</CodeSpace>
<P>向下堆叠</P>
<CodeSpace>
<AvatarGroup cascading={'left-up'} max={5}>
<Avatar url={'https://tdesign.gtimg.com/mobile/demos/avatar1.png'} />
<Avatar url={'https://tdesign.gtimg.com/mobile/demos/avatar1.png'} />
<Avatar url={'https://tdesign.gtimg.com/mobile/demos/avatar1.png'} />
<Avatar url={'https://tdesign.gtimg.com/mobile/demos/avatar1.png'} />
<Avatar url={'https://tdesign.gtimg.com/mobile/demos/avatar1.png'} />
<Avatar url={'https://tdesign.gtimg.com/mobile/demos/avatar1.png'} />
<Avatar url={'https://tdesign.gtimg.com/mobile/demos/avatar1.png'} />
</AvatarGroup>
</CodeSpace>
<P>带操作</P>
<CodeSpace>
<TypeDemo1 />
</CodeSpace>
<P>徽标头像</P>
<CodeSpace>
<View className="flexRow gapX10">
<Badge dot offset={[2, 2]}>
<Avatar url={'https://tdesign.gtimg.com/mobile/demos/avatar1.png'} />
</Badge>
<Badge count={5} offset={[-2, -2]}>
<Avatar url={'https://tdesign.gtimg.com/mobile/demos/avatar1.png'} />
</Badge>
<Badge count={'DL'} offset={[30, -5]} color={'#307AF2'} shape="round">
<Avatar url={'https://tdesign.gtimg.com/mobile/demos/avatar1.png'} />
</Badge>
</View>
</CodeSpace>
</Section>
<Section>
<H3>3.组件尺寸</H3>
<CodeSpace>
<View className="flexRow flexCenterV gapX10">
<Avatar size={'small'} url={'https://tdesign.gtimg.com/mobile/demos/avatar1.png'} />
<Avatar url={'https://tdesign.gtimg.com/mobile/demos/avatar1.png'} />
<Avatar size={'large'} url={'https://tdesign.gtimg.com/mobile/demos/avatar1.png'} />
</View>
</CodeSpace>
</Section>
</>
);
};

export default Demo;
3 changes: 3 additions & 0 deletions src/components/Avatar/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { Avatar } from './Avatar';
export { AvatarGroup } from './AvatarGroup';
export type { AvatarGroupProps, AvatarProps } from './types';
Loading

0 comments on commit 225ce96

Please sign in to comment.