UNPKG

json-joy

Version:

Collection of libraries for building collaborative editing apps.

86 lines (85 loc) 3.58 kB
"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; });