Path: blob/master/src/packages/frontend/editors/slate/elements/html/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 { useState } from "react";6import { register } from "../register";7import { useFocused, useSelected, useSlate } from "../hooks";8import { ensure_ends_in_two_newline, FOCUSED_COLOR } from "../../util";9import { SlateCodeMirror } from "../codemirror";10import { useSetElement } from "../set-element";11import HTML from "@cocalc/frontend/components/html-ssr";1213function isBR(s: string): boolean {14const x = s.toLowerCase().replace(/\s/g, "");15return x == "<br>" || x == "<br/>";16}1718const Element = ({ attributes, children, element }) => {19const focused = useFocused();20const selected = useSelected();21const border =22focused && selected23? `1px solid ${FOCUSED_COLOR}`24: `1px solid transparent`;25const html = ((element.html as string) ?? "").trim();2627// this feels ugly in practice, and we have the source so not doing it.28const is_comment = false;29// const is_comment = html.startsWith("<!--") && html.endsWith("-->");3031// mode for editing the raw html32const [editMode, setEditMode] = useState<boolean>(false);33const editor = useSlate();3435const setElement = useSetElement(editor, element);3637function renderEditMode() {38if (!editMode) return;39return (40<div style={{ boxShadow: "8px 8px 4px #888" }}>41<SlateCodeMirror42value={html}43onChange={(html) => {44setElement({ html });45}}46onBlur={() => setEditMode(false)}47info="html"48options={{49lineWrapping: true,50autofocus: true,51autoCloseTags: true,52smartIndent: true,53}}54isInline={element["type"] == "html_inline"}55/>56</div>57);58}5960if (element.type == "html_inline") {61return (62<span {...attributes}>63{renderEditMode()}64<code65style={{ color: is_comment ? "#a50" : "#aaa", border }}66onClick={() => {67setEditMode(true);68}}69>70{html}71</code>72{isBR(html) && <br />}73{children}74</span>75);76} else {77if (is_comment) {78return (79<div {...attributes}>80<div style={{ color: "#a50" }}>{html}</div>81{children}82</div>83);84}85return (86<div {...attributes}>87<div88style={{ border }}89contentEditable={false}90onDoubleClick={() => {91setEditMode(true);92}}93>94<HTML value={html} />95{renderEditMode()}96</div>97{children}98</div>99);100}101};102103register({104slateType: "html_inline",105Element,106fromSlate: ({ node }) => node.html as string,107});108109register({110slateType: "html_block",111Element,112fromSlate: ({ node }) => ensure_ends_in_two_newline(node.html as string),113});114115116