json-joy
Version:
Collection of libraries for building collaborative editing apps.
82 lines (81 loc) • 3.99 kB
JavaScript
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);