json-joy
Version:
Collection of libraries for building collaborative editing apps.
67 lines • 2.94 kB
JavaScript
import * as React from 'react';
import { put } from 'nano-theme';
import { CssClass } from '../constants';
import { CursorPlugin } from '../../plugins/cursor';
import { defaultPlugin } from '../../plugins/minimal';
import { PeritextSurfaceState } from '../state';
import { context } from './context';
import { BlockView } from './BlockView';
import { useBehaviorSubject } from 'nice-ui/lib/hooks/useBehaviorSubject';
import { createEvents } from '../../../json-crdt-extensions/peritext/events';
put('.' + CssClass.Editable, {
pos: 'relative',
zIndex: 1,
out: 0,
whiteSpace: 'nowrap',
wordWrap: 'break-word',
/** @todo Move these to the default theme. */
fontVariantNumeric: 'slashed-zero oldstyle-nums',
fontOpticalSizing: 'auto',
});
put('.' + CssClass.Overlays, {
pos: 'relative',
zIndex: 2,
h: '0px',
});
put('.' + CssClass.Inline, {
whiteSpace: 'pre-wrap',
});
export const PeritextView = React.memo((props) => {
const { peritext, plugins: plugins_, onStart: onState } = props;
// The `.stop()` is called when the editor unmounts.
const stop = React.useRef(void 0);
// Plugins provided through props, or a default set of plugins.
const plugins = React.useMemo(() => plugins_ ?? [new CursorPlugin(), defaultPlugin], [plugins_]);
/** Create the {@link PeritextSurfaceState} state management instance. */
const state = React.useMemo(() => new PeritextSurfaceState(createEvents(peritext), plugins), [peritext, plugins]);
/** Call `.start()` of {@link PeritextSurfaceState} and setup HTML element. */
const ref = (el) => {
if (!el)
return;
state.el = el;
stop.current = state.start();
onState?.(state);
};
/** Call `.stop()` of {@link PeritextSurfaceState} when the component unmounts. */
React.useLayoutEffect(() => () => stop.current?.(), []);
// Return the final result.
return (React.createElement(context.Provider, { value: state },
React.createElement("div", { className: CssClass.Editor },
React.createElement(PeritextViewInner, { div: ref, state: state }),
React.createElement("div", { ref: (el) => (state.portalEl = el || void 0), className: CssClass.Overlays }))));
});
const PeritextViewInner = React.memo((props) => {
const { state, div } = props;
// Subscribe to re-render events.
useBehaviorSubject(state.render$);
// Render the main body of the editor.
const block = state.peritext.blocks.root;
let children = (React.createElement("div", { ref: div, className: CssClass.Editable },
React.createElement(BlockView, { hash: block.hash, block: block })));
// Run the plugins to decorate our content body.
for (const plugin of state.plugins)
children = plugin.peritext?.(children, state) ?? children;
// Return the final result.
return children;
});
//# sourceMappingURL=PeritextView.js.map