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

Images in strings serialized by serializeHtml are displayed too small #3021

Open
seanbruce opened this issue Mar 12, 2024 · 1 comment
Open
Labels
bug Something isn't working plugin:serialize-html

Comments

@seanbruce
Copy link

seanbruce commented Mar 12, 2024

Description

When the string serialized by the serializeHtml() function contains img tags, there will be an inline style width:0 on a parent element of the tag. However, this style will cause the image to be displayed too small.

Steps to Reproduce

// https://github.com/udecode/plate/issues/2804#issuecomment-1931065187
const excludedSelectionPlugin = plugins?.filter(
  (plugin) => plugin.key !== "blockSelection"
);

const tmpEditor = createPlateEditor({ plugins: excludedSelectionPlugin });

interface ContentEditorProps {
  raw: Value;
  onContentUpdate: (raw: Value, html: string) => void;
}

function ContentEditor({ raw, onContentUpdate }: ContentEditorProps) {
  const [editorState, setEditorState] = React.useState<Value>([]);

  const handleSaveContent = () => {
    const html = serializeHtml(tmpEditor, {
      nodes: editorState,
      dndWrapper: (props) => <DndProvider backend={HTML5Backend} {...props} />,
    });
    onContentUpdate(editorState, html);
  };
  return (
    <>
      <RichTextEditor
        onEditorValueChange={setEditorState}
        initialValue={raw}
      />
      <Button className="my-4" onClick={handleSaveContent}>
        save
      </Button>
    </>
  );
}

I use the onContentUpdate function to save data to the database. The raw variable is the original state of the editor, and the html variable is the serialized string of the editor content, which is used to display directly on the page. The data in raw can be used to restore the editor state normally after being read from the API, but the img elements in the serialized html have incorrect inline styles, which causes the images to be displayed too small.

<div class="slate-img"><figure contenteditable="false"><div style="position:relative"><div style="width:0;min-width:92px;max-width:100%;position:relative"><div></div><img src="https://localhost:44392/api/cms-kit/media/9c6dc7ab-07d0-b34d-d549-3a112dffb475" draggable="true" alt="" style="\n"><div></div></div></div></figure></div>

Sandbox

Expected Behavior

The size of images edited in the editor should be the same as the size displayed on the page.

Environment

  • slate: "0.102.0"
  • slate-react: "0.102.0"
  • browser: brave

Bounty

Click here to add a bounty via Algora.

Funding

  • You can sponsor this specific effort via a Polar.sh pledge below
  • We receive the pledge once the issue is completed & verified
Fund with Polar
@seanbruce seanbruce added the bug Something isn't working label Mar 12, 2024
@seanbruce
Copy link
Author

seanbruce commented Mar 14, 2024

I found a code snippet that I think might be causing the bug.
https://github.com/udecode/plate/blob/304fc1ae7b7654008fddf444dfd9a3743cb3b28e/packages/resizable/src/components/Resizable.tsx#L28C1-L67C3

export const useResizableState = ({
  align = 'center',
  minWidth = 92,
  maxWidth = '100%',
}: ResizableOptions = {}) => {
  const element = useElement<TResizableElement>();
  const editor = useEditorRef();

  const nodeWidth = element?.width ?? '100%';

  const [width, setWidth] = useResizableStore().use.width();

  const setNodeWidth = React.useCallback(
    (w: number) => {
      const path = findNodePath(editor, element!);
      if (!path) return;

      if (w === nodeWidth) {
        // Focus the node if not resized
        select(editor, path);
      } else {
        setNodes<TResizableElement>(editor, { width: w }, { at: path });
      }
    },
    [editor, element, nodeWidth]
  );

  React.useEffect(() => {
    setWidth(nodeWidth);
  }, [nodeWidth, setWidth]);

  return {
    align,
    minWidth,
    maxWidth,
    setNodeWidth,
    setWidth,
    width,
  };
};
import React from 'react';
import { createAtomStore } from '@udecode/plate-common';

export const { resizableStore, useResizableStore, ResizableProvider } =
  createAtomStore(
    {
      width: 0 as React.CSSProperties['width'],
    },
    { name: 'resizable' }
  );

When I serialize the editor state to HTML, the value of nodeWidth is the width of the element, or 100% if I have not resize the element, but

useResizableStore always create store with default width value 0, in server rendering, useEffect won't fire. so 0 is the final value get render to static string

To summarize, when I call serializeHtml, and serializeHtml calls renderToStaticMarkup, the rendered image width will always be 0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working plugin:serialize-html
Projects
None yet
Development

No branches or pull requests

2 participants