mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-03-02 07:20:38 +00:00
merge
This commit is contained in:
commit
a57730f254
@ -20,10 +20,9 @@ import {
|
||||
getRectTarget,
|
||||
Rect,
|
||||
CanvasPoint,
|
||||
hotkey,
|
||||
} from '../designer';
|
||||
import { parseProps } from './utils/parse-props';
|
||||
import { isElement } from '@ali/lowcode-globals';
|
||||
import { isElement, hotkey } from '@ali/lowcode-globals';
|
||||
import { ComponentMetadata } from '@ali/lowcode-globals';
|
||||
import { BuiltinSimulatorRenderer } from './renderer';
|
||||
import clipboard from '../designer/clipboard';
|
||||
|
||||
@ -1,117 +0,0 @@
|
||||
import { Hotkey, isFormEvent } from '@ali/lowcode-globals';
|
||||
import { focusing } from './focusing';
|
||||
import { insertChildren } from '../document';
|
||||
import clipboard from './clipboard';
|
||||
|
||||
export const hotkey = new Hotkey();
|
||||
|
||||
// hotkey binding
|
||||
hotkey.bind(['backspace', 'del'], (e: KeyboardEvent) => {
|
||||
const doc = focusing.focusDesigner?.currentDocument;
|
||||
if (isFormEvent(e) || !doc) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
|
||||
const sel = doc.selection;
|
||||
const topItems = sel.getTopNodes();
|
||||
// TODO: check can remove
|
||||
topItems.forEach(node => {
|
||||
doc.removeNode(node);
|
||||
});
|
||||
sel.clear();
|
||||
});
|
||||
|
||||
hotkey.bind('escape', (e: KeyboardEvent) => {
|
||||
// const currentFocus = focusing.current;
|
||||
const sel = focusing.focusDesigner?.currentDocument?.selection;
|
||||
if (isFormEvent(e) || !sel) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
|
||||
sel.clear();
|
||||
// currentFocus.esc();
|
||||
});
|
||||
|
||||
// command + c copy command + x cut
|
||||
hotkey.bind(['command+c', 'ctrl+c', 'command+x', 'ctrl+x'], (e, action) => {
|
||||
const doc = focusing.focusDesigner?.currentDocument;
|
||||
if (isFormEvent(e) || !doc) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
|
||||
/*
|
||||
const doc = getCurrentDocument();
|
||||
if (isFormEvent(e) || !doc || !(focusing.id === 'outline' || focusing.id === 'canvas')) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
*/
|
||||
|
||||
const selected = doc.selection.getTopNodes(true);
|
||||
if (!selected || selected.length < 1) return;
|
||||
|
||||
const componentsMap = {};
|
||||
const componentsTree = selected.map(item => item.export(false));
|
||||
|
||||
const data = { type: 'nodeSchema', componentsMap, componentsTree };
|
||||
|
||||
clipboard.setData(data);
|
||||
/*
|
||||
const cutMode = action.indexOf('x') > 0;
|
||||
if (cutMode) {
|
||||
const parentNode = selected.getParent();
|
||||
parentNode.select();
|
||||
selected.remove();
|
||||
}
|
||||
*/
|
||||
});
|
||||
|
||||
// command + v paste
|
||||
hotkey.bind(['command+v', 'ctrl+v'], (e) => {
|
||||
const designer = focusing.focusDesigner;
|
||||
const doc = designer?.currentDocument;
|
||||
if (isFormEvent(e) || !designer || !doc) {
|
||||
return;
|
||||
}
|
||||
clipboard.waitPasteData(e, ({ componentsTree }) => {
|
||||
if (componentsTree) {
|
||||
const { target, index } = designer.getSuitableInsertion() || {};
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
const nodes = insertChildren(target, componentsTree, index);
|
||||
if (nodes) {
|
||||
doc.selection.selectAll(nodes.map(o => o.id));
|
||||
setTimeout(() => designer.activeTracker.track(nodes[0]), 10);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// command + z undo
|
||||
hotkey.bind(['command+z', 'ctrl+z'], (e) => {
|
||||
const his = focusing.focusDesigner?.currentHistory;
|
||||
if (isFormEvent(e) || !his) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
his.back();
|
||||
});
|
||||
|
||||
// command + shift + z redo
|
||||
hotkey.bind(['command+y', 'ctrl+y', 'command+shift+z'], (e) => {
|
||||
const his = focusing.focusDesigner?.currentHistory;
|
||||
if (isFormEvent(e) || !his) {
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
|
||||
his.forward();
|
||||
});
|
||||
|
||||
hotkey.mount(window);
|
||||
@ -1,7 +1,7 @@
|
||||
import './builtin-hotkey';
|
||||
export * from './designer';
|
||||
export * from './designer-view';
|
||||
export * from './dragon';
|
||||
export * from './hotkey';
|
||||
export * from './hovering';
|
||||
export * from './location';
|
||||
export * from './offset-observer';
|
||||
|
||||
@ -471,12 +471,31 @@ export class Node {
|
||||
isEmpty(): boolean {
|
||||
return this.children ? this.children.isEmpty() : true;
|
||||
}
|
||||
getChildren() {
|
||||
return this.children;
|
||||
}
|
||||
getComponentName() {
|
||||
return this.componentName;
|
||||
}
|
||||
insertBefore(node: Node, ref?: Node) {
|
||||
this.children?.insert(node, ref ? ref.index : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
getStatus() {
|
||||
return 'default';
|
||||
}
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
setStatus() {
|
||||
|
||||
}
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
getDOMNode() {
|
||||
const instance = this.document.simulator?.getComponentInstances(this)?.[0];
|
||||
if (!instance) {
|
||||
@ -484,18 +503,13 @@ export class Node {
|
||||
}
|
||||
return this.document.simulator?.findDOMNodes(instance)?.[0];
|
||||
}
|
||||
getChildren() {
|
||||
return this.children;
|
||||
}
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
getPage() {
|
||||
console.warn('getPage is deprecated, use document instead');
|
||||
return this.document;
|
||||
}
|
||||
getComponentName() {
|
||||
return this.componentName;
|
||||
}
|
||||
insertBefore(node: Node, ref?: Node) {
|
||||
this.children?.insert(node, ref ? ref.index : null);
|
||||
}
|
||||
}
|
||||
|
||||
export interface NodeParent extends Node {
|
||||
|
||||
@ -25,7 +25,7 @@ export interface HooksFuncs {
|
||||
[idx: number]: (msg: string, handler: (...args: []) => void) => void;
|
||||
}
|
||||
|
||||
export type KeyType = Function | Symbol | string;
|
||||
export type KeyType = Function | symbol | string;
|
||||
export type ClassType = Function | (new (...args: any[]) => any);
|
||||
export interface GetOptions {
|
||||
forceNew?: boolean;
|
||||
|
||||
@ -602,3 +602,6 @@ export class Hotkey {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const hotkey = new Hotkey();
|
||||
hotkey.mount(window);
|
||||
|
||||
@ -14,10 +14,11 @@
|
||||
"test:snapshot": "ava --update-snapshots"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ali/lowcode-designer": "^0.9.3",
|
||||
"@ali/lowcode-editor-core": "^0.8.6",
|
||||
"@ali/lowcode-globals": "^0.9.3",
|
||||
"@ali/lowcode-plugin-outline-pane": "^0.8.9",
|
||||
"@ali/lowcode-designer": "^0.9.2",
|
||||
"@ali/lowcode-editor-core": "^0.8.5",
|
||||
"@ali/lowcode-globals": "^0.9.2",
|
||||
"@ali/lowcode-plugin-outline-pane": "^0.8.8",
|
||||
"@ali/ve-stage-box": "^4.0.0",
|
||||
"@alifd/next": "^1.19.16",
|
||||
"classnames": "^2.2.6",
|
||||
"react": "^16"
|
||||
|
||||
130
packages/plugin-settings-pane/src/field/fields.tsx
Normal file
130
packages/plugin-settings-pane/src/field/fields.tsx
Normal file
@ -0,0 +1,130 @@
|
||||
import { Component } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { Icon } from '@alifd/next';
|
||||
import { Title, TitleContent } from '@ali/lowcode-globals';
|
||||
import { PopupPipe, PopupContext } from '../popup';
|
||||
import './index.less';
|
||||
|
||||
export interface FieldProps {
|
||||
className?: string;
|
||||
// span
|
||||
title?: TitleContent | null;
|
||||
}
|
||||
|
||||
export class CommonField extends Component<FieldProps> {
|
||||
private shell: HTMLDivElement | null = null;
|
||||
|
||||
private checkIsBlockField() {
|
||||
if (this.shell) {
|
||||
const setter = this.shell.lastElementChild!.firstElementChild;
|
||||
if (setter && setter.classList.contains('lc-block-setter')) {
|
||||
this.shell.classList.add('lc-block-field');
|
||||
this.shell.classList.remove('lc-inline-field');
|
||||
} else {
|
||||
this.shell.classList.remove('lc-block-field');
|
||||
this.shell.classList.add('lc-inline-field');
|
||||
}
|
||||
}
|
||||
}
|
||||
componentDidUpdate() {
|
||||
this.checkIsBlockField();
|
||||
}
|
||||
componentDidMount() {
|
||||
this.checkIsBlockField();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { className, children, title } = this.props;
|
||||
return (
|
||||
<div ref={(shell) => (this.shell = shell)} className={classNames('lc-field lc-inline-field', className)}>
|
||||
{title && (
|
||||
<div className="lc-field-head">
|
||||
<div className="lc-field-title">
|
||||
<Title title={title} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="lc-field-body">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export interface PopupFieldProps extends FieldProps {
|
||||
width?: number;
|
||||
}
|
||||
|
||||
export class PopupField extends Component<PopupFieldProps> {
|
||||
static contextType = PopupContext;
|
||||
private pipe: any;
|
||||
|
||||
static defaultProps: PopupFieldProps = {
|
||||
width: 300,
|
||||
};
|
||||
|
||||
render() {
|
||||
const { className, children, title, width } = this.props;
|
||||
if (!this.pipe) {
|
||||
this.pipe = (this.context as PopupPipe).create({ width });
|
||||
}
|
||||
|
||||
const titleElement = title && (
|
||||
<div className="lc-field-title">
|
||||
<Title title={title} />
|
||||
</div>
|
||||
);
|
||||
|
||||
this.pipe.send(<div className="lc-field-body">{children}</div>, titleElement);
|
||||
|
||||
return (
|
||||
<div className={classNames('lc-field lc-popup-field', className)}>
|
||||
{title && (
|
||||
<div
|
||||
className="lc-field-head"
|
||||
onClick={(e) => {
|
||||
this.pipe.show((e as any).target);
|
||||
}}
|
||||
>
|
||||
<div className="lc-field-title">
|
||||
<Title title={title} />
|
||||
</div>
|
||||
<Icon className="lc-field-icon" type="arrow-left" size="xs" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export type EntryFieldProps = FieldProps;
|
||||
|
||||
export class EntryField extends Component<EntryFieldProps> {
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { propName, stageName, tip, title, className } = this.props;
|
||||
const classNameList = classNames('engine-setting-field', 'engine-entry-field', className);
|
||||
const fieldProps: any = {};
|
||||
|
||||
if (stageName) {
|
||||
// 为 stage 切换奠定基础
|
||||
fieldProps['data-stage-target'] = stageName;
|
||||
}
|
||||
|
||||
const innerElements = [
|
||||
<span className="engine-field-title" key="field-title">
|
||||
{title}
|
||||
</span>,
|
||||
renderTip(tip, { propName }),
|
||||
<Icons name="arrow" className="engine-field-arrow" size="12px" key="engine-field-arrow-icon" />,
|
||||
];
|
||||
|
||||
return (
|
||||
<div className={classNameList} {...fieldProps}>
|
||||
{innerElements}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -3,50 +3,22 @@ import classNames from 'classnames';
|
||||
import { Icon } from '@alifd/next';
|
||||
import { Title, TitleContent } from '@ali/lowcode-globals';
|
||||
import './index.less';
|
||||
import { CommonField, PopupField } from './fields';
|
||||
|
||||
export interface FieldProps {
|
||||
className?: string;
|
||||
// span
|
||||
title?: TitleContent | null;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
export class Field extends Component<FieldProps> {
|
||||
private shell: HTMLDivElement | null = null;
|
||||
|
||||
private checkIsBlockField() {
|
||||
if (this.shell) {
|
||||
const setter = this.shell.lastElementChild!.firstElementChild;
|
||||
if (setter && setter.classList.contains('lc-block-setter')) {
|
||||
this.shell.classList.add('lc-block-field');
|
||||
this.shell.classList.remove('lc-inline-field');
|
||||
} else {
|
||||
this.shell.classList.remove('lc-block-field');
|
||||
this.shell.classList.add('lc-inline-field');
|
||||
}
|
||||
}
|
||||
}
|
||||
componentDidUpdate() {
|
||||
this.checkIsBlockField();
|
||||
}
|
||||
componentDidMount() {
|
||||
this.checkIsBlockField();
|
||||
}
|
||||
|
||||
render() {
|
||||
const { className, children, title } = this.props;
|
||||
|
||||
return (
|
||||
<div ref={shell => (this.shell = shell)} className={classNames('lc-field lc-inline-field', className)}>
|
||||
{title && (
|
||||
<div className="lc-field-head">
|
||||
<div className="lc-field-title">
|
||||
<Title title={title} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="lc-field-body">{children}</div>
|
||||
</div>
|
||||
);
|
||||
const { type, ...rest } = this.props;
|
||||
if (type === 'popup') {
|
||||
return <PopupField {...rest} />;
|
||||
}
|
||||
return <CommonField {...rest} />;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -28,12 +28,15 @@ export class PopupPipe {
|
||||
},
|
||||
show: (target: Element, actionKey?: string) => {
|
||||
this.currentId = id;
|
||||
this.popup({
|
||||
...props,
|
||||
actionKey,
|
||||
content: sendContent,
|
||||
title: sendTitle,
|
||||
}, target);
|
||||
this.popup(
|
||||
{
|
||||
...props,
|
||||
actionKey,
|
||||
content: sendContent,
|
||||
title: sendTitle,
|
||||
},
|
||||
target,
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -121,7 +124,7 @@ export class PopupContent extends PureComponent<{ safeId?: string }> {
|
||||
safeNode={id}
|
||||
visible={visible}
|
||||
style={{ width }}
|
||||
onVisibleChange={visible => {
|
||||
onVisibleChange={(visible) => {
|
||||
if (avoidLaterHidden) {
|
||||
return;
|
||||
}
|
||||
@ -136,7 +139,11 @@ export class PopupContent extends PureComponent<{ safeId?: string }> {
|
||||
shouldUpdatePosition
|
||||
>
|
||||
<div className="lc-ballon-title">{title}</div>
|
||||
<div className="lc-ballon-content"><PopupService actionKey={actionKey} safeId={id}>{content}</PopupService></div>
|
||||
<div className="lc-ballon-content">
|
||||
<PopupService actionKey={actionKey} safeId={id}>
|
||||
{content}
|
||||
</PopupService>
|
||||
</div>
|
||||
</Balloon>
|
||||
);
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ import {
|
||||
shallowIntl,
|
||||
isSetterConfig,
|
||||
createSetterContent,
|
||||
shallowEqual
|
||||
shallowEqual,
|
||||
} from '@ali/lowcode-globals';
|
||||
import { SettingField, isSettingField, SettingTarget } from './main';
|
||||
import { Field, FieldGroup } from './field';
|
||||
@ -38,7 +38,7 @@ class SettingFieldView extends Component<{ field: SettingField }> {
|
||||
} else if (setter) {
|
||||
this.setterType = setter;
|
||||
}
|
||||
let firstRun: boolean = true;
|
||||
let firstRun = true;
|
||||
this.dispose = field.onEffect(() => {
|
||||
const state: any = {};
|
||||
const { extraProps } = field;
|
||||
@ -137,7 +137,7 @@ class SettingGroupView extends Component<{ field: SettingField }> {
|
||||
super(props);
|
||||
const { field } = this.props;
|
||||
const { condition } = field.extraProps;
|
||||
let firstRun: boolean = true;
|
||||
let firstRun = true;
|
||||
this.dispose = field.onEffect(() => {
|
||||
const state: any = {};
|
||||
state.visible = field.isOne && typeof condition === 'function' ? !condition(field) : true;
|
||||
@ -204,7 +204,7 @@ export default class SettingsPane extends Component<{ target: SettingTarget }> {
|
||||
super(props);
|
||||
|
||||
const { target } = this.props;
|
||||
let firstRun: boolean = true;
|
||||
let firstRun = true;
|
||||
this.dispose = target.onEffect(() => {
|
||||
const state = {
|
||||
items: target.items.slice(),
|
||||
|
||||
@ -30,6 +30,7 @@
|
||||
"@ali/vu-logger": "^1.0.7",
|
||||
"@ali/vu-style-sheet": "^2.4.0",
|
||||
"@alifd/next": "^1.19.12",
|
||||
"@ali/ve-stage-box": "^4.0.0",
|
||||
"@alife/theme-lowcode-dark": "^0.1.0",
|
||||
"@alife/theme-lowcode-light": "^0.1.0",
|
||||
"react": "^16.8.1",
|
||||
|
||||
@ -18,16 +18,24 @@ const VEOldAPIs = {
|
||||
* Core UI Components
|
||||
*/
|
||||
ui: {
|
||||
// FIELD_TYPE_MAP
|
||||
Field: {
|
||||
SettingField,
|
||||
Stage,
|
||||
CaptionField,
|
||||
PopupField,
|
||||
EntryField,
|
||||
// SettingField,
|
||||
// Stage,
|
||||
// CaptionField,
|
||||
// PopupField,
|
||||
// EntryField,
|
||||
// AccordionField,
|
||||
// BlockField,
|
||||
// InlineField,
|
||||
// PlainField
|
||||
AccordionField,
|
||||
BlockField,
|
||||
InlineField,
|
||||
PlainField
|
||||
BlockField,
|
||||
CaptionField, // 不支持 variableSwitcher 版的 BlockField
|
||||
PlainField, // 不渲染 title 的 InlineField
|
||||
EntryField,
|
||||
PopupField,
|
||||
},
|
||||
Icon: Icons,
|
||||
Icons,
|
||||
|
||||
@ -149,11 +149,11 @@ export class Skeleton {
|
||||
return;
|
||||
}
|
||||
Object.keys(plugins).forEach((area) => {
|
||||
plugins[area].forEach(item => {
|
||||
plugins[area].forEach((item) => {
|
||||
const { pluginKey, type, props = {}, pluginProps } = item;
|
||||
const config: any = {
|
||||
area,
|
||||
type: "Widget",
|
||||
type: 'Widget',
|
||||
name: pluginKey,
|
||||
contentProps: pluginProps,
|
||||
};
|
||||
@ -181,7 +181,7 @@ export class Skeleton {
|
||||
}
|
||||
this.add(config);
|
||||
});
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
postEvent(event: SkeletonEvents, ...args: any[]) {
|
||||
@ -218,9 +218,9 @@ export class Skeleton {
|
||||
createContainer(
|
||||
name: string,
|
||||
handle: (item: any) => any,
|
||||
exclusive: boolean = false,
|
||||
exclusive = false,
|
||||
checkVisible: () => boolean = () => true,
|
||||
defaultSetCurrent: boolean = false,
|
||||
defaultSetCurrent = false,
|
||||
) {
|
||||
const container = new WidgetContainer(name, handle, exclusive, checkVisible, defaultSetCurrent);
|
||||
this.containers.set(name, container);
|
||||
@ -231,7 +231,7 @@ export class Skeleton {
|
||||
const { content, ...restConfig } = config;
|
||||
if (content) {
|
||||
if (typeof content === 'object' && !isValidElement(content)) {
|
||||
Object.keys(content).forEach(key => {
|
||||
Object.keys(content).forEach((key) => {
|
||||
if (/props$/i.test(key) && restConfig[key]) {
|
||||
restConfig[key] = {
|
||||
...restConfig[key],
|
||||
@ -247,17 +247,24 @@ export class Skeleton {
|
||||
}
|
||||
const { area } = restConfig;
|
||||
switch (area) {
|
||||
case 'leftArea': case 'left':
|
||||
case 'leftArea':
|
||||
case 'left':
|
||||
return this.leftArea.add(restConfig as any);
|
||||
case 'rightArea': case 'right':
|
||||
case 'rightArea':
|
||||
case 'right':
|
||||
return this.rightArea.add(restConfig as any);
|
||||
case 'topArea': case 'top':
|
||||
case 'topArea':
|
||||
case 'top':
|
||||
return this.topArea.add(restConfig as any);
|
||||
case 'toolbar':
|
||||
return this.toolbar.add(restConfig as any);
|
||||
case 'mainArea': case 'main': case 'center': case 'centerArea':
|
||||
case 'mainArea':
|
||||
case 'main':
|
||||
case 'center':
|
||||
case 'centerArea':
|
||||
return this.mainArea.add(restConfig as any);
|
||||
case 'bottomArea': case 'bottom':
|
||||
case 'bottomArea':
|
||||
case 'bottom':
|
||||
return this.bottomArea.add(restConfig as any);
|
||||
case 'leftFixedArea':
|
||||
return this.leftFixedArea.add(restConfig as any);
|
||||
|
||||
@ -3,6 +3,7 @@ import Popup from '@ali/ve-popups';
|
||||
import Icons from '@ali/ve-icons';
|
||||
import { render } from 'react-dom';
|
||||
import I18nUtil from '@ali/ve-i18n-util';
|
||||
import { hotkey as Hotkey } from '@ali/lowcode-globals';
|
||||
import { createElement } from 'react';
|
||||
import { VE_EVENTS as EVENTS, VE_HOOKS as HOOKS } from './const';
|
||||
import Bus from './bus';
|
||||
@ -68,6 +69,7 @@ const VisualEngine = {
|
||||
*/
|
||||
utils,
|
||||
I18nUtil,
|
||||
Hotkey,
|
||||
Env,
|
||||
/* pub/sub 集线器 */
|
||||
Bus,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user