[{"data":1,"prerenderedAt":1480},["ShallowReactive",2],{"navigation_docs":3,"-guides-collaboration":412,"-guides-collaboration-surround":1475},[4,38,84,326,386],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":37},"Getting started","i-lucide-rocket","\u002Fgetting-started","1.getting-started",[10,15,20,24,28,32],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fgetting-started\u002Fintroduction","1.getting-started\u002F1.introduction","i-lucide-book-open",{"title":16,"path":17,"stem":18,"icon":19},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F2.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":6},"Quick start: Nuxt","\u002Fgetting-started\u002Fquick-start-nuxt","1.getting-started\u002F3.quick-start-nuxt",{"title":25,"path":26,"stem":27,"icon":6},"Quick start: plain Vue","\u002Fgetting-started\u002Fquick-start-vue","1.getting-started\u002F4.quick-start-vue",{"title":29,"path":30,"stem":31,"icon":6},"Quick start: React","\u002Fgetting-started\u002Fquick-start-react","1.getting-started\u002F5.quick-start-react",{"title":33,"path":34,"stem":35,"icon":36},"Glossary","\u002Fgetting-started\u002Fglossary","1.getting-started\u002F6.glossary","i-lucide-book-a",false,{"title":39,"icon":40,"path":41,"stem":42,"children":43,"page":37},"Tutorial","i-lucide-graduation-cap","\u002Ftutorial","2.tutorial",[44,49,54,59,64,69,74,79],{"title":45,"path":46,"stem":47,"icon":48},"Tutorial: overview","\u002Ftutorial\u002Foverview","2.tutorial\u002F1.overview","i-lucide-map",{"title":50,"path":51,"stem":52,"icon":53},"Chapter 2: A simple editor","\u002Ftutorial\u002Fsimple-editor","2.tutorial\u002F2.simple-editor","i-lucide-pencil",{"title":55,"path":56,"stem":57,"icon":58},"Chapter 3: Compose features","\u002Ftutorial\u002Fcompose-features","2.tutorial\u002F3.compose-features","i-lucide-blocks",{"title":60,"path":61,"stem":62,"icon":63},"Chapter 4: Your own block, path A","\u002Ftutorial\u002Fown-block-path-a","2.tutorial\u002F4.own-block-path-a","i-lucide-square-plus",{"title":65,"path":66,"stem":67,"icon":68},"Chapter 5: Your own feature, path B","\u002Ftutorial\u002Fown-feature-path-b","2.tutorial\u002F5.own-feature-path-b","i-lucide-puzzle",{"title":70,"path":71,"stem":72,"icon":73},"Chapter 6: Backend and collaboration","\u002Ftutorial\u002Fbackend-and-collaboration","2.tutorial\u002F6.backend-and-collaboration","i-lucide-users",{"title":75,"path":76,"stem":77,"icon":78},"Chapter 7: AI","\u002Ftutorial\u002Fai","2.tutorial\u002F7.ai","i-lucide-sparkles",{"title":80,"path":81,"stem":82,"icon":83},"Chapter 8: The React surface","\u002Ftutorial\u002Freact-surface","2.tutorial\u002F8.react-surface","i-lucide-atom",{"title":85,"icon":14,"path":86,"stem":87,"children":88,"page":37},"Guides","\u002Fguides","3.guides",[89,93,98,103,108,112,116,121,126,130,134,139,144,149,154,159,164,169,174,179,184,189,194,199,204,209,213,218,223,228,233,237,242,247,251,256,261,266,271,276,281,286,291,295,302,307,311,316,321],{"title":90,"path":91,"stem":92,"icon":58},"Feature composition and entries","\u002Fguides\u002Fcomposition","3.guides\u002F1.composition",{"title":94,"path":95,"stem":96,"icon":97},"Media, mentions and transcript features","\u002Fguides\u002Fmedia-mentions-transcript","3.guides\u002F10.media-mentions-transcript","i-lucide-image",{"title":99,"path":100,"stem":101,"icon":102},"Authors and comments","\u002Fguides\u002Fauthors-and-comments","3.guides\u002F11.authors-and-comments","i-lucide-message-square-text",{"title":104,"path":105,"stem":106,"icon":107},"Themes (Obsidian)","\u002Fguides\u002Fthemes","3.guides\u002F12.themes","i-lucide-palette",{"title":109,"path":110,"stem":111,"icon":58},"Composites and the settings UI","\u002Fguides\u002Fcomposites","3.guides\u002F13.composites",{"title":113,"path":114,"stem":115,"icon":78},"AI","\u002Fguides\u002Fai","3.guides\u002F14.ai",{"title":117,"path":118,"stem":119,"icon":120},"Document tree","\u002Fguides\u002Fdocument-tree","3.guides\u002F15.document-tree","i-lucide-folder-tree",{"title":122,"path":123,"stem":124,"icon":125},"Markdown and code","\u002Fguides\u002Fmarkdown-and-code","3.guides\u002F16.markdown-and-code","i-lucide-file-code",{"title":127,"path":128,"stem":129,"icon":83},"Advanced editor in React","\u002Fguides\u002Fadvanced-react","3.guides\u002F17.advanced-react",{"title":131,"path":132,"stem":133,"icon":6},"Kitchen sink: learning path","\u002Fguides\u002Fadvanced-nuxt-example","3.guides\u002F18.advanced-nuxt-example",{"title":135,"path":136,"stem":137,"icon":138},"Production","\u002Fguides\u002Fproduction","3.guides\u002F19.production","i-lucide-server",{"title":140,"path":141,"stem":142,"icon":143},"Register the Nuxt module","\u002Fguides\u002Fnuxt-module","3.guides\u002F2.nuxt-module","i-lucide-package",{"title":145,"path":146,"stem":147,"icon":148},"Storage adapters, comment stores, Nitro host","\u002Fguides\u002Fstorage-adapters","3.guides\u002F20.storage-adapters","i-lucide-database",{"title":150,"path":151,"stem":152,"icon":153},"Migrating from #tiptap-editor","\u002Fguides\u002Fmigration","3.guides\u002F21.migration","i-lucide-arrow-right-left",{"title":155,"path":156,"stem":157,"icon":158},"Content tree mechanics","\u002Fguides\u002Fcontent-tree","3.guides\u002F22.content-tree","i-lucide-git-fork",{"title":160,"path":161,"stem":162,"icon":163},"Block capabilities, abilities and actions","\u002Fguides\u002Fblock-capabilities","3.guides\u002F23.block-capabilities","i-lucide-shield-check",{"title":165,"path":166,"stem":167,"icon":168},"Block types in code and JSON","\u002Fguides\u002Fblock-types","3.guides\u002F24.block-types","i-lucide-shapes",{"title":170,"path":171,"stem":172,"icon":173},"Derive methods and the Derivation index","\u002Fguides\u002Fderive-methods","3.guides\u002F25.derive-methods","i-lucide-git-branch-plus",{"title":175,"path":176,"stem":177,"icon":178},"Block properties and Property definitions","\u002Fguides\u002Fblock-properties","3.guides\u002F26.block-properties","i-lucide-sliders-horizontal",{"title":180,"path":181,"stem":182,"icon":183},"Image studio","\u002Fguides\u002Fimage-studio","3.guides\u002F27.image-studio","i-lucide-image-plus",{"title":185,"path":186,"stem":187,"icon":188},"Prüfung and Freigabestatus","\u002Fguides\u002Fpruefung","3.guides\u002F28.pruefung","i-lucide-stamp",{"title":190,"path":191,"stem":192,"icon":193},"Workspace: find, read, reference and embed Blocks across Documents","\u002Fguides\u002Fworkspace","3.guides\u002F29.workspace","i-lucide-network",{"title":195,"path":196,"stem":197,"icon":198},"EditorPorts: auth and storage","\u002Fguides\u002Feditor-ports","3.guides\u002F3.editor-ports","i-lucide-plug",{"title":200,"path":201,"stem":202,"icon":203},"Collections: an ordered list of Blocks","\u002Fguides\u002Fcollections","3.guides\u002F30.collections","i-lucide-list-checks",{"title":205,"path":206,"stem":207,"icon":208},"Data views: a query shown as table, list or board","\u002Fguides\u002Fdata-views","3.guides\u002F31.data-views","i-lucide-table-properties",{"title":210,"path":211,"stem":212,"icon":193},"Explore: backlinks, related Blocks and the trail","\u002Fguides\u002Fexplore","3.guides\u002F32.explore",{"title":214,"path":215,"stem":216,"icon":217},"Render: export a Block or a Document to a file","\u002Fguides\u002Frender","3.guides\u002F33.render","i-lucide-file-output",{"title":219,"path":220,"stem":221,"icon":222},"Importers: what a dropped file becomes","\u002Fguides\u002Fimporters","3.guides\u002F34.importers","i-lucide-file-input",{"title":224,"path":225,"stem":226,"icon":227},"Templates: start a Document from a Dokumentvorlage","\u002Fguides\u002Ftemplates","3.guides\u002F35.templates","i-lucide-file-stack",{"title":229,"path":230,"stem":231,"icon":232},"Citations","\u002Fguides\u002Fcitations","3.guides\u002F36.citations","i-lucide-quote",{"title":234,"path":235,"stem":236,"icon":163},"AI proposals and the export check","\u002Fguides\u002Fexport-check","3.guides\u002F37.export-check",{"title":238,"path":239,"stem":240,"icon":241},"Query: filter, sort, group and total Blocks","\u002Fguides\u002Fquery","3.guides\u002F38.query","i-lucide-list-filter",{"title":243,"path":244,"stem":245,"icon":246},"Edges: backlinks and authored connections","\u002Fguides\u002Fedges","3.guides\u002F39.edges","i-lucide-link-2",{"title":248,"path":249,"stem":250,"icon":163},"Server routes and authentication","\u002Fguides\u002Froutes-and-auth","3.guides\u002F4.routes-and-auth",{"title":252,"path":253,"stem":254,"icon":255},"Speech: text to audio, and subtitle files","\u002Fguides\u002Fspeech","3.guides\u002F41.speech","i-lucide-audio-lines",{"title":257,"path":258,"stem":259,"icon":260},"Graph: the Edges around a Block","\u002Fguides\u002Fgraph","3.guides\u002F42.graph","i-lucide-waypoints",{"title":262,"path":263,"stem":264,"icon":265},"PDF viewer: passages, anchors and quotes","\u002Fguides\u002Fpdf-viewer","3.guides\u002F43.pdf-viewer","i-lucide-file-search",{"title":267,"path":268,"stem":269,"icon":270},"Obsidian: import and export a vault","\u002Fguides\u002Fobsidian","3.guides\u002F44.obsidian","i-lucide-folder-input",{"title":272,"path":273,"stem":274,"icon":275},"Typst: render a Document as a PDF with citations","\u002Fguides\u002Ftypst","3.guides\u002F45.typst","i-lucide-file-text",{"title":277,"path":278,"stem":279,"icon":280},"Audio: read aloud, mixdown and ElevenLabs","\u002Fguides\u002Faudio","3.guides\u002F46.audio","i-lucide-audio-waveform",{"title":282,"path":283,"stem":284,"icon":285},"Slides: decks, slide layouts and exports","\u002Fguides\u002Fslides","3.guides\u002F47.slides","i-lucide-presentation",{"title":287,"path":288,"stem":289,"icon":290},"Knowledge graph: sources and concepts beside the Documents","\u002Fguides\u002Fknowledge-graph","3.guides\u002F49.knowledge-graph","i-lucide-share-2",{"title":292,"path":293,"stem":294,"icon":78},"AI configuration and secrets","\u002Fguides\u002Fai-configuration","3.guides\u002F5.ai-configuration",{"title":296,"path":297,"stem":298,"children":299,"icon":301},"Index on Postgres: typos, meaning and SQL pushdown","\u002Fguides\u002Findex-pg","3.guides\u002F50.index-pg",[300],{"title":296,"path":297,"stem":298,"icon":301},"i-lucide-database-zap",{"title":303,"path":304,"stem":305,"icon":306},"Charts: bar, line, pie and scatter over a query","\u002Fguides\u002Fcharts","3.guides\u002F51.charts","i-lucide-chart-column",{"title":308,"path":309,"stem":310,"icon":73},"Collaboration on the client","\u002Fguides\u002Fcollaboration","3.guides\u002F6.collaboration",{"title":312,"path":313,"stem":314,"icon":315},"Block UI (drag handle, hover actions)","\u002Fguides\u002Fblock-ui","3.guides\u002F7.block-ui","i-lucide-grip-vertical",{"title":317,"path":318,"stem":319,"icon":320},"Settings and app lifetime","\u002Fguides\u002Fsettings","3.guides\u002F8.settings","i-lucide-settings",{"title":322,"path":323,"stem":324,"icon":325},"Language","\u002Fguides\u002Flanguage","3.guides\u002F9.language","i-lucide-languages",{"title":327,"icon":14,"path":328,"stem":329,"children":330,"page":37},"Reference","\u002Freference","4.reference",[331,335,339,344,348,352,356,360,364,368,373,378,382],{"title":332,"path":333,"stem":334,"icon":143},"Public exports","\u002Freference\u002Fexports","4.reference\u002F1.exports",{"title":336,"path":337,"stem":338,"icon":173},"Derive method contract","\u002Freference\u002Fderive-methods","4.reference\u002F10.derive-methods",{"title":340,"path":341,"stem":342,"icon":343},"Changelog","\u002Freference\u002Fchangelog","4.reference\u002F11.changelog","i-lucide-history",{"title":345,"path":346,"stem":347,"icon":217},"Renderer port","\u002Freference\u002Frenderer-port","4.reference\u002F12.renderer-port",{"title":349,"path":350,"stem":351,"icon":255},"Speech port","\u002Freference\u002Fspeech-port","4.reference\u002F13.speech-port",{"title":353,"path":354,"stem":355,"icon":58},"Presets and features","\u002Freference\u002Fpresets-and-features","4.reference\u002F2.presets-and-features",{"title":357,"path":358,"stem":359,"icon":68},"Feature contract","\u002Freference\u002Ffeature-contract","4.reference\u002F3.feature-contract",{"title":361,"path":362,"stem":363,"icon":107},"CSS and UI-provider requirements","\u002Freference\u002Fcss-and-ui","4.reference\u002F4.css-and-ui",{"title":365,"path":366,"stem":367,"icon":148},"Vue-free advanced schema","\u002Freference\u002Fadvanced-schema","4.reference\u002F5.advanced-schema",{"title":369,"path":370,"stem":371,"icon":372},"Dependency rules","\u002Freference\u002Fdependency-rules","4.reference\u002F6.dependency-rules","i-lucide-git-branch",{"title":374,"path":375,"stem":376,"icon":377},"Commands","\u002Freference\u002Fcommands","4.reference\u002F7.commands","i-lucide-terminal",{"title":379,"path":380,"stem":381,"icon":163},"Block capability contract","\u002Freference\u002Fblock-capabilities","4.reference\u002F8.block-capabilities",{"title":383,"path":384,"stem":385,"icon":168},"Block type contract","\u002Freference\u002Fblock-types","4.reference\u002F9.block-types",{"title":387,"path":388,"stem":389,"children":390,"icon":393},"AI agents","\u002Fai-agents","5.ai-agents\u002F1.index",[391,394,398,402,407],{"title":392,"path":388,"stem":389,"icon":393},"Overview","i-lucide-bot",{"title":395,"path":396,"stem":397,"icon":198},"Integrate the editor","\u002Fai-agents\u002Fintegrate","5.ai-agents\u002F2.integrate",{"title":399,"path":400,"stem":401,"icon":68},"Add a block or feature","\u002Fai-agents\u002Fextend","5.ai-agents\u002F3.extend",{"title":403,"path":404,"stem":405,"icon":406},"Pitfalls and invariants","\u002Fai-agents\u002Finvariants","5.ai-agents\u002F4.invariants","i-lucide-shield-alert",{"title":408,"path":409,"stem":410,"icon":411},"Verify","\u002Fai-agents\u002Fverify","5.ai-agents\u002F5.verify","i-lucide-check-check",{"id":413,"title":308,"body":414,"description":1468,"extension":1469,"links":1470,"meta":1471,"navigation":1472,"path":309,"seo":1473,"stem":310,"__hash__":1474},"docs\u002F3.guides\u002F6.collaboration.md",{"type":415,"value":416,"toc":1462},"minimark",[417,422,431,977,987,1092,1194,1197,1203,1314,1318,1335,1345,1349,1352,1458],[418,419,421],"h2",{"id":420},"mounting-a-session","Mounting a session",[423,424,425,426,430],"p",{},"Collaboration is a feature, not a mode: the preset contains ",[427,428,429],"code",{},"collabFeature()",", and the surface is mounted with a session.",[432,433,438],"pre",{"className":434,"code":435,"language":436,"meta":437,"style":437},"language-vue shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003Cscript setup lang=\"ts\">\nimport { HocuspocusProvider } from '@hocuspocus\u002Fprovider'\nimport { collabFeature } from '@skaile\u002Fforge-editor\u002Fcollab\u002Fvue'\nimport { coreContentFeature, coreUiFeature, defineEditor } from '@skaile\u002Fforge-editor\u002Fcore'\nimport { EditorSurface } from '@skaile\u002Fforge-editor\u002Fvue'\nimport * as Y from 'yjs'\n\nconst preset = defineEditor({ features: [coreContentFeature(), coreUiFeature(), collabFeature()] })\nconst ydoc = new Y.Doc()\nconst provider = new HocuspocusProvider({\n  url: `${location.protocol === 'https:' ? 'wss' : 'ws'}:\u002F\u002F${location.host}\u002Fcollab\u002F${id}`,\n  name: id,\n  document: ydoc,\n})\nonBeforeUnmount(() => provider.destroy())\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003CEditorSurface :preset=\"preset\" :collaboration=\"{ ydoc, provider, user: { id: 'u1', name: 'Ada', color: '#3b82f6' } }\" \u002F>\n\u003C\u002Ftemplate>\n","vue","",[427,439,440,475,504,525,557,578,602,609,663,688,707,787,800,813,820,844,854,859,869,968],{"__ignoreMap":437},[441,442,445,449,453,457,460,463,466,470,472],"span",{"class":443,"line":444},"line",1,[441,446,448],{"class":447},"sMK4o","\u003C",[441,450,452],{"class":451},"swJcz","script",[441,454,456],{"class":455},"spNyl"," setup",[441,458,459],{"class":455}," lang",[441,461,462],{"class":447},"=",[441,464,465],{"class":447},"\"",[441,467,469],{"class":468},"sfazB","ts",[441,471,465],{"class":447},[441,473,474],{"class":447},">\n",[441,476,478,482,485,489,492,495,498,501],{"class":443,"line":477},2,[441,479,481],{"class":480},"s7zQu","import",[441,483,484],{"class":447}," {",[441,486,488],{"class":487},"sTEyZ"," HocuspocusProvider",[441,490,491],{"class":447}," }",[441,493,494],{"class":480}," from",[441,496,497],{"class":447}," '",[441,499,500],{"class":468},"@hocuspocus\u002Fprovider",[441,502,503],{"class":447},"'\n",[441,505,507,509,511,514,516,518,520,523],{"class":443,"line":506},3,[441,508,481],{"class":480},[441,510,484],{"class":447},[441,512,513],{"class":487}," collabFeature",[441,515,491],{"class":447},[441,517,494],{"class":480},[441,519,497],{"class":447},[441,521,522],{"class":468},"@skaile\u002Fforge-editor\u002Fcollab\u002Fvue",[441,524,503],{"class":447},[441,526,528,530,532,535,538,541,543,546,548,550,552,555],{"class":443,"line":527},4,[441,529,481],{"class":480},[441,531,484],{"class":447},[441,533,534],{"class":487}," coreContentFeature",[441,536,537],{"class":447},",",[441,539,540],{"class":487}," coreUiFeature",[441,542,537],{"class":447},[441,544,545],{"class":487}," defineEditor",[441,547,491],{"class":447},[441,549,494],{"class":480},[441,551,497],{"class":447},[441,553,554],{"class":468},"@skaile\u002Fforge-editor\u002Fcore",[441,556,503],{"class":447},[441,558,560,562,564,567,569,571,573,576],{"class":443,"line":559},5,[441,561,481],{"class":480},[441,563,484],{"class":447},[441,565,566],{"class":487}," EditorSurface",[441,568,491],{"class":447},[441,570,494],{"class":480},[441,572,497],{"class":447},[441,574,575],{"class":468},"@skaile\u002Fforge-editor\u002Fvue",[441,577,503],{"class":447},[441,579,581,583,586,589,592,595,597,600],{"class":443,"line":580},6,[441,582,481],{"class":480},[441,584,585],{"class":447}," *",[441,587,588],{"class":480}," as",[441,590,591],{"class":487}," Y ",[441,593,594],{"class":480},"from",[441,596,497],{"class":447},[441,598,599],{"class":468},"yjs",[441,601,503],{"class":447},[441,603,605],{"class":443,"line":604},7,[441,606,608],{"emptyLinePlaceholder":607},true,"\n",[441,610,612,615,618,620,623,626,629,632,635,638,641,644,646,648,650,652,654,657,660],{"class":443,"line":611},8,[441,613,614],{"class":455},"const",[441,616,617],{"class":487}," preset ",[441,619,462],{"class":447},[441,621,545],{"class":622},"s2Zo4",[441,624,625],{"class":487},"(",[441,627,628],{"class":447},"{",[441,630,631],{"class":451}," features",[441,633,634],{"class":447},":",[441,636,637],{"class":487}," [",[441,639,640],{"class":622},"coreContentFeature",[441,642,643],{"class":487},"()",[441,645,537],{"class":447},[441,647,540],{"class":622},[441,649,643],{"class":487},[441,651,537],{"class":447},[441,653,513],{"class":622},[441,655,656],{"class":487},"()] ",[441,658,659],{"class":447},"}",[441,661,662],{"class":487},")\n",[441,664,666,668,671,673,676,679,682,685],{"class":443,"line":665},9,[441,667,614],{"class":455},[441,669,670],{"class":487}," ydoc ",[441,672,462],{"class":447},[441,674,675],{"class":447}," new",[441,677,678],{"class":487}," Y",[441,680,681],{"class":447},".",[441,683,684],{"class":622},"Doc",[441,686,687],{"class":487},"()\n",[441,689,691,693,696,698,700,702,704],{"class":443,"line":690},10,[441,692,614],{"class":455},[441,694,695],{"class":487}," provider ",[441,697,462],{"class":447},[441,699,675],{"class":447},[441,701,488],{"class":622},[441,703,625],{"class":487},[441,705,706],{"class":447},"{\n",[441,708,710,713,715,718,721,723,726,729,731,734,737,740,742,745,747,750,752,755,758,761,764,766,768,771,773,776,778,781,784],{"class":443,"line":709},11,[441,711,712],{"class":451},"  url",[441,714,634],{"class":447},[441,716,717],{"class":447}," `${",[441,719,720],{"class":487},"location",[441,722,681],{"class":447},[441,724,725],{"class":487},"protocol ",[441,727,728],{"class":447},"===",[441,730,497],{"class":447},[441,732,733],{"class":468},"https:",[441,735,736],{"class":447},"'",[441,738,739],{"class":447}," ?",[441,741,497],{"class":447},[441,743,744],{"class":468},"wss",[441,746,736],{"class":447},[441,748,749],{"class":447}," :",[441,751,497],{"class":447},[441,753,754],{"class":468},"ws",[441,756,757],{"class":447},"'}",[441,759,760],{"class":468},":\u002F\u002F",[441,762,763],{"class":447},"${",[441,765,720],{"class":487},[441,767,681],{"class":447},[441,769,770],{"class":487},"host",[441,772,659],{"class":447},[441,774,775],{"class":468},"\u002Fcollab\u002F",[441,777,763],{"class":447},[441,779,780],{"class":487},"id",[441,782,783],{"class":447},"}`",[441,785,786],{"class":447},",\n",[441,788,790,793,795,798],{"class":443,"line":789},12,[441,791,792],{"class":451},"  name",[441,794,634],{"class":447},[441,796,797],{"class":487}," id",[441,799,786],{"class":447},[441,801,803,806,808,811],{"class":443,"line":802},13,[441,804,805],{"class":451},"  document",[441,807,634],{"class":447},[441,809,810],{"class":487}," ydoc",[441,812,786],{"class":447},[441,814,816,818],{"class":443,"line":815},14,[441,817,659],{"class":447},[441,819,662],{"class":487},[441,821,823,826,828,830,833,836,838,841],{"class":443,"line":822},15,[441,824,825],{"class":622},"onBeforeUnmount",[441,827,625],{"class":487},[441,829,643],{"class":447},[441,831,832],{"class":455}," =>",[441,834,835],{"class":487}," provider",[441,837,681],{"class":447},[441,839,840],{"class":622},"destroy",[441,842,843],{"class":487},"())\n",[441,845,847,850,852],{"class":443,"line":846},16,[441,848,849],{"class":447},"\u003C\u002F",[441,851,452],{"class":451},[441,853,474],{"class":447},[441,855,857],{"class":443,"line":856},17,[441,858,608],{"emptyLinePlaceholder":607},[441,860,862,864,867],{"class":443,"line":861},18,[441,863,448],{"class":447},[441,865,866],{"class":451},"template",[441,868,474],{"class":447},[441,870,872,875,878,880,883,885,887,889,891,893,896,898,900,903,906,909,912,914,917,920,922,925,927,930,932,934,937,939,941,944,946,948,951,953,955,958,960,963,965],{"class":443,"line":871},19,[441,873,874],{"class":447},"  \u003C",[441,876,877],{"class":451},"EditorSurface",[441,879,749],{"class":447},[441,881,882],{"class":455},"preset",[441,884,462],{"class":447},[441,886,465],{"class":447},[441,888,882],{"class":487},[441,890,465],{"class":447},[441,892,749],{"class":447},[441,894,895],{"class":455},"collaboration",[441,897,462],{"class":447},[441,899,465],{"class":447},[441,901,902],{"class":447},"{ ",[441,904,905],{"class":487},"ydoc",[441,907,908],{"class":447},", ",[441,910,911],{"class":487},"provider",[441,913,908],{"class":447},[441,915,916],{"class":451},"user",[441,918,919],{"class":447},": { ",[441,921,780],{"class":451},[441,923,924],{"class":447},": ",[441,926,736],{"class":447},[441,928,929],{"class":468},"u1",[441,931,736],{"class":447},[441,933,908],{"class":447},[441,935,936],{"class":451},"name",[441,938,924],{"class":447},[441,940,736],{"class":447},[441,942,943],{"class":468},"Ada",[441,945,736],{"class":447},[441,947,908],{"class":447},[441,949,950],{"class":451},"color",[441,952,924],{"class":447},[441,954,736],{"class":447},[441,956,957],{"class":468},"#3b82f6",[441,959,736],{"class":447},[441,961,962],{"class":447}," } }",[441,964,465],{"class":447},[441,966,967],{"class":447}," \u002F>\n",[441,969,971,973,975],{"class":443,"line":970},20,[441,972,849],{"class":447},[441,974,866],{"class":451},[441,976,474],{"class":447},[423,978,979,980,983,984,986],{},"React is the same with ",[427,981,982],{},"@skaile\u002Fforge-editor\u002Fcollab\u002Freact"," and the React ",[427,985,877],{},"; the Y.Doc and provider are created once per document id and destroyed in an effect cleanup:",[432,988,992],{"className":989,"code":990,"language":991,"meta":437,"style":437},"language-tsx shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { HocuspocusProvider } from '@hocuspocus\u002Fprovider'\nimport { collabFeature } from '@skaile\u002Fforge-editor\u002Fcollab\u002Freact'\nimport { coreContentFeature, coreUiFeature, defineEditor } from '@skaile\u002Fforge-editor\u002Fcore'\nimport { EditorSurface } from '@skaile\u002Fforge-editor\u002Freact'\nimport { useEffect, useMemo, useState } from 'react'\nimport * as Y from 'yjs'\n\nconst preset = defineEditor({ features: [coreContentFeature(), coreUiFeature(), collabFeature()] })\n\nfunction CollaborativeEditor({ id }: { id: string }) {\n  const [session, setSession] = useState\u003C{ ydoc: Y.Doc, provider: HocuspocusProvider } | null>(null)\n  useEffect(() => {\n    const ydoc = new Y.Doc()\n    const provider = new HocuspocusProvider({ url: `${location.protocol === 'https:' ? 'wss' : 'ws'}:\u002F\u002F${location.host}\u002Fcollab\u002F${id}`, name: id, document: ydoc })\n    setSession({ ydoc, provider })\n    return () => { provider.destroy(); setSession(null) }\n  }, [id])\n  const collaboration = useMemo(() => session && { ...session, user: { id: 'u1', name: 'Ada', color: '#3b82f6' } }, [session])\n  return collaboration ? \u003CEditorSurface key={id} preset={preset} collaboration={collaboration} \u002F> : null\n}\n","tsx",[427,993,994,999,1004,1009,1014,1019,1024,1028,1033,1037,1042,1047,1052,1057,1062,1067,1072,1077,1082,1087],{"__ignoreMap":437},[441,995,996],{"class":443,"line":444},[441,997,998],{},"import { HocuspocusProvider } from '@hocuspocus\u002Fprovider'\n",[441,1000,1001],{"class":443,"line":477},[441,1002,1003],{},"import { collabFeature } from '@skaile\u002Fforge-editor\u002Fcollab\u002Freact'\n",[441,1005,1006],{"class":443,"line":506},[441,1007,1008],{},"import { coreContentFeature, coreUiFeature, defineEditor } from '@skaile\u002Fforge-editor\u002Fcore'\n",[441,1010,1011],{"class":443,"line":527},[441,1012,1013],{},"import { EditorSurface } from '@skaile\u002Fforge-editor\u002Freact'\n",[441,1015,1016],{"class":443,"line":559},[441,1017,1018],{},"import { useEffect, useMemo, useState } from 'react'\n",[441,1020,1021],{"class":443,"line":580},[441,1022,1023],{},"import * as Y from 'yjs'\n",[441,1025,1026],{"class":443,"line":604},[441,1027,608],{"emptyLinePlaceholder":607},[441,1029,1030],{"class":443,"line":611},[441,1031,1032],{},"const preset = defineEditor({ features: [coreContentFeature(), coreUiFeature(), collabFeature()] })\n",[441,1034,1035],{"class":443,"line":665},[441,1036,608],{"emptyLinePlaceholder":607},[441,1038,1039],{"class":443,"line":690},[441,1040,1041],{},"function CollaborativeEditor({ id }: { id: string }) {\n",[441,1043,1044],{"class":443,"line":709},[441,1045,1046],{},"  const [session, setSession] = useState\u003C{ ydoc: Y.Doc, provider: HocuspocusProvider } | null>(null)\n",[441,1048,1049],{"class":443,"line":789},[441,1050,1051],{},"  useEffect(() => {\n",[441,1053,1054],{"class":443,"line":802},[441,1055,1056],{},"    const ydoc = new Y.Doc()\n",[441,1058,1059],{"class":443,"line":815},[441,1060,1061],{},"    const provider = new HocuspocusProvider({ url: `${location.protocol === 'https:' ? 'wss' : 'ws'}:\u002F\u002F${location.host}\u002Fcollab\u002F${id}`, name: id, document: ydoc })\n",[441,1063,1064],{"class":443,"line":822},[441,1065,1066],{},"    setSession({ ydoc, provider })\n",[441,1068,1069],{"class":443,"line":846},[441,1070,1071],{},"    return () => { provider.destroy(); setSession(null) }\n",[441,1073,1074],{"class":443,"line":856},[441,1075,1076],{},"  }, [id])\n",[441,1078,1079],{"class":443,"line":861},[441,1080,1081],{},"  const collaboration = useMemo(() => session && { ...session, user: { id: 'u1', name: 'Ada', color: '#3b82f6' } }, [session])\n",[441,1083,1084],{"class":443,"line":871},[441,1085,1086],{},"  return collaboration ? \u003CEditorSurface key={id} preset={preset} collaboration={collaboration} \u002F> : null\n",[441,1088,1089],{"class":443,"line":970},[441,1090,1091],{},"}\n",[1093,1094,1095,1118,1153,1164,1180,1187],"ul",{},[1096,1097,1098,1099,1102,1103,1107,1108,908,1111,908,1114,1117],"li",{},"The Y.Doc is the document: there is no ",[427,1100,1101],{},"v-model",". Core turns its own undo history off; the Collaboration extension brings a ",[1104,1105,1106],"strong",{},"per-client"," undo\u002Fredo (",[427,1109,1110],{},"Mod-z",[427,1112,1113],{},"Mod-y",[427,1115,1116],{},"Shift-Mod-z","), so undo never reverts another user's edits.",[1096,1119,1120,1122,1123,1126,1127,1129,1130,1132,1133,1136,1137,1140,1141,1144,1145,1148,1149,681],{},[427,1121,911],{}," adds remote carets (",[427,1124,1125],{},"CollaborationCaret",", labelled with ",[427,1128,916],{},"); without it the Y.Doc is edited locally only. ",[427,1131,916],{}," is an ",[427,1134,1135],{},"AuthorIdentity"," (",[427,1138,1139],{},"{ id, name, color }",", the app's stable user id): the optional ",[427,1142,1143],{},"authors"," and ",[427,1146,1147],{},"comments"," features attribute text and comments to it, see ",[1150,1151,99],"a",{"href":1152},"#authors-and-comments",[1096,1154,1155,1156,1158,1159,1161,1162,681],{},"Without a ",[427,1157,895],{}," prop ",[427,1160,429],{}," contributes no extension: the editor behaves like a standalone one with JSON ",[427,1163,1101],{},[1096,1165,1166,1167,1169,1170,1173,1174,1176,1177,1179],{},"Supplying ",[427,1168,895],{}," to a preset ",[1104,1171,1172],{},"without"," ",[427,1175,429],{}," is a setup error: the surface throws „",[427,1178,895],{}," needs a preset with the collaboration feature“.",[1096,1181,1182,1183,1186],{},"The mode is fixed at mount. Remount (change ",[427,1184,1185],{},"key",") when the document changes, so Y.Doc, provider and editor never bleed between documents.",[1096,1188,1189,1190,1193],{},"Include ",[427,1191,1192],{},"@skaile\u002Fforge-editor\u002Fstyles\u002Fcollab.css"," (the Nuxt module adds it) for the caret styles.",[418,1195,99],{"id":1196},"authors-and-comments",[423,1198,1199,1200,1202],{},"Two optional features build on the session's ",[427,1201,916],{},"; the advanced editor contains both.",[1093,1204,1205,1229,1257,1267],{},[1096,1206,1207,1210,1211,1214,1215,1217,1218,1221,1222,908,1225,1228],{},[427,1208,1209],{},"authorsFeature()"," marks every text run the user inserts with an ",[427,1212,1213],{},"author"," mark (",[427,1216,1139],{},"; one author per run, remote changes and Yjs undo\u002Fredo keep the original author's mark). Without ",[427,1219,1220],{},"collaboration.user"," it attributes nothing, so standalone editors write unmarked text. Colouring is a per-user preference (",[427,1223,1224],{},"editing.authorColors",[427,1226,1227],{},"editing.authorColorStyle",").",[1096,1230,1231,1234,1235,1238,1239,1242,1243,1245,1246,1249,1250,1253,1254,1256],{},[427,1232,1233],{},"commentsFeature()"," (requires ",[427,1236,1237],{},"collab",") stores comment threads in the Y.Doc, in a ",[427,1240,1241],{},"Y.Map"," named ",[427,1244,1147],{},"; the commented range is a ",[427,1247,1248],{},"comment"," mark. Threads therefore sync live and persist with the document, but they are ",[1104,1251,1252],{},"not"," part of the JSON\u002FMarkdown adapter content. Without a Y.Doc and a ",[427,1255,1220],{}," the UI says „Kommentare gibt es nur in gemeinsam bearbeiteten Dokumenten.“ and nothing can be written.",[1096,1258,1259,1260,1263,1264,1228],{},"Both marks are in ",[427,1261,1262],{},"advancedSchemaExtensions()",", so the server's Yjs↔JSON conversion keeps them. They have no Markdown form: Markdown export, imports and the AI context ignore them (",[427,1265,1266],{},"DocumentMarkdown",[1096,1268,1269,1270,1273,1274,1276,1277,1280,1281,1276,1284,1287,1288,1291,1292,1144,1295,1298,1299,1302,1303,1306,1307,1310,1311,1228],{},"Surface contract: ",[427,1271,1272],{},"v-model:comments-open"," (Vue ",[427,1275,877],{},"\u002F",[427,1278,1279],{},"AdvancedEditor",") or ",[427,1282,1283],{},"commentsOpen",[427,1285,1286],{},"onCommentsOpenChange"," (React) is the open state of the margin column, which the host renders with ",[427,1289,1290],{},"CommentsMargin"," inside the editor's scroll container; ",[427,1293,1294],{},"useEditorUi().toggleComments()",[427,1296,1297],{},"Mod-Shift-m"," toggle it, and it excludes the AI sidebar. The column lays its cards out with the framework-free ",[427,1300,1301],{},"layoutMargin"," \u002F ",[427,1304,1305],{},"createMarginController"," of ",[427,1308,1309],{},"@skaile\u002Fforge-editor\u002Fcomments",": the active thread sits exactly at its text's line, the others are one-line cards out of its way, resolved threads sit behind „Erledigt (n)“, and a thread whose text was deleted stays greyed out at the deletion point („Text gelöscht“) until undo re-attaches it (",[1150,1312,1313],{"href":100},"Authors and comments guide",[418,1315,1317],{"id":1316},"positions-that-survive-concurrent-edits","Positions that survive concurrent edits",[423,1319,1320,1322,1323,1326,1327,1330,1331,1334],{},[427,1321,429],{}," supplies ",[427,1324,1325],{},"DocAnchors"," with ",[427,1328,1329],{},"yjsAnchorResolver",": ranges captured through ",[427,1332,1333],{},"captureRange"," (AI reviews, ghost text, chat ops, the selection menu) are stored as Yjs relative positions and re-resolved after every remote change and undo\u002Fredo. Without the collab feature anchors map through local transactions only.",[423,1336,1337,1338,1340,1341,1344],{},"The resolver binds to the Yjs types of the editor's own Y.Doc. The package pins one ",[427,1339,599],{}," instance as a peer dependency: install a single copy in the host, or Yjs warns „already imported“ and ",[427,1342,1343],{},"instanceof"," checks fail.",[418,1346,1348],{"id":1347},"matching-schemas-who-owns-the-document","Matching schemas: who owns the document",[423,1350,1351],{},"The Yjs document is only valid if every participant uses the same schema.",[1093,1353,1354,1379,1395,1428],{},[1096,1355,1356,1357,1360,1361,1364,1365,1367,1368,1371,1372,1276,1375,1378],{},"The ",[1104,1358,1359],{},"server"," builds ",[427,1362,1363],{},"collabSchema()"," from ",[427,1366,1262],{}," plus the host's ",[427,1369,1370],{},"schema"," option of ",[427,1373,1374],{},"createCollabServer",[427,1376,1377],{},"installEditorServer"," (the package's collab route) and migrates and validates seeded content with it.",[1096,1380,1356,1381,1384,1385,1276,1388,1390,1391,1394],{},[1104,1382,1383],{},"client"," must mount a preset with the same schema: ",[427,1386,1387],{},"advancedEditor()",[427,1389,1279],{},", or your own preset whose features contribute the same nodes and marks (media, transcript, Typed blocks, mentions, authors and comments marks, block IDs). Custom ",[427,1392,1393],{},"blockTypes"," are storage, not schema, so they may differ per client.",[1096,1396,1397,1398,1402,1403,1406,1407,1410,1411,1414,1415,1418,1419,1422,1423,1427],{},"The host owns the ",[1399,1400,1401],"em",{},"document lifecycle",": create the ",[427,1404,1405],{},"Y.Doc"," and the ",[427,1408,1409],{},"HocuspocusProvider"," when the page mounts, destroy the provider on unmount (",[427,1412,1413],{},"onBeforeUnmount(() => provider.destroy())","), and call ",[427,1416,1417],{},"forgetDocument(id)"," of the ",[427,1420,1421],{},"EditorServer"," handle on the server before deleting a document (see ",[1150,1424,1426],{"href":1425},"\u002Fguides\u002Feditor-ports#deleting-a-document","Deleting a document","). The library never creates a provider for you.",[1096,1429,1430,1431,1434,1435,1438,1439,1442,1443,1446,1447,1449,1450,1453,1454,1457],{},"A plain-Vue or React app brings its own Hocuspocus server, builds its schema from ",[427,1432,1433],{},"\u002Fschema\u002Fadvanced"," and sets the Collaboration ",[427,1436,1437],{},"field"," to ",[427,1440,1441],{},"default",". A host block of your own (see ",[1150,1444,1445],{"href":71},"Backend and collaboration",") belongs to that schema too: pass its framework-free node in the server's ",[427,1448,1370],{}," option (",[427,1451,1452],{},"schema: () => [...advancedSchemaExtensions(), YourNode]","); a custom server builds ",[427,1455,1456],{},"getSchema([...advancedSchemaExtensions(), YourNode])"," itself.",[1459,1460,1461],"style",{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}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 .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 .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":437,"searchDepth":477,"depth":477,"links":1463},[1464,1465,1466,1467],{"id":420,"depth":477,"text":421},{"id":1196,"depth":477,"text":99},{"id":1316,"depth":477,"text":1317},{"id":1347,"depth":477,"text":1348},"Collaboration is a feature: mount a surface with a Yjs session, per-client undo, authors and comments, positions that survive concurrent edits, and matching schemas.","md",null,{},{"icon":73},{"title":308,"description":1468},"2rEdEany7FTi6rxRNHdSgVxpKvonTV1ng9j06x9qeXA",[1476,1478],{"title":303,"path":304,"stem":305,"description":1477,"icon":306,"children":-1},"The add-on @skaile\u002Fforge-editor-charts: the Block type chart, its configuration and the query it derives, the pure Vega-Lite specification, the node view with a chart editor for Vue and React, and the render target chart-svg.",{"title":312,"path":313,"stem":314,"description":1479,"icon":315,"children":-1},"Add the drag handle, hover targeting, block actions and block-range selection with blockUiFeature().",1793219820505]