Skip to content

Commit

Permalink
Merge pull request #97 from Tzz1194593491/feature/alert
Browse files Browse the repository at this point in the history
feat(alert): add alert component
  • Loading branch information
duenyang authored Jul 17, 2024
2 parents 551e049 + 1e3af1d commit 4316734
Show file tree
Hide file tree
Showing 18 changed files with 384 additions and 8 deletions.
6 changes: 6 additions & 0 deletions site/sidebar.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,12 @@ export default [
name: 'Notifications',
type: 'component', // 组件文档
children: [
{
title: 'Alert 警告提示',
name: 'alert',
path: '/components/alert',
component: () => import('tdesign-web-components/alert/README.md'),
},
{
title: 'Message 全局提示',
name: 'message',
Expand Down
44 changes: 44 additions & 0 deletions src/alert/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
title: Alert 消息
description: 警告条用于承载需要用户注意的信息。
isComponent: true
usage: { title: '', description: '' }
spline: base
---

### 基础的警告

使用简洁文字提示的最基础警告条,包含 4 种情况的提示:普通消息,成功,警示,失败。
{{ base }}

### 带操作的警告

当需要对此警告做操作,可以配置 operation 来增加相关操作。
{{ baseOperation }}

### 带相关描述文字的警告

{{ baseDescription }}

### 折叠的警告

当信息内容超过 `指定行数` 时,可使用折叠的方式将部分信息隐藏。
{{ baseCollapse }}

## API

| 名称 | 类型 | 默认值 | 说明 | 必传 |
|------------------|----------|-------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----|
| className | String | - | 类名 | N |
| style | Object | - | 样式,TS 类型:`Record<string, string \| number>` | N |
| close | TNode | false | 关闭按钮。值为 true 则显示默认关闭按钮;值为 false 则不显示按钮;值类型为 string 则直接显示;值类型为 Function 则可以自定关闭按钮。TS 类型:`string \| boolean\| TNode`[通用类型定义](https://github.com/TDesignOteam/tdesign-web-components/blob/main/src/common.ts) | N |
| icon | TElement | - | 图标。TS 类型:TNode。 [通用类型定义](https://github.com/TDesignOteam/tdesign-web-components/blob/main/src/common.ts) | N |
| maxLine | Number | 0 | 内容显示最大行数,超出的内容会折叠收起,用户点击后再展开。值为 0 表示不折叠 [通用类型定义](https://github.com/TDesignOteam/tdesign-web-components/blob/main/src/common.ts) | N |
| message | TNode | - | 内容(子元素)。TS 类型:`string\| TNode`[通用类型定义](https://github.com/TDesignOteam/tdesign-web-components/blob/main/src/common.ts) | N |
| operation | TElement | - | 跟在告警内容后面的操作区。TS 类型:`TNode`[通用类型定义](https://github.com/TDesignOteam/tdesign-web-components/blob/main/src/common.ts) | N |
| theme | String | info | 组件风格。可选项:success/info/warning/error | N |
| title | TNode | - | 标题。TS 类型:`string \| TNode`[通用类型定义](https://github.com/TDesignOteam/tdesign-web-components/blob/main/src/common.ts) | N |
| onClose | Function | - | TS 类型:`(context: { e: MouseEvent }) => void` <br/>关闭按钮点击时触发 | N |
| onClosed | Function | - | TS 类型:`(context: { e: TransitionEvent }) => void` <br/> 告警提示框关闭动画结束后触发 | N |
| onClick | Function | - | TS 类型:`(context: { e: MouseEvent }) => void`<br/>点击回到顶部时触发 | N |
| ignoreAttributes | String[] | - | 在host标签上忽略的属性 | N |
17 changes: 17 additions & 0 deletions src/alert/_example/base.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import 'tdesign-web-components/alert';
import 'tdesign-web-components/space';

import { Component } from 'omi';

export default class Alert extends Component {
render() {
return (
<t-space direction="vertical" style={{ width: '100%' }}>
<t-alert theme="success" message="这是一条成功的消息提示" />
<t-alert theme="info" message="这是一条普通的消息提示" />
<t-alert theme="warning" message="这是一条警示消息提示" />
<t-alert theme="error" message="高危操作/出错信息提示" />
</t-space>
);
}
}
22 changes: 22 additions & 0 deletions src/alert/_example/baseCollapse.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import 'tdesign-web-components/alert';
import 'tdesign-web-components/space';
import 'tdesign-web-components/button';

import { Component } from 'omi';

export default class Alert extends Component {
render() {
const message = [
'1.这是一条普通的消息提示描述,',
'2.这是一条普通的消息提示描述,',
'3.这是一条普通的消息提示描述,',
'4.这是一条普通的消息提示描述,',
'5.这是一条普通的消息提示描述,',
];
return (
<t-space direction="vertical" style={{ width: '100%' }}>
<t-alert message={message} maxLine={2} close />
</t-space>
);
}
}
22 changes: 22 additions & 0 deletions src/alert/_example/baseDescription.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import 'tdesign-web-components/alert';
import 'tdesign-web-components/space';
import 'tdesign-web-components/button';

import { Component } from 'omi';

export default class Alert extends Component {
render() {
const operation = <span>相关操作</span>;
return (
<t-space direction="vertical" style={{ width: '100%' }}>
<t-alert
theme="info"
title="这是一条普通的消息提示"
message="这是一条普通的消息提示描述,这是一条普通的消息提示描述"
operation={operation}
close
/>
</t-space>
);
}
}
19 changes: 19 additions & 0 deletions src/alert/_example/baseOperation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import 'tdesign-web-components/alert';
import 'tdesign-web-components/space';
import 'tdesign-web-components/button';

import { Component } from 'omi';

export default class Alert extends Component {
render() {
const operation = <span>相关操作</span>;
return (
<t-space direction="vertical" style={{ width: '100%' }}>
<t-alert theme="success" message="这是一条成功的消息提示" operation={operation} close />
<t-alert theme="info" message="这是一条普通的消息提示" operation={operation} close />
<t-alert theme="warning" message="这是一条警示消息提示" operation={operation} close />
<t-alert theme="error" message="高危操作/出错信息提示" operation={operation} close />
</t-space>
);
}
}
174 changes: 174 additions & 0 deletions src/alert/alert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
import 'tdesign-icons-web-components/esm/components/check-circle-filled';
import 'tdesign-icons-web-components/esm/components/info-circle-filled';
import 'tdesign-icons-web-components/esm/components/error-circle-filled';
import 'tdesign-icons-web-components/esm/components/close';

import { isObject } from 'lodash';
import { Component, createRef, signal, SignalValue, tag } from 'omi';

import classname, { getClassPrefix } from '../_util/classname.ts';
import parseTNode from '../_util/parseTNode.ts';
import { StyledProps } from '../common';
import { TdAlertProps } from './type.ts';

export interface AlertProps extends TdAlertProps, StyledProps {}

const expandText = '展开更多';

const collapseText = '收起';

@tag('t-alert')
export default class Alert extends Component<AlertProps> {
static css = [];

static defaultProps = {
close: false,
maxLine: 0,
theme: 'info',
};

static propTypes = {
close: [String, Number, Object, Function],
icon: [String, Number, Object, Function],
maxLine: Number,
message: [String, Number, Object, Function],
operation: [String, Number, Object, Function],
theme: String,
title: [String, Number, Object, Function],
onClose: Function,
onClick: Function,
ignoreAttributes: Object,
};

iconMap = {
success: <t-icon-check-circle-filled />,
info: <t-icon-info-circle-filled />,
error: <t-icon-error-circle-filled />,
warning: <t-icon-error-circle-filled />,
};

closed: SignalValue<boolean> = signal(false);

collapsed: SignalValue<boolean> = signal(true);

needUninstall: Set<Function> = new Set<Function>();

nodeRef = createRef<HTMLElement>();

classPrefix = getClassPrefix();

handleClose = (e?: MouseEvent) => {
const { onClose } = this.props;
this.nodeRef.current?.classList.add(`${this.classPrefix}-alert--closing`);
onClose?.({ e });
};

handleCloseEnd = (e?: TransitionEvent) => {
const { onClosed } = this.props;
const isTransitionTarget = e?.target === this.nodeRef.current;
// 防止子元素冒泡触发
if (e?.propertyName === 'opacity' && isTransitionTarget) {
this.closed.value = true;
onClosed?.({ e });
}
};

handleCollapse = () => {
this.collapsed.value = !this.collapsed.value;
};

renderTitle() {
const { title } = this.props;
return title ? <div className={`${this.classPrefix}-alert__title`}>{title}</div> : null;
}

renderMessage() {
const { maxLine, message } = this.props;
if (maxLine > 0 && Array.isArray(message)) {
return (
<div className={`${this.classPrefix}-alert__description`}>
{message.map((item, index) => {
if (this.collapsed.value) {
if (index < maxLine) {
return <div key={index}>{item}</div>;
}
return null;
}
return <div key={index}>{item}</div>;
})}
<div className={`${this.classPrefix}-alert__collapse`} onClick={this.handleCollapse}>
{this.collapsed.value ? expandText : collapseText}
</div>
</div>
);
}
return <div className={`${this.classPrefix}-alert__description`}>{message}</div>;
}

renderIcon() {
const { icon, theme } = this.props;
if (isObject(icon)) return icon;
return <div class={`${this.classPrefix}-alert__icon`}>{this.iconMap[theme] || this.iconMap.info}</div>;
}

renderClose() {
const { close } = this.props;
return (
<div className={`${this.classPrefix}-alert__close`} onClick={this.handleClose}>
{typeof close === 'boolean' && close ? <t-icon-close /> : parseTNode(close)}
</div>
);
}

renderOperation() {
const { operation } = this.props;
if (operation) {
return <div className={`${this.classPrefix}-alert__operation`}>{parseTNode(operation)}</div>;
}
return null;
}

renderContext() {
return (
<div className={`${this.classPrefix}-alert__content`}>
{this.renderTitle()}
<div className={`${this.classPrefix}-alert__message`}>
{this.renderMessage()}
{this.renderOperation()}
</div>
</div>
);
}

ready() {
this.nodeRef.current?.addEventListener('transitionend', this.handleCloseEnd);
}

uninstall() {
this.nodeRef.current?.removeEventListener('transitionend', this.handleCloseEnd);
}

render(props: AlertProps) {
const { className, style, theme, ignoreAttributes } = props;
if (ignoreAttributes?.length > 0) {
ignoreAttributes.forEach((attr) => {
this.removeAttribute(attr);
});
}
const cls = classname([
`${this.classPrefix}-alert`,
`${this.classPrefix}-alert--${theme}`,
{
[`${this.classPrefix}-is-hidden`]: this.closed.value,
},
className,
]);
return (
<div ref={this.nodeRef} className={cls} style={style}>
{this.renderIcon()}
{this.renderContext()}
{this.renderClose()}
</div>
);
}
}
8 changes: 8 additions & 0 deletions src/alert/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import './style/index.js';

import _Alert from './alert';

export type { AlertProps } from './alert';

export const Alert = _Alert;
export default Alert;
10 changes: 10 additions & 0 deletions src/alert/style/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { css, globalCSS } from 'omi';

// 为了做主题切换
import styles from '../../_common/style/web/components/alert/_index.less';

export const styleSheet = css`
${styles}
`;

globalCSS(styleSheet);
54 changes: 54 additions & 0 deletions src/alert/type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { TElement, TNode } from '../common';

export interface TdAlertProps {
/**
* 关闭按钮。值为 true 则显示默认关闭按钮;
* 值为 false 则不显示按钮;
* 值类型为 string 则直接显示;
* 值类型为 Function 则可以自定关闭按钮
*
* @default: false
*/
close?: TNode;
/**
* 图标
*/
icon?: TElement;
/**
* 内容显示最大行数,超出的内容会折叠收起,用户点击后再展开。
* 值为 0 表示不折叠
*
* @default: 0
*/
maxLine?: number;
/**
* 内容(子元素)
*/
message?: TNode;
/**
* 跟在告警内容后面的操作区。
*/
operation?: TNode;
/**
* 组件风格。可选项:success/info/warning/error
*
* @default: info
*/
theme?: string;
/**
* 标题
*/
title?: TNode;
/**
* 关闭按钮点击时触发
*/
onClose?: (context: { e: MouseEvent }) => void;
/**
* 告警提示框关闭动画结束后触发
*/
onClosed?: (context: { e: TransitionEvent }) => void;
/**
* 忽略的属性列表,忽略后,将不会传递给父元素
*/
ignoreAttributes?: string[];
}
Loading

0 comments on commit 4316734

Please sign in to comment.