UNPKG

json-joy

Version:

Collection of libraries for building collaborative editing apps.

82 lines (81 loc) 3.99 kB
import * as React from 'react'; import { LeafBlock } from '../../../json-crdt-extensions/peritext/block/LeafBlock'; import { InlineView } from './InlineView'; import { Char } from '../constants'; import { usePeritext } from './context'; import { CommonSliceType } from '../../../json-crdt-extensions'; import { CaretView } from './cursor/CaretView'; import { FocusView } from './cursor/FocusView'; import { InlineAttrEnd, InlineAttrPassing, InlineAttrStart } from '../../../json-crdt-extensions/peritext/block/Inline'; import { AnchorView } from './cursor/AnchorView'; export const BlockView = React.memo((props) => { const { block, el } = props; const { plugins, dom } = usePeritext(); const elements = []; if (block instanceof LeafBlock) { for (const inline of block.texts()) { const hasCursor = inline.hasCursor(); if (hasCursor) { const attr = inline.attr(); const italic = attr[CommonSliceType.i] && attr[CommonSliceType.i][0]; const cursorStart = inline.cursorStart(); if (cursorStart) { const key = cursorStart.start.key() + '-a'; let element; if (cursorStart.isStartFocused()) { if (cursorStart.isCollapsed()) element = React.createElement(CaretView, { key: key, italic: !!italic, point: cursorStart.start }); else { const isItalic = italic instanceof InlineAttrEnd || italic instanceof InlineAttrPassing; element = React.createElement(FocusView, { key: key, italic: isItalic }); } } else element = React.createElement(AnchorView, { key: key }); elements.push(element); } } elements.push(React.createElement(InlineView, { key: inline.key(), inline: inline })); if (hasCursor) { const cursorEnd = inline.cursorEnd(); const attr = inline.attr(); const italic = attr[CommonSliceType.i] && attr[CommonSliceType.i][0]; if (cursorEnd) { const key = cursorEnd.end.key() + '-b'; let element; if (cursorEnd.isEndFocused()) { if (cursorEnd.isCollapsed()) element = React.createElement(CaretView, { key: key, italic: !!italic, point: cursorEnd.start }); else element = (React.createElement(FocusView, { key: key, left: true, italic: italic instanceof InlineAttrStart || italic instanceof InlineAttrPassing })); } else element = React.createElement(AnchorView, { key: key }); elements.push(element); } } } } else { const children = block.children; const length = children.length; for (let i = 0; i < length; i++) { const child = children[i]; elements.push(React.createElement(BlockView, { key: child.key(), hash: child.hash, block: child })); } } let children = (React.createElement("span", { ref: (element) => { el?.(element); if (block instanceof LeafBlock) { const blockId = block.start.id; const blocks = dom.blocks; if (element) blocks.set(blockId, element); else blocks.del(blockId); } }, style: { position: 'relative', display: 'block' } }, elements.length ? elements : Char.ZeroLengthSpace)); for (const map of plugins) children = map.block?.(props, children) ?? children; return children; }, (prev, next) => prev.hash === next.hash);