mirror of
https://github.com/alibaba/lowcode-engine.git
synced 2026-01-24 10:38:15 +00:00
Merge branch 'release/0.9.3' of gitlab.alibaba-inc.com:ali-lowcode/ali-lowcode-engine into release/0.9.3
This commit is contained in:
commit
31a0fce529
@ -66,7 +66,9 @@ class Toolbar extends Component<{ observed: OffsetObserver }> {
|
|||||||
const MARGIN = 1;
|
const MARGIN = 1;
|
||||||
const BORDER = 2;
|
const BORDER = 2;
|
||||||
const SPACE_HEIGHT = BAR_HEIGHT + MARGIN + BORDER;
|
const SPACE_HEIGHT = BAR_HEIGHT + MARGIN + BORDER;
|
||||||
|
const SPACE_MINIMUM_WIDTH = 140; // magic number
|
||||||
let style: any;
|
let style: any;
|
||||||
|
// 计算 toolbar 的上/下位置
|
||||||
if (observed.top > SPACE_HEIGHT) {
|
if (observed.top > SPACE_HEIGHT) {
|
||||||
style = {
|
style = {
|
||||||
top: -SPACE_HEIGHT,
|
top: -SPACE_HEIGHT,
|
||||||
@ -83,10 +85,12 @@ class Toolbar extends Component<{ observed: OffsetObserver }> {
|
|||||||
top: Math.max(MARGIN, MARGIN - observed.top),
|
top: Math.max(MARGIN, MARGIN - observed.top),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (observed.width < 140) {
|
// 计算 toolbar 的左/右位置
|
||||||
|
if (SPACE_MINIMUM_WIDTH > observed.left + observed.width) {
|
||||||
style.left = Math.max(-BORDER, observed.left - width - BORDER);
|
style.left = Math.max(-BORDER, observed.left - width - BORDER);
|
||||||
} else {
|
} else {
|
||||||
style.right = Math.max(-BORDER, observed.right - width - BORDER);
|
style.right = Math.max(-BORDER, observed.right - width - BORDER);
|
||||||
|
style.justifyContent = 'flex-start';
|
||||||
}
|
}
|
||||||
const { node } = observed;
|
const { node } = observed;
|
||||||
const actions: ReactNodeArray = [];
|
const actions: ReactNodeArray = [];
|
||||||
|
|||||||
@ -839,22 +839,35 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
|||||||
this.scroller.cancel();
|
this.scroller.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ========= drag location logic: hepler for locate ==========
|
// ========= drag location logic: helper for locate ==========
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see ISensor
|
* @see ISensor
|
||||||
*/
|
*/
|
||||||
locate(e: LocateEvent): any {
|
locate(e: LocateEvent): any {
|
||||||
|
const { dragObject } = e;
|
||||||
|
const { nodes } = dragObject;
|
||||||
|
|
||||||
|
const operationalNodes = nodes?.filter((node: any) => {
|
||||||
|
const onMoveHook = node.componentMeta?.getMetadata()?.experimental?.callbacks?.onMoveHook;
|
||||||
|
const canMove = onMoveHook && typeof onMoveHook === 'function' ? onMoveHook() : true;
|
||||||
|
|
||||||
|
return canMove;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!operationalNodes || operationalNodes.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.sensing = true;
|
this.sensing = true;
|
||||||
this.scroller.scrolling(e);
|
this.scroller.scrolling(e);
|
||||||
const dropContainer = this.getDropContainer(e);
|
const dropContainer = this.getDropContainer(e);
|
||||||
const canDropIn = dropContainer.container?.componentMeta?.prototype?.options?.canDropIn;
|
const canDropIn = dropContainer?.container?.componentMeta?.prototype?.options?.canDropIn;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!dropContainer ||
|
!dropContainer ||
|
||||||
canDropIn === false ||
|
canDropIn === false ||
|
||||||
// too dirty
|
// too dirty
|
||||||
(typeof canDropIn === 'function' &&
|
(typeof canDropIn === 'function' && !canDropIn(operationalNodes[0]))
|
||||||
!canDropIn(e.dragObject.nodes[0]))
|
|
||||||
) {
|
) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -886,7 +899,7 @@ export class BuiltinSimulatorHost implements ISimulatorHost<BuiltinSimulatorProp
|
|||||||
event: e,
|
event: e,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (e.dragObject.type === 'node' && e.dragObject.nodes[0]?.getPrototype()?.isModal()) {
|
if (dragObject.type === 'node' && operationalNodes[0]?.getPrototype()?.isModal()) {
|
||||||
return this.designer.createLocation({
|
return this.designer.createLocation({
|
||||||
target: this.document.rootNode,
|
target: this.document.rootNode,
|
||||||
detail: {
|
detail: {
|
||||||
|
|||||||
@ -137,13 +137,13 @@ export class ComponentMeta {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseMetadata(metadta: ComponentMetadata) {
|
private parseMetadata(metadata: ComponentMetadata) {
|
||||||
const { componentName, npm } = metadta;
|
const { componentName, npm } = metadata;
|
||||||
this._npm = npm;
|
this._npm = npm;
|
||||||
this._componentName = componentName;
|
this._componentName = componentName;
|
||||||
|
|
||||||
// 额外转换逻辑
|
// 额外转换逻辑
|
||||||
this._transformedMetadata = this.transformMetadata(metadta);
|
this._transformedMetadata = this.transformMetadata(metadata);
|
||||||
|
|
||||||
const title = this._transformedMetadata.title;
|
const title = this._transformedMetadata.title;
|
||||||
if (title) {
|
if (title) {
|
||||||
|
|||||||
@ -77,7 +77,9 @@ hotkey.bind(['backspace', 'del'], (e: KeyboardEvent) => {
|
|||||||
const topItems = sel.getTopNodes();
|
const topItems = sel.getTopNodes();
|
||||||
// TODO: check can remove
|
// TODO: check can remove
|
||||||
topItems.forEach((node) => {
|
topItems.forEach((node) => {
|
||||||
|
if (node.canPerformAction('remove')) {
|
||||||
doc.removeNode(node);
|
doc.removeNode(node);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
sel.clear();
|
sel.clear();
|
||||||
});
|
});
|
||||||
@ -102,8 +104,13 @@ hotkey.bind(['command+c', 'ctrl+c', 'command+x', 'ctrl+x'], (e, action) => {
|
|||||||
}
|
}
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const selected = doc.selection.getTopNodes(true);
|
let selected = doc.selection.getTopNodes(true);
|
||||||
if (!selected || selected.length < 1) return;
|
selected = selected.filter((node) => {
|
||||||
|
return node.canPerformAction('copy');
|
||||||
|
})
|
||||||
|
if (!selected || selected.length < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const componentsMap = {};
|
const componentsMap = {};
|
||||||
const componentsTree = selected.map((item) => item.export(TransformStage.Clone));
|
const componentsTree = selected.map((item) => item.export(TransformStage.Clone));
|
||||||
|
|||||||
@ -20,6 +20,15 @@ export type GetDataType<T, NodeType> = T extends undefined
|
|||||||
: any
|
: any
|
||||||
: T;
|
: T;
|
||||||
|
|
||||||
|
export interface ComponentMap {
|
||||||
|
componentName: string;
|
||||||
|
package: string;
|
||||||
|
version?: string;
|
||||||
|
destructuring?: boolean;
|
||||||
|
exportName?: string;
|
||||||
|
subName?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export class DocumentModel {
|
export class DocumentModel {
|
||||||
/**
|
/**
|
||||||
* 根节点 类型有:Page/Component/Block
|
* 根节点 类型有:Page/Component/Block
|
||||||
@ -496,9 +505,13 @@ export class DocumentModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add toData
|
// add toData
|
||||||
toData() {
|
toData(extraComps?: string[]) {
|
||||||
const node = this.project?.currentDocument?.export(TransformStage.Save);
|
const node = this.project?.currentDocument?.export(TransformStage.Save);
|
||||||
return { componentsTree: [node] };
|
const data = {
|
||||||
|
componentsMap: this.getComponentsMap(extraComps),
|
||||||
|
componentsTree: [node],
|
||||||
|
};
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
getHistory(): History {
|
getHistory(): History {
|
||||||
@ -567,6 +580,37 @@ export class DocumentModel {
|
|||||||
return this.rootNodeVisitorMap[name];
|
return this.rootNodeVisitorMap[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getComponentsMap(extraComps?: string[]) {
|
||||||
|
const componentsMap: ComponentMap[] = [];
|
||||||
|
// 组件去重
|
||||||
|
const map: any = {};
|
||||||
|
for (let node of this.nodesMap.values()) {
|
||||||
|
const { componentName } = node || {};
|
||||||
|
if (!map[componentName] && node?.componentMeta?.npm?.package) {
|
||||||
|
map[componentName] = true;
|
||||||
|
componentsMap.push({
|
||||||
|
componentName,
|
||||||
|
package: node?.componentMeta?.npm?.package,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 合并外界传入的自定义渲染的组件
|
||||||
|
if (Array.isArray(extraComps)) {
|
||||||
|
extraComps.forEach(c => {
|
||||||
|
if (c && !map[c]) {
|
||||||
|
const m = this.getComponentMeta(c);
|
||||||
|
if (m && m.npm?.package) {
|
||||||
|
componentsMap.push({
|
||||||
|
componentName: c,
|
||||||
|
package: m.npm?.package,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return componentsMap;
|
||||||
|
}
|
||||||
|
|
||||||
onNodeCreate(func: (node: Node) => void) {
|
onNodeCreate(func: (node: Node) => void) {
|
||||||
this.emitter.on('nodecreate', func);
|
this.emitter.on('nodecreate', func);
|
||||||
return () => {
|
return () => {
|
||||||
|
|||||||
@ -702,6 +702,14 @@ export class Node<Schema extends NodeSchema = NodeSchema> {
|
|||||||
this.document.destroyNode(this);
|
this.document.destroyNode(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否可执行某action
|
||||||
|
*/
|
||||||
|
canPerformAction(action: string): boolean {
|
||||||
|
const availableActions = this.componentMeta?.availableActions?.map((action) => action.name) || [];
|
||||||
|
return availableActions.indexOf(action) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
// ======= compatible apis ====
|
// ======= compatible apis ====
|
||||||
isEmpty(): boolean {
|
isEmpty(): boolean {
|
||||||
return this.children ? this.children.isEmpty() : true;
|
return this.children ? this.children.isEmpty() : true;
|
||||||
|
|||||||
@ -122,20 +122,32 @@ export class OutlineMain implements ISensor, ITreeBoard, IScrollable {
|
|||||||
locate(e: LocateEvent): DropLocation | undefined | null {
|
locate(e: LocateEvent): DropLocation | undefined | null {
|
||||||
this.sensing = true;
|
this.sensing = true;
|
||||||
this.scroller?.scrolling(e);
|
this.scroller?.scrolling(e);
|
||||||
|
const { globalY, dragObject } = e;
|
||||||
|
const { nodes } = dragObject;
|
||||||
|
|
||||||
const tree = this._master?.currentTree;
|
const tree = this._master?.currentTree;
|
||||||
if (!tree || !this._shell) {
|
if (!tree || !this._shell) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const operationalNodes = nodes?.filter((node: any) => {
|
||||||
|
const onMoveHook = node.componentMeta?.getMetadata()?.experimental?.callbacks?.onMoveHook;
|
||||||
|
const canMove = onMoveHook && typeof onMoveHook === 'function' ? onMoveHook() : true;
|
||||||
|
|
||||||
|
return canMove;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!operationalNodes || operationalNodes.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const document = tree.document;
|
const document = tree.document;
|
||||||
const designer = document.designer;
|
const designer = document.designer;
|
||||||
const { globalY, dragObject } = e;
|
|
||||||
const pos = getPosFromEvent(e, this._shell);
|
const pos = getPosFromEvent(e, this._shell);
|
||||||
const irect = this.getInsertionRect();
|
const irect = this.getInsertionRect();
|
||||||
const originLoc = document.dropLocation;
|
const originLoc = document.dropLocation;
|
||||||
|
|
||||||
if (e.dragObject.type === 'node' && e.dragObject.nodes[0].getPrototype().isModal()) {
|
if (dragObject.type === 'node' && operationalNodes[0].getPrototype().isModal()) {
|
||||||
return designer.createLocation({
|
return designer.createLocation({
|
||||||
target: document.rootNode,
|
target: document.rootNode,
|
||||||
detail: {
|
detail: {
|
||||||
@ -195,7 +207,7 @@ export class OutlineMain implements ISensor, ITreeBoard, IScrollable {
|
|||||||
let focusSlots = pos.focusSlots;
|
let focusSlots = pos.focusSlots;
|
||||||
let { node } = treeNode;
|
let { node } = treeNode;
|
||||||
if (isDragNodeObject(dragObject)) {
|
if (isDragNodeObject(dragObject)) {
|
||||||
const nodes = dragObject.nodes;
|
const nodes = operationalNodes;
|
||||||
let i = nodes.length;
|
let i = nodes.length;
|
||||||
let p: any = node;
|
let p: any = node;
|
||||||
while (i-- > 0) {
|
while (i-- > 0) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user