Extract editor-session lifecycle from App.vue#95
Merged
Conversation
App.vue owned the Muya editor instance and all of its low-level runtime machinery directly: the module-scope editor variable and init token, the host-element ref, initialization with stale-init protection, the destroy/remount cycle behind opening a document, Markdown snapshots and document-state sync, post-open focus release, and the input/selection diagnostic hooks. That machinery now lives in a dedicated editor-session factory (createEditorSession in src/features/editor/editorSession.ts), and App.vue reaches the editor only through the session accessors. The session deliberately does not become a second application controller: status text policy, autosave scheduling, toolbar and link/image business actions, navigation, persistence, and Android workflows all stay in App.vue and are reached through injected collaborators (syncMarkdown, focus/blur handlers, selection-lifecycle functions, autosave timer handles), following the same factory-with-injected-options pattern as the existing selection lifecycle, autosave scheduler, and persistence modules. Everything moved verbatim; the only equivalence rewrites are syncMarkdown reusing the extracted syncDocumentFromEditor (same guard, normalization, and update call) and the init-complete log reading documentState stats directly instead of through App computeds that resolve to the same fields. Initialization ordering, token-based stale protection, cleanup on destroy and unmount, suppression reasons, and diagnostics semantics are unchanged. editorRuntime now exports CreateMuyaEditorOptions so the session can type the injected factory. New editorSession tests cover open/ready wiring, missing host element, stale-init supersession, the remount-through-home cycle, snapshot and sync behavior, destroy/teardown, repeated open/close cycles, init failure, input-diagnostics install/teardown and late enabling, focus release, and input-state description.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Final proactive decomposition PR: the Muya editor instance and its runtime lifecycle move out of
App.vueinto a dedicated editor-session boundary,createEditorSessioninsrc/features/editor/editorSession.ts.App.vuedrops from 1,659 to 1,457 lines and no longer owns any low-level editor machinery — it composes screens and coordinates workflows, reaching the editor only through session accessors.Ownership boundary
Before:
App.vueheld the module-scopeeditorvariable, the init token, the host-element ref,initEditor/openEditor/destroyEditor, Markdown snapshot + document-state sync, post-open focus release, and the input/selection diagnostic hooks — ~250 lines of editor internals interleaved with page composition.After — owned by the session:
editorReadystateopenEditorgetEditorMarkdownSnapshot/syncDocumentFromEditor(and the sharednormalizeEditorMarkdown)describeEditorInputStateIntentionally still in
App.vue: navigation and screen composition,syncMarkdown(status text + autosave scheduling policy), focus/blur status handlers, Android document open/save/share workflows, persistence orchestration, home actions, back-button/exit decisions, toolbar and link/image business actions, settings maintenance, notices.Why this is a session boundary, not a second app controller
The session receives App policy as injected collaborators —
syncMarkdown, focus/blur handlers, the selection-lifecycle functions, autosave timer handles,closeEditorToolbar— and never decides status wording, autosave timing, or navigation policy itself. This is the same factory-with-injected-options pattern ascreateEditorSelectionLifecycle,createAutosaveScheduler, andcreateCurrentDocumentPersistence; the mutual references between session, scheduler, and selection lifecycle use the deferred-closure convention already established inApp.vue.Behavior equivalence
Every moved function is verbatim except two documented equivalence rewrites:
syncMarkdownnow calls the extractedsyncDocumentFromEditor(markDirty)— same editor guard, same normalization, sameupdateDocumentMarkdowncall it previously inlined.documentState.value.stats.*directly; the App computeds it previously used resolve to exactly those fields.Initialization ordering, suppression reasons (
editor-init,editor-init-stale,editor-init-failed,editor-destroy), token-based race protection, remount semantics (screen flip through home with suppression update skipped), unmount cleanup, and all logging are unchanged.editorRuntimegains only anexportonCreateMuyaEditorOptionsso the session can type the injected factory. No UI, persistence, navigation, or Android bridge changes;third_party/muyauntouched.Testing
editorSession.test.ts(14 tests, happy-dom): open/ready wiring, missing host element, stale-init supersession (a superseded init resolving late must not replace the live editor), remount-through-home cycle, snapshot/sync incl. flush and single-newline normalization, destroy/teardown, suppression skip on remount destroy, repeated open/close cycles, init failure, diagnostics install/teardown + late enabling via the settings watcher path, focus release, input-state description.pnpm build(includesvue-tsc -b) clean.mobile-home-navigation,mobile-local-draft-lifecycle,mobile-android-document-lifecycle,mobile-markdown-editing— 23/23 passed.Per the decomposition plan, this is the last size-driven extraction; further refactoring should be driven by product changes, bugs, or ownership conflicts.