UI: Change code block usages

This commit is contained in:
fuma-nama
2024-07-27 20:58:05 +08:00
parent b502bd261b
commit b02eebf033
15 changed files with 227 additions and 137 deletions
+25
View File
@@ -0,0 +1,25 @@
---
'fumadocs-ui': major
---
**Move `keepCodeBlockBackground` option to code block component**
**why:** Easier to customise code block styles.
**migrate:**
Enable `keepBackground` on `<CodeBlock />`, and remove deprecated usage.
```tsx
import { Pre, CodeBlock } from 'fumadocs-ui/components/codeblock';
<MDX
components={{
pre: ({ ref: _ref, ...props }) => (
<CodeBlock keepBackground {...props}>
<Pre>{props.children}</Pre>
</CodeBlock>
),
}}
/>;
```
+9
View File
@@ -0,0 +1,9 @@
---
'fumadocs-core': major
---
**Remove deprecated option `defaultLang`**
**why:** The default language feature has been supported by Shiki Rehype integration, you should use it directly.
**migrate:** Rename to `defaultLanguage`.
+29
View File
@@ -0,0 +1,29 @@
---
'fumadocs-ui': major
---
**Change code block component usage**
**why:** The previous usage was confusing, some props are passed directly to `pre` while some are not.
**migrate:**
Pass all props to `CodeBlock` component.
This also includes class names, change your custom styles if necessary.
```tsx
import { Pre, CodeBlock } from 'fumadocs-ui/components/codeblock';
<MDX
components={{
// HTML `ref` attribute conflicts with `forwardRef`
pre: ({ ref: _ref, ...props }) => (
<CodeBlock {...props}>
<Pre>{props.children}</Pre>
</CodeBlock>
),
}}
/>;
```
You can ignore this if you didn't customise the default `pre` element.
+59 -13
View File
@@ -3,6 +3,8 @@ title: Markdown
description: How to write documents
---
import { HomeIcon } from 'lucide-react';
## Introduction
Fumadocs provides many useful extensions to MDX, a markup language. Here is a brief introduction to the default MDX syntax of Fumadocs UI.
@@ -72,7 +74,9 @@ see [MDX Syntax](https://mdxjs.com/docs/what-is-mdx/#mdx-syntax) to learn more.
### Cards
A [`Card`](/docs/ui/mdx/card) component is included by default. Similar to links, but you can display more information (e.g. icons).
Useful for adding links, it is included by default.
Same as normal links, but you can display more information (e.g. icons).
```mdx
<Cards>
@@ -92,32 +96,74 @@ A [`Card`](/docs/ui/mdx/card) component is included by default. Similar to links
/>
</Cards>
#### Icon
You can specify an icon to cards.
```mdx
import { HomeIcon } from 'lucide-react';
<Cards>
<Card
icon={<HomeIcon />}
href="/"
title="Home"
description="Go back to home"
/>
</Cards>
```
<Cards>
<Card
icon={<HomeIcon />}
href="/"
title="Home"
description="Go back to home"
/>
</Cards>
### Callouts
Useful for adding tips/warnings, it is included by default.
```mdx
<Callout title="Title" type="info">
Hello World
</Callout>
<Callout title="Title" type="warn">
Hello World
</Callout>
<Callout>Hello World</Callout>
```
<Callout>Hello World</Callout>
#### Title
Specify a callout title.
```mdx
<Callout title="Title">Hello World</Callout>
```
<Callout title="Title">Hello World</Callout>
#### Types
You can specify the type of callout.
- `info` (default)
- `warn`
- `error`
```mdx
<Callout title="Title" type="error">
Hello World
</Callout>
```
<Callout title="Title" type="info">
Hello World
</Callout>
<Callout title="Title" type="warn">
Hello World
</Callout>
<Callout title="Title" type="error">
Hello World
</Callout>
### Customisation
See [all MDX components and available options](/docs/ui/mdx).
## Heading Anchors
An anchor is automatically applied to all headings, it sanitizes invalid characters like spaces. (e.g. `Hello World` to `hello-world`)
+7 -25
View File
@@ -8,35 +8,17 @@ preview: callout
Add it to your MDX components.
```mdx
```tsx
import { Callout } from 'fumadocs-ui/components/callout';
<Callout title="Title">Hello World</Callout>
<MDX
components={{
Callout,
}}
/>;
```
### Types
You can specify the type of callout.
- `info` (default)
- `warn`
- `error`
```mdx
<Callout title="Title" type="warn">
Hello World
</Callout>
```
<Callout title="Title" type="warn">
Hello World
</Callout>
### Without Title
You can create a Callout without title.
<Callout>Hello World</Callout>
See [Markdown](/docs/ui/markdown#callouts) for usages.
### Reference
+7 -27
View File
@@ -10,24 +10,26 @@ import { HomeIcon } from 'lucide-react';
Add it to your MDX components.
```mdx
```tsx
import { Card, Cards } from 'fumadocs-ui/components/card';
<MDX
components={{
Card: (props) => <Card {...props} />,
Cards: (props) => <Cards {...props} />,
Card,
Cards,
}}
/>
/>;
```
See [Markdown](/docs/ui/markdown#cards) for usages.
### Cards
The container of cards.
### Card
Based on `<Link />`.
Based on Next.js `<Link />`.
```json doc-gen:typescript
{
@@ -36,28 +38,6 @@ Based on `<Link />`.
}
```
## Example
Pass the href, title and description.
```mdx
<Cards>
<Card
href="https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating"
title="Fetching, Caching, and Revalidating"
description="Learn more about caching in Next.js"
/>
</Cards>
```
<Cards>
<Card
href="https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating"
title="Fetching, Caching, and Revalidating"
description="Learn more about caching in Next.js"
/>
</Cards>
### With Icons
```mdx
+27 -8
View File
@@ -34,27 +34,46 @@ Display code blocks, added by default.
Wrap the pre element in `<CodeBlock />`, which acts as the wrapper of code block.
```mdx
```tsx
import { Pre, CodeBlock } from 'fumadocs-ui/components/codeblock';
<MDX
components={{
pre: ({ ref: _ref, title, ...props }) => (
<CodeBlock title={title}>
<Pre {...props} />
// HTML `ref` attribute conflicts with `forwardRef`
pre: ({ ref: _ref, ...props }) => (
<CodeBlock {...props}>
<Pre>{props.children}</Pre>
</CodeBlock>
),
}}
/>
/>;
```
See [Markdown](/docs/ui/markdown#codeblock) for supported features.
See [Markdown](/docs/ui/markdown#codeblock) for usages.
### Keep Background
Use the background color generated by Shiki (the Rehype Code plugin).
```tsx
import { Pre, CodeBlock } from 'fumadocs-ui/components/codeblock';
<MDX
components={{
pre: ({ ref: _ref, ...props }) => (
<CodeBlock keepBackground {...props}>
<Pre>{props.children}</Pre>
</CodeBlock>
),
}}
/>;
```
### Icons
You can specify a custom icon by passing an `icon` prop to `CodeBlock` component.
Specify a custom icon by passing an `icon` prop to `CodeBlock` component.
By default, the icon will be injected by the custom Shiki transformer automatically.
By default, the icon will be injected by the custom Shiki transformer.
```js title="config.js"
console.log('js');
+1 -1
View File
@@ -6,7 +6,7 @@ index: true
## Usage
The default MDX components include Card, Code Blocks and Headings.
The default MDX components include Cards, Callouts, Code Blocks and Headings.
```ts
import defaultComponents from 'fumadocs-ui/mdx';
+3 -4
View File
@@ -11,7 +11,6 @@ import {
} from 'fumadocs-ui/components/codeblock';
import { Popup, PopupContent, PopupTrigger } from 'fumadocs-ui/twoslash/popup';
import { Wrapper } from '@/components/preview/wrapper';
import { cn } from './utils/cn';
export function useMDXComponents(components: MDXComponents): MDXComponents {
return {
@@ -19,9 +18,9 @@ export function useMDXComponents(components: MDXComponents): MDXComponents {
Popup,
PopupContent,
PopupTrigger,
pre: ({ title, className, icon, allowCopy, ...props }: CodeBlockProps) => (
<CodeBlock title={title} icon={icon} allowCopy={allowCopy}>
<Pre className={cn('max-h-[400px]', className)} {...props} />
pre: (props: CodeBlockProps) => (
<CodeBlock {...props}>
<Pre className="max-h-[400px]">{props.children}</Pre>
</CodeBlock>
),
Tabs,
@@ -72,14 +72,6 @@ export type RehypeCodeOptions = RehypeShikiOptions & {
*/
filterMetaString?: (metaString: string) => string;
/**
* Default language
*
* @defaultValue plaintext
* @deprecated Use `defaultLanguage` instead
*/
defaultLang?: string;
/**
* Add icon to code blocks
*/
@@ -141,10 +133,6 @@ export function rehypeCode(
codeOptions.transformers = [...codeOptions.transformers, transformerTab()];
}
if (codeOptions.defaultLang) {
codeOptions.defaultLanguage = codeOptions.defaultLang;
}
return rehypeShiki.call(this, codeOptions) as Transformer<Root, Root>;
}
+1 -1
View File
@@ -70,7 +70,7 @@ export const Accordion = forwardRef<
className="not-prose flex flex-row items-center font-medium text-fd-foreground"
>
<AccordionPrimitive.Trigger className="flex flex-1 items-center gap-2 p-4 text-start focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fd-ring">
<ChevronRight className="-ms-1 size-4 text-fd-muted-foreground transition-transform duration-200 group-data-[state=open]/accordion:rotate-90" />
<ChevronRight className="-ms-1 size-4 shrink-0 text-fd-muted-foreground transition-transform duration-200 group-data-[state=open]/accordion:rotate-90" />
{title}
</AccordionPrimitive.Trigger>
{id ? <CopyButton id={id} /> : null}
+4 -2
View File
@@ -18,7 +18,7 @@ export function Cards(
export type CardProps = {
icon?: ReactNode;
title: string;
description: string;
description?: string;
} & Omit<LinkProps, 'title'>;
export function Card({
@@ -41,7 +41,9 @@ export function Card({
</div>
) : null}
<h3 className="mb-1 font-medium">{title}</h3>
<p className="text-fd-muted-foreground">{description}</p>
{description ? (
<p className="text-fd-muted-foreground">{description}</p>
) : null}
</Link>
);
}
+26 -3
View File
@@ -26,13 +26,25 @@ export type CodeBlockProps = HTMLAttributes<HTMLElement> & {
*/
icon?: ReactNode;
/**
* Allow to copy code with copy button
*
* @defaultValue true
*/
allowCopy?: boolean;
/**
* Keep original background color generated by Shiki or Rehype Code
*
* @defaultValue false
*/
keepBackground?: boolean;
};
export const Pre = forwardRef<HTMLPreElement, HTMLAttributes<HTMLPreElement>>(
({ className, ...props }, ref) => {
return (
<pre ref={ref} className={cn('nd-codeblock p-4', className)} {...props}>
<pre ref={ref} className={cn('p-4', className)} {...props}>
{props.children}
</pre>
);
@@ -42,7 +54,17 @@ export const Pre = forwardRef<HTMLPreElement, HTMLAttributes<HTMLPreElement>>(
Pre.displayName = 'Pre';
export const CodeBlock = forwardRef<HTMLElement, CodeBlockProps>(
({ title, allowCopy = true, icon, className, ...props }, ref) => {
(
{
title,
allowCopy = true,
keepBackground = false,
icon,
className,
...props
},
ref,
) => {
const areaRef = useRef<HTMLDivElement>(null);
const onCopy = useCallback(() => {
const pre = areaRef.current?.getElementsByTagName('pre').item(0);
@@ -61,7 +83,8 @@ export const CodeBlock = forwardRef<HTMLElement, CodeBlockProps>(
<figure
ref={ref}
className={cn(
'not-prose group relative my-6 overflow-hidden rounded-lg border bg-fd-secondary/50 text-sm',
'not-prose group fd-codeblock relative my-6 overflow-hidden rounded-lg border bg-fd-secondary/50 text-sm',
keepBackground && 'fd-codeblock-keep-bg',
className,
)}
{...props}
+10 -8
View File
@@ -2,15 +2,17 @@
import * as Base from '@/components/codeblock';
export function Pre({
title,
allowCopy,
icon,
...props
}: Base.CodeBlockProps): React.ReactElement {
/**
* You are NOT supposed to use this component directly.
*
* This should be referenced in the output generated by the Rehype Code plugin.
*
* @internal
*/
export function Pre(props: Base.CodeBlockProps): React.ReactElement {
return (
<Base.CodeBlock title={title} allowCopy={allowCopy} icon={icon}>
<Base.Pre {...props} />
<Base.CodeBlock {...props}>
<Base.Pre>{props.children}</Base.Pre>
</Base.CodeBlock>
);
}
+19 -33
View File
@@ -31,13 +31,6 @@ interface DocsUIOptions {
* Color preset
*/
preset?: keyof typeof presets | Preset;
/**
* Keep code block background of theme
*
* @defaultValue false
*/
keepCodeBlockBackground?: boolean;
}
type Keys =
@@ -115,11 +108,7 @@ function createTailwindColors(
}
export const docsUi = plugin.withOptions<DocsUIOptions>(
({
cssPrefix = '',
preset = 'default',
keepCodeBlockBackground = false,
} = {}) => {
({ cssPrefix = '', preset = 'default' } = {}) => {
return ({ addBase, addComponents, addUtilities }) => {
const { light, dark, css } =
typeof preset === 'string' ? presets[preset] : preset;
@@ -139,22 +128,22 @@ export const docsUi = plugin.withOptions<DocsUIOptions>(
if (css) addBase(css);
addComponents({
'.nd-codeblock span': {
'.fd-codeblock pre span': {
color: 'var(--shiki-light)',
},
'.dark .nd-codeblock span': {
'.dark .fd-codeblock pre span': {
color: 'var(--shiki-dark)',
},
'.nd-codeblock code': {
'.fd-codeblock code': {
display: 'grid',
'font-size': '13px',
},
'.nd-codeblock .highlighted': {
'.fd-codeblock .highlighted': {
margin: '0 -16px',
padding: '0 16px',
'background-color': `theme('colors.fd-primary.DEFAULT / 10%')`,
},
'.nd-codeblock .highlighted-word': {
'.fd-codeblock .highlighted-word': {
padding: '1px 2px',
margin: '-1px -3px',
border: '1px solid',
@@ -162,21 +151,14 @@ export const docsUi = plugin.withOptions<DocsUIOptions>(
'background-color': `theme('colors.fd-primary.DEFAULT / 10%')`,
'border-radius': '2px',
},
'.fd-codeblock-keep-bg': {
'background-color': 'var(--shiki-light-bg)',
},
'.dark .fd-codeblock-keep-bg': {
'background-color': 'var(--shiki-dark-bg)',
},
});
if (keepCodeBlockBackground) {
addComponents({
'.nd-codeblock': {
color: 'var(--shiki-light)',
'background-color': 'var(--shiki-light-bg)',
},
'.dark .nd-codeblock': {
color: 'var(--shiki-dark)',
'background-color': 'var(--shiki-dark-bg)',
},
});
}
addUtilities({
'.steps': {
'counter-reset': 'step',
@@ -234,9 +216,6 @@ export const docsUi = plugin.withOptions<DocsUIOptions>(
},
colors: createTailwindColors(cssPrefix, addGlobalColors),
...animations,
typography: {
DEFAULT: typographyConfig,
},
},
},
}),
@@ -246,6 +225,13 @@ export function createPreset(options: DocsUIOptions = {}): PresetsConfig {
return {
darkMode: 'class',
plugins: [typography, docsUi(options)],
theme: {
extend: {
typography: {
DEFAULT: typographyConfig,
},
},
},
};
}