json-joy
Version:
Collection of libraries for building collaborative editing apps.
86 lines (85 loc) • 3.58 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PeritextView = void 0;
const tslib_1 = require("tslib");
const React = tslib_1.__importStar(require("react"));
const react_dom_1 = require("react-dom");
const nano_theme_1 = require("nano-theme");
const constants_1 = require("../constants");
const cursor_1 = require("../../plugins/cursor");
const minimal_1 = require("../../plugins/minimal");
const state_1 = require("../state");
const events_1 = require("../../events");
const context_1 = require("./context");
const BlockView_1 = require("./BlockView");
const hooks_1 = require("./hooks");
(0, nano_theme_1.put)('.' + constants_1.CssClass.Editor, {
out: 0,
whiteSpace: 'nowrap',
wordWrap: 'break-word',
'caret-color': 'transparent',
'::selection': {
bgc: 'transparent',
},
/** @todo Move these to the default theme. */
fontVariantNumeric: 'slashed-zero oldstyle-nums',
fontOpticalSizing: 'auto',
});
(0, nano_theme_1.put)('.' + constants_1.CssClass.Inline, {
whiteSpace: 'pre-wrap',
});
exports.PeritextView = React.memo((props) => {
const { peritext, plugins: plugins_, onState } = props;
const ref = React.useRef(null);
// Plugins provided through props, or a default set of plugins.
const plugins = React.useMemo(() => plugins_ ?? [new cursor_1.CursorPlugin(), minimal_1.defaultPlugin], [plugins_]);
// Create the DOM element for the editor. And instantiate the state management.
const [el, state, stop] = React.useMemo(() => {
const div = document.createElement('div');
div.className = constants_1.CssClass.Editor;
const events = (0, events_1.createEvents)(peritext);
const state = new state_1.PeritextSurfaceState(events, div, plugins);
const stop = state.start();
return [div, state, stop];
}, [peritext, plugins]);
// Call life-cycle methods on the state.
React.useLayoutEffect(() => stop, [stop]);
React.useLayoutEffect(() => {
onState?.(state);
}, [onState, state]);
// Attach imperatively constructed <div> element to our container.
React.useLayoutEffect(() => {
const div = ref.current;
if (!div)
return;
const parent = div.parentElement;
parent.appendChild(el);
return () => {
if (el.parentNode === parent)
parent.removeChild(el);
};
}, [el]);
// Return the final result.
return (React.createElement(context_1.context.Provider, { value: state },
React.createElement(PeritextViewInner, { div: ref, state: state })));
});
const PeritextViewInner = React.memo((props) => {
const { state, div } = props;
const { peritext, render, el, plugins } = state;
// Subscribe to re-render events.
(0, hooks_1.useSyncStore)(render);
// Render the main body of the editor.
const block = peritext.blocks.root;
let children = block ? (0, react_dom_1.createPortal)(React.createElement(BlockView_1.BlockView, { hash: block.hash, block: block }), el) : null;
// Create container element, into which we will insert imperatively
// constructed <div> element.
children = (React.createElement(React.Fragment, null,
React.createElement("div", { ref: div, style: { visibility: 'hidden' } }),
children));
// Run the plugins to decorate our content body.
for (const { peritext: decorator } of plugins)
if (decorator)
children = decorator(children, state);
// Return the final result.
return children;
});