lexical icon indicating copy to clipboard operation
lexical copied to clipboard

How to keep styles between lines?

Open nickschinestzki opened this issue 10 months ago • 6 comments

Lexical version: 0.14.5

The current behavior

As mentioned in #5620, I am looking for a way to keep both formats and styles between lines. There was an update in #5822 with logic to persist formats (bold, italic, underline) between paragraphs and it works great. One part of the issue remains that I can't persist CSS styles in new paragraphs.

So in my use case, if the user selects a "body" font family different than the default one, or maybe a different text color, he needs to reapply them in every new paragraph after an empty line (See #5620 to understand this).

The expected behavior

When user breaks no matter how much lines, the CSS styles applied to a paragraph persist between lines.

Attempt to fix the issue

As an attempt to address this, I have created a CustomParagraphNode which is generating a new performance problem.

import { $applyNodeReplacement, ParagraphNode } from 'lexical';
import { $patchStyleText } from '@lexical/selection';

export class CustomParagraphNode extends ParagraphNode {
  constructor(cssStyle, key) {
    super(key);
    this.__cssStyle = cssStyle;
  }
  static getType() {
    return 'custom-paragraph';
  }
  getCssStyle() {
    const self = this.getLatest();
    return self.__cssStyle;
  }
  setCssStyle(style) {
    const self = this.getWritable();
    self.__cssStyle = style;
    return self;
  }

  static clone(node) {
    return new CustomParagraphNode(node.__cssStyle, node.__key);
  }

  // View
  static importJSON(serializedNode) {
    const node = $createCustomParagraphNode(serializedNode.cssStyle);
    node.setFormat(serializedNode.format);
    node.setIndent(serializedNode.indent);
    node.setDirection(serializedNode.direction);
    node.setTextFormat(serializedNode.textFormat);
    node.setCssStyle(serializedNode.cssStyle);
    return node;
  }

  createDOM(config) {
    const element = super.createDOM(config);
    element.style.cssText = this.__cssStyle;
    return element;
  }

  exportJSON() {
    return {
      ...super.exportJSON(),
      cssStyle: this.getCssStyle(),
      textFormat: this.getTextFormat(),
      type: 'custom-paragraph',
      version: 1,
    };
  }

  // Mutation

  insertNewAfter(rangeSelection, restoreSelection) {
    const newElement = $createCustomParagraphNode(rangeSelection.style);
    newElement.setTextFormat(rangeSelection.format);
    newElement.setCssStyle(rangeSelection.style);
    const direction = this.getDirection();
    newElement.setDirection(direction);
    newElement.setFormat(this.getFormatType());
    this.insertAfter(newElement, restoreSelection);
    $patchStyleText(rangeSelection, rangeSelection.style);
    return newElement;
  }
}

function $createCustomParagraphNode(cssStyle = '') {
  return new CustomParagraphNode(cssStyle);
}

The $patchStyleText(rangeSelection, rangeSelection.style) line is what reinstate the selection to keep having the same style, but that creates a performance issue that after creating some lines, the application will totally freeze.

nickschinestzki avatar Apr 24 '24 17:04 nickschinestzki

Have you tried using the example from the docs for the extendedTextNode: https://lexical.dev/docs/concepts/serialization#handling-extended-html-styling

ivailop7 avatar Apr 24 '24 21:04 ivailop7

This doesn't seem to solve the issue. I'm now trying to create some solution to apply the new "cssStyle" parameter that I created on CustomParagraphNode to apply to this ExtendedTextNode on creation, but I don't know if that's the right way of doing it.

nickschinestzki avatar Apr 30 '24 19:04 nickschinestzki

Hey @trueadm is it possible to give some attention to this issue? It seems like an important issue from a use-case and developers demand point of view. There's a discussion on discord about this: https://discord.com/channels/953974421008293909/1210630834458206312

nickschinestzki avatar May 06 '24 13:05 nickschinestzki

Hey @trueadm is it possible to give some attention to this issue? It seems like an important issue from a use-case and developers demand point of view. There's a discussion on discord about this: https://discord.com/channels/953974421008293909/1210630834458206312

Trueadm is no longer working on Lexical.

Regarding your use case, I think that a PR was recently merged that should help. Not sure if it has already been released or not.

moy2010 avatar May 07 '24 22:05 moy2010

Hey @trueadm is it possible to give some attention to this issue? It seems like an important issue from a use-case and developers demand point of view. There's a discussion on discord about this: https://discord.com/channels/953974421008293909/1210630834458206312

Trueadm is no longer working on Lexical.

Regarding your use case, I think that a PR was recently merged that should help. Not sure if it has already been released or not.

Are you talking about this PR? It certainly is an advance on this matter. But the issue is that it only persists the formatting (bold, italic, underline, etc) between paragraphs. Any very common use cases of persisting styles (font-family, color, font-size, etc) will be lost between spaced paragraphs.

nickschinestzki avatar May 08 '24 02:05 nickschinestzki

Are you talking about this PR?

Yep, that one. Now I see that it doesn't maintain the styles across paragraphs, thanks for pointing that out.

moy2010 avatar May 09 '24 17:05 moy2010