mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-25 04:20:02 +00:00
Core & UI: hotfix <DynamicCodeBlock /> Vite + React 19.2 compat issues
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'fumadocs-core': patch
|
||||
'fumadocs-ui': patch
|
||||
---
|
||||
|
||||
hotfix `<DynamicCodeBlock />` Vite + React 19.2 compat issues
|
||||
@@ -1,26 +1,22 @@
|
||||
'use client';
|
||||
import {
|
||||
type DependencyList,
|
||||
type ReactNode,
|
||||
use,
|
||||
useId,
|
||||
useMemo,
|
||||
} from 'react';
|
||||
import { type DependencyList, type ReactNode, use, useMemo } from 'react';
|
||||
import { highlight, type HighlightOptions } from './shiki';
|
||||
|
||||
const promises: Record<string, Promise<ReactNode>> = {};
|
||||
|
||||
/**
|
||||
* get highlighted results, should be used with React Suspense API.
|
||||
*
|
||||
* note: results are cached with (lang, code) as keys, if this is not the desired behaviour, pass a `deps` instead.
|
||||
*/
|
||||
export function useShiki(
|
||||
code: string,
|
||||
options: HighlightOptions,
|
||||
deps?: DependencyList,
|
||||
): ReactNode {
|
||||
const id = useId();
|
||||
const key = useMemo(() => {
|
||||
const state = deps ? JSON.stringify(deps) : `${options.lang}:${code}`;
|
||||
|
||||
return `${id}:${state}`;
|
||||
}, [code, deps, id, options.lang]);
|
||||
return deps ? JSON.stringify(deps) : `${options.lang}:${code}`;
|
||||
}, [code, deps, options.lang]);
|
||||
|
||||
return use((promises[key] ??= highlight(code, options)));
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ import {
|
||||
type FC,
|
||||
Suspense,
|
||||
use,
|
||||
useDeferredValue,
|
||||
useId,
|
||||
} from 'react';
|
||||
|
||||
export interface DynamicCodeblockProps {
|
||||
@@ -56,6 +58,7 @@ export function DynamicCodeBlock({
|
||||
options,
|
||||
wrapInSuspense = true,
|
||||
}: DynamicCodeblockProps) {
|
||||
const id = useId();
|
||||
const shikiOptions = {
|
||||
lang,
|
||||
...options,
|
||||
@@ -64,10 +67,18 @@ export function DynamicCodeBlock({
|
||||
...options?.components,
|
||||
},
|
||||
} satisfies HighlightOptions;
|
||||
let children = <Internal code={code} options={shikiOptions} />;
|
||||
|
||||
const children = (
|
||||
<PropsContext value={codeblock}>
|
||||
<Internal
|
||||
id={id}
|
||||
{...useDeferredValue({ code, options: shikiOptions })}
|
||||
/>
|
||||
</PropsContext>
|
||||
);
|
||||
|
||||
if (wrapInSuspense)
|
||||
children = (
|
||||
return (
|
||||
<Suspense
|
||||
fallback={
|
||||
<Placeholder code={code} components={shikiOptions.components} />
|
||||
@@ -77,7 +88,7 @@ export function DynamicCodeBlock({
|
||||
</Suspense>
|
||||
);
|
||||
|
||||
return <PropsContext value={codeblock}>{children}</PropsContext>;
|
||||
return children;
|
||||
}
|
||||
|
||||
function Placeholder({
|
||||
@@ -106,11 +117,13 @@ function Placeholder({
|
||||
}
|
||||
|
||||
function Internal({
|
||||
id,
|
||||
code,
|
||||
options,
|
||||
}: {
|
||||
id: string;
|
||||
code: string;
|
||||
options: HighlightOptions;
|
||||
}) {
|
||||
return useShiki(code, options);
|
||||
return useShiki(code, options, [id, options.lang, code]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user