Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: Block math equation is falsely converted to inline equation on MarkdownShortcutPlugin #6936

Open
MaxHamscher opened this issue Dec 10, 2024 · 5 comments · May be fixed by #7214
Open

Bug: Block math equation is falsely converted to inline equation on MarkdownShortcutPlugin #6936

MaxHamscher opened this issue Dec 10, 2024 · 5 comments · May be fixed by #7214
Labels

Comments

@MaxHamscher
Copy link

Typing an equation like "$$x^2 + y^2 = z^2$$" via "Insert Equation" and then pressing the MarkdownShortcutPlugin changes the equation to inline ($...$).

Lexical version: Current Playground version

Steps To Reproduce

  1. Enter an equation, e.g. "x^2 + y^2 = z^2" via the toolbar (Insert -> Insert Equation) and uncheck "inline".
  2. Press the Markdown button

Link to code example: https://playground.lexical.dev/

The current behavior

Block math equations like "$$...$$" are converted to inline "$...$" when using the ##MarkdownShortcutPlugin.

The expected behavior

Block math equations like "$$...$$" should stay the same when using the MarkdownShortcutPlugin.

Potential Solutions

Possibly quick: A new BLOCK_EQUATION transformer could be added to address the "$$" scenario. MarkdownTransformers
Way more complicated: One might migrate "$, $$" in general to modern LaTex syntax like "[...]"

Impact of fix

Users who rely on markdown capabilities are type safe with equations.

@vantage-ola
Copy link
Contributor

I may be wrong but I dont think there is a need for a new transformer... The issue might stem from EQUATION only handling inline. if its possible to accommodate both inline and block.

i tried to rewrite the EQUATION but it seems buggy and crashed the playground editor lol.

export const EQUATION: TextMatchTransformer = {
  dependencies: [EquationNode],
  export: (node) => {
    if (!$isEquationNode(node)) {
      return null;
    }

    const equation = node.getEquation();
    const isInline = node.isInline();
    return isInline ? `$${equation}$` : `$$${equation}$$`;
  },
  importRegExp: /\$([^$]+?)\$|\$\$([^$]+?)\$\$/,
  regExp: /\$([^$]+?)\$$|\$\$([^$]+?)\$\$$/,
  replace: (textNode, match) => {
    const [, inlineEquation, blockEquation] = match;
    const equation = inlineEquation || blockEquation;
    const isInline = !!inlineEquation;
    const equationNode = $createEquationNode(equation, isInline);
    textNode.replace(equationNode);
  },
  trigger: '$',
  type: 'text-match',
};

@etrepum
Copy link
Collaborator

etrepum commented Dec 14, 2024

I agree that a single transformer could probably handle both cases, but it needs to be implemented correctly. I would recommend writing up some unit tests, it's probably an issue with your regexes (it usually is, that syntax is tricky).

@nmzabith
Copy link

nmzabith commented Feb 18, 2025

@etrepum I hope following code resolves your issue

export const EQUATION: TextMatchTransformer = {
  dependencies: [EquationNode],
  export: (node) => {
    if (!$isEquationNode(node)) {
      return null;
    }
    const equation = node.getEquation().trim();
    const isInline = node.isInline();
    
    // For block equations, ensure proper spacing
    if (!isInline) {
      return `\n\$\$\n${equation}\n\$\$\n`;
    }
    
    // For inline equations, keep them in the same line
    return `\$\{equation\}\$`;
  },
  // Modified regex to better handle both inline and block equations
  importRegExp: /\$\$([^$]+?)\$\$|\$([^$\n]+?)\$/,
  regExp: /(\$\$([^$]+?)\$\$|\$([^$\n]+?)\$)$/,
  replace: (textNode, match) => {
    const fullMatch = match[0];
    const blockEq = match[1];
    const inlineEq = match[2];
    
    // If the equation has $$ it's a block equation
    const isBlock = fullMatch.startsWith('$$') && fullMatch.endsWith('$$');
    const equation = isBlock ? blockEq : inlineEq;

    if (!equation) {
      return;
    }

    const equationNode = $createEquationNode(equation.trim(), !isBlock);
    textNode.replace(equationNode);
  },
  trigger: '$',
  type: 'text-match',
};

@etrepum
Copy link
Collaborator

etrepum commented Feb 18, 2025

If you’d like to have that included in lexical you should submit a PR

@nmzabith
Copy link

Sure, i'll make a PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment