From cb34a1f456152a6ef9523d9241772eb764553b72 Mon Sep 17 00:00:00 2001
From: Garth Poitras <411908+gpoitch@users.noreply.github.com>
Date: Mon, 8 Aug 2022 09:44:52 -0400
Subject: [PATCH] Support React 18 (#108)
* Support React 18
* adapter
* Run tests in react 17 & 18
* Update the API - conditional imports are messy
* Revert prettier on README
* simplify api
* v0.14.0
---
README.md | 11 ++
demo/index.js | 6 +-
karma.conf.js | 6 +
package-lock.json | 301 ++++++++++++++++++++++++++----------
package.json | 17 +-
src/components/Container.js | 4 +-
src/utils/classToAtom.js | 7 +-
src/utils/classToCard.js | 9 +-
src/utils/react.js | 18 +++
test/setup.js | 5 +-
10 files changed, 288 insertions(+), 96 deletions(-)
create mode 100644 src/utils/react.js
diff --git a/README.md b/README.md
index 6bc6a16..535906e 100644
--- a/README.md
+++ b/README.md
@@ -343,6 +343,17 @@ mobiledoc-specific props:
- `name`: The name of this card.
- `onTeardown`: A callback that can be called when the rendered content is torn down.
+### React 18 Support
+
+ To use custom card & atom components in React 18 without warnings, you can pass a specific ReactDOM version as a prop on the Container:
+
+ ```js
+ import ReactDOM from 'react-dom/client';
+
+ ...;
+ ```
+
+ Notice the React 18 specific import path. Internally, components will render with the new `createRoot` API if available and fallback to the legacy `render` method.
## Development
diff --git a/demo/index.js b/demo/index.js
index a771fba..2c818c3 100644
--- a/demo/index.js
+++ b/demo/index.js
@@ -1,5 +1,5 @@
import React from 'react';
-import ReactDOM from 'react-dom';
+import ReactDOM from 'react-dom/client';
import '../node_modules/mobiledoc-kit/dist/mobiledoc.css';
import * as ReactMobiledoc from 'react-mobiledoc-editor';
@@ -46,6 +46,7 @@ const App = () => {
{...config}
mobiledoc={state}
onChange={setState}
+ ReactDOM={ReactDOM}
>
@@ -57,4 +58,5 @@ const App = () => {
);
};
-ReactDOM.render(, document.getElementById('root'));
+const root = ReactDOM.createRoot(document.getElementById('root'));
+root.render();
diff --git a/karma.conf.js b/karma.conf.js
index b5e7a3a..9f295c6 100644
--- a/karma.conf.js
+++ b/karma.conf.js
@@ -25,6 +25,12 @@ module.exports = function (config) {
resolve: {
alias: {
'react-mobiledoc-editor': __dirname,
+ ...(process.env.REACT_17 && {
+ react: 'react-17',
+ 'react-dom': 'react-dom-17',
+ '@cfaester/enzyme-adapter-react-18':
+ '@wojtekmaj/enzyme-adapter-react-17',
+ }),
},
},
module: {
diff --git a/package-lock.json b/package-lock.json
index 854d9eb..1251948 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,15 +1,15 @@
{
"name": "react-mobiledoc-editor",
- "version": "0.13.1",
+ "version": "0.14.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "react-mobiledoc-editor",
- "version": "0.13.1",
+ "version": "0.14.0",
"license": "BSD-3-Clause",
"dependencies": {
- "prop-types": "^15.7.2"
+ "prop-types": "^15.8.1"
},
"devDependencies": {
"@babel/core": "^7.18.10",
@@ -19,6 +19,7 @@
"@babel/plugin-transform-runtime": "^7.18.10",
"@babel/preset-env": "^7.18.10",
"@babel/preset-react": "^7.18.6",
+ "@cfaester/enzyme-adapter-react-18": "^0.5.1",
"@rollup/plugin-babel": "^5.3.1",
"@rollup/plugin-commonjs": "^22.0.1",
"@rollup/plugin-node-resolve": "^13.3.0",
@@ -48,8 +49,10 @@
"mobiledoc-kit": "^0.14.0",
"mocha": "^10.0.0",
"prettier": "^2.7.1",
- "react": "^17.0.1",
- "react-dom": "^17.0.1",
+ "react": "^18.2.0",
+ "react-17": "npm:react@^17",
+ "react-dom": "^18.2.0",
+ "react-dom-17": "npm:react-dom@^17",
"rimraf": "^3.0.2",
"rollup": "^2.77.2",
"rollup-plugin-auto-external": "^2.0.0",
@@ -63,8 +66,8 @@
},
"peerDependencies": {
"mobiledoc-kit": "^0.12.2 || ^0.13.0 || ^0.14.0",
- "react": "^16.3.0 || ^17.0.0",
- "react-dom": "^16.3.0 || ^17.0.0"
+ "react": "^16.3.0 || ^17.0.0 || ^18.0.0",
+ "react-dom": "^16.3.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/@ampproject/remapping": {
@@ -1865,6 +1868,28 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@cfaester/enzyme-adapter-react-18": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/@cfaester/enzyme-adapter-react-18/-/enzyme-adapter-react-18-0.5.1.tgz",
+ "integrity": "sha512-re27mknhfQsNoBjgn+kD9egD9hCIfb3i6ygzjFcSM2fBKPZFtzBKvtWkGAnzJ7W2fNR8LrCoYtrZtPZc+aUtvg==",
+ "dev": true,
+ "dependencies": {
+ "enzyme-shallow-equal": "^1.0.0",
+ "react-is": "^18.0.0",
+ "react-test-renderer": "^18.0.0"
+ },
+ "peerDependencies": {
+ "enzyme": "^3.0.0",
+ "react": "^18.0.0",
+ "react-dom": "^18.0.0"
+ }
+ },
+ "node_modules/@cfaester/enzyme-adapter-react-18/node_modules/react-is": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
+ "dev": true
+ },
"node_modules/@colors/colors": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
@@ -2610,18 +2635,18 @@
"dev": true
},
"node_modules/@wojtekmaj/enzyme-adapter-react-17/node_modules/react-test-renderer": {
- "version": "17.0.1",
- "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-17.0.1.tgz",
- "integrity": "sha512-/dRae3mj6aObwkjCcxZPlxDFh73XZLgvwhhyON2haZGUEhiaY5EjfAdw+d/rQmlcFwdTpMXCSGVk374QbCTlrA==",
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-17.0.2.tgz",
+ "integrity": "sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ==",
"dev": true,
"dependencies": {
"object-assign": "^4.1.1",
- "react-is": "^17.0.1",
+ "react-is": "^17.0.2",
"react-shallow-renderer": "^16.13.1",
- "scheduler": "^0.20.1"
+ "scheduler": "^0.20.2"
},
"peerDependencies": {
- "react": "17.0.1"
+ "react": "17.0.2"
}
},
"node_modules/@wojtekmaj/enzyme-adapter-utils": {
@@ -4813,17 +4838,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/eslint-plugin-react/node_modules/prop-types": {
- "version": "15.8.1",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
- "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
- "dev": true,
- "dependencies": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.13.1"
- }
- },
"node_modules/eslint-plugin-react/node_modules/resolve": {
"version": "2.0.0-next.3",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz",
@@ -8307,13 +8321,13 @@
"dev": true
},
"node_modules/prop-types": {
- "version": "15.7.2",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
- "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
+ "version": "15.8.1",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
+ "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"dependencies": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
- "react-is": "^16.8.1"
+ "react-is": "^16.13.1"
}
},
"node_modules/proxy-addr": {
@@ -8508,9 +8522,22 @@
}
},
"node_modules/react": {
- "version": "17.0.1",
- "resolved": "https://registry.npmjs.org/react/-/react-17.0.1.tgz",
- "integrity": "sha512-lG9c9UuMHdcAexXtigOZLX8exLWkW0Ku29qPRU8uhF2R9BN96dLCt0psvzPLlHc5OWkgymP3qwTRgbnw5BKx3w==",
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
+ "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
+ "dev": true,
+ "dependencies": {
+ "loose-envify": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/react-17": {
+ "name": "react",
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
+ "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
"dev": true,
"dependencies": {
"loose-envify": "^1.1.0",
@@ -8521,17 +8548,40 @@
}
},
"node_modules/react-dom": {
- "version": "17.0.1",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.1.tgz",
- "integrity": "sha512-6eV150oJZ9U2t9svnsspTMrWNyHc6chX0KzDeAOXftRa8bNeOKTTfCJ7KorIwenkHd2xqVTBTCZd79yk/lx/Ug==",
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
+ "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
+ "dev": true,
+ "dependencies": {
+ "loose-envify": "^1.1.0",
+ "scheduler": "^0.23.0"
+ },
+ "peerDependencies": {
+ "react": "^18.2.0"
+ }
+ },
+ "node_modules/react-dom-17": {
+ "name": "react-dom",
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
+ "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
"dev": true,
"dependencies": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
- "scheduler": "^0.20.1"
+ "scheduler": "^0.20.2"
},
"peerDependencies": {
- "react": "17.0.1"
+ "react": "17.0.2"
+ }
+ },
+ "node_modules/react-dom/node_modules/scheduler": {
+ "version": "0.23.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
+ "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
+ "dev": true,
+ "dependencies": {
+ "loose-envify": "^1.1.0"
}
},
"node_modules/react-is": {
@@ -8540,16 +8590,45 @@
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"node_modules/react-shallow-renderer": {
- "version": "16.14.1",
- "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.14.1.tgz",
- "integrity": "sha512-rkIMcQi01/+kxiTE9D3fdS959U1g7gs+/rborw++42m1O9FAQiNI/UNRZExVUoAOprn4umcXf+pFRou8i4zuBg==",
+ "version": "16.15.0",
+ "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz",
+ "integrity": "sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==",
"dev": true,
"dependencies": {
"object-assign": "^4.1.1",
- "react-is": "^16.12.0 || ^17.0.0"
+ "react-is": "^16.12.0 || ^17.0.0 || ^18.0.0"
+ },
+ "peerDependencies": {
+ "react": "^16.0.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
+ "node_modules/react-test-renderer": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-18.2.0.tgz",
+ "integrity": "sha512-JWD+aQ0lh2gvh4NM3bBM42Kx+XybOxCpgYK7F8ugAlpaTSnWsX+39Z4XkOykGZAHrjwwTZT3x3KxswVWxHPUqA==",
+ "dev": true,
+ "dependencies": {
+ "react-is": "^18.2.0",
+ "react-shallow-renderer": "^16.15.0",
+ "scheduler": "^0.23.0"
},
"peerDependencies": {
- "react": "^16.0.0 || ^17.0.0"
+ "react": "^18.2.0"
+ }
+ },
+ "node_modules/react-test-renderer/node_modules/react-is": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
+ "dev": true
+ },
+ "node_modules/react-test-renderer/node_modules/scheduler": {
+ "version": "0.23.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
+ "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
+ "dev": true,
+ "dependencies": {
+ "loose-envify": "^1.1.0"
}
},
"node_modules/read-pkg": {
@@ -8950,9 +9029,9 @@
"dev": true
},
"node_modules/scheduler": {
- "version": "0.20.1",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.1.tgz",
- "integrity": "sha512-LKTe+2xNJBNxu/QhHvDR14wUXHRQbVY5ZOYpOGWRzhydZUqrLb2JBvLPY7cAqFmqrWuDED0Mjk7013SZiOz6Bw==",
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
+ "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
"dev": true,
"dependencies": {
"loose-envify": "^1.1.0",
@@ -11958,6 +12037,25 @@
"to-fast-properties": "^2.0.0"
}
},
+ "@cfaester/enzyme-adapter-react-18": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/@cfaester/enzyme-adapter-react-18/-/enzyme-adapter-react-18-0.5.1.tgz",
+ "integrity": "sha512-re27mknhfQsNoBjgn+kD9egD9hCIfb3i6ygzjFcSM2fBKPZFtzBKvtWkGAnzJ7W2fNR8LrCoYtrZtPZc+aUtvg==",
+ "dev": true,
+ "requires": {
+ "enzyme-shallow-equal": "^1.0.0",
+ "react-is": "^18.0.0",
+ "react-test-renderer": "^18.0.0"
+ },
+ "dependencies": {
+ "react-is": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
+ "dev": true
+ }
+ }
+ },
"@colors/colors": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
@@ -12610,15 +12708,15 @@
"dev": true
},
"react-test-renderer": {
- "version": "17.0.1",
- "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-17.0.1.tgz",
- "integrity": "sha512-/dRae3mj6aObwkjCcxZPlxDFh73XZLgvwhhyON2haZGUEhiaY5EjfAdw+d/rQmlcFwdTpMXCSGVk374QbCTlrA==",
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-17.0.2.tgz",
+ "integrity": "sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ==",
"dev": true,
"requires": {
"object-assign": "^4.1.1",
- "react-is": "^17.0.1",
+ "react-is": "^17.0.2",
"react-shallow-renderer": "^16.13.1",
- "scheduler": "^0.20.1"
+ "scheduler": "^0.20.2"
}
}
}
@@ -14446,17 +14544,6 @@
"es-abstract": "^1.19.1"
}
},
- "prop-types": {
- "version": "15.8.1",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
- "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
- "dev": true,
- "requires": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.13.1"
- }
- },
"resolve": {
"version": "2.0.0-next.3",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz",
@@ -16882,13 +16969,13 @@
"dev": true
},
"prop-types": {
- "version": "15.7.2",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz",
- "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==",
+ "version": "15.8.1",
+ "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
+ "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"requires": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
- "react-is": "^16.8.1"
+ "react-is": "^16.13.1"
}
},
"proxy-addr": {
@@ -17034,9 +17121,18 @@
}
},
"react": {
- "version": "17.0.1",
- "resolved": "https://registry.npmjs.org/react/-/react-17.0.1.tgz",
- "integrity": "sha512-lG9c9UuMHdcAexXtigOZLX8exLWkW0Ku29qPRU8uhF2R9BN96dLCt0psvzPLlHc5OWkgymP3qwTRgbnw5BKx3w==",
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
+ "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
+ "dev": true,
+ "requires": {
+ "loose-envify": "^1.1.0"
+ }
+ },
+ "react-17": {
+ "version": "npm:react@17.0.2",
+ "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
+ "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
"dev": true,
"requires": {
"loose-envify": "^1.1.0",
@@ -17044,14 +17140,35 @@
}
},
"react-dom": {
- "version": "17.0.1",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.1.tgz",
- "integrity": "sha512-6eV150oJZ9U2t9svnsspTMrWNyHc6chX0KzDeAOXftRa8bNeOKTTfCJ7KorIwenkHd2xqVTBTCZd79yk/lx/Ug==",
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
+ "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
+ "dev": true,
+ "requires": {
+ "loose-envify": "^1.1.0",
+ "scheduler": "^0.23.0"
+ },
+ "dependencies": {
+ "scheduler": {
+ "version": "0.23.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
+ "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
+ "dev": true,
+ "requires": {
+ "loose-envify": "^1.1.0"
+ }
+ }
+ }
+ },
+ "react-dom-17": {
+ "version": "npm:react-dom@17.0.2",
+ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
+ "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
"dev": true,
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1",
- "scheduler": "^0.20.1"
+ "scheduler": "^0.20.2"
}
},
"react-is": {
@@ -17060,13 +17177,41 @@
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"react-shallow-renderer": {
- "version": "16.14.1",
- "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.14.1.tgz",
- "integrity": "sha512-rkIMcQi01/+kxiTE9D3fdS959U1g7gs+/rborw++42m1O9FAQiNI/UNRZExVUoAOprn4umcXf+pFRou8i4zuBg==",
+ "version": "16.15.0",
+ "resolved": "https://registry.npmjs.org/react-shallow-renderer/-/react-shallow-renderer-16.15.0.tgz",
+ "integrity": "sha512-oScf2FqQ9LFVQgA73vr86xl2NaOIX73rh+YFqcOp68CWj56tSfgtGKrEbyhCj0rSijyG9M1CYprTh39fBi5hzA==",
"dev": true,
"requires": {
"object-assign": "^4.1.1",
- "react-is": "^16.12.0 || ^17.0.0"
+ "react-is": "^16.12.0 || ^17.0.0 || ^18.0.0"
+ }
+ },
+ "react-test-renderer": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-18.2.0.tgz",
+ "integrity": "sha512-JWD+aQ0lh2gvh4NM3bBM42Kx+XybOxCpgYK7F8ugAlpaTSnWsX+39Z4XkOykGZAHrjwwTZT3x3KxswVWxHPUqA==",
+ "dev": true,
+ "requires": {
+ "react-is": "^18.2.0",
+ "react-shallow-renderer": "^16.15.0",
+ "scheduler": "^0.23.0"
+ },
+ "dependencies": {
+ "react-is": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
+ "dev": true
+ },
+ "scheduler": {
+ "version": "0.23.0",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
+ "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
+ "dev": true,
+ "requires": {
+ "loose-envify": "^1.1.0"
+ }
+ }
}
},
"read-pkg": {
@@ -17372,9 +17517,9 @@
"dev": true
},
"scheduler": {
- "version": "0.20.1",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.1.tgz",
- "integrity": "sha512-LKTe+2xNJBNxu/QhHvDR14wUXHRQbVY5ZOYpOGWRzhydZUqrLb2JBvLPY7cAqFmqrWuDED0Mjk7013SZiOz6Bw==",
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
+ "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
"dev": true,
"requires": {
"loose-envify": "^1.1.0",
diff --git a/package.json b/package.json
index 9ad4b9f..b727dd6 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "react-mobiledoc-editor",
- "version": "0.13.1",
+ "version": "0.14.0",
"description": "A Mobiledoc editor for React apps",
"repository": "joshfrench/react-mobiledoc-editor",
"homepage": "https://github.com/joshfrench/react-mobiledoc-editor",
@@ -28,7 +28,7 @@
"start": "concurrently \"npm:start:demo\" \"npm:build:watch\"",
"start:demo": "webpack-dev-server --mode development --hot --config webpack.demo.config.js",
"lint": "eslint src",
- "test": "npm run test:build && karma start --single-run",
+ "test": "npm run test:build && karma start --single-run && REACT_17=true karma start --single-run",
"test:watch": "concurrently \"karma start\" \"npm:build:watch\"",
"test:build": "npm run build && mocha test/build",
"posttest": "npm run lint && npm run format:check",
@@ -40,12 +40,12 @@
"prepublishOnly": "npm run build"
},
"dependencies": {
- "prop-types": "^15.7.2"
+ "prop-types": "^15.8.1"
},
"peerDependencies": {
"mobiledoc-kit": "^0.12.2 || ^0.13.0 || ^0.14.0",
- "react": "^16.3.0 || ^17.0.0",
- "react-dom": "^16.3.0 || ^17.0.0"
+ "react": "^16.3.0 || ^17.0.0 || ^18.0.0",
+ "react-dom": "^16.3.0 || ^17.0.0 || ^18.0.0"
},
"devDependencies": {
"@babel/core": "^7.18.10",
@@ -55,6 +55,7 @@
"@babel/plugin-transform-runtime": "^7.18.10",
"@babel/preset-env": "^7.18.10",
"@babel/preset-react": "^7.18.6",
+ "@cfaester/enzyme-adapter-react-18": "^0.5.1",
"@rollup/plugin-babel": "^5.3.1",
"@rollup/plugin-commonjs": "^22.0.1",
"@rollup/plugin-node-resolve": "^13.3.0",
@@ -84,8 +85,10 @@
"mobiledoc-kit": "^0.14.0",
"mocha": "^10.0.0",
"prettier": "^2.7.1",
- "react": "^17.0.1",
- "react-dom": "^17.0.1",
+ "react": "^18.2.0",
+ "react-17": "npm:react@^17",
+ "react-dom": "^18.2.0",
+ "react-dom-17": "npm:react-dom@^17",
"rimraf": "^3.0.2",
"rollup": "^2.77.2",
"rollup-plugin-auto-external": "^2.0.0",
diff --git a/src/components/Container.js b/src/components/Container.js
index 79328e5..c844d41 100644
--- a/src/components/Container.js
+++ b/src/components/Container.js
@@ -31,6 +31,7 @@ class Container extends React.Component {
placeholder,
serializeVersion,
spellcheck,
+ ReactDOM,
} = this.props;
const mobiledoc =
this.props.mobiledoc || (html ? undefined : EMPTY_MOBILEDOC);
@@ -39,7 +40,7 @@ class Container extends React.Component {
...this.props.options,
atoms,
autofocus,
- cardOptions: { cardProps },
+ cardOptions: { cardProps, ReactDOM },
cards,
html,
mobiledoc,
@@ -87,6 +88,7 @@ class Container extends React.Component {
spellcheck,
willCreateEditor,
onChange,
+ ReactDOM,
...componentProps
} = this.props;
/* eslint-enable no-unused-vars */
diff --git a/src/utils/classToAtom.js b/src/utils/classToAtom.js
index 5f2fde2..e9781bc 100644
--- a/src/utils/classToAtom.js
+++ b/src/utils/classToAtom.js
@@ -1,10 +1,11 @@
import React from 'react';
-import ReactDOM from 'react-dom';
+import { reactDomRender, reactDomUnmount } from './react';
const atomRenderer =
(component) =>
({ env, options, payload, value }) => {
const { onTeardown } = env;
+ const { ReactDOM } = options;
const element = React.createElement(component, {
...env,
@@ -14,9 +15,9 @@ const atomRenderer =
});
const targetNode = document.createElement('span');
- ReactDOM.render(element, targetNode);
+ const root = reactDomRender(ReactDOM, element, targetNode);
- onTeardown(() => ReactDOM.unmountComponentAtNode(targetNode));
+ onTeardown(() => reactDomUnmount(ReactDOM, root, targetNode));
return targetNode;
};
diff --git a/src/utils/classToCard.js b/src/utils/classToCard.js
index 06d490a..392d3ae 100644
--- a/src/utils/classToCard.js
+++ b/src/utils/classToCard.js
@@ -1,25 +1,26 @@
import React from 'react';
-import ReactDOM from 'react-dom';
+import { reactDomRender, reactDomUnmount } from './react';
const cardRenderer =
(component, isEditing = false) =>
({ env, options, payload }) => {
const targetNode = document.createElement('div');
const { didRender, onTeardown } = env;
+ const { cardProps, ReactDOM } = options;
+ let root;
didRender(() => {
payload = { ...payload }; // deref payload
- const { cardProps } = options;
const element = React.createElement(component, {
...env,
...cardProps,
payload,
isEditing,
});
- ReactDOM.render(element, targetNode);
+ root = reactDomRender(ReactDOM, element, targetNode);
});
- onTeardown(() => ReactDOM.unmountComponentAtNode(targetNode));
+ onTeardown(() => reactDomUnmount(ReactDOM, root, targetNode));
return targetNode;
};
diff --git a/src/utils/react.js b/src/utils/react.js
new file mode 100644
index 0000000..fd5af8d
--- /dev/null
+++ b/src/utils/react.js
@@ -0,0 +1,18 @@
+import ReactDOM from 'react-dom';
+
+export function reactDomRender(CustomReactDOM, element, target) {
+ const ResolvedReactDOM = CustomReactDOM || ReactDOM;
+ const createRoot = ResolvedReactDOM.createRoot; // React 18+
+ if (createRoot) {
+ const root = createRoot(target);
+ root.render(element);
+ return root;
+ } else {
+ ResolvedReactDOM.render(element, target);
+ }
+}
+
+export function reactDomUnmount(CustomReactDOM, root, target) {
+ if (root) root.unmount();
+ else (CustomReactDOM || ReactDOM).unmountComponentAtNode(target);
+}
diff --git a/test/setup.js b/test/setup.js
index d4f0be1..6c87cbe 100644
--- a/test/setup.js
+++ b/test/setup.js
@@ -1,8 +1,11 @@
import chai from 'chai';
import chaiEnzyme from 'chai-enzyme';
import Enzyme from 'enzyme';
-import Adapter from '@wojtekmaj/enzyme-adapter-react-17';
import sinonChai from 'sinon-chai';
+import React from 'react';
+import Adapter from '@cfaester/enzyme-adapter-react-18';
+
+console.log('Testing with React version:', React.version); // eslint-disable-line no-console
Enzyme.configure({ adapter: new Adapter() });