Example: temml
Math equation rendering using the Temml library.
Install this example with
shadcn: npx shadcn@latest add @prosekit/react-example-temmlnpx shadcn@latest add @prosekit/preact-example-temmlnpx shadcn@latest add @prosekit/solid-example-temmlimport 'prosekit/basic/style.css'
import 'prosekit/basic/typography.css'
import { createEditor, type NodeJSON } from 'prosekit/core'
import { ProseKit } from 'prosekit/react'
import { useMemo } from 'react'
import { sampleContent } from '../../sample/sample-doc-tex'
import { defineExtension } from './extension'
interface EditorProps {
initialContent?: NodeJSON
}
export default function Editor(props: EditorProps) {
const defaultContent = props.initialContent ?? sampleContent
const editor = useMemo(() => {
const extension = defineExtension()
return createEditor({ extension, defaultContent })
}, [defaultContent])
return (
<ProseKit editor={editor}>
<div className="box-border h-full w-full min-h-36 overflow-y-hidden overflow-x-hidden rounded-md border border-solid border-gray-200 dark:border-gray-700 shadow-sm flex flex-col bg-white dark:bg-gray-950 text-black dark:text-white">
<div className="relative w-full flex-1 box-border overflow-y-auto">
<div ref={editor.mount} className="ProseMirror box-border min-h-full px-[max(4rem,calc(50%-20rem))] py-8 outline-hidden outline-0 [&_span[data-mention=user]]:text-blue-500 [&_span[data-mention=tag]]:text-violet-500"></div>
</div>
</div>
</ProseKit>
)
}import { defineBasicExtension } from 'prosekit/basic'
import { union } from 'prosekit/core'
import { defineMath } from 'prosekit/extensions/math'
import { renderTemmlMathBlock, renderTemmlMathInline } from '../../sample/temml'
export function defineExtension() {
return union(defineBasicExtension(), defineMath({ renderMathBlock: renderTemmlMathBlock, renderMathInline: renderTemmlMathInline }))
}
export type EditorExtension = ReturnType<typeof defineExtension>'use client'
export { default as ExampleEditor } from './editor'import type { NodeJSON } from 'prosekit/core'
const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0`
const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}`
const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}`
export const sampleContent: NodeJSON = {
type: 'doc',
content: [
{
type: 'heading',
attrs: { level: 2 },
content: [{ type: 'text', text: 'Inline equations' }],
},
{
type: 'paragraph',
content: [
{ type: 'text', text: "Euler's identity " },
{ type: 'mathInline', content: [{ type: 'text', text: EULER_IDENTITY }] },
{ type: 'text', text: ' and the quadratic formula ' },
{ type: 'mathInline', content: [{ type: 'text', text: QUADRATIC_FORMULA }] },
{ type: 'text', text: ' can appear within text. Type ' },
{ type: 'text', marks: [{ type: 'code' }], text: '$...$' },
{ type: 'text', text: ' to insert an inline equation.' },
],
},
{
type: 'heading',
attrs: { level: 2 },
content: [{ type: 'text', text: 'Block equations' }],
},
{
type: 'paragraph',
content: [
{ type: 'text', text: 'The Gaussian integral:' },
],
},
{
type: 'mathBlock',
content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }],
},
{
type: 'paragraph',
content: [
{ type: 'text', text: 'Type ' },
{ type: 'text', marks: [{ type: 'code' }], text: '$$' },
{ type: 'text', text: ' in a new line and press Enter to create a block equation.' },
],
},
],
}import Temml from 'temml'
export function renderTemmlMathBlock(text: string, element: HTMLElement) {
Temml.render(text, element, { displayMode: true, annotate: true, throwOnError: false })
}
export function renderTemmlMathInline(text: string, element: HTMLElement) {
Temml.render(text, element, { displayMode: false, annotate: true, throwOnError: false })
}import 'prosekit/basic/style.css'
import 'prosekit/basic/typography.css'
import { useMemo } from 'preact/hooks'
import { createEditor, type NodeJSON } from 'prosekit/core'
import { ProseKit } from 'prosekit/preact'
import { sampleContent } from '../../sample/sample-doc-tex'
import { defineExtension } from './extension'
interface EditorProps {
initialContent?: NodeJSON
}
export default function Editor(props: EditorProps) {
const defaultContent = props.initialContent ?? sampleContent
const editor = useMemo(() => {
const extension = defineExtension()
return createEditor({ extension, defaultContent })
}, [defaultContent])
return (
<ProseKit editor={editor}>
<div className="box-border h-full w-full min-h-36 overflow-y-hidden overflow-x-hidden rounded-md border border-solid border-gray-200 dark:border-gray-700 shadow-sm flex flex-col bg-white dark:bg-gray-950 text-black dark:text-white">
<div className="relative w-full flex-1 box-border overflow-y-auto">
<div ref={editor.mount} className="ProseMirror box-border min-h-full px-[max(4rem,calc(50%-20rem))] py-8 outline-hidden outline-0 [&_span[data-mention=user]]:text-blue-500 [&_span[data-mention=tag]]:text-violet-500"></div>
</div>
</div>
</ProseKit>
)
}import { defineBasicExtension } from 'prosekit/basic'
import { union } from 'prosekit/core'
import { defineMath } from 'prosekit/extensions/math'
import { renderTemmlMathBlock, renderTemmlMathInline } from '../../sample/temml'
export function defineExtension() {
return union(defineBasicExtension(), defineMath({ renderMathBlock: renderTemmlMathBlock, renderMathInline: renderTemmlMathInline }))
}
export type EditorExtension = ReturnType<typeof defineExtension>export { default as ExampleEditor } from './editor'import type { NodeJSON } from 'prosekit/core'
const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0`
const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}`
const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}`
export const sampleContent: NodeJSON = {
type: 'doc',
content: [
{
type: 'heading',
attrs: { level: 2 },
content: [{ type: 'text', text: 'Inline equations' }],
},
{
type: 'paragraph',
content: [
{ type: 'text', text: "Euler's identity " },
{ type: 'mathInline', content: [{ type: 'text', text: EULER_IDENTITY }] },
{ type: 'text', text: ' and the quadratic formula ' },
{ type: 'mathInline', content: [{ type: 'text', text: QUADRATIC_FORMULA }] },
{ type: 'text', text: ' can appear within text. Type ' },
{ type: 'text', marks: [{ type: 'code' }], text: '$...$' },
{ type: 'text', text: ' to insert an inline equation.' },
],
},
{
type: 'heading',
attrs: { level: 2 },
content: [{ type: 'text', text: 'Block equations' }],
},
{
type: 'paragraph',
content: [
{ type: 'text', text: 'The Gaussian integral:' },
],
},
{
type: 'mathBlock',
content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }],
},
{
type: 'paragraph',
content: [
{ type: 'text', text: 'Type ' },
{ type: 'text', marks: [{ type: 'code' }], text: '$$' },
{ type: 'text', text: ' in a new line and press Enter to create a block equation.' },
],
},
],
}import Temml from 'temml'
export function renderTemmlMathBlock(text: string, element: HTMLElement) {
Temml.render(text, element, { displayMode: true, annotate: true, throwOnError: false })
}
export function renderTemmlMathInline(text: string, element: HTMLElement) {
Temml.render(text, element, { displayMode: false, annotate: true, throwOnError: false })
}import 'prosekit/basic/style.css'
import 'prosekit/basic/typography.css'
import { createEditor, type NodeJSON } from 'prosekit/core'
import { ProseKit } from 'prosekit/solid'
import type { JSX } from 'solid-js'
import { sampleContent } from '../../sample/sample-doc-tex'
import { defineExtension } from './extension'
interface EditorProps {
initialContent?: NodeJSON
}
export default function Editor(props: EditorProps): JSX.Element {
const defaultContent = props.initialContent ?? sampleContent
const extension = defineExtension()
const editor = createEditor({ extension, defaultContent })
return (
<ProseKit editor={editor}>
<div class="box-border h-full w-full min-h-36 overflow-y-hidden overflow-x-hidden rounded-md border border-solid border-gray-200 dark:border-gray-700 shadow-sm flex flex-col bg-white dark:bg-gray-950 text-black dark:text-white">
<div class="relative w-full flex-1 box-border overflow-y-auto">
<div ref={editor.mount} class="ProseMirror box-border min-h-full px-[max(4rem,calc(50%-20rem))] py-8 outline-hidden outline-0 [&_span[data-mention=user]]:text-blue-500 [&_span[data-mention=tag]]:text-violet-500"></div>
</div>
</div>
</ProseKit>
)
}import { defineBasicExtension } from 'prosekit/basic'
import { union } from 'prosekit/core'
import { defineMath } from 'prosekit/extensions/math'
import { renderTemmlMathBlock, renderTemmlMathInline } from '../../sample/temml'
export function defineExtension() {
return union(defineBasicExtension(), defineMath({ renderMathBlock: renderTemmlMathBlock, renderMathInline: renderTemmlMathInline }))
}
export type EditorExtension = ReturnType<typeof defineExtension>export { default as ExampleEditor } from './editor'import type { NodeJSON } from 'prosekit/core'
const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0`
const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}`
const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}`
export const sampleContent: NodeJSON = {
type: 'doc',
content: [
{
type: 'heading',
attrs: { level: 2 },
content: [{ type: 'text', text: 'Inline equations' }],
},
{
type: 'paragraph',
content: [
{ type: 'text', text: "Euler's identity " },
{ type: 'mathInline', content: [{ type: 'text', text: EULER_IDENTITY }] },
{ type: 'text', text: ' and the quadratic formula ' },
{ type: 'mathInline', content: [{ type: 'text', text: QUADRATIC_FORMULA }] },
{ type: 'text', text: ' can appear within text. Type ' },
{ type: 'text', marks: [{ type: 'code' }], text: '$...$' },
{ type: 'text', text: ' to insert an inline equation.' },
],
},
{
type: 'heading',
attrs: { level: 2 },
content: [{ type: 'text', text: 'Block equations' }],
},
{
type: 'paragraph',
content: [
{ type: 'text', text: 'The Gaussian integral:' },
],
},
{
type: 'mathBlock',
content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }],
},
{
type: 'paragraph',
content: [
{ type: 'text', text: 'Type ' },
{ type: 'text', marks: [{ type: 'code' }], text: '$$' },
{ type: 'text', text: ' in a new line and press Enter to create a block equation.' },
],
},
],
}import Temml from 'temml'
export function renderTemmlMathBlock(text: string, element: HTMLElement) {
Temml.render(text, element, { displayMode: true, annotate: true, throwOnError: false })
}
export function renderTemmlMathInline(text: string, element: HTMLElement) {
Temml.render(text, element, { displayMode: false, annotate: true, throwOnError: false })
}