[{"data":1,"prerenderedAt":3174},["ShallowReactive",2],{"navigation_docs":3,"-tutorial-own-feature-path-b":412,"-tutorial-own-feature-path-b-surround":3169},[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":65,"body":414,"description":3162,"extension":3163,"links":3164,"meta":3165,"navigation":3166,"path":66,"seo":3167,"stem":67,"__hash__":3168},"docs\u002F2.tutorial\u002F5.own-feature-path-b.md",{"type":415,"value":416,"toc":3146},"minimark",[417,421,433,436,441,462,776,820,832,849,1125,1236,1243,1273,1559,1562,1592,1599,1613,2657,2660,2756,2762,2768,2772,2790,2813,2823,2843,2851,2922,2944,2959,2962,3059,3069,3073,3082,3116,3120,3133,3137,3142],[418,419,420],"p",{},"Path A gave the callout a slash entry. Path B makes it a feature like the built-in ones: a toolbar button next to the media buttons, a hover menu on the block that switches the tone, „Umwandeln in Callout“ for paragraphs and „Umwandeln in …“ out of a callout. It reuses the node of chapter 4 unchanged.",[418,422,423,424,428,429,432],{},"A feature is a bundle of contributions behind one ",[425,426,427],"code",{},"id",". Features differ only by which contribution slots they fill; nothing is registered globally. The callout feature fills six slots, shown piece by piece below. Try the result first: the toolbar has a „Callout“ button in the ",[425,430,431],{},"inserts"," group, hovering a callout shows a bar with the tone menu, and the block's „Umwandeln in …“ menu lists the conversions:",[434,435],"demo-callout-path-b",{},[437,438,440],"h2",{"id":439},"the-feature","The feature",[418,442,443,446,447,450,451,453,454,457,458,461],{},[425,444,445],{},"feature.ts"," in the kitchen sink (",[425,448,449],{},"app\u002Feditor\u002Fcallout\u002F",") starts with the ability that gates the callout and the factory that returns the feature. Three fields identify it: ",[425,452,427],{},", the ",[425,455,456],{},"dimension"," (",[425,459,460],{},"'content'",", because it adds a node to the document) and the node it contributes.",[463,464,470],"pre",{"className":465,"code":466,"filename":467,"language":468,"meta":469,"style":469},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { command, type EditorFeature } from '@skaile\u002Fforge-editor\u002Fcore'\nimport { calloutConversions } from '.\u002Fconvert'\nimport { CalloutBlock } from '.\u002Findex'\nimport { Callout, TONES } from '.\u002Fnode'\n\n\u002F** The ability that gates the callout's toolbar button, `\u002F` command and hover menu; grant it at root through the `abilities` prop. *\u002F\nexport const CALLOUT_ABILITY = 'insert.callout'\n\n\u002F**\n * The callout as a full editor feature: node, one command (toolbar button merged into the `inserts` group beside\n * \"Speaker block\", and `\u002Fcallout`), a hover menu for the tone, the two-way \"Convert to …\" conversion and its description for the AI\n * (`aiContext.blocks`), so chat and generate tasks can create, convert to and edit callouts.\n *\u002F\nexport function calloutFeature(): EditorFeature\u003Cnever> {\n  return {\n    id: 'callout',\n    dimension: 'content',\n    schemaExtensions: () => [Callout],\n    extensions: () => [CalloutBlock],\n","app\u002Feditor\u002Fcallout\u002Ffeature.ts","ts","",[425,471,472,514,535,556,582,589,596,619,624,630,636,642,648,654,684,692,713,730,755],{"__ignoreMap":469},[473,474,477,481,485,489,492,495,498,501,504,507,511],"span",{"class":475,"line":476},"line",1,[473,478,480],{"class":479},"s7zQu","import",[473,482,484],{"class":483},"sMK4o"," {",[473,486,488],{"class":487},"sTEyZ"," command",[473,490,491],{"class":483},",",[473,493,494],{"class":479}," type",[473,496,497],{"class":487}," EditorFeature",[473,499,500],{"class":483}," }",[473,502,503],{"class":479}," from",[473,505,506],{"class":483}," '",[473,508,510],{"class":509},"sfazB","@skaile\u002Fforge-editor\u002Fcore",[473,512,513],{"class":483},"'\n",[473,515,517,519,521,524,526,528,530,533],{"class":475,"line":516},2,[473,518,480],{"class":479},[473,520,484],{"class":483},[473,522,523],{"class":487}," calloutConversions",[473,525,500],{"class":483},[473,527,503],{"class":479},[473,529,506],{"class":483},[473,531,532],{"class":509},".\u002Fconvert",[473,534,513],{"class":483},[473,536,538,540,542,545,547,549,551,554],{"class":475,"line":537},3,[473,539,480],{"class":479},[473,541,484],{"class":483},[473,543,544],{"class":487}," CalloutBlock",[473,546,500],{"class":483},[473,548,503],{"class":479},[473,550,506],{"class":483},[473,552,553],{"class":509},".\u002Findex",[473,555,513],{"class":483},[473,557,559,561,563,566,568,571,573,575,577,580],{"class":475,"line":558},4,[473,560,480],{"class":479},[473,562,484],{"class":483},[473,564,565],{"class":487}," Callout",[473,567,491],{"class":483},[473,569,570],{"class":487}," TONES",[473,572,500],{"class":483},[473,574,503],{"class":479},[473,576,506],{"class":483},[473,578,579],{"class":509},".\u002Fnode",[473,581,513],{"class":483},[473,583,585],{"class":475,"line":584},5,[473,586,588],{"emptyLinePlaceholder":587},true,"\n",[473,590,592],{"class":475,"line":591},6,[473,593,595],{"class":594},"sHwdD","\u002F** The ability that gates the callout's toolbar button, `\u002F` command and hover menu; grant it at root through the `abilities` prop. *\u002F\n",[473,597,599,602,606,609,612,614,617],{"class":475,"line":598},7,[473,600,601],{"class":479},"export",[473,603,605],{"class":604},"spNyl"," const",[473,607,608],{"class":487}," CALLOUT_ABILITY ",[473,610,611],{"class":483},"=",[473,613,506],{"class":483},[473,615,616],{"class":509},"insert.callout",[473,618,513],{"class":483},[473,620,622],{"class":475,"line":621},8,[473,623,588],{"emptyLinePlaceholder":587},[473,625,627],{"class":475,"line":626},9,[473,628,629],{"class":594},"\u002F**\n",[473,631,633],{"class":475,"line":632},10,[473,634,635],{"class":594}," * The callout as a full editor feature: node, one command (toolbar button merged into the `inserts` group beside\n",[473,637,639],{"class":475,"line":638},11,[473,640,641],{"class":594}," * \"Speaker block\", and `\u002Fcallout`), a hover menu for the tone, the two-way \"Convert to …\" conversion and its description for the AI\n",[473,643,645],{"class":475,"line":644},12,[473,646,647],{"class":594}," * (`aiContext.blocks`), so chat and generate tasks can create, convert to and edit callouts.\n",[473,649,651],{"class":475,"line":650},13,[473,652,653],{"class":594}," *\u002F\n",[473,655,657,659,662,666,669,672,675,678,681],{"class":475,"line":656},14,[473,658,601],{"class":479},[473,660,661],{"class":604}," function",[473,663,665],{"class":664},"s2Zo4"," calloutFeature",[473,667,668],{"class":483},"():",[473,670,497],{"class":671},"sBMFI",[473,673,674],{"class":483},"\u003C",[473,676,677],{"class":671},"never",[473,679,680],{"class":483},">",[473,682,683],{"class":483}," {\n",[473,685,687,690],{"class":475,"line":686},15,[473,688,689],{"class":479},"  return",[473,691,683],{"class":483},[473,693,695,699,702,704,707,710],{"class":475,"line":694},16,[473,696,698],{"class":697},"swJcz","    id",[473,700,701],{"class":483},":",[473,703,506],{"class":483},[473,705,706],{"class":509},"callout",[473,708,709],{"class":483},"'",[473,711,712],{"class":483},",\n",[473,714,716,719,721,723,726,728],{"class":475,"line":715},17,[473,717,718],{"class":697},"    dimension",[473,720,701],{"class":483},[473,722,506],{"class":483},[473,724,725],{"class":509},"content",[473,727,709],{"class":483},[473,729,712],{"class":483},[473,731,733,736,738,741,744,747,750,753],{"class":475,"line":732},18,[473,734,735],{"class":664},"    schemaExtensions",[473,737,701],{"class":483},[473,739,740],{"class":483}," ()",[473,742,743],{"class":604}," =>",[473,745,746],{"class":697}," [",[473,748,749],{"class":487},"Callout",[473,751,752],{"class":697},"]",[473,754,712],{"class":483},[473,756,758,761,763,765,767,769,772,774],{"class":475,"line":757},19,[473,759,760],{"class":664},"    extensions",[473,762,701],{"class":483},[473,764,740],{"class":483},[473,766,743],{"class":604},[473,768,746],{"class":697},[473,770,771],{"class":487},"CalloutBlock",[473,773,752],{"class":697},[473,775,712],{"class":483},[777,778,779,792,808],"ul",{},[780,781,782,788,789,791],"li",{},[783,784,785],"strong",{},[425,786,787],{},"extensions"," adds the node with its view to the editor's schema. Feature extensions are added in feature order, before the ",[425,790,787],{}," prop.",[780,793,794,799,800,803,804,807],{},[783,795,796],{},[425,797,798],{},"schemaExtensions"," names the Vue-free node file. A server that validates or seeds documents collects these with ",[425,801,802],{},"schemaExtensionsOf(features)"," from ",[425,805,806],{},"@skaile\u002Fforge-editor\u002Fcore\u002Fschema"," (chapter 6).",[780,809,810,815,816,819],{},[783,811,812],{},[425,813,814],{},"EditorFeature\u003Cnever>"," says the feature holds no framework components. It fits a Vue and a React list alike; the callout node view stays in ",[425,817,818],{},"index.ts",".",[821,822,824,827,828,831],"h3",{"id":823},"commands-toolbar-menu-and-palette-from-one-definition",[425,825,826],{},"commands",": toolbar, ",[425,829,830],{},"\u002F"," menu and palette from one definition",[418,833,834,835,838,839,842,843,845,846,848],{},"A command is declared once, with the placements that show it. ",[425,836,837],{},"toolbar: { group, order }"," puts it on the toolbar, ",[425,840,841],{},"slash: { id? }"," in the ",[425,844,830],{}," menu, and the ⌘K palette lists every command that runs or opens a menu. The toolbar, the ",[425,847,830],{}," menu and the palette all derive their entries and their enabled and visible state from the same definition, so a command cannot be gated differently in two places.",[463,850,852],{"className":465,"code":851,"filename":467,"language":468,"meta":469,"style":469},"    commands: () => [\n      command({\n        id: 'callout',\n        toolbar: { group: 'inserts', order: 15 },\n        slash: { id: 'callout' },\n        creates: { type: 'callout' },\n        icon: 'i-lucide-info',\n        label: 'Callout',\n        kbds: ['meta', 'shift', 'h'],\n        ability: CALLOUT_ABILITY,\n        command: c => c.toggleCallout(),\n        active: e => e.isActive('callout'),\n      }),\n    ],\n",[425,853,854,868,879,894,928,950,971,987,1002,1040,1052,1077,1109,1118],{"__ignoreMap":469},[473,855,856,859,861,863,865],{"class":475,"line":476},[473,857,858],{"class":671},"    commands",[473,860,701],{"class":483},[473,862,740],{"class":483},[473,864,743],{"class":604},[473,866,867],{"class":487}," [\n",[473,869,870,873,876],{"class":475,"line":516},[473,871,872],{"class":664},"      command",[473,874,875],{"class":487},"(",[473,877,878],{"class":483},"{\n",[473,880,881,884,886,888,890,892],{"class":475,"line":537},[473,882,883],{"class":697},"        id",[473,885,701],{"class":483},[473,887,506],{"class":483},[473,889,706],{"class":509},[473,891,709],{"class":483},[473,893,712],{"class":483},[473,895,896,899,901,903,906,908,910,912,914,916,919,921,925],{"class":475,"line":558},[473,897,898],{"class":697},"        toolbar",[473,900,701],{"class":483},[473,902,484],{"class":483},[473,904,905],{"class":697}," group",[473,907,701],{"class":483},[473,909,506],{"class":483},[473,911,431],{"class":509},[473,913,709],{"class":483},[473,915,491],{"class":483},[473,917,918],{"class":697}," order",[473,920,701],{"class":483},[473,922,924],{"class":923},"sbssI"," 15",[473,926,927],{"class":483}," },\n",[473,929,930,933,935,937,940,942,944,946,948],{"class":475,"line":584},[473,931,932],{"class":697},"        slash",[473,934,701],{"class":483},[473,936,484],{"class":483},[473,938,939],{"class":697}," id",[473,941,701],{"class":483},[473,943,506],{"class":483},[473,945,706],{"class":509},[473,947,709],{"class":483},[473,949,927],{"class":483},[473,951,952,955,957,959,961,963,965,967,969],{"class":475,"line":591},[473,953,954],{"class":697},"        creates",[473,956,701],{"class":483},[473,958,484],{"class":483},[473,960,494],{"class":697},[473,962,701],{"class":483},[473,964,506],{"class":483},[473,966,706],{"class":509},[473,968,709],{"class":483},[473,970,927],{"class":483},[473,972,973,976,978,980,983,985],{"class":475,"line":598},[473,974,975],{"class":697},"        icon",[473,977,701],{"class":483},[473,979,506],{"class":483},[473,981,982],{"class":509},"i-lucide-info",[473,984,709],{"class":483},[473,986,712],{"class":483},[473,988,989,992,994,996,998,1000],{"class":475,"line":621},[473,990,991],{"class":697},"        label",[473,993,701],{"class":483},[473,995,506],{"class":483},[473,997,749],{"class":509},[473,999,709],{"class":483},[473,1001,712],{"class":483},[473,1003,1004,1007,1009,1011,1013,1016,1018,1020,1022,1025,1027,1029,1031,1034,1036,1038],{"class":475,"line":626},[473,1005,1006],{"class":697},"        kbds",[473,1008,701],{"class":483},[473,1010,746],{"class":487},[473,1012,709],{"class":483},[473,1014,1015],{"class":509},"meta",[473,1017,709],{"class":483},[473,1019,491],{"class":483},[473,1021,506],{"class":483},[473,1023,1024],{"class":509},"shift",[473,1026,709],{"class":483},[473,1028,491],{"class":483},[473,1030,506],{"class":483},[473,1032,1033],{"class":509},"h",[473,1035,709],{"class":483},[473,1037,752],{"class":487},[473,1039,712],{"class":483},[473,1041,1042,1045,1047,1050],{"class":475,"line":632},[473,1043,1044],{"class":697},"        ability",[473,1046,701],{"class":483},[473,1048,1049],{"class":487}," CALLOUT_ABILITY",[473,1051,712],{"class":483},[473,1053,1054,1057,1059,1063,1065,1067,1069,1072,1075],{"class":475,"line":638},[473,1055,1056],{"class":664},"        command",[473,1058,701],{"class":483},[473,1060,1062],{"class":1061},"sHdIc"," c",[473,1064,743],{"class":604},[473,1066,1062],{"class":487},[473,1068,819],{"class":483},[473,1070,1071],{"class":664},"toggleCallout",[473,1073,1074],{"class":487},"()",[473,1076,712],{"class":483},[473,1078,1079,1082,1084,1087,1089,1091,1093,1096,1098,1100,1102,1104,1107],{"class":475,"line":644},[473,1080,1081],{"class":664},"        active",[473,1083,701],{"class":483},[473,1085,1086],{"class":1061}," e",[473,1088,743],{"class":604},[473,1090,1086],{"class":487},[473,1092,819],{"class":483},[473,1094,1095],{"class":664},"isActive",[473,1097,875],{"class":487},[473,1099,709],{"class":483},[473,1101,706],{"class":509},[473,1103,709],{"class":483},[473,1105,1106],{"class":487},")",[473,1108,712],{"class":483},[473,1110,1111,1114,1116],{"class":475,"line":650},[473,1112,1113],{"class":483},"      }",[473,1115,1106],{"class":487},[473,1117,712],{"class":483},[473,1119,1120,1123],{"class":475,"line":656},[473,1121,1122],{"class":487},"    ]",[473,1124,712],{"class":483},[777,1126,1127,1159,1195,1219],{},[780,1128,1129,1132,1133,1136,1137,1140,1141,1143,1144,1147,1148,1151,1152,1155,1156,1158],{},[783,1130,1131],{},"Groups."," ",[425,1134,1135],{},"toolbar.group"," must name a group some feature declares in ",[425,1138,1139],{},"toolbarGroups",". The callout needs none of its own: it puts its button into the ",[425,1142,431],{}," group that the transcript feature (speaker button, ",[425,1145,1146],{},"order: 10",") and the media feature (pickers, ",[425,1149,1150],{},"order"," 20 to 50) fill, so ",[425,1153,1154],{},"order: 15"," places „Callout“ between „Sprecherblock“ and the media buttons. A command ",[425,1157,427],{}," is unique per editor.",[780,1160,1161,1132,1164,1167,1168,1171,1172,1175,1176,1179,1180,1183,1184,1187,1188,1191,1192,819],{},[783,1162,1163],{},"Bodies.",[425,1165,1166],{},"command: chain => chain.toggleX()"," builds a ",[425,1169,1170],{},"run"," command from a command chain: it focuses the editor, runs the chain and is disabled while ",[425,1173,1174],{},"editor.can().chain()"," says it is impossible. ",[425,1177,1178],{},"active"," makes it a toggle. Write ",[425,1181,1182],{},"run: editor => …"," yourself for anything else, or ",[425,1185,1186],{},"menu"," for a dropdown. ",[425,1189,1190],{},"kbds"," only labels the tooltip; the shortcut itself is the node's ",[425,1193,1194],{},"addKeyboardShortcuts",[780,1196,1197,1132,1200,1203,1204,1207,1208,1211,1212,1215,1216,1218],{},[783,1198,1199],{},"Gating.",[425,1201,1202],{},"ability"," disables the command where the caret does not hold that ability. ",[425,1205,1206],{},"creates: { type }"," names the node the command inserts: it is disabled where the schema does not allow that node at the caret. ",[425,1209,1210],{},"can(editor)"," adds a structural check of your own, ",[425,1213,1214],{},"visible(editor)"," hides the command. The ",[425,1217,830],{}," menu lists enabled commands only; the toolbar and the palette grey them.",[780,1220,1221,1224,1225,1227,1228,1231,1232,1235],{},[783,1222,1223],{},"Abilities at root."," A command whose ",[425,1226,1202],{}," is neither in ",[425,1229,1230],{},"ROOT_ABILITIES"," nor granted by the ",[425,1233,1234],{},"abilities"," prop never becomes enabled at document root. The surface logs a warning once per command when it mounts. The mount below grants it.",[821,1237,1239,1242],{"id":1238},"blockactions-the-hover-menu",[425,1240,1241],{},"blockActions",": the hover menu",[418,1244,1245,1246,1249,1250,1252,1253,1256,1257,1259,1260,1262,1263,1265,1266,1268,1269,1272],{},"Hover actions sit on a block's top line at the editor's right edge, shown by an installed ",[425,1247,1248],{},"block-ui"," feature. ",[425,1251,1202],{}," is checked on the block itself, ",[425,1254,1255],{},"isVisible"," narrows it further, and ",[425,1258,1150],{}," sorts feature actions; actions with a larger ",[425,1261,1150],{},", like the callout's 500, follow the built-in ones. With ",[425,1264,1186],{}," instead of ",[425,1267,1170],{}," the action opens a dropdown. The callout's lists the tones and applies one with ",[425,1270,1271],{},"setCalloutTone"," after selecting the block.",[463,1274,1276],{"className":465,"code":1275,"filename":467,"language":468,"meta":469,"style":469},"    blockActions: () => [{\n      id: 'callout-tone',\n      label: 'Callout tone',\n      icon: 'i-lucide-palette',\n      ability: CALLOUT_ABILITY,\n      order: 500,\n      isVisible: ({ node }) => node.type.name === 'callout',\n      menu: ({ editor, pos }) => TONES.map(tone => ({\n        label: tone.label,\n        icon: tone.icon,\n        onSelect: () => editor.chain().focus().setNodeSelection(pos).setCalloutTone(tone.value).run(),\n      })),\n    }],\n    conversions: [calloutConversions],\n",[425,1277,1278,1293,1309,1325,1340,1351,1363,1404,1443,1459,1474,1529,1538,1547],{"__ignoreMap":469},[473,1279,1280,1283,1285,1287,1289,1291],{"class":475,"line":476},[473,1281,1282],{"class":671},"    blockActions",[473,1284,701],{"class":483},[473,1286,740],{"class":483},[473,1288,743],{"class":604},[473,1290,746],{"class":487},[473,1292,878],{"class":483},[473,1294,1295,1298,1300,1302,1305,1307],{"class":475,"line":516},[473,1296,1297],{"class":697},"      id",[473,1299,701],{"class":483},[473,1301,506],{"class":483},[473,1303,1304],{"class":509},"callout-tone",[473,1306,709],{"class":483},[473,1308,712],{"class":483},[473,1310,1311,1314,1316,1318,1321,1323],{"class":475,"line":537},[473,1312,1313],{"class":697},"      label",[473,1315,701],{"class":483},[473,1317,506],{"class":483},[473,1319,1320],{"class":509},"Callout tone",[473,1322,709],{"class":483},[473,1324,712],{"class":483},[473,1326,1327,1330,1332,1334,1336,1338],{"class":475,"line":558},[473,1328,1329],{"class":697},"      icon",[473,1331,701],{"class":483},[473,1333,506],{"class":483},[473,1335,107],{"class":509},[473,1337,709],{"class":483},[473,1339,712],{"class":483},[473,1341,1342,1345,1347,1349],{"class":475,"line":584},[473,1343,1344],{"class":697},"      ability",[473,1346,701],{"class":483},[473,1348,1049],{"class":487},[473,1350,712],{"class":483},[473,1352,1353,1356,1358,1361],{"class":475,"line":591},[473,1354,1355],{"class":697},"      order",[473,1357,701],{"class":483},[473,1359,1360],{"class":923}," 500",[473,1362,712],{"class":483},[473,1364,1365,1368,1370,1373,1376,1379,1381,1383,1385,1388,1390,1393,1396,1398,1400,1402],{"class":475,"line":598},[473,1366,1367],{"class":664},"      isVisible",[473,1369,701],{"class":483},[473,1371,1372],{"class":483}," ({",[473,1374,1375],{"class":1061}," node",[473,1377,1378],{"class":483}," })",[473,1380,743],{"class":604},[473,1382,1375],{"class":487},[473,1384,819],{"class":483},[473,1386,1387],{"class":487},"type",[473,1389,819],{"class":483},[473,1391,1392],{"class":487},"name ",[473,1394,1395],{"class":483},"===",[473,1397,506],{"class":483},[473,1399,706],{"class":509},[473,1401,709],{"class":483},[473,1403,712],{"class":483},[473,1405,1406,1409,1411,1413,1416,1418,1421,1423,1425,1427,1429,1432,1434,1437,1439,1441],{"class":475,"line":621},[473,1407,1408],{"class":664},"      menu",[473,1410,701],{"class":483},[473,1412,1372],{"class":483},[473,1414,1415],{"class":1061}," editor",[473,1417,491],{"class":483},[473,1419,1420],{"class":1061}," pos",[473,1422,1378],{"class":483},[473,1424,743],{"class":604},[473,1426,570],{"class":487},[473,1428,819],{"class":483},[473,1430,1431],{"class":664},"map",[473,1433,875],{"class":487},[473,1435,1436],{"class":1061},"tone",[473,1438,743],{"class":604},[473,1440,457],{"class":487},[473,1442,878],{"class":483},[473,1444,1445,1447,1449,1452,1454,1457],{"class":475,"line":626},[473,1446,991],{"class":697},[473,1448,701],{"class":483},[473,1450,1451],{"class":487}," tone",[473,1453,819],{"class":483},[473,1455,1456],{"class":487},"label",[473,1458,712],{"class":483},[473,1460,1461,1463,1465,1467,1469,1472],{"class":475,"line":632},[473,1462,975],{"class":697},[473,1464,701],{"class":483},[473,1466,1451],{"class":487},[473,1468,819],{"class":483},[473,1470,1471],{"class":487},"icon",[473,1473,712],{"class":483},[473,1475,1476,1479,1481,1483,1485,1487,1489,1492,1494,1496,1499,1501,1503,1506,1509,1511,1513,1516,1518,1521,1523,1525,1527],{"class":475,"line":638},[473,1477,1478],{"class":664},"        onSelect",[473,1480,701],{"class":483},[473,1482,740],{"class":483},[473,1484,743],{"class":604},[473,1486,1415],{"class":487},[473,1488,819],{"class":483},[473,1490,1491],{"class":664},"chain",[473,1493,1074],{"class":487},[473,1495,819],{"class":483},[473,1497,1498],{"class":664},"focus",[473,1500,1074],{"class":487},[473,1502,819],{"class":483},[473,1504,1505],{"class":664},"setNodeSelection",[473,1507,1508],{"class":487},"(pos)",[473,1510,819],{"class":483},[473,1512,1271],{"class":664},[473,1514,1515],{"class":487},"(tone",[473,1517,819],{"class":483},[473,1519,1520],{"class":487},"value)",[473,1522,819],{"class":483},[473,1524,1170],{"class":664},[473,1526,1074],{"class":487},[473,1528,712],{"class":483},[473,1530,1531,1533,1536],{"class":475,"line":644},[473,1532,1113],{"class":483},[473,1534,1535],{"class":487},"))",[473,1537,712],{"class":483},[473,1539,1540,1543,1545],{"class":475,"line":650},[473,1541,1542],{"class":483},"    }",[473,1544,752],{"class":487},[473,1546,712],{"class":483},[473,1548,1549,1552,1554,1557],{"class":475,"line":656},[473,1550,1551],{"class":671},"    conversions",[473,1553,701],{"class":483},[473,1555,1556],{"class":487}," [calloutConversions]",[473,1558,712],{"class":483},[418,1560,1561],{},"The bar is hidden while the editor is read-only.",[418,1563,1564,1565,1568,1569,1572,1573,1576,1577,1580,1581,1583,1584,1587,1588,1591],{},"Where the bar appears is the host's choice: ",[425,1566,1567],{},"blockUiFeature({ actions })"," (or ",[425,1570,1571],{},"composeEditor({ blockUi: { actions } })",") selects the hover bar (default), a toolbar on the block holding the selection, both, or none. An action can restrict itself with ",[425,1574,1575],{},"placement: 'hover' | 'toolbar' | 'both'"," (default ",[425,1578,1579],{},"'both'","), e.g. a rarely needed action on the toolbar only. ",[425,1582,1202],{}," stays a gate on the block's place in the document, not a presentation switch: removing an ability hides the action everywhere, ",[425,1585,1586],{},"placement"," and ",[425,1589,1590],{},"actions"," only decide on which surface it is offered.",[821,1593,1595,1598],{"id":1594},"conversions-umwandeln-in",[425,1596,1597],{},"conversions",": „Umwandeln in …“",[418,1600,1601,1602,1605,1606,1609,1610,701],{},"„Umwandeln in …“ (hover menu, toolbar groups, the AI ",[425,1603,1604],{},"convert"," operation) runs through ",[425,1607,1608],{},"ConversionProvider","s. The callout contributes one, in ",[425,1611,1612],{},"convert.ts",[463,1614,1617],{"className":465,"code":1615,"filename":1616,"language":468,"meta":469,"style":469},"import type { Node as PMNode } from '@tiptap\u002Fpm\u002Fmodel'\nimport {\n  childrenOf,\n  type ConversionProvider,\n  CORE_TARGET_IDS,\n  convertCoreBlocks,\n  type ConvertTarget,\n  createConverter,\n  finishConversion,\n  isCoreSource,\n  parseCoreTarget,\n} from '@skaile\u002Fforge-editor\u002Fcore'\n\nconst CALLOUT = 'callout'\n\u002F\u002F A host block names itself with the inert `custom` target: `id` is the target id and the node type name.\nconst TARGET: ConvertTarget = { type: 'custom', id: CALLOUT }\n\u002F** The core targets a callout unwraps into. *\u002F\nconst UNWRAP_TARGETS: readonly ConvertTarget[] = CORE_TARGET_IDS.flatMap(id => parseCoreTarget(id) ?? [])\n\nconst isCallout = (node: PMNode) => node.type.name === CALLOUT\n\n\u002F**\n * Paragraphs, headings, code blocks, lists and quotes become a callout (the quote rule: textblocks turn into\n * paragraphs, lists and quotes keep their blocks); a callout unwraps into every core target through the core engine.\n * `handlesSource` makes this provider execute every conversion of a callout, the core provider has none for it.\n *\u002F\nexport const calloutConversions: ConversionProvider = {\n  handlesSource: isCallout,\n  targets: (_editor, node) => {\n    const { nodes } = node.type.schema\n    if (isCallout(node)) return UNWRAP_TARGETS.filter(target => nodes[target.type])\n    return isCoreSource(node) && nodes[CALLOUT] ? [TARGET] : []\n  },\n  parseTarget: id => id === CALLOUT ? TARGET : null,\n  label: target => target.type === 'custom' && target.id === CALLOUT ? { label: 'Callout', icon: 'i-lucide-info' } : null,\n  convert: (state, $start, target) => {\n    const node = $start.nodeAfter\n    const { schema } = state\n    if (!node) return null\n    let output: PMNode[] | null\n    if (isCallout(node)) {\n      const children = childrenOf(node)\n      output = convertCoreBlocks(schema, children, target) ?? children\n    }\n    else if (target.type === 'custom' && target.id === CALLOUT && schema.nodes[CALLOUT] && isCoreSource(node)) {\n      const quote = createConverter(schema).toQuote([node])[0]\n      output = quote ? [schema.nodes[CALLOUT].create({ tone: 'info' }, quote.content)] : null\n    }\n    else return null\n    const blocks = output && finishConversion([node], output)\n    return blocks ? { from: $start.pos, to: $start.pos + node.nodeSize, blocks } : null\n  },\n}\n","app\u002Feditor\u002Fcallout\u002Fconvert.ts",[425,1618,1619,1647,1653,1660,1670,1677,1684,1693,1700,1707,1714,1721,1734,1738,1754,1759,1797,1802,1847,1851,1889,1894,1899,1905,1911,1917,1922,1939,1952,1975,2001,2050,2094,2100,2129,2206,2234,2250,2267,2286,2306,2323,2344,2375,2381,2447,2485,2548,2553,2563,2592,2647,2652],{"__ignoreMap":469},[473,1620,1621,1623,1625,1627,1630,1633,1636,1638,1640,1642,1645],{"class":475,"line":476},[473,1622,480],{"class":479},[473,1624,494],{"class":479},[473,1626,484],{"class":483},[473,1628,1629],{"class":487}," Node",[473,1631,1632],{"class":479}," as",[473,1634,1635],{"class":487}," PMNode",[473,1637,500],{"class":483},[473,1639,503],{"class":479},[473,1641,506],{"class":483},[473,1643,1644],{"class":509},"@tiptap\u002Fpm\u002Fmodel",[473,1646,513],{"class":483},[473,1648,1649,1651],{"class":475,"line":516},[473,1650,480],{"class":479},[473,1652,683],{"class":483},[473,1654,1655,1658],{"class":475,"line":537},[473,1656,1657],{"class":487},"  childrenOf",[473,1659,712],{"class":483},[473,1661,1662,1665,1668],{"class":475,"line":558},[473,1663,1664],{"class":479},"  type",[473,1666,1667],{"class":487}," ConversionProvider",[473,1669,712],{"class":483},[473,1671,1672,1675],{"class":475,"line":584},[473,1673,1674],{"class":487},"  CORE_TARGET_IDS",[473,1676,712],{"class":483},[473,1678,1679,1682],{"class":475,"line":591},[473,1680,1681],{"class":487},"  convertCoreBlocks",[473,1683,712],{"class":483},[473,1685,1686,1688,1691],{"class":475,"line":598},[473,1687,1664],{"class":479},[473,1689,1690],{"class":487}," ConvertTarget",[473,1692,712],{"class":483},[473,1694,1695,1698],{"class":475,"line":621},[473,1696,1697],{"class":487},"  createConverter",[473,1699,712],{"class":483},[473,1701,1702,1705],{"class":475,"line":626},[473,1703,1704],{"class":487},"  finishConversion",[473,1706,712],{"class":483},[473,1708,1709,1712],{"class":475,"line":632},[473,1710,1711],{"class":487},"  isCoreSource",[473,1713,712],{"class":483},[473,1715,1716,1719],{"class":475,"line":638},[473,1717,1718],{"class":487},"  parseCoreTarget",[473,1720,712],{"class":483},[473,1722,1723,1726,1728,1730,1732],{"class":475,"line":644},[473,1724,1725],{"class":483},"}",[473,1727,503],{"class":479},[473,1729,506],{"class":483},[473,1731,510],{"class":509},[473,1733,513],{"class":483},[473,1735,1736],{"class":475,"line":650},[473,1737,588],{"emptyLinePlaceholder":587},[473,1739,1740,1743,1746,1748,1750,1752],{"class":475,"line":656},[473,1741,1742],{"class":604},"const",[473,1744,1745],{"class":487}," CALLOUT ",[473,1747,611],{"class":483},[473,1749,506],{"class":483},[473,1751,706],{"class":509},[473,1753,513],{"class":483},[473,1755,1756],{"class":475,"line":686},[473,1757,1758],{"class":594},"\u002F\u002F A host block names itself with the inert `custom` target: `id` is the target id and the node type name.\n",[473,1760,1761,1763,1766,1768,1770,1773,1775,1777,1779,1781,1784,1786,1788,1790,1792,1794],{"class":475,"line":694},[473,1762,1742],{"class":604},[473,1764,1765],{"class":487}," TARGET",[473,1767,701],{"class":483},[473,1769,1690],{"class":671},[473,1771,1772],{"class":483}," =",[473,1774,484],{"class":483},[473,1776,494],{"class":697},[473,1778,701],{"class":483},[473,1780,506],{"class":483},[473,1782,1783],{"class":509},"custom",[473,1785,709],{"class":483},[473,1787,491],{"class":483},[473,1789,939],{"class":697},[473,1791,701],{"class":483},[473,1793,1745],{"class":487},[473,1795,1796],{"class":483},"}\n",[473,1798,1799],{"class":475,"line":715},[473,1800,1801],{"class":594},"\u002F** The core targets a callout unwraps into. *\u002F\n",[473,1803,1804,1806,1809,1811,1814,1816,1819,1821,1824,1826,1829,1831,1833,1835,1838,1841,1844],{"class":475,"line":732},[473,1805,1742],{"class":604},[473,1807,1808],{"class":487}," UNWRAP_TARGETS",[473,1810,701],{"class":483},[473,1812,1813],{"class":604}," readonly",[473,1815,1690],{"class":671},[473,1817,1818],{"class":487},"[] ",[473,1820,611],{"class":483},[473,1822,1823],{"class":487}," CORE_TARGET_IDS",[473,1825,819],{"class":483},[473,1827,1828],{"class":664},"flatMap",[473,1830,875],{"class":487},[473,1832,427],{"class":1061},[473,1834,743],{"class":604},[473,1836,1837],{"class":664}," parseCoreTarget",[473,1839,1840],{"class":487},"(id) ",[473,1842,1843],{"class":483},"??",[473,1845,1846],{"class":487}," [])\n",[473,1848,1849],{"class":475,"line":757},[473,1850,588],{"emptyLinePlaceholder":587},[473,1852,1854,1856,1859,1861,1863,1866,1868,1870,1872,1874,1876,1878,1880,1882,1884,1886],{"class":475,"line":1853},20,[473,1855,1742],{"class":604},[473,1857,1858],{"class":487}," isCallout ",[473,1860,611],{"class":483},[473,1862,457],{"class":483},[473,1864,1865],{"class":1061},"node",[473,1867,701],{"class":483},[473,1869,1635],{"class":671},[473,1871,1106],{"class":483},[473,1873,743],{"class":604},[473,1875,1375],{"class":487},[473,1877,819],{"class":483},[473,1879,1387],{"class":487},[473,1881,819],{"class":483},[473,1883,1392],{"class":487},[473,1885,1395],{"class":483},[473,1887,1888],{"class":487}," CALLOUT\n",[473,1890,1892],{"class":475,"line":1891},21,[473,1893,588],{"emptyLinePlaceholder":587},[473,1895,1897],{"class":475,"line":1896},22,[473,1898,629],{"class":594},[473,1900,1902],{"class":475,"line":1901},23,[473,1903,1904],{"class":594}," * Paragraphs, headings, code blocks, lists and quotes become a callout (the quote rule: textblocks turn into\n",[473,1906,1908],{"class":475,"line":1907},24,[473,1909,1910],{"class":594}," * paragraphs, lists and quotes keep their blocks); a callout unwraps into every core target through the core engine.\n",[473,1912,1914],{"class":475,"line":1913},25,[473,1915,1916],{"class":594}," * `handlesSource` makes this provider execute every conversion of a callout, the core provider has none for it.\n",[473,1918,1920],{"class":475,"line":1919},26,[473,1921,653],{"class":594},[473,1923,1925,1927,1929,1931,1933,1935,1937],{"class":475,"line":1924},27,[473,1926,601],{"class":479},[473,1928,605],{"class":604},[473,1930,523],{"class":487},[473,1932,701],{"class":483},[473,1934,1667],{"class":671},[473,1936,1772],{"class":483},[473,1938,683],{"class":483},[473,1940,1942,1945,1947,1950],{"class":475,"line":1941},28,[473,1943,1944],{"class":697},"  handlesSource",[473,1946,701],{"class":483},[473,1948,1949],{"class":487}," isCallout",[473,1951,712],{"class":483},[473,1953,1955,1958,1960,1962,1965,1967,1969,1971,1973],{"class":475,"line":1954},29,[473,1956,1957],{"class":664},"  targets",[473,1959,701],{"class":483},[473,1961,457],{"class":483},[473,1963,1964],{"class":1061},"_editor",[473,1966,491],{"class":483},[473,1968,1375],{"class":1061},[473,1970,1106],{"class":483},[473,1972,743],{"class":604},[473,1974,683],{"class":483},[473,1976,1978,1981,1983,1986,1988,1990,1992,1994,1996,1998],{"class":475,"line":1977},30,[473,1979,1980],{"class":604},"    const",[473,1982,484],{"class":483},[473,1984,1985],{"class":487}," nodes",[473,1987,500],{"class":483},[473,1989,1772],{"class":483},[473,1991,1375],{"class":487},[473,1993,819],{"class":483},[473,1995,1387],{"class":487},[473,1997,819],{"class":483},[473,1999,2000],{"class":487},"schema\n",[473,2002,2004,2007,2009,2012,2014,2016,2019,2022,2024,2026,2029,2031,2034,2036,2038,2041,2043,2045,2047],{"class":475,"line":2003},31,[473,2005,2006],{"class":479},"    if",[473,2008,457],{"class":697},[473,2010,2011],{"class":664},"isCallout",[473,2013,875],{"class":697},[473,2015,1865],{"class":487},[473,2017,2018],{"class":697},")) ",[473,2020,2021],{"class":479},"return",[473,2023,1808],{"class":487},[473,2025,819],{"class":483},[473,2027,2028],{"class":664},"filter",[473,2030,875],{"class":697},[473,2032,2033],{"class":1061},"target",[473,2035,743],{"class":604},[473,2037,1985],{"class":487},[473,2039,2040],{"class":697},"[",[473,2042,2033],{"class":487},[473,2044,819],{"class":483},[473,2046,1387],{"class":487},[473,2048,2049],{"class":697},"])\n",[473,2051,2053,2056,2059,2061,2063,2066,2069,2071,2073,2076,2079,2082,2084,2087,2089,2091],{"class":475,"line":2052},32,[473,2054,2055],{"class":479},"    return",[473,2057,2058],{"class":664}," isCoreSource",[473,2060,875],{"class":697},[473,2062,1865],{"class":487},[473,2064,2065],{"class":697},") ",[473,2067,2068],{"class":483},"&&",[473,2070,1985],{"class":487},[473,2072,2040],{"class":697},[473,2074,2075],{"class":487},"CALLOUT",[473,2077,2078],{"class":697},"] ",[473,2080,2081],{"class":483},"?",[473,2083,746],{"class":697},[473,2085,2086],{"class":487},"TARGET",[473,2088,2078],{"class":697},[473,2090,701],{"class":483},[473,2092,2093],{"class":697}," []\n",[473,2095,2097],{"class":475,"line":2096},33,[473,2098,2099],{"class":483},"  },\n",[473,2101,2103,2106,2108,2110,2112,2115,2117,2119,2121,2124,2126],{"class":475,"line":2102},34,[473,2104,2105],{"class":664},"  parseTarget",[473,2107,701],{"class":483},[473,2109,939],{"class":1061},[473,2111,743],{"class":604},[473,2113,2114],{"class":487}," id ",[473,2116,1395],{"class":483},[473,2118,1745],{"class":487},[473,2120,2081],{"class":483},[473,2122,2123],{"class":487}," TARGET ",[473,2125,701],{"class":483},[473,2127,2128],{"class":483}," null,\n",[473,2130,2132,2135,2137,2140,2142,2144,2146,2149,2151,2153,2155,2157,2160,2162,2164,2167,2169,2171,2173,2175,2178,2180,2182,2184,2186,2188,2191,2193,2195,2197,2199,2201,2204],{"class":475,"line":2131},35,[473,2133,2134],{"class":664},"  label",[473,2136,701],{"class":483},[473,2138,2139],{"class":1061}," target",[473,2141,743],{"class":604},[473,2143,2139],{"class":487},[473,2145,819],{"class":483},[473,2147,2148],{"class":487},"type ",[473,2150,1395],{"class":483},[473,2152,506],{"class":483},[473,2154,1783],{"class":509},[473,2156,709],{"class":483},[473,2158,2159],{"class":483}," &&",[473,2161,2139],{"class":487},[473,2163,819],{"class":483},[473,2165,2166],{"class":487},"id ",[473,2168,1395],{"class":483},[473,2170,1745],{"class":487},[473,2172,2081],{"class":483},[473,2174,484],{"class":483},[473,2176,2177],{"class":697}," label",[473,2179,701],{"class":483},[473,2181,506],{"class":483},[473,2183,749],{"class":509},[473,2185,709],{"class":483},[473,2187,491],{"class":483},[473,2189,2190],{"class":697}," icon",[473,2192,701],{"class":483},[473,2194,506],{"class":483},[473,2196,982],{"class":509},[473,2198,709],{"class":483},[473,2200,500],{"class":483},[473,2202,2203],{"class":483}," :",[473,2205,2128],{"class":483},[473,2207,2209,2212,2214,2216,2219,2221,2224,2226,2228,2230,2232],{"class":475,"line":2208},36,[473,2210,2211],{"class":664},"  convert",[473,2213,701],{"class":483},[473,2215,457],{"class":483},[473,2217,2218],{"class":1061},"state",[473,2220,491],{"class":483},[473,2222,2223],{"class":1061}," $start",[473,2225,491],{"class":483},[473,2227,2139],{"class":1061},[473,2229,1106],{"class":483},[473,2231,743],{"class":604},[473,2233,683],{"class":483},[473,2235,2237,2239,2241,2243,2245,2247],{"class":475,"line":2236},37,[473,2238,1980],{"class":604},[473,2240,1375],{"class":487},[473,2242,1772],{"class":483},[473,2244,2223],{"class":487},[473,2246,819],{"class":483},[473,2248,2249],{"class":487},"nodeAfter\n",[473,2251,2253,2255,2257,2260,2262,2264],{"class":475,"line":2252},38,[473,2254,1980],{"class":604},[473,2256,484],{"class":483},[473,2258,2259],{"class":487}," schema",[473,2261,500],{"class":483},[473,2263,1772],{"class":483},[473,2265,2266],{"class":487}," state\n",[473,2268,2270,2272,2274,2277,2279,2281,2283],{"class":475,"line":2269},39,[473,2271,2006],{"class":479},[473,2273,457],{"class":697},[473,2275,2276],{"class":483},"!",[473,2278,1865],{"class":487},[473,2280,2065],{"class":697},[473,2282,2021],{"class":479},[473,2284,2285],{"class":483}," null\n",[473,2287,2289,2292,2295,2297,2299,2301,2304],{"class":475,"line":2288},40,[473,2290,2291],{"class":604},"    let",[473,2293,2294],{"class":487}," output",[473,2296,701],{"class":483},[473,2298,1635],{"class":671},[473,2300,1818],{"class":697},[473,2302,2303],{"class":483},"|",[473,2305,2285],{"class":671},[473,2307,2309,2311,2313,2315,2317,2319,2321],{"class":475,"line":2308},41,[473,2310,2006],{"class":479},[473,2312,457],{"class":697},[473,2314,2011],{"class":664},[473,2316,875],{"class":697},[473,2318,1865],{"class":487},[473,2320,2018],{"class":697},[473,2322,878],{"class":483},[473,2324,2326,2329,2332,2334,2337,2339,2341],{"class":475,"line":2325},42,[473,2327,2328],{"class":604},"      const",[473,2330,2331],{"class":487}," children",[473,2333,1772],{"class":483},[473,2335,2336],{"class":664}," childrenOf",[473,2338,875],{"class":697},[473,2340,1865],{"class":487},[473,2342,2343],{"class":697},")\n",[473,2345,2347,2350,2352,2355,2357,2360,2362,2364,2366,2368,2370,2372],{"class":475,"line":2346},43,[473,2348,2349],{"class":487},"      output",[473,2351,1772],{"class":483},[473,2353,2354],{"class":664}," convertCoreBlocks",[473,2356,875],{"class":697},[473,2358,2359],{"class":487},"schema",[473,2361,491],{"class":483},[473,2363,2331],{"class":487},[473,2365,491],{"class":483},[473,2367,2139],{"class":487},[473,2369,2065],{"class":697},[473,2371,1843],{"class":483},[473,2373,2374],{"class":487}," children\n",[473,2376,2378],{"class":475,"line":2377},44,[473,2379,2380],{"class":483},"    }\n",[473,2382,2384,2387,2390,2392,2394,2396,2398,2401,2403,2405,2407,2409,2411,2413,2415,2417,2420,2422,2424,2426,2429,2431,2433,2435,2437,2439,2441,2443,2445],{"class":475,"line":2383},45,[473,2385,2386],{"class":479},"    else",[473,2388,2389],{"class":479}," if",[473,2391,457],{"class":697},[473,2393,2033],{"class":487},[473,2395,819],{"class":483},[473,2397,1387],{"class":487},[473,2399,2400],{"class":483}," ===",[473,2402,506],{"class":483},[473,2404,1783],{"class":509},[473,2406,709],{"class":483},[473,2408,2159],{"class":483},[473,2410,2139],{"class":487},[473,2412,819],{"class":483},[473,2414,427],{"class":487},[473,2416,2400],{"class":483},[473,2418,2419],{"class":487}," CALLOUT",[473,2421,2159],{"class":483},[473,2423,2259],{"class":487},[473,2425,819],{"class":483},[473,2427,2428],{"class":487},"nodes",[473,2430,2040],{"class":697},[473,2432,2075],{"class":487},[473,2434,2078],{"class":697},[473,2436,2068],{"class":483},[473,2438,2058],{"class":664},[473,2440,875],{"class":697},[473,2442,1865],{"class":487},[473,2444,2018],{"class":697},[473,2446,878],{"class":483},[473,2448,2450,2452,2455,2457,2460,2462,2464,2466,2468,2471,2474,2476,2479,2482],{"class":475,"line":2449},46,[473,2451,2328],{"class":604},[473,2453,2454],{"class":487}," quote",[473,2456,1772],{"class":483},[473,2458,2459],{"class":664}," createConverter",[473,2461,875],{"class":697},[473,2463,2359],{"class":487},[473,2465,1106],{"class":697},[473,2467,819],{"class":483},[473,2469,2470],{"class":664},"toQuote",[473,2472,2473],{"class":697},"([",[473,2475,1865],{"class":487},[473,2477,2478],{"class":697},"])[",[473,2480,2481],{"class":923},"0",[473,2483,2484],{"class":697},"]\n",[473,2486,2488,2490,2492,2494,2497,2499,2501,2503,2505,2507,2509,2511,2513,2516,2518,2521,2523,2525,2527,2530,2532,2535,2537,2539,2541,2544,2546],{"class":475,"line":2487},47,[473,2489,2349],{"class":487},[473,2491,1772],{"class":483},[473,2493,2454],{"class":487},[473,2495,2496],{"class":483}," ?",[473,2498,746],{"class":697},[473,2500,2359],{"class":487},[473,2502,819],{"class":483},[473,2504,2428],{"class":487},[473,2506,2040],{"class":697},[473,2508,2075],{"class":487},[473,2510,752],{"class":697},[473,2512,819],{"class":483},[473,2514,2515],{"class":664},"create",[473,2517,875],{"class":697},[473,2519,2520],{"class":483},"{",[473,2522,1451],{"class":697},[473,2524,701],{"class":483},[473,2526,506],{"class":483},[473,2528,2529],{"class":509},"info",[473,2531,709],{"class":483},[473,2533,2534],{"class":483}," },",[473,2536,2454],{"class":487},[473,2538,819],{"class":483},[473,2540,725],{"class":487},[473,2542,2543],{"class":697},")] ",[473,2545,701],{"class":483},[473,2547,2285],{"class":483},[473,2549,2551],{"class":475,"line":2550},48,[473,2552,2380],{"class":483},[473,2554,2556,2558,2561],{"class":475,"line":2555},49,[473,2557,2386],{"class":479},[473,2559,2560],{"class":479}," return",[473,2562,2285],{"class":483},[473,2564,2566,2568,2571,2573,2575,2577,2580,2582,2584,2586,2588,2590],{"class":475,"line":2565},50,[473,2567,1980],{"class":604},[473,2569,2570],{"class":487}," blocks",[473,2572,1772],{"class":483},[473,2574,2294],{"class":487},[473,2576,2159],{"class":483},[473,2578,2579],{"class":664}," finishConversion",[473,2581,2473],{"class":697},[473,2583,1865],{"class":487},[473,2585,752],{"class":697},[473,2587,491],{"class":483},[473,2589,2294],{"class":487},[473,2591,2343],{"class":697},[473,2593,2595,2597,2599,2601,2603,2605,2607,2609,2611,2614,2616,2619,2621,2623,2625,2627,2630,2632,2634,2637,2639,2641,2643,2645],{"class":475,"line":2594},51,[473,2596,2055],{"class":479},[473,2598,2570],{"class":487},[473,2600,2496],{"class":483},[473,2602,484],{"class":483},[473,2604,503],{"class":697},[473,2606,701],{"class":483},[473,2608,2223],{"class":487},[473,2610,819],{"class":483},[473,2612,2613],{"class":487},"pos",[473,2615,491],{"class":483},[473,2617,2618],{"class":697}," to",[473,2620,701],{"class":483},[473,2622,2223],{"class":487},[473,2624,819],{"class":483},[473,2626,2613],{"class":487},[473,2628,2629],{"class":483}," +",[473,2631,1375],{"class":487},[473,2633,819],{"class":483},[473,2635,2636],{"class":487},"nodeSize",[473,2638,491],{"class":483},[473,2640,2570],{"class":487},[473,2642,500],{"class":483},[473,2644,2203],{"class":483},[473,2646,2285],{"class":483},[473,2648,2650],{"class":475,"line":2649},52,[473,2651,2099],{"class":483},[473,2653,2655],{"class":475,"line":2654},53,[473,2656,1796],{"class":483},[418,2658,2659],{},"The rules a provider follows:",[777,2661,2662,2683,2699,2716,2750],{},[780,2663,2664,1132,2670,2673,2674,2677,2678,2680,2681,2669],{},[783,2665,2666,2667,2669],{},"The ",[425,2668,1783],{}," target.",[425,2671,2672],{},"ConvertTarget"," is a closed union of inert descriptors; ",[425,2675,2676],{},"{ type: 'custom', id, attrs? }"," is the member for host blocks. ",[425,2679,427],{}," is both the target id and the node type name. The core engine never executes a ",[425,2682,1783],{},[780,2684,2685,2688,2689,2692,2693,2695,2696,2698],{},[783,2686,2687],{},"Ownership."," The provider whose ",[425,2690,2691],{},"parseTarget(id)"," returns the target owns it (labels through ",[425,2694,1456],{},", execution through ",[425,2697,1604],{},"). A target id offered by two providers throws.",[780,2700,2701,2706,2707,2711,2712,2715],{},[783,2702,2703,819],{},[425,2704,2705],{},"handlesSource"," The first provider that claims a source block executes ",[2708,2709,2710],"em",{},"every"," conversion of it. The callout claims callouts, so unwrapping into a paragraph or a list runs here and reuses the core engine (",[425,2713,2714],{},"convertCoreBlocks","). Without a claim, the target's owner executes.",[780,2717,2718,1132,2721,2724,2725,2724,2727,2724,2730,2724,2733,2724,2736,1587,2739,2742,2743,2745,2746,2749],{},[783,2719,2720],{},"Helpers.",[425,2722,2723],{},"createConverter",", ",[425,2726,2714],{},[425,2728,2729],{},"childrenOf",[425,2731,2732],{},"isCoreSource",[425,2734,2735],{},"CORE_TARGET_IDS",[425,2737,2738],{},"parseCoreTarget",[425,2740,2741],{},"finishConversion"," (carries block IDs and checks the result) come from ",[425,2744,510],{},". Return ",[425,2747,2748],{},"null"," for \"not possible\"; the result must fit its parent, so a callout is only offered where one may stand.",[780,2751,2752,2755],{},[783,2753,2754],{},"One transaction."," A conversion is one undo step.",[821,2757,2759],{"id":2758},"aicontext",[425,2760,2761],{},"aiContext",[418,2763,2764,2765,2767],{},"The last slot, ",[425,2766,2761],{},", tells the model that the block exists and how to write it. It is chapter 7's topic.",[437,2769,2771],{"id":2770},"composing-and-mounting","Composing and mounting",[418,2773,2774,2775,2778,2779,2782,2783,2786,2787,2789],{},"The chapter-3 pattern again: a preset from ",[425,2776,2777],{},"defineEditor",", mounted with ",[425,2780,2781],{},"EditorSurface",". The preset lists the callout feature next to the core features and ",[425,2784,2785],{},"blockUiFeature()",", which draws the hover bar. The ",[425,2788,1234],{}," prop grants the custom ability at document root:",[463,2791,2796],{"className":2792,"code":2793,"filename":2794,"language":2795,"meta":469,"style":469},"language-vue shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","const preset = defineEditor({\n  features: [coreContentFeature(), coreUiFeature(), blockUiFeature(), calloutFeature()],\n})\n","docs\u002Fapp\u002Fcomponents\u002Fcontent\u002FDemoCalloutPathB.client.vue","vue",[425,2797,2798,2803,2808],{"__ignoreMap":469},[473,2799,2800],{"class":475,"line":476},[473,2801,2802],{"class":487},"const preset = defineEditor({\n",[473,2804,2805],{"class":475,"line":516},[473,2806,2807],{"class":487},"  features: [coreContentFeature(), coreUiFeature(), blockUiFeature(), calloutFeature()],\n",[473,2809,2810],{"class":475,"line":537},[473,2811,2812],{"class":487},"})\n",[418,2814,2815,2816,2818,2819,2822],{},"The custom ability is not part of ",[425,2817,1230],{},", so the host grants it at document root, or the toolbar button, ",[425,2820,2821],{},"\u002Fcallout"," and the hover menu stay hidden:",[463,2824,2826],{"className":2792,"code":2825,"filename":2794,"language":2795,"meta":469,"style":469},"const abilities: Partial\u003CAbilitiesOptions> = { root: [...ROOT_ABILITIES, CALLOUT_ABILITY] }\n",[425,2827,2828],{"__ignoreMap":469},[473,2829,2830,2833,2835,2838,2840],{"class":475,"line":476},[473,2831,2832],{"class":487},"const abilities: Partial",[473,2834,674],{"class":483},[473,2836,2837],{"class":697},"AbilitiesOptions",[473,2839,680],{"class":483},[473,2841,2842],{"class":487}," = { root: [...ROOT_ABILITIES, CALLOUT_ABILITY] }\n",[418,2844,2845,2847,2848,2850],{},[425,2846,1230],{}," is the built-in set from ",[425,2849,806],{},"; spreading it keeps every standard ability and adds yours. The surface then takes both:",[463,2852,2854],{"className":2792,"code":2853,"language":2795,"meta":469,"style":469},"\u003CEditorSurface v-model=\"content\" :preset=\"preset\" :abilities=\"abilities\" @ready=\"editor = $event\" \u002F>\n",[425,2855,2856],{"__ignoreMap":469},[473,2857,2858,2860,2862,2865,2867,2870,2872,2874,2876,2879,2881,2883,2885,2887,2889,2891,2893,2895,2897,2899,2902,2905,2907,2909,2912,2914,2917,2919],{"class":475,"line":476},[473,2859,674],{"class":483},[473,2861,2781],{"class":697},[473,2863,2864],{"class":604}," v-model",[473,2866,611],{"class":483},[473,2868,2869],{"class":483},"\"",[473,2871,725],{"class":487},[473,2873,2869],{"class":483},[473,2875,2203],{"class":483},[473,2877,2878],{"class":604},"preset",[473,2880,611],{"class":483},[473,2882,2869],{"class":483},[473,2884,2878],{"class":487},[473,2886,2869],{"class":483},[473,2888,2203],{"class":483},[473,2890,1234],{"class":604},[473,2892,611],{"class":483},[473,2894,2869],{"class":483},[473,2896,1234],{"class":487},[473,2898,2869],{"class":483},[473,2900,2901],{"class":483}," @",[473,2903,2904],{"class":604},"ready",[473,2906,611],{"class":483},[473,2908,2869],{"class":483},[473,2910,2911],{"class":487},"editor ",[473,2913,611],{"class":483},[473,2915,2916],{"class":487}," $event",[473,2918,2869],{"class":483},[473,2920,2921],{"class":483}," \u002F>\n",[418,2923,2924,2925,2928,2929,2932,2933,2936,2937,2940,2941,701],{},"In the repository's kitchen sink (",[425,2926,2927],{},"app\u002Fpages\u002Fkitchen-sink\u002Fsurface.vue",", route ",[425,2930,2931],{},"\u002Fkitchen-sink\u002Fsurface",") the callout joins the full advanced composition instead of a short list; ",[425,2934,2935],{},"add"," appends host features after the catalog. Another host feature, ",[425,2938,2939],{},"epikriseFeature()",", has its own page, ",[425,2942,2943],{},"\u002Fkitchen-sink\u002Fepikrise",[463,2945,2947],{"className":2792,"code":2946,"filename":2927,"language":2795,"meta":469,"style":469},"\u002F\u002F The advanced composition plus the host's own feature, handed to the surface as one preset.\nconst preset = advancedEditor({ blockTypes: defaultBlockTypes(useEditorI18n().t), add: [calloutFeature()] })\n",[425,2948,2949,2954],{"__ignoreMap":469},[473,2950,2951],{"class":475,"line":476},[473,2952,2953],{"class":487},"\u002F\u002F The advanced composition plus the host's own feature, handed to the surface as one preset.\n",[473,2955,2956],{"class":475,"line":516},[473,2957,2958],{"class":487},"const preset = advancedEditor({ blockTypes: defaultBlockTypes(useEditorI18n().t), add: [calloutFeature()] })\n",[418,2960,2961],{},"Rules for the composition:",[777,2963,2964,2991,3006,3024,3045],{},[780,2965,2966,2969,2970,2972,2973,2975,2976,2979,2980,2983,2984,2986,2987,2990],{},[783,2967,2968],{},"Declare the dimension."," Every feature names the axis it belongs to in ",[425,2971,456],{},": ",[425,2974,460],{}," (nodes, marks or structure; the callout), ",[425,2977,2978],{},"'interaction'"," (editing UX, no schema) or ",[425,2981,2982],{},"'ai'",". ",[425,2985,2777],{}," fails with ",[425,2988,2989],{},"feature \"\u003Cid>\" declares no dimension"," otherwise.",[780,2992,2993,1132,2996,2998,2999,3002,3003,3005],{},[783,2994,2995],{},"Order is order.",[425,2997,2777],{}," keeps the given order: toolbar groups, menu entries and the schema follow it. A feature that is not in the list contributes nothing, and a smaller list works too: ",[425,3000,3001],{},"core + ui + callout"," needs ",[425,3004,2785],{}," only for the hover actions.",[780,3007,3008,3011,3012,3014,3015,3017,3018,3021,3022,819],{},[783,3009,3010],{},"Grant a custom ability."," Items gated by your own ability id are inert until the ability exists at the caret. Without the grant the toolbar button is disabled, and ",[425,3013,2821],{}," and the hover menu are missing. Root abilities come from the ",[425,3016,1234],{}," prop; per-node rules go in ",[425,3019,3020],{},"rules",", or in the node's own ",[425,3023,1234],{},[780,3025,3026,3029,3030,3033,3034,830,3037,3040,3041,3044],{},[783,3027,3028],{},"Build the preset once."," Build it in ",[425,3031,3032],{},"\u003Cscript setup>"," (or a React ",[425,3035,3036],{},"useState",[425,3038,3039],{},"useMemo","): the preset is read once at mount, like every prop of the surface. Call ",[425,3042,3043],{},"advancedEditor()"," during component setup: some of its features hook the Vue app's lifetime.",[780,3046,3047,3052,3053,2972,3056,3058],{},[783,3048,3049,819],{},[425,3050,3051],{},"requires"," Name features your feature builds on with ",[425,3054,3055],{},"requires: ['block-ui']",[425,3057,2777],{}," throws at composition time when one is missing, instead of a button silently not appearing. The callout does not declare it because it works without hover actions.",[418,3060,3061,3062,3065,3066,819],{},"The full contract of ",[425,3063,3064],{},"EditorFeature",", including the slots this chapter did not use, is on ",[3067,3068,357],"a",{"href":358},[821,3070,3072],{"id":3071},"markdown-import","Markdown import",[418,3074,3075,3076,3079,3080,819],{},"The kitchen sink's Surface page has an „Insert Markdown“ button that shows the tokenizer of chapter 4 working through the block pipeline: ",[425,3077,3078],{},"parseBlocks(editor, markdown).blocks"," returns TipTap JSON blocks, here with a ",[425,3081,706],{},[463,3083,3085],{"className":2792,"code":3084,"filename":2927,"language":2795,"meta":469,"style":469},"\u002F** Imports Markdown with the callout syntax through the editor's block pipeline (the tokenizer of `callout\u002Fnode.ts`). *\u002F\nfunction insertCalloutMarkdown() {\n  const editor = pane.editor\n  if (!editor) return\n  editor.chain().focus().insertContent(parseBlocks(editor, CALLOUT_MARKDOWN).blocks).run()\n}\n",[425,3086,3087,3092,3097,3102,3107,3112],{"__ignoreMap":469},[473,3088,3089],{"class":475,"line":476},[473,3090,3091],{"class":487},"\u002F** Imports Markdown with the callout syntax through the editor's block pipeline (the tokenizer of `callout\u002Fnode.ts`). *\u002F\n",[473,3093,3094],{"class":475,"line":516},[473,3095,3096],{"class":487},"function insertCalloutMarkdown() {\n",[473,3098,3099],{"class":475,"line":537},[473,3100,3101],{"class":487},"  const editor = pane.editor\n",[473,3103,3104],{"class":475,"line":558},[473,3105,3106],{"class":487},"  if (!editor) return\n",[473,3108,3109],{"class":475,"line":584},[473,3110,3111],{"class":487},"  editor.chain().focus().insertContent(parseBlocks(editor, CALLOUT_MARKDOWN).blocks).run()\n",[473,3113,3114],{"class":475,"line":591},[473,3115,1796],{"class":487},[437,3117,3119],{"id":3118},"what-you-have-now","What you have now",[418,3121,3122,3123,3125,3126,3128,3129,3132],{},"The callout is a feature: a toolbar button in the ",[425,3124,431],{}," group, a ",[425,3127,2821],{}," entry and a shortcut from one command definition, a hover menu that switches the tone, „Umwandeln in …“ in both directions, all gated by ",[425,3130,3131],{},"CALLOUT_ABILITY",", which the host grants at the document root.",[437,3134,3136],{"id":3135},"next","Next",[418,3138,3139,3141],{},[3067,3140,70],{"href":71}," puts the editor behind a server and lets two browsers edit one document.",[3143,3144,3145],"style",{},"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 .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}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);}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}",{"title":469,"searchDepth":516,"depth":516,"links":3147},[3148,3157,3160,3161],{"id":439,"depth":516,"text":440,"children":3149},[3150,3152,3154,3156],{"id":823,"depth":537,"text":3151},"commands: toolbar, \u002F menu and palette from one definition",{"id":1238,"depth":537,"text":3153},"blockActions: the hover menu",{"id":1594,"depth":537,"text":3155},"conversions: „Umwandeln in …“",{"id":2758,"depth":537,"text":2761},{"id":2770,"depth":516,"text":2771,"children":3158},[3159],{"id":3071,"depth":537,"text":3072},{"id":3118,"depth":516,"text":3119},{"id":3135,"depth":516,"text":3136},"Turn the callout into an EditorFeature with a toolbar button, a hover menu for the tone, „Umwandeln in …“ and its own ability.","md",null,{},{"icon":68},{"title":65,"description":3162},"K-kaPn6wyri8s4_usYV5tgleKaa7Pumfk9Kq8_wXeFQ",[3170,3172],{"title":60,"path":61,"stem":62,"description":3171,"icon":63,"children":-1},"Write the „Hinweis“ callout as a TipTap node and plug it into SimpleEditor through the extensions and commands props.",{"title":70,"path":71,"stem":72,"description":3173,"icon":73,"children":-1},"Register the Nuxt module, hand it EditorPorts for identity and storage, and open one document in two browsers with the collaboration session.",1793178230036]