Path: blob/master/src/packages/frontend/editors/slate/slate-react/components/string.tsx
1698 views
import { Editor, Text, Path, Element, Node } from "slate";1import { ReactEditor, useSlateStatic } from "..";23/**4* Leaf content strings.5*/67const String = (props: {8isLast: boolean;9leaf: Text;10parent: Element;11text: Text;12}) => {13const { isLast, leaf, parent, text } = props;14const editor = useSlateStatic();15let path;16try {17path = ReactEditor.findPath(editor, text);18} catch (err) {19console.warn("WARNING: String -- unable to find path to node", text, err);20return <ZeroWidthString />;21}22const parentPath = Path.parent(path);2324// COMPAT: Render text inside void nodes with a zero-width space.25// So the node can contain selection but the text is not visible.26if (editor.isVoid(parent)) {27return <ZeroWidthString length={Node.string(parent).length} />;28}2930// COMPAT: If this is the last text node in an empty block, render a zero-31// width space that will convert into a line break when copying and pasting32// to support expected plain text.33if (34leaf.text === "" &&35parent.children[parent.children.length - 1] === text &&36!editor.isInline(parent) &&37Editor.string(editor, parentPath) === ""38) {39return <ZeroWidthString isLineBreak />;40}4142// COMPAT: If the text is empty, it's because it's on the edge of an inline43// node, so we render a zero-width space so that the selection can be44// inserted next to it still.45if (leaf.text === "") {46return <ZeroWidthString />;47}4849// COMPAT: Browsers will collapse trailing new lines at the end of blocks,50// so we need to add an extra trailing new lines to prevent that.51if (isLast && leaf.text.slice(-1) === "\n") {52return <TextString isTrailing text={leaf.text} />;53}5455return <TextString text={leaf.text} />;56};5758/**59* Leaf strings with text in them.60*/6162const TextString = (props: { text: string; isTrailing?: boolean }) => {63const { text, isTrailing = false } = props;64return (65<span data-slate-string>66{text}67{isTrailing ? "\n" : null}68</span>69);70};7172/**7374Leaf strings without text, render as zero-width strings... or do they? See below:7576The style below is a hack to workaround a bug when using Chrome, which doesn't happen on Firefox or Safari.77The solution below is inspired by https://stackoverflow.com/questions/25897883/edit-cursor-not-displayed-on-chrome-in-contenteditable78Here's how to reproduce the bug in cocalc and the style below removed.79801. Open a new blank doc with markdown source on the left and slate on the right.812. You can click either side and it focuses and shows a cursor.823. Click in the right slate side, then click the x to close the *left hand* markdown source.834. Broken -- no matter where you click, you can't get the slate editor to show a cursor (except on firefox and safari it works).8485The workaround of rendering a ZeroWidthString as actually 1px in width and display inline block,86evidently gives the cursor somewhere to be in the case of an empty document. It seems harmless to87leave this 1px width even for nonempty documents.88*/8990const ZeroWidthString = (props: { length?: number; isLineBreak?: boolean }) => {91const { length = 0, isLineBreak = false } = props;92return (93<span94data-slate-zero-width={isLineBreak ? "n" : "z"}95data-slate-length={length}96style={97/* see note above! */98{99display: "inline-block",100width: "1px",101textIndent: 0 /* This is needed to offset textIndex that is used in task list items!102This example breaks otherwise, if you put the cursor in the third bullet point and move up to previous line in the link.103104- x105- [ ] y wstein.org106-107*/,108}109}110>111{"\uFEFF"}112{isLineBreak ? <br /> : null}113</span>114);115};116117export default String;118119120