Skip to content

Commit

Permalink
feat(ui): add avatar component
Browse files Browse the repository at this point in the history
  • Loading branch information
xiejay97 committed Jul 19, 2022
1 parent 53f934d commit da42400
Show file tree
Hide file tree
Showing 17 changed files with 292 additions and 3 deletions.
9 changes: 7 additions & 2 deletions packages/site/src/app/styles/_app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@ body {
font-family: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', 'Liberation Sans', sans-serif,
'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
font-weight: 400;
line-height: 1.5;
color: var(--d-text-color);
text-align: null;
/* stylelint-disable-next-line declaration-property-value-allowed-list */
background-color: #fff;
text-size-adjust: 100%;
Expand Down Expand Up @@ -287,6 +285,13 @@ h3 {
margin-bottom: 12px;
}
}

section[id^='Avatar'] {
.d-avatar {
margin-right: 24px;
margin-bottom: 12px;
}
}
}

.app-demo-col {
Expand Down
Binary file added packages/site/src/assets/avatar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
80 changes: 80 additions & 0 deletions packages/ui/src/components/avatar/Avatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React, { useEffect, useRef, useState } from 'react';

import { usePrefixConfig, useComponentConfig } from '../../hooks';
import { registerComponentMate, getClassName } from '../../utils';

export interface DAvatarProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {
dShape?: string | number;
dImg?: React.ImgHTMLAttributes<HTMLImageElement>;
dIcon?: React.ReactNode;
dText?: React.ReactNode;
dSize?: number;
}

const { COMPONENT_NAME } = registerComponentMate({ COMPONENT_NAME: 'DAvatar' });
export function DAvatar(props: DAvatarProps): JSX.Element | null {
const {
dShape = 'circular',
dImg,
dIcon,
dText,
dSize = 40,

className,
style,
...restProps
} = useComponentConfig(COMPONENT_NAME, props);

//#region Context
const dPrefix = usePrefixConfig();
//#endregion

//#region Ref
const textRef = useRef<HTMLSpanElement>(null);
//#endregion

const [imgError, setImgError] = useState(false);
const type: 'img' | 'icon' | 'text' = dImg && !imgError ? 'img' : dIcon ? 'icon' : dText ? 'text' : 'img';

useEffect(() => {
if (textRef.current) {
const maxWidth = Math.sqrt(Math.pow(dSize / 2, 2) - Math.pow(textRef.current.clientHeight / 2, 2)) * 2;
if (textRef.current.clientWidth > maxWidth) {
textRef.current.style.cssText = `transform:scale(${maxWidth / textRef.current.clientWidth});`;
}
}
});

return (
<div
{...restProps}
className={getClassName(className, `${dPrefix}avatar`, `${dPrefix}avatar--${type}`, {
[`${dPrefix}avatar--${dShape}`]: dShape === 'circular' || dShape === 'square',
})}
style={{
...style,
width: dSize,
height: dSize,
fontSize: type === 'icon' ? dSize / 2 : type === 'text' ? dSize * 0.45 : undefined,
borderRadius: dShape === 'circular' || dShape === 'square' ? undefined : dShape,
}}
>
{type === 'img' ? (
// eslint-disable-next-line jsx-a11y/alt-text
<img
{...dImg}
className={getClassName(dImg?.className, `${dPrefix}avatar__img`)}
onError={(e) => {
dImg?.onError?.(e);

setImgError(true);
}}
/>
) : type === 'icon' ? (
dIcon
) : (
<span ref={textRef}>{dText}</span>
)}
</div>
);
}
21 changes: 21 additions & 0 deletions packages/ui/src/components/avatar/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
group: Data Display
title: Avatar
---

## API

### DTagProps

Extend `React.HTMLAttributes<HTMLDivElement>`.

<!-- prettier-ignore-start -->
| Property | Description | Type | Default |
| --- | --- | --- | --- |
| dType | Set tag type | 'primary' \| 'fill' \| 'outline' | 'primary' |
| dTheme | Set tag theme | 'primary' \| 'success' \| 'warning' \| 'danger' | - |
| dColor | Custom tag color | string | - |
| dSize | Set tag size | 'smaller' \| 'larger' | - |
| dClosable | Whether the tag can be closed | boolean | false |
| onClose | Callback when the close button is clicked | React.MouseEventHandler\<HTMLSpanElement\> | - |
<!-- prettier-ignore-end -->
20 changes: 20 additions & 0 deletions packages/ui/src/components/avatar/README.zh-Hant.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
title: 头像
---

## API

### DTagProps

继承 `React.HTMLAttributes<HTMLDivElement>`

<!-- prettier-ignore-start -->
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| dType | 设置标签形态 | 'primary' \| 'fill' \| 'outline' | 'primary' |
| dTheme | 设置标签主题 | 'primary' \| 'success' \| 'warning' \| 'danger' | - |
| dColor | 自定义标签颜色 | string | - |
| dSize | 设置标签尺寸 | 'smaller' \| 'larger' | - |
| dClosable | 标签是否可关闭 | boolean | false |
| onClose | 点击关闭按钮的回调 | React.MouseEventHandler\<HTMLSpanElement\> | - |
<!-- prettier-ignore-end -->
28 changes: 28 additions & 0 deletions packages/ui/src/components/avatar/demos/1.Basic.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
title:
en-US: Basic
zh-Hant: 基本
---

# en-US

The simplest usage.

# zh-Hant

最简单的用法。

```tsx
import { DAvatar, DBadge } from '@react-devui/ui';
import { UserOutlined } from '@react-devui/ui/icons';

export default function Demo() {
return (
<>
<DAvatar dImg={{ src: '/assets/avatar.png', alt: 'avatar' }}></DAvatar>
<DAvatar dIcon={<UserOutlined />}></DAvatar>
<DAvatar dText="U"></DAvatar>
</>
);
}
```
26 changes: 26 additions & 0 deletions packages/ui/src/components/avatar/demos/2.Shape.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
title:
en-US: Shape
zh-Hant: 形状
---

# en-US

Set the shape via `dShape`.

# zh-Hant

通过 `dShape` 设置形状。

```tsx
import { DAvatar } from '@react-devui/ui';

export default function Demo() {
return (
<>
<DAvatar dText="U" dShape="square"></DAvatar>
<DAvatar dText="U" dShape={8}></DAvatar>
</>
);
}
```
27 changes: 27 additions & 0 deletions packages/ui/src/components/avatar/demos/3.LoadError.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
title:
en-US: Failed to load
zh-Hant: 加载失败
---

# en-US

`dIcon` or `dText` will be displayed when the image fails to load, the priority is `dIcon` > `dText`.

# zh-Hant

`dIcon` 或者 `dText` 会在图片加载失败时显示,优先级 `dIcon` > `dText`

```tsx
import { DAvatar } from '@react-devui/ui';
import { UserOutlined } from '@react-devui/ui/icons';

export default function Demo() {
return (
<>
<DAvatar dImg={{ src: 'avatar.png', alt: 'avatar' }} dIcon={<UserOutlined />}></DAvatar>
<DAvatar dImg={{ src: 'avatar.png', alt: 'avatar' }} dText="U"></DAvatar>
</>
);
}
```
43 changes: 43 additions & 0 deletions packages/ui/src/components/avatar/demos/4.AutoSize.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
title:
en-US: Auto resize
zh-Hant: 自动调整大小
---

# en-US

Auto resize.

# zh-Hant

自动调整大小。

```tsx
import { useState } from 'react';

import { DAvatar, DRadioGroup } from '@react-devui/ui';
import { UserOutlined } from '@react-devui/ui/icons';

export default function Demo() {
const [size, setSize] = useState(40);

return (
<>
<DRadioGroup
dOptions={[30, 40, 50].map((size) => ({
label: size.toString(),
value: size,
}))}
dModel={size}
dType="outline"
onModelChange={setSize}
/>
<br />
<DAvatar dImg={{ src: '/assets/avatar.png', alt: 'avatar' }} dSize={size}></DAvatar>
<DAvatar dIcon={<UserOutlined />} dSize={size}></DAvatar>
<DAvatar dText="U" dSize={size}></DAvatar>
<DAvatar dText="DevUI" dSize={size}></DAvatar>
</>
);
}
```
1 change: 1 addition & 0 deletions packages/ui/src/components/avatar/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './Avatar';
2 changes: 1 addition & 1 deletion packages/ui/src/components/badge/demos/5.Transition.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default function Demo() {

return (
<>
<DInput dPlaceholder="Number" dType="number" dModel={value} dClearable onModelChange={setValue} />
<DInput dPlaceholder="Number" dType="number" dMin={0} dModel={value} dClearable onModelChange={setValue} />
<br />
<br />
<DBadge dValue={Number(value)} dMax={99}>
Expand Down
3 changes: 3 additions & 0 deletions packages/ui/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export { DAnchor } from './anchor';
export type { DAutoCompleteProps } from './auto-complete';
export { DAutoComplete } from './auto-complete';

export type { DAvatarProps } from './avatar';
export { DAvatar } from './avatar';

export type { DBadgeProps } from './badge';
export { DBadge } from './badge';

Expand Down
2 changes: 2 additions & 0 deletions packages/ui/src/hooks/d-config/contex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type {
DAffixProps,
DAnchorProps,
DAutoCompleteProps,
DAvatarProps,
DBadgeProps,
DButtonProps,
DCascaderProps,
Expand Down Expand Up @@ -59,6 +60,7 @@ export type DComponentConfig = {
DAffix: DAffixProps;
DAnchor: DAnchorProps;
DAutoComplete: DAutoCompleteProps<any>;
DAvatar: DAvatarProps;
DBadge: DBadgeProps;
DButton: DButtonProps;
DCascader: DCascaderProps<any, any>;
Expand Down
1 change: 1 addition & 0 deletions packages/ui/src/styles/_components.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
@import 'components/selectbox';

@import 'components/anchor';
@import 'components/avatar';
@import 'components/badge';
@import 'components/button';
@import 'components/cascader';
Expand Down
1 change: 1 addition & 0 deletions packages/ui/src/styles/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,5 @@ $colors: (
--#{$variable-prefix}tag-background-color: hsl(0deg 0% 94%);
--#{$variable-prefix}tag-fill-background-color: hsl(0deg 0% 58%);
--#{$variable-prefix}tabs-slider-background-color: hsl(0deg 0% 97%);
--#{$variable-prefix}avatar-background-color: #bdbdbd;
}
30 changes: 30 additions & 0 deletions packages/ui/src/styles/components/avatar.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
@include b(avatar) {
display: inline-flex;
align-items: center;
justify-content: center;
overflow: hidden;
vertical-align: top;

@include m(circular) {
border-radius: 50%;
}

@include m(square) {
border-radius: var(--#{$variable-prefix}border-radius);
}

@include m(icon) {
color: map.get($colors, 'white');
background-color: var(--#{$variable-prefix}avatar-background-color);
}

@include m(text) {
color: map.get($colors, 'white');
background-color: var(--#{$variable-prefix}avatar-background-color);
}

@include e(img) {
width: 100%;
height: 100%;
}
}
1 change: 1 addition & 0 deletions packages/ui/src/styles/theme-dark.scss
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,5 @@ body.dark {
--#{$variable-prefix}tag-background-color: hsl(0deg 0% 20%);
--#{$variable-prefix}tag-fill-background-color: hsl(0deg 0% 50%);
--#{$variable-prefix}tabs-slider-background-color: hsl(0deg 0% 26%);
--#{$variable-prefix}avatar-background-color: #666;
}

0 comments on commit da42400

Please sign in to comment.