Skip to content

INT-3352: Add support for tiny 8 #470

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

Merged
merged 12 commits into from
Jul 30, 2025
Merged
Show file tree
Hide file tree
Changes from 3 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
20 changes: 18 additions & 2 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"src/**/*.tsx"
],
"excludedFiles": [
"src/demo/demo.ts"
"src/demo/demo.ts",
"src/**/*.stories.*"
],
"plugins": ["@typescript-eslint"],
"extends": "plugin:@tinymce/standard",
Expand All @@ -18,6 +19,21 @@
"@tinymce/prefer-fun": "off"
}
},
{
"files": [ "src/**/*.stories.*" ],
"plugins": ["@typescript-eslint"],
"extends": "plugin:@tinymce/standard",
"parserOptions": {
"project": "tsconfig.storybook.json",
"sourceType": "module"
},
"rules": {
"@tinymce/prefer-fun": "off",
"no-console": "off",
"@typescript-eslint/no-implied-eval": "off",
"@typescript-eslint/no-unsafe-argument": "off"
}
},
{
"files": [
"**/*.js"
Expand All @@ -43,4 +59,4 @@
}
}
]
}
}
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

### Changed
- Default cloud channel to '8'

## 6.2.0 - 2025-06-02

### Added
Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@

This package is a thin wrapper around [TinyMCE](https://github.com/tinymce/tinymce) to make it easier to use in a Vue application.

* If you need detailed documentation on TinyMCE, see: [TinyMCE Documentation](https://www.tiny.cloud/docs/tinymce/7/).
* For the TinyMCE Vue Quick Start, see: [TinyMCE Documentation - Vue Integration](https://www.tiny.cloud/docs/tinymce/7/vue-cloud).
* For the TinyMCE Vue Technical Reference, see: [TinyMCE Documentation - TinyMCE Vue Technical Reference](https://www.tiny.cloud/docs/tinymce/7/vue-ref).
* If you need detailed documentation on TinyMCE, see: [TinyMCE Documentation](https://www.tiny.cloud/docs/tinymce/8/).
* For the TinyMCE Vue Quick Start, see: [TinyMCE Documentation - Vue Integration](https://www.tiny.cloud/docs/tinymce/8/vue-cloud).
* For the TinyMCE Vue Technical Reference, see: [TinyMCE Documentation - TinyMCE Vue Technical Reference](https://www.tiny.cloud/docs/tinymce/8/vue-ref).
* For our quick demos, check out the TinyMCE Vue [Storybook](https://tinymce.github.io/tinymce-vue/).


### Support

Version 7.0 is intended to support the tinymce version 7.6 and above.
Version 7.0 is intended to support the tinymce version 8.0 and above.
Version 6.0 is intended to support the tinymce version 7.6 and above.
Version 4.0 is intended to support Vue 3. For Vue 2.x and below please use previous versions of the wrapper.

### Issues
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tinymce/tinymce-vue",
"version": "6.2.1-rc",
"version": "7.0.0-rc",
"description": "Official TinyMCE Vue 3 Component",
"private": false,
"repository": {
Expand Down
55 changes: 29 additions & 26 deletions src/stories/Editor.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Story } from '@storybook/vue3';
import { onBeforeMount, ref } from 'vue';
import { ScriptLoader } from '../main/ts/ScriptLoader';

import type { EditorEvent, Editor as TinyMCEEditor } from 'tinymce';
import type { EditorEvent } from 'tinymce';
import { Editor } from '../main/ts/components/Editor';

const apiKey = 'qagffr3pkuv17a8on1afax661irst1hbr4e6tbv888sz91jc';
Expand All @@ -11,20 +11,22 @@ const content = `
TinyMCE provides a <span style="text-decoration: underline;">full-featured</span> rich text editing experience, and a featherweight download.
</h2>
<p style="text-align: center;">
<strong><span style="font-size: 14pt;"><span style="color: #7e8c8d; font-weight: 600;">No matter what you're building, TinyMCE has got you covered.</span></span></strong>
<strong>
<span style="font-size: 14pt;"><span style="color: #7e8c8d; font-weight: 600;">No matter what you're building, TinyMCE has got you covered.</span></span>
</strong>
</p>`;

let lastChannel = '5';
let lastChannel = '8';
const getConf = (stringConf: string) => {
let conf = {};
let conf = {};
console.log('parsing: ', stringConf);
try {
conf = Function('"use strict";return (' + stringConf + ')')();
} catch (err) {
console.error('failed to parse configuration: ', err);
}
return conf;
}
};

const removeTiny = () => {
delete (window as any).tinymce;
Expand All @@ -43,18 +45,17 @@ const loadTiny = (currentArgs: any) => {
}
};


export default {
title: 'Editor',
component: Editor,
argTypes: {
channel: {
table: {
defaultValue: {summary: '5'}
defaultValue: { summary: '5' }
},
defaultValue: '7',
options: ['5', '5-dev', '5-testing', '6-testing', '6-stable', '7-dev', '7-testing', '7-stable', '7.3', '7.4', '7.6'],
control: { type: 'select'}
defaultValue: '8-dev',
options: [ '5', '5-dev', '5-testing', '6-testing', '6-stable', '7-dev', '7-testing', '7-stable', '7.3', '7.4', '7.6', '8-dev', '8-testing', '8-stable' ],
control: { type: 'select' }
},
disabled: {
defaultValue: false,
Expand All @@ -80,8 +81,8 @@ export default {
};

export const Iframe: Story = (args) => ({
components: {Editor},
setup() {
components: { Editor },
setup: () => {
onBeforeMount(() => {
loadTiny(args);
});
Expand All @@ -92,14 +93,14 @@ export const Iframe: Story = (args) => ({
content,
cloudChannel: cc,
conf
}
};
},
template: '<div ><p>Ready</p><editor :api-key="apiKey" :initialValue="content" :cloud-channel="cloudChannel" :init="conf" /></div>'
});

export const Inline: Story = (args) => ({
components: { Editor },
setup() {
setup: () => {
onBeforeMount(() => {
loadTiny(args);
});
Expand All @@ -110,7 +111,7 @@ export const Inline: Story = (args) => ({
content,
cloudChannel: cc,
conf
}
};
},
template: `
<div style="padding-top: 100px;">
Expand All @@ -125,21 +126,23 @@ export const Inline: Story = (args) => ({

export const Controlled: Story = (args) => ({
components: { Editor },
setup() {
setup: () => {
onBeforeMount(() => {
loadTiny(args);
});
const cc = args.channel || lastChannel;
const conf = getConf(args.conf);
const log = (e: EditorEvent<any>, editor: TinyMCEEditor) => {console.log(e);};
const log = (e: EditorEvent<any>) => {
console.log(e);
};
const controlledContent = ref(content);
return {
apiKey,
content: controlledContent,
cloudChannel: cc,
conf,
log
}
};
},
template: `
<div>
Expand All @@ -160,16 +163,16 @@ export const Controlled: Story = (args) => ({

export const Disable: Story = (args) => ({
components: { Editor },
setup() {
setup: () => {
onBeforeMount(() => {
loadTiny(args);
});
const cc = args.channel || lastChannel;
const conf = getConf(args.conf);
const disabled = ref(args.disabled);
const toggleDisabled = (_) => {
const toggleDisabled = () => {
disabled.value = !disabled.value;
}
};

return {
apiKey,
Expand All @@ -178,7 +181,7 @@ export const Disable: Story = (args) => ({
conf,
disabled,
toggleDisabled
}
};
},
template: `
<div>
Expand All @@ -194,24 +197,24 @@ export const Disable: Story = (args) => ({

export const Readonly: Story = (args) => ({
components: { Editor },
setup() {
setup: () => {
onBeforeMount(() => {
loadTiny(args);
});
const cc = args.channel || lastChannel;
const conf = getConf(args.conf);
const readonly = ref(args.readonly);
const toggleReadonly = (_) => {
const toggleReadonly = () => {
readonly.value = !readonly.value;
}
};
return {
apiKey,
content,
cloudChannel: cc,
conf,
readonly,
toggleReadonly
}
};
},
template: `
<div>
Expand Down
7 changes: 6 additions & 1 deletion src/test/ts/browser/InitTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ describe('Editor Component Initialization Tests', () => {
Keyboard.keystroke(Keys.space(), {}, SugarElement.fromDom(vmContext.editor.getBody()) as SugarElement<Node>);
};

// TODO: Add tests for TinyMCE 8 initialization once it releases
Arr.each([ '4', '5', '6', '7' as const ], (version) => {
context(`Version: ${version}`, () => {

Expand All @@ -32,6 +33,7 @@ describe('Editor Component Initialization Tests', () => {
const vmContext = await pRender({}, `
<editor
:init="init"
license-key="gpl"
></editor>`);
Assertions.assertEq('Editor should not be inline', false, vmContext.editor.inline);
});
Expand All @@ -41,12 +43,13 @@ describe('Editor Component Initialization Tests', () => {
<editor
:init="init"
:inline="true"
license-key="gpl"
></editor>`);
Assertions.assertEq('Editor should be inline', true, vmContext.editor.inline);
});

it('should be inline with inline option in init', async () => {
const vmContext = await pRender({ init: { inline: true }});
const vmContext = await pRender({ init: { inline: true, license_key: 'gpl' }});
Assertions.assertEq('Editor should be inline', true, vmContext.editor.inline);
});

Expand All @@ -57,6 +60,7 @@ describe('Editor Component Initialization Tests', () => {
<editor
:init="init"
api-key="${VALID_API_KEY}"
license-key="gpl"
@update:modelValue="content=$event"
output-format="text"
></editor>
Expand All @@ -71,6 +75,7 @@ describe('Editor Component Initialization Tests', () => {
}, `
<editor
:init="init"
license-key="gpl"
api-key="${VALID_API_KEY}"
@update:modelValue="content=$event"
output-format="html"
Expand Down
37 changes: 35 additions & 2 deletions src/test/ts/browser/LoadTinyTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { cleanupGlobalTinymce, VALID_API_KEY } from '../alien/TestHelper';

describe('LoadTinyTest', () => {

const AssertTinymceVersion = (version: '4' | '5' | '6' | '7') => {
const AssertTinymceVersion = (version: '4' | '5' | '6' | '7' | '8') => {
Assertions.assertEq(`Loaded version of TinyMCE should be ${version}`, version, Global.tinymce.majorVersion);
};

Expand All @@ -17,6 +17,19 @@ describe('LoadTinyTest', () => {
cleanupGlobalTinymce();
});

// Skip this test as it requires a local version of TinyMCE 8
it.skip('Should be able to load local version of TinyMCE 8 using the tinymceScriptSrc prop', async () => {
await pRender({}, `
<editor
:init="init"
license-key="gpl"
tinymce-script-src="/project/node_modules/tinymce-8/tinymce.min.js"
></editor>
`);

AssertTinymceVersion('8');
});

it('Should be able to load local version of TinyMCE 7 using the tinymceScriptSrc prop', async () => {
await pRender({}, `
<editor
Expand Down Expand Up @@ -61,6 +74,26 @@ describe('LoadTinyTest', () => {
AssertTinymceVersion('4');
});

// Skip this test until TinyMCE 8 is released
it.skip('Should be able to load TinyMCE 8 from Cloud', async () => {
// The 8-dev should be swapped with 8-stable once 8 releases
await pRender({}, `
<editor
:init="init"
api-key="${VALID_API_KEY}"
cloud-channel="8-dev"
></editor>
`);

AssertTinymceVersion('8');
// The 8-dev should be swapped with 8-stable once 8 releases
Assertions.assertEq(
'TinyMCE 8 should have been loaded from Cloud',
`https://cdn.tiny.cloud/1/${VALID_API_KEY}/tinymce/8-dev`,
Global.tinymce.baseURI.source
);
});

it('Should be able to load TinyMCE 7 from Cloud', async () => {
await pRender({}, `
<editor
Expand Down Expand Up @@ -112,4 +145,4 @@ describe('LoadTinyTest', () => {
);
});
});
});
});
17 changes: 17 additions & 0 deletions tsconfig.storybook.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"target": "es2020",
"module": "esnext",
"lib": ["dom", "esnext"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"noEmit": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"jsx": "react-jsx"
},
"include": ["src/**/*.stories.*"]
}
6 changes: 3 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -15526,9 +15526,9 @@ tiny-emitter@^2.0.0:
integrity sha512-0a7DJnhniBx2psRuKcVQ9g4hujN6PAR4fPS0NSF1T1luH1RBDZVVEn2pGND6Ly+AW1lUm/cHOHjsasqBelMhbw==

tinymce@^7:
version "7.2.1"
resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-7.2.1.tgz#9b4f6b5a0fa647e2953c174ac69aa47483683332"
integrity sha512-ADd1cvdIuq6NWyii0ZOZRuu+9sHIdQfcRNWBcBps2K8vy7OjlRkX6iw7zz1WlL9kY4z4L1DvIP+xOrVX/46aHA==
version "7.9.1"
resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-7.9.1.tgz#1b18bad9cb7a3b4b12e3e5a7f29fc7daad0713d7"
integrity sha512-zaOHwmiP1EqTeLRXAvVriDb00JYnfEjWGPdKEuac7MiZJ5aiDMZ4Unc98Gmajn+PBljOmO1GKV6G0KwWn3+k8A==

tmp@^0.2.1:
version "0.2.1"
Expand Down