Skip to content

Commit

Permalink
feat(ErrorBlock): add createErrorBlock function for generating more…
Browse files Browse the repository at this point in the history
… light-weighted or customized ErrorBlock
  • Loading branch information
awmleer committed May 29, 2022
1 parent 3c05796 commit 8eb12cb
Show file tree
Hide file tree
Showing 10 changed files with 250 additions and 84 deletions.
68 changes: 68 additions & 0 deletions src/components/error-block/create-error-block.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import React, { FC, ReactElement, ReactNode } from 'react'
import classNames from 'classnames'
import { mergeProps } from '../../utils/with-default-props'
import { NativeProps, withNativeProps } from '../../utils/native-props'
import { useConfig } from '../config-provider'
import type { ErrorBlockStatus, ImageRecord } from '.'

const classPrefix = `adm-error-block`

export type ErrorBlockProps = {
status?: ErrorBlockStatus
title?: ReactNode
image?: string | ReactElement
description?: ReactNode
fullPage?: boolean
children?: React.ReactNode
} & NativeProps<
| '--image-height'
| '--image-height-full-page'
| '--image-width'
| '--image-width-full-page'
>

const defaultProps = {
status: 'default',
}

export function createErrorBlock(imageRecord: ImageRecord) {
const ErrorBlock: FC<ErrorBlockProps> = p => {
const props = mergeProps(defaultProps, p)
const { locale } = useConfig()
const contentPack = locale.ErrorBlock[props.status]
const des =
'description' in props ? props.description : contentPack.description
const title = 'title' in props ? props.title : contentPack.title
const image: ReactNode = props.image ?? imageRecord[props.status]
const imageNode =
typeof image === 'string' ? (
<img src={image} alt='error block image' />
) : (
image
)

return withNativeProps(
props,
<div
className={classNames(classPrefix, {
[`${classPrefix}-full-page`]: props.fullPage,
})}
>
<div className={`${classPrefix}-image`}>{imageNode}</div>
<div className={`${classPrefix}-description`}>
{title && (
<div className={`${classPrefix}-description-title`}>{title}</div>
)}
{des && (
<div className={`${classPrefix}-description-subtitle`}>{des}</div>
)}
</div>

{props.children && (
<div className={`${classPrefix}-content`}>{props.children}</div>
)}
</div>
)
}
return ErrorBlock
}
23 changes: 23 additions & 0 deletions src/components/error-block/demos/demo-3.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react'
import { createErrorBlock, Space } from 'antd-mobile'
import { DemoBlock } from 'demos'
import { defaultImage } from 'antd-mobile/es/components/error-block/images'

const ErrorBlock = createErrorBlock({
'default': defaultImage,
'empty':
'https://gw.alipayobjects.com/zos/bmw-prod/7a2970f8-9247-4196-b3b3-2d0218c18b59.svg',
})

export default () => {
return (
<>
<DemoBlock title='四种状态'>
<Space block direction='vertical' style={{ '--gap': '16px' }}>
<ErrorBlock status='default' />
<ErrorBlock status='empty' />
</Space>
</DemoBlock>
</>
)
}
4 changes: 4 additions & 0 deletions src/components/error-block/demos/demo-4.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.myErrorBlockIcon {
font-size: 48px;
color: var(--adm-color-weak);
}
23 changes: 23 additions & 0 deletions src/components/error-block/demos/demo-4.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react'
import { createErrorBlock, Space } from 'antd-mobile'
import { DemoBlock } from 'demos'
import { FileWrongOutline, SearchOutline } from 'antd-mobile-icons'
import styles from './demo-4.less'

const ErrorBlock = createErrorBlock({
'default': <FileWrongOutline className={styles.myErrorBlockIcon} />,
'empty': <SearchOutline className={styles.myErrorBlockIcon} />,
})

export default () => {
return (
<>
<DemoBlock title='四种状态'>
<Space block direction='vertical' style={{ '--gap': '16px' }}>
<ErrorBlock status='default' />
<ErrorBlock status='empty' />
</Space>
</DemoBlock>
</>
)
}
81 changes: 17 additions & 64 deletions src/components/error-block/error-block.tsx
Original file line number Diff line number Diff line change
@@ -1,67 +1,20 @@
import React, { FC, ReactElement, ReactNode } from 'react'
import classNames from 'classnames'
import { mergeProps } from '../../utils/with-default-props'
import { NativeProps, withNativeProps } from '../../utils/native-props'
import { useConfig } from '../config-provider'
import { imageRecord } from './images'
import { createErrorBlock } from './create-error-block'
import { ReactElement } from 'react'
import {
busyImage,
defaultImage,
disconnectedImage,
emptyImage,
} from './images'

const classPrefix = `adm-error-block`

export type ErrorBlockProps = {
status?: 'default' | 'disconnected' | 'empty' | 'busy'
title?: ReactNode
image?: string | ReactElement
description?: ReactNode
fullPage?: boolean
children?: React.ReactNode
} & NativeProps<
| '--image-height'
| '--image-height-full-page'
| '--image-width'
| '--image-width-full-page'
>

const defaultProps = {
status: 'default',
const imageRecord: Record<
'default' | 'disconnected' | 'empty' | 'busy',
ReactElement
> = {
'default': defaultImage,
'disconnected': disconnectedImage,
'empty': emptyImage,
'busy': busyImage,
}

export const ErrorBlock: FC<ErrorBlockProps> = p => {
const props = mergeProps(defaultProps, p)
const { locale } = useConfig()
const contentPack = locale.ErrorBlock[props.status]
const des =
'description' in props ? props.description : contentPack.description
const title = 'title' in props ? props.title : contentPack.title
let imageNode: ReactNode = imageRecord[props.status]

if (props.image) {
if (typeof props.image === 'string') {
imageNode = <img src={props.image} alt='error block image' />
} else {
imageNode = props.image
}
}

return withNativeProps(
props,
<div
className={classNames(classPrefix, {
[`${classPrefix}-full-page`]: props.fullPage,
})}
>
<div className={`${classPrefix}-image`}>{imageNode}</div>
<div className={`${classPrefix}-description`}>
{title && (
<div className={`${classPrefix}-description-title`}>{title}</div>
)}
{des && (
<div className={`${classPrefix}-description-subtitle`}>{des}</div>
)}
</div>

{props.children && (
<div className={`${classPrefix}-content`}>{props.children}</div>
)}
</div>
)
}
export const ErrorBlock = createErrorBlock(imageRecord)
19 changes: 4 additions & 15 deletions src/components/error-block/images/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,4 @@
import { ReactElement } from 'react'
import { defaultImage } from './default'
import { disconnectedImage } from './disconnected'
import { emptyImage } from './empty'
import { busyImage } from './busy'

export const imageRecord: Record<
'default' | 'disconnected' | 'empty' | 'busy',
ReactElement
> = {
'default': defaultImage,
'disconnected': disconnectedImage,
'empty': emptyImage,
'busy': busyImage,
}
export { defaultImage } from './default'
export { disconnectedImage } from './disconnected'
export { emptyImage } from './empty'
export { busyImage } from './busy'
53 changes: 51 additions & 2 deletions src/components/error-block/index.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ Use scene illustrations to indicate page exceptions.

Feedback prompts for six abnormal scenarios.

## ErrorBlock

### Demos

<code src="./demos/demo-basic.tsx"></code>

<code src="./demos/demo-full-page.tsx"></code>

<code src="./demos/demo2.tsx"></code>

## ErrorBlock

### Props

| Name | Description | Type | Default |
Expand All @@ -32,3 +34,50 @@ Feedback prompts for six abnormal scenarios.
| --image-height-full-page | Height of the image in `fullPage` mode | `200px` | `--adm-error-block-image-height-full-page` |
| --image-width | Width of the image | `auto` | `--adm-error-block-image-width` |
| --image-width-full-page | Width of the image in `fullPage` mode | `auto` | `--adm-error-block-image-width-full-page` |

## createErrorBlock

The `ErrorBlock` component is very simple to use, but it inevitably brings a problem: since we don't know which `status` you will use, we can only package image resources in four states. There will be some package size problems.

In order to import as few resources as possible, we provide a utility function `createErrorBlock`, which you can use to create a custom `ErrorBlock` component that contains only the materials you need.

Its type definition is:

```ts
declare function createErrorBlock(imageRecord: ImageRecord): React.ComponentType

type ImageRecord = Partial<Record<ErrorBlockStatus, string | ReactNode>>
type ErrorBlockStatus = 'default' | 'disconnected' | 'empty' | 'busy'
```
For example:
### Demos
If in your application, the ErrorBlock only needs to support the `default` state, then you can create a lightweight ErrorBlock that only packs the `default` image material like this:
```jsx
import {defaultImage} from 'antd-mobile/es/components/error-block/images'

const ErrorBlock = createErrorBlock({
'default': defaultImage,
})
```

We have exported images corresponding to four states in `antd-mobile/es/components/error-block/images`, you can use them directly: `defaultImage` `disconnectedImage` `emptyImage` `busyImage`.

Even, you can directly configure the image resources in the online CDN, which can greatly reduce the packaging size:

```jsx
const ErrorBlock = createErrorBlock({
'empty': 'https://gw.alipayobjects.com/zos/bmw-prod/7a2970f8-9247-4196-b3b3-2d0218c18b59.svg',
})
```

The final effect is:

<code src="./demos/demo-3.tsx"></code>

`createErrorBlock` does more than that, you can also use it to configure custom image presets to create a custom version of ErrorBlock. You can replace the image material to match the visual style of your own project, or replace it with a minimalist icon like this:

<code src="./demos/demo-4.tsx"></code>
8 changes: 7 additions & 1 deletion src/components/error-block/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import './error-block.less'
import { ReactNode } from 'react'
import { ErrorBlock } from './error-block'

export type { ErrorBlockProps } from './error-block'
export { createErrorBlock } from './create-error-block'

export type { ErrorBlockProps } from './create-error-block'

export type ErrorBlockStatus = 'default' | 'disconnected' | 'empty' | 'busy'
export type ImageRecord = Partial<Record<ErrorBlockStatus, string | ReactNode>>

export default ErrorBlock
53 changes: 51 additions & 2 deletions src/components/error-block/index.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@

适用于六种异常场景的反馈提示。

## ErrorBlock

### 示例

<code src="./demos/demo-basic.tsx"></code>

<code src="./demos/demo-full-page.tsx"></code>

<code src="./demos/demo2.tsx"></code>

## ErrorBlock

### 属性

| 属性 | 说明 | 类型 | 默认值 |
Expand All @@ -32,3 +34,50 @@
| --image-height-full-page | 整页模式下的图片高度 | `200px` | `--adm-error-block-image-height-full-page` |
| --image-width | 图片的宽度 | `auto` | `--adm-error-block-image-width` |
| --image-width-full-page | 整页模式下的图片宽度 | `auto` | `--adm-error-block-image-width-full-page` |

## createErrorBlock

`ErrorBlock` 组件用起来非常简单,但是它不可避免的带来了一个问题:由于我们不知道你会用到哪些 `status`,所以我们只能把四种状态下的图片资源都打包进来,这会带来一些包体积上的问题。

为了能够尽可能少的引入资源,我们提供了一个工具函数 `createErrorBlock`,你可以使用它来创建一个定制化的 `ErrorBlock` 组件,其中只包含你需要的素材。

它的类型定义是:

```ts
declare function createErrorBlock(imageRecord: ImageRecord): React.ComponentType

type ImageRecord = Partial<Record<ErrorBlockStatus, string | ReactNode>>
type ErrorBlockStatus = 'default' | 'disconnected' | 'empty' | 'busy'
```
例如:
### 示例
如果在你的应用中,ErrorBlock 只需要支持 `default` 这种状态,那么你可以这样创建一个只打包了 `default` 图片素材的轻量化的 ErrorBlock:
```jsx
import {defaultImage} from 'antd-mobile/es/components/error-block/images'

const ErrorBlock = createErrorBlock({
'default': defaultImage,
})
```

我们在 `antd-mobile/es/components/error-block/images` 中 export 了四种状态对应的图片,你可以直接使用它们:`defaultImage` `disconnectedImage` `emptyImage` `busyImage`

甚至,你可以直接配置成在线 CDN 中的图片资源,这样就可以很大程度上降低打包体积:

```jsx
const ErrorBlock = createErrorBlock({
'empty': 'https://gw.alipayobjects.com/zos/bmw-prod/7a2970f8-9247-4196-b3b3-2d0218c18b59.svg',
})
```

最终效果是:

<code src="./demos/demo-3.tsx"></code>

`createErrorBlock` 的作用不止于此,你还可以使用它配置自定义的图片预设,创建出一个定制版的 ErrorBlock。你可以把图片素材替换成符合你自己项目中视觉风格的,也可以像下面这样替换成极简风格的图标:

<code src="./demos/demo-4.tsx"></code>
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,5 @@ export { default as Toast } from './components/toast'
export { default as TreeSelect } from './components/tree-select'
export { default as VirtualInput } from './components/virtual-input'
export { default as WaterMark } from './components/water-mark'

export { createErrorBlock } from './components/error-block'

0 comments on commit 8eb12cb

Please sign in to comment.