e0a5f57793
Vendor the rebranded BoosAPI Desktop client (Tauri + Vue) into metapi as a monorepo subdirectory under desktop/. Source only — node_modules, dist, Cargo target and the upstream .git history are excluded. desktop/ keeps its own independent Cargo workspace (desktop/src-tauri with crates/*); it is not part of the backend boosapi crate, so a `cargo check` at the metapi root still compiles only the backend. Build the desktop app from desktop/src-tauri per desktop/README.md. Note: app icons are still placeholder assets pending the final BoosAPI logo. The updater signing keys live outside the repo and are not included.
186 lines
6.2 KiB
Markdown
186 lines
6.2 KiB
Markdown
---
|
|
description: Override built-in markstream-vue components like image, code_block, mermaid, and link with scoped, project-safe custom mappings.
|
|
---
|
|
|
|
# Override Built-in Components
|
|
|
|
Most advanced customization starts with `setCustomComponents`, not parser hooks.
|
|
|
|
Use this page when you want to:
|
|
|
|
- replace built-in renderers such as `image`, `code_block`, `mermaid`, or `link`
|
|
- keep overrides scoped to one part of the app
|
|
- understand which override key matches which node type
|
|
|
|
If you want trusted custom tags such as `thinking`, go to [Custom Tags & Advanced Components](/guide/custom-components). If props and slots are enough, stay with [Props & Options](/guide/props).
|
|
|
|
## 1. Prefer scoped overrides
|
|
|
|
Use `custom-id` on the renderer and register overrides under the same id:
|
|
|
|
```ts twoslash
|
|
import type { Component } from 'vue'
|
|
import { setCustomComponents } from 'markstream-vue'
|
|
|
|
declare const DocImage: Component
|
|
|
|
setCustomComponents('docs', {
|
|
image: DocImage,
|
|
})
|
|
```
|
|
|
|
```vue twoslash
|
|
<script setup lang="ts">
|
|
import MarkdownRender from 'markstream-vue'
|
|
|
|
const markdown = ''
|
|
</script>
|
|
|
|
<template>
|
|
<MarkdownRender custom-id="docs" :content="markdown" />
|
|
</template>
|
|
```
|
|
|
|
Why this is the default recommendation:
|
|
|
|
- it prevents one project area from changing another
|
|
- it makes testing and cleanup easier
|
|
- it matches how the renderer merges scoped and global mappings
|
|
|
|
The single-argument form `setCustomComponents({ ... })` is still supported, but it is best treated as a legacy global override.
|
|
|
|
## 2. The override keys you will actually use
|
|
|
|
| Key | What it replaces | Notes |
|
|
|-----|------------------|-------|
|
|
| `image` | `ImageNode` | Great first override for lightboxes, captions, or lazy-loading wrappers |
|
|
| `link` | `LinkNode` | Useful for analytics, router links, or custom tooltip behavior |
|
|
| `code_block` | Regular fenced code blocks | Used as the generic fallback after exact language keys and the built-in `mermaid` / `d2` / `infographic` routes |
|
|
| `mermaid` | Mermaid fenced blocks | Preferred over `code_block` when only Mermaid needs a custom renderer |
|
|
| `d2` | D2 and `d2lang` fenced blocks | Same routing idea as Mermaid |
|
|
| `infographic` | Infographic fenced blocks | Use when only infographic output changes |
|
|
| `inline_code` | Inline code spans | Useful for docs typography or special inline tooling |
|
|
| `heading`, `paragraph`, `list_item`, `blockquote` | Container nodes | Powerful, but you must render children yourself |
|
|
|
|
The full list of built-in node types lives in [Components API](/guide/components) and the exported `CustomComponents` type.
|
|
|
|
## 3. Start with leaf-like nodes
|
|
|
|
Leaf-like nodes are the easiest place to begin because they do not require you to manually re-render child nodes.
|
|
|
|
### Example: replace `image`
|
|
|
|
```vue twoslash
|
|
<script setup lang="ts">
|
|
import type { ImageNodeProps } from 'markstream-vue'
|
|
|
|
const props = defineProps<ImageNodeProps>()
|
|
</script>
|
|
|
|
<template>
|
|
<figure class="docs-image">
|
|
<img :src="props.node.src" :alt="props.node.alt" loading="lazy">
|
|
<figcaption v-if="props.node.title || props.node.alt">
|
|
{{ props.node.title || props.node.alt }}
|
|
</figcaption>
|
|
</figure>
|
|
</template>
|
|
```
|
|
|
|
```ts twoslash
|
|
import type { Component } from 'vue'
|
|
import { setCustomComponents } from 'markstream-vue'
|
|
|
|
declare const DocImage: Component
|
|
|
|
setCustomComponents('docs', {
|
|
image: DocImage,
|
|
})
|
|
```
|
|
|
|
### Example: switch regular code blocks to `MarkdownCodeBlockNode`
|
|
|
|
```ts twoslash
|
|
import { MarkdownCodeBlockNode, setCustomComponents } from 'markstream-vue'
|
|
|
|
setCustomComponents('docs', {
|
|
code_block: MarkdownCodeBlockNode,
|
|
})
|
|
```
|
|
|
|
This only changes regular fenced code blocks. Mermaid, D2, and infographic blocks still route to their specialized renderers unless you override `mermaid`, `d2`, or `infographic`.
|
|
|
|
### Example: target one fenced language directly
|
|
|
|
```ts twoslash
|
|
import type { Component } from 'vue'
|
|
import { setCustomComponents } from 'markstream-vue'
|
|
|
|
declare const EChartsBlockNode: Component
|
|
|
|
setCustomComponents('docs', {
|
|
echarts: EChartsBlockNode,
|
|
})
|
|
```
|
|
|
|
This only catches fences whose language is `echarts`. The routing order for code blocks is:
|
|
|
|
- exact language key such as `echarts`
|
|
- built-in specialized routes such as `mermaid`, `d2`, and `infographic`
|
|
- generic `code_block`
|
|
|
|
### Example: override Mermaid only
|
|
|
|
```ts twoslash
|
|
import type { Component } from 'vue'
|
|
import { setCustomComponents } from 'markstream-vue'
|
|
|
|
declare const CustomMermaidBlock: Component
|
|
|
|
setCustomComponents('docs', {
|
|
mermaid: CustomMermaidBlock,
|
|
})
|
|
```
|
|
|
|
This is the safest pattern when you want custom export controls, branding, or diagram chrome without affecting all code blocks.
|
|
|
|
## 4. What props your override receives
|
|
|
|
Every custom renderer receives the basics:
|
|
|
|
- `node`
|
|
- `loading`
|
|
- `indexKey`
|
|
- `customId`
|
|
- `isDark`
|
|
|
|
The renderer also forwards feature-specific props:
|
|
|
|
- regular code block overrides receive `stream`, `theme`, `darkTheme`, `lightTheme`, `monacoOptions`, `themes`, `minWidth`, `maxWidth`, and anything passed through `codeBlockProps` (`theme` is the recommended field; `darkTheme` / `lightTheme` remain for compatibility)
|
|
- Mermaid, D2, and infographic overrides receive the corresponding `mermaidProps`, `d2Props`, or `infographicProps`
|
|
- link and list overrides inherit tooltip and typewriter-related bindings from the parent renderer
|
|
|
|
The exported prop types in `markstream-vue` are the easiest way to keep your overrides strongly typed.
|
|
|
|
## 5. Container nodes need extra care
|
|
|
|
Overriding `heading`, `paragraph`, `list_item`, or `blockquote` is absolutely supported, but those nodes carry children. Your component needs to decide how to render them.
|
|
|
|
Practical advice:
|
|
|
|
- start with `image`, `link`, `code_block`, `mermaid`, or `inline_code` unless you truly need container-node control
|
|
- if you override a container node, inspect the built-in renderer in `src/components/*` and mirror the child-rendering pattern you need
|
|
- keep the override scoped with `custom-id` so you can iterate safely
|
|
|
|
## 6. Cleanup for dynamic scopes
|
|
|
|
If the override only lives for a temporary view, remove it when that scope is no longer needed:
|
|
|
|
```ts twoslash
|
|
import { removeCustomComponents } from 'markstream-vue'
|
|
|
|
removeCustomComponents('docs')
|
|
```
|
|
|
|
This is especially helpful in SPAs, Storybook stories, playgrounds, and test suites.
|