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 ( {lastItem && } {/* maybe need a child wrapper */} {children} ); }); 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 ( {childrenIds.map((childId, idx) => { if (isKanbanScene) { return ( ); } return ( ); })} ); }; const CollapsedNode = forwardRef< HTMLDivElement, ComponentPropsWithoutRef<'div'> >((props, ref) => { return ( ยทยทยท ); }); /** * Indent rendering child nodes */ export const withTreeViewChildren = ( creator: (props: CreateView) => ReactElement, customConfig: Partial = {} ) => { 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(false); useOnSelect(block.id, (isSelect: boolean) => { setIsSelect(isSelect); }); const handleCollapse = () => { block.setProperty('collapsed', { value: true }); }; const handleExpand = () => { block.setProperty('collapsed', { value: false }); }; return (
{creator(props)}
{collapsed && ( )} {showChildren && ( )}
); }; }; 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', });