Skip to content

Commit

Permalink
Merge pull request #510 from ckeditor/ck/cloud-poc
Browse files Browse the repository at this point in the history
Feature: Added `useCKEditorCloud` hook for managing asynchronous loading of CKEditor from a CDN.
Feature: Added withCKEditorCloud HOC to simplify CKEditor integration with CDN in React components.
  • Loading branch information
Mati365 authored Sep 5, 2024
2 parents 5306563 + 4636d99 commit ec8e603
Show file tree
Hide file tree
Showing 67 changed files with 3,426 additions and 446 deletions.
79 changes: 79 additions & 0 deletions demos/cdn-multiroot-react/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/**
* @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md.
*/

import React, { StrictMode, useState } from 'react';
import MultiRootEditorDemo from './MultiRootEditorDemo';
import MultiRootEditorRichDemo from './MultiRootEditorRichDemo';
import ContextMultiRootEditorDemo from './ContextMultiRootEditorDemo';

type Demo = 'editor' | 'rich' | 'context';

const multiRootEditorContent = {
intro: '<h2>Sample</h2><p>This is an instance of the ' +
'<a href="https://ckeditor.com/docs/ckeditor5/latest/builds/guides/overview.html#classic-editor">multi-root editor build</a>.</p>',
content: '<p>It is the custom content</p><figure class="image"><img src="/demos/sample.jpg" alt="CKEditor 5 Sample image."></figure>',
outro: '<p>You can use this sample to validate whether your ' +
'<a href="https://ckeditor.com/docs/ckeditor5/latest/builds/guides/development/custom-builds.html">custom build</a> works fine.</p>'
};

const rootsAttributes = {
intro: {
row: '1',
order: 10
},
content: {
row: '1',
order: 20
},
outro: {
row: '2',
order: 10
}
};

export default function App(): JSX.Element {
const [ demo, setDemo ] = useState<Demo>( 'editor' );

const renderDemo = () => {
switch ( demo ) {
case 'context':
return <ContextMultiRootEditorDemo />;
case 'editor':
return <MultiRootEditorDemo data={multiRootEditorContent} rootsAttributes={rootsAttributes} />;
case 'rich':
return <MultiRootEditorRichDemo data={multiRootEditorContent} rootsAttributes={rootsAttributes} />;
}
};

return (
<StrictMode>
<h1>CKEditor 5 – useMultiRootEditor – CDN development sample</h1>

<div className="buttons" style={ { textAlign: 'center' } }>
<button
onClick={ () => setDemo( 'editor' ) }
disabled={ demo == 'editor' }
>
Editor demo
</button>

<button
onClick={ () => setDemo( 'rich' ) }
disabled={ demo == 'rich' }
>
Rich integration demo
</button>

<button
onClick={ () => setDemo( 'context' ) }
disabled={ demo == 'context' }
>
Context demo
</button>
</div>
{ renderDemo() }
</StrictMode>
);
}
142 changes: 142 additions & 0 deletions demos/cdn-multiroot-react/ContextMultiRootEditorDemo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/**
* @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md.
*/

import React from 'react';

import { useMultiRootEditor, type MultiRootHookProps, CKEditorContext, withCKEditorCloud } from '../../src/index.js';
import { useCKCdnMultiRootEditor } from './useCKCdnMultiRootEditor.js';

const ContextEditorDemo = ( { editor }: { editor: any } ): JSX.Element => {
const editorProps: Partial<MultiRootHookProps> = {
editor,

onChange: ( event, editor ) => {
console.log( 'event: onChange', { event, editor } );
},
onBlur: ( event, editor ) => {
console.log( 'event: onBlur', { event, editor } );
},
onFocus: ( event, editor ) => {
console.log( 'event: onFocus', { event, editor } );
}
};

// First editor initialization.
const {
editor: editor1, editableElements: editableElements1, toolbarElement: toolbarElement1
} = useMultiRootEditor( {
...editorProps,
data: {
intro: '<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>',
content: '<p>Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>'
},

onReady: editor => {
window.editor1 = editor;

console.log( 'event: onChange', { editor } );
}
} as MultiRootHookProps );

// Second editor initialization.
const {
editor: editor2, editableElements: editableElements2, toolbarElement: toolbarElement2
} = useMultiRootEditor( {
...editorProps,
data: {
notes: '<p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p>'
},

onReady: editor => {
window.editor2 = editor;

console.log( 'event: onChange', { editor } );
}
} as MultiRootHookProps );

// Function to simulate an error in the editor.
// It is used for testing purposes to trigger the Watchdog to restart the editor.
// Remove it in the actual integration.
const simulateError = ( editor: any ) => {
setTimeout( () => {
const err: any = new Error( 'foo' );

err.context = editor;
err.is = () => true;

throw err;
} );
};

return (
<>
<h2 className="subtitle">Context Multi-root Editor Demo</h2>
<p className="info">
This sample demonstrates integration with CKEditorContext.<br />
</p>
<p className="info">Component&apos;s events are logged to the console.</p>
<hr /><br />

<div>
<div className="buttons">
<button
onClick={ () => simulateError( editor1! ) }
disabled={ !editor1 }
>
Simulate an error in first editor
</button>
</div>

{ toolbarElement1 }

<div className="flex">
{ editableElements1 }
</div>
</div>

<br />

<div>
<div className="buttons">
<button
onClick={ () => simulateError( editor2! ) }
disabled={ !editor2 }
>
Simulate an error in second editor
</button>
</div>

{ toolbarElement2 }

<div className="flex">
{ editableElements2 }
</div>
</div>
</>
);
};

const withCKCloud = withCKEditorCloud( {
cloud: {
version: '43.0.0',
languages: [ 'en', 'de' ],
premium: true
}
} );

const ContextMultiRootEditorDemo = withCKCloud( ( { cloud } ): JSX.Element => {
const MultiRootEditor = useCKCdnMultiRootEditor( cloud );

return (
<CKEditorContext
context={ MultiRootEditor.Context as any }
contextWatchdog={ MultiRootEditor.ContextWatchdog as any }
>
<ContextEditorDemo editor={MultiRootEditor} />
</CKEditorContext>
);
} );

export default ContextMultiRootEditorDemo;
55 changes: 55 additions & 0 deletions demos/cdn-multiroot-react/MultiRootEditorDemo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md.
*/

import React, { type ReactNode } from 'react';

import { useCKCdnMultiRootEditor } from './useCKCdnMultiRootEditor.js';
import {
useMultiRootEditor, withCKEditorCloud,
type MultiRootHookProps,
type WithCKEditorCloudHocProps
} from '../../src/index.js';

type EditorDemoProps = WithCKEditorCloudHocProps & {
data: Record<string, string>;
rootsAttributes: Record<string, Record<string, unknown>>;
};

const withCKCloud = withCKEditorCloud( {
cloud: {
version: '43.0.0',
languages: [ 'de' ],
premium: true
}
} );

const MultiRootEditorDemo = withCKCloud( ( { data, cloud }: EditorDemoProps ): ReactNode => {
const MultiRootEditor = useCKCdnMultiRootEditor( cloud );
const editorProps: MultiRootHookProps = {
editor: MultiRootEditor as any,
data
};

const { toolbarElement, editableElements } = useMultiRootEditor( editorProps );

return (
<>
<h2 className="subtitle">Multi-root Editor Demo</h2>
<p className="info">
This sample demonstrates the minimal React application that uses multi-root editor integration.<br />
You may use it as a starting point for your application.
</p>
<hr /><br />

<div>
{ toolbarElement }

{ editableElements }
</div>
</>
);
} );

export default MultiRootEditorDemo;
Loading

0 comments on commit ec8e603

Please sign in to comment.