ckeditor5-livewire 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hooks/context/context.d.ts +39 -0
- package/dist/hooks/context/context.d.ts.map +1 -0
- package/dist/hooks/context/contexts-registry.d.ts +9 -0
- package/dist/hooks/context/contexts-registry.d.ts.map +1 -0
- package/dist/hooks/context/index.d.ts +4 -0
- package/dist/hooks/context/index.d.ts.map +1 -0
- package/dist/hooks/context/typings.d.ts +34 -0
- package/dist/hooks/context/typings.d.ts.map +1 -0
- package/dist/hooks/editable.d.ts +40 -0
- package/dist/hooks/editable.d.ts.map +1 -0
- package/dist/hooks/editor/custom-editor-plugins.d.ts +54 -0
- package/dist/hooks/editor/custom-editor-plugins.d.ts.map +1 -0
- package/dist/hooks/editor/editor.d.ts +69 -0
- package/dist/hooks/editor/editor.d.ts.map +1 -0
- package/dist/hooks/editor/editors-registry.d.ts +9 -0
- package/dist/hooks/editor/editors-registry.d.ts.map +1 -0
- package/dist/hooks/editor/index.d.ts +3 -0
- package/dist/hooks/editor/index.d.ts.map +1 -0
- package/dist/hooks/editor/plugins/index.d.ts +3 -0
- package/dist/hooks/editor/plugins/index.d.ts.map +1 -0
- package/dist/hooks/editor/plugins/livewire-sync.d.ts +19 -0
- package/dist/hooks/editor/plugins/livewire-sync.d.ts.map +1 -0
- package/dist/hooks/editor/plugins/sync-editor-with-input.d.ts +6 -0
- package/dist/hooks/editor/plugins/sync-editor-with-input.d.ts.map +1 -0
- package/dist/hooks/editor/typings.d.ts +99 -0
- package/dist/hooks/editor/typings.d.ts.map +1 -0
- package/dist/hooks/editor/utils/create-editor-in-context.d.ts +44 -0
- package/dist/hooks/editor/utils/create-editor-in-context.d.ts.map +1 -0
- package/dist/hooks/editor/utils/get-editor-roots-values.d.ts +9 -0
- package/dist/hooks/editor/utils/get-editor-roots-values.d.ts.map +1 -0
- package/dist/hooks/editor/utils/index.d.ts +12 -0
- package/dist/hooks/editor/utils/index.d.ts.map +1 -0
- package/dist/hooks/editor/utils/is-single-editing-like-editor.d.ts +9 -0
- package/dist/hooks/editor/utils/is-single-editing-like-editor.d.ts.map +1 -0
- package/dist/hooks/editor/utils/load-editor-constructor.d.ts +9 -0
- package/dist/hooks/editor/utils/load-editor-constructor.d.ts.map +1 -0
- package/dist/hooks/editor/utils/load-editor-plugins.d.ts +20 -0
- package/dist/hooks/editor/utils/load-editor-plugins.d.ts.map +1 -0
- package/dist/hooks/editor/utils/load-editor-translations.d.ts +14 -0
- package/dist/hooks/editor/utils/load-editor-translations.d.ts.map +1 -0
- package/dist/hooks/editor/utils/normalize-custom-translations.d.ts +11 -0
- package/dist/hooks/editor/utils/normalize-custom-translations.d.ts.map +1 -0
- package/dist/hooks/editor/utils/query-editor-editables.d.ts +34 -0
- package/dist/hooks/editor/utils/query-editor-editables.d.ts.map +1 -0
- package/dist/hooks/editor/utils/resolve-editor-config-elements-references.d.ts +9 -0
- package/dist/hooks/editor/utils/resolve-editor-config-elements-references.d.ts.map +1 -0
- package/dist/hooks/editor/utils/set-editor-editable-height.d.ts +9 -0
- package/dist/hooks/editor/utils/set-editor-editable-height.d.ts.map +1 -0
- package/dist/hooks/editor/utils/wrap-with-watchdog.d.ts +24 -0
- package/dist/hooks/editor/utils/wrap-with-watchdog.d.ts.map +1 -0
- package/dist/hooks/hook.d.ts +58 -0
- package/dist/hooks/hook.d.ts.map +1 -0
- package/dist/hooks/index.d.ts +5 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/ui-part.d.ts +32 -0
- package/dist/hooks/ui-part.d.ts.map +1 -0
- package/dist/index.cjs +5 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +1146 -0
- package/dist/index.mjs.map +1 -0
- package/dist/shared/async-registry.d.ts +131 -0
- package/dist/shared/async-registry.d.ts.map +1 -0
- package/dist/shared/camel-case.d.ts +8 -0
- package/dist/shared/camel-case.d.ts.map +1 -0
- package/dist/shared/debounce.d.ts +2 -0
- package/dist/shared/debounce.d.ts.map +1 -0
- package/dist/shared/deep-camel-case-keys.d.ts +8 -0
- package/dist/shared/deep-camel-case-keys.d.ts.map +1 -0
- package/dist/shared/filter-object-values.d.ts +9 -0
- package/dist/shared/filter-object-values.d.ts.map +1 -0
- package/dist/shared/index.d.ts +13 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/is-empty-object.d.ts +2 -0
- package/dist/shared/is-empty-object.d.ts.map +1 -0
- package/dist/shared/is-plain-object.d.ts +8 -0
- package/dist/shared/is-plain-object.d.ts.map +1 -0
- package/dist/shared/map-object-values.d.ts +11 -0
- package/dist/shared/map-object-values.d.ts.map +1 -0
- package/dist/shared/once.d.ts +2 -0
- package/dist/shared/once.d.ts.map +1 -0
- package/dist/shared/timeout.d.ts +8 -0
- package/dist/shared/timeout.d.ts.map +1 -0
- package/dist/shared/uid.d.ts +7 -0
- package/dist/shared/uid.d.ts.map +1 -0
- package/dist/shared/wait-for.d.ts +20 -0
- package/dist/shared/wait-for.d.ts.map +1 -0
- package/dist/types/can-be-promise.type.d.ts +2 -0
- package/dist/types/can-be-promise.type.d.ts.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/required-by.type.d.ts +2 -0
- package/dist/types/required-by.type.d.ts.map +1 -0
- package/package.json +40 -0
- package/src/hooks/context/context.test.ts +394 -0
- package/src/hooks/context/context.ts +116 -0
- package/src/hooks/context/contexts-registry.test.ts +10 -0
- package/src/hooks/context/contexts-registry.ts +10 -0
- package/src/hooks/context/index.ts +3 -0
- package/src/hooks/context/typings.ts +39 -0
- package/src/hooks/editable.test.ts +276 -0
- package/src/hooks/editable.ts +122 -0
- package/src/hooks/editor/custom-editor-plugins.test.ts +103 -0
- package/src/hooks/editor/custom-editor-plugins.ts +84 -0
- package/src/hooks/editor/editor.test.ts +782 -0
- package/src/hooks/editor/editor.ts +357 -0
- package/src/hooks/editor/editors-registry.test.ts +10 -0
- package/src/hooks/editor/editors-registry.ts +10 -0
- package/src/hooks/editor/index.ts +2 -0
- package/src/hooks/editor/plugins/index.ts +2 -0
- package/src/hooks/editor/plugins/livewire-sync.ts +85 -0
- package/src/hooks/editor/plugins/sync-editor-with-input.ts +76 -0
- package/src/hooks/editor/typings.ts +114 -0
- package/src/hooks/editor/utils/create-editor-in-context.ts +90 -0
- package/src/hooks/editor/utils/get-editor-roots-values.ts +16 -0
- package/src/hooks/editor/utils/index.ts +11 -0
- package/src/hooks/editor/utils/is-single-editing-like-editor.test.ts +40 -0
- package/src/hooks/editor/utils/is-single-editing-like-editor.ts +11 -0
- package/src/hooks/editor/utils/load-editor-constructor.test.ts +62 -0
- package/src/hooks/editor/utils/load-editor-constructor.ts +27 -0
- package/src/hooks/editor/utils/load-editor-plugins.test.ts +100 -0
- package/src/hooks/editor/utils/load-editor-plugins.ts +71 -0
- package/src/hooks/editor/utils/load-editor-translations.ts +233 -0
- package/src/hooks/editor/utils/normalize-custom-translations.test.ts +152 -0
- package/src/hooks/editor/utils/normalize-custom-translations.ts +18 -0
- package/src/hooks/editor/utils/query-editor-editables.ts +102 -0
- package/src/hooks/editor/utils/resolve-editor-config-elements-references.test.ts +93 -0
- package/src/hooks/editor/utils/resolve-editor-config-elements-references.ts +36 -0
- package/src/hooks/editor/utils/set-editor-editable-height.test.ts +131 -0
- package/src/hooks/editor/utils/set-editor-editable-height.ts +15 -0
- package/src/hooks/editor/utils/wrap-with-watchdog.test.ts +45 -0
- package/src/hooks/editor/utils/wrap-with-watchdog.ts +51 -0
- package/src/hooks/hook.ts +87 -0
- package/src/hooks/index.ts +21 -0
- package/src/hooks/ui-part.test.ts +161 -0
- package/src/hooks/ui-part.ts +80 -0
- package/src/index.ts +5 -0
- package/src/livewire.d.ts +42 -0
- package/src/shared/async-registry.test.ts +658 -0
- package/src/shared/async-registry.ts +308 -0
- package/src/shared/camel-case.test.ts +35 -0
- package/src/shared/camel-case.ts +11 -0
- package/src/shared/debounce.test.ts +72 -0
- package/src/shared/debounce.ts +16 -0
- package/src/shared/deep-camel-case-keys.test.ts +34 -0
- package/src/shared/deep-camel-case-keys.ts +26 -0
- package/src/shared/filter-object-values.test.ts +25 -0
- package/src/shared/filter-object-values.ts +17 -0
- package/src/shared/index.ts +12 -0
- package/src/shared/is-empty-object.test.ts +78 -0
- package/src/shared/is-empty-object.ts +3 -0
- package/src/shared/is-plain-object.test.ts +38 -0
- package/src/shared/is-plain-object.ts +15 -0
- package/src/shared/map-object-values.test.ts +29 -0
- package/src/shared/map-object-values.ts +19 -0
- package/src/shared/once.test.ts +116 -0
- package/src/shared/once.ts +12 -0
- package/src/shared/timeout.test.ts +65 -0
- package/src/shared/timeout.ts +13 -0
- package/src/shared/uid.test.ts +25 -0
- package/src/shared/uid.ts +8 -0
- package/src/shared/wait-for.test.ts +24 -0
- package/src/shared/wait-for.ts +56 -0
- package/src/types/can-be-promise.type.ts +1 -0
- package/src/types/index.ts +2 -0
- package/src/types/required-by.type.ts +1 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { LivewireComponent, Wire } from '../livewire';
|
|
2
|
+
import type { CanBePromise } from '../types';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* An abstract class representing a class-based hook for Livewire components.
|
|
6
|
+
*/
|
|
7
|
+
export abstract class ClassHook<T extends object = Record<string, unknown>> {
|
|
8
|
+
/**
|
|
9
|
+
* The current state of the hook.
|
|
10
|
+
*/
|
|
11
|
+
state: ClassHookState = 'mounting';
|
|
12
|
+
|
|
13
|
+
constructor(
|
|
14
|
+
/**
|
|
15
|
+
* The Livewire component instance associated with this hook.
|
|
16
|
+
*/
|
|
17
|
+
protected livewireComponent: LivewireComponent,
|
|
18
|
+
) {}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The ephemeral snapshot of the Livewire component.
|
|
22
|
+
*/
|
|
23
|
+
get ephemeral(): T {
|
|
24
|
+
return this.livewireComponent.ephemeral as T;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The root HTML element of the Livewire component.
|
|
29
|
+
*/
|
|
30
|
+
get element(): HTMLElement {
|
|
31
|
+
return this.livewireComponent.el;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The wire interface for the Livewire component.
|
|
36
|
+
*/
|
|
37
|
+
get $wire(): Wire {
|
|
38
|
+
return this.livewireComponent.$wire;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Checks if the hook is in the process of being destroyed.
|
|
43
|
+
*/
|
|
44
|
+
isBeingDestroyed(): boolean {
|
|
45
|
+
return ['destroyed', 'destroying'].includes(this.state);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Called when the hook has been mounted to the DOM.
|
|
50
|
+
*/
|
|
51
|
+
abstract mounted(): CanBePromise<void>;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Called when the element has been removed from the DOM.
|
|
55
|
+
*/
|
|
56
|
+
abstract destroyed(): CanBePromise<void>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* A type that represents the state of a class-based hook.
|
|
61
|
+
*/
|
|
62
|
+
export type ClassHookState = 'mounting' | 'mounted' | 'destroying' | 'destroyed';
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Registers a Livewire hook that watches initialization of components and manages their lifecycle.
|
|
66
|
+
*
|
|
67
|
+
* @param name - The name of the component to watch for.
|
|
68
|
+
* @param Hook - A class that extends `ClassHook` to handle component lifecycle events.
|
|
69
|
+
*/
|
|
70
|
+
export function registerLivewireComponentHook(name: string, Hook: { new(component: LivewireComponent): ClassHook<any>; }) {
|
|
71
|
+
window.Livewire.hook('component.init', async ({ component, cleanup }) => {
|
|
72
|
+
if (component.name !== name) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const instance = new Hook(component);
|
|
77
|
+
|
|
78
|
+
cleanup(async () => {
|
|
79
|
+
instance.state = 'destroying';
|
|
80
|
+
await instance.destroyed();
|
|
81
|
+
instance.state = 'destroyed';
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
await instance.mounted();
|
|
85
|
+
instance.state = 'mounted';
|
|
86
|
+
});
|
|
87
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ContextComponentHook } from './context';
|
|
2
|
+
import { EditableComponentHook } from './editable';
|
|
3
|
+
import { EditorComponentHook } from './editor';
|
|
4
|
+
import { registerLivewireComponentHook } from './hook';
|
|
5
|
+
import { UIPartComponentHook } from './ui-part';
|
|
6
|
+
|
|
7
|
+
const COMPONENT_HOOKS = {
|
|
8
|
+
'ckeditor5': EditorComponentHook,
|
|
9
|
+
'ckeditor5-context': ContextComponentHook,
|
|
10
|
+
'ckeditor5-ui-part': UIPartComponentHook,
|
|
11
|
+
'ckeditor5-editable': EditableComponentHook,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Registers all available Livewire component hooks.
|
|
16
|
+
*/
|
|
17
|
+
export function registerLivewireComponentHooks() {
|
|
18
|
+
for (const [name, Hook] of Object.entries(COMPONENT_HOOKS)) {
|
|
19
|
+
registerLivewireComponentHook(name, Hook);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
createEditorHtmlElement,
|
|
5
|
+
createEditorPreset,
|
|
6
|
+
createEditorSnapshot,
|
|
7
|
+
createUIPartHtmlElement,
|
|
8
|
+
createUIPartSnapshot,
|
|
9
|
+
LivewireStub,
|
|
10
|
+
waitForTestEditor,
|
|
11
|
+
} from '~/test-utils';
|
|
12
|
+
|
|
13
|
+
import type { Snapshot as EditorSnapshot } from './editor';
|
|
14
|
+
|
|
15
|
+
import { EditorComponentHook } from './editor';
|
|
16
|
+
import { registerLivewireComponentHook } from './hook';
|
|
17
|
+
import { UIPartComponentHook } from './ui-part';
|
|
18
|
+
|
|
19
|
+
describe('ui-part component', () => {
|
|
20
|
+
let livewireStub: LivewireStub;
|
|
21
|
+
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
document.body.innerHTML = '';
|
|
24
|
+
livewireStub = window.Livewire = new LivewireStub();
|
|
25
|
+
|
|
26
|
+
registerLivewireComponentHook('ckeditor5', EditorComponentHook);
|
|
27
|
+
registerLivewireComponentHook('ckeditor5-ui-part', UIPartComponentHook);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
afterEach(async () => {
|
|
31
|
+
await livewireStub.$internal.destroy();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe('mounting ui part', () => {
|
|
35
|
+
it('should mount toolbar to the editor after mounting editor', async () => {
|
|
36
|
+
appendMultirootEditor();
|
|
37
|
+
|
|
38
|
+
const editor = await waitForTestEditor();
|
|
39
|
+
const toolbarElement = editor.ui.view.toolbar?.element;
|
|
40
|
+
|
|
41
|
+
const { el } = livewireStub.$internal.appendComponentToDOM({
|
|
42
|
+
name: 'ckeditor5-ui-part',
|
|
43
|
+
el: createUIPartHtmlElement(),
|
|
44
|
+
ephemeral: createUIPartSnapshot('toolbar'),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
expect(toolbarElement).toBeTruthy();
|
|
48
|
+
expect(el.contains(toolbarElement!)).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should mount menubar to the editor after mounting editor', async () => {
|
|
52
|
+
appendMultirootEditor();
|
|
53
|
+
|
|
54
|
+
const editor = await waitForTestEditor();
|
|
55
|
+
const menubarElement = (editor.ui.view as any).menuBarView.element;
|
|
56
|
+
|
|
57
|
+
const { el } = livewireStub.$internal.appendComponentToDOM({
|
|
58
|
+
name: 'ckeditor5-ui-part',
|
|
59
|
+
el: createUIPartHtmlElement(),
|
|
60
|
+
ephemeral: createUIPartSnapshot('menubar'),
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
expect(el.children.length).toBeGreaterThan(0);
|
|
64
|
+
expect(el.contains(menubarElement)).toBe(true);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should log error for unknown UI part name', async () => {
|
|
68
|
+
appendMultirootEditor();
|
|
69
|
+
await waitForTestEditor();
|
|
70
|
+
|
|
71
|
+
const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
72
|
+
|
|
73
|
+
livewireStub.$internal.appendComponentToDOM({
|
|
74
|
+
name: 'ckeditor5-ui-part',
|
|
75
|
+
el: createUIPartHtmlElement(),
|
|
76
|
+
ephemeral: createUIPartSnapshot('unknown-part'),
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(
|
|
80
|
+
expect.stringContaining('Unknown UI part name: "unknown-part"'),
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
consoleErrorSpy.mockRestore();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should mount UI part before editor is created', async () => {
|
|
87
|
+
const { el } = livewireStub.$internal.appendComponentToDOM({
|
|
88
|
+
name: 'ckeditor5-ui-part',
|
|
89
|
+
el: createUIPartHtmlElement(),
|
|
90
|
+
ephemeral: createUIPartSnapshot('toolbar'),
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
appendMultirootEditor();
|
|
94
|
+
|
|
95
|
+
const editor = await waitForTestEditor();
|
|
96
|
+
const toolbarElement = editor.ui.view.toolbar?.element;
|
|
97
|
+
|
|
98
|
+
expect(toolbarElement).toBeTruthy();
|
|
99
|
+
expect(el.contains(toolbarElement!)).toBe(true);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('destroying ui part', () => {
|
|
104
|
+
beforeEach(async () => {
|
|
105
|
+
appendMultirootEditor();
|
|
106
|
+
await waitForTestEditor();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('should clear UI part element on destruction', async () => {
|
|
110
|
+
const { id, el } = livewireStub.$internal.appendComponentToDOM({
|
|
111
|
+
name: 'ckeditor5-ui-part',
|
|
112
|
+
el: createUIPartHtmlElement(),
|
|
113
|
+
ephemeral: createUIPartSnapshot('toolbar'),
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
expect(el.children.length).toBeGreaterThan(0);
|
|
117
|
+
|
|
118
|
+
await livewireStub.$internal.unmountComponent(id);
|
|
119
|
+
|
|
120
|
+
expect(el.innerHTML).toBe('');
|
|
121
|
+
expect(el.style.display).toBe('none');
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('should hide element during destruction', async () => {
|
|
125
|
+
const { id, el } = livewireStub.$internal.appendComponentToDOM({
|
|
126
|
+
name: 'ckeditor5-ui-part',
|
|
127
|
+
el: createUIPartHtmlElement(),
|
|
128
|
+
ephemeral: createUIPartSnapshot('toolbar'),
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
await livewireStub.$internal.unmountComponent(id);
|
|
132
|
+
|
|
133
|
+
expect(el.style.display).toBe('none');
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('should handle destruction when mounted promise is not resolved yet', async () => {
|
|
137
|
+
const { id, el } = livewireStub.$internal.appendComponentToDOM({
|
|
138
|
+
name: 'ckeditor5-ui-part',
|
|
139
|
+
el: createUIPartHtmlElement(),
|
|
140
|
+
ephemeral: createUIPartSnapshot('toolbar'),
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
await livewireStub.$internal.unmountComponent(id);
|
|
144
|
+
|
|
145
|
+
expect(el.innerHTML).toBe('');
|
|
146
|
+
expect(el.style.display).toBe('none');
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
function appendMultirootEditor(initialContent: Record<string, string> = {}) {
|
|
151
|
+
livewireStub.$internal.appendComponentToDOM<EditorSnapshot>({
|
|
152
|
+
name: 'ckeditor5',
|
|
153
|
+
el: createEditorHtmlElement(),
|
|
154
|
+
ephemeral: {
|
|
155
|
+
...createEditorSnapshot(),
|
|
156
|
+
preset: createEditorPreset('multiroot'),
|
|
157
|
+
content: initialContent,
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
});
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { EditorsRegistry } from './editor/editors-registry';
|
|
2
|
+
import { ClassHook } from './hook';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* UI Part hook for Livewire. It allows you to create UI parts for multi-root editors.
|
|
6
|
+
*/
|
|
7
|
+
export class UIPartComponentHook extends ClassHook<Snapshot> {
|
|
8
|
+
/**
|
|
9
|
+
* The promise that resolves when the UI part is mounted.
|
|
10
|
+
*/
|
|
11
|
+
private mountedPromise: Promise<void> | null = null;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Mounts the UI part component.
|
|
15
|
+
*/
|
|
16
|
+
override async mounted() {
|
|
17
|
+
const { editorId, name } = this.ephemeral;
|
|
18
|
+
|
|
19
|
+
// If the editor is not registered yet, we will wait for it to be registered.
|
|
20
|
+
this.mountedPromise = EditorsRegistry.the.execute(editorId, (editor) => {
|
|
21
|
+
const { ui } = editor;
|
|
22
|
+
|
|
23
|
+
const uiViewName = mapUIPartView(name);
|
|
24
|
+
const uiPart = (ui.view as any)[uiViewName!];
|
|
25
|
+
|
|
26
|
+
if (!uiPart) {
|
|
27
|
+
console.error(`Unknown UI part name: "${name}". Supported names are "toolbar" and "menubar".`);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
this.element.appendChild(uiPart.element);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Destroys the UI part component. Unmounts UI parts from the editor.
|
|
37
|
+
*/
|
|
38
|
+
override async destroyed() {
|
|
39
|
+
// Let's hide the element during destruction to prevent flickering.
|
|
40
|
+
this.element.style.display = 'none';
|
|
41
|
+
|
|
42
|
+
// Let's wait for the mounted promise to resolve before proceeding with destruction.
|
|
43
|
+
await this.mountedPromise;
|
|
44
|
+
this.mountedPromise = null;
|
|
45
|
+
|
|
46
|
+
// Unmount all UI parts from the editor.
|
|
47
|
+
this.element.innerHTML = '';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Maps the UI part name to the corresponding view in the editor.
|
|
53
|
+
*/
|
|
54
|
+
function mapUIPartView(name: string): string | null {
|
|
55
|
+
switch (name) {
|
|
56
|
+
case 'toolbar':
|
|
57
|
+
return 'toolbar';
|
|
58
|
+
|
|
59
|
+
case 'menubar':
|
|
60
|
+
return 'menuBarView';
|
|
61
|
+
|
|
62
|
+
default:
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* A snapshot of the Livewire component's state relevant to the CKEditor5 UI part hook.
|
|
69
|
+
*/
|
|
70
|
+
export type Snapshot = {
|
|
71
|
+
/**
|
|
72
|
+
* The ID of the editor instance this UI part belongs to.
|
|
73
|
+
*/
|
|
74
|
+
editorId: string;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The name of the UI part (e.g., "toolbar", "menubar").
|
|
78
|
+
*/
|
|
79
|
+
name: string;
|
|
80
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { CanBePromise } from './types';
|
|
2
|
+
|
|
3
|
+
export type LivewireComponent<E = any> = {
|
|
4
|
+
id: string;
|
|
5
|
+
el: HTMLElement;
|
|
6
|
+
name: string;
|
|
7
|
+
ephemeral: E;
|
|
8
|
+
$wire: Wire;
|
|
9
|
+
effects: Record<string, unknown>;
|
|
10
|
+
canonical: Record<string, unknown>;
|
|
11
|
+
reactive: any;
|
|
12
|
+
children: Array<any>;
|
|
13
|
+
snapshot: Record<string, unknown>;
|
|
14
|
+
snapshotEncoded: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type Wire = {
|
|
18
|
+
set: (key: string | Record<string, any>, value?: any) => CanBePromise<void>;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type ComponentInitEvent = {
|
|
22
|
+
cleanup: (cb: VoidFunction) => void;
|
|
23
|
+
component: LivewireComponent;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
type Hook = {
|
|
27
|
+
(event: 'component.init', callback: (attrs: ComponentInitEvent) => void): void;
|
|
28
|
+
(event: string, callback: (attrs: any) => void): void;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export type LivewireGlobal = {
|
|
32
|
+
find: (id: string) => LivewireComponent | undefined;
|
|
33
|
+
all: () => LivewireComponent[];
|
|
34
|
+
on: (event: string, callback: (...params: any[]) => void) => void;
|
|
35
|
+
dispatch: (event: string, ...params: any[]) => void;
|
|
36
|
+
hook: Hook;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
declare global {
|
|
40
|
+
// eslint-disable-next-line vars-on-top
|
|
41
|
+
var Livewire: LivewireGlobal;
|
|
42
|
+
}
|