fix(editor): merge drag function and fix it (#9329)
This commit is contained in:
@@ -6,8 +6,6 @@ import {
|
|||||||
import { type Container, createIdentifier } from '@blocksuite/global/di';
|
import { type Container, createIdentifier } from '@blocksuite/global/di';
|
||||||
import { Job, Slice, type SliceSnapshot } from '@blocksuite/store';
|
import { Job, Slice, type SliceSnapshot } from '@blocksuite/store';
|
||||||
|
|
||||||
export type DropType = 'before' | 'after' | 'in';
|
|
||||||
|
|
||||||
export const DndApiExtensionIdentifier = createIdentifier<DNDAPIExtension>(
|
export const DndApiExtensionIdentifier = createIdentifier<DNDAPIExtension>(
|
||||||
'AffineDndApiIdentifier'
|
'AffineDndApiIdentifier'
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import type { BlockComponent } from '@blocksuite/block-std';
|
|||||||
import { type Point, Rect } from '@blocksuite/global/utils';
|
import { type Point, Rect } from '@blocksuite/global/utils';
|
||||||
import type { BlockModel } from '@blocksuite/store';
|
import type { BlockModel } from '@blocksuite/store';
|
||||||
|
|
||||||
|
import { BLOCK_CHILDREN_CONTAINER_PADDING_LEFT } from '../../consts/index.js';
|
||||||
import {
|
import {
|
||||||
getClosestBlockComponentByElement,
|
getClosestBlockComponentByElement,
|
||||||
getRectByBlockComponent,
|
getRectByBlockComponent,
|
||||||
@@ -10,6 +11,24 @@ import { matchFlavours } from '../model/index.js';
|
|||||||
import { getDropRectByPoint } from './get-drop-rect-by-point.js';
|
import { getDropRectByPoint } from './get-drop-rect-by-point.js';
|
||||||
import { DropFlags, type DroppingType, type DropResult } from './types.js';
|
import { DropFlags, type DroppingType, type DropResult } from './types.js';
|
||||||
|
|
||||||
|
function getVisiblePreviousElementSibling(element: Element | null) {
|
||||||
|
if (!element) return null;
|
||||||
|
let prev = element.previousElementSibling;
|
||||||
|
while (prev && !prev.checkVisibility()) {
|
||||||
|
prev = prev.previousElementSibling;
|
||||||
|
}
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getVisibleNextElementSibling(element: Element | null) {
|
||||||
|
if (!element) return null;
|
||||||
|
let next = element.nextElementSibling;
|
||||||
|
while (next && !next.checkVisibility()) {
|
||||||
|
next = next.nextElementSibling;
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the drop target.
|
* Calculates the drop target.
|
||||||
*/
|
*/
|
||||||
@@ -19,7 +38,10 @@ export function calcDropTarget(
|
|||||||
element: Element,
|
element: Element,
|
||||||
draggingElements: BlockComponent[] = [],
|
draggingElements: BlockComponent[] = [],
|
||||||
scale: number = 1,
|
scale: number = 1,
|
||||||
flavour: string | null = null // for block-hub
|
/**
|
||||||
|
* Allow the dragging block to be dropped as sublist
|
||||||
|
*/
|
||||||
|
allowSublist: boolean = true
|
||||||
): DropResult | null {
|
): DropResult | null {
|
||||||
const schema = model.doc.getSchemaByFlavour(
|
const schema = model.doc.getSchemaByFlavour(
|
||||||
'affine:database' as BlockSuite.Flavour
|
'affine:database' as BlockSuite.Flavour
|
||||||
@@ -28,14 +50,10 @@ export function calcDropTarget(
|
|||||||
|
|
||||||
let shouldAppendToDatabase = true;
|
let shouldAppendToDatabase = true;
|
||||||
|
|
||||||
if (children.length) {
|
if (children.length && draggingElements.length) {
|
||||||
if (draggingElements.length) {
|
shouldAppendToDatabase = draggingElements
|
||||||
shouldAppendToDatabase = draggingElements
|
.map(el => el.model)
|
||||||
.map(el => el.model)
|
.every(m => children.includes(m.flavour));
|
||||||
.every(m => children.includes(m.flavour));
|
|
||||||
} else if (flavour) {
|
|
||||||
shouldAppendToDatabase = children.includes(flavour);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -107,7 +125,7 @@ export function calcDropTarget(
|
|||||||
let prev;
|
let prev;
|
||||||
let prevRect;
|
let prevRect;
|
||||||
|
|
||||||
prev = element.previousElementSibling;
|
prev = getVisiblePreviousElementSibling(element);
|
||||||
if (prev) {
|
if (prev) {
|
||||||
if (
|
if (
|
||||||
draggingElements.length &&
|
draggingElements.length &&
|
||||||
@@ -118,7 +136,7 @@ export function calcDropTarget(
|
|||||||
prevRect = getRectByBlockComponent(prev);
|
prevRect = getRectByBlockComponent(prev);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
prev = element.parentElement?.previousElementSibling;
|
prev = getVisiblePreviousElementSibling(element.parentElement);
|
||||||
if (prev) {
|
if (prev) {
|
||||||
prevRect = prev.getBoundingClientRect();
|
prevRect = prev.getBoundingClientRect();
|
||||||
}
|
}
|
||||||
@@ -128,20 +146,37 @@ export function calcDropTarget(
|
|||||||
offsetY = (domRect.top - prevRect.bottom) / 2;
|
offsetY = (domRect.top - prevRect.bottom) / 2;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Only consider drop as children when target block is list block.
|
||||||
|
// To drop in, the position must after the target first
|
||||||
|
// If drop in target has children, we can use insert before or after of that children
|
||||||
|
// to achieve the same effect.
|
||||||
|
const hasChild = (element as BlockComponent).childBlocks.length;
|
||||||
|
if (
|
||||||
|
allowSublist &&
|
||||||
|
matchFlavours(model, ['affine:list']) &&
|
||||||
|
!hasChild &&
|
||||||
|
point.x > domRect.x + BLOCK_CHILDREN_CONTAINER_PADDING_LEFT
|
||||||
|
) {
|
||||||
|
type = 'in';
|
||||||
|
}
|
||||||
// after
|
// after
|
||||||
let next;
|
let next;
|
||||||
let nextRect;
|
let nextRect;
|
||||||
|
|
||||||
next = element.nextElementSibling;
|
next = getVisibleNextElementSibling(element);
|
||||||
if (next) {
|
if (next) {
|
||||||
if (draggingElements.length && next === draggingElements[0]) {
|
if (
|
||||||
|
type === 'after' &&
|
||||||
|
draggingElements.length &&
|
||||||
|
next === draggingElements[0]
|
||||||
|
) {
|
||||||
type = 'none';
|
type = 'none';
|
||||||
next = null;
|
next = null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
next = getClosestBlockComponentByElement(
|
next = getVisibleNextElementSibling(
|
||||||
element.parentElement
|
getClosestBlockComponentByElement(element.parentElement)
|
||||||
)?.nextElementSibling;
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next) {
|
if (next) {
|
||||||
@@ -159,6 +194,11 @@ export function calcDropTarget(
|
|||||||
top += domRect.height + offsetY;
|
top += domRect.height + offsetY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type === 'in') {
|
||||||
|
domRect.x += BLOCK_CHILDREN_CONTAINER_PADDING_LEFT;
|
||||||
|
domRect.width -= BLOCK_CHILDREN_CONTAINER_PADDING_LEFT;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type,
|
type,
|
||||||
rect: Rect.fromLWTH(domRect.left, domRect.width, top - height / 2, height),
|
rect: Rect.fromLWTH(domRect.left, domRect.width, top - height / 2, height),
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
export * from './calc-drop-target.js';
|
export * from './calc-drop-target.js';
|
||||||
export * from './get-drop-rect-by-point.js';
|
export * from './get-drop-rect-by-point.js';
|
||||||
export type { DropResult } from './types.js';
|
export * from './types.js';
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export enum DropFlags {
|
|||||||
/**
|
/**
|
||||||
* A dropping type.
|
* A dropping type.
|
||||||
*/
|
*/
|
||||||
export type DroppingType = 'none' | 'before' | 'after' | 'database';
|
export type DroppingType = 'none' | 'before' | 'after' | 'database' | 'in';
|
||||||
|
|
||||||
export type DropResult = {
|
export type DropResult = {
|
||||||
type: DroppingType;
|
type: DroppingType;
|
||||||
|
|||||||
@@ -259,9 +259,9 @@ export class DatabaseBlockComponent extends CaptionedBlockComponent<
|
|||||||
return () => {
|
return () => {
|
||||||
this.indicator.remove();
|
this.indicator.remove();
|
||||||
const model = this.doc.getBlock(id)?.model;
|
const model = this.doc.getBlock(id)?.model;
|
||||||
const target = this.doc.getBlock(result.dropBlockId)?.model ?? null;
|
const target = result.modelState.model;
|
||||||
let parent = this.doc.getParent(result.dropBlockId);
|
let parent = this.doc.getParent(target.id);
|
||||||
const shouldInsertIn = result.dropType === 'in';
|
const shouldInsertIn = result.type === 'in';
|
||||||
if (shouldInsertIn) {
|
if (shouldInsertIn) {
|
||||||
parent = target;
|
parent = target;
|
||||||
}
|
}
|
||||||
@@ -273,7 +273,7 @@ export class DatabaseBlockComponent extends CaptionedBlockComponent<
|
|||||||
[model],
|
[model],
|
||||||
parent,
|
parent,
|
||||||
target,
|
target,
|
||||||
result.dropType === 'before'
|
result.type === 'before'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
import type { DropType } from '@blocksuite/affine-shared/services';
|
|
||||||
import type { Rect } from '@blocksuite/global/utils';
|
|
||||||
|
|
||||||
export const DRAG_HANDLE_CONTAINER_HEIGHT = 24;
|
export const DRAG_HANDLE_CONTAINER_HEIGHT = 24;
|
||||||
export const DRAG_HANDLE_CONTAINER_WIDTH = 16;
|
export const DRAG_HANDLE_CONTAINER_WIDTH = 16;
|
||||||
export const DRAG_HANDLE_CONTAINER_WIDTH_TOP_LEVEL = 8;
|
export const DRAG_HANDLE_CONTAINER_WIDTH_TOP_LEVEL = 8;
|
||||||
@@ -20,9 +17,3 @@ export const HOVER_AREA_RECT_PADDING_TOP_LEVEL = 6;
|
|||||||
export const NOTE_CONTAINER_PADDING = 24;
|
export const NOTE_CONTAINER_PADDING = 24;
|
||||||
export const EDGELESS_NOTE_EXTRA_PADDING = 20;
|
export const EDGELESS_NOTE_EXTRA_PADDING = 20;
|
||||||
export const DRAG_HOVER_RECT_PADDING = 4;
|
export const DRAG_HOVER_RECT_PADDING = 4;
|
||||||
|
|
||||||
export type DropResult = {
|
|
||||||
rect: Rect | null;
|
|
||||||
dropBlockId: string;
|
|
||||||
dropType: DropType;
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import type { RootBlockModel } from '@blocksuite/affine-model';
|
import type { RootBlockModel } from '@blocksuite/affine-model';
|
||||||
|
import { DocModeProvider } from '@blocksuite/affine-shared/services';
|
||||||
import {
|
import {
|
||||||
DocModeProvider,
|
calcDropTarget,
|
||||||
type DropType,
|
type DroppingType,
|
||||||
} from '@blocksuite/affine-shared/services';
|
type DropResult,
|
||||||
import {
|
|
||||||
getScrollContainer,
|
getScrollContainer,
|
||||||
isInsideEdgelessEditor,
|
isInsideEdgelessEditor,
|
||||||
isInsidePageEditor,
|
isInsidePageEditor,
|
||||||
@@ -27,14 +27,12 @@ import { autoScroll } from '../../../root-block/text-selection/utils.js';
|
|||||||
import type { EdgelessRootService } from '../../edgeless/index.js';
|
import type { EdgelessRootService } from '../../edgeless/index.js';
|
||||||
import type { DragPreview } from './components/drag-preview.js';
|
import type { DragPreview } from './components/drag-preview.js';
|
||||||
import type { DropIndicator } from './components/drop-indicator.js';
|
import type { DropIndicator } from './components/drop-indicator.js';
|
||||||
import type { DropResult } from './config.js';
|
|
||||||
import type { AFFINE_DRAG_HANDLE_WIDGET } from './consts.js';
|
import type { AFFINE_DRAG_HANDLE_WIDGET } from './consts.js';
|
||||||
import { PreviewHelper } from './helpers/preview-helper.js';
|
import { PreviewHelper } from './helpers/preview-helper.js';
|
||||||
import { RectHelper } from './helpers/rect-helper.js';
|
import { RectHelper } from './helpers/rect-helper.js';
|
||||||
import { SelectionHelper } from './helpers/selection-helper.js';
|
import { SelectionHelper } from './helpers/selection-helper.js';
|
||||||
import { styles } from './styles.js';
|
import { styles } from './styles.js';
|
||||||
import {
|
import {
|
||||||
calcDropTarget,
|
|
||||||
containBlock,
|
containBlock,
|
||||||
containChildBlock,
|
containChildBlock,
|
||||||
getClosestBlockByPoint,
|
getClosestBlockByPoint,
|
||||||
@@ -107,9 +105,6 @@ export class AffineDragHandleWidget extends WidgetComponent<RootBlockModel> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let rect = null;
|
|
||||||
let dropType: DropType = 'before';
|
|
||||||
|
|
||||||
const result = calcDropTarget(
|
const result = calcDropTarget(
|
||||||
point,
|
point,
|
||||||
model,
|
model,
|
||||||
@@ -119,20 +114,9 @@ export class AffineDragHandleWidget extends WidgetComponent<RootBlockModel> {
|
|||||||
isDraggedElementNote === false
|
isDraggedElementNote === false
|
||||||
);
|
);
|
||||||
|
|
||||||
if (result) {
|
if (isDraggedElementNote && result?.type === 'in') return null;
|
||||||
rect = result.rect;
|
|
||||||
dropType = result.dropType;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDraggedElementNote && dropType === 'in') return null;
|
return result;
|
||||||
|
|
||||||
const dropIndicator = {
|
|
||||||
rect,
|
|
||||||
dropBlockId: blockId,
|
|
||||||
dropType,
|
|
||||||
};
|
|
||||||
|
|
||||||
return dropIndicator;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly _handleEventWatcher = new HandleEventWatcher(this);
|
private readonly _handleEventWatcher = new HandleEventWatcher(this);
|
||||||
@@ -181,8 +165,8 @@ export class AffineDragHandleWidget extends WidgetComponent<RootBlockModel> {
|
|||||||
|
|
||||||
private readonly _updateDropResult = (dropResult: DropResult | null) => {
|
private readonly _updateDropResult = (dropResult: DropResult | null) => {
|
||||||
if (!this.dropIndicator) return;
|
if (!this.dropIndicator) return;
|
||||||
this.dropBlockId = dropResult?.dropBlockId ?? '';
|
this.dropBlockId = dropResult?.modelState.model.id ?? '';
|
||||||
this.dropType = dropResult?.dropType ?? null;
|
this.dropType = dropResult?.type ?? null;
|
||||||
if (dropResult?.rect) {
|
if (dropResult?.rect) {
|
||||||
const offsetParentRect =
|
const offsetParentRect =
|
||||||
this.dragHandleContainerOffsetParent.getBoundingClientRect();
|
this.dragHandleContainerOffsetParent.getBoundingClientRect();
|
||||||
@@ -237,7 +221,7 @@ export class AffineDragHandleWidget extends WidgetComponent<RootBlockModel> {
|
|||||||
|
|
||||||
dropIndicator: DropIndicator | null = null;
|
dropIndicator: DropIndicator | null = null;
|
||||||
|
|
||||||
dropType: DropType | null = null;
|
dropType: DroppingType | null = null;
|
||||||
|
|
||||||
edgelessWatcher = new EdgelessWatcher(this);
|
edgelessWatcher = new EdgelessWatcher(this);
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,12 @@
|
|||||||
import { ParagraphBlockComponent } from '@blocksuite/affine-block-paragraph';
|
import { ParagraphBlockComponent } from '@blocksuite/affine-block-paragraph';
|
||||||
import type { ParagraphBlockModel } from '@blocksuite/affine-model';
|
import type { ParagraphBlockModel } from '@blocksuite/affine-model';
|
||||||
import { BLOCK_CHILDREN_CONTAINER_PADDING_LEFT } from '@blocksuite/affine-shared/consts';
|
import { DocModeProvider } from '@blocksuite/affine-shared/services';
|
||||||
import {
|
|
||||||
DocModeProvider,
|
|
||||||
type DropType,
|
|
||||||
} from '@blocksuite/affine-shared/services';
|
|
||||||
import {
|
import {
|
||||||
|
calcDropTarget,
|
||||||
|
type DropResult,
|
||||||
findClosestBlockComponent,
|
findClosestBlockComponent,
|
||||||
getBlockProps,
|
getBlockProps,
|
||||||
getClosestBlockComponentByElement,
|
|
||||||
getClosestBlockComponentByPoint,
|
getClosestBlockComponentByPoint,
|
||||||
getDropRectByPoint,
|
|
||||||
getRectByBlockComponent,
|
|
||||||
matchFlavours,
|
matchFlavours,
|
||||||
} from '@blocksuite/affine-shared/utils';
|
} from '@blocksuite/affine-shared/utils';
|
||||||
import type {
|
import type {
|
||||||
@@ -26,7 +21,6 @@ import {
|
|||||||
DRAG_HANDLE_CONTAINER_HEIGHT,
|
DRAG_HANDLE_CONTAINER_HEIGHT,
|
||||||
DRAG_HANDLE_CONTAINER_OFFSET_LEFT,
|
DRAG_HANDLE_CONTAINER_OFFSET_LEFT,
|
||||||
DRAG_HANDLE_CONTAINER_OFFSET_LEFT_LIST,
|
DRAG_HANDLE_CONTAINER_OFFSET_LEFT_LIST,
|
||||||
type DropResult,
|
|
||||||
EDGELESS_NOTE_EXTRA_PADDING,
|
EDGELESS_NOTE_EXTRA_PADDING,
|
||||||
NOTE_CONTAINER_PADDING,
|
NOTE_CONTAINER_PADDING,
|
||||||
} from './config.js';
|
} from './config.js';
|
||||||
@@ -181,116 +175,6 @@ export const getClosestBlockByPoint = (
|
|||||||
return closestBlock;
|
return closestBlock;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function calcDropTarget(
|
|
||||||
point: Point,
|
|
||||||
model: BlockModel,
|
|
||||||
element: Element,
|
|
||||||
draggingElements: BlockComponent[],
|
|
||||||
scale: number,
|
|
||||||
/**
|
|
||||||
* Allow the dragging block to be dropped as sublist
|
|
||||||
*/
|
|
||||||
allowSublist: boolean = true
|
|
||||||
): DropResult | null {
|
|
||||||
let type: DropType | 'none' = 'none';
|
|
||||||
const height = 3 * scale;
|
|
||||||
const dropRect = getDropRectByPoint(point, model, element);
|
|
||||||
if (!dropRect) return null;
|
|
||||||
const { rect: domRect } = dropRect;
|
|
||||||
|
|
||||||
const distanceToTop = Math.abs(domRect.top - point.y);
|
|
||||||
const distanceToBottom = Math.abs(domRect.bottom - point.y);
|
|
||||||
const before = distanceToTop < distanceToBottom;
|
|
||||||
|
|
||||||
type = before ? 'before' : 'after';
|
|
||||||
let offsetY = 4;
|
|
||||||
|
|
||||||
if (type === 'before') {
|
|
||||||
// before
|
|
||||||
let prev;
|
|
||||||
let prevRect;
|
|
||||||
|
|
||||||
prev = element.previousElementSibling;
|
|
||||||
if (prev) {
|
|
||||||
if (
|
|
||||||
draggingElements.length &&
|
|
||||||
prev === draggingElements[draggingElements.length - 1]
|
|
||||||
) {
|
|
||||||
type = 'none';
|
|
||||||
} else {
|
|
||||||
prevRect = getRectByBlockComponent(prev);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
prev = element.parentElement?.previousElementSibling;
|
|
||||||
if (prev) {
|
|
||||||
prevRect = prev.getBoundingClientRect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prevRect) {
|
|
||||||
offsetY = (domRect.top - prevRect.bottom) / 2;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Only consider drop as children when target block is list block.
|
|
||||||
// To drop in, the position must after the target first
|
|
||||||
// If drop in target has children, we can use insert before or after of that children
|
|
||||||
// to achieve the same effect.
|
|
||||||
const hasChild = (element as BlockComponent).childBlocks.length;
|
|
||||||
if (
|
|
||||||
allowSublist &&
|
|
||||||
matchFlavours(model, ['affine:list']) &&
|
|
||||||
!hasChild &&
|
|
||||||
point.x > domRect.x + BLOCK_CHILDREN_CONTAINER_PADDING_LEFT
|
|
||||||
) {
|
|
||||||
type = 'in';
|
|
||||||
}
|
|
||||||
// after
|
|
||||||
let next;
|
|
||||||
let nextRect;
|
|
||||||
|
|
||||||
next = element.nextElementSibling;
|
|
||||||
if (next) {
|
|
||||||
if (
|
|
||||||
type === 'after' &&
|
|
||||||
draggingElements.length &&
|
|
||||||
next === draggingElements[0]
|
|
||||||
) {
|
|
||||||
type = 'none';
|
|
||||||
next = null;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
next = getClosestBlockComponentByElement(
|
|
||||||
element.parentElement
|
|
||||||
)?.nextElementSibling;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (next) {
|
|
||||||
nextRect = getRectByBlockComponent(next);
|
|
||||||
offsetY = (nextRect.top - domRect.bottom) / 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type === 'none') return null;
|
|
||||||
|
|
||||||
let top = domRect.top;
|
|
||||||
if (type === 'before') {
|
|
||||||
top -= offsetY;
|
|
||||||
} else {
|
|
||||||
top += domRect.height + offsetY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type === 'in') {
|
|
||||||
domRect.x += BLOCK_CHILDREN_CONTAINER_PADDING_LEFT;
|
|
||||||
domRect.width -= BLOCK_CHILDREN_CONTAINER_PADDING_LEFT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
rect: Rect.fromLWTH(domRect.left, domRect.width, top - height / 2, height),
|
|
||||||
dropBlockId: model.id,
|
|
||||||
dropType: type,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getDropResult = (
|
export const getDropResult = (
|
||||||
event: MouseEvent,
|
event: MouseEvent,
|
||||||
scale: number = 1
|
scale: number = 1
|
||||||
|
|||||||
Reference in New Issue
Block a user