refactor: update block

This commit is contained in:
lawvs
2022-08-24 01:35:04 +08:00
parent dd24711f21
commit a4dc7bf127
17 changed files with 96 additions and 343 deletions
@@ -1,29 +1,28 @@
import type { TextProps } from '@toeverything/components/common';
import {
ContentColumnValue,
services,
Protocol,
services,
} from '@toeverything/datasource/db-service';
import { type CreateView } from '@toeverything/framework/virgo';
import { useEffect, useRef, useState } from 'react';
import {
BlockPendantProvider,
RenderBlockChildren,
supportChildren,
useOnSelect,
} from '@toeverything/components/editor-core';
import { styled } from '@toeverything/components/ui';
import { BlockContainer } from '../../components/BlockContainer';
import { List } from '../../components/style-container';
import {
TextManage,
type ExtendedTextUtils,
} from '../../components/text-manage';
import { tabBlock } from '../../utils/indent';
import { BulletIcon, getChildrenType, NumberType } from './data';
import { BulletBlock, BulletProperties } from './types';
import {
supportChildren,
RenderBlockChildren,
useOnSelect,
BlockPendantProvider,
} from '@toeverything/components/editor-core';
import { List } from '../../components/style-container';
import { getChildrenType, BulletIcon, NumberType } from './data';
import { IndentWrapper } from '../../components/IndentWrapper';
import { BlockContainer } from '../../components/BlockContainer';
import { styled } from '@toeverything/components/ui';
export const defaultBulletProps: BulletProperties = {
text: { value: [{ text: '' }] },
@@ -208,9 +207,7 @@ export const BulletView = ({ block, editor }: CreateView) => {
</div>
</List>
</BlockPendantProvider>
<IndentWrapper>
<RenderBlockChildren block={block} />
</IndentWrapper>
<RenderBlockChildren block={block} />
</BlockContainer>
);
};
@@ -1,18 +1,16 @@
import {
DefaultColumnsValue,
Protocol,
} from '@toeverything/datasource/db-service';
import {
AsyncBlock,
BaseView,
CreateView,
getTextHtml,
getTextProperties,
SelectBlock,
getTextHtml,
} from '@toeverything/framework/virgo';
import {
Protocol,
DefaultColumnsValue,
} from '@toeverything/datasource/db-service';
// import { withTreeViewChildren } from '../../utils/with-tree-view-children';
import { defaultBulletProps, BulletView } from './BulletView';
import { IndentWrapper } from '../../components/IndentWrapper';
import { BulletView, defaultBulletProps } from './BulletView';
export class BulletBlock extends BaseView {
public type = Protocol.Block.Type.bullet;
@@ -1,4 +1,4 @@
import { RenderBlock } from '@toeverything/components/editor-core';
import { useBlockRender } from '@toeverything/components/editor-core';
import { ChildrenView, CreateView } from '@toeverything/framework/virgo';
export const GridItemRender = function (
@@ -6,10 +6,11 @@ export const GridItemRender = function (
) {
const GridItem = function (props: CreateView) {
const { block } = props;
const { BlockRender } = useBlockRender();
const children = (
<>
{block.childrenIds.map(id => {
return <RenderBlock key={id} blockId={id} />;
return <BlockRender key={id} blockId={id} />;
})}
</>
);
@@ -1,16 +1,16 @@
import { RenderBlock } from '@toeverything/components/editor-core';
import { CreateView } from '@toeverything/framework/virgo';
import React, { useEffect, useRef, useState } from 'react';
import { GridHandle } from './GirdHandle';
import { useBlockRender } from '@toeverything/components/editor-core';
import { styled } from '@toeverything/components/ui';
import { Protocol } from '@toeverything/datasource/db-service';
import { CreateView } from '@toeverything/framework/virgo';
import { debounce, domToRect, Point } from '@toeverything/utils';
import clsx from 'clsx';
import React, { useEffect, useRef, useState } from 'react';
import ReactDOM from 'react-dom';
import {
GRID_ITEM_CLASS_NAME,
GRID_ITEM_CONTENT_CLASS_NAME,
} from '../grid-item/GridItem';
import { debounce, domToRect, Point } from '@toeverything/utils';
import clsx from 'clsx';
import { Protocol } from '@toeverything/datasource/db-service';
import { GridHandle } from './GirdHandle';
const DB_UPDATE_DELAY = 50;
const GRID_ON_DRAG_CLASS = 'grid-layout-on-drag';
@@ -31,6 +31,7 @@ export const Grid = function (props: CreateView) {
const originalLeftWidth = useRef<number>(gridItemMinWidth);
const originalRightWidth = useRef<number>(gridItemMinWidth);
const [alertHandleId, setAlertHandleId] = useState<string>(null);
const { BlockRender } = useBlockRender();
const getLeftRightGridItemDomByIndex = (index: number) => {
const gridItems = Array.from(gridContainerRef.current?.children).filter(
@@ -226,7 +227,7 @@ export const Grid = function (props: CreateView) {
key={id}
className={GRID_ITEM_CLASS_NAME}
>
<RenderBlock hasContainer={false} blockId={id} />
<BlockRender hasContainer={false} blockId={id} />
<GridHandle
onDrag={event => handleDragGrid(event, i)}
editor={editor}
@@ -2,5 +2,5 @@ import { RenderBlockChildren } from '@toeverything/components/editor-core';
import type { CreateView } from '@toeverything/framework/virgo';
export const ScenePage = ({ block }: CreateView) => {
return <RenderBlockChildren block={block} />;
return <RenderBlockChildren block={block} indent={false} />;
};
@@ -1,6 +1,6 @@
import {
KanbanCard,
RenderBlock,
useBlockRender,
useEditor,
useKanban,
} from '@toeverything/components/editor-core';
@@ -94,6 +94,7 @@ export const CardItem = ({
const [editable, setEditable] = useState(false);
const showKanbanRefPageFlag = useFlag('ShowKanbanRefPage', false);
const { editor } = useEditor();
const { BlockRender } = useBlockRender();
const onAddItem = async () => {
setEditable(true);
@@ -114,7 +115,7 @@ export const CardItem = ({
<MuiClickAwayListener onClickAway={() => setEditable(false)}>
<CardContainer>
<CardContent>
<RenderBlock blockId={id} />
<BlockRender blockId={id} />
</CardContent>
{showKanbanRefPageFlag && !editable && (
<Overlay onClick={onClickCard}>
@@ -1,8 +1,8 @@
import { TextProps } from '@toeverything/components/common';
import {
ContentColumnValue,
services,
Protocol,
services,
} from '@toeverything/datasource/db-service';
import { type CreateView } from '@toeverything/framework/virgo';
import { useEffect, useRef, useState } from 'react';
@@ -11,18 +11,17 @@ import {
type ExtendedTextUtils,
} from '../../components/text-manage';
import { tabBlock } from '../../utils/indent';
import { IndentWrapper } from '../../components/IndentWrapper';
import type { Numbered, NumberedAsyncBlock } from './types';
import { getChildrenType, getNumber } from './data';
import {
supportChildren,
RenderBlockChildren,
useOnSelect,
BlockPendantProvider,
RenderBlockChildren,
supportChildren,
useOnSelect,
} from '@toeverything/components/editor-core';
import { List } from '../../components/style-container';
import { BlockContainer } from '../../components/BlockContainer';
import { List } from '../../components/style-container';
import { getChildrenType, getNumber } from './data';
export const defaultTodoProps: Numbered = {
text: { value: [{ text: '' }] },
@@ -204,9 +203,7 @@ export const NumberedView = ({ block, editor }: CreateView) => {
</List>
</BlockPendantProvider>
<IndentWrapper>
<RenderBlockChildren block={block} />
</IndentWrapper>
<RenderBlockChildren block={block} />
</BlockContainer>
);
};
@@ -1,17 +1,16 @@
import {
DefaultColumnsValue,
Protocol,
} from '@toeverything/datasource/db-service';
import {
AsyncBlock,
BaseView,
getTextHtml,
getTextProperties,
SelectBlock,
getTextHtml,
} from '@toeverything/framework/virgo';
import {
Protocol,
DefaultColumnsValue,
} from '@toeverything/datasource/db-service';
// import { withTreeViewChildren } from '../../utils/with-tree-view-children';
import { defaultTodoProps, NumberedView } from './NumberedView';
import { IndentWrapper } from '../../components/IndentWrapper';
export class NumberedBlock extends BaseView {
public type = Protocol.Block.Type.numbered;
@@ -12,7 +12,6 @@ import { styled } from '@toeverything/components/ui';
import { Protocol } from '@toeverything/datasource/db-service';
import { CreateView } from '@toeverything/framework/virgo';
import { BlockContainer } from '../../components/BlockContainer';
import { IndentWrapper } from '../../components/IndentWrapper';
import { TextManage } from '../../components/text-manage';
import { dedentBlock, tabBlock } from '../../utils/indent';
interface CreateTextView extends CreateView {
@@ -255,9 +254,7 @@ export const TextView = ({
handleTab={onTab}
/>
</BlockPendantProvider>
<IndentWrapper>
<RenderBlockChildren block={block} />
</IndentWrapper>
<RenderBlockChildren block={block} />
</BlockContainer>
);
};
@@ -1,11 +1,17 @@
import { TextProps } from '@toeverything/components/common';
import {
AsyncBlock,
BlockPendantProvider,
CreateView,
useOnSelect,
} from '@toeverything/components/editor-core';
import { styled } from '@toeverything/components/ui';
import {
ContentColumnValue,
Protocol,
} from '@toeverything/datasource/db-service';
import { AsyncBlock, type CreateView } from '@toeverything/framework/virgo';
import { useRef } from 'react';
import { useRef, useState } from 'react';
import { BlockContainer } from '../../components/BlockContainer';
import {
TextManage,
type ExtendedTextUtils,
@@ -36,6 +42,10 @@ const todoIsEmpty = (contentValue: ContentColumnValue): boolean => {
export const TodoView = ({ block, editor }: CreateView) => {
const properties = { ...defaultTodoProps, ...block.getProperties() };
const text_ref = useRef<ExtendedTextUtils>(null);
const [isSelect, setIsSelect] = useState<boolean>(false);
useOnSelect(block.id, (isSelect: boolean) => {
setIsSelect(isSelect);
});
const turn_into_text_block = async () => {
// Convert to text block
@@ -121,28 +131,34 @@ export const TodoView = ({ block, editor }: CreateView) => {
};
return (
<TodoBlock>
<div className={'checkBoxContainer'}>
<CheckBox
checked={properties.checked?.value}
onChange={on_checked_change}
/>
</div>
<BlockContainer editor={editor} block={block} selected={isSelect}>
<BlockPendantProvider block={block}>
<TodoBlock>
<div className={'checkBoxContainer'}>
<CheckBox
checked={properties.checked?.value}
onChange={on_checked_change}
/>
</div>
<div className={'textContainer'}>
<TextManage
className={properties.checked?.value ? 'checked' : ''}
ref={text_ref}
editor={editor}
block={block}
supportMarkdown
placeholder="To-do"
handleEnter={on_text_enter}
handleBackSpace={on_backspace}
handleTab={on_tab}
/>
</div>
</TodoBlock>
<div className={'textContainer'}>
<TextManage
className={
properties.checked?.value ? 'checked' : ''
}
ref={text_ref}
editor={editor}
block={block}
supportMarkdown
placeholder="To-do"
handleEnter={on_text_enter}
handleBackSpace={on_backspace}
handleTab={on_tab}
/>
</div>
</TodoBlock>
</BlockPendantProvider>
</BlockContainer>
);
};
@@ -1,18 +1,16 @@
import {
BaseView,
getTextProperties,
AsyncBlock,
SelectBlock,
BaseView,
getTextHtml,
} from '@toeverything/framework/virgo';
// import type { CreateView } from '@toeverything/framework/virgo';
getTextProperties,
SelectBlock,
withTreeViewChildren,
} from '@toeverything/components/editor-core';
import {
Protocol,
DefaultColumnsValue,
Protocol,
} from '@toeverything/datasource/db-service';
// import { withTreeViewChildren } from '../../utils/with-tree-view-children';
import { withTreeViewChildren } from '../../utils/WithTreeViewChildren';
import { TodoView, defaultTodoProps } from './TodoView';
import { defaultTodoProps, TodoView } from './TodoView';
import type { TodoAsyncBlock } from './types';
export class TodoBlock extends BaseView {
@@ -23,7 +23,7 @@ export const BlockContainer = function ({
);
};
export const Container = styled('div')<{ selected: boolean }>(
export const Container = styled('div')<{ selected?: boolean }>(
({ selected, theme }) => ({
backgroundColor: selected ? theme.affine.palette.textSelected : '',
marginBottom: '2px',
@@ -1,17 +0,0 @@
import { PropsWithChildren } from 'react';
import { ChildrenView } from '@toeverything/framework/virgo';
import { styled } from '@toeverything/components/ui';
/**
* Indent rendering child nodes
*/
export const IndentWrapper = (props: PropsWithChildren) => {
return <StyledIdentWrapper>{props.children}</StyledIdentWrapper>;
};
const StyledIdentWrapper = styled('div')({
display: 'flex',
flexDirection: 'column',
// TODO: marginLeft should use theme provided by styled
marginLeft: '30px',
});
@@ -1 +0,0 @@
export * from './IndentWrapper';
@@ -1,4 +1,5 @@
export const isYoutubeUrl = (url?: string): boolean => {
if (!url) return false;
const allowedHosts = ['www.youtu.be', 'www.youtube.com'];
const host = new URL(url).host;
return allowedHosts.includes(host);
@@ -1,236 +0,0 @@
import {
BlockPendantProvider,
CreateView,
RenderBlock,
useCurrentView,
useOnSelect,
} from '@toeverything/components/editor-core';
import { styled } from '@toeverything/components/ui';
import type {
ComponentPropsWithoutRef,
ComponentPropsWithRef,
CSSProperties,
ReactElement,
} from 'react';
import { forwardRef, useState } from 'react';
import { SCENE_CONFIG } from '../blocks/group/config';
import { BlockContainer } from '../components/BlockContainer';
type WithChildrenConfig = {
indent: CSSProperties['marginLeft'];
};
const defaultConfig: WithChildrenConfig = {
indent: '30px',
};
const TreeView = forwardRef<
HTMLDivElement,
{ lastItem?: boolean } & ComponentPropsWithRef<'div'>
>(({ lastItem = false, children, onClick, ...restProps }, ref) => {
return (
<TreeWrapper ref={ref} {...restProps}>
<StyledTreeView>
<VerticalLine last={lastItem} onClick={onClick} />
<HorizontalLine last={lastItem} onClick={onClick} />
{lastItem && <LastItemRadius />}
</StyledTreeView>
{/* maybe need a child wrapper */}
{children}
</TreeWrapper>
);
});
interface ChildrenViewProp {
childrenIds: string[];
handleCollapse: () => void;
indent?: string | number;
}
const ChildrenView = ({
childrenIds,
handleCollapse,
indent,
}: ChildrenViewProp) => {
const [currentView] = useCurrentView();
const isKanbanScene = currentView.type === SCENE_CONFIG.KANBAN;
return (
<Children style={{ ...(!isKanbanScene && { marginLeft: indent }) }}>
{childrenIds.map((childId, idx) => {
if (isKanbanScene) {
return (
<StyledBorder key={childId}>
<RenderBlock blockId={childId} />
</StyledBorder>
);
}
return (
<TreeView
key={childId}
lastItem={idx === childrenIds.length - 1}
onClick={handleCollapse}
>
<RenderBlock key={childId} blockId={childId} />
</TreeView>
);
})}
</Children>
);
};
const CollapsedNode = forwardRef<
HTMLDivElement,
ComponentPropsWithoutRef<'div'>
>((props, ref) => {
return (
<TreeView ref={ref} lastItem={true} {...props}>
<Collapsed onClick={props.onClick}>···</Collapsed>
</TreeView>
);
});
/**
* Indent rendering child nodes
*/
export const withTreeViewChildren = (
creator: (props: CreateView) => ReactElement,
customConfig: Partial<WithChildrenConfig> = {}
) => {
const config = {
...defaultConfig,
...customConfig,
};
return (props: CreateView) => {
const { block, editor } = props;
const collapsed = block.getProperty('collapsed')?.value;
const childrenIds = block.childrenIds;
const showChildren = !collapsed && childrenIds.length > 0;
const [isSelect, setIsSelect] = useState<boolean>(false);
useOnSelect(block.id, (isSelect: boolean) => {
setIsSelect(isSelect);
});
const handleCollapse = () => {
block.setProperty('collapsed', { value: true });
};
const handleExpand = () => {
block.setProperty('collapsed', { value: false });
};
return (
<BlockContainer
editor={props.editor}
block={block}
selected={isSelect}
className={Wrapper.toString()}
>
<BlockPendantProvider block={block}>
<div>{creator(props)}</div>
</BlockPendantProvider>
{collapsed && (
<CollapsedNode
onClick={handleExpand}
style={{ marginLeft: config.indent }}
/>
)}
{showChildren && (
<ChildrenView
childrenIds={childrenIds}
handleCollapse={handleCollapse}
indent={config.indent}
/>
)}
</BlockContainer>
);
};
};
const Wrapper = styled('div')({ display: 'flex', flexDirection: 'column' });
const Children = Wrapper;
const TREE_COLOR = '#D5DFE6';
// adjust left and right margins of the the tree line
const TREE_LINE_LEFT_OFFSET = '-16px';
// determine the position of the horizontal line by the type of the item
const TREE_LINE_TOP_OFFSET = '20px'; // '50%'
const TREE_LINE_WIDTH = '12px';
const TreeWrapper = styled('div')({
position: 'relative',
});
const StyledTreeView = styled('div')({
position: 'absolute',
left: TREE_LINE_LEFT_OFFSET,
height: '100%',
});
const Line = styled('div')({
position: 'absolute',
cursor: 'pointer',
backgroundColor: TREE_COLOR,
// somehow tldraw would override this
boxSizing: 'content-box!important' as any,
// See [Can I add background color only for padding?](https://stackoverflow.com/questions/14628601/can-i-add-background-color-only-for-padding)
backgroundClip: 'content-box',
backgroundOrigin: 'content-box',
// Increase click hot spot
padding: '10px',
});
const VerticalLine = styled(Line)<{ last: boolean }>(({ last }) => ({
width: '1px',
height: last ? TREE_LINE_TOP_OFFSET : '100%',
paddingTop: 0,
paddingBottom: 0,
transform: 'translate(-50%, 0)',
opacity: last ? 0 : 'unset',
}));
const HorizontalLine = styled(Line)<{ last: boolean }>(({ last }) => ({
width: TREE_LINE_WIDTH,
height: '1px',
paddingLeft: 0,
paddingRight: 0,
top: TREE_LINE_TOP_OFFSET,
transform: 'translate(0, -50%)',
opacity: last ? 0 : 'unset',
}));
const Collapsed = styled('div')({
cursor: 'pointer',
display: 'inline-block',
color: '#98ACBD',
padding: '8px',
});
const LastItemRadius = styled('div')({
boxSizing: 'content-box',
position: 'absolute',
left: '-0.5px',
top: 0,
height: TREE_LINE_TOP_OFFSET,
bottom: '50%',
width: TREE_LINE_WIDTH,
borderWidth: '1px',
borderStyle: 'solid',
borderLeftColor: TREE_COLOR,
borderBottomColor: TREE_COLOR,
borderTop: 'none',
borderRight: 'none',
borderRadius: '0 0 0 3px',
pointerEvents: 'none',
});
const StyledBorder = styled('div')({
border: '1px solid #E0E6EB',
borderRadius: '5px',
margin: '4px',
});
@@ -69,4 +69,5 @@ export function RenderBlock({
const BlockContainer = styled('div')(({ theme }) => ({
fontSize: theme.typography.body1.fontSize,
flex: 1,
}));