fix: cannot drop image as list child (#11635)
Fixes [BS-3103](https://linear.app/affine-design/issue/BS-3103/drag-and-drop-bug-白板图片无法拖动到-list-的子项下面)
This commit is contained in:
@@ -99,9 +99,6 @@ export class AffineDragHandleWidget extends WidgetComponent<RootBlockModel> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._anchorModelDisposables = new DisposableGroup();
|
this._anchorModelDisposables = new DisposableGroup();
|
||||||
this._anchorModelDisposables.add(
|
|
||||||
blockModel.propsUpdated.subscribe(() => this.hide())
|
|
||||||
);
|
|
||||||
|
|
||||||
this._anchorModelDisposables.add(
|
this._anchorModelDisposables.add(
|
||||||
blockModel.deleted.subscribe(() => this.hide())
|
blockModel.deleted.subscribe(() => this.hide())
|
||||||
|
|||||||
@@ -195,25 +195,25 @@ export class DragEventWatcher {
|
|||||||
dragPayload: DragBlockPayload,
|
dragPayload: DragBlockPayload,
|
||||||
dropPayload: DropPayload
|
dropPayload: DropPayload
|
||||||
): DropResult | null => {
|
): DropResult | null => {
|
||||||
const model = dropBlock.model;
|
const dropModel = dropBlock.model;
|
||||||
|
|
||||||
const snapshot = dragPayload?.bsEntity?.snapshot;
|
const snapshot = dragPayload?.bsEntity?.snapshot;
|
||||||
if (
|
if (
|
||||||
!snapshot ||
|
!snapshot ||
|
||||||
snapshot.content.length === 0 ||
|
snapshot.content.length === 0 ||
|
||||||
!dragPayload?.from ||
|
!dragPayload?.from ||
|
||||||
matchModels(model, [DatabaseBlockModel])
|
matchModels(dropModel, [DatabaseBlockModel])
|
||||||
)
|
)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
const isDropOnNoteBlock = matchModels(model, [NoteBlockModel]);
|
const isDropOnNoteBlock = matchModels(dropModel, [NoteBlockModel]);
|
||||||
|
|
||||||
const schema = this.std.store.schema;
|
const schema = this.std.store.schema;
|
||||||
const edge = dropPayload.edge;
|
const edge = dropPayload.edge;
|
||||||
const scale = this.widget.scale.peek();
|
const scale = this.widget.scale.peek();
|
||||||
let result: DropResult | null = null;
|
let result: DropResult | null = null;
|
||||||
|
|
||||||
if (edge === 'right' && matchModels(dropBlock.model, [ListBlockModel])) {
|
if (edge === 'right' && matchModels(dropModel, [ListBlockModel])) {
|
||||||
const domRect = getRectByBlockComponent(dropBlock);
|
const domRect = getRectByBlockComponent(dropBlock);
|
||||||
const placement = 'in';
|
const placement = 'in';
|
||||||
|
|
||||||
@@ -279,7 +279,7 @@ export class DragEventWatcher {
|
|||||||
placement,
|
placement,
|
||||||
rect: Rect.fromLWTH(domRect.left, domRect.width, y, 3 * scale),
|
rect: Rect.fromLWTH(domRect.left, domRect.width, y, 3 * scale),
|
||||||
modelState: {
|
modelState: {
|
||||||
model,
|
model: dropModel,
|
||||||
rect: domRect,
|
rect: domRect,
|
||||||
element: dropBlock,
|
element: dropBlock,
|
||||||
},
|
},
|
||||||
@@ -548,70 +548,49 @@ export class DragEventWatcher {
|
|||||||
|
|
||||||
if (!parent) return;
|
if (!parent) return;
|
||||||
|
|
||||||
if (dragPayload.bsEntity?.fromMode === 'gfx') {
|
// drop on the same place, do nothing
|
||||||
if (!matchModels(parent, [NoteBlockModel])) {
|
if (
|
||||||
|
(dragPayload.from?.docId === this.widget.doc.id &&
|
||||||
|
result.placement === 'after' &&
|
||||||
|
parent.children[index]?.id === snapshot.content[0].id) ||
|
||||||
|
(result.placement === 'before' &&
|
||||||
|
parent.children[index - 1]?.id === last(snapshot.content)!.id)
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if not all blocks can be dropped in note block, merge the snapshot to the current doc
|
// drop a note on other note
|
||||||
if (
|
if (
|
||||||
!snapshot.content.every(block =>
|
matchModels(parent, [NoteBlockModel]) &&
|
||||||
schema.safeValidate(block.flavour, 'affine:note')
|
snapshot.content.every(block => block.flavour === 'affine:note')
|
||||||
) &&
|
|
||||||
// if all blocks are note blocks, merge it to the current parent note
|
|
||||||
!snapshot.content.every(block => block.flavour === 'affine:note')
|
|
||||||
) {
|
) {
|
||||||
// merge the snapshot to the current doc if the snapshot comes from other doc
|
snapshot.content = snapshot.content.filter(
|
||||||
if (dragPayload.from?.docId !== this.widget.doc.id) {
|
block =>
|
||||||
this._mergeSnapshotToCurDoc(snapshot)
|
dragPayload.from?.docId !== this.widget.doc.id ||
|
||||||
.then(idRemap => {
|
block.id !== parent.id
|
||||||
let largestElem!: {
|
|
||||||
size: number;
|
|
||||||
id: string;
|
|
||||||
flavour: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
idRemap.forEach(val => {
|
|
||||||
const gfxElement = this.gfx.getElementById(val) as GfxModel;
|
|
||||||
|
|
||||||
if (gfxElement?.elementBound) {
|
|
||||||
const elemBound = gfxElement.elementBound;
|
|
||||||
const flavour = isPrimitiveModel(gfxElement)
|
|
||||||
? gfxElement.type
|
|
||||||
: gfxElement.flavour;
|
|
||||||
|
|
||||||
largestElem =
|
|
||||||
(largestElem?.size ?? 0) < elemBound.w * elemBound.h
|
|
||||||
? { size: elemBound.w * elemBound.h, id: val, flavour }
|
|
||||||
: largestElem;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!largestElem) {
|
|
||||||
store.addBlock(
|
|
||||||
'affine:embed-linked-doc',
|
|
||||||
{
|
|
||||||
pageId: store.doc.id,
|
|
||||||
},
|
|
||||||
parent.id,
|
|
||||||
index
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
store.addBlock(
|
|
||||||
'affine:surface-ref',
|
|
||||||
{
|
|
||||||
reference: largestElem.id,
|
|
||||||
refFlavour: largestElem.flavour,
|
|
||||||
},
|
|
||||||
parent.id,
|
|
||||||
index
|
|
||||||
);
|
);
|
||||||
|
if (snapshot.content.length) {
|
||||||
|
this._onDropNoteOnNote(snapshot, parent.id, index);
|
||||||
}
|
}
|
||||||
})
|
return;
|
||||||
.catch(console.error);
|
|
||||||
}
|
}
|
||||||
// otherwise, just to create a surface-ref block
|
|
||||||
else {
|
// all blocks can be safely dropped in the target parent
|
||||||
|
if (
|
||||||
|
snapshot.content.every(block =>
|
||||||
|
schema.safeValidate(block.flavour, parent.flavour)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
this._dropToModel(snapshot, parent.id, index).catch(console.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
dragPayload.bsEntity?.fromMode === 'gfx' &&
|
||||||
|
matchModels(parent, [NoteBlockModel])
|
||||||
|
) {
|
||||||
|
// if the snapshot comes from the same doc, just create a surface-ref block
|
||||||
|
if (dragPayload.from?.docId === this.widget.doc.id) {
|
||||||
let largestElem!: {
|
let largestElem!: {
|
||||||
size: number;
|
size: number;
|
||||||
id: string;
|
id: string;
|
||||||
@@ -671,34 +650,57 @@ export class DragEventWatcher {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// otherwise, merge the snapshot into the current doc
|
||||||
|
// and create a surface-ref block or embed-linked-doc block
|
||||||
|
else {
|
||||||
|
this._mergeSnapshotToCurDoc(snapshot)
|
||||||
|
.then(idRemap => {
|
||||||
|
let largestElem!: {
|
||||||
|
size: number;
|
||||||
|
id: string;
|
||||||
|
flavour: string;
|
||||||
|
};
|
||||||
|
|
||||||
return;
|
idRemap.forEach(val => {
|
||||||
}
|
const gfxElement = this.gfx.getElementById(val) as GfxModel;
|
||||||
}
|
|
||||||
|
|
||||||
// drop a note on other note
|
if (gfxElement?.elementBound) {
|
||||||
if (matchModels(parent, [NoteBlockModel])) {
|
const elemBound = gfxElement.elementBound;
|
||||||
const [first] = snapshot.content;
|
const flavour = isPrimitiveModel(gfxElement)
|
||||||
if (first.flavour === 'affine:note') {
|
? gfxElement.type
|
||||||
if (parent.id !== first.id) {
|
: gfxElement.flavour;
|
||||||
this._onDropNoteOnNote(snapshot, parent.id, index);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// drop on the same place, do nothing
|
largestElem =
|
||||||
if (
|
(largestElem?.size ?? 0) < elemBound.w * elemBound.h
|
||||||
(dragPayload.from?.docId === this.widget.doc.id &&
|
? { size: elemBound.w * elemBound.h, id: val, flavour }
|
||||||
result.placement === 'after' &&
|
: largestElem;
|
||||||
parent.children[index]?.id === snapshot.content[0].id) ||
|
|
||||||
(result.placement === 'before' &&
|
|
||||||
parent.children[index - 1]?.id === last(snapshot.content)!.id)
|
|
||||||
) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this._dropToModel(snapshot, parent.id, index).catch(console.error);
|
if (!largestElem) {
|
||||||
|
store.addBlock(
|
||||||
|
'affine:embed-linked-doc',
|
||||||
|
{
|
||||||
|
pageId: store.doc.id,
|
||||||
|
},
|
||||||
|
parent.id,
|
||||||
|
index
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
store.addBlock(
|
||||||
|
'affine:surface-ref',
|
||||||
|
{
|
||||||
|
reference: largestElem.id,
|
||||||
|
refFlavour: largestElem.flavour,
|
||||||
|
},
|
||||||
|
parent.id,
|
||||||
|
index
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(console.error);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly _onDrop = (
|
private readonly _onDrop = (
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
import {
|
import { EdgelessLegacySlotIdentifier } from '@blocksuite/affine-block-surface';
|
||||||
EdgelessLegacySlotIdentifier,
|
|
||||||
type SurfaceBlockComponent,
|
|
||||||
} from '@blocksuite/affine-block-surface';
|
|
||||||
import { getSelectedRect } from '@blocksuite/affine-shared/utils';
|
import { getSelectedRect } from '@blocksuite/affine-shared/utils';
|
||||||
import { type IVec, Rect } from '@blocksuite/global/gfx';
|
import { type IVec, Rect } from '@blocksuite/global/gfx';
|
||||||
import {
|
import {
|
||||||
@@ -54,20 +51,14 @@ export class EdgelessWatcher {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this.widget.isGfxDragHandleVisible) {
|
if (this.widget.isGfxDragHandleVisible) {
|
||||||
this._showDragHandle().catch(console.error);
|
this._showDragHandle();
|
||||||
this._updateDragHoverRectTopLevelBlock();
|
this._updateDragHoverRectTopLevelBlock();
|
||||||
} else if (this.widget.activeDragHandle) {
|
} else if (this.widget.activeDragHandle) {
|
||||||
this.widget.hide();
|
this.widget.hide();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly _showDragHandle = async () => {
|
private readonly _showDragHandle = () => {
|
||||||
const surfaceModel = this.widget.doc.getModelsByFlavour('affine:surface');
|
|
||||||
const surface = this.widget.std.view.getBlock(
|
|
||||||
surfaceModel[0]!.id
|
|
||||||
) as SurfaceBlockComponent;
|
|
||||||
await surface.updateComplete;
|
|
||||||
|
|
||||||
if (!this.widget.anchorBlockId) return;
|
if (!this.widget.anchorBlockId) return;
|
||||||
|
|
||||||
const container = this.widget.dragHandleContainer;
|
const container = this.widget.dragHandleContainer;
|
||||||
@@ -119,7 +110,7 @@ export class EdgelessWatcher {
|
|||||||
|
|
||||||
this.widget.anchorBlockId.value = selectedElement.id;
|
this.widget.anchorBlockId.value = selectedElement.id;
|
||||||
|
|
||||||
this._showDragHandle().catch(console.error);
|
this._showDragHandle();
|
||||||
};
|
};
|
||||||
|
|
||||||
get hoveredElemAreaRect() {
|
get hoveredElemAreaRect() {
|
||||||
@@ -212,11 +203,27 @@ export class EdgelessWatcher {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
disposables.add(
|
||||||
|
std.store.slots.blockUpdated.subscribe(payload => {
|
||||||
|
if (
|
||||||
|
this.widget.isGfxDragHandleVisible &&
|
||||||
|
payload.id === this.widget.anchorBlockId.peek()
|
||||||
|
) {
|
||||||
|
if (payload.type === 'delete') {
|
||||||
|
this.widget.hide();
|
||||||
|
}
|
||||||
|
if (payload.type === 'update') {
|
||||||
|
this._showDragHandle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
if (surface) {
|
if (surface) {
|
||||||
disposables.add(
|
disposables.add(
|
||||||
surface.elementUpdated.subscribe(() => {
|
surface.elementUpdated.subscribe(() => {
|
||||||
if (this.widget.isGfxDragHandleVisible) {
|
if (this.widget.isGfxDragHandleVisible) {
|
||||||
this._showDragHandle().catch(console.error);
|
this._showDragHandle();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user