[{"data":1,"prerenderedAt":1287},["ShallowReactive",2],{"navigation_docs":3,"-guides-advanced-react":412,"-guides-advanced-react-surround":1282},[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":127,"body":414,"description":1275,"extension":1276,"links":1277,"meta":1278,"navigation":1279,"path":128,"seo":1280,"stem":129,"__hash__":1281},"docs\u002F3.guides\u002F17.advanced-react.md",{"type":415,"value":416,"toc":1273},"minimark",[417,539,551,653,659,826,841,884,1101,1104,1269],[418,419,420,424,425,428,429,431,432,435,436,439,440,443,444,443,447,443,450,443,453,456,457,460,461,464,465,468,469,443,472,443,475,443,478,443,481,443,484,443,487,443,490,443,493,443,495,443,498,443,501,443,504,443,507,443,510,513,514,523,524,527,528,443,531,534,535,538],"p",{},[421,422,423],"code",{},"AdvancedEditor"," from ",[421,426,427],{},"@skaile\u002Fforge-editor\u002Freact\u002Fadvanced"," is the React counterpart of the Vue ",[421,430,423],{},": an ",[421,433,434],{},"EditorSurface"," over ",[421,437,438],{},"composeEditor"," of its ",[421,441,442],{},"content",", ",[421,445,446],{},"interaction",[421,448,449],{},"ai",[421,451,452],{},"add",[421,454,455],{},"remove"," and ",[421,458,459],{},"backend"," props (defaults ",[421,462,463],{},"{ content: 'rich', interaction: 'full', ai: true }",", i.e. ",[421,466,467],{},"advancedEditor()","), which lists every feature and integration (",[421,470,471],{},"core-content",[421,473,474],{},"core-ui",[421,476,477],{},"media",[421,479,480],{},"transcript",[421,482,483],{},"composites",[421,485,486],{},"mentions",[421,488,489],{},"authors",[421,491,492],{},"comments",[421,494,449],{},[421,496,497],{},"collab",[421,499,500],{},"block-ui",[421,502,503],{},"composite-media",[421,505,506],{},"composite-ai",[421,508,509],{},"transcript-ai",[421,511,512],{},"themes",") with its React binding, in the same schema order as the Vue surface. It uses no Vue, Nuxt UI or Nuxt module. The runnable reference is ",[515,516,520],"a",{"href":517,"rel":518},"https:\u002F\u002Fgithub.com\u002Fskaile-ai\u002Fforge-editor\u002Ftree\u002Fmain\u002Fexamples\u002Freact-advanced",[519],"nofollow",[421,521,522],{},"examples\u002Freact-advanced"," (",[421,525,526],{},"bun run --cwd examples\u002Freact-advanced dev",", port 3043): the React counterpart of the Nuxt document page. It reuses the Nuxt app's documents, session and collaboration socket through the Vite proxy (",[421,529,530],{},"\u002Fapi",[421,532,533],{},"\u002Fcollab","), so start the Nuxt app first (",[421,536,537],{},"bun run dev",", port 3056).",[418,540,541,545,546,550],{},[542,543,544],"strong",{},"Setup"," is the ",[515,547,549],{"href":548},"\u002Fgetting-started\u002Fquick-start-react#setup","simple React setup"," plus three things:",[552,553,554,598,623],"ul",{},[555,556,557,560,561,564,565,456,568,571,572,443,575,578,579,582,583,586,587,523,590,593,594,597],"li",{},[542,558,559],{},"Styles."," Replace the three library imports by one: ",[421,562,563],{},"@import \"@skaile\u002Fforge-editor\u002Freact\u002Fstyles\u002Fadvanced.css\";"," after ",[421,566,567],{},"tailwindcss",[421,569,570],{},"tw-animate-css"," (it imports ",[421,573,574],{},"ui-vars.css",[421,576,577],{},"core.css",", every feature sheet and ",[421,580,581],{},"themes.css"," last, plus the bridge that lets an Obsidian theme restyle the shadcn tokens). Keep the ",[421,584,585],{},"@source"," for the library's whole ",[421,588,589],{},"dist",[421,591,592],{},"src"," in this repository, as the example does) and the shadcn theme block; ",[421,595,596],{},"examples\u002Freact-advanced\u002Fsrc\u002Findex.css"," has a complete copy.",[555,599,600,603,604,607,608,611,612,615,616,619,620,622],{},[542,601,602],{},"Notices."," Create the context with ",[421,605,606],{},"createEditorContext({ notify: reactNotifier })"," and render sonner's ",[421,609,610],{},"\u003CToaster \u002F>"," once inside the provider (both exported by ",[421,613,614],{},"@skaile\u002Fforge-editor\u002Freact","). Features send ",[421,617,618],{},"Notice","s to the surface's notifier (import problems, AI rate limits, comment errors, „Dokument gelöscht“ with undo in the tree); without ",[421,621,610],{}," none is visible.",[555,624,625,628,629,632,633,636,637,456,640,643,644,652],{},[542,626,627],{},"Dependencies."," The simple setup's list plus ",[421,630,631],{},"sonner"," (the ",[421,634,635],{},"Toaster"," and the notice seam), ",[421,638,639],{},"yjs",[421,641,642],{},"@hocuspocus\u002Fprovider"," for collaboration; use the exact version ranges of the ",[515,645,648,649],{"href":646,"rel":647},"https:\u002F\u002Fgithub.com\u002Fskaile-ai\u002Fforge-editor\u002Fblob\u002Fmain\u002Fexamples\u002Freact-advanced\u002Fpackage.json",[519],"example's ",[421,650,651],{},"package.json",".",[418,654,655,658],{},[421,656,657],{},"main.tsx",":",[660,661,667],"pre",{"className":662,"code":663,"filename":664,"language":665,"meta":666,"style":666},"language-tsx shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import lucide from '@iconify-json\u002Flucide\u002Ficons.json'\nimport { addCollection } from '@iconify\u002Freact'\nimport { createHttpBackend } from '@skaile\u002Fforge-editor\u002Fadapters\u002Fhttp'\nimport { createEditorContext } from '@skaile\u002Fforge-editor\u002Fcore'\nimport { EditorContextProvider, reactNotifier, Toaster } from '@skaile\u002Fforge-editor\u002Freact'\nimport { StrictMode } from 'react'\nimport { createRoot } from 'react-dom\u002Fclient'\nimport { App } from '.\u002FApp'\nimport '.\u002Findex.css'\n\n\u002F\u002F Preload the icon set: the page makes no request to the Iconify API.\naddCollection(lucide)\n\n\u002F\u002F The host owns the context; the provider never disposes it. The backend is the HTTP one (`\u002Fapi\u002Feditor` over the Nuxt host,\n\u002F\u002F the collaboration websocket `\u002Fcollab\u002F\u003Cid>`); the backend offers `settings`, so they sync with the host's account store,\n\u002F\u002F notices of app-level models become sonner toasts.\nconst context = createEditorContext({ backend: createHttpBackend(), notify: reactNotifier })\n\ncreateRoot(document.getElementById('app')!).render(\n  \u003CStrictMode>\n    \u003CEditorContextProvider context={context}>\n      \u003CApp \u002F>\n      \u003CToaster \u002F>\n    \u003C\u002FEditorContextProvider>\n  \u003C\u002FStrictMode>,\n)\n","examples\u002Freact-advanced\u002Fsrc\u002Fmain.tsx","tsx","",[421,668,669,677,683,689,695,701,707,713,719,725,732,738,744,749,755,761,767,773,778,784,790,796,802,808,814,820],{"__ignoreMap":666},[670,671,674],"span",{"class":672,"line":673},"line",1,[670,675,676],{},"import lucide from '@iconify-json\u002Flucide\u002Ficons.json'\n",[670,678,680],{"class":672,"line":679},2,[670,681,682],{},"import { addCollection } from '@iconify\u002Freact'\n",[670,684,686],{"class":672,"line":685},3,[670,687,688],{},"import { createHttpBackend } from '@skaile\u002Fforge-editor\u002Fadapters\u002Fhttp'\n",[670,690,692],{"class":672,"line":691},4,[670,693,694],{},"import { createEditorContext } from '@skaile\u002Fforge-editor\u002Fcore'\n",[670,696,698],{"class":672,"line":697},5,[670,699,700],{},"import { EditorContextProvider, reactNotifier, Toaster } from '@skaile\u002Fforge-editor\u002Freact'\n",[670,702,704],{"class":672,"line":703},6,[670,705,706],{},"import { StrictMode } from 'react'\n",[670,708,710],{"class":672,"line":709},7,[670,711,712],{},"import { createRoot } from 'react-dom\u002Fclient'\n",[670,714,716],{"class":672,"line":715},8,[670,717,718],{},"import { App } from '.\u002FApp'\n",[670,720,722],{"class":672,"line":721},9,[670,723,724],{},"import '.\u002Findex.css'\n",[670,726,728],{"class":672,"line":727},10,[670,729,731],{"emptyLinePlaceholder":730},true,"\n",[670,733,735],{"class":672,"line":734},11,[670,736,737],{},"\u002F\u002F Preload the icon set: the page makes no request to the Iconify API.\n",[670,739,741],{"class":672,"line":740},12,[670,742,743],{},"addCollection(lucide)\n",[670,745,747],{"class":672,"line":746},13,[670,748,731],{"emptyLinePlaceholder":730},[670,750,752],{"class":672,"line":751},14,[670,753,754],{},"\u002F\u002F The host owns the context; the provider never disposes it. The backend is the HTTP one (`\u002Fapi\u002Feditor` over the Nuxt host,\n",[670,756,758],{"class":672,"line":757},15,[670,759,760],{},"\u002F\u002F the collaboration websocket `\u002Fcollab\u002F\u003Cid>`); the backend offers `settings`, so they sync with the host's account store,\n",[670,762,764],{"class":672,"line":763},16,[670,765,766],{},"\u002F\u002F notices of app-level models become sonner toasts.\n",[670,768,770],{"class":672,"line":769},17,[670,771,772],{},"const context = createEditorContext({ backend: createHttpBackend(), notify: reactNotifier })\n",[670,774,776],{"class":672,"line":775},18,[670,777,731],{"emptyLinePlaceholder":730},[670,779,781],{"class":672,"line":780},19,[670,782,783],{},"createRoot(document.getElementById('app')!).render(\n",[670,785,787],{"class":672,"line":786},20,[670,788,789],{},"  \u003CStrictMode>\n",[670,791,793],{"class":672,"line":792},21,[670,794,795],{},"    \u003CEditorContextProvider context={context}>\n",[670,797,799],{"class":672,"line":798},22,[670,800,801],{},"      \u003CApp \u002F>\n",[670,803,805],{"class":672,"line":804},23,[670,806,807],{},"      \u003CToaster \u002F>\n",[670,809,811],{"class":672,"line":810},24,[670,812,813],{},"    \u003C\u002FEditorContextProvider>\n",[670,815,817],{"class":672,"line":816},25,[670,818,819],{},"  \u003C\u002FStrictMode>,\n",[670,821,823],{"class":672,"line":822},26,[670,824,825],{},")\n",[418,827,828,829,832,833,836,837,840],{},"The example passes ",[421,830,831],{},"createHttpBackend()"," so settings sync with the host's ",[421,834,835],{},"\u002Fapi\u002Feditor\u002Fsettings","; pass ",[421,838,839],{},"createMemoryBackend()"," for local-only settings.",[418,842,843,846,847,850,851,853,854,857,858,443,860,443,862,443,864,443,866,443,868,443,870,443,873,443,876,879,880,883],{},[542,844,845],{},"The page."," The chrome components beside the editor take the editor from ",[421,848,849],{},"onReady"," and find its preset through it. ",[421,852,423],{}," takes the surface's props except ",[421,855,856],{},"preset",", plus the composition props (",[421,859,442],{},[421,861,446],{},[421,863,449],{},[421,865,452],{},[421,867,455],{},[421,869,459],{},[421,871,872],{},"blockTypes",[421,874,875],{},"blockUi",[421,877,878],{},"coreContent",", read once at mount); ",[421,881,882],{},"\u003CAdvancedEditor remove={['tables']} ai={false} \u002F>"," is the advanced editor without tables and AI:",[660,885,887],{"className":662,"code":886,"language":665,"meta":666,"style":666},"import { AiSidebar } from '@skaile\u002Fforge-editor\u002Fai\u002Freact'\nimport { CommentsMargin } from '@skaile\u002Fforge-editor\u002Fcomments\u002Freact'\nimport { CompositeInspector } from '@skaile\u002Fforge-editor\u002Fcomposites\u002Freact'\nimport type { CollaborationSession } from '@skaile\u002Fforge-editor\u002Fcore'\nimport { EditorSettingsModal, EditorToolbar } from '@skaile\u002Fforge-editor\u002Freact'\nimport { AdvancedEditor } from '@skaile\u002Fforge-editor\u002Freact\u002Fadvanced'\nimport type { Editor } from '@tiptap\u002Fcore'\nimport { useState } from 'react'\n\nexport function Page({ id, session }: { id: string, session: CollaborationSession }) {\n  const [editor, setEditor] = useState\u003CEditor>()\n  const [scrollEl, setScrollEl] = useState\u003CHTMLElement | null>(null)\n  const [settingsOpen, setSettingsOpen] = useState(false)\n  const [sidebarOpen, setSidebarOpen] = useState(false)\n  const [commentsOpen, setCommentsOpen] = useState(false)\n\n  return (\n    \u003C>\n      \u003CEditorToolbar editor={editor} \u002F>\n      \u003Cmain ref={setScrollEl} className=\"relative flex min-h-0 flex-1 overflow-auto\">\n        \u003CAdvancedEditor\n          key={id}\n          collaboration={session}\n          documentId={id}\n          settingsUi=\"external\"\n          sidebarOpen={sidebarOpen}\n          onSidebarOpenChange={setSidebarOpen}\n          commentsOpen={commentsOpen}\n          onCommentsOpenChange={setCommentsOpen}\n          onReady={setEditor}\n          onSettingsOpen={() => setSettingsOpen(true)}\n        \u002F>\n        \u003CCommentsMargin editor={editor} container={scrollEl} open={commentsOpen} \u002F>\n      \u003C\u002Fmain>\n      \u003CCompositeInspector editor={editor} \u002F>\n      \u003CAiSidebar editor={editor} open={sidebarOpen} onOpenChange={setSidebarOpen} \u002F>\n      \u003CEditorSettingsModal editor={editor} open={settingsOpen} onOpenChange={setSettingsOpen} \u002F>\n    \u003C\u002F>\n  )\n}\n",[421,888,889,894,899,904,909,914,919,924,929,933,938,943,948,953,958,963,967,972,977,982,987,992,997,1002,1007,1012,1017,1023,1029,1035,1041,1047,1053,1059,1065,1071,1077,1083,1089,1095],{"__ignoreMap":666},[670,890,891],{"class":672,"line":673},[670,892,893],{},"import { AiSidebar } from '@skaile\u002Fforge-editor\u002Fai\u002Freact'\n",[670,895,896],{"class":672,"line":679},[670,897,898],{},"import { CommentsMargin } from '@skaile\u002Fforge-editor\u002Fcomments\u002Freact'\n",[670,900,901],{"class":672,"line":685},[670,902,903],{},"import { CompositeInspector } from '@skaile\u002Fforge-editor\u002Fcomposites\u002Freact'\n",[670,905,906],{"class":672,"line":691},[670,907,908],{},"import type { CollaborationSession } from '@skaile\u002Fforge-editor\u002Fcore'\n",[670,910,911],{"class":672,"line":697},[670,912,913],{},"import { EditorSettingsModal, EditorToolbar } from '@skaile\u002Fforge-editor\u002Freact'\n",[670,915,916],{"class":672,"line":703},[670,917,918],{},"import { AdvancedEditor } from '@skaile\u002Fforge-editor\u002Freact\u002Fadvanced'\n",[670,920,921],{"class":672,"line":709},[670,922,923],{},"import type { Editor } from '@tiptap\u002Fcore'\n",[670,925,926],{"class":672,"line":715},[670,927,928],{},"import { useState } from 'react'\n",[670,930,931],{"class":672,"line":721},[670,932,731],{"emptyLinePlaceholder":730},[670,934,935],{"class":672,"line":727},[670,936,937],{},"export function Page({ id, session }: { id: string, session: CollaborationSession }) {\n",[670,939,940],{"class":672,"line":734},[670,941,942],{},"  const [editor, setEditor] = useState\u003CEditor>()\n",[670,944,945],{"class":672,"line":740},[670,946,947],{},"  const [scrollEl, setScrollEl] = useState\u003CHTMLElement | null>(null)\n",[670,949,950],{"class":672,"line":746},[670,951,952],{},"  const [settingsOpen, setSettingsOpen] = useState(false)\n",[670,954,955],{"class":672,"line":751},[670,956,957],{},"  const [sidebarOpen, setSidebarOpen] = useState(false)\n",[670,959,960],{"class":672,"line":757},[670,961,962],{},"  const [commentsOpen, setCommentsOpen] = useState(false)\n",[670,964,965],{"class":672,"line":763},[670,966,731],{"emptyLinePlaceholder":730},[670,968,969],{"class":672,"line":769},[670,970,971],{},"  return (\n",[670,973,974],{"class":672,"line":775},[670,975,976],{},"    \u003C>\n",[670,978,979],{"class":672,"line":780},[670,980,981],{},"      \u003CEditorToolbar editor={editor} \u002F>\n",[670,983,984],{"class":672,"line":786},[670,985,986],{},"      \u003Cmain ref={setScrollEl} className=\"relative flex min-h-0 flex-1 overflow-auto\">\n",[670,988,989],{"class":672,"line":792},[670,990,991],{},"        \u003CAdvancedEditor\n",[670,993,994],{"class":672,"line":798},[670,995,996],{},"          key={id}\n",[670,998,999],{"class":672,"line":804},[670,1000,1001],{},"          collaboration={session}\n",[670,1003,1004],{"class":672,"line":810},[670,1005,1006],{},"          documentId={id}\n",[670,1008,1009],{"class":672,"line":816},[670,1010,1011],{},"          settingsUi=\"external\"\n",[670,1013,1014],{"class":672,"line":822},[670,1015,1016],{},"          sidebarOpen={sidebarOpen}\n",[670,1018,1020],{"class":672,"line":1019},27,[670,1021,1022],{},"          onSidebarOpenChange={setSidebarOpen}\n",[670,1024,1026],{"class":672,"line":1025},28,[670,1027,1028],{},"          commentsOpen={commentsOpen}\n",[670,1030,1032],{"class":672,"line":1031},29,[670,1033,1034],{},"          onCommentsOpenChange={setCommentsOpen}\n",[670,1036,1038],{"class":672,"line":1037},30,[670,1039,1040],{},"          onReady={setEditor}\n",[670,1042,1044],{"class":672,"line":1043},31,[670,1045,1046],{},"          onSettingsOpen={() => setSettingsOpen(true)}\n",[670,1048,1050],{"class":672,"line":1049},32,[670,1051,1052],{},"        \u002F>\n",[670,1054,1056],{"class":672,"line":1055},33,[670,1057,1058],{},"        \u003CCommentsMargin editor={editor} container={scrollEl} open={commentsOpen} \u002F>\n",[670,1060,1062],{"class":672,"line":1061},34,[670,1063,1064],{},"      \u003C\u002Fmain>\n",[670,1066,1068],{"class":672,"line":1067},35,[670,1069,1070],{},"      \u003CCompositeInspector editor={editor} \u002F>\n",[670,1072,1074],{"class":672,"line":1073},36,[670,1075,1076],{},"      \u003CAiSidebar editor={editor} open={sidebarOpen} onOpenChange={setSidebarOpen} \u002F>\n",[670,1078,1080],{"class":672,"line":1079},37,[670,1081,1082],{},"      \u003CEditorSettingsModal editor={editor} open={settingsOpen} onOpenChange={setSettingsOpen} \u002F>\n",[670,1084,1086],{"class":672,"line":1085},38,[670,1087,1088],{},"    \u003C\u002F>\n",[670,1090,1092],{"class":672,"line":1091},39,[670,1093,1094],{},"  )\n",[670,1096,1098],{"class":672,"line":1097},40,[670,1099,1100],{},"}\n",[418,1102,1103],{},"Notes:",[552,1105,1106,1149,1212,1233,1252],{},[555,1107,1108,1111,1112,1115,1116,523,1119,424,1122,1125,1126,1129,1130,1133,1134,1136,1137,1140,1141,1144,1145,1148],{},[542,1109,1110],{},"Collaboration."," The ",[421,1113,1114],{},"session"," is ",[421,1117,1118],{},"{ ydoc, provider, user }",[421,1120,1121],{},"CollaborationSession",[421,1123,1124],{},"@skaile\u002Fforge-editor\u002Fcore","): create the ",[421,1127,1128],{},"Y.Doc"," and the ",[421,1131,1132],{},"HocuspocusProvider"," in an effect (so StrictMode's double mount leaves exactly one provider), destroy the provider in its cleanup, and key the editor by document so a new document is a new Y.Doc (",[515,1135,308],{"href":309},"). Without ",[421,1138,1139],{},"collaboration"," pass ",[421,1142,1143],{},"value","\u002F",[421,1146,1147],{},"onChange"," for a standalone editor (the collaboration and comments features then contribute nothing).",[555,1150,1151,1154,1155,443,1158,1144,1161,443,1164,443,1167,443,1170,443,1173,443,1176,456,1179,1182,1183,424,1186,1188,1189,1192,1193,443,1196,443,1199,443,1202,443,1205,443,1208,1211],{},[542,1152,1153],{},"Beside the editor."," ",[421,1156,1157],{},"EditorToolbar",[421,1159,1160],{},"EditorSettingsModal",[421,1162,1163],{},"EditorSettingsPanel",[421,1165,1166],{},"CommentsMargin",[421,1168,1169],{},"CompositeTable",[421,1171,1172],{},"CompositeInspector",[421,1174,1175],{},"AiSidebar",[421,1177,1178],{},"EditorOutline",[421,1180,1181],{},"DocumentTree"," are components you place; each takes the ",[421,1184,1185],{},"editor",[421,1187,849],{},". ",[421,1190,1191],{},"useEditorUi(editor)"," returns the chrome of a ready editor (",[421,1194,1195],{},"openSettings(tab?)",[421,1197,1198],{},"toggleSidebar()",[421,1200,1201],{},"toggleComments()",[421,1203,1204],{},"commentsOpen",[421,1206,1207],{},"togglePalette()",[421,1209,1210],{},"paletteOpen",") for your own buttons.",[555,1213,1214,1217,1218,1221,1222,1224,1225,1228,1229,1232],{},[542,1215,1216],{},"Own features."," Pass them as ",[421,1219,1220],{},"add={[myFeature()]}"," (appended after the catalog), or build the preset for an ",[421,1223,434],{}," yourself: ",[421,1226,1227],{},"advancedEditor({ add: [myFeature()] })",", as in the Nuxt app's kitchen sink (",[421,1230,1231],{},"app\u002Fpages\u002Fkitchen-sink\u002Fsurface.vue",").",[555,1234,1235,1115,1238,1245,1246,1249,1250,652],{},[542,1236,1237],{},"The file browser",[515,1239,1240,424,1242],{"href":118},[421,1241,1181],{},[421,1243,1244],{},"@skaile\u002Fforge-editor\u002Ftree\u002Freact"," over a ",[421,1247,1248],{},"DocumentStore","; the example wires it to the host's ",[421,1251,530],{},[555,1253,1254,1257,1258,1261,1262,456,1265,1268],{},[542,1255,1256],{},"Backend."," The same as for the Vue advanced editor: ",[421,1259,1260],{},"\u002Fcollab\u002F:id",", the AI endpoints, assets, users\u002Ftags and themes of the Nuxt module and a host adapter (",[515,1263,1264],{"href":141},"Nuxt module",[515,1266,1267],{"href":196},"EditorPorts","). A React app with its own server brings the same routes.",[1270,1271,1272],"style",{},"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":666,"searchDepth":679,"depth":679,"links":1274},[],"Mount the collaborative AdvancedEditor on React with the chrome components beside it, over the same backend as the Vue surface.","md",null,{},{"icon":83},{"title":127,"description":1275},"NgX3j_zdJL70cMp0ylwSoDq1BfgIWmwiLhdTtPWfMU8",[1283,1285],{"title":122,"path":123,"stem":124,"description":1284,"icon":125,"children":-1},"Edit Markdown files as blocks with frontmatter and unknown fences preserved, edit source files in CodeMirror, and pick a surface per file type.",{"title":131,"path":132,"stem":133,"description":1286,"icon":6,"children":-1},"Fifteen pages, basics first: structure, content blocks, JSON and Markdown, block actions and settings, then the building blocks, then the use cases, each with the code that builds it",1793213902476]