UNPKG

@ckeditor/ckeditor5-vue

Version:

Official Vue.js 3+ component for CKEditor 5 – the best browser-based rich text editor.

1 lines 108 kB
{"version":3,"file":"ckeditor.umd.cjs","names":[],"sources":["../src/plugins/VueIntegrationUsageDataPlugin.ts","../src/utils/cleanupOrphanEditorElements.ts","../src/utils/wrapWithWatchdogIfPresent.ts","../src/composables/useIsUnmounted.ts","../src/composables/useEditorLifecycleEvents.ts","../src/composables/useEditorVModel.ts","../src/composables/useEditorReadOnly.ts","../src/composables/useEditorVersionCheck.ts","../src/utils/isClassicEditor.ts","../src/composables/useEditorElementDefinition.ts","../src/utils/normalizeEditorElementDefinition.ts","../src/DynamicElement.vue","../src/DynamicElement.vue","../src/Ckeditor.vue","../src/Ckeditor.vue","../src/CkeditorElement.vue","../src/CkeditorElement.vue","../src/multiroot/constants.ts","../src/multiroot/MultiRootEditorEditable.vue","../src/multiroot/MultiRootEditorEditable.vue","../src/multiroot/useMultiRootEditor.ts","../src/CkeditorMultiRoot.vue","../src/CkeditorMultiRoot.vue","../src/composables/useAsync.ts","../src/useCKEditorCloud.ts","../src/plugin.ts"],"sourcesContent":["/**\n * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options\n */\n\nimport { version } from 'vue';\nimport {\n\tcreateIntegrationUsageDataPlugin,\n\tappendExtraPluginsToEditorConfig,\n\tisCKEditorFreeLicense\n} from '@ckeditor/ckeditor5-integrations-common';\n\nimport type { EditorConfig } from 'ckeditor5';\n\n/**\n * This part of the code is not executed in open-source implementations using a GPL key.\n * It only runs when a specific license key is provided. If you are uncertain whether\n * this applies to your installation, please contact our support team.\n */\nexport const VueIntegrationUsageDataPlugin = createIntegrationUsageDataPlugin(\n\t'vue',\n\t{\n\t\tversion: __VUE_INTEGRATION_VERSION__,\n\t\tframeworkVersion: version\n\t}\n);\n\n/**\n * Appends all integration plugins to the editor configuration.\n *\n * @param editorConfig The editor configuration.\n * @returns The editor configuration with all integration plugins appended.\n */\nexport function appendUsageDataPluginToConfig( editorConfig: EditorConfig ): EditorConfig {\n\t/**\n\t * Do not modify the editor configuration if the editor is using a free license.\n\t */\n\tif ( isCKEditorFreeLicense( editorConfig.licenseKey ) ) {\n\t\treturn editorConfig;\n\t}\n\n\treturn appendExtraPluginsToEditorConfig( editorConfig, [\n\t\t/**\n\t\t * This part of the code is not executed in open-source implementations using a GPL key.\n\t\t * It only runs when a specific license key is provided. If you are uncertain whether\n\t\t * this applies to your installation, please contact our support team.\n\t\t */\n\t\tVueIntegrationUsageDataPlugin\n\t] );\n}\n","/**\n * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options\n */\n\nimport type { Editor } from 'ckeditor5';\n\n/**\n * Removes all DOM elements injected by a specific CKEditor instance.\n * Call this before assigning a new instance (e.g. in the 'restart' watchdog handler),\n * because the watchdog does not clean up the previous editor's DOM on its own.\n */\nexport function cleanupOrphanEditorElements( editor: Editor ): void {\n\tconst uiElement = editor.ui?.element;\n\n\tif ( uiElement?.isConnected ) {\n\t\tuiElement.remove();\n\t}\n\n\tconst bodyCollectionContainer = ( editor.ui as any )?.view?.body?._bodyCollectionContainer;\n\n\tif ( bodyCollectionContainer?.isConnected ) {\n\t\tbodyCollectionContainer.remove();\n\t}\n\n\tconst editingView = editor.editing?.view;\n\n\tif ( editingView ) {\n\t\tfor ( const domRoot of editingView.domRoots.values() ) {\n\t\t\tif ( !( domRoot instanceof HTMLElement ) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tdomRoot.removeAttribute( 'contenteditable' );\n\t\t\tdomRoot.removeAttribute( 'role' );\n\t\t\tdomRoot.removeAttribute( 'aria-label' );\n\t\t\tdomRoot.removeAttribute( 'aria-multiline' );\n\t\t\tdomRoot.removeAttribute( 'spellcheck' );\n\t\t\tdomRoot.classList.remove(\n\t\t\t\t'ck',\n\t\t\t\t'ck-content',\n\t\t\t\t'ck-editor__editable',\n\t\t\t\t'ck-rounded-corners',\n\t\t\t\t'ck-editor__editable_inline',\n\t\t\t\t'ck-blurred',\n\t\t\t\t'ck-focused'\n\t\t\t);\n\t\t}\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options\n */\n\nimport type { EditorRelaxedConstructor } from '@ckeditor/ckeditor5-integrations-common';\nimport type { EditorWithWatchdogRelaxedConstructor } from '../types.js';\nimport type { Editor, EditorWatchdog, WatchdogConfig } from 'ckeditor5';\n\nconst EDITOR_WATCHDOG_SYMBOL = Symbol.for( 'vue-editor-watchdog' );\n\nexport type EditorWithAttachedWatchdog<TEditor extends Editor = Editor> = TEditor & {\n\t[EDITOR_WATCHDOG_SYMBOL]?: EditorWatchdog;\n};\n\nexport type WatchdogErrorEventData<TEditor extends Editor> = {\n\terror: Error;\n\tcausesRestart: boolean;\n\twatchdog: EditorWatchdog;\n\teditor: TEditor;\n};\n\n/**\n * Returns an editor constructor optionally wrapped with EditorWatchdog.\n */\nexport function resolveEditorConstructor<TEditor extends Editor, TConstructor extends EditorWithWatchdogRelaxedConstructor<TEditor>>(\n\tEditor: TConstructor,\n\tdisableWatchdog: boolean,\n\twatchdogConfig?: WatchdogConfig\n): TConstructor {\n\treturn disableWatchdog ?\n\t\tEditor :\n\t\twrapWithWatchdogIfPresent( Editor, watchdogConfig ) as TConstructor;\n}\n\n/**\n * `EditorWatchdog#create` method does not return editor instance (returns `undefined` instead).\n * This function wraps editor constructor with EditorWatchdog and returns fake constructor that\n * returns editor instance assigned to initialized watchdog.\n *\n * It stores watchdog instance in hidden symbol assigned to editor. It simplifies storing both\n * instances in component's state (it's no longer required to store them separately).\n *\n * @param Editor The Editor creator to wrap.\n * @param watchdogConfig Watchdog configuration.\n * @returns The Editor creator wrapped with a watchdog.\n */\nexport function wrapWithWatchdogIfPresent<TEditor extends Editor>(\n\tEditor: EditorWithWatchdogRelaxedConstructor<TEditor>,\n\twatchdogConfig?: WatchdogConfig\n): EditorRelaxedConstructor<EditorWithAttachedWatchdog<TEditor>> {\n\tconst { EditorWatchdog } = Editor;\n\n\tif ( !EditorWatchdog ) {\n\t\treturn Editor;\n\t}\n\n\tconst watchdog = new EditorWatchdog( Editor, watchdogConfig );\n\n\twatchdog.setCreator( async ( ...args: Parameters<typeof Editor['create']> ) => {\n\t\tconst editor = await Editor.create( ...args );\n\n\t\t( editor as EditorWithAttachedWatchdog )[ EDITOR_WATCHDOG_SYMBOL ] = watchdog;\n\n\t\treturn editor;\n\t} );\n\n\treturn {\n\t\t...Editor,\n\t\teditorName: Editor.editorName,\n\t\tcreate: async ( ...args: Parameters<typeof watchdog.create> ) => {\n\t\t\tawait watchdog.create( ...args );\n\n\t\t\treturn watchdog.editor!;\n\t\t}\n\t};\n}\n\n/**\n * Unwraps the EditorWatchdog from the editor instance.\n *\n * @param editor Editor with attached watchdog.\n */\nexport function unwrapEditorWatchdog( editor: EditorWithAttachedWatchdog ): EditorWatchdog | null {\n\treturn editor[ EDITOR_WATCHDOG_SYMBOL ] ?? null;\n}\n\n/**\n * Attaches common EditorWatchdog runtime error handling.\n */\nexport function attachEditorWatchdogErrorHandler<TEditor extends Editor>(\n\teditor: EditorWithAttachedWatchdog<TEditor>,\n\t{\n\t\tisUnmounted,\n\t\tonError\n\t}: {\n\t\tisUnmounted: () => boolean;\n\t\tonError: ( data: WatchdogErrorEventData<TEditor> ) => void;\n\t}\n): EditorWatchdog | null {\n\tconst watchdog = unwrapEditorWatchdog( editor );\n\n\tif ( !watchdog ) {\n\t\treturn null;\n\t}\n\n\twatchdog.on( 'error', ( _, { error, causesRestart } ) => {\n\t\tif ( isUnmounted() ) {\n\t\t\treturn;\n\t\t}\n\n\t\tonError( {\n\t\t\terror,\n\t\t\tcausesRestart,\n\t\t\twatchdog,\n\t\t\teditor: watchdog.editor as TEditor\n\t\t} );\n\t} );\n\n\treturn watchdog;\n}\n\n/**\n * It destroys the editor watchdog if it is assigned to the editor. If it is not, the editor is destroyed.\n *\n * @param editor Editor with attached watchdog.\n */\nexport async function destroyEditorWithWatchdog( editor: EditorWithAttachedWatchdog ): Promise<void> {\n\tconst watchdog = unwrapEditorWatchdog( editor );\n\n\tif ( watchdog ) {\n\t\t// If watchdog is present on the editor, then destroy the watchdog. It'll automatically kill assigned editors.\n\t\tawait watchdog.destroy();\n\t} else {\n\t\t// If there is no watchdog, kill the editor.\n\t\tawait editor.destroy();\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options\n */\n\nimport { ref, onBeforeUnmount, type Ref } from 'vue';\n\nexport function useIsUnmounted(): Ref<boolean> {\n\tconst isUnmounted = ref( false );\n\n\tonBeforeUnmount( () => {\n\t\tisUnmounted.value = true;\n\t} );\n\n\treturn isUnmounted;\n}\n","/**\n * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options\n */\n\nimport type { Editor, EventInfo } from 'ckeditor5';\nimport { watch, type Ref, type EmitFn } from 'vue';\n\n/**\n * Hook that watches editor lifecycle events and maps them to Vue event emitters.\n */\nexport function useEditorLifecycleEvents<TEditor extends Editor>(\n\tinstance: Ref<TEditor | undefined>,\n\temit: EmitFn<EditorLifecycleEvents<TEditor>>\n): void {\n\twatch( instance, newInstance => {\n\t\t/* istanbul ignore if -- @preserve - Defensive check, instance never becomes undefined. */\n\t\tif ( !newInstance ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst { document } = newInstance.editing.view;\n\n\t\tdocument.on( 'focus', ( evt: EventInfo ) => emit( 'focus', evt, newInstance ) );\n\t\tdocument.on( 'blur', ( evt: EventInfo ) => emit( 'blur', evt, newInstance ) );\n\n\t\t// Let the world know the editor is ready.\n\t\temit( 'ready', newInstance );\n\n\t\tnewInstance.once( 'destroy', () => {\n\t\t\temit( 'destroy', newInstance );\n\t\t} );\n\t}, { flush: 'post' } );\n}\n\nexport type EditorLifecycleEvents<TEditor extends Editor> = {\n\tready: [ editor: TEditor ];\n\tdestroy: [ editor: TEditor ];\n\tblur: [ event: EventInfo, editor: TEditor ];\n\tfocus: [ event: EventInfo, editor: TEditor ];\n};\n","/**\n * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options\n */\n\nimport type { Editor, EventInfo } from 'ckeditor5';\nimport { debounce } from 'lodash-es';\nimport {\n\tref, watch, toValue,\n\ttype Ref, type EmitFn, type ModelRef, type MaybeRefOrGetter\n} from 'vue';\n\nimport { useIsUnmounted } from './useIsUnmounted.js';\n\nconst INPUT_EVENT_DEBOUNCE_WAIT = 300;\n\n/**\n * Hook that synchronizes editor state with currently set vue model.\n */\nexport function useEditorVModel<TEditor extends Editor>(\n\t{\n\t\tdisableTwoWayDataBinding,\n\t\temit,\n\t\tinstance,\n\t\tmodel\n\t}: Attrs<TEditor>\n): Result<TEditor> {\n\tconst lastEditorData = ref<string>();\n\tconst isUnmounted = useIsUnmounted();\n\n\t/**\n\t * Updates the internal cache and emits Vue-compatible events.\n\t */\n\tfunction assignEditorDataToModel( editor: TEditor, evt: EventInfo | null = null ) {\n\t\tconst data = lastEditorData.value = editor.data.get();\n\n\t\temit( 'update:modelValue', data, evt, editor );\n\t\temit( 'input', data, evt, editor );\n\t}\n\n\twatch( model, newModel => {\n\t\t// Synchronize changes of #modelValue. There are two sources of changes:\n\t\t//\n\t\t// External modelValue change ──────╮\n\t\t// ╰─────> ┏━━━━━━━━━━━┓\n\t\t// ┃ Component ┃\n\t\t// ╭─────> ┗━━━━━━━━━━━┛\n\t\t// Internal data change ──────╯\n\t\t// (typing, commands, collaboration)\n\t\t//\n\t\t// Case 1: If the change was external (via props), the editor data must be synced with\n\t\t// the component using instance#setData() and it is OK to destroy the selection.\n\t\t//\n\t\t// Case 2: If the change is the result of internal data change, the #modelValue is the\n\t\t// same as this.lastEditorData, which has been cached on #change:data. If we called\n\t\t// instance#setData() at this point, that would demolish the selection.\n\t\t//\n\t\t// To limit the number of instance#setData() which is time-consuming when there is a\n\t\t// lot of data we make sure:\n\t\t// * the new modelValue is at least different than the old modelValue (Case 1.)\n\t\t// * the new modelValue is different than the last internal instance state (Case 2.)\n\t\t//\n\t\t// See: https://github.com/ckeditor/ckeditor5-vue/issues/42.\n\t\tif ( instance.value && newModel !== lastEditorData.value ) {\n\t\t\tinstance.value.data.set( newModel );\n\t\t}\n\t} );\n\n\twatch( instance, ( newInstance, _oldInstance, onCleanup ) => {\n\t\t/* istanbul ignore if -- @preserve - Defensive check, instance never becomes undefined. */\n\t\tif ( !newInstance ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst emitDebouncedInputEvent = debounce( ( evt: EventInfo ) => {\n\t\t\tif ( toValue( disableTwoWayDataBinding ) || isUnmounted.value ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tassignEditorDataToModel( newInstance, evt );\n\t\t}, INPUT_EVENT_DEBOUNCE_WAIT, { leading: true } );\n\n\t\t// Debounce emitting the #input event. When data is huge, instance#getData()\n\t\t// takes a lot of time to execute on every single key press and ruins the UX.\n\t\t//\n\t\t// See: https://github.com/ckeditor/ckeditor5-vue/issues/42\n\t\tnewInstance.model.document.on( 'change:data', emitDebouncedInputEvent );\n\n\t\tnewInstance.once( 'destroy', () => {\n\t\t\temitDebouncedInputEvent.cancel();\n\t\t} );\n\n\t\tonCleanup( () => {\n\t\t\temitDebouncedInputEvent.cancel();\n\t\t} );\n\t} );\n\n\treturn {\n\t\tlastEditorData,\n\t\tassignEditorDataToModel\n\t};\n}\n\ntype Attrs<TEditor extends Editor> = {\n\tdisableTwoWayDataBinding: MaybeRefOrGetter<boolean>;\n\tmodel: ModelRef<string>;\n\temit: EmitFn<EditorVModelEvents<TEditor>>;\n\tinstance: Ref<TEditor | undefined>;\n};\n\ntype Result<TEditor extends Editor> = {\n\tlastEditorData: Ref<string | undefined>;\n\tassignEditorDataToModel( editor: TEditor, evt?: EventInfo | null ): void;\n};\n\nexport type EditorVModelEvents<TEditor extends Editor> = {\n\tinput: [ data: string, event: EventInfo | null, editor: TEditor ];\n\t'update:modelValue': [ data: string, event: EventInfo | null, editor: TEditor ];\n};\n","/**\n * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options\n */\n\nimport { toValue, watchEffect, type MaybeRefOrGetter } from 'vue';\nimport type { Editor } from 'ckeditor5';\n\nconst INTEGRATION_READ_ONLY_LOCK_ID = 'Lock from Vue integration (@ckeditor/ckeditor5-vue)';\n\n/**\n * Hook that toggles readonly state on provided instance.\n */\nexport function useEditorReadOnly(\n\tinstance: MaybeRefOrGetter<Editor | undefined>,\n\tdisabled: MaybeRefOrGetter<boolean | undefined>\n): void {\n\twatchEffect( () => {\n\t\tconst editor = toValue( instance );\n\t\tconst isDisabled = !!toValue( disabled );\n\n\t\tif ( editor ) {\n\t\t\ttoggleEditorReadOnly( editor, isDisabled );\n\t\t}\n\t}, { flush: 'sync' } );\n}\n\n/**\n * Toggles editor to readonly state.\n */\nfunction toggleEditorReadOnly( editor: Editor, readOnly: boolean ): void {\n\tif ( readOnly ) {\n\t\teditor.enableReadOnlyMode( INTEGRATION_READ_ONLY_LOCK_ID );\n\t} else {\n\t\teditor.disableReadOnlyMode( INTEGRATION_READ_ONLY_LOCK_ID );\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options\n */\n\nimport { compareInstalledCKBaseVersion } from '@ckeditor/ckeditor5-integrations-common';\n\n/**\n * Hook that check if integration is compatible with installed version of the editor.\n */\nexport function useEditorVersionCheck(): void {\n\tswitch ( compareInstalledCKBaseVersion( '42.0.0' ) ) {\n\t\tcase null:\n\t\t\tconsole.warn( 'Cannot find the \"CKEDITOR_VERSION\" in the \"window\" scope.' );\n\t\t\tbreak;\n\n\t\tcase -1:\n\t\t\tconsole.warn( 'The <CKEditor> component requires using CKEditor 5 in version 42+ or nightly build.' );\n\t\t\tbreak;\n\t}\n}\n","/**\n * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options\n */\n\nimport type { EditorRelaxedConstructor } from '@ckeditor/ckeditor5-integrations-common';\n\nexport function isClassicEditor( Editor: EditorRelaxedConstructor ): boolean {\n\treturn !Editor.editorName || Editor.editorName === 'ClassicEditor';\n}\n","/**\n * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options\n */\n\nimport { computed, toValue, type ComputedRef, type MaybeRefOrGetter } from 'vue';\nimport type { EditorRelaxedConfig } from '@ckeditor/ckeditor5-integrations-common';\n\nimport type { EditorWithWatchdogRelaxedConstructor } from '../types.js';\nimport type { EditorElementDefinition } from '../utils/normalizeEditorElementDefinition.js';\nimport { isClassicEditor } from '../utils/isClassicEditor.js';\n\n/**\n * Picks editor element definition from config if provided.\n */\nexport function useEditorElementDefinition(\n\t{\n\t\tEditor,\n\t\tconfig,\n\t\tdefaultElementName\n\t}: Options\n): ComputedRef<EditorElementDefinition> {\n\treturn computed<EditorElementDefinition>( () => {\n\t\tconst _config = toValue( config );\n\t\tconst _Editor = toValue( Editor );\n\n\t\tif ( !isClassicEditor( _Editor ) ) {\n\t\t\tconst customElementDefinition = _config.roots?.main?.element ?? _config.root?.element;\n\n\t\t\tif ( customElementDefinition ) {\n\t\t\t\treturn customElementDefinition;\n\t\t\t}\n\t\t}\n\n\t\treturn toValue( defaultElementName );\n\t} );\n}\n\ntype Options = {\n\tEditor: MaybeRefOrGetter<EditorWithWatchdogRelaxedConstructor>;\n\tconfig: MaybeRefOrGetter<EditorRelaxedConfig>;\n\tdefaultElementName: MaybeRefOrGetter<string>;\n};\n","/**\n * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options\n */\n\n/**\n * Normalizes an editor element definition into a structured object.\n *\n * @param definition The definition to normalize.\n * @returns A strictly typed object definition containing at least the element name.\n */\nexport function normalizeEditorElementDefinition( definition: EditorElementDefinition ): EditorElementObjectDefinition {\n\tif ( typeof HTMLElement !== 'undefined' && definition instanceof HTMLElement ) {\n\t\tthrow new Error(\n\t\t\t'An HTMLElement cannot be used as an editor element definition. ' +\n\t\t\t'Please pass a string or an object definition.'\n\t\t);\n\t}\n\n\tif ( typeof definition !== 'object' || definition === null ) {\n\t\treturn {\n\t\t\tname: definition\n\t\t};\n\t}\n\n\treturn definition as EditorElementObjectDefinition;\n}\n\n/**\n * Defines an editor element. It can be a tag name string or a detailed configuration object.\n */\nexport type EditorElementDefinition = string | EditorElementObjectDefinition;\n\n/**\n * An object-based definition for an editor element, allowing customization\n * of classes, styles, and HTML attributes.\n */\nexport type EditorElementObjectDefinition = {\n\n\t/**\n * The DOM tag name to use.\n */\n\tname: string;\n\n\t/**\n * Class name or array of class names to apply to the editable element. Each name can be provided as a string.\n */\n\tclasses?: string | Array<string>;\n\n\t/**\n * Inline styles to apply to the editable element as a record of style properties.\n */\n\tstyles?: Record<string, string>;\n\n\t/**\n * Additional DOM attributes to apply to the editable element.\n */\n\tattributes?: Record<string, string>;\n};\n","<!--\n * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options\n-->\n\n<script setup lang=\"ts\">\nimport { computed, ref } from 'vue';\n\nimport { type EditorElementDefinition, normalizeEditorElementDefinition } from './utils/normalizeEditorElementDefinition.js';\n\nconst props = withDefaults(\n\tdefineProps<{\n\t\tdefinition?: EditorElementDefinition | null;\n\t}>(),\n\t{\n\t\tdefinition: null\n\t}\n);\n\nconst elementRef = ref<HTMLElement>();\n\ndefineExpose( { elementRef } );\n\nconst definition = computed( () =>\n\tnormalizeEditorElementDefinition( props.definition ?? 'div' )\n);\n</script>\n\n<template>\n <component\n :is=\"definition.name\"\n ref=\"elementRef\"\n v-bind=\"definition.attributes\"\n :class=\"definition.classes\"\n :style=\"definition.styles\"\n />\n</template>\n","<!--\n * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options\n-->\n\n<script setup lang=\"ts\">\nimport { computed, ref } from 'vue';\n\nimport { type EditorElementDefinition, normalizeEditorElementDefinition } from './utils/normalizeEditorElementDefinition.js';\n\nconst props = withDefaults(\n\tdefineProps<{\n\t\tdefinition?: EditorElementDefinition | null;\n\t}>(),\n\t{\n\t\tdefinition: null\n\t}\n);\n\nconst elementRef = ref<HTMLElement>();\n\ndefineExpose( { elementRef } );\n\nconst definition = computed( () =>\n\tnormalizeEditorElementDefinition( props.definition ?? 'div' )\n);\n</script>\n\n<template>\n <component\n :is=\"definition.name\"\n ref=\"elementRef\"\n v-bind=\"definition.attributes\"\n :class=\"definition.classes\"\n :style=\"definition.styles\"\n />\n</template>\n","<!--\n * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options\n-->\n\n<template>\n <DynamicElement\n ref=\"editorElementRef\"\n :definition=\"elementDefinition\"\n />\n</template>\n\n<script\n\tsetup\n\tlang=\"ts\"\n\tgeneric=\"TEditorConstructor extends EditorWithWatchdogRelaxedConstructor\"\n>\nimport {\n\tref,\n\tonMounted,\n\tonBeforeUnmount,\n\tmarkRaw,\n\ttype Raw,\n\tgetCurrentInstance\n} from 'vue';\n\nimport type { CKEditorError, EditorConfig } from 'ckeditor5';\nimport type { EditorErrorDescription, EditorWithWatchdogRelaxedConstructor, Props } from './types.js';\n\nimport {\n\tassignElementToEditorConfig,\n\tassignInitialDataToEditorConfig,\n\tExtractEditorType,\n\tgetInstalledCKBaseFeatures\n} from '@ckeditor/ckeditor5-integrations-common';\n\nimport { appendUsageDataPluginToConfig } from './plugins/VueIntegrationUsageDataPlugin.js';\nimport { cleanupOrphanEditorElements } from './utils/cleanupOrphanEditorElements.js';\nimport {\n\tdestroyEditorWithWatchdog,\n\tattachEditorWatchdogErrorHandler,\n\tresolveEditorConstructor,\n\ttype EditorWithAttachedWatchdog\n} from './utils/wrapWithWatchdogIfPresent.js';\n\nimport { useIsUnmounted } from './composables/useIsUnmounted.js';\nimport { EditorLifecycleEvents, useEditorLifecycleEvents } from './composables/useEditorLifecycleEvents.js';\nimport { EditorVModelEvents, useEditorVModel } from './composables/useEditorVModel.js';\nimport { useEditorReadOnly } from './composables/useEditorReadOnly.js';\nimport { useEditorVersionCheck } from './composables/useEditorVersionCheck.js';\nimport { useEditorElementDefinition } from './composables/useEditorElementDefinition.js';\nimport DynamicElement from './DynamicElement.vue';\nimport { isClassicEditor } from './utils/isClassicEditor.js';\n\ntype TEditor = ExtractEditorType<TEditorConstructor>;\n\ndefineOptions( {\n\tname: 'CKEditor'\n} );\n\nconst model = defineModel( 'modelValue', { type: String, default: '' } );\nconst props = withDefaults( defineProps<Props<TEditorConstructor>>(), {\n\tconfig: () => ( {} ),\n\ttagName: 'div',\n\tdisableWatchdog: false,\n\tdisabled: false,\n\tdisableTwoWayDataBinding: false\n} );\n\nconst emit = defineEmits<\n\t& EditorLifecycleEvents<TEditor>\n\t& EditorVModelEvents<TEditor>\n\t& {\n\t\terror: [ error: Error | CKEditorError, description: EditorErrorDescription<TEditor> ],\n\t}\n>();\n\nconst currentInstance = getCurrentInstance();\nconst hasErrorHandler = () => !!currentInstance?.vnode.props?.onError;\n\nconst editorElementRef = ref<InstanceType<typeof DynamicElement>>();\nconst instance = ref<Raw<EditorWithAttachedWatchdog<TEditor>>>();\nconst isUnmounted = useIsUnmounted();\n\nconst { lastEditorData, assignEditorDataToModel } = useEditorVModel<TEditor>( {\n\tdisableTwoWayDataBinding: () => props.disableTwoWayDataBinding,\n\tmodel,\n\temit,\n\tinstance\n} );\n\nconst elementDefinition = useEditorElementDefinition({\n\tEditor: () => props.editor,\n\tconfig: () => props.config,\n\tdefaultElementName: () => props.tagName\n});\n\nuseEditorVersionCheck();\nuseEditorLifecycleEvents( instance, emit );\nuseEditorReadOnly( instance, () => props.disabled );\n\ndefineExpose( {\n\tinstance,\n\tlastEditorData\n} );\n\nonMounted( async () => {\n\tconst supports = getInstalledCKBaseFeatures();\n\n\t// Clone the config first so it never gets mutated (across multiple editor instances).\n\t// https://github.com/ckeditor/ckeditor5-vue/issues/101\n\tlet editorConfig: EditorConfig = appendUsageDataPluginToConfig( { ...props.config } );\n\n\t// Store model value before initialization to verify if it changed in the meantime.\n\tlet prevModelValue = model.value;\n\n\tif ( model.value ) {\n\t\teditorConfig = assignInitialDataToEditorConfig( editorConfig, model.value, true );\n\t}\n\n\tconst Constructor = resolveEditorConstructor( props.editor, props.disableWatchdog, props.watchdogConfig );\n\n\ttry {\n\t\tconst domElement = editorElementRef.value?.elementRef;\n\n\t\tif ( !domElement ) {\n\t\t\tthrow new Error( 'Editor element is not available. Make sure the component is mounted.' );\n\t\t}\n\n\t\tconst editor = await (\n\t\t\tsupports.elementConfigAttachment ?\n\t\t\t\tConstructor.create( assignElementToEditorConfig( Constructor, domElement, editorConfig ) ) :\n\t\t\t\tConstructor.create( domElement, editorConfig )\n\t\t) as unknown as EditorWithAttachedWatchdog<TEditor>;\n\n\t\tif ( isUnmounted.value ) {\n\t\t\tawait destroyEditorWithWatchdog( editor );\n\t\t\treturn;\n\t\t}\n\n\t\t// Synchronize the editor content. The #modelValue may change while the editor is being created, so the editor content has\n\t\t// to be synchronized with these potential changes as soon as it is ready.\n\t\tif ( model.value !== prevModelValue ) {\n\t\t\teditor.data.set( model.value );\n\t\t}\n\n\t\tconst watchdog = attachEditorWatchdogErrorHandler( editor, {\n\t\t\tisUnmounted: () => isUnmounted.value,\n\t\t\tonError: ( { error, watchdog, editor, causesRestart } ) => {\n\t\t\t\tif ( !hasErrorHandler() ) {\n\t\t\t\t\tconsole.error( error );\n\t\t\t\t}\n\n\t\t\t\temit( 'error', error, {\n\t\t\t\t\tphase: 'runtime',\n\t\t\t\t\twatchdog,\n\t\t\t\t\teditor,\n\t\t\t\t\tcausesRestart\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\n\t\tif ( watchdog ) {\n\t\t\twatchdog.on( 'restart', () => {\n\t\t\t\t// Sometimes editor leave a lot of orphaned elements. Try to remove them.\n\t\t\t\ttry {\n\t\t\t\t\tif ( instance.value && isClassicEditor( Constructor ) ) {\n\t\t\t\t\t\tcleanupOrphanEditorElements( instance.value );\n\t\t\t\t\t}\n\t\t\t\t} catch ( err ) {\n\t\t\t\t\tconsole.error( err );\n\t\t\t\t}\n\n\t\t\t\tif ( !isUnmounted.value ) {\n\t\t\t\t\tinstance.value = markRaw( watchdog.editor! as TEditor );\n\n\t\t\t\t\t// Rewind vue model back to old working state.\n\t\t\t\t\tassignEditorDataToModel( instance.value );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\tinstance.value = markRaw( editor );\n\t} catch ( error: any ) {\n\t\tif ( isUnmounted.value ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !hasErrorHandler() ) {\n\t\t\tconsole.error( error );\n\t\t}\n\n\t\temit( 'error', error, {\n\t\t\tphase: 'initialization'\n\t\t} );\n\t}\n} );\n\nonBeforeUnmount( async () => {\n\tconst editor = instance.value;\n\n\tif ( !editor ) {\n\t\treturn;\n\t}\n\n\tinstance.value = undefined;\n\n\tawait destroyEditorWithWatchdog( editor );\n} );\n</script>\n","<!--\n * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options\n-->\n\n<template>\n <DynamicElement\n ref=\"editorElementRef\"\n :definition=\"elementDefinition\"\n />\n</template>\n\n<script\n\tsetup\n\tlang=\"ts\"\n\tgeneric=\"TEditorConstructor extends EditorWithWatchdogRelaxedConstructor\"\n>\nimport {\n\tref,\n\tonMounted,\n\tonBeforeUnmount,\n\tmarkRaw,\n\ttype Raw,\n\tgetCurrentInstance\n} from 'vue';\n\nimport type { CKEditorError, EditorConfig } from 'ckeditor5';\nimport type { EditorErrorDescription, EditorWithWatchdogRelaxedConstructor, Props } from './types.js';\n\nimport {\n\tassignElementToEditorConfig,\n\tassignInitialDataToEditorConfig,\n\tExtractEditorType,\n\tgetInstalledCKBaseFeatures\n} from '@ckeditor/ckeditor5-integrations-common';\n\nimport { appendUsageDataPluginToConfig } from './plugins/VueIntegrationUsageDataPlugin.js';\nimport { cleanupOrphanEditorElements } from './utils/cleanupOrphanEditorElements.js';\nimport {\n\tdestroyEditorWithWatchdog,\n\tattachEditorWatchdogErrorHandler,\n\tresolveEditorConstructor,\n\ttype EditorWithAttachedWatchdog\n} from './utils/wrapWithWatchdogIfPresent.js';\n\nimport { useIsUnmounted } from './composables/useIsUnmounted.js';\nimport { EditorLifecycleEvents, useEditorLifecycleEvents } from './composables/useEditorLifecycleEvents.js';\nimport { EditorVModelEvents, useEditorVModel } from './composables/useEditorVModel.js';\nimport { useEditorReadOnly } from './composables/useEditorReadOnly.js';\nimport { useEditorVersionCheck } from './composables/useEditorVersionCheck.js';\nimport { useEditorElementDefinition } from './composables/useEditorElementDefinition.js';\nimport DynamicElement from './DynamicElement.vue';\nimport { isClassicEditor } from './utils/isClassicEditor.js';\n\ntype TEditor = ExtractEditorType<TEditorConstructor>;\n\ndefineOptions( {\n\tname: 'CKEditor'\n} );\n\nconst model = defineModel( 'modelValue', { type: String, default: '' } );\nconst props = withDefaults( defineProps<Props<TEditorConstructor>>(), {\n\tconfig: () => ( {} ),\n\ttagName: 'div',\n\tdisableWatchdog: false,\n\tdisabled: false,\n\tdisableTwoWayDataBinding: false\n} );\n\nconst emit = defineEmits<\n\t& EditorLifecycleEvents<TEditor>\n\t& EditorVModelEvents<TEditor>\n\t& {\n\t\terror: [ error: Error | CKEditorError, description: EditorErrorDescription<TEditor> ],\n\t}\n>();\n\nconst currentInstance = getCurrentInstance();\nconst hasErrorHandler = () => !!currentInstance?.vnode.props?.onError;\n\nconst editorElementRef = ref<InstanceType<typeof DynamicElement>>();\nconst instance = ref<Raw<EditorWithAttachedWatchdog<TEditor>>>();\nconst isUnmounted = useIsUnmounted();\n\nconst { lastEditorData, assignEditorDataToModel } = useEditorVModel<TEditor>( {\n\tdisableTwoWayDataBinding: () => props.disableTwoWayDataBinding,\n\tmodel,\n\temit,\n\tinstance\n} );\n\nconst elementDefinition = useEditorElementDefinition({\n\tEditor: () => props.editor,\n\tconfig: () => props.config,\n\tdefaultElementName: () => props.tagName\n});\n\nuseEditorVersionCheck();\nuseEditorLifecycleEvents( instance, emit );\nuseEditorReadOnly( instance, () => props.disabled );\n\ndefineExpose( {\n\tinstance,\n\tlastEditorData\n} );\n\nonMounted( async () => {\n\tconst supports = getInstalledCKBaseFeatures();\n\n\t// Clone the config first so it never gets mutated (across multiple editor instances).\n\t// https://github.com/ckeditor/ckeditor5-vue/issues/101\n\tlet editorConfig: EditorConfig = appendUsageDataPluginToConfig( { ...props.config } );\n\n\t// Store model value before initialization to verify if it changed in the meantime.\n\tlet prevModelValue = model.value;\n\n\tif ( model.value ) {\n\t\teditorConfig = assignInitialDataToEditorConfig( editorConfig, model.value, true );\n\t}\n\n\tconst Constructor = resolveEditorConstructor( props.editor, props.disableWatchdog, props.watchdogConfig );\n\n\ttry {\n\t\tconst domElement = editorElementRef.value?.elementRef;\n\n\t\tif ( !domElement ) {\n\t\t\tthrow new Error( 'Editor element is not available. Make sure the component is mounted.' );\n\t\t}\n\n\t\tconst editor = await (\n\t\t\tsupports.elementConfigAttachment ?\n\t\t\t\tConstructor.create( assignElementToEditorConfig( Constructor, domElement, editorConfig ) ) :\n\t\t\t\tConstructor.create( domElement, editorConfig )\n\t\t) as unknown as EditorWithAttachedWatchdog<TEditor>;\n\n\t\tif ( isUnmounted.value ) {\n\t\t\tawait destroyEditorWithWatchdog( editor );\n\t\t\treturn;\n\t\t}\n\n\t\t// Synchronize the editor content. The #modelValue may change while the editor is being created, so the editor content has\n\t\t// to be synchronized with these potential changes as soon as it is ready.\n\t\tif ( model.value !== prevModelValue ) {\n\t\t\teditor.data.set( model.value );\n\t\t}\n\n\t\tconst watchdog = attachEditorWatchdogErrorHandler( editor, {\n\t\t\tisUnmounted: () => isUnmounted.value,\n\t\t\tonError: ( { error, watchdog, editor, causesRestart } ) => {\n\t\t\t\tif ( !hasErrorHandler() ) {\n\t\t\t\t\tconsole.error( error );\n\t\t\t\t}\n\n\t\t\t\temit( 'error', error, {\n\t\t\t\t\tphase: 'runtime',\n\t\t\t\t\twatchdog,\n\t\t\t\t\teditor,\n\t\t\t\t\tcausesRestart\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\n\t\tif ( watchdog ) {\n\t\t\twatchdog.on( 'restart', () => {\n\t\t\t\t// Sometimes editor leave a lot of orphaned elements. Try to remove them.\n\t\t\t\ttry {\n\t\t\t\t\tif ( instance.value && isClassicEditor( Constructor ) ) {\n\t\t\t\t\t\tcleanupOrphanEditorElements( instance.value );\n\t\t\t\t\t}\n\t\t\t\t} catch ( err ) {\n\t\t\t\t\tconsole.error( err );\n\t\t\t\t}\n\n\t\t\t\tif ( !isUnmounted.value ) {\n\t\t\t\t\tinstance.value = markRaw( watchdog.editor! as TEditor );\n\n\t\t\t\t\t// Rewind vue model back to old working state.\n\t\t\t\t\tassignEditorDataToModel( instance.value );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\tinstance.value = markRaw( editor );\n\t} catch ( error: any ) {\n\t\tif ( isUnmounted.value ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !hasErrorHandler() ) {\n\t\t\tconsole.error( error );\n\t\t}\n\n\t\temit( 'error', error, {\n\t\t\tphase: 'initialization'\n\t\t} );\n\t}\n} );\n\nonBeforeUnmount( async () => {\n\tconst editor = instance.value;\n\n\tif ( !editor ) {\n\t\treturn;\n\t}\n\n\tinstance.value = undefined;\n\n\tawait destroyEditorWithWatchdog( editor );\n} );\n</script>\n","<!--\n * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options\n-->\n\n<template>\n <div ref=\"uiRef\" />\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, watchEffect } from 'vue';\nimport type { Editor } from 'ckeditor5';\n\ndefineOptions( {\n\tname: 'CkeditorElement'\n} );\n\ntype UIElementName = 'menuBar' | 'toolbar';\n\ntype EditorWithUIView = Editor & {\n\tui: {\n\t\tview: EditorUIViewWithElements;\n\t};\n};\n\ntype EditorUIViewWithElements = {\n\tmenuBarView?: {\n\t\telement?: HTMLElement | null;\n\t};\n\ttoolbar?: {\n\t\telement?: HTMLElement | null;\n\t};\n};\n\nconst props = withDefaults( defineProps<{\n\teditor?: EditorWithUIView | null;\n\telement?: UIElementName;\n}>(), {\n\teditor: null,\n\telement: 'toolbar'\n} );\n\nconst uiRef = ref<HTMLDivElement>();\n\nwatchEffect( onCleanup => {\n\tconst editor = props.editor;\n\tconst uiContainer = uiRef.value;\n\n\tif ( !editor || !uiContainer ) {\n\t\treturn;\n\t}\n\n\tconst uiElement = props.element === 'menuBar' ?\n\t\teditor.ui.view.menuBarView?.element :\n\t\teditor.ui.view.toolbar?.element;\n\n\tif ( !uiElement ) {\n\t\treturn;\n\t}\n\n\tuiContainer.appendChild( uiElement );\n\n\tonCleanup( () => {\n\t\tif ( uiContainer.contains( uiElement ) ) {\n\t\t\tuiContainer.removeChild( uiElement );\n\t\t}\n\t} );\n}, { flush: 'post' } );\n</script>\n","<!--\n * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options\n-->\n\n<template>\n <div ref=\"uiRef\" />\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, watchEffect } from 'vue';\nimport type { Editor } from 'ckeditor5';\n\ndefineOptions( {\n\tname: 'CkeditorElement'\n} );\n\ntype UIElementName = 'menuBar' | 'toolbar';\n\ntype EditorWithUIView = Editor & {\n\tui: {\n\t\tview: EditorUIViewWithElements;\n\t};\n};\n\ntype EditorUIViewWithElements = {\n\tmenuBarView?: {\n\t\telement?: HTMLElement | null;\n\t};\n\ttoolbar?: {\n\t\telement?: HTMLElement | null;\n\t};\n};\n\nconst props = withDefaults( defineProps<{\n\teditor?: EditorWithUIView | null;\n\telement?: UIElementName;\n}>(), {\n\teditor: null,\n\telement: 'toolbar'\n} );\n\nconst uiRef = ref<HTMLDivElement>();\n\nwatchEffect( onCleanup => {\n\tconst editor = props.editor;\n\tconst uiContainer = uiRef.value;\n\n\tif ( !editor || !uiContainer ) {\n\t\treturn;\n\t}\n\n\tconst uiElement = props.element === 'menuBar' ?\n\t\teditor.ui.view.menuBarView?.element :\n\t\teditor.ui.view.toolbar?.element;\n\n\tif ( !uiElement ) {\n\t\treturn;\n\t}\n\n\tuiContainer.appendChild( uiElement );\n\n\tonCleanup( () => {\n\t\tif ( uiContainer.contains( uiElement ) ) {\n\t\t\tuiContainer.removeChild( uiElement );\n\t\t}\n\t} );\n}, { flush: 'post' } );\n</script>\n","/**\n * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options\n */\n\nexport const ROOT_EDITABLE_OPTIONS_ATTRIBUTE = '$rootEditableOptions';\n","<!--\n * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options\n-->\n\n<template>\n <DynamicElement\n v-if=\"elementDefinition\"\n ref=\"editorElementRef\"\n :definition=\"elementDefinition\"\n />\n</template>\n\n\n<script setup lang=\"ts\">\nimport { computed, ref, watchEffect } from 'vue';\nimport type { MultiRootEditor } from 'ckeditor5';\n\nimport DynamicElement from '../DynamicElement.vue';\nimport { normalizeEditorElementDefinition } from '../utils/normalizeEditorElementDefinition.js';\nimport { ROOT_EDITABLE_OPTIONS_ATTRIBUTE } from './constants.js';\nimport type { RootEditableOptionsAttribute } from './types.js';\n\ndefineOptions( {\n\tname: 'CkeditorMultiRootEditable'\n} );\n\nconst props = withDefaults( defineProps<{\n\tid?: string;\n\trootName: string;\n\teditor?: MultiRootEditor | null;\n\teditableOptions?: RootEditableOptionsAttribute | null;\n}>(), {\n\tid: undefined,\n\teditor: null,\n\teditableOptions: null\n} );\n\nconst editorElementRef = ref<InstanceType<typeof DynamicElement>>();\n\nconst root = computed( () => props.editor?.model.document.getRoot( props.rootName ) ?? null );\n\nconst rootEditableOptions = computed<RootEditableOptionsAttribute | null>( () => {\n\tconst currentRoot = root.value;\n\n\tif ( !currentRoot ) {\n\t\treturn null;\n\t}\n\n\tconst options = props.editableOptions ??\n\t\tcurrentRoot.getAttribute( ROOT_EDITABLE_OPTIONS_ATTRIBUTE ) as RootEditableOptionsAttribute | undefined;\n\n\treturn { ...options };\n} );\n\nconst elementDefinition = computed( () => {\n\tconst options = rootEditableOptions.value;\n\n\tif ( !options ) {\n\t\treturn null;\n\t}\n\n\tconst normalizedDefinition = normalizeEditorElementDefinition( options.element ?? { name: 'div' } );\n\n\treturn {\n\t\t...normalizedDefinition,\n\t\tattributes: {\n\t\t\t...normalizedDefinition.attributes,\n\t\t\tid: props.id ?? props.rootName\n\t\t}\n\t};\n} );\n\nwatchEffect( onCleanup => {\n\tconst editor = props.editor;\n\tconst currentRoot = root.value;\n\tconst options = rootEditableOptions.value;\n\tconst element = editorElementRef.value?.elementRef;\n\n\tif ( !editor || !currentRoot || !options || !element ) {\n\t\treturn;\n\t}\n\n\tif ( editor.ui.getEditableElement( props.rootName ) ) {\n\t\teditor.detachEditable( currentRoot );\n\t}\n\n\tconst editable = editor.ui.view.createEditable( props.rootName, element, options.label );\n\n\teditable.isInlineRoot = !editor.model.schema.checkChild( currentRoot, '$block' );\n\teditor.ui.addEditable( editable, options.placeholder );\n\teditor.editing.view.forceRender();\n\n\tonCleanup( () => {\n\t\tif ( editor.state === 'destroyed' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst latestRoot = editor.model.document.getRoot( props.rootName );\n\n\t\tif ( latestRoot === currentRoot ) {\n\t\t\teditor.detachEditable( currentRoot );\n\t\t}\n\t} );\n}, { flush: 'post' } );\n</script>\n","<!--\n * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options\n-->\n\n<template>\n <DynamicElement\n v-if=\"elementDefinition\"\n ref=\"editorElementRef\"\n :definition=\"elementDefinition\"\n />\n</template>\n\n\n<script setup lang=\"ts\">\nimport { computed, ref, watchEffect } from 'vue';\nimport type { MultiRootEditor } from 'ckeditor5';\n\nimport DynamicElement from '../DynamicElement.vue';\nimport { normalizeEditorElementDefinition } from '../utils/normalizeEditorElementDefinition.js';\nimport { ROOT_EDITABLE_OPTIONS_ATTRIBUTE } from './constants.js';\nimport type { RootEditableOptionsAttribute } from './types.js';\n\ndefineOptions( {\n\tname: 'CkeditorMultiRootEditable'\n} );\n\nconst props = withDefaults( defineProps<{\n\tid?: string;\n\trootName: string;\n\teditor?: MultiRootEditor | null;\n\teditableOptions?: RootEditableOptionsAttribute | null;\n}>(), {\n\tid: undefined,\n\teditor: null,\n\teditableOptions: null\n} );\n\nconst editorElementRef = ref<InstanceType<typeof DynamicElement>>();\n\nconst root = computed( () => props.editor?.model.document.getRoot( props.rootName ) ?? null );\n\nconst rootEditableOptions = computed<RootEditableOptionsAttribute | null>( () => {\n\tconst currentRoot = root.value;\n\n\tif ( !currentRoot ) {\n\t\treturn null;\n\t}\n\n\tconst options = props.editableOptions ??\n\t\tcurrentRoot.getAttribute( ROOT_EDITABLE_OPTIONS_ATTRIBUTE ) as RootEditableOptionsAttribute | undefined;\n\n\treturn { ...options };\n} );\n\nconst elementDefinition = computed( () => {\n\tconst options = rootEditableOptions.value;\n\n\tif ( !options ) {\n\t\treturn null;\n\t}\n\n\tconst normalizedDefinition = normalizeEditorElementDefinition( options.element ?? { name: 'div' } );\n\n\treturn {\n\t\t...normalizedDefinition,\n\t\tattributes: {\n\t\t\t...normalizedDefinition.attributes,\n\t\t\tid: props.id ?? props.rootName\n\t\t}\n\t};\n} );\n\nwatchEffect( onCleanup => {\n\tconst editor = props.editor;\n\tconst currentRoot = root.value;\n\tconst options = rootEditableOptions.value;\n\tconst element = editorElementRef.value?.elementRef;\n\n\tif ( !editor || !currentRoot || !options || !element ) {\n\t\treturn;\n\t}\n\n\tif ( editor.ui.getEditableElement( props.rootName ) ) {\n\t\teditor.detachEditable( currentRoot );\n\t}\n\n\tconst editable = editor.ui.view.createEditable( props.rootName, element, options.label );\n\n\teditable.isInlineRoot = !editor.model.schema.checkChild( currentRoot, '$block' );\n\teditor.ui.addEditable( editable, options.placeholder );\n\teditor.editing.view.forceRender();\n\n\tonCleanup( () => {\n\t\tif ( editor.state === 'destroyed' ) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst latestRoot = editor.model.document.getRoot( props.rootName );\n\n\t\tif ( latestRoot === currentRoot ) {\n\t\t\teditor.detachEditable( currentRoot );\n\t\t}\n\t} );\n}, { flush: 'post' } );\n</script>\n","/**\n * @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options\n */\n\nimport {\n\tmarkRaw,\n\tnextTick,\n\tonBeforeUnmount,\n\tonMounted,\n\tref,\n\ttoValue,\n\twatch,\n\ttype MaybeRefOrGetter,\n\ttype Ref\n} from 'vue';\nimport { debounce } from 'lodash-es';\n\nimport type {\n\tAddRootEvent,\n\tCKEditorError,\n\tDetachRootEvent,\n\tEditorConfig,\n\tEventInfo,\n\tInlineEditableUIView,\n\tModelRootElement,\n\tModelWriter,\n\tMultiRootEditor,\n\tWatchdogConfig\n} from 'ckeditor5';\n\nimport {\n\tassignAttributesPropToMultiRootEditorConfig,\n\tassignInitialDataToMultirootEditorConfig,\n\tgetInstalledCKBaseFeatures,\n\ttype ExtractEditorType\n} from '@ckeditor/ckeditor5-integrations-common';\n\nimport { appendUsageDataPluginToConfig } from '../plugins/VueIntegrationUsageDataPlugin.js';\nimport { useIsUnmounted } from '../composables/useIsUnmounted.js';\nimport { useEditorReadOnly } from '../composables/useEditorReadOnly.js';\nimport { cleanupOrphanEditorElements } from '../utils/cleanupOrphanEditorElements.js';\nimport {\n\tattachEditorWatchdogErrorHandler,\n\tdestroyEditorWithWatchdog,\n\tresolveEditorConstructor,\n\ttype EditorWithAttachedWatchdog\n} from '../utils/wrapWithWatchdogIfPresent.js';\n\nimport { ROOT_EDITABLE_OPTIONS_ATTRIBUTE } from './constants.js';\nimport type {\n\tAddRootOptions,\n\tMultiRootEditorData,\n\tMultiRootEditorErrorDescription,\n\tMultiRootEditorRootsAttributes,\n\tMultiRootEditorWithWatchdogRelaxedConstructor\n} from './types.js';\n\nconst INPUT_EVENT_DEBOUNCE_WAIT = 300;\nconst EDITOR_DESTROYED_BEFORE_READY_MESSAGE = 'The editor was destroyed before it became ready.';\n\ntype EditorReadyCallback<TEditor extends MultiRootEditor> = {\n\tresolve: ( editor: TEditor ) => void;\n\treject: ( error: Error ) => void;\n};\n\nexport function useMultiRootEditor<TEditorConstructor extends MultiRootEditorWithWatchdogRelaxedConstructor>(\n\toptions: UseMultiRootEditorOptions<TEditorConstructor>\n): UseMultiRootEditorResult<ExtractEditorType<TEditorConstructor> & MultiRootEditor> {\n\ttype TEditor = ExtractEditorType<TEditorConstructor> & MultiRootEditor;\n\n\tconst isUnmounted = useIsUnmounted();\n\tconst instance = ref<EditorWithAttachedWatchdog<TEditor>>();\n\tconst data = ref<MultiRootEditorData>( cloneData( toValue( options.data ) ) );\n\tconst rootsAttributes = ref<MultiRootEditorRootsAttributes>(\n\t\tnormalizeRootsAttributes( toValue( options.rootsAttributes ), data.value )\n\t);\n\tconst roots = ref<Array<string>>( Object.keys( data.value ) );\n\tconst shouldUpdateEditor = ref( false );\n\tconst lastEditorData = ref<MultiRootEditorData>();\n\tconst lastEditorRootsAttributes = ref<MultiRootEditorRootsAttributes>();\n\n\tlet editorReadyCallbacks: Array<EditorReadyCallback<TEditor>> = [];\n\n\tuseEditorReadOnly( instance, () => toValue( options.disabled ) );\n\n\twatch( () => toValue( options.data ), newData => {\n\t\tif ( instance.value && lastEditorData.value && areRecordsEqual( newData, lastEditorData.value ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tsetData( cloneData( newData ) );\n\t}, { deep: true } );\n\n\twatch( () => toValue( options.rootsAttributes ), newRootsAttributes => {\n\t\tconst sourceRootsAttributes = cloneRootsAttributes( newRootsAttributes );\n\t\tconst normalizedRootsAttributes = normalizeRootsAttributes( newRootsAttributes, data.value );\n\t\tconst nextRootsAttributes = instance.value ?\n\t\t\tmergeRootsAttributes( rootsAttributes.value, normalizedRootsAttributes, data.value ) :\n\t\t\tnormalizedRootsAttributes;\n\t\tconst shouldEmitNormalizedRootsAttributes = !!instance.value && !areRecordsEqual( nextRootsAttributes, sourceRootsAttributes );\n\n\t\tif (\n\t\t\tinstance.value &&\n\t\t\tlastEditorRootsAttributes.value &&\n\t\t\tareRecordsEqual( nextRootsAttributes, lastEditorRootsAttributes.value )\n\t\t) {\n\t\t\tif ( shouldEmitNormalizedRootsAttributes ) {\n\t\t\t\tsetRootsAttributes( nextRootsAttributes );\n\t\t\t\temitRootsAttributes( null, instance.value as TEditor );\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tsetRootsAttributes( nextRootsAttributes );\n\n\t\tif ( shouldEmitNormalizedRootsAttributes ) {\n\t\t\temitRootsAttributes( null, instance.value as TEditor );\n\t\t}\n\t}, { deep: true } );\n\n\twatch( [ data, rootsAttributes ], () => {\n\t\tconst editor = instance.value;\n\n\t\tif ( !editor || !shouldUpdateEditor.value ) {\n\t\t\treturn;\n\t\t}\n\n\t\tshouldUpdateEditor.value = false;\n\t\tsyncEditorWithState( editor );\n\t}, { deep: true, flush: 'post' } );\n\n\twatch( instance, async ( newInstance, _oldInstance, onCleanup ) => {\n\t\t/* istanbul ignore if -- @preserve - Defensive check, instance can only be set to an editor here. */\n\t\tif ( !newInstance ) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet isCurrentInstance = true;\n\t\tconst editor = newInstance as TEditor;\n\t\tconst modelDocument = editor.model.document;\n\t\tconst viewDocument = editor.editing.view.document;\n\t\tconst emitDebouncedDataUpdate = debounce( ( event: EventInfo ) => {\n\t\t\tupdateStateFromEditor( editor, event );\n\t\t}, INPUT_EVENT_DEBOUNCE_WAIT, { leading: true } );\n\t\tconst onChangeDataListener = ( event: EventInfo ) => onChangeData( editor, event, emitDebouncedDataUpdate );\n\t\tconst onAddRootListener = ( event: EventInfo, root: ModelRootElement ) => onAddRoot( editor, event, root );\n\t\tconst onDetachRootListener = ( event: EventInfo, root: ModelRootElement ) => onDetachRoot( editor, event, root );\n\t\tconst onFocusListener = ( event: EventInfo ) => options