@barocss/math-editor 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ADAPTERS.md +31 -2
- package/API-JAVASCRIPT.md +157 -0
- package/API-REACT.md +202 -0
- package/API-SESSION.md +163 -0
- package/API-SOLID.md +90 -0
- package/API-SVELTE.md +83 -0
- package/API-VUE.md +104 -0
- package/API-WEB-COMPONENT.md +128 -0
- package/CHANGELOG.md +16 -0
- package/EMBEDDING.md +7 -0
- package/IMPLEMENTATION.md +132 -1
- package/JSON-MODEL.md +441 -0
- package/LATEX-GUIDE.md +248 -0
- package/LATEX-MODEL.md +290 -0
- package/LATEX-SCOPE.md +260 -4
- package/LOCALIZATION.md +7 -1
- package/README.md +91 -4
- package/RELEASING.md +1 -1
- package/ROADMAP.md +107 -16
- package/SUPPORT.md +128 -13
- package/SYMBOLS.md +33 -1
- package/VALIDATION.md +171 -0
- package/dist/core.d.ts +2 -0
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +2 -0
- package/dist/core.js.map +1 -1
- package/dist/document-codec.d.ts +4 -0
- package/dist/document-codec.d.ts.map +1 -0
- package/dist/document-codec.js +37 -0
- package/dist/document-codec.js.map +1 -0
- package/dist/dom/menu-position.d.ts +3 -0
- package/dist/dom/menu-position.d.ts.map +1 -0
- package/dist/dom/menu-position.js +44 -0
- package/dist/dom/menu-position.js.map +1 -0
- package/dist/dom/toolbar.d.ts +2 -0
- package/dist/dom/toolbar.d.ts.map +1 -1
- package/dist/dom/toolbar.js +16 -1
- package/dist/dom/toolbar.js.map +1 -1
- package/dist/dom.d.ts +1 -0
- package/dist/dom.d.ts.map +1 -1
- package/dist/dom.js +134 -24
- package/dist/dom.js.map +1 -1
- package/dist/editor-labels.d.ts.map +1 -1
- package/dist/editor-labels.js +42 -0
- package/dist/editor-labels.js.map +1 -1
- package/dist/fences.d.ts +11 -0
- package/dist/fences.d.ts.map +1 -0
- package/dist/fences.js +21 -0
- package/dist/fences.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/latex.d.ts +26 -0
- package/dist/latex.d.ts.map +1 -0
- package/dist/latex.js +689 -0
- package/dist/latex.js.map +1 -0
- package/dist/locales/en.js +108 -1
- package/dist/locales/en.json +108 -1
- package/dist/locales/ko.js +120 -2
- package/dist/locales/ko.json +120 -2
- package/dist/math-editor-toolbar.d.ts +5 -2
- package/dist/math-editor-toolbar.d.ts.map +1 -1
- package/dist/math-editor-toolbar.js +10 -6
- package/dist/math-editor-toolbar.js.map +1 -1
- package/dist/math-editor.d.ts +24 -4
- package/dist/math-editor.d.ts.map +1 -1
- package/dist/math-editor.js +218 -39
- package/dist/math-editor.js.map +1 -1
- package/dist/model.d.ts +10 -2
- package/dist/model.d.ts.map +1 -1
- package/dist/model.js +262 -9
- package/dist/model.js.map +1 -1
- package/dist/range.d.ts +1 -1
- package/dist/range.d.ts.map +1 -1
- package/dist/range.js +116 -6
- package/dist/range.js.map +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.d.ts.map +1 -1
- package/dist/session.d.ts +3 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +9 -1
- package/dist/session.js.map +1 -1
- package/dist/suggestions.d.ts +4 -0
- package/dist/suggestions.d.ts.map +1 -1
- package/dist/suggestions.js +158 -21
- package/dist/suggestions.js.map +1 -1
- package/dist/symbols.d.ts +1 -1
- package/dist/symbols.d.ts.map +1 -1
- package/dist/symbols.js +56 -5
- package/dist/symbols.js.map +1 -1
- package/package.json +3 -2
- package/src/fonts/KaTeX_AMS-Regular.woff2 +0 -0
- package/src/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
- package/src/fonts/KaTeX_Main-Bold.woff2 +0 -0
- package/src/fonts/KaTeX_Main-Regular.woff2 +0 -0
- package/src/fonts/KaTeX_Size2-Regular.woff2 +0 -0
- package/src/fonts/LICENSE-KaTeX.txt +21 -0
- package/src/style.css +868 -45
package/API-SVELTE.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Svelte API guide
|
|
2
|
+
|
|
3
|
+
`mathEditor` is a Svelte action around the native DOM editor. Svelte 5 is covered by the integration harness; the package peer range also permits Svelte 4, which is not separately certified.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install @barocss/math-editor@0.2.0 svelte
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Complete component
|
|
12
|
+
|
|
13
|
+
This legacy-syntax component works with Svelte 4 and Svelte 5:
|
|
14
|
+
|
|
15
|
+
```svelte
|
|
16
|
+
<script lang="ts">
|
|
17
|
+
import { mathEditor } from '@barocss/math-editor/svelte';
|
|
18
|
+
import type { DOMMathEditorOptions } from '@barocss/math-editor/dom';
|
|
19
|
+
import '@barocss/math-editor/style.css';
|
|
20
|
+
|
|
21
|
+
let locale = 'en';
|
|
22
|
+
let latex = '';
|
|
23
|
+
$: options = {
|
|
24
|
+
locale,
|
|
25
|
+
mode: 'inline',
|
|
26
|
+
toolbar: false,
|
|
27
|
+
onChange(document, output) {
|
|
28
|
+
latex = output;
|
|
29
|
+
// Persist document through your application here.
|
|
30
|
+
},
|
|
31
|
+
} satisfies DOMMathEditorOptions;
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<button on:click={() => locale = locale === 'en' ? 'ko' : 'en'}>Language</button>
|
|
35
|
+
<div use:mathEditor={options}></div>
|
|
36
|
+
<pre>{latex}</pre>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
In a Svelte 5 runes component, use `$state` for locale/output and `$derived` for the options object. The action itself is unchanged.
|
|
40
|
+
|
|
41
|
+
## Action contract
|
|
42
|
+
|
|
43
|
+
`mathEditor(host, options)` returns `update(next)` and `destroy()`. Svelte invokes these as the action parameter changes and the element is removed. Mutable options merge into the renderer; explicitly use `toolbar: false` to hide tools.
|
|
44
|
+
|
|
45
|
+
For an external toolbar or loading another document, create one `createMathSession()` per component instance and pass it as `session`. Call `session.load(validatedDocument)` to reset document/history. Use `onDestroy` to release host subscriptions and the external session. Do not expect a changed `defaultValue` or `session` action parameter to remount the editor; use a keyed block for a deliberate remount.
|
|
46
|
+
|
|
47
|
+
## Popup and SSR
|
|
48
|
+
|
|
49
|
+
Actions mount in the browser. Avoid `document`, `window` and localStorage at module initialization in SSR applications. A popup should create a fresh draft session and commit only on Apply. `onCancel` is a host notification; it does not close your dialog or revert your data automatically. Keep the action host empty; do not render Svelte children into its editor subtree.
|
|
50
|
+
|
|
51
|
+
## Svelte 5 runes: session, Undo and saved snapshot
|
|
52
|
+
|
|
53
|
+
This is a complete runes component, not legacy `$:` syntax. Save retains a structured snapshot in memory; Restore deliberately resets undo history. Replace the in-memory persistence with the storage adapter in the shared API when needed.
|
|
54
|
+
|
|
55
|
+
```svelte
|
|
56
|
+
<script lang="ts">
|
|
57
|
+
import { onDestroy } from 'svelte';
|
|
58
|
+
import { mathEditor } from '@barocss/math-editor/svelte';
|
|
59
|
+
import { createMathSession, createMathDocument } from '@barocss/math-editor/core';
|
|
60
|
+
import '@barocss/math-editor/style.css';
|
|
61
|
+
|
|
62
|
+
let saved = createMathDocument('x');
|
|
63
|
+
const session = createMathSession({ document: saved, locale: 'en' });
|
|
64
|
+
let snapshot = $state(session.getSnapshot());
|
|
65
|
+
const unsubscribe = session.subscribe(next => { snapshot = next; });
|
|
66
|
+
onDestroy(() => { unsubscribe(); session.destroy(); });
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<button disabled={!snapshot.canUndo} onclick={() => session.execute({ type: 'undo' })}>Undo</button>
|
|
70
|
+
<button disabled={!snapshot.canRedo} onclick={() => session.execute({ type: 'redo' })}>Redo</button>
|
|
71
|
+
<button onclick={() => { saved = session.getSnapshot().state.document; }}>Save</button>
|
|
72
|
+
<button onclick={() => session.load(saved)}>Restore saved</button>
|
|
73
|
+
<div use:mathEditor={{ session, locale: 'en' }}></div>
|
|
74
|
+
<pre>{snapshot.latex}</pre>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Persistence and ownership
|
|
78
|
+
|
|
79
|
+
Persist the `MathDocument` passed to `onChange`; LaTeX is derived output and is not an editable round-trip format. The package does not parse arbitrary LaTeX. Validate externally supplied JSON before loading it: loading assumes a trusted, structurally valid document with unique IDs. There is no server save or collaboration transport built in.
|
|
80
|
+
|
|
81
|
+
Keep the mount host empty. The editor owns its descendants; framework rendering into the same host can destroy caret and composition state. Use one editing surface per session. Destroy the renderer on teardown; a session supplied by the host remains the host's responsibility.
|
|
82
|
+
|
|
83
|
+
See [session and DOM API](API-SESSION.md) for exact options, commands, events and cleanup, and [renderer differences](ADAPTERS.md#current-renderer-parity) before choosing a native wrapper over the rich React editor.
|
package/API-VUE.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Vue 3 API guide
|
|
2
|
+
|
|
3
|
+
The `vMathEditor` directive mounts the native DOM editor. It is not a Vue component and does not implement `v-model`.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install @barocss/math-editor@0.2.0 vue
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Complete component
|
|
12
|
+
|
|
13
|
+
```vue
|
|
14
|
+
<script setup lang="ts">
|
|
15
|
+
import { computed, ref } from 'vue';
|
|
16
|
+
import { vMathEditor } from '@barocss/math-editor/vue';
|
|
17
|
+
import type { MathDocument } from '@barocss/math-editor/core';
|
|
18
|
+
import type { DOMMathEditorOptions } from '@barocss/math-editor/dom';
|
|
19
|
+
import '@barocss/math-editor/style.css';
|
|
20
|
+
|
|
21
|
+
const locale = ref('en');
|
|
22
|
+
const latex = ref('');
|
|
23
|
+
const saved = ref<MathDocument>();
|
|
24
|
+
const options = computed<DOMMathEditorOptions>(() => ({
|
|
25
|
+
locale: locale.value,
|
|
26
|
+
mode: 'inline',
|
|
27
|
+
toolbar: false,
|
|
28
|
+
onChange(document, output) {
|
|
29
|
+
saved.value = document;
|
|
30
|
+
latex.value = output;
|
|
31
|
+
},
|
|
32
|
+
}));
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<template>
|
|
36
|
+
<button @click="locale = locale === 'en' ? 'ko' : 'en'">Language</button>
|
|
37
|
+
<div v-math-editor="options"></div>
|
|
38
|
+
<pre>{{ latex }}</pre>
|
|
39
|
+
</template>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
With `<script setup>`, the imported `vMathEditor` is available as `v-math-editor`. Outside script setup, register it under `directives: { mathEditor: vMathEditor }`.
|
|
43
|
+
|
|
44
|
+
## Lifecycle and document replacement
|
|
45
|
+
|
|
46
|
+
| Vue hook | Adapter behavior |
|
|
47
|
+
|---|---|
|
|
48
|
+
| `mounted` | `mountMathEditor(host, options)` |
|
|
49
|
+
| `updated` | `editor.update(options)` |
|
|
50
|
+
| `unmounted` | `editor.destroy()` |
|
|
51
|
+
|
|
52
|
+
Reactive options change locale, mode, toolbar and callbacks without replacing history. `defaultValue` and `session` are mount-only; updating the options object is not a document load.
|
|
53
|
+
|
|
54
|
+
For commands or opening another document, create one `createMathSession()` instance in setup, pass it as `session` in options, and call `session.load(validatedDocument)`. Register host subscription cleanup and `session.destroy()` with `onUnmounted`. Avoid deeply proxying the session or recreating it inside a computed getter.
|
|
55
|
+
|
|
56
|
+
## Inline, popup and SSR
|
|
57
|
+
|
|
58
|
+
Use `mode: 'inline'` and `onCommit`/`onExit` for host caret handoff. In a modal, pass the modal element as mount-only `menuHost` when required by its focus trap. A new modal draft session keeps Cancel from modifying the original. Vue's `mounted` hook runs client-side; browser storage still belongs in your own client lifecycle. Keep the directive host empty and do not combine it with `v-html` or rendered children.
|
|
59
|
+
|
|
60
|
+
## Document switching, history buttons and explicit save
|
|
61
|
+
|
|
62
|
+
This complete component uses two trusted in-memory documents. Save stores a snapshot; switching tabs discards unsaved changes and resets history. Add a dirty-state confirmation in a product that must protect unsaved edits. The session is a plain variable, not a deeply reactive object.
|
|
63
|
+
|
|
64
|
+
```vue
|
|
65
|
+
<script setup lang="ts">
|
|
66
|
+
import { ref, shallowRef, onUnmounted } from 'vue';
|
|
67
|
+
import { vMathEditor } from '@barocss/math-editor/vue';
|
|
68
|
+
import { createMathSession, createMathDocument } from '@barocss/math-editor/core';
|
|
69
|
+
import '@barocss/math-editor/style.css';
|
|
70
|
+
|
|
71
|
+
const documents = [createMathDocument('x'), createMathDocument('y')];
|
|
72
|
+
const active = ref(0);
|
|
73
|
+
const session = createMathSession({ document: documents[0], locale: 'en' });
|
|
74
|
+
const snapshot = shallowRef(session.getSnapshot());
|
|
75
|
+
const unsubscribe = session.subscribe(next => { snapshot.value = next; });
|
|
76
|
+
const options = { session, locale: 'en' };
|
|
77
|
+
function open(index: number) {
|
|
78
|
+
active.value = index;
|
|
79
|
+
session.load(documents[index]);
|
|
80
|
+
}
|
|
81
|
+
function save() {
|
|
82
|
+
documents[active.value] = session.getSnapshot().state.document;
|
|
83
|
+
}
|
|
84
|
+
onUnmounted(() => { unsubscribe(); session.destroy(); });
|
|
85
|
+
</script>
|
|
86
|
+
|
|
87
|
+
<template>
|
|
88
|
+
<button @click="open(0)">Formula A</button>
|
|
89
|
+
<button @click="open(1)">Formula B</button>
|
|
90
|
+
<button :disabled="!snapshot.canUndo" @click="session.execute({ type: 'undo' })">Undo</button>
|
|
91
|
+
<button :disabled="!snapshot.canRedo" @click="session.execute({ type: 'redo' })">Redo</button>
|
|
92
|
+
<button @click="save">Save formula {{ active + 1 }}</button>
|
|
93
|
+
<div v-math-editor="options"></div>
|
|
94
|
+
<pre>{{ snapshot.latex }}</pre>
|
|
95
|
+
</template>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Persistence and ownership
|
|
99
|
+
|
|
100
|
+
Persist the `MathDocument` passed to `onChange`; LaTeX is derived output and is not an editable round-trip format. The package does not parse arbitrary LaTeX. Validate externally supplied JSON before loading it: loading assumes a trusted, structurally valid document with unique IDs. There is no server save or collaboration transport built in.
|
|
101
|
+
|
|
102
|
+
Keep the mount host empty. The editor owns its descendants; framework rendering into the same host can destroy caret and composition state. Use one editing surface per session. Destroy the renderer on teardown; a session supplied by the host remains the host's responsibility.
|
|
103
|
+
|
|
104
|
+
See [session and DOM API](API-SESSION.md) for exact options, commands, events and cleanup, and [renderer differences](ADAPTERS.md#current-renderer-parity) before choosing a native wrapper over the rich React editor.
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Web Component API guide
|
|
2
|
+
|
|
3
|
+
Use the custom element with plain HTML or a framework that can pass DOM properties and listen to native events. It uses the native renderer and light DOM, with no React dependency.
|
|
4
|
+
|
|
5
|
+
## Install and register
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install @barocss/math-editor@0.2.0
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
import { defineMathEditor } from '@barocss/math-editor/web-component';
|
|
13
|
+
import '@barocss/math-editor/style.css';
|
|
14
|
+
defineMathEditor();
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```html
|
|
18
|
+
<barocss-math-editor locale="en" mode="inline" toolbar="false"></barocss-math-editor>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Call registration on the client. The default tag is `barocss-math-editor`; `defineMathEditor('my-formula')` registers a custom name. Repeated registration returns the existing constructor. Do not choose a tag another library owns.
|
|
22
|
+
|
|
23
|
+
## Properties and commands
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import type { MathEditorElement } from '@barocss/math-editor/web-component';
|
|
27
|
+
import { createMathDocument } from '@barocss/math-editor/core';
|
|
28
|
+
|
|
29
|
+
const editor = document.querySelector<MathEditorElement>('barocss-math-editor');
|
|
30
|
+
if (!editor) throw new Error('Missing math element');
|
|
31
|
+
editor.value = createMathDocument('x'); // trusted MathDocument, resets undo
|
|
32
|
+
editor.session.execute({ type: 'structure', kind: 'superscript' });
|
|
33
|
+
editor.focusEditor();
|
|
34
|
+
const documentToSave = editor.value; // snapshot copy
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Use the `value` **property**, not a JSON HTML attribute. Assigning it opens a new document and resets undo. The `session` property is readonly but its methods are available for commands, subscription and loading.
|
|
38
|
+
|
|
39
|
+
## Attributes
|
|
40
|
+
|
|
41
|
+
| Attribute | Values / default |
|
|
42
|
+
|---|---|
|
|
43
|
+
| `locale` | Registered locale code, default `ko` |
|
|
44
|
+
| `mode` | `inline` or `block`; default block |
|
|
45
|
+
| `toolbar` | `false` hides it; otherwise present means visible; absent follows mode |
|
|
46
|
+
| `line-numbers` | `false` hides UI line numbers; otherwise visible |
|
|
47
|
+
| `enter-behavior` | `commit` overrides block newline behavior; otherwise follows mode |
|
|
48
|
+
|
|
49
|
+
Set inline mode before loading a document. Inline mode rejects multiple top-level rows. Presence-only `toolbar` is true, whereas `toolbar="false"` is false.
|
|
50
|
+
|
|
51
|
+
## Events
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
const save = event => {
|
|
55
|
+
const { document, latex } = event.detail;
|
|
56
|
+
console.log(document, latex);
|
|
57
|
+
};
|
|
58
|
+
editor.addEventListener('math-change', save);
|
|
59
|
+
editor.addEventListener('math-commit', event => console.log(event.detail.state.document));
|
|
60
|
+
editor.addEventListener('math-exit', event => console.log(event.detail.direction));
|
|
61
|
+
editor.addEventListener('math-cancel', () => console.log('Host decides whether to close'));
|
|
62
|
+
// On host teardown, remove your own listeners:
|
|
63
|
+
// editor.removeEventListener('math-change', save);
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
| Event | `detail` |
|
|
67
|
+
|---|---|
|
|
68
|
+
| `math-change` | `{ document, latex }` |
|
|
69
|
+
| `math-commit` | Full `MathSessionSnapshot` |
|
|
70
|
+
| `math-exit` | `{ direction: -1 | 1 }` |
|
|
71
|
+
| `math-cancel` | No detail payload |
|
|
72
|
+
|
|
73
|
+
Events bubble and are composed. Disconnect destroys the renderer; reconnect restores the same session/document/history. Permanent removal should also release host-owned subscriptions. Shared styles must be loaded in the page because this is light DOM, not a shadow-root widget.
|
|
74
|
+
|
|
75
|
+
## Complete form integration with JSON and LaTeX outputs
|
|
76
|
+
|
|
77
|
+
Custom elements do not automatically submit their document as form data. This function builds the form, synchronizes hidden fields, and calls a host callback with `FormData`. It does not assume a backend URL. Pass a trusted initial document and call the returned cleanup on route removal.
|
|
78
|
+
|
|
79
|
+
```js
|
|
80
|
+
import { defineMathEditor } from '@barocss/math-editor/web-component';
|
|
81
|
+
import '@barocss/math-editor/style.css';
|
|
82
|
+
|
|
83
|
+
export function mountFormulaForm(host, initialDocument, onSubmit) {
|
|
84
|
+
defineMathEditor();
|
|
85
|
+
const form = document.createElement('form');
|
|
86
|
+
const editor = document.createElement('barocss-math-editor');
|
|
87
|
+
editor.setAttribute('locale', 'en');
|
|
88
|
+
editor.value = initialDocument;
|
|
89
|
+
const json = document.createElement('input');
|
|
90
|
+
const latex = document.createElement('input');
|
|
91
|
+
json.type = latex.type = 'hidden';
|
|
92
|
+
json.name = 'formulaDocument';
|
|
93
|
+
latex.name = 'formulaLatex';
|
|
94
|
+
const button = document.createElement('button');
|
|
95
|
+
button.type = 'submit';
|
|
96
|
+
button.textContent = 'Save formula';
|
|
97
|
+
const sync = () => {
|
|
98
|
+
const snapshot = editor.session.getSnapshot();
|
|
99
|
+
json.value = JSON.stringify(snapshot.state.document);
|
|
100
|
+
latex.value = snapshot.latex;
|
|
101
|
+
};
|
|
102
|
+
const submit = event => {
|
|
103
|
+
event.preventDefault();
|
|
104
|
+
sync(); // Include the initial value even when no edit occurred.
|
|
105
|
+
onSubmit(new FormData(form));
|
|
106
|
+
};
|
|
107
|
+
editor.addEventListener('math-change', sync);
|
|
108
|
+
form.addEventListener('submit', submit);
|
|
109
|
+
form.append(editor, json, latex, button);
|
|
110
|
+
host.append(form);
|
|
111
|
+
sync();
|
|
112
|
+
return () => {
|
|
113
|
+
editor.removeEventListener('math-change', sync);
|
|
114
|
+
form.removeEventListener('submit', submit);
|
|
115
|
+
form.remove(); // disconnectedCallback releases the native renderer.
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
The JSON field is the editable source; LaTeX is an export. Validate and authorize submitted JSON on your server. Browser form fields are not a trust boundary. The host callback can implement pending/error UI around its own request.
|
|
121
|
+
|
|
122
|
+
## Persistence and ownership
|
|
123
|
+
|
|
124
|
+
Persist the `MathDocument` passed to `onChange`; LaTeX is derived output and is not an editable round-trip format. The package does not parse arbitrary LaTeX. Validate externally supplied JSON before loading it: loading assumes a trusted, structurally valid document with unique IDs. There is no server save or collaboration transport built in.
|
|
125
|
+
|
|
126
|
+
Keep the mount host empty. The editor owns its descendants; framework rendering into the same host can destroy caret and composition state. Use one editing surface per session. Destroy the renderer on teardown; a session supplied by the host remains the host's responsibility.
|
|
127
|
+
|
|
128
|
+
See [session and DOM API](API-SESSION.md) for exact options, commands, events and cleanup, and [renderer differences](ADAPTERS.md#current-renderer-parity) before choosing a native wrapper over the rich React editor.
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @barocss/math-editor
|
|
2
2
|
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Add bounded LaTeX import and validated JSON loading with atomic diagnostics and undoable editor imports. Expand editable notation with combined scripts, matrices and cases, integral and limit variants, scalable fences and radicals, accents and brace annotations, explicit sizes, mathematical alphabets, spacing and labeled arrows. Import unnumbered equation wrappers without numbering semantics.
|
|
8
|
+
|
|
9
|
+
Improve model-based selection, copying, pasting and wrapping; compact configurable toolbars; and editing typography and focus presentation. Complete English/Korean labels for the new catalog and validate locale pack structure and coverage. Update API, model, syntax, localization and embedding guides. Framework subpaths share this release; unsupported TeX macros, numbering and additional environments remain explicitly excluded.
|
|
10
|
+
|
|
11
|
+
### Editing and compatibility details
|
|
12
|
+
|
|
13
|
+
- Preserve combined scripts, delimiter sizing, integral bounds and limit placement. Add norms, multiple/contour integrals, annotations, accents, explicit fraction/binomial sizes, scoped alphabets, fine spacing and labeled arrows.
|
|
14
|
+
- Improve arrow discovery, Korean keyword search, matrix presets, toolbar expansion and focus/spacing geometry using KaTeX comparisons.
|
|
15
|
+
- Import `equation*` as formula content; reject numbering, macros and unsupported environments without modifying the existing document.
|
|
16
|
+
- Keep en/ko message keys inside validated JSON packs. Custom locale dictionaries retain English fallback.
|
|
17
|
+
|
|
3
18
|
## 0.1.0
|
|
4
19
|
|
|
5
20
|
Initial public release.
|
|
@@ -11,3 +26,4 @@ Initial public release.
|
|
|
11
26
|
- English/Korean JSON locale packs and host-registered translations and suggestion aliases.
|
|
12
27
|
|
|
13
28
|
The native surface has documented feature differences from the rich React editor. See ADAPTERS.md and VALIDATION.md for the supported scope. This release does not parse arbitrary LaTeX or evaluate expressions.
|
|
29
|
+
|
package/EMBEDDING.md
CHANGED
|
@@ -93,3 +93,10 @@ The layout lab demonstrates the interaction contracts; it is not installation in
|
|
|
93
93
|
Open `/layouts.html` in the math demo. Toggle each optional surface, edit the independent inline example, press Enter to create another host block, and open/cancel/apply the popup. Existing React UI and all framework adapters remain on `/` and `/adapters.html`.
|
|
94
94
|
|
|
95
95
|
The browser tests cover panel synchronization without extra change events, single-row completion, separate next-block creation, modal mouse suggestions, popup cancellation and one-step undo after applying a draft. OS IME testing remains deferred; this is not a full product integration certification.
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
## Note trial (0.2.0)
|
|
99
|
+
|
|
100
|
+
Note opts into the shared `LatexEditor` visual mode with `MathEditorSurface`. Existing tex-only atoms load through `parseLatex`; unsupported input stays in the original source editor. Visual draft changes produce `tex` plus JSON-encoded `mathDocument`. `setMathSource` validates the structure, source equality and inline policy, then applies one host transaction. Cancellation writes nothing. Direct source changes clear stale structure, while font/alignment-only edits retain it.
|
|
101
|
+
|
|
102
|
+
Other products must use the same [import scope](LATEX-SCOPE.md) and core parser. Do not add product-specific regex conversions. Existing Word OMML and Site/Slide ownership boundaries still need their own host adapters; the Note trial does not integrate those products automatically.
|
package/IMPLEMENTATION.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Implementation guide
|
|
2
2
|
|
|
3
|
+
See the [JSON model specification](JSON-MODEL.md) for required fields, exact slot order, invariants and persistence limits.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
See [LaTeX → JSON model mapping](LATEX-MODEL.md) for node types, slot order and complete conversion examples.
|
|
7
|
+
|
|
8
|
+
|
|
3
9
|
## Ownership and data flow
|
|
4
10
|
|
|
5
11
|
The host owns document persistence, placement and outer focus. `MathEditor` owns an editing session, its caret, composition draft, model range and up to 100 previous history states. Do not record each internal change into a second host undo stack without a session adapter.
|
|
@@ -62,7 +68,7 @@ Pointer hit testing uses token rectangles and mirror text ranges. A drag inside
|
|
|
62
68
|
|
|
63
69
|
`wrapRange` accepts one selected row and one of the supported wrapper kinds. It copies that balanced fragment into the new structure and replaces the range through `pasteFragment`. Fraction/power/subscript operations focus their empty second slot. Other wrappers leave the caret after the inserted structure. Power bases receive parentheses unless they are a simple name/number or an already grouped structure. This rule is not a precedence parser and does not infer algebraic equivalence.
|
|
64
70
|
|
|
65
|
-
The UI disables unsupported structural insertion while a model range is selected. Template insertion explicitly replaces the selection.
|
|
71
|
+
The UI disables unsupported structural insertion while a model range is selected. Template insertion explicitly replaces the selection. Selection actions use the regular portaled suggestion list beside the selected range. Printable keyboard input replaces a model selection and focuses the resulting input.
|
|
66
72
|
|
|
67
73
|
## Clipboard boundary
|
|
68
74
|
|
|
@@ -109,3 +115,128 @@ The existing React renderer still owns its original history and token-level inpu
|
|
|
109
115
|
The math package and demo source/CSS are consistently formatted. The React toolbar and native toolbar were extracted without moving caret/history ownership. Comments explain composition identity, publication/save notifications and structural clipboard boundaries. Formatting is intentionally separate from changing the selection algorithms: the two renderer implementations are still present.
|
|
110
116
|
|
|
111
117
|
Output views subscribe to one session and skip caret-only redraws. Host completion is explicit (`onCommit`, `onCancel`, `onExit`) and independent of the single-top-level-line model policy. Popup drafts apply through a transaction, not a history-resetting load. See [Embedding](EMBEDDING.md) for the layouts, product-specific data mismatches and the next integration gates.
|
|
118
|
+
|
|
119
|
+
### Workspace: binomial and operand suggestions
|
|
120
|
+
|
|
121
|
+
`binomial` has exactly two slots, upper then lower, and serializes as `\binom{n}{k}`. It shares validation, wrapping, navigation and undo with other structures. Operand suggestions carry `wrapOperand: true`, so acceptance preserves the query as a selected operand instead of deleting it. Both React and native DOM use the same acceptance function. In operand-only menus, bare Enter retains normal behavior until an arrow key selects an action.
|
|
122
|
+
|
|
123
|
+
### Workspace: limits and function colors
|
|
124
|
+
|
|
125
|
+
`limit` stores `[condition, body]` and exports `\lim_{condition}{body}`. Parsing accepts an optional lower condition and one body atom; missing slots stay editable. Repeated lower conditions and upper-limit syntax fail atomically. The React and native renderers stack the condition beneath the `lim` glyph, then render the body alongside it. Function names and `lim` use `--me-function` (default `#087b78`); nested slot tokens keep their own semantic colors.
|
|
126
|
+
|
|
127
|
+
### Workspace: imported notation compatibility
|
|
128
|
+
|
|
129
|
+
- Implemented `quad`/`qquad` as zero-slot spacing nodes, including suggestion insertion and deletion/Undo.
|
|
130
|
+
- Preserved explicit `limits: true` on sum/product/integral/limit nodes through import/export.
|
|
131
|
+
- Implemented one-slot `roman` groups: scoped `\rm` declarations normalize to `\mathrm{…}`. Parsing restores the enclosing expression boundary after nested groups.
|
|
132
|
+
- Regression fixtures include the reported quotient limit with Chinese text, the three-sum inequality and the chain-rule derivative.
|
|
133
|
+
|
|
134
|
+
### Workspace: fences, annotations and indexed-root rendering
|
|
135
|
+
|
|
136
|
+
Added curly/angle fences, open-closed and closed-open interval presets, generic fences with independent ends, and annotation/body nodes for overset/underset. Both renderers share the physical delimiter definitions. Selection wrapping retains the original expression and focuses the annotation when appropriate. Indexed roots now draw a radical that meets the overbar at the same coordinate, with the index overlapping its shoulder.
|
|
137
|
+
|
|
138
|
+
## Editing typography and focus: 2026-09-08 (workspace)
|
|
139
|
+
|
|
140
|
+
Active token inputs use a tinted background and caret without an outline or outer halo. Forced-colors mode retains its system focus outline. Toolbar, suggestion and surface keyboard-focus indicators keep their own rules. This changes presentation only; selection, clipboard and JSON/LaTeX output are unchanged.
|
|
141
|
+
|
|
142
|
+
Single-script slots use inline flex layout to avoid an extra line-box descent below the base. Passive boundary targets within script bases are 1px wide and expand when focused; text and single-script wrappers omit extra side margins. This aligns coefficients with the base and brings subscripts closer without removing editable caret positions.
|
|
143
|
+
|
|
144
|
+
The stylesheet bundles the MIT-licensed KaTeX Main font as `Barocss Math Glyphs`, scoped to ASCII digits and U+223C. Digits have consistent lining heights, and the similarity sign stays distinct from infinity. Other glyphs retain their existing font fallback. Consumers must ship the stylesheet's relative font asset and license.
|
|
145
|
+
|
|
146
|
+
### Workspace spacing refinement
|
|
147
|
+
|
|
148
|
+
Grid fences reuse the scalable parenthesis/brace masks. Grid gaps are 4px vertically and 12px horizontally with 3px/5px padding. Fraction/script/accent slots use flex boxes to avoid extra text-line descent. Nested fraction text is bounded at 16px and then 12px; this is a conservative local rule, not a complete TeX display/text/script style engine. Combined scripts keep 16px text with tighter line height. Active structural boundaries now use a 12px minimum; real empty slots retain their existing larger targets. Accent offsets and large-operator body spacing are reduced. These shared CSS rules apply to rich React and native DOM.
|
|
149
|
+
|
|
150
|
+
## Required visual check for notation changes
|
|
151
|
+
|
|
152
|
+
For every new mathematical feature or LaTeX syntax extension, compare the editor with KaTeX rendering of the same exported expression before completion. Check both rich React and native DOM, passive and active inputs, empty and populated slots, and representative nesting. Review delimiter/glyph shapes, baselines, script sizes, accent and limit placement, spacing, clipping and focus-induced movement. Adjust the editor as part of the feature, not as deferred visual polish. Preserve usable caret targets and document deliberate differences from KaTeX. KaTeX is a visual reference, not a parser-support contract or a pixel-equality requirement. Save comparison evidence and verify typing, navigation, deletion and Undo after layout changes.
|
|
153
|
+
|
|
154
|
+
Workspace norm support: one editable body, shared double-bar fences, `norm`/`노름`/`||` suggestions, range wrapping and LaTeX import/export. The parser accepts short `\lVert…\rVert` and scalable double-bar aliases; export uses `\left\Vert…\right\Vert`. Available in 0.2.0.
|
|
155
|
+
|
|
156
|
+
## Triple and contour integrals (workspace)
|
|
157
|
+
|
|
158
|
+
| Input | Model | Slots / behavior |
|
|
159
|
+
| --- | --- | --- |
|
|
160
|
+
| `\iiint_a^b{f}` | `tripleIntegral` | `[lower, upper, body]` |
|
|
161
|
+
| `\oint_C{f}` | `contourIntegral` | `[lower, upper, body]`; absent upper stays empty |
|
|
162
|
+
|
|
163
|
+
Search `iiint` / `삼중적분` / `∭`, or `oint` / `폐곡선적분` / `∮`. Tab visits lower, upper and body. Backspace after the structure unwraps its contents; Undo restores it. Both accept and preserve `\limits` for stacked bounds; default editing places bounds alongside the slanted glyph. Unbraced input consumes one body atom, as for existing integrals. `\nolimits` is supported in the current workspace. These are editable notation, not integration or path analysis. Contour glyphs use the bundled KaTeX Size2-Regular U+222E directly, with its native ring and slant. No pseudo-element strokes are added.
|
|
164
|
+
|
|
165
|
+
## Brace annotations (workspace)
|
|
166
|
+
|
|
167
|
+
| Input | Model | Slots |
|
|
168
|
+
| --- | --- | --- |
|
|
169
|
+
| `\overbrace{a+b}^{n}` | `overbrace` | `[annotation, body]` |
|
|
170
|
+
| `\underbrace{a+b}_{n}` | `underbrace` | `[annotation, body]` |
|
|
171
|
+
|
|
172
|
+
Type `overbrace` / `위중괄호` or `underbrace` / `아래중괄호`. The annotation is edited first; Tab moves into the body. Wrapping a selection preserves it in the body and focuses the empty annotation. Both slots allow nested math. The brace stretches across the body/annotation container. Backspace immediately after the structure unwraps its contents; Undo restores the structure.
|
|
173
|
+
|
|
174
|
+
The parser accepts a bare brace body and creates an empty annotation. Export always includes the corresponding `^{…}` or `_{…}`, including an empty annotation. Repeated annotation markers fail. An opposite-side script is handled as an outer ordinary script, not a second brace annotation. Slot order is annotation then body even for underbraces; this matches overset/underset. This workspace addition retains document version 1; older consumers must reject unknown structure kinds during validation.
|
|
175
|
+
|
|
176
|
+
## Compact and filtered toolbars (workspace)
|
|
177
|
+
|
|
178
|
+
Toolbars initially show up to eight structure buttons. More tools / Fewer tools toggles the remainder without changing the formula or history. Rich React also places matrix presets, templates and symbol shortcuts in the expanded section; Undo, Redo and `toolbarEnd` stay visible. Native toolbars contain structure buttons and history only and show a toggle when needed. The layout wraps naturally on narrow screens; this is not a guaranteed single-row toolbar.
|
|
179
|
+
|
|
180
|
+
```tsx
|
|
181
|
+
<MathEditor toolbar={['fraction', 'root', 'superscript', 'matrix']}
|
|
182
|
+
toolbarMaxItems={3} />
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
```js
|
|
186
|
+
mountMathEditor(host, session, {
|
|
187
|
+
toolbar: ['fraction', 'root', 'norm'],
|
|
188
|
+
toolbarMaxItems: 2,
|
|
189
|
+
});
|
|
190
|
+
mountMathToolbar(toolbarHost, session, {
|
|
191
|
+
kinds: ['fraction', 'root', 'norm'],
|
|
192
|
+
maxItems: 2,
|
|
193
|
+
});
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
`toolbar: false` hides the toolbar. A structure array filters its structure buttons only: it does not disable those structures in suggestions, parsing or the model, and does not filter React's auxiliary template/symbol controls. `toolbarMaxItems` (independent toolbar: `maxItems`) is a nonnegative count; zero initially hides all structure buttons behind More. A sufficiently large count shows all selected structure buttons initially. Expanded state belongs to the mounted toolbar and is not saved in the math document. The rich React `toolbar` array and compact behavior are available in 0.2.0.
|
|
197
|
+
|
|
198
|
+
## Additional accents (workspace)
|
|
199
|
+
|
|
200
|
+
| Syntax | Model / appearance | Search |
|
|
201
|
+
| --- | --- | --- |
|
|
202
|
+
| `\tilde{x}` | `tilde`, fixed-width centered wave | `tilde`, `물결악센트` |
|
|
203
|
+
| `\bar{x}` | `bar`, short centered line | `bar`, `짧은윗줄` |
|
|
204
|
+
| `\dot{x}` | `dot`, one centered dot | `dot`, `위점` |
|
|
205
|
+
| `\ddot{x}` | `ddot`, two dots | `ddot`, `두점` |
|
|
206
|
+
| `\widehat{AB}` | `widehat`, body-width hat | `widehat`, `넓은모자` |
|
|
207
|
+
| `\widetilde{AB}` | `widetilde`, body-width wave | `widetilde`, `넓은물결` |
|
|
208
|
+
|
|
209
|
+
Each is a structure with a unique `id` and exactly one MathRow in `slots: [body]`. Empty and nested bodies are supported, including scripts and fractions. Import preserves the command spelling; export emits the same command with a braced body. Selection wrapping retains the original expression. Tab continues outside; Backspace after the wrapper preserves its body, and Undo restores it. `dot` can also match a multiplication symbol: choose Dot accent explicitly or search `위점`. `bar` remains distinct from the existing body-width `overline`. These additions are in 0.2.0 and do not evaluate derivatives or estimates.
|
|
210
|
+
|
|
211
|
+
## Limit variants and placement (workspace)
|
|
212
|
+
|
|
213
|
+
`\limsup_{n}{x}` and `\liminf_{n}{x}` use `limsup` / `liminf` structures with exactly `[condition, body]` rows. Search `limsup` / `상극한` or `liminf` / `하극한`; Tab moves from condition to body. They do not evaluate sequence limits.
|
|
214
|
+
|
|
215
|
+
All limit-family, sum/product and integral nodes accept a single `\limits` or `\nolimits` immediately after the command, before scripts. The optional `limits` field is now boolean: omitted means default, `true` is stacked placement, `false` is side placement. Both explicit values survive JSON validation, copying and LaTeX export. Repeated/conflicting directives are rejected. Existing `limits: true` remains valid; older package builds do not accept `false` or the new limit kinds.
|
|
216
|
+
|
|
217
|
+
Placement is currently selected through imported LaTeX/model metadata, not a dedicated toolbar switch. Imported side conditions remain editable; normal limit suggestions use default placement. This is 0.2.0 functionality.
|
|
218
|
+
|
|
219
|
+
## Fine mathematical spacing (workspace)
|
|
220
|
+
|
|
221
|
+
| LaTeX | Node type | Width | Suggestion search |
|
|
222
|
+
| --- | --- | --- | --- |
|
|
223
|
+
| `\,` | `thinSpace` | 3mu / 1⁄6em | `thinspace`, `얇은간격` |
|
|
224
|
+
| `\:` | `mediumSpace` | 4mu / 2⁄9em | `mediumspace`, `중간간격` |
|
|
225
|
+
| `\;` | `thickSpace` | 5mu / 5⁄18em | `thickspace`, `두꺼운간격` |
|
|
226
|
+
| `\!` | `negativeThinSpace` | −3mu / −1⁄6em | `negativethinspace`, `간격줄이기` |
|
|
227
|
+
|
|
228
|
+
All four nodes have a unique ID and `slots: []`, like quad/qquad. Import/export preserve the exact command; ordinary source whitespace is still normalized. Insertion resumes immediately after the spacer. Backspace removes it and Undo restores it. Negative spacing uses a zero-width node with negative inline-end margin, not an overlay that intercepts pointer input. Click the adjoining text to edit; the spacer has no text slot. Plain punctuation remains literal and is not a spacing trigger.
|
|
229
|
+
|
|
230
|
+
Editor dimensions scale in script/limit slots. These are explicit gaps added to the editor's own token clearance, not a complete TeX math-glue or script-style suppression engine. Arbitrary dimensions (`\hspace`, `\kern`) and rubber-glue stretch/shrink remain unsupported. This is 0.2.0 functionality.
|
|
231
|
+
|
|
232
|
+
## Explicit fraction/binomial sizes
|
|
233
|
+
|
|
234
|
+
Reuse the existing two-slot structures with optional `mathStyle: 'display' | 'text'`. Validate metadata only on those two kinds, preserve it during model cloning, and choose the matching command at export. Suggestion presets carry `mathStyle` into insertion without duplicating toolbar structure kinds. React and DOM expose `data-math-style`; scoped size variables allow a nested explicit style to override its parent. Keep active inputs and passive tokens at the same size. General TeX style declarations are outside this implementation.
|
|
235
|
+
|
|
236
|
+
## Scoped math alphabets
|
|
237
|
+
|
|
238
|
+
`bold`, `calligraphic` and `blackboard` are one-slot structures validated by the document/clipboard codec. Both renderers use their generic structure path. Scoped CSS font variables keep inner alphabet choices independent of outer ones and leave structural glyphs unchanged. KaTeX font files live under `src/fonts` alongside their license. The parser retains the earlier five single number-set aliases to avoid changing stored symbol semantics.
|
|
239
|
+
|
|
240
|
+
## Labeled arrows
|
|
241
|
+
|
|
242
|
+
The `xrightarrow` and `xleftarrow` structures have two slots in upper/lower order. Parse the optional lower bracket before the required upper argument, then store in model order. Render the generic slots in three CSS grid rows, with a pseudo-element shaft and a fixed-size head in the middle row. Labels drive grid width; the decoration cannot intercept pointer events. These commands are inserted through the shared catalog and do not require a separate dialog.
|