diff --git a/src/runtime/component.ts b/src/runtime/component.ts index ba04025..fb7108f 100644 --- a/src/runtime/component.ts +++ b/src/runtime/component.ts @@ -1,14 +1,14 @@ -import { defineComponent, h, ref, toRef, getCurrentInstance } from 'vue' +import { defineComponent, h, ref, getCurrentInstance } from 'vue' import type { PropType, Ref } from 'vue' import { useShikiHighlighted } from './utils' import type { BundledLanguage } from 'shiki' -import type { HighlightOptions } from './types' +import type { UseHighlightOptions } from './types' export default defineComponent({ props: { code: String, lang: String as PropType, - highlightOptions: Object as PropType, + highlightOptions: Object as PropType, as: { type: String, default: 'pre' }, unwrap: { type: Boolean, default: undefined }, }, @@ -19,8 +19,8 @@ export default defineComponent({ ? getCurrentInstance()?.vnode?.el?.innerHTML : undefined - const highlighted = await useShikiHighlighted(toRef(props, 'code'), { - lang: props.lang, + const highlighted = await useShikiHighlighted(() => props.code, { + lang: () => props.lang, highlighted: hydratedCode, unwrap: props.unwrap ?? props.as === 'pre', ...props.highlightOptions, diff --git a/src/runtime/types.ts b/src/runtime/types.ts index bcef1c7..d9f3bf1 100644 --- a/src/runtime/types.ts +++ b/src/runtime/types.ts @@ -1,4 +1,5 @@ -import type { CodeToHastOptions, HighlighterCore } from 'shiki' +import type { MaybeRefOrGetter } from 'vue' +import type { BundledLanguage, BundledTheme, CodeToHastOptions, HighlighterCore } from 'shiki' import type { HighlighterCoreOptions } from 'shiki/core' export type HighlightOptions = Partial & { @@ -6,6 +7,12 @@ export type HighlightOptions = Partial & { unwrap?: boolean } +export type UseHighlightOptions = Omit & { + highlighted?: string + lang?: MaybeRefOrGetter + theme?: MaybeRefOrGetter +} + export type ShikiHighlighter = HighlighterCore & { highlight: (code: string, options: HighlightOptions) => string } diff --git a/src/runtime/utils.ts b/src/runtime/utils.ts index 6518dc4..60517e5 100644 --- a/src/runtime/utils.ts +++ b/src/runtime/utils.ts @@ -1,5 +1,5 @@ -import { ref, watchEffect, watch, toRef, type Ref } from 'vue' -import type { HighlightOptions, ShikiHighlighter } from './types' +import { ref, watch, toValue, type MaybeRefOrGetter } from 'vue' +import type { UseHighlightOptions, ShikiHighlighter } from './types' import { createHighlighter } from './shiki' /** @@ -43,38 +43,39 @@ export async function getShikiHighlighter(): Promise { * ``` */ export async function useShikiHighlighted( - code: string | undefined | Ref, - options: HighlightOptions & { highlighted?: string } = {}, + code: MaybeRefOrGetter, + options: UseHighlightOptions = {}, ) { - const _code = toRef(code) - if ('themes' in options && !options.themes) { delete options.themes } if (import.meta.server) { const highlighter = await getShikiHighlighter() - return ref(highlighter.highlight(_code.value || '', options)) + return ref(highlighter.highlight(toValue(code) || '', { + ...options, + lang: toValue(options.lang), + theme: toValue(options.theme), + })) } const highlighted = ref(options.highlighted || '') + const immediate = !highlighted.value - if (highlighted.value) { - const unwatch = watch(_code, () => { - unwatch() - init() - }) - } else { - await init() - } - - function init() { - getShikiHighlighter().then((highlighter) => { - watchEffect(() => { - highlighted.value = highlighter.highlight(_code.value || '', options) - }) + watch([ + () => toValue(code), + () => toValue(options.lang), + () => toValue(options.theme), + ], async ([_code, lang, theme]) => { + const highlighter = await getShikiHighlighter() + highlighted.value = highlighter.highlight(_code || '', { + ...options, + lang, + theme, }) - } + }, { + immediate, + }) return highlighted }