diff --git a/docs/zh-CN/components/divider.md b/docs/zh-CN/components/divider.md index 125692e7f..9775cb476 100755 --- a/docs/zh-CN/components/divider.md +++ b/docs/zh-CN/components/divider.md @@ -21,22 +21,51 @@ order: 42 ```schema: scope="body" [ { - "type": "divider" + "type": "divider", + "lineStyle": "solid" }, { "type": "divider", - "lineStyle": "solid" + "lineStyle": "dashed" + } +] +``` + +## 带标题的分割线 + +> `3.5.0`及以上版本 + +```schema: scope="body" +[ + { + "type": "divider", + "title": "Text", + "titlePosition": "left" + }, + { + "type": "divider", + "title": "Text", + "titlePosition": "center" + }, + { + "type": "divider", + "title": "Text", + "titlePosition": "right" } ] ``` ## 属性表 -| 属性名 | 类型 | 默认值 | 说明 | -| --------- | -------- | ------------ | ------------------------------------------ | +| 属性名 | 类型 | 默认值 | 说明 | 版本 | +| --------- | -------- | ------------ | --------------------------------------- |---------- | | type | `string` | | `"divider"` 指定为 分割线 渲染器 | | className | `string` | | 外层 Dom 的类名 | | lineStyle | `string` | `solid` | 分割线的样式,支持`dashed`和`solid` | -| direction | `string` | `horizontal` | 分割线的方向,支持`horizontal`和`vertical` | -| color | `string` | | 分割线的颜色 | -| rotate | `number` | | 分割线的旋转角度 | +| direction | `string` | `horizontal` | 分割线的方向,支持`horizontal`和`vertical` | `3.5.0` | +| color | `string` | | 分割线的颜色 | `3.5.0` | +| rotate | `number` | | 分割线的旋转角度 | `3.5.0` | +| title | [SchemaNode](../../docs/types/schemanode) | | 分割线的标题 | `3.5.0` | +| titleClassName | `string` | | 分割线的标题类名 | `3.5.0` | +| titlePosition | `string` | `center`| 分割线的标题位置,支持`left`、`center`和`right` | `3.5.0` | + diff --git a/packages/amis-editor/src/plugin/Divider.tsx b/packages/amis-editor/src/plugin/Divider.tsx index 7e26587f7..268bbffe3 100644 --- a/packages/amis-editor/src/plugin/Divider.tsx +++ b/packages/amis-editor/src/plugin/Divider.tsx @@ -1,6 +1,13 @@ -import {registerEditorPlugin} from 'amis-editor-core'; -import {BasePlugin} from 'amis-editor-core'; -import {getSchemaTpl} from 'amis-editor-core'; +import { + BasePlugin, + BaseEventContext, + defaultValue, + getI18nEnabled, + getSchemaTpl, + registerEditorPlugin, + tipedLabel, + valuePipeOut +} from 'amis-editor-core'; export class DividerPlugin extends BasePlugin { static id = 'DividerPlugin'; @@ -27,103 +34,203 @@ export class DividerPlugin extends BasePlugin { panelJustify = true; tags = ['展示']; - panelBody = getSchemaTpl('tabs', [ - { - title: '外观', - body: getSchemaTpl('collapseGroup', [ - { - title: '基本样式', - body: [ - getSchemaTpl('layout:originPosition', {value: 'left-top'}), - getSchemaTpl('layout:width:v2', { - visibleOn: - 'data.style && data.style.position && (data.style.position === "fixed" || data.style.position === "absolute")' - }), - { - mode: 'horizontal', - type: 'button-group-select', - label: '类型', - name: 'lineStyle', - value: 'dashed', - options: [ - { - value: 'dashed', - label: '虚线' - }, - { - value: 'solid', - label: '实线' + panelBodyCreator = (context: BaseEventContext) => { + const i18nEnabled = getI18nEnabled(); + return getSchemaTpl('tabs', [ + { + title: '属性', + body: getSchemaTpl('collapseGroup', [ + { + title: '基本', + body: [ + i18nEnabled + ? { + type: 'input-text-i18n', + name: 'title', + label: '标题', + placeholder: '请输入标题' + } + : getSchemaTpl('valueFormula', { + name: 'title', + label: '标题', + placeholder: '请输入标题', + rendererSchema: { + type: 'input-text' + } + }) + ] + }, + getSchemaTpl('status') + ]) + }, + { + title: '外观', + body: getSchemaTpl('collapseGroup', [ + { + title: '基本样式', + body: [ + getSchemaTpl('layout:originPosition', {value: 'left-top'}), + getSchemaTpl('layout:width:v2', { + visibleOn: + 'data.style && data.style.position && (data.style.position === "fixed" || data.style.position === "absolute")' + }), + { + mode: 'horizontal', + type: 'select', + label: '类型', + name: 'lineStyle', + value: 'solid', + options: [ + { + value: 'solid', + label: '实线' + }, + { + value: 'dashed', + label: '虚线' + } + ] + }, + { + mode: 'horizontal', + type: 'select', + label: '方向', + name: 'direction', + value: 'horizontal', + options: [ + { + value: 'horizontal', + label: '水平' + }, + { + value: 'vertical', + label: '垂直' + } + ] + }, + { + mode: 'horizontal', + type: 'input-number', + label: '角度', + name: 'rotate', + value: 0, + min: -360, + max: 360 + }, + getSchemaTpl('theme:select', { + mode: 'horizontal', + label: '线长', + name: 'style.width', + placeholder: '100%', + visibleOn: 'data.direction !== "vertical"', + clearValueOnHidden: true + }), + getSchemaTpl('theme:select', { + mode: 'horizontal', + label: '线长', + name: 'style.height', + placeholder: 'var(--sizes-base-15)', + visibleOn: 'data.direction === "vertical"', + clearValueOnHidden: true + }), + getSchemaTpl('theme:select', { + mode: 'horizontal', + label: '线宽', + name: 'style.borderWidth', + placeholder: '1px', + visibleOn: '!data.title || data.direction === "vertical"' + }), + getSchemaTpl('theme:select', { + mode: 'horizontal', + label: '线宽', + name: 'themeCss.titleWrapperControlClassName.border-bottom-width', + placeholder: '1px', + visibleOn: '!!data.title && data.direction !== "vertical"', + clearValueOnHidden: true, + pipeIn: (value: any, form: any) => { + if ( + value === undefined && + form.data?.style?.borderWidth !== undefined + ) { + const bwidth = form.data.style.borderWidth; + setTimeout(() => + form.setValueByName( + 'themeCss.titleWrapperControlClassName.border-bottom-width', + bwidth + ) + ); + return bwidth; + } + return value; } - ] - }, - { - mode: 'horizontal', - type: 'button-group-select', - label: '方向', - name: 'direction', - value: 'horizontal', - options: [ - { - value: 'horizontal', - label: '水平' - }, - { - value: 'vertical', - label: '垂直' - } - ] - }, - getSchemaTpl('theme:select', { - mode: 'horizontal', - label: '长度', - name: 'style.width', - placeholder: '100%', - visibleOn: 'direction !== "vertical"', - clearValueOnHidden: true - }), - getSchemaTpl('theme:select', { - mode: 'horizontal', - label: '长度', - name: 'style.height', - placeholder: 'var(--sizes-base-15)', - visibleOn: 'direction === "vertical"', - clearValueOnHidden: true - }), - getSchemaTpl('theme:select', { - mode: 'horizontal', - label: '宽度', - name: 'style.borderWidth', - placeholder: '1px' - }), - - getSchemaTpl('theme:colorPicker', { - mode: 'horizontal', - label: '颜色', - name: 'color', - placeholder: 'var(--colors-neutral-line-8)', - labelMode: 'input', - needGradient: true - }), - getSchemaTpl('theme:paddingAndMargin', { - name: 'style', - hidePadding: true - }), - { - mode: 'horizontal', - type: 'input-number', - label: '角度', - name: 'rotate', - value: 0 - } - ] - } - ]) - }, - { - title: '显隐', - body: [getSchemaTpl('ref'), getSchemaTpl('visible')] - } - ]); + }), + getSchemaTpl('theme:colorPicker', { + mode: 'horizontal', + label: '颜色', + name: 'color', + placeholder: 'var(--colors-neutral-line-8)', + labelMode: 'input', + needGradient: true + }), + getSchemaTpl('theme:paddingAndMargin', { + name: 'style', + hidePadding: true + }) + ] + }, + { + title: '标题样式', + visibleOn: '!!data.title && data.direction !== "vertical"', + body: [ + { + type: 'select', + name: 'titlePosition', + label: '位置', + pipeIn: defaultValue('center'), + options: [ + { + value: 'left', + label: '居左' + }, + { + value: 'center', + label: '居中' + }, + { + value: 'right', + label: '居右' + } + ], + clearValueOnHidden: true + }, + getSchemaTpl('theme:select', { + label: tipedLabel( + '距离', + '标题和最近左、右边框之间的距离,默认值5%' + ), + name: 'themeCss.titleWrapperControlClassName.flex-basis', + placeholder: '5%', + visibleOn: + 'data.titlePosition === "left" || data.titlePosition === "right"', + clearValueOnHidden: true + }), + getSchemaTpl('theme:font', { + title: '文字', + name: 'themeCss.titleControlClassName.font', + textAlign: false, + clearValueOnHidden: true + }), + getSchemaTpl('theme:paddingAndMargin', { + name: 'themeCss.titleControlClassName.padding-and-margin', + hidePadding: true, + clearValueOnHidden: true + }) + ] + } + ]) + } + ]); + }; } registerEditorPlugin(DividerPlugin); diff --git a/packages/amis-ui/scss/_components.scss b/packages/amis-ui/scss/_components.scss index 09d88bcd4..0c71d1841 100644 --- a/packages/amis-ui/scss/_components.scss +++ b/packages/amis-ui/scss/_components.scss @@ -2545,6 +2545,14 @@ --Divider-marginLeft: var(--sizes-size-0); --Divider-marginRight: var(--sizes-size-0); --Divider-marginBottom: var(--sizes-size-7); + --Divider-text-width: 5%; + --Divider-text-fontSize: var(--fonts-size-7); + --Divider-text-fontWeight: var(--fonts-weight-6); + --Divider-text-color: var(--colors-neutral-text-2); + --Divider-text-marginTop: var(--sizes-size-0); + --Divider-text-marginLeft: var(--sizes-size-9); + --Divider-text-marginRight: var(--sizes-size-9); + --Divider-text-marginBottom: var(--sizes-size-0); --inputFile-base-des-color: var(--colors-neutral-text-2); --inputFile-base-des-fontSize: var(--fonts-size-7); diff --git a/packages/amis-ui/scss/components/_divider.scss b/packages/amis-ui/scss/components/_divider.scss index ca9943ed0..af739d077 100644 --- a/packages/amis-ui/scss/components/_divider.scss +++ b/packages/amis-ui/scss/components/_divider.scss @@ -23,18 +23,53 @@ } &--horizontal { - border-bottom: var(--Divider-width) var(--Divider-style) - var(--Divider-color); + position: relative; height: px2rem(2px); + border-bottom: var(--Divider-width) var(--Divider-style) var(--Divider-color); + transform-origin: 0 center; + clear: both; } &--vertical { border-left: var(--Divider-width) var(--Divider-style) var(--Divider-color); height: var(--sizes-base-15); + transform-origin: center bottom; display: inline-block; } } +.#{$ns}Divider--with-text { + display: flex; + align-items: center; + height: unset; + border-bottom-width: 0 !important; + + &::before, + &::after { + content: ''; + height: 0; + flex: 1; + border-bottom: inherit; + border-bottom-width: var(--Divider-width); + } + + &.#{$ns}Divider--with-text-left:before, + &.#{$ns}Divider--with-text-right:after { + flex-basis: var(--Divider-text-width); + flex-grow: 0; + } +} + +.#{$ns}Divider-text { + margin: var(--Divider-text-marginTop) var(--Divider-text-marginRight) + var(--Divider-text-marginBottom) var(--Divider-text-marginLeft); + font-size: var(--Divider-text-fontSize); + font-weight: var(--Divider-text-fontWeight); + line-height: 1; + color: var(--Divider-text-color); + box-sizing: border-box; +} + /* 移动端样式调整 */ @include media-breakpoint-down(sm) { .#{$ns}Divider { diff --git a/packages/amis/src/renderers/Divider.tsx b/packages/amis/src/renderers/Divider.tsx index e50b3998b..cdc14e007 100644 --- a/packages/amis/src/renderers/Divider.tsx +++ b/packages/amis/src/renderers/Divider.tsx @@ -1,6 +1,13 @@ import React from 'react'; -import {Renderer, RendererProps} from 'amis-core'; -import {BaseSchema} from '../Schema'; +import { + Renderer, + RendererProps, + CustomStyle, + setThemeClassName, + isPureVariable, + resolveVariableAndFilter +} from 'amis-core'; +import {BaseSchema, SchemaCollection} from '../Schema'; /** * Divider 分割线渲染器。 @@ -12,6 +19,9 @@ export interface DividerSchema extends BaseSchema { direction?: 'horizontal' | 'vertical'; color?: string; rotate?: number; + title?: SchemaCollection; + titleClassName?: string; + titlePosition?: 'left' | 'center' | 'right'; [propName: string]: any; } @@ -20,20 +30,33 @@ export interface DividerProps Omit {} export default class Divider extends React.Component { - static defaultProps: Pick = { + static defaultProps: Pick< + DividerProps, + 'className' | 'lineStyle' | 'titleClassName' | 'titlePosition' + > = { className: '', - lineStyle: 'solid' + lineStyle: 'solid', + titleClassName: '', + titlePosition: 'center' }; render() { - const { + let { + render, classnames: cx, className, style = {}, lineStyle, direction, color, - rotate + rotate, + title, + titleClassName, + titlePosition, + id, + themeCss, + env, + data } = this.props; const borderColor: any = {}; @@ -46,22 +69,77 @@ export default class Divider extends React.Component { } } - let transform; + let transform = style?.transform || ''; if (rotate) { - transform = `${style?.transform || ''} rotate(${rotate}deg)`; + transform += ` rotate(${rotate}deg)`; } + + if (isPureVariable(title)) { + title = resolveVariableAndFilter(title, data); + } + + const classNames = cx( + 'Divider', + lineStyle ? `Divider--${lineStyle}` : '', + direction === 'vertical' ? 'Divider--vertical' : 'Divider--horizontal', + title && direction !== 'vertical' ? 'Divider--with-text' : '', + title && direction !== 'vertical' && titlePosition + ? `Divider--with-text-${titlePosition}` + : '', + title && direction !== 'vertical' + ? setThemeClassName('titleWrapperControlClassName', id, themeCss) + : '', + className + ); + return ( -
+
+ {title && direction !== 'vertical' ? ( + + {render('title', title)} + + ) : null} + +
); } }