mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-03-07 02:47:12 +00:00
feat: update
This commit is contained in:
parent
6d2a77a766
commit
bad2d5e8ad
@ -64,7 +64,7 @@ import {
|
|||||||
DragNodeObject,
|
DragNodeObject,
|
||||||
} from '@alilc/lowcode-types';
|
} from '@alilc/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';
|
||||||
import { Project } from '../project';
|
import { Project } from '../project';
|
||||||
import { Scroller } from '../designer/scroller';
|
import { Scroller } from '../designer/scroller';
|
||||||
@ -478,6 +478,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
|||||||
this.setupEvents();
|
this.setupEvents();
|
||||||
|
|
||||||
// bind hotkey & clipboard
|
// bind hotkey & clipboard
|
||||||
|
const hotkey = this.designer.editor.get('innerHotkey');
|
||||||
hotkey.mount(this._contentWindow);
|
hotkey.mount(this._contentWindow);
|
||||||
focusTracker.mount(this._contentWindow);
|
focusTracker.mount(this._contentWindow);
|
||||||
clipboard.injectCopyPaster(this._contentDocument);
|
clipboard.injectCopyPaster(this._contentDocument);
|
||||||
|
|||||||
@ -1,361 +0,0 @@
|
|||||||
import { hotkey, Editor, globalContext } from '@alilc/lowcode-editor-core';
|
|
||||||
import { isFormEvent } from '@alilc/lowcode-utils';
|
|
||||||
import { focusing } from './focusing';
|
|
||||||
import { insertChildren, TransformStage } from '../document';
|
|
||||||
import clipboard from './clipboard';
|
|
||||||
|
|
||||||
export function isInLiveEditing() {
|
|
||||||
const workSpace = globalContext.get('workSpace');
|
|
||||||
if (workSpace.isActive) {
|
|
||||||
return Boolean(
|
|
||||||
workSpace.window.editor.get('designer')?.project?.simulator?.liveEditing?.editing,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (globalContext.has(Editor)) {
|
|
||||||
return Boolean(
|
|
||||||
globalContext.get(Editor).get('designer')?.project?.simulator?.liveEditing?.editing,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* istanbul ignore next */
|
|
||||||
function getNextForSelect(next: any, head?: any, parent?: any): any {
|
|
||||||
if (next) {
|
|
||||||
if (!head) {
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
let ret;
|
|
||||||
if (next.isContainer()) {
|
|
||||||
const children = next.getChildren() || [];
|
|
||||||
if (children && !children.isEmpty()) {
|
|
||||||
ret = getNextForSelect(children.get(0));
|
|
||||||
if (ret) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = getNextForSelect(next.nextSibling);
|
|
||||||
if (ret) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parent) {
|
|
||||||
return getNextForSelect(parent.nextSibling, false, parent.getParent());
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* istanbul ignore next */
|
|
||||||
function getPrevForSelect(prev: any, head?: any, parent?: any): any {
|
|
||||||
if (prev) {
|
|
||||||
let ret;
|
|
||||||
if (!head && prev.isContainer()) {
|
|
||||||
const children = prev.getChildren() || [];
|
|
||||||
const lastChild = children && !children.isEmpty() ? children.get(children.size - 1) : null;
|
|
||||||
|
|
||||||
ret = getPrevForSelect(lastChild);
|
|
||||||
if (ret) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!head) {
|
|
||||||
return prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = getPrevForSelect(prev.prevSibling);
|
|
||||||
if (ret) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parent) {
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// hotkey binding
|
|
||||||
hotkey.bind(['backspace', 'del'], (e: KeyboardEvent) => {
|
|
||||||
if (isInLiveEditing()) return;
|
|
||||||
// TODO: use focus-tracker
|
|
||||||
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) => {
|
|
||||||
if (node.canPerformAction('remove')) {
|
|
||||||
doc.removeNode(node);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
sel.clear();
|
|
||||||
});
|
|
||||||
|
|
||||||
hotkey.bind('escape', (e: KeyboardEvent) => {
|
|
||||||
// const currentFocus = focusing.current;
|
|
||||||
if (isInLiveEditing()) return;
|
|
||||||
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) => {
|
|
||||||
if (isInLiveEditing()) return;
|
|
||||||
const doc = focusing.focusDesigner?.currentDocument;
|
|
||||||
if (isFormEvent(e) || !doc) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
let selected = doc.selection.getTopNodes(true);
|
|
||||||
selected = selected.filter((node) => {
|
|
||||||
return node.canPerformAction('copy');
|
|
||||||
});
|
|
||||||
if (!selected || selected.length < 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const componentsMap = {};
|
|
||||||
const componentsTree = selected.map((item) => item.export(TransformStage.Clone));
|
|
||||||
|
|
||||||
// FIXME: clear node.id
|
|
||||||
|
|
||||||
const data = { type: 'nodeSchema', componentsMap, componentsTree };
|
|
||||||
|
|
||||||
clipboard.setData(data);
|
|
||||||
|
|
||||||
const cutMode = action && action.indexOf('x') > 0;
|
|
||||||
if (cutMode) {
|
|
||||||
selected.forEach((node) => {
|
|
||||||
const parentNode = node.getParent();
|
|
||||||
parentNode?.select();
|
|
||||||
node.remove();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// command + v paste
|
|
||||||
hotkey.bind(['command+v', 'ctrl+v'], (e) => {
|
|
||||||
if (isInLiveEditing()) return;
|
|
||||||
const designer = focusing.focusDesigner;
|
|
||||||
const doc = designer?.currentDocument;
|
|
||||||
if (isFormEvent(e) || !designer || !doc) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* istanbul ignore next */
|
|
||||||
clipboard.waitPasteData(e, ({ componentsTree }) => {
|
|
||||||
if (componentsTree) {
|
|
||||||
const { target, index } = designer.getSuitableInsertion(componentsTree) || {};
|
|
||||||
if (!target) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let canAddComponentsTree = componentsTree.filter((i) => {
|
|
||||||
return doc.checkNestingUp(target, i);
|
|
||||||
});
|
|
||||||
if (canAddComponentsTree.length === 0) return;
|
|
||||||
const nodes = insertChildren(target, canAddComponentsTree, 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) => {
|
|
||||||
if (isInLiveEditing()) return;
|
|
||||||
const his = focusing.focusDesigner?.currentHistory;
|
|
||||||
if (isFormEvent(e) || !his) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
e.preventDefault();
|
|
||||||
const selection = focusing.focusDesigner?.currentSelection;
|
|
||||||
const curSelected = Array.from(selection?.selected);
|
|
||||||
his.back();
|
|
||||||
selection?.selectAll(curSelected);
|
|
||||||
});
|
|
||||||
|
|
||||||
// command + shift + z redo
|
|
||||||
hotkey.bind(['command+y', 'ctrl+y', 'command+shift+z'], (e) => {
|
|
||||||
if (isInLiveEditing()) return;
|
|
||||||
const his = focusing.focusDesigner?.currentHistory;
|
|
||||||
if (isFormEvent(e) || !his) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
e.preventDefault();
|
|
||||||
const selection = focusing.focusDesigner?.currentSelection;
|
|
||||||
const curSelected = Array.from(selection?.selected);
|
|
||||||
his.forward();
|
|
||||||
selection?.selectAll(curSelected);
|
|
||||||
});
|
|
||||||
|
|
||||||
// sibling selection
|
|
||||||
hotkey.bind(['left', 'right'], (e, action) => {
|
|
||||||
if (isInLiveEditing()) return;
|
|
||||||
const designer = focusing.focusDesigner;
|
|
||||||
const doc = designer?.currentDocument;
|
|
||||||
if (isFormEvent(e) || !doc) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
e.preventDefault();
|
|
||||||
const selected = doc.selection.getTopNodes(true);
|
|
||||||
if (!selected || selected.length < 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const firstNode = selected[0];
|
|
||||||
const silbing = action === 'left' ? firstNode?.prevSibling : firstNode?.nextSibling;
|
|
||||||
silbing?.select();
|
|
||||||
});
|
|
||||||
|
|
||||||
hotkey.bind(['up', 'down'], (e, action) => {
|
|
||||||
if (isInLiveEditing()) return;
|
|
||||||
const designer = focusing.focusDesigner;
|
|
||||||
const doc = designer?.currentDocument;
|
|
||||||
if (isFormEvent(e) || !doc) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
e.preventDefault();
|
|
||||||
const selected = doc.selection.getTopNodes(true);
|
|
||||||
if (!selected || selected.length < 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const firstNode = selected[0];
|
|
||||||
|
|
||||||
if (action === 'down') {
|
|
||||||
const next = getNextForSelect(firstNode, true, firstNode.getParent());
|
|
||||||
next?.select();
|
|
||||||
} else if (action === 'up') {
|
|
||||||
const prev = getPrevForSelect(firstNode, true, firstNode.getParent());
|
|
||||||
prev?.select();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
hotkey.bind(['option+left', 'option+right'], (e, action) => {
|
|
||||||
if (isInLiveEditing()) return;
|
|
||||||
const designer = focusing.focusDesigner;
|
|
||||||
const doc = designer?.currentDocument;
|
|
||||||
if (isFormEvent(e) || !doc) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
e.preventDefault();
|
|
||||||
const selected = doc.selection.getTopNodes(true);
|
|
||||||
if (!selected || selected.length < 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// TODO: 此处需要增加判断当前节点是否可被操作移动,原ve里是用 node.canOperating()来判断
|
|
||||||
// TODO: 移动逻辑也需要重新梳理,对于移动目标位置的选择,是否可以移入,需要增加判断
|
|
||||||
|
|
||||||
const firstNode = selected[0];
|
|
||||||
const parent = firstNode.getParent();
|
|
||||||
if (!parent) return;
|
|
||||||
|
|
||||||
const isPrev = action && /(left)$/.test(action);
|
|
||||||
|
|
||||||
const silbing = isPrev ? firstNode.prevSibling : firstNode.nextSibling;
|
|
||||||
if (silbing) {
|
|
||||||
if (isPrev) {
|
|
||||||
parent.insertBefore(firstNode, silbing);
|
|
||||||
} else {
|
|
||||||
parent.insertAfter(firstNode, silbing);
|
|
||||||
}
|
|
||||||
firstNode?.select();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
hotkey.bind(['option+up'], (e) => {
|
|
||||||
if (isInLiveEditing()) return;
|
|
||||||
const designer = focusing.focusDesigner;
|
|
||||||
const doc = designer?.currentDocument;
|
|
||||||
if (isFormEvent(e) || !doc) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
e.preventDefault();
|
|
||||||
const selected = doc.selection.getTopNodes(true);
|
|
||||||
if (!selected || selected.length < 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// TODO: 此处需要增加判断当前节点是否可被操作移动,原ve里是用 node.canOperating()来判断
|
|
||||||
// TODO: 移动逻辑也需要重新梳理,对于移动目标位置的选择,是否可以移入,需要增加判断
|
|
||||||
|
|
||||||
const firstNode = selected[0];
|
|
||||||
const parent = firstNode.getParent();
|
|
||||||
if (!parent) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const silbing = firstNode.prevSibling;
|
|
||||||
if (silbing) {
|
|
||||||
if (silbing.isContainer()) {
|
|
||||||
const place = silbing.getSuitablePlace(firstNode, null);
|
|
||||||
place.container.insertAfter(firstNode, place.ref);
|
|
||||||
} else {
|
|
||||||
parent.insertBefore(firstNode, silbing);
|
|
||||||
}
|
|
||||||
firstNode?.select();
|
|
||||||
} else {
|
|
||||||
const place = parent.getSuitablePlace(firstNode, null); // upwards
|
|
||||||
if (place) {
|
|
||||||
place.container.insertBefore(firstNode, place.ref);
|
|
||||||
firstNode?.select();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
hotkey.bind(['option+down'], (e) => {
|
|
||||||
if (isInLiveEditing()) return;
|
|
||||||
const designer = focusing.focusDesigner;
|
|
||||||
const doc = designer?.currentDocument;
|
|
||||||
if (isFormEvent(e) || !doc) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
e.preventDefault();
|
|
||||||
const selected = doc.selection.getTopNodes(true);
|
|
||||||
if (!selected || selected.length < 1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// TODO: 此处需要增加判断当前节点是否可被操作移动,原ve里是用 node.canOperating()来判断
|
|
||||||
// TODO: 移动逻辑也需要重新梳理,对于移动目标位置的选择,是否可以移入,需要增加判断
|
|
||||||
|
|
||||||
const firstNode = selected[0];
|
|
||||||
const parent = firstNode.getParent();
|
|
||||||
if (!parent) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const silbing = firstNode.nextSibling;
|
|
||||||
if (silbing) {
|
|
||||||
if (silbing.isContainer()) {
|
|
||||||
// const place = silbing.getSuitablePlace(firstNode, null);
|
|
||||||
silbing.insertBefore(firstNode, undefined);
|
|
||||||
// place.container.insertBefore(firstNode, place.ref);
|
|
||||||
} else {
|
|
||||||
parent.insertAfter(firstNode, silbing);
|
|
||||||
}
|
|
||||||
firstNode?.select();
|
|
||||||
} else {
|
|
||||||
const place = parent.getSuitablePlace(firstNode, null); // upwards
|
|
||||||
if (place) {
|
|
||||||
place.container.insertAfter(firstNode, place.ref);
|
|
||||||
firstNode?.select();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@ -109,4 +109,4 @@ class Clipboard {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new Clipboard();
|
export const clipboard = new Clipboard();
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import BuiltinDragGhostComponent from './drag-ghost';
|
|||||||
import { Designer, DesignerProps } from './designer';
|
import { Designer, DesignerProps } from './designer';
|
||||||
import { ProjectView } from '../project';
|
import { ProjectView } from '../project';
|
||||||
import './designer.less';
|
import './designer.less';
|
||||||
import clipboard from './clipboard';
|
import { clipboard } from './clipboard';
|
||||||
|
|
||||||
export class DesignerView extends Component<DesignerProps & {
|
export class DesignerView extends Component<DesignerProps & {
|
||||||
designer?: Designer;
|
designer?: Designer;
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
import './builtin-hotkey';
|
|
||||||
|
|
||||||
export * from './designer';
|
export * from './designer';
|
||||||
export * from './designer-view';
|
export * from './designer-view';
|
||||||
export * from './dragon';
|
export * from './dragon';
|
||||||
@ -9,3 +7,6 @@ export * from './offset-observer';
|
|||||||
export * from './scroller';
|
export * from './scroller';
|
||||||
export * from './setting';
|
export * from './setting';
|
||||||
export * from './active-tracker';
|
export * from './active-tracker';
|
||||||
|
export * from './focusing';
|
||||||
|
export * from '../document';
|
||||||
|
export * from './clipboard';
|
||||||
|
|||||||
@ -142,11 +142,13 @@ export class Editor extends (EventEmitter as any) implements IEditor {
|
|||||||
} || []);
|
} || []);
|
||||||
// assets.componentList = assets.componentList.concat(component.componentList || []);
|
// assets.componentList = assets.componentList.concat(component.componentList || []);
|
||||||
}
|
}
|
||||||
function setArrayAssets(value: any[]) {
|
function setArrayAssets(value: any[], preExportName: string = '', preSubName: string = '') {
|
||||||
value.forEach((d: any, i: number) => {
|
value.forEach((d: any, i: number) => {
|
||||||
Array.isArray(d) ? setArrayAssets(d) : setAssetsComponent(d, {
|
const exportName = [preExportName, i.toString()].filter(d => !!d).join('.');
|
||||||
exportName: i.toString(),
|
const subName = [preSubName, i.toString()].filter(d => !!d).join('.');
|
||||||
subName: i.toString(),
|
Array.isArray(d) ? setArrayAssets(d, exportName, subName) : setAssetsComponent(d, {
|
||||||
|
exportName,
|
||||||
|
subName,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -354,7 +354,7 @@ function fireCallback(callback: HotkeyCallback, e: KeyboardEvent, combo?: string
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Hotkey {
|
export class Hotkey {
|
||||||
private callBacks: HotkeyCallbacks = {};
|
callBacks: HotkeyCallbacks = {};
|
||||||
|
|
||||||
private directMap: HotkeyDirectMap = {};
|
private directMap: HotkeyDirectMap = {};
|
||||||
|
|
||||||
@ -368,6 +368,8 @@ export class Hotkey {
|
|||||||
|
|
||||||
private nextExpectedAction: boolean | string = false;
|
private nextExpectedAction: boolean | string = false;
|
||||||
|
|
||||||
|
constructor(readonly name: string = 'unknown') {}
|
||||||
|
|
||||||
mount(window: Window) {
|
mount(window: Window) {
|
||||||
const { document } = window;
|
const { document } = window;
|
||||||
const handleKeyEvent = this.handleKeyEvent.bind(this);
|
const handleKeyEvent = this.handleKeyEvent.bind(this);
|
||||||
@ -645,5 +647,5 @@ export class Hotkey {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const hotkey = new Hotkey();
|
// export const hotkey = new Hotkey();
|
||||||
hotkey.mount(window);
|
// hotkey.mount(window);
|
||||||
|
|||||||
@ -1,62 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@alilc/lowcode-editor-view",
|
|
||||||
"version": "1.0.15",
|
|
||||||
"description": "Shell Layer for AliLowCodeEngine",
|
|
||||||
"main": "lib/index.js",
|
|
||||||
"private": true,
|
|
||||||
"module": "es/index.js",
|
|
||||||
"files": [
|
|
||||||
"lib",
|
|
||||||
"es"
|
|
||||||
],
|
|
||||||
"scripts": {
|
|
||||||
"build": "build-scripts build --skip-demo",
|
|
||||||
"test": "build-scripts test --config build.test.json",
|
|
||||||
"test:cov": "build-scripts test --config build.test.json --jest-coverage"
|
|
||||||
},
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@alilc/lowcode-designer": "1.0.15",
|
|
||||||
"@alilc/lowcode-editor-core": "1.0.15",
|
|
||||||
"@alilc/lowcode-editor-skeleton": "1.0.15",
|
|
||||||
"@alilc/lowcode-types": "1.0.15",
|
|
||||||
"@alilc/lowcode-utils": "1.0.15",
|
|
||||||
"classnames": "^2.2.6",
|
|
||||||
"enzyme": "^3.11.0",
|
|
||||||
"enzyme-adapter-react-16": "^1.15.5",
|
|
||||||
"react": "^16",
|
|
||||||
"react-dom": "^16.7.0",
|
|
||||||
"zen-logger": "^1.1.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@alib/build-scripts": "^0.1.29",
|
|
||||||
"@alilc/lowcode-test-mate": "^1.0.1",
|
|
||||||
"@testing-library/react": "^11.2.2",
|
|
||||||
"@types/classnames": "^2.2.7",
|
|
||||||
"@types/jest": "^26.0.16",
|
|
||||||
"@types/lodash": "^4.14.165",
|
|
||||||
"@types/medium-editor": "^5.0.3",
|
|
||||||
"@types/node": "^13.7.1",
|
|
||||||
"@types/react": "^16",
|
|
||||||
"@types/react-dom": "^16",
|
|
||||||
"babel-jest": "^26.5.2",
|
|
||||||
"build-plugin-component": "^1.0.0",
|
|
||||||
"build-scripts-config": "^3.0.3",
|
|
||||||
"jest": "^26.6.3",
|
|
||||||
"lodash": "^4.17.20",
|
|
||||||
"moment": "^2.29.1",
|
|
||||||
"typescript": "^4.0.3"
|
|
||||||
},
|
|
||||||
"publishConfig": {
|
|
||||||
"access": "public",
|
|
||||||
"registry": "https://registry.npmjs.org/"
|
|
||||||
},
|
|
||||||
"resolutions": {
|
|
||||||
"@builder/babel-preset-ice": "1.0.1"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "http",
|
|
||||||
"url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/shell"
|
|
||||||
},
|
|
||||||
"gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6"
|
|
||||||
}
|
|
||||||
@ -1,70 +0,0 @@
|
|||||||
import { globalContext, Editor, engineConfig, Setters as InnerSetters, EngineOptions } from '@alilc/lowcode-editor-core';
|
|
||||||
import {
|
|
||||||
Designer,
|
|
||||||
LowCodePluginManager,
|
|
||||||
TransformStage,
|
|
||||||
} from '@alilc/lowcode-designer';
|
|
||||||
import {
|
|
||||||
Skeleton as InnerSkeleton,
|
|
||||||
} from '@alilc/lowcode-editor-skeleton';
|
|
||||||
import {
|
|
||||||
WorkSpace,
|
|
||||||
} from '@alilc/lowcode-workspace';
|
|
||||||
|
|
||||||
import { Hotkey, Project, Skeleton, Setters, Material, Event } from '@alilc/lowcode-shell';
|
|
||||||
import { getLogger } from '@alilc/lowcode-utils';
|
|
||||||
|
|
||||||
export class BasicContext {
|
|
||||||
skeleton;
|
|
||||||
plugins;
|
|
||||||
project;
|
|
||||||
setters;
|
|
||||||
material;
|
|
||||||
config;
|
|
||||||
event;
|
|
||||||
logger;
|
|
||||||
hotkey;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
const editor = new Editor();
|
|
||||||
// globalContext.register(editor, Editor);
|
|
||||||
// globalContext.register(editor, 'editor');
|
|
||||||
|
|
||||||
const innerSkeleton = new InnerSkeleton(editor);
|
|
||||||
editor.set('skeleton' as any, innerSkeleton);
|
|
||||||
|
|
||||||
const designer = new Designer({ editor });
|
|
||||||
editor.set('designer' as any, designer);
|
|
||||||
|
|
||||||
const plugins = new LowCodePluginManager(editor).toProxy();
|
|
||||||
editor.set('plugins' as any, plugins);
|
|
||||||
|
|
||||||
const { project: innerProject } = designer;
|
|
||||||
// const skeletonCabin = getSkeletonCabin(innerSkeleton);
|
|
||||||
// const { Workbench } = skeletonCabin;
|
|
||||||
|
|
||||||
const hotkey = new Hotkey();
|
|
||||||
const project = new Project(innerProject);
|
|
||||||
const skeleton = new Skeleton(innerSkeleton);
|
|
||||||
const innerSetters = new InnerSetters();
|
|
||||||
const setters = new Setters(innerSetters);
|
|
||||||
const material = new Material(editor);
|
|
||||||
const config = engineConfig;
|
|
||||||
const event = new Event(editor, { prefix: 'common' });
|
|
||||||
const logger = getLogger({ level: 'warn', bizName: 'common' });
|
|
||||||
// const designerCabin = getDesignerCabin(editor);
|
|
||||||
const objects = {
|
|
||||||
TransformStage,
|
|
||||||
};
|
|
||||||
const workSpace = new WorkSpace();
|
|
||||||
this.skeleton = skeleton;
|
|
||||||
this.plugins = plugins;
|
|
||||||
this.project = project;
|
|
||||||
this.setters = setters;
|
|
||||||
this.material = material;
|
|
||||||
this.config = config;
|
|
||||||
this.event = event;
|
|
||||||
this.logger = logger;
|
|
||||||
this.hotkey = hotkey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
// import { LowCodePluginManager } from "@alilc/lowcode-designer";
|
|
||||||
// import { Editor, Hotkey } from "@alilc/lowcode-editor-core";
|
|
||||||
// import { Material } from "@alilc/lowcode-shell";
|
|
||||||
|
|
||||||
// import {
|
|
||||||
// Skeleton as InnerSkeleton,
|
|
||||||
// SettingsPrimaryPane,
|
|
||||||
// registerDefaults,
|
|
||||||
// Workbench,
|
|
||||||
// } from '@alilc/lowcode-editor-skeleton';
|
|
||||||
import { EditorViewOptions } from '@alilc/lowcode-workspace';
|
|
||||||
import { BasicContext } from './base-context';
|
|
||||||
|
|
||||||
export class Context extends BasicContext {
|
|
||||||
constructor(public editorView: EditorViewOptions) {
|
|
||||||
super();
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
async init() {
|
|
||||||
await this.editorView?.init(this);
|
|
||||||
this.plugins.init();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,31 +0,0 @@
|
|||||||
import { skeletonSymbol } from '@alilc/lowcode-shell';
|
|
||||||
import { observer } from '@alilc/lowcode-editor-core';
|
|
||||||
import {
|
|
||||||
Workbench,
|
|
||||||
} from '@alilc/lowcode-editor-skeleton';
|
|
||||||
import { Component } from 'react';
|
|
||||||
import { Context } from './context';
|
|
||||||
|
|
||||||
export * from './base-context';
|
|
||||||
|
|
||||||
@observer
|
|
||||||
export class EditorView extends Component<any, any> {
|
|
||||||
// 因为 document 数据在不同视图下使用的是同一份,所以这里通过 constructor 传入
|
|
||||||
constructor(props: any) {
|
|
||||||
super(props);
|
|
||||||
this.ctx = new Context(props.editorView);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx: Context;
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const innerSkeleton = this.ctx.skeleton[skeletonSymbol];
|
|
||||||
return (
|
|
||||||
<Workbench
|
|
||||||
skeleton={innerSkeleton}
|
|
||||||
className="engine-main"
|
|
||||||
topAreaItemClassName="engine-actionitem"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"plugins": [
|
|
||||||
"build-plugin-component",
|
|
||||||
"@alilc/lowcode-test-mate/plugin/index.ts"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
|
|
||||||
collectCoverage: true,
|
|
||||||
collectCoverageFrom: [
|
|
||||||
'src/**/*.{ts,tsx}',
|
|
||||||
'!**/node_modules/**',
|
|
||||||
'!**/vendor/**',
|
|
||||||
],
|
|
||||||
};
|
|
||||||
@ -1,62 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@alilc/lowcode-editor-window",
|
|
||||||
"version": "1.0.15",
|
|
||||||
"description": "Shell Layer for AliLowCodeEngine",
|
|
||||||
"main": "lib/index.js",
|
|
||||||
"private": true,
|
|
||||||
"module": "es/index.js",
|
|
||||||
"files": [
|
|
||||||
"lib",
|
|
||||||
"es"
|
|
||||||
],
|
|
||||||
"scripts": {
|
|
||||||
"build": "build-scripts build --skip-demo",
|
|
||||||
"test": "build-scripts test --config build.test.json",
|
|
||||||
"test:cov": "build-scripts test --config build.test.json --jest-coverage"
|
|
||||||
},
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@alilc/lowcode-designer": "1.0.15",
|
|
||||||
"@alilc/lowcode-editor-core": "1.0.15",
|
|
||||||
"@alilc/lowcode-editor-skeleton": "1.0.15",
|
|
||||||
"@alilc/lowcode-types": "1.0.15",
|
|
||||||
"@alilc/lowcode-utils": "1.0.15",
|
|
||||||
"classnames": "^2.2.6",
|
|
||||||
"enzyme": "^3.11.0",
|
|
||||||
"enzyme-adapter-react-16": "^1.15.5",
|
|
||||||
"react": "^16",
|
|
||||||
"react-dom": "^16.7.0",
|
|
||||||
"zen-logger": "^1.1.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@alib/build-scripts": "^0.1.29",
|
|
||||||
"@alilc/lowcode-test-mate": "^1.0.1",
|
|
||||||
"@testing-library/react": "^11.2.2",
|
|
||||||
"@types/classnames": "^2.2.7",
|
|
||||||
"@types/jest": "^26.0.16",
|
|
||||||
"@types/lodash": "^4.14.165",
|
|
||||||
"@types/medium-editor": "^5.0.3",
|
|
||||||
"@types/node": "^13.7.1",
|
|
||||||
"@types/react": "^16",
|
|
||||||
"@types/react-dom": "^16",
|
|
||||||
"babel-jest": "^26.5.2",
|
|
||||||
"build-plugin-component": "^1.0.0",
|
|
||||||
"build-scripts-config": "^3.0.3",
|
|
||||||
"jest": "^26.6.3",
|
|
||||||
"lodash": "^4.17.20",
|
|
||||||
"moment": "^2.29.1",
|
|
||||||
"typescript": "^4.0.3"
|
|
||||||
},
|
|
||||||
"publishConfig": {
|
|
||||||
"access": "public",
|
|
||||||
"registry": "https://registry.npmjs.org/"
|
|
||||||
},
|
|
||||||
"resolutions": {
|
|
||||||
"@builder/babel-preset-ice": "1.0.1"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "http",
|
|
||||||
"url": "https://github.com/alibaba/lowcode-engine/tree/main/packages/shell"
|
|
||||||
},
|
|
||||||
"gitHead": "2669f179e6f899d395ce1942d0fe04f9c5ed48a6"
|
|
||||||
}
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
import { EditorWindow } from '@alilc/lowcode-workspace';
|
|
||||||
import { BasicContext } from '@alilc/lowcode-editor-view';
|
|
||||||
|
|
||||||
export class Context extends BasicContext {
|
|
||||||
constructor(public editorWindow: EditorWindow) {
|
|
||||||
super();
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
async init() {
|
|
||||||
await this.editorWindow.resource.init(this);
|
|
||||||
this.plugins.init();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
import { Component } from 'react';
|
|
||||||
import { EditorView } from '@alilc/lowcode-editor-view';
|
|
||||||
import { Context } from './context';
|
|
||||||
import { observer } from '@alilc/lowcode-editor-core';
|
|
||||||
|
|
||||||
@observer
|
|
||||||
export class EditorWindow extends Component<{
|
|
||||||
editorWindow: any;
|
|
||||||
}, any> {
|
|
||||||
constructor(props: any) {
|
|
||||||
super(props);
|
|
||||||
// if (!props.resource) {
|
|
||||||
// throw new Error('resource is required');
|
|
||||||
// }
|
|
||||||
this.ctx = new Context(props.editorWindow);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx;
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { resource, editorView } = this.props.editorWindow;
|
|
||||||
return (
|
|
||||||
<EditorView
|
|
||||||
resourceCtx={this.ctx}
|
|
||||||
resource={resource}
|
|
||||||
key={editorView.name}
|
|
||||||
editorView={editorView}
|
|
||||||
defaultViewType
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "../../tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "lib"
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"./src/"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -1,8 +1,16 @@
|
|||||||
/* eslint-disable no-param-reassign */
|
/* eslint-disable no-param-reassign */
|
||||||
import { createElement } from 'react';
|
import { createElement } from 'react';
|
||||||
import { render, unmountComponentAtNode } from 'react-dom';
|
import { render, unmountComponentAtNode } from 'react-dom';
|
||||||
import { globalContext, Editor, engineConfig, Setters as InnerSetters } from '@alilc/lowcode-editor-core';
|
import {
|
||||||
import { EngineOptions } from '@alilc/lowcode-types';
|
globalContext,
|
||||||
|
Editor,
|
||||||
|
engineConfig,
|
||||||
|
Setters as InnerSetters,
|
||||||
|
Hotkey as InnerHotkey,
|
||||||
|
} from '@alilc/lowcode-editor-core';
|
||||||
|
import { EngineOptions,
|
||||||
|
IPublicModelDocumentModel,
|
||||||
|
} from '@alilc/lowcode-types';
|
||||||
import {
|
import {
|
||||||
Designer,
|
Designer,
|
||||||
LowCodePluginManager,
|
LowCodePluginManager,
|
||||||
@ -37,6 +45,7 @@ import { componentMetaParser } from './inner-plugins/component-meta-parser';
|
|||||||
import { setterRegistry } from './inner-plugins/setter-registry';
|
import { setterRegistry } from './inner-plugins/setter-registry';
|
||||||
import { defaultPanelRegistry } from './inner-plugins/default-panel-registry';
|
import { defaultPanelRegistry } from './inner-plugins/default-panel-registry';
|
||||||
import { shellModelFactory } from './modules/shell-model-factory';
|
import { shellModelFactory } from './modules/shell-model-factory';
|
||||||
|
import { builtinHotkey } from './inner-plugins/builtin-hotkey';
|
||||||
|
|
||||||
export * from './modules/skeleton-types';
|
export * from './modules/skeleton-types';
|
||||||
export * from './modules/designer-types';
|
export * from './modules/designer-types';
|
||||||
@ -57,7 +66,8 @@ const designer = new Designer({ editor, shellModelFactory });
|
|||||||
editor.set('designer' as any, designer);
|
editor.set('designer' as any, designer);
|
||||||
const { project: innerProject } = designer;
|
const { project: innerProject } = designer;
|
||||||
|
|
||||||
const hotkey = new Hotkey();
|
const innerHotkey = new InnerHotkey();
|
||||||
|
const hotkey = new Hotkey(innerHotkey);
|
||||||
const project = new Project(innerProject);
|
const project = new Project(innerProject);
|
||||||
const skeleton = new Skeleton(innerSkeleton);
|
const skeleton = new Skeleton(innerSkeleton);
|
||||||
const innerSetters = new InnerSetters();
|
const innerSetters = new InnerSetters();
|
||||||
@ -67,6 +77,7 @@ const material = new Material(editor);
|
|||||||
editor.set('project', project);
|
editor.set('project', project);
|
||||||
editor.set('setters' as any, setters);
|
editor.set('setters' as any, setters);
|
||||||
editor.set('material', material);
|
editor.set('material', material);
|
||||||
|
editor.set('innerHotkey', innerHotkey);
|
||||||
const config = engineConfig;
|
const config = engineConfig;
|
||||||
const event = new Event(editor, { prefix: 'common' });
|
const event = new Event(editor, { prefix: 'common' });
|
||||||
const logger = getLogger({ level: 'warn', bizName: 'common' });
|
const logger = getLogger({ level: 'warn', bizName: 'common' });
|
||||||
@ -158,6 +169,7 @@ export async function init(
|
|||||||
await plugins.register(componentMetaParser(designer));
|
await plugins.register(componentMetaParser(designer));
|
||||||
await plugins.register(setterRegistry);
|
await plugins.register(setterRegistry);
|
||||||
await plugins.register(defaultPanelRegistry(editor, designer));
|
await plugins.register(defaultPanelRegistry(editor, designer));
|
||||||
|
await plugins.register(builtinHotkey);
|
||||||
|
|
||||||
await plugins.init(pluginPreference as any);
|
await plugins.init(pluginPreference as any);
|
||||||
|
|
||||||
@ -189,7 +201,7 @@ export async function destroy() {
|
|||||||
// remove all documents
|
// remove all documents
|
||||||
const { documents } = project;
|
const { documents } = project;
|
||||||
if (Array.isArray(documents) && documents.length > 0) {
|
if (Array.isArray(documents) && documents.length > 0) {
|
||||||
documents.forEach(((doc: DocumentModel) => project.removeDocument(doc)));
|
documents.forEach(((doc: IPublicModelDocumentModel) => project.removeDocument(doc)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: delete plugins except for core plugins
|
// TODO: delete plugins except for core plugins
|
||||||
|
|||||||
371
packages/engine/src/inner-plugins/builtin-hotkey.ts
Normal file
371
packages/engine/src/inner-plugins/builtin-hotkey.ts
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
import { Editor, globalContext } from '@alilc/lowcode-editor-core';
|
||||||
|
import { isFormEvent } from '@alilc/lowcode-utils';
|
||||||
|
import {
|
||||||
|
focusing,
|
||||||
|
insertChildren,
|
||||||
|
TransformStage,
|
||||||
|
clipboard,
|
||||||
|
ILowCodePluginContext,
|
||||||
|
} from '@alilc/lowcode-designer';
|
||||||
|
|
||||||
|
export function isInLiveEditing() {
|
||||||
|
const workSpace = globalContext.get('workSpace');
|
||||||
|
if (workSpace.isActive) {
|
||||||
|
return Boolean(
|
||||||
|
workSpace.window.editor.get('designer')?.project?.simulator?.liveEditing?.editing,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (globalContext.has(Editor)) {
|
||||||
|
return Boolean(
|
||||||
|
globalContext.get(Editor).get('designer')?.project?.simulator?.liveEditing?.editing,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
function getNextForSelect(next: any, head?: any, parent?: any): any {
|
||||||
|
if (next) {
|
||||||
|
if (!head) {
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ret;
|
||||||
|
if (next.isContainer()) {
|
||||||
|
const children = next.getChildren() || [];
|
||||||
|
if (children && !children.isEmpty()) {
|
||||||
|
ret = getNextForSelect(children.get(0));
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = getNextForSelect(next.nextSibling);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent) {
|
||||||
|
return getNextForSelect(parent.nextSibling, false, parent.getParent());
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* istanbul ignore next */
|
||||||
|
function getPrevForSelect(prev: any, head?: any, parent?: any): any {
|
||||||
|
if (prev) {
|
||||||
|
let ret;
|
||||||
|
if (!head && prev.isContainer()) {
|
||||||
|
const children = prev.getChildren() || [];
|
||||||
|
const lastChild = children && !children.isEmpty() ? children.get(children.size - 1) : null;
|
||||||
|
|
||||||
|
ret = getPrevForSelect(lastChild);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!head) {
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = getPrevForSelect(prev.prevSibling);
|
||||||
|
if (ret) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent) {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册默认的 setters
|
||||||
|
export const builtinHotkey = (ctx: ILowCodePluginContext) => {
|
||||||
|
return {
|
||||||
|
init() {
|
||||||
|
const { hotkey, project } = ctx;
|
||||||
|
// hotkey binding
|
||||||
|
hotkey.bind(['backspace', 'del'], (e: KeyboardEvent) => {
|
||||||
|
if (isInLiveEditing()) return;
|
||||||
|
// TODO: use focus-tracker
|
||||||
|
const doc = project.currentDocument;
|
||||||
|
if (isFormEvent(e) || !doc) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const sel = doc.selection;
|
||||||
|
const topItems = sel.getTopNodes();
|
||||||
|
// TODO: check can remove
|
||||||
|
topItems.forEach((node) => {
|
||||||
|
if (node?.canPerformAction('remove')) {
|
||||||
|
node && doc.removeNode(node);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
sel.clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
hotkey.bind('escape', (e: KeyboardEvent) => {
|
||||||
|
// const currentFocus = focusing.current;
|
||||||
|
if (isInLiveEditing()) return;
|
||||||
|
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) => {
|
||||||
|
if (isInLiveEditing()) return;
|
||||||
|
const doc = project.currentDocument;
|
||||||
|
if (isFormEvent(e) || !doc) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
let selected = doc.selection.getTopNodes(true);
|
||||||
|
selected = selected.filter((node) => {
|
||||||
|
return node?.canPerformAction('copy');
|
||||||
|
});
|
||||||
|
if (!selected || selected.length < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const componentsMap = {};
|
||||||
|
const componentsTree = selected.map((item) => item?.exportSchema(TransformStage.Clone));
|
||||||
|
|
||||||
|
// FIXME: clear node.id
|
||||||
|
|
||||||
|
const data = { type: 'nodeSchema', componentsMap, componentsTree };
|
||||||
|
|
||||||
|
clipboard.setData(data);
|
||||||
|
|
||||||
|
const cutMode = action && action.indexOf('x') > 0;
|
||||||
|
if (cutMode) {
|
||||||
|
selected.forEach((node) => {
|
||||||
|
const parentNode = node?.parent;
|
||||||
|
parentNode?.select();
|
||||||
|
node?.remove();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// command + v paste
|
||||||
|
hotkey.bind(['command+v', 'ctrl+v'], (e) => {
|
||||||
|
if (isInLiveEditing()) return;
|
||||||
|
// TODO
|
||||||
|
const designer = focusing.focusDesigner;
|
||||||
|
const doc = designer?.currentDocument;
|
||||||
|
if (isFormEvent(e) || !designer || !doc) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* istanbul ignore next */
|
||||||
|
clipboard.waitPasteData(e, ({ componentsTree }) => {
|
||||||
|
if (componentsTree) {
|
||||||
|
const { target, index } = designer.getSuitableInsertion(componentsTree) || {};
|
||||||
|
if (!target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let canAddComponentsTree = componentsTree.filter((i) => {
|
||||||
|
return doc.checkNestingUp(target, i);
|
||||||
|
});
|
||||||
|
if (canAddComponentsTree.length === 0) return;
|
||||||
|
const nodes = insertChildren(target, canAddComponentsTree, 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) => {
|
||||||
|
if (isInLiveEditing()) return;
|
||||||
|
const history = project.currentDocument?.history;
|
||||||
|
if (isFormEvent(e) || !history) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
const selection = project.currentDocument?.selection;
|
||||||
|
const curSelected = selection?.selected && Array.from(selection?.selected);
|
||||||
|
history.back();
|
||||||
|
selection?.selectAll(curSelected);
|
||||||
|
});
|
||||||
|
|
||||||
|
// command + shift + z redo
|
||||||
|
hotkey.bind(['command+y', 'ctrl+y', 'command+shift+z'], (e) => {
|
||||||
|
if (isInLiveEditing()) return;
|
||||||
|
const history = project.currentDocument?.history;
|
||||||
|
if (isFormEvent(e) || !history) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
const selection = project.currentDocument?.selection;
|
||||||
|
const curSelected = selection?.selected && Array.from(selection?.selected);
|
||||||
|
history.forward();
|
||||||
|
selection?.selectAll(curSelected);
|
||||||
|
});
|
||||||
|
|
||||||
|
// sibling selection
|
||||||
|
hotkey.bind(['left', 'right'], (e, action) => {
|
||||||
|
if (isInLiveEditing()) return;
|
||||||
|
const doc = project.currentDocument;
|
||||||
|
if (isFormEvent(e) || !doc) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
const selected = doc.selection.getTopNodes(true);
|
||||||
|
if (!selected || selected.length < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const firstNode = selected[0];
|
||||||
|
const silbing = action === 'left' ? firstNode?.prevSibling : firstNode?.nextSibling;
|
||||||
|
silbing?.select();
|
||||||
|
});
|
||||||
|
|
||||||
|
hotkey.bind(['up', 'down'], (e, action) => {
|
||||||
|
if (isInLiveEditing()) return;
|
||||||
|
const doc = project.currentDocument;
|
||||||
|
if (isFormEvent(e) || !doc) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
const selected = doc.selection.getTopNodes(true);
|
||||||
|
if (!selected || selected.length < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const firstNode = selected[0];
|
||||||
|
|
||||||
|
if (action === 'down') {
|
||||||
|
const next = getNextForSelect(firstNode, true, firstNode?.parent);
|
||||||
|
next?.select();
|
||||||
|
} else if (action === 'up') {
|
||||||
|
const prev = getPrevForSelect(firstNode, true, firstNode?.parent);
|
||||||
|
prev?.select();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
hotkey.bind(['option+left', 'option+right'], (e, action) => {
|
||||||
|
if (isInLiveEditing()) return;
|
||||||
|
const doc = project.currentDocument;
|
||||||
|
if (isFormEvent(e) || !doc) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
const selected = doc.selection.getTopNodes(true);
|
||||||
|
if (!selected || selected.length < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// TODO: 此处需要增加判断当前节点是否可被操作移动,原ve里是用 node.canOperating()来判断
|
||||||
|
// TODO: 移动逻辑也需要重新梳理,对于移动目标位置的选择,是否可以移入,需要增加判断
|
||||||
|
|
||||||
|
const firstNode = selected[0];
|
||||||
|
const parent = firstNode?.parent;
|
||||||
|
if (!parent) return;
|
||||||
|
|
||||||
|
const isPrev = action && /(left)$/.test(action);
|
||||||
|
|
||||||
|
const silbing = isPrev ? firstNode.prevSibling : firstNode.nextSibling;
|
||||||
|
if (silbing) {
|
||||||
|
if (isPrev) {
|
||||||
|
parent.insertBefore(firstNode, silbing);
|
||||||
|
} else {
|
||||||
|
parent.insertAfter(firstNode, silbing);
|
||||||
|
}
|
||||||
|
firstNode?.select();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
hotkey.bind(['option+up'], (e) => {
|
||||||
|
if (isInLiveEditing()) return;
|
||||||
|
const doc = project.currentDocument;
|
||||||
|
if (isFormEvent(e) || !doc) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
const selected = doc.selection.getTopNodes(true);
|
||||||
|
if (!selected || selected.length < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// TODO: 此处需要增加判断当前节点是否可被操作移动,原ve里是用 node.canOperating()来判断
|
||||||
|
// TODO: 移动逻辑也需要重新梳理,对于移动目标位置的选择,是否可以移入,需要增加判断
|
||||||
|
|
||||||
|
const firstNode = selected[0];
|
||||||
|
const parent = firstNode?.parent;
|
||||||
|
if (!parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const silbing = firstNode.prevSibling;
|
||||||
|
if (silbing) {
|
||||||
|
if (silbing.isContainer) {
|
||||||
|
const place = silbing.getSuitablePlace(firstNode, null);
|
||||||
|
silbing.insertAfter(place, place.ref);
|
||||||
|
} else {
|
||||||
|
parent.insertBefore(firstNode, silbing);
|
||||||
|
}
|
||||||
|
firstNode?.select();
|
||||||
|
} else {
|
||||||
|
const place = parent.getSuitablePlace(firstNode, null); // upwards
|
||||||
|
if (place) {
|
||||||
|
place.container.insertBefore(firstNode, place.ref);
|
||||||
|
firstNode?.select();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
hotkey.bind(['option+down'], (e) => {
|
||||||
|
if (isInLiveEditing()) return;
|
||||||
|
const doc = project.getCurrentDocument();
|
||||||
|
if (isFormEvent(e) || !doc) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
const selected = doc.selection.getTopNodes(true);
|
||||||
|
if (!selected || selected.length < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// TODO: 此处需要增加判断当前节点是否可被操作移动,原ve里是用 node.canOperating()来判断
|
||||||
|
// TODO: 移动逻辑也需要重新梳理,对于移动目标位置的选择,是否可以移入,需要增加判断
|
||||||
|
|
||||||
|
const firstNode = selected[0];
|
||||||
|
const parent = firstNode?.parent;
|
||||||
|
if (!parent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const silbing = firstNode.nextSibling;
|
||||||
|
if (silbing) {
|
||||||
|
if (silbing.isContainer) {
|
||||||
|
// const place = silbing.getSuitablePlace(firstNode, null);
|
||||||
|
silbing.insertBefore(firstNode, undefined);
|
||||||
|
// place.container.insertBefore(firstNode, place.ref);
|
||||||
|
} else {
|
||||||
|
parent.insertAfter(firstNode, silbing);
|
||||||
|
}
|
||||||
|
firstNode?.select();
|
||||||
|
} else {
|
||||||
|
const place = parent.getSuitablePlace(firstNode, null); // upwards
|
||||||
|
if (place) {
|
||||||
|
place.container.insertAfter(firstNode, place.ref);
|
||||||
|
firstNode?.select();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
builtinHotkey.pluginName = '___builtin_hotkey___';
|
||||||
@ -224,6 +224,11 @@ class Utils implements IPublicCommonUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class EditorCabin {
|
class EditorCabin {
|
||||||
|
private readonly [editorSymbol]: Editor;
|
||||||
|
|
||||||
|
constructor(editor: Editor) {
|
||||||
|
this[editorSymbol] = editor;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* @deprecated
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
@ -259,12 +264,13 @@ class EditorCabin {
|
|||||||
return innerIntl(data, params);
|
return innerIntl(data, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
/**
|
||||||
// * @deprecated
|
* @deprecated
|
||||||
// */
|
*/
|
||||||
// createSetterContent(setter: any, props: Record<string, any>): ReactNode {
|
createSetterContent = (setter: any, props: Record<string, any>): ReactNode => {
|
||||||
// return innerCreateSetterContent(setter, props);
|
const setters = this[editorSymbol].get('setters');
|
||||||
// }
|
return setters.createSetterContent(setter, props);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated
|
* @deprecated
|
||||||
@ -326,7 +332,7 @@ export default class Common implements IPublicApiCommon {
|
|||||||
constructor(editor: Editor, skeleton: InnerSkeleton) {
|
constructor(editor: Editor, skeleton: InnerSkeleton) {
|
||||||
this.__designerCabin = new DesignerCabin(editor);
|
this.__designerCabin = new DesignerCabin(editor);
|
||||||
this.__skeletonCabin = new SkeletonCabin(skeleton);
|
this.__skeletonCabin = new SkeletonCabin(skeleton);
|
||||||
this.__editorCabin = new EditorCabin();
|
this.__editorCabin = new EditorCabin(editor);
|
||||||
this.__utils = new Utils();
|
this.__utils = new Utils();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,29 @@
|
|||||||
import { hotkey } from '@alilc/lowcode-editor-core';
|
import { globalContext, Hotkey as InnerHotkey } from '@alilc/lowcode-editor-core';
|
||||||
|
import { hotkeySymbol } from './symbols';
|
||||||
import { Disposable, HotkeyCallback, IPublicApiHotkey } from '@alilc/lowcode-types';
|
import { Disposable, HotkeyCallback, IPublicApiHotkey } from '@alilc/lowcode-types';
|
||||||
|
|
||||||
|
const innerHotkeySymbol = Symbol('innerHotkey');
|
||||||
|
|
||||||
export default class Hotkey implements IPublicApiHotkey {
|
export default class Hotkey implements IPublicApiHotkey {
|
||||||
constructor(public name: string = 'unknown', public workspaceMode: boolean = false) {
|
private readonly [innerHotkeySymbol]: InnerHotkey;
|
||||||
|
get [hotkeySymbol](): InnerHotkey {
|
||||||
|
if (this.workspaceMode) {
|
||||||
|
return this[innerHotkeySymbol];
|
||||||
|
}
|
||||||
|
const workSpace = globalContext.get('workSpace');
|
||||||
|
if (workSpace.isActive) {
|
||||||
|
return workSpace.window.innerHotkey;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this[innerHotkeySymbol];
|
||||||
}
|
}
|
||||||
|
|
||||||
get callbacks() {
|
constructor(hotkey: InnerHotkey, public name: string = 'unknown', public workspaceMode: boolean = false) {
|
||||||
return hotkey.callBacks;
|
this[innerHotkeySymbol] = hotkey;
|
||||||
|
}
|
||||||
|
|
||||||
|
get callbacks(): any {
|
||||||
|
return this[hotkeySymbol].callBacks;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @deprecated
|
* @deprecated
|
||||||
@ -22,9 +39,9 @@ export default class Hotkey implements IPublicApiHotkey {
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
bind(combos: string[] | string, callback: HotkeyCallback, action?: string): Disposable {
|
bind(combos: string[] | string, callback: HotkeyCallback, action?: string): Disposable {
|
||||||
hotkey.bind(combos, callback, action);
|
this[hotkeySymbol].bind(combos, callback, action);
|
||||||
return () => {
|
return () => {
|
||||||
hotkey.unbind(combos, callback, action);
|
this[hotkeySymbol].unbind(combos, callback, action);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -527,4 +527,8 @@ export default class Node implements IPublicModelNode {
|
|||||||
internalToShellNode() {
|
internalToShellNode() {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
canPerformAction(actionName: string): boolean {
|
||||||
|
return this[nodeSymbol].canPerformAction(actionName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -92,7 +92,7 @@ export default class Selection implements IPublicModelSelection {
|
|||||||
* getTopNodes() will return [A, B], subA will be removed
|
* getTopNodes() will return [A, B], subA will be removed
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
getTopNodes(): Array<IPublicModelNode | null> {
|
getTopNodes(includeRoot: boolean = false): Array<IPublicModelNode | null> {
|
||||||
return this[selectionSymbol].getTopNodes().map((node: InnerNode) => Node.create(node));
|
return this[selectionSymbol].getTopNodes(includeRoot).map((node: InnerNode) => Node.create(node));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,3 +25,4 @@ export const simulatorRendererSymbol = Symbol('simulatorRenderer');
|
|||||||
export const dragObjectSymbol = Symbol('dragObject');
|
export const dragObjectSymbol = Symbol('dragObject');
|
||||||
export const locateEventSymbol = Symbol('locateEvent');
|
export const locateEventSymbol = Symbol('locateEvent');
|
||||||
export const designerCabinSymbol = Symbol('designerCabin');
|
export const designerCabinSymbol = Symbol('designerCabin');
|
||||||
|
export const hotkeySymbol = Symbol('hotkey');
|
||||||
@ -132,6 +132,11 @@ export interface EngineOptions {
|
|||||||
* 配置指定节点为根组件
|
* 配置指定节点为根组件
|
||||||
*/
|
*/
|
||||||
focusNodeSelector?: (rootNode: Node) => Node;
|
focusNodeSelector?: (rootNode: Node) => Node;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开启应用级设计模式
|
||||||
|
*/
|
||||||
|
enableWorkspaceMode?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IEngineConfig {
|
export interface IEngineConfig {
|
||||||
|
|||||||
@ -5,6 +5,8 @@ import { IPublicApiProject } from '../api';
|
|||||||
import { PropChangeOptions } from '../index';
|
import { PropChangeOptions } from '../index';
|
||||||
import { IPublicModelModalNodesManager } from './modal-nodes-manager';
|
import { IPublicModelModalNodesManager } from './modal-nodes-manager';
|
||||||
import { IPublicModelNode } from './node';
|
import { IPublicModelNode } from './node';
|
||||||
|
import { IPublicModelSelection } from './selection';
|
||||||
|
import { IPublicModelHistory } from './history';
|
||||||
|
|
||||||
|
|
||||||
export interface IPublicModelDocumentModel {
|
export interface IPublicModelDocumentModel {
|
||||||
@ -16,6 +18,10 @@ export interface IPublicModelDocumentModel {
|
|||||||
|
|
||||||
set id(id);
|
set id(id);
|
||||||
|
|
||||||
|
selection: IPublicModelSelection;
|
||||||
|
|
||||||
|
history: IPublicModelHistory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取当前文档所属的 project
|
* 获取当前文档所属的 project
|
||||||
* @returns
|
* @returns
|
||||||
|
|||||||
@ -12,7 +12,6 @@ import { IPublicModelNodeChildren } from './node-children';
|
|||||||
import { IPublicModelComponentMeta } from './component-meta';
|
import { IPublicModelComponentMeta } from './component-meta';
|
||||||
|
|
||||||
export interface IPublicModelNode {
|
export interface IPublicModelNode {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 节点 id
|
* 节点 id
|
||||||
*/
|
*/
|
||||||
@ -313,4 +312,11 @@ export interface IPublicModelNode {
|
|||||||
* @returns Boolean
|
* @returns Boolean
|
||||||
*/
|
*/
|
||||||
get isRGLContainer();
|
get isRGLContainer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否可执行某 action
|
||||||
|
* @param actionName action 名字
|
||||||
|
* @returns boolean
|
||||||
|
*/
|
||||||
|
canPerformAction(actionName: string): boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,5 +61,5 @@ export interface IPublicModelSelection {
|
|||||||
* getTopNodes() will return [A, B], subA will be removed
|
* getTopNodes() will return [A, B], subA will be removed
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
getTopNodes(): Array<IPublicModelNode | null>;
|
getTopNodes(includeRoot?: boolean): Array<IPublicModelNode | null>;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Editor, engineConfig, Setters as InnerSetters } from '@alilc/lowcode-editor-core';
|
import { Editor, engineConfig, Setters as InnerSetters, Hotkey as InnerHotkey } from '@alilc/lowcode-editor-core';
|
||||||
import {
|
import {
|
||||||
Designer,
|
Designer,
|
||||||
ILowCodePluginContextApiAssembler,
|
ILowCodePluginContextApiAssembler,
|
||||||
@ -18,6 +18,7 @@ import { getLogger } from '@alilc/lowcode-utils';
|
|||||||
import { setterRegistry } from 'engine/src/inner-plugins/setter-registry';
|
import { setterRegistry } from 'engine/src/inner-plugins/setter-registry';
|
||||||
import { componentMetaParser } from 'engine/src/inner-plugins/component-meta-parser';
|
import { componentMetaParser } from 'engine/src/inner-plugins/component-meta-parser';
|
||||||
import defaultPanelRegistry from 'engine/src/inner-plugins/default-panel-registry';
|
import defaultPanelRegistry from 'engine/src/inner-plugins/default-panel-registry';
|
||||||
|
import { builtinHotkey } from 'engine/src/inner-plugins/builtin-hotkey';
|
||||||
import { EditorWindow } from './editor-window/context';
|
import { EditorWindow } from './editor-window/context';
|
||||||
import { shellModelFactory } from './shell-model-factory';
|
import { shellModelFactory } from './shell-model-factory';
|
||||||
|
|
||||||
@ -37,6 +38,7 @@ export class BasicContext {
|
|||||||
registerInnerPlugins: any;
|
registerInnerPlugins: any;
|
||||||
innerSetters: any;
|
innerSetters: any;
|
||||||
innerSkeleton: any;
|
innerSkeleton: any;
|
||||||
|
innerHotkey: any;
|
||||||
|
|
||||||
constructor(workSpace: WorkSpace, name: string, public editorWindow?: EditorWindow) {
|
constructor(workSpace: WorkSpace, name: string, public editorWindow?: EditorWindow) {
|
||||||
const editor = new Editor(name, true);
|
const editor = new Editor(name, true);
|
||||||
@ -60,7 +62,8 @@ export class BasicContext {
|
|||||||
editor.set('designer' as any, designer);
|
editor.set('designer' as any, designer);
|
||||||
|
|
||||||
const { project: innerProject } = designer;
|
const { project: innerProject } = designer;
|
||||||
const hotkey = new Hotkey(name);
|
const innerHotkey = new InnerHotkey(name);
|
||||||
|
const hotkey = new Hotkey(innerHotkey, name, true);
|
||||||
const innerSetters = new InnerSetters(name);
|
const innerSetters = new InnerSetters(name);
|
||||||
const setters = new Setters(innerSetters, true);
|
const setters = new Setters(innerSetters, true);
|
||||||
const material = new Material(editor, true, name);
|
const material = new Material(editor, true, name);
|
||||||
@ -72,6 +75,9 @@ export class BasicContext {
|
|||||||
editor.set('setters', setters);
|
editor.set('setters', setters);
|
||||||
editor.set('project', project);
|
editor.set('project', project);
|
||||||
editor.set('material', material);
|
editor.set('material', material);
|
||||||
|
editor.set('hotkey', hotkey);
|
||||||
|
editor.set('innerHotkey', innerHotkey);
|
||||||
|
innerHotkey.mount(window);
|
||||||
this.innerSetters = innerSetters;
|
this.innerSetters = innerSetters;
|
||||||
this.innerSkeleton = innerSkeleton;
|
this.innerSkeleton = innerSkeleton;
|
||||||
this.skeleton = skeleton;
|
this.skeleton = skeleton;
|
||||||
@ -83,6 +89,7 @@ export class BasicContext {
|
|||||||
this.event = event;
|
this.event = event;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.hotkey = hotkey;
|
this.hotkey = hotkey;
|
||||||
|
this.innerHotkey = innerHotkey;
|
||||||
this.editor = editor;
|
this.editor = editor;
|
||||||
this.designer = designer;
|
this.designer = designer;
|
||||||
const common = new Common(editor, innerSkeleton);
|
const common = new Common(editor, innerSkeleton);
|
||||||
@ -110,6 +117,7 @@ export class BasicContext {
|
|||||||
await plugins.register(componentMetaParser(designer));
|
await plugins.register(componentMetaParser(designer));
|
||||||
await plugins.register(setterRegistry);
|
await plugins.register(setterRegistry);
|
||||||
await plugins.register(defaultPanelRegistry(editor, designer));
|
await plugins.register(defaultPanelRegistry(editor, designer));
|
||||||
|
await plugins.register(builtinHotkey);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -85,6 +85,10 @@ export class EditorWindow {
|
|||||||
return this.editorView?.innerSetters;
|
return this.editorView?.innerSetters;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get innerHotkey() {
|
||||||
|
return this.editorView?.innerHotkey;
|
||||||
|
}
|
||||||
|
|
||||||
get editor() {
|
get editor() {
|
||||||
return this.editorView?.editor;
|
return this.editorView?.editor;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user