fix outlines&events

This commit is contained in:
kangwei 2020-03-16 15:50:16 +08:00
parent 69e9c981a2
commit 573f91507c
9 changed files with 148 additions and 87 deletions

View File

@ -8,17 +8,17 @@ import OffsetObserver from '../../../../designer/helper/offset-observer';
import Node from '../../../../designer/document/node/node'; import Node from '../../../../designer/document/node/node';
@observer @observer
export class OutlineSelectingInstance extends Component<{ observed: OffsetObserver; highlight?: boolean }> { export class OutlineSelectingInstance extends Component<{
shouldComponentUpdate() { observed: OffsetObserver;
return false; highlight?: boolean;
} dragging?: boolean;
}> {
componentWillUnmount() { componentWillUnmount() {
this.props.observed.purge(); this.props.observed.purge();
} }
render() { render() {
const { observed, highlight } = this.props; const { observed, highlight, dragging } = this.props;
if (!observed.hasOffset) { if (!observed.hasOffset) {
return null; return null;
} }
@ -33,6 +33,7 @@ export class OutlineSelectingInstance extends Component<{ observed: OffsetObserv
const className = classNames('lc-outlines lc-outlines-selecting', { const className = classNames('lc-outlines lc-outlines-selecting', {
highlight, highlight,
dragging,
}); });
return ( return (
@ -51,6 +52,10 @@ export class OutlineSelectingForNode extends Component<{ node: Node }> {
return this.context; return this.context;
} }
get dragging(): boolean {
return this.host.designer.dragon.dragging;
}
@computed get instances() { @computed get instances() {
return this.host.getComponentInstances(this.props.node); return this.host.getComponentInstances(this.props.node);
} }
@ -77,7 +82,7 @@ export class OutlineSelectingForNode extends Component<{ node: Node }> {
if (!observed) { if (!observed) {
return null; return null;
} }
return <OutlineSelectingInstance key={observed.id} observed={observed} />; return <OutlineSelectingInstance key={observed.id} dragging={this.dragging} observed={observed} />;
})} })}
</Fragment> </Fragment>
); );
@ -92,12 +97,17 @@ export class OutlineSelecting extends Component {
return this.context; return this.context;
} }
get dragging(): boolean {
return this.host.designer.dragon.dragging;
}
@computed get selecting() { @computed get selecting() {
const doc = this.host.document; const doc = this.host.document;
if (doc.suspensed) { if (doc.suspensed) {
return null; return null;
} }
return doc.selection.getNodes(); const selection = doc.selection;
return this.dragging ? selection.getTopNodes() : selection.getNodes();
} }
shouldComponentUpdate() { shouldComponentUpdate() {
@ -106,6 +116,7 @@ export class OutlineSelecting extends Component {
render() { render() {
const selecting = this.selecting; const selecting = this.selecting;
console.info(selecting);
if (!selecting || selecting.length < 1) { if (!selecting || selecting.length < 1) {
// DIRTY FIX, recore has a bug! // DIRTY FIX, recore has a bug!
return <Fragment />; return <Fragment />;

View File

@ -22,7 +22,7 @@
&&-hovering { &&-hovering {
z-index: 1; z-index: 1;
border-style: dashed; border-style: dashed;
background: rgba(95, 240, 114, 0.04); background: rgba(0,121,242,.04);
&.x-loop { &.x-loop {
border-color: rgba(138, 93, 226, 0.8); border-color: rgba(138, 93, 226, 0.8);
@ -44,6 +44,7 @@
&&-selecting { &&-selecting {
z-index: 2; z-index: 2;
border-width: 2px;
&.x-loop { &.x-loop {
border-color: rgba(147, 112, 219, 1.0); border-color: rgba(147, 112, 219, 1.0);

View File

@ -145,9 +145,6 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
readonly scroller = this.designer.createScroller(this.viewport); readonly scroller = this.designer.createScroller(this.viewport);
mountViewport(viewport: Element | null) { mountViewport(viewport: Element | null) {
if (!viewport) {
return;
}
this.viewport.mount(viewport); this.viewport.mount(viewport);
} }
@ -174,10 +171,12 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
readonly libraryMap: { [key: string]: string } = {}; readonly libraryMap: { [key: string]: string } = {};
private _iframe?: HTMLIFrameElement;
async mountContentFrame(iframe: HTMLIFrameElement | null) { async mountContentFrame(iframe: HTMLIFrameElement | null) {
if (!iframe) { if (!iframe || this._iframe === iframe) {
return; return;
} }
this._iframe = iframe;
this._contentWindow = iframe.contentWindow!; this._contentWindow = iframe.contentWindow!;
@ -234,7 +233,13 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
// TODO: think of lock when edit a node // TODO: think of lock when edit a node
// 事件路由 // 事件路由
doc.addEventListener('mousedown', (downEvent: MouseEvent) => { doc.addEventListener(
'mousedown',
(downEvent: MouseEvent) => {
// stop response document focus event
downEvent.stopPropagation();
downEvent.preventDefault();
const nodeInst = this.getNodeInstanceFromElement(downEvent.target as Element); const nodeInst = this.getNodeInstanceFromElement(downEvent.target as Element);
const node = nodeInst?.node || this.document.rootNode; const node = nodeInst?.node || this.document.rootNode;
const isMulti = downEvent.metaKey || downEvent.ctrlKey; const isMulti = downEvent.metaKey || downEvent.ctrlKey;
@ -285,12 +290,32 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
} }
doc.addEventListener('mouseup', checkSelect, true); 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 // cause edit
doc.addEventListener('dblclick', (e: MouseEvent) => { doc.addEventListener(
// TODO: 'dblclick',
}); (e: MouseEvent) => {
// stop response document dblclick event
e.stopPropagation();
e.preventDefault();
// todo: quick editing
},
true,
);
} }
private disableHovering?: () => void; private disableHovering?: () => void;
@ -443,18 +468,28 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
let last: { x: number; y: number; r: number; b: number } | undefined; let last: { x: number; y: number; r: number; b: number } | undefined;
let computed = false; let computed = false;
const elems = elements.slice(); const elems = elements.slice();
const commonParent: Element | null = null;
while (true) { while (true) {
if (!rects || rects.length < 1) { if (!rects || rects.length < 1) {
const elem = elems.pop(); const elem = elems.pop();
if (!elem) { if (!elem) {
break; break;
} }
/*
if (!commonParent) {
commonParent = elem.parentElement;
} else if (elem.parentElement !== commonParent) {
continue;
}*/
rects = renderer.getClientRects(elem); rects = renderer.getClientRects(elem);
} }
const rect = rects.pop(); const rect = rects.pop();
if (!rect) { if (!rect) {
break; break;
} }
if (rect.width === 0 && rect.height === 0) {
continue;
}
if (!last) { if (!last) {
last = { last = {
x: rect.left, x: rect.left,
@ -677,8 +712,10 @@ export class SimulatorHost implements ISimulator<SimulatorProps> {
} }
const target = dropTarget; 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 parentInstance = this.getClosestNodeInstance(targetInstance, target.id);
const edge = this.computeComponentInstanceRect(parentInstance?.instance as any); const edge = this.computeComponentInstanceRect(parentInstance?.instance as any);

View File

@ -25,7 +25,7 @@ export default class Viewport implements IViewport {
private viewportElement?: Element; private viewportElement?: Element;
mount(viewportElement: Element | null) { mount(viewportElement: Element | null) {
if (!viewportElement) { if (!viewportElement || this.viewportElement === viewportElement) {
return; return;
} }
this.viewportElement = viewportElement; 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) { if (!this.rect || this.contentWidth === AutoFit) {
return 1; return 1;
} }
@ -63,14 +63,14 @@ export default class Viewport implements IViewport {
@obx.ref private _contentWidth: number | AutoFit = AutoFit; @obx.ref private _contentWidth: number | AutoFit = AutoFit;
get contentHeight(): number | AutoFit { @computed get contentHeight(): number | AutoFit {
if (!this.rect || this.scale === 1) { if (!this.rect || this.scale === 1) {
return AutoFit; return AutoFit;
} }
return this.height / this.scale; return this.height / this.scale;
} }
get contentWidth(): number | AutoFit { @computed get contentWidth(): number | AutoFit {
if (!this.rect || (this._contentWidth !== AutoFit && this._contentWidth <= this.width)) { if (!this.rect || (this._contentWidth !== AutoFit && this._contentWidth <= this.width)) {
return AutoFit; return AutoFit;
} }
@ -98,7 +98,7 @@ export default class Viewport implements IViewport {
return this._scrollTarget; return this._scrollTarget;
} }
@obx private _scrolling: boolean = false; @obx private _scrolling = false;
get scrolling(): boolean { get scrolling(): boolean {
return this._scrolling; return this._scrolling;
} }
@ -120,6 +120,7 @@ export default class Viewport implements IViewport {
this._scrolling = false; this._scrolling = false;
}, 80); }, 80);
}); });
target.addEventListener('resize', () => this.touch());
this._scrollTarget = scrollTarget; this._scrollTarget = scrollTarget;
} }

View File

@ -8,7 +8,9 @@
--font-size-btn-medium: @fontSize-4; --font-size-btn-medium: @fontSize-4;
--font-size-btn-small: @fontSize-5; --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-icon: rgba(255, 255, 255, 0.8);
--color-visited: rgba(179, 182, 201, 0.4); --color-visited: rgba(179, 182, 201, 0.4);
--color-actived: #498ee6; --color-actived: #498ee6;

View File

@ -61,10 +61,14 @@ export default class Designer {
this.dragon.onDragstart(e => { this.dragon.onDragstart(e => {
this.hovering.enable = false; this.hovering.enable = false;
const { dragObject } = e; const { dragObject } = e;
if (isDragNodeObject(dragObject) && dragObject.nodes.length === 1) { if (isDragNodeObject(dragObject)) {
if (dragObject.nodes.length === 1) {
// ensure current selecting // ensure current selecting
dragObject.nodes[0].select(); dragObject.nodes[0].select();
} }
} else {
this.currentSelection?.clear();
}
if (this.props?.onDragstart) { if (this.props?.onDragstart) {
this.props.onDragstart(e); this.props.onDragstart(e);
} }

View File

@ -374,7 +374,7 @@ export default class Node {
* 2 thisNode before or after otherNode * 2 thisNode before or after otherNode
* 0 thisNode same as otherNode * 0 thisNode same as otherNode
*/ */
comparePosition(otherNode: Node): number { comparePosition(otherNode: Node): PositionNO {
return comparePosition(this, otherNode); return comparePosition(this, otherNode);
} }
@ -455,31 +455,37 @@ export function contains(node1: Node, node2: Node): boolean {
// 8 node1 contained_by node2 // 8 node1 contained_by node2
// 2 node1 before or after node2 // 2 node1 before or after node2
// 0 node1 same as 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) { if (node1 === node2) {
return 0; return PositionNO.TheSame;
} }
const l1 = node1.zLevel; const l1 = node1.zLevel;
const l2 = node2.zLevel; const l2 = node2.zLevel;
if (l1 === l2) { if (l1 === l2) {
return 2; return PositionNO.BeforeOrAfter;
} }
let p: any; let p: any;
if (l1 > l2) { if (l1 < l2) {
p = getZLevelTop(node2, l1); p = getZLevelTop(node2, l1);
if (p && p === node1) { if (p && p === node1) {
return 16; return PositionNO.Contains;
} }
return 2; return PositionNO.BeforeOrAfter;
} }
p = getZLevelTop(node1, l2); p = getZLevelTop(node1, l2);
if (p && p === node2) { 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 { export function insertChild(container: NodeParent, thing: Node | NodeData, at?: number | null, copy?: boolean): Node {

View File

@ -1,4 +1,4 @@
import Node, { comparePosition } from './node/node'; import Node, { comparePosition, PositionNO } from './node/node';
import { obx } from '@recore/obx'; import { obx } from '@recore/obx';
import DocumentModel from './document-model'; import DocumentModel from './document-model';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
@ -136,12 +136,12 @@ export class Selection {
while (i-- > 0) { while (i-- > 0) {
const n = comparePosition(nodes[i], node); const n = comparePosition(nodes[i], node);
// nodes[i] contains node // nodes[i] contains node
if (n === 16 || n === 0) { if (n === PositionNO.Contains || n === PositionNO.TheSame) {
isTop = false; isTop = false;
break; break;
} }
// node contains nodes[i], delete nodes[i] // node contains nodes[i], delete nodes[i]
if (n === 8) { if (n === PositionNO.ContainedBy) {
nodes.splice(i, 1); nodes.splice(i, 1);
} }
} }

View File

@ -209,7 +209,6 @@ registerMetadataTransducer(metadata => {
props.push(propConfigToFieldConfig(prop)); props.push(propConfigToFieldConfig(prop));
}); });
return { return {
...metadata, ...metadata,
configure: { configure: {