// the minimum component, just a span import * as tsx from "vue-tsx-support"; import { Editor, Path, Node, Text } from 'slate'; import {VueEditor} from '../plugins' import { providedByText, TsxComponent } from '../types'; import { PropType } from 'vue'; interface ZeroWidthStringProps { length?: number isLineBreak?: boolean } /** * Leaf strings with text in them. */ const TextString = tsx.component({ props: { text: String, isTrailing: Boolean }, render() { const { text, isTrailing = false } = this return ( <span data-slate-string> {text} {isTrailing ? '\n' : null} </span> ) } }) /** * Leaf strings without text, render as zero-width strings. */ const ZeroWidthString: TsxComponent<ZeroWidthStringProps> = ({ props }) => { const { length = 0, isLineBreak = false } = props as ZeroWidthStringProps return ( <span data-slate-zero-width={isLineBreak ? 'n' : 'z'} data-slate-length={length} > {'\uFEFF'} {isLineBreak ? <br /> : null} </span> ) } /** * Leaf content strings. */ const string = tsx.component({ props: { leaf: { type: Object as PropType<Text> }, editor: Object }, inject: ['isLast', 'parent', 'text'], components: { TextString }, data(): providedByText { return {} }, render() { const { leaf, editor, isLast, parent, text } = this const path = VueEditor.findPath(editor, text as Node) const parentPath = Path.parent(path) // COMPAT: Render text inside void nodes with a zero-width space. // So the node can contain selection but the text is not visible. if (editor.isVoid(parent)) { return <ZeroWidthString length={Node.string(parent as Node).length} /> } // COMPAT: If this is the last text node in an empty block, render a zero- // width space that will convert into a line break when copying and pasting // to support expected plain text. if ( leaf.text === '' && (parent as Element & Editor).children[(parent as Element & Editor).children.length - 1] === text && !editor.isInline(parent) && Editor.string(editor, parentPath) === '' ) { return <ZeroWidthString isLineBreak={true} /> } // COMPAT: If the text is empty, it's because it's on the edge of an inline // node, so we render a zero-width space so that the selection can be // inserted next to it still. if (leaf.text === '') { return <ZeroWidthString /> } // COMPAT: Browsers will collapse trailing new lines at the end of blocks, // so we need to add an extra trailing new lines to prevent that. if (isLast && leaf.text.slice(-1) === '\n') { return <TextString isTrailing={true} text={leaf.text} /> } return <TextString text={leaf.text} /> } }) export default string