From 40f6f52e9ef48a3d8e62715e8ebcbad0b8512324 Mon Sep 17 00:00:00 2001 From: 7eliassen Date: Wed, 8 Jul 2026 12:18:47 +0300 Subject: [PATCH 1/5] fix/reset-flags --- src/application/services/useNoteEditor.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/application/services/useNoteEditor.ts b/src/application/services/useNoteEditor.ts index 1d5b4ad5..48ffffd4 100644 --- a/src/application/services/useNoteEditor.ts +++ b/src/application/services/useNoteEditor.ts @@ -144,6 +144,9 @@ export const useNoteEditor = function useNoteEditor(options: UseNoteEditorOption return; } + isEditorReady.value = false; + toolsUserConfigLoaded.value = false; + await loadToolsScripts(tools); }, { immediate: true, // load tools if they are passed to the composable immediately From f47175c2b4a9d5b40a8bc6fd2a9dc9335d3bd2f2 Mon Sep 17 00:00:00 2001 From: 7eliassen Date: Mon, 27 Jul 2026 19:34:05 +0300 Subject: [PATCH 2/5] fix: add reliable editor removal for onBeforeUnmount --- @codexteam/ui/src/vue/components/editor/useEditor.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/@codexteam/ui/src/vue/components/editor/useEditor.ts b/@codexteam/ui/src/vue/components/editor/useEditor.ts index e9d0b489..fe6daf97 100644 --- a/@codexteam/ui/src/vue/components/editor/useEditor.ts +++ b/@codexteam/ui/src/vue/components/editor/useEditor.ts @@ -126,8 +126,7 @@ export function useEditor(editorConfig: MaybeRefOrGetter, options: * Destroy editor instance after unmount */ onBeforeUnmount(() => { - editor?.destroy(); - editor = undefined; + destroyEditor() }); return { From 46ac19f08063cdd4015e5e52f64c35ef6819dbae Mon Sep 17 00:00:00 2001 From: 7eliassen Date: Mon, 27 Jul 2026 19:46:18 +0300 Subject: [PATCH 3/5] chore: lint fix --- @codexteam/ui/dev/pages/components/Editor.vue | 2 +- @codexteam/ui/src/vue/components/editor/useEditor.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/@codexteam/ui/dev/pages/components/Editor.vue b/@codexteam/ui/dev/pages/components/Editor.vue index c1680cdc..40c9a82a 100644 --- a/@codexteam/ui/dev/pages/components/Editor.vue +++ b/@codexteam/ui/dev/pages/components/Editor.vue @@ -40,7 +40,7 @@ placeholder="Write something or press / to select a tool" first-block-placeholder="Untitled" autofocus - :inlineToolbar="true" + :inline-toolbar="true" /> diff --git a/@codexteam/ui/src/vue/components/editor/useEditor.ts b/@codexteam/ui/src/vue/components/editor/useEditor.ts index fe6daf97..8fb7c533 100644 --- a/@codexteam/ui/src/vue/components/editor/useEditor.ts +++ b/@codexteam/ui/src/vue/components/editor/useEditor.ts @@ -126,7 +126,7 @@ export function useEditor(editorConfig: MaybeRefOrGetter, options: * Destroy editor instance after unmount */ onBeforeUnmount(() => { - destroyEditor() + destroyEditor(); }); return { From 06d665b4394a41e9e1573393879b830c061a368b Mon Sep 17 00:00:00 2001 From: 7eliassen Date: Mon, 27 Jul 2026 19:47:28 +0300 Subject: [PATCH 4/5] chore: update codexui version --- @codexteam/ui/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/@codexteam/ui/package.json b/@codexteam/ui/package.json index 50db201b..2550ce0f 100644 --- a/@codexteam/ui/package.json +++ b/@codexteam/ui/package.json @@ -1,6 +1,6 @@ { "name": "@codexteam/ui", - "version": "0.2.3", + "version": "0.2.5", "type": "module", "sideEffects": [ "*.css", From cf24fa8f1ad042d450caca216b3d011c5d4f19f9 Mon Sep 17 00:00:00 2001 From: 7eliassen Date: Mon, 27 Jul 2026 20:26:11 +0300 Subject: [PATCH 5/5] feat: add counter to prevent race condition --- src/application/services/useNoteEditor.ts | 41 +++++++++++++++++------ 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/src/application/services/useNoteEditor.ts b/src/application/services/useNoteEditor.ts index 48ffffd4..cdc76f4e 100644 --- a/src/application/services/useNoteEditor.ts +++ b/src/application/services/useNoteEditor.ts @@ -76,6 +76,13 @@ export const useNoteEditor = function useNoteEditor(options: UseNoteEditorOption */ const toolsUserConfigLoaded = ref(false); + /** + * Incremented on each new load request to discard stale async results. + * Prevents race conditions when rapid note switching causes multiple + * concurrent loadToolsScripts invocations. + */ + let currentLoadId = 0; + /** * Combine note and user tools * Undefined when user or note is not loaded @@ -102,10 +109,12 @@ export const useNoteEditor = function useNoteEditor(options: UseNoteEditorOption }); /** - * Downloads passed tools scripts and toggles-on the isEditorReady flag + * Downloads passed tools scripts and returns the loaded config object. + * Does not mutate shared state — the caller is responsible for applying the result * @param toolsConfigs - tools to download + * @returns loaded tools config */ - async function loadToolsScripts(toolsConfigs: EditorTool[]): Promise { + async function loadToolsScripts(toolsConfigs: EditorTool[]): Promise> { const loadedTools = await editorToolsService.getToolsLoaded(toolsConfigs); /** @@ -114,7 +123,7 @@ export const useNoteEditor = function useNoteEditor(options: UseNoteEditorOption */ const loadedToolsWithoutParagraph = loadedTools.filter(tool => tool.tool.name !== 'paragraph'); - toolsUserConfig = Object.fromEntries( + return Object.fromEntries( loadedToolsWithoutParagraph .map(toolClassAndInfo => [ toolClassAndInfo.tool.name, @@ -124,12 +133,6 @@ export const useNoteEditor = function useNoteEditor(options: UseNoteEditorOption }, ]) ); - toolsUserConfigLoaded.value = true; - - /** - * Now all tools are loaded, we're ready to use the editor - */ - isEditorReady.value = true; } /** @@ -144,10 +147,28 @@ export const useNoteEditor = function useNoteEditor(options: UseNoteEditorOption return; } + const loadId = ++currentLoadId; + isEditorReady.value = false; toolsUserConfigLoaded.value = false; - await loadToolsScripts(tools); + const loadedConfig = await loadToolsScripts(tools); + + /** + * If a newer load request has superseded this one — discard stale results + * to prevent overwriting state with tools from a previous note. + */ + if (loadId !== currentLoadId) { + return; + } + + toolsUserConfig = loadedConfig; + toolsUserConfigLoaded.value = true; + + /** + * Now all tools are loaded, we're ready to use the editor + */ + isEditorReady.value = true; }, { immediate: true, // load tools if they are passed to the composable immediately });