diff --git a/packages/amis-editor/package.json b/packages/amis-editor/package.json index bda18ed18..c77abc33f 100644 --- a/packages/amis-editor/package.json +++ b/packages/amis-editor/package.json @@ -1,6 +1,6 @@ { "name": "amis-editor", - "version": "5.2.1-layout.1", + "version": "5.2.1-layout.2", "description": "amis 可视化编辑器", "main": "lib/index.js", "module": "esm/index.js", diff --git a/packages/amis-editor/src/index.tsx b/packages/amis-editor/src/index.tsx index d12fa0b44..efc3d22fc 100644 --- a/packages/amis-editor/src/index.tsx +++ b/packages/amis-editor/src/index.tsx @@ -138,6 +138,12 @@ import './plugin/CodeView'; import './plugin/WebComponent'; import './plugin/CRUD2'; import './plugin/ColumnToggler'; +import './plugin/Layout/Layout_fixed_bottom'; +import './plugin/Layout/Layout_fixed_top'; +import './plugin/Layout/Layout_fixed'; +import './plugin/Layout/Layout_scroll_x'; +import './plugin/Layout/Layout_scroll_y'; +import './plugin/Layout/Layout1_2_v4'; import {GridPlugin} from './plugin/Grid'; diff --git a/packages/amis-editor/src/plugin/Container.tsx b/packages/amis-editor/src/plugin/Container.tsx index af2fac168..f0b0691e3 100644 --- a/packages/amis-editor/src/plugin/Container.tsx +++ b/packages/amis-editor/src/plugin/Container.tsx @@ -40,6 +40,7 @@ export class ContainerPlugin extends BasePlugin { curRendererSchema?.direction === 'row' || curRendererSchema?.direction === 'row-reverse'; const isFlexItem = this.manager?.isFlexItem(context?.id); + const isFlexColumnItem = this.manager?.isFlexColumnItem(context?.id); return getSchemaTpl('tabs', [ { @@ -79,6 +80,7 @@ export class ContainerPlugin extends BasePlugin { title: '布局', body: [ isFlexItem ? getSchemaTpl('layout:flex', { + isFlexColumnItem, visibleOn: 'data.style && (data.style.position === "static" || data.style.position === "relative")', }) : null, isFlexItem ? getSchemaTpl('layout:flex-grow', { @@ -98,35 +100,60 @@ export class ContainerPlugin extends BasePlugin { getSchemaTpl('layout:flexDirection', { visibleOn: 'data.style && data.style.display === "flex"', }), + getSchemaTpl('layout:justifyContent', { - visibleOn: 'data.style && data.style.display === "flex"', - label: tipedLabel( - `${isRowContent ? '水平' : '垂直'}对齐方式`, - '设置子元素在主轴上的对齐方式' - ) + label: '水平对齐方式', + visibleOn: 'data.style && data.style.display === "flex" && data.style.flexDirection === "row" || data.style.flexDirection === "row-reverse"' + }), + getSchemaTpl('layout:justifyContent', { + label: '垂直对齐方式', + visibleOn: 'data.style && data.style.display === "flex" && (data.style.flexDirection === "column" || data.style.flexDirection === "column-reverse")' }), getSchemaTpl('layout:alignItems', { - visibleOn: 'data.style && data.style.display === "flex"', - label: tipedLabel( - `${isRowContent ? '垂直' : '水平'}对齐方式`, - '设置子元素在交叉轴上的对齐方式' - ) + label: '水平对齐方式', + visibleOn: 'data.style && data.style.display === "flex" && (data.style.flexDirection === "column" || data.style.flexDirection === "column-reverse")' }), + getSchemaTpl('layout:alignItems', { + label: '垂直对齐方式', + visibleOn: 'data.style && data.style.display === "flex" && (data.style.flexDirection === "row" || data.style.flexDirection === "row-reverse")' + }), + getSchemaTpl('layout:flex-wrap', { visibleOn: 'data.style && data.style.display === "flex"', }), - getSchemaTpl('layout:isFixedHeight'), - getSchemaTpl('layout:height'), - getSchemaTpl('layout:max-height'), - getSchemaTpl('layout:min-height'), - getSchemaTpl('layout:overflow-y'), + getSchemaTpl('layout:isFixedHeight', { + visibleOn: `${!isFlexItem || !isFlexColumnItem}` + }), + getSchemaTpl('layout:height', { + visibleOn: `${!isFlexItem || !isFlexColumnItem}` + }), + getSchemaTpl('layout:max-height', { + visibleOn: `${!isFlexItem || !isFlexColumnItem}` + }), + getSchemaTpl('layout:min-height', { + visibleOn: `${!isFlexItem || !isFlexColumnItem}` + }), + getSchemaTpl('layout:overflow-y', { + visibleOn: `${!isFlexItem || !isFlexColumnItem} && (data.isFixedHeight || data.style && data.style.maxHeight) || (${isFlexItem && isFlexColumnItem} && data.style.flex === '0 0 auto')`, + }), + + getSchemaTpl('layout:isFixedWidth', { + visibleOn: `${!isFlexItem || isFlexColumnItem}` + }), + getSchemaTpl('layout:width', { + visibleOn: `${!isFlexItem || isFlexColumnItem}` + }), + getSchemaTpl('layout:max-width', { + visibleOn: `${!isFlexItem || isFlexColumnItem}` + }), + getSchemaTpl('layout:min-width', { + visibleOn: `${!isFlexItem || isFlexColumnItem}` + }), + getSchemaTpl('layout:overflow-x', { + visibleOn: `${!isFlexItem || isFlexColumnItem} && (data.isFixedWidth || data.style && data.style.maxWidth) || (${isFlexItem && !isFlexColumnItem} && data.style.flex === '0 0 auto')`, + }), - getSchemaTpl('layout:isFixedWidth'), - getSchemaTpl('layout:width'), - getSchemaTpl('layout:max-width'), - getSchemaTpl('layout:min-width'), - getSchemaTpl('layout:overflow-x'), !isFlexItem ? getSchemaTpl('layout:margin-center') : null, ] }, diff --git a/packages/amis-editor/src/plugin/Layout/FlexPluginBase.tsx b/packages/amis-editor/src/plugin/Layout/FlexPluginBase.tsx index 520f1c1db..312b1caba 100644 --- a/packages/amis-editor/src/plugin/Layout/FlexPluginBase.tsx +++ b/packages/amis-editor/src/plugin/Layout/FlexPluginBase.tsx @@ -50,13 +50,14 @@ export class FlexPluginBase extends BasePlugin { disabledRendererPlugin = false; name = '布局容器'; + order = -1200; isBaseComponent = true; icon = 'fa fa-columns'; pluginIcon = 'flex-container-plugin'; description = '布局容器 是基于 CSS Flex 实现的布局效果,它比 Grid 和 HBox 对子节点位置的可控性更强,比用 CSS 类的方式更易用'; docLink = '/amis/zh-CN/components/flex'; - tags = ['容器']; + tags = ['常见布局']; scaffold: any = defaultFlexContainerSchema; previewSchema = { ...this.scaffold @@ -72,6 +73,7 @@ export class FlexPluginBase extends BasePlugin { curRendererSchema?.direction === 'row' || curRendererSchema?.direction === 'row-reverse'; const isFlexItem = this.manager?.isFlexItem(context?.id); + const isFlexColumnItem = this.manager?.isFlexColumnItem(context?.id); return [ getSchemaTpl('tabs', [ @@ -85,6 +87,7 @@ export class FlexPluginBase extends BasePlugin { body: [ isFlexItem ? getSchemaTpl('layout:flex', { + isFlexColumnItem, visibleOn: 'data.style && (data.style.position === "static" || data.style.position === "relative")' }) @@ -97,6 +100,7 @@ export class FlexPluginBase extends BasePlugin { : null, isFlexItem ? getSchemaTpl('layout:flex-basis', { + label: isFlexColumnItem ? '默认高度' : '默认宽度', visibleOn: 'data.style && (data.style.position === "static" || data.style.position === "relative")' }) @@ -110,33 +114,61 @@ export class FlexPluginBase extends BasePlugin { getSchemaTpl('layout:flexDirection', { name: 'direction' }), + getSchemaTpl('layout:justifyContent', { name: 'justify', - label: tipedLabel( - `${isRowContent ? '水平' : '垂直'}对齐方式`, - '设置子元素在主轴上的对齐方式' - ) + label: '水平对齐方式', + visibleOn: 'data.direction === "row" || data.direction === "row-reverse"' + }), + // 备注: 重复一个是为了能实时联动,后续需要amis优化,支持label使用公式表达式 + getSchemaTpl('layout:justifyContent', { + name: 'justify', + label: '垂直对齐方式', + visibleOn: 'data.direction === "column" || data.direction === "column-reverse"' }), getSchemaTpl('layout:alignItems', { name: 'alignItems', - label: tipedLabel( - `${isRowContent ? '垂直' : '水平'}对齐方式`, - '设置子元素在交叉轴上的对齐方式' - ) + label: '水平对齐方式', + visibleOn: 'data.direction === "column" || data.direction === "column-reverse"' + }), + getSchemaTpl('layout:alignItems', { + name: 'alignItems', + label: '垂直对齐方式', + visibleOn: 'data.direction === "row" || data.direction === "row-reverse"' }), getSchemaTpl('layout:flex-wrap'), - getSchemaTpl('layout:isFixedHeight'), - getSchemaTpl('layout:height'), - getSchemaTpl('layout:max-height'), - getSchemaTpl('layout:min-height'), - getSchemaTpl('layout:overflow-y'), + getSchemaTpl('layout:isFixedHeight', { + visibleOn: `${!isFlexItem || !isFlexColumnItem}` + }), + getSchemaTpl('layout:height', { + visibleOn: `${!isFlexItem || !isFlexColumnItem}` + }), + getSchemaTpl('layout:max-height', { + visibleOn: `${!isFlexItem || !isFlexColumnItem}` + }), + getSchemaTpl('layout:min-height', { + visibleOn: `${!isFlexItem || !isFlexColumnItem}` + }), + getSchemaTpl('layout:overflow-y', { + visibleOn: `${!isFlexItem || !isFlexColumnItem} && (data.isFixedHeight || data.style && data.style.maxHeight) || (${isFlexItem && isFlexColumnItem} && data.style.flex === '0 0 auto')`, + }), - getSchemaTpl('layout:isFixedWidth'), - getSchemaTpl('layout:width'), - getSchemaTpl('layout:max-width'), - getSchemaTpl('layout:min-width'), - getSchemaTpl('layout:overflow-x'), + getSchemaTpl('layout:isFixedWidth', { + visibleOn: `${!isFlexItem || isFlexColumnItem}` + }), + getSchemaTpl('layout:width', { + visibleOn: `${!isFlexItem || isFlexColumnItem}` + }), + getSchemaTpl('layout:max-width', { + visibleOn: `${!isFlexItem || isFlexColumnItem}` + }), + getSchemaTpl('layout:min-width', { + visibleOn: `${!isFlexItem || isFlexColumnItem}` + }), + getSchemaTpl('layout:overflow-x', { + visibleOn: `${!isFlexItem || isFlexColumnItem} && (data.isFixedWidth || data.style && data.style.maxWidth) || (${isFlexItem && !isFlexColumnItem} && data.style.flex === '0 0 auto')`, + }), !isFlexItem ? getSchemaTpl('layout:margin-center') : null ] diff --git a/packages/amis-editor/src/plugin/Layout/Layout1_2_v4.tsx b/packages/amis-editor/src/plugin/Layout/Layout1_2_v4.tsx new file mode 100644 index 000000000..dbf866c33 --- /dev/null +++ b/packages/amis-editor/src/plugin/Layout/Layout1_2_v4.tsx @@ -0,0 +1,110 @@ +import {registerEditorPlugin} from 'amis-editor-core'; +import {FlexPluginBase} from './FlexPluginBase'; + +export default class Layout1_2_v4 extends FlexPluginBase { + name = '经典布局'; + isBaseComponent = true; + pluginIcon = 'layout-3-1-plugin'; + description = '常见布局:经典布局(基于 CSS Flex 实现的布局容器)。'; + tags = ['常见布局']; + order = 307; + scaffold: any = { + type: 'flex', + className: 'p-1', + items: [ + { + type: 'wrapper', + size: 'xs', + body: [], + style: { + flex: '0 0 auto', + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + alignItems: 'stretch' + } + }, + { + type: 'flex', + items: [ + { + type: 'wrapper', + size: 'xs', + body: [], + style: { + flex: '0 0 auto', + flexBasis: '250px', + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + alignItems: 'stretch' + } + }, + { + type: 'flex', + items: [ + { + type: 'wrapper', + size: 'xs', + body: [], + style: { + flex: '1 1 auto', + flexBasis: 'auto', + flexGrow: 1, + display: 'block' + } + }, + { + type: 'wrapper', + size: 'xs', + body: [], + style: { + flex: '1 1 auto', + flexBasis: 'auto', + flexGrow: 1, + display: 'block' + } + } + ], + style: { + position: 'static', + overflowX: 'auto', + overflowY: 'auto', + margin: '0', + flex: '1 1 auto', + flexGrow: 1, + flexBasis: 'auto' + }, + alignItems: 'stretch', + direction: 'column', + justify: 'center', + isFixedHeight: false, + isFixedWidth: false + } + ], + style: { + flex: '1 1 auto', + overflowX: 'auto', + margin: '0', + maxWidth: 'auto', + overflowY: 'auto', + position: 'static', + minWidth: 'auto', + width: 'auto', + maxHeight: 'auto', + minHeight: '300px' + }, + direction: 'row', + justify: 'flex-start', + alignItems: 'stretch', + isFixedHeight: false, + isFixedWidth: false + } + ], + direction: 'column', + justify: 'center', + alignItems: 'stretch' + }; +} + +registerEditorPlugin(Layout1_2_v4); \ No newline at end of file diff --git a/packages/amis-editor/src/plugin/Layout/Layout_fixed.tsx b/packages/amis-editor/src/plugin/Layout/Layout_fixed.tsx new file mode 100644 index 000000000..c490fc376 --- /dev/null +++ b/packages/amis-editor/src/plugin/Layout/Layout_fixed.tsx @@ -0,0 +1,29 @@ +import {registerEditorPlugin} from 'amis-editor-core'; +import {FlexPluginBase} from './FlexPluginBase'; + +export default class Layout_fixed extends FlexPluginBase { + name = '悬浮容器'; + isBaseComponent = true; + pluginIcon = 'layout-fixed-plugin'; + description = '常见布局:悬浮容器(基于 CSS Flex 实现的布局容器)。'; + tags = ['常见布局']; + order = 503; + scaffold: any = { + type: 'wrapper', + size: 'xs', + body: [], + style: { + position: 'fixed', + inset: 'auto 50px 50px auto', + zIndex: 10, + display: 'flex', + minWidth: '80px', + minHeight: '80px', + flexDirection: 'column', + justifyContent: 'flex-start', + alignItems: 'stretch' + } + }; +} + +registerEditorPlugin(Layout_fixed); \ No newline at end of file diff --git a/packages/amis-editor/src/plugin/Layout/Layout_fixed_bottom.tsx b/packages/amis-editor/src/plugin/Layout/Layout_fixed_bottom.tsx new file mode 100644 index 000000000..f7af09412 --- /dev/null +++ b/packages/amis-editor/src/plugin/Layout/Layout_fixed_bottom.tsx @@ -0,0 +1,76 @@ +import {registerEditorPlugin} from 'amis-editor-core'; +import {FlexPluginBase} from './FlexPluginBase'; + +export default class Layout_fixed_bottom extends FlexPluginBase { + name = '吸底容器'; + isBaseComponent = true; + pluginIcon = 'flex-container-plugin'; + description = '常见布局:吸底容器(基于 CSS Flex 实现的布局容器)。'; + tags = ['常见布局']; + order = 501; + scaffold: any = { + type: 'flex', + className: 'p-1', + items: [ + { + type: 'wrapper', + size: 'xs', + body: [], + style: { + flex: '1 1 auto', + flexBasis: 'auto', + flexGrow: 1, + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + alignItems: 'stretch' + } + }, + { + type: 'wrapper', + size: 'xs', + body: [], + style: { + flex: '1 1 auto', + flexBasis: 'auto', + flexGrow: 1, + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + alignItems: 'stretch' + } + }, + { + type: 'wrapper', + size: 'xs', + body: [], + style: { + flex: '1 1 auto', + flexBasis: 'auto', + flexGrow: 1, + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + alignItems: 'stretch' + } + } + ], + style: { + position: 'fixed', + inset: 'auto auto 0 0', + zIndex: 2, + width: '100%', + overflowX: 'auto', + margin: '0', + overflowY: 'auto', + height: 'auto' + }, + isFixedWidth: true, + direction: 'row', + justify: 'center', + alignItems: 'stretch', + isFixedHeight: false + }; +} + +registerEditorPlugin(Layout_fixed_bottom); \ No newline at end of file diff --git a/packages/amis-editor/src/plugin/Layout/Layout_fixed_top.tsx b/packages/amis-editor/src/plugin/Layout/Layout_fixed_top.tsx new file mode 100644 index 000000000..b114b59c2 --- /dev/null +++ b/packages/amis-editor/src/plugin/Layout/Layout_fixed_top.tsx @@ -0,0 +1,66 @@ +import {registerEditorPlugin} from 'amis-editor-core'; +import {FlexPluginBase} from './FlexPluginBase'; + +export default class Layout_fixed_top extends FlexPluginBase { + name = '吸顶容器'; + isBaseComponent = true; + pluginIcon = 'flex-container-plugin'; + description = '常见布局:吸顶容器(基于 CSS Flex 实现的布局容器)。'; + tags = ['常见布局']; + order = 502; + scaffold: any = { + type: 'flex', + className: 'p-1', + items: [ + { + type: 'wrapper', + size: 'xs', + body: [], + style: { + flex: '1 1 auto', + flexBasis: 'auto', + flexGrow: 1, + display: 'block' + } + }, + { + type: 'wrapper', + size: 'xs', + body: [], + style: { + flex: '1 1 auto', + flexBasis: 'auto', + flexGrow: 1, + display: 'block' + } + }, + { + type: 'wrapper', + size: 'xs', + body: [], + style: { + flex: '1 1 auto', + display: 'block', + flexBasis: 'auto', + flexGrow: 1 + } + } + ], + style: { + position: 'fixed', + inset: '0 auto auto 0', + zIndex: 10, + width: '100%', + overflowX: 'auto', + margin: '0', + overflowY: 'auto' + }, + isFixedWidth: true, + direction: 'row', + justify: 'center', + alignItems: 'stretch', + isFixedHeight: false + }; +} + +registerEditorPlugin(Layout_fixed_top); diff --git a/packages/amis-editor/src/plugin/Layout/Layout_scroll_x.tsx b/packages/amis-editor/src/plugin/Layout/Layout_scroll_x.tsx new file mode 100644 index 000000000..c6e4f2837 --- /dev/null +++ b/packages/amis-editor/src/plugin/Layout/Layout_scroll_x.tsx @@ -0,0 +1,146 @@ +import {registerEditorPlugin} from 'amis-editor-core'; +import {FlexPluginBase} from './FlexPluginBase'; + +export default class Layout_scroll_x extends FlexPluginBase { + name = 'x轴滚动容器'; + isBaseComponent = true; + pluginIcon = 'layout-3cols-plugin'; + description = '常见布局:x轴滚动容器(基于 CSS Flex 实现的布局容器)。'; + tags = ['常见布局']; + order = 505; + scaffold: any = { + type: 'flex', + className: 'p-1', + items: [ + { + type: 'wrapper', + size: 'xs', + body: [], + style: { + flex: '0 0 auto', + flexBasis: '200px', + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + alignItems: 'stretch', + position: 'static', + minWidth: 'auto', + minHeight: 'auto' + } + }, + { + type: 'wrapper', + size: 'xs', + body: [], + style: { + flex: '0 0 auto', + flexBasis: '200px', + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + alignItems: 'stretch', + position: 'static', + minWidth: 'auto', + minHeight: 'auto' + } + }, + { + type: 'wrapper', + size: 'xs', + body: [], + style: { + flex: '0 0 auto', + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + alignItems: 'stretch', + position: 'static', + minWidth: 'auto', + minHeight: 'auto', + flexBasis: '200px' + } + }, + { + type: 'wrapper', + size: 'xs', + body: [], + style: { + flex: '0 0 auto', + flexBasis: '200px', + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + alignItems: 'stretch', + position: 'static', + minWidth: 'auto', + minHeight: 'auto' + } + }, + { + type: 'wrapper', + size: 'xs', + body: [], + style: { + flex: '0 0 auto', + flexBasis: '200px', + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + alignItems: 'stretch', + position: 'static', + minWidth: 'auto', + minHeight: 'auto' + } + }, + { + type: 'wrapper', + size: 'xs', + body: [], + style: { + flex: '0 0 auto', + flexBasis: '200px', + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + alignItems: 'stretch', + position: 'static', + minWidth: 'auto', + minHeight: 'auto' + } + }, + { + type: 'wrapper', + size: 'xs', + body: [], + style: { + flex: '0 0 auto', + flexBasis: '200px', + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + alignItems: 'stretch', + position: 'static', + minWidth: 'auto', + minHeight: 'auto' + } + } + ], + direction: 'row', + justify: 'flex-start', + alignItems: 'stretch', + style: { + position: 'static', + minHeight: 'auto', + maxWidth: '1080px', + minWidth: 'auto', + height: '200px', + overflowX: 'scroll', + overflowY: 'scroll', + margin: '0 auto' + }, + isFixedHeight: true, + isFixedWidth: false + }; +} + +registerEditorPlugin(Layout_scroll_x); \ No newline at end of file diff --git a/packages/amis-editor/src/plugin/Layout/Layout_scroll_y.tsx b/packages/amis-editor/src/plugin/Layout/Layout_scroll_y.tsx new file mode 100644 index 000000000..3e96025d1 --- /dev/null +++ b/packages/amis-editor/src/plugin/Layout/Layout_scroll_y.tsx @@ -0,0 +1,130 @@ +import {registerEditorPlugin} from 'amis-editor-core'; +import {FlexPluginBase} from './FlexPluginBase'; + +export default class Layout_scroll_y extends FlexPluginBase { + name = 'y轴滚动容器'; + isBaseComponent = true; + pluginIcon = 'layout-3row-plugin'; + description = '常见布局:y轴滚动容器(基于 CSS Flex 实现的布局容器)。'; + tags = ['常见布局']; + order = 504; + scaffold: any = { + type: 'flex', + className: 'p-1', + items: [ + { + type: 'wrapper', + size: 'xs', + body: [], + style: { + flex: '0 0 auto', + flexBasis: '60px', + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + alignItems: 'stretch', + minWidth: 'auto', + minHeight: 'auto' + } + }, + { + type: 'wrapper', + size: 'xs', + body: [], + style: { + flex: '0 0 auto', + flexBasis: '60px', + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + alignItems: 'stretch', + position: 'static', + minWidth: 'auto', + minHeight: 'auto' + } + }, + { + type: 'wrapper', + size: 'xs', + body: [], + style: { + flex: '0 0 auto', + flexBasis: '60px', + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + alignItems: 'stretch', + position: 'static', + minWidth: 'auto', + minHeight: 'auto' + } + }, + { + type: 'wrapper', + size: 'xs', + body: [], + style: { + flex: '0 0 auto', + flexBasis: '60px', + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + alignItems: 'stretch', + position: 'static', + minWidth: 'auto', + minHeight: 'auto' + } + }, + { + type: 'wrapper', + size: 'xs', + body: [], + style: { + flex: '0 0 auto', + flexBasis: '60px', + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + alignItems: 'stretch', + position: 'static', + minWidth: 'auto', + minHeight: 'auto' + } + }, + { + type: 'wrapper', + size: 'xs', + body: [], + style: { + flex: '0 0 auto', + flexBasis: '60px', + display: 'flex', + flexDirection: 'column', + justifyContent: 'flex-start', + alignItems: 'stretch', + position: 'static', + minWidth: 'auto', + minHeight: 'auto' + } + } + ], + direction: 'column', + justify: 'flex-start', + alignItems: 'stretch', + style: { + position: 'static', + minHeight: 'auto', + maxWidth: 'auto', + minWidth: 'auto', + height: '200px', + width: 'auto', + overflowX: 'auto', + overflowY: 'scroll', + margin: '0' + }, + isFixedHeight: true, + isFixedWidth: false + }; +} + +registerEditorPlugin(Layout_scroll_y); \ No newline at end of file diff --git a/packages/amis-editor/src/plugin/Wrapper.tsx b/packages/amis-editor/src/plugin/Wrapper.tsx index d0050b379..18ca1c766 100644 --- a/packages/amis-editor/src/plugin/Wrapper.tsx +++ b/packages/amis-editor/src/plugin/Wrapper.tsx @@ -37,6 +37,7 @@ export class WrapperPlugin extends BasePlugin { panelBodyCreator = (context: BaseEventContext) => { const curRendererSchema = context?.schema; const isFlexItem = this.manager?.isFlexItem(context?.id); + const isFlexColumnItem = this.manager?.isFlexColumnItem(context?.id); return [ getSchemaTpl('tabs', [ @@ -49,12 +50,14 @@ export class WrapperPlugin extends BasePlugin { title: '布局', body: [ isFlexItem ? getSchemaTpl('layout:flex', { + isFlexColumnItem, visibleOn: 'data.style && (data.style.position === "static" || data.style.position === "relative")', }) : null, isFlexItem ? getSchemaTpl('layout:flex-grow', { visibleOn: 'data.style && data.style.flex !== "0 0 auto" && (data.style.position === "static" || data.style.position === "relative")', }) : null, isFlexItem ? getSchemaTpl('layout:flex-basis', { + label: isFlexColumnItem ? '默认高度' : '默认宽度', visibleOn: 'data.style && (data.style.position === "static" || data.style.position === "relative")', }) : null, getSchemaTpl('layout:position'), @@ -67,27 +70,59 @@ export class WrapperPlugin extends BasePlugin { getSchemaTpl('layout:flexDirection', { visibleOn: 'data.style && data.style.display === "flex"', }), + getSchemaTpl('layout:justifyContent', { - visibleOn: 'data.style && data.style.display === "flex"', + label: '水平对齐方式', + visibleOn: 'data.style && data.style.display === "flex" && data.style.flexDirection === "row" || data.style.flexDirection === "row-reverse"' + }), + getSchemaTpl('layout:justifyContent', { + label: '垂直对齐方式', + visibleOn: 'data.style && data.style.display === "flex" && (data.style.flexDirection === "column" || data.style.flexDirection === "column-reverse")' }), getSchemaTpl('layout:alignItems', { - visibleOn: 'data.style && data.style.display === "flex"', + label: '水平对齐方式', + visibleOn: 'data.style && data.style.display === "flex" && (data.style.flexDirection === "column" || data.style.flexDirection === "column-reverse")' }), + getSchemaTpl('layout:alignItems', { + label: '垂直对齐方式', + visibleOn: 'data.style && data.style.display === "flex" && (data.style.flexDirection === "row" || data.style.flexDirection === "row-reverse")' + }), + getSchemaTpl('layout:flex-wrap', { visibleOn: 'data.style && data.style.display === "flex"', }), - getSchemaTpl('layout:isFixedHeight'), - getSchemaTpl('layout:height'), - getSchemaTpl('layout:max-height'), - getSchemaTpl('layout:min-height'), - getSchemaTpl('layout:overflow-y'), + getSchemaTpl('layout:isFixedHeight', { + visibleOn: `${!isFlexItem || !isFlexColumnItem}` + }), + getSchemaTpl('layout:height', { + visibleOn: `${!isFlexItem || !isFlexColumnItem}` + }), + getSchemaTpl('layout:max-height', { + visibleOn: `${!isFlexItem || !isFlexColumnItem}` + }), + getSchemaTpl('layout:min-height', { + visibleOn: `${!isFlexItem || !isFlexColumnItem}` + }), + getSchemaTpl('layout:overflow-y', { + visibleOn: `${!isFlexItem || !isFlexColumnItem} && (data.isFixedHeight || data.style && data.style.maxHeight) || (${isFlexItem && isFlexColumnItem} && data.style.flex === '0 0 auto')`, + }), - getSchemaTpl('layout:isFixedWidth'), - getSchemaTpl('layout:width'), - getSchemaTpl('layout:max-width'), - getSchemaTpl('layout:min-width'), - getSchemaTpl('layout:overflow-x'), + getSchemaTpl('layout:isFixedWidth', { + visibleOn: `${!isFlexItem || isFlexColumnItem}` + }), + getSchemaTpl('layout:width', { + visibleOn: `${!isFlexItem || isFlexColumnItem}` + }), + getSchemaTpl('layout:max-width', { + visibleOn: `${!isFlexItem || isFlexColumnItem}` + }), + getSchemaTpl('layout:min-width', { + visibleOn: `${!isFlexItem || isFlexColumnItem}` + }), + getSchemaTpl('layout:overflow-x', { + visibleOn: `${!isFlexItem || isFlexColumnItem} && (data.isFixedWidth || data.style && data.style.maxWidth) || (${isFlexItem && !isFlexColumnItem} && data.style.flex === '0 0 auto')`, + }), !isFlexItem ? getSchemaTpl('layout:margin-center') : null, ] diff --git a/packages/amis-editor/src/tpl/layout.tsx b/packages/amis-editor/src/tpl/layout.tsx index a3b544257..647a442e7 100644 --- a/packages/amis-editor/src/tpl/layout.tsx +++ b/packages/amis-editor/src/tpl/layout.tsx @@ -506,28 +506,35 @@ setSchemaTpl( name?: string; value?: string, visibleOn?: string; + isFlexColumnItem?: boolean; }) => { return { type: 'switch', - label: config?.label || tipedLabel('弹性模式', '设置为弹性模式后,自动适配当前所在区域'), + label: config?.label || tipedLabel('弹性模式', '开启弹性模式后,自动适配当前所在区域'), name: config?.name || 'style.flex', value: config?.value || '0 0 auto', trueValue: '1 1 auto', falseValue: '0 0 auto', - onText: "弹性宽度", - offText: "固定宽度", + onText: "开启", + offText: "关闭", inputClassName: 'inline-flex justify-between', visibleOn: config?.visibleOn, onChange: (value: any, oldValue: boolean, model: any, form: any) => { if (!value || value === '0 0 auto') { - // 固定宽度模式下,剔除默认宽度和占比设置 + // 固定宽度模式下,剔除占比设置 form.setValueByName('style.flexGrow', undefined); } + // 重置overflow数值 + if (config?.isFlexColumnItem) { + form.setValueByName('style.overflowY', 'auto'); + } else { + form.setValueByName('style.overflowX', 'auto'); + } }, }; }); -// flex-basis默认宽度设置 +// flex-basis设置 setSchemaTpl( 'layout:flex-basis', (config?: { @@ -541,7 +548,7 @@ setSchemaTpl( }) => { return { type: 'input-number', - label: config?.label || tipedLabel('默认宽度', '在分配多余空间之前,其默认占据的主轴空间(main size)'), + label: tipedLabel(config?.label || '默认宽度', '在分配多余空间之前,其默认占据的主轴空间(main size)'), name: config?.name || 'style.flexBasis', value: config?.value || 'auto', visibleOn: config?.visibleOn, @@ -576,6 +583,156 @@ setSchemaTpl( }; }); +// 是否固定宽度: isFixedWidth 配置: +setSchemaTpl( + 'layout:isFixedWidth', + (config?: { + label?: string; + name?: string; + value?: string, + visibleOn?: string; + pipeIn?: (value: any, data: any) => void; + pipeOut?: (value: any, data: any) => void; + }) => { + return { + type: 'switch', + label: config?.label || '固定宽度', + name: config?.name || 'isFixedWidth', + value: config?.value || false, + visibleOn: config?.visibleOn, + inputClassName: 'inline-flex justify-between', + pipeIn: config?.pipeIn, + pipeOut: config?.pipeOut, + onChange: (value: boolean, oldValue: boolean, model: any, form: any) => { + if (value) { + // 固定宽度时,剔除最大宽度、最小宽度 + form.setValueByName('style.maxWidth', undefined); + form.setValueByName('style.minWidth', undefined); + } else { + // 非固定宽度时,剔除宽度数值 + form.setValueByName('style.width', undefined); + } + }, + }; +}); + +// 宽度设置 +setSchemaTpl( + 'layout:width', + (config?: { + label?: string; + name?: string; + value?: string, + visibleOn?: string; + unitOptions?: Array; + pipeIn?: (value: any, data: any) => void; + pipeOut?: (value: any, data: any) => void; + }) => { + return { + type: 'input-number', + label: config?.label || '宽度', + name: config?.name || 'style.width', + value: config?.value || '300px', + visibleOn: config?.visibleOn ? `${config?.visibleOn} && data.isFixedWidth` : 'data.isFixedWidth', + clearable: true, + unitOptions: config?.unitOptions ?? LayoutUnitOptions, + pipeIn: config?.pipeIn, + pipeOut: config?.pipeOut, + }; +}); + +// 最大宽度设置 +setSchemaTpl( + 'layout:max-width', + (config?: { + label?: string; + name?: string; + value?: string, + visibleOn?: string; + unitOptions?: Array; + pipeIn?: (value: any, data: any) => void; + pipeOut?: (value: any, data: any) => void; + }) => { + return { + type: 'input-number', + label: config?.label || tipedLabel('最大宽度', '最大宽度即当前元素最大的水平展示区域'), + name: config?.name || 'style.maxWidth', + value: config?.value, + min: '${style.minWidth | toInt}', + visibleOn: config?.visibleOn ? `${config?.visibleOn} && !data.isFixedWidth` : '!data.isFixedWidth', + clearable: true, + unitOptions: config?.unitOptions ?? LayoutUnitOptions, + pipeIn: config?.pipeIn, + pipeOut: config?.pipeOut, + }; +}); + +// 最小宽度设置 +setSchemaTpl( + 'layout:min-width', + (config?: { + label?: string; + name?: string; + value?: string, + visibleOn?: string; + unitOptions?: Array; + pipeIn?: (value: any, data: any) => void; + pipeOut?: (value: any, data: any) => void; + }) => { + return { + type: 'input-number', + label: config?.label || tipedLabel('最小宽度', '最小宽度即当前元素最小的水平展示区域'), + name: config?.name || 'style.minWidth', + value: config?.value, + max: '${style.maxWidth | toInt}', + visibleOn: config?.visibleOn ? `${config?.visibleOn} && !data.isFixedWidth` : '!data.isFixedWidth', + clearable: true, + unitOptions: config?.unitOptions ?? LayoutUnitOptions, + pipeIn: config?.pipeIn, + pipeOut: config?.pipeOut, + }; +}); + +// x轴(水平轴)滚动模式 +setSchemaTpl( + 'layout:overflow-x', + (config?: { + label?: string; + name?: string; + value?: string, + visibleOn?: string; + pipeIn?: (value: any, data: any) => void; + pipeOut?: (value: any, data: any) => void; + }) => { + return { + type: 'select', + label: config?.label || tipedLabel(' x轴滚动模式', '用于设置水平方向的滚动模式'), + name: config?.name || 'style.overflowX', + value: config?.value || 'auto', + visibleOn: config?.visibleOn, + pipeIn: config?.pipeIn, + pipeOut: config?.pipeOut, + options: [ + { + label: '超出显示', + value: 'visible' + }, + { + label: '超出隐藏', + value: 'hidden' + }, + { + label: '滚动显示', + value: 'scroll' + }, + { + label: '自动适配', + value: 'auto' + }, + ] + }; +}); + // 是否固定高度: isFixedHeight 配置: setSchemaTpl( 'layout:isFixedHeight', @@ -609,156 +766,6 @@ setSchemaTpl( }; }); -// 宽度设置 -setSchemaTpl( - 'layout:width', - (config?: { - label?: string; - name?: string; - value?: string, - visibleOn?: string; - unitOptions?: Array; - pipeIn?: (value: any, data: any) => void; - pipeOut?: (value: any, data: any) => void; - }) => { - return { - type: 'input-number', - label: config?.label || '宽度', - name: config?.name || 'style.width', - value: config?.value || '300px', - visibleOn: config?.visibleOn ?? 'data.isFixedWidth', - clearable: true, - unitOptions: config?.unitOptions ?? LayoutUnitOptions, - pipeIn: config?.pipeIn, - pipeOut: config?.pipeOut, - }; -}); - -// x轴(水平轴)滚动模式 -setSchemaTpl( - 'layout:overflow-x', - (config?: { - label?: string; - name?: string; - value?: string, - visibleOn?: string; - pipeIn?: (value: any, data: any) => void; - pipeOut?: (value: any, data: any) => void; - }) => { - return { - type: 'select', - label: config?.label || tipedLabel(' x轴滚动模式', '用于设置水平方向的滚动模式'), - name: config?.name || 'style.overflowX', - value: config?.value || 'auto', - visibleOn: config?.visibleOn ?? 'data.isFixedWidth || data.style && data.style.maxWidth', - pipeIn: config?.pipeIn, - pipeOut: config?.pipeOut, - options: [ - { - label: '超出显示', - value: 'visible' - }, - { - label: '超出隐藏', - value: 'hidden' - }, - { - label: '滚动显示', - value: 'scroll' - }, - { - label: '自动适配', - value: 'auto' - }, - ] - }; -}); - -// 最大宽度设置 -setSchemaTpl( - 'layout:max-width', - (config?: { - label?: string; - name?: string; - value?: string, - visibleOn?: string; - unitOptions?: Array; - pipeIn?: (value: any, data: any) => void; - pipeOut?: (value: any, data: any) => void; - }) => { - return { - type: 'input-number', - label: config?.label || tipedLabel('最大宽度', '最大宽度即当前元素最大的水平展示区域'), - name: config?.name || 'style.maxWidth', - value: config?.value, - min: '${style.minWidth | toInt}', - visibleOn: config?.visibleOn ?? '!data.isFixedWidth', - clearable: true, - unitOptions: config?.unitOptions ?? LayoutUnitOptions, - pipeIn: config?.pipeIn, - pipeOut: config?.pipeOut, - }; -}); - -// 最小宽度设置 -setSchemaTpl( - 'layout:min-width', - (config?: { - label?: string; - name?: string; - value?: string, - visibleOn?: string; - unitOptions?: Array; - pipeIn?: (value: any, data: any) => void; - pipeOut?: (value: any, data: any) => void; - }) => { - return { - type: 'input-number', - label: config?.label || tipedLabel('最小宽度', '最小宽度即当前元素最小的水平展示区域'), - name: config?.name || 'style.minWidth', - value: config?.value, - max: '${style.maxWidth | toInt}', - visibleOn: config?.visibleOn ?? '!data.isFixedWidth', - clearable: true, - unitOptions: config?.unitOptions ?? LayoutUnitOptions, - pipeIn: config?.pipeIn, - pipeOut: config?.pipeOut, - }; -}); - -// 是否固定高度: isFixedWidth 配置: -setSchemaTpl( - 'layout:isFixedWidth', - (config?: { - label?: string; - name?: string; - value?: string, - visibleOn?: string; - pipeIn?: (value: any, data: any) => void; - pipeOut?: (value: any, data: any) => void; - }) => { - return { - type: 'switch', - label: config?.label || '固定宽度', - name: config?.name || 'isFixedWidth', - value: config?.value || false, - visibleOn: config?.visibleOn, - inputClassName: 'inline-flex justify-between', - pipeIn: config?.pipeIn, - pipeOut: config?.pipeOut, - onChange: (value: boolean, oldValue: boolean, model: any, form: any) => { - if (value) { - // 固定宽度时,剔除最大宽度、最小宽度 - form.setValueByName('style.maxWidth', undefined); - form.setValueByName('style.minWidth', undefined); - } else { - // 非固定宽度时,剔除宽度数值 - form.setValueByName('style.width', undefined); - } - }, - }; -}); - // 高度设置 setSchemaTpl( 'layout:height', @@ -776,7 +783,7 @@ setSchemaTpl( label: config?.label || '高度', name: config?.name || 'style.height', value: config?.value || '300px', - visibleOn: config?.visibleOn ?? 'data.isFixedHeight', + visibleOn: config?.visibleOn ? `${config?.visibleOn} && data.isFixedHeight` : 'data.isFixedHeight', clearable: true, unitOptions: config?.unitOptions ?? LayoutUnitOptions, pipeIn: config?.pipeIn, @@ -802,7 +809,7 @@ setSchemaTpl( name: config?.name || 'style.maxHeight', value: config?.value, min: '${style.minHeight | toInt}', - visibleOn: config?.visibleOn ?? '!data.isFixedHeight', + visibleOn: config?.visibleOn ? `${config?.visibleOn} && !data.isFixedHeight` : '!data.isFixedHeight', clearable: true, unitOptions: config?.unitOptions ?? LayoutUnitOptions, pipeIn: config?.pipeIn, @@ -828,7 +835,7 @@ setSchemaTpl( name: config?.name || 'style.minHeight', value: config?.value, max: '${style.maxHeight | toInt}', - visibleOn: config?.visibleOn ?? '!data.isFixedHeight', + visibleOn: config?.visibleOn ? `${config?.visibleOn} && !data.isFixedHeight` : '!data.isFixedHeight', clearable: true, unitOptions: config?.unitOptions ?? LayoutUnitOptions, pipeIn: config?.pipeIn, @@ -852,7 +859,7 @@ setSchemaTpl( label: config?.label || tipedLabel(' y轴滚动模式', '用于设置垂直方向的滚动模式'), name: config?.name || 'style.overflowY', value: config?.value || 'auto', - visibleOn: config?.visibleOn ?? 'data.isFixedHeight || data.style && data.style.maxHeight', + visibleOn: config?.visibleOn, pipeIn: config?.pipeIn, pipeOut: config?.pipeOut, options: [