mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-01-13 09:41:57 +00:00
Merge branch 'release/0.9.2' into 'release/0.9.2'
主设置面板 entry display 使用 stagebox 的切换模式 RT See merge request !915532
This commit is contained in:
commit
0e65b1ff51
@ -102,8 +102,8 @@ context.use(HOOKS.VE_SETTING_FIELD_VARIABLE_SETTER, VariableSetter);
|
||||
const externals = ['react', 'react-dom', 'prop-types', 'react-router', 'react-router-dom', '@ali/recore'];
|
||||
|
||||
async function loadAssets() {
|
||||
const legaoAssets = await editor.utils.get('./raxAssets.json');
|
||||
// const legaoAssets = await editor.utils.get('./legao-assets.json');
|
||||
// const legaoAssets = await editor.utils.get('./raxAssets.json');
|
||||
const legaoAssets = await editor.utils.get('./legao-assets.json');
|
||||
|
||||
const assets = upgradeAssetsBundle(legaoAssets);
|
||||
|
||||
@ -145,11 +145,11 @@ async function loadAssets() {
|
||||
}
|
||||
|
||||
async function loadSchema() {
|
||||
const schema = await editor.utils.get('./rax.json');
|
||||
// const schema = await editor.utils.get('./schema.json');
|
||||
// const schema = await editor.utils.get('./rax.json');
|
||||
const schema = await editor.utils.get('./schema.json');
|
||||
editor.set('schema', schema);
|
||||
editor.set('renderEnv', 'rax');
|
||||
editor.set('clientTypes', ['mobile']);
|
||||
// editor.set('renderEnv', 'rax');
|
||||
// editor.set('clientTypes', ['mobile']);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -26,7 +26,10 @@
|
||||
"@alifd/next": "^1.20.12",
|
||||
"classnames": "^2.2.6",
|
||||
"react": "^16.8.1",
|
||||
"react-dom": "^16.8.1"
|
||||
"react-dom": "^16.8.1",
|
||||
"events": "^3.2.0",
|
||||
"@ali/ve-icons": "latest",
|
||||
"@ali/ve-less-variables": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@alib/build-scripts": "^0.1.3",
|
||||
|
||||
@ -147,8 +147,13 @@ export function createSettingFieldView(item: SettingField | CustomView, field: S
|
||||
}
|
||||
}
|
||||
|
||||
export type SettingsPaneProps = {
|
||||
target: SettingTopEntry | SettingField;
|
||||
usePopup?: boolean;
|
||||
};
|
||||
|
||||
@observer
|
||||
export class SettingsPane extends Component<{ target: SettingTopEntry | SettingField }> {
|
||||
export class SettingsPane extends Component<SettingsPaneProps> {
|
||||
static contextType = SkeletonContext;
|
||||
shouldComponentUpdate() {
|
||||
return false;
|
||||
@ -160,6 +165,8 @@ export class SettingsPane extends Component<{ target: SettingTopEntry | SettingF
|
||||
private handleClick = (e: MouseEvent) => {
|
||||
// compatiable vision stageBox
|
||||
// TODO: optimize these codes
|
||||
const { usePopup = true } = this.props;
|
||||
if (!usePopup) return;
|
||||
const pane = e.currentTarget as HTMLDivElement;
|
||||
let entry: any;
|
||||
function getTarget(node: any): any {
|
||||
|
||||
@ -4,6 +4,8 @@ import { Title, observer, Editor, obx, globalContext } from '@ali/lowcode-editor
|
||||
import { Node, isSettingField, SettingField, Designer } from '@ali/lowcode-designer';
|
||||
import { SettingsMain } from './main';
|
||||
import { SettingsPane } from './settings-pane';
|
||||
import { StageBox } from '../stage-box';
|
||||
import { SkeletonContext } from '../../context';
|
||||
import { createIcon } from '@ali/lowcode-utils';
|
||||
|
||||
@observer
|
||||
@ -114,7 +116,18 @@ export class SettingsPrimaryPane extends Component<{ editor: Editor }> {
|
||||
<div className="lc-settings-main">
|
||||
{this.renderBreadcrumb()}
|
||||
<div className="lc-settings-body">
|
||||
<SettingsPane target={settings} />
|
||||
<SkeletonContext.Consumer>
|
||||
{(skeleton) => {
|
||||
if (skeleton) {
|
||||
return (
|
||||
<StageBox skeleton={skeleton} target={settings}>
|
||||
<SettingsPane target={settings} usePopup={false} />
|
||||
</StageBox>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}}
|
||||
</SkeletonContext.Consumer>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@ -127,7 +140,18 @@ export class SettingsPrimaryPane extends Component<{ editor: Editor }> {
|
||||
}
|
||||
return (
|
||||
<Tab.Item className="lc-settings-tab-item" title={<Title title={field.title} />} key={field.name}>
|
||||
<SettingsPane target={field} key={field.id} />
|
||||
<SkeletonContext.Consumer>
|
||||
{(skeleton) => {
|
||||
if (skeleton) {
|
||||
return (
|
||||
<StageBox skeleton={skeleton} target={field} key={field.id}>
|
||||
<SettingsPane target={field} key={field.id} usePopup={false} />
|
||||
</StageBox>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}}
|
||||
</SkeletonContext.Consumer>
|
||||
</Tab.Item>
|
||||
);
|
||||
});
|
||||
|
||||
74
packages/editor-skeleton/src/components/stage-box/index.less
Normal file
74
packages/editor-skeleton/src/components/stage-box/index.less
Normal file
@ -0,0 +1,74 @@
|
||||
@import "~@ali/ve-less-variables/index.less";
|
||||
|
||||
.skeleton-stagebox {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
min-height: 50px;
|
||||
.skeleton-stagebox-stage {
|
||||
height: auto;
|
||||
overflow: hidden;
|
||||
|
||||
transition: transform 0.2s;
|
||||
|
||||
&.skeleton-stagebox-refer {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
&.skeleton-stagebox-stageout-left, &.skeleton-stagebox-stagein-right {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
&.skeleton-stagebox-stageout-right, &.skeleton-stagebox-stagein-left {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
|
||||
.skeleton-stagebox-stagebacker {
|
||||
cursor: pointer;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: var(--color-block-background-light, @normal-alpha-9);
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
|
||||
.skeleton-stagebox-stage-arrow {
|
||||
position: absolute;
|
||||
left: 3px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%) rotate(90deg);
|
||||
opacity: 0.6;
|
||||
}
|
||||
.skeleton-stagebox-stage-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
&:hover {
|
||||
background: var(--color-block-background-dark, @normal-alpha-7);
|
||||
.skeleton-stagebox-stage-arrow {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.skeleton-stagebox-stage-exit {
|
||||
position: absolute;
|
||||
right: 3px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
.skeleton-stagebox-stage-content {
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
&.skeleton-stagebox-has-backer {
|
||||
.skeleton-stagebox-stage-content {
|
||||
padding-top: 30px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,4 @@
|
||||
import StageBox from './stage-box';
|
||||
import './index.less';
|
||||
|
||||
export { StageBox };
|
||||
118
packages/editor-skeleton/src/components/stage-box/stage-box.tsx
Normal file
118
packages/editor-skeleton/src/components/stage-box/stage-box.tsx
Normal file
@ -0,0 +1,118 @@
|
||||
import React, { Component } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { observer } from '@ali/lowcode-editor-core';
|
||||
import { SettingTopEntry, SettingField } from '@ali/lowcode-designer';
|
||||
import StageChain from './stage-chain';
|
||||
import Stage from './stage';
|
||||
import { Skeleton } from '../../skeleton';
|
||||
import { Stage as StageWidget } from '../../widget/stage';
|
||||
|
||||
export const StageBoxDefaultProps = {};
|
||||
|
||||
export type StageBoxProps = typeof StageBoxDefaultProps & {
|
||||
stageChain?: StageChain;
|
||||
className?: string;
|
||||
children: React.ReactNode;
|
||||
skeleton: Skeleton;
|
||||
// @todo to remove
|
||||
target?: SettingTopEntry | SettingField;
|
||||
};
|
||||
|
||||
type WillDetachMember = () => void;
|
||||
|
||||
@observer
|
||||
export default class StageBox extends Component<StageBoxProps> {
|
||||
static defaultProps = StageBoxDefaultProps;
|
||||
|
||||
static displayName = 'StageBox';
|
||||
|
||||
private stageChain: StageChain;
|
||||
private willDetach: WillDetachMember[] = [];
|
||||
private shell: HTMLElement | null;
|
||||
|
||||
constructor(props: StageBoxProps) {
|
||||
super(props);
|
||||
const { stageChain, children, skeleton } = this.props;
|
||||
if (stageChain) {
|
||||
this.stageChain = stageChain;
|
||||
} else {
|
||||
const stateName = skeleton.createStage({
|
||||
content: children,
|
||||
});
|
||||
this.stageChain = new StageChain(skeleton.getStage(stateName as string) as StageWidget);
|
||||
}
|
||||
this.willDetach.push(this.stageChain.onStageChange(() => this.forceUpdate()));
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const shell = this.shell;
|
||||
|
||||
/**
|
||||
* 向上层递归寻找 target
|
||||
* @param node 节点
|
||||
* @returns 节点的 dataset.stageTarget 信息
|
||||
*/
|
||||
const getTarget = (node: HTMLElement | null): null | string => {
|
||||
if (!node || !shell?.contains(node) || (node.nodeName === 'A' && node.getAttribute('href'))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const target = node.dataset ? node.dataset.stageTarget : null;
|
||||
if (target) {
|
||||
return target;
|
||||
}
|
||||
return getTarget(node.parentNode as HTMLElement);
|
||||
};
|
||||
|
||||
const click = (e: MouseEvent) => {
|
||||
const target = getTarget(e.target as HTMLElement);
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (target === 'stageback') {
|
||||
this.stageChain.stageBack();
|
||||
} else {
|
||||
const { skeleton } = this.props;
|
||||
this.stageChain.stagePush(skeleton.getStage(target));
|
||||
}
|
||||
};
|
||||
|
||||
shell?.addEventListener('click', click, false);
|
||||
this.willDetach.push(() => shell?.removeEventListener('click', click, false));
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.willDetach) {
|
||||
this.willDetach.forEach((off: () => void) => off());
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const className = classNames('skeleton-stagebox', this.props.className);
|
||||
const stage = this.stageChain.getCurrentStage();
|
||||
const refer = stage?.getRefer();
|
||||
|
||||
let contentCurrent = null;
|
||||
let contentRefer = null;
|
||||
|
||||
if (refer) {
|
||||
contentCurrent = <Stage key={stage.getId()} stage={stage} direction={refer.direction} current />;
|
||||
contentRefer = <Stage key={refer?.stage?.getId()} stage={refer?.stage} direction={refer.direction} />;
|
||||
} else {
|
||||
contentCurrent = <Stage key={stage.getId()} stage={stage} current />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={(ref) => {
|
||||
this.shell = ref;
|
||||
}}
|
||||
className={className}
|
||||
>
|
||||
{contentRefer}
|
||||
{contentCurrent}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
import { EventEmitter } from 'events';
|
||||
import { Stage as StageWidget } from '../../widget/stage';
|
||||
|
||||
export default class StageChain {
|
||||
private emitter: EventEmitter;
|
||||
private stage: StageWidget;
|
||||
|
||||
constructor(stage: StageWidget) {
|
||||
this.emitter = new EventEmitter();
|
||||
this.stage = stage;
|
||||
}
|
||||
|
||||
stagePush(stage: StageWidget | null) {
|
||||
if (!stage) return;
|
||||
stage.setPrevious(this.stage);
|
||||
stage.setReferLeft(this.stage);
|
||||
this.stage = stage;
|
||||
this.emitter.emit('stagechange');
|
||||
}
|
||||
|
||||
stageBack() {
|
||||
const stage = this.stage.getPrevious();
|
||||
if (!stage) return;
|
||||
stage.setReferRight(this.stage);
|
||||
this.stage = stage;
|
||||
this.emitter.emit('stagechange');
|
||||
}
|
||||
|
||||
/**
|
||||
* 回到最开始
|
||||
*/
|
||||
stageBackToRoot() {
|
||||
while (!this.stage.isRoot) {
|
||||
const stage = this.stage.getPrevious();
|
||||
if (!stage) return;
|
||||
stage.setReferRight(this.stage);
|
||||
this.stage = stage;
|
||||
}
|
||||
this.emitter.emit('stagechange');
|
||||
}
|
||||
|
||||
getCurrentStage() {
|
||||
return this.stage;
|
||||
}
|
||||
|
||||
onStageChange(func: () => void) {
|
||||
this.emitter.on('stagechange', func);
|
||||
return () => {
|
||||
this.emitter.removeListener('stagechange', func);
|
||||
};
|
||||
}
|
||||
}
|
||||
93
packages/editor-skeleton/src/components/stage-box/stage.tsx
Normal file
93
packages/editor-skeleton/src/components/stage-box/stage.tsx
Normal file
@ -0,0 +1,93 @@
|
||||
// @todo 改成 hooks
|
||||
import React, { Component } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import Icons from '@ali/ve-icons';
|
||||
import { Stage as StageWidget } from '../../widget/stage';
|
||||
|
||||
export const StageDefaultProps = {
|
||||
current: false,
|
||||
};
|
||||
|
||||
export type StageProps = typeof StageDefaultProps & {
|
||||
stage?: StageWidget;
|
||||
current: boolean;
|
||||
direction?: string;
|
||||
};
|
||||
|
||||
export default class Stage extends Component<StageProps> {
|
||||
static defaultProps = StageDefaultProps;
|
||||
|
||||
private timer: number;
|
||||
private additionClassName: string | null;
|
||||
private shell: any;
|
||||
|
||||
componentDidMount() {
|
||||
this.doSkate();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.doSkate();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.clearTimeout(this.timer);
|
||||
}
|
||||
|
||||
doSkate() {
|
||||
window.clearTimeout(this.timer);
|
||||
if (this.additionClassName) {
|
||||
this.timer = window.setTimeout(() => {
|
||||
const elem = this.shell;
|
||||
if (elem) {
|
||||
if (this.props.current) {
|
||||
elem.classList.remove(this.additionClassName);
|
||||
} else {
|
||||
elem.classList.add(this.additionClassName);
|
||||
}
|
||||
this.additionClassName = null;
|
||||
}
|
||||
}, 15);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { stage, current, direction } = this.props;
|
||||
const content = stage?.getContent();
|
||||
|
||||
if (current) {
|
||||
if (direction) {
|
||||
this.additionClassName = `skeleton-stagebox-stagein-${direction}`;
|
||||
}
|
||||
} else if (direction) {
|
||||
this.additionClassName = `skeleton-stagebox-stageout-${direction}`;
|
||||
}
|
||||
|
||||
const className = classNames(
|
||||
'skeleton-stagebox-stage',
|
||||
{
|
||||
'skeleton-stagebox-refer': !current,
|
||||
},
|
||||
this.additionClassName,
|
||||
);
|
||||
|
||||
const stageBacker = stage?.hasBack() ? (
|
||||
<div className="skeleton-stagebox-stagebacker" data-stage-target="stageback">
|
||||
<Icons name="arrow" className="skeleton-stagebox-stage-arrow" size="medium" />
|
||||
<span className="skeleton-stagebox-stage-title">{stage.title}</span>
|
||||
<Icons name="exit" className="skeleton-stagebox-stage-exit" size="medium" />
|
||||
</div>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={(ref) => {
|
||||
this.shell = ref;
|
||||
}}
|
||||
className={className}
|
||||
>
|
||||
{stageBacker}
|
||||
<div className="skeleton-stagebox-stage-content">{content}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -20,7 +20,7 @@ import PanelDock from './widget/panel-dock';
|
||||
import Dock from './widget/dock';
|
||||
import { Stage, StageConfig } from './widget/stage';
|
||||
import { isValidElement } from 'react';
|
||||
import { isPlainObject } from '@ali/lowcode-utils';
|
||||
import { isPlainObject, uniqueId } from '@ali/lowcode-utils';
|
||||
import { Divider } from '@alifd/next';
|
||||
import { EditorConfig, PluginClassSet } from '@ali/lowcode-types';
|
||||
|
||||
@ -248,6 +248,19 @@ export class Skeleton {
|
||||
return this.panels.get(name);
|
||||
}
|
||||
|
||||
getStage(name: string) {
|
||||
return this.stages.container.get(name);
|
||||
}
|
||||
|
||||
createStage(config: any) {
|
||||
const stage = this.add({
|
||||
name: uniqueId('stage'),
|
||||
area: 'stages',
|
||||
...config,
|
||||
});
|
||||
return stage?.getName();
|
||||
}
|
||||
|
||||
createContainer(
|
||||
name: string,
|
||||
handle: (item: any) => any,
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { uniqueId } from '@ali/lowcode-utils';
|
||||
import Widget from './widget';
|
||||
import { Skeleton } from '../skeleton';
|
||||
import { WidgetConfig } from '../types';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user