Skip to content

Commit a2ed6c2

Browse files
jasmussenellatrixMamaduka
authored
Math format: seed LaTeX input from the current selection (#79052)
Co-authored-by: jasmussen <joen@git.wordpress.org> Co-authored-by: ellatrix <ellatrix@git.wordpress.org> Co-authored-by: Mamaduka <mamaduka@git.wordpress.org>
1 parent 3427bb2 commit a2ed6c2

3 files changed

Lines changed: 95 additions & 3 deletions

File tree

packages/format-library/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## Unreleased
44

5+
### Enhancements
6+
7+
- Math format: seed the LaTeX input from the current selection when marking text as math, and toggle an active math object back to its LaTeX source when the button is clicked again. ([79052](https://github.com/WordPress/gutenberg/pull/79052))
8+
59
## 5.48.0 (2026-06-10)
610

711
## 5.47.0 (2026-05-27)

packages/format-library/src/math/index.js

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44
import { __, sprintf } from '@wordpress/i18n';
55
import { useState, useEffect } from '@wordpress/element';
6-
import { insertObject, useAnchor } from '@wordpress/rich-text';
6+
import { insert, insertObject, useAnchor } from '@wordpress/rich-text';
77
import { RichTextToolbarButton } from '@wordpress/block-editor';
88
import {
99
Popover,
@@ -141,12 +141,42 @@ function Edit( {
141141
icon={ icon }
142142
title={ title }
143143
onClick={ () => {
144+
// If a math object is already active, revert it to its
145+
// LaTeX source so clicking the button toggles back to the
146+
// exact text it was created from. Keep the restored text
147+
// selected so it can be edited or re-marked right away.
148+
if ( isObjectActive ) {
149+
const latex =
150+
activeObjectAttributes?.[ 'data-latex' ] || '';
151+
const newValue = insert( value, latex );
152+
newValue.start = newValue.end - latex.length;
153+
onChange( newValue );
154+
onFocus();
155+
return;
156+
}
157+
// If there's a selection, seed the format with it so you
158+
// can type LaTeX inline and then mark it as math.
159+
const selectedText = value.text.slice(
160+
value.start,
161+
value.end
162+
);
163+
let innerHTML = '';
164+
if ( selectedText && latexToMathML ) {
165+
try {
166+
innerHTML = latexToMathML( selectedText, {
167+
displayMode: false,
168+
} );
169+
} catch {
170+
// Leave unrendered; the popover opens with the text
171+
// prefilled so the expression can be corrected.
172+
}
173+
}
144174
const newValue = insertObject( value, {
145175
type: name,
146176
attributes: {
147-
'data-latex': '',
177+
'data-latex': selectedText,
148178
},
149-
innerHTML: '',
179+
innerHTML,
150180
} );
151181
newValue.start = newValue.end - 1;
152182
onChange( newValue );

test/e2e/specs/editor/various/format-library/math.spec.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,62 @@ test.describe( 'Format Library - Math', () => {
8888
},
8989
] );
9090
} );
91+
92+
test( 'should seed the math format from the current selection', async ( {
93+
editor,
94+
page,
95+
pageUtils,
96+
} ) => {
97+
await editor.canvas
98+
.getByRole( 'button', { name: 'Add default block' } )
99+
.click();
100+
101+
// Type the LaTeX as plain text, then select it.
102+
await page.keyboard.type( 'equation: x^2' );
103+
await pageUtils.pressKeys( 'shift+ArrowLeft', { times: 3 } );
104+
105+
// Mark the selection as math.
106+
await editor.clickBlockToolbarButton( 'More' );
107+
await page.getByRole( 'menuitem', { name: 'Math' } ).click();
108+
109+
// The selected text should be used as the LaTeX and render immediately.
110+
expect( await editor.getBlocks() ).toMatchObject( [
111+
{
112+
name: 'core/paragraph',
113+
attributes: {
114+
content:
115+
'equation: <math data-latex="x^2"><semantics><msup><mi>x</mi><mn>2</mn></msup><annotation encoding="application/x-tex">x^2</annotation></semantics></math>',
116+
},
117+
},
118+
] );
119+
120+
// Clicking the button again on the active object should revert it to
121+
// its LaTeX source, so the round-trip lands back on the original text.
122+
await editor.clickBlockToolbarButton( 'More' );
123+
await page.getByRole( 'menuitem', { name: 'Math' } ).click();
124+
125+
expect( await editor.getBlocks() ).toMatchObject( [
126+
{
127+
name: 'core/paragraph',
128+
attributes: {
129+
content: 'equation: x^2',
130+
},
131+
},
132+
] );
133+
134+
// The restored text stays selected, so re-marking it as math without
135+
// reselecting should round-trip straight back to the math object.
136+
await editor.clickBlockToolbarButton( 'More' );
137+
await page.getByRole( 'menuitem', { name: 'Math' } ).click();
138+
139+
expect( await editor.getBlocks() ).toMatchObject( [
140+
{
141+
name: 'core/paragraph',
142+
attributes: {
143+
content:
144+
'equation: <math data-latex="x^2"><semantics><msup><mi>x</mi><mn>2</mn></msup><annotation encoding="application/x-tex">x^2</annotation></semantics></math>',
145+
},
146+
},
147+
] );
148+
} );
91149
} );

0 commit comments

Comments
 (0)