diff --git a/docs/content/3.rendering/3.nuxt.md b/docs/content/3.rendering/3.nuxt.md new file mode 100644 index 0000000..6541512 --- /dev/null +++ b/docs/content/3.rendering/3.nuxt.md @@ -0,0 +1,397 @@ +--- +title: Nuxt +description: Learn how to use MDC Syntax in a Nuxt application. +--- + +Render MDC content in Nuxt applications with automatic component registration. The `mdc-syntax/nuxt` module provides zero-config setup with auto-imported components and Nuxt UI integration. + +## Installation + +```bash +npm install mdc-syntax +``` + +Add the module to your `nuxt.config.ts`: + +```typescript +export default defineNuxtConfig({ + modules: ['mdc-syntax/nuxt'] +}) +``` + +--- + +## What the Module Does + +The `mdc-syntax/nuxt` module automatically: + +1. **Auto-imports Components** - Registers `` and `` components globally +2. **Registers Component Directory** - Makes `~/components/mdc` a global components directory for custom prose components +3. **Detects Nuxt UI** - Automatically configures Nuxt UI prose components when `@nuxt/ui` is installed +4. **Server-Side Support** - Full SSR/SSG compatibility + +--- + +## MDC Component + +The `MDC` component is automatically available in all your templates without imports. Pass markdown content and it handles parsing and rendering. + +### Basic Usage + +```vue + +``` + +### With Reactive Content + +```vue + + + +``` + +### Props + +| Prop | Type | Description | +|------|------|-------------| +| `markdown` | `string` | Markdown content to parse and render | +| `components` | `Record` | Custom component mappings | +| `excerpt` | `boolean` | Only render content before `` | + +### With Custom Components + +```vue + + + +``` + +### Excerpt Mode + +Render only content before ``: + +```vue + + + +``` + +--- + +## MDCRenderer Component + +The `MDCRenderer` component renders a pre-parsed Minimark AST. Use this when you need more control over parsing or are working with server-fetched content. + +### Basic Usage + +```vue + + + +``` + +### Props + +| Prop | Type | Description | +|------|------|-------------| +| `body` | `MinimarkTree` | Required. The parsed AST to render | +| `components` | `Record` | Custom component mappings | +| `componentsManifest` | `(name: string) => Promise | null` | Dynamic component loader | + +### With Server Data + +```vue + + + +``` + +### Streaming Support + +`MDCRenderer` works with `parseStreamIncremental` for real-time content: + +```vue + + + +``` + +--- + +## Custom Prose Components + +Override default HTML element rendering by creating components in the `~/components/mdc` directory. These components are automatically registered and used by the MDC renderer. + +### Directory Structure + +``` +~/components/ + mdc/ + Alert.vue + Card.vue + H1.vue + H2.vue + Pre.vue +``` + +### Creating Custom Components + +```vue + + + + + + +``` + +**Usage in markdown:** + +```markdown +::alert{type="warning"} +This is a warning message! +:: +``` + +### Overriding HTML Elements + +```vue + + + + +``` + +Components in `~/components/mdc` with lowercase names (h1, h2, p, etc.) automatically override HTML elements. + +--- + +## Nuxt UI Integration + +When `@nuxt/ui` is installed, MDC Syntax automatically uses Nuxt UI's prose components for enhanced styling. + +### Installation + +```bash +npm install @nuxt/ui +``` + +```typescript +// nuxt.config.ts +export default defineNuxtConfig({ + modules: ['mdc-syntax/nuxt', '@nuxt/ui'] +}) +``` + +### Auto-Detection + +The `mdc-syntax/nuxt` module detects Nuxt UI and: +- Registers Nuxt UI's prose components automatically +- Uses Nuxt UI styling for all HTML elements +- Provides consistent design with your Nuxt UI setup + +### Example Setup + +```vue + + + + +``` + +### CSS Setup + +```css +/* app/assets/css/main.css */ +@import "tailwindcss"; +@import "@nuxt/ui"; +``` + +```typescript +// nuxt.config.ts +export default defineNuxtConfig({ + modules: ['mdc-syntax/nuxt', '@nuxt/ui'], + css: ['~/assets/css/main.css'] +}) +``` + +--- + +## Server-Side Rendering + +MDC Syntax fully supports SSR and SSG in Nuxt: + +### Static Generation + +```vue + + + +``` + +### Dynamic SSR + +```vue + + + +``` + +### Prerendering + +```typescript +// nuxt.config.ts +export default defineNuxtConfig({ + modules: ['mdc-syntax/nuxt'], + nitro: { + prerender: { + routes: ['/blog', '/docs'] + } + } +}) +``` + +--- + +## See Also + +- [Vue Renderer](/rendering/vue) - Vue component API +- [React Renderer](/rendering/react) - React integration +- [Parse API](/api/parse) - Parsing options and streaming +- [MDC Syntax](/syntax/markdown) - Markdown component syntax diff --git a/examples/nuxt-ui/README.md b/examples/nuxt-ui/README.md new file mode 100644 index 0000000..478e413 --- /dev/null +++ b/examples/nuxt-ui/README.md @@ -0,0 +1,88 @@ +--- +title: Nuxt UI +description: A minimal example showing how to use MDC Syntax with Nuxt UI. +--- + +::code-tree{defaultValue="app/app.vue" expandAll} + +```vue [app/app.vue] + + +``` + +```ts [nuxt.config.ts] +// https://nuxt.com/docs/api/configuration/nuxt-config +export default defineNuxtConfig({ + modules: ['mdc-syntax/nuxt', '@nuxt/ui'], + compatibilityDate: '2025-07-15', + css: ['~/assets/css/main.css'], + devtools: { enabled: true } +}) +``` + +```css [app/assets/css/main.css] +@import "tailwindcss"; +@import "@nuxt/ui"; +``` + +```json [package.json] +{ + "name": "mdc-syntax-nuxt-ui", + "type": "module", + "private": true, + "scripts": { + "build": "nuxt build", + "dev": "nuxt dev", + "generate": "nuxt generate", + "preview": "nuxt preview", + "postinstall": "nuxt prepare" + }, + "dependencies": { + "@nuxt/ui": "^4.4.0", + "mdc-syntax": "^1.0.0", + "nuxt": "^4.3.1", + "tailwindcss": "^4.1.18" + } +} +``` + +```json [tsconfig.json] +{ + // https://nuxt.com/docs/guide/concepts/typescript + "files": [], + "references": [ + { + "path": "./.nuxt/tsconfig.app.json" + }, + { + "path": "./.nuxt/tsconfig.server.json" + }, + { + "path": "./.nuxt/tsconfig.shared.json" + }, + { + "path": "./.nuxt/tsconfig.node.json" + } + ] +} +``` + +:: + + +This example demonstrates how to use MDC Syntax with Nuxt UI. MDC Syntax automatically detects when Nuxt UI is installed and uses its components for rendering. Simply add both `mdc-syntax/nuxt` and `@nuxt/ui` modules to your Nuxt config, and the `MDC` component will use Nuxt UI components automatically. + +## What does `mdc-syntax/nuxt` module do + +- Registers the `` and `` components in Nuxt for automatic import. +- Registers the `~/components/mdc` directory in the app and all layers as a global components directory. + - This allows users to override prose components by creating components in this directory. +- Detects Nuxt UI and tells Nuxt UI to register its Prose components \ No newline at end of file diff --git a/examples/nuxt-ui/app/app.vue b/examples/nuxt-ui/app/app.vue new file mode 100644 index 0000000..2d20430 --- /dev/null +++ b/examples/nuxt-ui/app/app.vue @@ -0,0 +1,11 @@ + + + diff --git a/examples/nuxt-ui/app/assets/css/main.css b/examples/nuxt-ui/app/assets/css/main.css new file mode 100644 index 0000000..7c95c6f --- /dev/null +++ b/examples/nuxt-ui/app/assets/css/main.css @@ -0,0 +1,2 @@ +@import "tailwindcss"; +@import "@nuxt/ui"; diff --git a/examples/nuxt-ui/app/components/mdc/ProseP.vue b/examples/nuxt-ui/app/components/mdc/ProseP.vue new file mode 100644 index 0000000..d4b52aa --- /dev/null +++ b/examples/nuxt-ui/app/components/mdc/ProseP.vue @@ -0,0 +1,5 @@ + diff --git a/examples/nuxt-ui/nuxt.config.ts b/examples/nuxt-ui/nuxt.config.ts new file mode 100644 index 0000000..a13154e --- /dev/null +++ b/examples/nuxt-ui/nuxt.config.ts @@ -0,0 +1,7 @@ +// https://nuxt.com/docs/api/configuration/nuxt-config +export default defineNuxtConfig({ + modules: ['mdc-syntax/nuxt', '@nuxt/ui'], + devtools: { enabled: true }, + css: ['~/assets/css/main.css'], + compatibilityDate: '2025-07-15', +}) diff --git a/examples/nuxt-ui/package.json b/examples/nuxt-ui/package.json new file mode 100644 index 0000000..9225f31 --- /dev/null +++ b/examples/nuxt-ui/package.json @@ -0,0 +1,17 @@ +{ + "name": "mdc-syntax-nuxt-ui", + "type": "module", + "private": true, + "scripts": { + "build": "nuxt build", + "dev": "nuxt dev", + "generate": "nuxt generate", + "preview": "nuxt preview" + }, + "dependencies": { + "@nuxt/ui": "^4.4.0", + "mdc-syntax": "^1.0.0", + "nuxt": "^4.3.1", + "tailwindcss": "^4.1.18" + } +} diff --git a/examples/nuxt-ui/public/favicon.ico b/examples/nuxt-ui/public/favicon.ico new file mode 100644 index 0000000..18993ad Binary files /dev/null and b/examples/nuxt-ui/public/favicon.ico differ diff --git a/examples/nuxt-ui/tsconfig.json b/examples/nuxt-ui/tsconfig.json new file mode 100644 index 0000000..307b213 --- /dev/null +++ b/examples/nuxt-ui/tsconfig.json @@ -0,0 +1,18 @@ +{ + // https://nuxt.com/docs/guide/concepts/typescript + "files": [], + "references": [ + { + "path": "./.nuxt/tsconfig.app.json" + }, + { + "path": "./.nuxt/tsconfig.server.json" + }, + { + "path": "./.nuxt/tsconfig.shared.json" + }, + { + "path": "./.nuxt/tsconfig.node.json" + } + ] +} diff --git a/examples/nuxt/README.md b/examples/nuxt/README.md new file mode 100644 index 0000000..aad65e9 --- /dev/null +++ b/examples/nuxt/README.md @@ -0,0 +1,75 @@ +--- +title: Nuxt +description: A minimal example showing how to use MDC Syntax with Nuxt 4. +--- + +::code-tree{defaultValue="app/app.vue" expandAll} + +```vue [app/app.vue] + +``` + +```ts [nuxt.config.ts] +// https://nuxt.com/docs/api/configuration/nuxt-config +export default defineNuxtConfig({ + modules: ['mdc-syntax/nuxt'], + compatibilityDate: '2025-07-15', + devtools: { enabled: true } +}) +``` + +```json [package.json] +{ + "name": "mdc-syntax-nuxt", + "type": "module", + "private": true, + "scripts": { + "build": "nuxt build", + "dev": "nuxt dev", + "generate": "nuxt generate", + "preview": "nuxt preview", + "postinstall": "nuxt prepare" + }, + "dependencies": { + "nuxt": "^4.3.1", + "vue": "^3.5.28", + "mdc-syntax": "^1.0.0" + } +} +``` + +```json [tsconfig.json] +{ + // https://nuxt.com/docs/guide/concepts/typescript + "files": [], + "references": [ + { + "path": "./.nuxt/tsconfig.app.json" + }, + { + "path": "./.nuxt/tsconfig.server.json" + }, + { + "path": "./.nuxt/tsconfig.shared.json" + }, + { + "path": "./.nuxt/tsconfig.node.json" + } + ] +} +``` + +:: + + +This example demonstrates the simplest way to use MDC Syntax with Nuxt - just add the `mdc-syntax/nuxt` module to your Nuxt config, and the `MDC` component will be automatically available in your templates. The module handles parsing and rendering automatically. + +## What does `mdc-syntax/nuxt` module do + +- Registers the `` and `` components in Nuxt for automatic import. +- Registers the `~/components/mdc` directory in the app and all layers as a global components directory. + - This allows users to override prose components by creating components in this directory. \ No newline at end of file diff --git a/examples/nuxt/app/app.vue b/examples/nuxt/app/app.vue new file mode 100644 index 0000000..b6b2ae0 --- /dev/null +++ b/examples/nuxt/app/app.vue @@ -0,0 +1,5 @@ + diff --git a/examples/nuxt/nuxt.config.ts b/examples/nuxt/nuxt.config.ts new file mode 100644 index 0000000..8fb88af --- /dev/null +++ b/examples/nuxt/nuxt.config.ts @@ -0,0 +1,6 @@ +// https://nuxt.com/docs/api/configuration/nuxt-config +export default defineNuxtConfig({ + modules: ['mdc-syntax/nuxt'], + devtools: { enabled: true }, + compatibilityDate: '2025-07-15', +}) diff --git a/examples/nuxt/package.json b/examples/nuxt/package.json new file mode 100644 index 0000000..fb1d5f4 --- /dev/null +++ b/examples/nuxt/package.json @@ -0,0 +1,17 @@ +{ + "name": "mdc-syntax-nuxt", + "type": "module", + "private": true, + "scripts": { + "build": "nuxt build", + "dev": "nuxt dev", + "generate": "nuxt generate", + "preview": "nuxt preview" + }, + "dependencies": { + "nuxt": "^4.3.1", + "vue": "^3.5.28", + "vue-router": "^4.6.4", + "mdc-syntax": "^1.0.0" + } +} diff --git a/examples/nuxt/public/favicon.ico b/examples/nuxt/public/favicon.ico new file mode 100644 index 0000000..18993ad Binary files /dev/null and b/examples/nuxt/public/favicon.ico differ diff --git a/examples/nuxt/tsconfig.json b/examples/nuxt/tsconfig.json new file mode 100644 index 0000000..307b213 --- /dev/null +++ b/examples/nuxt/tsconfig.json @@ -0,0 +1,18 @@ +{ + // https://nuxt.com/docs/guide/concepts/typescript + "files": [], + "references": [ + { + "path": "./.nuxt/tsconfig.app.json" + }, + { + "path": "./.nuxt/tsconfig.server.json" + }, + { + "path": "./.nuxt/tsconfig.shared.json" + }, + { + "path": "./.nuxt/tsconfig.node.json" + } + ] +} diff --git a/examples/react-vite/package.json b/examples/react-vite/package.json index 397c989..7442235 100644 --- a/examples/react-vite/package.json +++ b/examples/react-vite/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@tailwindcss/vite": "^4.1.18", - "mdc-syntax": "workspace:*", + "mdc-syntax": "^1.0.0", "react": "^19.2.4", "react-dom": "^19.2.4" }, diff --git a/examples/vue-vite/README.md b/examples/vue-vite/README.md index 6a0d9d1..4d88b58 100644 --- a/examples/vue-vite/README.md +++ b/examples/vue-vite/README.md @@ -88,7 +88,7 @@ export default defineConfig({ }, "dependencies": { "@tailwindcss/vite": "^4.1.18", - "mdc-syntax": "workspace:*", + "mdc-syntax": "^1.0.0", "vue": "^3.5.27" }, "devDependencies": { diff --git a/examples/vue-vite/package.json b/examples/vue-vite/package.json index 9cdf4e3..3e80693 100644 --- a/examples/vue-vite/package.json +++ b/examples/vue-vite/package.json @@ -10,7 +10,7 @@ }, "dependencies": { "@tailwindcss/vite": "^4.1.18", - "mdc-syntax": "workspace:*", + "mdc-syntax": "^1.0.0", "vue": "^3.5.28" }, "devDependencies": { diff --git a/package.json b/package.json index 6ceaa43..7a91cef 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,8 @@ "dev:prepare": "nuxt prepare playground", "dev:react": "pnpm --filter mdc-syntax-react-vite run dev", "dev:vue": "pnpm --filter mdc-syntax-vue-vite run dev", + "dev:nuxt": "pnpm --filter mdc-syntax-nuxt run dev", + "dev:nuxt-ui": "pnpm --filter mdc-syntax-nuxt-ui run dev", "docs": "nuxt dev --extends docus docs", "prepack": "pnpm build", "build": "pnpm --filter './packages/**' run build", diff --git a/packages/mdc-syntax/build.config.mjs b/packages/mdc-syntax/build.config.mjs index c56dd8b..acc1d6a 100644 --- a/packages/mdc-syntax/build.config.mjs +++ b/packages/mdc-syntax/build.config.mjs @@ -26,5 +26,10 @@ export default defineBuildConfig({ input: './src/utils', outDir: './dist/utils', }, + { + type: 'transform', + input: './src/nuxt', + outDir: './dist/nuxt', + }, ], }) diff --git a/packages/mdc-syntax/package.json b/packages/mdc-syntax/package.json index 6cb41e5..5cc0155 100644 --- a/packages/mdc-syntax/package.json +++ b/packages/mdc-syntax/package.json @@ -20,7 +20,8 @@ "./vue/*": "./dist/vue/*.mjs", "./react": "./dist/react/index.mjs", "./react/*": "./dist/react/*.mjs", - "./stream": "./dist/stream.mjs" + "./stream": "./dist/stream.mjs", + "./nuxt": "./dist/nuxt/module.mjs" }, "main": "./dist/index.mjs", "module": "./dist/index.mjs", @@ -60,6 +61,7 @@ }, "devDependencies": { "@mdc-syntax/cjk": "workspace:*", + "@nuxt/kit": "^4.3.1", "github-slugger": "^2.0.0", "hast-util-to-string": "^3.0.1", "obuild": "^0.4.27", diff --git a/packages/mdc-syntax/src/nuxt/module.ts b/packages/mdc-syntax/src/nuxt/module.ts new file mode 100644 index 0000000..acd59e6 --- /dev/null +++ b/packages/mdc-syntax/src/nuxt/module.ts @@ -0,0 +1,60 @@ +import { defineNuxtModule, createResolver, addComponent, hasNuxtModule } from '@nuxt/kit' +import type { Nuxt } from 'nuxt/schema' +import fs from 'node:fs/promises' + +// Module options TypeScript interface definition +export interface MDCModuleOptions {} + +export default defineNuxtModule({ + meta: { + name: 'mdc-syntax', + configKey: 'mdc', + }, + // Default configuration options of the Nuxt module + defaults: {}, + async setup(_options, nuxt) { + const resolver = createResolver(import.meta.url) + + addComponent({ + name: 'MDC', + export: 'MDC', + filePath: resolver.resolve('../vue/components/MDC'), + priority: 1, + }) + addComponent({ + name: 'MDCRenderer', + export: 'MDCRenderer', + filePath: resolver.resolve('../vue/components/MDCRenderer'), + priority: 1, + }) + + if (hasNuxtModule('@nuxt/ui')) { + setupNuxtUI(nuxt) + } + + // Register user global components + const _layers = [...nuxt.options._layers].reverse() + for (const layer of _layers) { + const srcDir = layer.config.srcDir + const globalComponents = resolver.resolve(srcDir, 'components/mdc') + const dirStat = await fs.stat(globalComponents).catch(() => null) + if (dirStat && dirStat.isDirectory()) { + nuxt.hook('components:dirs', (dirs: any[]) => { + dirs.unshift({ + path: globalComponents, + global: true, + pathPrefix: false, + prefix: '', + }) + }) + } + } + }, +}) + +function setupNuxtUI(nuxt: Nuxt) { + // @ts-expect-error - Nuxt UI options are not typed + nuxt.options.ui = nuxt.options.ui || {} + // @ts-expect-error - Nuxt UI options are not typed + nuxt.options.ui.content = true +} diff --git a/packages/mdc-syntax/src/react/components/MDCRenderer.tsx b/packages/mdc-syntax/src/react/components/MDCRenderer.tsx index dbaa866..af5df31 100644 --- a/packages/mdc-syntax/src/react/components/MDCRenderer.tsx +++ b/packages/mdc-syntax/src/react/components/MDCRenderer.tsx @@ -4,40 +4,6 @@ import { standardProseComponents } from '.' import { camelCase, pascalCase } from 'scule' import { findLastTextNodeAndAppendNode, getCaret } from '../../utils/caret' -/** - * Default HTML tag mappings for MDC elements - */ -const defaultTagMap: Record = { - p: 'p', - h1: 'h1', - h2: 'h2', - h3: 'h3', - h4: 'h4', - h5: 'h5', - h6: 'h6', - ul: 'ul', - ol: 'ol', - li: 'li', - a: 'a', - strong: 'strong', - em: 'em', - code: 'code', - pre: 'pre', - blockquote: 'blockquote', - hr: 'hr', - br: 'br', - img: 'img', - table: 'table', - thead: 'thead', - tbody: 'tbody', - tr: 'tr', - th: 'th', - td: 'td', - del: 'del', - div: 'div', - span: 'span', -} - /** * Helper to get tag from a MinimarkNode */ @@ -125,22 +91,24 @@ function renderNode( const nodeProps = getProps(node) const children = getChildren(node) - // Check if there's a custom component for this tag (exact match or PascalCase) - let customComponent = components[tag] || components[pascalCase(tag)] + const pascalTag = pascalCase(tag) + const proseTag = `Prose${pascalTag}` + // Check if there's a custom component for this tag + let customComponent = components[proseTag] || components[tag] // If not in components map and manifest is provided, try dynamic resolution - if (!customComponent && componentsManifest && !defaultTagMap[tag]) { + if (!customComponent && componentsManifest) { const cacheKey = tag if (!asyncComponentCache.has(cacheKey)) { - asyncComponentCache.set( - cacheKey, - lazy(() => componentsManifest(tag)), - ) + const resolved = componentsManifest(tag) + if (resolved) { + asyncComponentCache.set(cacheKey, lazy(() => resolved)) + } } customComponent = asyncComponentCache.get(cacheKey) } - const Component = customComponent || defaultTagMap[tag] || tag + const Component = customComponent || tag // Prepare props const props: Record = { ...nodeProps } diff --git a/packages/mdc-syntax/src/react/components/index.tsx b/packages/mdc-syntax/src/react/components/index.tsx index cfbc65b..9174b4e 100644 --- a/packages/mdc-syntax/src/react/components/index.tsx +++ b/packages/mdc-syntax/src/react/components/index.tsx @@ -13,133 +13,133 @@ import { ProsePre } from './prose/ProsePre' */ // Headings -const ProseH1Standard: React.FC & { __node?: any }> = ({ __node, ...props }) => ( +const ProseH1: React.FC & { __node?: any }> = ({ __node, ...props }) => (

) -const ProseH2Standard: React.FC & { __node?: any }> = ({ __node, ...props }) => ( +const ProseH2: React.FC & { __node?: any }> = ({ __node, ...props }) => (

) -const ProseH3Standard: React.FC & { __node?: any }> = ({ __node, ...props }) => ( +const ProseH3: React.FC & { __node?: any }> = ({ __node, ...props }) => (

) -const ProseH4Standard: React.FC & { __node?: any }> = ({ __node, ...props }) => ( +const ProseH4: React.FC & { __node?: any }> = ({ __node, ...props }) => (

) -const ProseH5Standard: React.FC & { __node?: any }> = ({ __node, ...props }) => ( +const ProseH5: React.FC & { __node?: any }> = ({ __node, ...props }) => (
) -const ProseH6Standard: React.FC & { __node?: any }> = ({ __node, ...props }) => ( +const ProseH6: React.FC & { __node?: any }> = ({ __node, ...props }) => (
) // Text elements -const ProsePStandard: React.FC & { __node?: any }> = ({ __node, ...props }) => ( +const ProseP: React.FC & { __node?: any }> = ({ __node, ...props }) => (

) -const ProseStrongStandard: React.FC & { __node?: any }> = ({ __node, ...props }) => ( +const ProseStrong: React.FC & { __node?: any }> = ({ __node, ...props }) => ( ) -const ProseEmStandard: React.FC & { __node?: any }> = ({ __node, ...props }) => ( +const ProseEm: React.FC & { __node?: any }> = ({ __node, ...props }) => ( ) -const ProseDelStandard: React.FC & { __node?: any }> = ({ __node, ...props }) => ( +const ProseDel: React.FC & { __node?: any }> = ({ __node, ...props }) => ( ) // Links -const ProseAStandard: React.FC & { __node?: any }> = ({ __node, ...props }) => ( +const ProseA: React.FC & { __node?: any }> = ({ __node, ...props }) => ( ) // Code -const ProseCodeStandard: React.FC & { __node?: any }> = ({ __node, ...props }) => ( +const ProseCode: React.FC & { __node?: any }> = ({ __node, ...props }) => ( ) // Lists -const ProseUlStandard: React.FC & { __node?: any }> = ({ __node, ...props }) => ( +const ProseUl: React.FC & { __node?: any }> = ({ __node, ...props }) => (