feat: grid optimise

This commit is contained in:
SaikaSakura
2022-08-02 16:57:00 +08:00
parent b71dc4a04a
commit 3722dde811
4 changed files with 131 additions and 41 deletions

View File

@@ -12,6 +12,8 @@ type GridHandleProps = {
blockId: string; blockId: string;
enabledAddItem: boolean; enabledAddItem: boolean;
draggable: boolean; draggable: boolean;
alertHandleId: string;
onMouseEnter?: React.MouseEventHandler<HTMLDivElement>;
}; };
export const GridHandle: FC<GridHandleProps> = function ({ export const GridHandle: FC<GridHandleProps> = function ({
@@ -21,6 +23,8 @@ export const GridHandle: FC<GridHandleProps> = function ({
onDrag, onDrag,
onMouseDown, onMouseDown,
draggable, draggable,
alertHandleId,
onMouseEnter,
}) { }) {
const [isMouseDown, setIsMouseDown] = useState<boolean>(false); const [isMouseDown, setIsMouseDown] = useState<boolean>(false);
const handleMouseDown: React.MouseEventHandler<HTMLDivElement> = e => { const handleMouseDown: React.MouseEventHandler<HTMLDivElement> = e => {
@@ -44,16 +48,17 @@ export const GridHandle: FC<GridHandleProps> = function ({
editor.selectionManager.setActivatedNodeId(textBlock.id); editor.selectionManager.setActivatedNodeId(textBlock.id);
} }
}; };
const handleMouseEnter: React.MouseEventHandler<HTMLDivElement> = e => {
onMouseEnter && onMouseEnter(e);
};
return ( return (
<GridHandleContainer <GridHandleContainer
style={ isMouseDown={isMouseDown}
isMouseDown
? {
backgroundColor: '#3E6FDB',
}
: {}
}
onMouseDown={handleMouseDown} onMouseDown={handleMouseDown}
onMouseEnter={handleMouseEnter}
isAlert={alertHandleId === blockId}
> >
{enabledAddItem ? ( {enabledAddItem ? (
<AddGridHandle <AddGridHandle
@@ -67,7 +72,10 @@ export const GridHandle: FC<GridHandleProps> = function ({
); );
}; };
const GridHandleContainer = styled('div')(({ theme }) => ({ const GridHandleContainer = styled('div')<{
isMouseDown: boolean;
isAlert: boolean;
}>(({ theme, isMouseDown, isAlert }) => ({
position: 'relative', position: 'relative',
width: '10px', width: '10px',
flexGrow: '0', flexGrow: '0',
@@ -78,11 +86,17 @@ const GridHandleContainer = styled('div')(({ theme }) => ({
borderRadius: '1px', borderRadius: '1px',
backgroundClip: 'content-box', backgroundClip: 'content-box',
' &:hover': { ' &:hover': {
backgroundColor: theme.affine.palette.primary, backgroundColor: isAlert
? 'red !important'
: theme.affine.palette.primary,
[`.${GRID_ADD_HANDLE_NAME}`]: { [`.${GRID_ADD_HANDLE_NAME}`]: {
display: 'block', display: 'block',
}, },
}, },
...(isMouseDown &&
(isAlert
? { backgroundColor: 'red' }
: { backgroundColor: theme.affine.palette.primary })),
})); }));
const AddGridHandle = styled('div')(({ theme }) => ({ const AddGridHandle = styled('div')(({ theme }) => ({

View File

@@ -31,6 +31,7 @@ export const Grid: FC<CreateView> = function (props) {
const gridItemCountRef = useRef<number>(); const gridItemCountRef = useRef<number>();
const originalLeftWidth = useRef<number>(GRID_ITEM_MIN_WIDTH); const originalLeftWidth = useRef<number>(GRID_ITEM_MIN_WIDTH);
const originalRightWidth = useRef<number>(GRID_ITEM_MIN_WIDTH); const originalRightWidth = useRef<number>(GRID_ITEM_MIN_WIDTH);
const [alertHandleId, setAlertHandleId] = useState<string>(null);
const getLeftRightGridItemDomByIndex = (index: number) => { const getLeftRightGridItemDomByIndex = (index: number) => {
const gridItems = Array.from(gridContainerRef.current?.children).filter( const gridItems = Array.from(gridContainerRef.current?.children).filter(
@@ -117,7 +118,7 @@ export const Grid: FC<CreateView> = function (props) {
itemDom.style.width = width; itemDom.style.width = width;
}; };
const handleDragGrid = (e: MouseEvent, index: number) => { const handleDragGrid = async (e: MouseEvent, index: number) => {
setIsOnDrag(true); setIsOnDrag(true);
window.getSelection().removeAllRanges(); window.getSelection().removeAllRanges();
if (!isSetMouseUp.current) { if (!isSetMouseUp.current) {
@@ -165,39 +166,47 @@ export const Grid: FC<CreateView> = function (props) {
setItemWidth(leftGrid, newLeft); setItemWidth(leftGrid, newLeft);
setItemWidth(rightGrid, newRight); setItemWidth(rightGrid, newRight);
updateDbWidth(leftBlockId, newLeft, rightBlockId, newRight); updateDbWidth(leftBlockId, newLeft, rightBlockId, newRight);
[leftBlockId, rightBlockId].forEach(async blockId => {
if (await checkGridItemHasOverflow(blockId)) {
setAlertHandleId(leftBlockId);
} else {
setAlertHandleId(null);
}
});
} }
} }
}; };
const children = ( const checkGridItemHasOverflow = async (blockId: string) => {
<> let isOverflow = false;
{block.childrenIds.map((id, i) => { const block = await editor.getBlockById(blockId);
return ( if (block) {
<GridItem const blockDom = block.dom;
style={{ if (blockDom) {
transition: isOnDrag block.dom.style.overflow = 'scroll';
? 'none' if (block.dom.clientWidth !== block.dom.scrollWidth) {
: 'all 0.2s ease-in-out', isOverflow = true;
}} }
key={id} blockDom.style.overflow = 'visible';
className={GRID_ITEM_CLASS_NAME} }
> }
<RenderBlock hasContainer={false} blockId={id} /> return isOverflow;
<GridHandle };
onDrag={event => handleDragGrid(event, i)}
editor={editor} const handleHandleMouseEnter = (
onMouseDown={event => handleMouseDown(event, i)} e: React.MouseEvent<HTMLDivElement>,
blockId={id} index: number
enabledAddItem={ ) => {
block.childrenIds.length < MAX_ITEM_COUNT const leftBlockId = block.childrenIds[index];
} const rightBlockId = block.childrenIds[index + 1];
draggable={i !== block.childrenIds.length - 1} [leftBlockId, rightBlockId].forEach(async blockId => {
/> if (await checkGridItemHasOverflow(blockId)) {
</GridItem> setAlertHandleId(leftBlockId);
); } else {
})} setAlertHandleId(null);
</> }
); });
};
return ( return (
<> <>
@@ -206,7 +215,35 @@ export const Grid: FC<CreateView> = function (props) {
ref={gridContainerRef} ref={gridContainerRef}
isOnDrag={isOnDrag} isOnDrag={isOnDrag}
> >
{children} {block.childrenIds.map((id, i) => {
return (
<GridItem
style={{
transition: isOnDrag
? 'none'
: 'all 0.2s ease-in-out',
}}
key={id}
className={GRID_ITEM_CLASS_NAME}
>
<RenderBlock hasContainer={false} blockId={id} />
<GridHandle
onDrag={event => handleDragGrid(event, i)}
editor={editor}
onMouseDown={event => handleMouseDown(event, i)}
blockId={id}
enabledAddItem={
block.childrenIds.length < MAX_ITEM_COUNT
}
onMouseEnter={event =>
handleHandleMouseEnter(event, i)
}
alertHandleId={alertHandleId}
draggable={i !== block.childrenIds.length - 1}
/>
</GridItem>
);
})}
</GridContainer> </GridContainer>
{isOnDrag {isOnDrag
? ReactDOM.createPortal(<GridMask />, window.document.body) ? ReactDOM.createPortal(<GridMask />, window.document.body)

View File

@@ -12,6 +12,7 @@ enum DragType {
} }
const DRAG_STATE_CHANGE_EVENT_KEY = 'dragStateChange'; const DRAG_STATE_CHANGE_EVENT_KEY = 'dragStateChange';
const MAX_GRID_BLOCK_FLOOR = 3;
export class DragDropManager { export class DragDropManager {
private _editor: Editor; private _editor: Editor;
private _enabled: boolean; private _enabled: boolean;
@@ -231,6 +232,17 @@ export class DragDropManager {
if (!(await this._canBeDrop(event))) { if (!(await this._canBeDrop(event))) {
direction = BlockDropPlacement.none; direction = BlockDropPlacement.none;
} }
if (
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
if (gridBlocks.length >= MAX_GRID_BLOCK_FLOOR) {
direction = BlockDropPlacement.none;
}
}
this._setBlockDragDirection(direction); this._setBlockDragDirection(direction);
return direction; return direction;
} }

View File

@@ -340,7 +340,20 @@ export class Editor implements Virgo {
const rootBlockId = this.getRootBlockId(); const rootBlockId = this.getRootBlockId();
const rootBlock = await this.getBlockById(rootBlockId); const rootBlock = await this.getBlockById(rootBlockId);
const blockList: Array<AsyncBlock> = rootBlock ? [rootBlock] : []; const blockList: Array<AsyncBlock> = rootBlock ? [rootBlock] : [];
const children = (await rootBlock?.children()) || []; return [...blockList, ...(await this.getOffspring(rootBlockId))];
}
/**
*
* get all offspring of block
* @param {string} id
* @return {*}
* @memberof Editor
*/
async getOffspring(id: string) {
const block = await this.getBlockById(id);
const blockList: Array<AsyncBlock> = [];
const children = (await block?.children()) || [];
for (const block of children) { for (const block of children) {
if (!block) { if (!block) {
continue; continue;
@@ -379,6 +392,20 @@ export class Editor implements Virgo {
return lastBlock; return lastBlock;
} }
async getBlockPath(id: string) {
const block = await this.getBlockById(id);
if (!block) {
return [];
}
const path = [block];
let parent = await block.parent();
while (parent) {
path.unshift(parent);
parent = await parent.parent();
}
return path;
}
async getBlockByPoint(point: Point) { async getBlockByPoint(point: Point) {
const blockList = await this.getBlockList(); const blockList = await this.getBlockList();