Example: keymap
Install this example with
shadcn:npx shadcn@latest add @prosekit/react-example-keymapnpx shadcn@latest add @prosekit/preact-example-keymapnpx shadcn@latest add @prosekit/svelte-example-keymapnpx shadcn@latest add @prosekit/vue-example-keymapimport 'prosekit/basic/style.css'
import 'prosekit/basic/typography.css'
import {
useCallback,
useMemo,
useState,
} from 'preact/hooks'
import { createEditor } from 'prosekit/core'
import { ProseKit } from 'prosekit/preact'
import { defineExtension } from './extension'
import Toolbar from './toolbar'
export default function Editor() {
const editor = useMemo(() => {
const extension = defineExtension()
return createEditor({ extension })
}, [])
const [submissions, setSubmissions] = useState<string[]>([])
const pushSubmission = useCallback(
(hotkey: string) => {
const docString = JSON.stringify(editor.getDocJSON())
const submission = `${new Date().toISOString()}\t${hotkey}\n${docString}`
setSubmissions((prev) => [...prev, submission])
},
[editor],
)
return (
<ProseKit editor={editor}>
<div className="box-border h-full w-full min-h-36 overflow-y-hidden overflow-x-hidden rounded-md border border-solid border-gray-200 dark:border-gray-700 shadow-sm flex flex-col bg-white dark:bg-gray-950 text-black dark:text-white">
<Toolbar onSubmit={pushSubmission} />
<div className="relative w-full flex-1 box-border overflow-y-auto">
<div ref={editor.mount} className="ProseMirror box-border min-h-full px-[max(4rem,calc(50%-20rem))] py-8 outline-hidden outline-0 [&_span[data-mention=user]]:text-blue-500 [&_span[data-mention=tag]]:text-violet-500"></div>
</div>
</div>
<fieldset className="mt-4 box-border flex max-w-full w-full overflow-x-auto border p-4 rounded-md shadow-sm min-w-0">
<legend>Submit Records</legend>
<ol>
{submissions.map((submission, index) => (
<li key={index}>
<pre>{submission}</pre>
</li>
))}
</ol>
{submissions.length === 0 && <div>No submissions yet</div>}
</fieldset>
</ProseKit>
)
}import { defineBasicExtension } from 'prosekit/basic'
import { union } from 'prosekit/core'
export function defineExtension() {
return union(defineBasicExtension())
}
export type EditorExtension = ReturnType<typeof defineExtension>export { default as ExampleEditor } from './editor'import { useState } from 'preact/hooks'
import { Button } from '../../ui/button'
import { useSubmitKeymap } from './use-submit-keymap'
export default function Toolbar(props: {
onSubmit: (hotkey: string) => void
}) {
const [hotkey, setHotkey] = useState<'Shift-Enter' | 'Enter'>('Shift-Enter')
useSubmitKeymap(hotkey, props.onSubmit)
return (
<div className="z-2 box-border border-gray-200 dark:border-gray-800 border-solid border-l-0 border-r-0 border-t-0 border-b flex flex-wrap gap-1 p-2 items-center">
<Button
pressed={hotkey === 'Shift-Enter'}
onClick={() => setHotkey('Shift-Enter')}
>
<span className="mr-1">Submit with</span>
<kbd>Shift + Enter</kbd>
</Button>
<Button pressed={hotkey === 'Enter'} onClick={() => setHotkey('Enter')}>
<span className="mr-1">Submit with</span>
<kbd>Enter</kbd>
</Button>
</div>
)
}import { useMemo } from 'preact/hooks'
import type { Keymap } from 'prosekit/core'
import { useKeymap } from 'prosekit/preact'
export function useSubmitKeymap(
hotkey: 'Shift-Enter' | 'Enter',
onSubmit: (hotkey: string) => void,
) {
const keymap: Keymap = useMemo(() => {
return {
[hotkey]: () => {
onSubmit(hotkey)
return true
},
}
}, [hotkey, onSubmit])
useKeymap(keymap)
}import type {
ComponentChild,
MouseEventHandler,
} from 'preact'
import {
TooltipContent,
TooltipRoot,
TooltipTrigger,
} from 'prosekit/preact/tooltip'
export default function Button(props: {
pressed?: boolean
disabled?: boolean
onClick?: MouseEventHandler<HTMLButtonElement>
tooltip?: string
children: ComponentChild
}) {
return (
<TooltipRoot>
<TooltipTrigger className="block">
<button
data-state={props.pressed ? 'on' : 'off'}
disabled={props.disabled}
onClick={props.onClick}
onMouseDown={(event) => {
// Prevent the editor from being blurred when the button is clicked
event.preventDefault()
}}
className="outline-unset focus-visible:outline-unset flex items-center justify-center rounded-md p-2 font-medium transition focus-visible:ring-2 text-sm focus-visible:ring-gray-900 dark:focus-visible:ring-gray-300 disabled:pointer-events-none min-w-9 min-h-9 text-gray-900 dark:text-gray-50 disabled:text-gray-900/50 dark:disabled:text-gray-50/50 bg-transparent hover:bg-gray-100 dark:hover:bg-gray-800 data-[state=on]:bg-gray-200 dark:data-[state=on]:bg-gray-700"
>
{props.children}
{props.tooltip ? <span className="sr-only">{props.tooltip}</span> : null}
</button>
</TooltipTrigger>
{props.tooltip
? (
<TooltipContent className="z-50 overflow-hidden rounded-md border border-solid bg-gray-900 dark:bg-gray-50 px-3 py-1.5 text-xs text-gray-50 dark:text-gray-900 shadow-xs [&:not([data-state])]:hidden will-change-transform motion-safe:data-[state=open]:animate-in motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=open]:fade-in-0 motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=open]:zoom-in-95 motion-safe:data-[state=closed]:zoom-out-95 motion-safe:data-[state=open]:animate-duration-150 motion-safe:data-[state=closed]:animate-duration-200 motion-safe:data-[side=bottom]:slide-in-from-top-2 motion-safe:data-[side=bottom]:slide-out-to-top-2 motion-safe:data-[side=left]:slide-in-from-right-2 motion-safe:data-[side=left]:slide-out-to-right-2 motion-safe:data-[side=right]:slide-in-from-left-2 motion-safe:data-[side=right]:slide-out-to-left-2 motion-safe:data-[side=top]:slide-in-from-bottom-2 motion-safe:data-[side=top]:slide-out-to-bottom-2">
{props.tooltip}
</TooltipContent>
)
: null}
</TooltipRoot>
)
}export { default as Button } from './button'import 'prosekit/basic/style.css'
import 'prosekit/basic/typography.css'
import { createEditor } from 'prosekit/core'
import { ProseKit } from 'prosekit/react'
import {
useCallback,
useMemo,
useState,
} from 'react'
import { defineExtension } from './extension'
import Toolbar from './toolbar'
export default function Editor() {
const editor = useMemo(() => {
const extension = defineExtension()
return createEditor({ extension })
}, [])
const [submissions, setSubmissions] = useState<string[]>([])
const pushSubmission = useCallback(
(hotkey: string) => {
const docString = JSON.stringify(editor.getDocJSON())
const submission = `${new Date().toISOString()}\t${hotkey}\n${docString}`
setSubmissions((prev) => [...prev, submission])
},
[editor],
)
return (
<ProseKit editor={editor}>
<div className="box-border h-full w-full min-h-36 overflow-y-hidden overflow-x-hidden rounded-md border border-solid border-gray-200 dark:border-gray-700 shadow-sm flex flex-col bg-white dark:bg-gray-950 text-black dark:text-white">
<Toolbar onSubmit={pushSubmission} />
<div className="relative w-full flex-1 box-border overflow-y-auto">
<div ref={editor.mount} className="ProseMirror box-border min-h-full px-[max(4rem,calc(50%-20rem))] py-8 outline-hidden outline-0 [&_span[data-mention=user]]:text-blue-500 [&_span[data-mention=tag]]:text-violet-500"></div>
</div>
</div>
<fieldset className="mt-4 box-border flex max-w-full w-full overflow-x-auto border p-4 rounded-md shadow-sm min-w-0">
<legend>Submit Records</legend>
<ol>
{submissions.map((submission, index) => (
<li key={index}>
<pre>{submission}</pre>
</li>
))}
</ol>
{submissions.length === 0 && <div>No submissions yet</div>}
</fieldset>
</ProseKit>
)
}import { defineBasicExtension } from 'prosekit/basic'
import { union } from 'prosekit/core'
export function defineExtension() {
return union(defineBasicExtension())
}
export type EditorExtension = ReturnType<typeof defineExtension>'use client'
export { default as ExampleEditor } from './editor'import { useState } from 'react'
import { Button } from '../../ui/button'
import { useSubmitKeymap } from './use-submit-keymap'
export default function Toolbar(props: {
onSubmit: (hotkey: string) => void
}) {
const [hotkey, setHotkey] = useState<'Shift-Enter' | 'Enter'>('Shift-Enter')
useSubmitKeymap(hotkey, props.onSubmit)
return (
<div className="z-2 box-border border-gray-200 dark:border-gray-800 border-solid border-l-0 border-r-0 border-t-0 border-b flex flex-wrap gap-1 p-2 items-center">
<Button
pressed={hotkey === 'Shift-Enter'}
onClick={() => setHotkey('Shift-Enter')}
>
<span className="mr-1">Submit with</span>
<kbd>Shift + Enter</kbd>
</Button>
<Button pressed={hotkey === 'Enter'} onClick={() => setHotkey('Enter')}>
<span className="mr-1">Submit with</span>
<kbd>Enter</kbd>
</Button>
</div>
)
}import type { Keymap } from 'prosekit/core'
import { useKeymap } from 'prosekit/react'
import { useMemo } from 'react'
export function useSubmitKeymap(
hotkey: 'Shift-Enter' | 'Enter',
onSubmit: (hotkey: string) => void,
) {
const keymap: Keymap = useMemo(() => {
return {
[hotkey]: () => {
onSubmit(hotkey)
return true
},
}
}, [hotkey, onSubmit])
useKeymap(keymap)
}import {
TooltipContent,
TooltipRoot,
TooltipTrigger,
} from 'prosekit/react/tooltip'
import type {
MouseEventHandler,
ReactNode,
} from 'react'
export default function Button(props: {
pressed?: boolean
disabled?: boolean
onClick?: MouseEventHandler<HTMLButtonElement>
tooltip?: string
children: ReactNode
}) {
return (
<TooltipRoot>
<TooltipTrigger className="block">
<button
data-state={props.pressed ? 'on' : 'off'}
disabled={props.disabled}
onClick={props.onClick}
onMouseDown={(event) => {
// Prevent the editor from being blurred when the button is clicked
event.preventDefault()
}}
className="outline-unset focus-visible:outline-unset flex items-center justify-center rounded-md p-2 font-medium transition focus-visible:ring-2 text-sm focus-visible:ring-gray-900 dark:focus-visible:ring-gray-300 disabled:pointer-events-none min-w-9 min-h-9 text-gray-900 dark:text-gray-50 disabled:text-gray-900/50 dark:disabled:text-gray-50/50 bg-transparent hover:bg-gray-100 dark:hover:bg-gray-800 data-[state=on]:bg-gray-200 dark:data-[state=on]:bg-gray-700"
>
{props.children}
{props.tooltip ? <span className="sr-only">{props.tooltip}</span> : null}
</button>
</TooltipTrigger>
{props.tooltip
? (
<TooltipContent className="z-50 overflow-hidden rounded-md border border-solid bg-gray-900 dark:bg-gray-50 px-3 py-1.5 text-xs text-gray-50 dark:text-gray-900 shadow-xs [&:not([data-state])]:hidden will-change-transform motion-safe:data-[state=open]:animate-in motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=open]:fade-in-0 motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=open]:zoom-in-95 motion-safe:data-[state=closed]:zoom-out-95 motion-safe:data-[state=open]:animate-duration-150 motion-safe:data-[state=closed]:animate-duration-200 motion-safe:data-[side=bottom]:slide-in-from-top-2 motion-safe:data-[side=bottom]:slide-out-to-top-2 motion-safe:data-[side=left]:slide-in-from-right-2 motion-safe:data-[side=left]:slide-out-to-right-2 motion-safe:data-[side=right]:slide-in-from-left-2 motion-safe:data-[side=right]:slide-out-to-left-2 motion-safe:data-[side=top]:slide-in-from-bottom-2 motion-safe:data-[side=top]:slide-out-to-bottom-2">
{props.tooltip}
</TooltipContent>
)
: null}
</TooltipRoot>
)
}export { default as Button } from './button'<script lang="ts">
import 'prosekit/basic/style.css'
import 'prosekit/basic/typography.css'
import { createEditor } from 'prosekit/core'
import { ProseKit } from 'prosekit/svelte'
import { defineExtension } from './extension'
import Toolbar from './toolbar.svelte'
const extension = defineExtension()
const editor = createEditor({ extension })
let submissions = $state<string[]>([])
function pushSubmission(hotkey: string) {
const docString = JSON.stringify(editor.getDocJSON())
const submission = `${new Date().toISOString()}\t${hotkey}\n${docString}`
submissions = [...submissions, submission]
}
const mount = (element: HTMLElement) => {
editor.mount(element)
return { destroy: () => editor.unmount() }
}
</script>
<ProseKit {editor}>
<div class="box-border h-full w-full min-h-36 overflow-y-hidden overflow-x-hidden rounded-md border border-solid border-gray-200 dark:border-gray-700 shadow-sm flex flex-col bg-white dark:bg-gray-950 text-black dark:text-white">
<Toolbar onSubmit={pushSubmission} />
<div class="relative w-full flex-1 box-border overflow-y-auto">
<div use:mount class="ProseMirror box-border min-h-full px-[max(4rem,calc(50%-20rem))] py-8 outline-hidden outline-0 [&_span[data-mention=user]]:text-blue-500 [&_span[data-mention=tag]]:text-violet-500"></div>
</div>
</div>
<fieldset class="mt-4 box-border flex max-w-full w-full overflow-x-auto border p-4 rounded-md shadow-sm min-w-0">
<legend>Submit Records</legend>
<ol>
{#each submissions as submission, index (index)}
<li>
<pre>{submission}</pre>
</li>
{/each}
</ol>
{#if submissions.length === 0}
<div>No submissions yet</div>
{/if}
</fieldset>
</ProseKit>import { defineBasicExtension } from 'prosekit/basic'
import { union } from 'prosekit/core'
export function defineExtension() {
return union(defineBasicExtension())
}
export type EditorExtension = ReturnType<typeof defineExtension>export { default as ExampleEditor } from './editor.svelte'<script lang="ts">
import { useKeymap } from 'prosekit/svelte'
import {
derived,
writable,
} from 'svelte/store'
import { Button } from '../../ui/button'
interface Props {
onSubmit: (hotkey: string) => void
}
const props: Props = $props()
let hotkey = $state<'Shift-Enter' | 'Enter'>('Shift-Enter')
// Create a store from the reactive hotkey value
const hotkeyStore = writable<'Shift-Enter' | 'Enter'>('Shift-Enter')
// Update store when hotkey changes
$effect(() => {
hotkeyStore.set(hotkey)
})
// Create keymap derived from the hotkey store
const keymap = derived(hotkeyStore, ($hotkey) => ({
[$hotkey]: () => {
props.onSubmit($hotkey)
return true
},
}))
useKeymap(keymap)
function setHotkey(value: 'Shift-Enter' | 'Enter') {
hotkey = value
}
</script>
<div class="z-2 box-border border-gray-200 dark:border-gray-800 border-solid border-l-0 border-r-0 border-t-0 border-b flex flex-wrap gap-1 p-2 items-center">
<Button
pressed={hotkey === 'Shift-Enter'}
onClick={() => setHotkey('Shift-Enter')}
>
<span class="mr-1">Submit with</span>
<kbd>Shift + Enter</kbd>
</Button>
<Button
pressed={hotkey === 'Enter'}
onClick={() => setHotkey('Enter')}
>
<span class="mr-1">Submit with</span>
<kbd>Enter</kbd>
</Button>
</div><script lang="ts">
import {
TooltipContent,
TooltipRoot,
TooltipTrigger,
} from 'prosekit/svelte/tooltip'
interface Props {
pressed?: boolean
disabled?: boolean
onClick?: () => void
tooltip?: string
children?: import('svelte').Snippet
}
const props: Props = $props()
const pressed = $derived(props.pressed ?? false)
const disabled = $derived(props.disabled ?? false)
</script>
<TooltipRoot>
<TooltipTrigger class="block">
<button
data-state={pressed ? 'on' : 'off'}
{disabled}
class="outline-unset focus-visible:outline-unset flex items-center justify-center rounded-md p-2 font-medium transition focus-visible:ring-2 text-sm focus-visible:ring-gray-900 dark:focus-visible:ring-gray-300 disabled:pointer-events-none min-w-9 min-h-9 text-gray-900 dark:text-gray-50 disabled:text-gray-900/50 dark:disabled:text-gray-50/50 bg-transparent hover:bg-gray-100 dark:hover:bg-gray-800 data-[state=on]:bg-gray-200 dark:data-[state=on]:bg-gray-700"
onclick={props.onClick}
onmousedown={(e) => e.preventDefault()}
>
{@render props.children?.()}
{#if props.tooltip}
<span class="sr-only">{props.tooltip}</span>
{/if}
</button>
</TooltipTrigger>
{#if props.tooltip}
<TooltipContent class="z-50 overflow-hidden rounded-md border border-solid bg-gray-900 dark:bg-gray-50 px-3 py-1.5 text-xs text-gray-50 dark:text-gray-900 shadow-xs [&:not([data-state])]:hidden will-change-transform motion-safe:data-[state=open]:animate-in motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=open]:fade-in-0 motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=open]:zoom-in-95 motion-safe:data-[state=closed]:zoom-out-95 motion-safe:data-[state=open]:animate-duration-150 motion-safe:data-[state=closed]:animate-duration-200 motion-safe:data-[side=bottom]:slide-in-from-top-2 motion-safe:data-[side=bottom]:slide-out-to-top-2 motion-safe:data-[side=left]:slide-in-from-right-2 motion-safe:data-[side=left]:slide-out-to-right-2 motion-safe:data-[side=right]:slide-in-from-left-2 motion-safe:data-[side=right]:slide-out-to-left-2 motion-safe:data-[side=top]:slide-in-from-bottom-2 motion-safe:data-[side=top]:slide-out-to-bottom-2">
{props.tooltip}
</TooltipContent>
{/if}
</TooltipRoot>export { default as Button } from './button.svelte'<script setup lang="ts">
import 'prosekit/basic/style.css'
import 'prosekit/basic/typography.css'
import { createEditor } from 'prosekit/core'
import { ProseKit } from 'prosekit/vue'
import {
ref,
watchPostEffect,
} from 'vue'
import { defineExtension } from './extension'
import Toolbar from './toolbar.vue'
const extension = defineExtension()
const editor = createEditor({ extension })
const editorRef = ref<HTMLDivElement | null>(null)
const submissions = ref<string[]>([])
function pushSubmission(hotkey: string) {
const docString = JSON.stringify(editor.getDocJSON())
const submission = `${new Date().toISOString()}\t${hotkey}\n${docString}`
submissions.value = [...submissions.value, submission]
}
watchPostEffect((onCleanup) => {
editor.mount(editorRef.value)
onCleanup(() => editor.unmount())
})
</script>
<template>
<ProseKit :editor="editor">
<div class="box-border h-full w-full min-h-36 overflow-y-hidden overflow-x-hidden rounded-md border border-solid border-gray-200 dark:border-gray-700 shadow-sm flex flex-col bg-white dark:bg-gray-950 text-black dark:text-white">
<Toolbar @submit="pushSubmission" />
<div class="relative w-full flex-1 box-border overflow-y-auto">
<div ref="editorRef" class="ProseMirror box-border min-h-full px-[max(4rem,calc(50%-20rem))] py-8 outline-hidden outline-0 [&_span[data-mention=user]]:text-blue-500 [&_span[data-mention=tag]]:text-violet-500" />
</div>
</div>
<fieldset class="mt-4 box-border flex max-w-full w-full overflow-x-auto border p-4 rounded-md shadow-sm min-w-0">
<legend>Submit Records</legend>
<ol>
<li v-for="(submission, index) in submissions" :key="index">
<pre>{{ submission }}</pre>
</li>
</ol>
<div v-if="submissions.length === 0">No submissions yet</div>
</fieldset>
</ProseKit>
</template>import { defineBasicExtension } from 'prosekit/basic'
import { union } from 'prosekit/core'
export function defineExtension() {
return union(defineBasicExtension())
}
export type EditorExtension = ReturnType<typeof defineExtension>export { default as ExampleEditor } from './editor.vue'<script setup lang="ts">
import { ref } from 'vue'
import { Button } from '../../ui/button'
import { useSubmitKeymap } from './use-submit-keymap'
const props = defineProps<{
onSubmit: (hotkey: string) => void
}>()
const hotkey = ref<'Shift-Enter' | 'Enter'>('Shift-Enter')
useSubmitKeymap(hotkey, props.onSubmit)
function setHotkey(value: 'Shift-Enter' | 'Enter') {
hotkey.value = value
}
</script>
<template>
<div class="z-2 box-border border-gray-200 dark:border-gray-800 border-solid border-l-0 border-r-0 border-t-0 border-b flex flex-wrap gap-1 p-2 items-center">
<Button
:pressed="hotkey === 'Shift-Enter'"
@click="setHotkey('Shift-Enter')"
>
<span class="mr-1">Submit with</span>
<kbd>Shift + Enter</kbd>
</Button>
<Button
:pressed="hotkey === 'Enter'"
@click="setHotkey('Enter')"
>
<span class="mr-1">Submit with</span>
<kbd>Enter</kbd>
</Button>
</div>
</template>import type { Keymap } from 'prosekit/core'
import { useKeymap } from 'prosekit/vue'
import {
computed,
type Ref,
} from 'vue'
export function useSubmitKeymap(
hotkey: Ref<'Shift-Enter' | 'Enter'>,
onSubmit: (hotkey: string) => void,
) {
const keymap = computed<Keymap>(() => {
return {
[hotkey.value]: () => {
onSubmit(hotkey.value)
return true
},
}
})
useKeymap(keymap)
}<script setup lang="ts">
import {
TooltipContent,
TooltipRoot,
TooltipTrigger,
} from 'prosekit/vue/tooltip'
defineProps<{
pressed?: boolean
disabled?: boolean
onClick?: () => void
tooltip?: string
}>()
</script>
<template>
<TooltipRoot>
<TooltipTrigger class="block">
<button
:data-state="pressed ? 'on' : 'off'"
:disabled="disabled"
class="outline-unset focus-visible:outline-unset flex items-center justify-center rounded-md p-2 font-medium transition focus-visible:ring-2 text-sm focus-visible:ring-gray-900 dark:focus-visible:ring-gray-300 disabled:pointer-events-none min-w-9 min-h-9 text-gray-900 dark:text-gray-50 disabled:text-gray-900/50 dark:disabled:text-gray-50/50 bg-transparent hover:bg-gray-100 dark:hover:bg-gray-800 data-[state=on]:bg-gray-200 dark:data-[state=on]:bg-gray-700"
@click="onClick"
@mousedown.prevent
>
<slot />
<span v-if="tooltip" class="sr-only">{{ tooltip }}</span>
</button>
</TooltipTrigger>
<TooltipContent v-if="tooltip" class="z-50 overflow-hidden rounded-md border border-solid bg-gray-900 dark:bg-gray-50 px-3 py-1.5 text-xs text-gray-50 dark:text-gray-900 shadow-xs [&:not([data-state])]:hidden will-change-transform motion-safe:data-[state=open]:animate-in motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=open]:fade-in-0 motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=open]:zoom-in-95 motion-safe:data-[state=closed]:zoom-out-95 motion-safe:data-[state=open]:animate-duration-150 motion-safe:data-[state=closed]:animate-duration-200 motion-safe:data-[side=bottom]:slide-in-from-top-2 motion-safe:data-[side=bottom]:slide-out-to-top-2 motion-safe:data-[side=left]:slide-in-from-right-2 motion-safe:data-[side=left]:slide-out-to-right-2 motion-safe:data-[side=right]:slide-in-from-left-2 motion-safe:data-[side=right]:slide-out-to-left-2 motion-safe:data-[side=top]:slide-in-from-bottom-2 motion-safe:data-[side=top]:slide-out-to-bottom-2">
{{ tooltip }}
</TooltipContent>
</TooltipRoot>
</template>export { default as Button } from './button.vue'