mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-29 18:48:45 +08:00
feat: timeline组件支持detailClaaName/titleClassName/timeClassName & 关联上下文& 可视化配置 (#7654)
Co-authored-by: yanglu19 <yanglu19@baidu.com>
This commit is contained in:
parent
f6a35036e0
commit
34403e5b8e
@ -329,7 +329,9 @@ order: 73
|
||||
}
|
||||
```
|
||||
|
||||
## 远程数据
|
||||
## 动态数据
|
||||
|
||||
### 远程数据
|
||||
|
||||
```schema
|
||||
{
|
||||
@ -391,25 +393,85 @@ order: 73
|
||||
}
|
||||
```
|
||||
|
||||
### 数据域变量配置
|
||||
|
||||
> 3.4.0 及以上版本
|
||||
|
||||
```schema
|
||||
{
|
||||
"type": "page",
|
||||
"data": {
|
||||
"items": [
|
||||
{
|
||||
"title": "First",
|
||||
"time": "this is subTitle",
|
||||
"detail": "this is description"
|
||||
},
|
||||
{
|
||||
"title": "Second"
|
||||
},
|
||||
{
|
||||
"title": "Last"
|
||||
}
|
||||
]
|
||||
},
|
||||
"body": [
|
||||
{
|
||||
"type": "timeline",
|
||||
"source": "${items}"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
```schema
|
||||
{
|
||||
"type": "page",
|
||||
"data": {
|
||||
"items":
|
||||
{
|
||||
"First": "this is subTitle",
|
||||
"detail": "this is description",
|
||||
"title": "Second"
|
||||
}
|
||||
}
|
||||
,
|
||||
"body": [
|
||||
{
|
||||
"type": "timeline",
|
||||
"source": "${items}"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 属性表
|
||||
|
||||
| 属性名 | 类型 | 默认值 | 说明 |
|
||||
| --------- | ------------------------------------- | ---------- | ----------------------------------------------------------- |
|
||||
| type | `string` | | `"timeline"` 指定为 时间轴 渲染器 |
|
||||
| items | Array<[timelineItem](#timeline.item)> | [] | 配置节点数据 |
|
||||
| source | [API](../../../docs/types/api) | | 数据源,可通过数据映射获取当前数据域变量、或者配置 API 对象 |
|
||||
| mode | `left` \| `right` \| `alternate` | `right` | 指定文字相对于时间轴的位置,仅 direction=vertical 时支持 |
|
||||
| direction | `vertical` \| `horizontal` | `vertical` | 时间轴方向 |
|
||||
| reverse | `boolean` | `false` | 根据时间倒序显示 |
|
||||
| 属性名 | 类型 | 默认值 | 说明 |
|
||||
| --------------- | --------------------------------------------------------------------------------- | ---------- | ----------------------------------------------------------- |
|
||||
| type | `string` | | `"timeline"` 指定为 时间轴 渲染器 |
|
||||
| items | Array<[timelineItem](#timeline.item)> | [] | 配置节点数据 |
|
||||
| source | [API](../../../docs/types/api) 或 [数据映射](../../../docs/concepts/data-mapping) | | 数据源,可通过数据映射获取当前数据域变量、或者配置 API 对象 |
|
||||
| mode | `left` \| `right` \| `alternate` | `right` | 指定文字相对于时间轴的位置,仅 direction=vertical 时支持 |
|
||||
| direction | `vertical` \| `horizontal` | `vertical` | 时间轴方向 |
|
||||
| reverse | `boolean` | `false` | 根据时间倒序显示 |
|
||||
| iconClassName | `string` | | 统一配置的节点图标 CSS 类(3.4.0 版本支持)名 |
|
||||
| timeClassName | `string` | | 统一配置的节点时间 CSS 类(3.4.0 版本支持)名 |
|
||||
| titleClassName | `string` | | 统一配置的节点标题 CSS 类(3.4.0 版本支持)名 |
|
||||
| detailClassName | `string` | | 统一配置的节点详情 CSS 类(3.4.0 版本支持)名 |
|
||||
|
||||
### timeline.item
|
||||
|
||||
| 属性名 | 类型 | 默认值 | 说明 |
|
||||
| ------------------- | ------------------------------------------------------- | --------- | ----------------------------------------------------------- |
|
||||
| time | `string ` | | 节点时间 |
|
||||
| title | `string` \| [SchemaNode](../../docs/types/schemanode) | | 节点标题 |
|
||||
| detail | `string` | | 节点详细描述(折叠) |
|
||||
| detailCollapsedText | `string` | `展开` | 详细内容折叠时按钮文案 |
|
||||
| detailExpandedText | `string` | `折叠` | 详细内容展开时按钮文案 |
|
||||
| color | `string \| level样式(info、success、warning、danger)` | `#DADBDD` | 时间轴节点颜色 |
|
||||
| icon | `string` | | icon 名,支持 fontawesome v4 或使用 url(优先级高于 color) |
|
||||
| 属性名 | 类型 | 默认值 | 说明 |
|
||||
| ------------------- | ------------------------------------------------------- | --------- | ------------------------------------------------------------------------------- |
|
||||
| time | `string ` | | 节点时间 |
|
||||
| title | `string` \| [SchemaNode](../../docs/types/schemanode) | | 节点标题 |
|
||||
| detail | `string` | | 节点详细描述(折叠) |
|
||||
| detailCollapsedText | `string` | `展开` | 详细内容折叠时按钮文案 |
|
||||
| detailExpandedText | `string` | `折叠` | 详细内容展开时按钮文案 |
|
||||
| color | `string \| level样式(info、success、warning、danger)` | `#DADBDD` | 时间轴节点颜色 |
|
||||
| icon | `string` | | icon 名,支持 fontawesome v4 或使用 url(优先级高于 color) |
|
||||
| iconClassName | `string` | | 节点图标的 CSS 类名(优先级高于统一配置的 iconClassName ,(3.4.0 版本支持)) |
|
||||
| timeClassName | `string` | | 节点时间的 CSS 类名(优先级高于统一配置的 timeClassName,(3.4.0 版本支持)) |
|
||||
| titleClassName | `string` | | 节点标题的 CSS 类名(优先级高于统一配置的 titleClassName,(3.4.0 版本支持)) |
|
||||
| detailClassName | `string` | | 节点详情的 CSS 类名(优先级高于统一配置的 detailClassName,(3.4.0 版本支持)) |
|
||||
|
@ -136,7 +136,23 @@ export class TimelinePlugin extends BasePlugin {
|
||||
title: '外观',
|
||||
body: getSchemaTpl('collapseGroup', [
|
||||
getSchemaTpl('style:classNames', {
|
||||
isFormItem: false
|
||||
isFormItem: false,
|
||||
schema: [
|
||||
getSchemaTpl('className', {
|
||||
name: 'timeClassName',
|
||||
label: '时间区'
|
||||
}),
|
||||
|
||||
getSchemaTpl('className', {
|
||||
name: 'titleClassName',
|
||||
label: '标题区'
|
||||
}),
|
||||
|
||||
getSchemaTpl('className', {
|
||||
name: 'detailClassName',
|
||||
label: '详情区'
|
||||
})
|
||||
]
|
||||
})
|
||||
])
|
||||
}
|
||||
|
@ -77,6 +77,7 @@
|
||||
|
||||
.#{$ns}TimelineItem-title {
|
||||
display: flex;
|
||||
word-break: break-word;
|
||||
color: var(--TimelineItem--text-primary-color);
|
||||
font-size: var(--Timeline-title-fontSize);
|
||||
font-weight: var(--Timeline-title-fontWeight);
|
||||
@ -112,8 +113,8 @@
|
||||
|
||||
.#{$ns}TimelineItem-detail-visible {
|
||||
display: block;
|
||||
word-break: break-word;
|
||||
border-radius: var(--Timeline-visible-border-radius);
|
||||
max-width: var(--TimelineItem-detail-visible-max-width);
|
||||
font-size: var(--Timeline-detail-content-fontSize);
|
||||
font-weight: var(--Timeline-detail-content-fontWeight);
|
||||
color: var(--Timeline-detail-content-color);
|
||||
@ -131,6 +132,15 @@
|
||||
&.#{$ns}Timeline-left {
|
||||
.#{$ns}TimelineItem {
|
||||
flex-direction: row-reverse;
|
||||
.#{$ns}TimelineItem-title {
|
||||
text-align: right;
|
||||
}
|
||||
.#{$ns}TimelineItem-content,
|
||||
.#{$ns}TimelineItem-detail {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,6 +148,15 @@
|
||||
.#{$ns}TimelineItem:nth-child(odd) {
|
||||
flex-direction: row-reverse;
|
||||
max-width: 50%;
|
||||
.#{$ns}TimelineItem-title {
|
||||
text-align: right;
|
||||
}
|
||||
.#{$ns}TimelineItem-content,
|
||||
.#{$ns}TimelineItem-detail {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
.#{$ns}TimelineItem:nth-child(even) {
|
||||
@ -253,8 +272,8 @@
|
||||
|
||||
.#{$ns}TimelineItem-detail-visible {
|
||||
display: block;
|
||||
word-break: break-word;
|
||||
border-radius: var(--Timeline-visible-border-radius);
|
||||
max-width: var(--TimelineItem-detail-visible-max-width);
|
||||
font-size: var(--Timeline-detail-content-fontSize);
|
||||
font-weight: var(--Timeline-detail-content-fontWeight);
|
||||
color: var(--Timeline-detail-content-color);
|
||||
|
@ -7,6 +7,10 @@ export interface TimelineProps extends ThemeProps {
|
||||
direction?: 'vertical' | 'horizontal';
|
||||
reverse?: boolean;
|
||||
mode?: 'left' | 'right' | 'alternate';
|
||||
iconClassName?: string;
|
||||
timeClassName?: string;
|
||||
titleClassName?: string;
|
||||
detailClassName?: string;
|
||||
}
|
||||
|
||||
export function Timeline(props: TimelineProps) {
|
||||
@ -14,6 +18,11 @@ export function Timeline(props: TimelineProps) {
|
||||
items,
|
||||
style,
|
||||
classnames: cx,
|
||||
className,
|
||||
iconClassName,
|
||||
timeClassName,
|
||||
titleClassName,
|
||||
detailClassName,
|
||||
direction = 'vertical',
|
||||
reverse = false,
|
||||
mode = 'right'
|
||||
@ -25,11 +34,23 @@ export function Timeline(props: TimelineProps) {
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cx('Timeline', `Timeline-${direction}`, `Timeline-${mode}`)}
|
||||
className={cx(
|
||||
'Timeline',
|
||||
`Timeline-${direction}`,
|
||||
`Timeline-${mode}`,
|
||||
className
|
||||
)}
|
||||
style={style}
|
||||
>
|
||||
{timelineDatasource?.map((item: TimelineItemProps, index: number) => (
|
||||
<TimelineItem {...item} key={`TimelineItem-${index}`} />
|
||||
<TimelineItem
|
||||
{...item}
|
||||
key={`TimelineItem-${index}`}
|
||||
iconClassName={item.iconClassName || iconClassName}
|
||||
timeClassName={item.timeClassName || timeClassName}
|
||||
titleClassName={item.titleClassName || titleClassName}
|
||||
detailClassName={item.detailClassName || detailClassName}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
@ -43,6 +43,18 @@ export interface TimelineItemProps {
|
||||
|
||||
/** ICON的CSS类名 */
|
||||
iconClassName?: string;
|
||||
/**
|
||||
* 时间的CSS类名 (优先级高于外层titleClassName)
|
||||
*/
|
||||
timeClassName?: string;
|
||||
/**
|
||||
* 节点标题的CSS类名(优先级高于外层titleClassName)
|
||||
*/
|
||||
titleClassName?: string;
|
||||
/**
|
||||
* 节点详情的CSS类名(优先级高于外层detailClassName)
|
||||
*/
|
||||
detailClassName?: string;
|
||||
}
|
||||
|
||||
export interface TimelineItem
|
||||
@ -62,6 +74,9 @@ export function TimelineItem(props: TimelineItem) {
|
||||
color,
|
||||
icon,
|
||||
iconClassName,
|
||||
timeClassName,
|
||||
titleClassName,
|
||||
detailClassName,
|
||||
classnames: cx,
|
||||
translate: __,
|
||||
classPrefix,
|
||||
@ -97,7 +112,8 @@ export function TimelineItem(props: TimelineItem) {
|
||||
detailVisible
|
||||
? 'TimelineItem-detail-visible'
|
||||
: 'TimelineItem-detail-invisible'
|
||||
}`
|
||||
}`,
|
||||
detailClassName
|
||||
)}
|
||||
>
|
||||
{detail}
|
||||
@ -135,8 +151,8 @@ export function TimelineItem(props: TimelineItem) {
|
||||
)}
|
||||
</div>
|
||||
<div className={cx('TimelineItem-content')}>
|
||||
<div className={cx('TimelineItem-time')}>{time}</div>
|
||||
<div className={cx('TimelineItem-title')}>{title}</div>
|
||||
<div className={cx('TimelineItem-time', timeClassName)}>{time}</div>
|
||||
<div className={cx('TimelineItem-title', titleClassName)}>{title}</div>
|
||||
{detail && (
|
||||
<div className={cx('TimelineItem-detail')}>
|
||||
{renderDetail(detail, detailCollapsedText, detailExpandedText)}
|
||||
|
@ -229,9 +229,9 @@ test('Renderer:timeline itemTitleSchema', async () => {
|
||||
type: 'timeline',
|
||||
itemTitleSchema: [
|
||||
{
|
||||
type: "tpl",
|
||||
type: 'tpl',
|
||||
tpl: '<div class="itemSchemaClassName">${title}</div>'
|
||||
},
|
||||
}
|
||||
],
|
||||
items: [
|
||||
{
|
||||
@ -267,3 +267,51 @@ test('Renderer:timeline itemTitleSchema', async () => {
|
||||
expect(container).toMatchSnapshot();
|
||||
expect(container.querySelector('.itemSchemaClassName')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('Renderer:timeline detailClassName timeClassName', async () => {
|
||||
const {container, getByText} = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'timeline',
|
||||
detailClassName: 'auto-detail-class',
|
||||
items: [
|
||||
{
|
||||
time: '2019-02-07',
|
||||
title: '节点数据',
|
||||
detail: '#ffb200',
|
||||
detailCollapsedText: 'detailCollapsedText',
|
||||
detailExpandedText: 'detailExpandedText',
|
||||
icon: 'close'
|
||||
},
|
||||
{
|
||||
time: '2019-02-08',
|
||||
title: '节点数据',
|
||||
titleClassName: 'auto-item-title-class',
|
||||
detail: '#4F86F4'
|
||||
},
|
||||
{
|
||||
time: '2019-02-09',
|
||||
title: '节点数据',
|
||||
detail: 'success'
|
||||
},
|
||||
{
|
||||
time: '2019-02-09',
|
||||
title: '节点数据',
|
||||
detail: 'warning'
|
||||
}
|
||||
]
|
||||
},
|
||||
{},
|
||||
makeEnv()
|
||||
)
|
||||
);
|
||||
|
||||
fireEvent.click(getByText('detailExpandedText'));
|
||||
const timelineDetail = () =>
|
||||
container.querySelector('.cxd-TimelineItem-detail-visible')!;
|
||||
expect(timelineDetail()).toHaveClass('auto-detail-class');
|
||||
|
||||
const timelineTitles = () =>
|
||||
container.querySelectorAll('.cxd-TimelineItem-title')!;
|
||||
expect(timelineTitles()[1]).toHaveClass('auto-item-title-class');
|
||||
});
|
||||
|
@ -16,6 +16,7 @@ import type {
|
||||
SchemaTokenizeableString
|
||||
} from '../Schema';
|
||||
import type {IconCheckedSchema} from 'amis-ui';
|
||||
import {TimelineItemProps} from 'packages/amis-ui/src/components/TimelineItem';
|
||||
|
||||
export interface TimelineItemSchema extends Omit<BaseSchema, 'type'> {
|
||||
/**
|
||||
@ -57,6 +58,18 @@ export interface TimelineItemSchema extends Omit<BaseSchema, 'type'> {
|
||||
* 图标的CSS类名
|
||||
*/
|
||||
iconClassName?: string;
|
||||
/**
|
||||
* 节点时间的CSS类名(优先级高于统一配置的timeClassName)
|
||||
*/
|
||||
timeClassName?: string;
|
||||
/**
|
||||
* 节点标题的CSS类名(优先级高于统一配置的titleClassName)
|
||||
*/
|
||||
titleClassName?: string;
|
||||
/**
|
||||
* 节点详情的CSS类名(优先级高于统一配置的detailClassName)
|
||||
*/
|
||||
detailClassName?: string;
|
||||
}
|
||||
|
||||
export interface TimelineSchema extends BaseSchema {
|
||||
@ -93,6 +106,22 @@ export interface TimelineSchema extends BaseSchema {
|
||||
* 节点title自定一展示模板
|
||||
*/
|
||||
itemTitleSchema?: SchemaCollection;
|
||||
/**
|
||||
* 图标的CSS类名
|
||||
*/
|
||||
iconClassName?: string;
|
||||
/**
|
||||
* 节点时间的CSS类名
|
||||
*/
|
||||
timeClassName?: string;
|
||||
/**
|
||||
* 节点标题的CSS类名
|
||||
*/
|
||||
titleClassName?: string;
|
||||
/**
|
||||
* 节点详情的CSS类名
|
||||
*/
|
||||
detailClassName?: string;
|
||||
}
|
||||
|
||||
export interface TimelineProps
|
||||
@ -107,27 +136,36 @@ export function TimelineCmpt(props: TimelineProps) {
|
||||
direction,
|
||||
reverse,
|
||||
data,
|
||||
config,
|
||||
source,
|
||||
itemTitleSchema,
|
||||
className,
|
||||
timeClassName,
|
||||
titleClassName,
|
||||
detailClassName,
|
||||
render
|
||||
} = props;
|
||||
|
||||
// 获取源数据
|
||||
const timelineItemsRow: Array<TimelineItemSchema> = config || items || [];
|
||||
|
||||
// 渲染内容
|
||||
const resolveRender = (region: string, val?: SchemaCollection) =>
|
||||
typeof val === 'string' ? filter(val, data) : val && render(region, val);
|
||||
|
||||
// 处理源数据
|
||||
const resolveTimelineItems = timelineItemsRow?.map(
|
||||
const resolveTimelineItems: Array<TimelineItemProps> = (items || []).map(
|
||||
(timelineItem: TimelineItemSchema, index: number) => {
|
||||
const {icon, iconClassName, title} = timelineItem;
|
||||
const {
|
||||
icon,
|
||||
iconClassName,
|
||||
title,
|
||||
timeClassName,
|
||||
titleClassName,
|
||||
detailClassName
|
||||
} = timelineItem;
|
||||
|
||||
return {
|
||||
...timelineItem,
|
||||
iconClassName,
|
||||
timeClassName,
|
||||
titleClassName,
|
||||
detailClassName,
|
||||
icon: isPureVariable(icon)
|
||||
? resolveVariableAndFilter(icon, data, '| raw')
|
||||
: icon,
|
||||
@ -147,6 +185,10 @@ export function TimelineCmpt(props: TimelineProps) {
|
||||
reverse={reverse}
|
||||
mode={mode}
|
||||
style={style}
|
||||
className={className}
|
||||
timeClassName={timeClassName}
|
||||
titleClassName={titleClassName}
|
||||
detailClassName={detailClassName}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@ -158,8 +200,18 @@ const TimelineWithRemoteConfig = withRemoteConfig({
|
||||
RemoteOptionsProps & React.ComponentProps<typeof TimelineCmpt>
|
||||
> {
|
||||
render() {
|
||||
const {config, deferLoad, loading, updateConfig, ...rest} = this.props;
|
||||
return <TimelineCmpt config={config} {...rest} />;
|
||||
const {config, items, deferLoad, loading, updateConfig, ...rest} =
|
||||
this.props;
|
||||
|
||||
let sourceItems: Array<TimelineItemSchema> = config
|
||||
? Array.isArray(config)
|
||||
? config
|
||||
: Object.keys(config).map(key => ({
|
||||
time: key,
|
||||
title: config[key]
|
||||
}))
|
||||
: items || [];
|
||||
return <TimelineCmpt items={sourceItems} {...rest} />;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user