Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

### Added
- Support for `react` version `^19.0.0` by updating the `react` and `react-dom` in the `peerDependencies` to `^19.0.0`

## 6.0.0 - 2025-02-21

### Fixed
Expand Down
34 changes: 17 additions & 17 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
"prop-types": "^15.6.2"
},
"peerDependencies": {
"react": "^18.0.0 || ^17.0.1 || ^16.7.0",
"react-dom": "^18.0.0 || ^17.0.1 || ^16.7.0",
"react": "^19.0.0 || ^18.0.0 || ^17.0.1 || ^16.7.0",
"react-dom": "^19.0.0 || ^18.0.0 || ^17.0.1 || ^16.7.0",
"tinymce": "^7.0.0 || ^6.0.0 || ^5.5.1"
},
"peerDependenciesMeta": {
Expand All @@ -50,32 +50,32 @@
"@ephox/mcagar": "^9.0.0-alpha.0",
"@ephox/sand": "^6.0.9",
"@ephox/sugar": "^9.2.1",
"@storybook/addon-essentials": "^8.2.4",
"@storybook/addon-interactions": "^8.2.4",
"@storybook/addon-links": "^8.2.4",
"@storybook/blocks": "^8.2.4",
"@storybook/react": "^8.2.4",
"@storybook/react-vite": "^8.2.4",
"@storybook/addon-essentials": "^8.6.4",
"@storybook/addon-interactions": "^8.6.4",
"@storybook/addon-links": "^8.6.4",
"@storybook/blocks": "^8.6.4",
"@storybook/react": "^8.6.4",
"@storybook/react-vite": "^8.6.4",
"@tinymce/beehive-flow": "^0.19.0",
"@tinymce/eslint-plugin": "^2.4.0",
"@tinymce/miniature": "^6.0.0",
"@types/node": "^22.13.10",
"@types/prop-types": "^15.7.12",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"gh-pages": "^6.3.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"@types/prop-types": "^15.7.14",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"gh-pages": "^6.1.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"rimraf": "^6.0.1",
"storybook": "^8.2.4",
"tinymce": "^7.7.1",
"storybook": "^8.6.4",
"tinymce": "^7.2.1",
"tinymce-4": "npm:tinymce@^4",
"tinymce-5": "npm:tinymce@^5",
"tinymce-6": "npm:tinymce@^6",
"tinymce-7": "npm:tinymce@^7",
"typescript": "~5.8.2",
"vite": "^6.2.1"
},
"version": "6.0.1-rc",
"version": "7.0.0-rc",
"name": "@tinymce/tinymce-react"
}
4 changes: 2 additions & 2 deletions src/main/ts/components/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ export class Editor extends React.Component<IAllProps> {
public editor?: TinyMCEEditor;

private id: string;
private elementRef: React.RefObject<HTMLElement>;
private elementRef: React.RefObject<HTMLElement | null>;
private inline: boolean;
private currentContent?: string;
private boundHandlers: Record<string, (event: EditorEvent<unknown>) => unknown>;
Expand All @@ -155,7 +155,7 @@ export class Editor extends React.Component<IAllProps> {
public constructor(props: Partial<IAllProps>) {
super(props);
this.id = this.props.id || uuid('tiny-react');
this.elementRef = React.createRef<HTMLElement>();
this.elementRef = React.createRef<HTMLElement | null>();
this.inline = this.props.inline ?? this.props.init?.inline ?? false;
this.boundHandlers = {};
}
Expand Down
30 changes: 20 additions & 10 deletions src/test/ts/alien/Loader.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Fun, Optional } from '@ephox/katamari';
import { Remove, SugarElement, SugarNode } from '@ephox/sugar';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import * as ReactDOMClient from 'react-dom/client';
import { Editor, IAllProps, IProps, Version } from '../../../main/ts/components/Editor';
import { Editor as TinyMCEEditor } from 'tinymce';
import { before, context } from '@ephox/bedrock-client';
import { VersionLoader } from '@tinymce/miniature';
import { setMode } from 'src/main/ts/Utils';

// @ts-expect-error Remove when dispose polyfill is not needed
Symbol.dispose ??= Symbol('Symbol.dispose');
Expand Down Expand Up @@ -33,6 +34,7 @@ export const render = async (props: Partial<IAllProps> = {}, container: HTMLElem
const originalInit = props.init || {};
const originalSetup = originalInit.setup || Fun.noop;
const ref = React.createRef<Editor>();
const root = ReactDOMClient.createRoot(container);

const ctx = await new Promise<Context>((resolve, reject) => {
const init: IProps['init'] = {
Expand All @@ -43,18 +45,18 @@ export const render = async (props: Partial<IAllProps> = {}, container: HTMLElem
editor.on('SkinLoaded', () => {
setTimeout(() => {
Optional.from(ref.current)
.map(ReactDOM.findDOMNode)
.bind(Optional.from)
.bind((editorInstance) => Optional.from(editorInstance.editor?.targetElm))
.map(SugarElement.fromDom)
.filter(SugarNode.isHTMLElement)
.map((val) => val.dom)
.fold(() => reject('Could not find DOMNode'), (DOMNode) => {
resolve({
ref,
ref: ref as React.RefObject<Editor>,
editor,
DOMNode,
});
});
}
);
}, 0);
});
}
Expand All @@ -67,20 +69,28 @@ export const render = async (props: Partial<IAllProps> = {}, container: HTMLElem
* touch the nodes created by TinyMCE. Since this only seems to be an issue when rendering TinyMCE 4 directly
* into a root and a fix would be a breaking change, let's just wrap the editor in a <div> here for now.
*/
ReactDOM.render(<div><Editor ref={ref} apiKey='no-api-key' {...props} init={init} /></div>, container);
root.render(<div><Editor ref={ref} apiKey='no-api-key' {...props} init={init} /></div>);
});

const remove = () => {
ReactDOM.unmountComponentAtNode(container);
root.unmount();
Remove.remove(SugarElement.fromDom(container));
};

return {
...ctx,
/** By rendering the Editor into the same root, React will perform a diff and update. */
reRender: (newProps: IAllProps) => new Promise<void>((resolve) =>
ReactDOM.render(<div><Editor apiKey='no-api-key' ref={ctx.ref} {...newProps} /></div>, container, resolve)
),
reRender: (newProps: IAllProps) => new Promise<void>((resolve) => {
root.render(<div><Editor apiKey='no-api-key' ref={ctx.ref} {...newProps} /></div>);

if (newProps.disabled) {
setMode(ctx.editor, 'readonly');
}

newProps.value
? ctx.editor.once('change', (_event) => resolve())
: resolve();
}),
remove,
[Symbol.dispose]: remove
};
Expand Down
6 changes: 3 additions & 3 deletions src/test/ts/browser/EditorBehaviorTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { describe, it } from '@ephox/bedrock-client';
import { getTinymce } from '../../../main/ts/TinyMCE';
import { EventStore, VERSIONS } from '../alien/TestHelpers';
import { Editor as TinyMCEEditor, EditorEvent, Events } from 'tinymce';
import { Assertions } from '@ephox/agar';
import { Assertions, Waiter } from '@ephox/agar';
import { TinyAssertions } from '@ephox/mcagar';

type SetContentEvent = EditorEvent<Events.EditorEventMap['SetContent']>;
Expand Down Expand Up @@ -89,6 +89,7 @@ describe('EditorBehaviourTest', () => {
await ctx.reRender({ onSetContent: eventStore.createHandler('onSetContent') });

TinyAssertions.assertContent(ctx.editor, '<p>Initial Content</p>');
await Waiter.pWait(0); // Wait for React's state updates to complete before setting new content
ctx.editor.setContent('<p>New Content</p>');

eventStore.each<SetContentEvent>('onSetContent', (events) => {
Expand All @@ -98,7 +99,6 @@ describe('EditorBehaviourTest', () => {
events[0].editorEvent.content
);
});

eventStore.clearState();
});

Expand All @@ -114,8 +114,8 @@ describe('EditorBehaviourTest', () => {
});
eventStore.clearState();
ctx.editor.setContent('<p>Initial Content</p>');

await ctx.reRender({ onSetContent: eventStore.createHandler('NewHandler') });
await Waiter.pWait(0); // Wait for React's state updates to complete before setting new content
ctx.editor.setContent('<p>New Content</p>');

eventStore.each<SetContentEvent>('InitialHandler', (events) => {
Expand Down
Loading