fumadocs-openapi 10.2.4 → 10.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/generate-file.js.map +1 -1
- package/dist/playground/client.d.ts +11 -12
- package/dist/playground/client.d.ts.map +1 -1
- package/dist/playground/client.js +70 -74
- package/dist/playground/client.js.map +1 -1
- package/dist/playground/components/inputs.js +198 -187
- package/dist/playground/components/inputs.js.map +1 -1
- package/dist/playground/components/oauth-dialog.js +2 -2
- package/dist/playground/components/server-select.js +24 -25
- package/dist/playground/components/server-select.js.map +1 -1
- package/dist/playground/fetcher.js.map +1 -1
- package/dist/playground/index.js.map +1 -1
- package/dist/playground/schema.d.ts +1 -0
- package/dist/playground/schema.d.ts.map +1 -1
- package/dist/playground/schema.js +10 -12
- package/dist/playground/schema.js.map +1 -1
- package/dist/playground/status-info.js.map +1 -1
- package/dist/requests/generators/csharp.js.map +1 -1
- package/dist/requests/generators/curl.js.map +1 -1
- package/dist/requests/generators/go.js.map +1 -1
- package/dist/requests/generators/index.js.map +1 -1
- package/dist/requests/generators/java.js.map +1 -1
- package/dist/requests/generators/javascript.js.map +1 -1
- package/dist/requests/generators/python.js.map +1 -1
- package/dist/requests/media/adapter.js.map +1 -1
- package/dist/requests/media/encode.js.map +1 -1
- package/dist/requests/media/resolve-adapter.js +4 -0
- package/dist/requests/media/resolve-adapter.js.map +1 -1
- package/dist/server/create.js.map +1 -1
- package/dist/server/proxy.js.map +1 -1
- package/dist/server/source-api.js.map +1 -1
- package/dist/ui/api-page.js.map +1 -1
- package/dist/ui/contexts/api.js.map +1 -1
- package/dist/ui/operation/index.js.map +1 -1
- package/dist/ui/operation/request-tabs.js.map +1 -1
- package/dist/ui/operation/response-tabs.js.map +1 -1
- package/dist/ui/operation/usage-tabs/client.js.map +1 -1
- package/dist/ui/operation/usage-tabs/index.js.map +1 -1
- package/dist/ui/schema/client.d.ts.map +1 -1
- package/dist/ui/schema/client.js +120 -114
- package/dist/ui/schema/client.js.map +1 -1
- package/dist/ui/schema/index.js +1 -1
- package/dist/ui/schema/index.js.map +1 -1
- package/dist/utils/id-to-title.js.map +1 -1
- package/dist/utils/merge-schema.js.map +1 -1
- package/dist/utils/pages/builder.js.map +1 -1
- package/dist/utils/pages/preset-auto.js.map +1 -1
- package/dist/utils/pages/to-static-data.js.map +1 -1
- package/dist/utils/pages/to-text.js.map +1 -1
- package/package.json +13 -12
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-file.js","names":["
|
|
1
|
+
{"version":3,"file":"generate-file.js","names":["entries","path"],"sources":["../src/generate-file.ts"],"sourcesContent":["import { mkdir, writeFile } from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { generateDocument, type PagesToTextOptions, toText } from './utils/pages/to-text';\nimport type { ProcessedDocument } from '@/utils/process-document';\nimport type { OpenAPIServer } from '@/server';\nimport { createGetUrl, getSlugs } from 'fumadocs-core/source';\nimport { createAutoPreset, type SchemaToPagesOptions } from '@/utils/pages/preset-auto';\nimport { fromSchema, type OutputEntry } from '@/utils/pages/builder';\n\nexport interface OutputFile {\n path: string;\n content: string;\n}\n\ninterface IndexConfig {\n items: IndexItem[] | ((ctx: BeforeWriteContext) => IndexItem[]);\n\n /**\n * Generate URLs for cards\n */\n url:\n | ((filePath: string) => string)\n | {\n baseUrl: string;\n /**\n * Base content directory\n */\n contentDir: string;\n };\n}\n\ninterface IndexItem {\n path: string;\n title?: string;\n description?: string;\n\n /**\n * Specify linked pages:\n * - items in `inputs` to include all generated pages of a specific schema.\n * - specific Markdown/MDX files.\n */\n only?: string[];\n}\n\ninterface GenerateFilesConfig extends PagesToTextOptions {\n /**\n * the OpenAPI server object\n */\n input: OpenAPIServer;\n\n /**\n * Output directory\n */\n output: string;\n\n /**\n * Generate index files with cards linking to generated pages.\n */\n index?: IndexConfig;\n\n /**\n * Can add/change/remove output files before writing to file system\n **/\n beforeWrite?: (this: BeforeWriteContext, files: OutputFile[]) => void | Promise<void>;\n}\n\nexport type Config = SchemaToPagesOptions & GenerateFilesConfig;\n\ninterface BeforeWriteContext {\n readonly generated: Record<string, OutputFile[]>;\n readonly generatedEntries: Record<string, OutputEntry[]>;\n readonly documents: Record<string, ProcessedDocument>;\n}\n\nexport async function generateFiles(options: Config): Promise<void> {\n const files = await generateFilesOnly(options);\n const { output } = options;\n\n await Promise.all(\n files.map(async (file) => {\n const filePath = path.join(output, file.path);\n\n await mkdir(path.dirname(filePath), { recursive: true });\n await writeFile(filePath, file.content);\n console.log(`Generated: ${filePath}`);\n }),\n );\n}\n\nexport async function generateFilesOnly(\n options: SchemaToPagesOptions & Omit<GenerateFilesConfig, 'output'>,\n): Promise<OutputFile[]> {\n const schemas = await options.input.getSchemas();\n\n const files: OutputFile[] = [];\n const generated: Record<string, OutputFile[]> = {};\n const generatedEntries: Record<string, OutputEntry[]> = {};\n\n const entries = Object.entries(schemas);\n if (entries.length === 0) {\n throw new Error('No input files found.');\n }\n const preset = createAutoPreset(options);\n for (const [id, schema] of entries) {\n const entries = fromSchema(id, schema, preset);\n const schemaFiles = (generated[id] ??= []);\n\n generatedEntries[id] = entries;\n for (const entry of entries) {\n const file: OutputFile = {\n path: entry.path,\n content: toText(entry, schema, options),\n };\n\n schemaFiles.push(file);\n files.push(file);\n }\n }\n\n const context: BeforeWriteContext = {\n generated,\n generatedEntries,\n documents: schemas,\n };\n\n if (options.index) {\n writeIndexFiles(files, context, options);\n }\n\n await options.beforeWrite?.call(context, files);\n return files;\n}\n\nfunction writeIndexFiles(\n files: OutputFile[],\n context: BeforeWriteContext,\n options: SchemaToPagesOptions & Omit<GenerateFilesConfig, 'output'>,\n) {\n const { generatedEntries } = context;\n const { items, url } = options.index!;\n\n let urlFn: (path: string) => string;\n if (typeof url === 'object') {\n const getUrl = createGetUrl(url.baseUrl);\n\n urlFn = (file) => getUrl(getSlugs(path.relative(url.contentDir, file)));\n } else {\n urlFn = url;\n }\n\n function findEntryByPath(path: string) {\n for (const entries of Object.values(generatedEntries)) {\n const match = entries.find((entry) => entry.path === path);\n\n if (match) return match;\n }\n }\n\n function fileContent(index: IndexItem): string {\n const content: string[] = [];\n content.push('<Cards>');\n const pathToEntry = new Map<string, OutputEntry>();\n const only = index.only ?? Object.keys(context.generated);\n\n for (const item of only) {\n if (generatedEntries[item]) {\n for (const entry of generatedEntries[item]) {\n pathToEntry.set(entry.path, entry);\n }\n } else {\n const match = findEntryByPath(item);\n if (!match) {\n throw new Error(\n `${item} does not exist on \"input\", available: ${Object.keys(generatedEntries).join(', ')}.`,\n );\n }\n\n pathToEntry.set(match.path, match);\n }\n }\n\n for (const file of pathToEntry.values()) {\n const descriptionAttr = file.info.description\n ? `description=${JSON.stringify(file.info.description)} `\n : '';\n content.push(\n `<Card href=\"${urlFn(file.path)}\" title=${JSON.stringify(file.info.title)} ${descriptionAttr}/>`,\n );\n }\n\n content.push('</Cards>');\n return generateDocument(\n {\n title: index.title ?? 'Overview',\n description: index.description,\n },\n content.join('\\n'),\n options,\n );\n }\n\n for (const item of typeof items === 'function' ? items(context) : items) {\n files.push({\n path: path.extname(item.path).length === 0 ? `${item.path}.mdx` : item.path,\n content: fileContent(item),\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
import { ParsedSchema } from "../utils/schema.js";
|
|
2
|
-
import { RequestData } from "../requests/types.js";
|
|
3
2
|
import { FetchResult } from "./fetcher.js";
|
|
4
3
|
import { ParameterField, SecurityEntry } from "./index.js";
|
|
5
4
|
import { SchemaScope } from "./schema.js";
|
|
6
5
|
import { ComponentProps, FC, ReactNode } from "react";
|
|
7
|
-
import { FieldPath, UseControllerProps, UseControllerReturn } from "react-hook-form";
|
|
8
6
|
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
7
|
+
import { FieldKey } from "@fumari/stf";
|
|
9
8
|
|
|
10
9
|
//#region src/playground/client.d.ts
|
|
11
|
-
interface FormValues {
|
|
10
|
+
interface FormValues extends Record<string, unknown> {
|
|
12
11
|
path: Record<string, unknown>;
|
|
13
12
|
query: Record<string, unknown>;
|
|
14
13
|
header: Record<string, unknown>;
|
|
15
14
|
cookie: Record<string, unknown>;
|
|
16
15
|
body: unknown;
|
|
17
|
-
/**
|
|
18
|
-
* Store the cached encoded request data, do not modify it.
|
|
19
|
-
*/
|
|
20
|
-
_encoded?: RequestData;
|
|
21
16
|
}
|
|
22
17
|
interface PlaygroundClientProps extends ComponentProps<'form'>, SchemaScope {
|
|
23
18
|
route: string;
|
|
@@ -51,13 +46,12 @@ interface PlaygroundClientOptions {
|
|
|
51
46
|
/**
|
|
52
47
|
* render the paremeter inputs of API endpoint.
|
|
53
48
|
*
|
|
54
|
-
*
|
|
55
|
-
* - the library itself, with types from `fumadocs-openapi/playground/client`.
|
|
49
|
+
* for updating values, use:
|
|
56
50
|
* - the `Custom.useController()` from `fumadocs-openapi/playground/client`.
|
|
57
51
|
*
|
|
58
52
|
* Recommended types packages: `json-schema-typed`, `openapi-types`.
|
|
59
53
|
*/
|
|
60
|
-
renderParameterField?: (fieldName:
|
|
54
|
+
renderParameterField?: (fieldName: FieldKey, param: ParameterField) => ReactNode;
|
|
61
55
|
/**
|
|
62
56
|
* render the input for API endpoint body.
|
|
63
57
|
*
|
|
@@ -81,14 +75,19 @@ declare function PlaygroundClient({
|
|
|
81
75
|
...rest
|
|
82
76
|
}: PlaygroundClientProps): react_jsx_runtime0.JSX.Element;
|
|
83
77
|
interface AuthField {
|
|
84
|
-
fieldName:
|
|
78
|
+
fieldName: FieldKey;
|
|
85
79
|
defaultValue: unknown;
|
|
86
80
|
original?: SecurityEntry;
|
|
87
81
|
children: ReactNode;
|
|
88
82
|
mapOutput?: (values: unknown) => unknown;
|
|
89
83
|
}
|
|
90
84
|
declare const Custom: {
|
|
91
|
-
useController
|
|
85
|
+
useController(fieldName: FieldKey, options?: {
|
|
86
|
+
defaultValue?: unknown;
|
|
87
|
+
}): {
|
|
88
|
+
value: unknown;
|
|
89
|
+
setValue: (newValue: unknown) => boolean;
|
|
90
|
+
};
|
|
92
91
|
};
|
|
93
92
|
//#endregion
|
|
94
93
|
export { AuthField, Custom, FormValues, PlaygroundClientOptions, PlaygroundClientProps, PlaygroundClient as default };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","names":[],"sources":["../../src/playground/client.tsx"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.d.ts","names":[],"sources":["../../src/playground/client.tsx"],"sourcesContent":[],"mappings":";;;;;;;;;UAsDiB,UAAA,SAAmB;QAC5B;SACC;EAFQ,MAAA,EAGP,MAHkB,CAAA,MAAA,EAAA,OAAA,CAAA;EACpB,MAAA,EAGE,MAHF,CAAA,MAAA,EAAA,OAAA,CAAA;EACC,IAAA,EAAA,OAAA;;AAEC,UAIO,qBAAA,SAA8B,cAJrC,CAAA,MAAA,CAAA,EAI6D,WAJ7D,CAAA;EAJ0B,KAAA,EAAA,MAAA;EAAM,MAAA,EAAA,MAAA;EAQzB,UAAA,CAAA,EAGF,cAHwB,EAAA;EAGxB,UAAA,EACD,aADC,EAAA,EAAA;EACD,IAAA,CAAA,EAAA;IAEF,MAAA,EAAA,YAAA;IAMiB,SAAA,EAAA,MAAA;EAAf,CAAA;EAZiC;;;EAgB9B,UAAA,EAJH,MAIG,CAAA,MAAA,EAJY,YAIW,CAAA;EAIP,QAAA,CAAA,EAAA,MAAA;;AAQH,UAZb,uBAAA,CAYa;EAAX;;;EAWmC,mBAAA,CAAA,EAAA,CAAA,MAAA,EAnBrB,SAmBqB,EAAA,EAAA,GAnBL,SAmBK,EAAA;EAAmB;;;EAazD,cAAA,CAAA,EAAA,MAAA;EAcQ,UAAA,CAAA,EAvCT,OAuCyB,CAAA;IACtC,aAAA,EAvCiB,EAuCjB,CAAA;MACA,IAAA,EAxC4B,WAwC5B;IACA,CAAA,CAAA;EACA,CAAA,CAAA;EACA;;;;;;;;EA0Ue,oBAAS,CAAA,EAAA,CAAA,SAAA,EA1WW,QA0WX,EAAA,KAAA,EA1W4B,cA0W5B,EAAA,GA1W+C,SA0W/C;EACb;;;;AAiRb;;YAlnBc;;QAGP;;iBAciB,gBAAA;;;;;;;;;;;GAWrB,wBAAqB,kBAAA,CAAA,GAAA,CAAA;UAoUP,SAAA;aACJ;;aAGA;YACD;;;cA6QC;2BAEE"}
|
|
@@ -3,24 +3,25 @@
|
|
|
3
3
|
import { joinURL, resolveRequestData, resolveServerUrl, withBase } from "../utils/url.js";
|
|
4
4
|
import { useStorageKey } from "../ui/client/storage-key.js";
|
|
5
5
|
import { useApiContext } from "../ui/contexts/api.js";
|
|
6
|
-
import { cn } from "../utils/cn.js";
|
|
7
|
-
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../ui/components/select.js";
|
|
8
|
-
import { labelVariants } from "../ui/components/input.js";
|
|
9
|
-
import { SchemaProvider, useResolvedSchema } from "./schema.js";
|
|
10
|
-
import { FieldInput, FieldSet, JsonInput, ObjectInput } from "./components/inputs.js";
|
|
11
6
|
import { getStatusInfo } from "./status-info.js";
|
|
7
|
+
import { cn } from "../utils/cn.js";
|
|
12
8
|
import { MethodLabel } from "../ui/components/method-label.js";
|
|
13
9
|
import { useQuery } from "../utils/use-query.js";
|
|
14
10
|
import { encodeRequestData } from "../requests/media/encode.js";
|
|
11
|
+
import { SchemaProvider, useResolvedSchema } from "./schema.js";
|
|
12
|
+
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../ui/components/select.js";
|
|
13
|
+
import { labelVariants } from "../ui/components/input.js";
|
|
15
14
|
import ServerSelect from "./components/server-select.js";
|
|
16
15
|
import { useExampleRequests } from "../ui/operation/usage-tabs/client.js";
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
16
|
+
import { FieldInput, FieldSet, JsonInput, ObjectInput } from "./components/inputs.js";
|
|
17
|
+
import { Fragment, lazy, useEffect, useMemo, useRef, useState } from "react";
|
|
19
18
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
20
19
|
import { ChevronDown, LoaderCircle, X } from "lucide-react";
|
|
21
|
-
import { buttonVariants } from "fumadocs-ui/components/ui/button";
|
|
22
20
|
import { DynamicCodeBlock } from "fumadocs-ui/components/dynamic-codeblock";
|
|
23
21
|
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "fumadocs-ui/components/ui/collapsible";
|
|
22
|
+
import { buttonVariants } from "fumadocs-ui/components/ui/button";
|
|
23
|
+
import { StfProvider, useDataEngine, useFieldValue, useListener, useStf } from "@fumari/stf";
|
|
24
|
+
import { objectGet, objectSet, stringifyFieldKey } from "@fumari/stf/lib/utils";
|
|
24
25
|
|
|
25
26
|
//#region src/playground/client.tsx
|
|
26
27
|
const OauthDialog = lazy(() => import("./components/oauth-dialog.js").then((mod) => ({ default: mod.OauthDialog })));
|
|
@@ -28,7 +29,6 @@ const OauthDialogTrigger = lazy(() => import("./components/oauth-dialog.js").the
|
|
|
28
29
|
function PlaygroundClient({ route, method = "GET", securities, parameters = [], body, references, proxyUrl, writeOnly, readOnly, ...rest }) {
|
|
29
30
|
const { example: exampleId, examples, setExampleData } = useExampleRequests();
|
|
30
31
|
const storageKeys = useStorageKey();
|
|
31
|
-
const fieldInfoMap = useMemo(() => /* @__PURE__ */ new Map(), []);
|
|
32
32
|
const { mediaAdapters, serverRef, client: { playground: { components: { ResultDisplay = DefaultResultDisplay } = {}, requestTimeout = 10, transformAuthInputs } = {} } } = useApiContext();
|
|
33
33
|
const [securityId, setSecurityId] = useState(0);
|
|
34
34
|
const { inputs, mapInputs, initAuthValues } = useAuthInputs(securities[securityId], transformAuthInputs);
|
|
@@ -42,72 +42,61 @@ function PlaygroundClient({ route, method = "GET", securities, parameters = [],
|
|
|
42
42
|
cookie: requestData?.cookie ?? {}
|
|
43
43
|
};
|
|
44
44
|
}, [examples, exampleId]);
|
|
45
|
-
const
|
|
45
|
+
const stf = useStf({ defaultValues });
|
|
46
46
|
const testQuery = useQuery(async (input) => {
|
|
47
47
|
const targetServer = serverRef.current;
|
|
48
48
|
const fetcher = await import("./fetcher.js").then((mod) => mod.createBrowserFetcher(mediaAdapters, requestTimeout));
|
|
49
|
-
|
|
49
|
+
const encoded = encodeRequestData({
|
|
50
50
|
...mapInputs(input),
|
|
51
51
|
method,
|
|
52
52
|
bodyMediaType: body?.mediaType
|
|
53
53
|
}, mediaAdapters, parameters);
|
|
54
|
-
return fetcher.fetch(joinURL(withBase(targetServer ? resolveServerUrl(targetServer.url, targetServer.variables) : "/", window.location.origin), resolveRequestData(route,
|
|
54
|
+
return fetcher.fetch(joinURL(withBase(targetServer ? resolveServerUrl(targetServer.url, targetServer.variables) : "/", window.location.origin), resolveRequestData(route, encoded)), {
|
|
55
55
|
proxyUrl,
|
|
56
|
-
...
|
|
56
|
+
...encoded
|
|
57
57
|
});
|
|
58
58
|
});
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
const timerRef = useRef(null);
|
|
60
|
+
useListener({
|
|
61
|
+
stf,
|
|
62
|
+
onUpdate() {
|
|
63
|
+
if (timerRef.current) window.clearTimeout(timerRef.current);
|
|
64
|
+
timerRef.current = window.setTimeout(() => {
|
|
65
|
+
const values = stf.dataEngine.getData();
|
|
66
|
+
for (const item of inputs) {
|
|
67
|
+
const value = stf.dataEngine.get(item.fieldName);
|
|
68
|
+
if (value) localStorage.setItem(storageKeys.AuthField(item), JSON.stringify(value));
|
|
69
|
+
}
|
|
70
|
+
const data = {
|
|
71
|
+
...mapInputs(values),
|
|
72
|
+
method,
|
|
73
|
+
bodyMediaType: body?.mediaType
|
|
74
|
+
};
|
|
75
|
+
setExampleData(data, encodeRequestData(data, mediaAdapters, parameters));
|
|
76
|
+
}, timerRef.current ? 400 : 0);
|
|
63
77
|
}
|
|
64
|
-
const data = {
|
|
65
|
-
...mapInputs(values),
|
|
66
|
-
method,
|
|
67
|
-
bodyMediaType: body?.mediaType
|
|
68
|
-
};
|
|
69
|
-
values._encoded ??= encodeRequestData(data, mediaAdapters, parameters);
|
|
70
|
-
setExampleData(data, values._encoded);
|
|
71
78
|
});
|
|
72
79
|
useEffect(() => {
|
|
73
|
-
let timer = null;
|
|
74
|
-
const subscription = form.subscribe({
|
|
75
|
-
formState: { values: true },
|
|
76
|
-
callback({ values }) {
|
|
77
|
-
delete values._encoded;
|
|
78
|
-
if (timer) window.clearTimeout(timer);
|
|
79
|
-
timer = window.setTimeout(() => onUpdateDebounced(values), timer ? 400 : 0);
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
return () => subscription();
|
|
83
|
-
}, []);
|
|
84
|
-
useEffect(() => {
|
|
85
|
-
form.reset(initAuthValues(defaultValues));
|
|
86
|
-
return () => fieldInfoMap.clear();
|
|
87
|
-
}, [defaultValues]);
|
|
88
|
-
useEffect(() => {
|
|
89
|
-
form.reset((values) => initAuthValues(values));
|
|
90
80
|
return () => {
|
|
91
|
-
|
|
92
|
-
for (const item of inputs) set(values, item.fieldName, void 0);
|
|
93
|
-
return values;
|
|
94
|
-
});
|
|
81
|
+
stf.dataEngine.reset(defaultValues);
|
|
95
82
|
};
|
|
96
|
-
}, [
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
});
|
|
100
|
-
return /* @__PURE__ */ jsx(
|
|
101
|
-
|
|
83
|
+
}, [defaultValues]);
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
return initAuthValues(stf);
|
|
86
|
+
}, [defaultValues, inputs]);
|
|
87
|
+
return /* @__PURE__ */ jsx(StfProvider, {
|
|
88
|
+
value: stf,
|
|
102
89
|
children: /* @__PURE__ */ jsx(SchemaProvider, {
|
|
103
|
-
fieldInfoMap,
|
|
104
90
|
references,
|
|
105
91
|
writeOnly,
|
|
106
92
|
readOnly,
|
|
107
93
|
children: /* @__PURE__ */ jsxs("form", {
|
|
108
94
|
...rest,
|
|
109
95
|
className: cn("not-prose flex flex-col rounded-xl border shadow-md overflow-hidden bg-fd-card text-fd-card-foreground", rest.className),
|
|
110
|
-
onSubmit
|
|
96
|
+
onSubmit: (e) => {
|
|
97
|
+
testQuery.start(mapInputs(stf.dataEngine.getData()));
|
|
98
|
+
e.preventDefault();
|
|
99
|
+
},
|
|
111
100
|
children: [
|
|
112
101
|
/* @__PURE__ */ jsx(ServerSelect, {}),
|
|
113
102
|
/* @__PURE__ */ jsxs("div", {
|
|
@@ -133,7 +122,7 @@ function PlaygroundClient({ route, method = "GET", securities, parameters = [],
|
|
|
133
122
|
securities,
|
|
134
123
|
securityId,
|
|
135
124
|
setSecurityId,
|
|
136
|
-
children: inputs.map((input) => /* @__PURE__ */ jsx(Fragment, { children: input.children }, input.fieldName))
|
|
125
|
+
children: inputs.map((input) => /* @__PURE__ */ jsx(Fragment, { children: input.children }, stringifyFieldKey(input.fieldName)))
|
|
137
126
|
}),
|
|
138
127
|
/* @__PURE__ */ jsx(FormBody, {
|
|
139
128
|
body,
|
|
@@ -150,7 +139,7 @@ function PlaygroundClient({ route, method = "GET", securities, parameters = [],
|
|
|
150
139
|
}
|
|
151
140
|
function SecurityTabs({ securities, setSecurityId, securityId, children }) {
|
|
152
141
|
const [open, setOpen] = useState(false);
|
|
153
|
-
const
|
|
142
|
+
const engine = useDataEngine();
|
|
154
143
|
const result = /* @__PURE__ */ jsxs(CollapsiblePanel, {
|
|
155
144
|
title: "Authorization",
|
|
156
145
|
children: [/* @__PURE__ */ jsxs(Select, {
|
|
@@ -181,7 +170,7 @@ function SecurityTabs({ securities, setSecurityId, securityId, children }) {
|
|
|
181
170
|
setOpen(v);
|
|
182
171
|
if (v) setSecurityId(i);
|
|
183
172
|
},
|
|
184
|
-
setToken: (token) =>
|
|
173
|
+
setToken: (token) => engine.update(["header", "Authorization"], token),
|
|
185
174
|
children: result
|
|
186
175
|
});
|
|
187
176
|
}
|
|
@@ -207,7 +196,7 @@ function FormBody({ parameters = [], body }) {
|
|
|
207
196
|
path: "Path"
|
|
208
197
|
}[type],
|
|
209
198
|
children: items.map((field) => {
|
|
210
|
-
const fieldName =
|
|
199
|
+
const fieldName = [type, field.name];
|
|
211
200
|
if (renderParameterField) return renderParameterField(fieldName, field);
|
|
212
201
|
const contentTypes = field.content && Object.keys(field.content);
|
|
213
202
|
const schema = field.content && contentTypes && contentTypes.length > 0 ? field.content[contentTypes[0]].schema : field.schema;
|
|
@@ -215,7 +204,7 @@ function FormBody({ parameters = [], body }) {
|
|
|
215
204
|
name: field.name,
|
|
216
205
|
fieldName,
|
|
217
206
|
field: schema
|
|
218
|
-
}, fieldName);
|
|
207
|
+
}, stringifyFieldKey(fieldName));
|
|
219
208
|
})
|
|
220
209
|
}, type);
|
|
221
210
|
});
|
|
@@ -229,7 +218,7 @@ function BodyInput({ field: _field }) {
|
|
|
229
218
|
const [isJson, setIsJson] = useState(false);
|
|
230
219
|
if (field.format === "binary") return /* @__PURE__ */ jsx(FieldSet, {
|
|
231
220
|
field,
|
|
232
|
-
fieldName: "body"
|
|
221
|
+
fieldName: ["body"]
|
|
233
222
|
});
|
|
234
223
|
if (isJson) return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("button", {
|
|
235
224
|
className: cn(buttonVariants({
|
|
@@ -240,10 +229,10 @@ function BodyInput({ field: _field }) {
|
|
|
240
229
|
onClick: () => setIsJson(false),
|
|
241
230
|
type: "button",
|
|
242
231
|
children: "Close JSON Editor"
|
|
243
|
-
}), /* @__PURE__ */ jsx(JsonInput, { fieldName: "body" })] });
|
|
232
|
+
}), /* @__PURE__ */ jsx(JsonInput, { fieldName: ["body"] })] });
|
|
244
233
|
return /* @__PURE__ */ jsx(FieldSet, {
|
|
245
234
|
field,
|
|
246
|
-
fieldName: "body",
|
|
235
|
+
fieldName: ["body"],
|
|
247
236
|
collapsible: false,
|
|
248
237
|
name: /* @__PURE__ */ jsx("button", {
|
|
249
238
|
type: "button",
|
|
@@ -263,7 +252,7 @@ function useAuthInputs(securities, transform) {
|
|
|
263
252
|
const result = [];
|
|
264
253
|
if (!securities) return result;
|
|
265
254
|
for (const security of securities) if (security.type === "http" && security.scheme === "basic") {
|
|
266
|
-
const fieldName =
|
|
255
|
+
const fieldName = ["header", "Authorization"];
|
|
267
256
|
result.push({
|
|
268
257
|
fieldName,
|
|
269
258
|
original: security,
|
|
@@ -288,7 +277,7 @@ function useAuthInputs(securities, transform) {
|
|
|
288
277
|
})
|
|
289
278
|
});
|
|
290
279
|
} else if (security.type === "oauth2") {
|
|
291
|
-
const fieldName = "header
|
|
280
|
+
const fieldName = ["header", "Authorization"];
|
|
292
281
|
result.push({
|
|
293
282
|
fieldName,
|
|
294
283
|
original: security,
|
|
@@ -296,7 +285,7 @@ function useAuthInputs(securities, transform) {
|
|
|
296
285
|
children: /* @__PURE__ */ jsxs("fieldset", {
|
|
297
286
|
className: "flex flex-col gap-2",
|
|
298
287
|
children: [/* @__PURE__ */ jsx("label", {
|
|
299
|
-
htmlFor: fieldName,
|
|
288
|
+
htmlFor: stringifyFieldKey(fieldName),
|
|
300
289
|
className: cn(labelVariants()),
|
|
301
290
|
children: "Access Token"
|
|
302
291
|
}), /* @__PURE__ */ jsxs("div", {
|
|
@@ -318,7 +307,7 @@ function useAuthInputs(securities, transform) {
|
|
|
318
307
|
})
|
|
319
308
|
});
|
|
320
309
|
} else if (security.type === "http") {
|
|
321
|
-
const fieldName = "header
|
|
310
|
+
const fieldName = ["header", "Authorization"];
|
|
322
311
|
result.push({
|
|
323
312
|
fieldName,
|
|
324
313
|
original: security,
|
|
@@ -331,7 +320,7 @@ function useAuthInputs(securities, transform) {
|
|
|
331
320
|
})
|
|
332
321
|
});
|
|
333
322
|
} else if (security.type === "apiKey") {
|
|
334
|
-
const fieldName =
|
|
323
|
+
const fieldName = [security.in, security.name];
|
|
335
324
|
result.push({
|
|
336
325
|
fieldName,
|
|
337
326
|
defaultValue: "",
|
|
@@ -344,7 +333,7 @@ function useAuthInputs(securities, transform) {
|
|
|
344
333
|
})
|
|
345
334
|
});
|
|
346
335
|
} else {
|
|
347
|
-
const fieldName = "header
|
|
336
|
+
const fieldName = ["header", "Authorization"];
|
|
348
337
|
result.push({
|
|
349
338
|
fieldName,
|
|
350
339
|
defaultValue: "",
|
|
@@ -366,23 +355,26 @@ function useAuthInputs(securities, transform) {
|
|
|
366
355
|
const cloned = structuredClone(values);
|
|
367
356
|
for (const item of inputs) {
|
|
368
357
|
if (!item.mapOutput) continue;
|
|
369
|
-
|
|
358
|
+
objectSet(cloned, item.fieldName, item.mapOutput(objectGet(cloned, item.fieldName)));
|
|
370
359
|
}
|
|
371
360
|
return cloned;
|
|
372
361
|
};
|
|
373
|
-
const initAuthValues = (
|
|
362
|
+
const initAuthValues = (stf) => {
|
|
363
|
+
const { dataEngine } = stf;
|
|
374
364
|
for (const item of inputs) {
|
|
375
365
|
const stored = localStorage.getItem(storageKeys.AuthField(item));
|
|
376
366
|
if (stored) {
|
|
377
367
|
const parsed = JSON.parse(stored);
|
|
378
368
|
if (typeof parsed === typeof item.defaultValue) {
|
|
379
|
-
|
|
369
|
+
dataEngine.init(item.fieldName, parsed);
|
|
380
370
|
continue;
|
|
381
371
|
}
|
|
382
372
|
}
|
|
383
|
-
|
|
373
|
+
dataEngine.init(item.fieldName, item.defaultValue);
|
|
384
374
|
}
|
|
385
|
-
return
|
|
375
|
+
return () => {
|
|
376
|
+
for (const item of inputs) stf.dataEngine.delete(item.fieldName);
|
|
377
|
+
};
|
|
386
378
|
};
|
|
387
379
|
return {
|
|
388
380
|
inputs,
|
|
@@ -450,8 +442,12 @@ function CollapsiblePanel({ title, children, ...props }) {
|
|
|
450
442
|
}) })]
|
|
451
443
|
});
|
|
452
444
|
}
|
|
453
|
-
const Custom = { useController(
|
|
454
|
-
|
|
445
|
+
const Custom = { useController(fieldName, options) {
|
|
446
|
+
const [value, setValue] = useFieldValue(fieldName, options);
|
|
447
|
+
return {
|
|
448
|
+
value,
|
|
449
|
+
setValue
|
|
450
|
+
};
|
|
455
451
|
} };
|
|
456
452
|
|
|
457
453
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["defaultValues: FormValues","timer: number | null","result: AuthField[]"],"sources":["../../src/playground/client.tsx"],"sourcesContent":["'use client';\nimport {\n type FC,\n Fragment,\n lazy,\n type ReactNode,\n useEffect,\n useMemo,\n useState,\n useEffectEvent,\n type ComponentProps,\n} from 'react';\nimport type { FieldPath, UseControllerProps, UseControllerReturn } from 'react-hook-form';\nimport { FormProvider, get, set, useController, useForm, useFormContext } from 'react-hook-form';\nimport { useApiContext } from '@/ui/contexts/api';\nimport type { FetchResult } from '@/playground/fetcher';\nimport { FieldInput, FieldSet, JsonInput, ObjectInput } from './components/inputs';\nimport type { ParameterField, SecurityEntry } from '@/playground/index';\nimport { getStatusInfo } from './status-info';\nimport { joinURL, resolveRequestData, resolveServerUrl, withBase } from '@/utils/url';\nimport { DynamicCodeBlock } from 'fumadocs-ui/components/dynamic-codeblock';\nimport { MethodLabel } from '@/ui/components/method-label';\nimport { useQuery } from '@/utils/use-query';\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from 'fumadocs-ui/components/ui/collapsible';\nimport { X, ChevronDown, LoaderCircle } from 'lucide-react';\nimport { encodeRequestData } from '@/requests/media/encode';\nimport { buttonVariants } from 'fumadocs-ui/components/ui/button';\nimport { cn } from '@/utils/cn';\nimport {\n type FieldInfo,\n SchemaProvider,\n SchemaScope,\n useResolvedSchema,\n} from '@/playground/schema';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/ui/components/select';\nimport { labelVariants } from '@/ui/components/input';\nimport type { ParsedSchema } from '@/utils/schema';\nimport type { RequestData } from '@/requests/types';\nimport ServerSelect from './components/server-select';\nimport { useStorageKey } from '@/ui/client/storage-key';\nimport { useExampleRequests } from '@/ui/operation/usage-tabs/client';\n\nexport interface FormValues {\n path: Record<string, unknown>;\n query: Record<string, unknown>;\n header: Record<string, unknown>;\n cookie: Record<string, unknown>;\n body: unknown;\n\n /**\n * Store the cached encoded request data, do not modify it.\n */\n _encoded?: RequestData;\n}\n\nexport interface PlaygroundClientProps extends ComponentProps<'form'>, SchemaScope {\n route: string;\n method: string;\n parameters?: ParameterField[];\n securities: SecurityEntry[][];\n body?: {\n schema: ParsedSchema;\n mediaType: string;\n };\n /**\n * Resolver for $ref schemas you've passed\n */\n references: Record<string, ParsedSchema>;\n proxyUrl?: string;\n}\n\nexport interface PlaygroundClientOptions {\n /**\n * transform fields for auth-specific parameters (e.g. header)\n */\n transformAuthInputs?: (fields: AuthField[]) => AuthField[];\n\n /**\n * Request timeout in seconds (default: 10s)\n */\n requestTimeout?: number;\n\n components?: Partial<{\n ResultDisplay: FC<{ data: FetchResult }>;\n }>;\n\n /**\n * render the paremeter inputs of API endpoint.\n *\n * It uses `react-hook-form`, you can use either:\n * - the library itself, with types from `fumadocs-openapi/playground/client`.\n * - the `Custom.useController()` from `fumadocs-openapi/playground/client`.\n *\n * Recommended types packages: `json-schema-typed`, `openapi-types`.\n */\n renderParameterField?: (fieldName: FieldPath<FormValues>, param: ParameterField) => ReactNode;\n\n /**\n * render the input for API endpoint body.\n *\n * @see renderParameterField for customisation tips\n */\n renderBodyField?: (\n fieldName: 'body',\n info: {\n schema: ParsedSchema;\n mediaType: string;\n },\n ) => ReactNode;\n}\n\nconst OauthDialog = lazy(() =>\n import('./components/oauth-dialog').then((mod) => ({\n default: mod.OauthDialog,\n })),\n);\nconst OauthDialogTrigger = lazy(() =>\n import('./components/oauth-dialog').then((mod) => ({\n default: mod.OauthDialogTrigger,\n })),\n);\n\nexport default function PlaygroundClient({\n route,\n method = 'GET',\n securities,\n parameters = [],\n body,\n references,\n proxyUrl,\n writeOnly,\n readOnly,\n ...rest\n}: PlaygroundClientProps) {\n const { example: exampleId, examples, setExampleData } = useExampleRequests();\n const storageKeys = useStorageKey();\n const fieldInfoMap = useMemo(() => new Map<string, FieldInfo>(), []);\n const {\n mediaAdapters,\n serverRef,\n client: {\n playground: {\n components: { ResultDisplay = DefaultResultDisplay } = {},\n requestTimeout = 10,\n transformAuthInputs,\n } = {},\n },\n } = useApiContext();\n const [securityId, setSecurityId] = useState(0);\n const { inputs, mapInputs, initAuthValues } = useAuthInputs(\n securities[securityId],\n transformAuthInputs,\n );\n\n const defaultValues: FormValues = useMemo(() => {\n const requestData = examples.find((example) => example.id === exampleId)?.data;\n\n return {\n path: requestData?.path ?? {},\n query: requestData?.query ?? {},\n header: requestData?.header ?? {},\n body: requestData?.body ?? {},\n cookie: requestData?.cookie ?? {},\n };\n }, [examples, exampleId]);\n\n const form = useForm<FormValues>({\n defaultValues,\n });\n\n const testQuery = useQuery(async (input: FormValues) => {\n const targetServer = serverRef.current;\n const fetcher = await import('./fetcher').then((mod) =>\n mod.createBrowserFetcher(mediaAdapters, requestTimeout),\n );\n\n input._encoded ??= encodeRequestData(\n { ...mapInputs(input), method, bodyMediaType: body?.mediaType },\n mediaAdapters,\n parameters,\n );\n\n return fetcher.fetch(\n joinURL(\n withBase(\n targetServer ? resolveServerUrl(targetServer.url, targetServer.variables) : '/',\n window.location.origin,\n ),\n resolveRequestData(route, input._encoded),\n ),\n {\n proxyUrl,\n ...input._encoded,\n },\n );\n });\n\n const onUpdateDebounced = useEffectEvent((values: FormValues) => {\n for (const item of inputs) {\n const value = get(values, item.fieldName);\n\n if (value) {\n localStorage.setItem(storageKeys.AuthField(item), JSON.stringify(value));\n }\n }\n\n const data = {\n ...mapInputs(values),\n method,\n bodyMediaType: body?.mediaType,\n };\n values._encoded ??= encodeRequestData(data, mediaAdapters, parameters);\n setExampleData(data, values._encoded);\n });\n\n useEffect(() => {\n let timer: number | null = null;\n\n const subscription = form.subscribe({\n formState: {\n values: true,\n },\n callback({ values }) {\n // remove cached encoded request data\n delete values._encoded;\n\n if (timer) window.clearTimeout(timer);\n timer = window.setTimeout(() => onUpdateDebounced(values), timer ? 400 : 0);\n },\n });\n\n return () => subscription();\n // eslint-disable-next-line react-hooks/exhaustive-deps -- mounted once only\n }, []);\n\n useEffect(() => {\n form.reset(initAuthValues(defaultValues));\n\n return () => fieldInfoMap.clear();\n // eslint-disable-next-line react-hooks/exhaustive-deps -- ignore other parts\n }, [defaultValues]);\n\n useEffect(() => {\n form.reset((values) => initAuthValues(values));\n\n return () => {\n form.reset((values) => {\n for (const item of inputs) {\n set(values, item.fieldName, undefined);\n }\n\n return values;\n });\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps -- ignore other parts\n }, [inputs]);\n\n const onSubmit = form.handleSubmit((value) => {\n testQuery.start(mapInputs(value));\n });\n\n return (\n <FormProvider {...form}>\n <SchemaProvider\n fieldInfoMap={fieldInfoMap}\n references={references}\n writeOnly={writeOnly}\n readOnly={readOnly}\n >\n <form\n {...rest}\n className={cn(\n 'not-prose flex flex-col rounded-xl border shadow-md overflow-hidden bg-fd-card text-fd-card-foreground',\n rest.className,\n )}\n onSubmit={onSubmit}\n >\n <ServerSelect />\n <div className=\"flex flex-row items-center gap-2 text-sm p-3 not-last:pb-0\">\n <MethodLabel>{method}</MethodLabel>\n <Route route={route} className=\"flex-1\" />\n <button\n type=\"submit\"\n className={cn(buttonVariants({ color: 'primary', size: 'sm' }), 'w-14 py-1.5')}\n disabled={testQuery.isLoading}\n >\n {testQuery.isLoading ? <LoaderCircle className=\"size-4 animate-spin\" /> : 'Send'}\n </button>\n </div>\n\n {securities.length > 0 && (\n <SecurityTabs\n securities={securities}\n securityId={securityId}\n setSecurityId={setSecurityId}\n >\n {inputs.map((input) => (\n <Fragment key={input.fieldName}>{input.children}</Fragment>\n ))}\n </SecurityTabs>\n )}\n <FormBody body={body} parameters={parameters} />\n {testQuery.data ? <ResultDisplay data={testQuery.data} reset={testQuery.reset} /> : null}\n </form>\n </SchemaProvider>\n </FormProvider>\n );\n}\n\nfunction SecurityTabs({\n securities,\n setSecurityId,\n securityId,\n children,\n}: {\n securities: SecurityEntry[][];\n securityId: number;\n setSecurityId: (value: number) => void;\n children: ReactNode;\n}) {\n const [open, setOpen] = useState(false);\n const form = useFormContext();\n\n const result = (\n <CollapsiblePanel title=\"Authorization\">\n <Select value={securityId.toString()} onValueChange={(v) => setSecurityId(Number(v))}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {securities.map((security, i) => (\n <SelectItem key={i} value={i.toString()}>\n {security.map((item) => (\n <div key={item.id} className=\"max-w-[600px]\">\n <p className=\"font-mono font-medium\">{item.id}</p>\n <p className=\"text-fd-muted-foreground whitespace-pre-wrap\">{item.description}</p>\n </div>\n ))}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {children}\n </CollapsiblePanel>\n );\n\n for (let i = 0; i < securities.length; i++) {\n const security = securities[i];\n\n for (const item of security) {\n if (item.type === 'oauth2') {\n return (\n <OauthDialog\n scheme={item}\n scopes={item.scopes}\n open={open}\n setOpen={(v) => {\n setOpen(v);\n if (v) {\n setSecurityId(i);\n }\n }}\n setToken={(token) => form.setValue('header.Authorization', token)}\n >\n {result}\n </OauthDialog>\n );\n }\n }\n }\n\n return result;\n}\n\nconst ParamTypes = ['path', 'header', 'cookie', 'query'] as const;\n\nfunction FormBody({ parameters = [], body }: Pick<PlaygroundClientProps, 'parameters' | 'body'>) {\n const { renderParameterField, renderBodyField } = useApiContext().client.playground ?? {};\n const panels = useMemo(() => {\n return ParamTypes.map((type) => {\n const items = parameters.filter((v) => v.in === type);\n if (items.length === 0) return;\n\n return (\n <CollapsiblePanel\n key={type}\n title={\n {\n header: 'Header',\n cookie: 'Cookies',\n query: 'Query',\n path: 'Path',\n }[type]\n }\n >\n {items.map((field) => {\n const fieldName = `${type}.${field.name}` as const;\n if (renderParameterField) {\n return renderParameterField(fieldName, field);\n }\n\n const contentTypes = field.content && Object.keys(field.content);\n const schema = (\n field.content && contentTypes && contentTypes.length > 0\n ? field.content[contentTypes[0]].schema\n : field.schema\n ) as ParsedSchema;\n\n return (\n <FieldSet key={fieldName} name={field.name} fieldName={fieldName} field={schema} />\n );\n })}\n </CollapsiblePanel>\n );\n });\n }, [parameters, renderParameterField]);\n\n return (\n <>\n {panels}\n {body && (\n <CollapsiblePanel title=\"Body\">\n {renderBodyField ? renderBodyField('body', body) : <BodyInput field={body.schema} />}\n </CollapsiblePanel>\n )}\n </>\n );\n}\n\nfunction BodyInput({ field: _field }: { field: ParsedSchema }) {\n const field = useResolvedSchema(_field);\n const [isJson, setIsJson] = useState(false);\n\n if (field.format === 'binary') return <FieldSet field={field} fieldName=\"body\" />;\n\n if (isJson)\n return (\n <>\n <button\n className={cn(\n buttonVariants({\n color: 'secondary',\n size: 'sm',\n className: 'w-fit font-mono p-2',\n }),\n )}\n onClick={() => setIsJson(false)}\n type=\"button\"\n >\n Close JSON Editor\n </button>\n <JsonInput fieldName=\"body\" />\n </>\n );\n\n return (\n <FieldSet\n field={field}\n fieldName=\"body\"\n collapsible={false}\n name={\n <button\n type=\"button\"\n className={cn(\n buttonVariants({\n color: 'secondary',\n size: 'sm',\n className: 'p-2',\n }),\n )}\n onClick={() => setIsJson(true)}\n >\n Open JSON Editor\n </button>\n }\n />\n );\n}\n\nexport interface AuthField {\n fieldName: string;\n defaultValue: unknown;\n\n original?: SecurityEntry;\n children: ReactNode;\n\n mapOutput?: (values: unknown) => unknown;\n}\n\nfunction useAuthInputs(\n securities?: SecurityEntry[],\n transform?: (fields: AuthField[]) => AuthField[],\n) {\n const storageKeys = useStorageKey();\n const inputs = useMemo(() => {\n const result: AuthField[] = [];\n if (!securities) return result;\n\n for (const security of securities) {\n if (security.type === 'http' && security.scheme === 'basic') {\n const fieldName = `header.Authorization`;\n\n result.push({\n fieldName,\n original: security,\n defaultValue: {\n username: '',\n password: '',\n },\n mapOutput(out) {\n if (out && typeof out === 'object') {\n return `Basic ${btoa(`${'username' in out ? out.username : ''}:${'password' in out ? out.password : ''}`)}`;\n }\n\n return out;\n },\n children: (\n <ObjectInput\n field={{\n type: 'object',\n properties: {\n username: {\n type: 'string',\n },\n password: {\n type: 'string',\n },\n },\n required: ['username', 'password'],\n }}\n fieldName={fieldName}\n />\n ),\n });\n } else if (security.type === 'oauth2') {\n const fieldName = 'header.Authorization';\n\n result.push({\n fieldName: fieldName,\n original: security,\n defaultValue: 'Bearer ',\n children: (\n <fieldset className=\"flex flex-col gap-2\">\n <label htmlFor={fieldName} className={cn(labelVariants())}>\n Access Token\n </label>\n <div className=\"flex gap-2\">\n <FieldInput\n fieldName={fieldName}\n isRequired\n field={{\n type: 'string',\n }}\n className=\"flex-1\"\n />\n\n <OauthDialogTrigger\n type=\"button\"\n className={cn(\n buttonVariants({\n size: 'sm',\n color: 'secondary',\n }),\n )}\n >\n Authorize\n </OauthDialogTrigger>\n </div>\n </fieldset>\n ),\n });\n } else if (security.type === 'http') {\n const fieldName = 'header.Authorization';\n\n result.push({\n fieldName: fieldName,\n original: security,\n defaultValue: 'Bearer ',\n children: (\n <FieldSet\n name=\"Authorization (header)\"\n fieldName={fieldName}\n isRequired\n field={{\n type: 'string',\n }}\n />\n ),\n });\n } else if (security.type === 'apiKey') {\n const fieldName = `${security.in}.${security.name}`;\n\n result.push({\n fieldName,\n defaultValue: '',\n original: security,\n children: (\n <FieldSet\n fieldName={fieldName}\n name={`${security.name} (${security.in})`}\n isRequired\n field={{\n type: 'string',\n }}\n />\n ),\n });\n } else {\n const fieldName = 'header.Authorization';\n\n result.push({\n fieldName,\n defaultValue: '',\n original: security,\n children: (\n <>\n <FieldSet\n name=\"Authorization (header)\"\n isRequired\n fieldName={fieldName}\n field={{\n type: 'string',\n }}\n />\n <p className=\"text-fd-muted-foreground text-xs\">\n OpenID Connect is not supported at the moment, you can still set an access token\n here.\n </p>\n </>\n ),\n });\n }\n }\n\n return transform ? transform(result) : result;\n }, [securities, transform]);\n\n const mapInputs = (values: FormValues) => {\n const cloned = structuredClone(values);\n\n for (const item of inputs) {\n if (!item.mapOutput) continue;\n\n set(cloned, item.fieldName, item.mapOutput(get(cloned, item.fieldName)));\n }\n\n return cloned;\n };\n\n const initAuthValues = (values: FormValues) => {\n for (const item of inputs) {\n const stored = localStorage.getItem(storageKeys.AuthField(item));\n\n if (stored) {\n const parsed = JSON.parse(stored);\n if (typeof parsed === typeof item.defaultValue) {\n set(values, item.fieldName, parsed);\n continue;\n }\n }\n\n set(values, item.fieldName, item.defaultValue);\n }\n\n return values;\n };\n\n return { inputs, mapInputs, initAuthValues };\n}\n\nfunction Route({ route, ...props }: ComponentProps<'div'> & { route: string }) {\n return (\n <div\n {...props}\n className={cn(\n 'flex flex-row items-center gap-0.5 overflow-auto text-nowrap',\n props.className,\n )}\n >\n {route.split('/').map((part, index) => (\n <Fragment key={index}>\n {index > 0 && <span className=\"text-fd-muted-foreground\">/</span>}\n {part.startsWith('{') && part.endsWith('}') ? (\n <code className=\"bg-fd-primary/10 text-fd-primary\">{part}</code>\n ) : (\n <code className=\"text-fd-foreground\">{part}</code>\n )}\n </Fragment>\n ))}\n </div>\n );\n}\n\nfunction DefaultResultDisplay({ data, reset }: { data: FetchResult; reset: () => void }) {\n const statusInfo = useMemo(() => getStatusInfo(data.status), [data.status]);\n const { shikiOptions } = useApiContext();\n\n return (\n <div className=\"flex flex-col gap-3 p-3\">\n <div className=\"flex justify-between items-center\">\n <div className=\"inline-flex items-center gap-1.5 text-sm font-medium text-fd-foreground\">\n <statusInfo.icon className={cn('size-4', statusInfo.color)} />\n {statusInfo.description}\n </div>\n <button\n type=\"button\"\n className={cn(\n buttonVariants({ size: 'icon-xs' }),\n 'p-0 text-fd-muted-foreground hover:text-fd-accent-foreground [&_svg]:size-3.5',\n )}\n onClick={() => reset()}\n aria-label=\"Dismiss response\"\n >\n <X />\n </button>\n </div>\n <p className=\"text-sm text-fd-muted-foreground\">{data.status}</p>\n {data.data !== undefined && (\n <DynamicCodeBlock\n lang={typeof data.data === 'string' && data.data.length > 50000 ? 'text' : data.type}\n code={typeof data.data === 'string' ? data.data : JSON.stringify(data.data, null, 2)}\n options={shikiOptions}\n />\n )}\n </div>\n );\n}\n\nfunction CollapsiblePanel({\n title,\n children,\n ...props\n}: Omit<ComponentProps<'div'>, 'title'> & {\n title: ReactNode;\n}) {\n return (\n <Collapsible {...props} className=\"border-b last:border-b-0\">\n <CollapsibleTrigger className=\"group w-full flex items-center gap-2 p-3 text-sm font-medium\">\n {title}\n <ChevronDown className=\"ms-auto size-3.5 text-fd-muted-foreground group-data-[state=open]:rotate-180\" />\n </CollapsibleTrigger>\n <CollapsibleContent>\n <div className=\"flex flex-col gap-3 p-3 pt-1\">{children}</div>\n </CollapsibleContent>\n </Collapsible>\n );\n}\n\n// exports for customisations\nexport const Custom = {\n useController<\n TName extends FieldPath<FormValues> = FieldPath<FormValues>,\n TTransformedValues = FormValues,\n >(\n props: UseControllerProps<FormValues, TName, TTransformedValues>,\n ): UseControllerReturn<FormValues, TName> {\n return useController<FormValues, TName, TTransformedValues>(props);\n },\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":[],"sources":["../../src/playground/client.tsx"],"sourcesContent":["'use client';\nimport {\n type FC,\n Fragment,\n lazy,\n type ReactNode,\n useEffect,\n useMemo,\n useState,\n type ComponentProps,\n useRef,\n} from 'react';\nimport { useApiContext } from '@/ui/contexts/api';\nimport type { FetchResult } from '@/playground/fetcher';\nimport type { ParameterField, SecurityEntry } from '@/playground/index';\nimport { getStatusInfo } from './status-info';\nimport { joinURL, resolveRequestData, resolveServerUrl, withBase } from '@/utils/url';\nimport { DynamicCodeBlock } from 'fumadocs-ui/components/dynamic-codeblock';\nimport { MethodLabel } from '@/ui/components/method-label';\nimport { useQuery } from '@/utils/use-query';\nimport {\n Collapsible,\n CollapsibleContent,\n CollapsibleTrigger,\n} from 'fumadocs-ui/components/ui/collapsible';\nimport { X, ChevronDown, LoaderCircle } from 'lucide-react';\nimport { encodeRequestData } from '@/requests/media/encode';\nimport { buttonVariants } from 'fumadocs-ui/components/ui/button';\nimport { cn } from '@/utils/cn';\nimport { SchemaProvider, SchemaScope, useResolvedSchema } from '@/playground/schema';\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@/ui/components/select';\nimport { labelVariants } from '@/ui/components/input';\nimport type { ParsedSchema } from '@/utils/schema';\nimport ServerSelect from './components/server-select';\nimport { useStorageKey } from '@/ui/client/storage-key';\nimport { useExampleRequests } from '@/ui/operation/usage-tabs/client';\nimport {\n FieldKey,\n Stf,\n StfProvider,\n useDataEngine,\n useFieldValue,\n useListener,\n useStf,\n} from '@fumari/stf';\nimport { objectGet, objectSet, stringifyFieldKey } from '@fumari/stf/lib/utils';\nimport { FieldInput, FieldSet, JsonInput, ObjectInput } from './components/inputs';\n\nexport interface FormValues extends Record<string, unknown> {\n path: Record<string, unknown>;\n query: Record<string, unknown>;\n header: Record<string, unknown>;\n cookie: Record<string, unknown>;\n body: unknown;\n}\n\nexport interface PlaygroundClientProps extends ComponentProps<'form'>, SchemaScope {\n route: string;\n method: string;\n parameters?: ParameterField[];\n securities: SecurityEntry[][];\n body?: {\n schema: ParsedSchema;\n mediaType: string;\n };\n /**\n * Resolver for $ref schemas you've passed\n */\n references: Record<string, ParsedSchema>;\n proxyUrl?: string;\n}\n\nexport interface PlaygroundClientOptions {\n /**\n * transform fields for auth-specific parameters (e.g. header)\n */\n transformAuthInputs?: (fields: AuthField[]) => AuthField[];\n\n /**\n * Request timeout in seconds (default: 10s)\n */\n requestTimeout?: number;\n\n components?: Partial<{\n ResultDisplay: FC<{ data: FetchResult }>;\n }>;\n\n /**\n * render the paremeter inputs of API endpoint.\n *\n * for updating values, use:\n * - the `Custom.useController()` from `fumadocs-openapi/playground/client`.\n *\n * Recommended types packages: `json-schema-typed`, `openapi-types`.\n */\n renderParameterField?: (fieldName: FieldKey, param: ParameterField) => ReactNode;\n\n /**\n * render the input for API endpoint body.\n *\n * @see renderParameterField for customisation tips\n */\n renderBodyField?: (\n fieldName: 'body',\n info: {\n schema: ParsedSchema;\n mediaType: string;\n },\n ) => ReactNode;\n}\n\nconst OauthDialog = lazy(() =>\n import('./components/oauth-dialog').then((mod) => ({\n default: mod.OauthDialog,\n })),\n);\nconst OauthDialogTrigger = lazy(() =>\n import('./components/oauth-dialog').then((mod) => ({\n default: mod.OauthDialogTrigger,\n })),\n);\n\nexport default function PlaygroundClient({\n route,\n method = 'GET',\n securities,\n parameters = [],\n body,\n references,\n proxyUrl,\n writeOnly,\n readOnly,\n ...rest\n}: PlaygroundClientProps) {\n const { example: exampleId, examples, setExampleData } = useExampleRequests();\n const storageKeys = useStorageKey();\n const {\n mediaAdapters,\n serverRef,\n client: {\n playground: {\n components: { ResultDisplay = DefaultResultDisplay } = {},\n requestTimeout = 10,\n transformAuthInputs,\n } = {},\n },\n } = useApiContext();\n const [securityId, setSecurityId] = useState(0);\n const { inputs, mapInputs, initAuthValues } = useAuthInputs(\n securities[securityId],\n transformAuthInputs,\n );\n\n const defaultValues: FormValues = useMemo(() => {\n const requestData = examples.find((example) => example.id === exampleId)?.data;\n\n return {\n path: requestData?.path ?? {},\n query: requestData?.query ?? {},\n header: requestData?.header ?? {},\n body: requestData?.body ?? {},\n cookie: requestData?.cookie ?? {},\n };\n }, [examples, exampleId]);\n\n const stf = useStf({\n // it is fine to modify `defaultValues` in place\n // because we already try to persist the form values via `setExampleData`.\n defaultValues,\n });\n\n const testQuery = useQuery(async (input: FormValues) => {\n const targetServer = serverRef.current;\n const fetcher = await import('./fetcher').then((mod) =>\n mod.createBrowserFetcher(mediaAdapters, requestTimeout),\n );\n const encoded = encodeRequestData(\n { ...mapInputs(input), method, bodyMediaType: body?.mediaType },\n mediaAdapters,\n parameters,\n );\n return fetcher.fetch(\n joinURL(\n withBase(\n targetServer ? resolveServerUrl(targetServer.url, targetServer.variables) : '/',\n window.location.origin,\n ),\n resolveRequestData(route, encoded),\n ),\n {\n proxyUrl,\n ...encoded,\n },\n );\n });\n\n const timerRef = useRef<number | null>(null);\n useListener({\n stf,\n onUpdate() {\n if (timerRef.current) window.clearTimeout(timerRef.current);\n timerRef.current = window.setTimeout(\n () => {\n const values = stf.dataEngine.getData() as FormValues;\n for (const item of inputs) {\n const value = stf.dataEngine.get(item.fieldName);\n\n if (value) {\n localStorage.setItem(storageKeys.AuthField(item), JSON.stringify(value));\n }\n }\n\n const data = {\n ...mapInputs(values),\n method,\n bodyMediaType: body?.mediaType,\n };\n setExampleData(data, encodeRequestData(data, mediaAdapters, parameters));\n },\n timerRef.current ? 400 : 0,\n );\n },\n });\n\n useEffect(() => {\n return () => {\n stf.dataEngine.reset(defaultValues);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps -- ignore other parts\n }, [defaultValues]);\n\n useEffect(() => {\n return initAuthValues(stf);\n // eslint-disable-next-line react-hooks/exhaustive-deps -- ignore other parts\n }, [defaultValues, inputs]);\n\n return (\n <StfProvider value={stf}>\n <SchemaProvider references={references} writeOnly={writeOnly} readOnly={readOnly}>\n <form\n {...rest}\n className={cn(\n 'not-prose flex flex-col rounded-xl border shadow-md overflow-hidden bg-fd-card text-fd-card-foreground',\n rest.className,\n )}\n onSubmit={(e) => {\n testQuery.start(mapInputs(stf.dataEngine.getData() as FormValues));\n e.preventDefault();\n }}\n >\n <ServerSelect />\n <div className=\"flex flex-row items-center gap-2 text-sm p-3 not-last:pb-0\">\n <MethodLabel>{method}</MethodLabel>\n <Route route={route} className=\"flex-1\" />\n <button\n type=\"submit\"\n className={cn(buttonVariants({ color: 'primary', size: 'sm' }), 'w-14 py-1.5')}\n disabled={testQuery.isLoading}\n >\n {testQuery.isLoading ? <LoaderCircle className=\"size-4 animate-spin\" /> : 'Send'}\n </button>\n </div>\n\n {securities.length > 0 && (\n <SecurityTabs\n securities={securities}\n securityId={securityId}\n setSecurityId={setSecurityId}\n >\n {inputs.map((input) => (\n <Fragment key={stringifyFieldKey(input.fieldName)}>{input.children}</Fragment>\n ))}\n </SecurityTabs>\n )}\n <FormBody body={body} parameters={parameters} />\n {testQuery.data ? <ResultDisplay data={testQuery.data} reset={testQuery.reset} /> : null}\n </form>\n </SchemaProvider>\n </StfProvider>\n );\n}\n\nfunction SecurityTabs({\n securities,\n setSecurityId,\n securityId,\n children,\n}: {\n securities: SecurityEntry[][];\n securityId: number;\n setSecurityId: (value: number) => void;\n children: ReactNode;\n}) {\n const [open, setOpen] = useState(false);\n const engine = useDataEngine();\n\n const result = (\n <CollapsiblePanel title=\"Authorization\">\n <Select value={securityId.toString()} onValueChange={(v) => setSecurityId(Number(v))}>\n <SelectTrigger>\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {securities.map((security, i) => (\n <SelectItem key={i} value={i.toString()}>\n {security.map((item) => (\n <div key={item.id} className=\"max-w-[600px]\">\n <p className=\"font-mono font-medium\">{item.id}</p>\n <p className=\"text-fd-muted-foreground whitespace-pre-wrap\">{item.description}</p>\n </div>\n ))}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {children}\n </CollapsiblePanel>\n );\n\n for (let i = 0; i < securities.length; i++) {\n const security = securities[i];\n\n for (const item of security) {\n if (item.type === 'oauth2') {\n return (\n <OauthDialog\n scheme={item}\n scopes={item.scopes}\n open={open}\n setOpen={(v) => {\n setOpen(v);\n if (v) {\n setSecurityId(i);\n }\n }}\n setToken={(token) => engine.update(['header', 'Authorization'], token)}\n >\n {result}\n </OauthDialog>\n );\n }\n }\n }\n\n return result;\n}\n\nconst ParamTypes = ['path', 'header', 'cookie', 'query'] as const;\n\nfunction FormBody({ parameters = [], body }: Pick<PlaygroundClientProps, 'parameters' | 'body'>) {\n const { renderParameterField, renderBodyField } = useApiContext().client.playground ?? {};\n const panels = useMemo(() => {\n return ParamTypes.map((type) => {\n const items = parameters.filter((v) => v.in === type);\n if (items.length === 0) return;\n\n return (\n <CollapsiblePanel\n key={type}\n title={\n {\n header: 'Header',\n cookie: 'Cookies',\n query: 'Query',\n path: 'Path',\n }[type]\n }\n >\n {items.map((field) => {\n const fieldName: FieldKey = [type, field.name];\n if (renderParameterField) {\n return renderParameterField(fieldName, field);\n }\n\n const contentTypes = field.content && Object.keys(field.content);\n const schema = (\n field.content && contentTypes && contentTypes.length > 0\n ? field.content[contentTypes[0]].schema\n : field.schema\n ) as ParsedSchema;\n\n return (\n <FieldSet\n key={stringifyFieldKey(fieldName)}\n name={field.name}\n fieldName={fieldName}\n field={schema}\n />\n );\n })}\n </CollapsiblePanel>\n );\n });\n }, [parameters, renderParameterField]);\n\n return (\n <>\n {panels}\n {body && (\n <CollapsiblePanel title=\"Body\">\n {renderBodyField ? renderBodyField('body', body) : <BodyInput field={body.schema} />}\n </CollapsiblePanel>\n )}\n </>\n );\n}\n\nfunction BodyInput({ field: _field }: { field: ParsedSchema }) {\n const field = useResolvedSchema(_field);\n const [isJson, setIsJson] = useState(false);\n\n if (field.format === 'binary') return <FieldSet field={field} fieldName={['body']} />;\n\n if (isJson)\n return (\n <>\n <button\n className={cn(\n buttonVariants({\n color: 'secondary',\n size: 'sm',\n className: 'w-fit font-mono p-2',\n }),\n )}\n onClick={() => setIsJson(false)}\n type=\"button\"\n >\n Close JSON Editor\n </button>\n <JsonInput fieldName={['body']} />\n </>\n );\n\n return (\n <FieldSet\n field={field}\n fieldName={['body']}\n collapsible={false}\n name={\n <button\n type=\"button\"\n className={cn(\n buttonVariants({\n color: 'secondary',\n size: 'sm',\n className: 'p-2',\n }),\n )}\n onClick={() => setIsJson(true)}\n >\n Open JSON Editor\n </button>\n }\n />\n );\n}\n\nexport interface AuthField {\n fieldName: FieldKey;\n defaultValue: unknown;\n\n original?: SecurityEntry;\n children: ReactNode;\n\n mapOutput?: (values: unknown) => unknown;\n}\n\nfunction useAuthInputs(\n securities?: SecurityEntry[],\n transform?: (fields: AuthField[]) => AuthField[],\n) {\n const storageKeys = useStorageKey();\n const inputs = useMemo(() => {\n const result: AuthField[] = [];\n if (!securities) return result;\n\n for (const security of securities) {\n if (security.type === 'http' && security.scheme === 'basic') {\n const fieldName: FieldKey = ['header', 'Authorization'];\n\n result.push({\n fieldName,\n original: security,\n defaultValue: {\n username: '',\n password: '',\n },\n mapOutput(out) {\n if (out && typeof out === 'object') {\n return `Basic ${btoa(`${'username' in out ? out.username : ''}:${'password' in out ? out.password : ''}`)}`;\n }\n\n return out;\n },\n children: (\n <ObjectInput\n field={{\n type: 'object',\n properties: {\n username: {\n type: 'string',\n },\n password: {\n type: 'string',\n },\n },\n required: ['username', 'password'],\n }}\n fieldName={fieldName}\n />\n ),\n });\n } else if (security.type === 'oauth2') {\n const fieldName: FieldKey = ['header', 'Authorization'];\n\n result.push({\n fieldName,\n original: security,\n defaultValue: 'Bearer ',\n children: (\n <fieldset className=\"flex flex-col gap-2\">\n <label htmlFor={stringifyFieldKey(fieldName)} className={cn(labelVariants())}>\n Access Token\n </label>\n <div className=\"flex gap-2\">\n <FieldInput\n fieldName={fieldName}\n isRequired\n field={{\n type: 'string',\n }}\n className=\"flex-1\"\n />\n\n <OauthDialogTrigger\n type=\"button\"\n className={cn(\n buttonVariants({\n size: 'sm',\n color: 'secondary',\n }),\n )}\n >\n Authorize\n </OauthDialogTrigger>\n </div>\n </fieldset>\n ),\n });\n } else if (security.type === 'http') {\n const fieldName: FieldKey = ['header', 'Authorization'];\n\n result.push({\n fieldName,\n original: security,\n defaultValue: 'Bearer ',\n children: (\n <FieldSet\n name=\"Authorization (header)\"\n fieldName={fieldName}\n isRequired\n field={{\n type: 'string',\n }}\n />\n ),\n });\n } else if (security.type === 'apiKey') {\n const fieldName: FieldKey = [security.in, security.name];\n\n result.push({\n fieldName,\n defaultValue: '',\n original: security,\n children: (\n <FieldSet\n fieldName={fieldName}\n name={`${security.name} (${security.in})`}\n isRequired\n field={{\n type: 'string',\n }}\n />\n ),\n });\n } else {\n const fieldName: FieldKey = ['header', 'Authorization'];\n\n result.push({\n fieldName,\n defaultValue: '',\n original: security,\n children: (\n <>\n <FieldSet\n name=\"Authorization (header)\"\n isRequired\n fieldName={fieldName}\n field={{\n type: 'string',\n }}\n />\n <p className=\"text-fd-muted-foreground text-xs\">\n OpenID Connect is not supported at the moment, you can still set an access token\n here.\n </p>\n </>\n ),\n });\n }\n }\n\n return transform ? transform(result) : result;\n }, [securities, transform]);\n\n const mapInputs = (values: FormValues) => {\n const cloned = structuredClone(values);\n\n for (const item of inputs) {\n if (!item.mapOutput) continue;\n objectSet(cloned, item.fieldName, item.mapOutput(objectGet(cloned, item.fieldName)));\n }\n\n return cloned;\n };\n\n const initAuthValues = (stf: Stf) => {\n const { dataEngine } = stf;\n for (const item of inputs) {\n const stored = localStorage.getItem(storageKeys.AuthField(item));\n\n if (stored) {\n const parsed = JSON.parse(stored);\n if (typeof parsed === typeof item.defaultValue) {\n dataEngine.init(item.fieldName, parsed);\n continue;\n }\n }\n\n dataEngine.init(item.fieldName, item.defaultValue);\n }\n\n // reset\n return () => {\n for (const item of inputs) {\n stf.dataEngine.delete(item.fieldName);\n }\n };\n };\n\n return { inputs, mapInputs, initAuthValues };\n}\n\nfunction Route({ route, ...props }: ComponentProps<'div'> & { route: string }) {\n return (\n <div\n {...props}\n className={cn(\n 'flex flex-row items-center gap-0.5 overflow-auto text-nowrap',\n props.className,\n )}\n >\n {route.split('/').map((part, index) => (\n <Fragment key={index}>\n {index > 0 && <span className=\"text-fd-muted-foreground\">/</span>}\n {part.startsWith('{') && part.endsWith('}') ? (\n <code className=\"bg-fd-primary/10 text-fd-primary\">{part}</code>\n ) : (\n <code className=\"text-fd-foreground\">{part}</code>\n )}\n </Fragment>\n ))}\n </div>\n );\n}\n\nfunction DefaultResultDisplay({ data, reset }: { data: FetchResult; reset: () => void }) {\n const statusInfo = useMemo(() => getStatusInfo(data.status), [data.status]);\n const { shikiOptions } = useApiContext();\n\n return (\n <div className=\"flex flex-col gap-3 p-3\">\n <div className=\"flex justify-between items-center\">\n <div className=\"inline-flex items-center gap-1.5 text-sm font-medium text-fd-foreground\">\n <statusInfo.icon className={cn('size-4', statusInfo.color)} />\n {statusInfo.description}\n </div>\n <button\n type=\"button\"\n className={cn(\n buttonVariants({ size: 'icon-xs' }),\n 'p-0 text-fd-muted-foreground hover:text-fd-accent-foreground [&_svg]:size-3.5',\n )}\n onClick={() => reset()}\n aria-label=\"Dismiss response\"\n >\n <X />\n </button>\n </div>\n <p className=\"text-sm text-fd-muted-foreground\">{data.status}</p>\n {data.data !== undefined && (\n <DynamicCodeBlock\n lang={typeof data.data === 'string' && data.data.length > 50000 ? 'text' : data.type}\n code={typeof data.data === 'string' ? data.data : JSON.stringify(data.data, null, 2)}\n options={shikiOptions}\n />\n )}\n </div>\n );\n}\n\nfunction CollapsiblePanel({\n title,\n children,\n ...props\n}: Omit<ComponentProps<'div'>, 'title'> & {\n title: ReactNode;\n}) {\n return (\n <Collapsible {...props} className=\"border-b last:border-b-0\">\n <CollapsibleTrigger className=\"group w-full flex items-center gap-2 p-3 text-sm font-medium\">\n {title}\n <ChevronDown className=\"ms-auto size-3.5 text-fd-muted-foreground group-data-[state=open]:rotate-180\" />\n </CollapsibleTrigger>\n <CollapsibleContent>\n <div className=\"flex flex-col gap-3 p-3 pt-1\">{children}</div>\n </CollapsibleContent>\n </Collapsible>\n );\n}\n\nexport const Custom = {\n useController(\n fieldName: FieldKey,\n options?: {\n defaultValue?: unknown;\n },\n ) {\n const [value, setValue] = useFieldValue(fieldName, options);\n return {\n value,\n setValue,\n };\n },\n};\n"],"mappings":"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"}
|