mirror of
https://github.com/toeverything/AFFiNE.git
synced 2024-12-23 00:11:33 +03:00
Merge pull request #279 from toeverything/refactor/clean
Refactor/clean
This commit is contained in:
commit
91fa616942
@ -14,7 +14,7 @@ import { CreateView } from '@toeverything/framework/virgo';
|
|||||||
import { BlockContainer } from '../../components/BlockContainer';
|
import { BlockContainer } from '../../components/BlockContainer';
|
||||||
import { IndentWrapper } from '../../components/IndentWrapper';
|
import { IndentWrapper } from '../../components/IndentWrapper';
|
||||||
import { TextManage } from '../../components/text-manage';
|
import { TextManage } from '../../components/text-manage';
|
||||||
import { tabBlock } from '../../utils/indent';
|
import { dedentBlock, tabBlock } from '../../utils/indent';
|
||||||
interface CreateTextView extends CreateView {
|
interface CreateTextView extends CreateView {
|
||||||
// TODO: need to optimize
|
// TODO: need to optimize
|
||||||
containerClassName?: string;
|
containerClassName?: string;
|
||||||
@ -115,7 +115,19 @@ export const TextView = ({
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const preParent = await parentBlock.previousSibling();
|
// The parent block is group block or is the root block.
|
||||||
|
// Merge block to previous sibling.
|
||||||
|
//
|
||||||
|
// - group/root <- parent block
|
||||||
|
// - text1 <- preNode
|
||||||
|
// - text2 <- press backspace before target block
|
||||||
|
// - children
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
//
|
||||||
|
// - group/root
|
||||||
|
// - text1text2 <- merge block to previous sibling
|
||||||
|
// - children <- children should switch parent block
|
||||||
if (
|
if (
|
||||||
Protocol.Block.Type.group === parentBlock.type ||
|
Protocol.Block.Type.group === parentBlock.type ||
|
||||||
editor.getRootBlockId() === parentBlock.id
|
editor.getRootBlockId() === parentBlock.id
|
||||||
@ -130,10 +142,7 @@ export const TextView = ({
|
|||||||
block.id,
|
block.id,
|
||||||
'end'
|
'end'
|
||||||
);
|
);
|
||||||
if (
|
if (!block.blockProvider?.isEmpty()) {
|
||||||
block.getProperty('text').value[0] &&
|
|
||||||
block.getProperty('text').value[0]?.text !== ''
|
|
||||||
) {
|
|
||||||
const value = [
|
const value = [
|
||||||
...preNode.getProperty('text').value,
|
...preNode.getProperty('text').value,
|
||||||
...block.getProperty('text').value,
|
...block.getProperty('text').value,
|
||||||
@ -145,12 +154,13 @@ export const TextView = ({
|
|||||||
await preNode.append(...children);
|
await preNode.append(...children);
|
||||||
await block.remove();
|
await block.remove();
|
||||||
} else {
|
} else {
|
||||||
|
// If not pre node, block should be merged to the parent block
|
||||||
// TODO: point does not clear
|
// TODO: point does not clear
|
||||||
await editor.selectionManager.activePreviousNode(
|
await editor.selectionManager.activePreviousNode(
|
||||||
block.id,
|
block.id,
|
||||||
'start'
|
'start'
|
||||||
);
|
);
|
||||||
if (block.blockProvider.isEmpty()) {
|
if (block.blockProvider?.isEmpty()) {
|
||||||
await block.remove();
|
await block.remove();
|
||||||
const parentChild = await parentBlock.children();
|
const parentChild = await parentBlock.children();
|
||||||
if (
|
if (
|
||||||
@ -158,6 +168,8 @@ export const TextView = ({
|
|||||||
Protocol.Block.Type.group &&
|
Protocol.Block.Type.group &&
|
||||||
!parentChild.length
|
!parentChild.length
|
||||||
) {
|
) {
|
||||||
|
const preParent =
|
||||||
|
await parentBlock.previousSibling();
|
||||||
await editor.selectionManager.setSelectedNodesIds(
|
await editor.selectionManager.setSelectedNodesIds(
|
||||||
[preParent?.id ?? editor.getRootBlockId()]
|
[preParent?.id ?? editor.getRootBlockId()]
|
||||||
);
|
);
|
||||||
@ -198,17 +210,9 @@ export const TextView = ({
|
|||||||
await parentBlock.remove();
|
await parentBlock.remove();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else {
|
|
||||||
const nextNodes = await block.nextSiblings();
|
|
||||||
for (const nextNode of nextNodes) {
|
|
||||||
await nextNode.remove();
|
|
||||||
}
|
|
||||||
block.append(...nextNodes);
|
|
||||||
editor.commands.blockCommands.moveBlockAfter(
|
|
||||||
block.id,
|
|
||||||
parentBlock.id
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dedentBlock(editor, block);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import {
|
import {
|
||||||
type BlockEditor,
|
|
||||||
supportChildren,
|
supportChildren,
|
||||||
|
type BlockEditor,
|
||||||
} from '@toeverything/components/editor-core';
|
} from '@toeverything/components/editor-core';
|
||||||
import { Protocol } from '@toeverything/datasource/db-service';
|
import { Protocol } from '@toeverything/datasource/db-service';
|
||||||
import { AsyncBlock } from '@toeverything/framework/virgo';
|
import { AsyncBlock } from '@toeverything/framework/virgo';
|
||||||
@ -81,7 +81,7 @@ const indentBlock = async (block: TodoAsyncBlock) => {
|
|||||||
* └─ [ ]
|
* └─ [ ]
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
const dedentBlock = async (editor: BlockEditor, block: AsyncBlock) => {
|
export const dedentBlock = async (editor: BlockEditor, block: AsyncBlock) => {
|
||||||
if (editor.getRootBlockId() === block.id) {
|
if (editor.getRootBlockId() === block.id) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
/* eslint-disable max-lines */
|
/* eslint-disable max-lines */
|
||||||
|
import { Protocol } from '@toeverything/datasource/db-service';
|
||||||
import { domToRect, Point } from '@toeverything/utils';
|
import { domToRect, Point } from '@toeverything/utils';
|
||||||
import { AsyncBlock } from '../..';
|
import { AsyncBlock } from '../..';
|
||||||
import { GridDropType } from '../commands/types';
|
import { GridDropType } from '../commands/types';
|
||||||
@ -6,7 +7,6 @@ import { Editor } from '../editor';
|
|||||||
import { BlockDropPlacement, GroupDirection } from '../types';
|
import { BlockDropPlacement, GroupDirection } from '../types';
|
||||||
// TODO: Evaluate implementing custom events with Rxjs
|
// TODO: Evaluate implementing custom events with Rxjs
|
||||||
import EventEmitter from 'eventemitter3';
|
import EventEmitter from 'eventemitter3';
|
||||||
import { Protocol } from '@toeverything/datasource/db-service';
|
|
||||||
|
|
||||||
enum DragType {
|
enum DragType {
|
||||||
dragBlock = 'dragBlock',
|
dragBlock = 'dragBlock',
|
||||||
@ -281,6 +281,10 @@ export class DragDropManager {
|
|||||||
this._editor.getRootBlockId()
|
this._editor.getRootBlockId()
|
||||||
);
|
);
|
||||||
let direction = BlockDropPlacement.none;
|
let direction = BlockDropPlacement.none;
|
||||||
|
if (!rootBlock || !rootBlock.dom) {
|
||||||
|
console.warn('Can not find dom bind with block', rootBlock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const rootBlockRect = domToRect(rootBlock.dom);
|
const rootBlockRect = domToRect(rootBlock.dom);
|
||||||
let targetBlock: AsyncBlock | undefined;
|
let targetBlock: AsyncBlock | undefined;
|
||||||
let typesInfo = {
|
let typesInfo = {
|
||||||
@ -303,6 +307,10 @@ export class DragDropManager {
|
|||||||
if (direction !== BlockDropPlacement.none) {
|
if (direction !== BlockDropPlacement.none) {
|
||||||
const blockList = await this._editor.getBlockListByLevelOrder();
|
const blockList = await this._editor.getBlockListByLevelOrder();
|
||||||
targetBlock = blockList.find(block => {
|
targetBlock = blockList.find(block => {
|
||||||
|
if (!block.dom) {
|
||||||
|
console.warn('Can not find dom bind with block', block);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const domRect = domToRect(block.dom);
|
const domRect = domToRect(block.dom);
|
||||||
const pointChecker =
|
const pointChecker =
|
||||||
direction === BlockDropPlacement.outerLeft
|
direction === BlockDropPlacement.outerLeft
|
||||||
|
@ -1,15 +1,16 @@
|
|||||||
/* eslint-disable max-lines */
|
/* eslint-disable max-lines */
|
||||||
import {
|
import {
|
||||||
|
debounce,
|
||||||
domToRect,
|
domToRect,
|
||||||
|
getBlockIdByDom,
|
||||||
|
last,
|
||||||
Point,
|
Point,
|
||||||
Rect,
|
Rect,
|
||||||
last,
|
|
||||||
without,
|
without,
|
||||||
debounce,
|
|
||||||
getBlockIdByDom,
|
|
||||||
} from '@toeverything/utils';
|
} from '@toeverything/utils';
|
||||||
import EventEmitter from 'eventemitter3';
|
import EventEmitter from 'eventemitter3';
|
||||||
|
|
||||||
|
import { Protocol } from '@toeverything/datasource/db-service';
|
||||||
import { BlockEditor } from '../..';
|
import { BlockEditor } from '../..';
|
||||||
import { AsyncBlock } from '../block';
|
import { AsyncBlock } from '../block';
|
||||||
import { VirgoSelection } from '../types';
|
import { VirgoSelection } from '../types';
|
||||||
@ -18,19 +19,17 @@ import {
|
|||||||
changeEventName,
|
changeEventName,
|
||||||
CursorTypes,
|
CursorTypes,
|
||||||
IdList,
|
IdList,
|
||||||
|
SelectBlock,
|
||||||
selectEndEventName,
|
selectEndEventName,
|
||||||
SelectEventCallbackTypes,
|
SelectEventCallbackTypes,
|
||||||
SelectEventTypes,
|
SelectEventTypes,
|
||||||
|
SelectInfo,
|
||||||
SelectionSettings,
|
SelectionSettings,
|
||||||
SelectionSettingsMap,
|
SelectionSettingsMap,
|
||||||
SelectionTypes,
|
SelectionTypes,
|
||||||
SelectPosition,
|
SelectPosition,
|
||||||
SelectBlock,
|
|
||||||
SelectInfo,
|
|
||||||
} from './types';
|
} from './types';
|
||||||
import { isLikeBlockListIds } from './utils';
|
import { isLikeBlockListIds } from './utils';
|
||||||
import { Protocol } from '@toeverything/datasource/db-service';
|
|
||||||
import { Editor } from 'slate';
|
|
||||||
// IMP: maybe merge active and select into single function
|
// IMP: maybe merge active and select into single function
|
||||||
|
|
||||||
export type SelectionInfo = InstanceType<
|
export type SelectionInfo = InstanceType<
|
||||||
@ -336,12 +335,12 @@ export class SelectionManager implements VirgoSelection {
|
|||||||
});
|
});
|
||||||
for await (const childBlock of selectableChildren) {
|
for await (const childBlock of selectableChildren) {
|
||||||
const { dom } = childBlock;
|
const { dom } = childBlock;
|
||||||
if (dom && selectionRect.isIntersect(domToRect(dom))) {
|
|
||||||
selectedNodes.push(childBlock);
|
|
||||||
}
|
|
||||||
if (!dom) {
|
if (!dom) {
|
||||||
console.warn('can not find dom bind with block');
|
console.warn('can not find dom bind with block');
|
||||||
}
|
}
|
||||||
|
if (dom && selectionRect.isIntersect(domToRect(dom))) {
|
||||||
|
selectedNodes.push(childBlock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// if just only has one selected maybe select the children
|
// if just only has one selected maybe select the children
|
||||||
if (selectedNodes.length === 1) {
|
if (selectedNodes.length === 1) {
|
||||||
@ -1063,10 +1062,10 @@ export class SelectionManager implements VirgoSelection {
|
|||||||
index: number,
|
index: number,
|
||||||
blockId: string
|
blockId: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
let preRang = document.createRange();
|
const preRang = document.createRange();
|
||||||
preRang.setStart(nowRange.startContainer, index);
|
preRang.setStart(nowRange.startContainer, index);
|
||||||
preRang.setEnd(nowRange.endContainer, index);
|
preRang.setEnd(nowRange.endContainer, index);
|
||||||
let prePosition = preRang.getClientRects().item(0);
|
const prePosition = preRang.getClientRects().item(0);
|
||||||
this.activeNodeByNodeId(
|
this.activeNodeByNodeId(
|
||||||
blockId,
|
blockId,
|
||||||
new Point(prePosition.left, prePosition.bottom)
|
new Point(prePosition.left, prePosition.bottom)
|
||||||
|
@ -9,10 +9,10 @@ import {
|
|||||||
BlockDecoration,
|
BlockDecoration,
|
||||||
MapOperation,
|
MapOperation,
|
||||||
} from '@toeverything/datasource/jwt';
|
} from '@toeverything/datasource/jwt';
|
||||||
|
import { cloneDeep } from '@toeverything/utils';
|
||||||
import type { EventData } from '../block';
|
import type { EventData } from '../block';
|
||||||
import { AsyncBlock } from '../block';
|
import { AsyncBlock } from '../block';
|
||||||
import type { Editor } from '../editor';
|
import type { Editor } from '../editor';
|
||||||
import { cloneDeep } from '@toeverything/utils';
|
|
||||||
import { SelectBlock } from '../selection';
|
import { SelectBlock } from '../selection';
|
||||||
|
|
||||||
export interface CreateView {
|
export interface CreateView {
|
||||||
@ -114,7 +114,21 @@ export abstract class BaseView {
|
|||||||
// Whether the component is empty
|
// Whether the component is empty
|
||||||
isEmpty(block: AsyncBlock): boolean {
|
isEmpty(block: AsyncBlock): boolean {
|
||||||
const text = block.getProperty('text');
|
const text = block.getProperty('text');
|
||||||
return !text?.value?.[0]?.text;
|
const result = !text?.value?.[0]?.text;
|
||||||
|
|
||||||
|
// Assert that the text is really empty
|
||||||
|
if (
|
||||||
|
result &&
|
||||||
|
block.getProperty('text')?.value.some(content => content.text)
|
||||||
|
) {
|
||||||
|
console.warn(
|
||||||
|
'Assertion isEmpty error! The block has an empty start fragment, but it is not empty',
|
||||||
|
block
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Assert end
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
getSelProperties(block: AsyncBlock, selectInfo: any): DefaultColumnsValue {
|
getSelProperties(block: AsyncBlock, selectInfo: any): DefaultColumnsValue {
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
import { HookType, BlockDropPlacement } from '@toeverything/framework/virgo';
|
import { BlockDropPlacement, HookType } from '@toeverything/framework/virgo';
|
||||||
import { StrictMode } from 'react';
|
|
||||||
import { BasePlugin } from '../../base-plugin';
|
|
||||||
import { ignoreBlockTypes } from './menu-config';
|
|
||||||
import {
|
|
||||||
LineInfoSubject,
|
|
||||||
LeftMenuDraggable,
|
|
||||||
BlockDomInfo,
|
|
||||||
} from './LeftMenuDraggable';
|
|
||||||
import { PluginRenderRoot } from '../../utils';
|
|
||||||
import { Subject, throttleTime } from 'rxjs';
|
|
||||||
import { domToRect, last, Point } from '@toeverything/utils';
|
import { domToRect, last, Point } from '@toeverything/utils';
|
||||||
|
import { StrictMode } from 'react';
|
||||||
|
import { Subject, throttleTime } from 'rxjs';
|
||||||
|
import { BasePlugin } from '../../base-plugin';
|
||||||
|
import { PluginRenderRoot } from '../../utils';
|
||||||
|
import {
|
||||||
|
BlockDomInfo,
|
||||||
|
LeftMenuDraggable,
|
||||||
|
LineInfoSubject,
|
||||||
|
} from './LeftMenuDraggable';
|
||||||
|
import { ignoreBlockTypes } from './menu-config';
|
||||||
const DRAG_THROTTLE_DELAY = 60;
|
const DRAG_THROTTLE_DELAY = 60;
|
||||||
export class LeftMenuPlugin extends BasePlugin {
|
export class LeftMenuPlugin extends BasePlugin {
|
||||||
private _mousedown?: boolean;
|
private _mousedown?: boolean;
|
||||||
@ -111,6 +111,10 @@ export class LeftMenuPlugin extends BasePlugin {
|
|||||||
block.dom,
|
block.dom,
|
||||||
block.id
|
block.id
|
||||||
);
|
);
|
||||||
|
if (!targetBlock.dom) {
|
||||||
|
console.warn('Can not find dom bind with block', targetBlock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
this._lineInfo.next({
|
this._lineInfo.next({
|
||||||
direction,
|
direction,
|
||||||
blockInfo: {
|
blockInfo: {
|
||||||
|
@ -3,9 +3,7 @@ import type {
|
|||||||
MouseEventHandler,
|
MouseEventHandler,
|
||||||
PropsWithChildren,
|
PropsWithChildren,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { cx } from '../clsx';
|
|
||||||
import { styled } from '../styled';
|
import { styled } from '../styled';
|
||||||
import { buttonStatus } from './constants';
|
|
||||||
|
|
||||||
/* Temporary solution, needs to be adjusted */
|
/* Temporary solution, needs to be adjusted */
|
||||||
const SIZE_SMALL = 'small' as const;
|
const SIZE_SMALL = 'small' as const;
|
||||||
@ -29,13 +27,18 @@ const SIZE_CONFIG = {
|
|||||||
|
|
||||||
type SizeType = keyof typeof SIZE_CONFIG;
|
type SizeType = keyof typeof SIZE_CONFIG;
|
||||||
|
|
||||||
interface IconButtonProps {
|
type IconButtonContainerProps = {
|
||||||
|
size?: SizeType;
|
||||||
|
hoverColor?: string; // CSSProperties['backgroundColor'];
|
||||||
|
backgroundColor?: string; // CSSProperties['backgroundColor'];
|
||||||
|
disabled?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IconButtonProps extends IconButtonContainerProps {
|
||||||
onClick?: MouseEventHandler;
|
onClick?: MouseEventHandler;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
style?: CSSProperties;
|
style?: CSSProperties;
|
||||||
className?: string;
|
className?: string;
|
||||||
size?: SizeType;
|
|
||||||
hoverColor?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const IconButton = ({
|
export const IconButton = ({
|
||||||
@ -50,55 +53,40 @@ export const IconButton = ({
|
|||||||
{...props}
|
{...props}
|
||||||
onClick={disabled ? undefined : onClick}
|
onClick={disabled ? undefined : onClick}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
className={cx({ [buttonStatus.disabled]: disabled }, className)}
|
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const Container = styled('button')<{
|
const Container = styled('button')<IconButtonContainerProps>(
|
||||||
size?: SizeType;
|
({ theme, size = SIZE_MIDDLE, hoverColor, backgroundColor, disabled }) => {
|
||||||
hoverColor?: string;
|
const { iconSize, areaSize } = SIZE_CONFIG[size];
|
||||||
}>(({ theme, size = SIZE_MIDDLE, hoverColor }) => {
|
|
||||||
const { iconSize, areaSize } = SIZE_CONFIG[size];
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center',
|
|
||||||
width: areaSize,
|
|
||||||
height: areaSize,
|
|
||||||
backgroundColor: 'transparent',
|
|
||||||
color: theme.affine.palette.icons,
|
|
||||||
padding: theme.affine.spacing.iconPadding,
|
|
||||||
borderRadius: '3px',
|
|
||||||
|
|
||||||
'& svg': {
|
|
||||||
width: iconSize,
|
|
||||||
height: iconSize,
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
},
|
width: areaSize,
|
||||||
|
height: areaSize,
|
||||||
|
backgroundColor: backgroundColor ?? 'transparent',
|
||||||
|
color: theme.affine.palette.icons,
|
||||||
|
padding: theme.affine.spacing.iconPadding,
|
||||||
|
borderRadius: '3px',
|
||||||
|
|
||||||
'&:hover': {
|
'& svg': {
|
||||||
backgroundColor: hoverColor || theme.affine.palette.hover,
|
width: iconSize,
|
||||||
},
|
height: iconSize,
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
|
||||||
[`&${buttonStatus.hover}`]: {
|
'&:hover': {
|
||||||
backgroundColor: theme.affine.palette.hover,
|
backgroundColor: hoverColor || theme.affine.palette.hover,
|
||||||
},
|
},
|
||||||
|
|
||||||
'&:focus': {
|
...(disabled ? { cursor: 'not-allowed' } : {}),
|
||||||
color: theme.affine.palette.primary,
|
};
|
||||||
},
|
}
|
||||||
[`&.${buttonStatus.focus}`]: {
|
);
|
||||||
color: theme.affine.palette.primary,
|
|
||||||
},
|
|
||||||
|
|
||||||
[`&${buttonStatus.disabled}`]: {
|
|
||||||
cursor: 'not-allowed',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
export const buttonStatus = {
|
|
||||||
hover: '.hover',
|
|
||||||
focus: '.focus',
|
|
||||||
active: '.focus',
|
|
||||||
disabled: '.disabled',
|
|
||||||
};
|
|
Loading…
Reference in New Issue
Block a user