mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-26 06:31:49 +00:00
feat(openapi): support components.Heading in client config
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'fumadocs-openapi': patch
|
||||
---
|
||||
|
||||
Support `components.Heading` in client config
|
||||
@@ -52,7 +52,6 @@
|
||||
"@radix-ui/react-accordion": "^1.2.12",
|
||||
"@radix-ui/react-dialog": "^1.1.15",
|
||||
"@radix-ui/react-select": "^2.2.6",
|
||||
"@radix-ui/react-slot": "^1.2.4",
|
||||
"chokidar": "^5.0.0",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"github-slugger": "^2.0.0",
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
export * from './generate-file';
|
||||
export type { MediaAdapter } from '@/requests/media/adapter';
|
||||
|
||||
export type * from './types';
|
||||
export type * from './utils/pages/builder';
|
||||
export type * from './utils/pages/preset-auto';
|
||||
export type { MethodInformation, RenderContext } from './types';
|
||||
export type {
|
||||
OperationOutput,
|
||||
OutputEntry,
|
||||
OutputGroup,
|
||||
PageOutput,
|
||||
PagesBuilder,
|
||||
PagesBuilderConfig,
|
||||
WebhookOutput,
|
||||
} from './utils/pages/builder';
|
||||
export type { SchemaToPagesOptions } from './utils/pages/preset-auto';
|
||||
export type { OpenAPIV3_2, OpenAPIV3_1, OpenAPIV3, OpenAPIV2, OpenAPI } from '@/_openapi/types';
|
||||
|
||||
@@ -107,7 +107,7 @@ export interface PlaygroundClientOptions {
|
||||
* for updating values, use:
|
||||
* - the `Custom.useController()` from `fumadocs-openapi/playground/client`.
|
||||
*
|
||||
* Recommended types packages: `json-schema-typed`, `openapi-types`.
|
||||
* Recommended types packages: `json-schema-typed`.
|
||||
*/
|
||||
renderParameterField?: (fieldName: FieldKey, param: ParameterObject) => ReactNode;
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import type { DereferencedDocument } from '@/utils/document/dereference';
|
||||
import type { MediaAdapter } from '@/requests/media/adapter';
|
||||
import type { OpenAPIOptions } from '@/server';
|
||||
import type { CreateAPIPageOptions } from './ui/base';
|
||||
import type { HTMLAttributes, ReactNode } from 'react';
|
||||
import type { InlineCodeUsageGenerator } from './requests/generators';
|
||||
|
||||
export type Document = OpenAPIV3_2.Document;
|
||||
@@ -37,8 +36,11 @@ export interface RenderContext
|
||||
extends
|
||||
Pick<OpenAPIOptions, 'proxyUrl'>,
|
||||
Omit<
|
||||
RequireKeys<CreateAPIPageOptions, 'renderMarkdown' | 'generateTypeScriptDefinitions'>,
|
||||
'renderCodeBlock' | 'renderHeading' | 'generateTypeScriptSchema'
|
||||
RequireKeys<
|
||||
CreateAPIPageOptions,
|
||||
'renderMarkdown' | 'generateTypeScriptDefinitions' | 'renderCodeBlock'
|
||||
>,
|
||||
'renderHeading' | 'generateTypeScriptSchema'
|
||||
> {
|
||||
/**
|
||||
* dereferenced schema
|
||||
@@ -47,8 +49,6 @@ export interface RenderContext
|
||||
clientBoundary: typeof import('@/ui/client/boundary');
|
||||
|
||||
mediaAdapters: Record<string, MediaAdapter>;
|
||||
|
||||
renderCodeBlock: (lang: string, code: string) => ReactNode;
|
||||
}
|
||||
|
||||
export type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any -- rehype-react without types */
|
||||
import Slugger from 'github-slugger';
|
||||
import type { Awaitable, MethodInformation, RenderContext } from '@/types';
|
||||
import { parseSecurities, type NoReference } from '@/utils/schema';
|
||||
import type { DereferencedDocument } from '@/utils/document/dereference';
|
||||
@@ -7,7 +6,6 @@ import { defaultAdapters, MediaAdapter } from '@/requests/media/adapter';
|
||||
import type { FC, HTMLAttributes, ReactNode } from 'react';
|
||||
import type { OpenAPIServer } from '@/server';
|
||||
import type { APIPageClientOptions } from './client';
|
||||
import { Heading } from 'fumadocs-ui/components/heading';
|
||||
import { createRehypeCode } from 'fumadocs-core/mdx-plugins/rehype-code.core';
|
||||
import { remarkGfm } from 'fumadocs-core/mdx-plugins/remark-gfm';
|
||||
import defaultMdxComponents from 'fumadocs-ui/mdx';
|
||||
@@ -203,7 +201,7 @@ export interface CreateAPIPageOptions {
|
||||
*/
|
||||
provider?: (props: { children: ReactNode }) => ReactNode;
|
||||
/**
|
||||
* replace the server-side renderer
|
||||
* replace the renderer
|
||||
*/
|
||||
render?: (props: APIPlaygroundProps) => ReactNode;
|
||||
};
|
||||
@@ -276,7 +274,6 @@ export function createAPIPage(
|
||||
processed = document;
|
||||
}
|
||||
|
||||
const slugger = new Slugger();
|
||||
const { ApiProvider, PlaygroundClient, SchemaUI, ServerProvider, UsageTab, UsageTabsSelector } =
|
||||
await import('@/ui/client/boundary.lazy');
|
||||
|
||||
@@ -331,7 +328,7 @@ export function createAPIPage(
|
||||
|
||||
return out.result as ReactNode;
|
||||
},
|
||||
async renderCodeBlock(lang, code) {
|
||||
async renderCodeBlock({ lang, code }) {
|
||||
if (options.renderCodeBlock) {
|
||||
return options.renderCodeBlock({ lang, code });
|
||||
}
|
||||
|
||||
@@ -1,13 +1,24 @@
|
||||
'use client';
|
||||
import type { PlaygroundClientOptions } from '@/playground/client';
|
||||
import type { MediaAdapter } from '@/requests/media/adapter';
|
||||
import type { FC } from 'react';
|
||||
import type { ComponentProps, FC } from 'react';
|
||||
import type { CodeUsageGeneratorRegistry } from '@/requests/generators';
|
||||
import type { ExampleRequestItem } from '../operation/get-example-requests';
|
||||
|
||||
export interface APIPageClientOptions {
|
||||
playground?: PlaygroundClientOptions;
|
||||
operation?: OperationClientOptions;
|
||||
operation?: {
|
||||
APIExampleSelector?: FC<{
|
||||
items: ExampleRequestItem[];
|
||||
|
||||
value: string | undefined;
|
||||
onValueChange: (id: string) => void;
|
||||
}>;
|
||||
};
|
||||
|
||||
components?: {
|
||||
Heading?: FC<ComponentProps<'h1'> & { id: string; depth: number }>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set a prefix for `localStorage` keys.
|
||||
@@ -29,15 +40,6 @@ export interface APIPageClientOptions {
|
||||
codeUsages?: CodeUsageGeneratorRegistry;
|
||||
}
|
||||
|
||||
export interface OperationClientOptions {
|
||||
APIExampleSelector?: FC<{
|
||||
items: ExampleRequestItem[];
|
||||
|
||||
value: string | undefined;
|
||||
onValueChange: (id: string) => void;
|
||||
}>;
|
||||
}
|
||||
|
||||
export function defineClientConfig(options: APIPageClientOptions = {}): APIPageClientOptions {
|
||||
return options;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { useAnchorId } from '@/utils/auto-anchor.client';
|
||||
import type { ComponentProps } from 'react';
|
||||
import { Heading as BaseHeading } from 'fumadocs-ui/components/heading';
|
||||
import { useApiContext } from '../contexts/api';
|
||||
|
||||
export function Heading({
|
||||
id: _id,
|
||||
@@ -9,6 +10,8 @@ export function Heading({
|
||||
...props
|
||||
}: ComponentProps<'h1'> & { id: string; depth: number }) {
|
||||
const id = useAnchorId([_id]);
|
||||
const Component = useApiContext().client.components?.Heading;
|
||||
if (Component) return <Component id={id} depth={depth} {...props} />;
|
||||
|
||||
return <BaseHeading id={id} as={`h${depth}` as `h1`} {...props} />;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'use client';
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any -- rehype-react without types */
|
||||
import type { Document, RenderContext } from '@/types';
|
||||
import { defaultAdapters } from '@/requests/media/adapter';
|
||||
@@ -9,7 +10,6 @@ import {
|
||||
type FC,
|
||||
type ReactNode,
|
||||
} from 'react';
|
||||
import { Heading } from 'fumadocs-ui/components/heading';
|
||||
import { remarkGfm } from 'fumadocs-core/mdx-plugins/remark-gfm';
|
||||
import defaultMdxComponents from 'fumadocs-ui/mdx';
|
||||
import { remark } from 'remark';
|
||||
@@ -21,11 +21,11 @@ import type { APIPlaygroundProps, CreateAPIPageOptions } from './base';
|
||||
import { defaultShikiFactory } from 'fumadocs-core/highlight/shiki/full';
|
||||
import { compile } from '@fumari/json-schema-ts';
|
||||
import { ClientCodeBlock, ClientCodeBlockProvider } from './components/codeblock';
|
||||
import { slug } from 'github-slugger';
|
||||
import * as ClientBoundary from '@/ui/client/boundary';
|
||||
import { dereferenceDocument } from '@/utils/document/dereference';
|
||||
import { parseSecurities } from '@/utils/schema';
|
||||
import { AuthProvider } from '@/playground/auth';
|
||||
import { APIPageClientOptions } from './client';
|
||||
|
||||
export interface ClientApiPageProps extends Omit<ApiPageProps, 'document'> {
|
||||
payload: ClientApiPagePayload;
|
||||
@@ -36,9 +36,9 @@ export interface ClientApiPagePayload {
|
||||
proxyUrl?: string;
|
||||
}
|
||||
|
||||
export type CreateClientAPIPageOptions = Omit<
|
||||
Partial<CreateAPIPageOptions>,
|
||||
'generateTypeScriptSchema'
|
||||
export type CreateClientAPIPageOptions = Partial<
|
||||
Omit<CreateAPIPageOptions, 'generateTypeScriptSchema' | 'client'> &
|
||||
Omit<APIPageClientOptions, 'mediaAdapters' | 'codeUsages'>
|
||||
>;
|
||||
|
||||
/**
|
||||
@@ -115,6 +115,7 @@ export function createClientAPIPage({
|
||||
shikiOptions,
|
||||
generateTypeScriptDefinitions,
|
||||
clientBoundary: ClientBoundary,
|
||||
client: options,
|
||||
...options,
|
||||
mediaAdapters: {
|
||||
...defaultAdapters,
|
||||
@@ -133,12 +134,12 @@ export function createClientAPIPage({
|
||||
value: text,
|
||||
}).result as ReactNode;
|
||||
},
|
||||
renderCodeBlock(lang, code) {
|
||||
renderCodeBlock(props) {
|
||||
if (options.renderCodeBlock) {
|
||||
return options.renderCodeBlock({ lang, code });
|
||||
return options.renderCodeBlock(props);
|
||||
}
|
||||
|
||||
return <ClientCodeBlock lang={lang} code={code} />;
|
||||
return <ClientCodeBlock {...props} />;
|
||||
},
|
||||
}),
|
||||
[payload.proxyUrl, processed],
|
||||
|
||||
@@ -122,7 +122,10 @@ function RequestTabsItem({
|
||||
<AccordionTrigger>{v}</AccordionTrigger>
|
||||
</AccordionHeader>
|
||||
<AccordionContent className="prose-no-margin">
|
||||
{ctx.renderCodeBlock('json', JSON.stringify(data, null, 2))}
|
||||
{ctx.renderCodeBlock({
|
||||
lang: 'json',
|
||||
code: JSON.stringify(data, null, 2),
|
||||
})}
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
);
|
||||
|
||||
@@ -98,7 +98,10 @@ function renderResponseTabsDefault(tabs: ResponseTab[], ctx: RenderContext): Rea
|
||||
return (
|
||||
<>
|
||||
{example.description && ctx.renderMarkdown(example.description)}
|
||||
{ctx.renderCodeBlock('json', JSON.stringify(example.sample, null, 2))}
|
||||
{ctx.renderCodeBlock({
|
||||
lang: 'json',
|
||||
code: JSON.stringify(example.sample, null, 2),
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ export async function renderContextFrom(input: string): Promise<RenderContext> {
|
||||
},
|
||||
shiki: defaultShikiFactory,
|
||||
shikiOptions: { theme: 'github-light' },
|
||||
renderCodeBlock(_lang, code) {
|
||||
renderCodeBlock({ code }) {
|
||||
return code;
|
||||
},
|
||||
clientBoundary: ClientBoundary,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"compilerOptions": {
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
"lib": ["ESNext", "DOM"],
|
||||
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"target": "ES2020"
|
||||
}
|
||||
|
||||
Generated
-3
@@ -2757,9 +2757,6 @@ importers:
|
||||
'@radix-ui/react-select':
|
||||
specifier: ^2.2.6
|
||||
version: 2.2.6(@types/[email protected](@types/[email protected]))(@types/[email protected])([email protected]([email protected]))([email protected])
|
||||
'@radix-ui/react-slot':
|
||||
specifier: ^1.2.4
|
||||
version: 1.2.4(@types/[email protected])([email protected])
|
||||
chokidar:
|
||||
specifier: ^5.0.0
|
||||
version: 5.0.0
|
||||
|
||||
Reference in New Issue
Block a user