diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 23625a0..660d921 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -14,6 +14,7 @@ jobs:
strategy:
matrix:
node-version: [22, 24]
+ react-version: [18, 19]
steps:
- uses: actions/checkout@v7
- uses: actions/setup-node@v7
@@ -21,6 +22,8 @@ jobs:
node-version: ${{ matrix.node-version }}
cache: yarn
- run: yarn install --frozen-lockfile --ignore-scripts
+ - if: matrix.react-version != 19
+ run: yarn add --dev --ignore-scripts react@^${{ matrix.react-version }} react-dom@^${{ matrix.react-version }}
- run: yarn lint
- run: yarn prettier:check
- run: yarn build-and-test
diff --git a/package.json b/package.json
index 7682a1c..e31049d 100644
--- a/package.json
+++ b/package.json
@@ -38,8 +38,8 @@
"license": "Apache-2.0",
"peerDependencies": {
"draft-js": ">=0.7.0",
- "react": "^15.0.2 || ^16.0.0-rc || ^16.0.0 || ^17.0.0 || ^18.0.0",
- "react-dom": "^15.0.2 || ^16.0.0-rc || ^16.0.0 || ^17.0.0 || ^18.0.0"
+ "react": "^15.0.2 || ^16.0.0-rc || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
+ "react-dom": "^15.0.2 || ^16.0.0-rc || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
},
"dependencies": {
"@babel/runtime": "^7.5.5",
@@ -66,8 +66,8 @@
"jest": "^30.5.2",
"jest-environment-jsdom": "^30.5.2",
"prettier": "^3.9.10",
- "react": "^18.0.0",
- "react-dom": "^18.0.0",
+ "react": "^19.3.1",
+ "react-dom": "^19.3.1",
"rimraf": "^6.1.3",
"rollup": "^4.66.0"
},
diff --git a/src/convertToHTML.js b/src/convertToHTML.js
index df43e6f..edb1db5 100644
--- a/src/convertToHTML.js
+++ b/src/convertToHTML.js
@@ -1,7 +1,7 @@
// import Immutable from 'immutable'; // eslint-disable-line no-unused-vars
import invariant from 'invariant';
import React from 'react';
-import ReactDOMServer from 'react-dom/server';
+import renderToStaticMarkup from './util/renderToStaticMarkup';
import { convertToRaw } from 'draft-js';
import encodeBlock from './encodeBlock';
@@ -124,7 +124,7 @@ const convertToHTML =
Object.prototype.hasOwnProperty.call(blockHTML, 'empty')
) {
if (React.isValidElement(blockHTML.empty)) {
- html = ReactDOMServer.renderToStaticMarkup(blockHTML.empty);
+ html = renderToStaticMarkup(blockHTML.empty);
} else {
html = blockHTML.empty;
}
diff --git a/src/util/getBlockTags.js b/src/util/getBlockTags.js
index 45564b5..71c706b 100644
--- a/src/util/getBlockTags.js
+++ b/src/util/getBlockTags.js
@@ -1,6 +1,6 @@
import invariant from 'invariant';
import React from 'react';
-import ReactDOMServer from 'react-dom/server';
+import renderToStaticMarkup from './renderToStaticMarkup';
import splitReactElement from './splitReactElement';
function hasChildren(element) {
@@ -22,7 +22,7 @@ export default function getBlockTags(blockHTML) {
if (React.isValidElement(blockHTML)) {
if (hasChildren(blockHTML)) {
- return ReactDOMServer.renderToStaticMarkup(blockHTML);
+ return renderToStaticMarkup(blockHTML);
}
return splitReactElement(blockHTML);
diff --git a/src/util/getElementHTML.js b/src/util/getElementHTML.js
index af124d0..de54122 100644
--- a/src/util/getElementHTML.js
+++ b/src/util/getElementHTML.js
@@ -1,6 +1,6 @@
import invariant from 'invariant';
import React from 'react';
-import ReactDOMServer from 'react-dom/server';
+import renderToStaticMarkup from './renderToStaticMarkup';
import splitReactElement from './splitReactElement';
function hasChildren(element) {
@@ -21,7 +21,7 @@ export default function getElementHTML(element, text = null) {
if (React.isValidElement(element)) {
if (hasChildren(element)) {
- return ReactDOMServer.renderToStaticMarkup(element);
+ return renderToStaticMarkup(element);
}
const tags = splitReactElement(element);
diff --git a/src/util/renderToStaticMarkup.js b/src/util/renderToStaticMarkup.js
new file mode 100644
index 0000000..707f527
--- /dev/null
+++ b/src/util/renderToStaticMarkup.js
@@ -0,0 +1,12 @@
+import React from 'react';
+import ReactDOMServer from 'react-dom/server';
+
+const IMAGE_PRELOADS =
+ /]*\/>/g;
+
+const hoistsImagePreloads = parseInt(React.version, 10) >= 19;
+
+export default function renderToStaticMarkup(element) {
+ const html = ReactDOMServer.renderToStaticMarkup(element);
+ return hoistsImagePreloads ? html.replace(IMAGE_PRELOADS, '') : html;
+}
diff --git a/src/util/splitReactElement.js b/src/util/splitReactElement.js
index e1c5183..7389b4b 100644
--- a/src/util/splitReactElement.js
+++ b/src/util/splitReactElement.js
@@ -1,6 +1,6 @@
import invariant from 'invariant';
import React from 'react';
-import ReactDOMServer from 'react-dom/server';
+import renderToStaticMarkup from './renderToStaticMarkup';
// see http://w3c.github.io/html/syntax.html#writing-html-documents-elements
const VOID_TAGS = [
@@ -22,10 +22,10 @@ const VOID_TAGS = [
export default function splitReactElement(element) {
if (VOID_TAGS.indexOf(element.type) !== -1) {
- return ReactDOMServer.renderToStaticMarkup(element);
+ return renderToStaticMarkup(element);
}
- const tags = ReactDOMServer.renderToStaticMarkup(
+ const tags = renderToStaticMarkup(
React.cloneElement(element, {}, '\r')
).split('\r');
diff --git a/test/spec/convertToHTML-test.js b/test/spec/convertToHTML-test.js
index 27d9495..430bf5c 100644
--- a/test/spec/convertToHTML-test.js
+++ b/test/spec/convertToHTML-test.js
@@ -1099,4 +1099,116 @@ describe('convertToHTML', () => {
/missing HTML definition/
);
});
+
+ it('renders images in block HTML without preload links', () => {
+ const contentState = buildContentState([
+ {
+ type: 'atomic',
+ text: ' ',
+ },
+ ]);
+
+ const result = convertToHTML({
+ blockToHTML: {
+ atomic: (
+
+ 
;
+ }
+ return originalText;
+ },
+ })(contentState);
+
+ expect(result).toBe(
+ '

)).toBe(
+ '
'
+ );
+ });
+
+ it('renders a srcSet image without a preload link', () => {
+ expect(
+ renderToStaticMarkup(
+
+ )
+ ).toBe(
+ '
'
+ );
+ });
+
+ it('renders several images without preload links', () => {
+ expect(
+ renderToStaticMarkup(
+
+
+ 
