feat: outer drag 、fix new page selection

This commit is contained in:
SaikaSakura
2022-08-05 19:29:26 +08:00
parent 812af254aa
commit 5c51457761
16 changed files with 358 additions and 72 deletions

View File

@@ -187,7 +187,6 @@ export const SelectionRect = forwardRef<SelectionRef, SelectionProps>(
)
)
);
const scrollDirections = getScrollDirections(
endPointRef.current,
scrollManager.verticalScrollTriggerDistance,
@@ -204,6 +203,7 @@ export const SelectionRect = forwardRef<SelectionRef, SelectionProps>(
mouseType.current = 'up';
startPointBlock.current = null;
setShow(false);
setRect(Rect.fromLTRB(0, 0, 0, 0));
scrollManager.stopAutoScroll();
};

View File

@@ -159,6 +159,33 @@ export class BlockCommands {
return [];
}
public async moveInNewGridItem(
blockId: string,
gridItemId: string,
isBefore = false
) {
const block = await this._editor.getBlockById(blockId);
if (block) {
const gridItemBlock = await this._editor.createBlock(
Protocol.Block.Type.gridItem
);
const targetGridItemBlock = await this._editor.getBlockById(
gridItemId
);
await block.remove();
await gridItemBlock.append(block);
if (targetGridItemBlock && gridItemBlock) {
if (isBefore) {
await targetGridItemBlock.before(gridItemBlock);
} else {
await targetGridItemBlock.after(gridItemBlock);
}
}
return gridItemBlock;
}
return undefined;
}
public async splitGroupFromBlock(blockId: string) {
const block = await this._editor.getBlockById(blockId);
await splitGroup(this._editor, block);

View File

@@ -0,0 +1,27 @@
import { BlockEditor } from '../..';
/**
*
* the global config for the editor
* @class GridConfig
*/
export class GridConfig {
private _maxGridItemCount = 6;
private _editor: BlockEditor;
constructor(editor: BlockEditor) {
this._editor = editor;
}
get maxGridItemCount() {
return this._maxGridItemCount;
}
set maxGridItemCount(value) {
this._maxGridItemCount = value;
}
get gridItemMinWidth() {
return 100 / this.maxGridItemCount;
}
}

View File

@@ -0,0 +1,23 @@
import { BlockEditor } from '../..';
import { GridConfig } from './grid';
// TODO: if config be complex, add children config abstract
/**
*
* the global config for the editor
* @class EditorConfig
*/
export class EditorConfig {
private _maxGridItemCount = 6;
private _editor: BlockEditor;
private _grid: GridConfig;
constructor(editor: BlockEditor) {
this._editor = editor;
this._grid = new GridConfig(editor);
}
get grid() {
return this._grid;
}
}

View File

@@ -1,3 +1,4 @@
/* eslint-disable max-lines */
import { domToRect, Point } from '@toeverything/utils';
import { AsyncBlock } from '../..';
import { GridDropType } from '../commands/types';
@@ -5,6 +6,7 @@ import { Editor } from '../editor';
import { BlockDropPlacement, GroupDirection } from '../types';
// TODO: Evaluate implementing custom events with Rxjs
import EventEmitter from 'eventemitter3';
import { Protocol } from '@toeverything/datasource/db-service';
enum DragType {
dragBlock = 'dragBlock',
@@ -86,6 +88,7 @@ export class DragDropManager {
while (curr !== this._editor.getRootBlockId()) {
if (curr === blockId) return false;
const block = await this._editor.getBlockById(curr);
if (!block) return false;
curr = block.parentId;
}
return true;
@@ -114,6 +117,48 @@ export class DragDropManager {
: GridDropType.right
);
}
if (
[
BlockDropPlacement.outerLeft,
BlockDropPlacement.outerRight,
].includes(this._blockDragDirection)
) {
const targetBlock = await this._editor.getBlockById(
this._blockDragTargetId
);
if (targetBlock.type !== Protocol.Block.Type.grid) {
await this._editor.commands.blockCommands.createLayoutBlock(
blockId,
this._blockDragTargetId,
this._blockDragDirection ===
BlockDropPlacement.outerLeft
? GridDropType.left
: GridDropType.right
);
}
if (targetBlock.type === Protocol.Block.Type.grid) {
const gridItems = await targetBlock.children();
if (
BlockDropPlacement.outerRight ===
this._blockDragDirection
) {
await this._editor.commands.blockCommands.moveInNewGridItem(
blockId,
gridItems[gridItems.length - 1].id
);
}
if (
BlockDropPlacement.outerLeft ===
this._blockDragDirection
) {
await this._editor.commands.blockCommands.moveInNewGridItem(
blockId,
gridItems[0].id,
true
);
}
}
}
}
}
@@ -209,6 +254,93 @@ export class DragDropManager {
);
}
/**
*
* check if drag block is out of blocks and return direction
* @param {React.DragEvent<Element>} event
* @return {
* direction: BlockDropPlacement.none, // none, outerLeft, outerRight
* block: undefined, // the block in the same clientY
* isOuter: false, // if is drag over outer
* }
*
* @memberof DragDropManager
*/
public async checkOuterBlockDragTypes(event: React.DragEvent<Element>) {
const { clientX, clientY } = event;
const mousePoint = new Point(clientX, clientY);
const rootBlock = await this._editor.getBlockById(
this._editor.getRootBlockId()
);
let direction = BlockDropPlacement.none;
const rootBlockRect = domToRect(rootBlock.dom);
let targetBlock: AsyncBlock | undefined;
let typesInfo = {
direction: BlockDropPlacement.none,
block: undefined,
isOuter: false,
} as {
direction: BlockDropPlacement;
block: AsyncBlock | undefined;
isOuter: boolean;
};
if (rootBlockRect.isPointLeft(mousePoint)) {
direction = BlockDropPlacement.outerLeft;
typesInfo.isOuter = true;
}
if (rootBlockRect.isPointRight(mousePoint)) {
direction = BlockDropPlacement.outerRight;
typesInfo.isOuter = true;
}
if (direction !== BlockDropPlacement.none) {
const blockList = await this._editor.getBlockListByLevelOrder();
targetBlock = blockList.find(block => {
const domRect = domToRect(block.dom);
const pointChecker =
direction === BlockDropPlacement.outerLeft
? domRect.isPointLeft.bind(domRect)
: domRect.isPointRight.bind(domRect);
return (
block.type !== Protocol.Block.Type.page &&
block.type !== Protocol.Block.Type.group &&
pointChecker(mousePoint)
);
});
if (targetBlock) {
if (targetBlock.type !== Protocol.Block.Type.grid) {
this._setBlockDragDirection(direction);
this._setBlockDragTargetId(targetBlock.id);
typesInfo = {
direction,
block: targetBlock,
isOuter: true,
};
}
if (targetBlock.type === Protocol.Block.Type.grid) {
const children = await targetBlock.children();
if (
children.length <
this._editor.configManager.grid.maxGridItemCount
) {
typesInfo = {
direction,
block: targetBlock,
isOuter: true,
};
}
}
}
}
if (
typesInfo.direction !== BlockDropPlacement.none &&
typesInfo.block
) {
this._setBlockDragTargetId(targetBlock.id);
}
this._setBlockDragDirection(typesInfo.direction);
return typesInfo;
}
public async checkBlockDragTypes(
event: React.DragEvent<Element>,
blockDom: HTMLElement,
@@ -216,10 +348,25 @@ export class DragDropManager {
) {
const { clientX, clientY } = event;
this._setBlockDragTargetId(blockId);
const path = await this._editor.getBlockPath(blockId);
const mousePoint = new Point(clientX, clientY);
const rect = domToRect(blockDom);
/**
* IMP: compute the level of the target block
* future feature drag drop has level support do not delete
* const levelUnderGrid = Array.from(path)
.reverse()
.findIndex(block => block.type === Protocol.Block.Type.gridItem);
const levelUnderGroup = Array.from(path)
.reverse()
.findIndex(block => block.type === Protocol.Block.Type.group);
const blockLevel =
levelUnderGrid > 0 ? levelUnderGrid : levelUnderGroup;
console.log({ blockLevel, levelUnderGrid, levelUnderGroup });
*
*/
let direction = BlockDropPlacement.bottom;
if (mousePoint.x - rect.left <= this._dragBlockHotDistance) {
direction = BlockDropPlacement.left;
}
@@ -236,9 +383,10 @@ export class DragDropManager {
direction === BlockDropPlacement.left ||
direction === BlockDropPlacement.right
) {
const path = await this._editor.getBlockPath(blockId);
const gridBlocks = path.filter(block => block.type === 'grid');
// limit grid block floor counts
const gridBlocks = path.filter(
block => block.type === Protocol.Block.Type.grid
);
// limit grid block floor counts, when drag block to init grid
if (gridBlocks.length >= MAX_GRID_BLOCK_FLOOR) {
direction = BlockDropPlacement.none;
}

View File

@@ -3,6 +3,8 @@ export enum BlockDropPlacement {
right = 'right',
top = 'top',
bottom = 'bottom',
outerLeft = 'outer-left',
outerRight = 'outer-right',
none = 'none',
}

View File

@@ -35,6 +35,7 @@ import { BrowserClipboard } from './clipboard/browser-clipboard';
import { ClipboardPopulator } from './clipboard/clipboard-populator';
import { BlockHelper } from './block/block-helper';
import { DragDropManager } from './drag-drop';
import { EditorConfig } from './config';
export interface EditorCtorProps {
workspace: string;
@@ -56,6 +57,7 @@ export class Editor implements Virgo {
public dragDropManager = new DragDropManager(this);
public commands = new EditorCommands(this);
public blockHelper = new BlockHelper(this);
public configManager = new EditorConfig(this);
public bdCommands: Commands;
public ui_container?: HTMLDivElement;
public version = '0.0.1';
@@ -343,6 +345,23 @@ export class Editor implements Virgo {
return [...blockList, ...(await this.getOffspring(rootBlockId))];
}
async getBlockListByLevelOrder() {
const rootBlockId = this.getRootBlockId();
const rootBlock = await this.getBlockById(rootBlockId);
const blockList: Array<AsyncBlock> = [];
let nextToVisit: Array<AsyncBlock> = rootBlock ? [rootBlock] : [];
while (nextToVisit.length) {
let next: Array<AsyncBlock> = [];
for (const block of nextToVisit) {
const children = await block.children();
blockList.push(block);
next = next.concat(children);
}
nextToVisit = next;
}
return blockList;
}
/**
*
* get all offspring of block

View File

@@ -110,7 +110,6 @@ export class ScrollManager {
}
public emitScrollEvent(event: UIEvent) {
this.scrollContainer = event.target as HTMLElement;
this._scrollDirection = this._getScrollDirection();
this._scrollMoveOffset = Math.abs(
this.scrollContainer.scrollTop - this._scrollRecord[0]

View File

@@ -73,6 +73,7 @@ export interface Virgo {
getBlockById(blockId: string): Promise<AsyncBlock | null>;
setHotKeysScope(scope?: string): void;
getBlockList: () => Promise<AsyncBlock[]>;
getBlockListByLevelOrder: () => Promise<AsyncBlock[]>;
// removeBlocks: () => void;
storageManager: StorageManager | undefined;
selection: VirgoSelection;