diff --git a/packages/designer/src/builtin-simulator/host-view.tsx b/packages/designer/src/builtin-simulator/host-view.tsx
index fe89c0a35..b5b5640d0 100644
--- a/packages/designer/src/builtin-simulator/host-view.tsx
+++ b/packages/designer/src/builtin-simulator/host-view.tsx
@@ -1,5 +1,5 @@
import React, { Component } from 'react';
-import { observer } from '@ali/lowcode-editor-core';
+import { observer, globalContext } from '@ali/lowcode-editor-core';
import { BuiltinSimulatorHost, BuiltinSimulatorProps } from './host';
import { BemTools } from './bem-tools';
import { Project } from '../project';
@@ -73,14 +73,43 @@ class Canvas extends Component<{ host: BuiltinSimulatorHost }> {
@observer
class Content extends Component<{ host: BuiltinSimulatorHost }> {
+ state = {
+ disabledEvents: false,
+ };
+
+ private dispose?: () => void;
+
+ componentDidMount() {
+ const editor = globalContext.get('editor');
+ const onEnableEvents = (type: boolean) => {
+ this.setState({
+ disabledEvents: type,
+ });
+ };
+
+ editor.on('designer.builtinSimulator.disabledEvents', onEnableEvents);
+
+ this.dispose = () => {
+ editor.removeListener('designer.builtinSimulator.disabledEvents', onEnableEvents);
+ };
+ }
+
+ componentWillUnmount() {
+ this.dispose?.();
+ }
+
render() {
const sim = this.props.host;
+ const { disabledEvents } = this.state;
const { viewport } = sim;
- const frameStyle = {
+ const frameStyle: any = {
transform: `scale(${viewport.scale})`,
height: viewport.contentHeight,
width: viewport.contentWidth,
};
+ if (disabledEvents) {
+ frameStyle.pointerEvents = 'none';
+ }
return (
diff --git a/packages/editor-skeleton/src/components/draggable-line/index.less b/packages/editor-skeleton/src/components/draggable-line/index.less
new file mode 100644
index 000000000..ea27b2d9a
--- /dev/null
+++ b/packages/editor-skeleton/src/components/draggable-line/index.less
@@ -0,0 +1,15 @@
+.lc-draggable-line-vertical {
+ position: absolute;
+ width: 4px;
+ height: 100%;
+ background-color: transparent;
+ cursor: col-resize;
+}
+
+.lc-draggable-line-horizontal {
+ position: absolute;
+ width: 100%;
+ height: 4px;
+ background-color: transparent;
+ cursor: row-resize;
+}
diff --git a/packages/editor-skeleton/src/components/draggable-line/index.tsx b/packages/editor-skeleton/src/components/draggable-line/index.tsx
new file mode 100644
index 000000000..e3871c35f
--- /dev/null
+++ b/packages/editor-skeleton/src/components/draggable-line/index.tsx
@@ -0,0 +1,146 @@
+import { Component } from 'react';
+import classNames from 'classnames';
+import './index.less';
+
+export interface DraggableLineProps {
+ onDrag: (l: number, e: any) => any;
+ onDragStart?: () => any;
+ onDragEnd?: () => any;
+ position?: 'right' | 'left' | 'top';
+ className?: string;
+ maxIncrement?: number;
+ maxDecrement?: number;
+}
+
+export default class DraggableLine extends Component
{
+ static displayName = 'DraggableLine';
+
+ static defaultProps = {
+ onDrag() {},
+ position: 'right',
+ className: '',
+ maxIncrement: 100,
+ maxDecrement: 0,
+ };
+
+ private startDrag: boolean;
+ private canDrag: boolean;
+ private offset: number;
+ private currentOffset: number;
+ private offEvent: any;
+ private offDragEvent: any;
+ private startOffset: any;
+ private shell: HTMLElement | null = null;
+
+ constructor(props: DraggableLineProps) {
+ super(props);
+ this.startDrag = false;
+ this.canDrag = false;
+ this.offset = 0;
+ this.currentOffset = 0;
+ }
+
+ componentDidMount() {
+ this.offEvent = this.initEvent();
+ }
+
+ componentWillUnmount() {
+ if (this.offEvent) {
+ this.offEvent();
+ }
+ }
+
+ onSelectStart(e: any) {
+ if (this.startDrag) {
+ e.preventDefault();
+ }
+ }
+
+ onStartMove(e: any) {
+ const { onDragStart } = this.props;
+ if (!this.startDrag) {
+ onDragStart && onDragStart();
+ }
+ this.startDrag = true;
+ this.canDrag = true;
+ this.currentOffset = 0;
+ this.offDragEvent = this.initDragEvent();
+ this.startOffset = this.getClientPosition(e);
+ }
+
+ onEndMove() {
+ const { onDragEnd } = this.props;
+ if (this.startDrag) {
+ if (this.offDragEvent) {
+ this.offDragEvent();
+ }
+ this.startDrag = false;
+ this.offset = this.currentOffset;
+ }
+ onDragEnd && onDragEnd();
+ }
+
+ onDrag(e: any) {
+ const { position, onDrag, maxIncrement = 100, maxDecrement = 0 } = this.props;
+ if (this.startDrag) {
+ if (position === 'left' || position === 'top') {
+ this.currentOffset = this.offset + this.startOffset - this.getClientPosition(e);
+ } else {
+ this.currentOffset = this.offset + this.getClientPosition(e) - this.startOffset;
+ }
+
+ if (this.currentOffset < -maxDecrement) {
+ this.currentOffset = -maxDecrement;
+ } else if (this.currentOffset > maxIncrement) {
+ this.currentOffset = maxIncrement;
+ }
+
+ onDrag(this.currentOffset, e);
+ }
+ }
+
+ getClientPosition(e: any) {
+ const { position } = this.props;
+ return position === 'left' || position === 'right' ? e.clientX : e.clientY;
+ }
+
+ initEvent() {
+ const selectStart = this.onSelectStart.bind(this);
+ document.addEventListener('selectstart', selectStart);
+ return () => document.removeEventListener('selectstart', selectStart);
+ }
+
+ initDragEvent() {
+ const onDrag = this.onDrag.bind(this);
+ const onEndMove = this.onEndMove.bind(this);
+ document.addEventListener('mousemove', onDrag);
+ document.addEventListener('mouseup', onEndMove);
+ return () => {
+ document.removeEventListener('mousemove', onDrag);
+ document.removeEventListener('mouseup', onEndMove);
+ };
+ }
+
+ getParent() {
+ return this.shell?.parentElement;
+ }
+
+ render() {
+ const { className = '', position } = this.props;
+
+ return (
+ { this.shell = ref; }}
+ className={classNames(
+ position === 'left' || position === 'right'
+ ? 'lc-draggable-line-vertical'
+ : 'lc-draggable-line-horizontal',
+ {
+ [className]: !!className,
+ },
+ )}
+ onMouseDown={(e) => this.onStartMove(e)}
+ />
+ );
+ }
+}
diff --git a/packages/editor-skeleton/src/components/widget-views/index.less b/packages/editor-skeleton/src/components/widget-views/index.less
index 239885900..b392752be 100644
--- a/packages/editor-skeleton/src/components/widget-views/index.less
+++ b/packages/editor-skeleton/src/components/widget-views/index.less
@@ -5,10 +5,24 @@
&.hidden {
display: none;
}
-
}
.lc-widget-disabled {
pointer-events: none;
opacity: 0.4;
-}
\ No newline at end of file
+}
+
+.lc-draggable-line-vertical {
+ position: absolute;
+ width: 4px;
+ height: 100%;
+ top: 0;
+ background-color: transparent;
+ cursor: col-resize;
+ right: -2px;
+ z-index: 99;
+}
+
+.lc-engine-slate-draggable-line-right {
+ right: -2px;
+}
diff --git a/packages/editor-skeleton/src/components/widget-views/index.tsx b/packages/editor-skeleton/src/components/widget-views/index.tsx
index 4a6a38d94..33d72ff1c 100644
--- a/packages/editor-skeleton/src/components/widget-views/index.tsx
+++ b/packages/editor-skeleton/src/components/widget-views/index.tsx
@@ -9,6 +9,8 @@ import WidgetContainer from '../../widget/widget-container';
import Panel from '../../widget/panel';
import { IWidget } from '../../widget/widget';
import { SkeletonEvents } from '../../skeleton';
+import DraggableLine from '../draggable-line';
+import PanelOperationRow from './panel-operation-row';
import './index.less';
@@ -84,6 +86,75 @@ export class PanelDockView extends Component
{
export class DialogDockView extends Component {}
+export class DraggableLineView extends Component<{ panel: Panel }> {
+ private shell: any;
+ private defaultWidth: number;
+
+ private getDefaultWidth() {
+ const configWidth = this.props.panel?.config.props?.width;
+ if (configWidth) {
+ return configWidth;
+ }
+ if (this.defaultWidth) {
+ return this.defaultWidth;
+ }
+ const containerRef = this.shell?.getParent();
+ if (containerRef) {
+ this.defaultWidth = containerRef.offsetWidth;
+ return this.defaultWidth;
+ }
+ return 300;
+ }
+
+ onDrag(value: number) {
+ const defaultWidth = this.getDefaultWidth();
+ const width = defaultWidth + value;
+
+ const containerRef = this.shell?.getParent();
+ if (containerRef) {
+ containerRef.style.width = `${width}px`;
+ }
+
+ // 抛出事件,对于有些需要 panel 插件随着 度变化进行再次渲染的,由panel插件内部监听事件实现
+ const editor = globalContext.get(Editor);
+ editor?.emit('dockpane.drag', width);
+ }
+
+ onDragChange(type: 'start' | 'end') {
+ const editor = globalContext.get(Editor);
+ editor?.emit('dockpane.dragchange', type);
+ // builtinSimulator 屏蔽掉 鼠标事件
+ editor?.emit('designer.builtinSimulator.disabledEvents', type === 'start');
+ }
+
+ render() {
+ // left fixed 下不允许改变宽度
+ // 默认 关闭,通过配置开启
+ const enableDrag = this.props.panel.config.props?.enableDrag;
+ const isRightArea = this.props.panel.config?.area === 'rightArea';
+ if (isRightArea || !enableDrag || this.props.panel?.parent.name === 'leftFixedArea') {
+ return null;
+ }
+ return (
+ {
+ this.shell = ref;
+ }}
+ position="right"
+ className="lc-engine-slate-draggable-line-right"
+ onDrag={(e) => this.onDrag(e)}
+ onDragStart={() => this.onDragChange('start')}
+ onDragEnd={() => this.onDragChange('end')}
+ maxIncrement={500}
+ maxDecrement={0}
+ // TODO: 优化
+ // maxIncrement={dock.getMaxWidth() - this.cachedSize.width}
+ // maxDecrement={this.cachedSize.width - dock.getWidth()}
+ />
+ );
+ }
+}
+
@observer
export class TitledPanelView extends Component<{ panel: Panel; area?: string }> {
shouldComponentUpdate() {
@@ -131,15 +202,22 @@ export class TitledPanelView extends Component<{ panel: Panel; area?: string }>
})}
id={panelName}
>
+
{panel.body}
+
);
}
}
@observer
-export class PanelView extends Component<{ panel: Panel; area?: string }> {
+export class PanelView extends Component<{
+ panel: Panel;
+ area?: string;
+ hideOperationRow?: boolean;
+ hideDragLine?: boolean;
+}> {
shouldComponentUpdate() {
return false;
}
@@ -172,7 +250,7 @@ export class PanelView extends Component<{ panel: Panel; area?: string }> {
}
render() {
- const { panel, area } = this.props;
+ const { panel, area, hideOperationRow, hideDragLine } = this.props;
if (!panel.inited) {
return null;
}
@@ -189,7 +267,9 @@ export class PanelView extends Component<{ panel: Panel; area?: string }> {
})}
id={panelName}
>
+ {!hideOperationRow && }
{panel.body}
+ {!hideDragLine && }
);
}
@@ -203,7 +283,7 @@ export class TabsPanelView extends Component<{ container: WidgetContainer
const contents: ReactElement[] = [];
container.items.forEach((item: any) => {
titles.push();
- contents.push();
+ contents.push();
});
return (
@@ -302,11 +382,7 @@ export class WidgetView extends Component<{ widget: IWidget }> {
return null;
}
if (widget.disabled) {
- return (
-
- {widget.body}
-
- );
+ return {widget.body}
;
}
return widget.body;
}
diff --git a/packages/editor-skeleton/src/components/widget-views/panel-operation-row.tsx b/packages/editor-skeleton/src/components/widget-views/panel-operation-row.tsx
new file mode 100644
index 000000000..3dc06493b
--- /dev/null
+++ b/packages/editor-skeleton/src/components/widget-views/panel-operation-row.tsx
@@ -0,0 +1,67 @@
+import { Component, Fragment } from 'react';
+import { Button, Icon } from '@alifd/next';
+import { IconFix } from '../../icons/fix';
+import { IconFloat } from '../../icons/float';
+import Panel from '../../widget/panel';
+
+export default class PanelOperationRow extends Component<{ panel: Panel }> {
+ // fix or float
+ setDisplay() {
+ const { panel } = this.props;
+ const current = panel;
+ if (!current) {
+ return;
+ }
+ if (panel?.parent?.name === 'leftFloatArea') {
+ panel.skeleton.leftFloatArea.remove(current);
+ panel.skeleton.leftFixedArea.add(current);
+ panel.skeleton.leftFixedArea.container.active(current);
+ } else {
+ panel.skeleton.leftFixedArea.remove(current);
+ panel.skeleton.leftFloatArea.add(current);
+ panel.skeleton.leftFloatArea.container.active(current);
+ }
+ }
+
+ render() {
+ const { panel } = this.props;
+ const isRightArea = this.props.panel.config?.area === 'rightArea';
+ if (isRightArea) {
+ return null;
+ }
+ // can be set fixed by default
+ let canSetFixed = true;
+ if (panel?.config.props?.canSetFixed === false) {
+ canSetFixed = false;
+ }
+
+ const hideTitleBar = panel?.config.props?.hideTitleBar;
+
+ const areaName = panel?.parent?.name;
+ const area = panel.skeleton[areaName];
+
+ return (
+
+ {!hideTitleBar && (
+
+ {canSetFixed && (
+ // eslint-disable-next-line react/jsx-no-bind
+
+ )}
+
+
+ )}
+
+ );
+ }
+}
diff --git a/packages/editor-skeleton/src/layouts/left-fixed-pane.tsx b/packages/editor-skeleton/src/layouts/left-fixed-pane.tsx
index 283f787f4..18dd3c8e9 100644
--- a/packages/editor-skeleton/src/layouts/left-fixed-pane.tsx
+++ b/packages/editor-skeleton/src/layouts/left-fixed-pane.tsx
@@ -1,12 +1,10 @@
import { Component, Fragment } from 'react';
import classNames from 'classnames';
import { observer } from '@ali/lowcode-editor-core';
-import { Button, Icon } from '@alifd/next';
import Area from '../area';
import { PanelConfig } from '../types';
import Panel from '../widget/panel';
import { Designer } from '@ali/lowcode-designer';
-import { IconFloat } from '../icons/float';
@observer
export default class LeftFixedPane extends Component<{ area: Area }> {
@@ -19,21 +17,9 @@ export default class LeftFixedPane extends Component<{ area: Area
- {!hideTitleBar && (
-
-
-
-
- )}
);
diff --git a/packages/editor-skeleton/src/layouts/left-float-pane.tsx b/packages/editor-skeleton/src/layouts/left-float-pane.tsx
index 064bb83f7..cdf0c6868 100644
--- a/packages/editor-skeleton/src/layouts/left-float-pane.tsx
+++ b/packages/editor-skeleton/src/layouts/left-float-pane.tsx
@@ -1,13 +1,12 @@
import { Component, Fragment } from 'react';
import classNames from 'classnames';
import { observer, Focusable, focusTracker } from '@ali/lowcode-editor-core';
-import { Button, Icon } from '@alifd/next';
-import { IconFix } from '../icons/fix';
import Area from '../area';
import Panel from '../widget/panel';
@observer
export default class LeftFloatPane extends Component<{ area: Area }> {
+
shouldComponentUpdate() {
return false;
}
@@ -22,6 +21,7 @@ export default class LeftFloatPane extends Component<{ area: Area }>
const { area } = this.props;
const triggerClose = () => area.setVisible(false);
area.skeleton.editor.on('designer.dragstart', triggerClose);
+
this.dispose = () => {
area.skeleton.editor.removeListener('designer.dragstart', triggerClose);
};
@@ -95,29 +95,10 @@ export default class LeftFloatPane extends Component<{ area: Area }>
this.dispose?.();
}
- // 固定
- setFixed() {
- const { area } = this.props;
- const { current } = area;
- if (!current) {
- return;
- }
-
- area.skeleton.leftFloatArea.remove(current);
- area.skeleton.leftFixedArea.add(current);
- area.skeleton.leftFixedArea.container.active(current);
- }
-
render() {
const { area } = this.props;
const width = area.current?.config.props?.width;
- // can be set fixed by default
- let canSetFixed = true;
- if (area.current?.config.props?.canSetFixed === false) {
- canSetFixed = false;
- }
- const hideTitleBar = area.current?.config.props?.hideTitleBar;
const style = width ? {
width,
} : undefined;
@@ -129,32 +110,6 @@ export default class LeftFloatPane extends Component<{ area: Area }>
})}
style={style}
>
- {
- !hideTitleBar && (
-
- {
- canSetFixed && (
-
- )
- }
-
-
- )
- }
);
diff --git a/packages/editor-skeleton/src/layouts/workbench.less b/packages/editor-skeleton/src/layouts/workbench.less
index 9d8102e3e..a8541e3ae 100644
--- a/packages/editor-skeleton/src/layouts/workbench.less
+++ b/packages/editor-skeleton/src/layouts/workbench.less
@@ -49,6 +49,8 @@ body {
width: 100%;
height: 100%;
position: relative;
+ background-color: #fff;
+ background-color: var(--color-pane-background);
&.hidden {
display: none;
}
@@ -122,6 +124,9 @@ body {
.lc-panel {
height: 100%;
width: 100%;
+ position: relative;
+ background-color: #fff;
+ background-color: var(--color-pane-background);
// overflow: auto;
&.hidden {
display: none;
diff --git a/packages/editor-skeleton/src/types.ts b/packages/editor-skeleton/src/types.ts
index 83dc0f1f0..c6485f2cd 100644
--- a/packages/editor-skeleton/src/types.ts
+++ b/packages/editor-skeleton/src/types.ts
@@ -103,6 +103,7 @@ export interface PanelProps {
onInit?: (widget: IWidget) => any;
onDestroy?: () => any;
shortcut?: string; // 只有在特定位置,可触发 toggle show
+ enableDrag?: boolean; // 是否开启通过 drag 调整 宽度
}
export interface PanelDockConfig extends IDockBaseConfig {
diff --git a/packages/engine/src/engine-core.ts b/packages/engine/src/engine-core.ts
index c783073a3..4cb6f1e73 100644
--- a/packages/engine/src/engine-core.ts
+++ b/packages/engine/src/engine-core.ts
@@ -25,6 +25,7 @@ registerDefaults();
const editor = new Editor();
globalContext.register(editor, Editor);
+globalContext.register(editor, 'editor');
const skeleton = new Skeleton(editor);
editor.set(Skeleton, skeleton);
diff --git a/packages/vision-polyfill/src/panes.ts b/packages/vision-polyfill/src/panes.ts
index 0a61d860e..47fc38742 100644
--- a/packages/vision-polyfill/src/panes.ts
+++ b/packages/vision-polyfill/src/panes.ts
@@ -49,6 +49,7 @@ export interface OldPaneConfig {
fullScreen?: boolean; // todo
canSetFixed?: boolean; // 是否可以设置固定模式
defaultFixed?: boolean; // 是否默认固定
+ enableDrag?: boolean;
}
function upgradeConfig(config: OldPaneConfig): IWidgetBaseConfig & { area: string } {
@@ -83,6 +84,7 @@ function upgradeConfig(config: OldPaneConfig): IWidgetBaseConfig & { area: strin
isAction,
canSetFixed,
defaultFixed,
+ enableDrag,
} = config;
if (menu) {
newConfig.props.title = menu;
@@ -99,6 +101,7 @@ function upgradeConfig(config: OldPaneConfig): IWidgetBaseConfig & { area: strin
height,
maxHeight,
canSetFixed,
+ enableDrag,
};
if (defaultFixed) {
@@ -135,7 +138,6 @@ function upgradeConfig(config: OldPaneConfig): IWidgetBaseConfig & { area: strin
}
newConfig.props.onInit = init;
newConfig.props.onDestroy = destroy;
-
return newConfig;
}