fix: drag connector and group element (#10385)
This commit is contained in:
@@ -1,4 +1,8 @@
|
|||||||
import type { SurfaceBlockProps } from '@blocksuite/block-std/gfx';
|
import type { SurfaceBlockProps } from '@blocksuite/block-std/gfx';
|
||||||
|
import {
|
||||||
|
SURFACE_TEXT_UNIQ_IDENTIFIER,
|
||||||
|
SURFACE_YMAP_UNIQ_IDENTIFIER,
|
||||||
|
} from '@blocksuite/block-std/gfx';
|
||||||
import type {
|
import type {
|
||||||
FromSnapshotPayload,
|
FromSnapshotPayload,
|
||||||
SnapshotNode,
|
SnapshotNode,
|
||||||
@@ -7,10 +11,6 @@ import type {
|
|||||||
import { BaseBlockTransformer } from '@blocksuite/store';
|
import { BaseBlockTransformer } from '@blocksuite/store';
|
||||||
import * as Y from 'yjs';
|
import * as Y from 'yjs';
|
||||||
|
|
||||||
const SURFACE_TEXT_UNIQ_IDENTIFIER = 'affine:surface:text';
|
|
||||||
// Used for group children field
|
|
||||||
const SURFACE_YMAP_UNIQ_IDENTIFIER = 'affine:surface:ymap';
|
|
||||||
|
|
||||||
export class SurfaceBlockTransformer extends BaseBlockTransformer<SurfaceBlockProps> {
|
export class SurfaceBlockTransformer extends BaseBlockTransformer<SurfaceBlockProps> {
|
||||||
private _elementToJSON(element: Y.Map<unknown>) {
|
private _elementToJSON(element: Y.Map<unknown>) {
|
||||||
const value: Record<string, unknown> = {};
|
const value: Record<string, unknown> = {};
|
||||||
|
|||||||
@@ -63,10 +63,6 @@ export class BrushElementModel extends GfxPrimitiveElementModel<BrushProps> {
|
|||||||
return 'brush';
|
return 'brush';
|
||||||
}
|
}
|
||||||
|
|
||||||
static override propsToY(props: BrushProps) {
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
|
|
||||||
override containsBound(bounds: Bound) {
|
override containsBound(bounds: Bound) {
|
||||||
const points = getPointsFromBoundWithRotation(this);
|
const points = getPointsFromBoundWithRotation(this);
|
||||||
return points.some(point => bounds.containsPoint(point));
|
return points.some(point => bounds.containsPoint(point));
|
||||||
|
|||||||
@@ -125,8 +125,8 @@ export class ConnectorElementModel extends GfxPrimitiveElementModel<ConnectorEle
|
|||||||
return 'connector';
|
return 'connector';
|
||||||
}
|
}
|
||||||
|
|
||||||
static override propsToY(props: ConnectorElementProps) {
|
static propsToY(props: ConnectorElementProps) {
|
||||||
if (props.text && !(props.text instanceof Y.Text)) {
|
if (typeof props.text === 'string') {
|
||||||
props.text = new Y.Text(props.text);
|
props.text = new Y.Text(props.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ export class GroupElementModel extends GfxGroupLikeElementModel<GroupElementProp
|
|||||||
return 'group';
|
return 'group';
|
||||||
}
|
}
|
||||||
|
|
||||||
static override propsToY(props: Record<string, unknown>) {
|
static propsToY(props: Record<string, unknown>) {
|
||||||
if ('title' in props && !(props.title instanceof Y.Text)) {
|
if (typeof props.title === 'string') {
|
||||||
props.title = new Y.Text(props.title as string);
|
props.title = new Y.Text(props.title as string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ export class MindmapElementModel extends GfxGroupLikeElementModel<MindmapElement
|
|||||||
return 'mindmap';
|
return 'mindmap';
|
||||||
}
|
}
|
||||||
|
|
||||||
static override propsToY(props: Record<string, unknown>) {
|
static propsToY(props: Record<string, unknown>) {
|
||||||
if (
|
if (
|
||||||
props.children &&
|
props.children &&
|
||||||
!isNodeType(props.children as Record<string, unknown>) &&
|
!isNodeType(props.children as Record<string, unknown>) &&
|
||||||
|
|||||||
@@ -67,8 +67,8 @@ export class ShapeElementModel extends GfxPrimitiveElementModel<ShapeProps> {
|
|||||||
return 'shape';
|
return 'shape';
|
||||||
}
|
}
|
||||||
|
|
||||||
static override propsToY(props: ShapeProps) {
|
static propsToY(props: ShapeProps) {
|
||||||
if (props.text && !(props.text instanceof Y.Text)) {
|
if (typeof props.text === 'string') {
|
||||||
props.text = new Y.Text(props.text);
|
props.text = new Y.Text(props.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ export class TextElementModel extends GfxPrimitiveElementModel<TextElementProps>
|
|||||||
return 'text';
|
return 'text';
|
||||||
}
|
}
|
||||||
|
|
||||||
static override propsToY(props: Record<string, unknown>) {
|
static propsToY(props: Record<string, unknown>) {
|
||||||
if (props.text && !(props.text instanceof Y.Text)) {
|
if (typeof props.text === 'string') {
|
||||||
props.text = new Y.Text(props.text as string);
|
props.text = new Y.Text(props.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
return props;
|
return props;
|
||||||
|
|||||||
@@ -1,6 +1,16 @@
|
|||||||
import type { SurfaceBlockModel } from '@blocksuite/affine-block-surface';
|
import type { SurfaceBlockModel } from '@blocksuite/affine-block-surface';
|
||||||
|
import type { ConnectorElementModel } from '@blocksuite/affine-model';
|
||||||
import type { BlockStdScope } from '@blocksuite/block-std';
|
import type { BlockStdScope } from '@blocksuite/block-std';
|
||||||
import { isGfxGroupCompatibleModel } from '@blocksuite/block-std/gfx';
|
import {
|
||||||
|
GfxController,
|
||||||
|
type GfxModel,
|
||||||
|
isGfxGroupCompatibleModel,
|
||||||
|
} from '@blocksuite/block-std/gfx';
|
||||||
|
import {
|
||||||
|
assertType,
|
||||||
|
type IVec,
|
||||||
|
type SerializedXYWH,
|
||||||
|
} from '@blocksuite/global/utils';
|
||||||
import type { TransformerMiddleware } from '@blocksuite/store';
|
import type { TransformerMiddleware } from '@blocksuite/store';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,6 +28,7 @@ export const gfxBlocksFilter = (
|
|||||||
const surface = store.getBlocksByFlavour('affine:surface')[0]
|
const surface = store.getBlocksByFlavour('affine:surface')[0]
|
||||||
.model as SurfaceBlockModel;
|
.model as SurfaceBlockModel;
|
||||||
const idsToCheck = ids.slice();
|
const idsToCheck = ids.slice();
|
||||||
|
const gfx = std.get(GfxController);
|
||||||
|
|
||||||
for (const id of idsToCheck) {
|
for (const id of idsToCheck) {
|
||||||
const blockOrElem = store.getBlock(id)?.model ?? surface.getElementById(id);
|
const blockOrElem = store.getBlock(id)?.model ?? surface.getElementById(id);
|
||||||
@@ -45,5 +56,62 @@ export const gfxBlocksFilter = (
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
slots.afterExport.on(payload => {
|
||||||
|
if (payload.type !== 'block') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payload.model.flavour === 'affine:surface') {
|
||||||
|
const { snapshot } = payload;
|
||||||
|
const elementsMap = snapshot.props.elements as Record<
|
||||||
|
string,
|
||||||
|
{ type: string }
|
||||||
|
>;
|
||||||
|
|
||||||
|
Object.entries(elementsMap).forEach(([elementId, val]) => {
|
||||||
|
if (val.type === 'connector') {
|
||||||
|
assertType<{
|
||||||
|
type: 'connector';
|
||||||
|
source: { position: IVec; id?: string };
|
||||||
|
target: { position: IVec; id?: string };
|
||||||
|
xywh: SerializedXYWH;
|
||||||
|
}>(val);
|
||||||
|
|
||||||
|
const connectorElem = gfx.getElementById(
|
||||||
|
elementId
|
||||||
|
) as ConnectorElementModel;
|
||||||
|
|
||||||
|
if (!connectorElem) {
|
||||||
|
delete elementsMap[elementId];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// should be deleted during the import process
|
||||||
|
val.xywh = connectorElem.xywh;
|
||||||
|
|
||||||
|
['source', 'target'].forEach(key => {
|
||||||
|
const endpoint = val[key as 'source' | 'target'];
|
||||||
|
if (endpoint.id && !selectedIds.has(endpoint.id)) {
|
||||||
|
const endElem = gfx.getElementById(endpoint.id);
|
||||||
|
|
||||||
|
if (!endElem) {
|
||||||
|
delete elementsMap[elementId];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const endElemBound = (endElem as GfxModel).elementBound;
|
||||||
|
|
||||||
|
val[key as 'source' | 'target'] = {
|
||||||
|
position: endElemBound.getRelativePoint(
|
||||||
|
endpoint.position ?? [0.5, 0.5]
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -290,13 +290,28 @@ export function getSnapshotRect(snapshot: SliceSnapshot): Bound | null {
|
|||||||
if (block.flavour === 'affine:surface') {
|
if (block.flavour === 'affine:surface') {
|
||||||
if (block.props.elements) {
|
if (block.props.elements) {
|
||||||
Object.values(
|
Object.values(
|
||||||
block.props.elements as Record<string, { xywh: SerializedXYWH }>
|
block.props.elements as Record<
|
||||||
|
string,
|
||||||
|
{ type: string; xywh: SerializedXYWH }
|
||||||
|
>
|
||||||
).forEach(elem => {
|
).forEach(elem => {
|
||||||
if (elem.xywh) {
|
if (elem.xywh) {
|
||||||
bound = bound
|
bound = bound
|
||||||
? bound.unite(Bound.deserialize(elem.xywh))
|
? bound.unite(Bound.deserialize(elem.xywh))
|
||||||
: Bound.deserialize(elem.xywh);
|
: Bound.deserialize(elem.xywh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (elem.type === 'connector') {
|
||||||
|
let connectorBound: Bound | undefined;
|
||||||
|
|
||||||
|
if (elem.xywh) {
|
||||||
|
connectorBound = Bound.deserialize(elem.xywh);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connectorBound) {
|
||||||
|
bound = bound ? bound.unite(connectorBound) : connectorBound;
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { ParagraphBlockComponent } from '@blocksuite/affine-block-paragraph';
|
import { ParagraphBlockComponent } from '@blocksuite/affine-block-paragraph';
|
||||||
import { SurfaceBlockModel } from '@blocksuite/affine-block-surface';
|
|
||||||
import { DropIndicator } from '@blocksuite/affine-components/drop-indicator';
|
import { DropIndicator } from '@blocksuite/affine-components/drop-indicator';
|
||||||
import {
|
import {
|
||||||
AttachmentBlockModel,
|
AttachmentBlockModel,
|
||||||
@@ -45,11 +44,14 @@ import {
|
|||||||
type GfxModel,
|
type GfxModel,
|
||||||
GfxPrimitiveElementModel,
|
GfxPrimitiveElementModel,
|
||||||
isGfxGroupCompatibleModel,
|
isGfxGroupCompatibleModel,
|
||||||
|
SURFACE_YMAP_UNIQ_IDENTIFIER,
|
||||||
|
SurfaceBlockModel,
|
||||||
} from '@blocksuite/block-std/gfx';
|
} from '@blocksuite/block-std/gfx';
|
||||||
import {
|
import {
|
||||||
assertType,
|
assertType,
|
||||||
Bound,
|
Bound,
|
||||||
groupBy,
|
groupBy,
|
||||||
|
type IVec,
|
||||||
last,
|
last,
|
||||||
Point,
|
Point,
|
||||||
Rect,
|
Rect,
|
||||||
@@ -752,7 +754,11 @@ export class DragEventWatcher {
|
|||||||
const idRemap = new Map<string, string>();
|
const idRemap = new Map<string, string>();
|
||||||
let elemMap: Record<
|
let elemMap: Record<
|
||||||
string,
|
string,
|
||||||
{ type: string; children?: { json: Record<string, unknown> } }
|
{
|
||||||
|
type: string;
|
||||||
|
xywh?: SerializedXYWH;
|
||||||
|
children?: { json: Record<string, unknown> };
|
||||||
|
}
|
||||||
> = {};
|
> = {};
|
||||||
const blockMap: Record<
|
const blockMap: Record<
|
||||||
string,
|
string,
|
||||||
@@ -766,7 +772,7 @@ export class DragEventWatcher {
|
|||||||
const constructor = surface.getConstructor(elem.type);
|
const constructor = surface.getConstructor(elem.type);
|
||||||
const isGroup = Object.isPrototypeOf.call(
|
const isGroup = Object.isPrototypeOf.call(
|
||||||
GfxGroupLikeElementModel.prototype,
|
GfxGroupLikeElementModel.prototype,
|
||||||
constructor
|
constructor.prototype
|
||||||
);
|
);
|
||||||
|
|
||||||
return isGroup;
|
return isGroup;
|
||||||
@@ -782,24 +788,40 @@ export class DragEventWatcher {
|
|||||||
if (block.flavour === 'affine:surface') {
|
if (block.flavour === 'affine:surface') {
|
||||||
elemMap = (block.props.elements as typeof elemMap) ?? {};
|
elemMap = (block.props.elements as typeof elemMap) ?? {};
|
||||||
Object.entries(elemMap).forEach(([elemId, elem]) => {
|
Object.entries(elemMap).forEach(([elemId, elem]) => {
|
||||||
if (isGroupLikeElem(elem)) {
|
if (
|
||||||
// only add the group to the root if it's not a child of any other element
|
Object.values(containerTree).every(
|
||||||
if (
|
childSet => !childSet.has(elemId)
|
||||||
Object.values(containerTree).every(
|
)
|
||||||
childSet => !childSet.has(elemId)
|
) {
|
||||||
)
|
containerTree['root'].add(elemId);
|
||||||
) {
|
}
|
||||||
containerTree['root'].add(elem.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (isGroupLikeElem(elem)) {
|
||||||
Object.keys(elem.children?.json ?? {}).forEach(childId => {
|
Object.keys(elem.children?.json ?? {}).forEach(childId => {
|
||||||
containerTree[elemId] = containerTree[elemId] ?? new Set();
|
containerTree[elemId] = containerTree[elemId] ?? new Set();
|
||||||
containerTree[elemId].add(childId);
|
containerTree[elemId].add(childId);
|
||||||
// if the child was already added to the root, remove it
|
// if the child was already added to the root, remove it
|
||||||
containerTree['root'].delete(childId);
|
containerTree['root'].delete(childId);
|
||||||
});
|
});
|
||||||
} else {
|
return;
|
||||||
containerTree['root'].add(elemId);
|
} else if (elem.type === 'connector') {
|
||||||
|
assertType<{
|
||||||
|
type: 'connector';
|
||||||
|
source: { position: IVec; id?: string };
|
||||||
|
target: { position: IVec; id?: string };
|
||||||
|
}>(elem);
|
||||||
|
|
||||||
|
if (elem.source.id) {
|
||||||
|
containerTree[elemId] = containerTree[elemId] ?? new Set();
|
||||||
|
containerTree[elemId].add(elem.source.id);
|
||||||
|
containerTree['root'].delete(elem.source.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elem.target.id) {
|
||||||
|
containerTree[elemId] = containerTree[elemId] ?? new Set();
|
||||||
|
containerTree[elemId].add(elem.target.id);
|
||||||
|
containerTree['root'].delete(elem.target.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -876,19 +898,58 @@ export class DragEventWatcher {
|
|||||||
idRemap.set(id, slices.content[0].id);
|
idRemap.set(id, slices.content[0].id);
|
||||||
}
|
}
|
||||||
} else if (elemMap[id]) {
|
} else if (elemMap[id]) {
|
||||||
if (elemMap[id].children) {
|
const elem = elemMap[id];
|
||||||
const childJson = elemMap[id].children.json;
|
|
||||||
Object.keys(childJson).forEach(childId => {
|
Object.entries(elem).forEach(([_, val]) => {
|
||||||
if (idRemap.has(childId)) {
|
if (
|
||||||
const remappedId = idRemap.get(childId)!;
|
val instanceof Object &&
|
||||||
childJson[remappedId] = childJson[childId];
|
Reflect.has(val, SURFACE_YMAP_UNIQ_IDENTIFIER)
|
||||||
delete childJson[childId];
|
) {
|
||||||
} else {
|
const childJson = Reflect.get(val, 'json') as Record<
|
||||||
delete childJson[childId];
|
string,
|
||||||
|
unknown
|
||||||
|
>;
|
||||||
|
|
||||||
|
Object.keys(childJson).forEach(oldChildId => {
|
||||||
|
if (idRemap.has(oldChildId)) {
|
||||||
|
const remappedId = idRemap.get(oldChildId)!;
|
||||||
|
const val = structuredClone(childJson[oldChildId]);
|
||||||
|
|
||||||
|
if (elem.type === 'mindmap') {
|
||||||
|
assertType<{ parent?: string }>(val);
|
||||||
|
if (val.parent) {
|
||||||
|
val.parent = idRemap.get(val.parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
childJson[remappedId] = val;
|
||||||
|
delete childJson[oldChildId];
|
||||||
|
} else {
|
||||||
|
delete childJson[oldChildId];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (elem.type === 'connector') {
|
||||||
|
assertType<{
|
||||||
|
type: 'connector';
|
||||||
|
source: { position: IVec; id?: string };
|
||||||
|
target: { position: IVec; id?: string };
|
||||||
|
}>(elem);
|
||||||
|
|
||||||
|
(['source', 'target'] as const).forEach(key => {
|
||||||
|
const endpoint = elem[key];
|
||||||
|
if (endpoint.id) {
|
||||||
|
if (idRemap.get(endpoint.id)) {
|
||||||
|
endpoint.id = idRemap.get(endpoint.id);
|
||||||
|
} else {
|
||||||
|
delete endpoint.id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const newId = surface.addElement(elemMap[id]);
|
|
||||||
|
const newId = surface.addElement(elem);
|
||||||
idRemap.set(id, newId);
|
idRemap.set(id, newId);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -918,8 +979,45 @@ export class DragEventWatcher {
|
|||||||
if (block.flavour === 'affine:surface') {
|
if (block.flavour === 'affine:surface') {
|
||||||
if (block.props.elements) {
|
if (block.props.elements) {
|
||||||
Object.values(
|
Object.values(
|
||||||
block.props.elements as Record<string, { xywh: SerializedXYWH }>
|
block.props.elements as Record<
|
||||||
|
string,
|
||||||
|
{ type: string; xywh?: SerializedXYWH }
|
||||||
|
>
|
||||||
).forEach(elem => {
|
).forEach(elem => {
|
||||||
|
if (elem.type === 'connector') {
|
||||||
|
assertType<{
|
||||||
|
type: 'connector';
|
||||||
|
xywh?: SerializedXYWH;
|
||||||
|
source: { position: IVec; id?: string };
|
||||||
|
target: { position: IVec; id?: string };
|
||||||
|
}>(elem);
|
||||||
|
|
||||||
|
const connectorBound = elem.xywh
|
||||||
|
? Bound.deserialize(elem.xywh)
|
||||||
|
: new Bound(0, 0, 0, 0);
|
||||||
|
|
||||||
|
delete elem.xywh;
|
||||||
|
|
||||||
|
(['source', 'target'] as const).forEach(key => {
|
||||||
|
const endpoint = elem[key];
|
||||||
|
if (!endpoint.id) {
|
||||||
|
const originalPos = endpoint.position;
|
||||||
|
|
||||||
|
elem[key] = {
|
||||||
|
position: ignoreOriginalPos
|
||||||
|
? [
|
||||||
|
originalPos[0] - connectorBound.x + modelX,
|
||||||
|
originalPos[1] - connectorBound.y + modelY,
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
originalPos[0] - rect.x + modelX,
|
||||||
|
originalPos[1] - rect.y + modelY,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (elem.xywh) {
|
if (elem.xywh) {
|
||||||
const elemBound = Bound.deserialize(elem.xywh);
|
const elemBound = Bound.deserialize(elem.xywh);
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ export {
|
|||||||
prop,
|
prop,
|
||||||
} from './model/surface/local-element-model.js';
|
} from './model/surface/local-element-model.js';
|
||||||
export {
|
export {
|
||||||
|
SURFACE_TEXT_UNIQ_IDENTIFIER,
|
||||||
|
SURFACE_YMAP_UNIQ_IDENTIFIER,
|
||||||
SurfaceBlockModel,
|
SurfaceBlockModel,
|
||||||
type SurfaceBlockProps,
|
type SurfaceBlockProps,
|
||||||
type SurfaceMiddleware,
|
type SurfaceMiddleware,
|
||||||
|
|||||||
@@ -199,10 +199,6 @@ export abstract class GfxPrimitiveElementModel<
|
|||||||
this.seed = randomSeed();
|
this.seed = randomSeed();
|
||||||
}
|
}
|
||||||
|
|
||||||
static propsToY(props: Record<string, unknown>) {
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
|
|
||||||
containsBound(bounds: Bound): boolean {
|
containsBound(bounds: Bound): boolean {
|
||||||
return getPointsFromBoundWithRotation(this).some(point =>
|
return getPointsFromBoundWithRotation(this).some(point =>
|
||||||
bounds.containsPoint(point)
|
bounds.containsPoint(point)
|
||||||
|
|||||||
@@ -12,11 +12,20 @@ import { createDecoratorState } from './decorators/common.js';
|
|||||||
import { initializeObservers, initializeWatchers } from './decorators/index.js';
|
import { initializeObservers, initializeWatchers } from './decorators/index.js';
|
||||||
import {
|
import {
|
||||||
GfxGroupLikeElementModel,
|
GfxGroupLikeElementModel,
|
||||||
GfxPrimitiveElementModel,
|
type GfxPrimitiveElementModel,
|
||||||
syncElementFromY,
|
syncElementFromY,
|
||||||
} from './element-model.js';
|
} from './element-model.js';
|
||||||
import type { GfxLocalElementModel } from './local-element-model.js';
|
import type { GfxLocalElementModel } from './local-element-model.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used for text field
|
||||||
|
*/
|
||||||
|
export const SURFACE_TEXT_UNIQ_IDENTIFIER = 'affine:surface:text';
|
||||||
|
/**
|
||||||
|
* Used for field that use Y.Map. E.g. group children field
|
||||||
|
*/
|
||||||
|
export const SURFACE_YMAP_UNIQ_IDENTIFIER = 'affine:surface:ymap';
|
||||||
|
|
||||||
export type SurfaceBlockProps = {
|
export type SurfaceBlockProps = {
|
||||||
elements: Boxed<Y.Map<Y.Map<unknown>>>;
|
elements: Boxed<Y.Map<Y.Map<unknown>>>;
|
||||||
};
|
};
|
||||||
@@ -390,8 +399,28 @@ export class SurfaceBlockModel extends BlockModel<SurfaceBlockProps> {
|
|||||||
throw new Error(`Invalid element type: ${type}`);
|
throw new Error(`Invalid element type: ${type}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Object.entries(props).forEach(([key, val]) => {
|
||||||
|
if (val instanceof Object) {
|
||||||
|
if (Reflect.has(val, SURFACE_TEXT_UNIQ_IDENTIFIER)) {
|
||||||
|
const yText = new Y.Text();
|
||||||
|
yText.applyDelta(Reflect.get(val, 'delta'));
|
||||||
|
Reflect.set(props, key, yText);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Reflect.has(val, SURFACE_YMAP_UNIQ_IDENTIFIER)) {
|
||||||
|
const childJson = Reflect.get(val, 'json') as Record<string, unknown>;
|
||||||
|
const childrenYMap = new Y.Map<unknown>();
|
||||||
|
|
||||||
|
Object.keys(childJson).forEach(childId => {
|
||||||
|
childrenYMap.set(childId, childJson[childId]);
|
||||||
|
});
|
||||||
|
Reflect.set(props, key, childrenYMap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// @ts-expect-error ignore
|
// @ts-expect-error ignore
|
||||||
return (ctor.propsToY ?? GfxPrimitiveElementModel.propsToY)(props);
|
return ctor.propsToY ? ctor.propsToY(props) : props;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _watchGroupRelationChange() {
|
private _watchGroupRelationChange() {
|
||||||
|
|||||||
Reference in New Issue
Block a user