Skip to content

Instantly share code, notes, and snippets.

@gerryfletch
Last active August 23, 2023 09:12
Show Gist options
  • Save gerryfletch/09d9995725027fcbf060d0149441c3a8 to your computer and use it in GitHub Desktop.
Save gerryfletch/09d9995725027fcbf060d0149441c3a8 to your computer and use it in GitHub Desktop.
import * as React from "react";
import { CSSProperties, useEffect, useMemo } from "react";
import { MathfieldElement, MathfieldOptions } from "mathlive";
import { create } from "jss";
import camelCase from "jss-plugin-camel-case";
export type MathEditorProps = {
options?: Partial<MathfieldOptions>;
value: string;
onChange: (latex: string) => void;
onPlaceholderChange?: (placeholderId: string, latex: string) => void;
className?: string;
containerStyle?: CSSProperties;
placeholderStyle?: CSSProperties;
};
/**
* @returns a styled math-editor as a non-controlled React component with placeholder support.
*/
export const MathEditor = (props: MathEditorProps) => {
const containerRef = React.useRef<HTMLDivElement>(null);
const mfe = useMemo(() => new MathfieldElement(props.options), []);
useEffect(() => {
const container = containerRef.current!!;
container.innerHTML = "";
container.appendChild(mfe);
mfe.className = props.className || "";
// Listen to changes to main mathfield
mfe.addEventListener("input", ({ target }) =>
props.onChange((target as HTMLInputElement).value || "")
);
// Listen to placeholders, firing if onPlaceholderChange present
mfe.addEventListener("placeholder-change", ({ detail }) => {
const { placeholderId } = detail;
const value = mfe.getPlaceholderField(placeholderId)?.getValue() || "";
if (props.onPlaceholderChange) {
props.onPlaceholderChange(placeholderId, value);
}
});
// Add custom styles to placeholder mathfield elements
Object.values(mfe.placeholders).forEach((placeholder) =>
addStyleEl(placeholder, props.placeholderStyle ?? {})
);
}, []);
useEffect(() => {
mfe.value = props.value;
}, [props.value]);
return <div ref={containerRef} style={props.containerStyle} />;
};
/**
* Mathlive uses shadow DOMs which don't inherit global styles.
* We patch this by creating <style> tags for nested mathlive
* elements. `jss` is used to translate React CSSProperties into
* a stylesheet string which is inserted in a new style node.
* @param el Mathfield element to create styles for
* @param st CSS Properties
*/
const addStyleEl = (el: MathfieldElement, css: CSSProperties) => {
const node = document.createElement("style");
node.innerHTML = stylesheet("placeholder-mathfield", css);
el.appendChild(node);
el.classList.add("placeholder-mathfield");
};
const jss = create({ plugins: [camelCase()] });
const stylesheet = (className: string, styles?: CSSProperties): string =>
jss
.createStyleSheet({ [className]: styles }, { generateId: ({ key }) => key })
.toString();
@enzomarin
Copy link

Hello again, sorry to bother you but I need your help again. It turns out that when I use the virtual keyboard, that floating element appears on the screen that, in addition to being annoying, allows you to modify the mathematical expression (it shouldn't since it is defined as static). I've tried looking in the documentation but I can't find what it is or how to disable it.
Captura de pantalla 2023-08-23 a la(s) 00 04 56

@gerryfletch
Copy link
Author

Hey @enzomarin I haven't used or updated mathlive in months, but I don't recall seeing that floating window before so it may be something new. I'd advise raising a discussion on the main repository or on Gitter if the community is still active on there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment