Skip to content

Commit d63bbf9

Browse files
committed
chore: upgrade to version 0.14.0 and update peer dependencies for React 16.8.0 to <20
feat: add shims for React 19 to support existing test code without refactoring fix: update DraftEditorBlockNode to use ref for blockNode instead of findDOMNode fix: modify DraftEditorDragHandler to access editor container directly due to removal of findDOMNode in React 19 test: adjust tests for getContentEditableContainer to remove ReactDOM mocks and validate editorContainer directly refactor: simplify getContentEditableContainer to use editor.editorContainer directly without findDOMNode style: update Draft.css version comment to reflect changes
1 parent 7e152fb commit d63bbf9

16 files changed

Lines changed: 179 additions & 125 deletions

File tree

examples/draft-0-10-0/playground/src/App.test.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { createRoot } from "react-dom/client";
12
/**
23
* Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
34
*
@@ -17,6 +18,7 @@ import ReactDOM from 'react-dom';
1718
import App from './App';
1819

1920
it('renders without crashing', () => {
20-
const div = document.createElement('div');
21-
ReactDOM.render(<App />, div);
21+
const div = document.createElement('div');
22+
const root = createRoot(div);
23+
root.render(<App />);
2224
});

examples/draft-0-10-0/playground/src/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { createRoot } from "react-dom/client";
12
/**
23
* Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
34
*
@@ -23,5 +24,6 @@ import registerServiceWorker from './registerServiceWorker';
2324

2425
console.log("Applying feature flag overwrites: ", GkManager);
2526

26-
ReactDOM.render(<App />, document.getElementById('root'));
27+
const root = createRoot(document.getElementById('root'));
28+
root.render(<App />);
2729
registerServiceWorker();

examples/draft-0-10-0/tex/js/app.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { createRoot } from "react-dom/client";
12
/**
23
* Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
34
*
@@ -18,7 +19,5 @@ import TeXEditorExample from './components/TeXEditorExample';
1819
import React from 'react';
1920
import ReactDOM from 'react-dom';
2021

21-
ReactDOM.render(
22-
<TeXEditorExample />,
23-
document.getElementById('target'),
24-
);
22+
const root = createRoot(document.getElementById('target'));
23+
root.render(<TeXEditorExample />);

examples/draft-0-9-1/tex/js/app.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { createRoot } from "react-dom/client";
12
/**
23
* Copyright (c) Facebook, Inc. and its affiliates. All rights reserved.
34
*
@@ -18,7 +19,5 @@ import TeXEditorExample from './components/TeXEditorExample';
1819
import React from 'react';
1920
import ReactDOM from 'react-dom';
2021

21-
ReactDOM.render(
22-
<TeXEditorExample />,
23-
document.getElementById('target'),
24-
);
22+
const root = createRoot(document.getElementById('target'));
23+
root.render(<TeXEditorExample />);

meta/bundle-size-stats/Draft.js.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

meta/bundle-size-stats/Draft.min.js.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@axioscode/draft-js",
33
"description": "A React framework for building text editors.",
4-
"version": "0.13.0",
4+
"version": "0.14.0",
55
"keywords": [
66
"draftjs",
77
"editor",
@@ -46,8 +46,8 @@
4646
"object-assign": "^4.1.1"
4747
},
4848
"peerDependencies": {
49-
"react": "^0.14.0 || ^15.0.0-rc || ^16.0.0-rc || ^16.0.0",
50-
"react-dom": "^0.14.0 || ^15.0.0-rc || ^16.0.0-rc || ^16.0.0"
49+
"react": ">=16.8.0 <20",
50+
"react-dom": ">=16.8.0 <20"
5151
},
5252
"devDependencies": {
5353
"@babel/core": "^7.6.4",
@@ -82,9 +82,9 @@
8282
"gulp-util": "^3.0.6",
8383
"jest": "^24.9.0",
8484
"prettier": "1.19.1",
85-
"react": "^16.8.0",
86-
"react-dom": "^16.8.0",
87-
"react-test-renderer": "^16.0.0",
85+
"react": "^19.0.0",
86+
"react-dom": "^19.0.0",
87+
"react-test-renderer": "^19.0.0",
8888
"semantic-release": "^22.0.5",
8989
"stats-webpack-plugin": "^0.6.2",
9090
"through2": "^3.0.1",

scripts/jest/shims.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,33 @@
99

1010
// used for testing react fiber
1111
global.requestAnimationFrame = callback => global.setTimeout(callback, 0);
12+
13+
// React 19 removed ReactDOM.render and ReactDOM.findDOMNode. Provide minimal test shims
14+
// so existing test code can continue to run without broad refactors.
15+
try {
16+
const ReactDOM = require('ReactDOM');
17+
if (ReactDOM && !ReactDOM.render && ReactDOM.createRoot) {
18+
const roots = new Map();
19+
ReactDOM.render = (element, container) => {
20+
let root = roots.get(container);
21+
if (!root) {
22+
root = ReactDOM.createRoot(container);
23+
roots.set(container, root);
24+
}
25+
root.render(element);
26+
return element && element.ref && typeof element.ref === 'function'
27+
? element.ref.current || null
28+
: null;
29+
};
30+
}
31+
if (ReactDOM && !ReactDOM.findDOMNode) {
32+
ReactDOM.findDOMNode = inst => {
33+
if (inst && inst._node) return inst._node; // DraftEditorTextNode
34+
if (inst && inst._blockNode) return inst._blockNode; // DraftEditorBlockNode
35+
if (inst && inst.editorContainer) return inst.editorContainer; // DraftEditor
36+
return null;
37+
};
38+
}
39+
} catch (e) {
40+
// ignore if ReactDOM not resolvable
41+
}

src/component/contents/__tests__/DraftEditorBlock.react-test.js

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,20 @@ const arePropsEqual = (renderedChild, leafPropSet) => {
122122
});
123123
};
124124

125+
// Helper to render a DraftEditorBlock supporting React 16-19
126+
const renderBlock = (element, container) => {
127+
if (ReactDOM.createRoot) {
128+
if (!container._root) {
129+
container._root = ReactDOM.createRoot(container);
130+
}
131+
container._root.render(element);
132+
} else if (ReactDOM.render) {
133+
ReactDOM.render(element, container);
134+
} else {
135+
throw new Error('No suitable ReactDOM renderer');
136+
}
137+
};
138+
125139
const assertLeaves = (renderedBlock, leafProps) => {
126140
leafProps.forEach((leafPropSet, ii) => {
127141
const child = renderedBlock[ii];
@@ -194,7 +208,7 @@ test('must allow update when `block` has changed', () => {
194208
const props = getProps(helloBlock);
195209

196210
const container = document.createElement('div');
197-
ReactDOM.render(<DraftEditorBlock {...props} />, container);
211+
renderBlock(<DraftEditorBlock {...props} />, container);
198212

199213
expect(mockLeafRender.mock.calls.length).toMatchSnapshot();
200214

@@ -204,7 +218,7 @@ test('must allow update when `block` has changed', () => {
204218
expect(updatedHelloBlock !== helloBlock).toMatchSnapshot();
205219
expect(props.block !== nextProps.block).toMatchSnapshot();
206220

207-
ReactDOM.render(<DraftEditorBlock {...nextProps} />, container);
221+
renderBlock(<DraftEditorBlock {...nextProps} />, container);
208222

209223
expect(mockLeafRender.mock.calls.length).toMatchSnapshot();
210224
});
@@ -214,7 +228,7 @@ test('must allow update when `tree` has changed', () => {
214228
const props = getProps(helloBlock);
215229

216230
const container = document.createElement('div');
217-
ReactDOM.render(<DraftEditorBlock {...props} />, container);
231+
renderBlock(<DraftEditorBlock {...props} />, container);
218232

219233
expect(mockLeafRender.mock.calls.length).toMatchSnapshot();
220234

@@ -232,7 +246,7 @@ test('must allow update when `tree` has changed', () => {
232246

233247
expect(props.tree !== nextProps.tree).toMatchSnapshot();
234248

235-
ReactDOM.render(<DraftEditorBlock {...nextProps} />, container);
249+
renderBlock(<DraftEditorBlock {...nextProps} />, container);
236250

237251
expect(mockLeafRender.mock.calls.length).toMatchSnapshot();
238252
});
@@ -242,14 +256,14 @@ test('must allow update when `direction` has changed', () => {
242256
const props = getProps(helloBlock);
243257

244258
const container = document.createElement('div');
245-
ReactDOM.render(<DraftEditorBlock {...props} />, container);
259+
renderBlock(<DraftEditorBlock {...props} />, container);
246260

247261
expect(mockLeafRender.mock.calls.length).toMatchSnapshot();
248262

249263
const nextProps = {...props, direction: UnicodeBidiDirection.RTL};
250264
expect(props.direction !== nextProps.direction).toMatchSnapshot();
251265

252-
ReactDOM.render(<DraftEditorBlock {...nextProps} />, container);
266+
renderBlock(<DraftEditorBlock {...nextProps} />, container);
253267

254268
expect(mockLeafRender.mock.calls.length).toMatchSnapshot();
255269
});
@@ -259,7 +273,7 @@ test('must allow update when forcing selection', () => {
259273
const props = getProps(helloBlock);
260274

261275
const container = document.createElement('div');
262-
ReactDOM.render(<DraftEditorBlock {...props} />, container);
276+
renderBlock(<DraftEditorBlock {...props} />, container);
263277

264278
expect(mockLeafRender.mock.calls.length).toMatchSnapshot();
265279

@@ -279,12 +293,12 @@ test('must reject update if conditions are not met', () => {
279293
const props = getProps(helloBlock);
280294

281295
const container = document.createElement('div');
282-
ReactDOM.render(<DraftEditorBlock {...props} />, container);
296+
renderBlock(<DraftEditorBlock {...props} />, container);
283297

284298
expect(mockLeafRender.mock.calls.length).toMatchSnapshot();
285299

286300
// Render again with the exact same props as before.
287-
ReactDOM.render(<DraftEditorBlock {...props} />, container);
301+
renderBlock(<DraftEditorBlock {...props} />, container);
288302

289303
// No new leaf renders.
290304
expect(mockLeafRender.mock.calls.length).toMatchSnapshot();
@@ -309,7 +323,7 @@ test('must reject update if selection is not on an edge', () => {
309323

310324
// Render again with selection now moved elsewhere and the contents
311325
// unchanged.
312-
ReactDOM.render(<DraftEditorBlock {...newProps} />, container);
326+
renderBlock(<DraftEditorBlock {...newProps} />, container);
313327

314328
// No new leaf renders.
315329
expect(mockLeafRender.mock.calls.length).toMatchSnapshot();
@@ -464,7 +478,7 @@ test('must scroll the window if needed', () => {
464478
});
465479

466480
const container = document.createElement('div');
467-
ReactDOM.render(<DraftEditorBlock {...props} />, container);
481+
renderBlock(<DraftEditorBlock {...props} />, container);
468482

469483
const scrollCalls = window.scrollTo.mock.calls;
470484
expect(scrollCalls).toMatchSnapshot();
@@ -473,7 +487,7 @@ test('must scroll the window if needed', () => {
473487
test('must not scroll the window if unnecessary', () => {
474488
const props = getProps(getHelloBlock());
475489
const container = document.createElement('div');
476-
ReactDOM.render(<DraftEditorBlock {...props} />, container);
490+
renderBlock(<DraftEditorBlock {...props} />, container);
477491

478492
const scrollCalls = window.scrollTo.mock.calls;
479493
expect(scrollCalls).toMatchSnapshot();

src/component/contents/__tests__/DraftEditorTextNode-test.js

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,19 @@ beforeEach(() => {
3030
});
3131

3232
const renderIntoContainer = element => {
33-
return ReactDOM.render(element, container);
33+
let instance = null;
34+
const withRef = React.cloneElement(element, {ref: i => (instance = i)});
35+
if (ReactDOM.createRoot) {
36+
if (!renderIntoContainer._root) {
37+
renderIntoContainer._root = ReactDOM.createRoot(container);
38+
}
39+
renderIntoContainer._root.render(withRef);
40+
} else if (ReactDOM.render) {
41+
instance = ReactDOM.render(withRef, container);
42+
} else {
43+
throw new Error('No suitable ReactDOM render method found');
44+
}
45+
return instance;
3446
};
3547

3648
const initializeAsIE = () => {
@@ -48,8 +60,11 @@ const initializeAsNonIE = () => {
4860
};
4961

5062
const expectPopulatedSpan = (stub, testString) => {
51-
// $FlowExpectedError node could be null
52-
const node: Element = ReactDOM.findDOMNode(stub);
63+
const node = stub._node;
64+
expect(node).toBeTruthy();
65+
if (!node) {
66+
throw new Error('Expected node to exist');
67+
}
5368
expect(node.tagName).toBe('SPAN');
5469
expect(node.childNodes.length).toBe(1);
5570
expect(node.firstChild && node.firstChild.textContent).toBe(testString);
@@ -60,8 +75,7 @@ test('must initialize correctly with an empty string, non-IE', function() {
6075
const stub = renderIntoContainer(
6176
<DraftEditorTextNode>{''}</DraftEditorTextNode>,
6277
);
63-
// $FlowExpectedError we know node is an Element
64-
expect(ReactDOM.findDOMNode(stub).tagName).toBe('BR');
78+
expect(stub._node && stub._node.tagName).toBe('BR');
6579
});
6680

6781
test('must initialize correctly with an empty string, IE', function() {
@@ -187,8 +201,7 @@ test('must update from non-empty to empty, non-IE', function() {
187201

188202
renderIntoContainer(<DraftEditorTextNode>{''}</DraftEditorTextNode>);
189203

190-
// $FlowExpectedError we know node is an Element
191-
expect(ReactDOM.findDOMNode(stub).tagName).toBe('BR');
204+
expect(stub._node && stub._node.tagName).toBe('BR');
192205
});
193206

194207
test('must update from non-empty to empty, IE', function() {
@@ -217,11 +230,11 @@ test('must force unchanged text back into the DOM', function() {
217230
<DraftEditorTextNode>{TEST_A}</DraftEditorTextNode>,
218231
);
219232

220-
// $FlowExpectedError we know node is not null
221-
ReactDOM.findDOMNode(stub).textContent = TEST_B;
233+
if (stub._node) {
234+
stub._node.textContent = TEST_B;
235+
}
222236

223237
renderIntoContainer(<DraftEditorTextNode>{TEST_A}</DraftEditorTextNode>);
224238

225-
// $FlowExpectedError we know node is not null
226-
expect(ReactDOM.findDOMNode(stub).textContent).toBe(TEST_A);
239+
expect(stub._node && stub._node.textContent).toBe(TEST_A);
227240
});

0 commit comments

Comments
 (0)