This commit is contained in:
kangwei 2020-05-28 17:37:55 +08:00
commit 4ea1c775ec
13 changed files with 138 additions and 21 deletions

View File

@ -22,7 +22,7 @@ import {
CanvasPoint, CanvasPoint,
} from '../designer'; } from '../designer';
import { parseMetadata } from './utils/parse-metadata'; import { parseMetadata } from './utils/parse-metadata';
import { ComponentMetadata } from '@ali/lowcode-types'; import { ComponentMetadata, ComponentSchema } from '@ali/lowcode-types';
import { BuiltinSimulatorRenderer } from './renderer'; import { BuiltinSimulatorRenderer } from './renderer';
import clipboard from '../designer/clipboard'; import clipboard from '../designer/clipboard';
import { LiveEditing } from './live-editing/live-editing'; import { LiveEditing } from './live-editing/live-editing';
@ -447,6 +447,10 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
return this.renderer?.getComponent(componentName) || null; return this.renderer?.getComponent(componentName) || null;
} }
createComponent(schema: ComponentSchema): Component | null {
return this.renderer?.createComponent(schema) || null;
}
@obx.val private instancesMap = new Map<string, ComponentInstance[]>(); @obx.val private instancesMap = new Map<string, ComponentInstance[]>();
setInstance(id: string, instances: ComponentInstance[] | null) { setInstance(id: string, instances: ComponentInstance[] | null) {
if (instances == null) { if (instances == null) {

View File

@ -1,7 +1,9 @@
import { ComponentInstance, NodeInstance, Component } from '../simulator'; import { ComponentInstance, NodeInstance, Component } from '../simulator';
import { ComponentSchema } from '@ali/lowcode-types';
export interface BuiltinSimulatorRenderer { export interface BuiltinSimulatorRenderer {
readonly isSimulatorRenderer: true; readonly isSimulatorRenderer: true;
createComponent(schema: ComponentSchema): Component | null;
getComponent(componentName: string): Component; getComponent(componentName: string): Component;
getComponentInstances(id: string): ComponentInstance[] | null; getComponentInstances(id: string): ComponentInstance[] | null;
getClosestNodeInstance(from: ComponentInstance, nodeId?: string): NodeInstance<ComponentInstance> | null; getClosestNodeInstance(from: ComponentInstance, nodeId?: string): NodeInstance<ComponentInstance> | null;

View File

@ -228,7 +228,7 @@ export class Designer {
touchOffsetObserver() { touchOffsetObserver() {
this.clearOobxList(true); this.clearOobxList(true);
this.oobxList.forEach(item => item.compute()); this.oobxList.forEach((item) => item.compute());
} }
createSettingEntry(editor: IEditor, nodes: Node[]) { createSettingEntry(editor: IEditor, nodes: Node[]) {
@ -392,11 +392,16 @@ export class Designer {
@computed get componentsMap(): { [key: string]: NpmInfo | Component } { @computed get componentsMap(): { [key: string]: NpmInfo | Component } {
const maps: any = {}; const maps: any = {};
this._componentMetasMap.forEach((config, key) => { this._componentMetasMap.forEach((config, key) => {
const view = config.getMetadata().experimental?.view; const metaData = config.getMetadata();
if (view) { if (metaData.devMode === 'lowcode') {
maps[key] = view; maps[key] = this.currentDocument?.simulator?.createComponent(metaData.schema);
} else if (config.npm) { } else {
maps[key] = config.npm; const view = metaData.experimental?.view;
if (view) {
maps[key] = view;
} else if (config.npm) {
maps[key] = config.npm;
}
} }
}); });
return maps; return maps;

View File

@ -1,5 +1,5 @@
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { autorun, Reaction, untracked } from '@ali/lowcode-editor-core'; import { autorun, Reaction, untracked, globalContext, Editor } from '@ali/lowcode-editor-core';
import { NodeSchema } from '@ali/lowcode-types'; import { NodeSchema } from '@ali/lowcode-types';
// TODO: cache to localStorage // TODO: cache to localStorage
@ -114,6 +114,11 @@ export class History {
} }
const cursor = this.session.cursor - 1; const cursor = this.session.cursor - 1;
this.go(cursor); this.go(cursor);
const editor = globalContext.get(Editor);
if (!editor) {
return;
}
editor.emit('history.back', cursor);
} }
forward() { forward() {
@ -122,6 +127,11 @@ export class History {
} }
const cursor = this.session.cursor + 1; const cursor = this.session.cursor + 1;
this.go(cursor); this.go(cursor);
const editor = globalContext.get(Editor);
if (!editor) {
return;
}
editor.emit('history.forward', cursor);
} }
savePoint() { savePoint() {

View File

@ -1,5 +1,5 @@
import { Component as ReactComponent, ComponentType } from 'react'; import { Component as ReactComponent, ComponentType } from 'react';
import { ComponentMetadata } from '@ali/lowcode-types'; import { ComponentMetadata, ComponentSchema } from '@ali/lowcode-types';
import { ISensor, Point, ScrollTarget, IScrollable } from './designer'; import { ISensor, Point, ScrollTarget, IScrollable } from './designer';
import { Node } from './document'; import { Node } from './document';
@ -126,6 +126,10 @@ export interface ISimulatorHost<P = object> extends ISensor {
* *
*/ */
getComponentInstances(node: Node): ComponentInstance[] | null; getComponentInstances(node: Node): ComponentInstance[] | null;
/**
* schema
*/
createComponent(schema: ComponentSchema): Component | null;
/** /**
* *
*/ */

View File

@ -1,3 +1,6 @@
import { globalContext } from './di';
import { Editor } from './editor';
interface KeyMap { interface KeyMap {
[key: number]: string; [key: number]: string;
} }
@ -329,6 +332,16 @@ function fireCallback(callback: HotkeyCallback, e: KeyboardEvent, combo?: string
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
} }
const editor = globalContext.get(Editor);
if (!editor) {
return;
}
editor.emit('hotkey.callback.call', {
callback,
e,
combo,
sequence,
});
} }
export class Hotkey { export class Hotkey {

View File

@ -7,8 +7,23 @@ import { Tip } from '../tip';
import './title.less'; import './title.less';
export class Title extends Component<{ title: TitleContent; className?: string; onClick?: () => void }> { export class Title extends Component<{ title: TitleContent; className?: string; onClick?: () => void }> {
constructor(props: any) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(e: React.MouseEvent) {
const { title, onClick } = this.props as any;
const url = title && (title.docUrl || title.url);
if (url) {
window.open(url);
// 防止触发行操作(如折叠面板)
e.stopPropagation();
}
// TODO: 操作交互冲突,目前 mixedSetter 仅有 2 个 setter 注册时用到了 onClick
onClick && onClick(e);
}
render() { render() {
let { title, className, onClick } = this.props; let { title, className } = this.props;
if (title == null) { if (title == null) {
return null; return null;
} }
@ -40,7 +55,7 @@ export class Title extends Component<{ title: TitleContent; className?: string;
'has-tip': !!tip, 'has-tip': !!tip,
'only-icon': !title.label 'only-icon': !title.label
})} })}
onClick={onClick} onClick={this.handleClick}
> >
{icon ? <b className="lc-title-icon">{icon}</b> : null} {icon ? <b className="lc-title-icon">{icon}</b> : null}
{title.label ? intl(title.label) : null} {title.label ? intl(title.label) : null}

View File

@ -1,6 +1,6 @@
import { ComponentType, ReactElement, isValidElement, ComponentClass } from 'react'; import { ComponentType, ReactElement, isValidElement, ComponentClass } from 'react';
import { isPlainObject } from '@ali/lowcode-utils'; import { isPlainObject } from '@ali/lowcode-utils';
import { isI18nData, SettingTarget, InitialItem, FilterItem, isJSSlot, isJSExpression, AutorunItem } from '@ali/lowcode-types'; import { isI18nData, SettingTarget, InitialItem, FilterItem, isJSSlot, ProjectSchema, AutorunItem } from '@ali/lowcode-types';
import { untracked } from '@ali/lowcode-editor-core'; import { untracked } from '@ali/lowcode-editor-core';
type Field = SettingTarget; type Field = SettingTarget;
@ -167,6 +167,8 @@ export interface OldPrototypeConfig {
onResizeStart?: (e: MouseEvent, triggerDirection: string, dragment: Node) => void; onResizeStart?: (e: MouseEvent, triggerDirection: string, dragment: Node) => void;
onResize?: (e: MouseEvent, triggerDirection: string, dragment: Node, moveX: number, moveY: number) => void; onResize?: (e: MouseEvent, triggerDirection: string, dragment: Node, moveX: number, moveY: number) => void;
onResizeEnd?: (e: MouseEvent, triggerDirection: string, dragment: Node) => void; onResizeEnd?: (e: MouseEvent, triggerDirection: string, dragment: Node) => void;
devMode?: string;
schema?: ProjectSchema;
} }
export interface ISetterConfig { export interface ISetterConfig {
@ -607,6 +609,8 @@ export function upgradeMetadata(oldConfig: OldPrototypeConfig) {
onResizeStart, // onResizeStart onResizeStart, // onResizeStart
onResize, // onResize onResize, // onResize
onResizeEnd, // onResizeEnd onResizeEnd, // onResizeEnd
devMode,
schema,
} = oldConfig; } = oldConfig;
const meta: any = { const meta: any = {
@ -614,7 +618,8 @@ export function upgradeMetadata(oldConfig: OldPrototypeConfig) {
title, title,
icon, icon,
docUrl, docUrl,
devMode: 'procode', devMode: devMode || 'procode',
schema: schema?.componentsTree[0],
}; };
if (category) { if (category) {

View File

@ -1,5 +1,6 @@
import logger from '@ali/vu-logger'; import logger from '@ali/vu-logger';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { editor } from './editor';
/** /**
* Bus class as an EventEmitter * Bus class as an EventEmitter
@ -19,7 +20,6 @@ export class Bus {
// alias to unsub // alias to unsub
off(event: string, func: (...args: any[]) => any) { off(event: string, func: (...args: any[]) => any) {
this.unsub(event, func); this.unsub(event, func);
} }
// alias to pub // alias to pub
@ -62,4 +62,18 @@ export class Bus {
} }
} }
export default new Bus(); const bus = new Bus();
editor.on('hotkey.callback.call', (data) => {
bus.emit('ve.hotkey.callback.call', data);
});
editor.on('history.back', (data) => {
bus.emit('ve.history.back', data);
});
editor.on('history.forward', (data) => {
bus.emit('ve.history.forward', data);
});
export default bus;

View File

@ -2,6 +2,7 @@ import { skeleton, editor } from './editor';
import { ReactElement } from 'react'; import { ReactElement } from 'react';
import { IWidgetBaseConfig, Skeleton } from '@ali/lowcode-editor-skeleton'; import { IWidgetBaseConfig, Skeleton } from '@ali/lowcode-editor-skeleton';
import { uniqueId } from '@ali/lowcode-utils'; import { uniqueId } from '@ali/lowcode-utils';
import bus from './bus';
export interface IContentItemConfig { export interface IContentItemConfig {
title: string; title: string;
@ -175,6 +176,7 @@ const dockPane = Object.assign(skeleton.leftArea, {
console.warn(`Could not find pane with name ${name}`); console.warn(`Could not find pane with name ${name}`);
} }
pane?.active(); pane?.active();
bus.emit('ve.dock_pane.active_doc', pane);
}, },
/** /**

View File

@ -28,6 +28,11 @@ export class Field extends Component<FieldProps> {
display: this.props.defaultDisplay || 'inline', display: this.props.defaultDisplay || 'inline',
}; };
constructor(props: any) {
super(props);
this.handleClear = this.handleClear.bind(this);
}
private toggleExpand = () => { private toggleExpand = () => {
const { onExpandChange } = this.props; const { onExpandChange } = this.props;
const collapsed = !this.state.collapsed; const collapsed = !this.state.collapsed;
@ -68,6 +73,10 @@ export class Field extends Component<FieldProps> {
}); });
this.dispose = () => observer.disconnect(); this.dispose = () => observer.disconnect();
} }
private handleClear(e: React.MouseEvent) {
e.stopPropagation();
this.props.onClear && this.props.onClear();
}
componentDidMount() { componentDidMount() {
const { defaultDisplay } = this.props; const { defaultDisplay } = this.props;
if (!defaultDisplay || defaultDisplay === 'inline') { if (!defaultDisplay || defaultDisplay === 'inline') {
@ -118,7 +127,7 @@ export class Field extends Component<FieldProps> {
> >
<div className="lc-field-head" onClick={isAccordion ? this.toggleExpand : undefined}> <div className="lc-field-head" onClick={isAccordion ? this.toggleExpand : undefined}>
<div className="lc-field-title"> <div className="lc-field-title">
{createValueState(valueState, onClear)} {createValueState(valueState, this.handleClear)}
<Title title={title || ''} /> <Title title={title || ''} />
<InlineTip position="top">{tipContent}</InlineTip> <InlineTip position="top">{tipContent}</InlineTip>
</div> </div>
@ -143,7 +152,7 @@ export class Field extends Component<FieldProps> {
* *
* TODO: turn number to enum * TODO: turn number to enum
*/ */
function createValueState(valueState?: number, onClear?: () => void) { function createValueState(valueState?: number, onClear?: (e: React.MouseEvent) => void) {
let tip: any = null; let tip: any = null;
let className = 'lc-valuestate'; let className = 'lc-valuestate';
let icon: any = null; let icon: any = null;

View File

@ -1,4 +1,4 @@
import { createElement, ReactInstance, ComponentType } from 'react'; import React, { createElement, ReactInstance, ComponentType, ReactElement } from 'react';
import { render as reactRender } from 'react-dom'; import { render as reactRender } from 'react-dom';
import { host } from './host'; import { host } from './host';
import SimulatorRendererView from './renderer-view'; import SimulatorRendererView from './renderer-view';
@ -8,9 +8,9 @@ import { getClientRects } from './utils/get-client-rects';
import loader from './utils/loader'; import loader from './utils/loader';
import { reactFindDOMNodes, FIBER_KEY } from './utils/react-find-dom-nodes'; import { reactFindDOMNodes, FIBER_KEY } from './utils/react-find-dom-nodes';
import { isESModule, isElement, cursor, setNativeSelection } from '@ali/lowcode-utils'; import { isESModule, isElement, cursor, setNativeSelection } from '@ali/lowcode-utils';
import { RootSchema, NpmInfo } from '@ali/lowcode-types'; import { RootSchema, NpmInfo, ComponentSchema } from '@ali/lowcode-types';
// just use types // just use types
import { BuiltinSimulatorRenderer, NodeInstance } from '@ali/lowcode-designer'; import { BuiltinSimulatorRenderer, NodeInstance, Component, TransformStage } from '@ali/lowcode-designer';
import Slot from './builtin-components/slot'; import Slot from './builtin-components/slot';
import Leaf from './builtin-components/leaf'; import Leaf from './builtin-components/leaf';
@ -210,6 +210,39 @@ export class SimulatorRenderer implements BuiltinSimulatorRenderer {
return this.instancesMap.get(id) || null; return this.instancesMap.get(id) || null;
} }
createComponent(schema: ComponentSchema): Component | null {
const _schema = {
...schema,
};
_schema.methods = {};
_schema.lifeCycles = {};
const getElement = (componentsMap: any, schema: any): ReactElement => {
const Com = componentsMap[schema.componentName];
let children = null;
if (schema.children && schema.children.length > 0) {
children = schema.children.map((item: any) => getElement(componentsMap, item));
}
const _leaf = host.document.designer.currentDocument?.createNode(schema);
const props = host.document.designer.transformProps(schema.props || {}, host.document.createNode(schema), TransformStage.Render);
return createElement(Com, {...props, _leaf}, children);
}
const renderer = this;
class Com extends React.Component {
render() {
const componentsMap = renderer.componentsMap;
let children = null;
if (_schema.children && Array.isArray(_schema.children)) {
children = _schema.children?.map((item:any) => getElement(componentsMap, item));
}
return createElement(React.Fragment, {}, children);
}
}
return Com;
}
getClosestNodeInstance(from: ReactInstance, nodeId?: string): NodeInstance<ReactInstance> | null { getClosestNodeInstance(from: ReactInstance, nodeId?: string): NodeInstance<ReactInstance> | null {
return getClosestNodeInstance(from, nodeId); return getClosestNodeInstance(from, nodeId);
} }

View File

@ -5,7 +5,7 @@ import { TitleContent } from './title';
import { PropConfig } from './prop-config'; import { PropConfig } from './prop-config';
import { NpmInfo } from './npm'; import { NpmInfo } from './npm';
import { FieldConfig } from './field-config'; import { FieldConfig } from './field-config';
import { NodeSchema, NodeData } from './schema'; import { NodeSchema, NodeData, ComponentSchema } from './schema';
import { SettingTarget } from './setting-target'; import { SettingTarget } from './setting-target';
export type NestingFilter = (testNode: any, currentNode: any) => boolean; export type NestingFilter = (testNode: any, currentNode: any) => boolean;
@ -163,6 +163,7 @@ export interface ComponentMetadata {
props?: PropConfig[]; props?: PropConfig[];
configure?: FieldConfig[] | Configure; configure?: FieldConfig[] | Configure;
experimental?: Experimental; experimental?: Experimental;
schema?: ComponentSchema;
} }
export interface TransformedComponentMetadata extends ComponentMetadata { export interface TransformedComponentMetadata extends ComponentMetadata {