@barocss/math-editor 0.2.0 → 0.4.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 +25 -14
- package/API-JAVASCRIPT.md +1 -1
- package/API-REACT.md +5 -1
- package/API-SESSION.md +168 -6
- package/API-SOLID.md +1 -1
- package/API-SVELTE.md +1 -1
- package/API-VUE.md +1 -1
- package/API-WEB-COMPONENT.md +1 -1
- package/CHANGELOG.md +51 -1
- package/EMBEDDING.md +4 -0
- package/IMPLEMENTATION.md +27 -2
- package/JSON-MODEL.md +1 -0
- package/LATEX-GUIDE.md +13 -0
- package/LATEX-SCOPE.md +2 -2
- package/LICENSE +1 -3
- package/README.md +150 -36
- package/ROADMAP.md +96 -10
- package/STYLING.md +157 -0
- package/SUPPORT.md +29 -11
- package/VALIDATION.md +117 -4
- package/dist/core.d.ts +5 -1
- package/dist/core.js +5 -1
- package/dist/document-codec.d.ts +0 -1
- package/dist/document-codec.js +0 -1
- package/dist/dom/caret-geometry.d.ts +3 -0
- package/dist/dom/caret-geometry.js +41 -0
- package/dist/dom/elements.d.ts +1 -2
- package/dist/dom/elements.js +2 -3
- package/dist/dom/latex-panel.d.ts +10 -0
- package/dist/dom/latex-panel.js +59 -0
- package/dist/dom/matrix-selection.d.ts +11 -0
- package/dist/dom/matrix-selection.js +30 -0
- package/dist/dom/menu-position.d.ts +14 -2
- package/dist/dom/menu-position.js +84 -15
- package/dist/dom/presentation-controls.d.ts +4 -0
- package/dist/dom/presentation-controls.js +56 -0
- package/dist/dom/quick-panel.d.ts +12 -0
- package/dist/dom/quick-panel.js +102 -0
- package/dist/dom/selection.d.ts +29 -0
- package/dist/dom/selection.js +53 -0
- package/dist/dom/symbol-panel.d.ts +9 -0
- package/dist/dom/symbol-panel.js +146 -0
- package/dist/dom/theme.d.ts +6 -0
- package/dist/dom/theme.js +68 -0
- package/dist/dom/toolbar-catalog.d.ts +10 -0
- package/dist/dom/toolbar-catalog.js +35 -0
- package/dist/dom/toolbar.d.ts +13 -2
- package/dist/dom/toolbar.js +295 -28
- package/dist/dom.d.ts +7 -1
- package/dist/dom.js +527 -126
- package/dist/editor-labels.d.ts +0 -1
- package/dist/editor-labels.js +0 -1
- package/dist/enter-policy.d.ts +0 -1
- package/dist/enter-policy.js +0 -1
- package/dist/fences.d.ts +0 -1
- package/dist/fences.js +0 -1
- package/dist/i18n.d.ts +0 -1
- package/dist/i18n.js +0 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +4 -1
- package/dist/latex-insertion.d.ts +12 -0
- package/dist/latex-insertion.js +26 -0
- package/dist/latex-paste-panel.d.ts +3 -0
- package/dist/latex-paste-panel.js +18 -0
- package/dist/latex.d.ts +0 -1
- package/dist/latex.js +0 -1
- package/dist/lines.d.ts +0 -1
- package/dist/lines.js +0 -1
- package/dist/locales/en.js +28 -2
- package/dist/locales/en.json +28 -2
- package/dist/locales/ko.js +28 -2
- package/dist/locales/ko.json +28 -2
- package/dist/math-editor-toolbar.d.ts +4 -2
- package/dist/math-editor-toolbar.js +3 -4
- package/dist/math-editor.d.ts +5 -2
- package/dist/math-editor.js +300 -44
- package/dist/matrix-range.d.ts +40 -0
- package/dist/matrix-range.js +242 -0
- package/dist/matrix.d.ts +0 -1
- package/dist/matrix.js +0 -1
- package/dist/model.d.ts +0 -1
- package/dist/model.js +0 -1
- package/dist/outputs.d.ts +0 -1
- package/dist/outputs.js +0 -1
- package/dist/preferences.d.ts +24 -0
- package/dist/preferences.js +66 -0
- package/dist/presentation-controls.d.ts +10 -0
- package/dist/presentation-controls.js +10 -0
- package/dist/presentation.d.ts +13 -0
- package/dist/presentation.js +86 -0
- package/dist/quick-panel.d.ts +2 -0
- package/dist/quick-panel.js +17 -0
- package/dist/range.d.ts +4 -1
- package/dist/range.js +57 -1
- package/dist/react.d.ts +0 -1
- package/dist/react.js +0 -1
- package/dist/session.d.ts +31 -2
- package/dist/session.js +108 -7
- package/dist/solid.d.ts +0 -1
- package/dist/solid.js +0 -1
- package/dist/suggestions.d.ts +4 -1
- package/dist/suggestions.js +103 -13
- package/dist/svelte.d.ts +0 -1
- package/dist/svelte.js +0 -1
- package/dist/symbol-browser.d.ts +0 -1
- package/dist/symbol-browser.js +0 -1
- package/dist/symbols.d.ts +0 -1
- package/dist/symbols.js +0 -1
- package/dist/templates.d.ts +0 -1
- package/dist/templates.js +0 -1
- package/dist/tokens.d.ts +0 -1
- package/dist/tokens.js +0 -1
- package/dist/vertical-navigation.d.ts +15 -0
- package/dist/vertical-navigation.js +145 -0
- package/dist/vue.d.ts +0 -1
- package/dist/vue.js +0 -1
- package/dist/web-component.d.ts +0 -1
- package/dist/web-component.js +0 -1
- package/package.json +1 -1
- package/src/style.css +254 -129
- package/dist/core.d.ts.map +0 -1
- package/dist/core.js.map +0 -1
- package/dist/document-codec.d.ts.map +0 -1
- package/dist/document-codec.js.map +0 -1
- package/dist/dom/elements.d.ts.map +0 -1
- package/dist/dom/elements.js.map +0 -1
- package/dist/dom/menu-position.d.ts.map +0 -1
- package/dist/dom/menu-position.js.map +0 -1
- package/dist/dom/toolbar.d.ts.map +0 -1
- package/dist/dom/toolbar.js.map +0 -1
- package/dist/dom.d.ts.map +0 -1
- package/dist/dom.js.map +0 -1
- package/dist/editor-labels.d.ts.map +0 -1
- package/dist/editor-labels.js.map +0 -1
- package/dist/enter-policy.d.ts.map +0 -1
- package/dist/enter-policy.js.map +0 -1
- package/dist/fences.d.ts.map +0 -1
- package/dist/fences.js.map +0 -1
- package/dist/i18n.d.ts.map +0 -1
- package/dist/i18n.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/latex.d.ts.map +0 -1
- package/dist/latex.js.map +0 -1
- package/dist/lines.d.ts.map +0 -1
- package/dist/lines.js.map +0 -1
- package/dist/math-editor-toolbar.d.ts.map +0 -1
- package/dist/math-editor-toolbar.js.map +0 -1
- package/dist/math-editor.d.ts.map +0 -1
- package/dist/math-editor.js.map +0 -1
- package/dist/matrix.d.ts.map +0 -1
- package/dist/matrix.js.map +0 -1
- package/dist/model.d.ts.map +0 -1
- package/dist/model.js.map +0 -1
- package/dist/outputs.d.ts.map +0 -1
- package/dist/outputs.js.map +0 -1
- package/dist/range.d.ts.map +0 -1
- package/dist/range.js.map +0 -1
- package/dist/react.d.ts.map +0 -1
- package/dist/react.js.map +0 -1
- package/dist/session.d.ts.map +0 -1
- package/dist/session.js.map +0 -1
- package/dist/solid.d.ts.map +0 -1
- package/dist/solid.js.map +0 -1
- package/dist/suggestions.d.ts.map +0 -1
- package/dist/suggestions.js.map +0 -1
- package/dist/svelte.d.ts.map +0 -1
- package/dist/svelte.js.map +0 -1
- package/dist/symbol-browser.d.ts.map +0 -1
- package/dist/symbol-browser.js.map +0 -1
- package/dist/symbols.d.ts.map +0 -1
- package/dist/symbols.js.map +0 -1
- package/dist/templates.d.ts.map +0 -1
- package/dist/templates.js.map +0 -1
- package/dist/tokens.d.ts.map +0 -1
- package/dist/tokens.js.map +0 -1
- package/dist/vue.d.ts.map +0 -1
- package/dist/vue.js.map +0 -1
- package/dist/web-component.d.ts.map +0 -1
- package/dist/web-component.js.map +0 -1
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type MathLocale } from '../i18n.js';
|
|
2
|
+
import type { StructureKind } from '../model.js';
|
|
3
|
+
/** Full discovery search retains the symbol catalog and suggestion engine's ranking. */
|
|
4
|
+
export declare function findToolbarSymbols(query: string, locale: MathLocale): (readonly ["↑", "symbol.upArrow", "uparrow arrow 화살표", "- ->", "\\uparrow"] | readonly ["↕", "symbol.upDownArrow", "updownarrow arrow 화살표", "- ->", "\\updownarrow"] | readonly ["⇐", "symbol.doubleLeftArrow", "Leftarrow arrow 화살표", "- ->", "\\Leftarrow"] | readonly ["⇑", "symbol.doubleUpArrow", "Uparrow arrow 화살표", "- ->", "\\Uparrow"] | readonly ["⇓", "symbol.doubleDownArrow", "Downarrow arrow 화살표", "- ->", "\\Downarrow"] | readonly ["⇕", "symbol.doubleUpDownArrow", "Updownarrow arrow 화살표", "- ->", "\\Updownarrow"] | readonly ["↗", "symbol.northEastArrow", "nearrow arrow 화살표", "- ->", "\\nearrow"] | readonly ["↘", "symbol.southEastArrow", "searrow arrow 화살표", "- ->", "\\searrow"] | readonly ["↙", "symbol.southWestArrow", "swarrow arrow 화살표", "- ->", "\\swarrow"] | readonly ["↖", "symbol.northWestArrow", "nwarrow arrow 화살표", "- ->", "\\nwarrow"] | readonly ["⟶", "symbol.longRightArrow", "longrightarrow arrow 화살표", "- ->", "\\longrightarrow"] | readonly ["⟵", "symbol.longLeftArrow", "longleftarrow arrow 화살표", "- ->", "\\longleftarrow"] | readonly ["⟷", "symbol.longLeftRightArrow", "longleftrightarrow arrow 화살표", "-", "\\longleftrightarrow"] | readonly ["⟹", "symbol.longDoubleRightArrow", "Longrightarrow arrow 화살표", "- ->", "\\Longrightarrow"] | readonly ["⟸", "symbol.longDoubleLeftArrow", "Longleftarrow arrow 화살표", "- ->", "\\Longleftarrow"] | readonly ["⟺", "symbol.longDoubleLeftRightArrow", "Longleftrightarrow arrow 화살표", "", "\\Longleftrightarrow"] | readonly ["↪", "symbol.hookRightArrow", "hookrightarrow arrow 화살표", "- ->", "\\hookrightarrow"] | readonly ["↩", "symbol.hookLeftArrow", "hookleftarrow arrow 화살표", "- ->", "\\hookleftarrow"] | readonly ["⇀", "symbol.rightHarpoonUp", "rightharpoonup arrow 화살표", "- ->", "\\rightharpoonup"] | readonly ["↼", "symbol.leftHarpoonUp", "leftharpoonup arrow 화살표", "- ->", "\\leftharpoonup"] | readonly ["⇁", "symbol.rightHarpoonDown", "rightharpoondown arrow 화살표", "- ->", "\\rightharpoondown"] | readonly ["↽", "symbol.leftHarpoonDown", "leftharpoondown arrow 화살표", "- ->", "\\leftharpoondown"] | readonly ["⇌", "symbol.rightLeftHarpoons", "rightleftharpoons arrow 화살표", "- ->", "\\rightleftharpoons"] | readonly ["⇋", "symbol.leftRightHarpoons", "leftrightharpoons arrow 화살표", "- ->", "\\leftrightharpoons"] | readonly ["↓", "symbol.downArrow", "downarrow down 아래화살표 아래쪽화살표", "- ->", "\\downarrow"] | readonly ["⩾", "symbol.greaterOrEqualSlanted", "geqslant", "", "\\geqslant"] | readonly ["⩽", "symbol.lessOrEqualSlanted", "leqslant", "", "\\leqslant"] | readonly ["∋", "symbol.contains", "ni contains", "", "\\ni"] | readonly ["⊃", "symbol.superset", "supset superset", "", "\\supset"] | readonly ["⊇", "symbol.supersetOrEqual", "supseteq", "", "\\supseteq"] | readonly ["⊈", "symbol.notSubsetOrEqual", "nsubseteq", "", "\\nsubseteq"] | readonly ["∖", "symbol.setDifference", "setminus difference", "", "\\setminus"] | readonly ["ℕ", "symbol.naturals", "naturals natural", "", "\\mathbb{N}"] | readonly ["ℤ", "symbol.integers", "integers integer", "", "\\mathbb{Z}"] | readonly ["ℚ", "symbol.rationals", "rationals rational", "", "\\mathbb{Q}"] | readonly ["ℝ", "symbol.reals", "reals real", "", "\\mathbb{R}"] | readonly ["ℂ", "symbol.complexes", "complexes complex", "", "\\mathbb{C}"] | readonly ["⊥", "symbol.perpendicular", "perp perpendicular", "", "\\perp"] | readonly ["∥", "symbol.parallel", "parallel", "", "\\parallel"] | readonly ["≅", "symbol.congruent", "cong congruent", "", "\\cong"] | readonly ["∼", "symbol.similar", "sim similar", "", "\\sim"] | readonly ["↦", "symbol.mapsTo", "mapsto maps arrow 화살표", "|-> - ->", "\\mapsto"] | readonly ["…", "symbol.ellipsis", "ldots ellipsis", "", "\\ldots"] | readonly ["⋯", "symbol.centeredDots", "cdots", "", "\\cdots"] | readonly ["⋮", "symbol.verticalDots", "vdots", "", "\\vdots"] | readonly ["⋱", "symbol.diagonalDots", "ddots", "", "\\ddots"] | readonly ["°", "symbol.degree", "degree degrees 각도", "", "{}^{\\circ}"] | readonly ["∠", "symbol.angle", "angle", "", "\\angle"] | readonly ["+", "symbol.plus", "plus sum", "+", "+"] | readonly ["−", "symbol.minus", "minus", "-", "-"] | readonly ["±", "symbol.plusMinus", "plusminus sum", "+- +", "\\pm"] | readonly ["∓", "symbol.minusPlus", "minusplus", "-+ -", "\\mp"] | readonly ["×", "symbol.times", "times multiply", "*", "\\times"] | readonly ["·", "symbol.dot", "dot multiply", "*", "\\cdot"] | readonly ["÷", "symbol.divide", "divide division", "/", "\\div"] | readonly ["=", "symbol.equal", "equal", "=", "="] | readonly ["≠", "symbol.notEqual", "neq unequal", "!= /= =", "\\ne"] | readonly ["≈", "symbol.approximatelyEqual", "approx", "~ ~~ =", "\\approx"] | readonly ["≡", "symbol.equivalent", "equiv", "=== =", "\\equiv"] | readonly ["<", "symbol.lessThan", "less", "<", "<"] | readonly [">", "symbol.greaterThan", "greater", ">", ">"] | readonly ["≤", "symbol.lessOrEqual", "leq less", "<= <- <", "\\le"] | readonly ["≥", "symbol.greaterOrEqual", "geq greater", ">= >- >", "\\ge"] | readonly ["∝", "symbol.proportional", "proportional", "~", "\\propto"] | readonly ["→", "symbol.rightArrow", "rightarrow arrow", "-> -", "\\to"] | readonly ["←", "symbol.leftArrow", "leftarrow arrow", "<- < - ->", "\\leftarrow"] | readonly ["↔", "symbol.leftRightArrow", "leftrightarrow arrow", "<-> - ->", "\\leftrightarrow"] | readonly ["⇒", "symbol.implies", "implies arrow 화살표", "=> = - ->", "\\Rightarrow"] | readonly ["⇔", "symbol.iff", "iff arrow 화살표", "<=> - ->", "\\Leftrightarrow"] | readonly ["∈", "symbol.elementOf", "in element", "E", "\\in"] | readonly ["∉", "symbol.notElementOf", "notin element", "E/", "\\notin"] | readonly ["∀", "symbol.forAll", "forall", "A", "\\forall"] | readonly ["∃", "symbol.exists", "exists", "E", "\\exists"] | readonly ["∪", "symbol.union", "union", "U", "\\cup"] | readonly ["∩", "symbol.intersection", "intersection", "", "\\cap"] | readonly ["⊂", "symbol.subset", "subset", "<", "\\subset"] | readonly ["⊆", "symbol.subsetOrEqual", "subseteq", "<=", "\\subseteq"] | readonly ["∅", "symbol.emptySet", "emptyset", "", "\\emptyset"] | readonly ["∞", "symbol.infinity", "infinity infty", "", "\\infty"] | readonly ["∂", "symbol.partialDerivative", "partial derivative", "", "\\partial"] | readonly ["∇", "symbol.nabla", "nabla gradient", "", "\\nabla"] | readonly ["∧", "symbol.logicalAnd", "and wedge", "^", "\\wedge"] | readonly ["∨", "symbol.logicalOr", "or vee", "", "\\vee"] | readonly ["¬", "symbol.logicalNot", "not neg", "!", "\\neg"] | readonly ["α", "symbol.alpha", "alpha", "", "\\alpha"] | readonly ["β", "symbol.beta", "beta", "", "\\beta"] | readonly ["γ", "symbol.gamma", "gamma", "", "\\gamma"] | readonly ["δ", "symbol.delta", "delta", "", "\\delta"] | readonly ["ε", "symbol.epsilon", "epsilon", "", "\\epsilon"] | readonly ["ζ", "symbol.zeta", "zeta", "", "\\zeta"] | readonly ["η", "symbol.eta", "eta", "", "\\eta"] | readonly ["θ", "symbol.theta", "theta", "", "\\theta"] | readonly ["ι", "symbol.iota", "iota", "", "\\iota"] | readonly ["κ", "symbol.kappa", "kappa", "", "\\kappa"] | readonly ["λ", "symbol.lambda", "lambda", "", "\\lambda"] | readonly ["μ", "symbol.mu", "mu", "", "\\mu"] | readonly ["ν", "symbol.nu", "nu", "", "\\nu"] | readonly ["ξ", "symbol.xi", "xi", "", "\\xi"] | readonly ["π", "symbol.pi", "pi", "", "\\pi"] | readonly ["ρ", "symbol.rho", "rho", "", "\\rho"] | readonly ["σ", "symbol.sigma", "sigma", "", "\\sigma"] | readonly ["τ", "symbol.tau", "tau", "", "\\tau"] | readonly ["υ", "symbol.upsilon", "upsilon", "", "\\upsilon"] | readonly ["φ", "symbol.phi", "phi", "", "\\phi"] | readonly ["χ", "symbol.chi", "chi", "", "\\chi"] | readonly ["ψ", "symbol.psi", "psi", "", "\\psi"] | readonly ["ω", "symbol.omega", "omega", "", "\\omega"] | readonly ["Γ", "symbol.upperGamma", "Gamma", "", "\\Gamma"] | readonly ["Δ", "symbol.upperDelta", "Delta", "", "\\Delta"] | readonly ["Θ", "symbol.upperTheta", "Theta", "", "\\Theta"] | readonly ["Λ", "symbol.upperLambda", "Lambda", "", "\\Lambda"] | readonly ["Ξ", "symbol.upperXi", "Xi", "", "\\Xi"] | readonly ["Π", "symbol.upperPi", "Pi", "", "\\Pi"] | readonly ["Σ", "symbol.upperSigma", "Sigma", "", "\\Sigma"] | readonly ["Φ", "symbol.upperPhi", "Phi", "", "\\Phi"] | readonly ["Ψ", "symbol.upperPsi", "Psi", "", "\\Psi"] | readonly ["Ω", "symbol.upperOmega", "Omega", "", "\\Omega"])[];
|
|
5
|
+
/** Templates must not offer a back door around a host's allowed structure kinds. */
|
|
6
|
+
export declare function toolbarTemplates(kinds?: readonly StructureKind[]): import("../templates.js").MathTemplate[];
|
|
7
|
+
export declare function parseToolbarMatrixPreset(value: string): {
|
|
8
|
+
size: number;
|
|
9
|
+
identity: boolean;
|
|
10
|
+
} | undefined;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { mathLocaleAliases, translate } from '../i18n.js';
|
|
2
|
+
import { findSuggestions } from '../suggestions.js';
|
|
3
|
+
import { mathSymbols } from '../symbols.js';
|
|
4
|
+
import { createTemplate, mathTemplates } from '../templates.js';
|
|
5
|
+
/** Full discovery search retains the symbol catalog and suggestion engine's ranking. */
|
|
6
|
+
export function findToolbarSymbols(query, locale) {
|
|
7
|
+
const needle = query.trim().normalize('NFC').toLowerCase();
|
|
8
|
+
if (!needle)
|
|
9
|
+
return [...mathSymbols];
|
|
10
|
+
const matches = mathSymbols.filter(([glyph, label, aliases, triggers, latex]) => [
|
|
11
|
+
glyph,
|
|
12
|
+
translate('en', label),
|
|
13
|
+
translate('ko', label),
|
|
14
|
+
translate(locale, label),
|
|
15
|
+
...mathLocaleAliases(locale, `symbol-${glyph}`),
|
|
16
|
+
aliases,
|
|
17
|
+
triggers,
|
|
18
|
+
latex,
|
|
19
|
+
].some((value) => value.normalize('NFC').toLowerCase().includes(needle)));
|
|
20
|
+
const ranked = findSuggestions(query.trim(), query.trim().length, locale).candidates.filter((item) => item.value !== undefined);
|
|
21
|
+
const order = new Map(ranked.map((item, index) => [item.value, index]));
|
|
22
|
+
return matches.sort((a, b) => (order.get(a[0]) ?? Infinity) - (order.get(b[0]) ?? Infinity));
|
|
23
|
+
}
|
|
24
|
+
/** Templates must not offer a back door around a host's allowed structure kinds. */
|
|
25
|
+
export function toolbarTemplates(kinds) {
|
|
26
|
+
if (!kinds)
|
|
27
|
+
return mathTemplates;
|
|
28
|
+
const allowed = new Set(kinds);
|
|
29
|
+
const accepts = (row) => row.children.every((node) => node.type === 'text' || (allowed.has(node.type) && node.slots.every(accepts)));
|
|
30
|
+
return mathTemplates.filter((template) => createTemplate(template.id).rows.every(accepts));
|
|
31
|
+
}
|
|
32
|
+
export function parseToolbarMatrixPreset(value) {
|
|
33
|
+
const match = /^(identity-)?([234])$/.exec(value);
|
|
34
|
+
return match ? { size: Number(match[2]), identity: !!match[1] } : undefined;
|
|
35
|
+
}
|
package/dist/dom/toolbar.d.ts
CHANGED
|
@@ -1,13 +1,24 @@
|
|
|
1
|
+
import { type MathLocale } from '../i18n.js';
|
|
1
2
|
import type { MathSession } from '../session.js';
|
|
2
3
|
import type { StructureKind } from '../model.js';
|
|
3
4
|
export interface MathToolbarOptions {
|
|
4
5
|
kinds?: readonly StructureKind[];
|
|
5
6
|
/** Visible structure buttons before More; defaults to 8. */
|
|
6
7
|
maxItems?: number;
|
|
8
|
+
/** Labels while no editor is active; an attached session supplies its own locale. */
|
|
9
|
+
locale?: MathLocale;
|
|
7
10
|
onExecute?: () => void;
|
|
11
|
+
onPasteLatex?: () => void;
|
|
12
|
+
/** Close another utility owned by the editing surface before opening a toolbar panel. */
|
|
13
|
+
onOpenPanel?: () => void;
|
|
8
14
|
}
|
|
9
15
|
/** Independently mounted toolbar; the host may instead build any UI around session.execute(). */
|
|
10
|
-
export declare function mountMathToolbar(host: HTMLElement, session: MathSession, options?: MathToolbarOptions): {
|
|
16
|
+
export declare function mountMathToolbar(host: HTMLElement, session: MathSession | null, options?: MathToolbarOptions): {
|
|
17
|
+
/** Close discovery/paste panels without changing the formula or its selection. */
|
|
18
|
+
closePanels: () => void;
|
|
19
|
+
/** Reuse one toolbar for multiple editors without retaining previous subscriptions. */
|
|
20
|
+
setSession(next: MathSession | null): void;
|
|
21
|
+
/** Disable mutation controls while the attached native editor is composing. */
|
|
22
|
+
setDisabled(next: boolean): void;
|
|
11
23
|
destroy(): void;
|
|
12
24
|
};
|
|
13
|
-
//# sourceMappingURL=toolbar.d.ts.map
|
package/dist/dom/toolbar.js
CHANGED
|
@@ -1,61 +1,328 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { drawPresentationControls } from './presentation-controls.js';
|
|
2
|
+
import { mountQuickPanel } from './quick-panel.js';
|
|
3
|
+
import { mountLatexPanel } from './latex-panel.js';
|
|
4
|
+
import { elementFactory } from './elements.js';
|
|
5
|
+
import { translate, mathLocaleDirection, } from '../i18n.js';
|
|
3
6
|
import { mathStructures } from '../suggestions.js';
|
|
7
|
+
import { mathSymbols } from '../symbols.js';
|
|
8
|
+
import { resolveRange, wrappingKinds } from '../range.js';
|
|
9
|
+
import { activeGrid, insertIdentityMatrix, insertMatrix, matrixEnvironments, MATRIX_MAX_SIZE, resizeMatrix, setMatrixEnvironment, } from '../matrix.js';
|
|
10
|
+
import { parseToolbarMatrixPreset, toolbarTemplates } from './toolbar-catalog.js';
|
|
11
|
+
import { mountSymbolPanel } from './symbol-panel.js';
|
|
4
12
|
/** Independently mounted toolbar; the host may instead build any UI around session.execute(). */
|
|
5
13
|
export function mountMathToolbar(host, session, options = {}) {
|
|
14
|
+
const doc = host.ownerDocument;
|
|
15
|
+
const element = elementFactory(doc);
|
|
6
16
|
let expanded = false;
|
|
17
|
+
let activeSession = session;
|
|
18
|
+
let locale = options.locale ?? 'en';
|
|
19
|
+
let destroyed = false;
|
|
20
|
+
let disabled = false;
|
|
21
|
+
let quickPanel;
|
|
22
|
+
let latexPanel;
|
|
23
|
+
let symbolPanel;
|
|
7
24
|
const maxItems = Math.max(0, Math.floor(Number.isFinite(options.maxItems) ? options.maxItems : 8));
|
|
25
|
+
const templates = toolbarTemplates(options.kinds);
|
|
8
26
|
const toolbar = element('div', 'me-tools');
|
|
9
|
-
|
|
27
|
+
const gridTools = element('div', 'me-matrix-tools me-dom-grid-tools');
|
|
28
|
+
const presentation = element('div');
|
|
29
|
+
const panels = element('div', 'me-dom-toolbar-panels');
|
|
30
|
+
panels.hidden = true;
|
|
31
|
+
host.append(toolbar, gridTools, presentation, panels);
|
|
32
|
+
const closeSymbols = (restoreFocus = false) => {
|
|
33
|
+
quickPanel?.destroy();
|
|
34
|
+
quickPanel = undefined;
|
|
35
|
+
latexPanel?.destroy();
|
|
36
|
+
latexPanel = undefined;
|
|
37
|
+
symbolPanel?.destroy();
|
|
38
|
+
symbolPanel = undefined;
|
|
39
|
+
panels.hidden = true;
|
|
40
|
+
const toggle = toolbar.querySelector('[data-math-tool="symbols"]');
|
|
41
|
+
toggle?.setAttribute('aria-expanded', 'false');
|
|
42
|
+
if (restoreFocus)
|
|
43
|
+
toggle?.focus();
|
|
44
|
+
};
|
|
45
|
+
const enabled = () => !!activeSession && !disabled && !destroyed;
|
|
46
|
+
const execute = (command) => {
|
|
47
|
+
if (enabled() && activeSession.execute(command))
|
|
48
|
+
options.onExecute?.();
|
|
49
|
+
};
|
|
50
|
+
const transform = (operation) => {
|
|
51
|
+
if (!enabled())
|
|
52
|
+
return;
|
|
53
|
+
const current = activeSession.getSnapshot().state;
|
|
54
|
+
const next = operation(current);
|
|
55
|
+
if (next !== current && activeSession.apply(next))
|
|
56
|
+
options.onExecute?.();
|
|
57
|
+
};
|
|
10
58
|
const draw = () => {
|
|
11
|
-
const snapshot =
|
|
59
|
+
const snapshot = activeSession?.getSnapshot();
|
|
60
|
+
if (snapshot && (snapshot.locale !== locale || snapshot.matrixRange))
|
|
61
|
+
closeSymbols();
|
|
62
|
+
locale = snapshot?.locale ?? locale;
|
|
63
|
+
const t = (text, parameters) => translate(locale, text, parameters);
|
|
12
64
|
toolbar.replaceChildren();
|
|
65
|
+
gridTools.replaceChildren();
|
|
66
|
+
gridTools.hidden = true;
|
|
13
67
|
toolbar.setAttribute('role', 'toolbar');
|
|
14
68
|
toolbar.setAttribute('aria-label', t('toolbar.label'));
|
|
15
|
-
toolbar.dir = mathLocaleDirection(
|
|
69
|
+
toolbar.dir = mathLocaleDirection(locale);
|
|
70
|
+
const button = (label, action, blocked = false) => {
|
|
71
|
+
const result = element('button', '', label);
|
|
72
|
+
result.type = 'button';
|
|
73
|
+
result.disabled = !enabled() || blocked;
|
|
74
|
+
result.onmousedown = (event) => event.preventDefault();
|
|
75
|
+
result.onclick = () => {
|
|
76
|
+
if (!result.disabled && enabled())
|
|
77
|
+
action();
|
|
78
|
+
};
|
|
79
|
+
return result;
|
|
80
|
+
};
|
|
81
|
+
const hasRange = !!snapshot?.range || !!snapshot?.matrixRange;
|
|
82
|
+
const canWrap = snapshot?.range && resolveRange(snapshot.state.document, snapshot.range)?.length === 1;
|
|
16
83
|
const items = mathStructures.filter((item) => !options.kinds || options.kinds.includes(item.kind));
|
|
17
84
|
for (const item of expanded ? items : items.slice(0, maxItems)) {
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
button.onclick = () => {
|
|
23
|
-
session.execute({ type: 'structure', kind: item.kind });
|
|
24
|
-
options.onExecute?.();
|
|
25
|
-
};
|
|
26
|
-
toolbar.append(button);
|
|
85
|
+
const control = button(`${item.glyph} ${t(item.label)}`, () => execute({ type: 'structure', kind: item.kind }), hasRange && (!canWrap || !wrappingKinds.includes(item.kind)));
|
|
86
|
+
control.setAttribute('aria-label', t(item.label));
|
|
87
|
+
control.dataset.mathTool = item.kind;
|
|
88
|
+
toolbar.append(control);
|
|
27
89
|
}
|
|
28
|
-
if (
|
|
90
|
+
if (expanded) {
|
|
91
|
+
const quick = button(t('quick.title'), () => {
|
|
92
|
+
options.onOpenPanel?.();
|
|
93
|
+
closeSymbols();
|
|
94
|
+
const target = activeSession;
|
|
95
|
+
panels.hidden = false;
|
|
96
|
+
quickPanel = mountQuickPanel(panels, {
|
|
97
|
+
locale,
|
|
98
|
+
preferences: target.preferences,
|
|
99
|
+
allowedTemplates: templates.map((item) => item.id),
|
|
100
|
+
onInsert: (item) => enabled() &&
|
|
101
|
+
activeSession === target &&
|
|
102
|
+
target.execute(item.template
|
|
103
|
+
? { type: 'template', id: item.template }
|
|
104
|
+
: { type: 'text', value: item.glyph }),
|
|
105
|
+
onClose: () => {
|
|
106
|
+
closeSymbols();
|
|
107
|
+
options.onExecute?.();
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
}, !!snapshot?.matrixRange);
|
|
111
|
+
quick.dataset.mathTool = 'quick';
|
|
112
|
+
toolbar.append(quick);
|
|
113
|
+
const paste = button(t('clipboard.latexTitle'), () => {
|
|
114
|
+
options.onOpenPanel?.();
|
|
115
|
+
closeSymbols();
|
|
116
|
+
if (options.onPasteLatex) {
|
|
117
|
+
options.onPasteLatex();
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
panels.hidden = false;
|
|
121
|
+
latexPanel = mountLatexPanel(panels, {
|
|
122
|
+
locale,
|
|
123
|
+
onInsert: (source) => activeSession.pasteLatex(source),
|
|
124
|
+
onClose: () => {
|
|
125
|
+
closeSymbols();
|
|
126
|
+
options.onExecute?.();
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
}, !!snapshot?.matrixRange);
|
|
130
|
+
paste.dataset.mathTool = 'paste-latex';
|
|
131
|
+
paste.title = t('clipboard.latexShortcut');
|
|
132
|
+
toolbar.append(paste);
|
|
133
|
+
if (!options.kinds || options.kinds.includes('matrix')) {
|
|
134
|
+
const select = element('select', 'me-matrix-size');
|
|
135
|
+
select.setAttribute('aria-label', t('matrix.preset'));
|
|
136
|
+
select.dataset.mathTool = 'matrix-preset';
|
|
137
|
+
select.disabled = !enabled() || hasRange;
|
|
138
|
+
const placeholder = element('option', '', t('matrix.presetPlaceholder'));
|
|
139
|
+
placeholder.value = '';
|
|
140
|
+
placeholder.disabled = true;
|
|
141
|
+
select.append(placeholder);
|
|
142
|
+
for (const identity of [false, true])
|
|
143
|
+
for (const size of [2, 3, 4]) {
|
|
144
|
+
const item = element('option', '', t(identity ? 'matrix.insertIdentity' : 'matrix.insert', {
|
|
145
|
+
rows: size,
|
|
146
|
+
columns: size,
|
|
147
|
+
}));
|
|
148
|
+
item.value = `${identity ? 'identity-' : ''}${size}`;
|
|
149
|
+
select.append(item);
|
|
150
|
+
}
|
|
151
|
+
select.value = '';
|
|
152
|
+
select.onchange = () => {
|
|
153
|
+
const preset = parseToolbarMatrixPreset(select.value);
|
|
154
|
+
select.value = '';
|
|
155
|
+
if (preset && !select.disabled)
|
|
156
|
+
transform((state) => (preset.identity ? insertIdentityMatrix : insertMatrix)(state, preset.size));
|
|
157
|
+
};
|
|
158
|
+
toolbar.append(select);
|
|
159
|
+
}
|
|
160
|
+
if (templates.length) {
|
|
161
|
+
const select = element('select', 'me-matrix-size');
|
|
162
|
+
select.setAttribute('aria-label', t('template.label'));
|
|
163
|
+
select.dataset.mathTool = 'template';
|
|
164
|
+
select.disabled = !enabled() || !!snapshot?.matrixRange;
|
|
165
|
+
const placeholder = element('option', '', t('template.placeholder'));
|
|
166
|
+
placeholder.value = '';
|
|
167
|
+
placeholder.disabled = true;
|
|
168
|
+
select.append(placeholder);
|
|
169
|
+
for (const template of templates) {
|
|
170
|
+
const item = element('option', '', t(template.label, template.labelParameters));
|
|
171
|
+
item.value = template.id;
|
|
172
|
+
select.append(item);
|
|
173
|
+
}
|
|
174
|
+
select.value = '';
|
|
175
|
+
select.onchange = () => {
|
|
176
|
+
const id = select.value;
|
|
177
|
+
select.value = '';
|
|
178
|
+
if (!select.disabled && templates.some((template) => template.id === id))
|
|
179
|
+
execute({ type: 'template', id });
|
|
180
|
+
};
|
|
181
|
+
toolbar.append(select);
|
|
182
|
+
}
|
|
183
|
+
const symbols = button(t('symbols.title'), () => {
|
|
184
|
+
if (symbolPanel) {
|
|
185
|
+
closeSymbols(true);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
options.onOpenPanel?.();
|
|
189
|
+
closeSymbols();
|
|
190
|
+
const target = activeSession;
|
|
191
|
+
panels.hidden = false;
|
|
192
|
+
symbols.setAttribute('aria-expanded', 'true');
|
|
193
|
+
symbolPanel = mountSymbolPanel(panels, {
|
|
194
|
+
locale,
|
|
195
|
+
onClose: () => closeSymbols(true),
|
|
196
|
+
onInsert: (glyph) => {
|
|
197
|
+
if (activeSession !== target || !enabled())
|
|
198
|
+
return;
|
|
199
|
+
closeSymbols();
|
|
200
|
+
execute({ type: 'text', value: glyph });
|
|
201
|
+
},
|
|
202
|
+
});
|
|
203
|
+
}, !!snapshot?.matrixRange);
|
|
204
|
+
symbols.dataset.mathTool = 'symbols';
|
|
205
|
+
symbols.setAttribute('aria-expanded', String(!!symbolPanel));
|
|
206
|
+
toolbar.append(symbols);
|
|
207
|
+
for (const glyph of ['α', 'β', 'π', 'θ', '∞']) {
|
|
208
|
+
const item = mathSymbols.find((symbol) => symbol[0] === glyph);
|
|
209
|
+
const control = button(glyph, () => execute({ type: 'text', value: glyph }), !!snapshot?.matrixRange);
|
|
210
|
+
control.setAttribute('aria-label', t(item[1]));
|
|
211
|
+
toolbar.append(control);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// More also reveals discovery controls when all allowed structures already fit.
|
|
215
|
+
{
|
|
29
216
|
const toggle = element('button', 'me-toolbar-toggle', t(expanded ? 'toolbar.less' : 'toolbar.more'));
|
|
30
217
|
toggle.type = 'button';
|
|
31
218
|
toggle.setAttribute('aria-expanded', String(expanded));
|
|
32
219
|
toggle.onmousedown = (event) => event.preventDefault();
|
|
33
220
|
toggle.onclick = () => {
|
|
34
221
|
expanded = !expanded;
|
|
222
|
+
if (!expanded)
|
|
223
|
+
closeSymbols();
|
|
35
224
|
draw();
|
|
36
|
-
toolbar.querySelector('
|
|
225
|
+
toolbar.querySelector('.me-toolbar-toggle')?.focus();
|
|
37
226
|
};
|
|
38
227
|
toolbar.append(toggle);
|
|
39
228
|
}
|
|
40
229
|
for (const type of ['undo', 'redo']) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
230
|
+
toolbar.append(button(t(type === 'undo' ? 'history.undo' : 'history.redo'), () => execute({ type }), !(type === 'undo' ? snapshot?.canUndo : snapshot?.canRedo)));
|
|
231
|
+
}
|
|
232
|
+
if (snapshot)
|
|
233
|
+
drawPresentationControls(presentation, snapshot.state, locale, (id, change) => execute({ type: 'presentation', id, change }), !enabled() || hasRange, options.kinds);
|
|
234
|
+
else
|
|
235
|
+
presentation.hidden = true;
|
|
236
|
+
const context = snapshot && activeGrid(snapshot.state);
|
|
237
|
+
if (context && (!options.kinds || options.kinds.includes(context.matrix.type))) {
|
|
238
|
+
gridTools.hidden = false;
|
|
239
|
+
gridTools.dir = mathLocaleDirection(locale);
|
|
240
|
+
gridTools.setAttribute('role', 'toolbar');
|
|
241
|
+
gridTools.setAttribute('aria-label', t(context.matrix.type === 'matrix' ? 'matrix.edit' : 'grid.editRows'));
|
|
242
|
+
gridTools.append(element('span', '', `${context.rows} × ${context.matrix.columns}`), element('small', '', t('grid.position', { row: context.row + 1, column: context.column + 1 })));
|
|
243
|
+
const selected = hasRange || snapshot.state.caret.start !== snapshot.state.caret.end;
|
|
244
|
+
if (context.matrix.type === 'matrix') {
|
|
245
|
+
const select = element('select');
|
|
246
|
+
select.setAttribute('aria-label', t('matrix.delimiters'));
|
|
247
|
+
select.dataset.mathTool = 'matrix-delimiters';
|
|
248
|
+
select.disabled = !enabled() || selected;
|
|
249
|
+
for (const item of matrixEnvironments) {
|
|
250
|
+
const option = element('option', '', t(item.label));
|
|
251
|
+
option.value = item.value;
|
|
252
|
+
select.append(option);
|
|
253
|
+
}
|
|
254
|
+
select.value = context.matrix.environment;
|
|
255
|
+
select.onchange = () => {
|
|
256
|
+
if (!select.disabled)
|
|
257
|
+
transform((state) => setMatrixEnvironment(state, select.value));
|
|
258
|
+
};
|
|
259
|
+
gridTools.append(select);
|
|
260
|
+
for (const [tool, label, command] of [
|
|
261
|
+
['matrix-select', 'matrix.selectCells', { type: 'matrix-select' }],
|
|
262
|
+
['matrix-select-all', 'matrix.selectAll', { type: 'matrix-select', all: true }],
|
|
263
|
+
['matrix-transpose', 'matrix.transpose', { type: 'matrix-transpose' }],
|
|
264
|
+
]) {
|
|
265
|
+
const control = button(t(label), () => execute(command), !!snapshot.range);
|
|
266
|
+
control.dataset.mathTool = tool;
|
|
267
|
+
gridTools.append(control);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
for (const axis of ['row', 'column']) {
|
|
271
|
+
if (axis === 'column' && context.matrix.type !== 'matrix')
|
|
272
|
+
continue;
|
|
273
|
+
const size = axis === 'row' ? context.rows : context.matrix.columns;
|
|
274
|
+
for (const action of ['insert', 'delete']) {
|
|
275
|
+
const key = axis === 'row'
|
|
276
|
+
? action === 'insert'
|
|
277
|
+
? 'grid.addRow'
|
|
278
|
+
: 'grid.deleteRow'
|
|
279
|
+
: action === 'insert'
|
|
280
|
+
? 'grid.addColumn'
|
|
281
|
+
: 'grid.deleteColumn';
|
|
282
|
+
const control = button(t(key), () => transform((state) => resizeMatrix(state, axis, action)), selected || (action === 'insert' ? size >= MATRIX_MAX_SIZE : size <= 1));
|
|
283
|
+
control.dataset.mathTool = `${axis}-${action}`;
|
|
284
|
+
if (action === 'delete') {
|
|
285
|
+
control.title = t(axis === 'row' ? 'grid.deleteRowShortcut' : 'grid.deleteColumnShortcut');
|
|
286
|
+
control.setAttribute('aria-keyshortcuts', axis === 'row' ? 'Alt+Shift+ArrowUp' : 'Alt+Shift+ArrowLeft');
|
|
287
|
+
}
|
|
288
|
+
gridTools.append(control);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
50
291
|
}
|
|
51
292
|
};
|
|
52
|
-
|
|
293
|
+
let unsubscribe = activeSession?.subscribe(draw);
|
|
53
294
|
draw();
|
|
54
295
|
return {
|
|
296
|
+
/** Close discovery/paste panels without changing the formula or its selection. */
|
|
297
|
+
closePanels: () => closeSymbols(),
|
|
298
|
+
/** Reuse one toolbar for multiple editors without retaining previous subscriptions. */
|
|
299
|
+
setSession(next) {
|
|
300
|
+
if (destroyed)
|
|
301
|
+
return;
|
|
302
|
+
if (next !== activeSession || !next)
|
|
303
|
+
closeSymbols();
|
|
304
|
+
unsubscribe?.();
|
|
305
|
+
activeSession = next;
|
|
306
|
+
unsubscribe = next?.subscribe(draw);
|
|
307
|
+
draw();
|
|
308
|
+
},
|
|
309
|
+
/** Disable mutation controls while the attached native editor is composing. */
|
|
310
|
+
setDisabled(next) {
|
|
311
|
+
if (destroyed || disabled === next)
|
|
312
|
+
return;
|
|
313
|
+
disabled = next;
|
|
314
|
+
if (next)
|
|
315
|
+
closeSymbols();
|
|
316
|
+
draw();
|
|
317
|
+
},
|
|
55
318
|
destroy() {
|
|
56
|
-
|
|
319
|
+
destroyed = true;
|
|
320
|
+
unsubscribe?.();
|
|
321
|
+
closeSymbols();
|
|
57
322
|
toolbar.remove();
|
|
323
|
+
gridTools.remove();
|
|
324
|
+
presentation.remove();
|
|
325
|
+
panels.remove();
|
|
58
326
|
},
|
|
59
327
|
};
|
|
60
328
|
}
|
|
61
|
-
//# sourceMappingURL=toolbar.js.map
|
package/dist/dom.d.ts
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
|
+
import type { MathPreferences } from './preferences.js';
|
|
1
2
|
export { mountMathLatex, mountMathPreview, type MathOutput, type MathPreviewOptions, } from './outputs.js';
|
|
2
3
|
export { mountMathToolbar, type MathToolbarOptions } from './dom/toolbar.js';
|
|
3
4
|
import { type MathSession, type MathEditorMode } from './session.js';
|
|
4
5
|
import { type MathLocale } from './i18n.js';
|
|
5
6
|
import { type MathDocument, type StructureKind } from './model.js';
|
|
6
7
|
export interface DOMMathEditorOptions {
|
|
8
|
+
/** Mount-only UI preferences; ignored when an external session owns the store. */
|
|
9
|
+
preferences?: MathPreferences;
|
|
7
10
|
session?: MathSession;
|
|
8
11
|
/** Mount-only portal container; defaults to the nearest dialog, otherwise document.body. */
|
|
9
12
|
menuHost?: HTMLElement;
|
|
13
|
+
/** Keep suggestion and wrapping menus clear of host controls outside the math surface. */
|
|
14
|
+
menuAvoidElements?: () => readonly HTMLElement[];
|
|
10
15
|
defaultValue?: MathDocument;
|
|
11
16
|
locale?: MathLocale;
|
|
12
17
|
mode?: MathEditorMode;
|
|
@@ -14,6 +19,8 @@ export interface DOMMathEditorOptions {
|
|
|
14
19
|
toolbarMaxItems?: number;
|
|
15
20
|
showLineNumbers?: boolean;
|
|
16
21
|
onChange?: (document: MathDocument, latex: string) => void;
|
|
22
|
+
/** Final DOM/caret notification, including focus and selection-only updates. */
|
|
23
|
+
onRender?: () => void;
|
|
17
24
|
onExit?: (direction: -1 | 1) => void;
|
|
18
25
|
/** Default: block=newline, inline=commit. Suggestions always take priority. */
|
|
19
26
|
enterBehavior?: 'newline' | 'commit';
|
|
@@ -30,4 +37,3 @@ export interface DOMMathEditor {
|
|
|
30
37
|
}
|
|
31
38
|
/** Native DOM renderer. No React or framework runtime is imported by this module. */
|
|
32
39
|
export declare function mountMathEditor(host: HTMLElement, initial?: DOMMathEditorOptions): DOMMathEditor;
|
|
33
|
-
//# sourceMappingURL=dom.d.ts.map
|