[{"data":1,"prerenderedAt":613},["ShallowReactive",2],{"msfe-doc:\u002Fen\u002Fguide\u002Fvue":3},{"id":4,"title":5,"body":6,"description":597,"extension":598,"keywords":599,"locale":605,"meta":606,"navigation":124,"order":607,"path":608,"section":609,"seo":610,"stem":611,"__hash__":612},"docs\u002Fguide\u002Fvue.en.md","Vue integration",{"type":7,"value":8,"toc":588},"minimark",[9,14,38,310,313,335,339,360,364,368,383,461,475,497,508,512,519,523,539,543,550,553,557,573,584],[10,11,13],"h2",{"id":12},"create-and-mount","Create and mount",[15,16,17,21,22,25,26,29,30,33,34,37],"p",{},[18,19,20],"code",{},"useMsfeEditor()"," returns the shallow ",[18,23,24],{},"editor"," ref and component ",[18,27,28],{},"host",". Render ",[18,31,32],{},"VueNodeViewHost"," in your template so component views retain your application's ",[18,35,36],{},"provide\u002Finject"," context.",[39,40,45],"pre",{"className":41,"code":42,"language":43,"meta":44,"style":44},"language-vue shiki shiki-themes github-light github-light github-dark","\u003Cscript setup lang=\"ts\">\nimport { shallowRef } from 'vue'\nimport { useMsfeEditor, VueNodeViewHost } from '@quirekit\u002Fmsfe-vue'\nimport { StarterKit } from '@quirekit\u002Fmsfe-starter-kit'\n\nconst parent = shallowRef\u003CHTMLElement | null>(null)\nconst { editor, host } = useMsfeEditor(parent, () => ({\n  markdown: '## Start writing',\n  mode: 'live',\n  extensions: [StarterKit],\n}))\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv ref=\"parent\" \u002F>\n  \u003CVueNodeViewHost :host=\"host\" \u002F>\n\u003C\u002Ftemplate>\n","vue","",[18,46,47,77,93,106,119,126,162,194,206,217,223,229,239,244,254,277,301],{"__ignoreMap":44},[48,49,52,56,60,64,67,70,74],"span",{"class":50,"line":51},"line",1,[48,53,55],{"class":54},"sVPnS","\u003C",[48,57,59],{"class":58},"su0ou","script",[48,61,63],{"class":62},"sgQzM"," setup",[48,65,66],{"class":62}," lang",[48,68,69],{"class":54},"=",[48,71,73],{"class":72},"s-HEn","\"ts\"",[48,75,76],{"class":54},">\n",[48,78,80,84,87,90],{"class":50,"line":79},2,[48,81,83],{"class":82},"sDD9d","import",[48,85,86],{"class":54}," { shallowRef } ",[48,88,89],{"class":82},"from",[48,91,92],{"class":72}," 'vue'\n",[48,94,96,98,101,103],{"class":50,"line":95},3,[48,97,83],{"class":82},[48,99,100],{"class":54}," { useMsfeEditor, VueNodeViewHost } ",[48,102,89],{"class":82},[48,104,105],{"class":72}," '@quirekit\u002Fmsfe-vue'\n",[48,107,109,111,114,116],{"class":50,"line":108},4,[48,110,83],{"class":82},[48,112,113],{"class":54}," { StarterKit } ",[48,115,89],{"class":82},[48,117,118],{"class":72}," '@quirekit\u002Fmsfe-starter-kit'\n",[48,120,122],{"class":50,"line":121},5,[48,123,125],{"emptyLinePlaceholder":124},true,"\n",[48,127,129,132,136,139,142,144,147,150,153,156,159],{"class":50,"line":128},6,[48,130,131],{"class":82},"const",[48,133,135],{"class":134},"sUNQB"," parent",[48,137,138],{"class":82}," =",[48,140,141],{"class":62}," shallowRef",[48,143,55],{"class":54},[48,145,146],{"class":62},"HTMLElement",[48,148,149],{"class":82}," |",[48,151,152],{"class":134}," null",[48,154,155],{"class":54},">(",[48,157,158],{"class":134},"null",[48,160,161],{"class":54},")\n",[48,163,165,167,170,172,175,177,180,182,185,188,191],{"class":50,"line":164},7,[48,166,131],{"class":82},[48,168,169],{"class":54}," { ",[48,171,24],{"class":134},[48,173,174],{"class":54},", ",[48,176,28],{"class":134},[48,178,179],{"class":54}," } ",[48,181,69],{"class":82},[48,183,184],{"class":62}," useMsfeEditor",[48,186,187],{"class":54},"(parent, () ",[48,189,190],{"class":82},"=>",[48,192,193],{"class":54}," ({\n",[48,195,197,200,203],{"class":50,"line":196},8,[48,198,199],{"class":54},"  markdown: ",[48,201,202],{"class":72},"'## Start writing'",[48,204,205],{"class":54},",\n",[48,207,209,212,215],{"class":50,"line":208},9,[48,210,211],{"class":54},"  mode: ",[48,213,214],{"class":72},"'live'",[48,216,205],{"class":54},[48,218,220],{"class":50,"line":219},10,[48,221,222],{"class":54},"  extensions: [StarterKit],\n",[48,224,226],{"class":50,"line":225},11,[48,227,228],{"class":54},"}))\n",[48,230,232,235,237],{"class":50,"line":231},12,[48,233,234],{"class":54},"\u003C\u002F",[48,236,59],{"class":58},[48,238,76],{"class":54},[48,240,242],{"class":50,"line":241},13,[48,243,125],{"emptyLinePlaceholder":124},[48,245,247,249,252],{"class":50,"line":246},14,[48,248,55],{"class":54},[48,250,251],{"class":58},"template",[48,253,76],{"class":54},[48,255,257,260,263,266,268,271,275],{"class":50,"line":256},15,[48,258,259],{"class":54},"  \u003C",[48,261,262],{"class":58},"div",[48,264,265],{"class":62}," ref",[48,267,69],{"class":54},[48,269,270],{"class":72},"\"parent\"",[48,272,274],{"class":273},"shEpO"," \u002F",[48,276,76],{"class":54},[48,278,280,282,284,287,289,291,294,296,298],{"class":50,"line":279},16,[48,281,259],{"class":54},[48,283,32],{"class":58},[48,285,286],{"class":54}," :",[48,288,28],{"class":62},[48,290,69],{"class":54},[48,292,293],{"class":72},"\"",[48,295,28],{"class":54},[48,297,293],{"class":72},[48,299,300],{"class":54}," \u002F>\n",[48,302,304,306,308],{"class":50,"line":303},17,[48,305,234],{"class":54},[48,307,251],{"class":58},[48,309,76],{"class":54},[15,311,312],{},"The composable creates the instance after mounting and disposes of the editor and component host on unmount. Do not create a separate Vue application for node rendering.",[15,314,315,318,319,322,323,326,327,330,331,334],{},[18,316,317],{},"options.onError"," receives runtime errors and exceptions from ",[18,320,321],{},"createMsfeEditor()"," during creation.\nAfter failed creation, ",[18,324,325],{},"editor.value"," remains ",[18,328,329],{},"undefined"," and the component host is disposed.\nDisplay an error and preserve the source before explicitly remounting with corrected configuration.\nWithout ",[18,332,333],{},"onError",", creation exceptions continue to Vue's error handling. Exceptions from the options\nfactory itself also remain Vue-owned. The composable never retries or rebuilds a document automatically.",[10,336,338],{"id":337},"update-content-and-mode","Update content and mode",[15,340,341,342,174,345,174,348,351,352,355,356,359],{},"Initial options are not deeply watched. After mounting, use ",[18,343,344],{},"setMode()",[18,346,347],{},"setReadOnly()",[18,349,350],{},"applyChanges()",", or ",[18,353,354],{},"replaceDocument()",". Avoid writing the entire document back after each keystroke through a full-text ",[18,357,358],{},"v-model",".",[361,362],"msfe-demo",{"name":363},"basic\u002Feditor",[10,365,367],{"id":366},"observe-editor-state-in-vue","Observe editor state in Vue",[15,369,370,371,374,375,378,379,382],{},"Use ",[18,372,373],{},"useMsfeState()"," inside ",[18,376,377],{},"setup()"," instead of wiring ",[18,380,381],{},"watch(editor)",", initial snapshots and cleanup yourself:",[39,384,388],{"className":385,"code":386,"language":387,"meta":44,"style":44},"language-ts shiki shiki-themes github-light github-light github-dark","import { useMsfeState } from '@quirekit\u002Fmsfe-vue'\n\nconst state = useMsfeState(editor) \u002F\u002F Pass directly to MdProse.state\nconst cursor = useMsfeState(editor, {\n  select: state => state.selection.main.head,\n})\n","ts",[18,389,390,401,405,424,438,456],{"__ignoreMap":44},[48,391,392,394,397,399],{"class":50,"line":51},[48,393,83],{"class":82},[48,395,396],{"class":54}," { useMsfeState } ",[48,398,89],{"class":82},[48,400,105],{"class":72},[48,402,403],{"class":50,"line":79},[48,404,125],{"emptyLinePlaceholder":124},[48,406,407,409,412,414,417,420],{"class":50,"line":95},[48,408,131],{"class":82},[48,410,411],{"class":134}," state",[48,413,138],{"class":82},[48,415,416],{"class":62}," useMsfeState",[48,418,419],{"class":54},"(editor) ",[48,421,423],{"class":422},"sqmzS","\u002F\u002F Pass directly to MdProse.state\n",[48,425,426,428,431,433,435],{"class":50,"line":108},[48,427,131],{"class":82},[48,429,430],{"class":134}," cursor",[48,432,138],{"class":82},[48,434,416],{"class":62},[48,436,437],{"class":54},"(editor, {\n",[48,439,440,443,446,450,453],{"class":50,"line":121},[48,441,442],{"class":62},"  select",[48,444,445],{"class":54},": ",[48,447,449],{"class":448},"sde8i","state",[48,451,452],{"class":82}," =>",[48,454,455],{"class":54}," state.selection.main.head,\n",[48,457,458],{"class":50,"line":128},[48,459,460],{"class":54},"})\n",[15,462,463,464,467,468,470,471,474],{},"The source accepts an instance, ref or getter such as ",[18,465,466],{},"() => props.editor",". The result is a readonly\nshallow ref. It is ",[18,469,329],{}," before creation, after failed creation, or when the instance is cleared\nor destroyed; use ",[18,472,473],{},"v-if=\"state\""," to wait for a snapshot. Scope disposal and instance replacement\nautomatically unsubscribe, without destroying a borrowed editor.",[15,476,477,478,481,482,485,486,489,490,493,494,359],{},"The composable connects to MSFE's ",[18,479,480],{},"subscribeState()"," and observes accepted CodeMirror states only.\nReferences update synchronously without cloning state, reparsing, serializing the document or writing\nback. Components that do not call this composable gain no subscription. ",[18,483,484],{},"select"," and optional ",[18,487,488],{},"equal","\nfollow the core contract: selectors must be pure and bounded, run once per accepted update, and notify\nVue only when their result changes. Equality defaults to ",[18,491,492],{},"Object.is",". For newly allocated objects,\nprovide a comparator such as ",[18,495,496],{},"equal: (a, b) => a.from === b.from && a.to === b.to",[15,498,499,500,503,504,507],{},"The selector is fixed when the composable is created. It depends on the supplied immutable state and\ndoes not track other Vue refs read inside it. Combine reactive inputs such as locale with the returned\nvalue in a separate ",[18,501,502],{},"computed()",". Use full snapshots for readers and narrow fields for small controls.\n",[18,505,506],{},"MdProse"," still decides whether selection-only changes can reuse reading content.",[10,509,511],{"id":510},"nuxt-and-server-rendering","Nuxt and server rendering",[15,513,514,515,518],{},"The editor requires the browser DOM. In Nuxt, use a client component or ",[18,516,517],{},"ClientOnly"," around the editor mount; documentation and navigation can still render on the server. Reserve reasonable placeholder height to limit layout shifts during loading.",[10,520,522],{"id":521},"custom-components","Custom components",[15,524,370,525,528,529,532,533,538],{},[18,526,527],{},"VueNodeViewRenderer()"," to replace a source node's UI, or ",[18,530,531],{},"VueComponentViewRenderer()"," for controls such as search panels. See ",[534,535,537],"a",{"href":536},"\u002Fen\u002Fextensions\u002Fcustom-node","Custom nodes"," for the complete field-update lifecycle.",[10,540,542],{"id":541},"providers-and-nodeviews","Providers and NodeViews",[15,544,545,546,549],{},"Provide locale, permissions and host services through the existing application tree. NodeViews and ComponentViews retain that context through the Host; ",[18,547,548],{},"shared\u002Flocale.ts"," demonstrates localization. Do not persist reactive UI objects or services in Markdown attributes.",[15,551,552],{},"Changing the complete extension set requires an explicit lifecycle decision: preserve source and required host state, then recreate. The options factory is an initialization entry, not a deep reactive configuration or hot plugin loader.",[10,554,556],{"id":555},"nuxt-checks","Nuxt checks",[558,559,560,564,567,570],"ol",{},[561,562,563],"li",{},"Create the DOM editor in client-only components and render explanatory content\u002Fplaceholders on the server.",[561,565,566],{},"Avoid duplicate Vue and CodeMirror state\u002Fview copies; deduplicate linked workspace packages in the bundler.",[561,568,569],{},"Install component dependencies in the consuming app rather than relying on documentation-site aliases.",[561,571,572],{},"Resolve unsaved state before routing away. Unmount cleanup alone cannot guarantee persistence.",[15,574,575,576,579,580,359],{},"For complex components see ",[534,577,578],{"href":536},"nodes"," and ",[534,581,583],{"href":582},"\u002Fen\u002Fextensions\u002Fdiagrams","diagrams",[585,586,587],"style",{},"html pre.shiki code .sVPnS, html code.shiki .sVPnS{--shiki-default:#24292E;--shiki-light:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .su0ou, html code.shiki .su0ou{--shiki-default:#22863A;--shiki-light:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sgQzM, html code.shiki .sgQzM{--shiki-default:#6F42C1;--shiki-light:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s-HEn, html code.shiki .s-HEn{--shiki-default:#032F62;--shiki-light:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sDD9d, html code.shiki .sDD9d{--shiki-default:#D73A49;--shiki-light:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sUNQB, html code.shiki .sUNQB{--shiki-default:#005CC5;--shiki-light:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .shEpO, html code.shiki .shEpO{--shiki-default:#B31D28;--shiki-default-font-style:italic;--shiki-light:#B31D28;--shiki-light-font-style:italic;--shiki-dark:#FDAEB7;--shiki-dark-font-style:italic}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sqmzS, html code.shiki .sqmzS{--shiki-default:#6A737D;--shiki-light:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sde8i, html code.shiki .sde8i{--shiki-default:#E36209;--shiki-light:#E36209;--shiki-dark:#FFAB70}",{"title":44,"searchDepth":79,"depth":79,"links":589},[590,591,592,593,594,595,596],{"id":12,"depth":79,"text":13},{"id":337,"depth":79,"text":338},{"id":366,"depth":79,"text":367},{"id":510,"depth":79,"text":511},{"id":521,"depth":79,"text":522},{"id":541,"depth":79,"text":542},{"id":555,"depth":79,"text":556},"Mount the editor within your existing component tree, preserving themes, injection, and view lifecycles.","md",[600,601,602,603,604],"Vue","Nuxt","Teleport","useMsfeEditor","useMsfeState","en",{},0,"\u002Fen\u002Fguide\u002Fvue","Integration",{"title":5,"description":597},"guide\u002Fvue.en","uwtSbEyWSVTN-CLwkIRF2d3-dwbzWqHaCF6870nPN6w",1793046311992]