diff --git a/packages/demo/public/legao-assets.json b/packages/demo/public/legao-assets.json index e499f3918..d3feb0cc8 100644 --- a/packages/demo/public/legao-assets.json +++ b/packages/demo/public/legao-assets.json @@ -115,8 +115,8 @@ }, { "prototypeConfigsUrl": [ - "https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-deep/2.0.11/proto.3f4f5d1.css", - "https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-deep/2.0.11/proto.057b4c5.js" + "https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-deep/2.1.12/proto.611ab53.css", + "https://g.alicdn.com/legao-comp/web_bundle_0724/@ali/vc-deep/2.1.12/proto.5b7b3d3.js" ], "prototypeViewsUrl": null, "alias": "", diff --git a/packages/designer/package.json b/packages/designer/package.json index f5eae7abd..fb48f074d 100644 --- a/packages/designer/package.json +++ b/packages/designer/package.json @@ -19,6 +19,7 @@ "@ali/lowcode-types": "^0.8.3", "@ali/lowcode-utils": "^0.8.4", "classnames": "^2.2.6", + "event": "^1.0.0", "react": "^16", "react-dom": "^16.7.0" }, diff --git a/packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx b/packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx new file mode 100644 index 000000000..b0036c5c4 --- /dev/null +++ b/packages/designer/src/builtin-simulator/bem-tools/border-resizing.tsx @@ -0,0 +1,273 @@ +import { Component, Fragment } from 'react'; +import DragResizeEngine from './drag-resize-engine'; +import { observer, computed } from '@ali/lowcode-editor-core'; +import classNames from 'classnames'; +import { SimulatorContext } from '../context'; +import { BuiltinSimulatorHost } from '../host'; +import { OffsetObserver, Designer } from '../../designer'; + +@observer +export default class BoxResizing extends Component<{ host: BuiltinSimulatorHost }> { + static contextType = SimulatorContext; + + get host(): BuiltinSimulatorHost { + return this.props.host; + } + + get dragging(): boolean { + return this.host.designer.dragon.dragging; + } + + @computed get selecting() { + const doc = this.host.document; + if (doc.suspensed) { + return null; + } + const selection = doc.selection; + return this.dragging ? selection.getTopNodes() : selection.getNodes(); + } + + shouldComponentUpdate() { + return false; + } + + componentDidUpdate() { + // this.hoveringCapture.setBoundary(this.outline); + // this.willBind(); + } + + render() { + const selecting = this.selecting; + if (!selecting || selecting.length < 1) { + // DIRTY FIX, recore has a bug! + return ; + } + + // const componentMeta = selecting[0].componentMeta; + // const metaData = componentMeta.getMetadata(); + + return ( + + {selecting.map((node) => ( + + ))} + + ); + } +} + +@observer +export class BoxResizingForNode extends Component<{ host: BuiltinSimulatorHost; node: Node }> { + static contextType = SimulatorContext; + + get host(): BuiltinSimulatorHost { + return this.props.host; + } + + get dragging(): boolean { + return this.host.designer.dragon.dragging; + } + + @computed get instances() { + return this.host.getComponentInstances(this.props.node); + } + + shouldComponentUpdate() { + return false; + } + + render() { + const { instances } = this; + const { node } = this.props; + const designer = this.host.designer; + + if (!instances || instances.length < 1) { + return null; + } + return ( + + {instances.map((instance: any) => { + const observed = designer.createOffsetObserver({ + node, + instance, + }); + if (!observed) { + return null; + } + return ( + + ); + })} + + ); + } +} + +@observer +export class BoxResizingInstance extends Component<{ + observed: OffsetObserver; + highlight?: boolean; + dragging?: boolean; + designer?: Designer; +}> { + // private outline: any; + private willUnbind: () => any; + private outlineRight: any; + private outlineLeft: any; + private dragEngine: DragResizeEngine; + + constructor(props: any) { + super(props); + this.dragEngine = new DragResizeEngine(props.designer); + } + + componentWillUnmount() { + if (this.willUnbind) { + this.willUnbind(); + } + this.props.observed.purge(); + } + + getExperiMentalFns = (metaData: any) => { + if (metaData.experimental && metaData.experimental.callbacks) { + return metaData.experimantal.callbacks; + } + }; + + componentDidMount() { + // this.hoveringCapture.setBoundary(this.outline); + this.willBind(); + + const resize = (e: MouseEvent, direction: string, node: any, moveX: number, moveY: number) => { + const metaData = node.componentMeta.getMetadata(); + if ( + metaData && + metaData.experimental && + metaData.experimental.callbacks && + typeof metaData.experimental.callbacks.onResize === 'function' + ) { + e.trigger = direction; + e.deltaX = moveX; + e.deltaY = moveY; + metaData.experimental.callbacks.onResize(e, node); + } + }; + + const resizeStart = (e: MouseEvent, direction: string, node: any) => { + const metaData = node.componentMeta.getMetadata(); + if ( + metaData && + metaData.experimental && + metaData.experimental.callbacks && + typeof metaData.experimental.callbacks.onResizeStart === 'function' + ) { + e.trigger = direction; + metaData.experimental.callbacks.onResizeStart(e, node); + } + }; + + const resizeEnd = (e: MouseEvent, direction: string, node: any) => { + const metaData = node.componentMeta.getMetadata(); + if ( + metaData && + metaData.experimental && + metaData.experimental.callbacks && + typeof metaData.experimental.callbacks.onResizeEnd === 'function' + ) { + e.trigger = direction; + metaData.experimental.callbacks.onResizeStart(e, node); + } + }; + + this.dragEngine.onResize(resize); + this.dragEngine.onResizeStart(resizeStart); + this.dragEngine.onResizeEnd(resizeEnd); + } + + willBind() { + if (this.willUnbind) { + this.willUnbind(); + } + + if (!this.outlineRight && !this.outlineLeft) { + return; + } + + const unBind: any[] = []; + + unBind.push( + this.dragEngine.from(this.outlineRight, 'e', () => { + // if (!this.hoveringLine.hasOutline()) { + // return null; + // } + // return this.hoveringLine.getCurrentNode(); + return this.props.observed.node; + }), + ); + unBind.push( + this.dragEngine.from(this.outlineLeft, 'w', () => { + return this.props.observed.node; + // if (!this.hoveringLine.hasOutline()) { + // return null; + // } + // return this.hoveringLine.getCurrentNode(); + }), + ); + + this.willUnbind = () => { + if (unBind && unBind.length > 0) { + unBind.forEach((item) => { + item(); + }); + } + this.willUnbind = () => {}; + }; + } + + render() { + const { observed } = this.props; + if (!observed.hasOffset) { + return null; + } + + const { node, offsetWidth, offsetHeight, offsetTop, offsetLeft } = observed; + let triggerVisible: any = []; + const metaData = node.componentMeta.getMetadata(); + if (metaData && metaData.experimental && metaData.experimental.getResizingHandlers) { + triggerVisible = metaData.experimental.getResizingHandlers(node); + } + + const className = classNames('lc-borders lc-resize-box'); + + return ( +
+ {triggerVisible.includes('w') && ( +
{ + this.outlineLeft = ref; + }} + className={className} + style={{ + height: offsetHeight, + transform: `translate(${offsetLeft - 10}px, ${offsetTop}px)`, + width: 20, + }} + /> + )} + {triggerVisible.includes('e') && ( +
{ + this.outlineRight = ref; + }} + style={{ + height: offsetHeight, + transform: `translate(${offsetLeft + offsetWidth - 10}px, ${offsetTop}px)`, + width: 20, + }} + /> + )} +
+ ); + } +} diff --git a/packages/designer/src/builtin-simulator/bem-tools/borders.less b/packages/designer/src/builtin-simulator/bem-tools/borders.less index a2469519c..4b10396ed 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/borders.less +++ b/packages/designer/src/builtin-simulator/bem-tools/borders.less @@ -49,6 +49,28 @@ } } + &.lc-resize-box { + border-width: 0; + z-index: 1; + cursor: ew-resize; + pointer-events: auto; + align-items: center; + justify-content: center; + display: flex; + + &:after { + content: ""; + display: block; + height: calc(100% - 20px); + min-height: 50%; + width: 4px; + background: #738397; + border-radius: 2px; + // animation: flashing 1.5s infinite linear; + } + } + + // &&-hovering { &&-detecting { z-index: 1; border-style: dashed; diff --git a/packages/designer/src/builtin-simulator/bem-tools/drag-resize-engine.ts b/packages/designer/src/builtin-simulator/bem-tools/drag-resize-engine.ts new file mode 100644 index 000000000..11308316e --- /dev/null +++ b/packages/designer/src/builtin-simulator/bem-tools/drag-resize-engine.ts @@ -0,0 +1,138 @@ +import * as EventEmitter from 'events'; +import { ISimulatorHost, isSimulatorHost } from '../../../../designer/src/simulator'; +import { Designer } from '../../../../designer/src/designer/designer'; +import { setNativeSelection, cursor } from '@ali/lowcode-utils'; +// import Cursor from './cursor'; +// import Pages from './pages'; + +function makeEventsHandler( + boostEvent: MouseEvent | DragEvent, + sensors: ISimulatorHost[], +): (fn: (sdoc: Document) => void) => void { + const topDoc = window.top.document; + const sourceDoc = boostEvent.view?.document || topDoc; + // TODO: optimize this logic, reduce listener + // const boostPrevented = boostEvent.defaultPrevented; + const docs = new Set(); + // if (boostPrevented || isDragEvent(boostEvent)) { + docs.add(topDoc); + // } + docs.add(sourceDoc); + // if (sourceDoc !== topDoc || isDragEvent(boostEvent)) { + sensors.forEach((sim) => { + const sdoc = sim.contentDocument; + if (sdoc) { + docs.add(sdoc); + } + }); + // } + + return (handle: (sdoc: Document) => void) => { + docs.forEach((doc) => handle(doc)); + }; +} + +// 拖动缩放 +export default class DragResizeEngine { + private emitter: EventEmitter; + private dragResizing = false; + + constructor(readonly designer: Designer) { + this.designer = designer; + this.emitter = new EventEmitter(); + } + + private getMasterSensors(): ISimulatorHost[] { + return this.designer.project.documents + .map((doc) => { + // TODO: not use actived, + if (doc.actived && doc.simulator?.sensorAvailable) { + return doc.simulator; + } + return null; + }) + .filter(Boolean) as any; + } + + isDragResizing() { + return this.dragResizing; + } + + /** + * drag reszie from + * @param shell + * @param direction n/s/e/w + * @param boost (e: MouseEvent) => VE.Node + */ + from(shell: Element, direction: string, boost: (e: MouseEvent) => any) { + let node: any; + let startEvent: MouseEvent; + + if (!shell) { + return () => {}; + } + + const move = (e: MouseEvent) => { + const moveX = e.clientX - startEvent.clientX; + const moveY = e.clientY - startEvent.clientY; + + this.emitter.emit('resize', e, direction, node, moveX, moveY); + }; + + const masterSensors = this.getMasterSensors(); + + const over = (e: MouseEvent) => { + const handleEvents = makeEventsHandler(e, masterSensors); + handleEvents((doc) => { + doc.removeEventListener('mousemove', move, true); + doc.removeEventListener('mouseup', over, true); + }); + + this.dragResizing = false; + cursor.release(); + + this.emitter.emit('resizeEnd', e, direction, node); + }; + + const mousedown = (e: MouseEvent) => { + node = boost(e); + startEvent = e; + const handleEvents = makeEventsHandler(e, masterSensors); + handleEvents((doc) => { + doc.addEventListener('mousemove', move, true); + doc.addEventListener('mouseup', over, true); + }); + + this.emitter.emit('resizestart', e, direction, node); + this.dragResizing = true; + cursor.addState('ew-resize'); + }; + shell.addEventListener('mousedown', mousedown); + return () => { + shell.removeEventListener('mousedown', mousedown); + }; + } + + onResizeStart(func: (e: MouseEvent, direction: string, node: any) => any) { + this.emitter.on('resizestart', func); + return () => { + this.emitter.removeListener('resizestart', func); + }; + } + + onResize(func: (e: MouseEvent, direction: string, node: any, moveX: number, moveY: number) => any) { + this.emitter.on('resize', func); + return () => { + this.emitter.removeListener('resize', func); + }; + } + + onResizeEnd(func: (e: MouseEvent, direction: string, node: any) => any) { + this.emitter.on('resizeEnd', func); + return () => { + this.emitter.removeListener('resizeEnd', func); + }; + } +} + +// new DragResizeEngine(); diff --git a/packages/designer/src/builtin-simulator/bem-tools/index.tsx b/packages/designer/src/builtin-simulator/bem-tools/index.tsx index 881ff9396..c22951c2f 100644 --- a/packages/designer/src/builtin-simulator/bem-tools/index.tsx +++ b/packages/designer/src/builtin-simulator/bem-tools/index.tsx @@ -3,6 +3,7 @@ import { observer } from '@ali/lowcode-editor-core'; import { BorderDetecting } from './border-detecting'; import { BuiltinSimulatorHost } from '../host'; import { BorderSelecting } from './border-selecting'; +import BorderResizing from './border-resizing'; import { InsertionView } from './insertion'; import './bem-tools.less'; import './borders.less'; @@ -21,6 +22,7 @@ export class BemTools extends Component<{ host: BuiltinSimulatorHost }> { +
); } diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 63a75421d..e5c18d33d 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -426,6 +426,7 @@ export class Node { return this.parent.children.indexOf(this); } + /** * 获取下一个兄弟节点 */ @@ -618,6 +619,9 @@ export class Node { getId() { return this.id; } + getIndex() { + return this.index; + } getNode() { return this; }