From 40a23dbc31d08ac22a85e5dc807ccb16e0604b4c Mon Sep 17 00:00:00 2001 From: Daybrush Date: Tue, 8 Nov 2022 00:39:59 +0900 Subject: [PATCH] feat: support group persist #780 --- .../src/react-moveable/InitialMoveable.tsx | 7 +- .../MoveableIndividualGroup.tsx | 16 +- .../src/react-moveable/MoveableManager.tsx | 30 +++- .../src/react-moveable/ables/Groupable.tsx | 14 +- .../src/react-moveable/utils/persist.ts | 7 +- .../stories/4-Options/0-Default.stories.tsx | 11 +- .../4-Options/ReactGroupPersistDataApp.tsx | 142 +++++++++++++++++ .../ReactIndividualGroupPersistDataApp.tsx | 143 ++++++++++++++++++ .../stories/4-Options/ReactPersistDataApp.tsx | 20 ++- 9 files changed, 369 insertions(+), 21 deletions(-) create mode 100644 packages/react-moveable/stories/4-Options/ReactGroupPersistDataApp.tsx create mode 100644 packages/react-moveable/stories/4-Options/ReactIndividualGroupPersistDataApp.tsx diff --git a/packages/react-moveable/src/react-moveable/InitialMoveable.tsx b/packages/react-moveable/src/react-moveable/InitialMoveable.tsx index 47853773a..50acab2a5 100644 --- a/packages/react-moveable/src/react-moveable/InitialMoveable.tsx +++ b/packages/react-moveable/src/react-moveable/InitialMoveable.tsx @@ -136,7 +136,7 @@ export class InitialMoveable const refTargets = this._updateRefs(true); const elementTargets = getElementTargets(refTargets, this.selectorMap); - const isGroup = elementTargets.length > 1; + let isGroup = elementTargets.length > 1; const totalAbles = moveableContructor.getTotalAbles(); const ables = [ ...totalAbles, @@ -156,6 +156,11 @@ export class InitialMoveable const prevMoveable = this.moveable; + const persistData = props.persistData; + + if (persistData?.children) { + isGroup = true; + } if (isGroup) { if (props.individualGroupable) { return { public moveables: MoveableManager[] = []; public render() { + const props = this.props; const { cspNonce, cssStyled: ControlBoxElement, - targets, - } = this.props; + persistData, + } = props; + + let targets: Array = props.targets || []; + const length = targets.length; + const canPersist = this.isUnmounted || !length; + let persistDatChildren = persistData?.children ?? []; + if (canPersist && !length && persistDatChildren.length) { + targets = persistDatChildren.map(() => null); + } else if (!canPersist) { + persistDatChildren = []; + } return { {...this.props} target={target} wrapperMoveable={this} + persistData={persistDatChildren[i]} />; })} ; diff --git a/packages/react-moveable/src/react-moveable/MoveableManager.tsx b/packages/react-moveable/src/react-moveable/MoveableManager.tsx index 8b3547bf0..36f180be5 100644 --- a/packages/react-moveable/src/react-moveable/MoveableManager.tsx +++ b/packages/react-moveable/src/react-moveable/MoveableManager.tsx @@ -25,13 +25,13 @@ import { GroupableProps, } from "./types"; import { triggerAble, getTargetAbleGesto, getAbleGesto, checkMoveableTarget } from "./gesto/getAbleGesto"; -import { plus } from "@scena/matrix"; +import { minus, plus } from "@scena/matrix"; import { addClass, cancelAnimationFrame, find, getKeys, IObject, removeClass, requestAnimationFrame, } from "@daybrush/utils"; import { renderLine } from "./renderDirections"; -import { fitPoints, getAreaSize, getOverlapSize, isInside } from "overlap-area"; +import { fitPoints, getAreaSize, getMinMaxs, getOverlapSize, isInside } from "overlap-area"; import EventManager from "./EventManager"; import styled from "react-css-styled"; import EventEmitter from "@scena/event-emitter"; @@ -728,7 +728,7 @@ export default class MoveableManager } public getState(): MoveableManagerState { const props = this.props; - if (props.target) { + if (props.target || (props as any).targets?.length) { this._hasFirstTarget = true; } const hasControlBox = this.controlBox; @@ -736,7 +736,29 @@ export default class MoveableManager const firstRenderState = props.firstRenderState as any; if (!this._hasFirstTarget && persistData) { - this.updateState(getPersistState(persistData), false); + const persistState = getPersistState(persistData); + + if (props.groupable) { + const { + pos1, + pos2, + pos3, + pos4, + } = persistState; + const minPos = getMinMaxs([pos1!, pos2!, pos3!, pos4!]); + const delta = [minPos.minX, minPos.minY]; + const pos = [persistState.left!, persistState.top!]; + + persistState.pos1 = minus(pos1!, delta); + persistState.pos2 = minus(pos2!, delta); + persistState.pos3 = minus(pos3!, delta); + persistState.pos4 = minus(pos4!, delta); + persistState.origin = minus(plus(pos, persistState.origin!), delta); + persistState.beforeOrigin = minus(plus(pos, persistState.beforeOrigin!), delta); + + persistState.posDelta = delta; + } + this.updateState(persistState, false); } else if (firstRenderState && !hasControlBox) { return firstRenderState; } diff --git a/packages/react-moveable/src/react-moveable/ables/Groupable.tsx b/packages/react-moveable/src/react-moveable/ables/Groupable.tsx index 254d42cdc..00e33f852 100644 --- a/packages/react-moveable/src/react-moveable/ables/Groupable.tsx +++ b/packages/react-moveable/src/react-moveable/ables/Groupable.tsx @@ -16,14 +16,21 @@ export default { } as const, events: {} as const, render(moveable: MoveableGroupInterface, React: Renderer): any[] { - const targets = moveable.props.targets || []; + const props = moveable.props; + let targets: Array = props.targets || []; moveable.moveables = []; - const { left, top } = moveable.state; + const { left, top, isPersisted } = moveable.getState(); const position = [left, top]; - const props = moveable.props; const zoom = props.zoom || 1; const renderGroupRects = moveable.renderGroupRects; + let persistDatChildren = props.persistData?.children || []; + + if (isPersisted) { + targets = persistDatChildren.map(() => null); + } else { + persistDatChildren = []; + } return [ ...targets.map((target, i) => { @@ -38,6 +45,7 @@ export default { hideChildMoveableDefaultLines={props.hideChildMoveableDefaultLines} parentMoveable={moveable} parentPosition={position} + persistData={persistDatChildren[i]} zoom={zoom} />; }), diff --git a/packages/react-moveable/src/react-moveable/utils/persist.ts b/packages/react-moveable/src/react-moveable/utils/persist.ts index 31d561956..229d823ae 100644 --- a/packages/react-moveable/src/react-moveable/utils/persist.ts +++ b/packages/react-moveable/src/react-moveable/utils/persist.ts @@ -4,11 +4,12 @@ import { MoveableManagerState, PersistRectData } from "../types"; export function getPersistState(rect: PersistRectData): Partial { - const beforeOrigin = minus(rect.origin, [rect.left, rect.top]); + const origin = minus(rect.origin, [rect.left, rect.top]); return { ...rect, - beforeOrigin, - origin: beforeOrigin, + beforeOrigin: origin, + // originalBeforeOrigin: origin, + origin, isPersisted: true, }; } diff --git a/packages/react-moveable/stories/4-Options/0-Default.stories.tsx b/packages/react-moveable/stories/4-Options/0-Default.stories.tsx index 773387d25..ca4e78df8 100644 --- a/packages/react-moveable/stories/4-Options/0-Default.stories.tsx +++ b/packages/react-moveable/stories/4-Options/0-Default.stories.tsx @@ -33,7 +33,16 @@ group.add("Cursor is applied in viewer during dragging.", { -group.add("First render with persisted data.", { +group.add("First render with persisted data", { app: require("./ReactPersistDataApp").default, path: require.resolve("./ReactPersistDataApp"), }); + +group.add("First render with persisted data (group)", { + app: require("./ReactGroupPersistDataApp").default, + path: require.resolve("./ReactGroupPersistDataApp"), +}); +group.add("First render with persisted data (individual group)", { + app: require("./ReactIndividualGroupPersistDataApp").default, + path: require.resolve("./ReactIndividualGroupPersistDataApp"), +}); diff --git a/packages/react-moveable/stories/4-Options/ReactGroupPersistDataApp.tsx b/packages/react-moveable/stories/4-Options/ReactGroupPersistDataApp.tsx new file mode 100644 index 000000000..557aed7bd --- /dev/null +++ b/packages/react-moveable/stories/4-Options/ReactGroupPersistDataApp.tsx @@ -0,0 +1,142 @@ +import * as React from "react"; +import Moveable from "@/react-moveable"; + +export default function App() { + return ( +
+

+ * You can persist by `moveable.getRect()` method. +

+
No Target1
+
No Target2
+
No Target3
+ { + e.events.forEach(ev => { + ev.target.style.cssText += ev.cssText; + }); + }} + onRenderGroupEnd={e => { + console.log(JSON.stringify(e.moveable.getRect(), undefined, 4)); + }} + /> +
+ ); +} diff --git a/packages/react-moveable/stories/4-Options/ReactIndividualGroupPersistDataApp.tsx b/packages/react-moveable/stories/4-Options/ReactIndividualGroupPersistDataApp.tsx new file mode 100644 index 000000000..b1fae473c --- /dev/null +++ b/packages/react-moveable/stories/4-Options/ReactIndividualGroupPersistDataApp.tsx @@ -0,0 +1,143 @@ +import * as React from "react"; +import Moveable from "@/react-moveable"; + +export default function App() { + return ( +
+

+ * You can persist by `moveable.getRect()` method. +

+
No Target1
+
No Target2
+
No Target3
+ { + e.events.forEach(ev => { + ev.target.style.cssText += ev.cssText; + }); + }} + onRenderGroupEnd={e => { + console.log(JSON.stringify(e.moveable.getRect(), undefined, 4)); + }} + /> +
+ ); +} diff --git a/packages/react-moveable/stories/4-Options/ReactPersistDataApp.tsx b/packages/react-moveable/stories/4-Options/ReactPersistDataApp.tsx index f1c86a5a2..5308202ba 100644 --- a/packages/react-moveable/stories/4-Options/ReactPersistDataApp.tsx +++ b/packages/react-moveable/stories/4-Options/ReactPersistDataApp.tsx @@ -7,21 +7,27 @@ export default function App() {

* You can persist by `moveable.getRect()` method.

+
+ No Target +
{ e.target.style.cssText += e.cssText;