json-joy
Version:
Collection of libraries for building collaborative editing apps.
80 lines • 2.77 kB
JavaScript
import * as React from 'react';
import { put } from 'nano-theme';
import { CssClass, ElementAttr } from '../constants';
import { usePeritext } from './context';
put('.' + CssClass.Inline, {
/**
* Font *kerning* is the variable distance between every pair of characters.
* It is adjusted to make the text more readable. This disables it, so that
* there is always the same distance between characters.
*
* Useful because, while moving the cursor the characters can be arbitrarily
* grouped into <span> elements, the distance between them should be
* consistent to avoid layout shifts. Otherwise, there is a text shift when
* moving the cursor. For example, consider:
*
* ```jsx
* <span>Word</span>
* ```
*
* vs.
*
* ```jsx
* <span>W</span><span>ord</span>
* ```
*
* The kerning between letters "W" and "o" changes and results in a shift, if
* this property is not set.
*/
fontKerning: 'none',
/**
* Similar to `fontKerning`, but for ligatures. Ligatures are special glyphs
* that combine two or more characters into a single glyph. We disable them
* so that the text is more visually predictable.
*/
fontVariantLigatures: 'none',
/**
* Hide the default system caret (and selection). Peritext renders its own
* caret and selection, see `CaretView` component as example.
*
* The default Peritext caret and selection are invisible, but the plugins
* can fully customize their appearance.
*/
caretColor: 'transparent',
'::selection': {
bgc: 'transparent',
},
});
/** @todo Add ability to compute `.hash` for {@link Inline} nodes and use for memoization. */
export const InlineView = (props) => {
const { inline } = props;
const ctx = usePeritext();
const { plugins, dom } = ctx;
const ref = React.useRef(null);
const text = inline.text();
const span = ref.current;
if (span)
span[ElementAttr.InlineOffset] = inline;
let attr = {
className: CssClass.Inline,
ref: (span) => {
const inlines = dom.inlines;
const start = inline.start;
ref.current = span;
if (span) {
span[ElementAttr.InlineOffset] = inline;
inlines.set(start, span);
}
else {
inlines.del(start);
}
},
};
for (const map of plugins)
attr = map.text?.(attr, inline, ctx) ?? attr;
let children = React.createElement("span", { ...attr }, text);
for (const map of plugins)
children = map.inline?.(props, children) ?? children;
return children;
};
//# sourceMappingURL=InlineView.js.map