@barocss/math-editor 0.4.0 → 0.5.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.
Files changed (49) hide show
  1. package/API-SESSION.md +10 -0
  2. package/API-WEB-COMPONENT.md +2 -0
  3. package/CHANGELOG.md +61 -0
  4. package/EDITING-SCENARIOS.md +174 -0
  5. package/IMPLEMENTATION.md +95 -0
  6. package/LATEX-GUIDE.md +22 -0
  7. package/LATEX-MODEL.md +12 -0
  8. package/LATEX-SCOPE.md +10 -1
  9. package/README.md +73 -19
  10. package/RELEASING.md +81 -10
  11. package/RENDERING-TESTS.md +79 -0
  12. package/ROADMAP.md +132 -5
  13. package/VALIDATION.md +331 -0
  14. package/dist/context-tools.d.ts +21 -0
  15. package/dist/context-tools.js +37 -0
  16. package/dist/dom/context-keyboard.d.ts +2 -0
  17. package/dist/dom/context-keyboard.js +22 -0
  18. package/dist/dom/menu-position.d.ts +3 -0
  19. package/dist/dom/menu-position.js +45 -1
  20. package/dist/dom.d.ts +2 -0
  21. package/dist/dom.js +187 -38
  22. package/dist/latex.js +11 -0
  23. package/dist/locales/en.js +13 -1
  24. package/dist/locales/en.json +13 -1
  25. package/dist/locales/ko.js +13 -1
  26. package/dist/locales/ko.json +13 -1
  27. package/dist/math-editor.d.ts +3 -1
  28. package/dist/math-editor.js +394 -280
  29. package/dist/math-layout.d.ts +12 -0
  30. package/dist/math-layout.js +59 -0
  31. package/dist/math-spacing.d.ts +13 -0
  32. package/dist/math-spacing.js +87 -0
  33. package/dist/model.d.ts +4 -0
  34. package/dist/model.js +49 -4
  35. package/dist/root-transform.d.ts +19 -0
  36. package/dist/root-transform.js +69 -0
  37. package/dist/suggestions.d.ts +9 -0
  38. package/dist/suggestions.js +53 -0
  39. package/dist/web-component.js +9 -1
  40. package/package.json +11 -3
  41. package/src/fonts/KaTeX_Math-Italic.woff2 +0 -0
  42. package/src/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  43. package/src/fonts/README.md +18 -0
  44. package/src/shapes/README.md +21 -0
  45. package/src/shapes/parenthesis-bottom.svg +1 -0
  46. package/src/shapes/parenthesis-top.svg +1 -0
  47. package/src/shapes/parenthesis.svg +1 -0
  48. package/src/shapes/radical.svg +1 -0
  49. package/src/style.css +695 -44
package/API-SESSION.md CHANGED
@@ -323,3 +323,13 @@ Choose the change appropriate to the target:
323
323
  `default` removes the explicit metadata. `setMathPresentation(state, id, change)` is the pure equivalent. Unsupported changes or stale IDs return the original state; the session command returns false. This is presentation editing of existing syntax, not algebraic conversion or general TeX styling.
324
324
 
325
325
  Toolbars expose `closePanels()` to dismiss their nonmodal utilities without editing the formula. `onOpenPanel` and `onPasteLatex` are optional mounting callbacks for a host that coordinates its own utility panels. Built-in surfaces keep only one utility/discovery panel open at a time.
326
+
327
+ ### Keyboard access to transformations
328
+
329
+ In React and native DOM fields, **Alt+Down** opens or reopens suggestions and
330
+ selects the first available contextual transformation. Up/Down browses and Enter
331
+ applies; Escape dismisses. On macOS, Alt is the Option key. Root and bracket
332
+ transformations preserve the existing operand. The shortcut works with
333
+ `toolbar: false` and `contextTools: false`, including inline mode. Normal text
334
+ input continues to use the standard suggestion ordering; a context-only menu
335
+ requires navigation before Enter can apply a change instead of a host commit.
@@ -126,3 +126,5 @@ Persist the `MathDocument` passed to `onChange`; LaTeX is derived output and is
126
126
  Keep the mount host empty. The editor owns its descendants; framework rendering into the same host can destroy caret and composition state. Use one editing surface per session. Destroy the renderer on teardown; a session supplied by the host remains the host's responsibility.
127
127
 
128
128
  See [session and DOM API](API-SESSION.md) for exact options, commands, events and cleanup, and [renderer differences](ADAPTERS.md#current-renderer-parity) before choosing a native wrapper over the rich React editor.
129
+
130
+ Set `context-tools="false"` to hide the contextual structure footer. Changing this attribute updates the mounted editor. Conversion suggestions remain available.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,66 @@
1
1
  # @barocss/math-editor
2
2
 
3
+ ## 0.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Show query-independent radical tools below the active editing surface. Include conversion, index editing, disabled explanations, F6/Escape focus navigation, en/ko labels and a contextTools opt-out (context-tools for Web Components). Preserve model history and hide stale context during range selection or blur.
8
+ - Add contextual bracket transformations to suggestions, with Alt+Down discovery and keyboard acceptance in inline fields without toolbar or footer. Preserve contents, caret and history; target the nearest root/fence and reject stale actions. Include optional footer bracket controls and localized keyboard guidance.
9
+ - Add contextual suggestions to convert a square root to an indexed root while preserving the radicand. Select the new index `2` for immediate editing. Allow conversion back to a square root only for an empty index or `2`. Include English/Korean labels and shared behavior in React and native DOM integrations.
10
+
11
+ ### Patch Changes
12
+
13
+ - Resolve operator presentation from mathematical slot context in React and native
14
+ DOM editors. Use text/script-size glyphs and side limits inside fractions and
15
+ scripts, preserve explicit limit placement, and apply smaller nested bounds.
16
+ Add context-resolution unit tests and KaTeX glyph-width/font/position checks.
17
+ - Align named-function and fraction boundaries with mathematical spacing in React
18
+ and native DOM. Remove repeated function glyph padding and fixed fraction outer
19
+ margins. Preserve thin function spacing in script styles and omit it before plain
20
+ opening parentheses.
21
+ - Use bundled KaTeX math faces for variables, upright symbols and display operators. Remove artificial integral skew, scale delimiter widths, and preserve curved over/underbrace ends with licensed KaTeX SVG slices. Refine radical sizing, root-index placement, matrix columns and integral limit spacing in both editable and passive views.
22
+
23
+ Extend the source-only geometry audit with opt-in horizontal-position checks, font asset fingerprints, explicit font loading and multiple-integral/long-brace cases. Retain the KaTeX MIT attribution for bundled assets.
24
+
25
+ - Use shared mathematical spacing for text runs in React and native DOM. Distinguish
26
+ unary signs from binary operators, space relations and punctuation, and suppress
27
+ these gaps inside scripts. Remove excess glyph padding and reduce inactive caret
28
+ boundary width while preserving empty input targets.
29
+ - Use small operator glyphs and side limits in inline mode. Reduce nested script
30
+ size, adjust radicals inside superscripts, and preserve curved end caps on very
31
+ tall parentheses. Extend source-only KaTeX comparisons to large fences, deep
32
+ nesting, and actual inline mode.
33
+ - Fix KaTeX-compatible export and import for literal caret and tilde characters in
34
+ math text runs. Protect complex root-index arguments without changing JSON
35
+ structure. Add clearance between nested radical rules and extend rendering
36
+ regression checks.
37
+ - Use KaTeX-derived SVG contours for radicals and short/tall parentheses. Keep
38
+ existing editing boxes while improving tapered strokes and curved ends. Include
39
+ the outline assets and attribution in the package, and extend visual comparison
40
+ fixtures to simple roots and short parentheses.
41
+ - Correct the size, height and spacing of fraction terms used as scripts. Add editor/KaTeX geometry and screenshot fixtures for fractional powers and subscripts. Allow Delete and Backspace inside empty non-grid slots to remove their wrapper while retaining other content and Undo support.
42
+ - Match ordinary script and root-index font scales more closely to KaTeX in passive and active editing. Add a source-only rendering audit with per-formula measurements, screenshots and a tracked difference ledger.
43
+ - Keep formula selections intact when Up/Down navigates a visible wrapping suggestion menu. Enter applies the highlighted wrapper to the selected content. Left/Right still restores the caret, and Shift+arrows extends the selection. Apply the same behavior to React and native DOM fields used by host integrations.
44
+ - Align nested fraction terms, matrix rows, annotations and operator limits more closely with KaTeX. Scale large and contour integral geometry with the configured font size. Preserve explicit display-fraction sizes and positions inside scripts. Use matching input and passive-text metrics to retain edit positions.
45
+
46
+ Expand the source-only geometry audit to 33 formulas, including two font sizes, React and DOM rendering, active typing checks and a local image comparison gallery.
47
+
48
+ ## 0.4.1
49
+
50
+ ### Patch Changes
51
+
52
+ - Move each host implementation, tests and host-specific styles into its own plugin
53
+ package. Keep only shared data, draft-field UI and messages in the private common
54
+ package. Preserve the public entry points and stored formula format.
55
+
56
+ Declare ProseMirror as Tiptap's public dependency instead of bundling a second
57
+ copy of its host implementation. Keep host SDKs and the math core external, and
58
+ include common helpers and declarations within each published artifact.
59
+
60
+ Resolve workspace imports from source without a prior build. Use publishConfig
61
+ entry-point overrides for the core and all public plugins, and verify staged npm
62
+ artifacts against their generated runtime and declaration paths.
63
+
3
64
  ## 0.4.0
4
65
 
5
66
  ### Minor Changes
@@ -0,0 +1,174 @@
1
+ # Editing scenarios
2
+
3
+ Use this document to manage editing behavior. [Supported features](SUPPORT.md)
4
+ lists notation; this register describes what a person does with that notation.
5
+ [Validation](VALIDATION.md) stores dated execution evidence. Neither the number
6
+ of features nor the number of unit tests proves that an editing flow works.
7
+
8
+ ## Status and ownership
9
+
10
+ Keep each scenario ID stable. Add the ID to the browser fixture that exercises
11
+ it and to a bug report when that flow fails. The person changing the behavior
12
+ updates its expected result, test mapping and execution record in the same change.
13
+ The release owner reviews unresolved cases before publishing.
14
+
15
+ | Status | Meaning |
16
+ | --- | --- |
17
+ | Recorded | A dated run is recorded for the stated scope. This is not a pass for every adapter or a future build. |
18
+ | Rerun | Related browser checks exist, but this register does not certify the full scenario on the current source. |
19
+ | Extend | Some assertions exist; additional browser steps or checks are required. |
20
+ | Manual | Requires a person or device. No automated pass is claimed. |
21
+
22
+ P0 covers loss of content, blocked input, invalid output and host persistence.
23
+ P1 covers discoverability, navigation and presentation. P2 covers additional
24
+ platform coverage. A known P0 failure blocks release for the affected scope.
25
+ An unrun or unsupported case must never be counted as passed.
26
+
27
+ ## Scenario register
28
+
29
+ Start each case with a fresh editor unless the steps specify saved content.
30
+ Use actual key presses for typing and actual pointer movement for drag cases.
31
+ `Cmd` applies on macOS; `Ctrl` applies on Windows/Linux. Do not substitute a
32
+ programmatic value assignment for a focus or typing assertion.
33
+
34
+ | ID | Priority / flow | Steps | Required result | Status / test mapping |
35
+ | --- | --- | --- | --- | --- |
36
+ | EDIT-001 | P0 — Continuous input | Enter `4ab+12`, one key at a time. Pause after `4`. Resume while suggestions are visible. Move left, insert `x`, then delete it. | Each key appears once. The input retains focus. Numbers and variables remain in order; no key changes host prose. | Rerun — `quill-typing-check.js`, `typing-check.js`, `token-paste-check.js` |
37
+ | EDIT-002 | P0 — Operand wrapping | Type `4ab`. Choose absolute value for the `ab` operand. Continue typing after the structure. Repeat with parentheses, fraction and root. | `ab` remains inside the chosen structure; `4` remains outside. The cursor reaches the intended slot or following boundary. No operand disappears. | Rerun — `operand-size-check.js`; `suggestions.test.ts` |
38
+ | EDIT-003 | P0 — Selected suggestion | Type `abcd`. Select `cd` with Shift+Left twice. Use Down/Up, choose root, then Enter. Repeat with mouse drag. | The range stays selected while options change. Only `cd` is wrapped. The input receives focus after acceptance. | Rerun — `selection-suggestions-check.js`. Recorded 2026-09-09 for React and nine hosts before radical suggestions were added; rerun after suggestion changes. |
39
+ | EDIT-004 | P0 — Return to a caret | Select part of `abcd`, press Left or Right, then type `q`. Repeat with a selection that includes a fraction. In the native field, dismiss the menu with Escape before testing Up/Down collapse. | Left uses the ordered start; Right uses the ordered end. Typing inserts at that edge instead of replacing the old range. A fraction boundary does not enter the wrong slot. | Rerun — `selection-collapse-check.js`, `tinymce-inline-check.js` |
40
+ | EDIT-005 | P0 — Radical conversion | Load `\sqrt{x+1}`. Choose Change to Indexed root. Replace the selected `2` with `3`. Return to the radicand, then edit the index to `2` and convert back. Undo and Redo. | The radicand and nested nodes survive. Index `2` is selected on conversion. Index `3` cannot be silently discarded. One conversion is one Undo step. | Recorded, partial scope — `root-transform-check.js` (React/Quill, pointer and keyboard acceptance, 2026-09-09); `root-transform.test.ts` (Undo/Redo and nested trees). Browser Undo/Redo and the other hosts still need a run. |
41
+ | EDIT-006 | P0 — Structure deletion | Create a fraction, scripts, aligned equations and cases. Test Backspace/Delete at inner and outer boundaries with empty and populated slots. Undo each deletion. | Behavior matches the documented boundary rule. Populated grid cells are not silently merged or lost. Undo restores content and structure. | Extend — `empty-slot-deletion-check.js` recorded React/DOM Delete, Backspace and Undo for empty roots, fractions, exponents and root indices on 2026-09-09. Grid and populated-boundary checks remain separate: `grid-deletion.test.ts`, `native-parity-check.js`. |
42
+ | EDIT-007 | P0 — Copy and paste a range | Select text plus a nested fraction. Copy, move the caret, paste, then cut and Undo. Repeat across two editor instances. | The selected structure is preserved; unselected content stays unchanged. Cut can be undone. A rejected paste leaves the document unchanged. | Extend — `native-parity-check.js`, `token-paste-check.js`, `range.test.ts`; real OS clipboard coverage remains separate. |
43
+ | EDIT-008 | P0 — LaTeX import failure | Import `\frac{x}{y}+z`. Edit `x`. Attempt an unsupported command and malformed braces. Cancel, then reopen. | Valid input is editable. Invalid or unsupported input reports a diagnostic and retains the previous formula. Cancel does not replace host content. | Rerun — `latex-paste-host-check.js`, `latex-insertion.test.ts`, `latex.test.ts` |
44
+ | EDIT-009 | P0 — Apply, Cancel and history | Open an existing host formula. Edit and Cancel. Reopen, edit and Apply. Run host Undo and Redo. | Cancel leaves the stored host data unchanged. Apply creates one host history operation. Host serialization contains formula data, not input/menu DOM. | Rerun — host fixtures, including `tinymce-inline-check.js`, `quill-composition-check.js`, `ckeditor-check.js` |
45
+ | EDIT-010 | P0 — Save and reopen | Edit nested content, Apply, Save and Restore. Reload the stored host document and reopen the formula. | Structure, LaTeX and configured presentation survive. The formula is editable after restoration. Do not claim persistence from a preview-only check. | Rerun — `unified-check.js` and host-specific fixtures; record each supported storage format. |
46
+ | EDIT-011 | P0 — Host boundary and read-only | Move from prose into an inline formula with a boundary arrow. Edit, exit and continue prose. Switch the host to read-only with a draft open. | Math key events do not edit prose. Read-only closes or disables the draft according to the host contract and prevents new mutations. | Rerun — `shared-boundary-check.js`, `host-check.js`, host-specific fixtures |
47
+ | EDIT-012 | P1 — Suggestion scrolling | Type `matrix`. Park the pointer over a menu item. Press Down repeatedly with pauses; reverse with Up. Test near the bottom of the viewport and in an iframe. | Each press moves one option. The selected option stays visible. The list does not jump back; the page and host do not scroll unexpectedly. | Rerun — `suggestion-arrow-check.js`, `suggestion-menu-clipping-check.js`, `iframe-field-check.js` |
48
+ | EDIT-013 | P1 — Nested navigation | Enter `x_i^2`, a fraction inside a root, and a limit. Move with Left/Right, Up/Down and Tab at every slot boundary. | The nearest structure owns vertical movement when no suggestion menu is active. Selection and caret positions remain valid. | Rerun — `react-vertical-check.js`, `vertical-check.js`, `vertical-navigation.test.ts` |
49
+ | EDIT-014 | P1 — Rectangular matrix | Type `3x7` and accept the matrix. Fill cells; add/delete rows and columns. Test `1x2` and `2x1` boundaries. | Dimensions match the request. Existing cells retain their content. Cursor movement follows the resulting grid. | Rerun — `matrix-size-shortcut-check.js`, `matrix.test.ts`, `native-tools-host-check.js` |
50
+ | EDIT-015 | P0 — Matrix range editing | Select a cell rectangle. Copy/paste, clear, Undo and transpose. Test a mismatched or oversized paste. | Cell boundaries and nested structures survive. Invalid operations leave the matrix unchanged. Draft operations do not create host history entries. | Rerun — `matrix-range-check.js`, `matrix-range-host-check.js`, `matrix-range.test.ts` |
51
+ | EDIT-016 | P1 — Lines, alignment and cases | Create two lines. Insert aligned equations and cases; add a row and edit both columns. Try Enter in inline mode. | Block layouts retain their rows. Inline mode does not create an extra formula line. Enter follows the configured host commit policy. | Extend — `typing-check.js`, `lines.test.ts`, `equation.test.ts`, `embedding.test.ts`; add a combined browser flow. |
52
+ | EDIT-017 | P1 — Preview agreement | Edit a nested root, scripts, tall fences, integrals with limits, and a chemical formula. Compare exported LaTeX in KaTeX at a matched base size. Repeat with the input active. | Mathematical structure agrees. Baselines, fences, indices and limits remain readable. Focus backgrounds and hit areas do not obscure notation. | Recorded metric baseline — 77 formulas / 288 React/DOM mode-size comparisons passed on 2026-09-10. See the source-only `test/rendering/STATUS.md` ledger. Selected metrics and active-input checks do not certify every glyph or every editing flow. |
53
+ | EDIT-018 | P1 — Language and multiple instances | Switch en/ko with a draft open. Open another editor and its suggestions. Repeat with a registered custom locale. | Labels resolve, formulas do not change, focus and menus stay with the right instance, and search aliases use the locale fallback rules. | Rerun — `plugins-locale-check.js`, `shared-symbol-tools-check.js`, `locale-discovery.test.ts` |
54
+ | EDIT-019 | P0 — Long edit session | Build a fraction, wrap a selection, convert a radical, insert a matrix, undo five steps, redo five, Apply, Save and reopen. Repeat without resetting the page. | No stuck focus, lost selection, duplicated operation or draft leakage. All checkpoints retain the expected formula. | Recorded, scoped — `test/editing/continuous.browser.js`, run with `pnpm --filter @barocss/math-editor test:editing`. React standalone block, Quill/Tiptap/ProseMirror/Lexical/TinyMCE/CKEditor/Slate in-place block/inline, and Editor.js/Gutenberg block passed on 2026-09-10 (17 targets, 499 checkpoints); includes two uninterrupted formula history chains and host Apply/Save/reload/Restore/Cancel. Editor.js has no host history integration, so document Undo/Redo remains unverified there. Inline additionally verifies Enter commit without new paragraphs, right-boundary exit, prose caret position and host Undo. TinyMCE uses its inline host, CKEditor uses ClassicEditor, and Gutenberg uses the standalone provider demo. Other configurations and native OS input remain unverified by this run. |
55
+ | EDIT-020 | P2 — Native IME and clipboard | On a real OS, compose Korean text, move the caret, use suggestions, cancel composition and paste with the system clipboard. | Composed text appears once; composition keys do not apply suggestions or host commands prematurely. Clipboard data is preserved according to the documented formats. | Manual — previously deferred by the user. Synthetic composition/DataTransfer checks do not certify OS behavior. |
56
+
57
+ ## Contextual structure tools
58
+
59
+ These scenarios specify the footer independently from the suggestion list. The
60
+ footer has a single target: the nearest enclosing radical or fence. It is shown only
61
+ while that editor is active, outside literal text and model/matrix selections.
62
+ Native text selection within the active slot is allowed, including the selected
63
+ index produced by conversion.
64
+
65
+ | ID | Priority / flow | Steps | Required result | Coverage |
66
+ | --- | --- | --- | --- | --- |
67
+ | EDIT-021 | P1 — Discover without search | Click inside a root. Put the caret at the start of its text. Dismiss suggestions with Escape. Move outside the root. | Footer shows the current structure and conversion even with no query or no open suggestions. Leaving the radical hides it. | `context-tools-check.js` |
68
+ | EDIT-022 | P0 — Footer conversion and index edit | Convert a root using the footer. Replace selected index `2` with `3`. Click the radicand, choose Edit index, type `2`, convert back and Undo. | Content survives, index editing selects the existing index, a non-square index blocks reverse conversion with a visible reason, and Undo restores the structure. | `context-tools-check.js` |
69
+ | EDIT-023 | P0 — Keyboard-only footer | From input, press F6, Escape, F6 and Enter. Tab between available buttons. | F6 enters tools; Escape returns to the same input. Button activation edits the intended structure. Keys do not reach host prose. Tab uses native button order. | F6/Escape/Enter recorded in `context-tools-check.js`; explicit Tab-order assertion remains to add. |
70
+ | EDIT-024 | P0 — Nearest nested target | Open `\sqrt[3]{a+\sqrt{x}}`. Move between `a` and `x`. | Footer identifies the outer indexed root at `a` and inner square root at `x`. Index editing targets the corresponding root. | `context-tools-options-check.js`, `root-transform.test.ts` |
71
+ | EDIT-025 | P1 — Locale without model changes | Show tools, change en to ko, then edit the index. | Structure name, actions, disabled reason and keyboard hint update together. Stored formula content is unchanged by locale selection. | `context-tools-options-check.js`; direct document equality on locale switch remains to add. |
72
+ | EDIT-026 | P0 — Scope and focus | Create a model range, collapse it, blur the field, reopen, then destroy the instance. Repeat focus navigation inside an iframe. | Range mode does not show stale caret actions. Collapse restores context; blur hides it; destroy removes it. Focus stays in the iframe's own document. | `context-tools-check.js`, `context-tools-options-check.js` |
73
+ | EDIT-027 | P0 — Composition guard | Dispatch composition start and end in the native field with context visible. | Actions are disabled during composition and resume afterward. This guard test is not OS IME certification. | Synthetic coverage in `context-tools-options-check.js`; real OS behavior remains EDIT-020. |
74
+ | EDIT-028 | P1 — Embedding opt-out | Set `contextTools: false`, then update to true. Repeat with `context-tools="false"` on a Web Component. | Footer hides without changing the formula or removing suggestion-based conversions. Attribute updates take effect without remounting. | Visibility/update coverage in `context-tools-options-check.js`; per-framework wrapper smoke checks remain to add. |
75
+
76
+ ## Inline transformation suggestions
77
+
78
+ The suggestion list is the primary keyboard entry point for structural changes.
79
+ It remains available when both toolbar and context footer are hidden. Alt+Down
80
+ opens or reopens suggestions and highlights the first available transformation;
81
+ Up/Down browses, Enter applies, and Escape dismisses without editing the formula.
82
+ Automatic context-only suggestions require navigation before Enter can apply them,
83
+ so an inline host's commit key is not silently replaced.
84
+
85
+ | ID | Priority / scenario | Steps | Expected result | Coverage |
86
+ | --- | --- | --- | --- | --- |
87
+ | EDIT-029 | P0 — Fence suggestions in inline fields | Type inside parentheses. Press Alt+Down, Enter, then continue typing. Repeat after dismissing the menu. | The list distinguishes changing a fence from wrapping an operand. Existing content and caret are preserved; the menu does not take DOM focus. | `fence-suggestions-check.js`, `context-tools.test.ts` |
88
+ | EDIT-030 | P0 — Browse, cancel and Undo | Open changes, browse with Up/Down, cancel with Escape. Reopen, apply, type, then undo typing and conversion separately. | Browsing and cancellation do not change the formula. Conversion makes one history entry. | `fence-suggestions-check.js` |
89
+ | EDIT-031 | P0 — Nearest wrapper and all fence pairs | Change each of eight fence types. Test nested fractions, roots, mixed delimiters and stale targets. Use F6/Left/Right/Enter if the optional footer is enabled. | Only the nearest supported wrapper changes. Slot IDs, content and caret remain stable. Explicit left/right metadata is removed when selecting a standard pair. | `context-tools.test.ts`, `fence-context-check.js`; browser nested targeting in EDIT-032 |
90
+ | EDIT-032 | P0 — No-toolbar inline iframe | Hide toolbar/footer in an inline iframe field. Change an inner fence with suggestions, switch ko/en and continue typing. Destroy the editor. | The complete workflow works without auxiliary UI. Locale changes leave the document unchanged. Focus uses the iframe document; teardown removes suggestions. | `fence-inline-options-check.js`; installed host/browser breadth remains separate validation work |
91
+
92
+ Execution scope is recorded in [Validation](VALIDATION.md). A mapped case may
93
+ still contain pending assertions, as stated in the Coverage column.
94
+
95
+ Browser fixture names above refer to `apps/math-integrations/tests/`. Unit fixture
96
+ names refer to `packages/math-editor/test/`. A mapping identifies related coverage,
97
+ not an assertion that every step already exists in that file. Extend cases need
98
+ explicit browser assertions before they can receive a full pass.
99
+
100
+ ## Test environments
101
+
102
+ Record renderer, adapter, mode and browser separately. An integration using the
103
+ native DOM field does not prove the rich React field, and an iframe can have its
104
+ own focus, event and CSS failures.
105
+
106
+ | Layer | Required scope when that layer changes |
107
+ | --- | --- |
108
+ | Shared model / suggestions | Unit checks plus affected editing scenarios on rich React and native DOM. |
109
+ | Framework adapter | The affected adapter: pure JS, Web Component, Vue, Svelte, Solid, or React wrapper. Record the actual renderer used. |
110
+ | Host integration | Every affected host. Shared field changes need the nine-host smoke set: Tiptap, ProseMirror, Lexical, Editor.js, TinyMCE, CKEditor, Quill, Slate, Gutenberg. |
111
+ | Mode / container | Inline and block where supported; TinyMCE classic iframe as well as inline. Editor.js and Gutenberg block-only scenarios are N/A for inline tests. |
112
+ | Browser | Record Chromium, Firefox or WebKit explicitly. Current Chromium evidence does not cover the other engines. |
113
+ | Build source | Workspace source for development; packed artifacts for release checks. Neither implies the other. |
114
+
115
+ ## Per-run record
116
+
117
+ Append detailed evidence to [Validation](VALIDATION.md), using this template.
118
+ Record an immutable revision when possible. For an uncommitted workspace, record
119
+ that fact and save the tested patch or a source fingerprint with the run artifacts.
120
+ A date alone does not identify the tested code.
121
+
122
+ ```text
123
+ Run ID: edit-YYYYMMDD-NN
124
+ Scenario IDs:
125
+ Source: commit / workspace fingerprint / package versions and archive hashes
126
+ Fixture revision:
127
+ Renderer and host:
128
+ Mode and container:
129
+ Browser, OS, locale:
130
+ Input formula and steps:
131
+ Expected result:
132
+ Observed result:
133
+ Outcome: PASS / FAIL / BLOCKED / NOT RUN / N/A
134
+ Evidence: log, screenshot pair, trace or recorded host data
135
+ Remaining steps and excluded environments:
136
+ Issue / follow-up:
137
+ ```
138
+
139
+ A scenario passes only when all required assertions pass in the recorded scope.
140
+ For partial coverage, report the passing steps and keep the rest unverified.
141
+ Do not convert historical validation totals into a current release pass.
142
+
143
+ ## Change workflow
144
+
145
+ 1. Assign a scenario ID to each editing bug before changing its behavior.
146
+ 2. Reproduce the smallest failing input sequence. Capture the caret, selection,
147
+ highlighted suggestion, document and host data where relevant.
148
+ 3. Add or update a regression fixture with the same ID. Check the final model,
149
+ cursor/focus and history behavior, not only whether an element is visible.
150
+ 4. Implement the change. Run its model tests, affected browser scenarios and the
151
+ nearest negative case. Compare editor/KaTeX output when notation changes.
152
+ 5. Record the result and its scope. Mark related scenarios for rerun if later
153
+ changes touch their input, selection, suggestions, history or host handling.
154
+ 6. Before release, run the applicable P0 cases against the release candidate and
155
+ check packed imports. Any excluded host/browser must be stated explicitly.
156
+
157
+ The Markdown register is the source of truth for scope and acceptance criteria.
158
+ The browser fixtures contain executable assertions. The validation report holds
159
+ run evidence. The documentation site renders this register; it does not execute
160
+ the browser checks. Automated release enforcement is not implemented by this
161
+ register alone.
162
+
163
+ ## Next work
164
+
165
+ 1. Maintain the EDIT-019 baseline across all nine integration demos and React
166
+ standalone block. Extend it separately to TinyMCE iframe, WordPress admin and
167
+ other host configurations. Preserve exact checkpoints and host-history assertions.
168
+ 2. Add missing browser steps for EDIT-006, EDIT-007 and EDIT-016. Include negative
169
+ cases and real host Undo/Redo rather than testing only model transformations.
170
+ 3. Reuse the EDIT-019 runner pattern for additional scenario IDs. It already
171
+ records source fingerprints and fails on changed source or failed assertions.
172
+ CI/release enforcement remains separate work.
173
+ 4. Schedule Firefox/WebKit and real OS IME/clipboard coverage separately. Keep
174
+ manual requirements visible without representing synthetic events as a substitute.
package/IMPLEMENTATION.md CHANGED
@@ -265,3 +265,98 @@ operations needs a new model version or parser command.
265
265
  Native text rows are tokenized with the same `tokenizeMathText`/`tokenIndexAt` rules as rich React. Every rendered run retains its model ID and UTF-16 token start/end. Input events replace only that token's slice. Pointer/keyboard offsets are translated to model coordinates; boundary deletion joins neighboring text without discarding it. IME preedit updates the stable input/mirror and is committed before re-tokenizing. Literal text/operator names remain one input.
266
266
 
267
267
  `latex-insertion.ts` parses before applying a range insertion. `preferences.ts` owns validated UI lists independently of formula sessions/history. `presentation.ts` changes only supported metadata while preserving subtree IDs and caret. The nonmodal native panels are reused by React wrappers, so diagnostics and favorites use one implementation. Host clipboard boundaries stay intact and no system clipboard reads are implicit.
268
+
269
+ ### Contextual radical conversions
270
+
271
+ `findStateSuggestions(state, locale, caret?)` augments text search with the nearest
272
+ enclosing radical's conversion actions. `transformRootId` binds an action to that
273
+ structure; `acceptSuggestion` validates the current target before conversion and
274
+ does not remove the query. `root-transform.ts` clones the document, preserves the
275
+ radicand tree and structure ID, and updates the slots. Converting to an indexed
276
+ root adds a selected index `2`; converting to a square root rejects any nonempty
277
+ index other than `2`. Both renderers use this shared path and their normal history
278
+ commit mechanism. Context-only actions require pointer acceptance or arrow-key
279
+ selection before Enter can apply them.
280
+
281
+ ### Empty-slot deletion and script fractions
282
+
283
+ `unwrapEmptySlot` removes a non-grid wrapper from inside a truly empty slot.
284
+ Both Delete and Backspace call it before boundary-specific deletion. The other
285
+ slots are retained; an empty root index collapses to a square root, and an empty
286
+ paired script preserves the other script. A populated row or ordinary structural
287
+ boundary is not an empty slot. Grid cells keep their shape and their existing
288
+ explicit deletion controls. The edit uses the normal history commit.
289
+
290
+ Fractional script presentation uses compact row heights and term metrics in both
291
+ renderers. See [Rendering checks](RENDERING-TESTS.md) for the bounded geometry
292
+ comparison and remaining layout work.
293
+
294
+ ### Query-independent context footer
295
+
296
+ `rootEditingContext(state)` derives the nearest radical, conversion availability
297
+ and index caret from the model. React and DOM render the same actions below the
298
+ surface. The footer does not use suggestion text, dismissal or candidate indices.
299
+ Transformations use `transformRoot` and normal history; Edit index only moves
300
+ and selects the caret. Model/matrix selections and blur hide context actions.
301
+ F6 and Escape are handled within the editor to retain host/iframe focus. Native
302
+ composition disables footer actions without replacing the composing input.
303
+
304
+ ### Shared fence transformations
305
+
306
+ `structureEditingContext` selects the nearest supported radical or fence and
307
+ excludes literal text. `findStateSuggestions` adds fence transformations before
308
+ operand-wrapping actions, while retaining explicit symbol/command matches first.
309
+ `transformFenceId` distinguishes metadata changes from new structure insertion.
310
+ Acceptance validates the current target before preserving content, IDs and caret.
311
+
312
+ React and native DOM handle Alt+Down before modifier-key fallthrough. The shortcut
313
+ reopens a dismissed list and arms the first context action. Normal contextual
314
+ menus still require navigation before Enter overrides host commit behavior.
315
+ The footer is optional; suggestions do not depend on its visibility.
316
+
317
+
318
+ ## Contextual operator layout
319
+
320
+ `src/math-layout.ts` derives display, text, script and scriptscript contexts from
321
+ model slots on each render. It does not mutate or persist presentation metadata.
322
+ Fractions reduce the style of their terms; scripts reduce their labels; indexed
323
+ root indices use scriptscript style. Explicit fraction styles reset that context. Aligned cells enter display style; matrix and cases cells enter text style.
324
+
325
+ Both React and native DOM consume the same row/operator map. Operator attributes
326
+ select the large or small font and side or stacked limits. Explicit limits remain
327
+ authoritative. Scoped row attributes keep a nested operator body at its own size
328
+ while reducing its bounds. This replaces the inline-only CSS decision, which
329
+ could not identify operators inside fractions or nested scripts.
330
+
331
+ The current CSS application is scoped to operators. Other structures still use
332
+ their existing layout rules; this is not a complete TeX layout engine.
333
+
334
+ ### Horizontal text spacing
335
+
336
+ `math-spacing.ts` computes spacing between lexical runs without changing the
337
+ saved document, token boundaries or caret offsets. Both renderers use the same
338
+ values. Common binary operators use 4 mu, relations use 5 mu and punctuation
339
+ uses 3 mu before the next atom (18 mu = 1 em). Neighboring atoms distinguish
340
+ unary signs from binary operators. Binary, relation and punctuation gaps are
341
+ suppressed in script and scriptscript rows.
342
+
343
+ Measuring spans use glyph width instead of adding padding to every math token.
344
+ Literal text fields retain their text layout. Named-function fields use unpadded glyph measurement. Inactive model
345
+ boundaries use 1 px; empty expression slots and the active boundary keep their
346
+ existing input hit areas. Other structure interiors and full TeX atom classification are separate work. These rules do not provide a complete
347
+ TeX horizontal layout engine.
348
+
349
+
350
+ ### Named functions and fraction boundaries
351
+
352
+ Named functions and fractions participate in the same horizontal-spacing pass as
353
+ text runs. A named function uses a thin gap next to an ordinary atom or another
354
+ named function, and no gap before a plain opening parenthesis. These thin gaps
355
+ remain in script styles at the corresponding reduced font size. Binary and
356
+ relation gaps still disappear in scripts. Fractions contribute an ordinary atom
357
+ and receive their external gap once, rather than adding fixed margins on both
358
+ sides. The function name's measuring span adds no glyph padding.
359
+
360
+ The spacing map contains structure IDs for these two families and token-offset
361
+ keys for text. Other structure families keep their existing outer layout. This
362
+ change does not alter LaTeX output, JSON, selection offsets or editing commands.
package/LATEX-GUIDE.md CHANGED
@@ -259,3 +259,25 @@ Typing `{` offers both paired braces and cases. Paired braces remain the first c
259
259
  Use **Paste as LaTeX** in More tools, or **Alt+Shift+V**, to paste a source fragment at the current caret or selected range. Ctrl/Cmd+Enter inserts it; unsupported input stays in the source field with a diagnostic. Ordinary paste retains its existing literal-text behavior.
260
260
 
261
261
  When the caret is inside a structure, the toolbar can change its bracket pair, fraction/binomial display size, or operator limit placement. These actions preserve contents and support one-step Undo. Recent & favorites keeps frequently used symbols/templates available without searching again. See [editing utilities](API-SESSION.md#editing-utilities--workspace).
262
+
263
+ ### Change a radical while editing
264
+
265
+ Inside `\sqrt{x}`, choose **Change to Indexed root** in the suggestions. The
266
+ result is `\sqrt[2]{x}` with `2` selected for replacement. The content under the
267
+ radical is preserved. An indexed root with an empty index or `2` offers **Change
268
+ to Square root**. Other indices must be edited before that conversion is offered.
269
+ This editing operation does not change the LaTeX grammar or JSON model schema.
270
+
271
+
272
+ ## Literal caret/tilde and complex root indices
273
+
274
+ A literal `^` or `~` in a model text run exports as `\char"005E{}` or
275
+ `\char"007E{}`. These spellings render in KaTeX math mode and load back into the
276
+ same text run. The importer also accepts `\textasciicircum{}` and
277
+ `\textasciitilde{}` as input aliases. Inside `\text{...}`, text-mode escaping
278
+ remains unchanged. General TeX `\char` codes are not supported.
279
+
280
+ An index containing braces or brackets is grouped when exported. For example,
281
+ `\sqrt[{x^2}]{y}` and `\sqrt[{\left[a\right]}]{y}` keep the optional index
282
+ argument intact. Grouping does not add a JSON node or remove editable structure.
283
+ Simple indices continue to export as `\sqrt[3]{x}`.
package/LATEX-MODEL.md CHANGED
@@ -288,3 +288,15 @@ Type `xrightarrow`, `xleftarrow`, or search for “labeled arrow” / “설명
288
288
  `\begin{equation*} ... \end{equation*}` imports its body into the existing root math row. It creates no new node kind and adds no suggestion item. Export emits the body without the environment wrapper. Nested supported structures remain editable. Missing/mismatched endings and unsupported commands fail atomically.
289
289
 
290
290
  Numbered `equation`, `\tag` and `\label` are not supported: the model cannot preserve numbering or references. Use `equation*` only when formula-only import is intended. `align`, `split` and `array` remain open.
291
+
292
+
293
+ ### Protected root indices and literal characters
294
+
295
+ | Model content | Canonical LaTeX | Import result |
296
+ | --- | --- | --- |
297
+ | Text run containing `^` | `\char"005E{}` | Same text run, not a superscript |
298
+ | Text run containing `~` | `\char"007E{}` | Same text run, not an accent |
299
+ | `indexedRoot` with a structured index | `\sqrt[{…}]{…}` | Same index and radicand slots; protective braces add no model node |
300
+
301
+ Literal text groups keep their existing text-mode escapes. Only the two character
302
+ codes above are supported; this does not implement arbitrary TeX character codes.
package/LATEX-SCOPE.md CHANGED
@@ -19,7 +19,7 @@ The first product target is Note: open an existing supported LaTeX formula in a
19
19
  | Import for editing | `parseLatex` and the editor model | Parser succeeds and every resulting node remains editable |
20
20
  | Export LaTeX | `toLatex` | Supported model produces valid presentation output |
21
21
 
22
- KaTeX display support does **not** imply editable import support. For example, KaTeX can display annotations such as underbraces that the editor cannot yet import. Unsupported notation must fail without a partial conversion.
22
+ KaTeX display support does **not** imply editable import support. For example, a host can configure KaTeX macros that the editor does not import. Unsupported notation must fail without a partial conversion.
23
23
 
24
24
  ## V1 grammar
25
25
 
@@ -261,3 +261,12 @@ Type `xrightarrow`, `xleftarrow`, or search for “labeled arrow” / “설명
261
261
  `\begin{equation*} ... \end{equation*}` imports its body into the existing root math row. It creates no new node kind and adds no suggestion item. Export emits the body without the environment wrapper. Nested supported structures remain editable. Missing/mismatched endings and unsupported commands fail atomically.
262
262
 
263
263
  Numbered `equation`, `\tag` and `\label` are not supported: the model cannot preserve numbering or references. Use `equation*` only when formula-only import is intended. `align`, `split` and `array` remain open.
264
+
265
+
266
+ ## Compatibility corrections — 2026-09-10
267
+
268
+ Math-mode caret and tilde text runs export with bounded `\char"005E{}` and
269
+ `\char"007E{}` commands. Text-mode aliases remain accepted and literal text-group
270
+ escaping is unchanged. Arbitrary character codes remain unsupported.
271
+ Complex root indices export inside a protective group, preserving their existing
272
+ JSON slots. See [the LaTeX guide](LATEX-GUIDE.md#literal-carettilde-and-complex-root-indices).
package/README.md CHANGED
@@ -1,8 +1,17 @@
1
1
  # @barocss/math-editor
2
2
 
3
+ See [Editing scenarios](EDITING-SCENARIOS.md) for stable scenario IDs, acceptance criteria, coverage gaps and per-run reporting.
4
+
5
+
3
6
  An embeddable math editor for writing LaTeX-compatible formulas. Edit expressions in place, select existing math, and wrap it in fractions, roots, powers or delimiters. The package includes a framework-independent model, a rich React editor, and a native DOM editor with framework adapters.
4
7
 
5
- **Release:** core **0.4.0**, with nine host editor plugins at **0.1.0**. This editor does not calculate, solve equations or parse arbitrary LaTeX.
8
+ This editor does not calculate, solve equations or parse arbitrary LaTeX.
9
+
10
+ ## Packaging changes in 0.4.1
11
+
12
+ Each host plugin owns its source and version. Workspace apps import source without
13
+ a prerequisite build; npm consumers receive generated runtime and declarations.
14
+ The private common module is included in each plugin and is not installed separately.
6
15
 
7
16
  ## Editing additions in 0.4.0
8
17
 
@@ -14,19 +23,19 @@ Choose the core package for a standalone math field. Choose one additional host
14
23
 
15
24
  | Package | Purpose | Formula placement | Release status |
16
25
  | --- | --- | --- | --- |
17
- | `@barocss/math-editor` | Math model, LaTeX import/export, editor, toolbar and framework adapters | Standalone, inline or multiline | 0.4.0; MIT |
18
- | `@barocss/math-editor-tiptap` | Tiptap node extension | Inline and block | 0.1.0; MIT |
19
- | `@barocss/math-editor-prosemirror` | ProseMirror schema, commands and node views | Inline and block | 0.1.0; MIT |
20
- | `@barocss/math-editor-lexical` | Lexical math node and registration | Inline and block | 0.1.0; MIT |
21
- | `@barocss/math-editor-editorjs` | Editor.js math Tool | Block | 0.1.0; MIT |
22
- | `@barocss/math-editor-tinymce` | TinyMCE plugin with in-place or panel editing | Inline and block | 0.1.0; MIT |
23
- | `@barocss/math-editor-ckeditor` | CKEditor 5 model objects and widgets | Inline and block | 0.1.0; MIT |
24
- | `@barocss/math-editor-quill` | Quill math embeds and registration | Inline and block | 0.1.0; MIT |
25
- | `@barocss/math-editor-slate` | Slate void elements and React rendering | Inline and block | 0.1.0; MIT |
26
- | `@barocss/math-editor-gutenberg` | WordPress Gutenberg math block | Block | 0.1.0; MIT |
27
- | `@barocss/math-editor-integrations` | Shared implementation used to build the nine host packages | Internal development | Private; not an install target |
28
-
29
- The host plugins require `@barocss/math-editor@^0.4.0`. The core and all nine host packages use the MIT license, with copyright attributed to barocss.com. Each package includes its own LICENSE file. Host SDKs retain their own licenses.
26
+ | `@barocss/math-editor` | Math model, LaTeX import/export, editor, toolbar and framework adapters | Standalone, inline or multiline | MIT |
27
+ | `@barocss/math-editor-tiptap` | Tiptap node extension | Inline and block | MIT |
28
+ | `@barocss/math-editor-prosemirror` | ProseMirror schema, commands and node views | Inline and block | MIT |
29
+ | `@barocss/math-editor-lexical` | Lexical math node and registration | Inline and block | MIT |
30
+ | `@barocss/math-editor-editorjs` | Editor.js math Tool | Block | MIT |
31
+ | `@barocss/math-editor-tinymce` | TinyMCE plugin with in-place or panel editing | Inline and block | MIT |
32
+ | `@barocss/math-editor-ckeditor` | CKEditor 5 model objects and widgets | Inline and block | MIT |
33
+ | `@barocss/math-editor-quill` | Quill math embeds and registration | Inline and block | MIT |
34
+ | `@barocss/math-editor-slate` | Slate void elements and React rendering | Inline and block | MIT |
35
+ | `@barocss/math-editor-gutenberg` | WordPress Gutenberg math block | Block | MIT |
36
+ | `@barocss/math-editor-integrations` | Common data, draft UI, messages and styles; each host owns its plugin source | Internal development | Private; not an install target |
37
+
38
+ Install the core with each host plugin; the package manifests declare compatible peer versions. The core and all nine host packages use the MIT license, with copyright attributed to barocss.com. Each package includes its own LICENSE file. Host SDKs retain their own licenses.
30
39
 
31
40
  Each host package exports its adapter, `/shared` helpers and `/style.css`. Load the core stylesheet as well. Gutenberg also exports `/data` for its stored-data codec. Install only the host package you use; there is no public all-host bundle. Formula placement, keyboard entry, history and clipboard behavior depend on the host.
32
41
 
@@ -58,10 +67,10 @@ For editor-only, external toolbar, LaTeX, preview, inline and popup compositions
58
67
 
59
68
  ## Quick start
60
69
 
61
- Install version 0.4.0 from npm:
70
+ Install version 0.4.1 from npm:
62
71
 
63
72
  ```sh
64
- npm install @barocss/math-editor@0.4.0
73
+ npm install @barocss/math-editor@0.4.1
65
74
  # For the rich React UI:
66
75
  npm install react react-dom
67
76
  ```
@@ -72,7 +81,6 @@ To develop the package and demo from this monorepo:
72
81
 
73
82
  ```sh
74
83
  pnpm install
75
- pnpm --filter @barocss/math-editor build
76
84
  pnpm --filter @barocss/math-demo dev
77
85
  # http://localhost:5184
78
86
  ```
@@ -165,7 +173,7 @@ Native passive text preserves these lexical colors; its whole active run still u
165
173
  | Model selection | Backspace / Delete | Delete selection |
166
174
  | Editor | Cmd/Ctrl+Z / Cmd/Ctrl+Shift+Z | Undo / redo |
167
175
 
168
- Vertical arrows use the nearest inner structure before an enclosing grid, then fall back to another equation line. Paired scripts can move along their shared column; a base moves up to its superscript and down to its subscript. Suggestions retain arrow-key priority. Composition, literal text and noncollapsed text selections do not trigger structural movement. React and native surfaces share this behavior.
176
+ Vertical arrows use the nearest inner structure before an enclosing grid, then fall back to another equation line. Paired scripts can move along their shared column; a base moves up to its superscript and down to its subscript. Visible suggestions retain Up/Down priority, including after Shift+arrow or drag selection. Enter applies the highlighted wrapper to the selected content; Left/Right restores the caret, and Shift+arrows adjusts the range. Composition, literal text and noncollapsed text selections do not trigger structural movement. React and native surfaces share this behavior.
169
177
 
170
178
  The framework-free `moveVertical(state, direction, geometry?)` helper is exported from `/core`. Without rendered geometry, it selects the first text run in the target slot and clamps the current offset. At a lexical token boundary, rendered geometry distinguishes the previous token's end from the next token's start. Each move uses the current caret's horizontal position; a preferred column is not retained across repeated moves through shorter rows. Shift+arrow selection remains a separate operation.
171
179
 
@@ -206,7 +214,7 @@ pnpm --filter @barocss/math-demo build
206
214
  pnpm --filter @barocss/math-demo test:e2e
207
215
  ```
208
216
 
209
- The demo consumes package exports from `dist`; rebuild the package before browser tests. Browser tests use Playwright Chromium and start port 5184 if needed. Actual OS Korean IME tests remain deferred at the user's request.
217
+ The demo consumes workspace source exports and does not require a package build. Release checks use `publishConfig.exports` and inspect the packed JavaScript and declarations. Browser tests use Playwright Chromium and start port 5184 if needed. Actual OS Korean IME tests remain deferred at the user's request.
210
218
 
211
219
  - [Symbol / English / Korean name table](https://math-editor.barocss.com/docs/symbols.html)
212
220
  - [LaTeX editing guide and upcoming notation](https://math-editor.barocss.com/docs/latex-guide.html)
@@ -350,3 +358,49 @@ MIT License. Copyright (c) 2026 barocss.com.
350
358
 
351
359
  The npm package includes the full license in `LICENSE`. Bundled KaTeX fonts retain
352
360
  their separate copyright and MIT notice in `src/fonts/LICENSE-KaTeX.txt`.
361
+
362
+ ### Change an existing radical
363
+
364
+ Place the caret inside a square root and choose **Change to Indexed root** in
365
+ the suggestions. The radicand, including nested structures, stays intact. The
366
+ new index is `2` and is selected so you can immediately type `3`, `n`, or another
367
+ index. The explicit choice creates one Undo step.
368
+
369
+ **Change to Square root** is available inside an indexed root with an empty
370
+ index or index `2`. Other indices must be edited first; conversion does not
371
+ discard them. The nearest enclosing radical is the target. Conversion choices
372
+ do not consume the text used to search, and an unselected conversion does not
373
+ intercept Enter. Both React and native DOM integrations support this behavior.
374
+
375
+ Empty non-grid slots support Delete and Backspace directly. Removing the wrapper
376
+ keeps other slot content and can be undone. See [Rendering checks](RENDERING-TESTS.md)
377
+ for editor/KaTeX comparison fixtures and the current visual verification scope.
378
+
379
+ ### Contextual structure tools
380
+
381
+ While the caret is inside a radical, the optional editor footer shows its current type,
382
+ conversion action and, for indexed roots, **Edit index**. No search text is needed.
383
+ Dismissing suggestions leaves the footer available. An unavailable conversion
384
+ stays disabled with an explanation. F6 moves focus to the tools; Escape returns
385
+ to input. The footer hides outside the radical, on blur, or during model selection.
386
+
387
+ Set `contextTools={false}` on rich React, or `contextTools: false` in native DOM
388
+ options, to hide this footer. Native framework wrappers accept the same option.
389
+ The Web Component uses `context-tools="false"`. This setting does not remove
390
+ conversion suggestions. See [Editing scenarios](EDITING-SCENARIOS.md) EDIT-021
391
+ through EDIT-028 for acceptance criteria and pending coverage.
392
+
393
+ ### Change brackets from suggestions
394
+
395
+ Place the caret inside brackets and press **Alt+Down** (Option+Down on macOS).
396
+ The existing suggestion list opens with a transformation selected. Use Up/Down
397
+ and Enter to change the surrounding brackets; Escape closes the list unchanged.
398
+ “Change brackets” preserves the enclosed formula and caret, unlike an action
399
+ that wraps text in a new pair. Available pairs include parentheses, brackets,
400
+ braces, angle brackets, absolute value, norm and both half-open intervals.
401
+
402
+ This works in inline fields with `toolbar: false` and `contextTools: false`.
403
+ Automatic contextual suggestions do not consume Enter until you navigate them.
404
+ The optional footer also offers bracket buttons via F6, Left/Right and Enter.
405
+ Nested roots and fences share a nearest-wrapper target. See EDIT-029 through
406
+ EDIT-032 in [Editing scenarios](EDITING-SCENARIOS.md).