Path: blob/master/src/packages/frontend/editors/slate/elements/paragraph/editable.tsx
1698 views
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45import { register } from "../register";6import { useFocused, useSelected, useCollapsed } from "../hooks";78register({9slateType: "paragraph",1011Element: ({ attributes, children, element }) => {12if (element.type != "paragraph") throw Error("bug");1314// All this complexity is because we only show empty paragraphs15// when the cursor is in them, since we create them dynamically in16// order to work around a fundamental shortcoming in the design17// of slatejs wrt cursor navigation (e.g., you can't move the cursor18// between block voids or before various elements at the beginning19// of a document such as bulleted lists).20const focused = useFocused();21const selected = useSelected();22const collapsed = useCollapsed();23const isEmpty =24element.children.length == 1 && element.children[0]["text"] == "";25if (isEmpty && !(collapsed && focused && selected)) {26// Only show empty paragraph if selection is collapsed, editor is27// focused, and para is selected.28return (29<span {...attributes} style={{ position: "absolute" }}>30{children}31</span>32);33}3435// Below the textIndent: 0 is needed due to task lists -- see slate/elements/list/list-item.tsx3637if (hasImageAsChild(element)) {38// We use a div in this case, since our image renderer resize functionality39// (via the re-resizer packages) uses divs, and divs are not allowed inside40// of paragraphs.41return (42<div {...attributes}>43<span style={{ textIndent: 0 }}>{children}</span>44</div>45);46}4748// Normal paragraph rendering.49return (50<p {...attributes}>51<span style={{ textIndent: 0 }}>{children}</span>52</p>53);5455/*56// I wish I could just use a div instead of a p because57// you can't have58// any div's inside of a p, and things like image resize use59// div's under the hood in the implementation.60// However, there are rules (e.g., from bootstrap's type.less)61// like this62// blockquote {... p { &:last-child { margin-bottom: 0; } }63// so, e.g., a paragraph in a quote doesn't have that extra64// bottom margin. That's a lot more work to re-implement65// using a div...66return (67<div {...attributes} style={{ marginBottom: "1em" }}>68{children}69</div>70);71*/72},7374fromSlate: ({ children, info }) => {75if (children.trim() == "") {76// We discard empty paragraphs entirely, since that's77// what markdown does. Also, to make void blocks easier to78// work with, we sometimes automatically add blank paragraphs79// above or below them, and it is silly if those result in80// lots of meaningless blank lines in the md file.81return "";82}8384// trimLeft is because prettier (say) strips whitespace from beginning of paragraphs.85const s = children.trimLeft() + "\n";86if (info.lastChild || info.parent?.type == "list_item") return s;87return s + "\n";88},89});9091function hasImageAsChild(element): boolean {92for (const x of element.children) {93if (x["type"] == "image") return true;94}95return false;96}979899