Path: blob/master/src/packages/frontend/editors/slate/elements/math/math-widget.tsx
1698 views
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45// Katex support -- NOTE: this import of katex is pretty LARGE.6import "katex/dist/katex.min.css";78// Everything else.9import {10React,11useEffect,12useFrameContext,13useRef,14useState,15} from "@cocalc/frontend/app-framework";16import { SlateCodeMirror } from "../codemirror";17import { useFocused, useSelected } from "../../slate-react";18import { useCollapsed } from "../hooks";19import { StaticElement } from "./index";20import { Popover } from "antd";21import { Icon } from "@cocalc/frontend/components/icon";2223interface Props {24value: string;25isInline: boolean;26onChange?: (string) => void;27}2829export const SlateMath: React.FC<Props> = React.memo(30({ value, onChange, isInline }) => {31const [editMode, setEditMode] = useState<boolean>(false);32const frameContext = useFrameContext();33const justBlurred = useRef<boolean>(false);3435const focused = useFocused();36const selected = useSelected();37const collapsed = useCollapsed();3839useEffect(() => {40if (focused && selected && collapsed && !justBlurred.current) {41setEditMode(true);42}43}, [selected, focused, collapsed]);4445function renderLaTeX() {46const Element = isInline ? "span" : "div";47return (48<Element49style={50editMode51? {52color: "#337ab7",53border: "1px solid #337ab7",54borderRadius: "8px",55...(isInline56? { margin: "-7px -3px", padding: "6px 2px" }57: undefined),58}59: !isInline60? { border: "1px solid transparent" }61: undefined62}63onClick={async (e) => {64e.preventDefault();65e.stopPropagation();66// switch to edit mode when you click on it.67setEditMode?.(true);68// also make the frame containing this active... if we're in a frame editor (hence the ?. !)69frameContext.actions?.set_active_id?.(frameContext.id);70}}71>72{/* below since we are abusing the StaticElement component a bit */}73<StaticElement74element={75{ value, type: isInline ? "math_inline" : "math_block" } as any76}77children={undefined}78attributes={{} as any}79/>80</Element>81);82}83// putting renderEditMode before is critical since as we type, length of formula changes,84// and default would move the popover as we type, which is horrible8586// !frameContext.project_id is so that this also works when using editor outside of any87// particular project.88const open =89editMode &&90((frameContext.isFocused && frameContext.isVisible) ||91!frameContext.project_id);9293return (94<span contentEditable={false} style={{ cursor: "pointer" }}>95<Popover96open={open}97destroyOnHidden98title={99<>100<Icon name="pencil" style={{ marginRight: "5px" }} />{" "}101{isInline ? "Inline" : "Display"} LaTeX Mathematics102</>103}104content={() => (105<SlateCodeMirror106style={{ maxWidth: "90vw", width: "700px" }}107value={value}108onChange={(value) => {109onChange?.(value.trim().replace(/^\s*[\r\n]/gm, ""));110}}111onBlur={() => {112justBlurred.current = true;113setTimeout(() => {114justBlurred.current = false;115}, 1);116setEditMode(false);117}}118info="tex"119options={{120lineWrapping: true,121autofocus: true,122}}123isInline={true}124/>125)}126>127{renderLaTeX()}128</Popover>129</span>130);131},132);133134135