[{"data":1,"prerenderedAt":824},["ShallowReactive",2],{"msfe-doc:\u002Fen\u002Fconcepts\u002Fextensions":3},{"id":4,"title":5,"body":6,"description":813,"extension":814,"keywords":815,"locale":817,"meta":818,"navigation":197,"order":176,"path":819,"section":820,"seo":821,"stem":822,"__hash__":823},"docs\u002Fconcepts\u002Fextensions.en.md","Extension model and composition",{"type":7,"value":8,"toc":804},"minimark",[9,14,30,159,163,386,393,397,427,434,438,511,534,537,541,637,652,656,762,775,779,800],[10,11,13],"h2",{"id":12},"choose-the-owner-first","Choose the owner first",[15,16,17,21,22,25,26,29],"p",{},[18,19,20],"code",{},"Extension"," supplies general behavior and presets; ",[18,23,24],{},"Node"," describes source nodes; ",[18,27,28],{},"Mark"," describes inline annotations. They share authoring hooks. They do not create a ProseMirror schema or a second JSON document.",[31,32,33,49],"table",{},[34,35,36],"thead",{},[37,38,39,43,46],"tr",{},[40,41,42],"th",{},"Goal",[40,44,45],{},"Entry point",[40,47,48],{},"Walkthrough",[50,51,52,70,86,106,122,138],"tbody",{},[37,53,54,58,63],{},[55,56,57],"td",{},"Change defaults",[55,59,60],{},[18,61,62],{},".configure()",[55,64,65],{},[66,67,69],"a",{"href":68},"\u002Fen\u002Fextensions\u002Fcontainers","Containers",[37,71,72,75,80],{},[55,73,74],{},"Keep syntax, replace controls",[55,76,77],{},[18,78,79],{},".extend({ addNodeView() {} })",[55,81,82],{},[66,83,85],{"href":84},"\u002Fen\u002Fextensions\u002Fcode-blocks","Code blocks",[37,87,88,91,100],{},[55,89,90],{},"Introduce syntax with writable fields",[55,92,93,96,97],{},[18,94,95],{},"Node.create()"," + ",[18,98,99],{},"defineSource()",[55,101,102],{},[66,103,105],{"href":104},"\u002Fen\u002Fextensions\u002Fcustom-node","Custom nodes",[37,107,108,111,116],{},[55,109,110],{},"Add parsing rules",[55,112,113],{},[18,114,115],{},"addMarkdownExtensions()",[55,117,118],{},[66,119,121],{"href":120},"\u002Fen\u002Fextensions\u002Fmarkdown-plugins","Markdown plugins",[37,123,124,127,132],{},[55,125,126],{},"Render multiline structural previews",[55,128,129],{},[18,130,131],{},"addProjectionLayers()",[55,133,134],{},[66,135,137],{"href":136},"\u002Fen\u002Fextensions\u002Fdiagrams","Diagrams",[37,139,140,143,148],{},[55,141,142],{},"Add transient state or input behavior",[55,144,145],{},[18,146,147],{},"Extension.create()",[55,149,150,154,155],{},[66,151,153],{"href":152},"\u002Fen\u002Fguide\u002Fstate","State",", ",[66,156,158],{"href":157},"\u002Fen\u002Fextensions\u002Finput-rules","input rules",[10,160,162],{"id":161},"create-declare-a-reusable-definition","create: declare a reusable definition",[164,165,170],"pre",{"className":166,"code":167,"language":168,"meta":169,"style":169},"language-ts shiki shiki-themes github-light github-light github-dark","import { Extension } from '@quirekit\u002Fmsfe-core'\n\ninterface Options {\n  \u002F** Host application name used by this extension. *\u002F\n  label: string\n}\ninterface Storage {\n  \u002F** Accepted source changes observed in this installation. *\u002F\n  changes: number\n}\nexport const Audit = Extension.create\u003COptions, Storage>({\n  name: 'audit',\n  addOptions() { return { label: 'editor' } },\n  addStorage() { return { changes: 0 } },\n  onUpdate() { this.storage.changes += 1 },\n})\n","ts","",[18,171,172,192,199,212,219,233,239,249,255,266,271,306,318,339,357,380],{"__ignoreMap":169},[173,174,177,181,185,188],"span",{"class":175,"line":176},"line",1,[173,178,180],{"class":179},"sDD9d","import",[173,182,184],{"class":183},"sVPnS"," { Extension } ",[173,186,187],{"class":179},"from",[173,189,191],{"class":190},"s-HEn"," '@quirekit\u002Fmsfe-core'\n",[173,193,195],{"class":175,"line":194},2,[173,196,198],{"emptyLinePlaceholder":197},true,"\n",[173,200,202,205,209],{"class":175,"line":201},3,[173,203,204],{"class":179},"interface",[173,206,208],{"class":207},"sgQzM"," Options",[173,210,211],{"class":183}," {\n",[173,213,215],{"class":175,"line":214},4,[173,216,218],{"class":217},"sqmzS","  \u002F** Host application name used by this extension. *\u002F\n",[173,220,222,226,229],{"class":175,"line":221},5,[173,223,225],{"class":224},"sde8i","  label",[173,227,228],{"class":179},":",[173,230,232],{"class":231},"sUNQB"," string\n",[173,234,236],{"class":175,"line":235},6,[173,237,238],{"class":183},"}\n",[173,240,242,244,247],{"class":175,"line":241},7,[173,243,204],{"class":179},[173,245,246],{"class":207}," Storage",[173,248,211],{"class":183},[173,250,252],{"class":175,"line":251},8,[173,253,254],{"class":217},"  \u002F** Accepted source changes observed in this installation. *\u002F\n",[173,256,258,261,263],{"class":175,"line":257},9,[173,259,260],{"class":224},"  changes",[173,262,228],{"class":179},[173,264,265],{"class":231}," number\n",[173,267,269],{"class":175,"line":268},10,[173,270,238],{"class":183},[173,272,274,277,280,283,286,289,292,295,298,300,303],{"class":175,"line":273},11,[173,275,276],{"class":179},"export",[173,278,279],{"class":179}," const",[173,281,282],{"class":231}," Audit",[173,284,285],{"class":179}," =",[173,287,288],{"class":183}," Extension.",[173,290,291],{"class":207},"create",[173,293,294],{"class":183},"\u003C",[173,296,297],{"class":207},"Options",[173,299,154],{"class":183},[173,301,302],{"class":207},"Storage",[173,304,305],{"class":183},">({\n",[173,307,309,312,315],{"class":175,"line":308},12,[173,310,311],{"class":183},"  name: ",[173,313,314],{"class":190},"'audit'",[173,316,317],{"class":183},",\n",[173,319,321,324,327,330,333,336],{"class":175,"line":320},13,[173,322,323],{"class":207},"  addOptions",[173,325,326],{"class":183},"() { ",[173,328,329],{"class":179},"return",[173,331,332],{"class":183}," { label: ",[173,334,335],{"class":190},"'editor'",[173,337,338],{"class":183}," } },\n",[173,340,342,345,347,349,352,355],{"class":175,"line":341},14,[173,343,344],{"class":207},"  addStorage",[173,346,326],{"class":183},[173,348,329],{"class":179},[173,350,351],{"class":183}," { changes: ",[173,353,354],{"class":231},"0",[173,356,338],{"class":183},[173,358,360,363,365,368,371,374,377],{"class":175,"line":359},15,[173,361,362],{"class":207},"  onUpdate",[173,364,326],{"class":183},[173,366,367],{"class":231},"this",[173,369,370],{"class":183},".storage.changes ",[173,372,373],{"class":179},"+=",[173,375,376],{"class":231}," 1",[173,378,379],{"class":183}," },\n",[173,381,383],{"class":175,"line":382},16,[173,384,385],{"class":183},"})\n",[15,387,388,389,392],{},"Definitions can be reused across editors. Options and storage are resolved independently per installation. Do not put instance state in module globals. Storage suits temporary services and counters; use ",[18,390,391],{},"defineState()"," for transaction mapping, history or projection dependencies.",[10,394,396],{"id":395},"configure-change-options","configure: change options",[164,398,400],{"className":166,"code":399,"language":168,"meta":169,"style":169},"const ReportAudit = Audit.configure({ label: 'report' })\n",[18,401,402],{"__ignoreMap":169},[173,403,404,407,410,412,415,418,421,424],{"class":175,"line":176},[173,405,406],{"class":179},"const",[173,408,409],{"class":231}," ReportAudit",[173,411,285],{"class":179},[173,413,414],{"class":183}," Audit.",[173,416,417],{"class":207},"configure",[173,419,420],{"class":183},"({ label: ",[173,422,423],{"class":190},"'report'",[173,425,426],{"class":183}," })\n",[15,428,429,430,433],{},"This returns a new definition. Plain records merge recursively; arrays replace entirely; functions and non-plain objects replace by value. Retain default container names explicitly when changing ",[18,431,432],{},"types",". Configuration is not a mounted-instance hot update. Use instance methods for theme, mode and permission changes.",[10,435,437],{"id":436},"extend-override-a-hook-deliberately","extend: override a hook deliberately",[164,439,441],{"className":166,"code":440,"language":168,"meta":169,"style":169},"const Audited = Audit.extend({\n  onUpdate(event) {\n    this.parent?.(event)\n    console.debug(this.options.label, event.revision)\n  },\n})\n",[18,442,443,460,473,487,502,507],{"__ignoreMap":169},[173,444,445,447,450,452,454,457],{"class":175,"line":176},[173,446,406],{"class":179},[173,448,449],{"class":231}," Audited",[173,451,285],{"class":179},[173,453,414],{"class":183},[173,455,456],{"class":207},"extend",[173,458,459],{"class":183},"({\n",[173,461,462,464,467,470],{"class":175,"line":194},[173,463,362],{"class":207},[173,465,466],{"class":183},"(",[173,468,469],{"class":224},"event",[173,471,472],{"class":183},") {\n",[173,474,475,478,481,484],{"class":175,"line":201},[173,476,477],{"class":231},"    this",[173,479,480],{"class":183},".",[173,482,483],{"class":207},"parent",[173,485,486],{"class":183},"?.(event)\n",[173,488,489,492,495,497,499],{"class":175,"line":214},[173,490,491],{"class":183},"    console.",[173,493,494],{"class":207},"debug",[173,496,466],{"class":183},[173,498,367],{"class":231},[173,500,501],{"class":183},".options.label, event.revision)\n",[173,503,504],{"class":175,"line":221},[173,505,506],{"class":183},"  },\n",[173,508,509],{"class":175,"line":235},[173,510,385],{"class":183},[15,512,513,514,517,518,154,521,154,524,527,528,531,532,480],{},"Overridden hooks do not automatically combine results. Call the current hook's ",[18,515,516],{},"this.parent?.()"," to retain parent behavior and explicitly combine returned arrays. Use ordinary methods whenever a hook needs ",[18,519,520],{},"this.options",[18,522,523],{},"this.storage",[18,525,526],{},"this.editor"," or ",[18,529,530],{},"this.parent","; arrow functions capture a different ",[18,533,367],{},[15,535,536],{},"Derived definitions inherit the name. Replace the corresponding preset entry instead of installing both definitions. Renaming alone does not resolve competing replacement projections.",[10,538,540],{"id":539},"install-one-preset","Install one preset",[164,542,544],{"className":166,"code":543,"language":168,"meta":169,"style":169},"import { StarterKit } from '@quirekit\u002Fmsfe-starter-kit'\nimport { CodeBlock } from '@quirekit\u002Fmsfe-code-block'\n\nconst CustomCodeBlock = CodeBlock.extend({\n  \u002F\u002F Add the renderer from the code-block tutorial here.\n})\nconst extensions = [\n  StarterKit.configure({ codeBlock: CustomCodeBlock, image: false }),\n  Audit,\n]\n",[18,545,546,558,570,574,590,595,599,611,627,632],{"__ignoreMap":169},[173,547,548,550,553,555],{"class":175,"line":176},[173,549,180],{"class":179},[173,551,552],{"class":183}," { StarterKit } ",[173,554,187],{"class":179},[173,556,557],{"class":190}," '@quirekit\u002Fmsfe-starter-kit'\n",[173,559,560,562,565,567],{"class":175,"line":194},[173,561,180],{"class":179},[173,563,564],{"class":183}," { CodeBlock } ",[173,566,187],{"class":179},[173,568,569],{"class":190}," '@quirekit\u002Fmsfe-code-block'\n",[173,571,572],{"class":175,"line":201},[173,573,198],{"emptyLinePlaceholder":197},[173,575,576,578,581,583,586,588],{"class":175,"line":214},[173,577,406],{"class":179},[173,579,580],{"class":231}," CustomCodeBlock",[173,582,285],{"class":179},[173,584,585],{"class":183}," CodeBlock.",[173,587,456],{"class":207},[173,589,459],{"class":183},[173,591,592],{"class":175,"line":221},[173,593,594],{"class":217},"  \u002F\u002F Add the renderer from the code-block tutorial here.\n",[173,596,597],{"class":175,"line":235},[173,598,385],{"class":183},[173,600,601,603,606,608],{"class":175,"line":241},[173,602,406],{"class":179},[173,604,605],{"class":231}," extensions",[173,607,285],{"class":179},[173,609,610],{"class":183}," [\n",[173,612,613,616,618,621,624],{"class":175,"line":251},[173,614,615],{"class":183},"  StarterKit.",[173,617,417],{"class":207},[173,619,620],{"class":183},"({ codeBlock: CustomCodeBlock, image: ",[173,622,623],{"class":231},"false",[173,625,626],{"class":183}," }),\n",[173,628,629],{"class":175,"line":257},[173,630,631],{"class":183},"  Audit,\n",[173,633,634],{"class":175,"line":268},[173,635,636],{"class":183},"]\n",[15,638,639,640,643,644,647,648,651],{},"Use ",[18,641,642],{},"addExtensions()"," to compose a business preset, then install that preset once. ",[18,645,646],{},"requires"," names extension dependencies. Dependency-ready extensions install in descending ",[18,649,650],{},"priority",", default 100. Duplicate names and missing dependencies are diagnosed before mounting; array reordering should not conceal configuration errors.",[10,653,655],{"id":654},"lifecycle-and-ownership","Lifecycle and ownership",[31,657,658,671],{},[34,659,660],{},[37,661,662,665,668],{},[40,663,664],{},"Phase",[40,666,667],{},"Available context",[40,669,670],{},"Appropriate work",[50,672,673,684,697,710,723,736,749],{},[37,674,675,678,681],{},[55,676,677],{},"Configuration and state creation",[55,679,680],{},"Definitions, options and slots",[55,682,683],{},"Repeatable work without DOM effects",[37,685,686,691,694],{},[55,687,688],{},[18,689,690],{},"onBeforeCreate",[55,692,693],{},"Configuration and state, no mounted DOM",[55,695,696],{},"Logic independent of mounting",[37,698,699,704,707],{},[55,700,701],{},[18,702,703],{},"onCreate",[55,705,706],{},"Mounted editor",[55,708,709],{},"Subscribe to host services; optionally return a disposer",[37,711,712,717,720],{},[55,713,714],{},[18,715,716],{},"onUpdate",[55,718,719],{},"Accepted source changes",[55,721,722],{},"Incremental observation and dirty state",[37,724,725,730,733],{},[55,726,727],{},[18,728,729],{},"onTransaction",[55,731,732],{},"Every accepted transaction",[55,734,735],{},"Bounded reads, including selection\u002Feffects",[37,737,738,743,746],{},[55,739,740],{},[18,741,742],{},"onSelectionUpdate",[55,744,745],{},"A changed selection",[55,747,748],{},"Refresh dependent toolbar state",[37,750,751,756,759],{},[55,752,753],{},[18,754,755],{},"onDestroy",[55,757,758],{},"Disposal in progress",[55,760,761],{},"Cleanup in reverse installation order",[15,763,764,765,769,770,774],{},"Components can unmount on scrolling, source reveal or mode changes. Their lifetime is shorter than the editor's. Bind ",[66,766,768],{"href":767},"\u002Fen\u002Fextensions\u002Fresources","asynchronous resources"," to the appropriate scope. See ",[66,771,773],{"href":772},"\u002Fen\u002Fapi\u002Fextensions","Extension API"," for exact hook signatures.",[10,776,778],{"id":777},"earlier-descriptors","Earlier descriptors",[15,780,781,784,785,788,789,154,792,795,796,799],{},[18,782,783],{},"defineExtension()"," and ",[18,786,787],{},"defineNodeView()"," remain public low-level entries. Their earlier descriptor configuration does not share all modern deep-merge semantics. Prefer the authoring API for new features. Tiptap-style names do not imply support for ",[18,790,791],{},"parseHTML",[18,793,794],{},"renderHTML",", ProseMirror schema ",[18,797,798],{},"content"," or direct ProseMirror plugin installation.",[801,802,803],"style",{},"html pre.shiki code .sDD9d, html code.shiki .sDD9d{--shiki-default:#D73A49;--shiki-light:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVPnS, html code.shiki .sVPnS{--shiki-default:#24292E;--shiki-light:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s-HEn, html code.shiki .s-HEn{--shiki-default:#032F62;--shiki-light:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sgQzM, html code.shiki .sgQzM{--shiki-default:#6F42C1;--shiki-light:#6F42C1;--shiki-dark:#B392F0}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}html pre.shiki code .sUNQB, html code.shiki .sUNQB{--shiki-default:#005CC5;--shiki-light:#005CC5;--shiki-dark:#79B8FF}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);}",{"title":169,"searchDepth":194,"depth":194,"links":805},[806,807,808,809,810,811,812],{"id":12,"depth":194,"text":13},{"id":161,"depth":194,"text":162},{"id":395,"depth":194,"text":396},{"id":436,"depth":194,"text":437},{"id":539,"depth":194,"text":540},{"id":654,"depth":194,"text":655},{"id":777,"depth":194,"text":778},"Understand create, configure, extend, installation order and ownership.","md",[20,417,456,650,646,816],"lifecycle","en",{},"\u002Fen\u002Fconcepts\u002Fextensions","Core concepts",{"title":5,"description":813},"concepts\u002Fextensions.en","xHEtQWfp7OKcFfqW4TdZCwiuMUrnM678HzRHcqWq3mI",1793046312068]