From 573f91507c64adf620dd34b98ac3012f935caa79 Mon Sep 17 00:00:00 2001 From: kangwei Date: Mon, 16 Mar 2020 15:50:16 +0800 Subject: [PATCH] fix outlines&events --- .../host/auxilary/outline-selecting.tsx | 27 +++- .../simulator/host/auxilary/outlines.less | 3 +- .../src/builtins/simulator/host/host.ts | 149 +++++++++++------- .../src/builtins/simulator/host/viewport.ts | 11 +- packages/designer/src/designer/designer.less | 4 +- packages/designer/src/designer/designer.ts | 10 +- .../src/designer/document/node/node.ts | 24 +-- .../src/designer/document/selection.ts | 6 +- .../src/register-transducer.ts | 1 - 9 files changed, 148 insertions(+), 87 deletions(-) diff --git a/packages/designer/src/builtins/simulator/host/auxilary/outline-selecting.tsx b/packages/designer/src/builtins/simulator/host/auxilary/outline-selecting.tsx index 0273daf07..9618de6ae 100644 --- a/packages/designer/src/builtins/simulator/host/auxilary/outline-selecting.tsx +++ b/packages/designer/src/builtins/simulator/host/auxilary/outline-selecting.tsx @@ -8,17 +8,17 @@ import OffsetObserver from '../../../../designer/helper/offset-observer'; import Node from '../../../../designer/document/node/node'; @observer -export class OutlineSelectingInstance extends Component<{ observed: OffsetObserver; highlight?: boolean }> { - shouldComponentUpdate() { - return false; - } - +export class OutlineSelectingInstance extends Component<{ + observed: OffsetObserver; + highlight?: boolean; + dragging?: boolean; +}> { componentWillUnmount() { this.props.observed.purge(); } render() { - const { observed, highlight } = this.props; + const { observed, highlight, dragging } = this.props; if (!observed.hasOffset) { return null; } @@ -33,6 +33,7 @@ export class OutlineSelectingInstance extends Component<{ observed: OffsetObserv const className = classNames('lc-outlines lc-outlines-selecting', { highlight, + dragging, }); return ( @@ -51,6 +52,10 @@ export class OutlineSelectingForNode extends Component<{ node: Node }> { return this.context; } + get dragging(): boolean { + return this.host.designer.dragon.dragging; + } + @computed get instances() { return this.host.getComponentInstances(this.props.node); } @@ -77,7 +82,7 @@ export class OutlineSelectingForNode extends Component<{ node: Node }> { if (!observed) { return null; } - return ; + return ; })} ); @@ -92,12 +97,17 @@ export class OutlineSelecting extends Component { return this.context; } + get dragging(): boolean { + return this.host.designer.dragon.dragging; + } + @computed get selecting() { const doc = this.host.document; if (doc.suspensed) { return null; } - return doc.selection.getNodes(); + const selection = doc.selection; + return this.dragging ? selection.getTopNodes() : selection.getNodes(); } shouldComponentUpdate() { @@ -106,6 +116,7 @@ export class OutlineSelecting extends Component { render() { const selecting = this.selecting; + console.info(selecting); if (!selecting || selecting.length < 1) { // DIRTY FIX, recore has a bug! return ; diff --git a/packages/designer/src/builtins/simulator/host/auxilary/outlines.less b/packages/designer/src/builtins/simulator/host/auxilary/outlines.less index fc3e1042e..1bf8c163d 100644 --- a/packages/designer/src/builtins/simulator/host/auxilary/outlines.less +++ b/packages/designer/src/builtins/simulator/host/auxilary/outlines.less @@ -22,7 +22,7 @@ &&-hovering { z-index: 1; border-style: dashed; - background: rgba(95, 240, 114, 0.04); + background: rgba(0,121,242,.04); &.x-loop { border-color: rgba(138, 93, 226, 0.8); @@ -44,6 +44,7 @@ &&-selecting { z-index: 2; + border-width: 2px; &.x-loop { border-color: rgba(147, 112, 219, 1.0); diff --git a/packages/designer/src/builtins/simulator/host/host.ts b/packages/designer/src/builtins/simulator/host/host.ts index ab64b23c9..a3620245d 100644 --- a/packages/designer/src/builtins/simulator/host/host.ts +++ b/packages/designer/src/builtins/simulator/host/host.ts @@ -145,9 +145,6 @@ export class SimulatorHost implements ISimulator { readonly scroller = this.designer.createScroller(this.viewport); mountViewport(viewport: Element | null) { - if (!viewport) { - return; - } this.viewport.mount(viewport); } @@ -174,10 +171,12 @@ export class SimulatorHost implements ISimulator { readonly libraryMap: { [key: string]: string } = {}; + private _iframe?: HTMLIFrameElement; async mountContentFrame(iframe: HTMLIFrameElement | null) { - if (!iframe) { + if (!iframe || this._iframe === iframe) { return; } + this._iframe = iframe; this._contentWindow = iframe.contentWindow!; @@ -234,63 +233,89 @@ export class SimulatorHost implements ISimulator { // TODO: think of lock when edit a node // 事件路由 - doc.addEventListener('mousedown', (downEvent: MouseEvent) => { - const nodeInst = this.getNodeInstanceFromElement(downEvent.target as Element); - const node = nodeInst?.node || this.document.rootNode; - const isMulti = downEvent.metaKey || downEvent.ctrlKey; - const isLeftButton = downEvent.which === 1 || downEvent.button === 0; - const checkSelect = (e: MouseEvent) => { - doc.removeEventListener('mouseup', checkSelect, true); - if (!isShaken(downEvent, e)) { - const id = node.id; - designer.activeTracker.track(node); - if (isMulti && !isRootNode(node) && selection.has(id)) { - selection.remove(id); - } else { - selection.select(id); - } - } - }; + doc.addEventListener( + 'mousedown', + (downEvent: MouseEvent) => { + // stop response document focus event + downEvent.stopPropagation(); + downEvent.preventDefault(); - if (isLeftButton && !isRootNode(node)) { - let nodes: Node[] = [node]; - let ignoreUpSelected = false; - // 排除根节点拖拽 - selection.remove(this.document.rootNode.id); - if (isMulti) { - // multi select mode, directily add - if (!selection.has(node.id)) { + const nodeInst = this.getNodeInstanceFromElement(downEvent.target as Element); + const node = nodeInst?.node || this.document.rootNode; + const isMulti = downEvent.metaKey || downEvent.ctrlKey; + const isLeftButton = downEvent.which === 1 || downEvent.button === 0; + const checkSelect = (e: MouseEvent) => { + doc.removeEventListener('mouseup', checkSelect, true); + if (!isShaken(downEvent, e)) { + const id = node.id; designer.activeTracker.track(node); - selection.add(node.id); - ignoreUpSelected = true; + if (isMulti && !isRootNode(node) && selection.has(id)) { + selection.remove(id); + } else { + selection.select(id); + } } - // 获得顶层 nodes - nodes = selection.getTopNodes(); - } else if (selection.containsNode(node)) { - nodes = selection.getTopNodes(); - } else { - // will clear current selection & select dragment in dragstart - } - designer.dragon.boost( - { - type: DragObjectType.Node, - nodes, - }, - downEvent, - ); - if (ignoreUpSelected) { - // multi select mode has add selected, should return - return; - } - } + }; - doc.addEventListener('mouseup', checkSelect, true); - }); + if (isLeftButton && !isRootNode(node)) { + let nodes: Node[] = [node]; + let ignoreUpSelected = false; + // 排除根节点拖拽 + selection.remove(this.document.rootNode.id); + if (isMulti) { + // multi select mode, directily add + if (!selection.has(node.id)) { + designer.activeTracker.track(node); + selection.add(node.id); + ignoreUpSelected = true; + } + // 获得顶层 nodes + nodes = selection.getTopNodes(); + } else if (selection.containsNode(node)) { + nodes = selection.getTopNodes(); + } else { + // will clear current selection & select dragment in dragstart + } + designer.dragon.boost( + { + type: DragObjectType.Node, + nodes, + }, + downEvent, + ); + if (ignoreUpSelected) { + // multi select mode has add selected, should return + return; + } + } + + doc.addEventListener('mouseup', checkSelect, true); + }, + true, + ); + + doc.addEventListener( + 'click', + e => { + // stop response document click event + e.preventDefault(); + e.stopPropagation(); + // todo: catch link redirect + }, + true, + ); // cause edit - doc.addEventListener('dblclick', (e: MouseEvent) => { - // TODO: - }); + doc.addEventListener( + 'dblclick', + (e: MouseEvent) => { + // stop response document dblclick event + e.stopPropagation(); + e.preventDefault(); + // todo: quick editing + }, + true, + ); } private disableHovering?: () => void; @@ -443,18 +468,28 @@ export class SimulatorHost implements ISimulator { let last: { x: number; y: number; r: number; b: number } | undefined; let computed = false; const elems = elements.slice(); + const commonParent: Element | null = null; while (true) { if (!rects || rects.length < 1) { const elem = elems.pop(); if (!elem) { break; } + /* + if (!commonParent) { + commonParent = elem.parentElement; + } else if (elem.parentElement !== commonParent) { + continue; + }*/ rects = renderer.getClientRects(elem); } const rect = rects.pop(); if (!rect) { break; } + if (rect.width === 0 && rect.height === 0) { + continue; + } if (!last) { last = { x: rect.left, @@ -677,8 +712,10 @@ export class SimulatorHost implements ISimulator { } const target = dropTarget; - const targetInstance = e.targetInstance as ReactInstance; + // FIXME: e.target is #document, etc., does not has e.targetInstance + + const targetInstance = e.targetInstance as ReactInstance; const parentInstance = this.getClosestNodeInstance(targetInstance, target.id); const edge = this.computeComponentInstanceRect(parentInstance?.instance as any); diff --git a/packages/designer/src/builtins/simulator/host/viewport.ts b/packages/designer/src/builtins/simulator/host/viewport.ts index 3ae3d41df..a22f87704 100644 --- a/packages/designer/src/builtins/simulator/host/viewport.ts +++ b/packages/designer/src/builtins/simulator/host/viewport.ts @@ -25,7 +25,7 @@ export default class Viewport implements IViewport { private viewportElement?: Element; mount(viewportElement: Element | null) { - if (!viewportElement) { + if (!viewportElement || this.viewportElement === viewportElement) { return; } this.viewportElement = viewportElement; @@ -54,7 +54,7 @@ export default class Viewport implements IViewport { /** * 缩放比例 */ - get scale(): number { + @computed get scale(): number { if (!this.rect || this.contentWidth === AutoFit) { return 1; } @@ -63,14 +63,14 @@ export default class Viewport implements IViewport { @obx.ref private _contentWidth: number | AutoFit = AutoFit; - get contentHeight(): number | AutoFit { + @computed get contentHeight(): number | AutoFit { if (!this.rect || this.scale === 1) { return AutoFit; } return this.height / this.scale; } - get contentWidth(): number | AutoFit { + @computed get contentWidth(): number | AutoFit { if (!this.rect || (this._contentWidth !== AutoFit && this._contentWidth <= this.width)) { return AutoFit; } @@ -98,7 +98,7 @@ export default class Viewport implements IViewport { return this._scrollTarget; } - @obx private _scrolling: boolean = false; + @obx private _scrolling = false; get scrolling(): boolean { return this._scrolling; } @@ -120,6 +120,7 @@ export default class Viewport implements IViewport { this._scrolling = false; }, 80); }); + target.addEventListener('resize', () => this.touch()); this._scrollTarget = scrollTarget; } diff --git a/packages/designer/src/designer/designer.less b/packages/designer/src/designer/designer.less index 7f73d92b1..9c3a7dfa9 100644 --- a/packages/designer/src/designer/designer.less +++ b/packages/designer/src/designer/designer.less @@ -8,7 +8,9 @@ --font-size-btn-medium: @fontSize-4; --font-size-btn-small: @fontSize-5; - --color-brand-light: rgb(102, 188, 92); + --color-brand: #006cff; + --color-brand-light: #197aff; + --color-brand-dark: #0060e5; --color-icon: rgba(255, 255, 255, 0.8); --color-visited: rgba(179, 182, 201, 0.4); --color-actived: #498ee6; diff --git a/packages/designer/src/designer/designer.ts b/packages/designer/src/designer/designer.ts index 10b802d98..73c479f26 100644 --- a/packages/designer/src/designer/designer.ts +++ b/packages/designer/src/designer/designer.ts @@ -61,9 +61,13 @@ export default class Designer { this.dragon.onDragstart(e => { this.hovering.enable = false; const { dragObject } = e; - if (isDragNodeObject(dragObject) && dragObject.nodes.length === 1) { - // ensure current selecting - dragObject.nodes[0].select(); + if (isDragNodeObject(dragObject)) { + if (dragObject.nodes.length === 1) { + // ensure current selecting + dragObject.nodes[0].select(); + } + } else { + this.currentSelection?.clear(); } if (this.props?.onDragstart) { this.props.onDragstart(e); diff --git a/packages/designer/src/designer/document/node/node.ts b/packages/designer/src/designer/document/node/node.ts index 2bdc4106e..1c46e1f2e 100644 --- a/packages/designer/src/designer/document/node/node.ts +++ b/packages/designer/src/designer/document/node/node.ts @@ -374,7 +374,7 @@ export default class Node { * 2 thisNode before or after otherNode * 0 thisNode same as otherNode */ - comparePosition(otherNode: Node): number { + comparePosition(otherNode: Node): PositionNO { return comparePosition(this, otherNode); } @@ -455,31 +455,37 @@ export function contains(node1: Node, node2: Node): boolean { // 8 node1 contained_by node2 // 2 node1 before or after node2 // 0 node1 same as node2 -export function comparePosition(node1: Node, node2: Node): number { +export enum PositionNO { + Contains = 16, + ContainedBy = 8, + BeforeOrAfter = 2, + TheSame = 0, +} +export function comparePosition(node1: Node, node2: Node): PositionNO { if (node1 === node2) { - return 0; + return PositionNO.TheSame; } const l1 = node1.zLevel; const l2 = node2.zLevel; if (l1 === l2) { - return 2; + return PositionNO.BeforeOrAfter; } let p: any; - if (l1 > l2) { + if (l1 < l2) { p = getZLevelTop(node2, l1); if (p && p === node1) { - return 16; + return PositionNO.Contains; } - return 2; + return PositionNO.BeforeOrAfter; } p = getZLevelTop(node1, l2); if (p && p === node2) { - return 8; + return PositionNO.ContainedBy; } - return 2; + return PositionNO.BeforeOrAfter; } export function insertChild(container: NodeParent, thing: Node | NodeData, at?: number | null, copy?: boolean): Node { diff --git a/packages/designer/src/designer/document/selection.ts b/packages/designer/src/designer/document/selection.ts index 117351ebf..14bddac12 100644 --- a/packages/designer/src/designer/document/selection.ts +++ b/packages/designer/src/designer/document/selection.ts @@ -1,4 +1,4 @@ -import Node, { comparePosition } from './node/node'; +import Node, { comparePosition, PositionNO } from './node/node'; import { obx } from '@recore/obx'; import DocumentModel from './document-model'; import { EventEmitter } from 'events'; @@ -136,12 +136,12 @@ export class Selection { while (i-- > 0) { const n = comparePosition(nodes[i], node); // nodes[i] contains node - if (n === 16 || n === 0) { + if (n === PositionNO.Contains || n === PositionNO.TheSame) { isTop = false; break; } // node contains nodes[i], delete nodes[i] - if (n === 8) { + if (n === PositionNO.ContainedBy) { nodes.splice(i, 1); } } diff --git a/packages/plugin-settings/src/register-transducer.ts b/packages/plugin-settings/src/register-transducer.ts index 165ec1c3c..ebd2de72c 100644 --- a/packages/plugin-settings/src/register-transducer.ts +++ b/packages/plugin-settings/src/register-transducer.ts @@ -209,7 +209,6 @@ registerMetadataTransducer(metadata => { props.push(propConfigToFieldConfig(prop)); }); - return { ...metadata, configure: {