diff --git a/src/api.md b/src/api.md
index fbfef0d26..86f144755 100644
--- a/src/api.md
+++ b/src/api.md
@@ -3007,7 +3007,7 @@ The depth in the expression tree. 0 for top-level elements
optional id: string;
```
-id associated with this element or its ancestor, set with `\htmlId` or
+id associated with this element or its ancestor, set with `\htmlId` or
`\cssId`
@@ -5990,29 +5990,6 @@ set onScrollIntoView(value): void
#### Localization
-
-
-
-
-##### MathfieldElement.fractionNavigationOrder
-
-```ts
-static fractionNavigationOrder: "numerator-denominator" | "denominator-numerator" = 'numerator-denominator';
-```
-
-When using the keyboard to navigate a fraction, the order in which the
-numerator and navigator are traversed:
-- "numerator-denominator": first the elements in the numerator, then
- the elements in the denominator.
-- "denominator-numerator": first the elements in the denominator, then
- the elements in the numerator. In some East-Asian cultures, fractions
- are read and written denominator first ("fēnzhī"). With this option
- the keyboard navigation follows this convention.
-
-**Default**: `"numerator-denominator"`
-
-
-
@@ -6047,6 +6024,37 @@ set static decimalSeparator(value): void
+
+
+
+
+##### MathfieldElement.fractionNavigationOrder
+
+```ts
+get static fractionNavigationOrder(): "denominator-numerator" | "numerator-denominator"
+```
+
+When using the keyboard to navigate a fraction, the order in which the
+numerator and navigator are traversed:
+- "numerator-denominator": first the elements in the numerator, then
+ the elements in the denominator.
+- "denominator-numerator": first the elements in the denominator, then
+ the elements in the numerator. In some East-Asian cultures, fractions
+ are read and written denominator first ("fēnzhī"). With this option
+ the keyboard navigation follows this convention.
+
+**Default**: `"numerator-denominator"`
+
+```ts
+set static fractionNavigationOrder(s): void
+```
+
+• **s**: `"denominator-numerator"` \| `"numerator-denominator"`
+
+`"denominator-numerator"` \| `"numerator-denominator"`
+
+
+
@@ -6407,9 +6415,9 @@ readonly [`Keybinding`](#keybinding)[]
```ts
get letterShapeStyle():
| "auto"
- | "french"
| "tex"
| "iso"
+ | "french"
| "upright"
```
@@ -6421,15 +6429,15 @@ set letterShapeStyle(value): void
• **value**:
\| `"auto"`
- \| `"french"`
\| `"tex"`
\| `"iso"`
+ \| `"french"`
\| `"upright"`
\| `"auto"`
- \| `"french"`
\| `"tex"`
\| `"iso"`
+ \| `"french"`
\| `"upright"`
diff --git a/src/atoms/composition.ts b/src/atoms/composition.ts
index 559afb81b..78d26eb69 100644
--- a/src/atoms/composition.ts
+++ b/src/atoms/composition.ts
@@ -1,4 +1,4 @@
-import type { ParseMode, Style } from '../public/core-types';
+import type { ParseMode } from '../public/core-types';
import { Atom } from '../core/atom-class';
import { Box } from '../core/box';
diff --git a/src/atoms/genfrac.ts b/src/atoms/genfrac.ts
index 39fabc548..bc5e70dc9 100644
--- a/src/atoms/genfrac.ts
+++ b/src/atoms/genfrac.ts
@@ -6,8 +6,8 @@ import { VBox } from '../core/v-box';
import { makeCustomSizedDelim, makeNullDelimiter } from '../core/delimiters';
import { Context } from '../core/context';
import { AXIS_HEIGHT } from '../core/font-metrics';
-import type { AtomJson } from 'core/types';
-import { _MathEnvironment } from 'core/math-environment';
+import type { AtomJson } from '../core/types';
+import { _MathEnvironment } from '../core/math-environment';
export type GenfracOptions = {
continuousFraction?: boolean;
diff --git a/src/atoms/group.ts b/src/atoms/group.ts
index d066b03e4..940832bfc 100644
--- a/src/atoms/group.ts
+++ b/src/atoms/group.ts
@@ -1,4 +1,4 @@
-import type { ParseMode, Style } from '../public/core-types';
+import type { ParseMode } from '../public/core-types';
import { Atom } from '../core/atom-class';
import type { Context } from '../core/context';
diff --git a/src/atoms/latex.ts b/src/atoms/latex.ts
index b650ffb6c..7576cc3e5 100644
--- a/src/atoms/latex.ts
+++ b/src/atoms/latex.ts
@@ -1,5 +1,3 @@
-import type { Style } from '../public/core-types';
-
import { Atom } from '../core/atom-class';
import { Box } from '../core/box';
import { Context } from '../core/context';
diff --git a/src/atoms/subsup.ts b/src/atoms/subsup.ts
index cbb6ec4ae..0d9af0e19 100644
--- a/src/atoms/subsup.ts
+++ b/src/atoms/subsup.ts
@@ -11,6 +11,27 @@ export class SubsupAtom extends Atom {
this.subsupPlacement = 'auto';
}
+ get children(): Readonly {
+ if (!this._children) {
+ const result: Atom[] = [];
+
+ const sub = this.branch('subscript');
+ if (sub)
+ for (const x of sub) {
+ result.push(...x.children);
+ result.push(x);
+ }
+ const sup = this.branch('superscript');
+ if (sup)
+ for (const x of sup) {
+ result.push(...x.children);
+ result.push(x);
+ }
+ this._children = result;
+ }
+ return this._children;
+ }
+
static fromJson(json: { [key: string]: any }): SubsupAtom {
const result = new SubsupAtom(json as any);
for (const branch of NAMED_BRANCHES)
diff --git a/src/core/atom-class.ts b/src/core/atom-class.ts
index d5c3df27f..33bd1c644 100644
--- a/src/core/atom-class.ts
+++ b/src/core/atom-class.ts
@@ -360,7 +360,7 @@ export class Atom {
}
bodyToLatex(options: ToLatexOptions): string {
- let defaultMode =
+ const defaultMode =
options.defaultMode ?? (this.mode === 'math' ? 'math' : 'text');
return Mode.serialize(this.body, { ...options, defaultMode });
@@ -549,9 +549,7 @@ export class Atom {
this.style.variant = style.variant;
if (style.variantStyle && !this.style.variantStyle)
this.style.variantStyle = style.variantStyle;
- } else {
- this.style = { ...this.style, ...style };
- }
+ } else this.style = { ...this.style, ...style };
if (this.style.fontFamily === 'none') delete this.style.fontFamily;
diff --git a/src/core/modes-math.ts b/src/core/modes-math.ts
index 21fa6e3ac..fad53346d 100644
--- a/src/core/modes-math.ts
+++ b/src/core/modes-math.ts
@@ -273,9 +273,8 @@ function emitBoldRun(run: Atom[], options: ToLatexOptions): string[] {
// Get the content of the run
const value = joinLatex(x.map((x) => x.value ?? ''));
- if (/^[a-zA-Z0-9]+$/.test(value)) {
+ if (/^[a-zA-Z0-9]+$/.test(value))
return latexCommand('\\mathbf', joinLatex(emitVariantRun(x, options)));
- }
// If the run contains a mix of characters, use `\bm`
return latexCommand('\\bm', joinLatex(emitVariantRun(x, options)));
diff --git a/src/editor-mathfield/autocomplete.ts b/src/editor-mathfield/autocomplete.ts
index 22f426b62..449eafcd9 100644
--- a/src/editor-mathfield/autocomplete.ts
+++ b/src/editor-mathfield/autocomplete.ts
@@ -160,9 +160,9 @@ export function complete(
if (completion === 'reject') return true;
- let style = { ...computeInsertStyle(mathfield) };
+ const style = { ...computeInsertStyle(mathfield) };
// If we're inserting a non-alphanumeric character, reset the variant
- if (!/^[a-zA-Z0-9]$/.test(latex) && this.styleBias !== 'none') {
+ if (!/^[a-zA-Z0-9]$/.test(latex) && mathfield.styleBias !== 'none') {
style.variant = 'normal';
style.variantStyle = undefined;
}
diff --git a/src/editor-mathfield/keyboard-input.ts b/src/editor-mathfield/keyboard-input.ts
index 3247a303b..7e48f2cf6 100644
--- a/src/editor-mathfield/keyboard-input.ts
+++ b/src/editor-mathfield/keyboard-input.ts
@@ -616,7 +616,7 @@ function insertMathModeChar(mathfield: _Mathfield, c: string): void {
return;
}
- let style = { ...computeInsertStyle(mathfield) };
+ const style = { ...computeInsertStyle(mathfield) };
// If we're inserting a non-alphanumeric character, reset the variant
if (!/[a-zA-Z0-9]/.test(c) && mathfield.styleBias !== 'none') {
diff --git a/src/editor-mathfield/mathfield-private.ts b/src/editor-mathfield/mathfield-private.ts
index 77b55b18e..4883a0c4d 100644
--- a/src/editor-mathfield/mathfield-private.ts
+++ b/src/editor-mathfield/mathfield-private.ts
@@ -5,15 +5,15 @@ import type {
Keybinding,
KeyboardLayoutName,
} from '../public/options';
+import type { Mathfield } from '../public/mathfield';
import type {
- Mathfield,
InsertOptions,
OutputFormat,
Offset,
Range,
Selection,
ApplyStyleOptions,
-} from '../public/mathfield';
+} from '../public/core-types';
import { canVibrate } from '../ui/utils/capabilities';
@@ -452,7 +452,7 @@ If you are using Vue, this may be because you are using the runtime-only build o
// to adjust the UI (popover, etc...)
window.addEventListener('resize', this, { signal });
document.addEventListener('scroll', this, { signal });
- this.resizeObserver = new ResizeObserver((entries) => {
+ this.resizeObserver = new ResizeObserver((_entries) => {
if (this.resizeObserverStarted) {
this.resizeObserverStarted = false;
return;
@@ -1125,7 +1125,7 @@ If you are using Vue, this may be because you are using the runtime-only build o
} else if (s === '&') addColumnAfter(this.model);
else {
if (this.model.selectionIsCollapsed) {
- let style = { ...computeInsertStyle(this) };
+ const style = { ...computeInsertStyle(this) };
// If we're inserting a non-alphanumeric character, reset the variant
if (!/^[a-zA-Z0-9]$/.test(s) && this.styleBias !== 'none') {
style.variant = 'normal';
@@ -1425,8 +1425,7 @@ If you are using Vue, this may be because you are using the runtime-only build o
locked?: boolean;
correctness?: 'correct' | 'incorrect' | 'undefined';
}): string[] {
- return this.model
- .getAllAtoms()
+ return this.model.atoms
.filter((a: PromptAtom) => {
if (a.type !== 'prompt') return false;
if (!filter) return true;
@@ -1600,11 +1599,11 @@ If you are using Vue, this may be because you are using the runtime-only build o
// If we're at the start or the end of a LaTeX group,
// move inside the group and don't switch mode.
const sibling = model.at(pos + 1);
- if (sibling?.type === 'first' && sibling.mode === 'latex') {
+ if (sibling?.type === 'first' && sibling.mode === 'latex')
model.position = pos + 1;
- } else if (latexGroup && sibling?.mode !== 'latex') {
+ else if (latexGroup && sibling?.mode !== 'latex')
model.position = pos - 1;
- } else {
+ else {
// We may have moved from math to text, or text to math.
this.switchMode(mode);
}
diff --git a/src/editor-mathfield/mode-editor-latex.ts b/src/editor-mathfield/mode-editor-latex.ts
index bd82d0918..59e1660cb 100644
--- a/src/editor-mathfield/mode-editor-latex.ts
+++ b/src/editor-mathfield/mode-editor-latex.ts
@@ -1,5 +1,5 @@
/* eslint-disable no-new */
-import { Offset, Range, InsertOptions } from '../public/mathfield';
+import { Offset, Range, InsertOptions } from '../public/core-types';
import { LatexAtom, LatexGroupAtom } from '../atoms/latex';
import { range } from '../editor-model/selection-utils';
import { Atom } from '../core/atom-class';
diff --git a/src/editor-mathfield/mode-editor-math.ts b/src/editor-mathfield/mode-editor-math.ts
index 829d2bcb2..3c0e1bed4 100644
--- a/src/editor-mathfield/mode-editor-math.ts
+++ b/src/editor-mathfield/mode-editor-math.ts
@@ -2,7 +2,7 @@
import type { Expression } from '@cortex-js/compute-engine/dist/types/math-json/math-json-format';
-import { InsertOptions, Offset, OutputFormat } from '../public/mathfield';
+import type { InsertOptions, Offset, OutputFormat } from '../public/core-types';
import { requestUpdate } from './render';
@@ -169,7 +169,7 @@ export class MathModeEditor extends ModeEditor {
}
insert(model: _Model, input: string, options: InsertOptions): boolean {
- let data =
+ const data =
typeof input === 'string'
? input
: globalThis.MathfieldElement.computeEngine?.box(input).latex ?? '';
diff --git a/src/editor-mathfield/mode-editor-text.ts b/src/editor-mathfield/mode-editor-text.ts
index 55dc8d973..6bf224acf 100644
--- a/src/editor-mathfield/mode-editor-text.ts
+++ b/src/editor-mathfield/mode-editor-text.ts
@@ -1,7 +1,8 @@
/* eslint-disable no-new */
-import type { InsertOptions } from '../public/mathfield';
+import type { InsertOptions } from '../public/core-types';
import { parseLatex } from '../core/core';
+import type { ContextInterface } from '../core/types';
import { Atom } from '../core/atom-class';
import { _Model } from '../editor-model/model-private';
import { range } from '../editor-model/selection-utils';
@@ -10,7 +11,6 @@ import { applyStyleToUnstyledAtoms } from '../editor-model/styling';
import { _Mathfield } from './mathfield-private';
import { ModeEditor } from './mode-editor';
import { requestUpdate } from './render';
-import type { ContextInterface } from '../core/types';
export class TextModeEditor extends ModeEditor {
constructor() {
diff --git a/src/editor-mathfield/mode-editor.ts b/src/editor-mathfield/mode-editor.ts
index 51460c129..f50d475f1 100644
--- a/src/editor-mathfield/mode-editor.ts
+++ b/src/editor-mathfield/mode-editor.ts
@@ -3,7 +3,7 @@ import { TextAtom } from '../atoms/text';
import { _Model } from '../editor-model/model-private';
import { range } from '../editor-model/selection-utils';
import { MODE_SHIFT_COMMANDS } from '../formats/parse-math-string';
-import { InsertOptions, OutputFormat, Range } from '../public/mathfield';
+import type { InsertOptions, OutputFormat, Range } from '../public/core-types';
import { _Mathfield } from './mathfield-private';
const CLIPBOARD_LATEX_BEGIN = '$$';
diff --git a/src/editor-mathfield/pointer-input.ts b/src/editor-mathfield/pointer-input.ts
index 907bd394d..097743bdb 100644
--- a/src/editor-mathfield/pointer-input.ts
+++ b/src/editor-mathfield/pointer-input.ts
@@ -4,7 +4,7 @@ import { requestUpdate } from './render';
import { Atom } from '../core/atom-class';
import { acceptCommandSuggestion } from './autocomplete';
import { selectGroup } from '../editor-model/commands-select';
-import type { Offset } from 'public/mathfield';
+import type { Offset } from 'public/core-types';
let gLastTap: { x: number; y: number; time: number } | null = null;
let gTapCount = 0;
diff --git a/src/editor-mathfield/render.ts b/src/editor-mathfield/render.ts
index 1baa533be..f6c4a2b84 100644
--- a/src/editor-mathfield/render.ts
+++ b/src/editor-mathfield/render.ts
@@ -197,9 +197,7 @@ export function render(
)
hideMenu = true;
// If the width of the element is less than 50px, hide the menu
- if (!hideMenu && field.offsetWidth < 50) {
- hideMenu = true;
- }
+ if (!hideMenu && field.offsetWidth < 50) hideMenu = true;
menuToggle.style.display = hideMenu ? 'none' : '';
}
@@ -426,7 +424,6 @@ export function reparse(mathfield: _Mathfield | null): void {
}
export function reparseAllMathfields(): void {
- for (const mathfield of document.querySelectorAll('.ML__mathfield')) {
+ for (const mathfield of document.querySelectorAll('.ML__mathfield'))
if ('_mathfield' in mathfield) reparse(mathfield._mathfield as _Mathfield);
- }
}
diff --git a/src/editor-mathfield/styling.ts b/src/editor-mathfield/styling.ts
index 6e913aa69..fcf7fc692 100644
--- a/src/editor-mathfield/styling.ts
+++ b/src/editor-mathfield/styling.ts
@@ -192,11 +192,12 @@ export function defaultInsertStyleHook(
if (bias === 'none') return mathfield.defaultStyle;
// In text mode, we inherit the style of the sibling atom
- if (model.mode === 'text')
+ if (model.mode === 'text') {
return (
model.at(bias === 'right' ? info.after : info.before)?.style ??
mathfield.defaultStyle
);
+ }
if (model.mode === 'math') {
const atom = model.at(bias === 'right' ? info.after : info.before);
diff --git a/src/editor-mathfield/utils.ts b/src/editor-mathfield/utils.ts
index 43d4f6f11..8b95e45d9 100644
--- a/src/editor-mathfield/utils.ts
+++ b/src/editor-mathfield/utils.ts
@@ -1,5 +1,5 @@
import { Atom } from '../core/atom-class';
-import type { ElementInfo, Offset, Range } from '../public/mathfield';
+import type { ElementInfo, Offset, Range } from '../public/core-types';
import { OriginValidator } from '../public/options';
import { _Mathfield } from './mathfield-private';
@@ -223,16 +223,17 @@ export function getElementInfo(
const atom = mf.model.at(offset);
if (!atom) return undefined;
- let result: ElementInfo = {};
+ const result: ElementInfo = {};
const bounds = getAtomBounds(mf, atom);
- if (bounds)
+ if (bounds) {
result.bounds = new DOMRect(
bounds.left,
bounds.top,
bounds.right - bounds.left,
bounds.bottom - bounds.top
);
+ }
result.depth = atom.treeDepth - 2;
@@ -262,9 +263,8 @@ export function getElementInfo(
}
if (a.command === '\\htmlId' || a.command === '\\cssId') {
- if (!result.id && a.args && typeof a.args[0] === 'string') {
+ if (!result.id && a.args && typeof a.args[0] === 'string')
result.id = a.args[0];
- }
}
a = a.parent;
}
diff --git a/src/editor-model/commands.ts b/src/editor-model/commands.ts
index 92cc23fe6..1427d5eb2 100644
--- a/src/editor-model/commands.ts
+++ b/src/editor-model/commands.ts
@@ -4,7 +4,7 @@ import { ArrayAtom } from '../atoms/array';
import { LatexAtom } from '../atoms/latex';
import { TextAtom } from '../atoms/text';
import { LETTER_AND_DIGITS } from '../latex-commands/definitions-utils';
-import type { Offset, Selection } from '../public/mathfield';
+import type { Offset, Selection } from '../public/core-types';
import { getCommandSuggestionRange } from '../editor-mathfield/mode-editor-latex';
import { PromptAtom } from '../atoms/prompt';
import { getLocalDOMRect } from 'editor-mathfield/utils';
diff --git a/src/editor-model/delete.ts b/src/editor-model/delete.ts
index 73b71145e..8ed6b2f09 100644
--- a/src/editor-model/delete.ts
+++ b/src/editor-model/delete.ts
@@ -1,5 +1,4 @@
import type { ContentChangeType } from '../public/options';
-import type { Range } from '../public/mathfield';
import { LeftRightAtom } from '../atoms/leftright';
import { Atom } from '../core/atom';
@@ -7,6 +6,8 @@ import { _Model } from './model-private';
import { range } from './selection-utils';
import { MathfieldElement } from 'public/mathfield-element';
import type { Branch } from 'core/types';
+import type { Range } from 'public/core-types';
+
// import {
// arrayFirstCellByRow,
// arrayColRow,
diff --git a/src/editor-model/model-private.ts b/src/editor-model/model-private.ts
index ebc61b620..91250d65f 100644
--- a/src/editor-model/model-private.ts
+++ b/src/editor-model/model-private.ts
@@ -1,11 +1,9 @@
import type {
- Model,
- Mathfield,
Offset,
Range,
Selection,
OutputFormat,
-} from '../public/mathfield';
+} from '../public/core-types';
import type {
ContentChangeOptions,
ContentChangeType,
@@ -39,6 +37,7 @@ import type { ModelState, GetAtomOptions, AnnounceVerb } from './types';
import type { BranchName, ToLatexOptions } from 'core/types';
import { isValidMathfield } from '../editor-mathfield/utils';
+import { Mathfield, Model } from 'public/mathfield';
/** @internal */
export class _Model implements Model {
@@ -378,21 +377,6 @@ export class _Model implements Model {
return result;
}
- /**
- * Unlike `getAtoms()`, the argument here is an index
- * Return all the atoms, in order, starting at startingIndex
- * then looping back at the beginning
- */
- getAllAtoms(startingIndex = 0): Readonly {
- const result: Atom[] = [];
- const last = this.lastOffset;
- for (let i = startingIndex; i <= last; i++) result.push(this.atoms[i]);
-
- for (let i = 0; i < startingIndex; i++) result.push(this.atoms[i]);
-
- return result;
- }
-
findAtom(
filter: (x: Atom) => boolean,
startingIndex = 0,
@@ -569,6 +553,7 @@ export class _Model implements Model {
skipPlaceholders: format === 'latex-without-placeholders',
defaultMode: this.mathfield.options.defaultMode,
};
+
return joinLatex(
ranges.map((range) => Atom.serialize(this.getAtoms(range), options))
);
@@ -585,13 +570,13 @@ export class _Model implements Model {
/**
* Unlike `setSelection`, this method is intended to be used in response
- * to a user action, and it performs various adjustments to result
- * in a more intuitive selection.
+ * to a user action, and it performs various adjustments to result in a more
+ * intuitive selection.
+ *
* For example:
- * - when all the children of an atom are selected, the atom
- * become selected.
- * - this method will *not* change the anchor, but may result
- * in a selection whose boundary is outside the anchor
+ * - when all the children of an atom are selected, the atom become selected.
+ * - this method will *not* change the anchor, but may result in a selection
+ * whose boundary is outside the anchor
*/
extendSelectionTo(anchor: Offset, position: Offset): boolean {
if (!this.mathfield.contentEditable && this.mathfield.userSelect === 'none')
@@ -675,8 +660,8 @@ export class _Model implements Model {
defaultAnnounceHook(this.mathfield, command, previousPosition, atoms);
}
- // Suppress notification while scope is executed,
- // then notify of content change, and selection change (if actual change)
+ // Suppress notification while scope is executed, then notify of content
+ // change, and selection change (if actual change)
deferNotifications(
options: {
content?: boolean;
diff --git a/src/editor-model/selection-utils.ts b/src/editor-model/selection-utils.ts
index 2ff7344fd..34bbfbc4a 100644
--- a/src/editor-model/selection-utils.ts
+++ b/src/editor-model/selection-utils.ts
@@ -1,5 +1,4 @@
-import { ParseMode } from 'public/core-types';
-import { Offset, Range, Selection } from '../public/mathfield';
+import type { ParseMode, Offset, Range, Selection } from '../public/core-types';
import { _Model } from './model-private';
export function compareSelection(
diff --git a/src/editor-model/styling.ts b/src/editor-model/styling.ts
index 6cd3e2afc..989b2ae1c 100644
--- a/src/editor-model/styling.ts
+++ b/src/editor-model/styling.ts
@@ -1,22 +1,20 @@
import { Atom } from '../core/atom';
import type { _Model } from './model-private';
-import { Range } from '../public/mathfield';
import { isArray } from '../common/types';
import { DEFAULT_FONT_SIZE } from '../core/font-metrics';
-import type { Style, VariantStyle } from '../public/core-types';
+import type { Style, VariantStyle, Range } from '../public/core-types';
import { PrivateStyle } from '../core/types';
export function applyStyleToUnstyledAtoms(
- atom: Atom | ReadonlyArray | undefined,
+ atom: Atom | readonly Atom[] | undefined,
style?: Style
): void {
if (!atom || !style) return;
if (isArray(atom)) {
// Apply styling options to each atom
atom.forEach((x) => applyStyleToUnstyledAtoms(x, style));
- } else if (typeof atom === 'object') {
+ } else if (typeof atom === 'object')
atom.applyStyle(style, { unstyledOnly: true });
- }
}
/**
diff --git a/src/editor-model/types.ts b/src/editor-model/types.ts
index 6fdde8a42..cd224b5f3 100644
--- a/src/editor-model/types.ts
+++ b/src/editor-model/types.ts
@@ -1,6 +1,5 @@
import type { AtomJson } from 'core/types';
-import type { ParseMode } from 'public/core-types';
-import type { Selection } from 'public/mathfield';
+import type { ParseMode, Selection } from 'public/core-types';
export type AnnounceVerb =
| 'plonk'
diff --git a/src/editor/commands.ts b/src/editor/commands.ts
index 274e941ea..03b2c678b 100644
--- a/src/editor/commands.ts
+++ b/src/editor/commands.ts
@@ -241,12 +241,12 @@ export function parseCommand(
): [SelectorPrivate, ...any[]] | SelectorPrivate | undefined {
if (!command) return undefined;
if (isArray(command) && command.length > 0) {
- let selector = command[0];
+ const selector = command[0];
// Convert kebab case (like-this) to camel case (likeThis).
selector.replace(/-\w/g, (m) => m[1].toUpperCase());
- if (selector === 'performWithFeedback' && command.length === 2) {
+ if (selector === 'performWithFeedback' && command.length === 2)
return [selector, parseCommand(command[1])];
- }
+
return [selector as SelectorPrivate, ...command.slice(1)];
}
@@ -257,7 +257,7 @@ export function parseCommand(
if (match) {
const selector = match[1];
selector.replace(/-\w/g, (m) => m[1].toUpperCase());
- let args = match[2].split(',').map((x) => x.trim());
+ const args = match[2].split(',').map((x) => x.trim());
return [
selector as SelectorPrivate,
...args.map((arg) => {
@@ -280,7 +280,7 @@ export function parseCommand(
];
}
- let selector = command;
+ const selector = command;
selector.replace(/-\w/g, (m) => m[1].toUpperCase());
return selector as SelectorPrivate;
diff --git a/src/editor/default-menu.ts b/src/editor/default-menu.ts
index f637dbc6e..c649dab95 100644
--- a/src/editor/default-menu.ts
+++ b/src/editor/default-menu.ts
@@ -727,10 +727,11 @@ function variantMenuItem(
id: `variant-${variant}`,
label: () => {
const textSelection = getSelectionPlainString(mf);
- if (textSelection.length < 12)
+ if (textSelection.length < 12) {
return convertLatexToMarkup(
`\\${command}{${getSelectionPlainString(mf)}}`
);
+ }
return localize(tooltip) ?? tooltip;
},
class: 'ML__xl',
@@ -753,10 +754,11 @@ function variantStyleMenuItem(
label: () => {
const textSelection = getSelectionPlainString(mf);
- if (textSelection.length > 0 && textSelection.length < 12)
+ if (textSelection.length > 0 && textSelection.length < 12) {
return convertLatexToMarkup(
`\\${command}{${getSelectionPlainString(mf)}}`
);
+ }
return localize(tooltip) ?? tooltip;
},
diff --git a/src/editor/undo.ts b/src/editor/undo.ts
index ec7669fbe..bc99962f3 100644
--- a/src/editor/undo.ts
+++ b/src/editor/undo.ts
@@ -1,7 +1,7 @@
import type { ModelState } from 'editor-model/types';
import type { _Model } from '../editor-model/model-private';
-import type { Selection } from '../public/mathfield';
+import type { Selection } from '../public/core-types';
export class UndoManager {
// Maximum number of undo/redo states
diff --git a/src/formats/atom-to-math-json.ts b/src/formats/atom-to-math-json.ts
new file mode 100644
index 000000000..7ec74f08f
--- /dev/null
+++ b/src/formats/atom-to-math-json.ts
@@ -0,0 +1,10 @@
+import { Atom } from 'core/atom';
+import { Expression, Range } from 'public/core-types';
+
+export function atomToMathJson(
+ atom: Atom | Readonly | undefined,
+ range: Range | undefined
+): Expression {
+ // @todo
+ return '';
+}
diff --git a/src/formats/parse-math-string.ts b/src/formats/parse-math-string.ts
index 0539076e1..310af6a94 100644
--- a/src/formats/parse-math-string.ts
+++ b/src/formats/parse-math-string.ts
@@ -1,4 +1,4 @@
-import { OutputFormat } from '../public/mathfield';
+import { OutputFormat } from '../public/core-types';
import {
InlineShortcutDefinitions,
getInlineShortcut,
@@ -216,8 +216,8 @@ function parseMathArgument(
let match = '';
s = s.trim();
let rest = s;
- let lFence = s.charAt(0);
- let rFence = { '(': ')', '{': '}', '[': ']' }[lFence];
+ const lFence = s.charAt(0);
+ const rFence = { '(': ')', '{': '}', '[': ']' }[lFence];
if (rFence) {
// It's a fence
let level = 1;
diff --git a/src/mathlive.ts b/src/mathlive.ts
index 969e52b71..314c3a75c 100644
--- a/src/mathlive.ts
+++ b/src/mathlive.ts
@@ -62,11 +62,11 @@ export function globalMathLive(): MathLiveGlobal {
*/
export function renderMathInDocument(options?: StaticRenderOptions): void {
- if (document.readyState === 'loading')
+ if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () =>
renderMathInElement(document.body, options)
);
- else renderMathInElement(document.body, options);
+ } else renderMathInElement(document.body, options);
}
function getElement(element: string | HTMLElement): HTMLElement | null {
diff --git a/src/public/commands.ts b/src/public/commands.ts
index 25ed7f5e2..9764fa242 100644
--- a/src/public/commands.ts
+++ b/src/public/commands.ts
@@ -1,7 +1,12 @@
import type { Keys } from './types-utils';
-import type { ParseMode, Style, TabularEnvironment } from './core-types';
-import type { InsertOptions, Mathfield, Model } from './mathfield';
+import type {
+ InsertOptions,
+ ParseMode,
+ Style,
+ TabularEnvironment,
+} from './core-types';
+import type { Mathfield, Model } from './mathfield';
/**
* How much of the formula should be spoken:
diff --git a/src/public/core-types.ts b/src/public/core-types.ts
index 6779c4348..ac0267af9 100644
--- a/src/public/core-types.ts
+++ b/src/public/core-types.ts
@@ -456,3 +456,207 @@ export type Environment =
| 'displaymath'
| 'center'
| TabularEnvironment;
+
+/** @category MathJSON */
+export declare type Expression =
+ | number
+ | string
+ | { [key: string]: any }
+ | [Expression, ...Expression[]];
+
+/**
+ *
+| Format | Description |
+| :-------------------- | :---------------------- |
+| `"ascii-math"` | A string of [ASCIIMath](http://asciimath.org/). |
+| `"latex"` | LaTeX rendering of the content, with LaTeX macros not expanded. |
+| `"latex-expanded"` | All macros are recursively expanded to their definition. |
+| `"latex-unstyled"` | Styling (background color, color) is ignored |
+| `"latex-without-placeholders"` | Replace `\placeholder` commands with their body |
+| `"math-json"` | A MathJSON abstract syntax tree, as an object literal formated as a JSON string. Note: you must import the CortexJS Compute Engine to obtain a result. |
+| `"math-ml"` | A string of MathML markup. |
+' `"plain-text"` | A plain text rendering of the content. |
+| `"spoken"` | Spoken text rendering, using the default format defined in config, which could be either text or SSML markup. |
+| `"spoken-text"` | A plain spoken text rendering of the content. |
+| `"spoken-ssml"` | A SSML (Speech Synthesis Markup Language) version of the content, which can be used with some text-to-speech engines such as AWS. |
+| `"spoken-ssml-with-highlighting"`| Like `"spoken-ssml"` but with additional annotations necessary for synchronized highlighting (read aloud). |
+
+ * To use the`"math-json"` format the Compute Engine library must be loaded. Use for example:
+ *
+```js
+import "https://unpkg.com/@cortex-js/compute-engine?module";
+```
+ *
+ */
+export type OutputFormat =
+ | 'ascii-math'
+ | 'latex'
+ | 'latex-expanded'
+ | 'latex-unstyled'
+ | 'latex-without-placeholders'
+ | 'math-json'
+ | 'math-ml'
+ | 'plain-text'
+ | 'spoken'
+ | 'spoken-text'
+ | 'spoken-ssml'
+ | 'spoken-ssml-with-highlighting';
+
+export type InsertOptions = {
+ /** If `"auto"` or omitted, the current mode is used */
+ mode?: ParseMode | 'auto';
+ /**
+ * The format of the input string:
+ *
+
+| | |
+|:------------|:------------|
+|`"auto"`| The string is LaTeX fragment or command) (default)|
+|`"latex"`| The string is a LaTeX fragment|
+ *
+ */
+ format?: OutputFormat | 'auto';
+ insertionMode?:
+ | 'replaceSelection'
+ | 'replaceAll'
+ | 'insertBefore'
+ | 'insertAfter';
+ /**
+ * Describes where the selection
+ * will be after the insertion:
+
+| | |
+| :---------- | :---------- |
+|`"placeholder"`| The selection will be the first available placeholder in the text that has been inserted (default)|
+|`"after"`| The selection will be an insertion point after the inserted text|
+|`"before"`| The selection will be an insertion point before the inserted text|
+|`"item"`| The inserted text will be selected|
+ */
+ selectionMode?: 'placeholder' | 'after' | 'before' | 'item';
+
+ silenceNotifications?: boolean;
+ /** If `true`, the mathfield will be focused after
+ * the insertion
+ */
+ focus?: boolean;
+ /** If `true`, provide audio and haptic feedback
+ */
+ feedback?: boolean;
+ /** If `true`, scroll the mathfield into view after insertion such that the
+ * insertion point is visible
+ */
+ scrollIntoView?: boolean;
+
+ style?: Style;
+};
+
+export type ApplyStyleOptions = {
+ range?: Range;
+ operation?: 'set' | 'toggle';
+ silenceNotifications?: boolean;
+};
+
+/**
+ * Some additional information about an element in the formula
+ */
+
+export type ElementInfo = {
+ // start?: Offset;
+ // end?: Offset;
+ // parent?: ElementInfo;
+ // kind?:
+ // | 'accent'
+ // | 'cell' // Inside a matrix or environment
+ // | 'box' // Inside a rectangular box
+ // | 'composition' // Inside an input-method composition
+ // | 'enclosure' // A more complex kind of box/annotation displayed around a subexpression
+ // | 'error'
+ // | 'numerator'
+ // | 'denominator'
+ // | 'group' // Delimited with braces
+ // | 'latex' // Raw LaTeX composition
+ // | 'overlap'
+ // | 'above'
+ // | 'below'
+ // | 'phantom'
+ // | 'placeholder'
+ // | 'superscript'
+ // | 'subscript'
+ // | 'radicand'
+ // | 'index'
+ // | 'body'
+ // | 'text';
+
+ /** The depth in the expression tree. 0 for top-level elements */
+ depth?: number;
+
+ /** The bounding box of the element */
+ bounds?: DOMRect;
+
+ /** id associated with this element or its ancestor, set with `\htmlId` or
+ `\cssId`
+*/
+ id?: string;
+
+ /** HTML attributes associated with element or its ancestores, set with
+ * `\htmlData`
+ */
+ data?: Record;
+
+ /** The mode (math, text or LaTeX) */
+ mode?: ParseMode;
+
+ /** A LaTeX representation of the element */
+ latex?: string;
+
+ /** The style (color, weight, variant, etc...) of this element. */
+ style?: Style;
+};
+
+/**
+ * A position of the caret/insertion point from the beginning of the formula.
+ */
+export type Offset = number;
+
+/**
+ * A pair of offsets (boundary points) that can be used to denote a fragment
+ * of an expression.
+ *
+ * A range is said to be collapsed when start and end are equal.
+ *
+ * When specifying a range, a negative offset can be used to indicate an
+ * offset from the last valid offset, i.e. -1 is the last valid offset, -2
+ * is one offset before that, etc...
+ *
+ * A normalized range will always be such that start <= end, start >= 0,
+ * end >= 0, start < lastOffset, end < lastOffset. All the methods return
+ * a normalized range.
+ *
+ * **See Also**
+ * * {@linkcode Selection}
+ */
+
+export type Range = [start: Offset, end: Offset];
+
+/**
+ * A selection is a set of ranges (to support discontinuous selection, for
+ * example when selecting a column in a matrix).
+ *
+ * If there is a single range and that range is collapsed, the selection is
+ * collapsed.
+ *
+ * A selection can also have a direction. While many operations are insensitive
+ * to the direction, a few are. For example, when selecting a fragment of an
+ * expression from left to right, the direction of this range will be "forward".
+ * Pressing the left arrow key will sets the insertion at the start of the range.
+ * Conversely, if the selection is made from right to left, the direction is
+ * "backward" and pressing the left arrow key will set the insertion point at
+ * the end of the range.
+ *
+ * **See Also**
+ * * {@linkcode Range}
+ */
+export type Selection = {
+ ranges: Range[];
+ direction?: 'forward' | 'backward' | 'none';
+};
diff --git a/src/public/mathfield-element.ts b/src/public/mathfield-element.ts
index 14e8a00b3..c182a424c 100644
--- a/src/public/mathfield-element.ts
+++ b/src/public/mathfield-element.ts
@@ -1,21 +1,20 @@
import type { Selector } from './commands';
import type {
+ Expression,
LatexSyntaxError,
LatexValue,
MacroDictionary,
+ Offset,
ParseMode,
Registers,
Style,
-} from './core-types';
-import type {
- InsertOptions,
- OutputFormat,
- Offset,
- Range,
Selection,
- Mathfield,
+ Range,
+ OutputFormat,
ElementInfo,
-} from './mathfield';
+ InsertOptions,
+} from './core-types';
+import type { InsertStyleHook, Mathfield } from './mathfield';
import type {
InlineShortcutDefinitions,
Keybinding,
@@ -51,15 +50,8 @@ import { getStylesheet, getStylesheetContent } from '../common/stylesheet';
import { Scrim } from '../ui/utils/scrim';
import { isOffset, isRange, isSelection } from 'editor-model/selection-utils';
import { KeyboardModifiers } from './ui-events-types';
-import { defaultInsertStyleHook } from 'editor-mathfield/styling';
-import { _MathEnvironment } from 'core/math-environment';
-
-/** @category MathJSON */
-export declare type Expression =
- | number
- | string
- | { [key: string]: any }
- | [Expression, ...Expression[]];
+import { defaultInsertStyleHook } from '../editor-mathfield/styling';
+import { _MathEnvironment } from '../core/math-environment';
if (!isBrowser()) {
console.error(
@@ -343,12 +335,6 @@ const DEPRECATED_OPTIONS = {
fractionNavigationOrder: 'MathfieldElement.fractionNavigationOrder = ...',
};
-export type InsertStyleHook = (
- sender: Mathfield,
- at: Offset,
- info: { before: Offset; after: Offset }
-) => Readonly
@@ -51,7 +41,8 @@