arnog / mathlive

A web component for easy math input
https://cortexjs.io/mathlive
MIT License
1.56k stars 277 forks source link

Macros not available at MFE instantiation #2353

Open AllyMarthaJ opened 5 months ago

AllyMarthaJ commented 5 months ago

Description

Macros are not available at MathfieldElement instantiation.

This means that if creating a MathfieldElement programmatically and injecting it into the page at a later time, we erase any pre-existing macros.

Steps to Reproduce

Minimal, reproducible example:

import { MathfieldElement } from "mathlive"; // Using something like webpack

function createMfe() {
    const mf = MathfieldElement();
    mf.macros = { ...mf.macros, sf: { args: 1, def: "\\mathsf{#1}", captureSelection: false } };
}

document.body.appendChild(createMfe());

Codepen: https://codepen.io/ladyally/pen/NWmLmro

I can get around this by deferring macro setting to the next frame.

Work around: https://codepen.io/ladyally/pen/VwNGNKr

Actual Behavior

Observe that macros such as \imaginaryI does not work, but \sf{x} does (for example).

Expected Behavior

I would expect pre-existing macros to be loaded before assigning new ones. Or, at the very least, being able to set macros at instantiation in addition to any ones which will be loaded further on.

Environment

Is this a regression: did it use to work in a previous version?

MathLive version : 0.95.0. Replicable on latest mathlive (per the codepen!).

Operating System macOS 13.2.1

Browser Chrome

arnog commented 5 months ago

That's an interesting issue. Before the element is attached to the DOM, there are some limitations, and this is currently one of them. See the description of the lifecycle: https://cortexjs.io/mathlive/guides/lifecycle/

In general, the recommendation is to listen for the mount event and do the customization of the mathfield from within that event handler.

I'll try to see if this can be improved...

AllyMarthaJ commented 5 months ago

Ahhh right, okay! That makes sense; most of the examples in the documentation sort of depend on that implicitly I suppose.

arnog commented 5 months ago

Yes, the examples in the doc have been carefully chosen. Before the component is mounted, if some properties are modified, they are stored aside, then reapplied when the component is finally mounted. This doesn’t work for properties like macros that require being able to read the current value as well.

Maybe it would be better to just throw if any properties are read or modified. before the component is mounted and require those changes to be made in the mount handler?

AllyMarthaJ commented 5 months ago

Maybe it would be better to just throw if any properties are read or modified. before the component is mounted and require those changes to be made in the mount handler?

Yup, I think that works. Either way it's good to know 🙂

AllyMarthaJ commented 3 months ago

Noting something else I discovered for posterity: a bug wherein if you set the content of the mathfield before it's mounted, and then instantiate the config on mount then some weird stuff with braces occurs. At a glance: set the content to \placeholder, configure on mount, and then typing ( will insert ()( instead. e.g.

image

Not that it's a problem, because setting the content after it's mounted also fixes the issue. So...that was fun.

arnog commented 3 months ago

@AllyMarthaJ maybe it doesn't matter much, but I've tried to reproduce this issue and have not had much luck. You wouldn't happen to have a CodePen that illustrates the problem?

AllyMarthaJ commented 3 months ago

@arnog I've got one for you here: https://codepen.io/ladyally/pen/wvbrxmN

What I realised when coming up with this example is that there's an additional call to focus. Without the call to focus, this doesn't occur. My bad, sorry!

Just for posterity I added a delay so it's easier to focus on the codepen iframe before the mathfield loads. It's not necessary to repro the bug.

screambeard commented 3 months ago

I would like to pitch in on this issue as well. We ran into this problem when upgrading from 0.98.6. I can make a new issue, but i think this is related to the same underlying cause.

We do the following:

This worked fine up to version 0.98.6. However, from version 0.99.0 on (and thus also in 0.100.0) we have the following issue:

Since this is a regression from the previous version I would like to see if we can fix this and allow again to set macros before adding anything to the dom. This allows for configuring the mathfield before allowing a user to interact instead of having to wait for it to be available in the DOM.

To show this I've created the following three CodePens:

In addition, a separate issue arises in version 0.100.0 when having to set the macros after the mathfield has been added to the DOM: it causes focus on the (last) mathfield. See this new issue regarding that problem: https://github.com/arnog/mathlive/issues/2427

arnog commented 3 months ago

@screambeard Thanks for the detailed report. I think the issue of updating after mount and the mathfield not refreshing is fixed in the unreleased version, but I'll double-check.

The issue with setting macros before mount is that the default macros are not available at that time. So you can override the macros, but you can't add to them.

Changing lifecycle so that macros can be modified (and read) before mount is not trivial, but I'll look into it.

screambeard commented 3 months ago

@arnog thanks for the explanation. The only thing I'm a bit confused by is why this changed from 0.98.6 to 0.99.0? Because we were able to add macros before mounting in version 0.98.6.

I think the key blocker for upgrading for us at this moment is the other issue regarding the focus on mathfield when updating the macros: https://github.com/arnog/mathlive/issues/2427.

Let me know if I can help you with anything.