lexical icon indicating copy to clipboard operation
lexical copied to clipboard

Feature: paragraphNode should apply configured indent value from theme on exportDOM

Open 2wheeh opened this issue 1 year ago • 2 comments

from exportDOM

image

from reconciler

image

element returned from exportDOM of paragraphNode doesn't have indent class from theme and doesn't apply configured indentation base value as well.

instead, it always has 20px as indentation value which makes difference between generated html and contenteditable.

Should this exported element have indent class from theme and also same indent value as configured in indent class ?

2wheeh avatar May 10 '24 23:05 2wheeh

What i understand:

  1. When importing, 20px seems to be set considering to pasting HTML with a small base indent size. https://github.com/facebook/lexical/blob/157b77c2d84fb47aa85f98171e4285b284c26abc/packages/lexical/src/nodes/LexicalParagraphNode.ts#L197
  2. For consistency between exporting and importing, we are setting 20px text-indent on exporting as well. https://github.com/facebook/lexical/blob/157b77c2d84fb47aa85f98171e4285b284c26abc/packages/lexical/src/nodes/LexicalParagraphNode.ts#L126
  3. However, the default indent size when creating DOM is 40px. https://github.com/facebook/lexical/blob/157b77c2d84fb47aa85f98171e4285b284c26abc/packages/lexical/src/LexicalReconciler.ts#L122
  4. Pasting HTML copied from the same editor (same namespace) doesn't trigger importDOM, which is utilized for HTML strings copied from outside sources. https://github.com/facebook/lexical/blob/157b77c2d84fb47aa85f98171e4285b284c26abc/packages/lexical-clipboard/src/clipboard.ts#L134
  5. Thus, the situation here: ensuring (A) consistency between exporting and importing for outside the editor vs (B) consistency between creating and exporting from within the editor.

Personally, I lean towards (B) since it ensures the same result for the same editor state source but (A) is for outside sources.

2wheeh avatar May 11 '24 10:05 2wheeh

For someone who needs this, you can utilize HTML config as a workaround.

for example:

const htmlConfig: HTMLConfig = {
  export: new Map([
    [
      ParagraphNode,
      (editor, node) => {
        const targetNode = node as ParagraphNode;
        const element = document.createElement('p');

        if (element && isHTMLElement(element)) {
          if (targetNode.isEmpty()) {
            element.append(document.createElement('br'));
          }

          const formatType = targetNode.getFormatType();
          element.style.textAlign = formatType;

          const direction = targetNode.getDirection();
          if (direction) {
            element.dir = direction;
          }
          const indent = targetNode.getIndent();
          setElementIndent(element, indent, editor._config.theme.indent);
        }

        return {
          element,
        };
      },
    ],
  ]),
};

const DEFAULT_INDENT_VALUE = '40px';

function setElementIndent(dom: HTMLElement, indent: number, indentClassName?: string): void {
  if (indent < 1) {
    return;
  }

  if (typeof indentClassName === 'string') {
    dom.classList.add(indentClassName);
  }

  const indentationBaseValue =
    window.getComputedStyle(dom).getPropertyValue('--lexical-indent-base-value') ||
    DEFAULT_INDENT_VALUE;

  dom.style.setProperty(
    // padding-inline-start is not widely supported in email HTML, but
    // Lexical Reconciler uses padding-inline-start. Using text-indent instead.
    'text-indent',
    `${indent * parseInt(indentationBaseValue, 10)}px`
  );
}

2wheeh avatar May 11 '24 17:05 2wheeh