@barocss/math-editor 0.1.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 +170 -0
- package/CHANGELOG.md +13 -0
- package/EMBEDDING.md +95 -0
- package/IMPLEMENTATION.md +111 -0
- package/LATEX-SCOPE.md +7 -0
- package/LICENSE +23 -0
- package/LOCALIZATION.md +97 -0
- package/README.md +151 -0
- package/RELEASING.md +31 -0
- package/ROADMAP.md +102 -0
- package/SUPPORT.md +160 -0
- package/SYMBOLS.md +96 -0
- package/VALIDATION.md +85 -0
- package/dist/core.d.ts +11 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +11 -0
- package/dist/core.js.map +1 -0
- package/dist/dom/elements.d.ts +3 -0
- package/dist/dom/elements.d.ts.map +1 -0
- package/dist/dom/elements.js +9 -0
- package/dist/dom/elements.js.map +1 -0
- package/dist/dom/toolbar.d.ts +11 -0
- package/dist/dom/toolbar.d.ts.map +1 -0
- package/dist/dom/toolbar.js +46 -0
- package/dist/dom/toolbar.js.map +1 -0
- package/dist/dom.d.ts +32 -0
- package/dist/dom.d.ts.map +1 -0
- package/dist/dom.js +581 -0
- package/dist/dom.js.map +1 -0
- package/dist/editor-labels.d.ts +9 -0
- package/dist/editor-labels.d.ts.map +1 -0
- package/dist/editor-labels.js +31 -0
- package/dist/editor-labels.js.map +1 -0
- package/dist/enter-policy.d.ts +11 -0
- package/dist/enter-policy.d.ts.map +1 -0
- package/dist/enter-policy.js +13 -0
- package/dist/enter-policy.js.map +1 -0
- package/dist/i18n.d.ts +20 -0
- package/dist/i18n.d.ts.map +1 -0
- package/dist/i18n.js +58 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/lines.d.ts +7 -0
- package/dist/lines.d.ts.map +1 -0
- package/dist/lines.js +51 -0
- package/dist/lines.js.map +1 -0
- package/dist/locales/en.js +214 -0
- package/dist/locales/en.json +213 -0
- package/dist/locales/ko.js +214 -0
- package/dist/locales/ko.json +213 -0
- package/dist/math-editor-toolbar.d.ts +24 -0
- package/dist/math-editor-toolbar.d.ts.map +1 -0
- package/dist/math-editor-toolbar.js +21 -0
- package/dist/math-editor-toolbar.js.map +1 -0
- package/dist/math-editor.d.ts +23 -0
- package/dist/math-editor.d.ts.map +1 -0
- package/dist/math-editor.js +692 -0
- package/dist/math-editor.js.map +1 -0
- package/dist/matrix.d.ts +29 -0
- package/dist/matrix.d.ts.map +1 -0
- package/dist/matrix.js +125 -0
- package/dist/matrix.js.map +1 -0
- package/dist/model.d.ts +74 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +262 -0
- package/dist/model.js.map +1 -0
- package/dist/outputs.d.ts +13 -0
- package/dist/outputs.d.ts.map +1 -0
- package/dist/outputs.js +61 -0
- package/dist/outputs.js.map +1 -0
- package/dist/range.d.ts +30 -0
- package/dist/range.d.ts.map +1 -0
- package/dist/range.js +275 -0
- package/dist/range.js.map +1 -0
- package/dist/react.d.ts +11 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +20 -0
- package/dist/react.js.map +1 -0
- package/dist/session.d.ts +50 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +116 -0
- package/dist/session.js.map +1 -0
- package/dist/solid.d.ts +12 -0
- package/dist/solid.d.ts.map +1 -0
- package/dist/solid.js +9 -0
- package/dist/solid.js.map +1 -0
- package/dist/suggestions.d.ts +27 -0
- package/dist/suggestions.d.ts.map +1 -0
- package/dist/suggestions.js +125 -0
- package/dist/suggestions.js.map +1 -0
- package/dist/svelte.d.ts +5 -0
- package/dist/svelte.d.ts.map +1 -0
- package/dist/svelte.js +14 -0
- package/dist/svelte.js.map +1 -0
- package/dist/symbol-browser.d.ts +8 -0
- package/dist/symbol-browser.d.ts.map +1 -0
- package/dist/symbol-browser.js +32 -0
- package/dist/symbol-browser.js.map +1 -0
- package/dist/symbols.d.ts +3 -0
- package/dist/symbols.d.ts.map +1 -0
- package/dist/symbols.js +94 -0
- package/dist/symbols.js.map +1 -0
- package/dist/templates.d.ts +16 -0
- package/dist/templates.d.ts.map +1 -0
- package/dist/templates.js +86 -0
- package/dist/templates.js.map +1 -0
- package/dist/tokens.d.ts +11 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +24 -0
- package/dist/tokens.js.map +1 -0
- package/dist/vue.d.ts +5 -0
- package/dist/vue.d.ts.map +1 -0
- package/dist/vue.js +16 -0
- package/dist/vue.js.map +1 -0
- package/dist/web-component.d.ts +10 -0
- package/dist/web-component.d.ts.map +1 -0
- package/dist/web-component.js +67 -0
- package/dist/web-component.js.map +1 -0
- package/package.json +124 -0
- package/src/style.css +781 -0
package/ADAPTERS.md
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Framework adapters and embedding
|
|
2
|
+
|
|
3
|
+
## Distribution architecture
|
|
4
|
+
|
|
5
|
+
One ESM npm package exposes independent entry points. This keeps document types, commands and clipboard formats on one version. Six separate npm packages are unnecessary until independently versioned adapters are useful.
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
model / range / grids / suggestions / locale
|
|
9
|
+
↓
|
|
10
|
+
MathSession
|
|
11
|
+
↓
|
|
12
|
+
native DOM surface + toolbar
|
|
13
|
+
↙ ↓ ↓ ↓ ↘
|
|
14
|
+
Web Component Vue Svelte Solid React surface
|
|
15
|
+
|
|
16
|
+
Rich React MathEditor → same model operations, its own renderer/history
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
| Import | Purpose | Runtime dependency |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| `@barocss/math-editor` | Existing rich React editor and public model helpers | React + React DOM |
|
|
22
|
+
| `@barocss/math-editor/core` | All pure helpers, commands, sessions and locale registration | None |
|
|
23
|
+
| `@barocss/math-editor/dom` | Native surface and independent toolbar | Browser DOM |
|
|
24
|
+
| `@barocss/math-editor/web-component` | Explicit custom-element registration | Browser DOM |
|
|
25
|
+
| `@barocss/math-editor/react` | Existing `MathEditor` and native `MathEditorSurface` | React + React DOM |
|
|
26
|
+
| `@barocss/math-editor/vue` | Vue 3 directive `vMathEditor` | Vue host; type-only import |
|
|
27
|
+
| `@barocss/math-editor/svelte` | Svelte action `mathEditor` | Svelte host; type-only import |
|
|
28
|
+
| `@barocss/math-editor/solid` | Solid directive `mathEditor` | Solid |
|
|
29
|
+
| `@barocss/math-editor/style.css` | Shared presentation styles | None |
|
|
30
|
+
|
|
31
|
+
Framework peers are optional: install only the framework you import. Importing `core`, `dom` or `web-component` does not load React. DOM mounting and element registration are client-only; module import safety is not SSR rendering or hydration support. Use your framework's client lifecycle. The package is ESM-only and unbundled; use a bundler or browser import map. No CDN global/IIFE build is provided.
|
|
32
|
+
|
|
33
|
+
## Pure JavaScript, inline mode and external toolbars
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import { createMathSession } from '@barocss/math-editor/core';
|
|
37
|
+
import { mountMathEditor, mountMathToolbar } from '@barocss/math-editor/dom';
|
|
38
|
+
import '@barocss/math-editor/style.css';
|
|
39
|
+
|
|
40
|
+
const session = createMathSession({ locale: 'en', mode: 'inline' });
|
|
41
|
+
const editor = mountMathEditor(document.querySelector('#formula'), {
|
|
42
|
+
session,
|
|
43
|
+
toolbar: false,
|
|
44
|
+
onChange(document, latex) { save(document, latex); },
|
|
45
|
+
onExit(direction) { restoreHostCaret(direction); },
|
|
46
|
+
});
|
|
47
|
+
const tools = mountMathToolbar(document.querySelector('#tools'), session, {
|
|
48
|
+
kinds: ['fraction', 'root', 'superscript'],
|
|
49
|
+
onExecute: () => editor.focus(),
|
|
50
|
+
});
|
|
51
|
+
// A custom button, floating menu or professional toolbar uses the same API.
|
|
52
|
+
session.execute({ type: 'text', value: 'α' });
|
|
53
|
+
session.execute({ type: 'structure', kind: 'fraction' });
|
|
54
|
+
session.execute({ type: 'template', id: 'quadratic' });
|
|
55
|
+
|
|
56
|
+
// On host teardown:
|
|
57
|
+
tools.destroy();
|
|
58
|
+
editor.destroy();
|
|
59
|
+
session.destroy();
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Use real non-null HTMLElements for the mount hosts. `toolbar` accepts `false`, `true`, or a list of structure kinds. By default block mode shows tools and inline mode hides them. `mountMathToolbar` may live anywhere in the page and retains the session's last caret/range. Custom tools can use `session.getSnapshot()` and `session.subscribe()` for context and disabled states, then call `execute`, `apply`, or `paste`. For example, `session.apply(resizeMatrix(session.getSnapshot().state, 'row', 'delete'))` reuses the grid command. Avoid replacing the session on each framework render.
|
|
63
|
+
|
|
64
|
+
`inline` means **one top-level equation row**, not a fixed-height text glyph. Fractions, matrices, aligned blocks and cases may still be tall. Top-level newline commands and multiline paste return `false` without altering the document. Loading a multiline document or changing such a document to inline throws an error. Enter first accepts a visible suggestion. Shift+Enter inside a grid edits that grid. Otherwise inline Enter calls `onCommit(snapshot)`, or `onExit(1)` when no commit callback is supplied. Tab navigates slots and calls `onExit` at an outer boundary when provided. The host owns the surrounding prose, focus restoration and its own undo integration. No automatic `contenteditable` host binding is included.
|
|
65
|
+
|
|
66
|
+
Session snapshots are copies. `subscribe((snapshot, documentChanged) => ...)` also reports caret/locale changes with `false`; save only document changes. `load()` opens a trusted document and resets undo. `defaultValue`, `session` and `menuHost` are mount-only; call `session.load()` to open another document. Options passed to `update()` merge with existing options; explicitly pass `toolbar: false` or another concrete value to change them. Externally supplied sessions survive renderer teardown; internally created sessions are owned by the renderer. Use one editing surface per session; multiple synchronized simultaneous editors are not a supported collaboration feature.
|
|
67
|
+
|
|
68
|
+
## React
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
import { MathEditorSurface } from '@barocss/math-editor/react';
|
|
72
|
+
<MathEditorSurface locale="en" mode="inline" toolbar={false} onChange={save} />
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Keep `MathEditor` for the existing full editor, including the symbol browser and richer selection UI. `MathEditorSurface` uses the new native renderer and options. They share document formats, not a live history instance. Do not assume feature parity; see below.
|
|
76
|
+
|
|
77
|
+
## Web Component
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import { defineMathEditor, type MathEditorElement } from '@barocss/math-editor/web-component';
|
|
81
|
+
defineMathEditor(); // once; repeated calls for the same tag return its constructor
|
|
82
|
+
const element = document.querySelector('barocss-math-editor') as MathEditorElement;
|
|
83
|
+
element.value = savedDocument;
|
|
84
|
+
element.addEventListener('math-change', event => {
|
|
85
|
+
const { document, latex } = (event as CustomEvent).detail;
|
|
86
|
+
save(document, latex);
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```html
|
|
91
|
+
<barocss-math-editor locale="en" mode="inline" toolbar="false"></barocss-math-editor>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The element uses light DOM, so import the shared CSS in the page. Attributes: `locale`, `mode`, `toolbar`, `line-numbers`, `enter-behavior`. Use the `value` property for a document, not a JSON attribute. `session` is available for custom toolbar commands; `focusEditor()` activates the caret. `math-change`, `math-commit`, `math-cancel` and `math-exit` bubble across boundaries. Disconnect removes the DOM and subscriptions; reconnect restores the same document and history. Set the mode before loading documents to apply its policy. Do not reuse a custom-element tag already owned by another library.
|
|
95
|
+
|
|
96
|
+
## Vue 3
|
|
97
|
+
|
|
98
|
+
```vue
|
|
99
|
+
<script setup lang="ts">
|
|
100
|
+
import { vMathEditor } from '@barocss/math-editor/vue';
|
|
101
|
+
import '@barocss/math-editor/style.css';
|
|
102
|
+
const options = { locale: 'en', toolbar: false };
|
|
103
|
+
</script>
|
|
104
|
+
<template><div v-math-editor="options" /></template>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The directive mounts, updates options and destroys through Vue's directive hooks. Keep its host empty: the editor owns the children. [Vue directive lifecycle](https://vuejs.org/guide/reusability/custom-directives.html).
|
|
108
|
+
|
|
109
|
+
## Svelte
|
|
110
|
+
|
|
111
|
+
```svelte
|
|
112
|
+
<script>
|
|
113
|
+
import { mathEditor } from '@barocss/math-editor/svelte';
|
|
114
|
+
import '@barocss/math-editor/style.css';
|
|
115
|
+
</script>
|
|
116
|
+
<div use:mathEditor={{ locale: 'en', mode: 'inline' }}></div>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The action returns `update` and `destroy`. Svelte 5 was used for the browser integration test; Svelte 4 is allowed by the peer range but not separately tested. No compiler or Svelte runtime is shipped in the action. [Svelte actions](https://svelte.dev/docs/svelte/use).
|
|
120
|
+
|
|
121
|
+
## Solid
|
|
122
|
+
|
|
123
|
+
```tsx
|
|
124
|
+
import { mathEditor } from '@barocss/math-editor/solid';
|
|
125
|
+
import '@barocss/math-editor/style.css';
|
|
126
|
+
// Keep the directive import as a value in TypeScript builds.
|
|
127
|
+
void mathEditor;
|
|
128
|
+
<div use:mathEditor={{ locale: 'en', toolbar: false }} />
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
The directive reads its accessor in a reactive effect and cleans up with `onCleanup`. Do not also render children into its host. [Solid directives](https://docs.solidjs.com/reference/jsx-attributes/use).
|
|
132
|
+
|
|
133
|
+
## Current renderer parity
|
|
134
|
+
|
|
135
|
+
| Capability | Existing React `MathEditor` | Native surface and all wrappers |
|
|
136
|
+
|---|---|---|
|
|
137
|
+
| 13 structure kinds / 90 symbol suggestions / templates | Yes | Same model and suggestion catalog |
|
|
138
|
+
| Multiline block, grids and grid keyboard commands | Yes | Implemented; representative Chromium coverage |
|
|
139
|
+
| Single top-level row inline policy | No dedicated prop | Yes |
|
|
140
|
+
| Separately mounted/custom toolbar | Not a session API | Yes |
|
|
141
|
+
| English/Korean/custom locale registry | Yes | Yes |
|
|
142
|
+
| Active input granularity | Lexical token | Whole logical text run |
|
|
143
|
+
| Variable/constant/symbol colors | Editing and preview | Preview segments; active run uses one color |
|
|
144
|
+
| Pointer range, structural clipboard, wrapping | Rich implementation | Initial implementation; whole-run visual highlight |
|
|
145
|
+
| Drag starting inside the active input across structures | Yes | Pending; start in preview |
|
|
146
|
+
| Searchable all-symbol panel, matrix context toolbar | Yes | Pending; suggestions/core commands available |
|
|
147
|
+
| Composition candidate preview | Disabled choices while composing | Menu hidden while composing |
|
|
148
|
+
| Keyboard model ranges / OS IME matrix / full accessibility audit | Pending | Pending |
|
|
149
|
+
|
|
150
|
+
The native renderer is an integration preview, not a replacement of the rich React editor. Completing parity before switching the main entry is the next release gate. Trusted document loading still needs schema/ID validation. LaTeX is export-only; plain-text paste is not a LaTeX parser.
|
|
151
|
+
|
|
152
|
+
## Local verification and packaging
|
|
153
|
+
|
|
154
|
+
The demo's `/adapters.html` mounts pure JS, inline, custom French, Web Component, Vue, Svelte, Solid and React surfaces. Its checked-in Svelte harness is generated with `node packages/math-editor/examples/compile-svelte.mjs`; this fixture tooling is not part of the published API.
|
|
155
|
+
|
|
156
|
+
```sh
|
|
157
|
+
pnpm --filter @barocss/math-editor build
|
|
158
|
+
pnpm --filter @barocss/math-editor test
|
|
159
|
+
pnpm --filter @barocss/math-demo test:e2e
|
|
160
|
+
pnpm --filter @barocss/math-demo build
|
|
161
|
+
# Inspect a tarball locally; this does not publish:
|
|
162
|
+
pnpm --dir packages/math-editor pack --pack-destination /tmp/math-editor-package
|
|
163
|
+
node packages/math-editor/scripts/check-package.mjs /tmp/math-editor-package/barocss-math-editor-0.1.0.tgz
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Release work still includes package ownership/versioning, an explicit release decision, supported-browser and framework-version CI, bundle budgets and renderer parity. No registry publication has been performed.
|
|
167
|
+
|
|
168
|
+
## Independent outputs and host completion
|
|
169
|
+
|
|
170
|
+
The DOM entry also exports `mountMathLatex` and `mountMathPreview`. See [Embedding](EMBEDDING.md) for the four-surface composition contract, native `enterBehavior`/`onCommit`/`onCancel`, popup draft handling and Note-style next-block creation. The rich React editor adds `toolbar`, `toolbarEnd` and `showTokenLegend`; its dedicated single-line/host-completion API remains the native `MathEditorSurface`.
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# @barocss/math-editor
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
Initial public release.
|
|
6
|
+
|
|
7
|
+
- Structured expression model, LaTeX export, undo/redo and model-based selection/clipboard operations.
|
|
8
|
+
- Rich React editor with symbol discovery, matrices, aligned equations, cases and editable templates.
|
|
9
|
+
- Native DOM surface with pure JavaScript, Web Component, React, Vue, Svelte and Solid entry points.
|
|
10
|
+
- Optional toolbars, inline/block modes, host callbacks and independent LaTeX/preview views.
|
|
11
|
+
- English/Korean JSON locale packs and host-registered translations and suggestion aliases.
|
|
12
|
+
|
|
13
|
+
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.
|
package/EMBEDDING.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Composable math editing and host integration
|
|
2
|
+
|
|
3
|
+
The unit of integration is a **math session**, not a fixed editor panel. The host chooses where four independent surfaces live and what happens when editing ends. The package owns the math tree and caret; it does not create Note blocks, move slide objects, save a Site page or issue API requests.
|
|
4
|
+
|
|
5
|
+
## Four surfaces
|
|
6
|
+
|
|
7
|
+
| Surface | API | Ownership |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| Editing | `mountMathEditor(host, options)` | Native input, math selection, suggestions, math undo |
|
|
10
|
+
| Toolbar | `mountMathToolbar(host, session, options)` | Optional command UI; may be elsewhere in the page |
|
|
11
|
+
| LaTeX | `mountMathLatex(host, session)` | Read-only generated text; preserves browser selection on caret-only changes |
|
|
12
|
+
| Preview | `mountMathPreview(host, session, { render })` | Subscription and lifetime; host provides rendering implementation |
|
|
13
|
+
|
|
14
|
+
All four APIs are exported by `@barocss/math-editor/dom`. Toolbar, LaTeX and preview are optional. They do not recreate or reset the session when mounted/unmounted. Destroy each view when its host disappears. An externally supplied session outlives its views and must be destroyed by its owner.
|
|
15
|
+
|
|
16
|
+
| Composition | Suggested use | Completion policy |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| Editor only | Embedded form field / API input | `onChange(document, latex)` |
|
|
19
|
+
| Toolbar + editor | Dedicated formula tool | Internal multiline editing |
|
|
20
|
+
| Editor + LaTeX, optional toolbar | LaTeX generator | Exported source; no arbitrary LaTeX import |
|
|
21
|
+
| Editor + preview, optional toolbar | WYSIWYG verification | Render through a host-selected engine |
|
|
22
|
+
| Editor + LaTeX + preview | Authoring/debugging lab | Same session for all views |
|
|
23
|
+
| Inline editor | Formula in prose or a constrained field | Single top-level row, `onCommit`/`onExit` |
|
|
24
|
+
| Popup editor | Draft an expression away from the host canvas | Apply once or discard the separate draft |
|
|
25
|
+
| One editor per math block | Note-style consecutive formulas | Host creates the next block after `onCommit` |
|
|
26
|
+
|
|
27
|
+
Preview is not synonymous with a downloadable image. The sample uses KaTeX HTML/MathML. An SVG/PNG renderer, font embedding, image sizing and export are separate adapters still to be implemented. Keep the editable `MathDocument` even if a host also stores an image or LaTeX cache.
|
|
28
|
+
|
|
29
|
+
## Minimal composition
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import { createMathSession } from '@barocss/math-editor/core';
|
|
33
|
+
import { mountMathEditor, mountMathToolbar, mountMathLatex, mountMathPreview } from '@barocss/math-editor/dom';
|
|
34
|
+
import '@barocss/math-editor/style.css';
|
|
35
|
+
|
|
36
|
+
const session = createMathSession({ locale: 'en' });
|
|
37
|
+
const editor = mountMathEditor(editorHost, { session, toolbar: false, onChange: saveDraft });
|
|
38
|
+
const toolbar = mountMathToolbar(toolbarHost, session, { onExecute: () => editor.focus() });
|
|
39
|
+
const latex = mountMathLatex(latexHost, session);
|
|
40
|
+
const preview = mountMathPreview(previewHost, session, {
|
|
41
|
+
render(element, snapshot) {
|
|
42
|
+
// Example only: the host imports/configures its renderer and handles errors.
|
|
43
|
+
katex.render(snapshot.latex, element, { displayMode: snapshot.mode === 'block', trust: false });
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Hosts may arrange these in a column, side panel, floating toolbar or popup. No layout preset forces a markup hierarchy. `render` can return cleanup for resources/listeners; it runs again when LaTeX, mode or locale changes, not when only the caret moves. Handle rendering errors inside the supplied renderer. Dispose in reverse ownership order: preview/LaTeX/toolbar/editor, then the externally created session.
|
|
49
|
+
|
|
50
|
+
React's rich `MathEditor` additionally accepts `toolbar={false}`, `showTokenLegend={false}` and `toolbarEnd={<HostActions />}`. The sample's reset action uses this slot. React's native `MathEditorSurface` and the Vue/Svelte/Solid adapters accept the shared DOM options. The rich React renderer still has its own history; sharing a document format does not make it a live session view.
|
|
51
|
+
|
|
52
|
+
## Enter, Escape and host focus
|
|
53
|
+
|
|
54
|
+
`mode` and `enterBehavior` answer different questions:
|
|
55
|
+
|
|
56
|
+
- `mode: 'inline'` enforces one **top-level** row at every session mutation boundary. Nested matrices, cases and fractions may still be tall. It is not a fixed-height guarantee.
|
|
57
|
+
- `mode: 'block'` permits multiple top-level rows.
|
|
58
|
+
- `enterBehavior: 'newline'` uses internal block editing (default in block mode).
|
|
59
|
+
- `enterBehavior: 'commit'` reports completion to the host. Inline mode always completes instead of adding a top-level row, even if `newline` was requested.
|
|
60
|
+
|
|
61
|
+
Keyboard precedence is deliberate:
|
|
62
|
+
|
|
63
|
+
1. An unmodified Enter accepts a visible suggestion.
|
|
64
|
+
2. Shift+Enter inside a grid adds an internal row, including in inline or host-commit mode.
|
|
65
|
+
3. Inline/commit mode invokes `onCommit(snapshot)`; without it, the existing `onExit(1)` fallback is used.
|
|
66
|
+
4. Normal block mode splits an outer row; aligned/cases Enter adds a row; matrix Enter alone does nothing.
|
|
67
|
+
|
|
68
|
+
`onCommit` does not mutate the formula or create a host block. The snapshot includes the document, LaTeX and caret. A Note adapter can save the current node, insert a sibling math block and focus a new editor. A form can move focus to the next field. A popup can apply the draft and close. Treat this as a completion request, not proof that an asynchronous save succeeded.
|
|
69
|
+
|
|
70
|
+
Escape first dismisses suggestions or a selected grid. A subsequent Escape exits active editing and invokes `onCancel` if present. The host decides whether cancellation closes a popup and whether its draft is discarded. Tab/outer arrows use `onExit(-1 | 1)` for host focus restoration. The host must retain an outer selection bookmark before editing begins.
|
|
71
|
+
|
|
72
|
+
Web Components expose `enter-behavior="commit"`, `math-commit`, `math-cancel` and `math-exit` using the same policy. Native suggestions mount inside the nearest `<dialog>` by default so the browser's modal inertness does not block their mouse interaction. A mount-only `menuHost` override supports other overlay systems.
|
|
73
|
+
|
|
74
|
+
## Drafts, persistence and undo
|
|
75
|
+
|
|
76
|
+
For popup editing, clone the source into a **separate** session. Cancel destroys the draft without touching the original. Apply commits the draft through the host's transaction API once. The layout demo uses `sourceSession.apply(draftSnapshot.state)` so applying the popup is one undoable math edit; `load()` would incorrectly reset the source's history.
|
|
77
|
+
|
|
78
|
+
For direct inline editing, decide whether host persistence observes each `onChange` or only completion. Saving each update to an API is possible, but debounce/network state belongs to the host. Do not put every keystroke in both host and math undo stacks. A production bridge must define one user-visible undo path and handle undo across the math/host boundary.
|
|
79
|
+
|
|
80
|
+
## Existing product boundaries found in this repository
|
|
81
|
+
|
|
82
|
+
| Product | Current evidence / required bridge | Recommended first integration |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| Note | `office-note/src/note-schema.ts` defines `mathInline` and `mathBlock` with `tex`; `office-text/src/latex.ts` owns insertion/source commands. Markdown exchange also preserves `tex`. This editor uses a different `MathDocument` tree. | A versioned editable payload alongside the LaTeX cache, a node-view mount, and Enter-to-sibling-block transactions. Keep existing source editing for tex-only content until supported import exists. |
|
|
85
|
+
| Word | `office-word/src/math-schema.ts` uses named OMML-style slots, with existing buildup/navigation/commands. Its document model is not interchangeable with this package. | Explicit supported-subset conversion and round-trip tests. Preserve unsupported OMML nodes and current DOCX behavior; do not replace them with LaTeX strings. |
|
|
86
|
+
| Slide | The host controls object selection, position, scale and document transactions. This change has not connected its canvas objects to a math session. | Start with a popup draft/apply path, then test direct editing under canvas scaling and host focus restoration. |
|
|
87
|
+
| Site | The host controls authoring versus published output. This change has not connected its document nodes to a math session. | A dedicated math node/view; persist editable data, publish rendered output without toolbars, caret slots or development controls. |
|
|
88
|
+
|
|
89
|
+
The layout lab demonstrates the interaction contracts; it is not installation into these four products. A shared host bridge can consolidate data conversion, selection bookmarks, completion and transaction policy, while each product keeps its own placement/schema adapter. No general LaTeX parser, OMML converter, saved-document validator or host-wide undo bridge is included yet.
|
|
90
|
+
|
|
91
|
+
## Try and verify
|
|
92
|
+
|
|
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
|
+
|
|
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.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Implementation guide
|
|
2
|
+
|
|
3
|
+
## Ownership and data flow
|
|
4
|
+
|
|
5
|
+
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.
|
|
6
|
+
|
|
7
|
+
A typical edit follows:
|
|
8
|
+
|
|
9
|
+
1. A native input event supplies text and UTF-16 selection offsets.
|
|
10
|
+
2. The editor maps those offsets from the active lexical token to its logical `MathText` run.
|
|
11
|
+
3. A pure model operation returns the next document and caret.
|
|
12
|
+
4. `commit` records the prior state; `publish` updates React and calls `onChange` for committed document changes.
|
|
13
|
+
5. A layout effect focuses the new active input and restores its local selection.
|
|
14
|
+
|
|
15
|
+
Navigation does not create a document history entry. Locale changes do not remount the editor. `defaultValue` is deliberately mount-only.
|
|
16
|
+
|
|
17
|
+
## Source map
|
|
18
|
+
|
|
19
|
+
| Module | Responsibility |
|
|
20
|
+
|---|---|
|
|
21
|
+
| `model.ts` | Serializable types, constructors, basic insertion/unwrapping, text traversal, history and LaTeX export |
|
|
22
|
+
| `tokens.ts` | Lexical variable/numeric/symbol segmentation and boundary affinity |
|
|
23
|
+
| `math-editor.tsx` | Native input lifecycle, IME, pointer hit testing, selection UI, keyboard routing and portal |
|
|
24
|
+
| `range.ts` | Endpoint ordering, balanced selection resolution, slicing, insertion, wrapping and clipboard validation |
|
|
25
|
+
| `matrix.ts` | Innermost grid lookup, row/column changes, delimiters and grid navigation |
|
|
26
|
+
| `lines.ts` | Top-level line split/join and vertical navigation |
|
|
27
|
+
| `suggestions.ts` | Longest symbolic triggers, bilingual aliases, candidates and acceptance |
|
|
28
|
+
| `symbols.ts` | Glyph, message key, search aliases, symbolic triggers and LaTeX mapping |
|
|
29
|
+
| `templates.ts` | Fresh editable template trees and insertion through the range model |
|
|
30
|
+
| `math-editor-toolbar.tsx` | Rich React toolbar presentation and host action slot; no history ownership |
|
|
31
|
+
| `dom/toolbar.ts`, `dom/elements.ts` | Native command toolbar and safe element construction |
|
|
32
|
+
| `outputs.ts` | Independent LaTeX/preview subscriptions and cleanup |
|
|
33
|
+
| `enter-policy.ts` | Suggestion/grid/newline/host completion precedence |
|
|
34
|
+
| `locales/*.json` | Built-in translation data and parameterized message templates |
|
|
35
|
+
| `i18n.ts`, `editor-labels.ts` | Keyed dictionary lookup, fallback, interpolation and shared accessible editor paths |
|
|
36
|
+
| `symbol-browser.tsx` | Browse/search the shared catalog, preserve the math caret, isolate search clipboard/keyboard events |
|
|
37
|
+
| `style.css` | Mathematical layout, token colors, focus, range marks and tools |
|
|
38
|
+
| `apps/math-demo` | Language selector, examples, LaTeX text, copy action and KaTeX verification view |
|
|
39
|
+
|
|
40
|
+
## Presentation tree invariants
|
|
41
|
+
|
|
42
|
+
- Every row starts and ends with a text node. Structures have text boundaries on both sides.
|
|
43
|
+
- IDs address rows, structures and logical text runs. Clipboard insertion regenerates IDs; never reuse IDs for a pasted instance.
|
|
44
|
+
- Fractions have two slots; roots one; powers/subscripts two; delimiters one; large operators three (lower, upper, body).
|
|
45
|
+
- Matrices have a row-major slots array, a column count and one of six delimiter environments. Both dimensions are 1–20.
|
|
46
|
+
- Aligned equations and cases use the same grid machinery but always have two columns and 1–20 rows.
|
|
47
|
+
- `additionalLines` is a document-level concept. A nested `MathRow` is a horizontal expression, not a multiline document.
|
|
48
|
+
|
|
49
|
+
`structuredClone` is used for model changes. This is intentionally simple and has not been benchmarked for very large documents.
|
|
50
|
+
|
|
51
|
+
## Active-input rendering and composition
|
|
52
|
+
|
|
53
|
+
Passive tokens render as spans. Only the active token renders an input. A hidden text mirror supplies browser-shaped width and pointer offset measurements. Variable, numeric constant and symbol colors do not change the stored text. Logical text runs remain intact when the UI displays several tokens.
|
|
54
|
+
|
|
55
|
+
During composition, the token partition and input element are held stable. Suggestions are visible but disabled. Enter and arrows remain with the IME; parent handlers do not receive editing keystrokes. On composition end, the complete text is committed as one history change and tokenization resumes. Synthetic composition tests are not a substitute for actual OS input-method validation.
|
|
56
|
+
|
|
57
|
+
## Ranges and transformations
|
|
58
|
+
|
|
59
|
+
`MathRange` has anchor/focus points identified by logical text ID and UTF-16 offset. `resolveRange` orders them in document traversal order and finds the deepest shared row. Endpoints in different slots expand to a balanced common structure; endpoints on different document lines produce multiple row slices.
|
|
60
|
+
|
|
61
|
+
Pointer hit testing uses token rectangles and mirror text ranges. A drag inside the current input stays native until it leaves that field. A model selection suppresses the active input. Partial token marks reflect the actual selected substring.
|
|
62
|
+
|
|
63
|
+
`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
|
+
|
|
65
|
+
The UI disables unsupported structural insertion while a model range is selected. Template insertion explicitly replaces the selection. Contextual wrap tools appear below the surface so their appearance does not move the expression during a drag.
|
|
66
|
+
|
|
67
|
+
## Clipboard boundary
|
|
68
|
+
|
|
69
|
+
Copies write a versioned `MathFragment` and plain-text LaTeX. `parseFragment` rejects oversized payloads (>200,000 characters), too many nodes (>10,000), excessive nesting (>40), more than 200 rows, invalid slot arities and invalid grid geometry. Valid insertion creates fresh IDs and preserves the destination prefix/suffix. Malformed custom data falls back to plain text when available.
|
|
70
|
+
|
|
71
|
+
External text is literal input, not executable HTML and not parsed LaTeX. Newlines produce top-level rows; a multiline insertion in a nested slot is rejected. Whole saved documents still require a future validator and version-migration policy.
|
|
72
|
+
|
|
73
|
+
## Localization
|
|
74
|
+
|
|
75
|
+
`locale` defaults to `ko` and is propagated through toolbar labels, slot accessible names, token descriptions, suggestions, matrix controls, status text and wrap tools. The portal has its own `lang` attribute. The demo separately translates surrounding copy and updates the HTML language/title.
|
|
76
|
+
|
|
77
|
+
Catalog labels and details are English message keys with explicit interpolation parameters. `translate` resolves JSON dictionaries with regional/base/English fallback. Accessible line, grid and slot paths are built by `editor-labels.ts`, shared by both renderers. `findSuggestions(text, caret, locale)` returns localized labels/details while preserving stable IDs, aliases and insertion payloads. English/Korean aliases remain available; localized names and registered aliases add discovery in the selected language. Never translate user-authored formula text or persist locale in the math tree.
|
|
78
|
+
|
|
79
|
+
To add a locale, register a JSON pack with message values and search aliases; no type union or renderer changes are needed. Translate host page copy separately, then test the full catalog and accessible names. See [LOCALIZATION.md](LOCALIZATION.md) for supported scope and examples. Custom host labels are translated by the host. A composition in progress must not be remounted when locale changes.
|
|
80
|
+
|
|
81
|
+
## Adding a symbol, template or structure
|
|
82
|
+
|
|
83
|
+
**Symbol:** add a catalog tuple with glyph, label, aliases, optional trigger and valid LaTeX. The catalog powers discovery and export. Prefer unambiguous triggers; existing `/`, `^` and `_` stay opt-in. Test longest-trigger ordering, alias acceptance, undo, and KaTeX output.
|
|
84
|
+
|
|
85
|
+
**Template:** construct fresh model rows, preserve text boundaries, register an ID/label/aliases, and insert through `pasteFragment`. Do not embed opaque LaTeX. Test ID independence, editing, clipboard validation, insertion/replacement and renderer output. The quadratic template is a presentation of the formula; it does not enforce `a ≠ 0` or compute roots.
|
|
86
|
+
|
|
87
|
+
**Structure:** extend `StructureKind`, constructors, slot labels, rendering/CSS, LaTeX export and clipboard arity validation together. Decide cursor order, deletion, range normalization and nested layout before exposing a button. Add model tests and browser input/undo tests. A new symbol glyph alone does not implement a new structural editing capability.
|
|
88
|
+
|
|
89
|
+
## Integration and testing
|
|
90
|
+
|
|
91
|
+
Use package exports in consumers, not source-path imports. Mount with a new key only when changing documents. Integrators must implement persistence, trusted-data validation, outer focus, and an explicit host/internal undo ownership contract.
|
|
92
|
+
|
|
93
|
+
Unit tests cover deterministic transformations and export. Browser tests exercise the active-input transition, navigation, drag ranges, clipboard events, wrapping, language switches and templates. Clipboard automation uses synthetic DataTransfer payloads; separate manual in-app checks exercised real copy/paste shortcuts. See [VALIDATION.md](./VALIDATION.md) for evidence and remaining platform limits.
|
|
94
|
+
|
|
95
|
+
## Line gutter and symbol discovery
|
|
96
|
+
|
|
97
|
+
The line gutter renders only for multiple top-level rows when `showLineNumbers` is enabled. Numbers are outside `MathRow` rendering, hidden from accessibility and unselectable; pointer events on the gutter do not start math selection. Deleting/joining rows derives the updated numbering from document order.
|
|
98
|
+
|
|
99
|
+
The symbol browser is a localized, searchable section, not a modal. It opens with search focus and lists the shared catalog in a scrollable grid. Native search input copy/cut/paste and keyboard events stop propagation to the editor. Choosing a glyph inserts through `pasteFragment` at the saved caret/range and closes the browser as one undoable change. Escape closes without changing the formula.
|
|
100
|
+
|
|
101
|
+
## Framework-neutral integration layer (2026-09-07)
|
|
102
|
+
|
|
103
|
+
`session.ts` owns immutable history snapshots, model ranges, command dispatch, locale and block/inline policy. It reports document mutations separately from caret or configuration notifications. `dom.ts` mounts a native view and one active logical-run input; the standalone toolbar subscribes to the same session. Destroy removes DOM, portal, event listeners and subscriptions. Framework wrappers only connect mount/update/cleanup; custom elements retain their session across disconnect/reconnect.
|
|
104
|
+
|
|
105
|
+
The existing React renderer still owns its original history and token-level input behavior. Shared document transformations do not yet imply shared renderer behavior. See [ADAPTERS.md](ADAPTERS.md) for exact lifecycle contracts, parity gaps and distribution entries, and [LOCALIZATION.md](LOCALIZATION.md) for external dictionaries. Inline policy is enforced at session mutations, load, paste and undo/redo boundaries, so a toolbar cannot accidentally introduce a second top-level row.
|
|
106
|
+
|
|
107
|
+
## Composition refactor — 2026-09-08
|
|
108
|
+
|
|
109
|
+
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
|
+
|
|
111
|
+
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.
|
package/LATEX-SCOPE.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# LaTeX scope
|
|
2
|
+
|
|
3
|
+
The current, consolidated scope lives in [SUPPORT.md](./SUPPORT.md), including structural notation, all 90 catalog symbols, template discovery and editing limitations.
|
|
4
|
+
|
|
5
|
+
LaTeX is an export format. The editor's source of truth is its version-1 JSON presentation tree. Backslash aliases in suggestions do not make this a general LaTeX parser. External LaTeX paste, unsupported environments and macros remain future work; see the [roadmap](./ROADMAP.md).
|
|
6
|
+
|
|
7
|
+
The demo uses KaTeX 0.16.28 with `trust: false` and `throwOnError: true`. Unit tests render every catalog symbol and template, and representative matrices/line structures. Renderer compatibility is not proof of mathematical correctness or complete TeX support.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 BaroCSS contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
|
22
|
+
|
|
23
|
+
|
package/LOCALIZATION.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Localization and suggestion languages
|
|
2
|
+
|
|
3
|
+
## Support policy
|
|
4
|
+
|
|
5
|
+
Locale identifies UI language and regional wording, not a country restriction. The library accepts custom language tags such as `fr`, `ja`, `zh-CN` and `pt-BR`; it does not maintain an allowlist of countries.
|
|
6
|
+
|
|
7
|
+
| Level | Available now | Meaning |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| Complete bundled UI packs | `en`, `ko` | All library message keys are present, including toolbars, suggestions, symbol names, slot labels and accessibility text. The main demo has separate matching page packs. |
|
|
10
|
+
| Custom language packs | Host-registered JSON | Translate messages and supply search aliases. Missing messages fall back to English. No limit to two languages is imposed by the API. |
|
|
11
|
+
| Working example | Partial `fr` pack in `examples/locales/fr.json` | Demonstrates localized fraction/symbol/matrix discovery in the adapter demo. It is not a complete French translation. |
|
|
12
|
+
| Search regression coverage | French, Japanese, Chinese, Arabic, Hindi, German | Tests exercise localized labels, aliases and combining marks. These fixtures are not bundled translations or native-speaker certification. |
|
|
13
|
+
| RTL UI | `direction: "rtl"` option | Formula layout remains LTR. Full RTL interaction, screen-reader and OS IME validation remain release work. |
|
|
14
|
+
|
|
15
|
+
We will add complete bundled languages when all messages, symbol names, aliases and interpolation parameters are translated and reviewed, with browser tests. There is no committed date or claim that every locale is fully supported. A new language should not require editing renderer logic.
|
|
16
|
+
|
|
17
|
+
## Register a JSON pack
|
|
18
|
+
|
|
19
|
+
Start from `src/locales/en.json` for a complete translation. All message keys are stable English identifiers; translate values only. A partial pack is also valid:
|
|
20
|
+
|
|
21
|
+
```json
|
|
22
|
+
{
|
|
23
|
+
"direction": "ltr",
|
|
24
|
+
"messages": {
|
|
25
|
+
"structure.fraction": "Fraction",
|
|
26
|
+
"structure.fractionDetail": "Modifier le numérateur et le dénominateur",
|
|
27
|
+
"slot.numerator": "Numérateur",
|
|
28
|
+
"slot.denominator": "Dénominateur",
|
|
29
|
+
"expression.line": "Expression ligne {line}",
|
|
30
|
+
"matrix.size": "Matrice {rows}×{columns}",
|
|
31
|
+
"symbol.elementOf": "Appartient à",
|
|
32
|
+
"suggestion.create": "Créer à partir de « {query} »"
|
|
33
|
+
},
|
|
34
|
+
"aliases": {
|
|
35
|
+
"fraction": ["rapport"],
|
|
36
|
+
"matrix": ["matrice"],
|
|
37
|
+
"symbol-∈": ["appartient", "élément"]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
import french from './fr.json';
|
|
44
|
+
import { registerMathLocale, createMathSession } from '@barocss/math-editor/core';
|
|
45
|
+
import { mountMathEditor } from '@barocss/math-editor/dom';
|
|
46
|
+
|
|
47
|
+
registerMathLocale('fr', french);
|
|
48
|
+
const session = createMathSession({ locale: 'fr-CA' });
|
|
49
|
+
const editor = mountMathEditor(host, { session });
|
|
50
|
+
// Uses fr-CA overrides if registered, otherwise fr, then en.
|
|
51
|
+
session.configure({ locale: 'ko' }); // Retains formula and undo history.
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Register before mounting. Use the `locale` prop on React `MathEditor`, the shared DOM options on framework adapters, or the Web Component's locale attribute. A host may load packs with its own JSON imports, fetch, or i18n framework. The editor performs no fetching or automatic translation.
|
|
55
|
+
|
|
56
|
+
The complete configuration is `messages`, optional `aliases`, and optional `direction`. Message values use named placeholders such as `{line}`, `{rows}` and `{columns}`. Keep their names unchanged. There are no source-text keys or custom formatting callbacks.
|
|
57
|
+
|
|
58
|
+
## How discovery works
|
|
59
|
+
|
|
60
|
+
`findSuggestions(text, caret, locale)` uses the same language registry as the renderer. It returns localized candidate labels and descriptions while preserving insertion IDs and formula content.
|
|
61
|
+
|
|
62
|
+
- Search accepts the localized label, locale-pack aliases and existing English/Korean catalog aliases.
|
|
63
|
+
- Symbol triggers such as `/`, `^`, `E/` and `->` are language-independent. Matching literal symbols appear before structures.
|
|
64
|
+
- Word matching is case-insensitive prefix matching on the trailing word, optionally preceded by `\`. Unicode letters and combining marks are accepted; NFC normalization handles composed/decomposed accents without changing replacement offsets.
|
|
65
|
+
- Supply single-word aliases for multiword names. Space-separated phrases, transliteration, fuzzy matching, accent removal and language-specific word segmentation are not implemented.
|
|
66
|
+
- Symbol-browser search also includes translated names, aliases, glyphs and LaTeX spellings. It uses substring matching.
|
|
67
|
+
|
|
68
|
+
| Alias key | Applies to | Example |
|
|
69
|
+
| --- | --- | --- |
|
|
70
|
+
| Structure ID | A structure candidate | `fraction`, `root`, `cases`, `aligned` |
|
|
71
|
+
| `matrix` | All standard matrix size presets | `"matrix": ["matrice"]` |
|
|
72
|
+
| `identity` | All identity matrix size presets | `"identity": ["identité"]` |
|
|
73
|
+
| Exact preset ID | One size only | `matrix-3`, `identity-4` |
|
|
74
|
+
| `symbol-` + glyph | One literal symbol | `symbol-α`, `symbol-∈` |
|
|
75
|
+
| `template-` + template ID | One editable template | `template-quadratic`, `template-zero-2`, `template-vector-3` |
|
|
76
|
+
|
|
77
|
+
Message keys and suggestion IDs have different jobs: `structure.fraction` selects display text; `fraction` selects an insertion candidate's aliases. See `mathStructures`, `mathSymbols` and `mathTemplates` from `/core` for catalog entries, and [SYMBOLS.md](./SYMBOLS.md) for symbol names.
|
|
78
|
+
|
|
79
|
+
## Resolution and ownership
|
|
80
|
+
|
|
81
|
+
The small `translate(locale, key, parameters)` helper performs dictionary lookup, fallback and literal interpolation. It has no dependency on a UI framework.
|
|
82
|
+
|
|
83
|
+
1. Look up an exact locale override, then its base language, then English. Tags are trimmed and case-normalized. Only the first language subtag is used as the base: `zh-Hant-TW` falls back to `zh`, not `zh-Hant`.
|
|
84
|
+
2. Resolve named parameters once. `$` and braces in parameter values stay literal. Missing parameters remain visible as placeholders; unknown keys remain visible as keys.
|
|
85
|
+
3. Merge search aliases from the exact locale and base pack. Registering a custom tag again replaces its definition; built-in `ko` and `en` cannot be overwritten.
|
|
86
|
+
|
|
87
|
+
Registration is startup configuration and does not notify mounted views on its own. Change a locale prop or session option to refresh the UI. No ICU plurals, dates, number formatting or locale-dependent decimal parsing are provided. Locale never rewrites user math, document IDs, clipboard content or LaTeX.
|
|
88
|
+
|
|
89
|
+
The main demo's heading/help/footer copy lives separately in `apps/math-demo/src/locales`. Registering a library pack does not translate the surrounding Site/Word/Slide/Note interface. To expose a third language throughout a host, add both its page translations and its library pack, then select the same locale for each. The main demo currently exposes only its complete English and Korean page translations.
|
|
90
|
+
|
|
91
|
+
Raw built-in packs are exported as `@barocss/math-editor/locales/en.json` and `/locales/ko.json`. `mathEnglishMessages` exposes the canonical key/value dictionary for tooling. The build emits equivalent ESM data modules so runtime imports do not require JSON import attributes. Edit JSON, never generated `dist` files.
|
|
92
|
+
|
|
93
|
+
## Verify a new pack
|
|
94
|
+
|
|
95
|
+
Compare its message keys and placeholder names against English. Exercise translated labels and aliases for a literal symbol, a structure, a matrix size and a template. Check nested slot names, language switching without data loss, and missing-message fallback. For a complete release, also review wording with a fluent speaker and test keyboard, screen-reader and relevant IME/RTL behavior in target browsers.
|
|
96
|
+
|
|
97
|
+
See [VALIDATION.md](./VALIDATION.md) for current test coverage and [ROADMAP.md](./ROADMAP.md) for remaining renderer and accessibility work.
|