mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-25 04:20:02 +00:00
OpenAPI: support schemaUI option for customising schema UI
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'fumadocs-openapi': major
|
||||
---
|
||||
|
||||
Rename option `content.showExampleInFields` to `schemaUI.showExample`.
|
||||
@@ -2,11 +2,15 @@
|
||||
import Slugger from 'github-slugger';
|
||||
import { Operation } from '@/ui/operation';
|
||||
import type { MethodInformation, RenderContext } from '@/types';
|
||||
import { createMethod, NoReference } from '@/utils/schema';
|
||||
import {
|
||||
createMethod,
|
||||
type NoReference,
|
||||
type ResolvedSchema,
|
||||
} from '@/utils/schema';
|
||||
import type { OpenAPIV3_1 } from 'openapi-types';
|
||||
import type { ProcessedDocument } from '@/utils/process-document';
|
||||
import { defaultAdapters, MediaAdapter } from '@/requests/media/adapter';
|
||||
import { ComponentProps, FC, ReactNode } from 'react';
|
||||
import type { ComponentProps, FC, ReactNode } from 'react';
|
||||
import {
|
||||
highlight,
|
||||
type HighlightOptionsCommon,
|
||||
@@ -32,6 +36,7 @@ import remarkRehype from 'remark-rehype';
|
||||
import { toJsxRuntime } from 'hast-util-to-jsx-runtime';
|
||||
import * as JsxRuntime from 'react/jsx-runtime';
|
||||
import { CodeBlock, Pre } from 'fumadocs-ui/components/codeblock';
|
||||
import type { SchemaUIProps } from './schema/client';
|
||||
|
||||
type Awaitable<T> = T | Promise<T>;
|
||||
|
||||
@@ -77,13 +82,6 @@ export interface CreateAPIPageOptions {
|
||||
* Customise page content
|
||||
*/
|
||||
content?: {
|
||||
/**
|
||||
* Show examples under the generated content of JSON schemas.
|
||||
*
|
||||
* @defaultValue false
|
||||
*/
|
||||
showExampleInFields?: boolean;
|
||||
|
||||
renderResponseTabs?: (
|
||||
tabs: ResponseTab[],
|
||||
ctx: RenderContext,
|
||||
@@ -107,6 +105,25 @@ export interface CreateAPIPageOptions {
|
||||
) => Awaitable<ReactNode>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Info UI for JSON schemas
|
||||
*/
|
||||
schemaUI?: {
|
||||
render?: (
|
||||
options: Omit<SchemaUIProps, 'generated'> & {
|
||||
root: ResolvedSchema;
|
||||
},
|
||||
ctx: RenderContext,
|
||||
) => Awaitable<ReactNode>;
|
||||
|
||||
/**
|
||||
* Show examples under the generated content of JSON schemas.
|
||||
*
|
||||
* @defaultValue false
|
||||
*/
|
||||
showExample?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* Customise API playground
|
||||
*/
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
TabsList,
|
||||
TabsTrigger,
|
||||
} from 'fumadocs-ui/components/tabs';
|
||||
import type { SchemaData, SchemaUIData } from '@/ui/schema';
|
||||
import type { SchemaData, SchemaUIGeneratedData } from '@/ui/schema';
|
||||
import {
|
||||
Collapsible,
|
||||
CollapsibleContent,
|
||||
@@ -33,7 +33,7 @@ import {
|
||||
import { cn } from 'fumadocs-ui/utils/cn';
|
||||
import { cva } from 'class-variance-authority';
|
||||
|
||||
interface DataContextType extends SchemaUIData {
|
||||
interface DataContextType extends SchemaUIGeneratedData {
|
||||
readOnly?: boolean;
|
||||
writeOnly?: boolean;
|
||||
}
|
||||
@@ -63,13 +63,6 @@ const PropertyContext = createContext<PropertyContextType>({
|
||||
|
||||
const DataContext = createContext<DataContextType | null>(null);
|
||||
|
||||
export function SchemaUIProvider(props: {
|
||||
value: DataContextType;
|
||||
children: ReactNode;
|
||||
}) {
|
||||
return <DataContext value={props.value}>{props.children}</DataContext>;
|
||||
}
|
||||
|
||||
function useData() {
|
||||
return use(DataContext)!;
|
||||
}
|
||||
@@ -82,29 +75,47 @@ export interface SchemaUIProps {
|
||||
name: string;
|
||||
required?: boolean;
|
||||
as?: 'property' | 'body';
|
||||
|
||||
readOnly?: boolean;
|
||||
writeOnly?: boolean;
|
||||
generated: SchemaUIGeneratedData;
|
||||
}
|
||||
|
||||
export function SchemaUI({
|
||||
name,
|
||||
required = false,
|
||||
as = 'property',
|
||||
generated,
|
||||
readOnly,
|
||||
writeOnly,
|
||||
}: SchemaUIProps) {
|
||||
const { $root, refs } = useData();
|
||||
const schema = refs[$root];
|
||||
const context: DataContextType = useMemo(
|
||||
() => ({
|
||||
...generated,
|
||||
readOnly,
|
||||
writeOnly,
|
||||
}),
|
||||
[generated, readOnly, writeOnly],
|
||||
);
|
||||
const isProperty = as === 'property' || !isExpandable(schema);
|
||||
|
||||
if (as === 'property' || !isExpandable(schema)) {
|
||||
return (
|
||||
<SchemaUIProperty
|
||||
name={name}
|
||||
$type={$root}
|
||||
overrides={{
|
||||
required,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return <SchemaUIContent $type={$root} />;
|
||||
return (
|
||||
<DataContext value={context}>
|
||||
{isProperty ? (
|
||||
<SchemaUIProperty
|
||||
name={name}
|
||||
$type={$root}
|
||||
overrides={{
|
||||
required,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<SchemaUIContent $type={$root} />
|
||||
)}
|
||||
</DataContext>
|
||||
);
|
||||
}
|
||||
|
||||
function SchemaUIContent({ $type }: { $type: string }) {
|
||||
|
||||
@@ -4,7 +4,7 @@ import type { RenderContext } from '@/types';
|
||||
import { FormatFlags, schemaToString } from '@/utils/schema-to-string';
|
||||
import { combineSchema } from '@/utils/combine-schema';
|
||||
import type { SchemaUIProps } from '@/ui/schema/client';
|
||||
import { SchemaUILazy, SchemaUIProviderLazy } from '@/ui/schema/lazy';
|
||||
import { SchemaUILazy } from '@/ui/schema/lazy';
|
||||
|
||||
export interface FieldBase {
|
||||
description?: ReactNode;
|
||||
@@ -51,36 +51,31 @@ export interface SchemaUIOptions {
|
||||
ctx: RenderContext;
|
||||
}
|
||||
|
||||
export interface SchemaUIData {
|
||||
export interface SchemaUIGeneratedData {
|
||||
$root: string;
|
||||
refs: Record<string, SchemaData>;
|
||||
}
|
||||
|
||||
export function Schema(
|
||||
props: SchemaUIOptions &
|
||||
SchemaUIProps & {
|
||||
readOnly?: boolean;
|
||||
writeOnly?: boolean;
|
||||
},
|
||||
) {
|
||||
const data = generateSchemaUI(props);
|
||||
export function Schema({
|
||||
ctx,
|
||||
root,
|
||||
...props
|
||||
}: SchemaUIOptions & Omit<SchemaUIProps, 'generated'>) {
|
||||
if (ctx.schemaUI?.render) {
|
||||
return ctx.schemaUI.render({ root, ...props }, ctx);
|
||||
}
|
||||
|
||||
return (
|
||||
<SchemaUIProviderLazy
|
||||
value={{
|
||||
...data,
|
||||
readOnly: props.readOnly,
|
||||
writeOnly: props.writeOnly,
|
||||
}}
|
||||
>
|
||||
<SchemaUILazy name={props.name} required={props.required} as={props.as} />
|
||||
</SchemaUIProviderLazy>
|
||||
<SchemaUILazy {...props} generated={generateSchemaUI({ ctx, root })} />
|
||||
);
|
||||
}
|
||||
|
||||
function generateSchemaUI({ ctx, root }: SchemaUIOptions): SchemaUIData {
|
||||
function generateSchemaUI({
|
||||
ctx,
|
||||
root,
|
||||
}: SchemaUIOptions): SchemaUIGeneratedData {
|
||||
const refs: Record<string, SchemaData> = {};
|
||||
const { content: { showExampleInFields = false } = {} } = ctx;
|
||||
const { showExample = false } = ctx.schemaUI ?? {};
|
||||
|
||||
function generateInfoTags(schema: Exclude<ResolvedSchema, boolean>) {
|
||||
const fields: ReactNode[] = [];
|
||||
@@ -155,7 +150,7 @@ function generateSchemaUI({ ctx, root }: SchemaUIOptions): SchemaUIData {
|
||||
);
|
||||
}
|
||||
|
||||
if (showExampleInFields && schema.examples) {
|
||||
if (showExample && schema.examples) {
|
||||
for (const example of schema.examples) {
|
||||
fields.push(field('Example', JSON.stringify(example, null, 2)));
|
||||
}
|
||||
|
||||
@@ -4,7 +4,3 @@ import { wrapLazy } from '../../utils/lazy';
|
||||
export const SchemaUILazy = wrapLazy(() =>
|
||||
import('./client').then((mod) => ({ default: mod.SchemaUI })),
|
||||
);
|
||||
|
||||
export const SchemaUIProviderLazy = wrapLazy(() =>
|
||||
import('./client').then((mod) => ({ default: mod.SchemaUIProvider })),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user